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.shared_preferences; 6 7 import static org.junit.Assert.assertEquals; 8 import static org.junit.Assert.assertFalse; 9 import static org.junit.Assert.assertNull; 10 import static org.junit.Assert.assertTrue; 11 import static org.mockito.ArgumentMatchers.eq; 12 import static org.mockito.Mockito.times; 13 import static org.mockito.Mockito.verify; 14 15 import androidx.test.filters.SmallTest; 16 17 import org.junit.Before; 18 import org.junit.Test; 19 import org.junit.runner.RunWith; 20 import org.mockito.Mock; 21 import org.mockito.MockitoAnnotations; 22 23 import org.chromium.base.test.BaseRobolectricTestRunner; 24 25 import java.util.Arrays; 26 import java.util.Collections; 27 import java.util.HashSet; 28 import java.util.Map; 29 import java.util.Set; 30 31 /** Unit tests for {@link SharedPreferencesManager}. */ 32 @RunWith(BaseRobolectricTestRunner.class) 33 public class SharedPreferencesManagerTest { 34 @Mock private PreferenceKeyChecker mChecker; 35 36 private static final KeyPrefix TEST_PREFIX = new KeyPrefix("TestPrefix.*"); 37 private static final String PREFIXED_KEY_1 = TEST_PREFIX.createKey("stemA"); 38 private static final String PREFIXED_KEY_2 = TEST_PREFIX.createKey("stemB"); 39 private static final String PREFIXED_KEY_3 = TEST_PREFIX.createKey(33); 40 41 private SharedPreferencesManager mSubject; 42 43 @Before setUp()44 public void setUp() { 45 MockitoAnnotations.initMocks(this); 46 mSubject = new SharedPreferencesManager(mChecker); 47 } 48 49 @Test 50 @SmallTest testWriteReadInt()51 public void testWriteReadInt() { 52 // Verify default return values when no value is written. 53 assertEquals(0, mSubject.readInt("int_key")); 54 assertEquals(987, mSubject.readInt("int_key", 987)); 55 assertFalse(mSubject.contains("int_key")); 56 57 // Write a value. 58 mSubject.writeInt("int_key", 123); 59 60 // Verify value written can be read. 61 assertEquals(123, mSubject.readInt("int_key")); 62 assertEquals(123, mSubject.readInt("int_key", 987)); 63 assertTrue(mSubject.contains("int_key")); 64 65 // Remove the value. 66 mSubject.removeKey("int_key"); 67 68 // Verify the removed value is not returned anymore. 69 assertEquals(0, mSubject.readInt("int_key")); 70 assertFalse(mSubject.contains("int_key")); 71 } 72 73 @Test 74 @SmallTest testIncrementInt()75 public void testIncrementInt() { 76 mSubject.writeInt("int_key", 100); 77 int result = mSubject.incrementInt("int_key"); 78 79 assertEquals(101, result); 80 assertEquals(101, mSubject.readInt("int_key")); 81 } 82 83 @Test 84 @SmallTest testIncrementIntDefault()85 public void testIncrementIntDefault() { 86 int result = mSubject.incrementInt("int_key"); 87 88 assertEquals(1, result); 89 assertEquals(1, mSubject.readInt("int_key")); 90 } 91 92 @Test 93 @SmallTest testWriteReadBoolean()94 public void testWriteReadBoolean() { 95 // Verify default return values when no value is written. 96 assertEquals(false, mSubject.readBoolean("bool_key", false)); 97 assertEquals(true, mSubject.readBoolean("bool_key", true)); 98 assertFalse(mSubject.contains("bool_key")); 99 100 // Write a value. 101 mSubject.writeBoolean("bool_key", true); 102 103 // Verify value written can be read. 104 assertEquals(true, mSubject.readBoolean("bool_key", false)); 105 assertEquals(true, mSubject.readBoolean("bool_key", true)); 106 assertTrue(mSubject.contains("bool_key")); 107 108 // Remove the value. 109 mSubject.removeKey("bool_key"); 110 111 // Verify the removed value is not returned anymore. 112 assertEquals(false, mSubject.readBoolean("bool_key", false)); 113 assertEquals(true, mSubject.readBoolean("bool_key", true)); 114 assertFalse(mSubject.contains("bool_key")); 115 } 116 117 @Test 118 @SmallTest testWriteReadString()119 public void testWriteReadString() { 120 // Verify default return values when no value is written. 121 assertEquals("default", mSubject.readString("string_key", "default")); 122 assertFalse(mSubject.contains("string_key")); 123 124 // Write a value. 125 mSubject.writeString("string_key", "foo"); 126 127 // Verify value written can be read. 128 assertEquals("foo", mSubject.readString("string_key", "default")); 129 assertTrue(mSubject.contains("string_key")); 130 131 // Remove the value. 132 mSubject.removeKey("string_key"); 133 134 // Verify the removed value is not returned anymore. 135 assertEquals("default", mSubject.readString("string_key", "default")); 136 assertFalse(mSubject.contains("string_key")); 137 } 138 139 @Test 140 @SmallTest testWriteReadLong()141 public void testWriteReadLong() { 142 // Verify default return values when no value is written. 143 assertEquals(0, mSubject.readLong("long_key")); 144 assertEquals(9876543210L, mSubject.readLong("long_key", 9876543210L)); 145 assertFalse(mSubject.contains("long_key")); 146 147 // Write a value. 148 mSubject.writeLong("long_key", 9999999999L); 149 150 // Verify value written can be read. 151 assertEquals(9999999999L, mSubject.readLong("long_key")); 152 assertEquals(9999999999L, mSubject.readLong("long_key", 9876543210L)); 153 assertTrue(mSubject.contains("long_key")); 154 155 // Remove the value. 156 mSubject.removeKey("long_key"); 157 158 // Verify the removed value is not returned anymore. 159 assertEquals(0, mSubject.readLong("long_key")); 160 assertFalse(mSubject.contains("long_key")); 161 } 162 163 @Test 164 @SmallTest testWriteReadFloat()165 public void testWriteReadFloat() { 166 // Verify default return values when no value is written. 167 assertEquals(1.5f, mSubject.readFloat("float_key", 1.5f), 0.001f); 168 assertFalse(mSubject.contains("float_key")); 169 170 // Write a value. 171 mSubject.writeFloat("float_key", 42.42f); 172 173 // Verify value written can be read. 174 assertEquals(42.42f, mSubject.readFloat("float_key", 1.5f), 0.001f); 175 assertTrue(mSubject.contains("float_key")); 176 177 // Remove the value. 178 mSubject.removeKey("float_key"); 179 180 // Verify the removed value is not returned anymore. 181 assertEquals(1.5f, mSubject.readFloat("float_key", 1.5f), 0.001f); 182 assertFalse(mSubject.contains("float_key")); 183 } 184 185 @Test 186 @SmallTest testWriteReadDouble()187 public void testWriteReadDouble() { 188 // Verify default return values when no value is written. 189 assertEquals(1.5d, mSubject.readDouble("double_key", 1.5d), 0.001f); 190 assertFalse(mSubject.contains("double_key")); 191 192 // Write a value. 193 mSubject.writeDouble("double_key", 42.42f); 194 195 // Verify value written can be read. 196 assertEquals(42.42d, mSubject.readDouble("double_key", 1.5d), 0.001f); 197 assertTrue(mSubject.contains("double_key")); 198 199 // Remove the value. 200 mSubject.removeKey("double_key"); 201 202 // Verify the removed value is not returned anymore. 203 assertEquals(1.5d, mSubject.readDouble("double_key", 1.5d), 0.001f); 204 assertFalse(mSubject.contains("double_key")); 205 } 206 207 @Test 208 @SmallTest testWriteReadStringSet()209 public void testWriteReadStringSet() { 210 Set<String> defaultStringSet = new HashSet<>(Arrays.asList("a", "b", "c")); 211 Set<String> exampleStringSet = new HashSet<>(Arrays.asList("d", "e")); 212 213 // Verify default return values when no value is written. 214 assertEquals(Collections.emptySet(), mSubject.readStringSet("string_set_key")); 215 assertEquals(defaultStringSet, mSubject.readStringSet("string_set_key", defaultStringSet)); 216 assertNull(mSubject.readStringSet("string_set_key", null)); 217 assertFalse(mSubject.contains("string_set_key")); 218 219 // Write a value. 220 mSubject.writeStringSet("string_set_key", exampleStringSet); 221 222 // Verify value written can be read. 223 assertEquals(exampleStringSet, mSubject.readStringSet("string_set_key")); 224 assertEquals(exampleStringSet, mSubject.readStringSet("string_set_key", defaultStringSet)); 225 assertEquals(exampleStringSet, mSubject.readStringSet("string_set_key", null)); 226 assertTrue(mSubject.contains("string_set_key")); 227 228 // Remove the value. 229 mSubject.removeKey("string_set_key"); 230 231 // Verify the removed value is not returned anymore. 232 assertEquals(Collections.emptySet(), mSubject.readStringSet("string_set_key")); 233 assertFalse(mSubject.contains("string_set_key")); 234 } 235 236 @Test 237 @SmallTest testAddToStringSet()238 public void testAddToStringSet() { 239 mSubject.writeStringSet("string_set_key", new HashSet<>(Collections.singletonList("bar"))); 240 mSubject.addToStringSet("string_set_key", "foo"); 241 242 assertEquals( 243 new HashSet<>(Arrays.asList("foo", "bar")), 244 mSubject.readStringSet("string_set_key")); 245 } 246 247 @Test 248 @SmallTest testAddToStringSetDefault()249 public void testAddToStringSetDefault() { 250 mSubject.addToStringSet("string_set_key", "foo"); 251 252 assertEquals( 253 new HashSet<>(Collections.singletonList("foo")), 254 mSubject.readStringSet("string_set_key")); 255 } 256 257 @Test 258 @SmallTest testRemoveFromStringSet()259 public void testRemoveFromStringSet() { 260 mSubject.writeStringSet("string_set_key", new HashSet<>(Arrays.asList("foo", "bar"))); 261 mSubject.removeFromStringSet("string_set_key", "foo"); 262 263 assertEquals( 264 new HashSet<>(Collections.singletonList("bar")), 265 mSubject.readStringSet("string_set_key")); 266 } 267 268 @Test 269 @SmallTest testRemoveFromStringSetDefault()270 public void testRemoveFromStringSetDefault() { 271 mSubject.removeFromStringSet("string_set_key", "foo"); 272 273 assertEquals(Collections.emptySet(), mSubject.readStringSet("string_set_key")); 274 } 275 276 @Test(expected = UnsupportedOperationException.class) 277 @SmallTest testReadStringSet_nonEmpty_returnsUnmodifiable()278 public void testReadStringSet_nonEmpty_returnsUnmodifiable() { 279 Set<String> exampleStringSet = new HashSet<>(Arrays.asList("d", "e")); 280 mSubject.writeStringSet("string_set_key", exampleStringSet); 281 282 Set<String> unmodifiableSet = mSubject.readStringSet("string_set_key"); 283 284 // Should throw an exception 285 unmodifiableSet.add("f"); 286 } 287 288 @Test 289 @SmallTest testWriteIntSync()290 public void testWriteIntSync() throws InterruptedException { 291 // Verify default return values when no value is written. 292 assertEquals(0, mSubject.readInt("int_key")); 293 294 // Write a value on a background thread. 295 Thread t = new Thread(() -> mSubject.writeIntSync("int_key", 123)); 296 t.start(); 297 t.join(); 298 299 // Verify value written can be read. 300 assertEquals(123, mSubject.readInt("int_key")); 301 } 302 303 @Test 304 @SmallTest testWriteBooleanSync()305 public void testWriteBooleanSync() throws InterruptedException { 306 // Verify default return values when no value is written. 307 assertEquals(false, mSubject.readBoolean("bool_key", false)); 308 309 // Write a value on a background thread. 310 Thread t = new Thread(() -> mSubject.writeBooleanSync("bool_key", true)); 311 t.start(); 312 t.join(); 313 314 // Verify value written can be read. 315 assertEquals(true, mSubject.readBoolean("bool_key", false)); 316 } 317 318 @Test 319 @SmallTest testWriteStringSync()320 public void testWriteStringSync() throws InterruptedException { 321 // Verify default return values when no value is written. 322 assertEquals("default", mSubject.readString("string_key", "default")); 323 324 // Write a value on a background thread. 325 Thread t = new Thread(() -> mSubject.writeStringSync("string_key", "foo")); 326 t.start(); 327 t.join(); 328 329 // Verify value written can be read. 330 assertEquals("foo", mSubject.readString("string_key", "default")); 331 } 332 333 @Test 334 @SmallTest testWriteLongSync()335 public void testWriteLongSync() throws InterruptedException { 336 // Verify default return values when no value is written. 337 assertEquals(0, mSubject.readLong("long_key")); 338 339 // Write a value on a background thread. 340 Thread t = new Thread(() -> mSubject.writeLongSync("long_key", 9999999999L)); 341 t.start(); 342 t.join(); 343 344 // Verify value written can be read. 345 assertEquals(9999999999L, mSubject.readLong("long_key")); 346 } 347 348 @Test 349 @SmallTest testWriteFloatSync()350 public void testWriteFloatSync() throws InterruptedException { 351 // Verify default return values when no value is written. 352 assertEquals(0f, mSubject.readFloat("float_key", 0f), 0f); 353 354 // Write a value on a background thread. 355 Thread t = new Thread(() -> mSubject.writeFloatSync("float_key", 42.42f)); 356 t.start(); 357 t.join(); 358 359 // Verify value written can be read. 360 assertEquals(42.42f, mSubject.readFloat("float_key", 1.5f), 0.001f); 361 } 362 363 @Test 364 @SmallTest testRemoveKeySync()365 public void testRemoveKeySync() throws InterruptedException { 366 // Write a value. 367 mSubject.writeInt("int_key", 123); 368 assertEquals(123, mSubject.readInt("int_key", 999)); 369 370 // Write the value on a background thread. 371 Thread t = new Thread(() -> mSubject.removeKeySync("int_key")); 372 t.start(); 373 t.join(); 374 375 // Verify value was removed. 376 assertEquals(999, mSubject.readInt("int_key", 999)); 377 } 378 379 @Test 380 @SmallTest testRemoveKeys()381 public void testRemoveKeys() { 382 KeyPrefix otherPrefix = new KeyPrefix("OtherPrefix.*"); 383 384 // Write some values, both prefixes and not prefixed. 385 mSubject.writeInt(PREFIXED_KEY_1, 111); 386 mSubject.writeInt(PREFIXED_KEY_2, 222); 387 mSubject.writeInt(PREFIXED_KEY_3, 333); 388 mSubject.writeInt(otherPrefix.createKey("stemA"), 444); 389 mSubject.writeInt("OtherKey", 555); 390 391 // Remove them 392 mSubject.removeKeysWithPrefix(TEST_PREFIX); 393 394 // Verify only values for the given prefix were removed. 395 assertEquals(0, mSubject.readInt(PREFIXED_KEY_1, 0)); 396 assertEquals(0, mSubject.readInt(PREFIXED_KEY_2, 0)); 397 assertEquals(0, mSubject.readInt(PREFIXED_KEY_3, 0)); 398 assertEquals(444, mSubject.readInt(otherPrefix.createKey("stemA"), 0)); 399 assertEquals(555, mSubject.readInt("OtherKey", 0)); 400 } 401 402 @Test 403 @SmallTest testReadStringsWithPrefix()404 public void testReadStringsWithPrefix() { 405 // Write some values. 406 mSubject.writeString(PREFIXED_KEY_1, "first"); 407 mSubject.writeString(PREFIXED_KEY_2, "second"); 408 mSubject.writeString(PREFIXED_KEY_3, "third"); 409 mSubject.writeString("OtherKey", "fourth"); 410 411 // Verify values written are read with readStringsWithPrefix(). 412 Map<String, String> result = mSubject.readStringsWithPrefix(TEST_PREFIX); 413 assertEquals(3, result.size()); 414 415 assertEquals("first", result.get(PREFIXED_KEY_1)); 416 assertEquals("second", result.get(PREFIXED_KEY_2)); 417 assertEquals("third", result.get(PREFIXED_KEY_3)); 418 } 419 420 @Test 421 @SmallTest testReadIntsWithPrefix()422 public void testReadIntsWithPrefix() { 423 // Write some values. 424 mSubject.writeInt(PREFIXED_KEY_1, 1); 425 mSubject.writeInt(PREFIXED_KEY_2, 2); 426 mSubject.writeInt(PREFIXED_KEY_3, 3); 427 mSubject.writeInt("OtherKey", 4); 428 429 // Verify values written are read with readIntsWithPrefix(). 430 Map<String, Integer> result = mSubject.readIntsWithPrefix(TEST_PREFIX); 431 assertEquals(3, result.size()); 432 assertEquals(1, result.get(PREFIXED_KEY_1).intValue()); 433 assertEquals(2, result.get(PREFIXED_KEY_2).intValue()); 434 assertEquals(3, result.get(PREFIXED_KEY_3).intValue()); 435 } 436 437 @Test 438 @SmallTest testReadLongsWithPrefix()439 public void testReadLongsWithPrefix() { 440 // Write some values. 441 mSubject.writeLong(PREFIXED_KEY_1, 21474836470001L); 442 mSubject.writeLong(PREFIXED_KEY_2, 21474836470002L); 443 mSubject.writeLong(PREFIXED_KEY_3, 21474836470003L); 444 mSubject.writeLong("OtherKey", 21474836470004L); 445 446 // Verify values written are read with readLongsWithPrefix(). 447 Map<String, Long> result = mSubject.readLongsWithPrefix(TEST_PREFIX); 448 assertEquals(3, result.size()); 449 assertEquals(21474836470001L, result.get(PREFIXED_KEY_1).longValue()); 450 assertEquals(21474836470002L, result.get(PREFIXED_KEY_2).longValue()); 451 assertEquals(21474836470003L, result.get(PREFIXED_KEY_3).longValue()); 452 } 453 454 @Test 455 @SmallTest testReadFloatsWithPrefix()456 public void testReadFloatsWithPrefix() { 457 // Write some values. 458 mSubject.writeFloat(PREFIXED_KEY_1, 1.0f); 459 mSubject.writeFloat(PREFIXED_KEY_2, 2.5f); 460 mSubject.writeFloat(PREFIXED_KEY_3, 3.5f); 461 mSubject.writeFloat("OtherKey", 4.0f); 462 463 // Verify values written are read with readFloatsWithPrefix(). 464 Map<String, Float> result = mSubject.readFloatsWithPrefix(TEST_PREFIX); 465 assertEquals(3, result.size()); 466 assertEquals(1.0f, result.get(PREFIXED_KEY_1), 1e-10); 467 assertEquals(2.5f, result.get(PREFIXED_KEY_2), 1e-10); 468 assertEquals(3.5f, result.get(PREFIXED_KEY_3), 1e-10); 469 } 470 471 @Test 472 @SmallTest testReadDoublesWithPrefix()473 public void testReadDoublesWithPrefix() { 474 // Write some values. 475 mSubject.writeDouble(PREFIXED_KEY_1, 1.0); 476 mSubject.writeDouble(PREFIXED_KEY_2, 2.5); 477 mSubject.writeDouble(PREFIXED_KEY_3, 3.5); 478 mSubject.writeDouble("OtherKey", 4.0); 479 480 // Verify values written are read with readDoublesWithPrefix(). 481 Map<String, Double> result = mSubject.readDoublesWithPrefix(TEST_PREFIX); 482 assertEquals(3, result.size()); 483 assertEquals(1.0, result.get(PREFIXED_KEY_1), 1e-10); 484 assertEquals(2.5, result.get(PREFIXED_KEY_2), 1e-10); 485 assertEquals(3.5, result.get(PREFIXED_KEY_3).doubleValue(), 1e-10); 486 } 487 488 @Test 489 @SmallTest testReadBooleansWithPrefix()490 public void testReadBooleansWithPrefix() { 491 // Write some values. 492 mSubject.writeBoolean(PREFIXED_KEY_1, true); 493 mSubject.writeBoolean(PREFIXED_KEY_2, false); 494 mSubject.writeBoolean(PREFIXED_KEY_3, true); 495 mSubject.writeBoolean("OtherKey", true); 496 497 // Verify values written are read with readBooleansWithPrefix(). 498 Map<String, Boolean> result = mSubject.readBooleansWithPrefix(TEST_PREFIX); 499 assertEquals(3, result.size()); 500 assertTrue(result.get(PREFIXED_KEY_1)); 501 assertFalse(result.get(PREFIXED_KEY_2)); 502 assertTrue(result.get(PREFIXED_KEY_3)); 503 } 504 505 @Test 506 @SmallTest testCheckerIsCalled()507 public void testCheckerIsCalled() { 508 mSubject.writeInt("int_key", 123); 509 verify(mChecker, times(1)).checkIsKeyInUse(eq("int_key")); 510 mSubject.readInt("int_key"); 511 verify(mChecker, times(2)).checkIsKeyInUse(eq("int_key")); 512 mSubject.incrementInt("int_key"); 513 verify(mChecker, times(3)).checkIsKeyInUse(eq("int_key")); 514 515 mSubject.writeBoolean("bool_key", true); 516 verify(mChecker, times(1)).checkIsKeyInUse(eq("bool_key")); 517 mSubject.readBoolean("bool_key", false); 518 verify(mChecker, times(2)).checkIsKeyInUse(eq("bool_key")); 519 520 mSubject.writeString("string_key", "foo"); 521 verify(mChecker, times(1)).checkIsKeyInUse(eq("string_key")); 522 mSubject.readString("string_key", ""); 523 verify(mChecker, times(2)).checkIsKeyInUse(eq("string_key")); 524 525 mSubject.writeLong("long_key", 999L); 526 verify(mChecker, times(1)).checkIsKeyInUse(eq("long_key")); 527 mSubject.readLong("long_key"); 528 verify(mChecker, times(2)).checkIsKeyInUse(eq("long_key")); 529 530 mSubject.writeFloat("float_key", 2.5f); 531 verify(mChecker, times(1)).checkIsKeyInUse(eq("float_key")); 532 mSubject.readFloat("float_key", 0f); 533 verify(mChecker, times(2)).checkIsKeyInUse(eq("float_key")); 534 535 mSubject.writeDouble("double_key", 2.5d); 536 verify(mChecker, times(1)).checkIsKeyInUse(eq("double_key")); 537 mSubject.readDouble("double_key", 0d); 538 verify(mChecker, times(2)).checkIsKeyInUse(eq("double_key")); 539 540 mSubject.writeStringSet("string_set_key", new HashSet<>()); 541 verify(mChecker, times(1)).checkIsKeyInUse(eq("string_set_key")); 542 mSubject.readStringSet("string_set_key"); 543 verify(mChecker, times(2)).checkIsKeyInUse(eq("string_set_key")); 544 mSubject.addToStringSet("string_set_key", "bar"); 545 verify(mChecker, times(3)).checkIsKeyInUse(eq("string_set_key")); 546 mSubject.removeFromStringSet("string_set_key", "bar"); 547 verify(mChecker, times(4)).checkIsKeyInUse(eq("string_set_key")); 548 549 mSubject.removeKey("some_key"); 550 verify(mChecker, times(1)).checkIsKeyInUse(eq("some_key")); 551 mSubject.contains("some_key"); 552 verify(mChecker, times(2)).checkIsKeyInUse(eq("some_key")); 553 554 mSubject.readBooleansWithPrefix(TEST_PREFIX); 555 verify(mChecker, times(1)).checkIsPrefixInUse(eq(TEST_PREFIX)); 556 mSubject.readIntsWithPrefix(TEST_PREFIX); 557 verify(mChecker, times(2)).checkIsPrefixInUse(eq(TEST_PREFIX)); 558 mSubject.readLongsWithPrefix(TEST_PREFIX); 559 verify(mChecker, times(3)).checkIsPrefixInUse(eq(TEST_PREFIX)); 560 mSubject.readFloatsWithPrefix(TEST_PREFIX); 561 verify(mChecker, times(4)).checkIsPrefixInUse(eq(TEST_PREFIX)); 562 mSubject.readDoublesWithPrefix(TEST_PREFIX); 563 verify(mChecker, times(5)).checkIsPrefixInUse(eq(TEST_PREFIX)); 564 mSubject.readStringsWithPrefix(TEST_PREFIX); 565 verify(mChecker, times(6)).checkIsPrefixInUse(eq(TEST_PREFIX)); 566 mSubject.removeKeysWithPrefix(TEST_PREFIX); 567 verify(mChecker, times(7)).checkIsPrefixInUse(eq(TEST_PREFIX)); 568 } 569 } 570