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.Iterator; 13 import java.util.NoSuchElementException; 14 15 /** 16 * Tests for (@link ObserverList}. 17 */ 18 public class ObserverListTest extends InstrumentationTestCase { 19 interface Observer { 20 void observe(int x); 21 } 22 23 private static class Foo implements Observer { 24 private final int mScalar; 25 private int mTotal = 0; 26 27 Foo(int scalar) { 28 mScalar = scalar; 29 } 30 31 @Override 32 public void observe(int x) { 33 mTotal += x * mScalar; 34 } 35 } 36 37 /** 38 * An observer which add a given Observer object to the list when observe is called. 39 */ 40 private static class FooAdder implements Observer { 41 private final ObserverList<Observer> mList; 42 private final Observer mLucky; 43 44 FooAdder(ObserverList<Observer> list, Observer oblivious) { 45 mList = list; 46 mLucky = oblivious; 47 } 48 49 @Override 50 public void observe(int x) { 51 mList.addObserver(mLucky); 52 } 53 } 54 55 /** 56 * An observer which removes a given Observer object from the list when observe is called. 57 */ 58 private static class FooRemover implements Observer { 59 private final ObserverList<Observer> mList; 60 private final Observer mDoomed; 61 62 FooRemover(ObserverList<Observer> list, Observer innocent) { 63 mList = list; 64 mDoomed = innocent; 65 } 66 67 @Override 68 public void observe(int x) { 69 mList.removeObserver(mDoomed); 70 } 71 } 72 73 private static <T> int getSizeOfIterable(Iterable<T> iterable) { 74 int num = 0; 75 for (T el : iterable) 76 num++; 77 return num; 78 } 79 80 @SmallTest 81 @Feature({"Android-AppBase"}) 82 public void testRemoveWhileIteration() { 83 ObserverList<Observer> observerList = new ObserverList<Observer>(); 84 Foo a = new Foo(1); 85 Foo b = new Foo(-1); 86 Foo c = new Foo(1); 87 Foo d = new Foo(-1); 88 Foo e = new Foo(-1); 89 FooRemover evil = new FooRemover(observerList, c); 90 91 observerList.addObserver(a); 92 observerList.addObserver(b); 93 94 for (Observer obs : observerList) 95 obs.observe(10); 96 97 // Removing an observer not in the list should do nothing. 98 observerList.removeObserver(e); 99 100 observerList.addObserver(evil); 101 observerList.addObserver(c); 102 observerList.addObserver(d); 103 104 for (Observer obs : observerList) 105 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"}) 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) 133 obs.observe(10); 134 135 assertTrue(observerList.hasObserver(c)); 136 assertEquals(10, a.mTotal); 137 assertEquals(-10, b.mTotal); 138 assertEquals(0, c.mTotal); 139 } 140 141 @SmallTest 142 @Feature({"Android-AppBase"}) 143 public void testIterator() { 144 ObserverList<Integer> observerList = new ObserverList<Integer>(); 145 observerList.addObserver(5); 146 observerList.addObserver(10); 147 observerList.addObserver(15); 148 assertEquals(3, getSizeOfIterable(observerList)); 149 150 observerList.removeObserver(10); 151 assertEquals(2, getSizeOfIterable(observerList)); 152 153 Iterator<Integer> it = observerList.iterator(); 154 assertTrue(it.hasNext()); 155 assertTrue(5 == it.next()); 156 assertTrue(it.hasNext()); 157 assertTrue(15 == it.next()); 158 assertFalse(it.hasNext()); 159 160 boolean removeExceptionThrown = false; 161 try { 162 it.remove(); 163 fail("Expecting UnsupportedOperationException to be thrown here."); 164 } catch (UnsupportedOperationException e) { 165 removeExceptionThrown = true; 166 } 167 assertTrue(removeExceptionThrown); 168 assertEquals(2, getSizeOfIterable(observerList)); 169 170 boolean noElementExceptionThrown = false; 171 try { 172 it.next(); 173 fail("Expecting NoSuchElementException to be thrown here."); 174 } catch (NoSuchElementException e) { 175 noElementExceptionThrown = true; 176 } 177 assertTrue(noElementExceptionThrown); 178 } 179 180 @SmallTest 181 @Feature({"Android-AppBase"}) 182 public void testRewindableIterator() { 183 ObserverList<Integer> observerList = new ObserverList<Integer>(); 184 observerList.addObserver(5); 185 observerList.addObserver(10); 186 observerList.addObserver(15); 187 assertEquals(3, getSizeOfIterable(observerList)); 188 189 ObserverList.RewindableIterator<Integer> it = observerList.rewindableIterator(); 190 assertTrue(it.hasNext()); 191 assertTrue(5 == it.next()); 192 assertTrue(it.hasNext()); 193 assertTrue(10 == it.next()); 194 assertTrue(it.hasNext()); 195 assertTrue(15 == it.next()); 196 assertFalse(it.hasNext()); 197 198 it.rewind(); 199 200 assertTrue(it.hasNext()); 201 assertTrue(5 == it.next()); 202 assertTrue(it.hasNext()); 203 assertTrue(10 == it.next()); 204 assertTrue(it.hasNext()); 205 assertTrue(15 == it.next()); 206 assertEquals(5, (int) observerList.mObservers.get(0)); 207 observerList.removeObserver(5); 208 assertEquals(null, observerList.mObservers.get(0)); 209 210 it.rewind(); 211 212 assertEquals(10, (int) observerList.mObservers.get(0)); 213 assertTrue(it.hasNext()); 214 assertTrue(10 == it.next()); 215 assertTrue(it.hasNext()); 216 assertTrue(15 == it.next()); 217 } 218 } 219