1 // Copyright 2019 The Chromium Authors 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.supplier; 6 7 import static org.junit.Assert.assertEquals; 8 import static org.junit.Assert.assertFalse; 9 import static org.junit.Assert.assertNotSame; 10 import static org.junit.Assert.assertTrue; 11 12 import android.os.Handler; 13 14 import org.junit.Test; 15 import org.junit.runner.RunWith; 16 import org.robolectric.annotation.Config; 17 18 import org.chromium.base.Callback; 19 import org.chromium.base.test.BaseRobolectricTestRunner; 20 21 /** Unit tests for {@link ObservableSupplierImpl}. */ 22 @RunWith(BaseRobolectricTestRunner.class) 23 @Config(manifest = Config.NONE) 24 public class ObservableSupplierImplTest { 25 private static final String TEST_STRING_1 = "Test"; 26 private static final String TEST_STRING_2 = "Test2"; 27 28 private int mCallCount; 29 private String mLastSuppliedString; 30 private ObservableSupplierImpl<String> mSupplier = new ObservableSupplierImpl<>(); 31 32 @Test testObserverNotification_SetMultiple()33 public void testObserverNotification_SetMultiple() { 34 Callback<String> supplierObserver = 35 result -> { 36 mCallCount++; 37 mLastSuppliedString = result; 38 }; 39 40 mSupplier.addObserver(supplierObserver); 41 checkState(0, null, null, "before setting first string."); 42 43 mSupplier.set(TEST_STRING_1); 44 checkState(1, TEST_STRING_1, TEST_STRING_1, "after setting first string."); 45 46 mSupplier.set(TEST_STRING_2); 47 checkState(2, TEST_STRING_2, TEST_STRING_2, "after setting second string."); 48 49 mSupplier.set(null); 50 checkState(3, null, null, "after setting third string."); 51 } 52 53 @Test testObserverNotification_SetSame()54 public void testObserverNotification_SetSame() { 55 Callback<String> supplierObserver = 56 result -> { 57 mCallCount++; 58 mLastSuppliedString = result; 59 }; 60 61 mSupplier.addObserver(supplierObserver); 62 checkState(0, null, null, "before setting first string."); 63 64 mSupplier.set(TEST_STRING_1); 65 checkState(1, TEST_STRING_1, TEST_STRING_1, "after setting first string."); 66 67 mSupplier.set(TEST_STRING_1); 68 checkState(1, TEST_STRING_1, TEST_STRING_1, "after resetting first string."); 69 70 // Need to trick Java to not intern our new string. 71 String anotherTestString1 = new String(new char[] {'T', 'e', 's', 't'}); 72 assertNotSame(TEST_STRING_1, anotherTestString1); 73 mSupplier.set(anotherTestString1); 74 // Don't use checkState, as the string arguments do not really make sense. 75 assertEquals( 76 "Incorrect call count after setting a different but equal string.", 1, mCallCount); 77 } 78 79 @Test testObserverNotification_RemoveObserver()80 public void testObserverNotification_RemoveObserver() { 81 Callback<String> supplierObserver = 82 result -> { 83 mCallCount++; 84 mLastSuppliedString = result; 85 }; 86 87 mSupplier.addObserver(supplierObserver); 88 checkState(0, null, null, "before setting first string."); 89 90 mSupplier.set(TEST_STRING_1); 91 checkState(1, TEST_STRING_1, TEST_STRING_1, "after setting first string."); 92 93 mSupplier.removeObserver(supplierObserver); 94 95 mSupplier.set(TEST_STRING_2); 96 checkState(1, TEST_STRING_1, TEST_STRING_2, "after setting second string."); 97 } 98 99 @Test testObserverNotification_RegisterObserverAfterSet()100 public void testObserverNotification_RegisterObserverAfterSet() { 101 Handler handler = new Handler(); 102 handler.post( 103 () -> { 104 mSupplier.set(TEST_STRING_1); 105 checkState(0, null, TEST_STRING_1, "after setting first string."); 106 107 Callback<String> supplierObserver = 108 (String result) -> { 109 mCallCount++; 110 mLastSuppliedString = result; 111 }; 112 113 mSupplier.addObserver(supplierObserver); 114 115 checkState(0, null, TEST_STRING_1, "after setting observer."); 116 }); 117 118 handler.post(() -> checkState(1, TEST_STRING_1, TEST_STRING_1, "in second message loop.")); 119 } 120 121 @Test testObserverNotification_RegisterObserverAfterSetThenSetAgain()122 public void testObserverNotification_RegisterObserverAfterSetThenSetAgain() { 123 Handler handler = new Handler(); 124 handler.post( 125 () -> { 126 mSupplier.set(TEST_STRING_1); 127 checkState(0, null, TEST_STRING_1, "after setting first string."); 128 129 Callback<String> supplierObserver = 130 (String result) -> { 131 mCallCount++; 132 mLastSuppliedString = result; 133 }; 134 135 mSupplier.addObserver(supplierObserver); 136 137 checkState(0, null, TEST_STRING_1, "after setting observer."); 138 139 mSupplier.set(TEST_STRING_2); 140 checkState(1, TEST_STRING_2, TEST_STRING_2, "after setting second string."); 141 }); 142 143 handler.post(() -> checkState(1, TEST_STRING_2, TEST_STRING_2, "in second message loop.")); 144 } 145 146 @Test testObserverNotification_RegisterObserverAfterSetThenRemove()147 public void testObserverNotification_RegisterObserverAfterSetThenRemove() { 148 Handler handler = new Handler(); 149 handler.post( 150 () -> { 151 mSupplier.set(TEST_STRING_1); 152 checkState(0, null, TEST_STRING_1, "after setting first string."); 153 154 Callback<String> supplierObserver = 155 (String result) -> { 156 mCallCount++; 157 mLastSuppliedString = result; 158 }; 159 160 mSupplier.addObserver(supplierObserver); 161 162 checkState(0, null, TEST_STRING_1, "after setting observer."); 163 164 mSupplier.removeObserver(supplierObserver); 165 }); 166 167 handler.post(() -> checkState(0, null, TEST_STRING_1, "in second message loop.")); 168 } 169 170 @Test testObserverNotification_RemoveObserverInsideCallback()171 public void testObserverNotification_RemoveObserverInsideCallback() { 172 Callback<String> supplierObserver = 173 new Callback<>() { 174 @Override 175 public void onResult(String result) { 176 mCallCount++; 177 mLastSuppliedString = result; 178 mSupplier.removeObserver(this); 179 } 180 }; 181 182 mSupplier.addObserver(supplierObserver); 183 checkState(0, null, null, "before setting first string."); 184 185 mSupplier.set(TEST_STRING_1); 186 checkState(1, TEST_STRING_1, TEST_STRING_1, "after setting first string."); 187 188 mSupplier.set(TEST_STRING_2); 189 checkState(1, TEST_STRING_1, TEST_STRING_2, "after setting second string."); 190 } 191 192 @Test testHasObservers()193 public void testHasObservers() { 194 Callback<String> observer1 = (ignored) -> {}; 195 Callback<String> observer2 = (ignored) -> {}; 196 197 assertFalse("No observers yet", mSupplier.hasObservers()); 198 199 mSupplier.addObserver(observer1); 200 assertTrue("Should have observer1", mSupplier.hasObservers()); 201 202 mSupplier.addObserver(observer1); 203 assertTrue("Adding observer1 twice shouldn't break anything", mSupplier.hasObservers()); 204 205 mSupplier.removeObserver(observer1); 206 assertFalse( 207 "observer1 should be entirely removed with one remove", mSupplier.hasObservers()); 208 209 mSupplier.addObserver(observer1); 210 mSupplier.addObserver(observer2); 211 assertTrue("Should have multiple observers", mSupplier.hasObservers()); 212 213 mSupplier.removeObserver(observer1); 214 assertTrue("Should still have observer2", mSupplier.hasObservers()); 215 216 mSupplier.removeObserver(observer1); 217 assertTrue("Removing observer1 twice shouldn't break anything", mSupplier.hasObservers()); 218 219 mSupplier.removeObserver(observer2); 220 assertFalse("Both observers should be gone", mSupplier.hasObservers()); 221 } 222 checkState( int expectedCallCount, String expectedLastSuppliedString, String expectedStringFromGet, String assertDescription)223 private void checkState( 224 int expectedCallCount, 225 String expectedLastSuppliedString, 226 String expectedStringFromGet, 227 String assertDescription) { 228 assertEquals("Incorrect call count " + assertDescription, expectedCallCount, mCallCount); 229 assertEquals( 230 "Incorrect last supplied string " + assertDescription, 231 expectedLastSuppliedString, 232 mLastSuppliedString); 233 assertEquals( 234 "Incorrect #get() " + assertDescription, expectedStringFromGet, mSupplier.get()); 235 } 236 } 237