1 /*
<lambda>null2  * Copyright (C) 2016 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 package androidx.room
17 
18 import android.content.Context
19 import androidx.kruth.assertThat
20 import androidx.kruth.assertThrows
21 import androidx.room.Room.databaseBuilder
22 import androidx.room.Room.inMemoryDatabaseBuilder
23 import androidx.room.migration.Migration
24 import androidx.sqlite.SQLiteDriver
25 import androidx.sqlite.db.SupportSQLiteDatabase
26 import androidx.sqlite.db.SupportSQLiteOpenHelper
27 import androidx.sqlite.db.framework.FrameworkSQLiteOpenHelperFactory
28 import instantiateImpl
29 import java.io.File
30 import java.util.concurrent.Executor
31 import java.util.concurrent.TimeUnit
32 import kotlin.coroutines.EmptyCoroutineContext
33 import kotlinx.coroutines.Dispatchers
34 import org.junit.Assert
35 import org.junit.Test
36 import org.junit.runner.RunWith
37 import org.junit.runners.JUnit4
38 import org.mockito.kotlin.any
39 import org.mockito.kotlin.mock
40 import org.mockito.kotlin.whenever
41 
42 @RunWith(JUnit4::class)
43 class BuilderTest {
44     @Test
45     fun nullName() {
46         try {
47             databaseBuilder(mock(), RoomDatabase::class.java, null).build()
48         } catch (e: IllegalArgumentException) {
49             assertThat(e.message)
50                 .isEqualTo(
51                     "Cannot build a database with null or empty name. If you are trying to create an " +
52                         "in memory database, use Room.inMemoryDatabaseBuilder"
53                 )
54         }
55     }
56 
57     @Test
58     fun databaseBuilderWithFactory() {
59         val db =
60             databaseBuilder(
61                     context = mock(),
62                     name = "TestDatabase",
63                     factory = { TestDatabase::class.instantiateImpl() }
64                 )
65                 .build()
66         // Assert that the db is built successfully.
67         assertThat(db).isInstanceOf<TestDatabase>()
68     }
69 
70     @Test
71     fun emptyName() {
72         try {
73             databaseBuilder(mock(), RoomDatabase::class.java, "  ").build()
74         } catch (e: IllegalArgumentException) {
75             assertThat(e.message)
76                 .isEqualTo(
77                     "Cannot build a database with null or empty name. If you are trying to create an " +
78                         "in memory database, use Room.inMemoryDatabaseBuilder"
79                 )
80         }
81     }
82 
83     @Test
84     fun specialMemoryName() {
85         try {
86             databaseBuilder(mock(), RoomDatabase::class.java, ":memory:").build()
87         } catch (e: IllegalArgumentException) {
88             assertThat(e.message)
89                 .isEqualTo(
90                     "Cannot build a database with the special name ':memory:'. If you are trying " +
91                         "to create an in memory database, use Room.inMemoryDatabaseBuilder"
92                 )
93         }
94     }
95 
96     @Test
97     fun executors_setQueryExecutor() {
98         val executor: Executor = mock()
99         val db =
100             databaseBuilder(mock(), TestDatabase::class.java, "foo")
101                 .setQueryExecutor(executor)
102                 .build()
103 
104         assertThat(db.databaseConfiguration.queryExecutor).isEqualTo(executor)
105         assertThat(db.databaseConfiguration.transactionExecutor).isEqualTo(executor)
106     }
107 
108     @Test
109     fun executors_setTransactionExecutor() {
110         val executor: Executor = mock()
111         val db =
112             databaseBuilder(mock(), TestDatabase::class.java, "foo")
113                 .setTransactionExecutor(executor)
114                 .build()
115 
116         assertThat(db.databaseConfiguration.queryExecutor).isEqualTo(executor)
117         assertThat(db.databaseConfiguration.transactionExecutor).isEqualTo(executor)
118     }
119 
120     @Test
121     fun executors_setBothExecutors() {
122         val executor1: Executor = mock()
123         val executor2: Executor = mock()
124         val db =
125             databaseBuilder(mock(), TestDatabase::class.java, "foo")
126                 .setQueryExecutor(executor1)
127                 .setTransactionExecutor(executor2)
128                 .build()
129 
130         assertThat(db.databaseConfiguration.queryExecutor).isEqualTo(executor1)
131         assertThat(db.databaseConfiguration.transactionExecutor).isEqualTo(executor2)
132     }
133 
134     @Test
135     fun executors_setCoroutineContext() {
136         assertThrows<IllegalArgumentException> {
137                 databaseBuilder(mock(), TestDatabase::class.java, "foo")
138                     .setQueryCoroutineContext(Dispatchers.IO)
139                     .setTransactionExecutor(mock())
140                     .build()
141             }
142             .hasMessageThat()
143             .contains("This builder has already been configured with a CoroutineContext.")
144     }
145 
146     @Test
147     fun coroutineContext_setQueryExecutor() {
148         assertThrows<IllegalArgumentException> {
149                 databaseBuilder(mock(), TestDatabase::class.java, "foo")
150                     .setQueryExecutor(mock())
151                     .setQueryCoroutineContext(Dispatchers.IO)
152                     .build()
153             }
154             .hasMessageThat()
155             .contains("This builder has already been configured with an Executor.")
156     }
157 
158     @Test
159     fun coroutineContext_setTransactionExecutor() {
160         assertThrows<IllegalArgumentException> {
161                 databaseBuilder(mock(), TestDatabase::class.java, "foo")
162                     .setTransactionExecutor(mock())
163                     .setQueryCoroutineContext(Dispatchers.IO)
164                     .build()
165             }
166             .hasMessageThat()
167             .contains("This builder has already been configured with an Executor.")
168     }
169 
170     @Test
171     fun coroutineContext_missingDispatcher() {
172         assertThrows<IllegalArgumentException> {
173                 databaseBuilder(mock(), TestDatabase::class.java, "foo")
174                     .setQueryCoroutineContext(EmptyCoroutineContext)
175                     .build()
176             }
177             .hasMessageThat()
178             .contains("It is required that the coroutine context contain a dispatcher.")
179     }
180 
181     @Test
182     fun migration() {
183         val m1: Migration = EmptyMigration(0, 1)
184         val m2: Migration = EmptyMigration(1, 2)
185         val db =
186             databaseBuilder(mock(), TestDatabase::class.java, "foo").addMigrations(m1, m2).build()
187 
188         val config: DatabaseConfiguration = (db as BuilderTest_TestDatabase_Impl).mConfig
189         val migrations = config.migrationContainer
190 
191         assertThat(migrations.findMigrationPath(0, 1)).containsExactlyElementsIn(listOf(m1))
192         assertThat(migrations.findMigrationPath(1, 2)).containsExactlyElementsIn(listOf(m2))
193         assertThat(migrations.findMigrationPath(0, 2)).containsExactlyElementsIn(listOf(m1, m2))
194         assertThat(migrations.findMigrationPath(2, 0)).isNull()
195         assertThat(migrations.findMigrationPath(0, 3)).isNull()
196     }
197 
198     @Test
199     fun migrationOverride() {
200         val m1: Migration = EmptyMigration(0, 1)
201         val m2: Migration = EmptyMigration(1, 2)
202         val m3: Migration = EmptyMigration(0, 1)
203         val db =
204             databaseBuilder(mock(), TestDatabase::class.java, "foo")
205                 .addMigrations(m1, m2, m3)
206                 .build()
207 
208         val config: DatabaseConfiguration = (db as BuilderTest_TestDatabase_Impl).mConfig
209         val migrations = config.migrationContainer
210 
211         assertThat(migrations.findMigrationPath(0, 1)).containsExactlyElementsIn(listOf(m3))
212         assertThat(migrations.findMigrationPath(1, 2)).containsExactlyElementsIn(listOf(m2))
213         assertThat(migrations.findMigrationPath(0, 3)).isNull()
214     }
215 
216     @Test
217     fun migrationJump() {
218         val m1: Migration = EmptyMigration(0, 1)
219         val m2: Migration = EmptyMigration(1, 2)
220         val m3: Migration = EmptyMigration(2, 3)
221         val m4: Migration = EmptyMigration(0, 3)
222         val db =
223             databaseBuilder(mock(), TestDatabase::class.java, "foo")
224                 .addMigrations(m1, m2, m3, m4)
225                 .build()
226 
227         val config: DatabaseConfiguration = (db as BuilderTest_TestDatabase_Impl).mConfig
228         val migrations = config.migrationContainer
229 
230         assertThat(migrations.findMigrationPath(0, 3)).containsExactlyElementsIn(listOf(m4))
231         assertThat(migrations.findMigrationPath(1, 3)).containsExactlyElementsIn(listOf(m2, m3))
232     }
233 
234     @Test
235     fun migrationDowngrade() {
236         val m1_2: Migration = EmptyMigration(1, 2)
237         val m2_3: Migration = EmptyMigration(2, 3)
238         val m3_4: Migration = EmptyMigration(3, 4)
239         val m3_2: Migration = EmptyMigration(3, 2)
240         val m2_1: Migration = EmptyMigration(2, 1)
241         val db =
242             databaseBuilder(mock(), TestDatabase::class.java, "foo")
243                 .addMigrations(m1_2, m2_3, m3_4, m3_2, m2_1)
244                 .build()
245         val config: DatabaseConfiguration = (db as BuilderTest_TestDatabase_Impl).mConfig
246         val migrations = config.migrationContainer
247         assertThat(migrations.findMigrationPath(3, 2)).containsExactlyElementsIn(listOf(m3_2))
248         assertThat(migrations.findMigrationPath(3, 1)).containsExactlyElementsIn(listOf(m3_2, m2_1))
249     }
250 
251     @Test
252     fun skipMigration() {
253         val context: Context = mock()
254         val db =
255             inMemoryDatabaseBuilder(context, TestDatabase::class.java)
256                 .fallbackToDestructiveMigration(false)
257                 .build()
258         val config: DatabaseConfiguration = (db as BuilderTest_TestDatabase_Impl).mConfig
259         assertThat(config.requireMigration).isFalse()
260     }
261 
262     @Test
263     fun fallbackToDestructiveMigrationFrom_calledOnce_migrationsNotRequiredForValues() {
264         val context: Context = mock()
265         val db =
266             inMemoryDatabaseBuilder(context, TestDatabase::class.java)
267                 .fallbackToDestructiveMigrationFrom(true, 1, 2)
268                 .build()
269         val config: DatabaseConfiguration = (db as BuilderTest_TestDatabase_Impl).mConfig
270         assertThat(config.isMigrationRequired(1, 2)).isFalse()
271         assertThat(config.isMigrationRequired(2, 3)).isFalse()
272     }
273 
274     @Test
275     fun fallbackToDestructiveMigrationFrom_calledTwice_migrationsNotRequiredForValues() {
276         val context: Context = mock()
277         val db =
278             inMemoryDatabaseBuilder(context, TestDatabase::class.java)
279                 .fallbackToDestructiveMigrationFrom(true, 1, 2)
280                 .fallbackToDestructiveMigrationFrom(true, 3, 4)
281                 .build()
282         val config: DatabaseConfiguration = (db as BuilderTest_TestDatabase_Impl).mConfig
283         assertThat(config.isMigrationRequired(1, 2)).isFalse()
284         assertThat(config.isMigrationRequired(2, 3)).isFalse()
285         assertThat(config.isMigrationRequired(3, 4)).isFalse()
286         assertThat(config.isMigrationRequired(4, 5)).isFalse()
287     }
288 
289     @Test
290     fun isMigrationRequiredFrom_fallBackToDestructiveCalled_alwaysReturnsFalse() {
291         val context: Context = mock()
292         val db =
293             inMemoryDatabaseBuilder(context, TestDatabase::class.java)
294                 .fallbackToDestructiveMigration(false)
295                 .build()
296         val config: DatabaseConfiguration = (db as BuilderTest_TestDatabase_Impl).mConfig
297 
298         assertThat(config.isMigrationRequired(0, 1)).isFalse()
299         assertThat(config.isMigrationRequired(1, 2)).isFalse()
300         assertThat(config.isMigrationRequired(5, 6)).isFalse()
301         assertThat(config.isMigrationRequired(7, 12)).isFalse()
302         assertThat(config.isMigrationRequired(132, 150)).isFalse()
303 
304         assertThat(config.isMigrationRequired(1, 0)).isFalse()
305         assertThat(config.isMigrationRequired(2, 1)).isFalse()
306         assertThat(config.isMigrationRequired(6, 5)).isFalse()
307         assertThat(config.isMigrationRequired(7, 12)).isFalse()
308         assertThat(config.isMigrationRequired(150, 132)).isFalse()
309     }
310 
311     // isMigrationRequiredFrom doesn't know about downgrade only so it always returns true
312     @Test
313     fun isMigrationRequired_destructiveMigrationOnDowngrade_returnTrueWhenUpgrading() {
314         val context: Context = mock()
315         val db =
316             inMemoryDatabaseBuilder(context, TestDatabase::class.java)
317                 .fallbackToDestructiveMigrationOnDowngrade(false)
318                 .build()
319         val config: DatabaseConfiguration = (db as BuilderTest_TestDatabase_Impl).mConfig
320 
321         // isMigrationRequiredFrom doesn't know about downgrade only so it always returns true
322         assertThat(config.isMigrationRequired(0, 1)).isTrue()
323         assertThat(config.isMigrationRequired(1, 2)).isTrue()
324         assertThat(config.isMigrationRequired(5, 6)).isTrue()
325         assertThat(config.isMigrationRequired(7, 12)).isTrue()
326         assertThat(config.isMigrationRequired(132, 150)).isTrue()
327     }
328 
329     // isMigrationRequiredFrom doesn't know about downgrade only so it always returns true
330     @Test
331     fun isMigrationRequired_destructiveMigrationOnDowngrade_returnFalseWhenDowngrading() {
332         val context: Context = mock()
333         val db =
334             inMemoryDatabaseBuilder(context, TestDatabase::class.java)
335                 .fallbackToDestructiveMigrationOnDowngrade(false)
336                 .build()
337         val config: DatabaseConfiguration = (db as BuilderTest_TestDatabase_Impl).mConfig
338 
339         // isMigrationRequiredFrom doesn't know about downgrade only so it always returns true
340         assertThat(config.isMigrationRequired(1, 0)).isFalse()
341         assertThat(config.isMigrationRequired(2, 1)).isFalse()
342         assertThat(config.isMigrationRequired(6, 5)).isFalse()
343         assertThat(config.isMigrationRequired(12, 7)).isFalse()
344         assertThat(config.isMigrationRequired(150, 132)).isFalse()
345     }
346 
347     @Test
348     fun isMigrationRequiredFrom_byDefault_alwaysReturnsTrue() {
349         val context: Context = mock()
350         val db = inMemoryDatabaseBuilder(context, TestDatabase::class.java).build()
351         val config: DatabaseConfiguration = (db as BuilderTest_TestDatabase_Impl).mConfig
352 
353         assertThat(config.isMigrationRequired(0, 1)).isTrue()
354         assertThat(config.isMigrationRequired(1, 2)).isTrue()
355         assertThat(config.isMigrationRequired(5, 6)).isTrue()
356         assertThat(config.isMigrationRequired(7, 12)).isTrue()
357         assertThat(config.isMigrationRequired(132, 150)).isTrue()
358 
359         assertThat(config.isMigrationRequired(1, 0)).isTrue()
360         assertThat(config.isMigrationRequired(2, 1)).isTrue()
361         assertThat(config.isMigrationRequired(6, 5)).isTrue()
362         assertThat(config.isMigrationRequired(7, 12)).isTrue()
363         assertThat(config.isMigrationRequired(150, 132)).isTrue()
364     }
365 
366     @Test
367     fun isMigrationRequiredFrom_fallBackToDestFromCalled_falseForProvidedValues() {
368         val context: Context = mock()
369         val db =
370             inMemoryDatabaseBuilder(context, TestDatabase::class.java)
371                 .fallbackToDestructiveMigrationFrom(true, 1, 4, 81)
372                 .build()
373         val config: DatabaseConfiguration = (db as BuilderTest_TestDatabase_Impl).mConfig
374         assertThat(config.isMigrationRequired(1, 2)).isFalse()
375         assertThat(config.isMigrationRequired(4, 8)).isFalse()
376         assertThat(config.isMigrationRequired(81, 90)).isFalse()
377     }
378 
379     @Test
380     fun isMigrationRequiredFrom_fallBackToDestFromCalled_trueForNonProvidedValues() {
381         val context: Context = mock()
382         val db =
383             inMemoryDatabaseBuilder(context, TestDatabase::class.java)
384                 .fallbackToDestructiveMigrationFrom(true, 1, 4, 81)
385                 .build()
386         val config: DatabaseConfiguration = (db as BuilderTest_TestDatabase_Impl).mConfig
387         assertThat(config.isMigrationRequired(2, 3)).isTrue()
388         assertThat(config.isMigrationRequired(3, 4)).isTrue()
389         assertThat(config.isMigrationRequired(73, 80)).isTrue()
390     }
391 
392     @Test
393     fun autoMigrationShouldBeAddedToMigrations_WhenManualDowngradeMigrationIsPresent() {
394         val context: Context = mock()
395         val db =
396             inMemoryDatabaseBuilder(context, TestDatabase::class.java)
397                 .addMigrations(EmptyMigration(1, 0))
398                 .build() as BuilderTest_TestDatabase_Impl
399         val config: DatabaseConfiguration = db.databaseConfiguration
400         assertThat(config.migrationContainer.findMigrationPath(1, 2))
401             .isEqualTo((db.mAutoMigrations))
402     }
403 
404     @Test
405     fun fallbackToDestructiveMigrationOnDowngrade_withProvidedValues_falseForDowngrades() {
406         val context: Context = mock()
407         val db =
408             inMemoryDatabaseBuilder(context, TestDatabase::class.java)
409                 .fallbackToDestructiveMigrationOnDowngrade(false)
410                 .fallbackToDestructiveMigrationFrom(true, 2, 4)
411                 .build()
412         val config: DatabaseConfiguration = (db as BuilderTest_TestDatabase_Impl).mConfig
413         assertThat(config.isMigrationRequired(1, 2)).isTrue()
414         assertThat(config.isMigrationRequired(2, 3)).isFalse()
415         assertThat(config.isMigrationRequired(3, 4)).isTrue()
416         assertThat(config.isMigrationRequired(4, 5)).isFalse()
417         assertThat(config.isMigrationRequired(5, 6)).isTrue()
418         assertThat(config.isMigrationRequired(2, 1)).isFalse()
419         assertThat(config.isMigrationRequired(3, 2)).isFalse()
420         assertThat(config.isMigrationRequired(4, 3)).isFalse()
421         assertThat(config.isMigrationRequired(5, 4)).isFalse()
422         assertThat(config.isMigrationRequired(6, 5)).isFalse()
423     }
424 
425     @Test
426     fun createBasic() {
427         val context: Context = mock()
428         val db = inMemoryDatabaseBuilder(context, TestDatabase::class.java).build()
429         assertThat(db).isInstanceOf<BuilderTest_TestDatabase_Impl>()
430         val config: DatabaseConfiguration = (db as BuilderTest_TestDatabase_Impl).mConfig
431         assertThat(config).isNotNull()
432         assertThat(config.context).isEqualTo(context)
433         assertThat(config.name).isNull()
434         assertThat(config.allowMainThreadQueries).isFalse()
435         assertThat(config.journalMode).isEqualTo(RoomDatabase.JournalMode.TRUNCATE)
436         assertThat(config.sqliteOpenHelperFactory).isInstanceOf<FrameworkSQLiteOpenHelperFactory>()
437     }
438 
439     @Test
440     fun createAllowMainThread() {
441         val context: Context = mock()
442         val db =
443             inMemoryDatabaseBuilder(context, TestDatabase::class.java)
444                 .allowMainThreadQueries()
445                 .build()
446         val config: DatabaseConfiguration = (db as BuilderTest_TestDatabase_Impl).mConfig
447         assertThat(config.allowMainThreadQueries).isTrue()
448     }
449 
450     @Test
451     fun createWriteAheadLogging() {
452         val context: Context = mock()
453         val db =
454             databaseBuilder(context, TestDatabase::class.java, "foo")
455                 .setJournalMode(RoomDatabase.JournalMode.WRITE_AHEAD_LOGGING)
456                 .build()
457         assertThat(db).isInstanceOf<BuilderTest_TestDatabase_Impl>()
458         val config: DatabaseConfiguration = (db as BuilderTest_TestDatabase_Impl).mConfig
459         assertThat(config.journalMode).isEqualTo(RoomDatabase.JournalMode.WRITE_AHEAD_LOGGING)
460     }
461 
462     @Test
463     fun createWithFactoryAndVersion() {
464         val context: Context = mock()
465         val factory: SupportSQLiteOpenHelper.Factory = mock()
466         whenever(factory.create(any())).thenReturn(mock())
467         val db =
468             inMemoryDatabaseBuilder(context, TestDatabase::class.java)
469                 .openHelperFactory(factory)
470                 .build()
471         assertThat(db).isInstanceOf<BuilderTest_TestDatabase_Impl>()
472         val config: DatabaseConfiguration = (db as BuilderTest_TestDatabase_Impl).mConfig
473         assertThat(config).isNotNull()
474         assertThat(config.sqliteOpenHelperFactory).isEqualTo(factory)
475     }
476 
477     @Test
478     fun createFromAssetAndFromFile() {
479         var exception: Exception? = null
480         try {
481             databaseBuilder(mock(), TestDatabase::class.java, "foo")
482                 .createFromAsset("assets-path")
483                 .createFromFile(File("not-a--real-file"))
484                 .build()
485             Assert.fail("Build should have thrown")
486         } catch (e: Exception) {
487             exception = e
488         }
489         assertThat(exception).isInstanceOf<IllegalArgumentException>()
490         assertThat(exception)
491             .hasMessageThat()
492             .contains(
493                 "More than one of createFromAsset(), " +
494                     "createFromInputStream(), and createFromFile() were called on this Builder"
495             )
496     }
497 
498     @Test
499     fun createInMemoryFromAsset() {
500         var exception: Exception? = null
501         try {
502             inMemoryDatabaseBuilder(mock(), TestDatabase::class.java)
503                 .createFromAsset("assets-path")
504                 .build()
505             Assert.fail("Build should have thrown")
506         } catch (e: Exception) {
507             exception = e
508         }
509         assertThat(exception).isInstanceOf<IllegalArgumentException>()
510         assertThat(exception)
511             .hasMessageThat()
512             .contains("Cannot create from asset or file for an in-memory")
513     }
514 
515     @Test
516     fun createInMemoryFromFile() {
517         var exception: Exception? = null
518         try {
519             inMemoryDatabaseBuilder(mock(), TestDatabase::class.java)
520                 .createFromFile(File("not-a--real-file"))
521                 .build()
522             Assert.fail("Build should have thrown")
523         } catch (e: Exception) {
524             exception = e
525         }
526         assertThat(exception).isInstanceOf<IllegalArgumentException>()
527         assertThat(exception)
528             .hasMessageThat()
529             .contains("Cannot create from asset or file for an in-memory")
530     }
531 
532     @Test
533     fun driverProvided() {
534         val driver: SQLiteDriver = mock()
535         val db = inMemoryDatabaseBuilder(mock(), TestDatabase::class.java).setDriver(driver).build()
536         assertThat(db).isInstanceOf<BuilderTest_TestDatabase_Impl>()
537         val config: DatabaseConfiguration = (db as BuilderTest_TestDatabase_Impl).mConfig
538         assertThat(config.sqliteDriver).isEqualTo(driver)
539         assertThat(config.sqliteOpenHelperFactory).isNull()
540     }
541 
542     @Test
543     fun bothDriverAndFactoryProvided() {
544         try {
545             inMemoryDatabaseBuilder(mock(), RoomDatabase::class.java)
546                 .setDriver(mock())
547                 .openHelperFactory(mock())
548                 .build()
549         } catch (e: IllegalArgumentException) {
550             assertThat(e.message)
551                 .isEqualTo(
552                     "A RoomDatabase cannot be configured with both a SQLiteDriver and a " +
553                         "SupportOpenHelper.Factory."
554                 )
555         }
556     }
557 
558     @OptIn(ExperimentalRoomApi::class)
559     @Test
560     fun driverProvidedAutoClose() {
561         assertThrows<IllegalArgumentException> {
562                 inMemoryDatabaseBuilder(mock(), TestDatabase::class.java)
563                     .setAutoCloseTimeout(3, TimeUnit.SECONDS)
564                     .setDriver(mock())
565                     .build()
566             }
567             .hasMessageThat()
568             .isEqualTo("Auto Closing Database is not supported when an SQLiteDriver is configured.")
569     }
570 
571     @OptIn(ExperimentalRoomApi::class)
572     @Test
573     fun driverProvidedPrePackaged() {
574         assertThrows<IllegalArgumentException> {
575                 inMemoryDatabaseBuilder(mock(), TestDatabase::class.java)
576                     .createFromAsset("asset.db")
577                     .setDriver(mock())
578                     .build()
579             }
580             .hasMessageThat()
581             .isEqualTo("Pre-Package Database is not supported when an SQLiteDriver is configured.")
582     }
583 
584     @OptIn(ExperimentalRoomApi::class)
585     @Test
586     fun driverProvidedQueryCallback() {
587         assertThrows<IllegalArgumentException> {
588                 inMemoryDatabaseBuilder(mock(), TestDatabase::class.java)
589                     .setQueryCallback(Dispatchers.IO) { _, _ -> }
590                     .setDriver(mock())
591                     .build()
592             }
593             .hasMessageThat()
594             .isEqualTo("Query Callback is not supported when an SQLiteDriver is configured.")
595     }
596 
597     internal abstract class TestDatabase : RoomDatabase() {
598         lateinit var databaseConfiguration: DatabaseConfiguration
599 
600         override fun init(configuration: DatabaseConfiguration) {
601             super.init(configuration)
602             databaseConfiguration = configuration
603         }
604     }
605 
606     internal class EmptyMigration(start: Int, end: Int) : Migration(start, end) {
607         override fun migrate(db: SupportSQLiteDatabase) {}
608     }
609 }
610