Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristian W. Damus2018-01-16 18:46:02 +0000
committerChristian W. Damus2018-01-16 19:11:50 +0000
commitc64c055670da08d2545634789e9b146e346a4e06 (patch)
tree4ca010171165ad5673fd42aff5d5912e7d9f547c /plugins
parent6cd3f271dfd6390e61c13a02370646fc4671b60a (diff)
downloadorg.eclipse.papyrus-collaborativemodeling-c64c055670da08d2545634789e9b146e346a4e06.tar.gz
org.eclipse.papyrus-collaborativemodeling-c64c055670da08d2545634789e9b146e346a4e06.tar.xz
org.eclipse.papyrus-collaborativemodeling-c64c055670da08d2545634789e9b146e346a4e06.zip
Bug 529897 - [Compare] Log spammed with ClassCastExceptions during compare
Ensure that adapters added to the Resource dynamic proxies see those same proxies in their call-backs, including in Notifications. Change-Id: I69a1700506837ba33870222691e0424bc95296fb
Diffstat (limited to 'plugins')
-rw-r--r--plugins/compare/bundles/org.eclipse.papyrus.compare.uml2/src/org/eclipse/papyrus/compare/uml2/internal/hook/migration/ModelSetWrapper.java236
-rw-r--r--plugins/compare/tests/org.eclipse.papyrus.compare.uml2.tests/.settings/org.eclipse.core.resources.prefs2
-rw-r--r--plugins/compare/tests/org.eclipse.papyrus.compare.uml2.tests/.settings/org.eclipse.core.runtime.prefs2
-rw-r--r--plugins/compare/tests/org.eclipse.papyrus.compare.uml2.tests/.settings/org.eclipse.jdt.ui.prefs66
-rw-r--r--plugins/compare/tests/org.eclipse.papyrus.compare.uml2.tests/src/org/eclipse/papyrus/compare/uml2/tests/profiles/migration/ModelSetWrapperTest.java315
-rw-r--r--plugins/compare/tests/org.eclipse.papyrus.compare.uml2.tests/src/org/eclipse/papyrus/compare/uml2/tests/suite/AllUITests.java12
6 files changed, 625 insertions, 8 deletions
diff --git a/plugins/compare/bundles/org.eclipse.papyrus.compare.uml2/src/org/eclipse/papyrus/compare/uml2/internal/hook/migration/ModelSetWrapper.java b/plugins/compare/bundles/org.eclipse.papyrus.compare.uml2/src/org/eclipse/papyrus/compare/uml2/internal/hook/migration/ModelSetWrapper.java
index d63cb2df..6b521eec 100644
--- a/plugins/compare/bundles/org.eclipse.papyrus.compare.uml2/src/org/eclipse/papyrus/compare/uml2/internal/hook/migration/ModelSetWrapper.java
+++ b/plugins/compare/bundles/org.eclipse.papyrus.compare.uml2/src/org/eclipse/papyrus/compare/uml2/internal/hook/migration/ModelSetWrapper.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2016, 2017 EclipseSource Services GmbH and others.
+ * Copyright (c) 2016, 2018 EclipseSource Services GmbH 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
@@ -7,12 +7,15 @@
*
* Contributors:
* Martin Fleck - initial API and implementation
- * Christian W. Damus - bug 526932
- * Christian W. Damus - bug 512529
+ * Christian W. Damus - bugs 526932, 512529, 529897
*******************************************************************************/
package org.eclipse.papyrus.compare.uml2.internal.hook.migration;
+import com.google.common.collect.BiMap;
+import com.google.common.collect.HashBiMap;
import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
+import com.google.common.collect.MapMaker;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
@@ -20,11 +23,16 @@ import java.lang.reflect.Proxy;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedHashSet;
+import java.util.List;
import java.util.Map;
import org.eclipse.emf.common.notify.Adapter;
import org.eclipse.emf.common.notify.Notification;
+import org.eclipse.emf.common.notify.NotificationWrapper;
import org.eclipse.emf.common.notify.Notifier;
+import org.eclipse.emf.common.notify.impl.AdapterImpl;
+import org.eclipse.emf.common.util.DelegatingEList;
+import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EPackage.Registry;
import org.eclipse.emf.ecore.resource.ContentHandler;
@@ -424,6 +432,8 @@ public class ModelSetWrapper extends ModelSet {
private class ResourceProxy implements InvocationHandler {
private final Resource resource;
+ private EList<Adapter> adapterList;
+
ResourceProxy(Resource resource) {
super();
@@ -444,10 +454,230 @@ public class ModelSetWrapper extends ModelSet {
return null;
}
break;
+ case "eAdapters": //$NON-NLS-1$
+ return getAdapters(proxy);
}
return method.invoke(resource, args);
}
+ EList<Adapter> getAdapters(Object proxy) {
+ if (adapterList == null) {
+ adapterList = new ProxyAdapterList(resource, (Resource)proxy);
+ }
+ return adapterList;
+ }
}
+
+ /**
+ * An adapter list implementation for {@link ResourceProxy} instances to ensure that {@link Adapter}
+ * call-backs are invoked with the resource proxy that the adapters are added to, not the underlying real
+ * resource.
+ *
+ * @author Christian W. Damus
+ */
+ @SuppressWarnings("serial")
+ private class ProxyAdapterList extends DelegatingEList<Adapter> implements EObservableAdapterList {
+
+ // Map of "real adapter" <--> wrapper
+ private final BiMap<Adapter, Adapter> adapters = HashBiMap.create();
+
+ private final Notifier owner;
+
+ private final Notifier proxy;
+
+ private final EList<Adapter> delegate;
+
+ private List<Listener> listeners;
+
+ /**
+ * Initializes me with the real resource {@link notifier} and its {@code proxy} that I present to
+ * adapters in their call-backs.
+ *
+ * @param notifier
+ * the real notifier
+ * @param proxy
+ * its proxy wrapper
+ */
+ ProxyAdapterList(Notifier notifier, Notifier proxy) {
+ super();
+
+ owner = notifier;
+ this.proxy = proxy;
+ delegate = notifier.eAdapters();
+ }
+
+ @Override
+ protected List<Adapter> delegateList() {
+ return delegate;
+ }
+
+ @Override
+ protected boolean delegateContains(Object object) {
+ // The delegate list contains wrappers, not the real adapters
+ Object search = adapters.get(object);
+ return super.delegateContains(search == null ? object : search);
+ }
+
+ @Override
+ protected int delegateIndexOf(Object object) {
+ // The delegate list contains wrappers, not the real adapters.
+ // This is needed to support removal
+ Object search = adapters.get(object);
+ return super.delegateIndexOf(search == null ? object : search);
+ }
+
+ @Override
+ protected int delegateLastIndexOf(Object object) {
+ // The delegate list contains wrappers, not the real adapters.
+ // This is needed as counterpart to indexOf
+ Object search = adapters.get(object);
+ return super.delegateLastIndexOf(search == null ? object : search);
+ }
+
+ @Override
+ protected Adapter validate(int index, Adapter object) {
+ Adapter result = adapters.get(object);
+ if (result == null) {
+ result = new ProxyAdapter(object, owner, proxy);
+ adapters.put(object, result);
+ }
+
+ return result;
+ }
+
+ @Override
+ protected void didAdd(int index, Adapter newObject) {
+ if (listeners != null) {
+ for (Listener next : listeners) {
+ next.added(proxy, newObject);
+ }
+ }
+ }
+
+ @Override
+ protected void didRemove(int index, Adapter oldObject) {
+ if (listeners != null) {
+ for (Listener next : listeners) {
+ next.removed(proxy, oldObject);
+ }
+ }
+ adapters.inverse().remove(oldObject);
+ }
+
+ @Override
+ protected void didSet(int index, Adapter newObject, Adapter oldObject) {
+ didRemove(index, oldObject);
+ didAdd(index, newObject);
+ }
+
+ //
+ // EObservableAdapterList protocol
+ //
+
+ public void addListener(Listener listener) {
+ if (listeners == null) {
+ listeners = Lists.newArrayListWithExpectedSize(1);
+ }
+ listeners.add(listener);
+ }
+
+ public void removeListener(Listener listener) {
+ if (listeners != null) {
+ listeners.remove(listener);
+ }
+ }
+ }
+
+ //
+ // Nested types
+ //
+
+ /**
+ * An wrapper for adapters to ensure that the {@link Adapter} call-backs are invoked with the notifier
+ * proxy that the adapters are added to, not the underlying real notifier.
+ *
+ * @author Christian W. Damus
+ */
+ private class ProxyAdapter extends AdapterImpl {
+ private final Adapter delegate;
+
+ private final Notifier notifier;
+
+ private final Notifier proxy;
+
+ /** Cache of notification wrappers for presentation of the notifier as the proxy. */
+ private final Map<Notification, Notification> notificationWrappers = new MapMaker().weakKeys()
+ .weakValues().makeMap();
+
+ /**
+ * Initializes me with the real resource {@link notifier} and its {@code proxy} that I present to my
+ * wrapper {@link adapter} in its call-backs.
+ *
+ * @param adapter
+ * my real adapter delegate
+ * @param notifier
+ * the real notifier
+ * @param proxy
+ * its proxy wrapper
+ */
+ ProxyAdapter(Adapter adapter, Notifier notifier, Notifier proxy) {
+ super();
+
+ delegate = adapter;
+ this.notifier = notifier;
+ this.proxy = proxy;
+ }
+
+ @Override
+ public void notifyChanged(Notification msg) {
+ delegate.notifyChanged(wrap(msg));
+ }
+
+ Notification wrap(Notification msg) {
+ Notification result = msg;
+
+ if (msg.getNotifier() == notifier) {
+ // Wrap it
+ result = notificationWrappers.get(msg);
+ if (result == null) {
+ result = new NotificationWrapper(proxy, msg);
+ notificationWrappers.put(msg, result);
+ }
+ }
+
+ return result;
+ }
+
+ @Override
+ public boolean isAdapterForType(Object type) {
+ return delegate.isAdapterForType(type);
+ }
+
+ @Override
+ public void setTarget(Notifier newTarget) {
+ if (newTarget == notifier) {
+ delegate.setTarget(proxy);
+ } else {
+ delegate.setTarget(newTarget);
+ }
+ }
+
+ @Override
+ public void unsetTarget(Notifier oldTarget) {
+ if (delegate instanceof Adapter.Internal) {
+ if (oldTarget == notifier) {
+ ((Adapter.Internal)delegate).unsetTarget(proxy);
+ } else {
+ ((Adapter.Internal)delegate).unsetTarget(oldTarget);
+ }
+ }
+ }
+
+ @Override
+ public String toString() {
+ return delegate.toString();
+ }
+ }
+
}
diff --git a/plugins/compare/tests/org.eclipse.papyrus.compare.uml2.tests/.settings/org.eclipse.core.resources.prefs b/plugins/compare/tests/org.eclipse.papyrus.compare.uml2.tests/.settings/org.eclipse.core.resources.prefs
new file mode 100644
index 00000000..99f26c02
--- /dev/null
+++ b/plugins/compare/tests/org.eclipse.papyrus.compare.uml2.tests/.settings/org.eclipse.core.resources.prefs
@@ -0,0 +1,2 @@
+eclipse.preferences.version=1
+encoding/<project>=UTF-8
diff --git a/plugins/compare/tests/org.eclipse.papyrus.compare.uml2.tests/.settings/org.eclipse.core.runtime.prefs b/plugins/compare/tests/org.eclipse.papyrus.compare.uml2.tests/.settings/org.eclipse.core.runtime.prefs
new file mode 100644
index 00000000..5a0ad22d
--- /dev/null
+++ b/plugins/compare/tests/org.eclipse.papyrus.compare.uml2.tests/.settings/org.eclipse.core.runtime.prefs
@@ -0,0 +1,2 @@
+eclipse.preferences.version=1
+line.separator=\n
diff --git a/plugins/compare/tests/org.eclipse.papyrus.compare.uml2.tests/.settings/org.eclipse.jdt.ui.prefs b/plugins/compare/tests/org.eclipse.papyrus.compare.uml2.tests/.settings/org.eclipse.jdt.ui.prefs
new file mode 100644
index 00000000..57660252
--- /dev/null
+++ b/plugins/compare/tests/org.eclipse.papyrus.compare.uml2.tests/.settings/org.eclipse.jdt.ui.prefs
@@ -0,0 +1,66 @@
+eclipse.preferences.version=1
+editor_save_participant_org.eclipse.jdt.ui.postsavelistener.cleanup=true
+formatter_profile=_EMF Compare
+formatter_settings_version=12
+org.eclipse.jdt.ui.ignorelowercasenames=true
+org.eclipse.jdt.ui.importorder=fr;com;java;javax;org;
+org.eclipse.jdt.ui.ondemandthreshold=99
+org.eclipse.jdt.ui.staticondemandthreshold=99
+sp_cleanup.add_default_serial_version_id=true
+sp_cleanup.add_generated_serial_version_id=false
+sp_cleanup.add_missing_annotations=true
+sp_cleanup.add_missing_deprecated_annotations=true
+sp_cleanup.add_missing_methods=false
+sp_cleanup.add_missing_nls_tags=false
+sp_cleanup.add_missing_override_annotations=true
+sp_cleanup.add_missing_override_annotations_interface_methods=false
+sp_cleanup.add_serial_version_id=false
+sp_cleanup.always_use_blocks=true
+sp_cleanup.always_use_parentheses_in_expressions=false
+sp_cleanup.always_use_this_for_non_static_field_access=false
+sp_cleanup.always_use_this_for_non_static_method_access=false
+sp_cleanup.convert_functional_interfaces=false
+sp_cleanup.convert_to_enhanced_for_loop=false
+sp_cleanup.correct_indentation=false
+sp_cleanup.format_source_code=true
+sp_cleanup.format_source_code_changes_only=false
+sp_cleanup.insert_inferred_type_arguments=false
+sp_cleanup.make_local_variable_final=false
+sp_cleanup.make_parameters_final=false
+sp_cleanup.make_private_fields_final=true
+sp_cleanup.make_type_abstract_if_missing_method=false
+sp_cleanup.make_variable_declarations_final=false
+sp_cleanup.never_use_blocks=false
+sp_cleanup.never_use_parentheses_in_expressions=true
+sp_cleanup.on_save_use_additional_actions=true
+sp_cleanup.organize_imports=true
+sp_cleanup.qualify_static_field_accesses_with_declaring_class=false
+sp_cleanup.qualify_static_member_accesses_through_instances_with_declaring_class=true
+sp_cleanup.qualify_static_member_accesses_through_subtypes_with_declaring_class=true
+sp_cleanup.qualify_static_member_accesses_with_declaring_class=false
+sp_cleanup.qualify_static_method_accesses_with_declaring_class=false
+sp_cleanup.remove_private_constructors=true
+sp_cleanup.remove_redundant_type_arguments=false
+sp_cleanup.remove_trailing_whitespaces=false
+sp_cleanup.remove_trailing_whitespaces_all=true
+sp_cleanup.remove_trailing_whitespaces_ignore_empty=false
+sp_cleanup.remove_unnecessary_casts=false
+sp_cleanup.remove_unnecessary_nls_tags=true
+sp_cleanup.remove_unused_imports=true
+sp_cleanup.remove_unused_local_variables=false
+sp_cleanup.remove_unused_private_fields=true
+sp_cleanup.remove_unused_private_members=false
+sp_cleanup.remove_unused_private_methods=true
+sp_cleanup.remove_unused_private_types=true
+sp_cleanup.sort_members=false
+sp_cleanup.sort_members_all=false
+sp_cleanup.use_anonymous_class_creation=false
+sp_cleanup.use_blocks=true
+sp_cleanup.use_blocks_only_for_return_and_throw=false
+sp_cleanup.use_lambda=false
+sp_cleanup.use_parentheses_in_expressions=false
+sp_cleanup.use_this_for_non_static_field_access=false
+sp_cleanup.use_this_for_non_static_field_access_only_if_necessary=true
+sp_cleanup.use_this_for_non_static_method_access=false
+sp_cleanup.use_this_for_non_static_method_access_only_if_necessary=true
+sp_cleanup.use_type_arguments=false
diff --git a/plugins/compare/tests/org.eclipse.papyrus.compare.uml2.tests/src/org/eclipse/papyrus/compare/uml2/tests/profiles/migration/ModelSetWrapperTest.java b/plugins/compare/tests/org.eclipse.papyrus.compare.uml2.tests/src/org/eclipse/papyrus/compare/uml2/tests/profiles/migration/ModelSetWrapperTest.java
new file mode 100644
index 00000000..8b7e8e67
--- /dev/null
+++ b/plugins/compare/tests/org.eclipse.papyrus.compare.uml2.tests/src/org/eclipse/papyrus/compare/uml2/tests/profiles/migration/ModelSetWrapperTest.java
@@ -0,0 +1,315 @@
+/*******************************************************************************
+ * Copyright (c) 2018 Christian W. Damus 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:
+ * Christian W. Damus - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.papyrus.compare.uml2.tests.profiles.migration;
+
+import static org.hamcrest.CoreMatchers.hasItem;
+import static org.hamcrest.CoreMatchers.instanceOf;
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.CoreMatchers.not;
+import static org.hamcrest.CoreMatchers.notNullValue;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assume.assumeThat;
+
+import com.google.common.collect.ArrayListMultimap;
+import com.google.common.collect.ListMultimap;
+
+import java.lang.reflect.Proxy;
+import java.lang.reflect.UndeclaredThrowableException;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+import java.util.regex.Pattern;
+
+import org.eclipse.emf.common.notify.Adapter;
+import org.eclipse.emf.common.notify.Notification;
+import org.eclipse.emf.common.notify.Notifier;
+import org.eclipse.emf.common.notify.impl.AdapterImpl;
+import org.eclipse.emf.common.util.URI;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.resource.Resource;
+import org.eclipse.emf.ecore.resource.ResourceSet;
+import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl;
+import org.eclipse.emf.ecore.util.EcoreUtil;
+import org.eclipse.papyrus.compare.uml2.internal.hook.migration.ModelSetWrapper;
+import org.eclipse.uml2.uml.Profile;
+import org.eclipse.uml2.uml.resource.UMLResource;
+import org.hamcrest.BaseMatcher;
+import org.hamcrest.CoreMatchers;
+import org.hamcrest.Description;
+import org.hamcrest.Matcher;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * Tests for the {@link ModelSetWrapper} class.
+ *
+ * @author Christian W. Damus
+ */
+@SuppressWarnings({"nls", "boxing" })
+public class ModelSetWrapperTest {
+
+ private static final URI STANDARD_PROFILE_URI = URI.createURI(UMLResource.STANDARD_PROFILE_URI);
+
+ private ResourceSet fixture;
+
+ /**
+ * Initializes me.
+ */
+ public ModelSetWrapperTest() {
+ super();
+ }
+
+ @Test
+ public void resourceWrapper() {
+ Resource resource = fixture.getResource(STANDARD_PROFILE_URI, true);
+
+ assertThat(resource, isProxy());
+ assertThat(resource.getURI(), is(STANDARD_PROFILE_URI));
+ assertThat(resource.isLoaded(), is(true));
+ assertThat(resource.getContents(), CoreMatchers.<EObject> hasItem(instanceOf(Profile.class)));
+ }
+
+ @Test
+ public void notifications() {
+ final ListMultimap<URI, String> invocations = ArrayListMultimap.create();
+
+ class TestAdapter extends AdapterImpl {
+ private Pattern invocationPattern = Pattern.compile("(.+?)( x(\\d+))?");
+
+ @Override
+ public boolean isAdapterForType(Object type) {
+ if (getTarget() instanceof Resource) {
+ recordInvocation(getTarget(), "isAdapter");
+ }
+ return type == ModelSetWrapperTest.class;
+ }
+
+ void recordInvocation(Object context, String label) {
+ if (context instanceof Notification) {
+ recordInvocation(((Notification)context).getNotifier(), label);
+ } else if (context instanceof URI) {
+ recordInvocation((URI)context, label);
+ } else if (context instanceof Resource) {
+ recordInvocation(((Resource)context).getURI(), label);
+ } else {
+ recordInvocation(null, label);
+ }
+ }
+
+ void recordInvocation(URI context, String label) {
+ if (!invocations.containsKey(context)) {
+ invocations.put(context, label);
+ } else {
+ final List<String> these = invocations.get(context);
+ int lastIndex = these.size() - 1;
+ String last = these.get(lastIndex);
+ java.util.regex.Matcher m = invocationPattern.matcher(last);
+
+ if (!m.matches() || !m.group(1).equals(label)) {
+ these.add(label);
+ } else if (m.group(3) != null) {
+ // Increment the count
+ int count = Integer.parseInt(m.group(3));
+ these.set(lastIndex, String.format("%s x%s", label, count + 1));
+ } else {
+ // Start the count
+ these.set(lastIndex, String.format("%s x2", label));
+ }
+ }
+ }
+
+ @Override
+ public void notifyChanged(Notification msg) {
+ if (msg.getNotifier() instanceof Resource) {
+ if (msg.getEventType() == Notification.REMOVING_ADAPTER) {
+ recordInvocation(msg, "notifyChanged: removingAdapter");
+ } else {
+ switch (msg.getFeatureID(Resource.class)) {
+ case Resource.RESOURCE__IS_LOADED:
+ if (msg.getNewBooleanValue()) {
+ recordInvocation(msg, "loaded");
+ } else {
+ recordInvocation(msg, "unloaded");
+ }
+ break;
+ case Resource.RESOURCE__CONTENTS:
+ case Resource.RESOURCE__IS_TRACKING_MODIFICATION:
+ case Resource.RESOURCE__IS_MODIFIED:
+ recordInvocation(msg, "notifyChanged: "
+ + resourceFeature(msg.getFeatureID(Resource.class)));
+ break;
+ default:
+ // Pass
+ break;
+ }
+ }
+ assertThat(msg.getNotifier(), isProxy());
+ } else if (msg.getNotifier() instanceof ResourceSet) {
+ handleResourceSet(msg);
+ }
+ }
+
+ @Override
+ public void setTarget(Notifier newTarget) {
+ // only track resources
+ if (newTarget instanceof Resource) {
+ recordInvocation(newTarget, "setTarget");
+ assertThat(newTarget, isProxy());
+ super.setTarget(newTarget);
+ }
+ }
+
+ @Override
+ public void unsetTarget(Notifier oldTarget) {
+ // only track resources
+ if (oldTarget instanceof Resource) {
+ recordInvocation(oldTarget, "unsetTarget");
+ assertThat(oldTarget, isProxy());
+ super.unsetTarget(oldTarget);
+ }
+ }
+
+ protected void handleResourceSet(Notification msg) {
+ switch (msg.getFeatureID(ResourceSet.class)) {
+ case ResourceSet.RESOURCE_SET__RESOURCES:
+ switch (msg.getEventType()) {
+ case Notification.ADD:
+ ((Resource)msg.getNewValue()).eAdapters().add(this);
+ break;
+ case Notification.ADD_MANY:
+ for (Object next : (Collection<?>)msg.getNewValue()) {
+ ((Resource)next).eAdapters().add(this);
+ }
+ break;
+ case Notification.REMOVE:
+ ((Resource)msg.getOldValue()).eAdapters().remove(this);
+ break;
+ case Notification.REMOVE_MANY:
+ for (Object next : (Collection<?>)msg.getOldValue()) {
+ ((Resource)next).eAdapters().remove(this);
+ }
+ break;
+ case Notification.SET:
+ ((Resource)msg.getOldValue()).eAdapters().remove(this);
+ ((Resource)msg.getNewValue()).eAdapters().add(this);
+ break;
+ default:
+ // Pass
+ break;
+ }
+ break;
+ default:
+ // Pass
+ break;
+ }
+
+ }
+ }
+
+ try {
+ fixture.eAdapters().add(new TestAdapter());
+
+ Resource resource = fixture.getResource(STANDARD_PROFILE_URI, true);
+ assumeThat(resource, isProxy());
+
+ Adapter adapter = EcoreUtil.getExistingAdapter(resource, ModelSetWrapperTest.class);
+ assertThat(adapter, notNullValue());
+ assertThat(resource.eAdapters(), hasItem(adapter));
+
+ resource.unload();
+ fixture.getResources().remove(resource);
+
+ // The adapter removes itself from the resource when the resource is
+ // removed from the set
+ assertThat(resource.eAdapters(), not(hasItem(adapter)));
+ } catch (UndeclaredThrowableException e) {
+ for (Throwable unwrap = e.getUndeclaredThrowable(); unwrap != null; unwrap = unwrap.getCause()) {
+ if (unwrap instanceof Error) {
+ throw (Error)unwrap; // Usually AssertionError
+ }
+ }
+ throw e; // Re-throw
+ }
+
+ assertThat(invocations.get(STANDARD_PROFILE_URI), is(Arrays.asList( //
+ "setTarget", //
+ "notifyChanged: isTrackingModification", // because ModelSet does that
+ "notifyChanged: isModified x2", //
+ "notifyChanged: contents", // loaded all at once
+ "notifyChanged: isModified", //
+ "loaded", //
+ "notifyChanged: isModified x3", // unloading
+ "notifyChanged: contents", // unloaded all at once
+ "unloaded", //
+ "notifyChanged: removingAdapter", //
+ "unsetTarget" //
+ )));
+ }
+
+ //
+ // Test framework
+ //
+
+ @Before
+ public void createFixture() {
+ ResourceSet rset = new ResourceSetImpl();
+ fixture = new ModelSetWrapper(rset);
+ }
+
+ @After
+ public void destroyFixture() {
+ ModelSetWrapper wrapper = (ModelSetWrapper)fixture;
+ for (Resource next : wrapper.getResources()) {
+ next.unload();
+ }
+ wrapper.getResources().clear();
+ wrapper.detach();
+ }
+
+ Matcher<Object> isProxy() {
+ return new BaseMatcher<Object>() {
+ public void describeTo(Description description) {
+ description.appendText("is a Java proxy");
+ }
+
+ public boolean matches(Object item) {
+ return item != null && Proxy.isProxyClass(item.getClass());
+ }
+ };
+ }
+
+ static String resourceFeature(int featureID) {
+ switch (featureID) {
+ case Resource.RESOURCE__CONTENTS:
+ return "contents";
+ case Resource.RESOURCE__ERRORS:
+ return "errors";
+ case Resource.RESOURCE__IS_LOADED:
+ return "isLoaded";
+ case Resource.RESOURCE__IS_MODIFIED:
+ return "isModified";
+ case Resource.RESOURCE__IS_TRACKING_MODIFICATION:
+ return "isTrackingModification";
+ case Resource.RESOURCE__RESOURCE_SET:
+ return "resourceSet";
+ case Resource.RESOURCE__TIME_STAMP:
+ return "timestamp";
+ case Resource.RESOURCE__URI:
+ return "uri";
+ case Resource.RESOURCE__WARNINGS:
+ return "warnings";
+ default:
+ return "<other>";
+ }
+ }
+}
diff --git a/plugins/compare/tests/org.eclipse.papyrus.compare.uml2.tests/src/org/eclipse/papyrus/compare/uml2/tests/suite/AllUITests.java b/plugins/compare/tests/org.eclipse.papyrus.compare.uml2.tests/src/org/eclipse/papyrus/compare/uml2/tests/suite/AllUITests.java
index e1c5ce20..a6fa7248 100644
--- a/plugins/compare/tests/org.eclipse.papyrus.compare.uml2.tests/src/org/eclipse/papyrus/compare/uml2/tests/suite/AllUITests.java
+++ b/plugins/compare/tests/org.eclipse.papyrus.compare.uml2.tests/src/org/eclipse/papyrus/compare/uml2/tests/suite/AllUITests.java
@@ -1,5 +1,5 @@
/*******************************************************************************
- * Copyright (c) 2016 EclipseSource Services GmbH and others.
+ * Copyright (c) 2016, 2018 EclipseSource Services GmbH 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
@@ -7,23 +7,25 @@
*
* Contributors:
* Martin Fleck - initial API and implementation
+ * Christian W. Damus - bug 529897
*******************************************************************************/
package org.eclipse.papyrus.compare.uml2.tests.suite;
+import org.eclipse.papyrus.compare.uml2.tests.profiles.migration.ModelSetWrapperTest;
import org.eclipse.papyrus.compare.uml2.tests.profiles.migration.ProfileMigrationTest;
import org.junit.runner.RunWith;
import org.junit.runners.Suite;
import org.junit.runners.Suite.SuiteClasses;
/**
- * This test suite allows us to launch all tests for EMF Compare for UML at once. This test suite should
- * contain classes that need the UI in order to be executed. Tests that do not need the UI should go to
- * {@link AllTests}.
+ * Test suite for the Papyrus Compare UML2 tests.
*
* @author Martin Fleck <mfleck@eclipsesource.com>
*/
@RunWith(Suite.class)
-@SuiteClasses({ProfileMigrationTest.class })
+@SuiteClasses({ProfileMigrationTest.class, //
+ ModelSetWrapperTest.class, //
+})
public class AllUITests {
}

Back to the top