1 /* 2 * Copyright (C) 2017 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; 18 19 import static junit.framework.Assert.assertEquals; 20 import static junit.framework.Assert.fail; 21 22 import android.database.Cursor; 23 import android.database.MatrixCursor; 24 import android.database.MergeCursor; 25 import android.provider.DocumentsContract.Document; 26 import android.support.test.filters.SmallTest; 27 import android.support.test.runner.AndroidJUnit4; 28 29 import com.android.documentsui.base.DocumentInfo; 30 import com.android.documentsui.roots.RootCursorWrapper; 31 import com.android.documentsui.testing.TestEventListener; 32 import com.android.documentsui.testing.TestFeatures; 33 34 import org.junit.Before; 35 import org.junit.Test; 36 import org.junit.runner.RunWith; 37 38 import java.util.BitSet; 39 import java.util.Random; 40 41 @RunWith(AndroidJUnit4.class) 42 @SmallTest 43 public class ModelTest { 44 45 private static final int ITEM_COUNT = 10; 46 private static final String AUTHORITY = "test_authority"; 47 48 private static final String[] COLUMNS = new String[]{ 49 RootCursorWrapper.COLUMN_AUTHORITY, 50 Document.COLUMN_DOCUMENT_ID, 51 Document.COLUMN_FLAGS, 52 Document.COLUMN_DISPLAY_NAME, 53 Document.COLUMN_SIZE, 54 Document.COLUMN_LAST_MODIFIED, 55 Document.COLUMN_MIME_TYPE 56 }; 57 58 private static final String[] NAMES = new String[] { 59 "4", 60 "foo", 61 "1", 62 "bar", 63 "*(Ljifl;a", 64 "0", 65 "baz", 66 "2", 67 "3", 68 "%$%VD" 69 }; 70 71 private Cursor cursor; 72 private Model model; 73 private TestFeatures features; 74 75 @Before 76 public void setUp() { 77 features = new TestFeatures(); 78 79 Random rand = new Random(); 80 81 MatrixCursor c = new MatrixCursor(COLUMNS); 82 for (int i = 0; i < ITEM_COUNT; ++i) { 83 MatrixCursor.RowBuilder row = c.newRow(); 84 row.add(RootCursorWrapper.COLUMN_AUTHORITY, AUTHORITY); 85 row.add(Document.COLUMN_DOCUMENT_ID, Integer.toString(i)); 86 row.add(Document.COLUMN_FLAGS, Document.FLAG_SUPPORTS_DELETE); 87 // Generate random document names and sizes. This forces the model's internal sort code 88 // to actually do something. 89 row.add(Document.COLUMN_DISPLAY_NAME, NAMES[i]); 90 row.add(Document.COLUMN_SIZE, rand.nextInt()); 91 } 92 cursor = c; 93 94 DirectoryResult r = new DirectoryResult(); 95 r.cursor = cursor; 96 97 // Instantiate the model with a dummy view adapter and listener that (for now) do nothing. 98 model = new Model(features); 99 // not sure why we add a listener here at all. 100 model.addUpdateListener(new TestEventListener<>()); 101 model.update(r); 102 } 103 104 // Tests that the item count is correct. 105 @Test 106 public void testItemCount() { 107 assertEquals(ITEM_COUNT, model.getItemCount()); 108 } 109 110 // Tests multiple authorities with clashing document IDs. 111 @Test 112 public void testModelIdIsUnique() { 113 MatrixCursor cIn1 = new MatrixCursor(COLUMNS); 114 MatrixCursor cIn2 = new MatrixCursor(COLUMNS); 115 116 // Make two sets of items with the same IDs, under different authorities. 117 final String AUTHORITY0 = "auth0"; 118 final String AUTHORITY1 = "auth1"; 119 120 for (int i = 0; i < ITEM_COUNT; ++i) { 121 MatrixCursor.RowBuilder row0 = cIn1.newRow(); 122 row0.add(RootCursorWrapper.COLUMN_AUTHORITY, AUTHORITY0); 123 row0.add(Document.COLUMN_DOCUMENT_ID, Integer.toString(i)); 124 125 MatrixCursor.RowBuilder row1 = cIn2.newRow(); 126 row1.add(RootCursorWrapper.COLUMN_AUTHORITY, AUTHORITY1); 127 row1.add(Document.COLUMN_DOCUMENT_ID, Integer.toString(i)); 128 } 129 130 Cursor cIn = new MergeCursor(new Cursor[] { cIn1, cIn2 }); 131 132 // Update the model, then make sure it contains all the expected items. 133 DirectoryResult r = new DirectoryResult(); 134 r.cursor = cIn; 135 model.update(r); 136 137 assertEquals(ITEM_COUNT * 2, model.getItemCount()); 138 BitSet b0 = new BitSet(ITEM_COUNT); 139 BitSet b1 = new BitSet(ITEM_COUNT); 140 141 for (String id: model.getModelIds()) { 142 Cursor cOut = model.getItem(id); 143 String authority = 144 DocumentInfo.getCursorString(cOut, RootCursorWrapper.COLUMN_AUTHORITY); 145 String docId = DocumentInfo.getCursorString(cOut, Document.COLUMN_DOCUMENT_ID); 146 147 switch (authority) { 148 case AUTHORITY0: 149 b0.set(Integer.parseInt(docId)); 150 break; 151 case AUTHORITY1: 152 b1.set(Integer.parseInt(docId)); 153 break; 154 default: 155 fail("Unrecognized authority string"); 156 } 157 } 158 159 assertEquals(ITEM_COUNT, b0.cardinality()); 160 assertEquals(ITEM_COUNT, b1.cardinality()); 161 } 162 163 // Tests the base case for Model.getItem. 164 @Test 165 public void testGetItem() { 166 String[] ids = model.getModelIds(); 167 assertEquals(ITEM_COUNT, ids.length); 168 for (int i = 0; i < ITEM_COUNT; ++i) { 169 Cursor c = model.getItem(ids[i]); 170 assertEquals(i, c.getPosition()); 171 } 172 } 173 174 @Test 175 public void testResetAfterGettingException() { 176 DirectoryResult result = new DirectoryResult(); 177 result.exception = new Exception(); 178 179 model.update(result); 180 181 assertEquals(0, model.getItemCount()); 182 } 183 } 184