Index: base/android/javatests/src/org/chromium/base/ObserverListTest.java |
diff --git a/base/android/javatests/src/org/chromium/base/ObserverListTest.java b/base/android/javatests/src/org/chromium/base/ObserverListTest.java |
new file mode 100644 |
index 0000000000000000000000000000000000000000..10c898c2a3a3c0f12600de205111bceb7b83940a |
--- /dev/null |
+++ b/base/android/javatests/src/org/chromium/base/ObserverListTest.java |
@@ -0,0 +1,180 @@ |
+// Copyright 2013 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+package org.chromium.base; |
+ |
+import android.test.InstrumentationTestCase; |
+import android.test.suitebuilder.annotation.SmallTest; |
+ |
+import org.chromium.base.test.util.Feature; |
+ |
+import java.lang.Iterable; |
+import java.util.Iterator; |
+import java.util.NoSuchElementException; |
+ |
+/** |
+ * Tests for (@link ObserverList}. |
+ */ |
+public class ObserverListTest extends InstrumentationTestCase { |
+ interface Observer { |
+ void observe(int x); |
+ } |
+ |
+ private static class Foo implements Observer { |
+ private final int mScalar; |
+ private int mTotal = 0; |
+ |
+ Foo(int scalar) { |
+ mScalar = scalar; |
+ } |
+ |
+ @Override |
+ public void observe(int x) { |
+ mTotal += x * mScalar; |
+ } |
+ } |
+ |
+ /** |
+ * An observer which add a given Observer object to the list when observe is called. |
+ */ |
+ private static class FooAdder implements Observer { |
+ private final ObserverList<Observer> mList; |
+ private final Observer mLucky; |
+ |
+ FooAdder(ObserverList<Observer> list, Observer oblivious) { |
+ mList = list; |
+ mLucky = oblivious; |
+ } |
+ |
+ @Override |
+ public void observe(int x) { |
+ mList.addObserver(mLucky); |
+ } |
+ } |
+ |
+ /** |
+ * An observer which removes a given Observer object from the list when observe is called. |
+ */ |
+ private static class FooRemover implements Observer { |
+ private final ObserverList<Observer> mList; |
+ private final Observer mDoomed; |
+ |
+ FooRemover(ObserverList<Observer> list, Observer innocent) { |
+ mList = list; |
+ mDoomed = innocent; |
+ } |
+ |
+ @Override |
+ public void observe(int x) { |
+ mList.removeObserver(mDoomed); |
+ } |
+ } |
+ |
+ private static <T> int getSizeOfIterable(Iterable<T> iterable) { |
+ int num = 0; |
+ for (T el : iterable) |
+ num++; |
+ return num; |
+ } |
+ |
+ @SmallTest |
+ @Feature({"Android-AppBase"}) |
+ public void testRemoveWhileIteration() { |
+ ObserverList<Observer> observerList = new ObserverList<Observer>(); |
+ Foo a = new Foo(1); |
+ Foo b = new Foo(-1); |
+ Foo c = new Foo(1); |
+ Foo d = new Foo(-1); |
+ Foo e = new Foo(-1); |
+ FooRemover evil = new FooRemover(observerList, c); |
+ |
+ observerList.addObserver(a); |
+ observerList.addObserver(b); |
+ |
+ for (Observer obs : observerList) |
+ obs.observe(10); |
+ |
+ // Removing an observer not in the list should do nothing. |
+ observerList.removeObserver(e); |
+ |
+ observerList.addObserver(evil); |
+ observerList.addObserver(c); |
+ observerList.addObserver(d); |
+ |
+ for (Observer obs : observerList) |
+ obs.observe(10); |
+ |
+ // observe should be called twice on a. |
+ assertEquals(20, a.mTotal); |
+ // observe should be called twice on b. |
+ assertEquals(-20, b.mTotal); |
+ // evil removed c from the observerList before it got any callbacks. |
+ assertEquals(0, c.mTotal); |
+ // observe should be called once on d. |
+ assertEquals(-10, d.mTotal); |
+ // e was never added to the list, observe should not be called. |
+ assertEquals(0, e.mTotal); |
+ } |
+ |
+ @SmallTest |
+ @Feature({"Android-AppBase"}) |
+ public void testAddWhileIteration() { |
+ ObserverList<Observer> observerList = new ObserverList<Observer>(); |
+ Foo a = new Foo(1); |
+ Foo b = new Foo(-1); |
+ Foo c = new Foo(1); |
+ FooAdder evil = new FooAdder(observerList, c); |
+ |
+ observerList.addObserver(evil); |
+ observerList.addObserver(a); |
+ observerList.addObserver(b); |
+ |
+ for (Observer obs : observerList) |
+ obs.observe(10); |
+ |
+ assertTrue(observerList.hasObserver(c)); |
+ assertEquals(10, a.mTotal); |
+ assertEquals(-10, b.mTotal); |
+ assertEquals(0, c.mTotal); |
+ } |
+ |
+ @SmallTest |
+ @Feature({"Android-AppBase"}) |
+ public void testIterator() { |
+ ObserverList<Integer> observerList = new ObserverList<Integer>(); |
+ observerList.addObserver(5); |
+ observerList.addObserver(10); |
+ observerList.addObserver(15); |
+ assertEquals(3, getSizeOfIterable(observerList)); |
+ |
+ observerList.removeObserver(10); |
+ assertEquals(2, getSizeOfIterable(observerList)); |
+ |
+ Iterator<Integer> it = observerList.iterator(); |
+ assertTrue(it.hasNext()); |
+ assertTrue(5 == it.next()); |
+ assertTrue(it.hasNext()); |
+ assertTrue(15 == it.next()); |
+ assertFalse(it.hasNext()); |
+ |
+ boolean removeExceptionThrown = false; |
+ try { |
+ it.remove(); |
+ fail("Expecting UnsupportedOperationException to be thrown here."); |
+ } catch (UnsupportedOperationException e) { |
+ removeExceptionThrown = true; |
+ } |
+ assertTrue(removeExceptionThrown); |
+ assertEquals(2, getSizeOfIterable(observerList)); |
+ |
+ boolean noElementExceptionThrown = false; |
+ try { |
+ it.next(); |
+ fail("Expecting NoSuchElementException to be thrown here."); |
+ } catch (NoSuchElementException e) { |
+ noElementExceptionThrown = true; |
+ } |
+ assertTrue(noElementExceptionThrown); |
+ } |
+} |