OSDN Git Service

Merge "Zen Condition text and primary click changes"
[android-x86/packages-apps-Settings.git] / tests / robotests / src / com / android / settings / dashboard / DashboardDataTest.java
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 com.android.settings.dashboard;
18
19 import static com.android.settings.dashboard.DashboardData.STABLE_ID_CONDITION_CONTAINER;
20 import static com.android.settings.dashboard.DashboardData.STABLE_ID_CONDITION_FOOTER;
21 import static com.android.settings.dashboard.DashboardData.STABLE_ID_SUGGESTION_CONTAINER;
22 import static com.android.settings.dashboard.DashboardData.STABLE_ID_SUGGESTION_CONDITION_DIVIDER;
23 import static com.google.common.truth.Truth.assertThat;
24 import static org.mockito.Mockito.mock;
25 import static org.mockito.Mockito.when;
26
27 import android.app.PendingIntent;
28 import android.service.settings.suggestions.Suggestion;
29 import android.support.annotation.NonNull;
30 import android.support.v7.util.DiffUtil;
31 import android.support.v7.util.ListUpdateCallback;
32
33 import com.android.settings.TestConfig;
34 import com.android.settings.dashboard.conditional.AirplaneModeCondition;
35 import com.android.settings.dashboard.conditional.Condition;
36 import com.android.settingslib.drawer.DashboardCategory;
37 import com.android.settingslib.drawer.Tile;
38
39 import org.junit.Before;
40 import org.junit.Test;
41 import org.junit.runner.RunWith;
42 import org.mockito.Mock;
43 import org.mockito.MockitoAnnotations;
44 import org.robolectric.RobolectricTestRunner;
45 import org.robolectric.annotation.Config;
46
47 import java.util.ArrayList;
48 import java.util.Arrays;
49 import java.util.Collections;
50 import java.util.List;
51 import java.util.Objects;
52
53 @RunWith(RobolectricTestRunner.class)
54 @Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
55 public class DashboardDataTest {
56     private static final String TEST_SUGGESTION_TITLE = "Use fingerprint";
57     private static final String TEST_CATEGORY_TILE_TITLE = "Display";
58
59     private DashboardData mDashboardDataWithOneConditions;
60     private DashboardData mDashboardDataWithTwoConditions;
61     private DashboardData mDashboardDataWithNoItems;
62     private DashboardCategory mDashboardCategory;
63     @Mock
64     private Tile mTestCategoryTile;
65     @Mock
66     private Condition mTestCondition;
67     @Mock
68     private Condition mSecondCondition; // condition used to test insert in DiffUtil
69     private Suggestion mTestSuggestion;
70
71     @Before
72     public void SetUp() {
73         MockitoAnnotations.initMocks(this);
74
75         mDashboardCategory = new DashboardCategory();
76
77         // Build suggestions
78         final List<Suggestion> suggestions = new ArrayList<>();
79         mTestSuggestion = new Suggestion.Builder("pkg")
80                 .setTitle(TEST_SUGGESTION_TITLE)
81                 .setPendingIntent(mock(PendingIntent.class))
82                 .build();
83         suggestions.add(mTestSuggestion);
84
85         // Build oneItemConditions
86         final List<Condition> oneItemConditions = new ArrayList<>();
87         when(mTestCondition.shouldShow()).thenReturn(true);
88         oneItemConditions.add(mTestCondition);
89
90         // Build twoItemConditions
91         final List<Condition> twoItemsConditions = new ArrayList<>();
92         when(mSecondCondition.shouldShow()).thenReturn(true);
93         twoItemsConditions.add(mTestCondition);
94         twoItemsConditions.add(mSecondCondition);
95
96         // Build category
97         mTestCategoryTile.title = TEST_CATEGORY_TILE_TITLE;
98         mDashboardCategory.title = "test";
99
100         mDashboardCategory.addTile(mTestCategoryTile);
101
102         // Build DashboardData
103         mDashboardDataWithOneConditions = new DashboardData.Builder()
104                 .setConditions(oneItemConditions)
105                 .setCategory(mDashboardCategory)
106                 .setSuggestions(suggestions)
107                 .setConditionExpanded(true)
108                 .build();
109
110         mDashboardDataWithTwoConditions = new DashboardData.Builder()
111                 .setConditions(twoItemsConditions)
112                 .setCategory(mDashboardCategory)
113                 .setSuggestions(suggestions)
114                 .setConditionExpanded(true)
115                 .build();
116
117         mDashboardDataWithNoItems = new DashboardData.Builder()
118                 .setConditions(null)
119                 .setCategory(null)
120                 .setSuggestions(null)
121                 .build();
122     }
123
124     @Test
125     public void testBuildItemsData_shouldSetstableId() {
126         final List<DashboardData.Item> items = mDashboardDataWithOneConditions.getItemList();
127
128         // suggestion, seperator, condition, footer, 1 tile
129         assertThat(items).hasSize(5);
130
131         assertThat(items.get(0).id).isEqualTo(STABLE_ID_SUGGESTION_CONTAINER);
132         assertThat(items.get(1).id).isEqualTo(STABLE_ID_SUGGESTION_CONDITION_DIVIDER);
133         assertThat(items.get(2).id).isEqualTo(STABLE_ID_CONDITION_CONTAINER);
134         assertThat(items.get(3).id).isEqualTo(STABLE_ID_CONDITION_FOOTER);
135         assertThat(items.get(4).id).isEqualTo(Objects.hash(mTestCategoryTile.title));
136     }
137
138     @Test
139     public void testBuildItemsData_containsAllData() {
140         final Object[] expectedObjects = {
141                 mDashboardDataWithOneConditions.getSuggestions(),
142                 null /* divider */,
143                 mDashboardDataWithOneConditions.getConditions(),
144                 null /* footer */, mTestCategoryTile};
145         final int expectedSize = expectedObjects.length;
146
147         assertThat(mDashboardDataWithOneConditions.getItemList()).hasSize(expectedSize);
148
149         for (int i = 0; i < expectedSize; i++) {
150             final Object item = mDashboardDataWithOneConditions.getItemEntityByPosition(i);
151             if (item instanceof List) {
152                 assertThat(item).isEqualTo(expectedObjects[i]);
153             } else if (item instanceof DashboardData.ConditionHeaderData) {
154                 DashboardData.ConditionHeaderData i1 =
155                         (DashboardData.ConditionHeaderData) item;
156                 DashboardData.ConditionHeaderData i2 =
157                         (DashboardData.ConditionHeaderData) expectedObjects[i];
158                 assertThat(i1.title).isEqualTo(i2.title);
159                 assertThat(i1.conditionCount).isEqualTo(i2.conditionCount);
160             } else {
161                 assertThat(item).isSameAs(expectedObjects[i]);
162             }
163         }
164     }
165
166     @Test
167     public void testGetPositionByEntity_selfInstance_returnPositionFound() {
168         final int position = mDashboardDataWithOneConditions
169                 .getPositionByEntity(mDashboardDataWithOneConditions.getConditions());
170         assertThat(position).isNotEqualTo(DashboardData.POSITION_NOT_FOUND);
171     }
172
173     @Test
174     public void testGetPositionByEntity_notExisted_returnNotFound() {
175         final Condition condition = mock(AirplaneModeCondition.class);
176         final int position = mDashboardDataWithOneConditions.getPositionByEntity(condition);
177         assertThat(position).isEqualTo(DashboardData.POSITION_NOT_FOUND);
178     }
179
180     @Test
181     public void testGetPositionByTile_selfInstance_returnPositionFound() {
182         final int position = mDashboardDataWithOneConditions
183                 .getPositionByTile(mTestCategoryTile);
184         assertThat(position).isNotEqualTo(DashboardData.POSITION_NOT_FOUND);
185     }
186
187     @Test
188     public void testGetPositionByTile_equalTitle_returnPositionFound() {
189         final Tile tile = mock(Tile.class);
190         tile.title = TEST_CATEGORY_TILE_TITLE;
191         final int position = mDashboardDataWithOneConditions.getPositionByTile(tile);
192         assertThat(position).isNotEqualTo(DashboardData.POSITION_NOT_FOUND);
193     }
194
195     @Test
196     public void testGetPositionByTile_notExisted_returnNotFound() {
197         final Tile tile = mock(Tile.class);
198         tile.title = "";
199         final int position = mDashboardDataWithOneConditions.getPositionByTile(tile);
200         assertThat(position).isEqualTo(DashboardData.POSITION_NOT_FOUND);
201     }
202
203     @Test
204     public void testDiffUtil_DataEqual_noResultData() {
205         List<ListUpdateResult.ResultData> testResultData = new ArrayList<>();
206         testDiffUtil(mDashboardDataWithOneConditions,
207                 mDashboardDataWithOneConditions, testResultData);
208     }
209
210     @Test
211     public void testDiffUtil_InsertOneCondition_ResultDataOneChanged() {
212         //Build testResultData
213         final List<ListUpdateResult.ResultData> testResultData = new ArrayList<>();
214         // Item in position 3 is the condition container containing the list of conditions, which
215         // gets 1 more item
216         testResultData.add(new ListUpdateResult.ResultData(
217                 ListUpdateResult.ResultData.TYPE_OPERATION_CHANGE, 2, 1));
218
219         testDiffUtil(mDashboardDataWithOneConditions,
220                 mDashboardDataWithTwoConditions, testResultData);
221     }
222
223     @Test
224     public void testDiffUtil_RemoveOneSuggestion_causeItemRemoveAndChange() {
225         //Build testResultData
226         final List<ListUpdateResult.ResultData> testResultData = new ArrayList<>();
227         // removed suggestion and the divider
228         testResultData.add(new ListUpdateResult.ResultData(
229                 ListUpdateResult.ResultData.TYPE_OPERATION_REMOVE, 0, 2));
230         testResultData.add(new ListUpdateResult.ResultData(
231                 ListUpdateResult.ResultData.TYPE_OPERATION_CHANGE, 2, 1));
232         // Build DashboardData
233         final List<Condition> oneItemConditions = new ArrayList<>();
234         when(mTestCondition.shouldShow()).thenReturn(true);
235         oneItemConditions.add(mTestCondition);
236         final List<Suggestion> suggestions = new ArrayList<>();
237         suggestions.add(mTestSuggestion);
238
239         final DashboardData oldData = new DashboardData.Builder()
240                 .setConditions(oneItemConditions)
241                 .setCategory(mDashboardCategory)
242                 .setSuggestions(suggestions)
243                 .setConditionExpanded(false)
244                 .build();
245         final DashboardData newData = new DashboardData.Builder()
246                 .setConditions(oneItemConditions)
247                 .setSuggestions(null)
248                 .setCategory(mDashboardCategory)
249                 .setConditionExpanded(false)
250                 .build();
251
252         testDiffUtil(oldData, newData, testResultData);
253     }
254
255     @Test
256     public void testDiffUtil_DeleteAllData_ResultDataOneDeleted() {
257         //Build testResultData
258         final List<ListUpdateResult.ResultData> testResultData = new ArrayList<>();
259         testResultData.add(new ListUpdateResult.ResultData(
260                 ListUpdateResult.ResultData.TYPE_OPERATION_REMOVE, 0, 5));
261
262         testDiffUtil(mDashboardDataWithOneConditions, mDashboardDataWithNoItems, testResultData);
263     }
264
265     @Test
266     public void testDiffUtil_typeSuggestedContainer_ResultDataNothingChanged() {
267         //Build testResultData
268         final List<ListUpdateResult.ResultData> testResultData = new ArrayList<>();
269
270         DashboardData prevData = new DashboardData.Builder()
271                 .setConditions(null)
272                 .setCategory(null)
273                 .setSuggestions(Arrays.asList(mTestSuggestion))
274                 .build();
275         DashboardData currentData = new DashboardData.Builder()
276                 .setConditions(null)
277                 .setCategory(null)
278                 .setSuggestions(Arrays.asList(mTestSuggestion))
279                 .build();
280         testDiffUtil(prevData, currentData, testResultData);
281     }
282
283     /**
284      * Test when using the
285      * {@link com.android.settings.dashboard.DashboardData.ItemsDataDiffCallback}
286      * to transfer List from {@paramref baseDashboardData} to {@paramref diffDashboardData}, whether
287      * the transform data result is equals to {@paramref testResultData}
288      * <p>
289      * The steps are described below:
290      * 1. Calculate a {@link android.support.v7.util.DiffUtil.DiffResult} from
291      * {@paramref baseDashboardData} to {@paramref diffDashboardData}
292      * <p>
293      * 2. Dispatch the {@link android.support.v7.util.DiffUtil.DiffResult} calculated from step 1
294      * into {@link ListUpdateResult}
295      * <p>
296      * 3. Get result data(a.k.a. baseResultData) from {@link ListUpdateResult} and compare it to
297      * {@paramref testResultData}
298      * <p>
299      * Because baseResultData and {@paramref testResultData} don't have sequence. When do the
300      * comparison, we will sort them first and then compare the inside data from them one by one.
301      */
302     private void testDiffUtil(DashboardData baseDashboardData, DashboardData diffDashboardData,
303             List<ListUpdateResult.ResultData> testResultData) {
304         final DiffUtil.DiffResult diffUtilResult = DiffUtil.calculateDiff(
305                 new DashboardData.ItemsDataDiffCallback(
306                         baseDashboardData.getItemList(), diffDashboardData.getItemList()));
307
308         // Dispatch to listUpdateResult, then listUpdateResult will have result data
309         final ListUpdateResult listUpdateResult = new ListUpdateResult();
310         diffUtilResult.dispatchUpdatesTo(listUpdateResult);
311
312         final List<ListUpdateResult.ResultData> baseResultData = listUpdateResult.getResultData();
313         assertThat(testResultData.size()).isEqualTo(baseResultData.size());
314
315         // Sort them so we can compare them one by one using a for loop
316         Collections.sort(baseResultData);
317         Collections.sort(testResultData);
318         final int size = baseResultData.size();
319         for (int i = 0; i < size; i++) {
320             // Refer to equals method in ResultData
321             assertThat(baseResultData.get(i)).isEqualTo(testResultData.get(i));
322         }
323     }
324
325     /**
326      * This class contains the result about how the changes made to convert one
327      * list to another list. It implements ListUpdateCallback to record the result data.
328      */
329     private static class ListUpdateResult implements ListUpdateCallback {
330         final private List<ResultData> mResultData;
331
332         public ListUpdateResult() {
333             mResultData = new ArrayList<>();
334         }
335
336         public List<ResultData> getResultData() {
337             return mResultData;
338         }
339
340         @Override
341         public void onInserted(int position, int count) {
342             mResultData.add(new ResultData(ResultData.TYPE_OPERATION_INSERT, position, count));
343         }
344
345         @Override
346         public void onRemoved(int position, int count) {
347             mResultData.add(new ResultData(ResultData.TYPE_OPERATION_REMOVE, position, count));
348         }
349
350         @Override
351         public void onMoved(int fromPosition, int toPosition) {
352             mResultData.add(
353                     new ResultData(ResultData.TYPE_OPERATION_MOVE, fromPosition, toPosition));
354         }
355
356         @Override
357         public void onChanged(int position, int count, Object payload) {
358             mResultData.add(new ResultData(ResultData.TYPE_OPERATION_CHANGE, position, count));
359         }
360
361         /**
362          * This class contains general type and field to record the operation data generated
363          * in {@link ListUpdateCallback}. Please refer to {@link ListUpdateCallback} for more info.
364          * <p>
365          * The following are examples about the data stored in this class:
366          * <p>
367          * "The data starts from position(arg1) with count number(arg2) is changed(operation)"
368          * or "The data is moved(operation) from position1(arg1) to position2(arg2)"
369          */
370         private static class ResultData implements Comparable<ResultData> {
371             public static final int TYPE_OPERATION_INSERT = 0;
372             public static final int TYPE_OPERATION_REMOVE = 1;
373             public static final int TYPE_OPERATION_MOVE = 2;
374             public static final int TYPE_OPERATION_CHANGE = 3;
375
376             public final int operation;
377             public final int arg1;
378             public final int arg2;
379
380             public ResultData(int operation, int arg1, int arg2) {
381                 this.operation = operation;
382                 this.arg1 = arg1;
383                 this.arg2 = arg2;
384             }
385
386             @Override
387             public boolean equals(Object obj) {
388                 if (this == obj) {
389                     return true;
390                 }
391
392                 if (!(obj instanceof ResultData)) {
393                     return false;
394                 }
395
396                 ResultData targetData = (ResultData) obj;
397
398                 return operation == targetData.operation && arg1 == targetData.arg1
399                         && arg2 == targetData.arg2;
400             }
401
402             @Override
403             public int compareTo(@NonNull ResultData resultData) {
404                 if (this.operation != resultData.operation) {
405                     return operation - resultData.operation;
406                 }
407
408                 if (arg1 != resultData.arg1) {
409                     return arg1 - resultData.arg1;
410                 }
411
412                 return arg2 - resultData.arg2;
413             }
414
415             @Override
416             public String toString() {
417                 return "op:" + operation + ",arg1:" + arg1 + ",arg2:" + arg2;
418             }
419         }
420     }
421 }