Home | History | Annotate | Download | only in cts
      1 /*
      2  * Copyright (C) 2007 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 import android.content.ContentValues;
     20 import android.content.Context;
     21 import android.database.Cursor;
     22 import android.database.CursorIndexOutOfBoundsException;
     23 import android.database.CursorWrapper;
     24 import android.database.DataSetObserver;
     25 import android.database.DatabaseUtils;
     26 import android.database.sqlite.SQLiteCursor;
     27 import android.database.sqlite.SQLiteCursorDriver;
     28 import android.database.sqlite.SQLiteDatabase;
     29 import android.database.sqlite.SQLiteQuery;
     30 import android.database.sqlite.SQLiteStatement;
     31 import android.os.Looper;
     32 import android.test.AndroidTestCase;
     33 import android.test.PerformanceTestCase;
     34 import android.test.suitebuilder.annotation.LargeTest;
     35 import android.test.suitebuilder.annotation.MediumTest;
     36 import android.util.Log;
     37 
     38 import java.io.File;
     39 import java.util.Arrays;
     40 import java.util.Random;
     41 
     42 public class DatabaseCursorTest extends AndroidTestCase implements PerformanceTestCase {
     43     private static final String sString1 = "this is a test";
     44     private static final String sString2 = "and yet another test";
     45     private static final String sString3 = "this string is a little longer, but still a test";
     46 
     47     private static final int CURRENT_DATABASE_VERSION = 42;
     48     private SQLiteDatabase mDatabase;
     49     private File mDatabaseFile;
     50     protected static final int TYPE_CURSOR = 0;
     51     protected static final int TYPE_CURSORWRAPPER = 1;
     52     private int  mTestType = TYPE_CURSOR;
     53 
     54     @Override
     55     protected void setUp() throws Exception {
     56         super.setUp();
     57         File dbDir = getContext().getDir("tests", Context.MODE_PRIVATE);
     58         mDatabaseFile = new File(dbDir, "database_test.db");
     59         if (mDatabaseFile.exists()) {
     60             mDatabaseFile.delete();
     61         }
     62         mDatabase = SQLiteDatabase.openOrCreateDatabase(mDatabaseFile.getPath(), null);
     63         assertNotNull(mDatabase);
     64         mDatabase.setVersion(CURRENT_DATABASE_VERSION);
     65     }
     66 
     67     @Override
     68     protected void tearDown() throws Exception {
     69         mDatabase.close();
     70         mDatabaseFile.delete();
     71         super.tearDown();
     72     }
     73 
     74     public void setupTestType(int testType) {
     75         mTestType = testType;
     76     }
     77 
     78     private Cursor getTestCursor(Cursor cursor) {
     79         switch (mTestType) {
     80         case TYPE_CURSORWRAPPER:
     81             return new CursorWrapper(cursor);
     82         case TYPE_CURSOR:
     83         default:
     84             return cursor;
     85         }
     86     }
     87 
     88     public boolean isPerformanceOnly() {
     89         return false;
     90     }
     91 
     92     // These test can only be run once.
     93     public int startPerformance(Intermediates intermediates) {
     94         return 1;
     95     }
     96 
     97     private void populateDefaultTable() {
     98         mDatabase.execSQL("CREATE TABLE test (_id INTEGER PRIMARY KEY, data TEXT);");
     99 
    100         mDatabase.execSQL("INSERT INTO test (data) VALUES ('" + sString1 + "');");
    101         mDatabase.execSQL("INSERT INTO test (data) VALUES ('" + sString2 + "');");
    102         mDatabase.execSQL("INSERT INTO test (data) VALUES ('" + sString3 + "');");
    103     }
    104 
    105     @MediumTest
    106     public void testBlob() throws Exception {
    107         // create table
    108         mDatabase.execSQL(
    109                 "CREATE TABLE test (_id INTEGER PRIMARY KEY, s TEXT, d REAL, l INTEGER, b BLOB);");
    110         // insert blob
    111         Object[] args = new Object[4];
    112 
    113         byte[] blob = new byte[1000];
    114         byte value = 99;
    115         Arrays.fill(blob, value);
    116         args[3] = blob;
    117 
    118         String s = new String("text");
    119         args[0] = s;
    120         Double d = 99.9;
    121         args[1] = d;
    122         Long l = (long) 1000;
    123         args[2] = l;
    124 
    125         String sql = "INSERT INTO test (s, d, l, b) VALUES (?,?,?,?)";
    126         mDatabase.execSQL(sql, args);
    127         // use cursor to access blob
    128 
    129         Cursor testCursor = mDatabase.query("test", null, null, null, null, null, null);
    130 
    131         testCursor.moveToNext();
    132         ContentValues cv = new ContentValues();
    133         DatabaseUtils.cursorRowToContentValues(testCursor, cv);
    134 
    135         int bCol = testCursor.getColumnIndexOrThrow("b");
    136         int sCol = testCursor.getColumnIndexOrThrow("s");
    137         int dCol = testCursor.getColumnIndexOrThrow("d");
    138         int lCol = testCursor.getColumnIndexOrThrow("l");
    139         byte[] cBlob = testCursor.getBlob(bCol);
    140         assertTrue(Arrays.equals(blob, cBlob));
    141         assertEquals(s, testCursor.getString(sCol));
    142         assertEquals((double) d, testCursor.getDouble(dCol));
    143         assertEquals((long) l, testCursor.getLong(lCol));
    144     }
    145 
    146     @MediumTest
    147     public void testRealColumns() throws Exception {
    148         mDatabase.execSQL("CREATE TABLE test (_id INTEGER PRIMARY KEY, data REAL);");
    149         ContentValues values = new ContentValues();
    150         values.put("data", 42.11);
    151         long id = mDatabase.insert("test", "data", values);
    152         assertTrue(id > 0);
    153         Cursor testCursor = getTestCursor(mDatabase.rawQuery("SELECT data FROM test", null));
    154         assertNotNull(testCursor);
    155         assertTrue(testCursor.moveToFirst());
    156         assertEquals(42.11, testCursor.getDouble(0));
    157         testCursor.close();
    158     }
    159 
    160     @MediumTest
    161     public void testCursor1() throws Exception {
    162         populateDefaultTable();
    163 
    164         Cursor testCursor = getTestCursor(mDatabase.query("test", null, null, null, null, null,
    165                 null));
    166 
    167         int dataColumn = testCursor.getColumnIndexOrThrow("data");
    168 
    169         // The cursor should ignore text before the last period when looking for a column. (This
    170         // is a temporary hack in all implementations of getColumnIndex.)
    171         int dataColumn2 = testCursor.getColumnIndexOrThrow("junk.data");
    172         assertEquals(dataColumn, dataColumn2);
    173 
    174         assertSame(3, testCursor.getCount());
    175 
    176         assertTrue(testCursor.isBeforeFirst());
    177 
    178         try {
    179             testCursor.getInt(0);
    180             fail("CursorIndexOutOfBoundsException expected");
    181         } catch (CursorIndexOutOfBoundsException ex) {
    182             // expected
    183         }
    184 
    185         testCursor.moveToNext();
    186         assertEquals(1, testCursor.getInt(0));
    187 
    188         String s = testCursor.getString(dataColumn);
    189         assertEquals(sString1, s);
    190 
    191         testCursor.moveToNext();
    192         s = testCursor.getString(dataColumn);
    193         assertEquals(sString2, s);
    194 
    195         testCursor.moveToNext();
    196         s = testCursor.getString(dataColumn);
    197         assertEquals(sString3, s);
    198 
    199         testCursor.moveToPosition(-1);
    200         testCursor.moveToNext();
    201         s = testCursor.getString(dataColumn);
    202         assertEquals(sString1, s);
    203 
    204         testCursor.moveToPosition(2);
    205         s = testCursor.getString(dataColumn);
    206         assertEquals(sString3, s);
    207 
    208         int i;
    209 
    210         for (testCursor.moveToFirst(), i = 0; !testCursor.isAfterLast();
    211                 testCursor.moveToNext(), i++) {
    212             testCursor.getInt(0);
    213         }
    214 
    215         assertEquals(3, i);
    216 
    217         try {
    218             testCursor.getInt(0);
    219             fail("CursorIndexOutOfBoundsException expected");
    220         } catch (CursorIndexOutOfBoundsException ex) {
    221             // expected
    222         }
    223         testCursor.close();
    224     }
    225 
    226     @MediumTest
    227     public void testCursor2() throws Exception {
    228         populateDefaultTable();
    229 
    230         Cursor testCursor = getTestCursor(mDatabase.query("test", null, "_id > 1000", null, null,
    231                 null, null));
    232         assertEquals(0, testCursor.getCount());
    233         assertTrue(testCursor.isBeforeFirst());
    234 
    235         try {
    236             testCursor.getInt(0);
    237             fail("CursorIndexOutOfBoundsException expected");
    238         } catch (CursorIndexOutOfBoundsException ex) {
    239             // expected
    240         }
    241 
    242         int i;
    243         for (testCursor.moveToFirst(), i = 0; !testCursor.isAfterLast();
    244                 testCursor.moveToNext(), i++) {
    245             testCursor.getInt(0);
    246         }
    247         assertEquals(0, i);
    248         try {
    249             testCursor.getInt(0);
    250             fail("CursorIndexOutOfBoundsException expected");
    251         } catch (CursorIndexOutOfBoundsException ex) {
    252             // expected
    253         }
    254         testCursor.close();
    255     }
    256 
    257     @MediumTest
    258     public void testLargeField() throws Exception {
    259         mDatabase.execSQL("CREATE TABLE test (_id INTEGER PRIMARY KEY, data TEXT);");
    260 
    261         StringBuilder sql = new StringBuilder(2100);
    262         sql.append("INSERT INTO test (data) VALUES ('");
    263         Random random = new Random(System.currentTimeMillis());
    264         StringBuilder randomString = new StringBuilder(1979);
    265         for (int i = 0; i < 1979; i++) {
    266             randomString.append((random.nextInt() & 0xf) % 10);
    267         }
    268         sql.append(randomString);
    269         sql.append("');");
    270         mDatabase.execSQL(sql.toString());
    271 
    272         Cursor testCursor = getTestCursor(mDatabase.query("test", null, null, null, null, null,
    273                 null));
    274         assertNotNull(testCursor);
    275         assertEquals(1, testCursor.getCount());
    276 
    277         assertTrue(testCursor.moveToFirst());
    278         assertEquals(0, testCursor.getPosition());
    279         String largeString = testCursor.getString(testCursor.getColumnIndexOrThrow("data"));
    280         assertNotNull(largeString);
    281         assertEquals(randomString.toString(), largeString);
    282         testCursor.close();
    283     }
    284 
    285     private class TestObserver extends DataSetObserver {
    286         int total;
    287         SQLiteCursor c;
    288         boolean quit = false;
    289 
    290         public TestObserver(int total_, SQLiteCursor cursor) {
    291             c = cursor;
    292             total = total_;
    293         }
    294 
    295         @Override
    296         public void onChanged() {
    297             int count = c.getCount();
    298             if (total == count) {
    299                 int i = 0;
    300                 while (c.moveToNext()) {
    301                     assertEquals(i, c.getInt(1));
    302                     i++;
    303                 }
    304                 assertEquals(count, i);
    305                 quit = true;
    306                 Looper.myLooper().quit();
    307             }
    308         }
    309 
    310         @Override
    311         public void onInvalidated() {
    312         }
    313     }
    314 
    315     @LargeTest
    316     public void testManyRowsLong() throws Exception {
    317         mDatabase.beginTransaction();
    318         final int count = 9000;
    319         try {
    320             mDatabase.execSQL("CREATE TABLE test (_id INTEGER PRIMARY KEY, data INT);");
    321 
    322             for (int i = 0; i < count; i++) {
    323                 mDatabase.execSQL("INSERT INTO test (data) VALUES (" + i + ");");
    324             }
    325             mDatabase.setTransactionSuccessful();
    326         } finally {
    327             mDatabase.endTransaction();
    328         }
    329 
    330         Cursor testCursor = getTestCursor(mDatabase.query("test", new String[] { "data" },
    331                 null, null, null, null, null));
    332         assertNotNull(testCursor);
    333 
    334         int i = 0;
    335         while (testCursor.moveToNext()) {
    336             assertEquals(i, testCursor.getInt(0));
    337             i++;
    338         }
    339         assertEquals(count, i);
    340         assertEquals(count, testCursor.getCount());
    341 
    342         Log.d("testManyRows", "count " + Integer.toString(i));
    343         testCursor.close();
    344     }
    345 
    346     @LargeTest
    347     public void testManyRowsTxt() throws Exception {
    348         mDatabase.execSQL("CREATE TABLE test (_id INTEGER PRIMARY KEY, data TEXT);");
    349         StringBuilder sql = new StringBuilder(2100);
    350         sql.append("INSERT INTO test (data) VALUES ('");
    351         Random random = new Random(System.currentTimeMillis());
    352         StringBuilder randomString = new StringBuilder(1979);
    353         for (int i = 0; i < 1979; i++) {
    354             randomString.append((random.nextInt() & 0xf) % 10);
    355         }
    356         sql.append(randomString);
    357         sql.append("');");
    358 
    359         // if cursor window size changed, adjust this value too
    360         final int count = 600; // more than two fillWindow needed
    361         for (int i = 0; i < count; i++) {
    362             mDatabase.execSQL(sql.toString());
    363         }
    364 
    365         Cursor testCursor = getTestCursor(mDatabase.query("test", new String[] { "data" }, null,
    366                 null, null, null, null));
    367         assertNotNull(testCursor);
    368 
    369         int i = 0;
    370         while (testCursor.moveToNext()) {
    371             assertEquals(randomString.toString(), testCursor.getString(0));
    372             i++;
    373         }
    374         assertEquals(count, i);
    375         assertEquals(count, testCursor.getCount());
    376         testCursor.close();
    377     }
    378 
    379     @LargeTest
    380     public void testManyRowsTxtLong() throws Exception {
    381         mDatabase.execSQL("CREATE TABLE test (_id INTEGER PRIMARY KEY, txt TEXT, data INT);");
    382 
    383         Random random = new Random(System.currentTimeMillis());
    384         StringBuilder randomString = new StringBuilder(1979);
    385         for (int i = 0; i < 1979; i++) {
    386             randomString.append((random.nextInt() & 0xf) % 10);
    387         }
    388 
    389         // if cursor window size changed, adjust this value too
    390         final int count = 600;
    391         for (int i = 0; i < count; i++) {
    392             StringBuilder sql = new StringBuilder(2100);
    393             sql.append("INSERT INTO test (txt, data) VALUES ('");
    394             sql.append(randomString);
    395             sql.append("','");
    396             sql.append(i);
    397             sql.append("');");
    398             mDatabase.execSQL(sql.toString());
    399         }
    400 
    401         Cursor testCursor = getTestCursor(mDatabase.query("test", new String[] { "txt", "data" },
    402                 null, null, null, null, null));
    403         assertNotNull(testCursor);
    404 
    405         int i = 0;
    406         while (testCursor.moveToNext()) {
    407             assertEquals(randomString.toString(), testCursor.getString(0));
    408             assertEquals(i, testCursor.getInt(1));
    409             i++;
    410         }
    411         assertEquals(count, i);
    412         assertEquals(count, testCursor.getCount());
    413         testCursor.close();
    414     }
    415 
    416     @MediumTest
    417     public void testRequery() throws Exception {
    418         populateDefaultTable();
    419 
    420         Cursor testCursor = getTestCursor(mDatabase.rawQuery("SELECT * FROM test", null));
    421         assertNotNull(testCursor);
    422         assertEquals(3, testCursor.getCount());
    423         testCursor.deactivate();
    424         testCursor.requery();
    425         assertEquals(3, testCursor.getCount());
    426         testCursor.close();
    427     }
    428 
    429     @MediumTest
    430     public void testRequeryWithSelection() throws Exception {
    431         populateDefaultTable();
    432 
    433         Cursor testCursor = getTestCursor(
    434                 mDatabase.rawQuery("SELECT data FROM test WHERE data = '" + sString1 + "'",
    435                 null));
    436         assertNotNull(testCursor);
    437         assertEquals(1, testCursor.getCount());
    438         assertTrue(testCursor.moveToFirst());
    439         assertEquals(sString1, testCursor.getString(0));
    440         testCursor.deactivate();
    441         testCursor.requery();
    442         assertEquals(1, testCursor.getCount());
    443         assertTrue(testCursor.moveToFirst());
    444         assertEquals(sString1, testCursor.getString(0));
    445         testCursor.close();
    446     }
    447 
    448     @MediumTest
    449     public void testRequeryWithSelectionArgs() throws Exception {
    450         populateDefaultTable();
    451 
    452         Cursor testCursor = getTestCursor(mDatabase.rawQuery("SELECT data FROM test WHERE data = ?",
    453                 new String[] { sString1 }));
    454         assertNotNull(testCursor);
    455         assertEquals(1, testCursor.getCount());
    456         assertTrue(testCursor.moveToFirst());
    457         assertEquals(sString1, testCursor.getString(0));
    458         testCursor.deactivate();
    459         testCursor.requery();
    460         assertEquals(1, testCursor.getCount());
    461         assertTrue(testCursor.moveToFirst());
    462         assertEquals(sString1, testCursor.getString(0));
    463         testCursor.close();
    464     }
    465 
    466     @MediumTest
    467     public void testRequeryWithAlteredSelectionArgs() throws Exception {
    468         /**
    469          * Test the ability of a subclass of SQLiteCursor to change its query arguments.
    470          */
    471         populateDefaultTable();
    472 
    473         SQLiteDatabase.CursorFactory factory = new SQLiteDatabase.CursorFactory() {
    474             public Cursor newCursor(SQLiteDatabase db, SQLiteCursorDriver masterQuery,
    475                     String editTable, SQLiteQuery query) {
    476                 return new SQLiteCursor(db, masterQuery, editTable, query) {
    477                     @Override
    478                     public boolean requery() {
    479                         setSelectionArguments(new String[] { "2" });
    480                         return super.requery();
    481                     }
    482                 };
    483             }
    484         };
    485         Cursor testCursor = getTestCursor(mDatabase.rawQueryWithFactory(factory,
    486                 "SELECT data FROM test WHERE _id <= ?",
    487                 new String[] { "1" }, null));
    488         assertNotNull(testCursor);
    489         assertEquals(1, testCursor.getCount());
    490         assertTrue(testCursor.moveToFirst());
    491         assertEquals(sString1, testCursor.getString(0));
    492 
    493         // Our hacked requery() changes the query arguments in the cursor.
    494         testCursor.requery();
    495 
    496         assertEquals(2, testCursor.getCount());
    497         assertTrue(testCursor.moveToFirst());
    498         assertEquals(sString1, testCursor.getString(0));
    499         assertTrue(testCursor.moveToNext());
    500         assertEquals(sString2, testCursor.getString(0));
    501 
    502         // Test that setting query args on a deactivated cursor also works.
    503         testCursor.deactivate();
    504         testCursor.requery();
    505     }
    506 }
    507