OSDN Git Service

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