blob: 8331ba094567c6e5b743615317de943b940f4b84 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2009, 2015 Wind River Systems and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Wind River Systems - initial API and implementation
* Winnie Lai (Texas Instruments) - Individual Element Number Format test cases (Bug 202556)
*******************************************************************************/
package org.eclipse.cdt.tests.dsf.vm;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.concurrent.ExecutionException;
import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
import org.eclipse.cdt.dsf.concurrent.DefaultDsfExecutor;
import org.eclipse.cdt.dsf.concurrent.DsfExecutor;
import org.eclipse.cdt.dsf.concurrent.IDsfStatusConstants;
import org.eclipse.cdt.dsf.concurrent.Query;
import org.eclipse.cdt.dsf.debug.service.IFormattedValues;
import org.eclipse.cdt.dsf.debug.ui.viewmodel.IDebugVMConstants;
import org.eclipse.cdt.dsf.debug.ui.viewmodel.numberformat.FormattedValueVMUtil;
import org.eclipse.cdt.dsf.debug.ui.viewmodel.numberformat.IElementFormatProvider;
import org.eclipse.cdt.dsf.service.DsfSession;
import org.eclipse.cdt.dsf.service.IDsfService;
import org.eclipse.cdt.dsf.ui.viewmodel.AbstractVMAdapter;
import org.eclipse.cdt.dsf.ui.viewmodel.IVMNode;
import org.eclipse.cdt.dsf.ui.viewmodel.IVMProvider;
import org.eclipse.cdt.dsf.ui.viewmodel.properties.IPropertiesUpdate;
import org.eclipse.cdt.dsf.ui.viewmodel.properties.PropertiesUpdateStatus;
import org.eclipse.cdt.dsf.ui.viewmodel.update.IVMUpdatePolicy;
import org.eclipse.cdt.dsf.ui.viewmodel.update.ManualUpdatePolicy;
import org.eclipse.cdt.tests.dsf.IViewerUpdatesListenerConstants;
import org.eclipse.cdt.tests.dsf.vm.TestModel.TestElement;
import org.eclipse.cdt.tests.dsf.vm.TestModel.TestElementValidator;
import org.eclipse.cdt.tests.dsf.vm.TestModel.TestEvent;
import org.eclipse.debug.internal.ui.viewers.model.IInternalTreeModelViewer;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDelta;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext;
import org.eclipse.debug.internal.ui.viewers.model.provisional.ITreeModelViewer;
import org.eclipse.debug.internal.ui.viewers.model.provisional.TreeModelViewer;
import org.eclipse.jface.viewers.TreePath;
import org.eclipse.jface.viewers.ViewerLabel;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.XMLMemento;
import junit.framework.AssertionFailedError;
import junit.framework.TestCase;
/**
* Tests to verify the operation of FormattedValuesVMUtil
* @since 2.2
*/
abstract public class FormattedValueTests extends TestCase
implements IViewerUpdatesListenerConstants, IDebugVMConstants {
Display fDisplay;
Shell fShell;
DsfExecutor fDsfExecutor;
DsfSession fDsfSession;
ITreeModelViewer fViewer;
TestModelUpdatesListener fViewerListener;
TestModelUpdatesListener fVMListener;
FormattedValuesListener fFormattedValuesListener;
TestModel fModel;
DummyFormattedValueService fDummyValuesService;
AbstractVMAdapter fVMAdapter;
TestModelCachingVMProvider fVMProvider;
int vmListenerLevel = -1;
public FormattedValueTests(String name) {
super(name);
}
/**
* @throws java.lang.Exception
*/
@Override
protected void setUp() throws Exception {
fDsfExecutor = new DefaultDsfExecutor();
fDsfSession = DsfSession.startSession(fDsfExecutor, getClass().getName());
fDisplay = PlatformUI.getWorkbench().getDisplay();
fShell = new Shell(fDisplay/*, SWT.ON_TOP | SWT.SHELL_TRIM*/);
fShell.setMaximized(true);
fShell.setLayout(new FillLayout());
fViewer = createViewer(fDisplay, fShell);
fModel = new TestModel(fDsfSession);
initializeService(fModel);
fDummyValuesService = new DummyFormattedValueService(fDsfSession);
initializeService(fDummyValuesService);
fViewerListener = new TestModelUpdatesListener(fViewer, true, false);
fModel.setRoot(new TestElement(fModel, "root", new TestElement[0]));
fModel.setElementChildren(TreePath.EMPTY, makeModelElements(fModel, getTestModelDepth(), "model"));
fVMAdapter = new AbstractVMAdapter() {
@Override
protected IVMProvider createViewModelProvider(IPresentationContext context) {
return fVMProvider;
}
};
fVMProvider = new TestModelCachingVMProvider(fVMAdapter, fViewer.getPresentationContext(), fDsfSession);
fVMListener = new TestModelUpdatesListener();
fVMProvider.getNode().setVMUpdateListener(fVMListener);
fVMProvider.getNode().getLabelProvider().addPropertiesUpdateListener(fViewerListener);
fFormattedValuesListener = new FormattedValuesListener(fModel);
fVMProvider.getNode().setFormattedValuesListener(fFormattedValuesListener);
fModel.setTestModelListener(fFormattedValuesListener);
fShell.open();
}
/**
* helper to create view model and viewer
* @param vmOnly true to create view model only and do not create viewer
*/
void createViewer(boolean vmOnly) {
if (vmOnly == false) {
fDisplay = PlatformUI.getWorkbench().getDisplay();
fShell = new Shell(fDisplay/*, SWT.ON_TOP | SWT.SHELL_TRIM*/);
fShell.setMaximized(true);
fShell.setLayout(new FillLayout());
fViewer = createViewer(fDisplay, fShell);
fViewerListener = new TestModelUpdatesListener(fViewer, true, false);
}
fVMProvider = new TestElementFormatVMProvider(fVMAdapter, fViewer.getPresentationContext(), fDsfSession);
fVMListener = new TestModelUpdatesListener();
fVMProvider.getNode().setVMUpdateListener(fVMListener);
fVMProvider.getNode().getLabelProvider().addPropertiesUpdateListener(fViewerListener);
fVMProvider.getNode().setFormattedValuesListener(fFormattedValuesListener);
if (vmOnly == false) {
fShell.open();
}
}
/**
* helper to destory view model and viewer
* @param vmOnly true to destory view model only and do not destroy viewer
*/
void destroyViewer(boolean vmOnly) {
fVMProvider.getNode().setFormattedValuesListener(null);
fVMProvider.getNode().getLabelProvider().removePropertiesUpdateListener(fViewerListener);
fVMProvider.getNode().setVMUpdateListener(null);
fVMListener.dispose();
if (vmOnly == false) {
fViewerListener.dispose();
fViewer.getPresentationContext().dispose();
// Close the shell
fShell.close();
while (!fShell.isDisposed())
if (!fDisplay.readAndDispatch())
fDisplay.sleep();
}
}
/**
* helper to recreate view model only
*/
void recreateViewModel() {
destroyViewer(true);
createViewer(true);
}
/**
* helper to recreate viewer (and view model)
*/
void recreateViewer() {
destroyViewer(false);
createViewer(false);
}
private void initializeService(final IDsfService service) throws InterruptedException, ExecutionException {
Query<Object> initQuery = new Query<>() {
@Override
protected void execute(DataRequestMonitor<Object> rm) {
rm.setData(new Object());
service.initialize(rm);
}
};
fDsfExecutor.execute(initQuery);
initQuery.get();
}
abstract protected IInternalTreeModelViewer createViewer(Display display, Shell shell);
/**
* @throws java.lang.Exception
*/
@Override
protected void tearDown() throws Exception {
fVMProvider.getNode().setFormattedValuesListener(null);
fModel.setTestModelListener(null);
fVMProvider.getNode().getLabelProvider().removePropertiesUpdateListener(fViewerListener);
fVMProvider.getNode().setVMUpdateListener(null);
fVMAdapter.dispose();
fVMListener.dispose();
fViewerListener.dispose();
shutdownService(fDummyValuesService);
shutdownService(fModel);
fViewer.getPresentationContext().dispose();
// Close the shell and exit.
fShell.close();
while (!fShell.isDisposed())
if (!fDisplay.readAndDispatch())
fDisplay.sleep();
DsfSession.endSession(fDsfSession);
fDsfExecutor.shutdown();
}
private void shutdownService(final IDsfService service) throws InterruptedException, ExecutionException {
Query<Object> shutdownQuery = new Query<>() {
@Override
protected void execute(DataRequestMonitor<Object> rm) {
rm.setData(new Object());
service.shutdown(rm);
}
};
fDsfExecutor.execute(shutdownQuery);
shutdownQuery.get();
}
/**
* Depth (size) of the test model to be used in the tests. This number allows
* the jface based tests to use a small enough model to fit on the screen, and
* for the virtual viewer to exercise the content provider to a greater extent.
*/
abstract protected int getTestModelDepth();
public void testValidate() {
setInput(IFormattedValues.NATURAL_FORMAT);
setFormatAndValidate(IFormattedValues.HEX_FORMAT, false, false, false);
}
public void testChangeFormat() {
setInput(IFormattedValues.NATURAL_FORMAT);
setFormatAndValidate(IFormattedValues.HEX_FORMAT, false, false, false);
setFormatAndValidate(IFormattedValues.NATURAL_FORMAT, false, false, false);
}
public void testChangeFormatManualUpdateMode() {
setInput(IFormattedValues.NATURAL_FORMAT);
setUpdatePolicy(ManualUpdatePolicy.MANUAL_UPDATE_POLICY_ID);
// Chenge to a new format, this does not cause the cache entries to be
// set to dirty. Retrieving new format values should happen from the service.
setFormatAndValidate(IFormattedValues.HEX_FORMAT, true, false, false);
// Change _back_ to natural format. Values should be retrieved from cache.
setFormatAndValidate(IFormattedValues.NATURAL_FORMAT, true, true, false);
// Generate an event which will cause all cache entries to be marked dirty.
postEventInManualUpdateMode();
// Change back again to hex format. Values should be retrieved from cache.
setFormatAndValidate(IFormattedValues.HEX_FORMAT, true, true, false);
// Change to a decimal, which is not cached, values should come with an error.
setFormatAndValidate(IFormattedValues.DECIMAL_FORMAT, true, true, true);
}
private void postEventInManualUpdateMode() {
// Generate an event which will cause all cache entries to be marked dirty.
fViewerListener.reset();
fViewerListener.addUpdates(TreePath.EMPTY, fModel.getRootElement(), -1,
ALL_UPDATES_COMPLETE | PROPERTY_UPDATES);
fVMListener.reset();
fFormattedValuesListener.reset();
fVMProvider.postEvent(new TestEvent(fModel.getRootElement(), IModelDelta.CONTENT));
while (!fViewerListener.isFinished(ALL_UPDATES_COMPLETE | PROPERTY_UPDATES))
if (!fDisplay.readAndDispatch())
fDisplay.sleep();
assertTrue(fFormattedValuesListener.getFormattedValuesCompleted().isEmpty());
}
public void testInvalidFormat() {
setInput(IFormattedValues.NATURAL_FORMAT);
fViewerListener.reset();
fViewerListener.addUpdates(TreePath.EMPTY, ((TestElementVMContext) fViewer.getInput()).getElement(), -1,
ALL_UPDATES_COMPLETE | PROPERTY_UPDATES);
fVMListener.reset();
fVMListener.addUpdates(TreePath.EMPTY, fModel.getRootElement(), -1, ALL_UPDATES_COMPLETE | PROPERTY_UPDATES);
// Set the new number format to the viewer.
fViewer.getPresentationContext().setProperty(PROP_FORMATTED_VALUE_FORMAT_PREFERENCE, "invalid format");
while (!fViewerListener.isFinished(ALL_UPDATES_COMPLETE | PROPERTY_UPDATES)
|| !fVMListener.isFinished(CONTENT_UPDATES | PROPERTY_UPDATES))
if (!fDisplay.readAndDispatch())
fDisplay.sleep();
validateModel(IFormattedValues.HEX_FORMAT,
" (" + FormattedValueVMUtil.getFormatLabel(IFormattedValues.HEX_FORMAT) + ")",
DummyFormattedValueService.DUMMY_FORMAT, " (" + DummyFormattedValueService.DUMMY_FORMAT + ")");
}
/**
* Test that each element can have its own format
*/
public void testValidateElement() {
recreateViewModel();
String preferenceFormat = IFormattedValues.NATURAL_FORMAT;
setInput(preferenceFormat);
// set each element to the same element format different than the preference format, and verify
HashMap<String, ElementFormatSetting> map = new HashMap<>();
String[] format = { IFormattedValues.HEX_FORMAT };
makeElementFormatSetting(fViewer, TreePath.EMPTY, format, -1, 0, map);
ArrayList<ElementFormatSetting> elementFormats = new ArrayList<>(map.values());
setFormatAndValidate(preferenceFormat, elementFormats, elementFormats, true, false, false);
// element of same level use the same format and different levels have different formats, and verify
map.clear();
format = new String[] { IFormattedValues.HEX_FORMAT, IFormattedValues.DECIMAL_FORMAT,
IFormattedValues.OCTAL_FORMAT, IFormattedValues.BINARY_FORMAT, IFormattedValues.NATURAL_FORMAT };
makeElementFormatSetting(fViewer, TreePath.EMPTY, format, -1, 0, map);
elementFormats = new ArrayList<>(map.values());
setFormatAndValidate(preferenceFormat, elementFormats, elementFormats, false, false, false);
}
/**
* Test that each element can change to a format and then restore to preference format
*/
public void testChangeElementFormat() {
recreateViewModel();
String preferenceFormat = IFormattedValues.HEX_FORMAT;
setInput(IFormattedValues.NATURAL_FORMAT);
setFormatAndValidate(preferenceFormat, false, false, false);
// set each element to a format, and verify
HashMap<String, ElementFormatSetting> map = new HashMap<>();
String[] format = { IFormattedValues.HEX_FORMAT, IFormattedValues.DECIMAL_FORMAT, IFormattedValues.OCTAL_FORMAT,
IFormattedValues.BINARY_FORMAT, IFormattedValues.NATURAL_FORMAT };
makeElementFormatSetting(fViewer, TreePath.EMPTY, format, -1, 0, map);
ArrayList<ElementFormatSetting> elementFormats = new ArrayList<>(map.values());
setFormatAndValidate(preferenceFormat, elementFormats, elementFormats, false, false, false);
// Restore each element to preference format, and verify
for (ElementFormatSetting e : elementFormats) {
e.formatId = null;
}
setFormatAndValidate(preferenceFormat, elementFormats, elementFormats, false, false, false);
}
/**
* Test changing element to a format and then restore to preference format,
* using a view model provider that applies a format to child elements
* of a certain level of depth.
*/
public void testChangeElementFormatApplyDepth() {
recreateViewModel();
if (fVMProvider instanceof TestElementFormatVMProvider == false) {
return;
}
TestElementFormatVMProvider myVM = (TestElementFormatVMProvider) fVMProvider;
String preferenceFormat = IFormattedValues.HEX_FORMAT;
setInput(IFormattedValues.NATURAL_FORMAT);
setFormatAndValidate(preferenceFormat, false, false, false);
int[] myDepths = new int[] { -1, 2 };
for (int depth : myDepths) {
myVM.elementFormatApplyDepth = depth;
// set top level element to a format, and verify top and child elements
// at certain levels have the correct format.
String[] format = { IFormattedValues.DECIMAL_FORMAT };
HashMap<String, ElementFormatSetting> map = new HashMap<>();
makeElementFormatSetting(fViewer, TreePath.EMPTY, format, 1, 0, map);
ArrayList<ElementFormatSetting> setElementFormats = new ArrayList<>(map.values());
HashMap<String, ElementFormatSetting> expMap = new HashMap<>();
makeElementFormatSetting(fViewer, TreePath.EMPTY, format, depth, 0, expMap);
ArrayList<ElementFormatSetting> expectElementFormats = new ArrayList<>(expMap.values());
setFormatAndValidate(preferenceFormat, setElementFormats, expectElementFormats, false, false, false);
// Restore top level element to preference format, and verify.
for (ElementFormatSetting e : setElementFormats) {
e.formatId = null;
}
for (ElementFormatSetting e : expectElementFormats) {
e.formatId = null;
}
setFormatAndValidate(preferenceFormat, setElementFormats, expectElementFormats, false, false, false);
}
}
/**
* Test changing format of each element under manual update policy.
* Formatted values should be retrieved from cache if available.
* Changing to a format whose formatted value is not in cache should get a cache miss error.
*/
public void testChangeElementFormatManualUpdateMode() {
recreateViewModel();
String preferenceFormat = IFormattedValues.NATURAL_FORMAT;
setInput(IFormattedValues.NATURAL_FORMAT);
setUpdatePolicy(ManualUpdatePolicy.MANUAL_UPDATE_POLICY_ID);
// Change to a new format, this does not cause the cache entries to be
// set to dirty. Retrieving new format values should happen from the service.
HashMap<String, ElementFormatSetting> map1 = new HashMap<>();
String[] format1 = { IFormattedValues.HEX_FORMAT };
makeElementFormatSetting(fViewer, TreePath.EMPTY, format1, -1, 0, map1);
ArrayList<ElementFormatSetting> elementFormats1 = new ArrayList<>(map1.values());
setFormatAndValidate(preferenceFormat, elementFormats1, elementFormats1, true, false, false);
// Remove element format and so restore back to preference - natural format. Values should be retrieved from cache.
HashMap<String, ElementFormatSetting> map2 = new HashMap<>();
String[] format2 = { null };
makeElementFormatSetting(fViewer, TreePath.EMPTY, format2, -1, 0, map2);
ArrayList<ElementFormatSetting> elementFormats2 = new ArrayList<>(map2.values());
setFormatAndValidate(preferenceFormat, elementFormats2, elementFormats2, true, true, false);
// Generate an event which will cause all cache entries to be marked dirty.
postEventInManualUpdateMode();
// Change back again to hex format. Values should be retrieved from cache.
setFormatAndValidate(preferenceFormat, elementFormats1, elementFormats1, true, true, false);
// Change to a decimal, which is not cached, values should come with an error.
HashMap<String, ElementFormatSetting> map3 = new HashMap<>();
String[] format3 = { IFormattedValues.DECIMAL_FORMAT };
makeElementFormatSetting(fViewer, TreePath.EMPTY, format3, -1, 0, map3);
ArrayList<ElementFormatSetting> elementFormats3 = new ArrayList<>(map3.values());
setFormatAndValidate(preferenceFormat, elementFormats3, elementFormats3, true, true, true);
}
/**
* Test changing element format under manual update policy,
* using a view model provider that applies a format to child elements
* of a certain level of depth.
*/
public void testChangeElementFormatApplyDepthManualUpdateMode() {
int[] myDepths = new int[] { -1, 2 };
for (int depth : myDepths) {
recreateViewer();
if (fVMProvider instanceof TestElementFormatVMProvider == false) {
return;
}
TestElementFormatVMProvider myVM = (TestElementFormatVMProvider) fVMProvider;
String preferenceFormat = IFormattedValues.NATURAL_FORMAT;
setInput(IFormattedValues.NATURAL_FORMAT);
setUpdatePolicy(ManualUpdatePolicy.MANUAL_UPDATE_POLICY_ID);
myVM.elementFormatApplyDepth = depth;
// Change top level to a new format, this does not cause the cache entries to be
// set to dirty. Retrieving new format values should happen from the service.
String[] format1 = { IFormattedValues.HEX_FORMAT };
HashMap<String, ElementFormatSetting> map1 = new HashMap<>();
makeElementFormatSetting(fViewer, TreePath.EMPTY, format1, 1, 0, map1);
ArrayList<ElementFormatSetting> elementFormats1 = new ArrayList<>(map1.values());
HashMap<String, ElementFormatSetting> expMap1 = new HashMap<>();
makeElementFormatSetting(fViewer, TreePath.EMPTY, format1, depth, 0, expMap1);
ArrayList<ElementFormatSetting> expectElementFormats1 = new ArrayList<>(expMap1.values());
vmListenerLevel = depth;
setFormatAndValidate(preferenceFormat, elementFormats1, expectElementFormats1, true, false, false);
// Remove element format and so restore back to preference format - natural. Values should be retrieved from cache.
String[] format2 = { null };
HashMap<String, ElementFormatSetting> map2 = new HashMap<>();
makeElementFormatSetting(fViewer, TreePath.EMPTY, format2, 1, 0, map2);
ArrayList<ElementFormatSetting> elementFormats2 = new ArrayList<>(map2.values());
HashMap<String, ElementFormatSetting> expMap2 = new HashMap<>();
makeElementFormatSetting(fViewer, TreePath.EMPTY, format2, depth, 0, expMap2);
ArrayList<ElementFormatSetting> expectElementFormats2 = new ArrayList<>(expMap2.values());
setFormatAndValidate(preferenceFormat, elementFormats2, expectElementFormats2, true, true, false);
// Generate an event which will cause all cache entries to be marked dirty.
postEventInManualUpdateMode();
// Change back again to hex format. Values should be retrieved from cache.
setFormatAndValidate(preferenceFormat, elementFormats1, expectElementFormats1, true, true, false);
// Change to a decimal, which is not cached, values should come with an error.
String[] format3 = { IFormattedValues.DECIMAL_FORMAT };
HashMap<String, ElementFormatSetting> map3 = new HashMap<>();
makeElementFormatSetting(fViewer, TreePath.EMPTY, format3, 1, 0, map3);
ArrayList<ElementFormatSetting> elementFormats3 = new ArrayList<>(map3.values());
HashMap<String, ElementFormatSetting> expMap3 = new HashMap<>();
makeElementFormatSetting(fViewer, TreePath.EMPTY, format3, depth, 0, expMap3);
ArrayList<ElementFormatSetting> expectElementFormats3 = new ArrayList<>(expMap3.values());
setFormatAndValidate(preferenceFormat, elementFormats3, expectElementFormats3, true, true, true);
}
}
/**
* Test that when the preference format is invalid, each element can still change to a format.
* Also, each element can restore to the invalid preference format such that
* the element uses first available format from service.
*/
public void testChangeElementFormatWithInvalidPreference() {
recreateViewModel();
String preferenceFormat = IFormattedValues.NATURAL_FORMAT;
setInput(preferenceFormat);
// set preference format to an invalid format and verify
setInvalidPreferenceAndVerify();
// set each element to a format, and verify
HashMap<String, ElementFormatSetting> map = new HashMap<>();
String[] format = { IFormattedValues.HEX_FORMAT, IFormattedValues.DECIMAL_FORMAT, IFormattedValues.OCTAL_FORMAT,
IFormattedValues.BINARY_FORMAT, IFormattedValues.NATURAL_FORMAT };
makeElementFormatSetting(fViewer, TreePath.EMPTY, format, -1, 0, map);
ArrayList<ElementFormatSetting> elementFormats = new ArrayList<>(map.values());
setFormatAndValidate("invalid format", elementFormats, elementFormats, false, false, false);
// Restore each element to preference format which is an invalid format
for (ElementFormatSetting e : elementFormats) {
e.formatId = null;
}
fViewerListener.reset();
fViewerListener.addUpdates(TreePath.EMPTY, ((TestElementVMContext) fViewer.getInput()).getElement(), -1,
ALL_UPDATES_COMPLETE | PROPERTY_UPDATES);
fVMListener.reset();
fVMListener.addUpdates(TreePath.EMPTY, fModel.getRootElement(), -1, ALL_UPDATES_COMPLETE | PROPERTY_UPDATES);
if (fVMProvider instanceof IElementFormatProvider) {
IElementFormatProvider ep = ((IElementFormatProvider) fVMProvider);
for (ElementFormatSetting es : elementFormats) {
ep.setActiveFormat(fViewer.getPresentationContext(), es.nodes.toArray(new IVMNode[es.nodes.size()]),
fViewer.getInput(), es.elementPaths.toArray(new TreePath[es.elementPaths.size()]), es.formatId);
}
}
while (!fViewerListener.isFinished(ALL_UPDATES_COMPLETE | PROPERTY_UPDATES)
|| !fVMListener.isFinished(CONTENT_UPDATES | PROPERTY_UPDATES)) {
if (!fDisplay.readAndDispatch()) {
fDisplay.sleep();
}
}
// verify service's first available format is used
validateModel(IFormattedValues.HEX_FORMAT,
" (" + FormattedValueVMUtil.getFormatLabel(IFormattedValues.HEX_FORMAT) + ")",
DummyFormattedValueService.DUMMY_FORMAT, " (" + DummyFormattedValueService.DUMMY_FORMAT + ")");
}
/**
* Test that when an element is set to to an invalid format, the element uses preference format.
*/
public void testInvalidElementFormat() {
recreateViewModel();
String preferenceFormat = IFormattedValues.NATURAL_FORMAT;
setInput(preferenceFormat);
// set each element to an invalid format
setElementInvalidFormat();
// verify preference format is used when element format is invalid
validateModel(preferenceFormat, "");
}
/**
* Test that when an element is set to to an invalid format and the preference format is invalid,
* the element uses first available format from service.
*/
public void testInvalidElementFormatWithInvalidPreference() {
recreateViewModel();
String preferenceFormat = IFormattedValues.NATURAL_FORMAT;
setInput(preferenceFormat);
// set preference format to an invalid format and verify
setInvalidPreferenceAndVerify();
// set each element to an invalid format
setElementInvalidFormat();
// verify service's first available format is used when element format and preference format are invalid
validateModel(IFormattedValues.HEX_FORMAT,
" (" + FormattedValueVMUtil.getFormatLabel(IFormattedValues.HEX_FORMAT) + ")",
DummyFormattedValueService.DUMMY_FORMAT, " (" + DummyFormattedValueService.DUMMY_FORMAT + ")");
}
/**
* Test that element format can be persisted in memento and viewer
* can restore to the persisted settings.
*/
public void testPersistElementFormat() {
recreateViewModel();
String preferenceFormat = IFormattedValues.HEX_FORMAT;
setInput(IFormattedValues.NATURAL_FORMAT);
setFormatAndValidate(preferenceFormat, false, false, false);
// set each element to a format, and verify
HashMap<String, ElementFormatSetting> map = new HashMap<>();
String[] format = { IFormattedValues.HEX_FORMAT, IFormattedValues.DECIMAL_FORMAT, IFormattedValues.OCTAL_FORMAT,
IFormattedValues.BINARY_FORMAT, IFormattedValues.NATURAL_FORMAT };
makeElementFormatSetting(fViewer, TreePath.EMPTY, format, -1, 0, map);
ArrayList<ElementFormatSetting> elementFormats = new ArrayList<>(map.values());
setFormatAndValidate(preferenceFormat, elementFormats, elementFormats, false, false, false);
// save settings
XMLMemento memento = XMLMemento.createWriteRoot("TEST");
if (fViewer instanceof TreeModelViewer == false)
return;
((TreeModelViewer) fViewer).saveState(memento);
// throw away any settings inside the viewer and create a new viewer
// with memento settings, this is the same effect resulted from closing
// and opening workspace again.
recreateViewer();
if (fViewer instanceof TreeModelViewer == false)
return;
((TreeModelViewer) fViewer).initState(memento);
setInput(IFormattedValues.NATURAL_FORMAT);
preferenceFormat = (String) fViewer.getPresentationContext()
.getProperty(PROP_FORMATTED_VALUE_FORMAT_PREFERENCE);
validateModel(elementFormats, preferenceFormat, "", preferenceFormat, "");
}
/**
* helper class that stores some element paths and nodes using a certain format
*/
class ElementFormatSetting {
ArrayList<IVMNode> nodes;
ArrayList<TreePath> elementPaths;
String formatId;
}
/**
* helper to create element format settings for all children paths of a given element path.
* Tree paths at the same level will use the same format. Tree paths at different
* levels will use different formats.
* @param _viewer tree viewer
* @param path given element path
* @param formats formats to rotate for different levels of children tree paths
* @param levelStop depth to stop recursively walk down the children.
* @param levelIndex index to a format for a level of children
* @param result store the created element format settings
*/
void makeElementFormatSetting(ITreeModelViewer _viewer, TreePath path, String[] formats, int levelStop,
int levelIndex, HashMap<String, ElementFormatSetting> result) {
if (levelStop >= 0 && levelIndex >= levelStop)
return;
IInternalTreeModelViewer viewer = (IInternalTreeModelViewer) _viewer;
int childCount = viewer.getChildCount(path);
if (childCount == 0)
return;
String fmt = formats[levelIndex % formats.length];
ElementFormatSetting setting = result.get(fmt);
if (setting == null) {
setting = new ElementFormatSetting();
setting.nodes = new ArrayList<>(childCount);
setting.elementPaths = new ArrayList<>(childCount);
setting.formatId = fmt;
result.put(fmt, setting);
}
for (int i = 0; i < childCount; i++) {
Object viewerObject = viewer.getChildElement(path, i);
if (viewerObject instanceof TestElementVMContext) {
TreePath childPath = path.createChildPath(viewerObject);
setting.nodes.add(((TestElementVMContext) viewerObject).getVMNode());
setting.elementPaths.add(childPath);
makeElementFormatSetting(viewer, childPath, formats, levelStop, levelIndex + 1, result);
}
}
}
/**
* helper to set element to an invalid format
*/
void setElementInvalidFormat() {
fViewerListener.reset();
fViewerListener.addUpdates(TreePath.EMPTY, ((TestElementVMContext) fViewer.getInput()).getElement(), -1,
ALL_UPDATES_COMPLETE | PROPERTY_UPDATES);
fVMListener.reset();
fVMListener.addUpdates(TreePath.EMPTY, fModel.getRootElement(), -1, ALL_UPDATES_COMPLETE | PROPERTY_UPDATES);
HashMap<String, ElementFormatSetting> map = new HashMap<>();
String[] format = { "invalid element format" };
makeElementFormatSetting(fViewer, TreePath.EMPTY, format, -1, 0, map);
ArrayList<ElementFormatSetting> elementFormats = new ArrayList<>(map.values());
if (fVMProvider instanceof IElementFormatProvider) {
IElementFormatProvider ep = ((IElementFormatProvider) fVMProvider);
for (ElementFormatSetting es : elementFormats) {
ep.setActiveFormat(fViewer.getPresentationContext(), es.nodes.toArray(new IVMNode[es.nodes.size()]),
fViewer.getInput(), es.elementPaths.toArray(new TreePath[es.elementPaths.size()]), es.formatId);
}
}
while (!fViewerListener.isFinished(ALL_UPDATES_COMPLETE | PROPERTY_UPDATES)
|| !fVMListener.isFinished(CONTENT_UPDATES | PROPERTY_UPDATES)) {
if (!fDisplay.readAndDispatch()) {
fDisplay.sleep();
}
}
}
/**
* helper to set preference to an invalid format and verify.
*/
void setInvalidPreferenceAndVerify() {
fViewerListener.reset();
fViewerListener.addUpdates(TreePath.EMPTY, ((TestElementVMContext) fViewer.getInput()).getElement(), -1,
ALL_UPDATES_COMPLETE | PROPERTY_UPDATES);
fVMListener.reset();
fVMListener.addUpdates(TreePath.EMPTY, fModel.getRootElement(), -1, ALL_UPDATES_COMPLETE | PROPERTY_UPDATES);
fViewer.getPresentationContext().setProperty(PROP_FORMATTED_VALUE_FORMAT_PREFERENCE, "invalid format");
while (!fViewerListener.isFinished(ALL_UPDATES_COMPLETE | PROPERTY_UPDATES)
|| !fVMListener.isFinished(CONTENT_UPDATES | PROPERTY_UPDATES)) {
if (!fDisplay.readAndDispatch()) {
fDisplay.sleep();
}
}
validateModel(IFormattedValues.HEX_FORMAT,
" (" + FormattedValueVMUtil.getFormatLabel(IFormattedValues.HEX_FORMAT) + ")",
DummyFormattedValueService.DUMMY_FORMAT, " (" + DummyFormattedValueService.DUMMY_FORMAT + ")");
}
/**
* Initial format is NATURAL.
*/
private void setInput(String formatId) {
// Set the new number format to the viewer.
fViewer.getPresentationContext().setProperty(PROP_FORMATTED_VALUE_FORMAT_PREFERENCE, formatId);
fViewer.setAutoExpandLevel(-1);
TestElementVMContext rootVMC = fVMProvider.getElementVMContext(fViewer.getPresentationContext(),
fModel.getRootElement());
// Create the listener
fViewerListener.reset();
fViewerListener.addUpdates(TreePath.EMPTY, rootVMC.getElement(), -1, ALL_UPDATES_COMPLETE | PROPERTY_UPDATES);
fVMListener.reset();
fVMListener.addUpdates(TreePath.EMPTY, rootVMC.getElement(), -1, ALL_UPDATES_COMPLETE | PROPERTY_UPDATES);
fFormattedValuesListener.reset();
fViewer.setInput(rootVMC);
while (!fViewerListener.isFinished(ALL_UPDATES_COMPLETE | PROPERTY_UPDATES)
|| !fVMListener.isFinished(CONTENT_COMPLETE | PROPERTY_UPDATES))
if (!fDisplay.readAndDispatch())
fDisplay.sleep();
assertTrue(fFormattedValuesListener.isFinished());
}
private void setUpdatePolicy(String policyId) {
IVMUpdatePolicy[] policies = fVMProvider.getAvailableUpdatePolicies();
IVMUpdatePolicy newPolicy = null;
for (IVMUpdatePolicy policy : policies) {
if (policyId.equals(policy.getID())) {
newPolicy = policy;
break;
}
}
if (newPolicy != null) {
fVMProvider.setActiveUpdatePolicy(newPolicy);
} else {
throw new RuntimeException("Update policy " + policyId + " not available");
}
fViewerListener.reset();
fViewerListener.addUpdates(TreePath.EMPTY, fModel.getRootElement(), -1,
ALL_UPDATES_COMPLETE | PROPERTY_UPDATES);
fVMListener.setFailOnRedundantUpdates(false);
while (!fViewerListener.isFinished(ALL_UPDATES_COMPLETE | PROPERTY_UPDATES))
if (!fDisplay.readAndDispatch())
fDisplay.sleep();
fVMListener.setFailOnRedundantUpdates(true);
}
private void setFormatAndValidate(String formatId, boolean expectContentCached, boolean expectFormattedValuesCached,
boolean expectCacheMissError) {
setFormatAndValidate(formatId, null, null, expectContentCached, expectFormattedValuesCached,
expectCacheMissError);
}
private void setFormatAndValidate(String formatId, ArrayList<ElementFormatSetting> setElementFormats,
ArrayList<ElementFormatSetting> expectElementFormats, boolean expectContentCached,
boolean expectFormattedValuesCached, boolean expectCacheMissError) {
fViewerListener.reset();
fViewerListener.addUpdates(TreePath.EMPTY, ((TestElementVMContext) fViewer.getInput()).getElement(), -1,
ALL_UPDATES_COMPLETE | PROPERTY_UPDATES);
fVMListener.reset();
int vmUpdateFlags = PROPERTY_UPDATES;
if (!expectContentCached) {
vmUpdateFlags |= ALL_UPDATES_COMPLETE;
}
fVMListener.addUpdates(TreePath.EMPTY, fModel.getRootElement(), vmListenerLevel, vmUpdateFlags);
fFormattedValuesListener.reset();
if (expectFormattedValuesCached && !expectCacheMissError) {
fFormattedValuesListener.setCachedFormats(new String[] { formatId });
}
if (fVMProvider instanceof IElementFormatProvider && setElementFormats != null) {
IElementFormatProvider ep = ((IElementFormatProvider) fVMProvider);
for (ElementFormatSetting es : setElementFormats) {
ep.setActiveFormat(fViewer.getPresentationContext(), es.nodes.toArray(new IVMNode[es.nodes.size()]),
fViewer.getInput(), es.elementPaths.toArray(new TreePath[es.elementPaths.size()]), es.formatId);
}
} else {
// Set the new number format to the viewer.
fViewer.getPresentationContext().setProperty(PROP_FORMATTED_VALUE_FORMAT_PREFERENCE, formatId);
}
while (!fViewerListener.isFinished(ALL_UPDATES_COMPLETE | PROPERTY_UPDATES)
|| !fVMListener.isFinished(CONTENT_UPDATES | PROPERTY_UPDATES))
if (!fDisplay.readAndDispatch())
fDisplay.sleep();
if (expectCacheMissError) {
try {
validateModel(expectElementFormats, formatId, "", formatId, "");
throw new RuntimeException("Expected validateModel to fail");
} catch (AssertionFailedError e) {
// expected
}
} else {
validateModel(expectElementFormats, formatId, "", formatId, "");
}
if (expectCacheMissError) {
String formatProperty = FormattedValueVMUtil.getPropertyForFormatId(formatId);
assertTrue(fFormattedValuesListener.getFormattedValuesCompleted().isEmpty());
assertFalse(fFormattedValuesListener.getPropertiesUpdates().isEmpty());
for (IPropertiesUpdate update : fFormattedValuesListener.getPropertiesUpdates()) {
PropertiesUpdateStatus status = (PropertiesUpdateStatus) update.getStatus();
assertEquals(IDsfStatusConstants.INVALID_STATE, status.getCode());
ElementFormatSetting elementFormat = null;
if (expectElementFormats != null) {
TreePath viewerPath = update.getElementPath();
for (ElementFormatSetting es : expectElementFormats) {
if (es.elementPaths.indexOf(viewerPath) >= 0) {
elementFormat = es;
break;
}
}
}
if (elementFormat != null) {
assertEquals("Cache contains stale data. Refresh view.",
status.getStatus(FormattedValueVMUtil.getPropertyForFormatId(elementFormat.formatId))
.getMessage());
} else {
assertEquals("Cache contains stale data. Refresh view.",
status.getStatus(formatProperty).getMessage());
}
assertEquals("Cache contains stale data. Refresh view.",
status.getStatus(PROP_FORMATTED_VALUE_ACTIVE_FORMAT_VALUE).getMessage());
assertEquals(1, status.getChildren().length);
}
} else {
assertTrue(fFormattedValuesListener.isFinished());
}
}
private void validateModel(final String formatId, final String suffix) {
validateModel(formatId, suffix, formatId, suffix);
}
private void validateModel(final String formatId, final String suffix, final String dummyFormatId,
final String dummySuffix) {
validateModel(null, formatId, suffix, dummyFormatId, dummySuffix);
}
private void validateModel(final ArrayList<ElementFormatSetting> elementFormats, final String formatId,
final String suffix, final String dummyFormatId, final String dummySuffix) {
fModel.validateData(fViewer, TreePath.EMPTY, new TestElementValidator() {
@Override
public void validate(TestElement modelElement, TestElement viewerElement, TreePath viewerPath) {
ViewerLabel label = fViewer.getElementLabel(viewerPath, TestModelCachingVMProvider.COLUMN_ID);
assertEquals(modelElement.getID(), label.getText());
ElementFormatSetting elementFormat = null;
if (elementFormats != null) {
for (ElementFormatSetting es : elementFormats) {
if (es.elementPaths.indexOf(viewerPath) >= 0) {
elementFormat = es;
break;
}
}
}
label = fViewer.getElementLabel(viewerPath, TestModelCachingVMProvider.COLUMN_FORMATTED_VALUE);
if (elementFormat == null || elementFormat.formatId == null) {
assertEquals(fModel.getFormattedValueText(modelElement, formatId) + suffix, label.getText());
} else {
String suffix = elementFormat.formatId.equals(formatId) ? ""
: " (" + FormattedValueVMUtil.getFormatLabel(elementFormat.formatId) + ")";
assertEquals(fModel.getFormattedValueText(modelElement, elementFormat.formatId) + suffix,
label.getText());
}
label = fViewer.getElementLabel(viewerPath, TestModelCachingVMProvider.COLUMN_DUMMY_VALUE);
if (elementFormat == null || elementFormat.formatId == null) {
assertEquals(dummyFormatId + dummySuffix, label.getText());
} else {
String suffix = elementFormat.formatId.equals(formatId) ? ""
: " (" + FormattedValueVMUtil.getFormatLabel(elementFormat.formatId) + ")";
assertEquals(elementFormat.formatId + suffix, label.getText());
}
}
});
}
private TestElement[] makeModelElements(TestModel model, int depth, String prefix) {
TestElement[] elements = new TestElement[depth];
for (int i = 0; i < depth; i++) {
String name = prefix + "." + i;
elements[i] = new TestElement(model, name, makeModelElements(model, i, name));
}
return elements;
}
}