1 /* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License 15 */ 16 17 package android.preference2.cts; 18 19 import static org.junit.Assert.assertEquals; 20 import static org.junit.Assert.assertNotNull; 21 import static org.junit.Assert.assertNull; 22 import static org.junit.Assert.assertTrue; 23 import static org.mockito.AdditionalMatchers.or; 24 import static org.mockito.Matchers.any; 25 import static org.mockito.Matchers.anyBoolean; 26 import static org.mockito.Matchers.anyFloat; 27 import static org.mockito.Matchers.anyInt; 28 import static org.mockito.Matchers.anyLong; 29 import static org.mockito.Matchers.anyString; 30 import static org.mockito.Matchers.eq; 31 import static org.mockito.Matchers.isNull; 32 import static org.mockito.Matchers.nullable; 33 import static org.mockito.Mockito.atLeast; 34 import static org.mockito.Mockito.atLeastOnce; 35 import static org.mockito.Mockito.mock; 36 import static org.mockito.Mockito.verify; 37 import static org.mockito.Mockito.verifyNoMoreInteractions; 38 import static org.mockito.Mockito.verifyZeroInteractions; 39 import static org.mockito.Mockito.when; 40 41 import android.content.Context; 42 import android.content.SharedPreferences; 43 import android.preference.CheckBoxPreference; 44 import android.preference.Preference; 45 import android.preference.PreferenceDataStore; 46 import android.preference.PreferenceManager; 47 import android.preference.PreferenceScreen; 48 import android.support.test.filters.SmallTest; 49 import android.support.test.rule.ActivityTestRule; 50 import android.support.test.runner.AndroidJUnit4; 51 52 import org.junit.Before; 53 import org.junit.Rule; 54 import org.junit.Test; 55 import org.junit.runner.RunWith; 56 57 import java.util.HashSet; 58 import java.util.Set; 59 60 @SmallTest 61 @RunWith(AndroidJUnit4.class) 62 public class PreferenceDataStoreTest { 63 64 private PreferenceFragmentActivity mActivity; 65 private PreferenceWrapper mPreference; 66 private PreferenceDataStore mDataStore; 67 private PreferenceScreen mScreen; 68 private PreferenceManager mManager; 69 private SharedPreferences mSharedPref; 70 71 private static final String KEY = "TestPrefKey"; 72 private static final String TEST_STR = "Test"; 73 private static final String TEST_DEFAULT_STR = "TestDefault"; 74 private static final String TEST_WRONG_STR = "TestFromSharedPref"; 75 76 @Rule 77 public ActivityTestRule<PreferenceFragmentActivity> mActivityRule = 78 new ActivityTestRule<>(PreferenceFragmentActivity.class); 79 80 81 @Before setup()82 public void setup() { 83 mActivity = mActivityRule.getActivity(); 84 mPreference = new PreferenceWrapper(mActivity); 85 mPreference.setKey(KEY); 86 87 // Assign the Preference to the PreferenceFragment. 88 mScreen = mActivity.prefFragment.getPreferenceManager().createPreferenceScreen(mActivity); 89 mManager = mScreen.getPreferenceManager(); 90 mSharedPref = mManager.getSharedPreferences(); 91 92 mDataStore = mock(PreferenceDataStore.class); 93 94 // Make sure that the key is not present in SharedPreferences to ensure test correctness. 95 mManager.getSharedPreferences().edit().remove(KEY).commit(); 96 } 97 98 @Test testThatDataStoreIsNullByDefault()99 public void testThatDataStoreIsNullByDefault() { 100 Preference preference = new Preference(mActivity); 101 mScreen.addPreference(preference); 102 103 assertNull(preference.getPreferenceDataStore()); 104 assertNotNull(preference.getSharedPreferences()); 105 106 assertNull(mManager.getPreferenceDataStore()); 107 assertNotNull(mManager.getSharedPreferences()); 108 } 109 110 @Test testSetGetOnPreference()111 public void testSetGetOnPreference() { 112 Preference preference = new Preference(mActivity); 113 preference.setPreferenceDataStore(mDataStore); 114 115 assertEquals(mDataStore, preference.getPreferenceDataStore()); 116 assertNull(preference.getSharedPreferences()); 117 } 118 119 @Test testSetGetOnPreferenceManager()120 public void testSetGetOnPreferenceManager() { 121 mManager.setPreferenceDataStore(mDataStore); 122 123 assertEquals(mDataStore, mManager.getPreferenceDataStore()); 124 assertNull(mManager.getSharedPreferences()); 125 } 126 127 @Test testSetOnPreferenceManagerGetOnPreference()128 public void testSetOnPreferenceManagerGetOnPreference() { 129 Preference preference = new Preference(mActivity); 130 mScreen.addPreference(preference); 131 mManager.setPreferenceDataStore(mDataStore); 132 133 assertEquals(mDataStore, preference.getPreferenceDataStore()); 134 assertNull(preference.getSharedPreferences()); 135 } 136 137 @Test testDataStoresHierarchy()138 public void testDataStoresHierarchy() { 139 mPreference.setPreferenceDataStore(mDataStore); 140 PreferenceDataStore secondaryDataStore = mock(PreferenceDataStore.class); 141 mScreen.addPreference(mPreference); 142 mManager.setPreferenceDataStore(secondaryDataStore); 143 mPreference.putString(TEST_STR); 144 145 // Check that the Preference returns the correct data store. 146 assertEquals(mDataStore, mPreference.getPreferenceDataStore()); 147 148 // Check that the secondary data store assigned to the manager was NOT used. 149 verifyZeroInteractions(secondaryDataStore); 150 151 // Check that the primary data store assigned directly to the preference was used. 152 verify(mDataStore, atLeastOnce()).getString(eq(KEY), any()); 153 } 154 155 @Test testPutStringWithDataStoreOnPref()156 public void testPutStringWithDataStoreOnPref() { 157 mPreference.setPreferenceDataStore(mDataStore); 158 mScreen.addPreference(mPreference); 159 putStringTestCommon(); 160 } 161 162 @Test testPutStringWithDataStoreOnMgr()163 public void testPutStringWithDataStoreOnMgr() { 164 mManager.setPreferenceDataStore(mDataStore); 165 mScreen.addPreference(mPreference); 166 putStringTestCommon(); 167 } 168 putStringTestCommon()169 private void putStringTestCommon() { 170 mPreference.putString(TEST_STR); 171 172 verify(mDataStore, atLeast(0)).getString(eq(KEY), nullable(String.class)); 173 verify(mDataStore, atLeastOnce()).putString(eq(KEY), anyString()); 174 verifyNoMoreInteractions(mDataStore); 175 176 // Test that the value was NOT propagated to SharedPreferences. 177 assertNull(mSharedPref.getString(KEY, null)); 178 } 179 180 @Test testGetStringWithDataStoreOnPref()181 public void testGetStringWithDataStoreOnPref() { 182 mPreference.setPreferenceDataStore(mDataStore); 183 mScreen.addPreference(mPreference); 184 mPreference.getString(TEST_STR); 185 verify(mDataStore, atLeastOnce()).getString(eq(KEY), eq(TEST_STR)); 186 } 187 188 @Test testGetStringWithDataStoreOnMgr()189 public void testGetStringWithDataStoreOnMgr() { 190 mManager.setPreferenceDataStore(mDataStore); 191 mScreen.addPreference(mPreference); 192 mPreference.getString(TEST_STR); 193 verify(mDataStore, atLeastOnce()).getString(eq(KEY), eq(TEST_STR)); 194 } 195 196 /** 197 * This test makes sure that when a default value is set to a preference that has a data store 198 * assigned that the default value is correctly propagated to 199 * {@link Preference#onSetInitialValue(boolean, Object)} instead of passing a value from 200 * {@link android.content.SharedPreferences}. We have this test only for String because the 201 * implementation is not dependent on value type so this coverage should be fine. 202 */ 203 @Test testDefaultStringValue()204 public void testDefaultStringValue() { 205 mPreference.setPreferenceDataStore(mDataStore); 206 mPreference.setDefaultValue(TEST_DEFAULT_STR); 207 mSharedPref.edit().putString(KEY, TEST_WRONG_STR).commit(); 208 mScreen.addPreference(mPreference); 209 mSharedPref.edit().remove(KEY).commit(); 210 assertEquals(TEST_DEFAULT_STR, mPreference.defaultValue); 211 } 212 213 /** 214 * Test that the initial value is taken from the data store (before the preference gets assigned 215 * to the preference hierarchy). 216 */ 217 @Test testInitialValueIsFromDataStoreOnPreference()218 public void testInitialValueIsFromDataStoreOnPreference() { 219 when(mDataStore.getBoolean(anyString(), anyBoolean())).thenReturn(true); 220 221 CheckBoxPreference pref = new CheckBoxPreference(mActivityRule.getActivity()); 222 pref.setKey("CheckboxTestPref"); 223 pref.setPreferenceDataStore(mDataStore); 224 225 mScreen.addPreference(pref); 226 227 assertTrue(pref.isChecked()); 228 } 229 230 /** 231 * Test that the initial value is taken from the data store (before the preference gets assigned 232 * to the preference hierarchy). 233 */ 234 @Test testInitialValueIsFromDataStoreOnPreferenceManager()235 public void testInitialValueIsFromDataStoreOnPreferenceManager() { 236 when(mDataStore.getBoolean(anyString(), anyBoolean())).thenReturn(true); 237 mManager.setPreferenceDataStore(mDataStore); 238 239 CheckBoxPreference pref = new CheckBoxPreference(mActivityRule.getActivity()); 240 pref.setKey("CheckboxTestPref"); 241 242 mScreen.addPreference(pref); 243 244 assertTrue(pref.isChecked()); 245 } 246 247 @Test testPutStringSetWithDataStoreOnPref()248 public void testPutStringSetWithDataStoreOnPref() { 249 mPreference.setPreferenceDataStore(mDataStore); 250 mScreen.addPreference(mPreference); 251 putStringSetTestCommon(); 252 } 253 254 @Test testPutStringSetWithDataStoreOnMgr()255 public void testPutStringSetWithDataStoreOnMgr() { 256 mManager.setPreferenceDataStore(mDataStore); 257 mScreen.addPreference(mPreference); 258 putStringSetTestCommon(); 259 } 260 putStringSetTestCommon()261 private void putStringSetTestCommon() { 262 Set<String> testSet = new HashSet<>(); 263 testSet.add(TEST_STR); 264 mPreference.putStringSet(testSet); 265 266 verify(mDataStore, atLeast(0)).getStringSet(eq(KEY), or(isNull(Set.class), any())); 267 verify(mDataStore, atLeastOnce()).putStringSet(eq(KEY), or(isNull(Set.class), any())); 268 verifyNoMoreInteractions(mDataStore); 269 270 // Test that the value was NOT propagated to SharedPreferences. 271 assertNull(mSharedPref.getStringSet(KEY, null)); 272 } 273 274 @Test testGetStringSetWithDataStoreOnPref()275 public void testGetStringSetWithDataStoreOnPref() { 276 mPreference.setPreferenceDataStore(mDataStore); 277 mScreen.addPreference(mPreference); 278 Set<String> testSet = new HashSet<>(); 279 mPreference.getStringSet(testSet); 280 verify(mDataStore, atLeastOnce()).getStringSet(eq(KEY), eq(testSet)); 281 } 282 283 @Test testGetStringSetWithDataStoreOnMgr()284 public void testGetStringSetWithDataStoreOnMgr() { 285 mManager.setPreferenceDataStore(mDataStore); 286 mScreen.addPreference(mPreference); 287 Set<String> testSet = new HashSet<>(); 288 mPreference.getStringSet(testSet); 289 verify(mDataStore, atLeastOnce()).getStringSet(eq(KEY), eq(testSet)); 290 } 291 292 @Test testPutIntWithDataStoreOnPref()293 public void testPutIntWithDataStoreOnPref() { 294 mPreference.setPreferenceDataStore(mDataStore); 295 mScreen.addPreference(mPreference); 296 putIntTestCommon(); 297 } 298 299 @Test testPutIntWithDataStoreOnMgr()300 public void testPutIntWithDataStoreOnMgr() { 301 mManager.setPreferenceDataStore(mDataStore); 302 mScreen.addPreference(mPreference); 303 putIntTestCommon(); 304 } 305 putIntTestCommon()306 private void putIntTestCommon() { 307 mPreference.putInt(1); 308 309 verify(mDataStore, atLeast(0)).getInt(eq(KEY), anyInt()); 310 verify(mDataStore, atLeastOnce()).putInt(eq(KEY), anyInt()); 311 verifyNoMoreInteractions(mDataStore); 312 313 // Test that the value was NOT propagated to SharedPreferences. 314 assertEquals(-1, mSharedPref.getInt(KEY, -1)); 315 } 316 317 @Test testGetIntWithDataStoreOnPref()318 public void testGetIntWithDataStoreOnPref() { 319 mPreference.setPreferenceDataStore(mDataStore); 320 mScreen.addPreference(mPreference); 321 mPreference.getInt(1); 322 verify(mDataStore, atLeastOnce()).getInt(eq(KEY), eq(1)); 323 } 324 325 @Test testGetIntWithDataStoreOnMgr()326 public void testGetIntWithDataStoreOnMgr() { 327 mManager.setPreferenceDataStore(mDataStore); 328 mScreen.addPreference(mPreference); 329 mPreference.getInt(1); 330 verify(mDataStore, atLeastOnce()).getInt(eq(KEY), eq(1)); 331 } 332 333 @Test testPutLongWithDataStoreOnPref()334 public void testPutLongWithDataStoreOnPref() { 335 mPreference.setPreferenceDataStore(mDataStore); 336 mScreen.addPreference(mPreference); 337 putLongTestCommon(); 338 } 339 340 @Test testPutLongWithDataStoreOnMgr()341 public void testPutLongWithDataStoreOnMgr() { 342 mManager.setPreferenceDataStore(mDataStore); 343 mScreen.addPreference(mPreference); 344 putLongTestCommon(); 345 } 346 putLongTestCommon()347 private void putLongTestCommon() { 348 mPreference.putLong(1L); 349 350 verify(mDataStore, atLeast(0)).getLong(eq(KEY), anyLong()); 351 verify(mDataStore, atLeastOnce()).putLong(eq(KEY), anyLong()); 352 verifyNoMoreInteractions(mDataStore); 353 354 // Test that the value was NOT propagated to SharedPreferences. 355 assertEquals(-1, mSharedPref.getLong(KEY, -1L)); 356 } 357 358 @Test testGetLongWithDataStoreOnPref()359 public void testGetLongWithDataStoreOnPref() { 360 mPreference.setPreferenceDataStore(mDataStore); 361 mScreen.addPreference(mPreference); 362 mPreference.getLong(1L); 363 verify(mDataStore, atLeastOnce()).getLong(eq(KEY), eq(1L)); 364 } 365 366 @Test testGetLongWithDataStoreOnMgr()367 public void testGetLongWithDataStoreOnMgr() { 368 mManager.setPreferenceDataStore(mDataStore); 369 mScreen.addPreference(mPreference); 370 mPreference.getLong(1L); 371 verify(mDataStore, atLeastOnce()).getLong(eq(KEY), eq(1L)); 372 } 373 374 @Test testPutFloatWithDataStoreOnPref()375 public void testPutFloatWithDataStoreOnPref() { 376 mPreference.setPreferenceDataStore(mDataStore); 377 mScreen.addPreference(mPreference); 378 putFloatTestCommon(); 379 } 380 381 @Test testPutFloatWithDataStoreOnMgr()382 public void testPutFloatWithDataStoreOnMgr() { 383 mManager.setPreferenceDataStore(mDataStore); 384 mScreen.addPreference(mPreference); 385 putFloatTestCommon(); 386 } 387 putFloatTestCommon()388 private void putFloatTestCommon() { 389 mPreference.putFloat(1f); 390 391 verify(mDataStore, atLeast(0)).getFloat(eq(KEY), anyFloat()); 392 verify(mDataStore, atLeastOnce()).putFloat(eq(KEY), anyFloat()); 393 verifyNoMoreInteractions(mDataStore); 394 395 // Test that the value was NOT propagated to SharedPreferences. 396 assertEquals(-1, mSharedPref.getFloat(KEY, -1f), 0.1f /* epsilon */); 397 } 398 399 @Test testGetFloatWithDataStoreOnPref()400 public void testGetFloatWithDataStoreOnPref() { 401 mPreference.setPreferenceDataStore(mDataStore); 402 mScreen.addPreference(mPreference); 403 mPreference.getFloat(1f); 404 verify(mDataStore, atLeastOnce()).getFloat(eq(KEY), eq(1f)); 405 } 406 407 @Test testGetFloatWithDataStoreOnMgr()408 public void testGetFloatWithDataStoreOnMgr() { 409 mManager.setPreferenceDataStore(mDataStore); 410 mScreen.addPreference(mPreference); 411 mPreference.getFloat(1f); 412 verify(mDataStore, atLeastOnce()).getFloat(eq(KEY), eq(1f)); 413 } 414 415 @Test testPutBooleanWithDataStoreOnPref()416 public void testPutBooleanWithDataStoreOnPref() { 417 mPreference.setPreferenceDataStore(mDataStore); 418 mScreen.addPreference(mPreference); 419 putBooleanTestCommon(); 420 } 421 422 @Test testPutBooleanWithDataStoreOnMgr()423 public void testPutBooleanWithDataStoreOnMgr() { 424 mManager.setPreferenceDataStore(mDataStore); 425 mScreen.addPreference(mPreference); 426 putBooleanTestCommon(); 427 } 428 putBooleanTestCommon()429 private void putBooleanTestCommon() { 430 mPreference.putBoolean(true); 431 432 verify(mDataStore, atLeast(0)).getBoolean(eq(KEY), anyBoolean()); 433 verify(mDataStore, atLeastOnce()).putBoolean(eq(KEY), anyBoolean()); 434 verifyNoMoreInteractions(mDataStore); 435 436 // Test that the value was NOT propagated to SharedPreferences. 437 assertEquals(false, mSharedPref.getBoolean(KEY, false)); 438 } 439 440 @Test testGetBooleanWithDataStoreOnPref()441 public void testGetBooleanWithDataStoreOnPref() { 442 mPreference.setPreferenceDataStore(mDataStore); 443 mScreen.addPreference(mPreference); 444 mPreference.getBoolean(true); 445 verify(mDataStore, atLeastOnce()).getBoolean(eq(KEY), eq(true)); 446 } 447 448 @Test testGetBooleanWithDataStoreOnMgr()449 public void testGetBooleanWithDataStoreOnMgr() { 450 mManager.setPreferenceDataStore(mDataStore); 451 mScreen.addPreference(mPreference); 452 mPreference.getBoolean(true); 453 verify(mDataStore, atLeastOnce()).getBoolean(eq(KEY), eq(true)); 454 } 455 456 /** 457 * When {@link PreferenceDataStore} is NOT assigned, the getter for SharedPreferences should not 458 * return null. 459 */ 460 @Test testSharedPrefNotNullIfNoDS()461 public void testSharedPrefNotNullIfNoDS() { 462 mScreen.addPreference(mPreference); 463 assertNotNull(mPreference.getSharedPreferences()); 464 assertNotNull(mPreference.getEditor()); 465 } 466 467 /** 468 * When {@link PreferenceDataStore} is NOT assigned, the getter for SharedPreferences must not 469 * return null for PreferenceManager. 470 */ 471 @Test testSharedPrefNotNullIfNoDSMgr()472 public void testSharedPrefNotNullIfNoDSMgr() { 473 assertNotNull(mManager.getSharedPreferences()); 474 } 475 476 /** 477 * When {@link PreferenceDataStore} is assigned, the getter for SharedPreferences has to return 478 * null. 479 */ 480 @Test testSharedPrefNullIfWithDS()481 public void testSharedPrefNullIfWithDS() { 482 mScreen.addPreference(mPreference); 483 mPreference.setPreferenceDataStore(mDataStore); 484 assertNull(mPreference.getSharedPreferences()); 485 assertNull(mPreference.getEditor()); 486 } 487 488 /** 489 * When {@link PreferenceDataStore} is assigned, the getter for SharedPreferences has to return 490 * null for PreferenceManager. 491 */ 492 @Test testSharedPrefNullIfWithDSMgr()493 public void testSharedPrefNullIfWithDSMgr() { 494 mManager.setPreferenceDataStore(mDataStore); 495 assertNull(mManager.getSharedPreferences()); 496 } 497 498 /** 499 * Wrapper to allow to easily call protected methods. 500 */ 501 private static class PreferenceWrapper extends Preference { 502 503 Object defaultValue; 504 PreferenceWrapper(Context context)505 PreferenceWrapper(Context context) { 506 super(context); 507 } 508 putString(String value)509 void putString(String value) { 510 persistString(value); 511 } 512 getString(String defaultValue)513 String getString(String defaultValue) { 514 return getPersistedString(defaultValue); 515 } 516 putStringSet(Set<String> values)517 void putStringSet(Set<String> values) { 518 persistStringSet(values); 519 } 520 getStringSet(Set<String> defaultValues)521 Set<String> getStringSet(Set<String> defaultValues) { 522 return getPersistedStringSet(defaultValues); 523 } 524 putInt(int value)525 void putInt(int value) { 526 persistInt(value); 527 } 528 getInt(int defaultValue)529 int getInt(int defaultValue) { 530 return getPersistedInt(defaultValue); 531 } 532 putLong(long value)533 void putLong(long value) { 534 persistLong(value); 535 } 536 getLong(long defaultValue)537 long getLong(long defaultValue) { 538 return getPersistedLong(defaultValue); 539 } 540 putFloat(float value)541 void putFloat(float value) { 542 persistFloat(value); 543 } 544 getFloat(float defaultValue)545 float getFloat(float defaultValue) { 546 return getPersistedFloat(defaultValue); 547 } 548 putBoolean(boolean value)549 void putBoolean(boolean value) { 550 persistBoolean(value); 551 } 552 getBoolean(boolean defaultValue)553 boolean getBoolean(boolean defaultValue) { 554 return getPersistedBoolean(defaultValue); 555 } 556 557 @Override onSetInitialValue(boolean restorePersistedValue, Object defaultValue)558 protected void onSetInitialValue(boolean restorePersistedValue, Object defaultValue) { 559 this.defaultValue = defaultValue; 560 super.onSetInitialValue(restorePersistedValue, defaultValue); 561 } 562 } 563 564 } 565