Home | History | Annotate | Download | only in instrumentation
      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 package com.android.settingslib.core.instrumentation;
     17 
     18 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.ACTION_SETTINGS_PREFERENCE_CHANGE;
     19 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_SETTINGS_PREFERENCE_CHANGE_FLOAT_VALUE;
     20 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_SETTINGS_PREFERENCE_CHANGE_INT_VALUE;
     21 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_SETTINGS_PREFERENCE_CHANGE_NAME;
     22 import static org.mockito.Matchers.any;
     23 import static org.mockito.Matchers.anyInt;
     24 import static org.mockito.Matchers.argThat;
     25 import static org.mockito.Matchers.eq;
     26 import static org.mockito.Mockito.times;
     27 import static org.mockito.Mockito.verify;
     28 
     29 import android.content.Context;
     30 import android.content.SharedPreferences;
     31 import android.util.Pair;
     32 
     33 import com.android.settingslib.SettingsLibRobolectricTestRunner;
     34 
     35 import org.junit.Before;
     36 import org.junit.Test;
     37 import org.junit.runner.RunWith;
     38 import org.mockito.Answers;
     39 import org.mockito.ArgumentMatcher;
     40 import org.mockito.Mock;
     41 import org.mockito.MockitoAnnotations;
     42 
     43 @RunWith(SettingsLibRobolectricTestRunner.class)
     44 public class SharedPreferenceLoggerTest {
     45 
     46     private static final String TEST_TAG = "tag";
     47     private static final String TEST_KEY = "key";
     48 
     49     @Mock(answer = Answers.RETURNS_DEEP_STUBS)
     50     private Context mContext;
     51 
     52     private ArgumentMatcher<Pair<Integer, Object>> mNamePairMatcher;
     53     @Mock
     54     private MetricsFeatureProvider mMetricsFeature;
     55     private SharedPreferencesLogger mSharedPrefLogger;
     56 
     57     @Before
     58     public void init() {
     59         MockitoAnnotations.initMocks(this);
     60         mSharedPrefLogger = new SharedPreferencesLogger(mContext, TEST_TAG, mMetricsFeature);
     61         mNamePairMatcher = pairMatches(FIELD_SETTINGS_PREFERENCE_CHANGE_NAME, String.class);
     62     }
     63 
     64     @Test
     65     public void putInt_shouldNotLogInitialPut() {
     66         final SharedPreferences.Editor editor = mSharedPrefLogger.edit();
     67         editor.putInt(TEST_KEY, 1);
     68         editor.putInt(TEST_KEY, 1);
     69         editor.putInt(TEST_KEY, 1);
     70         editor.putInt(TEST_KEY, 2);
     71         editor.putInt(TEST_KEY, 2);
     72         editor.putInt(TEST_KEY, 2);
     73         editor.putInt(TEST_KEY, 2);
     74 
     75         verify(mMetricsFeature, times(6)).action(any(Context.class), anyInt(),
     76                 argThat(mNamePairMatcher),
     77                 argThat(pairMatches(FIELD_SETTINGS_PREFERENCE_CHANGE_INT_VALUE, Integer.class)));
     78     }
     79 
     80     @Test
     81     public void putBoolean_shouldNotLogInitialPut() {
     82         final SharedPreferences.Editor editor = mSharedPrefLogger.edit();
     83         editor.putBoolean(TEST_KEY, true);
     84         editor.putBoolean(TEST_KEY, true);
     85         editor.putBoolean(TEST_KEY, false);
     86         editor.putBoolean(TEST_KEY, false);
     87         editor.putBoolean(TEST_KEY, false);
     88 
     89 
     90         verify(mMetricsFeature).action(any(Context.class), anyInt(),
     91                 argThat(mNamePairMatcher),
     92                 argThat(pairMatches(FIELD_SETTINGS_PREFERENCE_CHANGE_INT_VALUE, true)));
     93         verify(mMetricsFeature, times(3)).action(any(Context.class), anyInt(),
     94                 argThat(mNamePairMatcher),
     95                 argThat(pairMatches(FIELD_SETTINGS_PREFERENCE_CHANGE_INT_VALUE, false)));
     96     }
     97 
     98     @Test
     99     public void putLong_shouldNotLogInitialPut() {
    100         final SharedPreferences.Editor editor = mSharedPrefLogger.edit();
    101         editor.putLong(TEST_KEY, 1);
    102         editor.putLong(TEST_KEY, 1);
    103         editor.putLong(TEST_KEY, 1);
    104         editor.putLong(TEST_KEY, 1);
    105         editor.putLong(TEST_KEY, 2);
    106 
    107         verify(mMetricsFeature, times(4)).action(any(Context.class), anyInt(),
    108                 argThat(mNamePairMatcher),
    109                 argThat(pairMatches(FIELD_SETTINGS_PREFERENCE_CHANGE_INT_VALUE, Integer.class)));
    110     }
    111 
    112     @Test
    113     public void putLong_biggerThanIntMax_shouldLogIntMax() {
    114         final SharedPreferences.Editor editor = mSharedPrefLogger.edit();
    115         final long veryBigNumber = 500L + Integer.MAX_VALUE;
    116         editor.putLong(TEST_KEY, 1);
    117         editor.putLong(TEST_KEY, veryBigNumber);
    118 
    119         verify(mMetricsFeature).action(any(Context.class), anyInt(),
    120                 argThat(mNamePairMatcher),
    121                 argThat(pairMatches(
    122                         FIELD_SETTINGS_PREFERENCE_CHANGE_INT_VALUE, Integer.MAX_VALUE)));
    123     }
    124 
    125     @Test
    126     public void putLong_smallerThanIntMin_shouldLogIntMin() {
    127         final SharedPreferences.Editor editor = mSharedPrefLogger.edit();
    128         final long veryNegativeNumber = -500L + Integer.MIN_VALUE;
    129         editor.putLong(TEST_KEY, 1);
    130         editor.putLong(TEST_KEY, veryNegativeNumber);
    131 
    132         verify(mMetricsFeature).action(any(Context.class), anyInt(),
    133                 argThat(mNamePairMatcher),
    134                 argThat(pairMatches(
    135                         FIELD_SETTINGS_PREFERENCE_CHANGE_INT_VALUE, Integer.MIN_VALUE)));
    136     }
    137 
    138     @Test
    139     public void putFloat_shouldNotLogInitialPut() {
    140         final SharedPreferences.Editor editor = mSharedPrefLogger.edit();
    141         editor.putFloat(TEST_KEY, 1);
    142         editor.putFloat(TEST_KEY, 1);
    143         editor.putFloat(TEST_KEY, 1);
    144         editor.putFloat(TEST_KEY, 1);
    145         editor.putFloat(TEST_KEY, 2);
    146 
    147         verify(mMetricsFeature, times(4)).action(any(Context.class), anyInt(),
    148                 argThat(mNamePairMatcher),
    149                 argThat(pairMatches(FIELD_SETTINGS_PREFERENCE_CHANGE_FLOAT_VALUE, Float.class)));
    150     }
    151 
    152     @Test
    153     public void logPackage_shouldUseLogPackageApi() {
    154         mSharedPrefLogger.logPackageName("key", "com.android.settings");
    155         verify(mMetricsFeature).action(any(Context.class),
    156                 eq(ACTION_SETTINGS_PREFERENCE_CHANGE),
    157                 eq("com.android.settings"),
    158                 any(Pair.class));
    159     }
    160 
    161     private ArgumentMatcher<Pair<Integer, Object>> pairMatches(int tag, Class clazz) {
    162         return pair -> pair.first == tag && isInstanceOfType(pair.second, clazz);
    163     }
    164 
    165     private ArgumentMatcher<Pair<Integer, Object>> pairMatches(int tag, boolean bool) {
    166         return pair -> pair.first == tag
    167                 && isInstanceOfType(pair.second, Integer.class)
    168                 && pair.second.equals((bool ? 1 : 0));
    169     }
    170 
    171     private ArgumentMatcher<Pair<Integer, Object>> pairMatches(int tag, int val) {
    172         return pair -> pair.first == tag
    173                 && isInstanceOfType(pair.second, Integer.class)
    174                 && pair.second.equals(val);
    175     }
    176 
    177     /** Returns true if the instance is assignable to the type Clazz. */
    178     private static boolean isInstanceOfType(Object instance, Class<?> clazz) {
    179         return clazz.isInstance(instance);
    180     }
    181 }
    182