SelectionManagerTest.java revision b8874fd0df55113d472c6704b91bd493c577caeb
1/*
2 * Copyright (C) 2015 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
17package com.android.documentsui.selection;
18
19import android.support.test.filters.SmallTest;
20import android.support.test.runner.AndroidJUnit4;
21import android.util.SparseBooleanArray;
22
23import com.android.documentsui.dirlist.TestDocumentsAdapter;
24import com.android.documentsui.selection.SelectionManager;
25import com.android.documentsui.dirlist.TestData;
26import com.android.documentsui.selection.Selection;
27import com.android.documentsui.testing.SelectionManagers;
28
29import org.junit.Before;
30import org.junit.Test;
31import org.junit.runner.RunWith;
32
33import java.util.ArrayList;
34import java.util.HashSet;
35import java.util.List;
36import java.util.Set;
37
38@RunWith(AndroidJUnit4.class)
39@SmallTest
40public class SelectionManagerTest {
41
42    private static final List<String> ITEMS = TestData.create(100);
43
44    private final Set<String> mIgnored = new HashSet<>();
45    private TestDocumentsAdapter mAdapter;
46    private SelectionManager mManager;
47    private TestSelectionListener mCallback;
48    private TestItemSelectionListener mItemCallback;
49    private SelectionProbe mSelection;
50
51    @Before
52    public void setUp() throws Exception {
53        mCallback = new TestSelectionListener();
54        mItemCallback = new TestItemSelectionListener();
55        mAdapter = new TestDocumentsAdapter(ITEMS);
56        mManager = SelectionManagers.createTestInstance(
57                mAdapter,
58                SelectionManager.MODE_MULTIPLE,
59                (String id, boolean nextState) -> (!nextState || !mIgnored.contains(id)));
60        mManager.addCallback(mCallback);
61        mManager.addItemCallback(mItemCallback);
62
63        mSelection = new SelectionProbe(mManager, mItemCallback);
64
65        mIgnored.clear();
66    }
67
68    @Test
69    public void testSelection() {
70        // Check selection.
71        mManager.toggleSelection(ITEMS.get(7));
72        mSelection.assertSelection(7);
73        // Check deselection.
74        mManager.toggleSelection(ITEMS.get(7));
75        mSelection.assertNoSelection();
76    }
77
78    @Test
79    public void testSelection_DoNothingOnUnselectableItem() {
80        mIgnored.add(ITEMS.get(7));
81
82        mManager.toggleSelection(ITEMS.get(7));
83        mSelection.assertNoSelection();
84    }
85
86    @Test
87    public void testSelection_NotifiesSelectionChanged() {
88        // Selection should notify.
89        mManager.toggleSelection(ITEMS.get(7));
90        mCallback.assertSelectionChanged();
91        // Deselection should notify.
92        mManager.toggleSelection(ITEMS.get(7));
93        mCallback.assertSelectionChanged();
94    }
95
96    @Test
97    public void testSelection_PersistsOnUpdate() {
98        mManager.toggleSelection(ITEMS.get(7));
99
100        mAdapter.updateTestModelIds(ITEMS);
101
102        mSelection.assertSelection(7);
103    }
104
105    @Test
106    public void testSelection_IntersectsWithNewDataSet() {
107        mManager.toggleSelection(ITEMS.get(99));
108        mManager.toggleSelection(ITEMS.get(7));
109
110        mAdapter.updateTestModelIds(TestData.create(50));
111
112        mSelection.assertSelection(7);
113    }
114
115    @Test
116    public void testSetItemsSelected() {
117        mManager.setItemsSelected(getStringIds(6, 7, 8), true);
118
119        mSelection.assertRangeSelected(6, 8);
120    }
121
122    @Test
123    public void testSetItemsSelected_SkipUnselectableItem() {
124        mIgnored.add(ITEMS.get(7));
125
126        mManager.setItemsSelected(getStringIds(6, 7, 8), true);
127
128        mSelection.assertSelected(6);
129        mSelection.assertNotSelected(7);
130        mSelection.assertSelected(8);
131    }
132
133    @Test
134    public void testRangeSelection() {
135        mManager.startRangeSelection(15);
136        mManager.snapRangeSelection(19);
137        mSelection.assertRangeSelection(15, 19);
138    }
139
140    @Test
141    public void testRangeSelection_SkipUnselectableItem() {
142        mIgnored.add(ITEMS.get(17));
143
144        mManager.startRangeSelection(15);
145        mManager.snapRangeSelection(19);
146
147        mSelection.assertRangeSelected(15, 16);
148        mSelection.assertNotSelected(17);
149        mSelection.assertRangeSelected(18, 19);
150    }
151
152    @Test
153    public void testRangeSelection_snapExpand() {
154        mManager.startRangeSelection(15);
155        mManager.snapRangeSelection(19);
156        mManager.snapRangeSelection(27);
157        mSelection.assertRangeSelection(15, 27);
158    }
159
160    @Test
161    public void testRangeSelection_snapContract() {
162        mManager.startRangeSelection(15);
163        mManager.snapRangeSelection(27);
164        mManager.snapRangeSelection(19);
165        mSelection.assertRangeSelection(15, 19);
166    }
167
168    @Test
169    public void testRangeSelection_snapInvert() {
170        mManager.startRangeSelection(15);
171        mManager.snapRangeSelection(27);
172        mManager.snapRangeSelection(3);
173        mSelection.assertRangeSelection(3, 15);
174    }
175
176    @Test
177    public void testRangeSelection_multiple() {
178        mManager.startRangeSelection(15);
179        mManager.snapRangeSelection(27);
180        mManager.endRangeSelection();
181        mManager.startRangeSelection(42);
182        mManager.snapRangeSelection(57);
183        mSelection.assertSelectionSize(29);
184        mSelection.assertRangeSelected(15, 27);
185        mSelection.assertRangeSelected(42, 57);
186    }
187
188    @Test
189    public void testProvisionalRangeSelection() {
190        mManager.startRangeSelection(13);
191        mManager.snapProvisionalRangeSelection(15);
192        mSelection.assertRangeSelection(13, 15);
193        mManager.getSelection().applyProvisionalSelection();
194        mManager.endRangeSelection();
195        mSelection.assertSelectionSize(3);
196    }
197
198    @Test
199    public void testProvisionalRangeSelection_endEarly() {
200        mManager.startRangeSelection(13);
201        mManager.snapProvisionalRangeSelection(15);
202        mSelection.assertRangeSelection(13, 15);
203
204        mManager.endRangeSelection();
205        // If we end range selection prematurely for provision selection, nothing should be selected
206        // except the first item
207        mSelection.assertSelectionSize(1);
208    }
209
210    @Test
211    public void testProvisionalRangeSelection_snapExpand() {
212        mManager.startRangeSelection(13);
213        mManager.snapProvisionalRangeSelection(15);
214        mSelection.assertRangeSelection(13, 15);
215        mManager.getSelection().applyProvisionalSelection();
216        mManager.snapRangeSelection(18);
217        mSelection.assertRangeSelection(13, 18);
218    }
219
220    @Test
221    public void testCombinationRangeSelection_IntersectsOldSelection() {
222        mManager.startRangeSelection(13);
223        mManager.snapRangeSelection(15);
224        mSelection.assertRangeSelection(13, 15);
225
226        mManager.startRangeSelection(11);
227        mManager.snapProvisionalRangeSelection(18);
228        mSelection.assertRangeSelected(11, 18);
229        mManager.endRangeSelection();
230        mSelection.assertRangeSelected(13, 15);
231        mSelection.assertRangeSelected(11, 11);
232        mSelection.assertSelectionSize(4);
233    }
234
235    @Test
236    public void testProvisionalSelection() {
237        Selection s = mManager.getSelection();
238        mSelection.assertNoSelection();
239
240        // Mimicking band selection case -- BandController notifies item callback by itself.
241        mItemCallback.onItemStateChanged(ITEMS.get(1), true);
242        mItemCallback.onItemStateChanged(ITEMS.get(2), true);
243
244        SparseBooleanArray provisional = new SparseBooleanArray();
245        provisional.append(1, true);
246        provisional.append(2, true);
247        s.setProvisionalSelection(getItemIds(provisional));
248        mSelection.assertSelection(1, 2);
249    }
250
251    @Test
252    public void testProvisionalSelection_Replace() {
253        Selection s = mManager.getSelection();
254
255        // Mimicking band selection case -- BandController notifies item callback by itself.
256        mItemCallback.onItemStateChanged(ITEMS.get(1), true);
257        mItemCallback.onItemStateChanged(ITEMS.get(2), true);
258        SparseBooleanArray provisional = new SparseBooleanArray();
259        provisional.append(1, true);
260        provisional.append(2, true);
261        s.setProvisionalSelection(getItemIds(provisional));
262
263        mItemCallback.onItemStateChanged(ITEMS.get(1), false);
264        mItemCallback.onItemStateChanged(ITEMS.get(2), false);
265        provisional.clear();
266
267        mItemCallback.onItemStateChanged(ITEMS.get(3), true);
268        mItemCallback.onItemStateChanged(ITEMS.get(4), true);
269        provisional.append(3, true);
270        provisional.append(4, true);
271        s.setProvisionalSelection(getItemIds(provisional));
272        mSelection.assertSelection(3, 4);
273    }
274
275    @Test
276    public void testProvisionalSelection_IntersectsExistingProvisionalSelection() {
277        Selection s = mManager.getSelection();
278
279        // Mimicking band selection case -- BandController notifies item callback by itself.
280        mItemCallback.onItemStateChanged(ITEMS.get(1), true);
281        mItemCallback.onItemStateChanged(ITEMS.get(2), true);
282        SparseBooleanArray provisional = new SparseBooleanArray();
283        provisional.append(1, true);
284        provisional.append(2, true);
285        s.setProvisionalSelection(getItemIds(provisional));
286
287        mItemCallback.onItemStateChanged(ITEMS.get(1), false);
288        mItemCallback.onItemStateChanged(ITEMS.get(2), false);
289        provisional.clear();
290
291        mItemCallback.onItemStateChanged(ITEMS.get(1), true);
292        provisional.append(1, true);
293        s.setProvisionalSelection(getItemIds(provisional));
294        mSelection.assertSelection(1);
295    }
296
297    @Test
298    public void testProvisionalSelection_Apply() {
299        Selection s = mManager.getSelection();
300
301        // Mimicking band selection case -- BandController notifies item callback by itself.
302        mItemCallback.onItemStateChanged(ITEMS.get(1), true);
303        mItemCallback.onItemStateChanged(ITEMS.get(2), true);
304        SparseBooleanArray provisional = new SparseBooleanArray();
305        provisional.append(1, true);
306        provisional.append(2, true);
307        s.setProvisionalSelection(getItemIds(provisional));
308        s.applyProvisionalSelection();
309
310        mSelection.assertSelection(1, 2);
311    }
312
313    @Test
314    public void testProvisionalSelection_Cancel() {
315        mManager.toggleSelection(ITEMS.get(1));
316        mManager.toggleSelection(ITEMS.get(2));
317        Selection s = mManager.getSelection();
318
319        SparseBooleanArray provisional = new SparseBooleanArray();
320        provisional.append(3, true);
321        provisional.append(4, true);
322        s.setProvisionalSelection(getItemIds(provisional));
323        s.cancelProvisionalSelection();
324
325        // Original selection should remain.
326        mSelection.assertSelection(1, 2);
327    }
328
329    @Test
330    public void testProvisionalSelection_IntersectsAppliedSelection() {
331        mManager.toggleSelection(ITEMS.get(1));
332        mManager.toggleSelection(ITEMS.get(2));
333        Selection s = mManager.getSelection();
334
335        // Mimicking band selection case -- BandController notifies item callback by itself.
336        mItemCallback.onItemStateChanged(ITEMS.get(3), true);
337        SparseBooleanArray provisional = new SparseBooleanArray();
338        provisional.append(2, true);
339        provisional.append(3, true);
340        s.setProvisionalSelection(getItemIds(provisional));
341        mSelection.assertSelection(1, 2, 3);
342    }
343
344    private static Set<String> getItemIds(SparseBooleanArray selection) {
345        Set<String> ids = new HashSet<>();
346
347        int count = selection.size();
348        for (int i = 0; i < count; ++i) {
349            ids.add(ITEMS.get(selection.keyAt(i)));
350        }
351
352        return ids;
353    }
354
355    private static Iterable<String> getStringIds(int... ids) {
356        List<String> stringIds = new ArrayList<>(ids.length);
357        for (int id : ids) {
358            stringIds.add(ITEMS.get(id));
359        }
360        return stringIds;
361    }
362}
363