• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.database.cts;
18 
19 
20 import android.content.Context;
21 import android.database.AbstractCursor;
22 import android.database.CharArrayBuffer;
23 import android.database.ContentObserver;
24 import android.database.CursorIndexOutOfBoundsException;
25 import android.database.CursorWindow;
26 import android.database.DataSetObserver;
27 import android.database.sqlite.SQLiteDatabase;
28 import android.net.Uri;
29 import android.os.Bundle;
30 import android.test.InstrumentationTestCase;
31 
32 import java.io.File;
33 import java.util.ArrayList;
34 import java.util.Random;
35 
36 /**
37  * Test {@link AbstractCursor}.
38  */
39 public class AbstractCursorTest extends InstrumentationTestCase {
40     private static final int POSITION0 = 0;
41     private static final int POSITION1 = 1;
42     private  static final int ROW_MAX = 10;
43     private static final int DATA_COUNT = 10;
44     private static final String[] COLUMN_NAMES1 = new String[] {
45         "_id",             // 0
46         "number"           // 1
47     };
48     private static final String[] COLUMN_NAMES = new String[] { "name", "number", "profit" };
49     private TestAbstractCursor mTestAbstractCursor;
50     private Object mLockObj = new Object();
51 
52     private SQLiteDatabase mDatabase;
53     private File mDatabaseFile;
54     private AbstractCursor mDatabaseCursor;
55 
56     @Override
setUp()57     protected void setUp() throws Exception {
58         super.setUp();
59 
60         setupDatabase();
61         ArrayList<ArrayList> list = createTestList(ROW_MAX, COLUMN_NAMES.length);
62         mTestAbstractCursor = new TestAbstractCursor(COLUMN_NAMES, list);
63     }
64 
65     @Override
tearDown()66     protected void tearDown() throws Exception {
67         mDatabaseCursor.close();
68         mTestAbstractCursor.close();
69         mDatabase.close();
70         if (mDatabaseFile.exists()) {
71             mDatabaseFile.delete();
72         }
73         super.tearDown();
74     }
75 
testConstructor()76     public void testConstructor() {
77         TestAbstractCursor abstractCursor = new TestAbstractCursor();
78         assertEquals(-1, abstractCursor.getPosition());
79     }
80 
testGetBlob()81     public void testGetBlob() {
82         try {
83             mTestAbstractCursor.getBlob(0);
84             fail("getBlob should throws a UnsupportedOperationException here");
85         } catch (UnsupportedOperationException e) {
86             // expected
87         }
88     }
89 
testRegisterDataSetObserver()90     public void testRegisterDataSetObserver() {
91         MockDataSetObserver datasetObserver = new MockDataSetObserver();
92 
93         try {
94             mDatabaseCursor.unregisterDataSetObserver(datasetObserver);
95             fail("Can't unregister DataSetObserver before it is registered.");
96         } catch (IllegalStateException e) {
97             // expected
98         }
99 
100         mDatabaseCursor.registerDataSetObserver(datasetObserver);
101 
102         try {
103             mDatabaseCursor.registerDataSetObserver(datasetObserver);
104             fail("Can't register DataSetObserver twice before unregister it.");
105         } catch (IllegalStateException e) {
106             // expected
107         }
108 
109         mDatabaseCursor.unregisterDataSetObserver(datasetObserver);
110         mDatabaseCursor.registerDataSetObserver(datasetObserver);
111     }
112 
testRegisterContentObserver()113     public void testRegisterContentObserver() {
114         MockContentObserver contentObserver = new MockContentObserver();
115 
116         try {
117             mDatabaseCursor.unregisterContentObserver(contentObserver);
118             fail("Can't unregister ContentObserver before it is registered.");
119         } catch (IllegalStateException e) {
120             // expected
121         }
122 
123         mDatabaseCursor.registerContentObserver(contentObserver);
124 
125         try {
126             mDatabaseCursor.registerContentObserver(contentObserver);
127             fail("Can't register DataSetObserver twice before unregister it.");
128         } catch (IllegalStateException e) {
129             // expected
130         }
131 
132         mDatabaseCursor.unregisterContentObserver(contentObserver);
133         mDatabaseCursor.registerContentObserver(contentObserver);
134     }
135 
testSetNotificationUri()136     public void testSetNotificationUri() {
137         String MOCK_URI = "content://abstractrcursortest/testtable";
138         mDatabaseCursor.setNotificationUri(getInstrumentation().getContext().getContentResolver(),
139                 Uri.parse(MOCK_URI));
140     }
141 
testRespond()142     public void testRespond() {
143         Bundle b = new Bundle();
144         Bundle bundle = mDatabaseCursor.respond(b);
145         assertSame(Bundle.EMPTY, bundle);
146 
147         bundle = mDatabaseCursor.respond(null);
148         assertSame(Bundle.EMPTY, bundle);
149     }
150 
testRequery()151     public void testRequery() {
152         MockDataSetObserver mock = new MockDataSetObserver();
153         mDatabaseCursor.registerDataSetObserver(mock);
154         assertFalse(mock.hadCalledOnChanged());
155         mDatabaseCursor.requery();
156         assertTrue(mock.hadCalledOnChanged());
157     }
158 
testOnChange()159     public void testOnChange() throws InterruptedException {
160         MockContentObserver mock = new MockContentObserver();
161         mTestAbstractCursor.registerContentObserver(mock);
162         assertFalse(mock.hadCalledOnChange());
163         mTestAbstractCursor.onChange(true);
164         synchronized(mLockObj) {
165             if ( !mock.hadCalledOnChange() ) {
166                 mLockObj.wait(5000);
167             }
168         }
169         assertTrue(mock.hadCalledOnChange());
170     }
171 
testOnMove()172     public void testOnMove() {
173         mTestAbstractCursor.resetOnMoveRet();
174         assertFalse(mTestAbstractCursor.getOnMoveRet());
175         mTestAbstractCursor.moveToFirst();
176         mTestAbstractCursor.moveToPosition(5);
177         assertTrue(mTestAbstractCursor.getOnMoveRet());
178         assertEquals(0, mTestAbstractCursor.getOldPos());
179         assertEquals(5, mTestAbstractCursor.getNewPos());
180     }
181 
testMoveToPrevious()182     public void testMoveToPrevious() {
183         // Test moveToFirst, isFirst, moveToNext, getPosition
184         assertTrue(mDatabaseCursor.moveToFirst());
185         assertTrue(mDatabaseCursor.isFirst());
186         assertEquals(0, mDatabaseCursor.getPosition());
187         assertTrue(mDatabaseCursor.moveToNext());
188         assertEquals(1, mDatabaseCursor.getPosition());
189         assertFalse(mDatabaseCursor.isFirst());
190         assertTrue(mDatabaseCursor.moveToNext());
191         assertEquals(2, mDatabaseCursor.getPosition());
192 
193         // invoke moveToPosition with a number larger than row count.
194         assertFalse(mDatabaseCursor.moveToPosition(30000));
195         assertEquals(mDatabaseCursor.getCount(), mDatabaseCursor.getPosition());
196 
197         assertFalse(mDatabaseCursor.moveToPosition(-1));
198         assertEquals(-1, mDatabaseCursor.getPosition());
199         assertTrue(mDatabaseCursor.isBeforeFirst());
200 
201         mDatabaseCursor.moveToPosition(5);
202         assertEquals(5, mDatabaseCursor.getPosition());
203 
204         // Test moveToPrevious
205         assertTrue(mDatabaseCursor.moveToPrevious());
206         assertEquals(4, mDatabaseCursor.getPosition());
207         assertTrue(mDatabaseCursor.moveToPrevious());
208         assertEquals(3, mDatabaseCursor.getPosition());
209         assertTrue(mDatabaseCursor.moveToPrevious());
210         assertEquals(2, mDatabaseCursor.getPosition());
211 
212         // Test moveToLast, isLast, moveToPrevius, isAfterLast.
213         assertFalse(mDatabaseCursor.isLast());
214         assertTrue(mDatabaseCursor.moveToLast());
215         assertTrue(mDatabaseCursor.isLast());
216         assertFalse(mDatabaseCursor.isAfterLast());
217 
218         assertFalse(mDatabaseCursor.moveToNext());
219         assertTrue(mDatabaseCursor.isAfterLast());
220         assertFalse(mDatabaseCursor.moveToNext());
221         assertTrue(mDatabaseCursor.isAfterLast());
222         assertFalse(mDatabaseCursor.isLast());
223         assertTrue(mDatabaseCursor.moveToPrevious());
224         assertTrue(mDatabaseCursor.isLast());
225         assertTrue(mDatabaseCursor.moveToPrevious());
226         assertFalse(mDatabaseCursor.isLast());
227 
228         // Test move(int).
229         mDatabaseCursor.moveToFirst();
230         assertEquals(0, mDatabaseCursor.getPosition());
231         assertFalse(mDatabaseCursor.move(-1));
232         assertEquals(-1, mDatabaseCursor.getPosition());
233         assertTrue(mDatabaseCursor.move(1));
234         assertEquals(0, mDatabaseCursor.getPosition());
235 
236         assertTrue(mDatabaseCursor.move(5));
237         assertEquals(5, mDatabaseCursor.getPosition());
238         assertTrue(mDatabaseCursor.move(-1));
239         assertEquals(4, mDatabaseCursor.getPosition());
240 
241         mDatabaseCursor.moveToLast();
242         assertTrue(mDatabaseCursor.isLast());
243         assertFalse(mDatabaseCursor.isAfterLast());
244         assertFalse(mDatabaseCursor.move(1));
245         assertFalse(mDatabaseCursor.isLast());
246         assertTrue(mDatabaseCursor.isAfterLast());
247         assertTrue(mDatabaseCursor.move(-1));
248         assertTrue(mDatabaseCursor.isLast());
249         assertFalse(mDatabaseCursor.isAfterLast());
250     }
251 
testIsClosed()252     public void testIsClosed() {
253         assertFalse(mDatabaseCursor.isClosed());
254         mDatabaseCursor.close();
255         assertTrue(mDatabaseCursor.isClosed());
256     }
257 
testGetWindow()258     public void testGetWindow() {
259         CursorWindow window = new CursorWindow(false);
260         assertEquals(0, window.getNumRows());
261         // fill window from position 0
262         mDatabaseCursor.fillWindow(0, window);
263 
264         assertNotNull(mDatabaseCursor.getWindow());
265         assertEquals(mDatabaseCursor.getCount(), window.getNumRows());
266 
267         while (mDatabaseCursor.moveToNext()) {
268             assertEquals(mDatabaseCursor.getInt(POSITION1),
269                     window.getInt(mDatabaseCursor.getPosition(), POSITION1));
270         }
271         window.clear();
272     }
273 
testGetWantsAllOnMoveCalls()274     public void testGetWantsAllOnMoveCalls() {
275         assertFalse(mDatabaseCursor.getWantsAllOnMoveCalls());
276     }
277 
testIsFieldUpdated()278     public void testIsFieldUpdated() {
279         mTestAbstractCursor.moveToFirst();
280         assertFalse(mTestAbstractCursor.isFieldUpdated(0));
281     }
282 
testGetUpdatedField()283     public void testGetUpdatedField() {
284         mTestAbstractCursor.moveToFirst();
285         assertNull(mTestAbstractCursor.getUpdatedField(0));
286     }
287 
testGetExtras()288     public void testGetExtras() {
289         assertSame(Bundle.EMPTY, mDatabaseCursor.getExtras());
290     }
291 
testGetCount()292     public void testGetCount() {
293         assertEquals(DATA_COUNT, mDatabaseCursor.getCount());
294     }
295 
testGetColumnNames()296     public void testGetColumnNames() {
297         String[] names = mDatabaseCursor.getColumnNames();
298         assertEquals(COLUMN_NAMES1.length, names.length);
299 
300         for (int i = 0; i < COLUMN_NAMES1.length; i++) {
301             assertEquals(COLUMN_NAMES1[i], names[i]);
302         }
303     }
304 
testGetColumnName()305     public void testGetColumnName() {
306         assertEquals(COLUMN_NAMES1[0], mDatabaseCursor.getColumnName(0));
307         assertEquals(COLUMN_NAMES1[1], mDatabaseCursor.getColumnName(1));
308     }
309 
testGetColumnIndexOrThrow()310     public void testGetColumnIndexOrThrow() {
311         final String COLUMN_FAKE = "fake_name";
312         assertEquals(POSITION0, mDatabaseCursor.getColumnIndex(COLUMN_NAMES1[POSITION0]));
313         assertEquals(POSITION1, mDatabaseCursor.getColumnIndex(COLUMN_NAMES1[POSITION1]));
314         assertEquals(POSITION0, mDatabaseCursor.getColumnIndexOrThrow(COLUMN_NAMES1[POSITION0]));
315         assertEquals(POSITION1, mDatabaseCursor.getColumnIndexOrThrow(COLUMN_NAMES1[POSITION1]));
316 
317         try {
318             mDatabaseCursor.getColumnIndexOrThrow(COLUMN_FAKE);
319             fail("IllegalArgumentException expected, but not thrown");
320         } catch (IllegalArgumentException expected) {
321             // expected
322         }
323     }
324 
testGetColumnIndex()325     public void testGetColumnIndex() {
326         assertEquals(POSITION0, mDatabaseCursor.getColumnIndex(COLUMN_NAMES1[POSITION0]));
327         assertEquals(POSITION1, mDatabaseCursor.getColumnIndex(COLUMN_NAMES1[POSITION1]));
328     }
329 
testGetColumnCount()330     public void testGetColumnCount() {
331         assertEquals(COLUMN_NAMES1.length, mDatabaseCursor.getColumnCount());
332     }
333 
testDeactivate()334     public void testDeactivate() {
335         MockDataSetObserver mock = new MockDataSetObserver();
336         mDatabaseCursor.registerDataSetObserver(mock);
337         assertFalse(mock.hadCalledOnInvalid());
338         mDatabaseCursor.deactivate();
339         assertTrue(mock.hadCalledOnInvalid());
340     }
341 
testCopyStringToBuffer()342     public void testCopyStringToBuffer() {
343         CharArrayBuffer ca = new CharArrayBuffer(1000);
344         mTestAbstractCursor.moveToFirst();
345         mTestAbstractCursor.copyStringToBuffer(0, ca);
346         CursorWindow window = new CursorWindow(false);
347         mTestAbstractCursor.fillWindow(0, window);
348 
349         StringBuffer sb = new StringBuffer();
350         sb.append(window.getString(0, 0));
351         String str = mTestAbstractCursor.getString(0);
352         assertEquals(str.length(), ca.sizeCopied);
353         assertEquals(sb.toString(), new String(ca.data, 0, ca.sizeCopied));
354     }
355 
testCheckPosition()356     public void testCheckPosition() {
357         // Test with position = -1.
358         try {
359             mTestAbstractCursor.checkPosition();
360             fail("copyStringToBuffer() should throws CursorIndexOutOfBoundsException here.");
361         } catch (CursorIndexOutOfBoundsException e) {
362             // expected
363         }
364 
365         // Test with position = count.
366         assertTrue(mTestAbstractCursor.moveToPosition(mTestAbstractCursor.getCount() - 1));
367         mTestAbstractCursor.checkPosition();
368 
369         try {
370             assertFalse(mTestAbstractCursor.moveToPosition(mTestAbstractCursor.getCount()));
371             assertEquals(mTestAbstractCursor.getCount(), mTestAbstractCursor.getPosition());
372             mTestAbstractCursor.checkPosition();
373             fail("copyStringToBuffer() should throws CursorIndexOutOfBoundsException here.");
374         } catch (CursorIndexOutOfBoundsException e) {
375             // expected
376         }
377     }
378 
379     @SuppressWarnings("unchecked")
createTestList(int rows, int cols)380     private static ArrayList<ArrayList> createTestList(int rows, int cols) {
381         ArrayList<ArrayList> list = new ArrayList<ArrayList>();
382         Random ran = new Random();
383 
384         for (int i = 0; i < rows; i++) {
385             ArrayList<Integer> col = new ArrayList<Integer>();
386             list.add(col);
387 
388             for (int j = 0; j < cols; j++) {
389                 // generate random number
390                 Integer r = ran.nextInt();
391                 col.add(r);
392             }
393         }
394 
395         return list;
396     }
397 
setupDatabase()398     private void setupDatabase() {
399         File dbDir = getInstrumentation().getTargetContext().getDir("tests",
400                 Context.MODE_WORLD_WRITEABLE);
401         mDatabaseFile = new File(dbDir, "database_test.db");
402         if (mDatabaseFile.exists()) {
403             mDatabaseFile.delete();
404         }
405         mDatabase = SQLiteDatabase.openOrCreateDatabase(mDatabaseFile.getPath(), null);
406         assertNotNull(mDatabaseFile);
407         mDatabase.execSQL("CREATE TABLE test1 (_id INTEGER PRIMARY KEY, number TEXT);");
408         generateData();
409         mDatabaseCursor = (AbstractCursor) mDatabase.query("test1", null, null, null, null, null,
410                 null);
411     }
412 
generateData()413     private void generateData() {
414         for ( int i = 0; i < DATA_COUNT; i++) {
415             mDatabase.execSQL("INSERT INTO test1 (number) VALUES ('" + i + "');");
416         }
417     }
418 
419     private class TestAbstractCursor extends AbstractCursor {
420         private boolean mOnMoveReturnValue;
421         private int mOldPosition;
422         private int mNewPosition;
423         private String[] mColumnNames;
424         private ArrayList<Object>[] mRows;
425         private boolean mHadCalledOnChange = false;
426 
TestAbstractCursor()427         public TestAbstractCursor() {
428             super();
429         }
430         @SuppressWarnings("unchecked")
TestAbstractCursor(String[] columnNames, ArrayList<ArrayList> rows)431         public TestAbstractCursor(String[] columnNames, ArrayList<ArrayList> rows) {
432             int colCount = columnNames.length;
433             boolean foundID = false;
434             mRowIdColumnIndex = 0;
435 
436             // Add an _id column if not in columnNames
437             for (int i = 0; i < colCount; ++i) {
438                 if (columnNames[i].compareToIgnoreCase("_id") == 0) {
439                     mColumnNames = columnNames;
440                     foundID = true;
441                     break;
442                 }
443             }
444 
445             if (!foundID) {
446                 mColumnNames = new String[colCount + 1];
447                 System.arraycopy(columnNames, 0, mColumnNames, 0, columnNames.length);
448                 mColumnNames[colCount] = "_id";
449             }
450 
451             int rowCount = rows.size();
452             mRows = new ArrayList[rowCount];
453 
454             for (int i = 0; i < rowCount; ++i) {
455                 mRows[i] = rows.get(i);
456 
457                 if (!foundID) {
458                     mRows[i].add(Long.valueOf(i));
459                 }
460             }
461         }
462 
getOnMoveRet()463         public boolean getOnMoveRet() {
464             return mOnMoveReturnValue;
465         }
466 
resetOnMoveRet()467         public void resetOnMoveRet() {
468             mOnMoveReturnValue = false;
469         }
470 
getOldPos()471         public int getOldPos() {
472             return mOldPosition;
473         }
474 
getNewPos()475         public int getNewPos() {
476             return mNewPosition;
477         }
478 
479         @Override
onMove(int oldPosition, int newPosition)480         public boolean onMove(int oldPosition, int newPosition) {
481             mOnMoveReturnValue = super.onMove(oldPosition, newPosition);
482             mOldPosition = oldPosition;
483             mNewPosition = newPosition;
484             return mOnMoveReturnValue;
485         }
486 
487         @Override
getCount()488         public int getCount() {
489             return mRows.length;
490         }
491 
492         @Override
getColumnNames()493         public String[] getColumnNames() {
494             return mColumnNames;
495         }
496 
497         @Override
getString(int columnIndex)498         public String getString(int columnIndex) {
499             Object cell = mRows[mPos].get(columnIndex);
500             return (cell == null) ? null : cell.toString();
501         }
502 
503         @Override
getShort(int columnIndex)504         public short getShort(int columnIndex) {
505             Number num = (Number) mRows[mPos].get(columnIndex);
506             return num.shortValue();
507         }
508 
509         @Override
getInt(int columnIndex)510         public int getInt(int columnIndex) {
511             Number num = (Number) mRows[mPos].get(columnIndex);
512             return num.intValue();
513         }
514 
515         @Override
getLong(int columnIndex)516         public long getLong(int columnIndex) {
517             Number num = (Number) mRows[mPos].get(columnIndex);
518             return num.longValue();
519         }
520 
521         @Override
getFloat(int columnIndex)522         public float getFloat(int columnIndex) {
523             Number num = (Number) mRows[mPos].get(columnIndex);
524             return num.floatValue();
525         }
526 
527         @Override
getDouble(int columnIndex)528         public double getDouble(int columnIndex) {
529             Number num = (Number) mRows[mPos].get(columnIndex);
530             return num.doubleValue();
531         }
532 
533         @Override
isNull(int column)534         public boolean isNull(int column) {
535             return false;
536         }
537 
hadCalledOnChange()538         public boolean hadCalledOnChange() {
539             return mHadCalledOnChange;
540         }
541 
542         // the following are protected methods
543         @Override
checkPosition()544         protected void checkPosition() {
545             super.checkPosition();
546         }
547 
548         @Override
getUpdatedField(int columnIndex)549         protected Object getUpdatedField(int columnIndex) {
550             return super.getUpdatedField(columnIndex);
551         }
552 
553         @Override
isFieldUpdated(int columnIndex)554         protected boolean isFieldUpdated(int columnIndex) {
555             return super.isFieldUpdated(columnIndex);
556         }
557 
558         @Override
onChange(boolean selfChange)559         protected void onChange(boolean selfChange) {
560             super.onChange(selfChange);
561             mHadCalledOnChange = true;
562         }
563     }
564 
565     private class MockContentObserver extends ContentObserver {
566         public boolean mHadCalledOnChange;
567 
MockContentObserver()568         public MockContentObserver() {
569             super(null);
570         }
571 
572         @Override
onChange(boolean selfChange)573         public void onChange(boolean selfChange) {
574             super.onChange(selfChange);
575             mHadCalledOnChange = true;
576             synchronized(mLockObj) {
577                 mLockObj.notify();
578             }
579         }
580 
581         @Override
deliverSelfNotifications()582         public boolean deliverSelfNotifications() {
583             return true;
584         }
585 
hadCalledOnChange()586         public boolean hadCalledOnChange() {
587             return mHadCalledOnChange;
588         }
589     }
590 
591     private class MockDataSetObserver extends DataSetObserver {
592         private boolean mHadCalledOnChanged;
593         private boolean mHadCalledOnInvalid;
594 
595         @Override
onChanged()596         public void onChanged() {
597             super.onChanged();
598             mHadCalledOnChanged = true;
599         }
600 
601         @Override
onInvalidated()602         public void onInvalidated() {
603             super.onInvalidated();
604             mHadCalledOnInvalid = true;
605         }
606 
hadCalledOnChanged()607         public boolean hadCalledOnChanged() {
608             return mHadCalledOnChanged;
609         }
610 
hadCalledOnInvalid()611         public boolean hadCalledOnInvalid() {
612             return mHadCalledOnInvalid;
613         }
614     }
615 }
616