1 package org.robolectric.shadows; 2 3 import static android.database.sqlite.SQLiteDatabase.OPEN_READWRITE; 4 import static com.google.common.truth.Truth.assertThat; 5 import static org.junit.Assert.assertEquals; 6 import static org.junit.Assert.fail; 7 8 import android.content.ContentValues; 9 import android.database.Cursor; 10 import android.database.sqlite.SQLiteDatabase; 11 import android.database.sqlite.SQLiteException; 12 import android.database.sqlite.SQLiteGlobal; 13 import android.os.CancellationSignal; 14 import android.os.OperationCanceledException; 15 import androidx.test.core.app.ApplicationProvider; 16 import androidx.test.ext.junit.runners.AndroidJUnit4; 17 import java.io.File; 18 import java.util.ArrayList; 19 import java.util.List; 20 import java.util.concurrent.CountDownLatch; 21 import org.junit.After; 22 import org.junit.Before; 23 import org.junit.Test; 24 import org.junit.runner.RunWith; 25 26 @RunWith(AndroidJUnit4.class) 27 public class SQLiteDatabaseTest { 28 private SQLiteDatabase database; 29 private List<SQLiteDatabase> openDatabases = new ArrayList<>(); 30 private static final String ANY_VALID_SQL = "SELECT 1"; 31 private File databasePath; 32 33 @Before setUp()34 public void setUp() throws Exception { 35 databasePath = ApplicationProvider.getApplicationContext().getDatabasePath("database.db"); 36 databasePath.getParentFile().mkdirs(); 37 38 database = openOrCreateDatabase(databasePath); 39 database.execSQL( 40 "CREATE TABLE table_name (\n" 41 + " id INTEGER PRIMARY KEY AUTOINCREMENT,\n" 42 + " first_column VARCHAR(255),\n" 43 + " second_column BINARY,\n" 44 + " name VARCHAR(255),\n" 45 + " big_int INTEGER\n" 46 + ");"); 47 48 database.execSQL( 49 "CREATE TABLE rawtable (\n" 50 + " id INTEGER PRIMARY KEY AUTOINCREMENT,\n" 51 + " first_column VARCHAR(255),\n" 52 + " second_column BINARY,\n" 53 + " name VARCHAR(255),\n" 54 + " big_int INTEGER\n" 55 + ");"); 56 57 database.execSQL( 58 "CREATE TABLE exectable (\n" 59 + " id INTEGER PRIMARY KEY AUTOINCREMENT,\n" 60 + " first_column VARCHAR(255),\n" 61 + " second_column BINARY,\n" 62 + " name VARCHAR(255),\n" 63 + " big_int INTEGER\n" 64 + ");"); 65 66 database.execSQL( 67 "CREATE TABLE blob_table (\n" + " id INTEGER PRIMARY KEY,\n" + " blob_col BLOB\n" + ");"); 68 69 String stringColumnValue = "column_value"; 70 byte[] byteColumnValue = new byte[] {1, 2, 3}; 71 72 ContentValues values = new ContentValues(); 73 74 values.put("first_column", stringColumnValue); 75 values.put("second_column", byteColumnValue); 76 77 database.insert("rawtable", null, values); 78 //////////////////////////////////////////////// 79 String stringColumnValue2 = "column_value2"; 80 byte[] byteColumnValue2 = new byte[] {4, 5, 6}; 81 ContentValues values2 = new ContentValues(); 82 83 values2.put("first_column", stringColumnValue2); 84 values2.put("second_column", byteColumnValue2); 85 86 database.insert("rawtable", null, values2); 87 } 88 89 @After tearDown()90 public void tearDown() { 91 for (SQLiteDatabase openDatabase : openDatabases) { 92 openDatabase.close(); 93 } 94 } 95 96 @Test testInsertAndQuery()97 public void testInsertAndQuery() { 98 String stringColumnValue = "column_value"; 99 byte[] byteColumnValue = new byte[] {1, 2, 3}; 100 101 ContentValues values = new ContentValues(); 102 103 values.put("first_column", stringColumnValue); 104 values.put("second_column", byteColumnValue); 105 106 database.insert("table_name", null, values); 107 108 Cursor cursor = 109 database.query( 110 "table_name", 111 new String[] {"second_column", "first_column"}, 112 null, 113 null, 114 null, 115 null, 116 null); 117 118 assertThat(cursor.moveToFirst()).isTrue(); 119 120 byte[] byteValueFromDatabase = cursor.getBlob(0); 121 String stringValueFromDatabase = cursor.getString(1); 122 123 assertThat(stringValueFromDatabase).isEqualTo(stringColumnValue); 124 assertThat(byteValueFromDatabase).isEqualTo(byteColumnValue); 125 cursor.close(); 126 } 127 128 @Test testInsertAndRawQuery()129 public void testInsertAndRawQuery() { 130 String stringColumnValue = "column_value"; 131 byte[] byteColumnValue = new byte[] {1, 2, 3}; 132 133 ContentValues values = new ContentValues(); 134 135 values.put("first_column", stringColumnValue); 136 values.put("second_column", byteColumnValue); 137 138 database.insert("table_name", null, values); 139 140 Cursor cursor = 141 database.rawQuery("select second_column, first_column from" + " table_name", null); 142 143 assertThat(cursor.moveToFirst()).isTrue(); 144 145 byte[] byteValueFromDatabase = cursor.getBlob(0); 146 String stringValueFromDatabase = cursor.getString(1); 147 148 assertThat(stringValueFromDatabase).isEqualTo(stringColumnValue); 149 assertThat(byteValueFromDatabase).isEqualTo(byteColumnValue); 150 cursor.close(); 151 } 152 153 @Test(expected = android.database.SQLException.class) testInsertOrThrowWithSQLException()154 public void testInsertOrThrowWithSQLException() { 155 ContentValues values = new ContentValues(); 156 values.put("id", 1); 157 158 database.insertOrThrow("table_name", null, values); 159 database.insertOrThrow("table_name", null, values); 160 } 161 162 @Test testInsertOrThrow()163 public void testInsertOrThrow() { 164 String stringColumnValue = "column_value"; 165 byte[] byteColumnValue = new byte[] {1, 2, 3}; 166 ContentValues values = new ContentValues(); 167 values.put("first_column", stringColumnValue); 168 values.put("second_column", byteColumnValue); 169 database.insertOrThrow("table_name", null, values); 170 171 Cursor cursor = 172 database.rawQuery("select second_column, first_column from" + " table_name", null); 173 assertThat(cursor.moveToFirst()).isTrue(); 174 byte[] byteValueFromDatabase = cursor.getBlob(0); 175 String stringValueFromDatabase = cursor.getString(1); 176 assertThat(stringValueFromDatabase).isEqualTo(stringColumnValue); 177 assertThat(byteValueFromDatabase).isEqualTo(byteColumnValue); 178 cursor.close(); 179 } 180 181 @Test(expected = IllegalArgumentException.class) testRawQueryThrowsIndex0NullException()182 public void testRawQueryThrowsIndex0NullException() { 183 database.rawQuery( 184 "select second_column, first_column from rawtable" + " WHERE `id` = ?", 185 new String[] {null}); 186 } 187 188 @Test(expected = IllegalArgumentException.class) testRawQueryThrowsIndex0NullException2()189 public void testRawQueryThrowsIndex0NullException2() { 190 database.rawQuery("select second_column, first_column from rawtable", new String[] {null}); 191 } 192 193 @Test testRawQueryCountWithOneArgument()194 public void testRawQueryCountWithOneArgument() { 195 Cursor cursor = 196 database.rawQuery( 197 "select second_column, first_column from rawtable WHERE" + " `id` = ?", 198 new String[] {"1"}); 199 assertThat(cursor.getCount()).isEqualTo(1); 200 cursor.close(); 201 } 202 203 @Test testRawQueryCountWithNullArgs()204 public void testRawQueryCountWithNullArgs() { 205 Cursor cursor = database.rawQuery("select second_column, first_column from rawtable", null); 206 assertThat(cursor.getCount()).isEqualTo(2); 207 cursor.close(); 208 } 209 210 @Test testRawQueryCountWithEmptyArguments()211 public void testRawQueryCountWithEmptyArguments() { 212 Cursor cursor = 213 database.rawQuery( 214 "select second_column, first_column" + " from" + " rawtable", new String[] {}); 215 assertThat(cursor.getCount()).isEqualTo(2); 216 cursor.close(); 217 } 218 219 @Test(expected = IllegalArgumentException.class) shouldThrowWhenArgumentsDoNotMatchQuery()220 public void shouldThrowWhenArgumentsDoNotMatchQuery() { 221 database.rawQuery("select second_column, first_column from rawtable", new String[] {"1"}); 222 } 223 224 @Test testInsertWithException()225 public void testInsertWithException() { 226 ContentValues values = new ContentValues(); 227 228 assertEquals(-1, database.insert("table_that_doesnt_exist", null, values)); 229 } 230 231 @Test testEmptyTable()232 public void testEmptyTable() { 233 Cursor cursor = 234 database.query( 235 "table_name", 236 new String[] {"second_column", "first_column"}, 237 null, 238 null, 239 null, 240 null, 241 null); 242 243 assertThat(cursor.moveToFirst()).isFalse(); 244 cursor.close(); 245 } 246 247 @Test testInsertRowIdGeneration()248 public void testInsertRowIdGeneration() { 249 ContentValues values = new ContentValues(); 250 values.put("name", "Chuck"); 251 252 long id = database.insert("table_name", null, values); 253 254 assertThat(id).isNotEqualTo(0L); 255 } 256 257 @Test testInsertKeyGeneration()258 public void testInsertKeyGeneration() { 259 ContentValues values = new ContentValues(); 260 values.put("name", "Chuck"); 261 262 long key = 263 database.insertWithOnConflict("table_name", null, values, SQLiteDatabase.CONFLICT_IGNORE); 264 265 assertThat(key).isNotEqualTo(0L); 266 } 267 268 @Test testInsertDuplicatedKeyGeneration()269 public void testInsertDuplicatedKeyGeneration() { 270 ContentValues values = new ContentValues(); 271 values.put("id", 123); 272 values.put("name", "Chuck"); 273 274 long firstKey = 275 database.insertWithOnConflict("table_name", null, values, SQLiteDatabase.CONFLICT_IGNORE); 276 277 assertThat(firstKey).isEqualTo(123L); 278 279 long duplicateKey = 280 database.insertWithOnConflict("table_name", null, values, SQLiteDatabase.CONFLICT_IGNORE); 281 282 assertThat(duplicateKey).isEqualTo(-1L); 283 } 284 285 @Test testInsertEmptyBlobArgument()286 public void testInsertEmptyBlobArgument() { 287 ContentValues emptyBlobValues = new ContentValues(); 288 emptyBlobValues.put("id", 1); 289 emptyBlobValues.put("blob_col", new byte[] {}); 290 291 ContentValues nullBlobValues = new ContentValues(); 292 nullBlobValues.put("id", 2); 293 nullBlobValues.put("blob_col", (byte[]) null); 294 295 long key = 296 database.insertWithOnConflict( 297 "blob_table", null, emptyBlobValues, SQLiteDatabase.CONFLICT_FAIL); 298 assertThat(key).isNotEqualTo(0L); 299 key = 300 database.insertWithOnConflict( 301 "blob_table", null, nullBlobValues, SQLiteDatabase.CONFLICT_FAIL); 302 assertThat(key).isNotEqualTo(0L); 303 304 Cursor cursor = 305 database.query("blob_table", new String[] {"blob_col"}, "id=1", null, null, null, null); 306 try { 307 assertThat(cursor.moveToFirst()).isTrue(); 308 assertThat(cursor.getBlob(cursor.getColumnIndexOrThrow("blob_col"))).isNotNull(); 309 } finally { 310 cursor.close(); 311 } 312 313 cursor = 314 database.query("blob_table", new String[] {"blob_col"}, "id=2", null, null, null, null); 315 try { 316 assertThat(cursor.moveToFirst()).isTrue(); 317 assertThat(cursor.getBlob(cursor.getColumnIndexOrThrow("blob_col"))).isNull(); 318 } finally { 319 cursor.close(); 320 } 321 } 322 323 @Test testUpdate()324 public void testUpdate() { 325 addChuck(); 326 327 assertThat(updateName(1234L, "Buster")).isEqualTo(1); 328 329 Cursor cursor = 330 database.query("table_name", new String[] {"id", "name"}, null, null, null, null, null); 331 assertThat(cursor.moveToFirst()).isTrue(); 332 assertThat(cursor.getCount()).isEqualTo(1); 333 334 assertIdAndName(cursor, 1234L, "Buster"); 335 cursor.close(); 336 } 337 338 @Test testUpdateNoMatch()339 public void testUpdateNoMatch() { 340 addChuck(); 341 342 assertThat(updateName(5678L, "Buster")).isEqualTo(0); 343 344 Cursor cursor = 345 database.query("table_name", new String[] {"id", "name"}, null, null, null, null, null); 346 assertThat(cursor.moveToFirst()).isTrue(); 347 assertThat(cursor.getCount()).isEqualTo(1); 348 349 assertIdAndName(cursor, 1234L, "Chuck"); 350 cursor.close(); 351 } 352 353 @Test testUpdateAll()354 public void testUpdateAll() { 355 addChuck(); 356 addJulie(); 357 358 assertThat(updateName("Belvedere")).isEqualTo(2); 359 360 Cursor cursor = 361 database.query("table_name", new String[] {"id", "name"}, null, null, null, null, null); 362 assertThat(cursor.moveToFirst()).isTrue(); 363 assertThat(cursor.getCount()).isEqualTo(2); 364 365 assertIdAndName(cursor, 1234L, "Belvedere"); 366 assertThat(cursor.moveToNext()).isTrue(); 367 368 assertIdAndName(cursor, 1235L, "Belvedere"); 369 assertThat(cursor.isLast()).isTrue(); 370 assertThat(cursor.moveToNext()).isFalse(); 371 assertThat(cursor.isAfterLast()).isTrue(); 372 assertThat(cursor.moveToNext()).isFalse(); 373 cursor.close(); 374 } 375 376 @Test testDelete()377 public void testDelete() { 378 addChuck(); 379 380 int deleted = database.delete("table_name", "id=1234", null); 381 assertThat(deleted).isEqualTo(1); 382 383 assertEmptyDatabase(); 384 } 385 386 @Test testDeleteNoMatch()387 public void testDeleteNoMatch() { 388 addChuck(); 389 390 int deleted = database.delete("table_name", "id=5678", null); 391 assertThat(deleted).isEqualTo(0); 392 393 assertNonEmptyDatabase(); 394 } 395 396 @Test testDeleteAll()397 public void testDeleteAll() { 398 addChuck(); 399 addJulie(); 400 401 int deleted = database.delete("table_name", "1", null); 402 assertThat(deleted).isEqualTo(2); 403 404 assertEmptyDatabase(); 405 } 406 407 @Test testExecSQL()408 public void testExecSQL() { 409 database.execSQL("INSERT INTO table_name (id, name) VALUES(1234, 'Chuck');"); 410 411 Cursor cursor = database.rawQuery("SELECT COUNT(*) FROM table_name", null); 412 assertThat(cursor).isNotNull(); 413 assertThat(cursor.moveToNext()).isTrue(); 414 assertThat(cursor.getInt(0)).isEqualTo(1); 415 cursor.close(); 416 417 cursor = database.rawQuery("SELECT * FROM table_name", null); 418 assertThat(cursor).isNotNull(); 419 assertThat(cursor.moveToNext()).isTrue(); 420 421 assertThat(cursor.getInt(cursor.getColumnIndex("id"))).isEqualTo(1234); 422 assertThat(cursor.getString(cursor.getColumnIndex("name"))).isEqualTo("Chuck"); 423 cursor.close(); 424 } 425 426 @Test testExecSQLParams()427 public void testExecSQLParams() { 428 database.execSQL( 429 "CREATE TABLE `routine` (`id` INTEGER PRIMARY KEY AUTOINCREMENT , `name`" 430 + " VARCHAR , `lastUsed` INTEGER DEFAULT 0 , " 431 + " UNIQUE (`name`)) ", 432 new Object[] {}); 433 database.execSQL( 434 "INSERT INTO `routine` (`name`" + " ,`lastUsed`" + " ) VALUES" + " (?,?)", 435 new Object[] {"Leg Press", 0}); 436 database.execSQL( 437 "INSERT INTO `routine` (`name`" + " ,`lastUsed`" + " ) VALUES" + " (?,?)", 438 new Object[] {"Bench" + " Press", 1}); 439 440 Cursor cursor = database.rawQuery("SELECT COUNT(*) FROM `routine`", null); 441 assertThat(cursor).isNotNull(); 442 assertThat(cursor.moveToNext()).isTrue(); 443 assertThat(cursor.getInt(0)).isEqualTo(2); 444 cursor.close(); 445 446 cursor = database.rawQuery("SELECT `id`, `name` ,`lastUsed` FROM `routine`", null); 447 assertThat(cursor).isNotNull(); 448 assertThat(cursor.moveToNext()).isTrue(); 449 450 assertThat(cursor.getInt(cursor.getColumnIndex("id"))).isEqualTo(1); 451 assertThat(cursor.getInt(cursor.getColumnIndex("lastUsed"))).isEqualTo(0); 452 assertThat(cursor.getString(cursor.getColumnIndex("name"))).isEqualTo("Leg Press"); 453 454 assertThat(cursor.moveToNext()).isTrue(); 455 456 assertThat(cursor.getInt(cursor.getColumnIndex("id"))).isEqualTo(2); 457 assertThat(cursor.getInt(cursor.getColumnIndex("lastUsed"))).isEqualTo(1); 458 assertThat(cursor.getString(cursor.getColumnIndex("name"))).isEqualTo("Bench Press"); 459 cursor.close(); 460 } 461 462 @Test(expected = SQLiteException.class) execSqlShouldThrowOnBadQuery()463 public void execSqlShouldThrowOnBadQuery() { 464 database.execSQL("INSERT INTO table_name;"); // invalid SQL 465 } 466 467 @Test(expected = IllegalArgumentException.class) testExecSQLExceptionParametersWithoutArguments()468 public void testExecSQLExceptionParametersWithoutArguments() { 469 database.execSQL("insert into exectable (first_column) values (?);", null); 470 } 471 472 @Test(expected = IllegalArgumentException.class) testExecSQLWithNullBindArgs()473 public void testExecSQLWithNullBindArgs() { 474 database.execSQL("insert into exectable (first_column) values ('sdfsfs');", null); 475 } 476 477 @Test(expected = IllegalArgumentException.class) testExecSQLTooManyBindArguments()478 public void testExecSQLTooManyBindArguments() { 479 database.execSQL( 480 "insert into exectable (first_column) values" + " ('kjhk');", new String[] {"xxxx"}); 481 } 482 483 @Test testExecSQLWithEmptyBindArgs()484 public void testExecSQLWithEmptyBindArgs() { 485 database.execSQL("insert into exectable (first_column) values ('eff');", new String[] {}); 486 } 487 488 @Test testExecSQLInsertNull()489 public void testExecSQLInsertNull() { 490 String name = "nullone"; 491 492 database.execSQL( 493 "insert into exectable (first_column, name)" + " values" + " (?,?);", 494 new String[] {null, name}); 495 496 Cursor cursor = 497 database.rawQuery( 498 "select * from exectable WHERE" + " `name`" + " = ?", new String[] {name}); 499 cursor.moveToFirst(); 500 int firstIndex = cursor.getColumnIndex("first_column"); 501 int nameIndex = cursor.getColumnIndex("name"); 502 assertThat(cursor.getString(nameIndex)).isEqualTo(name); 503 assertThat(cursor.getString(firstIndex)).isEqualTo(null); 504 cursor.close(); 505 } 506 507 @Test testExecSQLAutoIncrementSQLite()508 public void testExecSQLAutoIncrementSQLite() { 509 database.execSQL( 510 "CREATE TABLE auto_table (id INTEGER PRIMARY KEY AUTOINCREMENT, name" + " VARCHAR(255));"); 511 512 ContentValues values = new ContentValues(); 513 values.put("name", "Chuck"); 514 515 long key = database.insert("auto_table", null, values); 516 assertThat(key).isNotEqualTo(0L); 517 518 long key2 = database.insert("auto_table", null, values); 519 assertThat(key2).isNotEqualTo(key); 520 } 521 522 @Test(expected = IllegalStateException.class) testClose()523 public void testClose() { 524 database.close(); 525 526 database.execSQL("INSERT INTO table_name (id, name) VALUES(1234, 'Chuck');"); 527 } 528 529 @Test testIsOpen()530 public void testIsOpen() { 531 assertThat(database.isOpen()).isTrue(); 532 database.close(); 533 assertThat(database.isOpen()).isFalse(); 534 } 535 536 @Test shouldStoreGreatBigHonkingIntegersCorrectly()537 public void shouldStoreGreatBigHonkingIntegersCorrectly() { 538 database.execSQL("INSERT INTO table_name(big_int) VALUES(1234567890123456789);"); 539 Cursor cursor = 540 database.query("table_name", new String[] {"big_int"}, null, null, null, null, null); 541 assertThat(cursor.moveToFirst()).isTrue(); 542 assertEquals(1234567890123456789L, cursor.getLong(0)); 543 cursor.close(); 544 } 545 546 @Test testSuccessTransaction()547 public void testSuccessTransaction() { 548 database.beginTransaction(); 549 database.execSQL("INSERT INTO table_name (id, name) VALUES(1234, 'Chuck');"); 550 database.setTransactionSuccessful(); 551 database.endTransaction(); 552 553 Cursor cursor = database.rawQuery("SELECT COUNT(*) FROM table_name", null); 554 assertThat(cursor.moveToNext()).isTrue(); 555 assertThat(cursor.getInt(0)).isEqualTo(1); 556 cursor.close(); 557 } 558 559 @Test testFailureTransaction()560 public void testFailureTransaction() { 561 database.beginTransaction(); 562 563 database.execSQL("INSERT INTO table_name (id, name) VALUES(1234, 'Chuck');"); 564 565 final String select = "SELECT COUNT(*) FROM table_name"; 566 567 Cursor cursor = database.rawQuery(select, null); 568 assertThat(cursor.moveToNext()).isTrue(); 569 assertThat(cursor.getInt(0)).isEqualTo(1); 570 cursor.close(); 571 572 database.endTransaction(); 573 574 cursor = database.rawQuery(select, null); 575 assertThat(cursor.moveToNext()).isTrue(); 576 assertThat(cursor.getInt(0)).isEqualTo(0); 577 cursor.close(); 578 } 579 580 @Test testSuccessNestedTransaction()581 public void testSuccessNestedTransaction() { 582 database.beginTransaction(); 583 database.execSQL("INSERT INTO table_name (id, name) VALUES(1234, 'Chuck');"); 584 database.beginTransaction(); 585 database.execSQL("INSERT INTO table_name (id, name) VALUES(12345, 'Julie');"); 586 database.setTransactionSuccessful(); 587 database.endTransaction(); 588 database.setTransactionSuccessful(); 589 database.endTransaction(); 590 591 Cursor cursor = database.rawQuery("SELECT COUNT(*) FROM table_name", null); 592 assertThat(cursor.moveToNext()).isTrue(); 593 assertThat(cursor.getInt(0)).isEqualTo(2); 594 cursor.close(); 595 } 596 597 @Test testFailureNestedTransaction()598 public void testFailureNestedTransaction() { 599 database.beginTransaction(); 600 database.execSQL("INSERT INTO table_name (id, name) VALUES(1234, 'Chuck');"); 601 database.beginTransaction(); 602 database.execSQL("INSERT INTO table_name (id, name) VALUES(12345, 'Julie');"); 603 database.endTransaction(); 604 database.setTransactionSuccessful(); 605 database.endTransaction(); 606 607 Cursor cursor = database.rawQuery("SELECT COUNT(*) FROM table_name", null); 608 assertThat(cursor.moveToNext()).isTrue(); 609 assertThat(cursor.getInt(0)).isEqualTo(0); 610 cursor.close(); 611 } 612 613 @Test testTransactionAlreadySuccessful()614 public void testTransactionAlreadySuccessful() { 615 database.beginTransaction(); 616 database.setTransactionSuccessful(); 617 try { 618 database.setTransactionSuccessful(); 619 fail("didn't receive the expected IllegalStateException"); 620 } catch (IllegalStateException e) { 621 assertThat(e.getMessage()).contains("transaction"); 622 assertThat(e.getMessage()).contains("successful"); 623 } finally { 624 database.endTransaction(); 625 } 626 } 627 628 @Test testInTransaction()629 public void testInTransaction() { 630 assertThat(database.inTransaction()).isFalse(); 631 database.beginTransaction(); 632 assertThat(database.inTransaction()).isTrue(); 633 database.endTransaction(); 634 assertThat(database.inTransaction()).isFalse(); 635 } 636 637 @Test testReplace()638 public void testReplace() { 639 long id = addChuck(); 640 assertThat(id).isNotEqualTo(-1L); 641 642 ContentValues values = new ContentValues(); 643 values.put("id", id); 644 values.put("name", "Norris"); 645 646 long replaceId = database.replace("table_name", null, values); 647 assertThat(replaceId).isEqualTo(id); 648 649 String query = "SELECT name FROM table_name where id = " + id; 650 Cursor cursor = executeQuery(query); 651 652 assertThat(cursor.moveToNext()).isTrue(); 653 assertThat(cursor.getString(cursor.getColumnIndex("name"))).isEqualTo("Norris"); 654 cursor.close(); 655 } 656 657 @Test testReplaceIsReplacing()658 public void testReplaceIsReplacing() { 659 final String query = "SELECT first_column FROM table_name WHERE id = "; 660 String stringValueA = "column_valueA"; 661 String stringValueB = "column_valueB"; 662 long id = 1; 663 664 ContentValues valuesA = new ContentValues(); 665 valuesA.put("id", id); 666 valuesA.put("first_column", stringValueA); 667 668 ContentValues valuesB = new ContentValues(); 669 valuesB.put("id", id); 670 valuesB.put("first_column", stringValueB); 671 672 long firstId = database.replaceOrThrow("table_name", null, valuesA); 673 Cursor firstCursor = executeQuery(query + firstId); 674 assertThat(firstCursor.moveToNext()).isTrue(); 675 long secondId = database.replaceOrThrow("table_name", null, valuesB); 676 Cursor secondCursor = executeQuery(query + secondId); 677 assertThat(secondCursor.moveToNext()).isTrue(); 678 679 assertThat(firstId).isEqualTo(id); 680 assertThat(secondId).isEqualTo(id); 681 assertThat(firstCursor.getString(0)).isEqualTo(stringValueA); 682 assertThat(secondCursor.getString(0)).isEqualTo(stringValueB); 683 firstCursor.close(); 684 secondCursor.close(); 685 } 686 687 @Test shouldCreateDefaultCursorFactoryWhenNullFactoryPassedToRawQuery()688 public void shouldCreateDefaultCursorFactoryWhenNullFactoryPassedToRawQuery() { 689 Cursor cursor = database.rawQueryWithFactory(null, ANY_VALID_SQL, null, null); 690 cursor.close(); 691 } 692 693 @Test shouldCreateDefaultCursorFactoryWhenNullFactoryPassedToQuery()694 public void shouldCreateDefaultCursorFactoryWhenNullFactoryPassedToQuery() { 695 Cursor cursor = 696 database.queryWithFactory( 697 null, false, "table_name", null, null, null, null, null, null, null); 698 cursor.close(); 699 } 700 701 @Test shouldOpenExistingDatabaseFromFileSystemIfFileExists()702 public void shouldOpenExistingDatabaseFromFileSystemIfFileExists() { 703 database.close(); 704 705 SQLiteDatabase db = 706 SQLiteDatabase.openDatabase(databasePath.getAbsolutePath(), null, OPEN_READWRITE); 707 Cursor c = db.rawQuery("select * from rawtable", null); 708 assertThat(c).isNotNull(); 709 assertThat(c.getCount()).isEqualTo(2); 710 c.close(); 711 assertThat(db.isOpen()).isTrue(); 712 db.close(); 713 assertThat(db.isOpen()).isFalse(); 714 715 SQLiteDatabase reopened = 716 SQLiteDatabase.openDatabase(databasePath.getAbsolutePath(), null, OPEN_READWRITE); 717 assertThat(reopened).isNotSameInstanceAs(db); 718 assertThat(reopened.isOpen()).isTrue(); 719 reopened.close(); 720 } 721 722 @Test(expected = SQLiteException.class) shouldThrowIfFileDoesNotExist()723 public void shouldThrowIfFileDoesNotExist() { 724 File testDb = new File("/i/do/not/exist"); 725 assertThat(testDb.exists()).isFalse(); 726 SQLiteDatabase.openOrCreateDatabase(testDb.getAbsolutePath(), null); 727 } 728 729 @Test shouldUseInMemoryDatabaseWhenCallingCreate()730 public void shouldUseInMemoryDatabaseWhenCallingCreate() { 731 SQLiteDatabase db = SQLiteDatabase.create(null); 732 assertThat(db.isOpen()).isTrue(); 733 assertThat(db.getPath()).isEqualTo(":memory:"); 734 db.close(); 735 } 736 737 @Test shouldSetAndGetVersion()738 public void shouldSetAndGetVersion() { 739 assertThat(database.getVersion()).isEqualTo(0); 740 database.setVersion(20); 741 assertThat(database.getVersion()).isEqualTo(20); 742 } 743 744 @Test testTwoConcurrentDbConnections()745 public void testTwoConcurrentDbConnections() { 746 SQLiteDatabase db1 = openOrCreateDatabase("db1"); 747 SQLiteDatabase db2 = openOrCreateDatabase("db2"); 748 749 db1.execSQL("CREATE TABLE foo(id INTEGER PRIMARY KEY AUTOINCREMENT, data TEXT);"); 750 db2.execSQL("CREATE TABLE bar(id INTEGER PRIMARY KEY AUTOINCREMENT, data TEXT);"); 751 752 ContentValues d1 = new ContentValues(); 753 d1.put("data", "d1"); 754 755 ContentValues d2 = new ContentValues(); 756 d2.put("data", "d2"); 757 758 db1.insert("foo", null, d1); 759 db2.insert("bar", null, d2); 760 761 Cursor c = db1.rawQuery("select * from foo", null); 762 assertThat(c).isNotNull(); 763 assertThat(c.getCount()).isEqualTo(1); 764 assertThat(c.moveToNext()).isTrue(); 765 assertThat(c.getString(c.getColumnIndex("data"))).isEqualTo("d1"); 766 c.close(); 767 768 c = db2.rawQuery("select * from bar", null); 769 assertThat(c).isNotNull(); 770 assertThat(c.getCount()).isEqualTo(1); 771 assertThat(c.moveToNext()).isTrue(); 772 assertThat(c.getString(c.getColumnIndex("data"))).isEqualTo("d2"); 773 c.close(); 774 } 775 776 @Test(expected = SQLiteException.class) testQueryThrowsSQLiteException()777 public void testQueryThrowsSQLiteException() { 778 SQLiteDatabase db1 = openOrCreateDatabase("db1"); 779 db1.query("FOO", null, null, null, null, null, null); 780 } 781 782 @Test(expected = SQLiteException.class) testShouldThrowSQLiteExceptionIfOpeningNonexistentDatabase()783 public void testShouldThrowSQLiteExceptionIfOpeningNonexistentDatabase() { 784 SQLiteDatabase.openDatabase("/does/not/exist", null, OPEN_READWRITE); 785 } 786 787 @Test testCreateAndDropTable()788 public void testCreateAndDropTable() throws Exception { 789 SQLiteDatabase db = openOrCreateDatabase("db1"); 790 db.execSQL("CREATE TABLE foo(id INTEGER PRIMARY KEY AUTOINCREMENT, data TEXT);"); 791 Cursor c = db.query("FOO", null, null, null, null, null, null); 792 assertThat(c).isNotNull(); 793 c.close(); 794 db.close(); 795 db = openOrCreateDatabase("db1"); 796 db.execSQL("DROP TABLE IF EXISTS foo;"); 797 try { 798 c = db.query("FOO", null, null, null, null, null, null); 799 fail("expected no such table exception"); 800 } catch (SQLiteException e) { 801 // TODO 802 } 803 db.close(); 804 } 805 806 @Test testCreateAndAlterTable()807 public void testCreateAndAlterTable() { 808 SQLiteDatabase db = openOrCreateDatabase("db1"); 809 db.execSQL("CREATE TABLE foo(id INTEGER PRIMARY KEY AUTOINCREMENT, data TEXT);"); 810 Cursor c = db.query("FOO", null, null, null, null, null, null); 811 assertThat(c).isNotNull(); 812 c.close(); 813 db.close(); 814 db = openOrCreateDatabase("db1"); 815 db.execSQL("ALTER TABLE foo ADD COLUMN more TEXT NULL;"); 816 c = db.query("FOO", null, null, null, null, null, null); 817 assertThat(c).isNotNull(); 818 int moreIndex = c.getColumnIndex("more"); 819 assertThat(moreIndex).isAtLeast(0); 820 c.close(); 821 } 822 823 @Test testDataInMemoryDatabaseIsPersistentAfterClose()824 public void testDataInMemoryDatabaseIsPersistentAfterClose() { 825 SQLiteDatabase db1 = openOrCreateDatabase("db1"); 826 db1.execSQL("CREATE TABLE foo(id INTEGER PRIMARY KEY AUTOINCREMENT, data TEXT);"); 827 ContentValues d1 = new ContentValues(); 828 d1.put("data", "d1"); 829 db1.insert("foo", null, d1); 830 db1.close(); 831 832 SQLiteDatabase db2 = openOrCreateDatabase("db1"); 833 Cursor c = db2.rawQuery("select * from foo", null); 834 assertThat(c).isNotNull(); 835 assertThat(c.getCount()).isEqualTo(1); 836 assertThat(c.moveToNext()).isTrue(); 837 assertThat(c.getString(c.getColumnIndex("data"))).isEqualTo("d1"); 838 c.close(); 839 } 840 841 @Test testRawQueryWithFactoryAndCancellationSignal()842 public void testRawQueryWithFactoryAndCancellationSignal() { 843 CancellationSignal signal = new CancellationSignal(); 844 845 Cursor cursor = 846 database.rawQueryWithFactory(null, "select * from" + " table_name", null, null, signal); 847 assertThat(cursor).isNotNull(); 848 assertThat(cursor.getColumnCount()).isEqualTo(5); 849 assertThat(cursor.isClosed()).isFalse(); 850 851 signal.cancel(); 852 853 try { 854 cursor.moveToNext(); 855 fail("did not get cancellation signal"); 856 } catch (OperationCanceledException e) { 857 // expected 858 } 859 cursor.close(); 860 } 861 862 @Test testRawQueryWithCommonTableExpression()863 public void testRawQueryWithCommonTableExpression() { 864 try (Cursor cursor = 865 database.rawQuery( 866 "WITH RECURSIVE\n" 867 + " cnt(x) AS (VALUES(1) UNION ALL SELECT x+1 FROM cnt WHERE x<100)\n" 868 + "SELECT COUNT(*) FROM cnt;", 869 null)) { 870 assertThat(cursor).isNotNull(); 871 assertThat(cursor.moveToNext()).isTrue(); 872 assertThat(cursor.getCount()).isEqualTo(1); 873 assertThat(cursor.isNull(0)).isFalse(); 874 assertThat(cursor.getLong(0)).isEqualTo(100); 875 } 876 } 877 878 @Test shouldBeAbleToBeUsedFromDifferentThread()879 public void shouldBeAbleToBeUsedFromDifferentThread() { 880 final CountDownLatch sync = new CountDownLatch(1); 881 final Throwable[] error = {null}; 882 883 new Thread() { 884 @Override 885 public void run() { 886 try (Cursor c = executeQuery("select * from table_name")) { 887 } catch (Throwable e) { 888 e.printStackTrace(); 889 error[0] = e; 890 } finally { 891 sync.countDown(); 892 } 893 } 894 }.start(); 895 896 try { 897 sync.await(); 898 } catch (InterruptedException e) { 899 throw new RuntimeException(e); 900 } 901 902 assertThat(error[0]).isNull(); 903 } 904 executeQuery(String query)905 private Cursor executeQuery(String query) { 906 return database.rawQuery(query, null); 907 } 908 addChuck()909 private long addChuck() { 910 return addPerson(1234L, "Chuck"); 911 } 912 addJulie()913 private long addJulie() { 914 return addPerson(1235L, "Julie"); 915 } 916 addPerson(long id, String name)917 private long addPerson(long id, String name) { 918 ContentValues values = new ContentValues(); 919 values.put("id", id); 920 values.put("name", name); 921 return database.insert("table_name", null, values); 922 } 923 updateName(long id, String name)924 private int updateName(long id, String name) { 925 ContentValues values = new ContentValues(); 926 values.put("name", name); 927 return database.update("table_name", values, "id=" + id, null); 928 } 929 updateName(String name)930 private int updateName(String name) { 931 ContentValues values = new ContentValues(); 932 values.put("name", name); 933 return database.update("table_name", values, null, null); 934 } 935 assertIdAndName(Cursor cursor, long id, String name)936 private void assertIdAndName(Cursor cursor, long id, String name) { 937 long idValueFromDatabase; 938 String stringValueFromDatabase; 939 940 idValueFromDatabase = cursor.getLong(0); 941 stringValueFromDatabase = cursor.getString(1); 942 assertThat(idValueFromDatabase).isEqualTo(id); 943 assertThat(stringValueFromDatabase).isEqualTo(name); 944 } 945 assertEmptyDatabase()946 private void assertEmptyDatabase() { 947 Cursor cursor = 948 database.query("table_name", new String[] {"id", "name"}, null, null, null, null, null); 949 assertThat(cursor.moveToFirst()).isFalse(); 950 assertThat(cursor.isClosed()).isFalse(); 951 assertThat(cursor.getCount()).isEqualTo(0); 952 cursor.close(); 953 } 954 assertNonEmptyDatabase()955 private void assertNonEmptyDatabase() { 956 Cursor cursor = 957 database.query("table_name", new String[] {"id", "name"}, null, null, null, null, null); 958 assertThat(cursor.moveToFirst()).isTrue(); 959 assertThat(cursor.getCount()).isNotEqualTo(0); 960 cursor.close(); 961 } 962 963 @Test shouldAlwaysReturnCorrectIdFromInsert()964 public void shouldAlwaysReturnCorrectIdFromInsert() { 965 database.execSQL( 966 "CREATE TABLE table_A (\n" 967 + " _id INTEGER PRIMARY KEY AUTOINCREMENT,\n" 968 + " id INTEGER DEFAULT 0\n" 969 + ");"); 970 971 database.execSQL("CREATE VIRTUAL TABLE new_search USING fts3 (id);"); 972 973 database.execSQL( 974 "CREATE TRIGGER t1 AFTER INSERT ON table_A WHEN new.id=0 BEGIN UPDATE" 975 + " table_A SET id=-new._id WHERE _id=new._id AND id=0; END;"); 976 database.execSQL( 977 "CREATE TRIGGER t2 AFTER INSERT ON table_A BEGIN INSERT INTO new_search" 978 + " (id) VALUES (new._id); END;"); 979 database.execSQL( 980 "CREATE TRIGGER t3 BEFORE UPDATE ON table_A BEGIN DELETE FROM new_search" 981 + " WHERE id MATCH old._id; END;"); 982 database.execSQL( 983 "CREATE TRIGGER t4 AFTER UPDATE ON table_A BEGIN INSERT INTO new_search" 984 + " (id) VALUES (new._id); END;"); 985 986 long[] returnedIds = 987 new long[] { 988 database.insert("table_A", "id", new ContentValues()), 989 database.insert("table_A", "id", new ContentValues()) 990 }; 991 992 Cursor c = database.query("table_A", new String[] {"_id"}, null, null, null, null, null); 993 assertThat(c).isNotNull(); 994 995 long[] actualIds = new long[c.getCount()]; 996 for (c.moveToFirst(); !c.isAfterLast(); c.moveToNext()) { 997 actualIds[c.getPosition()] = c.getLong(c.getColumnIndexOrThrow("_id")); 998 } 999 c.close(); 1000 1001 assertThat(returnedIds).isEqualTo(actualIds); 1002 } 1003 1004 @Test shouldCorrectlyReturnNullValues()1005 public void shouldCorrectlyReturnNullValues() { 1006 database.execSQL( 1007 "CREATE TABLE null_test (col_int INTEGER, col_text TEXT, col_real REAL," 1008 + " col_blob BLOB)"); 1009 1010 ContentValues data = new ContentValues(); 1011 data.putNull("col_int"); 1012 data.putNull("col_text"); 1013 data.putNull("col_real"); 1014 data.putNull("col_blob"); 1015 assertThat(database.insert("null_test", null, data)).isAtLeast(0L); 1016 1017 Cursor nullValuesCursor = database.query("null_test", null, null, null, null, null, null); 1018 nullValuesCursor.moveToFirst(); 1019 final int colsCount = 4; 1020 for (int i = 0; i < colsCount; i++) { 1021 assertThat(nullValuesCursor.getType(i)).isEqualTo(Cursor.FIELD_TYPE_NULL); 1022 assertThat(nullValuesCursor.getString(i)).isNull(); 1023 } 1024 assertThat(nullValuesCursor.getBlob(3)).isNull(); 1025 nullValuesCursor.close(); 1026 } 1027 1028 @Test sqliteGlobal_defaults()1029 public void sqliteGlobal_defaults() { 1030 assertThat(SQLiteGlobal.getDefaultSyncMode()).isEqualTo("OFF"); 1031 assertThat(SQLiteGlobal.getWALSyncMode()).isEqualTo("OFF"); 1032 assertThat(SQLiteGlobal.getDefaultJournalMode()).isEqualTo("MEMORY"); 1033 } 1034 openOrCreateDatabase(String name)1035 private SQLiteDatabase openOrCreateDatabase(String name) { 1036 return openOrCreateDatabase(ApplicationProvider.getApplicationContext().getDatabasePath(name)); 1037 } 1038 openOrCreateDatabase(File databasePath)1039 private SQLiteDatabase openOrCreateDatabase(File databasePath) { 1040 SQLiteDatabase database = SQLiteDatabase.openOrCreateDatabase(databasePath, null); 1041 openDatabases.add(database); 1042 return database; 1043 } 1044 } 1045