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