blob: 84a24f3226a0cfbd835b7cad9c7a65c44936984a [file] [log] [blame]
/*******************************************************************************
* 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;
}
}