1 /*
2  * Copyright (C) 2008 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 android.widget;
18 
19 import android.content.Context;
20 import android.database.Cursor;
21 import android.database.MatrixCursor;
22 import android.test.AndroidTestCase;
23 
24 import androidx.test.filters.SmallTest;
25 import androidx.test.filters.Suppress;
26 
27 import com.google.android.collect.Lists;
28 
29 import java.util.ArrayList;
30 import java.util.Random;
31 
32 /**
33  * This is a series of tests of basic API contracts for SimpleCursorAdapter.  It is
34  * incomplete and can use work.
35  *
36  * NOTE:  This contract holds for underlying cursor types too and these should
37  * be extracted into a set of tests that can be run on any descendant of CursorAdapter.
38  */
39 @Suppress // Failing.
40 public class SimpleCursorAdapterTest extends AndroidTestCase {
41 
42     String[] mFrom;
43     int[] mTo;
44     int mLayout;
45     Context mContext;
46 
47     ArrayList<ArrayList> mData2x2;
48     Cursor mCursor2x2;
49 
50     /**
51      * Set up basic columns and cursor for the tests
52      */
53     @Override
setUp()54     public void setUp() throws Exception {
55         super.setUp();
56 
57         // all the pieces needed for the various tests
58         mFrom = new String[]{"Column1", "Column2", "_id"};
59         mTo = new int[]{com.android.internal.R.id.text1, com.android.internal.R.id.text2};
60         mLayout = com.android.internal.R.layout.simple_list_item_2;
61         mContext = getContext();
62 
63         // raw data for building a basic test cursor
64         mData2x2 = createTestList(2, 2);
65         mCursor2x2 = createCursor(mFrom, mData2x2);
66     }
67 
68     /**
69      * Borrowed from CursorWindowTest.java
70      */
createTestList(int rows, int cols)71     private ArrayList<ArrayList> createTestList(int rows, int cols) {
72         ArrayList<ArrayList> list = Lists.newArrayList();
73         Random generator = new Random();
74 
75         for (int i = 0; i < rows; i++) {
76             ArrayList<Integer> col = Lists.newArrayList();
77             list.add(col);
78             for (int j = 0; j < cols; j++) {
79                 // generate random number
80                 Integer r = generator.nextInt();
81                 col.add(r);
82             }
83             col.add(i);
84         }
85         return list;
86     }
87 
88     /**
89      * Test creating with a live cursor
90      */
91     @SmallTest
testCreateLive()92     public void testCreateLive() {
93         SimpleCursorAdapter ca = new SimpleCursorAdapter(mContext, mLayout, mCursor2x2, mFrom, mTo);
94 
95         // Now see if we can pull 2 rows from the adapter
96         assertEquals(2, ca.getCount());
97     }
98 
99     /**
100      * Test creating with a null cursor
101      */
102     @SmallTest
testCreateNull()103     public void testCreateNull() {
104         SimpleCursorAdapter ca = new SimpleCursorAdapter(mContext, mLayout, null, mFrom, mTo);
105 
106         // The adapter should report zero rows
107         assertEquals(0, ca.getCount());
108     }
109 
110     /**
111      * Test changeCursor() with live cursor
112      */
113     @SmallTest
testChangeCursorLive()114     public void testChangeCursorLive() {
115         SimpleCursorAdapter ca = new SimpleCursorAdapter(mContext, mLayout, mCursor2x2, mFrom, mTo);
116 
117         // Now see if we can pull 2 rows from the adapter
118         assertEquals(2, ca.getCount());
119 
120         // now put in a different cursor (5 rows)
121         ArrayList<ArrayList> data2 = createTestList(5, 2);
122         Cursor c2 = createCursor(mFrom, data2);
123         ca.changeCursor(c2);
124 
125         // Now see if we can pull 5 rows from the adapter
126         assertEquals(5, ca.getCount());
127     }
128 
129     /**
130      * Test changeCursor() with null cursor
131      */
132     @SmallTest
testChangeCursorNull()133     public void testChangeCursorNull() {
134         SimpleCursorAdapter ca = new SimpleCursorAdapter(mContext, mLayout, mCursor2x2, mFrom, mTo);
135 
136         // Now see if we can pull 2 rows from the adapter
137         assertEquals(2, ca.getCount());
138 
139         // now put in null
140         ca.changeCursor(null);
141 
142         // The adapter should report zero rows
143         assertEquals(0, ca.getCount());
144     }
145 
146     /**
147      * Test changeCursor() with differing column layout.  This confirms that the Adapter can
148      * deal with cursors that have the same essential data (as defined by the original mFrom
149      * array) but it's OK if the physical structure of the cursor changes (columns rearranged).
150      */
151     @SmallTest
testChangeCursorColumns()152     public void testChangeCursorColumns() {
153         TestSimpleCursorAdapter ca = new TestSimpleCursorAdapter(mContext, mLayout, mCursor2x2,
154                 mFrom, mTo);
155 
156         // check columns of original - mFrom and mTo should line up
157         int[] columns = ca.getConvertedFrom();
158         assertEquals(columns[0], 0);
159         assertEquals(columns[1], 1);
160 
161         // Now make a new cursor with similar data but rearrange the columns
162         String[] swappedFrom = new String[]{"Column2", "Column1", "_id"};
163         Cursor c2 = createCursor(swappedFrom, mData2x2);
164         ca.changeCursor(c2);
165         assertEquals(2, ca.getCount());
166 
167         // check columns to see if rearrangement tracked (should be swapped now)
168         columns = ca.getConvertedFrom();
169         assertEquals(columns[0], 1);
170         assertEquals(columns[1], 0);
171     }
172 
173     /**
174      * Test that you can safely construct with a null cursor *and* null to/from arrays.
175      * This is new functionality added in 12/2008.
176      */
177     @SmallTest
testNullConstructor()178     public void testNullConstructor() {
179         SimpleCursorAdapter ca = new SimpleCursorAdapter(mContext, mLayout, null, null, null);
180         assertEquals(0, ca.getCount());
181     }
182 
183     /**
184      * Test going from a null cursor to a non-null cursor *and* setting the to/from arrays
185      * This is new functionality added in 12/2008.
186      */
187     @SmallTest
testChangeNullToMapped()188     public void testChangeNullToMapped() {
189         TestSimpleCursorAdapter ca = new TestSimpleCursorAdapter(mContext, mLayout, null, null, null);
190         assertEquals(0, ca.getCount());
191 
192         ca.changeCursorAndColumns(mCursor2x2, mFrom, mTo);
193         assertEquals(2, ca.getCount());
194 
195         // check columns of original - mFrom and mTo should line up
196         int[] columns = ca.getConvertedFrom();
197         assertEquals(2, columns.length);
198         assertEquals(0, columns[0]);
199         assertEquals(1, columns[1]);
200         int[] viewIds = ca.getTo();
201         assertEquals(2, viewIds.length);
202         assertEquals(com.android.internal.R.id.text1, viewIds[0]);
203         assertEquals(com.android.internal.R.id.text2, viewIds[1]);
204     }
205 
206     /**
207      * Test going from one mapping to a different mapping
208      * This is new functionality added in 12/2008.
209      */
210     @SmallTest
testChangeMapping()211     public void testChangeMapping() {
212         TestSimpleCursorAdapter ca = new TestSimpleCursorAdapter(mContext, mLayout, mCursor2x2,
213                 mFrom, mTo);
214         assertEquals(2, ca.getCount());
215 
216         // Now create a new configuration with same cursor and just one column mapped
217         String[] singleFrom = new String[]{"Column1"};
218         int[] singleTo = new int[]{com.android.internal.R.id.text1};
219         ca.changeCursorAndColumns(mCursor2x2, singleFrom, singleTo);
220 
221         // And examine the results, make sure they're still consistent
222         int[] columns = ca.getConvertedFrom();
223         assertEquals(1, columns.length);
224         assertEquals(0, columns[0]);
225         int[] viewIds = ca.getTo();
226         assertEquals(1, viewIds.length);
227         assertEquals(com.android.internal.R.id.text1, viewIds[0]);
228 
229         // And again, same cursor, different map
230         singleFrom = new String[]{"Column2"};
231         singleTo = new int[]{com.android.internal.R.id.text2};
232         ca.changeCursorAndColumns(mCursor2x2, singleFrom, singleTo);
233 
234         // And examine the results, make sure they're still consistent
235         columns = ca.getConvertedFrom();
236         assertEquals(1, columns.length);
237         assertEquals(1, columns[0]);
238         viewIds = ca.getTo();
239         assertEquals(1, viewIds.length);
240         assertEquals(com.android.internal.R.id.text2, viewIds[0]);
241     }
242 
createCursor(String[] columns, ArrayList<ArrayList> list)243     private static MatrixCursor createCursor(String[] columns, ArrayList<ArrayList> list) {
244         MatrixCursor cursor = new MatrixCursor(columns, list.size());
245         for (ArrayList row : list) {
246             cursor.addRow(row);
247         }
248         return cursor;
249     }
250 
251     /**
252      * This is simply a way to sneak a look at the protected mFrom() array.  A more API-
253      * friendly way to do this would be to mock out a View and a ViewBinder and exercise
254      * it via those seams.
255      */
256     private static class TestSimpleCursorAdapter extends SimpleCursorAdapter {
257 
TestSimpleCursorAdapter(Context context, int layout, Cursor c, String[] from, int[] to)258         public TestSimpleCursorAdapter(Context context, int layout, Cursor c,
259                 String[] from, int[] to) {
260             super(context, layout, c, from, to);
261         }
262 
getConvertedFrom()263         int[] getConvertedFrom() {
264             return mFrom;
265         }
266 
getTo()267         int[] getTo() {
268             return mTo;
269         }
270     }
271 }
272