mirror of
https://github.com/f-droid/fdroidclient.git
synced 2026-04-20 23:07:26 -04:00
Add test for AppMetadataFTS table migration
This commit is contained in:
@@ -0,0 +1,187 @@
|
||||
package org.fdroid.database
|
||||
|
||||
import android.content.ContentValues
|
||||
import android.content.Context
|
||||
import android.database.sqlite.SQLiteDatabase
|
||||
import androidx.arch.core.executor.testing.InstantTaskExecutorRule
|
||||
import androidx.room.Room
|
||||
import androidx.room.testing.MigrationTestHelper
|
||||
import androidx.sqlite.db.SupportSQLiteDatabase
|
||||
import androidx.sqlite.db.framework.FrameworkSQLiteOpenHelperFactory
|
||||
import androidx.test.core.app.ApplicationProvider
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import androidx.test.platform.app.InstrumentationRegistry
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import org.fdroid.database.TestUtils.getOrFail
|
||||
import org.fdroid.test.TestUtils.getRandomString
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import kotlin.random.Random
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
private const val TEST_DB = "fts-test"
|
||||
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
internal class FtsCaseInsensitiveMigrationTest {
|
||||
|
||||
@get:Rule
|
||||
val helper: MigrationTestHelper = MigrationTestHelper(
|
||||
instrumentation = InstrumentationRegistry.getInstrumentation(),
|
||||
databaseClass = FDroidDatabaseInt::class.java,
|
||||
specs = emptyList(),
|
||||
openFactory = FrameworkSQLiteOpenHelperFactory(),
|
||||
)
|
||||
|
||||
@get:Rule
|
||||
val instantExec = InstantTaskExecutorRule()
|
||||
|
||||
private val context: Context = ApplicationProvider.getApplicationContext()
|
||||
|
||||
private val repo = ContentValues().apply {
|
||||
put("repoId", 1)
|
||||
put("name", Converters.localizedTextV2toString(mapOf(
|
||||
"de" to "a", "en-US" to "b")))
|
||||
put("address", getRandomString())
|
||||
put("certificate", "abcdef")
|
||||
put("description", Converters.localizedTextV2toString(mapOf(
|
||||
"de" to "aa", "en-US" to "bb")))
|
||||
put("version", Random.nextLong())
|
||||
put("timestamp", Random.nextLong())
|
||||
}
|
||||
|
||||
private val repoPrefs = ContentValues().apply {
|
||||
put("repoId", 1)
|
||||
put("enabled", true)
|
||||
put("weight", 1)
|
||||
}
|
||||
|
||||
private val oeffiMetadata = ContentValues().apply {
|
||||
put("packageName", "de.schildbach.oeffi")
|
||||
put("repoId", 1)
|
||||
put("name", Converters.localizedTextV2toString(mapOf(
|
||||
"de" to "Öffi", "en-US" to "Offi")))
|
||||
put("description", Converters.localizedTextV2toString(mapOf(
|
||||
"de" to "Öffentlicher Nahverkehr", "en-US" to "Public Transport")))
|
||||
put("license", "GPL-3.0")
|
||||
put("summary", Converters.localizedTextV2toString(mapOf(
|
||||
"de" to "Der König des Fahrplandschungels!",
|
||||
"en-US" to " King of public transit planning!")))
|
||||
put("localizedName", "Öffi")
|
||||
put("localizedSummary", "Der König des Fahrplandschungels!")
|
||||
put("added", Random.nextLong())
|
||||
put("lastUpdated", Random.nextLong())
|
||||
put("isCompatible", true)
|
||||
}
|
||||
|
||||
private val oeffiVersion = ContentValues().apply {
|
||||
put("repoId", 1)
|
||||
put("packageName", "de.schildbach.oeffi")
|
||||
put("versionId", 1)
|
||||
put("added", 1000)
|
||||
put("isCompatible", true)
|
||||
put("file_name", "transportr.apk")
|
||||
put("file_sha256", "73475CB40A568E8DA8A045CED110137E159F890AC4DA883B6B17DC651B3A8049")
|
||||
put("manifest_versionName", "1.0.0")
|
||||
put("manifest_versionCode", 1)
|
||||
}
|
||||
|
||||
private val transportrMetadata = ContentValues().apply {
|
||||
put("packageName", "de.grobox.liberario")
|
||||
put("repoId", 1)
|
||||
put("name", Converters.localizedTextV2toString(mapOf(
|
||||
"de" to "Transportr", "en-US" to "Transportr")))
|
||||
put("description", Converters.localizedTextV2toString(mapOf(
|
||||
"de" to "Öffentlicher Nahverkehr", "en-US" to "Public Transport")))
|
||||
put("license", "GPL-3.0")
|
||||
put("summary", Converters.localizedTextV2toString(mapOf(
|
||||
"de" to "Freier Assistent für den öffentlichen Nahverkehr ohne Werbung und Tracking",
|
||||
"en-US" to "Free Public Transport Assistant without Ads or Tracking")))
|
||||
put("localizedName", "Transportr")
|
||||
put("localizedSummary",
|
||||
"Freier Assistent für den öffentlichen Nahverkehr ohne Werbung und Tracking")
|
||||
put("added", Random.nextLong())
|
||||
put("lastUpdated", Random.nextLong())
|
||||
put("isCompatible", true)
|
||||
}
|
||||
|
||||
private val transportrVersion = ContentValues().apply {
|
||||
put("repoId", 1)
|
||||
put("packageName", "de.grobox.liberario")
|
||||
put("versionId", 1)
|
||||
put("added", 1000)
|
||||
put("isCompatible", true)
|
||||
put("file_name", "transportr.apk")
|
||||
put("file_sha256", "73475CB40A568E8DA8A045CED110137E159F890AC4DA883B6B17DC651B3A8049")
|
||||
put("manifest_versionName", "1.0.0")
|
||||
put("manifest_versionCode", 1)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testMigration() = runBlocking {
|
||||
|
||||
helper.createDatabase(TEST_DB, 5).use { db ->
|
||||
// Database has schema version 5. Insert some data using SQL queries.
|
||||
// We can't use DAO classes because they expect the latest schema.
|
||||
db.insert(CoreRepository.TABLE, SQLiteDatabase.CONFLICT_FAIL, repo)
|
||||
db.insert(RepositoryPreferences.TABLE, SQLiteDatabase.CONFLICT_FAIL, repoPrefs)
|
||||
db.insert(AppMetadata.TABLE, SQLiteDatabase.CONFLICT_FAIL, oeffiMetadata)
|
||||
db.insert(AppMetadata.TABLE, SQLiteDatabase.CONFLICT_FAIL, transportrMetadata)
|
||||
db.insert(Version.TABLE, SQLiteDatabase.CONFLICT_FAIL, oeffiVersion)
|
||||
db.insert(Version.TABLE, SQLiteDatabase.CONFLICT_FAIL, transportrVersion)
|
||||
|
||||
// Show that search is case sensitive for diacritics
|
||||
assertSearch(db, "Öffi", 1)
|
||||
assertSearch(db, "öffi", 0)
|
||||
// using no diacritics does match any case
|
||||
assertSearch(db, "Offi", 0)
|
||||
assertSearch(db, "offi", 0)
|
||||
// it's case sensitive so only "öffentlichen" from Transportr is found
|
||||
assertSearch(db, "öff*", 1)
|
||||
assertSearch(db, "König", 1)
|
||||
|
||||
}
|
||||
|
||||
helper.runMigrationsAndValidate(TEST_DB, 6, true, MIGRATION_5_6).close()
|
||||
|
||||
// now get the Room DB, so we can use our DAOs for verifying the migration
|
||||
Room.databaseBuilder(context, FDroidDatabaseInt::class.java, TEST_DB)
|
||||
.allowMainThreadQueries()
|
||||
.build().use { db ->
|
||||
// assert that apps are still there
|
||||
val metadata = db.getAppDao().getAppMetadata()
|
||||
assertEquals(2, metadata.size)
|
||||
// default search with no diacritics
|
||||
assertGetAppListItems(db, "*Transport*", 1)
|
||||
assertGetAppListItems(db, "Transportr", 1)
|
||||
assertGetAppListItems(db, "*f*", 2)
|
||||
// no or wrong diacritics
|
||||
assertGetAppListItems(db, "Offi", 0)
|
||||
assertGetAppListItems(db, "offi", 0)
|
||||
assertGetAppListItems(db, "õffi", 0)
|
||||
assertGetAppListItems(db, "*Offi*", 0)
|
||||
assertGetAppListItems(db, "*offi*", 0)
|
||||
assertGetAppListItems(db, "Konig", 0)
|
||||
// correct diacritics
|
||||
assertGetAppListItems(db, "*Öffi*", 1)
|
||||
assertGetAppListItems(db, "*öffi*", 1)
|
||||
assertGetAppListItems(db, "Öffi", 1)
|
||||
assertGetAppListItems(db, "öffi", 1)
|
||||
// both apps have "öff" in their name or summary
|
||||
assertGetAppListItems(db, "*öff*", 2)
|
||||
assertGetAppListItems(db, "König", 1)
|
||||
}
|
||||
}
|
||||
|
||||
private fun assertSearch(db: SupportSQLiteDatabase, query: String, expected: Int) {
|
||||
db.query("SELECT * FROM AppMetadataFts WHERE AppMetadataFts MATCH '$query'")
|
||||
.use { cursor -> assertEquals(expected, cursor.count) }
|
||||
}
|
||||
|
||||
private fun assertGetAppListItems(db: FDroidDatabaseInt, query: String, expected: Int) {
|
||||
db.getAppDao().getAppListItems(query).getOrFail().let {
|
||||
assertEquals(expected, it.size)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user