| /******************************************************************************* |
| * Copyright (c) 2000, 2009 IBM Corporation and others. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| * IBM Corporation - initial API and implementation |
| *******************************************************************************/ |
| package org.eclipse.ui.tests.api; |
| |
| import java.lang.reflect.Method; |
| |
| import org.eclipse.core.resources.IWorkspace; |
| import org.eclipse.core.resources.ResourcesPlugin; |
| import org.eclipse.core.runtime.IAdaptable; |
| import org.eclipse.ui.IAggregateWorkingSet; |
| import org.eclipse.ui.IMemento; |
| import org.eclipse.ui.IWorkingSet; |
| import org.eclipse.ui.IWorkingSetManager; |
| import org.eclipse.ui.XMLMemento; |
| import org.eclipse.ui.internal.AbstractWorkingSet; |
| import org.eclipse.ui.internal.AbstractWorkingSetManager; |
| import org.eclipse.ui.internal.AggregateWorkingSet; |
| import org.eclipse.ui.internal.IWorkbenchConstants; |
| import org.eclipse.ui.tests.harness.util.ArrayUtil; |
| import org.eclipse.ui.tests.harness.util.UITestCase; |
| |
| public class IAggregateWorkingSetTest extends UITestCase { |
| |
| final static String WORKING_SET_NAME = "testws"; |
| final static String AGGREGATE_WORKING_SET_NAME_ = "testaggregatews"; |
| final static String WSET_PAGE_ID="org.eclipse.ui.resourceWorkingSetPage"; |
| IWorkspace fWorkspace; |
| |
| IWorkingSet[] components; |
| IAggregateWorkingSet fWorkingSet; |
| |
| public IAggregateWorkingSetTest(String testName) { |
| super(testName); |
| } |
| |
| protected void doSetUp() throws Exception { |
| super.doSetUp(); |
| IWorkingSetManager workingSetManager = fWorkbench |
| .getWorkingSetManager(); |
| |
| fWorkspace = ResourcesPlugin.getWorkspace(); |
| components = new IWorkingSet[4]; |
| for (int i = 0; i < 4; i++) { |
| components[i] = workingSetManager.createWorkingSet(WORKING_SET_NAME |
| + i, new IAdaptable[] {}); |
| workingSetManager.addWorkingSet(components[i]); |
| } |
| fWorkingSet = (IAggregateWorkingSet) workingSetManager |
| .createAggregateWorkingSet(AGGREGATE_WORKING_SET_NAME_, |
| AGGREGATE_WORKING_SET_NAME_, components); |
| |
| workingSetManager.addWorkingSet(fWorkingSet); |
| } |
| protected void doTearDown() throws Exception { |
| IWorkingSetManager workingSetManager = fWorkbench.getWorkingSetManager(); |
| workingSetManager.removeWorkingSet(fWorkingSet); |
| for (int i = 0; i < components.length; i++) { |
| workingSetManager.removeWorkingSet(components[i]); |
| } |
| super.doTearDown(); |
| } |
| |
| public void testSaveWSet() throws Throwable { |
| //<possible client code> |
| IWorkingSetManager workingSetManager = fWorkbench |
| .getWorkingSetManager(); |
| IWorkingSet set=workingSetManager.getWorkingSet(AGGREGATE_WORKING_SET_NAME_); |
| if(set.isAggregateWorkingSet()){ |
| IWorkingSet[] sets=((IAggregateWorkingSet)set).getComponents(); |
| if(sets.length>=1){ |
| sets[0]=null; //client fails to pay enough attention to specs or unknowingly does this |
| } |
| } |
| //</possible client code> |
| //error makes it look like it comes from workingsets api, with no clue about the actual culprit |
| IMemento memento=XMLMemento.createWriteRoot(IWorkbenchConstants.TAG_WORKING_SET); |
| set.saveState(memento); |
| } |
| public void testGetElemets() throws Throwable { |
| //<possible client code> |
| IWorkingSetManager workingSetManager = fWorkbench |
| .getWorkingSetManager(); |
| IWorkingSet set=workingSetManager.getWorkingSet(AGGREGATE_WORKING_SET_NAME_); |
| if(set.isAggregateWorkingSet()){ |
| IWorkingSet[] sets=((IAggregateWorkingSet)set).getComponents(); |
| if(sets.length>1){ |
| //code 2 fails to pay enough attention to specs or unknowingly does this |
| sets[0]=workingSetManager.createWorkingSet(WORKING_SET_NAME, new IAdaptable[] { fWorkspace.getRoot() }); |
| //code 1 part removes a workingset |
| workingSetManager.removeWorkingSet(sets[1]); |
| } |
| } |
| //</possible client code> |
| |
| //unexpected |
| assertTrue(ArrayUtil.equals( |
| new IAdaptable[] {}, |
| fWorkingSet.getElements())); |
| } |
| |
| /** |
| * Core of the problem: while Eclipse is running, name collisions among working sets |
| * don't matter. However, on save and restart names will be used to identify working |
| * sets, which could possibly lead to cycles in aggregate working sets. |
| * |
| * Bottom line: if there are multiple aggregate working sets with the same name, expect |
| * trouble on restart. |
| * |
| * To create a cycle we have to be creative: |
| * - create an aggregate1 with an ID = "testCycle" |
| * - create an aggregate2 with an ID = "testCycle" containing aggregate1 |
| * - save it into IMemento |
| * |
| * Now the IMememnto creates a self reference: |
| * |
| * <workingSet name="testCycle" label="testCycle" aggregate="true"> |
| * <workingSet IMemento.internal.id="testCycle" /> |
| * </workingSet> |
| * |
| * All we have to do to emulate stack overflow is to create a working set based on this IMemento. |
| * |
| * @throws Throwable |
| */ |
| public void testWorkingSetCycle() throws Throwable { |
| IWorkingSetManager manager = fWorkbench.getWorkingSetManager(); |
| |
| // create an IMemento with a cycle in it |
| IAggregateWorkingSet aggregate = (IAggregateWorkingSet) manager |
| .createAggregateWorkingSet("testCycle","testCycle", new IWorkingSet[0]); |
| |
| IAggregateWorkingSet aggregate2 = (IAggregateWorkingSet) manager |
| .createAggregateWorkingSet("testCycle","testCycle", new IWorkingSet[] {aggregate}); |
| |
| IMemento memento=XMLMemento.createWriteRoot(IWorkbenchConstants.TAG_WORKING_SET); |
| aggregate2.saveState(memento); |
| |
| // load the IMemento |
| IAggregateWorkingSet aggregateReloaded = null; |
| try { |
| aggregateReloaded = (IAggregateWorkingSet) manager.createWorkingSet(memento); |
| manager.addWorkingSet(aggregateReloaded); |
| aggregateReloaded.getComponents(); |
| } catch (StackOverflowError e) { |
| e.printStackTrace(); |
| fail("Stack overflow for self-referenced aggregate working set", e); |
| } finally { |
| if (aggregateReloaded != null) |
| manager.removeWorkingSet(aggregateReloaded); |
| } |
| } |
| |
| /** |
| * Tests cleanup of the cycle from an aggregate working set. |
| * @throws Throwable |
| */ |
| public void testCycleCleanup() throws Throwable { |
| IWorkingSetManager manager = fWorkbench.getWorkingSetManager(); |
| |
| // create an IMemento with a cycle in it: { good, good, cycle, good, good } |
| IAggregateWorkingSet aggregateSub0 = (IAggregateWorkingSet) manager |
| .createAggregateWorkingSet("testCycle0","testCycle0", new IWorkingSet[0]); |
| |
| IAggregateWorkingSet aggregateSub1 = (IAggregateWorkingSet) manager |
| .createAggregateWorkingSet("testCycle1","testCycle1", new IWorkingSet[0]); |
| |
| IAggregateWorkingSet aggregateSub2 = (IAggregateWorkingSet) manager |
| .createAggregateWorkingSet("testCycle","testCycle", new IWorkingSet[0]); // cycle |
| |
| IAggregateWorkingSet aggregateSub3 = (IAggregateWorkingSet) manager |
| .createAggregateWorkingSet("testCycle3","testCycle3", new IWorkingSet[0]); |
| |
| IAggregateWorkingSet aggregateSub4 = (IAggregateWorkingSet) manager |
| .createAggregateWorkingSet("testCycle4","testCycle4", new IWorkingSet[0]); |
| |
| |
| IAggregateWorkingSet aggregate = (IAggregateWorkingSet) manager |
| .createAggregateWorkingSet("testCycle","testCycle", new IWorkingSet[] {aggregateSub0, |
| aggregateSub1, aggregateSub2, aggregateSub3, aggregateSub4}); |
| |
| manager.addWorkingSet(aggregateSub0); |
| manager.addWorkingSet(aggregateSub1); |
| manager.addWorkingSet(aggregateSub3); |
| manager.addWorkingSet(aggregateSub4); |
| |
| IMemento memento=XMLMemento.createWriteRoot(IWorkbenchConstants.TAG_WORKING_SET); |
| aggregate.saveState(memento); |
| |
| // load the IMemento |
| IAggregateWorkingSet aggregateReloaded = null; |
| try { |
| aggregateReloaded = (IAggregateWorkingSet) manager.createWorkingSet(memento); |
| manager.addWorkingSet(aggregateReloaded); |
| IWorkingSet[] aggregates = aggregateReloaded.getComponents(); |
| assertNotNull(aggregates); |
| assertEquals(4, aggregates.length); |
| for(int i = 0; i < aggregates.length; i++) |
| assertFalse("testCycle".equals(aggregates[i].getName())); |
| } catch (StackOverflowError e) { |
| e.printStackTrace(); |
| fail("Stack overflow for self-referenced aggregate working set", e); |
| } finally { |
| if (aggregateReloaded != null) |
| manager.removeWorkingSet(aggregateReloaded); |
| } |
| } |
| |
| /* |
| * Test related to Bug 217955.The initial fix made changes that caused |
| * save/restore to fail due to early restore and forward reference in |
| * memento of aggregates |
| */ |
| public void testWorkingSetSaveRestoreAggregates() throws Throwable { |
| IWorkingSetManager manager = fWorkbench.getWorkingSetManager(); |
| String nameA = "A"; |
| String nameB = "B"; |
| String nameC = "C"; |
| |
| IWorkingSet wSetA = manager |
| .createWorkingSet(nameA, new IAdaptable[] {}); |
| manager.addWorkingSet(wSetA); |
| |
| IAggregateWorkingSet wSetB = (IAggregateWorkingSet) manager |
| .createAggregateWorkingSet(nameB, nameB, new IWorkingSet[] {}); |
| manager.addWorkingSet(wSetB); |
| |
| IAggregateWorkingSet wSetC = (IAggregateWorkingSet) manager |
| .createAggregateWorkingSet(nameC, nameC, new IWorkingSet[0]); |
| manager.addWorkingSet(wSetC); |
| |
| try { |
| assertEquals("Failed to add workingset" + nameA, wSetA, manager |
| .getWorkingSet(nameA)); |
| |
| assertEquals("Failed to add workingset" + nameC, wSetC, manager |
| .getWorkingSet(nameC)); |
| |
| assertEquals("Failed to add workingset" + nameB, wSetB, manager |
| .getWorkingSet(nameB)); |
| |
| invokeMethod(AggregateWorkingSet.class, "setComponents", wSetB, |
| new Object[] { new IWorkingSet[] { |
| wSetA, wSetC } }, |
| new Class[] { new IWorkingSet[] {}.getClass() }); |
| |
| saveRestoreWorkingSetManager(); |
| |
| IAggregateWorkingSet restoredB = (IAggregateWorkingSet) manager |
| .getWorkingSet(nameB); |
| assertTrue("Unable to save/restore correctly", restoredB!=null); |
| |
| IAggregateWorkingSet restoredC = (IAggregateWorkingSet) manager |
| .getWorkingSet(nameC); |
| assertTrue("Unable to save/restore correctly", restoredC!=null); |
| |
| IWorkingSet[] componenets1=wSetB.getComponents(); |
| IWorkingSet[] componenets2=((IAggregateWorkingSet) manager |
| .getWorkingSet(nameB)).getComponents(); |
| |
| if (componenets1.length != componenets2.length) |
| fail(nameB + " has lost data in the process of save/restore"); |
| else { |
| for (int i = 0; i < componenets1.length; i++) |
| if (!componenets1[i].equals(componenets2[i])) |
| fail(nameB + " has lost data in the process of save/restore"); |
| } |
| |
| } finally { |
| // restore |
| IWorkingSet set = manager.getWorkingSet(nameA); |
| if (set != null) { |
| manager.removeWorkingSet(set); |
| } |
| set = manager.getWorkingSet(nameB); |
| if (set != null) { |
| manager.removeWorkingSet(set); |
| } |
| set = manager.getWorkingSet(nameC); |
| if (set != null) { |
| manager.removeWorkingSet(set); |
| } |
| } |
| } |
| |
| private void saveRestoreWorkingSetManager() { |
| IMemento managerMemento = XMLMemento |
| .createWriteRoot(IWorkbenchConstants.TAG_WORKING_SET_MANAGER); |
| IWorkingSetManager manager = fWorkbench.getWorkingSetManager(); |
| IWorkingSet[] sets = manager.getAllWorkingSets(); |
| for (int i = 0; i < sets.length; i++) { |
| if(sets[i].getId()==null){ |
| //set default id as set by factory |
| sets[i].setId(WSET_PAGE_ID); |
| } |
| } |
| invokeMethod(AbstractWorkingSetManager.class, "saveWorkingSetState", |
| manager, new Object[] { managerMemento }, |
| new Class[] { IMemento.class }); |
| invokeMethod(AbstractWorkingSetManager.class, "saveMruList", manager, |
| new Object[] { managerMemento }, new Class[] { IMemento.class }); |
| for (int i = 0; i < sets.length; i++) { |
| ((AbstractWorkingSet) sets[i]).disconnect(); |
| } |
| for (int i = 0; i < sets.length; i++) { |
| manager.removeWorkingSet(sets[i]); |
| } |
| //manager.dispose(); //not needed, also cause problems |
| invokeMethod(AbstractWorkingSetManager.class, "restoreWorkingSetState", |
| manager, new Object[] { managerMemento }, |
| new Class[] { IMemento.class }); |
| invokeMethod(AbstractWorkingSetManager.class, "restoreMruList", |
| manager, new Object[] { managerMemento }, |
| new Class[] { IMemento.class }); |
| } |
| |
| private Object invokeMethod(Class clazz, String methodName, |
| Object instance, Object[] args, Class[] argsClasses) { |
| try { |
| Method method = clazz.getDeclaredMethod(methodName, argsClasses); |
| method.setAccessible(true); |
| return method.invoke(instance, args); |
| } catch (Exception e) { |
| fail("Failure in invoking " + clazz.getName() + methodName, e); |
| } |
| return null; |
| } |
| } |