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