1 /* 2 * Copyright (C) 2009 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.database.sqlite.cts; 18 19 import java.io.File; 20 import java.util.ArrayList; 21 import java.util.Locale; 22 23 import android.content.ContentValues; 24 import android.database.Cursor; 25 import android.database.DatabaseUtils; 26 import android.database.SQLException; 27 import android.database.sqlite.SQLiteCursor; 28 import android.database.sqlite.SQLiteCursorDriver; 29 import android.database.sqlite.SQLiteDatabase; 30 import android.database.sqlite.SQLiteDatabase.CursorFactory; 31 import android.database.sqlite.SQLiteException; 32 import android.database.sqlite.SQLiteQuery; 33 import android.database.sqlite.SQLiteStatement; 34 import android.database.sqlite.SQLiteTransactionListener; 35 import android.test.AndroidTestCase; 36 import android.test.MoreAsserts; 37 import android.test.suitebuilder.annotation.LargeTest; 38 import android.test.suitebuilder.annotation.SmallTest; 39 import dalvik.annotation.TestTargets; 40 import dalvik.annotation.TestTargetNew; 41 import dalvik.annotation.TestLevel; 42 import dalvik.annotation.TestTargetClass; 43 import dalvik.annotation.ToBeFixed; 44 45 @TestTargetClass(android.database.sqlite.SQLiteDatabase.class) 46 public class SQLiteDatabaseTest extends AndroidTestCase { 47 private SQLiteDatabase mDatabase; 48 private File mDatabaseFile; 49 private String mDatabaseFilePath; 50 private String mDatabaseDir; 51 52 private boolean mTransactionListenerOnBeginCalled; 53 private boolean mTransactionListenerOnCommitCalled; 54 private boolean mTransactionListenerOnRollbackCalled; 55 56 private static final String DATABASE_FILE_NAME = "database_test.db"; 57 private static final String TABLE_NAME = "test"; 58 private static final int COLUMN_ID_INDEX = 0; 59 private static final int COLUMN_NAME_INDEX = 1; 60 private static final int COLUMN_AGE_INDEX = 2; 61 private static final int COLUMN_ADDR_INDEX = 3; 62 private static final String[] TEST_PROJECTION = new String[] { 63 "_id", // 0 64 "name", // 1 65 "age", // 2 66 "address" // 3 67 }; 68 69 @Override 70 protected void setUp() throws Exception { 71 super.setUp(); 72 73 getContext().deleteDatabase(DATABASE_FILE_NAME); 74 mDatabaseFilePath = getContext().getDatabasePath(DATABASE_FILE_NAME).getPath(); 75 mDatabaseFile = getContext().getDatabasePath(DATABASE_FILE_NAME); 76 mDatabaseDir = mDatabaseFile.getParent(); 77 mDatabaseFile.getParentFile().mkdirs(); // directory may not exist 78 mDatabase = SQLiteDatabase.openOrCreateDatabase(mDatabaseFile, null); 79 assertNotNull(mDatabase); 80 81 mTransactionListenerOnBeginCalled = false; 82 mTransactionListenerOnCommitCalled = false; 83 mTransactionListenerOnRollbackCalled = false; 84 } 85 86 @Override 87 protected void tearDown() throws Exception { 88 mDatabase.close(); 89 mDatabaseFile.delete(); 90 super.tearDown(); 91 } 92 93 @TestTargets({ 94 @TestTargetNew( 95 level = TestLevel.COMPLETE, 96 notes = "Test openDatabase", 97 method = "openDatabase", 98 args = {java.lang.String.class, 99 android.database.sqlite.SQLiteDatabase.CursorFactory.class, int.class} 100 ), 101 @TestTargetNew( 102 level = TestLevel.COMPLETE, 103 notes = "Test openOrCreateDatabase", 104 method = "openOrCreateDatabase", 105 args = {java.io.File.class, 106 android.database.sqlite.SQLiteDatabase.CursorFactory.class} 107 ), 108 @TestTargetNew( 109 level = TestLevel.COMPLETE, 110 notes = "Test openOrCreateDatabase", 111 method = "openOrCreateDatabase", 112 args = {java.lang.String.class, 113 android.database.sqlite.SQLiteDatabase.CursorFactory.class} 114 ), 115 @TestTargetNew( 116 level = TestLevel.COMPLETE, 117 notes = "Test close", 118 method = "close", 119 args = {} 120 ), 121 @TestTargetNew( 122 level = TestLevel.COMPLETE, 123 notes = "Test create", 124 method = "create", 125 args = {android.database.sqlite.SQLiteDatabase.CursorFactory.class} 126 ) 127 }) 128 public void testOpenDatabase() { 129 CursorFactory factory = new CursorFactory() { 130 public Cursor newCursor(SQLiteDatabase db, SQLiteCursorDriver masterQuery, 131 String editTable, SQLiteQuery query) { 132 return new MockSQLiteCursor(db, masterQuery, editTable, query); 133 } 134 }; 135 136 SQLiteDatabase db = SQLiteDatabase.openDatabase(mDatabaseFilePath, 137 factory, SQLiteDatabase.CREATE_IF_NECESSARY); 138 assertNotNull(db); 139 db.close(); 140 141 File dbFile = new File(mDatabaseDir, "database_test12345678.db"); 142 dbFile.delete(); 143 assertFalse(dbFile.exists()); 144 db = SQLiteDatabase.openOrCreateDatabase(dbFile.getPath(), factory); 145 assertNotNull(db); 146 db.close(); 147 dbFile.delete(); 148 149 dbFile = new File(mDatabaseDir, DATABASE_FILE_NAME); 150 db = SQLiteDatabase.openOrCreateDatabase(dbFile, factory); 151 assertNotNull(db); 152 db.close(); 153 dbFile.delete(); 154 155 db = SQLiteDatabase.create(factory); 156 assertNotNull(db); 157 db.close(); 158 } 159 160 private class MockSQLiteCursor extends SQLiteCursor { 161 public MockSQLiteCursor(SQLiteDatabase db, SQLiteCursorDriver driver, 162 String editTable, SQLiteQuery query) { 163 super(db, driver, editTable, query); 164 } 165 } 166 167 @TestTargets({ 168 @TestTargetNew( 169 level = TestLevel.COMPLETE, 170 notes = "Test beginTransaction()", 171 method = "beginTransaction", 172 args = {} 173 ), 174 @TestTargetNew( 175 level = TestLevel.COMPLETE, 176 notes = "Test endTransaction()", 177 method = "endTransaction", 178 args = {} 179 ), 180 @TestTargetNew( 181 level = TestLevel.COMPLETE, 182 notes = "Test setTransactionSuccessful()", 183 method = "setTransactionSuccessful", 184 args = {} 185 ), 186 @TestTargetNew( 187 level = TestLevel.COMPLETE, 188 notes = "Test inTransaction()", 189 method = "inTransaction", 190 args = {} 191 ), 192 @TestTargetNew( 193 level = TestLevel.COMPLETE, 194 notes = "Test isDbLockedByCurrentThread()", 195 method = "isDbLockedByCurrentThread", 196 args = {} 197 ), 198 @TestTargetNew( 199 level = TestLevel.COMPLETE, 200 notes = "Test isDbLockedByOtherThreads()", 201 method = "isDbLockedByOtherThreads", 202 args = {} 203 ) 204 }) 205 public void testTransaction() { 206 mDatabase.execSQL("CREATE TABLE test (num INTEGER);"); 207 mDatabase.execSQL("INSERT INTO test (num) VALUES (0)"); 208 209 // test execSQL without any explicit transactions. 210 setNum(1); 211 assertNum(1); 212 213 // Test a single-level transaction. 214 setNum(0); 215 assertFalse(mDatabase.inTransaction()); 216 mDatabase.beginTransaction(); 217 assertTrue(mDatabase.inTransaction()); 218 setNum(1); 219 mDatabase.setTransactionSuccessful(); 220 mDatabase.endTransaction(); 221 assertFalse(mDatabase.inTransaction()); 222 assertNum(1); 223 assertFalse(mDatabase.isDbLockedByCurrentThread()); 224 assertFalse(mDatabase.isDbLockedByOtherThreads()); 225 226 // Test a rolled-back transaction. 227 setNum(0); 228 assertFalse(mDatabase.inTransaction()); 229 mDatabase.beginTransaction(); 230 setNum(1); 231 assertTrue(mDatabase.inTransaction()); 232 mDatabase.endTransaction(); 233 assertFalse(mDatabase.inTransaction()); 234 assertNum(0); 235 assertFalse(mDatabase.isDbLockedByCurrentThread()); 236 assertFalse(mDatabase.isDbLockedByOtherThreads()); 237 238 // it should throw IllegalStateException if we end a non-existent transaction. 239 assertThrowsIllegalState(new Runnable() { 240 public void run() { 241 mDatabase.endTransaction(); 242 } 243 }); 244 245 // it should throw IllegalStateException if a set a non-existent transaction as clean. 246 assertThrowsIllegalState(new Runnable() { 247 public void run() { 248 mDatabase.setTransactionSuccessful(); 249 } 250 }); 251 252 mDatabase.beginTransaction(); 253 mDatabase.setTransactionSuccessful(); 254 // it should throw IllegalStateException if we mark a transaction as clean twice. 255 assertThrowsIllegalState(new Runnable() { 256 public void run() { 257 mDatabase.setTransactionSuccessful(); 258 } 259 }); 260 // it should throw IllegalStateException if we begin a transaction after marking the 261 // parent as clean. 262 assertThrowsIllegalState(new Runnable() { 263 public void run() { 264 mDatabase.beginTransaction(); 265 } 266 }); 267 mDatabase.endTransaction(); 268 assertFalse(mDatabase.isDbLockedByCurrentThread()); 269 assertFalse(mDatabase.isDbLockedByOtherThreads()); 270 271 assertFalse(mDatabase.inTransaction()); 272 // Test a two-level transaction. 273 setNum(0); 274 mDatabase.beginTransaction(); 275 assertTrue(mDatabase.inTransaction()); 276 mDatabase.beginTransaction(); 277 assertTrue(mDatabase.inTransaction()); 278 setNum(1); 279 mDatabase.setTransactionSuccessful(); 280 mDatabase.endTransaction(); 281 assertTrue(mDatabase.inTransaction()); 282 mDatabase.setTransactionSuccessful(); 283 mDatabase.endTransaction(); 284 assertFalse(mDatabase.inTransaction()); 285 assertNum(1); 286 assertFalse(mDatabase.isDbLockedByCurrentThread()); 287 assertFalse(mDatabase.isDbLockedByOtherThreads()); 288 289 // Test rolling back an inner transaction. 290 setNum(0); 291 mDatabase.beginTransaction(); 292 mDatabase.beginTransaction(); 293 setNum(1); 294 mDatabase.endTransaction(); 295 mDatabase.setTransactionSuccessful(); 296 mDatabase.endTransaction(); 297 assertNum(0); 298 assertFalse(mDatabase.isDbLockedByCurrentThread()); 299 assertFalse(mDatabase.isDbLockedByOtherThreads()); 300 301 // Test rolling back an outer transaction. 302 setNum(0); 303 mDatabase.beginTransaction(); 304 mDatabase.beginTransaction(); 305 setNum(1); 306 mDatabase.setTransactionSuccessful(); 307 mDatabase.endTransaction(); 308 mDatabase.endTransaction(); 309 assertNum(0); 310 assertFalse(mDatabase.isDbLockedByCurrentThread()); 311 assertFalse(mDatabase.isDbLockedByOtherThreads()); 312 } 313 314 private void setNum(int num) { 315 mDatabase.execSQL("UPDATE test SET num = " + num); 316 } 317 318 private void assertNum(int num) { 319 assertEquals(num, DatabaseUtils.longForQuery(mDatabase, 320 "SELECT num FROM test", null)); 321 } 322 323 private void assertThrowsIllegalState(Runnable r) { 324 try { 325 r.run(); 326 fail("did not throw expected IllegalStateException"); 327 } catch (IllegalStateException e) { 328 } 329 } 330 331 @TestTargets({ 332 @TestTargetNew( 333 level = TestLevel.COMPLETE, 334 notes = "Test getMaximumSize()", 335 method = "getMaximumSize", 336 args = {} 337 ), 338 @TestTargetNew( 339 level = TestLevel.COMPLETE, 340 notes = "Test setMaximumSize(long)", 341 method = "setMaximumSize", 342 args = {long.class} 343 ) 344 }) 345 public void testAccessMaximumSize() { 346 long curMaximumSize = mDatabase.getMaximumSize(); 347 348 // the new maximum size is less than the current size. 349 mDatabase.setMaximumSize(curMaximumSize - 1); 350 assertEquals(curMaximumSize, mDatabase.getMaximumSize()); 351 352 // the new maximum size is more than the current size. 353 mDatabase.setMaximumSize(curMaximumSize + 1); 354 assertEquals(curMaximumSize + mDatabase.getPageSize(), mDatabase.getMaximumSize()); 355 assertTrue(mDatabase.getMaximumSize() > curMaximumSize); 356 } 357 358 @TestTargets({ 359 @TestTargetNew( 360 level = TestLevel.COMPLETE, 361 notes = "Test getPageSize()", 362 method = "getPageSize", 363 args = {} 364 ), 365 @TestTargetNew( 366 level = TestLevel.COMPLETE, 367 notes = "Test setPageSize(long)", 368 method = "setPageSize", 369 args = {long.class} 370 ) 371 }) 372 @ToBeFixed(bug = "1676383", explanation = "setPageSize does not work as javadoc declares.") 373 public void testAccessPageSize() { 374 File databaseFile = new File(mDatabaseDir, "database.db"); 375 if (databaseFile.exists()) { 376 databaseFile.delete(); 377 } 378 SQLiteDatabase database = null; 379 try { 380 database = SQLiteDatabase.openOrCreateDatabase(databaseFile.getPath(), null); 381 382 long initialValue = database.getPageSize(); 383 // check that this does not throw an exception 384 // setting a different page size may not be supported after the DB has been created 385 database.setPageSize(initialValue); 386 assertEquals(initialValue, database.getPageSize()); 387 388 } finally { 389 if (database != null) { 390 database.close(); 391 databaseFile.delete(); 392 } 393 } 394 } 395 396 @TestTargetNew( 397 level = TestLevel.COMPLETE, 398 notes = "Test compileStatement(String)", 399 method = "compileStatement", 400 args = {java.lang.String.class} 401 ) 402 public void testCompileStatement() { 403 mDatabase.execSQL("CREATE TABLE test (_id INTEGER PRIMARY KEY, " 404 + "name TEXT, age INTEGER, address TEXT);"); 405 406 String name = "Mike"; 407 int age = 21; 408 String address = "LA"; 409 410 // at the beginning, there is no record in the database. 411 Cursor cursor = mDatabase.query("test", TEST_PROJECTION, null, null, null, null, null); 412 assertNotNull(cursor); 413 assertEquals(0, cursor.getCount()); 414 415 String sql = "INSERT INTO test (name, age, address) VALUES (?, ?, ?);"; 416 SQLiteStatement insertStatement = mDatabase.compileStatement(sql); 417 DatabaseUtils.bindObjectToProgram(insertStatement, 1, name); 418 DatabaseUtils.bindObjectToProgram(insertStatement, 2, age); 419 DatabaseUtils.bindObjectToProgram(insertStatement, 3, address); 420 insertStatement.execute(); 421 insertStatement.close(); 422 cursor.close(); 423 424 cursor = mDatabase.query("test", TEST_PROJECTION, null, null, null, null, null); 425 assertNotNull(cursor); 426 assertEquals(1, cursor.getCount()); 427 cursor.moveToNext(); 428 assertEquals(name, cursor.getString(COLUMN_NAME_INDEX)); 429 assertEquals(age, cursor.getInt(COLUMN_AGE_INDEX)); 430 assertEquals(address, cursor.getString(COLUMN_ADDR_INDEX)); 431 cursor.close(); 432 433 SQLiteStatement deleteStatement = mDatabase.compileStatement("DELETE FROM test"); 434 deleteStatement.execute(); 435 436 cursor = mDatabase.query("test", null, null, null, null, null, null); 437 assertEquals(0, cursor.getCount()); 438 cursor.deactivate(); 439 deleteStatement.close(); 440 cursor.close(); 441 } 442 443 @TestTargetNew( 444 level = TestLevel.COMPLETE, 445 notes = "Test delete(String, String, String[])", 446 method = "delete", 447 args = {java.lang.String.class, java.lang.String.class, java.lang.String[].class} 448 ) 449 public void testDelete() { 450 mDatabase.execSQL("CREATE TABLE test (_id INTEGER PRIMARY KEY, " 451 + "name TEXT, age INTEGER, address TEXT);"); 452 mDatabase.execSQL("INSERT INTO test (name, age, address) VALUES ('Mike', 20, 'LA');"); 453 mDatabase.execSQL("INSERT INTO test (name, age, address) VALUES ('Jack', 30, 'London');"); 454 mDatabase.execSQL("INSERT INTO test (name, age, address) VALUES ('Jim', 35, 'Chicago');"); 455 456 // delete one record. 457 int count = mDatabase.delete(TABLE_NAME, "name = 'Mike'", null); 458 assertEquals(1, count); 459 460 Cursor cursor = mDatabase.query(TABLE_NAME, TEST_PROJECTION, null, 461 null, null, null, null); 462 assertNotNull(cursor); 463 // there are 2 records here. 464 assertEquals(2, cursor.getCount()); 465 cursor.moveToFirst(); 466 assertEquals("Jack", cursor.getString(COLUMN_NAME_INDEX)); 467 assertEquals(30, cursor.getInt(COLUMN_AGE_INDEX)); 468 assertEquals("London", cursor.getString(COLUMN_ADDR_INDEX)); 469 cursor.moveToNext(); 470 assertEquals("Jim", cursor.getString(COLUMN_NAME_INDEX)); 471 assertEquals(35, cursor.getInt(COLUMN_AGE_INDEX)); 472 assertEquals("Chicago", cursor.getString(COLUMN_ADDR_INDEX)); 473 cursor.close(); 474 475 // delete another record. 476 count = mDatabase.delete(TABLE_NAME, "name = ?", new String[] { "Jack" }); 477 assertEquals(1, count); 478 479 cursor = mDatabase.query(TABLE_NAME, TEST_PROJECTION, null, null, null, 480 null, null); 481 assertNotNull(cursor); 482 // there are 1 records here. 483 assertEquals(1, cursor.getCount()); 484 cursor.moveToFirst(); 485 assertEquals("Jim", cursor.getString(COLUMN_NAME_INDEX)); 486 assertEquals(35, cursor.getInt(COLUMN_AGE_INDEX)); 487 assertEquals("Chicago", cursor.getString(COLUMN_ADDR_INDEX)); 488 cursor.close(); 489 490 mDatabase.execSQL("INSERT INTO test (name, age, address) VALUES ('Mike', 20, 'LA');"); 491 mDatabase.execSQL("INSERT INTO test (name, age, address) VALUES ('Jack', 30, 'London');"); 492 493 // delete all records. 494 count = mDatabase.delete(TABLE_NAME, null, null); 495 assertEquals(3, count); 496 497 cursor = mDatabase.query(TABLE_NAME, TEST_PROJECTION, null, null, null, null, null); 498 assertNotNull(cursor); 499 assertEquals(0, cursor.getCount()); 500 cursor.close(); 501 } 502 503 @TestTargets({ 504 @TestTargetNew( 505 level = TestLevel.COMPLETE, 506 notes = "Test execSQL(String)", 507 method = "execSQL", 508 args = {java.lang.String.class} 509 ), 510 @TestTargetNew( 511 level = TestLevel.COMPLETE, 512 notes = "Test execSQL(String, Object[])", 513 method = "execSQL", 514 args = {java.lang.String.class, java.lang.Object[].class} 515 ) 516 }) 517 public void testExecSQL() { 518 mDatabase.execSQL("CREATE TABLE test (_id INTEGER PRIMARY KEY, " 519 + "name TEXT, age INTEGER, address TEXT);"); 520 521 // add a new record. 522 mDatabase.execSQL("INSERT INTO test (name, age, address) VALUES ('Mike', 20, 'LA');"); 523 524 Cursor cursor = mDatabase.query(TABLE_NAME, TEST_PROJECTION, null, 525 null, null, null, null); 526 assertNotNull(cursor); 527 assertEquals(1, cursor.getCount()); 528 cursor.moveToFirst(); 529 assertEquals("Mike", cursor.getString(COLUMN_NAME_INDEX)); 530 assertEquals(20, cursor.getInt(COLUMN_AGE_INDEX)); 531 assertEquals("LA", cursor.getString(COLUMN_ADDR_INDEX)); 532 cursor.close(); 533 534 // add other new record. 535 mDatabase.execSQL("INSERT INTO test (name, age, address) VALUES ('Jack', 30, 'London');"); 536 537 cursor = mDatabase.query(TABLE_NAME, TEST_PROJECTION, null, null, null, null, null); 538 assertNotNull(cursor); 539 assertEquals(2, cursor.getCount()); 540 cursor.moveToFirst(); 541 assertEquals("Mike", cursor.getString(COLUMN_NAME_INDEX)); 542 assertEquals(20, cursor.getInt(COLUMN_AGE_INDEX)); 543 assertEquals("LA", cursor.getString(COLUMN_ADDR_INDEX)); 544 cursor.moveToNext(); 545 assertEquals("Jack", cursor.getString(COLUMN_NAME_INDEX)); 546 assertEquals(30, cursor.getInt(COLUMN_AGE_INDEX)); 547 assertEquals("London", cursor.getString(COLUMN_ADDR_INDEX)); 548 cursor.close(); 549 550 // delete a record. 551 mDatabase.execSQL("DELETE FROM test WHERE name = ?;", new String[] { "Jack" }); 552 553 cursor = mDatabase.query(TABLE_NAME, TEST_PROJECTION, null, null, null, null, null); 554 assertNotNull(cursor); 555 assertEquals(1, cursor.getCount()); 556 cursor.moveToFirst(); 557 assertEquals("Mike", cursor.getString(COLUMN_NAME_INDEX)); 558 assertEquals(20, cursor.getInt(COLUMN_AGE_INDEX)); 559 assertEquals("LA", cursor.getString(COLUMN_ADDR_INDEX)); 560 cursor.close(); 561 562 // delete a non-exist record. 563 mDatabase.execSQL("DELETE FROM test WHERE name = ?;", new String[] { "Wrong Name" }); 564 565 cursor = mDatabase.query(TABLE_NAME, TEST_PROJECTION, null, null, null, null, null); 566 assertNotNull(cursor); 567 assertEquals(1, cursor.getCount()); 568 cursor.moveToFirst(); 569 assertEquals("Mike", cursor.getString(COLUMN_NAME_INDEX)); 570 assertEquals(20, cursor.getInt(COLUMN_AGE_INDEX)); 571 assertEquals("LA", cursor.getString(COLUMN_ADDR_INDEX)); 572 cursor.close(); 573 574 try { 575 // execSQL can not use for query. 576 mDatabase.execSQL("SELECT * FROM test;"); 577 fail("should throw SQLException."); 578 } catch (SQLException e) { 579 } 580 581 // make sure execSQL can't be used to execute more than 1 sql statement at a time 582 mDatabase.execSQL("UPDATE test SET age = 40 WHERE name = 'Mike';" + 583 "UPDATE test SET age = 50 WHERE name = 'Mike';"); 584 // age should be updated to 40 not to 50 585 cursor = mDatabase.query(TABLE_NAME, TEST_PROJECTION, null, null, null, null, null); 586 assertNotNull(cursor); 587 assertEquals(1, cursor.getCount()); 588 cursor.moveToFirst(); 589 assertEquals("Mike", cursor.getString(COLUMN_NAME_INDEX)); 590 assertEquals(40, cursor.getInt(COLUMN_AGE_INDEX)); 591 assertEquals("LA", cursor.getString(COLUMN_ADDR_INDEX)); 592 cursor.close(); 593 594 // make sure sql injection is NOT allowed or has no effect when using query() 595 String harmfulQuery = "name = 'Mike';UPDATE test SET age = 50 WHERE name = 'Mike'"; 596 cursor = mDatabase.query(TABLE_NAME, TEST_PROJECTION, harmfulQuery, null, null, null, null); 597 assertNotNull(cursor); 598 assertEquals(1, cursor.getCount()); 599 cursor.moveToFirst(); 600 assertEquals("Mike", cursor.getString(COLUMN_NAME_INDEX)); 601 // row's age column SHOULD NOT be 50 602 assertEquals(40, cursor.getInt(COLUMN_AGE_INDEX)); 603 assertEquals("LA", cursor.getString(COLUMN_ADDR_INDEX)); 604 cursor.close();; 605 } 606 607 @TestTargetNew( 608 level = TestLevel.COMPLETE, 609 notes = "Test findEditTable(String)", 610 method = "findEditTable", 611 args = {java.lang.String.class} 612 ) 613 public void testFindEditTable() { 614 String tables = "table1 table2 table3"; 615 assertEquals("table1", SQLiteDatabase.findEditTable(tables)); 616 617 tables = "table1,table2,table3"; 618 assertEquals("table1", SQLiteDatabase.findEditTable(tables)); 619 620 tables = "table1"; 621 assertEquals("table1", SQLiteDatabase.findEditTable(tables)); 622 623 try { 624 SQLiteDatabase.findEditTable(""); 625 fail("should throw IllegalStateException."); 626 } catch (IllegalStateException e) { 627 } 628 } 629 630 @TestTargetNew( 631 level = TestLevel.COMPLETE, 632 notes = "Test getPath()", 633 method = "getPath", 634 args = {} 635 ) 636 public void testGetPath() { 637 assertEquals(mDatabaseFilePath, mDatabase.getPath()); 638 } 639 640 @TestTargets({ 641 @TestTargetNew( 642 level = TestLevel.COMPLETE, 643 notes = "Test getVersion()", 644 method = "getVersion", 645 args = {} 646 ), 647 @TestTargetNew( 648 level = TestLevel.COMPLETE, 649 notes = "Test setVersion(int)", 650 method = "setVersion", 651 args = {int.class} 652 ) 653 }) 654 public void testAccessVersion() { 655 mDatabase.setVersion(1); 656 assertEquals(1, mDatabase.getVersion()); 657 658 mDatabase.setVersion(3); 659 assertEquals(3, mDatabase.getVersion()); 660 } 661 662 @TestTargets({ 663 @TestTargetNew( 664 level = TestLevel.COMPLETE, 665 notes = "Test insert(String, String, ContentValues)", 666 method = "insert", 667 args = {java.lang.String.class, java.lang.String.class, 668 android.content.ContentValues.class} 669 ), 670 @TestTargetNew( 671 level = TestLevel.COMPLETE, 672 notes = "Test insertOrThrow(String, String, ContentValues)", 673 method = "insertOrThrow", 674 args = {java.lang.String.class, java.lang.String.class, 675 android.content.ContentValues.class} 676 ) 677 }) 678 public void testInsert() { 679 mDatabase.execSQL("CREATE TABLE test (_id INTEGER PRIMARY KEY, " 680 + "name TEXT, age INTEGER, address TEXT);"); 681 682 ContentValues values = new ContentValues(); 683 values.put("name", "Jack"); 684 values.put("age", 20); 685 values.put("address", "LA"); 686 mDatabase.insert(TABLE_NAME, "name", values); 687 688 Cursor cursor = mDatabase.query(TABLE_NAME, TEST_PROJECTION, null, 689 null, null, null, null); 690 assertNotNull(cursor); 691 assertEquals(1, cursor.getCount()); 692 cursor.moveToFirst(); 693 assertEquals("Jack", cursor.getString(COLUMN_NAME_INDEX)); 694 assertEquals(20, cursor.getInt(COLUMN_AGE_INDEX)); 695 assertEquals("LA", cursor.getString(COLUMN_ADDR_INDEX)); 696 cursor.close(); 697 698 mDatabase.insert(TABLE_NAME, "name", null); 699 cursor = mDatabase.query(TABLE_NAME, TEST_PROJECTION, null, null, null, 700 null, null); 701 assertNotNull(cursor); 702 assertEquals(2, cursor.getCount()); 703 cursor.moveToFirst(); 704 assertEquals("Jack", cursor.getString(COLUMN_NAME_INDEX)); 705 assertEquals(20, cursor.getInt(COLUMN_AGE_INDEX)); 706 assertEquals("LA", cursor.getString(COLUMN_ADDR_INDEX)); 707 cursor.moveToNext(); 708 assertNull(cursor.getString(COLUMN_NAME_INDEX)); 709 cursor.close(); 710 711 values = new ContentValues(); 712 values.put("Wrong Key", "Wrong value"); 713 mDatabase.insert(TABLE_NAME, "name", values); 714 // there are still 2 records. 715 cursor = mDatabase.query(TABLE_NAME, TEST_PROJECTION, null, null, null, 716 null, null); 717 assertNotNull(cursor); 718 assertEquals(2, cursor.getCount()); 719 cursor.close(); 720 721 // delete all record. 722 mDatabase.execSQL("DELETE FROM test;"); 723 724 values = new ContentValues(); 725 values.put("name", "Mike"); 726 values.put("age", 30); 727 values.put("address", "London"); 728 mDatabase.insertOrThrow(TABLE_NAME, "name", values); 729 730 cursor = mDatabase.query(TABLE_NAME, TEST_PROJECTION, null, null, null, 731 null, null); 732 assertNotNull(cursor); 733 assertEquals(1, cursor.getCount()); 734 cursor.moveToFirst(); 735 assertEquals("Mike", cursor.getString(COLUMN_NAME_INDEX)); 736 assertEquals(30, cursor.getInt(COLUMN_AGE_INDEX)); 737 assertEquals("London", cursor.getString(COLUMN_ADDR_INDEX)); 738 cursor.close(); 739 740 mDatabase.insertOrThrow(TABLE_NAME, "name", null); 741 cursor = mDatabase.query(TABLE_NAME, TEST_PROJECTION, null, null, null, 742 null, null); 743 assertNotNull(cursor); 744 assertEquals(2, cursor.getCount()); 745 cursor.moveToFirst(); 746 assertEquals("Mike", cursor.getString(COLUMN_NAME_INDEX)); 747 assertEquals(30, cursor.getInt(COLUMN_AGE_INDEX)); 748 assertEquals("London", cursor.getString(COLUMN_ADDR_INDEX)); 749 cursor.moveToNext(); 750 assertNull(cursor.getString(COLUMN_NAME_INDEX)); 751 cursor.close(); 752 753 values = new ContentValues(); 754 values.put("Wrong Key", "Wrong value"); 755 try { 756 mDatabase.insertOrThrow(TABLE_NAME, "name", values); 757 fail("should throw SQLException."); 758 } catch (SQLException e) { 759 } 760 } 761 762 @TestTargetNew( 763 level = TestLevel.COMPLETE, 764 notes = "Test isOpen()", 765 method = "isOpen", 766 args = {} 767 ) 768 public void testIsOpen() { 769 assertTrue(mDatabase.isOpen()); 770 771 mDatabase.close(); 772 assertFalse(mDatabase.isOpen()); 773 } 774 775 @TestTargetNew( 776 level = TestLevel.COMPLETE, 777 notes = "Test isReadOnly()", 778 method = "isReadOnly", 779 args = {} 780 ) 781 public void testIsReadOnly() { 782 assertFalse(mDatabase.isReadOnly()); 783 784 SQLiteDatabase database = null; 785 try { 786 database = SQLiteDatabase.openDatabase(mDatabaseFilePath, null, 787 SQLiteDatabase.OPEN_READONLY); 788 assertTrue(database.isReadOnly()); 789 } finally { 790 if (database != null) { 791 database.close(); 792 } 793 } 794 } 795 796 @TestTargetNew( 797 level = TestLevel.COMPLETE, 798 notes = "Test releaseMemory()", 799 method = "releaseMemory", 800 args = {} 801 ) 802 public void testReleaseMemory() { 803 SQLiteDatabase.releaseMemory(); 804 } 805 806 @TestTargetNew( 807 level = TestLevel.COMPLETE, 808 notes = "Test setLockingEnabled()", 809 method = "setLockingEnabled", 810 args = {boolean.class} 811 ) 812 public void testSetLockingEnabled() { 813 mDatabase.execSQL("CREATE TABLE test (num INTEGER);"); 814 mDatabase.execSQL("INSERT INTO test (num) VALUES (0)"); 815 816 mDatabase.setLockingEnabled(false); 817 818 mDatabase.beginTransaction(); 819 setNum(1); 820 assertNum(1); 821 mDatabase.setTransactionSuccessful(); 822 mDatabase.endTransaction(); 823 } 824 825 @TestTargets({ 826 @TestTargetNew( 827 level = TestLevel.COMPLETE, 828 notes = "Test yieldIfContended()", 829 method = "yieldIfContended", 830 args = {} 831 ), 832 @TestTargetNew( 833 level = TestLevel.COMPLETE, 834 notes = "Test yieldIfContendedSafely()", 835 method = "yieldIfContendedSafely", 836 args = {} 837 ) 838 }) 839 @SuppressWarnings("deprecation") 840 public void testYieldIfContended() { 841 assertFalse(mDatabase.yieldIfContended()); 842 843 mDatabase.execSQL("CREATE TABLE test (num INTEGER);"); 844 mDatabase.execSQL("INSERT INTO test (num) VALUES (0)"); 845 846 // Make sure that things work outside an explicit transaction. 847 setNum(1); 848 assertNum(1); 849 850 setNum(0); 851 assertFalse(mDatabase.inTransaction()); 852 mDatabase.beginTransaction(); 853 assertTrue(mDatabase.inTransaction()); 854 assertFalse(mDatabase.yieldIfContended()); 855 setNum(1); 856 mDatabase.setTransactionSuccessful(); 857 mDatabase.endTransaction(); 858 859 mDatabase.beginTransaction(); 860 assertTrue(mDatabase.inTransaction()); 861 assertFalse(mDatabase.yieldIfContendedSafely()); 862 setNum(1); 863 mDatabase.setTransactionSuccessful(); 864 mDatabase.endTransaction(); 865 } 866 867 @TestTargets({ 868 @TestTargetNew( 869 level = TestLevel.COMPLETE, 870 notes = "Test query", 871 method = "query", 872 args = {boolean.class, java.lang.String.class, java.lang.String[].class, 873 java.lang.String.class, java.lang.String[].class, java.lang.String.class, 874 java.lang.String.class, java.lang.String.class, java.lang.String.class} 875 ), 876 @TestTargetNew( 877 level = TestLevel.COMPLETE, 878 notes = "Test queryWithFactory", 879 method = "queryWithFactory", 880 args = {android.database.sqlite.SQLiteDatabase.CursorFactory.class, boolean.class, 881 java.lang.String.class, java.lang.String[].class, java.lang.String.class, 882 java.lang.String[].class, java.lang.String.class, java.lang.String.class, 883 java.lang.String.class, java.lang.String.class} 884 ), 885 @TestTargetNew( 886 level = TestLevel.COMPLETE, 887 notes = "Test query", 888 method = "query", 889 args = {java.lang.String.class, java.lang.String[].class, java.lang.String.class, 890 java.lang.String[].class, java.lang.String.class, java.lang.String.class, 891 java.lang.String.class} 892 ), 893 @TestTargetNew( 894 level = TestLevel.COMPLETE, 895 notes = "Test query", 896 method = "query", 897 args = {java.lang.String.class, java.lang.String[].class, java.lang.String.class, 898 java.lang.String[].class, java.lang.String.class, java.lang.String.class, 899 java.lang.String.class, java.lang.String.class} 900 ), 901 @TestTargetNew( 902 level = TestLevel.COMPLETE, 903 notes = "Test rawQuery", 904 method = "rawQuery", 905 args = {java.lang.String.class, java.lang.String[].class} 906 ), 907 @TestTargetNew( 908 level = TestLevel.COMPLETE, 909 notes = "Test rawQueryWithFactory", 910 method = "rawQueryWithFactory", 911 args = {android.database.sqlite.SQLiteDatabase.CursorFactory.class, 912 java.lang.String.class, java.lang.String[].class, java.lang.String.class} 913 ) 914 }) 915 public void testQuery() { 916 mDatabase.execSQL("CREATE TABLE employee (_id INTEGER PRIMARY KEY, " + 917 "name TEXT, month INTEGER, salary INTEGER);"); 918 mDatabase.execSQL("INSERT INTO employee (name, month, salary) " + 919 "VALUES ('Mike', '1', '1000');"); 920 mDatabase.execSQL("INSERT INTO employee (name, month, salary) " + 921 "VALUES ('Mike', '2', '3000');"); 922 mDatabase.execSQL("INSERT INTO employee (name, month, salary) " + 923 "VALUES ('jack', '1', '2000');"); 924 mDatabase.execSQL("INSERT INTO employee (name, month, salary) " + 925 "VALUES ('jack', '3', '1500');"); 926 mDatabase.execSQL("INSERT INTO employee (name, month, salary) " + 927 "VALUES ('Jim', '1', '1000');"); 928 mDatabase.execSQL("INSERT INTO employee (name, month, salary) " + 929 "VALUES ('Jim', '3', '3500');"); 930 931 Cursor cursor = mDatabase.query(true, "employee", new String[] { "name", "sum(salary)" }, 932 null, null, "name", "sum(salary)>1000", "name", null); 933 assertNotNull(cursor); 934 assertEquals(3, cursor.getCount()); 935 936 final int COLUMN_NAME_INDEX = 0; 937 final int COLUMN_SALARY_INDEX = 1; 938 cursor.moveToFirst(); 939 assertEquals("Jim", cursor.getString(COLUMN_NAME_INDEX)); 940 assertEquals(4500, cursor.getInt(COLUMN_SALARY_INDEX)); 941 cursor.moveToNext(); 942 assertEquals("Mike", cursor.getString(COLUMN_NAME_INDEX)); 943 assertEquals(4000, cursor.getInt(COLUMN_SALARY_INDEX)); 944 cursor.moveToNext(); 945 assertEquals("jack", cursor.getString(COLUMN_NAME_INDEX)); 946 assertEquals(3500, cursor.getInt(COLUMN_SALARY_INDEX)); 947 cursor.close(); 948 949 CursorFactory factory = new CursorFactory() { 950 public Cursor newCursor(SQLiteDatabase db, SQLiteCursorDriver masterQuery, 951 String editTable, SQLiteQuery query) { 952 return new MockSQLiteCursor(db, masterQuery, editTable, query); 953 } 954 }; 955 cursor = mDatabase.queryWithFactory(factory, true, "employee", 956 new String[] { "name", "sum(salary)" }, 957 null, null, "name", "sum(salary) > 1000", "name", null); 958 assertNotNull(cursor); 959 assertTrue(cursor instanceof MockSQLiteCursor); 960 cursor.moveToFirst(); 961 assertEquals("Jim", cursor.getString(COLUMN_NAME_INDEX)); 962 assertEquals(4500, cursor.getInt(COLUMN_SALARY_INDEX)); 963 cursor.moveToNext(); 964 assertEquals("Mike", cursor.getString(COLUMN_NAME_INDEX)); 965 assertEquals(4000, cursor.getInt(COLUMN_SALARY_INDEX)); 966 cursor.moveToNext(); 967 assertEquals("jack", cursor.getString(COLUMN_NAME_INDEX)); 968 assertEquals(3500, cursor.getInt(COLUMN_SALARY_INDEX)); 969 cursor.close(); 970 971 cursor = mDatabase.query("employee", new String[] { "name", "sum(salary)" }, 972 null, null, "name", "sum(salary) <= 4000", "name"); 973 assertNotNull(cursor); 974 assertEquals(2, cursor.getCount()); 975 976 cursor.moveToFirst(); 977 assertEquals("Mike", cursor.getString(COLUMN_NAME_INDEX)); 978 assertEquals(4000, cursor.getInt(COLUMN_SALARY_INDEX)); 979 cursor.moveToNext(); 980 assertEquals("jack", cursor.getString(COLUMN_NAME_INDEX)); 981 assertEquals(3500, cursor.getInt(COLUMN_SALARY_INDEX)); 982 cursor.close(); 983 984 cursor = mDatabase.query("employee", new String[] { "name", "sum(salary)" }, 985 null, null, "name", "sum(salary) > 1000", "name", "2"); 986 assertNotNull(cursor); 987 assertEquals(2, cursor.getCount()); 988 989 cursor.moveToFirst(); 990 assertEquals("Jim", cursor.getString(COLUMN_NAME_INDEX)); 991 assertEquals(4500, cursor.getInt(COLUMN_SALARY_INDEX)); 992 cursor.moveToNext(); 993 assertEquals("Mike", cursor.getString(COLUMN_NAME_INDEX)); 994 assertEquals(4000, cursor.getInt(COLUMN_SALARY_INDEX)); 995 cursor.close(); 996 997 String sql = "SELECT name, month FROM employee WHERE salary > ?;"; 998 cursor = mDatabase.rawQuery(sql, new String[] { "2000" }); 999 assertNotNull(cursor); 1000 assertEquals(2, cursor.getCount()); 1001 1002 final int COLUMN_MONTH_INDEX = 1; 1003 cursor.moveToFirst(); 1004 assertEquals("Mike", cursor.getString(COLUMN_NAME_INDEX)); 1005 assertEquals(2, cursor.getInt(COLUMN_MONTH_INDEX)); 1006 cursor.moveToNext(); 1007 assertEquals("Jim", cursor.getString(COLUMN_NAME_INDEX)); 1008 assertEquals(3, cursor.getInt(COLUMN_MONTH_INDEX)); 1009 cursor.close(); 1010 1011 cursor = mDatabase.rawQueryWithFactory(factory, sql, new String[] { "2000" }, null); 1012 assertNotNull(cursor); 1013 assertEquals(2, cursor.getCount()); 1014 assertTrue(cursor instanceof MockSQLiteCursor); 1015 cursor.moveToFirst(); 1016 assertEquals("Mike", cursor.getString(COLUMN_NAME_INDEX)); 1017 assertEquals(2, cursor.getInt(COLUMN_MONTH_INDEX)); 1018 cursor.moveToNext(); 1019 assertEquals("Jim", cursor.getString(COLUMN_NAME_INDEX)); 1020 assertEquals(3, cursor.getInt(COLUMN_MONTH_INDEX)); 1021 cursor.close(); 1022 } 1023 1024 @TestTargets({ 1025 @TestTargetNew( 1026 level = TestLevel.COMPLETE, 1027 notes = "Test replace()", 1028 method = "replace", 1029 args = {java.lang.String.class, java.lang.String.class, 1030 android.content.ContentValues.class} 1031 ), 1032 @TestTargetNew( 1033 level = TestLevel.COMPLETE, 1034 notes = "Test replaceOrThrow()", 1035 method = "replaceOrThrow", 1036 args = {java.lang.String.class, java.lang.String.class, 1037 android.content.ContentValues.class} 1038 ) 1039 }) 1040 public void testReplace() { 1041 mDatabase.execSQL("CREATE TABLE test (_id INTEGER PRIMARY KEY, " 1042 + "name TEXT, age INTEGER, address TEXT);"); 1043 1044 ContentValues values = new ContentValues(); 1045 values.put("name", "Jack"); 1046 values.put("age", 20); 1047 values.put("address", "LA"); 1048 mDatabase.replace(TABLE_NAME, "name", values); 1049 1050 Cursor cursor = mDatabase.query(TABLE_NAME, TEST_PROJECTION, 1051 null, null, null, null, null); 1052 assertNotNull(cursor); 1053 assertEquals(1, cursor.getCount()); 1054 cursor.moveToFirst(); 1055 int id = cursor.getInt(COLUMN_ID_INDEX); 1056 assertEquals("Jack", cursor.getString(COLUMN_NAME_INDEX)); 1057 assertEquals(20, cursor.getInt(COLUMN_AGE_INDEX)); 1058 assertEquals("LA", cursor.getString(COLUMN_ADDR_INDEX)); 1059 cursor.close(); 1060 1061 values = new ContentValues(); 1062 values.put("_id", id); 1063 values.put("name", "Mike"); 1064 values.put("age", 40); 1065 values.put("address", "London"); 1066 mDatabase.replace(TABLE_NAME, "name", values); 1067 1068 cursor = mDatabase.query(TABLE_NAME, TEST_PROJECTION, null, null, null, null, null); 1069 assertNotNull(cursor); 1070 assertEquals(1, cursor.getCount()); // there is still ONLY 1 record. 1071 cursor.moveToFirst(); 1072 assertEquals("Mike", cursor.getString(COLUMN_NAME_INDEX)); 1073 assertEquals(40, cursor.getInt(COLUMN_AGE_INDEX)); 1074 assertEquals("London", cursor.getString(COLUMN_ADDR_INDEX)); 1075 cursor.close(); 1076 1077 values = new ContentValues(); 1078 values.put("name", "Jack"); 1079 values.put("age", 20); 1080 values.put("address", "LA"); 1081 mDatabase.replaceOrThrow(TABLE_NAME, "name", values); 1082 1083 cursor = mDatabase.query(TABLE_NAME, TEST_PROJECTION, null, null, null, null, null); 1084 assertNotNull(cursor); 1085 assertEquals(2, cursor.getCount()); 1086 cursor.moveToFirst(); 1087 assertEquals("Mike", cursor.getString(COLUMN_NAME_INDEX)); 1088 assertEquals(40, cursor.getInt(COLUMN_AGE_INDEX)); 1089 assertEquals("London", cursor.getString(COLUMN_ADDR_INDEX)); 1090 cursor.moveToNext(); 1091 assertEquals("Jack", cursor.getString(COLUMN_NAME_INDEX)); 1092 assertEquals(20, cursor.getInt(COLUMN_AGE_INDEX)); 1093 assertEquals("LA", cursor.getString(COLUMN_ADDR_INDEX)); 1094 cursor.close(); 1095 1096 values = new ContentValues(); 1097 values.put("Wrong Key", "Wrong value"); 1098 try { 1099 mDatabase.replaceOrThrow(TABLE_NAME, "name", values); 1100 fail("should throw SQLException."); 1101 } catch (SQLException e) { 1102 } 1103 } 1104 1105 @TestTargetNew( 1106 level = TestLevel.COMPLETE, 1107 notes = "Test update()", 1108 method = "update", 1109 args = {java.lang.String.class, android.content.ContentValues.class, 1110 java.lang.String.class, java.lang.String[].class} 1111 ) 1112 public void testUpdate() { 1113 mDatabase.execSQL("CREATE TABLE test (_id INTEGER PRIMARY KEY, data TEXT);"); 1114 1115 mDatabase.execSQL("INSERT INTO test (data) VALUES ('string1');"); 1116 mDatabase.execSQL("INSERT INTO test (data) VALUES ('string2');"); 1117 mDatabase.execSQL("INSERT INTO test (data) VALUES ('string3');"); 1118 1119 String updatedString = "this is an updated test"; 1120 ContentValues values = new ContentValues(1); 1121 values.put("data", updatedString); 1122 assertEquals(1, mDatabase.update("test", values, "_id=1", null)); 1123 Cursor cursor = mDatabase.query("test", null, "_id=1", null, null, null, null); 1124 assertNotNull(cursor); 1125 assertEquals(1, cursor.getCount()); 1126 cursor.moveToFirst(); 1127 String value = cursor.getString(cursor.getColumnIndexOrThrow("data")); 1128 assertEquals(updatedString, value); 1129 cursor.close(); 1130 } 1131 1132 @TestTargetNew( 1133 level = TestLevel.COMPLETE, 1134 notes = "Test needUpgrade(int)", 1135 method = "needUpgrade", 1136 args = {int.class} 1137 ) 1138 public void testNeedUpgrade() { 1139 mDatabase.setVersion(0); 1140 assertTrue(mDatabase.needUpgrade(1)); 1141 mDatabase.setVersion(1); 1142 assertFalse(mDatabase.needUpgrade(1)); 1143 } 1144 1145 @TestTargetNew( 1146 level = TestLevel.COMPLETE, 1147 notes = "Test setLocale(Locale)", 1148 method = "setLocale", 1149 args = {java.util.Locale.class} 1150 ) 1151 public void testSetLocale() { 1152 final String[] STRINGS = { 1153 "c\u00f4t\u00e9", 1154 "cote", 1155 "c\u00f4te", 1156 "cot\u00e9", 1157 "boy", 1158 "dog", 1159 "COTE", 1160 }; 1161 1162 mDatabase.execSQL("CREATE TABLE test (data TEXT COLLATE LOCALIZED);"); 1163 for (String s : STRINGS) { 1164 mDatabase.execSQL("INSERT INTO test VALUES('" + s + "');"); 1165 } 1166 1167 mDatabase.setLocale(new Locale("en", "US")); 1168 1169 String sql = "SELECT data FROM test ORDER BY data COLLATE LOCALIZED ASC"; 1170 Cursor cursor = mDatabase.rawQuery(sql, null); 1171 assertNotNull(cursor); 1172 ArrayList<String> items = new ArrayList<String>(); 1173 while (cursor.moveToNext()) { 1174 items.add(cursor.getString(0)); 1175 } 1176 String[] results = items.toArray(new String[items.size()]); 1177 assertEquals(STRINGS.length, results.length); 1178 cursor.close(); 1179 1180 // The database code currently uses PRIMARY collation strength, 1181 // meaning that all versions of a character compare equal (regardless 1182 // of case or accents), leaving the "cote" flavors in database order. 1183 MoreAsserts.assertEquals(results, new String[] { 1184 STRINGS[4], // "boy" 1185 STRINGS[0], // sundry forms of "cote" 1186 STRINGS[1], 1187 STRINGS[2], 1188 STRINGS[3], 1189 STRINGS[6], // "COTE" 1190 STRINGS[5], // "dog" 1191 }); 1192 } 1193 1194 @TestTargetNew( 1195 level = TestLevel.COMPLETE, 1196 notes = "Test onAllReferencesReleased()", 1197 method = "onAllReferencesReleased", 1198 args = {} 1199 ) 1200 public void testOnAllReferencesReleased() { 1201 assertTrue(mDatabase.isOpen()); 1202 mDatabase.releaseReference(); 1203 assertFalse(mDatabase.isOpen()); 1204 } 1205 1206 @TestTargetNew( 1207 level = TestLevel.COMPLETE, 1208 notes = "Test transaction with SQLTransactionListener()", 1209 method = "beginTransactionWithListener", 1210 args = {SQLiteTransactionListener.class} 1211 ) 1212 public void testTransactionWithSQLiteTransactionListener() { 1213 mDatabase.execSQL("CREATE TABLE test (num INTEGER);"); 1214 mDatabase.execSQL("INSERT INTO test (num) VALUES (0)"); 1215 1216 assertEquals(mTransactionListenerOnBeginCalled, false); 1217 assertEquals(mTransactionListenerOnCommitCalled, false); 1218 assertEquals(mTransactionListenerOnRollbackCalled, false); 1219 mDatabase.beginTransactionWithListener(new TestSQLiteTransactionListener()); 1220 1221 // Assert that the transcation has started 1222 assertEquals(mTransactionListenerOnBeginCalled, true); 1223 assertEquals(mTransactionListenerOnCommitCalled, false); 1224 assertEquals(mTransactionListenerOnRollbackCalled, false); 1225 1226 setNum(1); 1227 1228 // State shouldn't have changed 1229 assertEquals(mTransactionListenerOnBeginCalled, true); 1230 assertEquals(mTransactionListenerOnCommitCalled, false); 1231 assertEquals(mTransactionListenerOnRollbackCalled, false); 1232 1233 // commit the transaction 1234 mDatabase.setTransactionSuccessful(); 1235 mDatabase.endTransaction(); 1236 1237 // the listener should have been told that commit was called 1238 assertEquals(mTransactionListenerOnBeginCalled, true); 1239 assertEquals(mTransactionListenerOnCommitCalled, true); 1240 assertEquals(mTransactionListenerOnRollbackCalled, false); 1241 } 1242 1243 @TestTargetNew( 1244 level = TestLevel.COMPLETE, 1245 notes = "Test transaction w/rollback with SQLTransactionListener()", 1246 method = "beginTransactionWithListener", 1247 args = {SQLiteTransactionListener.class} 1248 ) 1249 public void testRollbackTransactionWithSQLiteTransactionListener() { 1250 mDatabase.execSQL("CREATE TABLE test (num INTEGER);"); 1251 mDatabase.execSQL("INSERT INTO test (num) VALUES (0)"); 1252 1253 assertEquals(mTransactionListenerOnBeginCalled, false); 1254 assertEquals(mTransactionListenerOnCommitCalled, false); 1255 assertEquals(mTransactionListenerOnRollbackCalled, false); 1256 mDatabase.beginTransactionWithListener(new TestSQLiteTransactionListener()); 1257 1258 // Assert that the transcation has started 1259 assertEquals(mTransactionListenerOnBeginCalled, true); 1260 assertEquals(mTransactionListenerOnCommitCalled, false); 1261 assertEquals(mTransactionListenerOnRollbackCalled, false); 1262 1263 setNum(1); 1264 1265 // State shouldn't have changed 1266 assertEquals(mTransactionListenerOnBeginCalled, true); 1267 assertEquals(mTransactionListenerOnCommitCalled, false); 1268 assertEquals(mTransactionListenerOnRollbackCalled, false); 1269 1270 // commit the transaction 1271 mDatabase.endTransaction(); 1272 1273 // the listener should have been told that commit was called 1274 assertEquals(mTransactionListenerOnBeginCalled, true); 1275 assertEquals(mTransactionListenerOnCommitCalled, false); 1276 assertEquals(mTransactionListenerOnRollbackCalled, true); 1277 } 1278 1279 private class TestSQLiteTransactionListener implements SQLiteTransactionListener { 1280 public void onBegin() { 1281 mTransactionListenerOnBeginCalled = true; 1282 } 1283 1284 public void onCommit() { 1285 mTransactionListenerOnCommitCalled = true; 1286 } 1287 1288 public void onRollback() { 1289 mTransactionListenerOnRollbackCalled = true; 1290 } 1291 } 1292 1293 @TestTargetNew( 1294 level = TestLevel.COMPLETE, 1295 notes = "removed the android-provided group_concat built-in function." + 1296 "Instead we are now using the sqlite3.c provided group_concat function." + 1297 "and it returns NULL if the columnds to be concatenated have null values" + 1298 " in them", 1299 method = "sqlite3::group_concat built-in function", 1300 args = {java.lang.String.class} 1301 ) 1302 public void testGroupConcat() { 1303 mDatabase.execSQL("CREATE TABLE test (i INT, j TEXT);"); 1304 1305 // insert 2 rows 1306 String sql = "INSERT INTO test (i) VALUES (?);"; 1307 SQLiteStatement insertStatement = mDatabase.compileStatement(sql); 1308 DatabaseUtils.bindObjectToProgram(insertStatement, 1, 1); 1309 insertStatement.execute(); 1310 DatabaseUtils.bindObjectToProgram(insertStatement, 1, 2); 1311 insertStatement.execute(); 1312 insertStatement.close(); 1313 1314 // make sure there are 2 rows in the table 1315 Cursor cursor = mDatabase.rawQuery("SELECT count(*) FROM test", null); 1316 assertNotNull(cursor); 1317 assertEquals(1, cursor.getCount()); 1318 cursor.moveToNext(); 1319 assertEquals(2, cursor.getInt(0)); 1320 cursor.close(); 1321 1322 // concatenate column j from all the rows. should return NULL 1323 cursor = mDatabase.rawQuery("SELECT group_concat(j, ' ') FROM test", null); 1324 assertNotNull(cursor); 1325 assertEquals(1, cursor.getCount()); 1326 cursor.moveToNext(); 1327 assertNull(cursor.getString(0)); 1328 cursor.close(); 1329 1330 // drop the table 1331 mDatabase.execSQL("DROP TABLE test;"); 1332 // should get no exceptions 1333 } 1334 1335 @TestTargetNew( 1336 level = TestLevel.COMPLETE, 1337 notes = "test schema changes - change existing table.", 1338 method = "compileStatement", 1339 args = {java.lang.String.class} 1340 ) 1341 public void testSchemaChanges() { 1342 mDatabase.execSQL("CREATE TABLE test (i INT, j INT);"); 1343 1344 // at the beginning, there is no record in the database. 1345 Cursor cursor = mDatabase.rawQuery("SELECT * FROM test", null); 1346 assertNotNull(cursor); 1347 assertEquals(0, cursor.getCount()); 1348 cursor.close(); 1349 1350 String sql = "INSERT INTO test VALUES (?, ?);"; 1351 SQLiteStatement insertStatement = mDatabase.compileStatement(sql); 1352 DatabaseUtils.bindObjectToProgram(insertStatement, 1, 1); 1353 DatabaseUtils.bindObjectToProgram(insertStatement, 2, 2); 1354 insertStatement.execute(); 1355 insertStatement.close(); 1356 1357 // read the data from the table and make sure it is correct 1358 cursor = mDatabase.rawQuery("SELECT i,j FROM test", null); 1359 assertNotNull(cursor); 1360 assertEquals(1, cursor.getCount()); 1361 cursor.moveToNext(); 1362 assertEquals(1, cursor.getInt(0)); 1363 assertEquals(2, cursor.getInt(1)); 1364 cursor.close(); 1365 1366 // alter the table and execute another statement 1367 mDatabase.execSQL("ALTER TABLE test ADD COLUMN k int;"); 1368 sql = "INSERT INTO test VALUES (?, ?, ?);"; 1369 insertStatement = mDatabase.compileStatement(sql); 1370 DatabaseUtils.bindObjectToProgram(insertStatement, 1, 3); 1371 DatabaseUtils.bindObjectToProgram(insertStatement, 2, 4); 1372 DatabaseUtils.bindObjectToProgram(insertStatement, 3, 5); 1373 insertStatement.execute(); 1374 insertStatement.close(); 1375 1376 // read the data from the table and make sure it is correct 1377 cursor = mDatabase.rawQuery("SELECT i,j,k FROM test", null); 1378 assertNotNull(cursor); 1379 assertEquals(2, cursor.getCount()); 1380 cursor.moveToNext(); 1381 assertEquals(1, cursor.getInt(0)); 1382 assertEquals(2, cursor.getInt(1)); 1383 assertNull(cursor.getString(2)); 1384 cursor.moveToNext(); 1385 assertEquals(3, cursor.getInt(0)); 1386 assertEquals(4, cursor.getInt(1)); 1387 assertEquals(5, cursor.getInt(2)); 1388 cursor.close(); 1389 1390 // make sure the old statement - which should *try to reuse* cached query plan - 1391 // still works 1392 cursor = mDatabase.rawQuery("SELECT i,j FROM test", null); 1393 assertNotNull(cursor); 1394 assertEquals(2, cursor.getCount()); 1395 cursor.moveToNext(); 1396 assertEquals(1, cursor.getInt(0)); 1397 assertEquals(2, cursor.getInt(1)); 1398 cursor.moveToNext(); 1399 assertEquals(3, cursor.getInt(0)); 1400 assertEquals(4, cursor.getInt(1)); 1401 cursor.close(); 1402 1403 SQLiteStatement deleteStatement = mDatabase.compileStatement("DELETE FROM test"); 1404 deleteStatement.execute(); 1405 deleteStatement.close(); 1406 } 1407 1408 @TestTargetNew( 1409 level = TestLevel.COMPLETE, 1410 notes = "test schema changes - add new table.", 1411 method = "compileStatement", 1412 args = {java.lang.String.class} 1413 ) 1414 public void testSchemaChangesNewTable() { 1415 mDatabase.execSQL("CREATE TABLE test (i INT, j INT);"); 1416 1417 // at the beginning, there is no record in the database. 1418 Cursor cursor = mDatabase.rawQuery("SELECT * FROM test", null); 1419 assertNotNull(cursor); 1420 assertEquals(0, cursor.getCount()); 1421 cursor.close(); 1422 1423 String sql = "INSERT INTO test VALUES (?, ?);"; 1424 SQLiteStatement insertStatement = mDatabase.compileStatement(sql); 1425 DatabaseUtils.bindObjectToProgram(insertStatement, 1, 1); 1426 DatabaseUtils.bindObjectToProgram(insertStatement, 2, 2); 1427 insertStatement.execute(); 1428 insertStatement.close(); 1429 1430 // read the data from the table and make sure it is correct 1431 cursor = mDatabase.rawQuery("SELECT i,j FROM test", null); 1432 assertNotNull(cursor); 1433 assertEquals(1, cursor.getCount()); 1434 cursor.moveToNext(); 1435 assertEquals(1, cursor.getInt(0)); 1436 assertEquals(2, cursor.getInt(1)); 1437 cursor.close(); 1438 1439 // alter the table and execute another statement 1440 mDatabase.execSQL("CREATE TABLE test_new (i INT, j INT, k INT);"); 1441 sql = "INSERT INTO test_new VALUES (?, ?, ?);"; 1442 insertStatement = mDatabase.compileStatement(sql); 1443 DatabaseUtils.bindObjectToProgram(insertStatement, 1, 3); 1444 DatabaseUtils.bindObjectToProgram(insertStatement, 2, 4); 1445 DatabaseUtils.bindObjectToProgram(insertStatement, 3, 5); 1446 insertStatement.execute(); 1447 insertStatement.close(); 1448 1449 // read the data from the table and make sure it is correct 1450 cursor = mDatabase.rawQuery("SELECT i,j,k FROM test_new", null); 1451 assertNotNull(cursor); 1452 assertEquals(1, cursor.getCount()); 1453 cursor.moveToNext(); 1454 assertEquals(3, cursor.getInt(0)); 1455 assertEquals(4, cursor.getInt(1)); 1456 assertEquals(5, cursor.getInt(2)); 1457 cursor.close(); 1458 1459 // make sure the old statement - which should *try to reuse* cached query plan - 1460 // still works 1461 cursor = mDatabase.rawQuery("SELECT i,j FROM test", null); 1462 assertNotNull(cursor); 1463 assertEquals(1, cursor.getCount()); 1464 cursor.moveToNext(); 1465 assertEquals(1, cursor.getInt(0)); 1466 assertEquals(2, cursor.getInt(1)); 1467 cursor.close(); 1468 1469 SQLiteStatement deleteStatement = mDatabase.compileStatement("DELETE FROM test"); 1470 deleteStatement.execute(); 1471 deleteStatement.close(); 1472 1473 SQLiteStatement deleteStatement2 = mDatabase.compileStatement("DELETE FROM test_new"); 1474 deleteStatement2.execute(); 1475 deleteStatement2.close(); 1476 } 1477 1478 @TestTargetNew( 1479 level = TestLevel.COMPLETE, 1480 notes = "test schema changes - drop existing table.", 1481 method = "compileStatement", 1482 args = {java.lang.String.class} 1483 ) 1484 public void testSchemaChangesDropTable() { 1485 mDatabase.execSQL("CREATE TABLE test (i INT, j INT);"); 1486 1487 // at the beginning, there is no record in the database. 1488 Cursor cursor = mDatabase.rawQuery("SELECT * FROM test", null); 1489 assertNotNull(cursor); 1490 assertEquals(0, cursor.getCount()); 1491 cursor.close(); 1492 1493 String sql = "INSERT INTO test VALUES (?, ?);"; 1494 SQLiteStatement insertStatement = mDatabase.compileStatement(sql); 1495 DatabaseUtils.bindObjectToProgram(insertStatement, 1, 1); 1496 DatabaseUtils.bindObjectToProgram(insertStatement, 2, 2); 1497 insertStatement.execute(); 1498 insertStatement.close(); 1499 1500 // read the data from the table and make sure it is correct 1501 cursor = mDatabase.rawQuery("SELECT i,j FROM test", null); 1502 assertNotNull(cursor); 1503 assertEquals(1, cursor.getCount()); 1504 cursor.moveToNext(); 1505 assertEquals(1, cursor.getInt(0)); 1506 assertEquals(2, cursor.getInt(1)); 1507 } 1508 1509 @TestTargetNew( 1510 level = TestLevel.COMPLETE, 1511 notes = "test enableWriteAheadLogging", 1512 method = "enableWriteAheadLogging", 1513 args = {} 1514 ) 1515 /** 1516 * With sqlite's write-ahead-logging (WAL) enabled, readers get old version of data 1517 * from the table that a writer is modifying at the same time. 1518 * <p> 1519 * This method does the following to test this sqlite3 feature 1520 * <ol> 1521 * <li>creates a table in the database and populates it with 5 rows of data</li> 1522 * <li>do "select count(*) from this_table" and expect to receive 5</li> 1523 * <li>start a writer thread who BEGINs a transaction, INSERTs a single row 1524 * into this_table</li> 1525 * <li>writer stops the transaction at this point, kicks off a reader thread - which will 1526 * do the above SELECT query: "select count(*) from this_table"</li> 1527 * <li>this query should return value 5 - because writer is still in transaction and 1528 * sqlite returns OLD version of the data</li> 1529 * <li>writer ends the transaction, thus making the extra row now visible to everyone</li> 1530 * <li>reader is kicked off again to do the same query. this time query should 1531 * return value = 6 which includes the newly inserted row into this_table.</li> 1532 *</p> 1533 * @throws InterruptedException 1534 */ 1535 @LargeTest 1536 public void testReaderGetsOldVersionOfDataWhenWriterIsInXact() throws InterruptedException { 1537 // redo setup to create WAL enabled database 1538 mDatabase.close(); 1539 new File(mDatabase.getPath()).delete(); 1540 mDatabase = SQLiteDatabase.openOrCreateDatabase(mDatabaseFile.getPath(), null, null); 1541 boolean rslt = mDatabase.enableWriteAheadLogging(); 1542 assertTrue(rslt); 1543 assertNotNull(mDatabase); 1544 1545 // create a new table and insert 5 records into it. 1546 mDatabase.execSQL("CREATE TABLE t1 (i int, j int);"); 1547 mDatabase.beginTransaction(); 1548 for (int i = 0; i < 5; i++) { 1549 mDatabase.execSQL("insert into t1 values(?,?);", new String[] {i+"", i+""}); 1550 } 1551 mDatabase.setTransactionSuccessful(); 1552 mDatabase.endTransaction(); 1553 1554 // make sure a reader can read the above data 1555 ReaderQueryingData r1 = new ReaderQueryingData(5); 1556 r1.start(); 1557 Thread.yield(); 1558 try {r1.join();} catch (Exception e) {} 1559 1560 WriterDoingSingleTransaction w = new WriterDoingSingleTransaction(); 1561 w.start(); 1562 w.join(); 1563 } 1564 1565 private class WriterDoingSingleTransaction extends Thread { 1566 @Override public void run() { 1567 // start a transaction 1568 mDatabase.beginTransactionNonExclusive(); 1569 mDatabase.execSQL("insert into t1 values(?,?);", new String[] {"11", "11"}); 1570 assertTrue(mDatabase.isOpen()); 1571 1572 // while the writer is in a transaction, start a reader and make sure it can still 1573 // read 5 rows of data (= old data prior to the current transaction) 1574 ReaderQueryingData r1 = new ReaderQueryingData(5); 1575 r1.start(); 1576 try {r1.join();} catch (Exception e) {} 1577 1578 // now, have the writer do the select count(*) 1579 // it should execute on the same connection as this transaction 1580 // and count(*) should reflect the newly inserted row 1581 Long l = DatabaseUtils.longForQuery(mDatabase, "select count(*) from t1", null); 1582 assertEquals(6, l.intValue()); 1583 1584 // end transaction 1585 mDatabase.setTransactionSuccessful(); 1586 mDatabase.endTransaction(); 1587 1588 // reader should now be able to read 6 rows = new data AFTER this transaction 1589 r1 = new ReaderQueryingData(6); 1590 r1.start(); 1591 try {r1.join();} catch (Exception e) {} 1592 } 1593 } 1594 1595 private class ReaderQueryingData extends Thread { 1596 private int count; 1597 /** 1598 * constructor with a param to indicate the number of rows expected to be read 1599 */ 1600 public ReaderQueryingData(int count) { 1601 this.count = count; 1602 } 1603 @Override public void run() { 1604 Long l = DatabaseUtils.longForQuery(mDatabase, "select count(*) from t1", null); 1605 assertEquals(count, l.intValue()); 1606 } 1607 } 1608 1609 @TestTargetNew( 1610 level = TestLevel.COMPLETE, 1611 notes = "test exceptions from enableWriteAheadLogging().", 1612 method = "enableWriteAheadLogging", 1613 args = {} 1614 ) 1615 public void testExceptionsFromEnableWriteAheadLogging() { 1616 // attach a database 1617 // redo setup to create WAL enabled database 1618 mDatabase.close(); 1619 new File(mDatabase.getPath()).delete(); 1620 mDatabase = SQLiteDatabase.openOrCreateDatabase(mDatabaseFile.getPath(), null, null); 1621 1622 // attach a database and call enableWriteAheadLogging - should not be allowed 1623 mDatabase.execSQL("attach database ':memory:' as memoryDb"); 1624 boolean rslt = mDatabase.enableWriteAheadLogging(); 1625 assertFalse(rslt); 1626 // enableWriteAheadLogging on memory database is not allowed 1627 SQLiteDatabase db = SQLiteDatabase.create(null); 1628 rslt = db.enableWriteAheadLogging(); 1629 assertFalse(rslt); 1630 db.close(); 1631 } 1632 } 1633