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