• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2009 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.sqlite.cts;
18 
19 
20 import android.content.Context;
21 import android.database.AbstractCursor;
22 import android.database.Cursor;
23 import android.database.CursorWindow;
24 import android.database.DataSetObserver;
25 import android.database.StaleDataException;
26 import android.database.sqlite.SQLiteCursor;
27 import android.database.sqlite.SQLiteDatabase;
28 import android.database.sqlite.SQLiteDirectCursorDriver;
29 import android.test.AndroidTestCase;
30 
31 import java.util.Arrays;
32 
33 /**
34  * Test {@link AbstractCursor}.
35  */
36 public class SQLiteCursorTest extends AndroidTestCase {
37     private SQLiteDatabase mDatabase;
38     private static final String[] COLUMNS = new String[] { "_id", "number_1", "number_2" };
39     private static final String TABLE_NAME = "test";
40     private static final String TABLE_COLUMNS = " number_1 INTEGER, number_2 INTEGER";
41     private static final int DEFAULT_TABLE_VALUE_BEGINS = 1;
42     private static final int TEST_COUNT = 10;
43     private static final String TEST_SQL = "SELECT * FROM test ORDER BY number_1";
44     private static final String DATABASE_FILE = "database_test.db";
45 
46     @Override
setUp()47     protected void setUp() throws Exception {
48         super.setUp();
49         getContext().deleteDatabase(DATABASE_FILE);
50         mDatabase = getContext().openOrCreateDatabase(DATABASE_FILE, Context.MODE_PRIVATE, null);
51         createTable(TABLE_NAME, TABLE_COLUMNS);
52         addValuesIntoTable(TABLE_NAME, DEFAULT_TABLE_VALUE_BEGINS, TEST_COUNT);
53     }
54 
55     @Override
tearDown()56     protected void tearDown() throws Exception {
57         mDatabase.close();
58         getContext().deleteDatabase(DATABASE_FILE);
59         super.tearDown();
60     }
61 
testConstructor()62     public void testConstructor() {
63         SQLiteDirectCursorDriver cursorDriver = new SQLiteDirectCursorDriver(mDatabase,
64                 TEST_SQL, TABLE_NAME, null);
65         try {
66             new SQLiteCursor(mDatabase, cursorDriver, TABLE_NAME, null);
67             fail("constructor didn't throw IllegalArgumentException when SQLiteQuery is null");
68         } catch (IllegalArgumentException e) {
69         }
70 
71         // get SQLiteCursor by querying database
72         SQLiteCursor cursor = getCursor();
73         assertNotNull(cursor);
74     }
75 
testClose()76     public void testClose() {
77         SQLiteCursor cursor = getCursor();
78         assertTrue(cursor.moveToFirst());
79         assertFalse(cursor.isClosed());
80         assertTrue(cursor.requery());
81         cursor.close();
82         assertFalse(cursor.requery());
83         try {
84             cursor.moveToFirst();
85             fail("moveToFirst didn't throw IllegalStateException after closed.");
86         } catch (IllegalStateException e) {
87         }
88         assertTrue(cursor.isClosed());
89     }
90 
testRegisterDataSetObserver()91     public void testRegisterDataSetObserver() {
92         SQLiteCursor cursor = getCursor();
93         MockCursorWindow cursorWindow = new MockCursorWindow(false);
94 
95         MockObserver observer = new MockObserver();
96 
97         cursor.setWindow(cursorWindow);
98         // Before registering, observer can't be notified.
99         assertFalse(observer.hasInvalidated());
100         cursor.moveToLast();
101         assertFalse(cursorWindow.isClosed());
102         cursor.deactivate();
103         assertFalse(observer.hasInvalidated());
104         // deactivate() will close the CursorWindow
105         assertTrue(cursorWindow.isClosed());
106 
107         // test registering DataSetObserver
108         assertTrue(cursor.requery());
109         cursor.registerDataSetObserver(observer);
110         assertFalse(observer.hasInvalidated());
111         cursor.moveToLast();
112         assertEquals(TEST_COUNT, cursor.getInt(1));
113         cursor.deactivate();
114         // deactivate method can invoke invalidate() method, can be observed by DataSetObserver.
115         assertTrue(observer.hasInvalidated());
116 
117         try {
118             cursor.getInt(1);
119             fail("After deactivating, cursor cannot execute getting value operations.");
120         } catch (StaleDataException e) {
121         }
122 
123         assertTrue(cursor.requery());
124         cursor.moveToLast();
125         assertEquals(TEST_COUNT, cursor.getInt(1));
126 
127         // can't register a same observer twice.
128         try {
129             cursor.registerDataSetObserver(observer);
130             fail("didn't throw IllegalStateException when register existed observer");
131         } catch (IllegalStateException e) {
132         }
133 
134         // after unregistering, observer can't be notified.
135         cursor.unregisterDataSetObserver(observer);
136         observer.resetStatus();
137         assertFalse(observer.hasInvalidated());
138         cursor.deactivate();
139         assertFalse(observer.hasInvalidated());
140     }
141 
testRequery()142     public void testRequery() {
143         final String DELETE = "DELETE FROM " + TABLE_NAME + " WHERE number_1 =";
144         final String DELETE_1 = DELETE + "1;";
145         final String DELETE_2 = DELETE + "2;";
146 
147         mDatabase.execSQL(DELETE_1);
148         // when cursor is created, it refreshes CursorWindow and populates cursor count
149         SQLiteCursor cursor = getCursor();
150         MockObserver observer = new MockObserver();
151         cursor.registerDataSetObserver(observer);
152         assertEquals(TEST_COUNT - 1, cursor.getCount());
153         assertFalse(observer.hasChanged());
154 
155         mDatabase.execSQL(DELETE_2);
156         // when getCount() has invoked once, it can no longer refresh CursorWindow.
157         assertEquals(TEST_COUNT - 1, cursor.getCount());
158 
159         assertTrue(cursor.requery());
160         // only after requery, getCount can get most up-to-date counting info now.
161         assertEquals(TEST_COUNT - 2, cursor.getCount());
162         assertTrue(observer.hasChanged());
163     }
164 
testRequery2()165     public void testRequery2() {
166         mDatabase.disableWriteAheadLogging();
167         mDatabase.execSQL("create table testRequery2 (i int);");
168         mDatabase.execSQL("insert into testRequery2 values(1);");
169         mDatabase.execSQL("insert into testRequery2 values(2);");
170         Cursor c = mDatabase.rawQuery("select * from testRequery2 order by i", null);
171         assertEquals(2, c.getCount());
172         assertTrue(c.moveToFirst());
173         assertEquals(1, c.getInt(0));
174         assertTrue(c.moveToNext());
175         assertEquals(2, c.getInt(0));
176         // add more data to the table and requery
177         mDatabase.execSQL("insert into testRequery2 values(3);");
178         assertTrue(c.requery());
179         assertEquals(3, c.getCount());
180         assertTrue(c.moveToFirst());
181         assertEquals(1, c.getInt(0));
182         assertTrue(c.moveToNext());
183         assertEquals(2, c.getInt(0));
184         assertTrue(c.moveToNext());
185         assertEquals(3, c.getInt(0));
186         // close the database and see if requery throws an exception
187         mDatabase.close();
188         assertFalse(c.requery());
189     }
190 
testGetColumnIndex()191     public void testGetColumnIndex() {
192         SQLiteCursor cursor = getCursor();
193 
194         for (int i = 0; i < COLUMNS.length; i++) {
195             assertEquals(i, cursor.getColumnIndex(COLUMNS[i]));
196         }
197 
198         assertTrue(Arrays.equals(COLUMNS, cursor.getColumnNames()));
199     }
200 
testSetSelectionArguments()201     public void testSetSelectionArguments() {
202         final String SELECTION = "_id > ?";
203         int TEST_ARG1 = 2;
204         int TEST_ARG2 = 5;
205         SQLiteCursor cursor = (SQLiteCursor) mDatabase.query(TABLE_NAME, null, SELECTION,
206                 new String[] { Integer.toString(TEST_ARG1) }, null, null, null);
207         assertEquals(TEST_COUNT - TEST_ARG1, cursor.getCount());
208         cursor.setSelectionArguments(new String[] { Integer.toString(TEST_ARG2) });
209         cursor.requery();
210         assertEquals(TEST_COUNT - TEST_ARG2, cursor.getCount());
211     }
212 
testOnMove()213     public void testOnMove() {
214         // Do not test this API. It is callback which:
215         // 1. The callback mechanism has been tested in super class
216         // 2. The functionality is implementation details, no need to test
217     }
218 
createTable(String tableName, String columnNames)219     private void createTable(String tableName, String columnNames) {
220         String sql = "Create TABLE " + tableName + " (_id INTEGER PRIMARY KEY, "
221                 + columnNames + " );";
222         mDatabase.execSQL(sql);
223     }
224 
addValuesIntoTable(String tableName, int start, int end)225     private void addValuesIntoTable(String tableName, int start, int end) {
226         for (int i = start; i <= end; i++) {
227             mDatabase.execSQL("INSERT INTO " + tableName + "(number_1) VALUES ('" + i + "');");
228         }
229     }
230 
getCursor()231     private SQLiteCursor getCursor() {
232         SQLiteCursor cursor = (SQLiteCursor) mDatabase.query(TABLE_NAME, null, null,
233                 null, null, null, null);
234         return cursor;
235     }
236 
237     private class MockObserver extends DataSetObserver {
238         private boolean mHasChanged = false;
239         private boolean mHasInvalidated = false;
240 
241         @Override
onChanged()242         public void onChanged() {
243             super.onChanged();
244             mHasChanged = true;
245         }
246 
247         @Override
onInvalidated()248         public void onInvalidated() {
249             super.onInvalidated();
250             mHasInvalidated = true;
251         }
252 
resetStatus()253         protected void resetStatus() {
254             mHasChanged = false;
255             mHasInvalidated = false;
256         }
257 
hasChanged()258         protected boolean hasChanged() {
259             return mHasChanged;
260         }
261 
hasInvalidated()262         protected boolean hasInvalidated () {
263             return mHasInvalidated;
264         }
265     }
266 
267     private class MockCursorWindow extends CursorWindow {
268         private boolean mIsClosed = false;
269 
MockCursorWindow(boolean localWindow)270         public MockCursorWindow(boolean localWindow) {
271             super(localWindow);
272         }
273 
274         @Override
close()275         public void close() {
276             super.close();
277             mIsClosed = true;
278         }
279 
isClosed()280         public boolean isClosed() {
281             return mIsClosed;
282         }
283     }
284 }
285