Home | History | Annotate | Download | only in selection
      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 
     17 package com.android.documentsui.selection;
     18 import static org.junit.Assert.assertFalse;
     19 
     20 import android.support.test.filters.SmallTest;
     21 import android.support.test.runner.AndroidJUnit4;
     22 import android.util.SparseBooleanArray;
     23 
     24 import com.android.documentsui.selection.SelectionHelper.SelectionPredicate;
     25 import com.android.documentsui.selection.testing.SelectionProbe;
     26 import com.android.documentsui.selection.testing.TestAdapter;
     27 import com.android.documentsui.selection.testing.TestSelectionObserver;
     28 import com.android.documentsui.selection.testing.TestStableIdProvider;
     29 
     30 import org.junit.Before;
     31 import org.junit.Test;
     32 import org.junit.runner.RunWith;
     33 
     34 import java.util.ArrayList;
     35 import java.util.HashSet;
     36 import java.util.List;
     37 import java.util.Set;
     38 
     39 @RunWith(AndroidJUnit4.class)
     40 @SmallTest
     41 public class DefaultSelectionHelperTest {
     42 
     43     private List<String> mItems;
     44     private Set<String> mIgnored;
     45     private TestAdapter mAdapter;
     46     private DefaultSelectionHelper mHelper;
     47     private TestSelectionObserver mListener;
     48     private SelectionProbe mSelection;
     49 
     50     @Before
     51     public void setUp() throws Exception {
     52         mIgnored = new HashSet<>();
     53         mItems = TestAdapter.createItemList(100);
     54         mListener = new TestSelectionObserver();
     55         mAdapter = new TestAdapter();
     56         mAdapter.updateTestModelIds(mItems);
     57 
     58         SelectionPredicate canSelect = new SelectionPredicate() {
     59 
     60             @Override
     61             public boolean canSetStateForId(String id, boolean nextState) {
     62                 return !nextState || !mIgnored.contains(id);
     63             }
     64 
     65             @Override
     66             public boolean canSetStateAtPosition(int position, boolean nextState) {
     67                 throw new UnsupportedOperationException("Not implemented.");
     68             }
     69         };
     70         mHelper = new DefaultSelectionHelper(
     71                 DefaultSelectionHelper.MODE_MULTIPLE,
     72                 mAdapter,
     73                 new TestStableIdProvider(mAdapter),
     74                 canSelect);
     75 
     76         mHelper.addObserver(mListener);
     77 
     78         mSelection = new SelectionProbe(mHelper, mListener);
     79 
     80         mIgnored.clear();
     81     }
     82 
     83     @Test
     84     public void testSelect() {
     85         mHelper.select(mItems.get(7));
     86 
     87         mSelection.assertSelection(7);
     88     }
     89 
     90     @Test
     91     public void testDeselect() {
     92         mHelper.select(mItems.get(7));
     93         mHelper.deselect(mItems.get(7));
     94 
     95         mSelection.assertNoSelection();
     96     }
     97 
     98     @Test
     99     public void testSelection_DoNothingOnUnselectableItem() {
    100         mIgnored.add(mItems.get(7));
    101         boolean selected = mHelper.select(mItems.get(7));
    102 
    103         assertFalse(selected);
    104         mSelection.assertNoSelection();
    105     }
    106 
    107     @Test
    108     public void testSelect_NotifiesListenersOfChange() {
    109         mHelper.select(mItems.get(7));
    110 
    111         mListener.assertSelectionChanged();
    112     }
    113 
    114     @Test
    115     public void testSelect_NotifiesAdapterOfSelect() {
    116         mHelper.select(mItems.get(7));
    117 
    118         mAdapter.assertNotifiedOfSelectionChange(7);
    119     }
    120 
    121     @Test
    122     public void testSelect_NotifiesAdapterOfDeselect() {
    123         mHelper.select(mItems.get(7));
    124         mAdapter.resetSelectionNotifications();
    125         mHelper.deselect(mItems.get(7));
    126         mAdapter.assertNotifiedOfSelectionChange(7);
    127     }
    128 
    129     @Test
    130     public void testDeselect_NotifiesSelectionChanged() {
    131         mHelper.select(mItems.get(7));
    132         mHelper.deselect(mItems.get(7));
    133 
    134         mListener.assertSelectionChanged();
    135     }
    136 
    137     @Test
    138     public void testSelection_PersistsOnUpdate() {
    139         mHelper.select(mItems.get(7));
    140         mAdapter.updateTestModelIds(mItems);
    141 
    142         mSelection.assertSelection(7);
    143     }
    144 
    145     @Test
    146     public void testSelection_IntersectsWithNewDataSet() {
    147         mHelper.select(mItems.get(99));
    148         mHelper.select(mItems.get(7));
    149 
    150         mAdapter.updateTestModelIds(TestAdapter.createItemList(50));
    151 
    152         mSelection.assertSelection(7);
    153     }
    154 
    155     @Test
    156     public void testSetItemsSelected() {
    157         mHelper.setItemsSelected(getStringIds(6, 7, 8), true);
    158 
    159         mSelection.assertRangeSelected(6, 8);
    160     }
    161 
    162     @Test
    163     public void testSetItemsSelected_SkipUnselectableItem() {
    164         mIgnored.add(mItems.get(7));
    165 
    166         mHelper.setItemsSelected(getStringIds(6, 7, 8), true);
    167 
    168         mSelection.assertSelected(6);
    169         mSelection.assertNotSelected(7);
    170         mSelection.assertSelected(8);
    171     }
    172 
    173     @Test
    174     public void testRangeSelection() {
    175         mHelper.startRange(15);
    176         mHelper.extendRange(19);
    177         mSelection.assertRangeSelection(15, 19);
    178     }
    179 
    180     @Test
    181     public void testRangeSelection_SkipUnselectableItem() {
    182         mIgnored.add(mItems.get(17));
    183 
    184         mHelper.startRange(15);
    185         mHelper.extendRange(19);
    186 
    187         mSelection.assertRangeSelected(15, 16);
    188         mSelection.assertNotSelected(17);
    189         mSelection.assertRangeSelected(18, 19);
    190     }
    191 
    192     @Test
    193     public void testRangeSelection_snapExpand() {
    194         mHelper.startRange(15);
    195         mHelper.extendRange(19);
    196         mHelper.extendRange(27);
    197         mSelection.assertRangeSelection(15, 27);
    198     }
    199 
    200     @Test
    201     public void testRangeSelection_snapContract() {
    202         mHelper.startRange(15);
    203         mHelper.extendRange(27);
    204         mHelper.extendRange(19);
    205         mSelection.assertRangeSelection(15, 19);
    206     }
    207 
    208     @Test
    209     public void testRangeSelection_snapInvert() {
    210         mHelper.startRange(15);
    211         mHelper.extendRange(27);
    212         mHelper.extendRange(3);
    213         mSelection.assertRangeSelection(3, 15);
    214     }
    215 
    216     @Test
    217     public void testRangeSelection_multiple() {
    218         mHelper.startRange(15);
    219         mHelper.extendRange(27);
    220         mHelper.endRange();
    221         mHelper.startRange(42);
    222         mHelper.extendRange(57);
    223         mSelection.assertSelectionSize(29);
    224         mSelection.assertRangeSelected(15, 27);
    225         mSelection.assertRangeSelected(42, 57);
    226     }
    227 
    228     @Test
    229     public void testProvisionalRangeSelection() {
    230         mHelper.startRange(13);
    231         mHelper.extendProvisionalRange(15);
    232         mSelection.assertRangeSelection(13, 15);
    233         mHelper.getSelection().mergeProvisionalSelection();
    234         mHelper.endRange();
    235         mSelection.assertSelectionSize(3);
    236     }
    237 
    238     @Test
    239     public void testProvisionalRangeSelection_endEarly() {
    240         mHelper.startRange(13);
    241         mHelper.extendProvisionalRange(15);
    242         mSelection.assertRangeSelection(13, 15);
    243 
    244         mHelper.endRange();
    245         // If we end range selection prematurely for provision selection, nothing should be selected
    246         // except the first item
    247         mSelection.assertSelectionSize(1);
    248     }
    249 
    250     @Test
    251     public void testProvisionalRangeSelection_snapExpand() {
    252         mHelper.startRange(13);
    253         mHelper.extendProvisionalRange(15);
    254         mSelection.assertRangeSelection(13, 15);
    255         mHelper.getSelection().mergeProvisionalSelection();
    256         mHelper.extendRange(18);
    257         mSelection.assertRangeSelection(13, 18);
    258     }
    259 
    260     @Test
    261     public void testCombinationRangeSelection_IntersectsOldSelection() {
    262         mHelper.startRange(13);
    263         mHelper.extendRange(15);
    264         mSelection.assertRangeSelection(13, 15);
    265 
    266         mHelper.startRange(11);
    267         mHelper.extendProvisionalRange(18);
    268         mSelection.assertRangeSelected(11, 18);
    269         mHelper.endRange();
    270         mSelection.assertRangeSelected(13, 15);
    271         mSelection.assertRangeSelected(11, 11);
    272         mSelection.assertSelectionSize(4);
    273     }
    274 
    275     @Test
    276     public void testProvisionalSelection() {
    277         Selection s = mHelper.getSelection();
    278         mSelection.assertNoSelection();
    279 
    280         // Mimicking band selection case -- BandController notifies item callback by itself.
    281         mListener.onItemStateChanged(mItems.get(1), true);
    282         mListener.onItemStateChanged(mItems.get(2), true);
    283 
    284         SparseBooleanArray provisional = new SparseBooleanArray();
    285         provisional.append(1, true);
    286         provisional.append(2, true);
    287         s.setProvisionalSelection(getItemIds(provisional));
    288         mSelection.assertSelection(1, 2);
    289     }
    290 
    291     @Test
    292     public void testProvisionalSelection_Replace() {
    293         Selection s = mHelper.getSelection();
    294 
    295         // Mimicking band selection case -- BandController notifies item callback by itself.
    296         mListener.onItemStateChanged(mItems.get(1), true);
    297         mListener.onItemStateChanged(mItems.get(2), true);
    298         SparseBooleanArray provisional = new SparseBooleanArray();
    299         provisional.append(1, true);
    300         provisional.append(2, true);
    301         s.setProvisionalSelection(getItemIds(provisional));
    302 
    303         mListener.onItemStateChanged(mItems.get(1), false);
    304         mListener.onItemStateChanged(mItems.get(2), false);
    305         provisional.clear();
    306 
    307         mListener.onItemStateChanged(mItems.get(3), true);
    308         mListener.onItemStateChanged(mItems.get(4), true);
    309         provisional.append(3, true);
    310         provisional.append(4, true);
    311         s.setProvisionalSelection(getItemIds(provisional));
    312         mSelection.assertSelection(3, 4);
    313     }
    314 
    315     @Test
    316     public void testProvisionalSelection_IntersectsExistingProvisionalSelection() {
    317         Selection s = mHelper.getSelection();
    318 
    319         // Mimicking band selection case -- BandController notifies item callback by itself.
    320         mListener.onItemStateChanged(mItems.get(1), true);
    321         mListener.onItemStateChanged(mItems.get(2), true);
    322         SparseBooleanArray provisional = new SparseBooleanArray();
    323         provisional.append(1, true);
    324         provisional.append(2, true);
    325         s.setProvisionalSelection(getItemIds(provisional));
    326 
    327         mListener.onItemStateChanged(mItems.get(1), false);
    328         mListener.onItemStateChanged(mItems.get(2), false);
    329         provisional.clear();
    330 
    331         mListener.onItemStateChanged(mItems.get(1), true);
    332         provisional.append(1, true);
    333         s.setProvisionalSelection(getItemIds(provisional));
    334         mSelection.assertSelection(1);
    335     }
    336 
    337     @Test
    338     public void testProvisionalSelection_Apply() {
    339         Selection s = mHelper.getSelection();
    340 
    341         // Mimicking band selection case -- BandController notifies item callback by itself.
    342         mListener.onItemStateChanged(mItems.get(1), true);
    343         mListener.onItemStateChanged(mItems.get(2), true);
    344         SparseBooleanArray provisional = new SparseBooleanArray();
    345         provisional.append(1, true);
    346         provisional.append(2, true);
    347         s.setProvisionalSelection(getItemIds(provisional));
    348         s.mergeProvisionalSelection();
    349 
    350         mSelection.assertSelection(1, 2);
    351     }
    352 
    353     @Test
    354     public void testProvisionalSelection_Cancel() {
    355         mHelper.select(mItems.get(1));
    356         mHelper.select(mItems.get(2));
    357         Selection s = mHelper.getSelection();
    358 
    359         SparseBooleanArray provisional = new SparseBooleanArray();
    360         provisional.append(3, true);
    361         provisional.append(4, true);
    362         s.setProvisionalSelection(getItemIds(provisional));
    363         s.clearProvisionalSelection();
    364 
    365         // Original selection should remain.
    366         mSelection.assertSelection(1, 2);
    367     }
    368 
    369     @Test
    370     public void testProvisionalSelection_IntersectsAppliedSelection() {
    371         mHelper.select(mItems.get(1));
    372         mHelper.select(mItems.get(2));
    373         Selection s = mHelper.getSelection();
    374 
    375         // Mimicking band selection case -- BandController notifies item callback by itself.
    376         mListener.onItemStateChanged(mItems.get(3), true);
    377         SparseBooleanArray provisional = new SparseBooleanArray();
    378         provisional.append(2, true);
    379         provisional.append(3, true);
    380         s.setProvisionalSelection(getItemIds(provisional));
    381         mSelection.assertSelection(1, 2, 3);
    382     }
    383 
    384     @Test
    385     public void testObserverOnChanged_NotifiesListenersOfChange() {
    386         mAdapter.notifyDataSetChanged();
    387 
    388         mListener.assertSelectionChanged();
    389     }
    390 
    391     private Set<String> getItemIds(SparseBooleanArray selection) {
    392         Set<String> ids = new HashSet<>();
    393 
    394         int count = selection.size();
    395         for (int i = 0; i < count; ++i) {
    396             ids.add(mItems.get(selection.keyAt(i)));
    397         }
    398 
    399         return ids;
    400     }
    401 
    402     private Iterable<String> getStringIds(int... ids) {
    403         List<String> stringIds = new ArrayList<>(ids.length);
    404         for (int id : ids) {
    405             stringIds.add(mItems.get(id));
    406         }
    407         return stringIds;
    408     }
    409 }
    410