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