• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 package org.chromium.base;
6 
7 import android.test.InstrumentationTestCase;
8 import android.test.suitebuilder.annotation.SmallTest;
9 
10 import org.chromium.base.test.util.Feature;
11 
12 import java.util.Collection;
13 import java.util.Iterator;
14 import java.util.NoSuchElementException;
15 
16 /**
17  * Tests for (@link ObserverList}.
18  */
19 public class ObserverListTest extends InstrumentationTestCase {
20     interface Observer {
observe(int x)21         void observe(int x);
22     }
23 
24     private static class Foo implements Observer {
25         private final int mScalar;
26         private int mTotal = 0;
27 
Foo(int scalar)28         Foo(int scalar) {
29             mScalar = scalar;
30         }
31 
32         @Override
observe(int x)33         public void observe(int x) {
34             mTotal += x * mScalar;
35         }
36     }
37 
38     /**
39      * An observer which add a given Observer object to the list when observe is called.
40      */
41     private static class FooAdder implements Observer {
42         private final ObserverList<Observer> mList;
43         private final Observer mLucky;
44 
FooAdder(ObserverList<Observer> list, Observer oblivious)45         FooAdder(ObserverList<Observer> list, Observer oblivious) {
46             mList = list;
47             mLucky = oblivious;
48         }
49 
50         @Override
observe(int x)51         public void observe(int x) {
52             mList.addObserver(mLucky);
53         }
54     }
55 
56     /**
57      * An observer which removes a given Observer object from the list when observe is called.
58      */
59     private static class FooRemover implements Observer {
60         private final ObserverList<Observer> mList;
61         private final Observer mDoomed;
62 
FooRemover(ObserverList<Observer> list, Observer innocent)63         FooRemover(ObserverList<Observer> list, Observer innocent) {
64             mList = list;
65             mDoomed = innocent;
66         }
67 
68         @Override
observe(int x)69         public void observe(int x) {
70             mList.removeObserver(mDoomed);
71         }
72     }
73 
74     @SuppressWarnings("ElementsCountedInLoop")
getSizeOfIterable(Iterable<T> iterable)75     private static <T> int getSizeOfIterable(Iterable<T> iterable) {
76         if (iterable instanceof Collection<?>) return ((Collection<?>) iterable).size();
77         int num = 0;
78         for (T el : iterable) num++;
79         return num;
80     }
81 
82     @SmallTest
83     @Feature({"Android-AppBase"})
testRemoveWhileIteration()84     public void testRemoveWhileIteration() {
85         ObserverList<Observer> observerList = new ObserverList<Observer>();
86         Foo a = new Foo(1);
87         Foo b = new Foo(-1);
88         Foo c = new Foo(1);
89         Foo d = new Foo(-1);
90         Foo e = new Foo(-1);
91         FooRemover evil = new FooRemover(observerList, c);
92 
93         observerList.addObserver(a);
94         observerList.addObserver(b);
95 
96         for (Observer obs : observerList) obs.observe(10);
97 
98         // Removing an observer not in the list should do nothing.
99         observerList.removeObserver(e);
100 
101         observerList.addObserver(evil);
102         observerList.addObserver(c);
103         observerList.addObserver(d);
104 
105         for (Observer obs : observerList) obs.observe(10);
106 
107         // observe should be called twice on a.
108         assertEquals(20, a.mTotal);
109         // observe should be called twice on b.
110         assertEquals(-20, b.mTotal);
111         // evil removed c from the observerList before it got any callbacks.
112         assertEquals(0, c.mTotal);
113         // observe should be called once on d.
114         assertEquals(-10, d.mTotal);
115         // e was never added to the list, observe should not be called.
116         assertEquals(0, e.mTotal);
117     }
118 
119     @SmallTest
120     @Feature({"Android-AppBase"})
testAddWhileIteration()121     public void testAddWhileIteration() {
122         ObserverList<Observer> observerList = new ObserverList<Observer>();
123         Foo a = new Foo(1);
124         Foo b = new Foo(-1);
125         Foo c = new Foo(1);
126         FooAdder evil = new FooAdder(observerList, c);
127 
128         observerList.addObserver(evil);
129         observerList.addObserver(a);
130         observerList.addObserver(b);
131 
132         for (Observer obs : observerList) obs.observe(10);
133 
134         assertTrue(observerList.hasObserver(c));
135         assertEquals(10, a.mTotal);
136         assertEquals(-10, b.mTotal);
137         assertEquals(0, c.mTotal);
138     }
139 
140     @SmallTest
141     @Feature({"Android-AppBase"})
testIterator()142     public void testIterator() {
143         ObserverList<Integer> observerList = new ObserverList<Integer>();
144         observerList.addObserver(5);
145         observerList.addObserver(10);
146         observerList.addObserver(15);
147         assertEquals(3, getSizeOfIterable(observerList));
148 
149         observerList.removeObserver(10);
150         assertEquals(2, getSizeOfIterable(observerList));
151 
152         Iterator<Integer> it = observerList.iterator();
153         assertTrue(it.hasNext());
154         assertTrue(5 == it.next());
155         assertTrue(it.hasNext());
156         assertTrue(15 == it.next());
157         assertFalse(it.hasNext());
158 
159         boolean removeExceptionThrown = false;
160         try {
161             it.remove();
162             fail("Expecting UnsupportedOperationException to be thrown here.");
163         } catch (UnsupportedOperationException e) {
164             removeExceptionThrown = true;
165         }
166         assertTrue(removeExceptionThrown);
167         assertEquals(2, getSizeOfIterable(observerList));
168 
169         boolean noElementExceptionThrown = false;
170         try {
171             it.next();
172             fail("Expecting NoSuchElementException to be thrown here.");
173         } catch (NoSuchElementException e) {
174             noElementExceptionThrown = true;
175         }
176         assertTrue(noElementExceptionThrown);
177     }
178 
179     @SmallTest
180     @Feature({"Android-AppBase"})
testRewindableIterator()181     public void testRewindableIterator() {
182         ObserverList<Integer> observerList = new ObserverList<Integer>();
183         observerList.addObserver(5);
184         observerList.addObserver(10);
185         observerList.addObserver(15);
186         assertEquals(3, getSizeOfIterable(observerList));
187 
188         ObserverList.RewindableIterator<Integer> it = observerList.rewindableIterator();
189         assertTrue(it.hasNext());
190         assertTrue(5 == it.next());
191         assertTrue(it.hasNext());
192         assertTrue(10 == it.next());
193         assertTrue(it.hasNext());
194         assertTrue(15 == it.next());
195         assertFalse(it.hasNext());
196 
197         it.rewind();
198 
199         assertTrue(it.hasNext());
200         assertTrue(5 == it.next());
201         assertTrue(it.hasNext());
202         assertTrue(10 == it.next());
203         assertTrue(it.hasNext());
204         assertTrue(15 == it.next());
205         assertEquals(5, (int) observerList.mObservers.get(0));
206         observerList.removeObserver(5);
207         assertEquals(null, observerList.mObservers.get(0));
208 
209         it.rewind();
210 
211         assertEquals(10, (int) observerList.mObservers.get(0));
212         assertTrue(it.hasNext());
213         assertTrue(10 == it.next());
214         assertTrue(it.hasNext());
215         assertTrue(15 == it.next());
216     }
217 
218     @SmallTest
219     @Feature({"Android-AppBase"})
testAddObserverReturnValue()220     public void testAddObserverReturnValue() {
221         ObserverList<Object> observerList = new ObserverList<Object>();
222 
223         Object a = new Object();
224         assertTrue(observerList.addObserver(a));
225         assertFalse(observerList.addObserver(a));
226 
227         Object b = new Object();
228         assertTrue(observerList.addObserver(b));
229         assertFalse(observerList.addObserver(null));
230     }
231 
232     @SmallTest
233     @Feature({"Android-AppBase"})
testRemoveObserverReturnValue()234     public void testRemoveObserverReturnValue() {
235         ObserverList<Object> observerList = new ObserverList<Object>();
236 
237         Object a = new Object();
238         Object b = new Object();
239         observerList.addObserver(a);
240         observerList.addObserver(b);
241 
242         assertTrue(observerList.removeObserver(a));
243         assertFalse(observerList.removeObserver(a));
244         assertFalse(observerList.removeObserver(new Object()));
245         assertTrue(observerList.removeObserver(b));
246         assertFalse(observerList.removeObserver(null));
247 
248         // If we remove an object while iterating, it will be replaced by 'null'.
249         observerList.addObserver(a);
250         assertTrue(observerList.removeObserver(a));
251         assertFalse(observerList.removeObserver(null));
252     }
253 
254     @SmallTest
255     @Feature({"Android-AppBase"})
testSize()256     public void testSize() {
257         ObserverList<Object> observerList = new ObserverList<Object>();
258 
259         assertEquals(0, observerList.size());
260         assertTrue(observerList.isEmpty());
261 
262         observerList.addObserver(null);
263         assertEquals(0, observerList.size());
264         assertTrue(observerList.isEmpty());
265 
266         Object a = new Object();
267         observerList.addObserver(a);
268         assertEquals(1, observerList.size());
269         assertFalse(observerList.isEmpty());
270 
271         observerList.addObserver(a);
272         assertEquals(1, observerList.size());
273         assertFalse(observerList.isEmpty());
274 
275         observerList.addObserver(null);
276         assertEquals(1, observerList.size());
277         assertFalse(observerList.isEmpty());
278 
279         Object b = new Object();
280         observerList.addObserver(b);
281         assertEquals(2, observerList.size());
282         assertFalse(observerList.isEmpty());
283 
284         observerList.removeObserver(null);
285         assertEquals(2, observerList.size());
286         assertFalse(observerList.isEmpty());
287 
288         observerList.removeObserver(new Object());
289         assertEquals(2, observerList.size());
290         assertFalse(observerList.isEmpty());
291 
292         observerList.removeObserver(b);
293         assertEquals(1, observerList.size());
294         assertFalse(observerList.isEmpty());
295 
296         observerList.removeObserver(b);
297         assertEquals(1, observerList.size());
298         assertFalse(observerList.isEmpty());
299 
300         observerList.removeObserver(a);
301         assertEquals(0, observerList.size());
302         assertTrue(observerList.isEmpty());
303 
304         observerList.removeObserver(a);
305         observerList.removeObserver(b);
306         observerList.removeObserver(null);
307         observerList.removeObserver(new Object());
308         assertEquals(0, observerList.size());
309         assertTrue(observerList.isEmpty());
310 
311         observerList.addObserver(new Object());
312         observerList.addObserver(new Object());
313         observerList.addObserver(new Object());
314         observerList.addObserver(a);
315         assertEquals(4, observerList.size());
316         assertFalse(observerList.isEmpty());
317 
318         observerList.clear();
319         assertEquals(0, observerList.size());
320         assertTrue(observerList.isEmpty());
321 
322         observerList.removeObserver(a);
323         observerList.removeObserver(b);
324         observerList.removeObserver(null);
325         observerList.removeObserver(new Object());
326         assertEquals(0, observerList.size());
327         assertTrue(observerList.isEmpty());
328     }
329 }
330