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