diff options
author | nileshagrawal@chromium.org <nileshagrawal@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-03-01 21:35:34 +0000 |
---|---|---|
committer | nileshagrawal@chromium.org <nileshagrawal@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-03-01 21:35:34 +0000 |
commit | 2afee1373c1233260f32bccb86483b53a3a280cc (patch) | |
tree | 5fb6229161a97bb75f576a6f13c9f45bcd57dea3 /base/android/javatests | |
parent | 644f4fba5a0fd2b13ef21e7f76e419ae3dc9db56 (diff) | |
download | chromium_src-2afee1373c1233260f32bccb86483b53a3a280cc.zip chromium_src-2afee1373c1233260f32bccb86483b53a3a280cc.tar.gz chromium_src-2afee1373c1233260f32bccb86483b53a3a280cc.tar.bz2 |
Android: Add a java version of ObserverList.
Provides a safe container to maintain observer/listener lists which can be modified during iteration.
This is heavily based on the C++ version.
TBR=jam@chromium.org
BUG=
Review URL: https://codereview.chromium.org/12378004
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@185595 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'base/android/javatests')
-rw-r--r-- | base/android/javatests/src/org/chromium/base/ObserverListTest.java | 180 |
1 files changed, 180 insertions, 0 deletions
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 0000000..10c898c --- /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); + } +} |