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