diff options
author | Christian W. Damus | 2016-02-02 19:26:56 +0000 |
---|---|---|
committer | Christian W. Damus | 2016-02-02 21:22:46 +0000 |
commit | 5808a056ea10850dc850f67f8607e20f027e51a3 (patch) | |
tree | 2deef3def13597170dd7b07ceac3f8b423edd665 /tests/junit | |
parent | 47808f46fa6baeccc0074b9eabc7e29d6c461da6 (diff) | |
download | org.eclipse.papyrus-5808a056ea10850dc850f67f8607e20f027e51a3.tar.gz org.eclipse.papyrus-5808a056ea10850dc850f67f8607e20f027e51a3.tar.xz org.eclipse.papyrus-5808a056ea10850dc850f67f8607e20f027e51a3.zip |
Bug 487027: [Welcome Page] AssertionFailedException
https://bugs.eclipse.org/bugs/show_bug.cgi?id=487027
Ensure proper disposal of observables for diagram/table views
and languages when the Welcome Page is closed, by leveraging
the reference-counted observables framework.
Change-Id: I671650e54ca01c4072282109b47efdac52ab28e3
Diffstat (limited to 'tests/junit')
9 files changed, 428 insertions, 27 deletions
diff --git a/tests/junit/plugins/infra/editor/org.eclipse.papyrus.infra.editor.welcome.tests/src/org/eclipse/papyrus/infra/editor/welcome/tests/WelcomeModelElementTest.java b/tests/junit/plugins/infra/editor/org.eclipse.papyrus.infra.editor.welcome.tests/src/org/eclipse/papyrus/infra/editor/welcome/tests/WelcomeModelElementTest.java index 8542083311e..af6075a1f9c 100644 --- a/tests/junit/plugins/infra/editor/org.eclipse.papyrus.infra.editor.welcome.tests/src/org/eclipse/papyrus/infra/editor/welcome/tests/WelcomeModelElementTest.java +++ b/tests/junit/plugins/infra/editor/org.eclipse.papyrus.infra.editor.welcome.tests/src/org/eclipse/papyrus/infra/editor/welcome/tests/WelcomeModelElementTest.java @@ -1,5 +1,5 @@ /***************************************************************************** - * Copyright (c) 2015 Christian W. Damus and others. + * Copyright (c) 2015, 2016 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 @@ -117,6 +117,26 @@ public class WelcomeModelElementTest extends AbstractWelcomePageTest { assertThat(lang.getVersion().getValue().compareTo(new Version("2.5")), not(lessThan(0))); } + /** + * Verifies correct and complete disposal of observables when they are no longer needed. + */ + @Test + public void dispose_bug487027() { + @SuppressWarnings("unchecked") + IObservableList<LanguageObservable> languages = (IObservableList<LanguageObservable>) fixture.getObservable("languages"); + + assumeThat(languages, hasItem(anything())); + LanguageObservable lang = languages.get(0); + + // Dispose the model-element + fixture.dispose(); + + // Let the auto-release pool clean up + editor.flushDisplayEvents(); + + assertThat("Language observable not disposed", lang.isDisposed(), is(true)); + } + @Test public void isEditable() { assertThat(fixture.isEditable("privateLayout"), is(true)); diff --git a/tests/junit/plugins/infra/gmfdiag/org.eclipse.papyrus.infra.gmfdiag.welcome.tests/src/org/eclipse/papyrus/infra/gmfdiag/welcome/tests/WelcomeModelElementTest.java b/tests/junit/plugins/infra/gmfdiag/org.eclipse.papyrus.infra.gmfdiag.welcome.tests/src/org/eclipse/papyrus/infra/gmfdiag/welcome/tests/WelcomeModelElementTest.java index c55c9ff27ed..9bfa0aa6be2 100644 --- a/tests/junit/plugins/infra/gmfdiag/org.eclipse.papyrus.infra.gmfdiag.welcome.tests/src/org/eclipse/papyrus/infra/gmfdiag/welcome/tests/WelcomeModelElementTest.java +++ b/tests/junit/plugins/infra/gmfdiag/org.eclipse.papyrus.infra.gmfdiag.welcome.tests/src/org/eclipse/papyrus/infra/gmfdiag/welcome/tests/WelcomeModelElementTest.java @@ -20,6 +20,7 @@ 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 java.util.Collection; import java.util.Collections; @@ -124,18 +125,7 @@ public class WelcomeModelElementTest extends AbstractWelcomePageTest { } }); - editor.execute(new RecordingCommand(editor.getEditingDomain(), "Create Diagram") { - - @Override - protected void doExecute() { - // Be resilient against misconfigured diagrams: look for the class diagram, specifically - ViewPrototype prototype = PolicyChecker.getCurrent().getPrototypesFor(editor.getModel()).stream() - .filter(proto -> proto.getConfiguration() instanceof PapyrusDiagram) - .filter(proto -> EcoreUtil.getURI(proto.getConfiguration()).toString().contains("org.eclipse.papyrus.uml.diagram.clazz")) - .findAny().get(); - prototype.instantiateOn(editor.getModel(), "CreatedInTest"); - } - }); + createSomeDiagram(); assertThat("List did not notify", created[0], notNullValue()); assertThat(views.size(), is(7)); @@ -148,6 +138,36 @@ public class WelcomeModelElementTest extends AbstractWelcomePageTest { assertThat(fixture.isEditable("garbage"), is(false)); } + /** + * Verifies correct and complete disposal of observables when they are no longer needed. + */ + @Test + public void dispose_bug487027() { + IObservableList<NotationObservable> views = getNotationViews(); + + NotationObservable[] obs = { null }; + + views.addListChangeListener(event -> { + for (ListDiffEntry<? extends NotationObservable> next : event.diff.getDifferences()) { + if (next.isAddition() && "CreatedInTest".equals(getName(next.getElement().getView().getValue()))) { + obs[0] = next.getElement(); + } + } + }); + + createSomeDiagram(); + + assumeThat("Didn't get the created notation observable", obs[0], notNullValue()); + + // Dispose the model-element + fixture.dispose(); + + // Let the auto-release pool clean up + editor.flushDisplayEvents(); + + assertThat("Notation observable not disposed", obs[0].isDisposed(), is(true)); + } + // // Test framework // @@ -175,4 +195,19 @@ public class WelcomeModelElementTest extends AbstractWelcomePageTest { EStructuralFeature nameAttribute = object.eClass().getEStructuralFeature("name"); return (String) object.eGet(nameAttribute); } + + void createSomeDiagram() { + editor.execute(new RecordingCommand(editor.getEditingDomain(), "Create Diagram") { + + @Override + protected void doExecute() { + // Be resilient against misconfigured diagrams: look for the class diagram, specifically + ViewPrototype prototype = PolicyChecker.getCurrent().getPrototypesFor(editor.getModel()).stream() + .filter(proto -> proto.getConfiguration() instanceof PapyrusDiagram) + .filter(proto -> EcoreUtil.getURI(proto.getConfiguration()).toString().contains("org.eclipse.papyrus.uml.diagram.clazz")) + .findAny().get(); + prototype.instantiateOn(editor.getModel(), "CreatedInTest"); + } + }); + } } diff --git a/tests/junit/plugins/infra/org.eclipse.papyrus.infra.tools.tests/.classpath b/tests/junit/plugins/infra/org.eclipse.papyrus.infra.tools.tests/.classpath index ad32c83a788..eca7bdba8f0 100644 --- a/tests/junit/plugins/infra/org.eclipse.papyrus.infra.tools.tests/.classpath +++ b/tests/junit/plugins/infra/org.eclipse.papyrus.infra.tools.tests/.classpath @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="UTF-8"?> <classpath> - <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6"/> + <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/> <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/> <classpathentry kind="src" path="src"/> <classpathentry kind="output" path="bin"/> diff --git a/tests/junit/plugins/infra/org.eclipse.papyrus.infra.tools.tests/.settings/org.eclipse.jdt.core.prefs b/tests/junit/plugins/infra/org.eclipse.papyrus.infra.tools.tests/.settings/org.eclipse.jdt.core.prefs index 94d61f00da6..b3aa6d60f94 100644 --- a/tests/junit/plugins/infra/org.eclipse.papyrus.infra.tools.tests/.settings/org.eclipse.jdt.core.prefs +++ b/tests/junit/plugins/infra/org.eclipse.papyrus.infra.tools.tests/.settings/org.eclipse.jdt.core.prefs @@ -1,10 +1,10 @@ eclipse.preferences.version=1 org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled -org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 -org.eclipse.jdt.core.compiler.compliance=1.6 +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 +org.eclipse.jdt.core.compiler.compliance=1.8 org.eclipse.jdt.core.compiler.problem.assertIdentifier=error org.eclipse.jdt.core.compiler.problem.enumIdentifier=error -org.eclipse.jdt.core.compiler.source=1.6 +org.eclipse.jdt.core.compiler.source=1.8 org.eclipse.jdt.core.formatter.align_type_members_on_columns=false org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16 org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation=0 diff --git a/tests/junit/plugins/infra/org.eclipse.papyrus.infra.tools.tests/META-INF/MANIFEST.MF b/tests/junit/plugins/infra/org.eclipse.papyrus.infra.tools.tests/META-INF/MANIFEST.MF index 55e768039b8..b12fb347e45 100644 --- a/tests/junit/plugins/infra/org.eclipse.papyrus.infra.tools.tests/META-INF/MANIFEST.MF +++ b/tests/junit/plugins/infra/org.eclipse.papyrus.infra.tools.tests/META-INF/MANIFEST.MF @@ -16,4 +16,4 @@ Bundle-Version: 1.2.0.qualifier Bundle-Name: Papyrus Infrastructure Tools Tests
Bundle-ManifestVersion: 2
Bundle-SymbolicName: org.eclipse.papyrus.infra.tools.tests;singleton:=true
-Bundle-RequiredExecutionEnvironment: JavaSE-1.6
+Bundle-RequiredExecutionEnvironment: JavaSE-1.8
diff --git a/tests/junit/plugins/infra/org.eclipse.papyrus.infra.tools.tests/src/org/eclipse/papyrus/infra/tools/databinding/AllDataBindingTests.java b/tests/junit/plugins/infra/org.eclipse.papyrus.infra.tools.tests/src/org/eclipse/papyrus/infra/tools/databinding/AllDataBindingTests.java index bcb4fd3f0a5..cbbb6ba3bb4 100644 --- a/tests/junit/plugins/infra/org.eclipse.papyrus.infra.tools.tests/src/org/eclipse/papyrus/infra/tools/databinding/AllDataBindingTests.java +++ b/tests/junit/plugins/infra/org.eclipse.papyrus.infra.tools.tests/src/org/eclipse/papyrus/infra/tools/databinding/AllDataBindingTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014 CEA and others. + * Copyright (c) 2014, 2016 CEA, 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 @@ -8,12 +8,13 @@ * * Contributors: * Christian W. Damus (CEA) - Initial API and implementation + * Christian W. Damus - bug 487027 * */ package org.eclipse.papyrus.infra.tools.databinding; -import org.junit.runner.RunWith; import org.eclipse.papyrus.junit.framework.classification.ClassificationSuite; +import org.junit.runner.RunWith; import org.junit.runners.Suite.SuiteClasses; @@ -21,7 +22,13 @@ import org.junit.runners.Suite.SuiteClasses; * The test suite for data-bindings API. */ @RunWith(ClassificationSuite.class) -@SuiteClasses({ DelegatingObservableValueTest.class, DelegatingObservableSetTest.class, DelegatingObservableListTest.class }) +@SuiteClasses({ + DelegatingObservableValueTest.class, + DelegatingObservableSetTest.class, + DelegatingObservableListTest.class, + WritableListWithIteratorTest.class, + WritableListWithIteratorContainmentTest.class, +}) public class AllDataBindingTests { private AllDataBindingTests() { diff --git a/tests/junit/plugins/infra/org.eclipse.papyrus.infra.tools.tests/src/org/eclipse/papyrus/infra/tools/databinding/RealmRunner.java b/tests/junit/plugins/infra/org.eclipse.papyrus.infra.tools.tests/src/org/eclipse/papyrus/infra/tools/databinding/RealmRunner.java index c5bce9bd2d2..ce8c9ea3ac4 100644 --- a/tests/junit/plugins/infra/org.eclipse.papyrus.infra.tools.tests/src/org/eclipse/papyrus/infra/tools/databinding/RealmRunner.java +++ b/tests/junit/plugins/infra/org.eclipse.papyrus.infra.tools.tests/src/org/eclipse/papyrus/infra/tools/databinding/RealmRunner.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014 CEA and others. + * Copyright (c) 2014, 2016 CEA, 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 @@ -8,6 +8,7 @@ * * Contributors: * Christian W. Damus (CEA) - Initial API and implementation + * Christian W. Damus - bug 487027 * */ package org.eclipse.papyrus.infra.tools.databinding; @@ -16,16 +17,20 @@ import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.Assert.fail; +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; import java.util.List; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.ThreadFactory; +import java.util.stream.Stream; import org.eclipse.core.databinding.observable.IObservable; import org.eclipse.core.databinding.observable.ObservableTracker; import org.eclipse.core.databinding.observable.Realm; import org.eclipse.papyrus.junit.framework.classification.ClassificationRunner; +import org.junit.runner.notification.Failure; import org.junit.runner.notification.RunNotifier; import org.junit.runners.model.FrameworkMethod; import org.junit.runners.model.InitializationError; @@ -38,8 +43,25 @@ import org.junit.runners.model.Statement; */ public class RealmRunner extends ClassificationRunner { - public RealmRunner(Class<?> klass) throws InitializationError { + private final Field realmField; + + public RealmRunner(@SuppressWarnings("rawtypes") Class klass) throws InitializationError { super(klass); + + realmField = Stream.iterate(klass, Class::getSuperclass) + .flatMap(c -> Stream.of(c.getDeclaredFields())) + .filter(f -> Modifier.isStatic(f.getModifiers())) + .filter(f -> f.getType() == Realm.class) + .findAny().get(); + realmField.setAccessible(true); + } + + private TestRealm getRealm() throws Exception { + return ((TestRealm) realmField.get(null)); + } + + private void setRealm(TestRealm realm) throws Exception { + realmField.set(null, realm); } @Override @@ -49,12 +71,12 @@ public class RealmRunner extends ClassificationRunner { @Override public void evaluate() throws Throwable { - DelegatingObservableTest.realm = new TestRealm(); + setRealm(new TestRealm()); try { base.evaluate(); } finally { - ((TestRealm) DelegatingObservableTest.realm).dispose(); - DelegatingObservableTest.realm = null; + getRealm().dispose(); + setRealm(null); } } }; @@ -77,7 +99,11 @@ public class RealmRunner extends ClassificationRunner { } }; - DelegatingObservableTest.realm.exec(run); + try { + getRealm().exec(run); + } catch (Exception e) { + notifier.fireTestFailure(new Failure(describeChild(method), e)); + } run.await(); } diff --git a/tests/junit/plugins/infra/org.eclipse.papyrus.infra.tools.tests/src/org/eclipse/papyrus/infra/tools/databinding/WritableListWithIteratorContainmentTest.java b/tests/junit/plugins/infra/org.eclipse.papyrus.infra.tools.tests/src/org/eclipse/papyrus/infra/tools/databinding/WritableListWithIteratorContainmentTest.java new file mode 100644 index 00000000000..ca44b521fde --- /dev/null +++ b/tests/junit/plugins/infra/org.eclipse.papyrus.infra.tools.tests/src/org/eclipse/papyrus/infra/tools/databinding/WritableListWithIteratorContainmentTest.java @@ -0,0 +1,125 @@ +/***************************************************************************** + * Copyright (c) 2016 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.infra.tools.databinding; + +import static org.hamcrest.CoreMatchers.is; +import static org.junit.Assert.assertThat; + +import java.util.Arrays; + +import org.eclipse.core.databinding.observable.Realm; +import org.eclipse.papyrus.junit.utils.rules.HouseKeeper; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + +/** + * Test cases for the {@link WritableListWithIterator.Containment} class. + */ +@RunWith(RealmRunner.class) +public class WritableListWithIteratorContainmentTest { + + protected static Realm realm; + + @Rule + public HouseKeeper houseKeeper = new HouseKeeper(); + + private WritableListWithIterator.Containment<MutableString> fixture; + + + @Test + public void testRetainRelease() { + MutableString a = MutableString.of("a"); + MutableString b = MutableString.of("b"); + MutableString c = MutableString.of("c"); + + c.retain(); // Claim this one + + fixture.addAll(Arrays.asList(a, b, c)); + + assertThat(b.isDisposed(), is(false)); + + fixture.remove(b); + + assertThat(b.isDisposed(), is(true)); + + c.release(); + + assertThat(c.isDisposed(), is(false)); // The list still has it + + fixture.remove(c); + + assertThat(c.isDisposed(), is(true)); + } + + @Test + public void testDispose() { + MutableString a = MutableString.of("a"); + MutableString b = MutableString.of("b"); + MutableString c = MutableString.of("c"); + + fixture.addAll(Arrays.asList(a, b, c)); + + assertThat(a.isDisposed(), is(false)); + assertThat(b.isDisposed(), is(false)); + assertThat(c.isDisposed(), is(false)); + + fixture.dispose(); + + assertThat(a.isDisposed(), is(true)); + assertThat(b.isDisposed(), is(true)); + assertThat(c.isDisposed(), is(true)); + } + + // + // Test framework + // + + @Before + public void createFixture() { + fixture = houseKeeper.cleanUpLater(new WritableListWithIterator.Containment<>(realm)); + } + + static class MutableString extends ReferenceCountedObservable.Value<String> { + + private String value; + + private MutableString() { + super(realm); + } + + public static MutableString of(String value) { + MutableString result = new MutableString(); + result.setValue(value); + return result; + } + + @Override + public Object getValueType() { + return String.class; + } + + @Override + protected void doSetValue(String value) { + this.value = value; + } + + @Override + protected String doGetValue() { + return value; + } + + } +} diff --git a/tests/junit/plugins/infra/org.eclipse.papyrus.infra.tools.tests/src/org/eclipse/papyrus/infra/tools/databinding/WritableListWithIteratorTest.java b/tests/junit/plugins/infra/org.eclipse.papyrus.infra.tools.tests/src/org/eclipse/papyrus/infra/tools/databinding/WritableListWithIteratorTest.java new file mode 100644 index 00000000000..fae4e0037d4 --- /dev/null +++ b/tests/junit/plugins/infra/org.eclipse.papyrus.infra.tools.tests/src/org/eclipse/papyrus/infra/tools/databinding/WritableListWithIteratorTest.java @@ -0,0 +1,188 @@ +/***************************************************************************** + * Copyright (c) 2016 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.infra.tools.databinding; + +import static org.hamcrest.CoreMatchers.hasItem; +import static org.hamcrest.CoreMatchers.is; +import static org.junit.Assert.assertThat; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Iterator; +import java.util.List; +import java.util.ListIterator; + +import org.eclipse.core.databinding.observable.Realm; +import org.eclipse.core.databinding.observable.list.IListChangeListener; +import org.eclipse.core.databinding.observable.list.IObservableList; +import org.eclipse.core.databinding.observable.list.ListChangeEvent; +import org.eclipse.core.databinding.observable.list.ListDiffVisitor; +import org.eclipse.papyrus.infra.tools.databinding.ReferenceCountedObservable.AutoReleasePool; +import org.eclipse.papyrus.junit.utils.rules.HouseKeeper; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + +/** + * Test cases for the {@link WritableListWithIterator} class. + */ +@RunWith(RealmRunner.class) +public class WritableListWithIteratorTest { + + protected static Realm realm; + + @Rule + public HouseKeeper houseKeeper = new HouseKeeper(); + + private WritableListWithIterator<String> fixture; + + @Test + public void testRetain() { + fixture.retain(); + fixture.retain(); + + fixture.release(); + + assertThat(fixture.isDisposed(), is(false)); + } + + @Test + public void testRelease() { + fixture.retain(); + + fixture.release(); + + assertThat(fixture.isDisposed(), is(true)); + } + + @Test + public void testAutorelease() throws Exception { + fixture.retain(); + + fixture.autorelease(); + + assertThat(fixture.isDisposed(), is(false)); + + // Drain the pending autorelease pool + AutoReleasePool.get(realm).release(); + + assertThat(fixture.isDisposed(), is(true)); + } + + @Test + public void testIterator() { + fixture.addAll(Arrays.asList("a", "b", "c")); + + ListChangeAssertion<String> changes = ListChangeAssertion.on(fixture); + + Iterator<String> iter = fixture.iterator(); + assertThat(iter.next(), is("a")); + assertThat(iter.next(), is("b")); + iter.remove(); + changes.assertRemoved("b"); + assertThat(iter.next(), is("c")); + assertThat(iter.hasNext(), is(false)); + } + + @Test + public void testListIterator() { + fixture.addAll(Arrays.asList("a", "b", "c")); + + ListChangeAssertion<String> changes = ListChangeAssertion.on(fixture); + + ListIterator<String> iter = fixture.listIterator(); + assertThat(iter.next(), is("a")); + assertThat(iter.next(), is("b")); + iter.remove(); + changes.assertRemoved("b"); + iter.add("d"); + changes.assertAdded("d"); + assertThat(iter.next(), is("c")); + iter.set("e"); + changes.assertRemoved("c"); + changes.assertAdded("e"); + assertThat(iter.hasNext(), is(false)); + } + + @Test + public void testListIterator_int() { + fixture.addAll(Arrays.asList("a", "b", "c")); + + ListChangeAssertion<String> changes = ListChangeAssertion.on(fixture); + + ListIterator<String> iter = fixture.listIterator(3); + assertThat(iter.previous(), is("c")); + assertThat(iter.previous(), is("b")); + iter.remove(); + changes.assertRemoved("b"); + iter.add("d"); + changes.assertAdded("d"); + assertThat(iter.previous(), is("d")); + assertThat(iter.previous(), is("a")); + iter.set("e"); + changes.assertRemoved("a"); + changes.assertAdded("e"); + assertThat(iter.hasPrevious(), is(false)); + } + + // + // Test framework + // + + @Before + public void createFixture() { + fixture = houseKeeper.cleanUpLater(new WritableListWithIterator<>(realm)); + } + + static class ListChangeAssertion<E> implements IListChangeListener<E> { + private List<E> added = new ArrayList<>(); + private List<E> removed = new ArrayList<>(); + + public static <E> ListChangeAssertion<E> on(IObservableList<E> list) { + ListChangeAssertion<E> result = new ListChangeAssertion<>(); + list.addListChangeListener(result); + return result; + } + + @SuppressWarnings({ "rawtypes", "unchecked" }) + @Override + public void handleListChange(ListChangeEvent<? extends E> event) { + event.diff.accept((ListDiffVisitor) new ListDiffVisitor<E>() { + @Override + public void handleAdd(int index, E element) { + added.add(element); + } + + @Override + public void handleRemove(int index, E element) { + removed.add(element); + } + }); + } + + public void assertAdded(E element) { + assertThat(added, hasItem(element)); + } + + public void assertRemoved(E element) { + assertThat(removed, hasItem(element)); + } + + public void reset() { + added.clear(); + removed.clear(); + } + } +} |