| /******************************************************************************* |
| * 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; |
| } |
| } |