• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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