DatabaseGeneralTest.java revision 59d60420ba9246eee152852b6a597a0aba7f704d
1/*
2 * Copyright (C) 2006 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.database;
18
19import static android.database.DatabaseUtils.InsertHelper.TABLE_INFO_PRAGMA_COLUMNNAME_INDEX;
20import static android.database.DatabaseUtils.InsertHelper.TABLE_INFO_PRAGMA_DEFAULT_INDEX;
21import android.content.ContentValues;
22import android.content.Context;
23import android.database.sqlite.SQLiteDatabase;
24import android.os.Handler;
25import android.os.Parcel;
26import android.test.AndroidTestCase;
27import android.test.PerformanceTestCase;
28import android.test.suitebuilder.annotation.LargeTest;
29import android.test.suitebuilder.annotation.MediumTest;
30import android.test.suitebuilder.annotation.SmallTest;
31import android.util.Log;
32import android.util.Pair;
33
34import junit.framework.Assert;
35
36import java.io.File;
37import java.util.ArrayList;
38import java.util.Arrays;
39import java.util.Locale;
40
41public class DatabaseGeneralTest extends AndroidTestCase implements PerformanceTestCase {
42    private static final String TAG = "DatabaseGeneralTest";
43
44    private static final String sString1 = "this is a test";
45    private static final String sString2 = "and yet another test";
46    private static final String sString3 = "this string is a little longer, but still a test";
47    private static final String PHONE_NUMBER = "16175551212";
48
49    private static final int CURRENT_DATABASE_VERSION = 42;
50    private SQLiteDatabase mDatabase;
51    private File mDatabaseFile;
52
53    @Override
54    protected void setUp() throws Exception {
55        super.setUp();
56        File dbDir = getContext().getDir(this.getClass().getName(), Context.MODE_PRIVATE);
57        mDatabaseFile = new File(dbDir, "database_test.db");
58        if (mDatabaseFile.exists()) {
59            mDatabaseFile.delete();
60        }
61        mDatabase = SQLiteDatabase.openOrCreateDatabase(mDatabaseFile.getPath(), null);
62        assertNotNull(mDatabase);
63        mDatabase.setVersion(CURRENT_DATABASE_VERSION);
64    }
65
66    @Override
67    protected void tearDown() throws Exception {
68        mDatabase.close();
69        mDatabaseFile.delete();
70        super.tearDown();
71    }
72
73    public boolean isPerformanceOnly() {
74        return false;
75    }
76
77    // These test can only be run once.
78    public int startPerformance(Intermediates intermediates) {
79        return 1;
80    }
81
82    private void populateDefaultTable() {
83        mDatabase.execSQL("CREATE TABLE test (_id INTEGER PRIMARY KEY, data TEXT);");
84
85        mDatabase.execSQL("INSERT INTO test (data) VALUES ('" + sString1 + "');");
86        mDatabase.execSQL("INSERT INTO test (data) VALUES ('" + sString2 + "');");
87        mDatabase.execSQL("INSERT INTO test (data) VALUES ('" + sString3 + "');");
88    }
89
90    @MediumTest
91    public void testVersion() throws Exception {
92        assertEquals(CURRENT_DATABASE_VERSION, mDatabase.getVersion());
93        mDatabase.setVersion(11);
94        assertEquals(11, mDatabase.getVersion());
95    }
96
97    @MediumTest
98    public void testUpdate() throws Exception {
99        populateDefaultTable();
100
101        ContentValues values = new ContentValues(1);
102        values.put("data", "this is an updated test");
103        assertEquals(1, mDatabase.update("test", values, "_id=1", null));
104        Cursor c = mDatabase.query("test", null, "_id=1", null, null, null, null);
105        assertNotNull(c);
106        assertEquals(1, c.getCount());
107        c.moveToFirst();
108        String value = c.getString(c.getColumnIndexOrThrow("data"));
109        assertEquals("this is an updated test", value);
110    }
111
112    @MediumTest
113    public void testPhoneNumbersEqual() throws Exception {
114        mDatabase.execSQL("CREATE TABLE phones (num TEXT);");
115        mDatabase.execSQL("INSERT INTO phones (num) VALUES ('911');");
116        mDatabase.execSQL("INSERT INTO phones (num) VALUES ('5555');");
117        mDatabase.execSQL("INSERT INTO phones (num) VALUES ('+" + PHONE_NUMBER + "');");
118
119        String number;
120        Cursor c;
121
122        c = mDatabase.query("phones", null,
123                "PHONE_NUMBERS_EQUAL(num, '504-555-7683')", null, null, null, null);
124        assertTrue(c == null || c.getCount() == 0);
125        c.close();
126
127        c = mDatabase.query("phones", null,
128                "PHONE_NUMBERS_EQUAL(num, '911')", null, null, null, null);
129        assertNotNull(c);
130        assertEquals(1, c.getCount());
131        c.moveToFirst();
132        number = c.getString(c.getColumnIndexOrThrow("num"));
133        assertEquals("911", number);
134        c.close();
135
136        c = mDatabase.query("phones", null,
137                "PHONE_NUMBERS_EQUAL(num, '5555')", null, null, null, null);
138        assertNotNull(c);
139        assertEquals(1, c.getCount());
140        c.moveToFirst();
141        number = c.getString(c.getColumnIndexOrThrow("num"));
142        assertEquals("5555", number);
143        c.close();
144
145        c = mDatabase.query("phones", null,
146                "PHONE_NUMBERS_EQUAL(num, '180055555555')", null, null, null, null);
147        assertTrue(c == null || c.getCount() == 0);
148        c.close();
149
150        c = mDatabase.query("phones", null,
151                "PHONE_NUMBERS_EQUAL(num, '+" + PHONE_NUMBER + "')", null, null, null, null);
152        assertNotNull(c);
153        assertEquals(1, c.getCount());
154        c.moveToFirst();
155        number = c.getString(c.getColumnIndexOrThrow("num"));
156        assertEquals("+" + PHONE_NUMBER, number);
157        c.close();
158
159        c = mDatabase.query("phones", null,
160                "PHONE_NUMBERS_EQUAL(num, '+1 (617).555-1212')", null, null, null, null);
161        assertNotNull(c);
162        assertEquals(1, c.getCount());
163        c.moveToFirst();
164        number = c.getString(c.getColumnIndexOrThrow("num"));
165        assertEquals("+" + PHONE_NUMBER, number);
166        c.close();
167
168        c = mDatabase.query("phones", null,
169                "PHONE_NUMBERS_EQUAL(num, '" + PHONE_NUMBER + "')", null, null, null, null);
170        assertNotNull(c);
171        assertEquals(1, c.getCount());
172        c.moveToFirst();
173        number = c.getString(c.getColumnIndexOrThrow("num"));
174        assertEquals("+" + PHONE_NUMBER, number);
175        c.close();
176
177        /*
178        c = mDatabase.query("phones", null,
179                "PHONE_NUMBERS_EQUAL(num, '5551212')", null, null, null, null);
180        assertNotNull(c);
181        assertEquals(1, c.getCount());
182        c.moveToFirst();
183        number = c.getString(c.getColumnIndexOrThrow("num"));
184        assertEquals("+" + PHONE_NUMBER, number);
185        c.close();
186        */
187
188        c = mDatabase.query("phones", null,
189                "PHONE_NUMBERS_EQUAL(num, '011" + PHONE_NUMBER + "')", null, null, null, null);
190        assertNotNull(c);
191        assertEquals(1, c.getCount());
192        c.moveToFirst();
193        number = c.getString(c.getColumnIndexOrThrow("num"));
194        assertEquals("+" + PHONE_NUMBER, number);
195        c.close();
196
197        c = mDatabase.query("phones", null,
198                "PHONE_NUMBERS_EQUAL(num, '00" + PHONE_NUMBER + "')", null, null, null, null);
199        assertNotNull(c);
200        assertEquals(1, c.getCount());
201        c.moveToFirst();
202        number = c.getString(c.getColumnIndexOrThrow("num"));
203        assertEquals("+" + PHONE_NUMBER, number);
204        c.close();
205    }
206
207    private void phoneNumberCompare(String phone1, String phone2, boolean equal,
208            boolean useStrictComparation) {
209        String[] temporalPhoneNumbers = new String[2];
210        temporalPhoneNumbers[0] = phone1;
211        temporalPhoneNumbers[1] = phone2;
212
213        Cursor cursor = mDatabase.rawQuery(
214                String.format(
215                        "SELECT CASE WHEN PHONE_NUMBERS_EQUAL(?, ?, %d) " +
216                        "THEN 'equal' ELSE 'not equal' END",
217                        (useStrictComparation ? 1 : 0)),
218                temporalPhoneNumbers);
219        try {
220            assertNotNull(cursor);
221            assertTrue(cursor.moveToFirst());
222            if (equal) {
223                assertEquals(String.format("Unexpectedly, \"%s != %s\".", phone1, phone2),
224                        "equal", cursor.getString(0));
225            } else {
226                assertEquals(String.format("Unexpectedly, \"%s\" == \"%s\".", phone1, phone2),
227                        "not equal", cursor.getString(0));
228            }
229        } finally {
230            if (cursor != null) {
231                cursor.close();
232            }
233        }
234    }
235
236    private void assertPhoneNumberEqual(String phone1, String phone2) throws Exception {
237        assertPhoneNumberEqual(phone1, phone2, true);
238        assertPhoneNumberEqual(phone1, phone2, false);
239    }
240
241    private void assertPhoneNumberEqual(String phone1, String phone2, boolean useStrict)
242            throws Exception {
243        phoneNumberCompare(phone1, phone2, true, useStrict);
244    }
245
246    private void assertPhoneNumberNotEqual(String phone1, String phone2) throws Exception {
247        assertPhoneNumberNotEqual(phone1, phone2, true);
248        assertPhoneNumberNotEqual(phone1, phone2, false);
249    }
250
251    private void assertPhoneNumberNotEqual(String phone1, String phone2, boolean useStrict)
252            throws Exception {
253        phoneNumberCompare(phone1, phone2, false, useStrict);
254    }
255
256    /**
257     * Tests international matching issues for the PHONE_NUMBERS_EQUAL function.
258     *
259     * @throws Exception
260     */
261    @SmallTest
262    public void testPhoneNumbersEqualInternationl() throws Exception {
263        assertPhoneNumberEqual("1", "1");
264        assertPhoneNumberEqual("123123", "123123");
265        assertPhoneNumberNotEqual("123123", "923123");
266        assertPhoneNumberNotEqual("123123", "123129");
267        assertPhoneNumberNotEqual("123123", "1231234");
268        assertPhoneNumberNotEqual("123123", "0123123", false);
269        assertPhoneNumberNotEqual("123123", "0123123", true);
270        assertPhoneNumberEqual("650-253-0000", "6502530000");
271        assertPhoneNumberEqual("650-253-0000", "650 253 0000");
272        assertPhoneNumberEqual("650 253 0000", "6502530000");
273        assertPhoneNumberEqual("+1 650-253-0000", "6502530000");
274        assertPhoneNumberEqual("001 650-253-0000", "6502530000");
275        assertPhoneNumberEqual("0111 650-253-0000", "6502530000");
276
277        // Russian trunk digit
278        assertPhoneNumberEqual("+79161234567", "89161234567");
279
280        // French trunk digit
281        assertPhoneNumberEqual("+33123456789", "0123456789");
282
283        // Trunk digit for city codes in the Netherlands
284        assertPhoneNumberEqual("+31771234567", "0771234567");
285
286        // Test broken caller ID seen on call from Thailand to the US
287        assertPhoneNumberEqual("+66811234567", "166811234567");
288
289        // Test the same in-country number with different country codes
290        assertPhoneNumberNotEqual("+33123456789", "+1123456789");
291
292        // Test one number with country code and the other without
293        assertPhoneNumberEqual("5125551212", "+15125551212");
294
295        // Test two NANP numbers that only differ in the area code
296        assertPhoneNumberNotEqual("5125551212", "6505551212");
297
298        // Japanese phone numbers
299        assertPhoneNumberEqual("090-1234-5678", "+819012345678");
300        assertPhoneNumberEqual("090(1234)5678", "+819012345678");
301        assertPhoneNumberEqual("090-1234-5678", "+81-90-1234-5678");
302
303        // Equador
304        assertPhoneNumberEqual("+593(800)123-1234", "8001231234");
305        assertPhoneNumberEqual("+593-2-1234-123", "21234123");
306
307        // Two continuous 0 at the beginning of the phone string should not be
308        // treated as trunk prefix in the strict comparation.
309        assertPhoneNumberEqual("008001231234", "8001231234", false);
310        assertPhoneNumberNotEqual("008001231234", "8001231234", true);
311
312        // Confirm that the bug found before does not re-appear in the strict compalation
313        assertPhoneNumberEqual("080-1234-5678", "+819012345678", false);
314        assertPhoneNumberNotEqual("080-1234-5678", "+819012345678", true);
315    }
316
317    @MediumTest
318    public void testCopyString() throws Exception {
319        mDatabase.execSQL("CREATE TABLE guess (numi INTEGER, numf FLOAT, str TEXT);");
320        mDatabase.execSQL(
321                "INSERT INTO guess (numi,numf,str) VALUES (0,0.0,'ZoomZoomZoomZoom');");
322        mDatabase.execSQL("INSERT INTO guess (numi,numf,str) VALUES (2000000000,3.1415926535,'');");
323        String chinese = "\u4eac\u4ec5 \u5c3d\u5f84\u60ca";
324        String[] arr = new String[1];
325        arr[0] = chinese;
326        mDatabase.execSQL("INSERT INTO guess (numi,numf,str) VALUES (-32768,-1.0,?)", arr);
327
328        Cursor c;
329
330        c = mDatabase.rawQuery("SELECT * FROM guess", null);
331
332        c.moveToFirst();
333
334        CharArrayBuffer buf = new CharArrayBuffer(14);
335
336        String compareTo = c.getString(c.getColumnIndexOrThrow("numi"));
337        int numiIdx = c.getColumnIndexOrThrow("numi");
338        int numfIdx = c.getColumnIndexOrThrow("numf");
339        int strIdx = c.getColumnIndexOrThrow("str");
340
341        c.copyStringToBuffer(numiIdx, buf);
342        assertEquals(1, buf.sizeCopied);
343        assertEquals(compareTo, new String(buf.data, 0, buf.sizeCopied));
344
345        c.copyStringToBuffer(strIdx, buf);
346        assertEquals("ZoomZoomZoomZoom", new String(buf.data, 0, buf.sizeCopied));
347
348        c.moveToNext();
349        compareTo = c.getString(numfIdx);
350
351        c.copyStringToBuffer(numfIdx, buf);
352        assertEquals(compareTo, new String(buf.data, 0, buf.sizeCopied));
353        c.copyStringToBuffer(strIdx, buf);
354        assertEquals(0, buf.sizeCopied);
355
356        c.moveToNext();
357        c.copyStringToBuffer(numfIdx, buf);
358        assertEquals(-1.0, Double.valueOf(
359                new String(buf.data, 0, buf.sizeCopied)).doubleValue());
360
361        c.copyStringToBuffer(strIdx, buf);
362        compareTo = c.getString(strIdx);
363        assertEquals(chinese, compareTo);
364
365        assertEquals(chinese, new String(buf.data, 0, buf.sizeCopied));
366        c.close();
367    }
368
369    @MediumTest
370    public void testSchemaChange1() throws Exception {
371        SQLiteDatabase db1 = mDatabase;
372        Cursor cursor;
373
374        db1.execSQL("CREATE TABLE db1 (_id INTEGER PRIMARY KEY, data TEXT);");
375
376        cursor = db1.query("db1", null, null, null, null, null, null);
377        assertNotNull("Cursor is null", cursor);
378
379        db1.execSQL("CREATE TABLE db2 (_id INTEGER PRIMARY KEY, data TEXT);");
380
381        assertEquals(0, cursor.getCount());
382        cursor.deactivate();
383    }
384
385    @MediumTest
386    public void testSchemaChange2() throws Exception {
387        SQLiteDatabase db1 = mDatabase;
388        SQLiteDatabase db2 = SQLiteDatabase.openOrCreateDatabase(mDatabaseFile, null);
389        Cursor cursor;
390
391        db1.execSQL("CREATE TABLE db1 (_id INTEGER PRIMARY KEY, data TEXT);");
392
393        cursor = db1.query("db1", null, null, null, null, null, null);
394        assertNotNull("Cursor is null", cursor);
395        assertEquals(0, cursor.getCount());
396        cursor.deactivate();
397        // this cause exception because we're still using sqlite_prepate16 and not
398        // sqlite_prepare16_v2. The v2 variant added the ability to check the
399        // schema version and handle the case when the schema has changed
400        // Marco Nelissen claim it was 2x slower to compile SQL statements so
401        // I reverted back to the v1 variant.
402        /* db2.execSQL("CREATE TABLE db2 (_id INTEGER PRIMARY KEY, data TEXT);");
403
404        cursor = db1.query("db1", null, null, null, null, null, null);
405        assertNotNull("Cursor is null", cursor);
406        assertEquals(0, cursor.count());
407        cursor.deactivate();
408        */
409    }
410
411    @MediumTest
412    public void testSchemaChange3() throws Exception {
413        SQLiteDatabase db1 = mDatabase;
414        SQLiteDatabase db2 = SQLiteDatabase.openOrCreateDatabase(mDatabaseFile, null);
415        Cursor cursor;
416
417
418        db1.execSQL("CREATE TABLE db1 (_id INTEGER PRIMARY KEY, data TEXT);");
419        db1.execSQL("INSERT INTO db1 (data) VALUES ('test');");
420
421        cursor = db1.query("db1", null, null, null, null, null, null);
422        // this cause exception because we're still using sqlite_prepate16 and not
423        // sqlite_prepare16_v2. The v2 variant added the ability to check the
424        // schema version and handle the case when the schema has changed
425        // Marco Nelissen claim it was 2x slower to compile SQL statements so
426        // I reverted back to the v1 variant.
427        /* db2.execSQL("CREATE TABLE db2 (_id INTEGER PRIMARY KEY, data TEXT);");
428
429        assertNotNull("Cursor is null", cursor);
430        assertEquals(1, cursor.count());
431        assertTrue(cursor.first());
432        assertEquals("test", cursor.getString(cursor.getColumnIndexOrThrow("data")));
433        cursor.deactivate();
434        */
435    }
436
437    private class ChangeObserver extends ContentObserver {
438        private int mCursorNotificationCount = 0;
439        private int mNotificationCount = 0;
440
441        public int getCursorNotificationCount() {
442            return mCursorNotificationCount;
443        }
444
445        public int getNotificationCount() {
446            return mNotificationCount;
447        }
448
449        public ChangeObserver(boolean cursor) {
450            super(new Handler());
451            mCursor = cursor;
452        }
453
454        @Override
455        public boolean deliverSelfNotifications() {
456            return true;
457        }
458
459        @Override
460        public void onChange(boolean selfChange) {
461            if (mCursor) {
462                mCursorNotificationCount++;
463            } else {
464                mNotificationCount++;
465            }
466        }
467
468        boolean mCursor;
469    }
470
471    @MediumTest
472    public void testSelectionArgs() throws Exception {
473        mDatabase.execSQL("CREATE TABLE test (_id INTEGER PRIMARY KEY, data TEXT);");
474        ContentValues values = new ContentValues(1);
475        values.put("data", "don't forget to handled 's");
476        mDatabase.insert("test", "data", values);
477        values.clear();
478        values.put("data", "no apostrophes here");
479        mDatabase.insert("test", "data", values);
480        Cursor c = mDatabase.query(
481                "test", null, "data GLOB ?", new String[]{"*'*"}, null, null, null);
482        assertEquals(1, c.getCount());
483        assertTrue(c.moveToFirst());
484        assertEquals("don't forget to handled 's", c.getString(1));
485        c.deactivate();
486
487        // make sure code should checking null string properly so that
488        // it won't crash
489        try {
490            mDatabase.query("test", new String[]{"_id"},
491                    "_id=?", new String[]{null}, null, null, null);
492            fail("expected exception not thrown");
493        } catch (IllegalArgumentException e) {
494            // expected
495        }
496    }
497
498    @MediumTest
499    public void testTokenize() throws Exception {
500        Cursor c;
501        mDatabase.execSQL("CREATE TABLE tokens (" +
502                "token TEXT COLLATE unicode," +
503                "source INTEGER," +
504                "token_index INTEGER," +
505                "tag TEXT" +
506                ");");
507        mDatabase.execSQL("CREATE TABLE tokens_no_index (" +
508                "token TEXT COLLATE unicode," +
509                "source INTEGER" +
510                ");");
511
512        Assert.assertEquals(0, DatabaseUtils.longForQuery(mDatabase,
513                "SELECT _TOKENIZE(NULL, NULL, NULL, NULL)", null));
514        Assert.assertEquals(0, DatabaseUtils.longForQuery(mDatabase,
515                "SELECT _TOKENIZE('tokens', NULL, NULL, NULL)", null));
516        Assert.assertEquals(0, DatabaseUtils.longForQuery(mDatabase,
517                "SELECT _TOKENIZE('tokens', 10, NULL, NULL)", null));
518        Assert.assertEquals(0, DatabaseUtils.longForQuery(mDatabase,
519                "SELECT _TOKENIZE('tokens', 10, 'some string', NULL)", null));
520
521        Assert.assertEquals(3, DatabaseUtils.longForQuery(mDatabase,
522                "SELECT _TOKENIZE('tokens', 11, 'some string ok', ' ', 1, 'foo')", null));
523        Assert.assertEquals(2, DatabaseUtils.longForQuery(mDatabase,
524                "SELECT _TOKENIZE('tokens', 11, 'second field', ' ', 1, 'bar')", null));
525
526        Assert.assertEquals(3, DatabaseUtils.longForQuery(mDatabase,
527                "SELECT _TOKENIZE('tokens_no_index', 20, 'some string ok', ' ')", null));
528        Assert.assertEquals(3, DatabaseUtils.longForQuery(mDatabase,
529                "SELECT _TOKENIZE('tokens_no_index', 21, 'foo bar baz', ' ', 0)", null));
530
531        // test Chinese
532        String chinese = new String("\u4eac\u4ec5 \u5c3d\u5f84\u60ca");
533        Assert.assertEquals(2, DatabaseUtils.longForQuery(mDatabase,
534                "SELECT _TOKENIZE('tokens', 12,'" + chinese + "', ' ', 1)", null));
535
536        String icustr = new String("Fr\u00e9d\u00e9ric Hj\u00f8nnev\u00e5g");
537
538        Assert.assertEquals(2, DatabaseUtils.longForQuery(mDatabase,
539                "SELECT _TOKENIZE('tokens', 13, '" + icustr + "', ' ', 1)", null));
540
541        Assert.assertEquals(9, DatabaseUtils.longForQuery(mDatabase,
542                "SELECT count(*) from tokens;", null));
543
544        String key = DatabaseUtils.getHexCollationKey("Frederic Hjonneva");
545        Assert.assertEquals(1, DatabaseUtils.longForQuery(mDatabase,
546                "SELECT count(*) from tokens where token GLOB '" + key + "*'", null));
547        Assert.assertEquals(13, DatabaseUtils.longForQuery(mDatabase,
548                "SELECT source from tokens where token GLOB '" + key + "*'", null));
549        Assert.assertEquals(0, DatabaseUtils.longForQuery(mDatabase,
550                "SELECT token_index from tokens where token GLOB '" + key + "*'", null));
551        key = DatabaseUtils.getHexCollationKey("Hjonneva");
552        Assert.assertEquals(1, DatabaseUtils.longForQuery(mDatabase,
553                "SELECT count(*) from tokens where token GLOB '" + key + "*'", null));
554        Assert.assertEquals(13, DatabaseUtils.longForQuery(mDatabase,
555                "SELECT source from tokens where token GLOB '" + key + "*'", null));
556        Assert.assertEquals(1, DatabaseUtils.longForQuery(mDatabase,
557                "SELECT token_index from tokens where token GLOB '" + key + "*'", null));
558
559        key = DatabaseUtils.getHexCollationKey("some string ok");
560        Assert.assertEquals(1, DatabaseUtils.longForQuery(mDatabase,
561                "SELECT count(*) from tokens where token GLOB '" + key + "*'", null));
562        Assert.assertEquals(11, DatabaseUtils.longForQuery(mDatabase,
563                "SELECT source from tokens where token GLOB '" + key + "*'", null));
564        Assert.assertEquals(0, DatabaseUtils.longForQuery(mDatabase,
565                "SELECT token_index from tokens where token GLOB '" + key + "*'", null));
566        Assert.assertEquals("foo", DatabaseUtils.stringForQuery(mDatabase,
567                "SELECT tag from tokens where token GLOB '" + key + "*'", null));
568        key = DatabaseUtils.getHexCollationKey("string");
569        Assert.assertEquals(1, DatabaseUtils.longForQuery(mDatabase,
570                "SELECT count(*) from tokens where token GLOB '" + key + "*'", null));
571        Assert.assertEquals(11, DatabaseUtils.longForQuery(mDatabase,
572                "SELECT source from tokens where token GLOB '" + key + "*'", null));
573        Assert.assertEquals(1, DatabaseUtils.longForQuery(mDatabase,
574                "SELECT token_index from tokens where token GLOB '" + key + "*'", null));
575        Assert.assertEquals("foo", DatabaseUtils.stringForQuery(mDatabase,
576                "SELECT tag from tokens where token GLOB '" + key + "*'", null));
577        key = DatabaseUtils.getHexCollationKey("ok");
578        Assert.assertEquals(1, DatabaseUtils.longForQuery(mDatabase,
579                "SELECT count(*) from tokens where token GLOB '" + key + "*'", null));
580        Assert.assertEquals(11, DatabaseUtils.longForQuery(mDatabase,
581                "SELECT source from tokens where token GLOB '" + key + "*'", null));
582        Assert.assertEquals(2, DatabaseUtils.longForQuery(mDatabase,
583                "SELECT token_index from tokens where token GLOB '" + key + "*'", null));
584        Assert.assertEquals("foo", DatabaseUtils.stringForQuery(mDatabase,
585                "SELECT tag from tokens where token GLOB '" + key + "*'", null));
586
587        key = DatabaseUtils.getHexCollationKey("second field");
588        Assert.assertEquals(1, DatabaseUtils.longForQuery(mDatabase,
589                "SELECT count(*) from tokens where token GLOB '" + key + "*'", null));
590        Assert.assertEquals(11, DatabaseUtils.longForQuery(mDatabase,
591                "SELECT source from tokens where token GLOB '" + key + "*'", null));
592        Assert.assertEquals(0, DatabaseUtils.longForQuery(mDatabase,
593                "SELECT token_index from tokens where token GLOB '" + key + "*'", null));
594        Assert.assertEquals("bar", DatabaseUtils.stringForQuery(mDatabase,
595                "SELECT tag from tokens where token GLOB '" + key + "*'", null));
596        key = DatabaseUtils.getHexCollationKey("field");
597        Assert.assertEquals(1, DatabaseUtils.longForQuery(mDatabase,
598                "SELECT count(*) from tokens where token GLOB '" + key + "*'", null));
599        Assert.assertEquals(11, DatabaseUtils.longForQuery(mDatabase,
600                "SELECT source from tokens where token GLOB '" + key + "*'", null));
601        Assert.assertEquals(1, DatabaseUtils.longForQuery(mDatabase,
602                "SELECT token_index from tokens where token GLOB '" + key + "*'", null));
603        Assert.assertEquals("bar", DatabaseUtils.stringForQuery(mDatabase,
604                "SELECT tag from tokens where token GLOB '" + key + "*'", null));
605
606        key = DatabaseUtils.getHexCollationKey(chinese);
607        String[] a = new String[1];
608        a[0] = key;
609        Assert.assertEquals(1, DatabaseUtils.longForQuery(mDatabase,
610                "SELECT count(*) from tokens where token= ?", a));
611        Assert.assertEquals(12, DatabaseUtils.longForQuery(mDatabase,
612                "SELECT source from tokens where token= ?", a));
613        Assert.assertEquals(0, DatabaseUtils.longForQuery(mDatabase,
614                "SELECT token_index from tokens where token= ?", a));
615        a[0] += "*";
616        Assert.assertEquals(1, DatabaseUtils.longForQuery(mDatabase,
617             "SELECT count(*) from tokens where token GLOB ?", a));
618        Assert.assertEquals(12, DatabaseUtils.longForQuery(mDatabase,
619                "SELECT source from tokens where token GLOB ?", a));
620        Assert.assertEquals(0, DatabaseUtils.longForQuery(mDatabase,
621                "SELECT token_index from tokens where token GLOB ?", a));
622
623       Assert.assertEquals(1, DatabaseUtils.longForQuery(mDatabase,
624                "SELECT count(*) from tokens where token= '" + key + "'", null));
625       Assert.assertEquals(12, DatabaseUtils.longForQuery(mDatabase,
626               "SELECT source from tokens where token= '" + key + "'", null));
627       Assert.assertEquals(0, DatabaseUtils.longForQuery(mDatabase,
628               "SELECT token_index from tokens where token= '" + key + "'", null));
629
630        Assert.assertEquals(1, DatabaseUtils.longForQuery(mDatabase,
631                "SELECT count(*) from tokens where token GLOB '" + key + "*'", null));
632        Assert.assertEquals(12, DatabaseUtils.longForQuery(mDatabase,
633                "SELECT source from tokens where token GLOB '" + key + "*'", null));
634        Assert.assertEquals(0, DatabaseUtils.longForQuery(mDatabase,
635                "SELECT token_index from tokens where token GLOB '" + key + "*'", null));
636
637        key = DatabaseUtils.getHexCollationKey("\u4eac\u4ec5");
638        Assert.assertEquals(1, DatabaseUtils.longForQuery(mDatabase,
639                "SELECT count(*) from tokens where token GLOB '" + key + "*'", null));
640        Assert.assertEquals(12, DatabaseUtils.longForQuery(mDatabase,
641                "SELECT source from tokens where token GLOB '" + key + "*'", null));
642        Assert.assertEquals(0, DatabaseUtils.longForQuery(mDatabase,
643                "SELECT token_index from tokens where token GLOB '" + key + "*'", null));
644
645        key = DatabaseUtils.getHexCollationKey("\u5c3d\u5f84\u60ca");
646        Log.d("DatabaseGeneralTest", "key = " + key);
647        Assert.assertEquals(1, DatabaseUtils.longForQuery(mDatabase,
648                "SELECT count(*) from tokens where token GLOB '" + key + "*'", null));
649        Assert.assertEquals(12, DatabaseUtils.longForQuery(mDatabase,
650                "SELECT source from tokens where token GLOB '" + key + "*'", null));
651        Assert.assertEquals(1, DatabaseUtils.longForQuery(mDatabase,
652                "SELECT token_index from tokens where token GLOB '" + key + "*'", null));
653
654        Assert.assertEquals(0, DatabaseUtils.longForQuery(mDatabase,
655                "SELECT count(*) from tokens where token GLOB 'ab*'", null));
656
657        key = DatabaseUtils.getHexCollationKey("some string ok");
658        Assert.assertEquals(1, DatabaseUtils.longForQuery(mDatabase,
659                "SELECT count(*) from tokens_no_index where token GLOB '" + key + "*'", null));
660        Assert.assertEquals(20, DatabaseUtils.longForQuery(mDatabase,
661                "SELECT source from tokens_no_index where token GLOB '" + key + "*'", null));
662
663        key = DatabaseUtils.getHexCollationKey("bar");
664        Assert.assertEquals(1, DatabaseUtils.longForQuery(mDatabase,
665                "SELECT count(*) from tokens_no_index where token GLOB '" + key + "*'", null));
666        Assert.assertEquals(21, DatabaseUtils.longForQuery(mDatabase,
667                "SELECT source from tokens_no_index where token GLOB '" + key + "*'", null));
668    }
669
670    @MediumTest
671    public void testTransactions() throws Exception {
672        mDatabase.execSQL("CREATE TABLE test (num INTEGER);");
673        mDatabase.execSQL("INSERT INTO test (num) VALUES (0)");
674
675        // Make sure that things work outside an explicit transaction.
676        setNum(1);
677        checkNum(1);
678
679        // Test a single-level transaction.
680        setNum(0);
681        mDatabase.beginTransaction();
682        setNum(1);
683        mDatabase.setTransactionSuccessful();
684        mDatabase.endTransaction();
685        checkNum(1);
686        Assert.assertFalse(mDatabase.isDbLockedByCurrentThread());
687
688        // Test a rolled-back transaction.
689        setNum(0);
690        mDatabase.beginTransaction();
691        setNum(1);
692        mDatabase.endTransaction();
693        checkNum(0);
694        Assert.assertFalse(mDatabase.isDbLockedByCurrentThread());
695
696        // We should get an error if we end a non-existent transaction.
697        assertThrowsIllegalState(new Runnable() { public void run() {
698            mDatabase.endTransaction();
699        }});
700
701        // We should get an error if a set a non-existent transaction as clean.
702        assertThrowsIllegalState(new Runnable() { public void run() {
703            mDatabase.setTransactionSuccessful();
704        }});
705
706        mDatabase.beginTransaction();
707        mDatabase.setTransactionSuccessful();
708        // We should get an error if we mark a transaction as clean twice.
709        assertThrowsIllegalState(new Runnable() { public void run() {
710            mDatabase.setTransactionSuccessful();
711        }});
712        // We should get an error if we begin a transaction after marking the parent as clean.
713        assertThrowsIllegalState(new Runnable() { public void run() {
714            mDatabase.beginTransaction();
715        }});
716        mDatabase.endTransaction();
717        Assert.assertFalse(mDatabase.isDbLockedByCurrentThread());
718
719        // Test a two-level transaction.
720        setNum(0);
721        mDatabase.beginTransaction();
722        mDatabase.beginTransaction();
723        setNum(1);
724        mDatabase.setTransactionSuccessful();
725        mDatabase.endTransaction();
726        mDatabase.setTransactionSuccessful();
727        mDatabase.endTransaction();
728        checkNum(1);
729        Assert.assertFalse(mDatabase.isDbLockedByCurrentThread());
730
731        // Test rolling back an inner transaction.
732        setNum(0);
733        mDatabase.beginTransaction();
734        mDatabase.beginTransaction();
735        setNum(1);
736        mDatabase.endTransaction();
737        mDatabase.setTransactionSuccessful();
738        mDatabase.endTransaction();
739        checkNum(0);
740        Assert.assertFalse(mDatabase.isDbLockedByCurrentThread());
741
742        // Test rolling back an outer transaction.
743        setNum(0);
744        mDatabase.beginTransaction();
745        mDatabase.beginTransaction();
746        setNum(1);
747        mDatabase.setTransactionSuccessful();
748        mDatabase.endTransaction();
749        mDatabase.endTransaction();
750        checkNum(0);
751        Assert.assertFalse(mDatabase.isDbLockedByCurrentThread());
752    }
753
754    private void setNum(int num) {
755        mDatabase.execSQL("UPDATE test SET num = " + num);
756    }
757
758    private void checkNum(int num) {
759        Assert.assertEquals(
760                num, DatabaseUtils.longForQuery(mDatabase, "SELECT num FROM test", null));
761    }
762
763    private void assertThrowsIllegalState(Runnable r) {
764        boolean ok = false;
765        try {
766            r.run();
767        } catch (IllegalStateException e) {
768            ok = true;
769        }
770        Assert.assertTrue(ok);
771    }
772
773    // Disable these until we can explicitly mark them as stress tests
774    public void xxtestMem1() throws Exception {
775        populateDefaultTable();
776
777        for (int i = 0; i < 50000; i++) {
778            Cursor cursor = mDatabase.query("test", null, null, null, null, null, null);
779            cursor.moveToFirst();
780            cursor.close();
781//                Log.i("~~~~", "Finished round " + i);
782        }
783    }
784
785    // Disable these until we can explicitly mark them as stress tests
786    public void xxtestMem2() throws Exception {
787        populateDefaultTable();
788
789        for (int i = 0; i < 50000; i++) {
790            Cursor cursor = mDatabase.query("test", null, null, null, null, null, null);
791            cursor.close();
792//                Log.i("~~~~", "Finished round " + i);
793        }
794    }
795
796    // Disable these until we can explicitly mark them as stress tests
797    public void xxtestMem3() throws Exception {
798        populateDefaultTable();
799
800        for (int i = 0; i < 50000; i++) {
801            Cursor cursor = mDatabase.query("test", null, null, null, null, null, null);
802            cursor.deactivate();
803//                Log.i("~~~~", "Finished round " + i);
804        }
805    }
806
807    @MediumTest
808    public void testContentValues() throws Exception {
809        ContentValues values = new ContentValues();
810        values.put("string", "value");
811        assertEquals("value", values.getAsString("string"));
812        byte[] bytes = new byte[42];
813        Arrays.fill(bytes, (byte) 0x28);
814        values.put("byteArray", bytes);
815        assertTrue(Arrays.equals(bytes, values.getAsByteArray("byteArray")));
816
817        // Write the ContentValues to a Parcel and then read them out
818        Parcel p = Parcel.obtain();
819        values.writeToParcel(p, 0);
820        p.setDataPosition(0);
821        values = ContentValues.CREATOR.createFromParcel(p);
822
823        // Read the values out again and make sure they're the same
824        assertTrue(Arrays.equals(bytes, values.getAsByteArray("byteArray")));
825        assertEquals("value", values.get("string"));
826    }
827
828    @MediumTest
829    public void testTableInfoPragma() throws Exception {
830        mDatabase.execSQL("CREATE TABLE pragma_test (" +
831                "i INTEGER DEFAULT 1234, " +
832                "j INTEGER, " +
833                "s TEXT DEFAULT 'hello', " +
834                "t TEXT, " +
835                "'select' TEXT DEFAULT \"hello\")");
836        try {
837            Cursor cur = mDatabase.rawQuery("PRAGMA table_info(pragma_test)", null);
838            Assert.assertEquals(5, cur.getCount());
839
840            Assert.assertTrue(cur.moveToNext());
841            Assert.assertEquals("i",
842                    cur.getString(TABLE_INFO_PRAGMA_COLUMNNAME_INDEX));
843            Assert.assertEquals("1234",
844                    cur.getString(TABLE_INFO_PRAGMA_DEFAULT_INDEX));
845
846            Assert.assertTrue(cur.moveToNext());
847            Assert.assertEquals("j",
848                    cur.getString(TABLE_INFO_PRAGMA_COLUMNNAME_INDEX));
849            Assert.assertNull(cur.getString(TABLE_INFO_PRAGMA_DEFAULT_INDEX));
850
851            Assert.assertTrue(cur.moveToNext());
852            Assert.assertEquals("s",
853                    cur.getString(TABLE_INFO_PRAGMA_COLUMNNAME_INDEX));
854            Assert.assertEquals("'hello'",
855                    cur.getString(TABLE_INFO_PRAGMA_DEFAULT_INDEX));
856
857            Assert.assertTrue(cur.moveToNext());
858            Assert.assertEquals("t",
859                    cur.getString(TABLE_INFO_PRAGMA_COLUMNNAME_INDEX));
860            Assert.assertNull(cur.getString(TABLE_INFO_PRAGMA_DEFAULT_INDEX));
861
862            Assert.assertTrue(cur.moveToNext());
863            Assert.assertEquals("select",
864                    cur.getString(TABLE_INFO_PRAGMA_COLUMNNAME_INDEX));
865            Assert.assertEquals("\"hello\"",
866                    cur.getString(TABLE_INFO_PRAGMA_DEFAULT_INDEX));
867
868            cur.close();
869        } catch (Throwable t) {
870            throw new RuntimeException(
871                    "If you see this test fail, it's likely that something about " +
872                    "sqlite's PRAGMA table_info(...) command has changed.", t);
873        }
874    }
875
876    @MediumTest
877    public void testInsertHelper() throws Exception {
878        Cursor cur;
879        ContentValues cv;
880        long row;
881
882        mDatabase.execSQL("CREATE TABLE insert_test (" +
883                "_id INTEGER PRIMARY KEY, " +
884                "s TEXT NOT NULL UNIQUE, " +
885                "t TEXT NOT NULL DEFAULT 'hello world', " +
886                "i INTEGER, " +
887                "j INTEGER NOT NULL DEFAULT 1234, " +
888                "'select' TEXT)");
889
890        DatabaseUtils.InsertHelper ih =
891            new DatabaseUtils.InsertHelper(mDatabase, "insert_test");
892
893        cv = new ContentValues();
894        cv.put("s", "one");
895        row = ih.insert(cv);
896        cur = mDatabase.rawQuery("SELECT * FROM insert_test WHERE _id == " + row, null);
897        Assert.assertTrue(cur.moveToFirst());
898        Assert.assertEquals("one", cur.getString(1));
899        Assert.assertEquals("hello world", cur.getString(2));
900        Assert.assertNull(cur.getString(3));
901        Assert.assertEquals(1234, cur.getLong(4));
902        Assert.assertNull(cur.getString(5));
903        cur.close();
904
905        cv = new ContentValues();
906        cv.put("s", "two");
907        cv.put("t", "goodbye world");
908        row = ih.insert(cv);
909        cur = mDatabase.rawQuery("SELECT * FROM insert_test WHERE _id == " + row, null);
910        Assert.assertTrue(cur.moveToFirst());
911        Assert.assertEquals("two", cur.getString(1));
912        Assert.assertEquals("goodbye world", cur.getString(2));
913        Assert.assertNull(cur.getString(3));
914        Assert.assertEquals(1234, cur.getLong(4));
915        Assert.assertNull(cur.getString(5));
916        cur.close();
917
918        cv = new ContentValues();
919        cv.put("t", "goodbye world");
920        row = ih.insert(cv);
921        Assert.assertEquals(-1, row);
922
923        cv = new ContentValues();
924        cv.put("s", "three");
925        cv.put("i", 2345);
926        cv.put("j", 3456);
927        cv.put("select", "tricky");
928        row = ih.insert(cv);
929        cur = mDatabase.rawQuery("SELECT * FROM insert_test WHERE _id == " + row, null);
930        Assert.assertTrue(cur.moveToFirst());
931        Assert.assertEquals("three", cur.getString(1));
932        Assert.assertEquals("hello world", cur.getString(2));
933        Assert.assertEquals(2345, cur.getLong(3));
934        Assert.assertEquals(3456, cur.getLong(4));
935        Assert.assertEquals("tricky", cur.getString(5));
936        cur.close();
937
938        cv = new ContentValues();
939        cv.put("s", "three");
940        cv.put("i", 6789);
941        row = ih.insert(cv);
942        Assert.assertEquals(-1, row);
943        row = ih.replace(cv);
944        cur = mDatabase.rawQuery("SELECT * FROM insert_test WHERE _id == " + row, null);
945        Assert.assertTrue(cur.moveToFirst());
946        Assert.assertEquals("three", cur.getString(1));
947        Assert.assertEquals("hello world", cur.getString(2));
948        Assert.assertEquals(6789, cur.getLong(3));
949        cur.close();
950
951        ih.close();
952    }
953
954    @MediumTest
955    public void testSemicolonsInStatements() throws Exception {
956        mDatabase.execSQL("CREATE TABLE pragma_test (" +
957                "i INTEGER DEFAULT 1234, " +
958                "j INTEGER, " +
959                "s TEXT DEFAULT 'hello', " +
960                "t TEXT, " +
961                "'select' TEXT DEFAULT \"hello\")");
962        try {
963            // ending the sql statement with  semicolons shouldn't be a problem.
964            Cursor cur = mDatabase.rawQuery("PRAGMA database_list;", null);
965            cur.close();
966            // two semicolons in the statement shouldn't be a problem.
967            cur = mDatabase.rawQuery("PRAGMA database_list;;", null);
968            cur.close();
969        } catch (Throwable t) {
970            fail("unexpected, of course");
971        }
972    }
973
974    @MediumTest
975    public void testUnionsWithBindArgs() {
976        /* make sure unions with bindargs work http://b/issue?id=1061291 */
977        mDatabase.execSQL("CREATE TABLE A (i int);");
978        mDatabase.execSQL("create table B (k int);");
979        mDatabase.execSQL("create table C (n int);");
980        mDatabase.execSQL("insert into A values(1);");
981        mDatabase.execSQL("insert into A values(2);");
982        mDatabase.execSQL("insert into A values(3);");
983        mDatabase.execSQL("insert into B values(201);");
984        mDatabase.execSQL("insert into B values(202);");
985        mDatabase.execSQL("insert into B values(203);");
986        mDatabase.execSQL("insert into C values(901);");
987        mDatabase.execSQL("insert into C values(902);");
988        String s = "select i from A where i > 2 " +
989                "UNION select k from B where k > 201 " +
990                "UNION select n from C where n !=900;";
991        Cursor c = mDatabase.rawQuery(s, null);
992        int n = c.getCount();
993        c.close();
994        String s1 = "select i from A where i > ? " +
995                "UNION select k from B where k > ? " +
996                "UNION select n from C where n != ?;";
997        Cursor c1 = mDatabase.rawQuery(s1, new String[]{"2", "201", "900"});
998        assertEquals(n, c1.getCount());
999        c1.close();
1000    }
1001
1002    /**
1003     * This test is available only when the platform has a locale with the language "ja".
1004     * It finishes without failure when it is not available.
1005     */
1006    @MediumTest
1007    public void testCollateLocalizedForJapanese() throws Exception {
1008        final String testName = "DatabaseGeneralTest#testCollateLocalizedForJapanese()";
1009        final Locale[] localeArray = Locale.getAvailableLocales();
1010        final String japanese = Locale.JAPANESE.getLanguage();
1011        final String english = Locale.ENGLISH.getLanguage();
1012        Locale japaneseLocale = null;
1013        Locale englishLocale = null;
1014        for (Locale locale : localeArray) {
1015            if (locale != null) {
1016                final String language = locale.getLanguage();
1017                if (language == null) {
1018                    continue;
1019                } else if (language.equals(japanese)) {
1020                    japaneseLocale = locale;
1021                } else if (language.equals(english)) {
1022                    englishLocale = locale;
1023                }
1024            }
1025
1026            if (japaneseLocale != null && englishLocale != null) {
1027                break;
1028            }
1029        }
1030
1031        if (japaneseLocale == null || englishLocale == null) {
1032            Log.d(TAG, testName + "n is silently skipped since " +
1033                    (englishLocale == null ?
1034                            (japaneseLocale == null ?
1035                                    "Both English and Japanese locales do not exist." :
1036                                    "English locale does not exist.") :
1037                            (japaneseLocale == null ?
1038                                    "Japanese locale does not exist." :
1039                                    "...why?")));
1040            return;
1041        }
1042
1043        Locale originalLocale = Locale.getDefault();
1044        try {
1045
1046            final String dbName = "collate_localized_test";
1047            mDatabase.execSQL("CREATE TABLE " + dbName + " (" +
1048                    "_id INTEGER PRIMARY KEY, " +
1049                    "s TEXT COLLATE LOCALIZED) ");
1050            DatabaseUtils.InsertHelper ih =
1051                new DatabaseUtils.InsertHelper(mDatabase, dbName);
1052            ContentValues cv = new ContentValues();
1053
1054            cv = new ContentValues();  //
1055            cv.put("s", "\uFF75\uFF77\uFF85\uFF9C");  // O-ki-na-wa in half-width Katakana
1056            ih.insert(cv);
1057
1058            cv = new ContentValues();  //
1059            cv.put("s", "\u306B\u307B\u3093");  // Ni-ho-n in Hiragana
1060            ih.insert(cv);
1061
1062            cv = new ContentValues();  //
1063            cv.put("s", "\u30A2\u30E1\u30EA\u30AB");  // A-me-ri-ca in hull-width Katakana
1064            ih.insert(cv);
1065
1066            // Assume setLocale() does REINDEX and an English locale does not consider
1067            // Japanese-specific LOCALIZED order.
1068            Locale.setDefault(englishLocale);
1069            Locale.setDefault(japaneseLocale);
1070
1071            Cursor cur = mDatabase.rawQuery(
1072                    "SELECT * FROM " + dbName + " ORDER BY s", null);
1073            assertTrue(cur.moveToFirst());
1074            assertEquals("\u30A2\u30E1\u30EA\u30AB", cur.getString(1));
1075            assertTrue(cur.moveToNext());
1076            assertEquals("\uFF75\uFF77\uFF85\uFF9C", cur.getString(1));
1077            assertTrue(cur.moveToNext());
1078            assertEquals("\u306B\u307B\u3093", cur.getString(1));
1079        } finally {
1080            if (originalLocale != null) {
1081                try {
1082                    Locale.setDefault(originalLocale);
1083                } catch (Exception e) {
1084                }
1085            }
1086        }
1087    }
1088
1089    @SmallTest
1090    public void testSetMaxCahesize() {
1091        mDatabase.execSQL("CREATE TABLE test (i int, j int);");
1092        mDatabase.execSQL("insert into test values(1,1);");
1093        // set cache size
1094        int N = SQLiteDatabase.MAX_SQL_CACHE_SIZE;
1095        mDatabase.setMaxSqlCacheSize(N);
1096
1097        // try reduce cachesize
1098        try {
1099            mDatabase.setMaxSqlCacheSize(1);
1100        } catch (IllegalStateException e) {
1101            assertTrue(e.getMessage().contains("cannot set cacheSize to a value less than"));
1102        }
1103    }
1104
1105    @LargeTest
1106    public void testDefaultDatabaseErrorHandler() {
1107        DefaultDatabaseErrorHandler errorHandler = new DefaultDatabaseErrorHandler();
1108
1109        // close the database. and call corruption handler.
1110        // it should delete the database file.
1111        File dbfile = new File(mDatabase.getPath());
1112        mDatabase.close();
1113        assertFalse(mDatabase.isOpen());
1114        assertTrue(dbfile.exists());
1115        try {
1116            errorHandler.onCorruption(mDatabase);
1117            assertFalse(dbfile.exists());
1118        } catch (Exception e) {
1119            fail("unexpected");
1120        }
1121
1122        // create an in-memory database. and corruption handler shouldn't try to delete it
1123        SQLiteDatabase memoryDb = SQLiteDatabase.openOrCreateDatabase(":memory:", null);
1124        assertNotNull(memoryDb);
1125        memoryDb.close();
1126        assertFalse(memoryDb.isOpen());
1127        try {
1128            errorHandler.onCorruption(memoryDb);
1129        } catch (Exception e) {
1130            fail("unexpected");
1131        }
1132
1133        // create a database, keep it open, call corruption handler. database file should be deleted
1134        SQLiteDatabase dbObj = SQLiteDatabase.openOrCreateDatabase(mDatabase.getPath(), null);
1135        assertTrue(dbfile.exists());
1136        assertNotNull(dbObj);
1137        assertTrue(dbObj.isOpen());
1138        try {
1139            errorHandler.onCorruption(dbObj);
1140            assertFalse(dbfile.exists());
1141        } catch (Exception e) {
1142            fail("unexpected");
1143        }
1144
1145        // create a database, attach 2 more databases to it
1146        //    attached database # 1: ":memory:"
1147        //    attached database # 2: mDatabase.getPath() + "1";
1148        // call corruption handler. database files including the one for attached database # 2
1149        // should be deleted
1150        String attachedDb1File = mDatabase.getPath() + "1";
1151        dbObj = SQLiteDatabase.openOrCreateDatabase(mDatabase.getPath(), null);
1152        dbObj.execSQL("ATTACH DATABASE ':memory:' as memoryDb");
1153        dbObj.execSQL("ATTACH DATABASE '" +  attachedDb1File + "' as attachedDb1");
1154        assertTrue(dbfile.exists());
1155        assertTrue(new File(attachedDb1File).exists());
1156        assertNotNull(dbObj);
1157        assertTrue(dbObj.isOpen());
1158        ArrayList<Pair<String, String>> attachedDbs = dbObj.getAttachedDbs();
1159        try {
1160            errorHandler.onCorruption(dbObj);
1161            assertFalse(dbfile.exists());
1162            assertFalse(new File(attachedDb1File).exists());
1163        } catch (Exception e) {
1164            fail("unexpected");
1165        }
1166
1167        // same as above, except this is a bit of stress testing. attach 5 database files
1168        // and make sure they are all removed.
1169        int N = 5;
1170        ArrayList<String> attachedDbFiles = new ArrayList<String>(N);
1171        for (int i = 0; i < N; i++) {
1172            attachedDbFiles.add(mDatabase.getPath() + i);
1173        }
1174        dbObj = SQLiteDatabase.openOrCreateDatabase(mDatabase.getPath(), null);
1175        dbObj.execSQL("ATTACH DATABASE ':memory:' as memoryDb");
1176        for (int i = 0; i < N; i++) {
1177            dbObj.execSQL("ATTACH DATABASE '" +  attachedDbFiles.get(i) + "' as attachedDb" + i);
1178        }
1179        assertTrue(dbfile.exists());
1180        for (int i = 0; i < N; i++) {
1181            assertTrue(new File(attachedDbFiles.get(i)).exists());
1182        }
1183        assertNotNull(dbObj);
1184        assertTrue(dbObj.isOpen());
1185        attachedDbs = dbObj.getAttachedDbs();
1186        try {
1187            errorHandler.onCorruption(dbObj);
1188            assertFalse(dbfile.exists());
1189            for (int i = 0; i < N; i++) {
1190                assertFalse(new File(attachedDbFiles.get(i)).exists());
1191            }
1192        } catch (Exception e) {
1193            fail("unexpected");
1194        }
1195    }
1196}
1197