music: add cache repository test
Add tests for the cache repository and cache data structure.
This commit is contained in:
parent
881fb58648
commit
ad672ed919
5 changed files with 271 additions and 42 deletions
|
@ -149,6 +149,8 @@ dependencies {
|
||||||
debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.12'
|
debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.12'
|
||||||
testImplementation "junit:junit:4.13.2"
|
testImplementation "junit:junit:4.13.2"
|
||||||
testImplementation "io.mockk:mockk:1.13.7"
|
testImplementation "io.mockk:mockk:1.13.7"
|
||||||
|
testImplementation "org.robolectric:robolectric:4.9"
|
||||||
|
testImplementation 'androidx.test:core-ktx:1.5.0'
|
||||||
androidTestImplementation 'androidx.test.ext:junit:1.1.5'
|
androidTestImplementation 'androidx.test.ext:junit:1.1.5'
|
||||||
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
|
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,40 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2023 Auxio Project
|
|
||||||
* StubTest.kt is part of Auxio.
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.oxycblt.auxio
|
|
||||||
|
|
||||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
|
||||||
import androidx.test.platform.app.InstrumentationRegistry
|
|
||||||
import org.junit.Assert.*
|
|
||||||
import org.junit.Test
|
|
||||||
import org.junit.runner.RunWith
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Instrumented test, which will execute on an Android device.
|
|
||||||
*
|
|
||||||
* See [testing documentation](http://d.android.com/tools/testing).
|
|
||||||
*/
|
|
||||||
@RunWith(AndroidJUnit4::class)
|
|
||||||
class StubTest {
|
|
||||||
// TODO: Make tests
|
|
||||||
@Test
|
|
||||||
fun useAppContext() {
|
|
||||||
val appContext = InstrumentationRegistry.getInstrumentation().targetContext
|
|
||||||
assertEquals("org.oxycblt.auxio.debug", appContext.packageName)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -63,9 +63,9 @@ data class CachedSong(
|
||||||
/** @see RawSong */
|
/** @see RawSong */
|
||||||
var durationMs: Long,
|
var durationMs: Long,
|
||||||
/** @see RawSong.replayGainTrackAdjustment */
|
/** @see RawSong.replayGainTrackAdjustment */
|
||||||
val replayGainTrackAdjustment: Float?,
|
val replayGainTrackAdjustment: Float? = null,
|
||||||
/** @see RawSong.replayGainAlbumAdjustment */
|
/** @see RawSong.replayGainAlbumAdjustment */
|
||||||
val replayGainAlbumAdjustment: Float?,
|
val replayGainAlbumAdjustment: Float? = null,
|
||||||
/** @see RawSong.musicBrainzId */
|
/** @see RawSong.musicBrainzId */
|
||||||
var musicBrainzId: String? = null,
|
var musicBrainzId: String? = null,
|
||||||
/** @see RawSong.name */
|
/** @see RawSong.name */
|
||||||
|
|
|
@ -43,6 +43,7 @@ interface Separators {
|
||||||
const val SLASH = '/'
|
const val SLASH = '/'
|
||||||
const val PLUS = '+'
|
const val PLUS = '+'
|
||||||
const val AND = '&'
|
const val AND = '&'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new instance from the **current state** of the given [MusicSettings]'s
|
* Creates a new instance from the **current state** of the given [MusicSettings]'s
|
||||||
* user-defined separator configuration.
|
* user-defined separator configuration.
|
||||||
|
|
266
app/src/test/java/org/oxycblt/auxio/music/cache/CacheRepositoryTest.kt
vendored
Normal file
266
app/src/test/java/org/oxycblt/auxio/music/cache/CacheRepositoryTest.kt
vendored
Normal file
|
@ -0,0 +1,266 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2023 Auxio Project
|
||||||
|
* CacheRepositoryTest.kt is part of Auxio.
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.oxycblt.auxio.music.cache
|
||||||
|
|
||||||
|
import io.mockk.Runs
|
||||||
|
import io.mockk.coEvery
|
||||||
|
import io.mockk.coVerifyAll
|
||||||
|
import io.mockk.coVerifySequence
|
||||||
|
import io.mockk.just
|
||||||
|
import io.mockk.mockk
|
||||||
|
import io.mockk.slot
|
||||||
|
import java.lang.IllegalStateException
|
||||||
|
import kotlinx.coroutines.runBlocking
|
||||||
|
import org.junit.Assert.assertEquals
|
||||||
|
import org.junit.Assert.assertFalse
|
||||||
|
import org.junit.Assert.assertTrue
|
||||||
|
import org.junit.Test
|
||||||
|
import org.oxycblt.auxio.music.device.RawSong
|
||||||
|
import org.oxycblt.auxio.music.info.Date
|
||||||
|
|
||||||
|
class CacheRepositoryTest {
|
||||||
|
@Test
|
||||||
|
fun cache_read_noInvalidate() {
|
||||||
|
val dao =
|
||||||
|
mockk<CachedSongsDao> {
|
||||||
|
coEvery { readSongs() }.returnsMany(listOf(CACHED_SONG_A, CACHED_SONG_B))
|
||||||
|
}
|
||||||
|
val cacheRepository = CacheRepositoryImpl(dao)
|
||||||
|
val cache = requireNotNull(runBlocking { cacheRepository.readCache() })
|
||||||
|
coVerifyAll { dao.readSongs() }
|
||||||
|
assertFalse(cache.invalidated)
|
||||||
|
|
||||||
|
val songA = RawSong(mediaStoreId = 0, dateAdded = 1, dateModified = 2)
|
||||||
|
assertTrue(cache.populate(songA))
|
||||||
|
assertEquals(RAW_SONG_A, songA)
|
||||||
|
|
||||||
|
assertFalse(cache.invalidated)
|
||||||
|
|
||||||
|
val songB = RawSong(mediaStoreId = 9, dateAdded = 10, dateModified = 11)
|
||||||
|
assertTrue(cache.populate(songB))
|
||||||
|
assertEquals(RAW_SONG_B, songB)
|
||||||
|
|
||||||
|
assertFalse(cache.invalidated)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun cache_read_invalidate() {
|
||||||
|
val dao =
|
||||||
|
mockk<CachedSongsDao> {
|
||||||
|
coEvery { readSongs() }.returnsMany(listOf(CACHED_SONG_A, CACHED_SONG_B))
|
||||||
|
}
|
||||||
|
val cacheRepository = CacheRepositoryImpl(dao)
|
||||||
|
val cache = requireNotNull(runBlocking { cacheRepository.readCache() })
|
||||||
|
coVerifyAll { dao.readSongs() }
|
||||||
|
assertFalse(cache.invalidated)
|
||||||
|
|
||||||
|
val nullStart = RawSong(mediaStoreId = 0, dateAdded = 0, dateModified = 0)
|
||||||
|
val nullEnd = RawSong(mediaStoreId = 0, dateAdded = 0, dateModified = 0)
|
||||||
|
assertFalse(cache.populate(nullStart))
|
||||||
|
assertEquals(nullStart, nullEnd)
|
||||||
|
|
||||||
|
assertTrue(cache.invalidated)
|
||||||
|
|
||||||
|
val songB = RawSong(mediaStoreId = 9, dateAdded = 10, dateModified = 11)
|
||||||
|
assertTrue(cache.populate(songB))
|
||||||
|
assertEquals(RAW_SONG_B, songB)
|
||||||
|
|
||||||
|
assertTrue(cache.invalidated)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun cache_read_crashes() {
|
||||||
|
val dao = mockk<CachedSongsDao> { coEvery { readSongs() } throws IllegalStateException() }
|
||||||
|
val cacheRepository = CacheRepositoryImpl(dao)
|
||||||
|
assertEquals(null, runBlocking { cacheRepository.readCache() })
|
||||||
|
coVerifyAll { dao.readSongs() }
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun cache_write() {
|
||||||
|
var currentlyStoredSongs = listOf<CachedSong>()
|
||||||
|
val insertSongsArg = slot<List<CachedSong>>()
|
||||||
|
val dao =
|
||||||
|
mockk<CachedSongsDao> {
|
||||||
|
coEvery { nukeSongs() } answers { currentlyStoredSongs = listOf() }
|
||||||
|
|
||||||
|
coEvery { insertSongs(capture(insertSongsArg)) } answers
|
||||||
|
{
|
||||||
|
currentlyStoredSongs = insertSongsArg.captured
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val cacheRepository = CacheRepositoryImpl(dao)
|
||||||
|
|
||||||
|
val rawSongs = listOf(RAW_SONG_A, RAW_SONG_B)
|
||||||
|
runBlocking { cacheRepository.writeCache(rawSongs) }
|
||||||
|
|
||||||
|
val cachedSongs = listOf(CACHED_SONG_A, CACHED_SONG_B)
|
||||||
|
coVerifySequence {
|
||||||
|
dao.nukeSongs()
|
||||||
|
dao.insertSongs(cachedSongs)
|
||||||
|
}
|
||||||
|
assertEquals(cachedSongs, currentlyStoredSongs)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun cache_write_nukeCrashes() {
|
||||||
|
val dao =
|
||||||
|
mockk<CachedSongsDao> {
|
||||||
|
coEvery { nukeSongs() } throws IllegalStateException()
|
||||||
|
coEvery { insertSongs(listOf()) } just Runs
|
||||||
|
}
|
||||||
|
val cacheRepository = CacheRepositoryImpl(dao)
|
||||||
|
runBlocking { cacheRepository.writeCache(listOf()) }
|
||||||
|
coVerifyAll { dao.nukeSongs() }
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun cache_write_insertCrashes() {
|
||||||
|
val dao =
|
||||||
|
mockk<CachedSongsDao> {
|
||||||
|
coEvery { nukeSongs() } just Runs
|
||||||
|
coEvery { insertSongs(listOf()) } throws IllegalStateException()
|
||||||
|
}
|
||||||
|
val cacheRepository = CacheRepositoryImpl(dao)
|
||||||
|
runBlocking { cacheRepository.writeCache(listOf()) }
|
||||||
|
coVerifySequence {
|
||||||
|
dao.nukeSongs()
|
||||||
|
dao.insertSongs(listOf())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private companion object {
|
||||||
|
val CACHED_SONG_A =
|
||||||
|
CachedSong(
|
||||||
|
mediaStoreId = 0,
|
||||||
|
dateAdded = 1,
|
||||||
|
dateModified = 2,
|
||||||
|
size = 3,
|
||||||
|
durationMs = 4,
|
||||||
|
replayGainTrackAdjustment = 5.5f,
|
||||||
|
replayGainAlbumAdjustment = 6.6f,
|
||||||
|
musicBrainzId = "Song MBID A",
|
||||||
|
name = "Song Name A",
|
||||||
|
sortName = "Song Sort Name A",
|
||||||
|
track = 7,
|
||||||
|
disc = 8,
|
||||||
|
subtitle = "Subtitle A",
|
||||||
|
date = Date.from("2020-10-10"),
|
||||||
|
albumMusicBrainzId = "Album MBID A",
|
||||||
|
albumName = "Album Name A",
|
||||||
|
albumSortName = "Album Sort Name A",
|
||||||
|
releaseTypes = listOf("Release Type A"),
|
||||||
|
artistMusicBrainzIds = listOf("Artist MBID A"),
|
||||||
|
artistNames = listOf("Artist Name A"),
|
||||||
|
artistSortNames = listOf("Artist Sort Name A"),
|
||||||
|
albumArtistMusicBrainzIds = listOf("Album Artist MBID A"),
|
||||||
|
albumArtistNames = listOf("Album Artist Name A"),
|
||||||
|
albumArtistSortNames = listOf("Album Artist Sort Name A"),
|
||||||
|
genreNames = listOf("Genre Name A"),
|
||||||
|
)
|
||||||
|
|
||||||
|
val RAW_SONG_A =
|
||||||
|
RawSong(
|
||||||
|
mediaStoreId = 0,
|
||||||
|
dateAdded = 1,
|
||||||
|
dateModified = 2,
|
||||||
|
size = 3,
|
||||||
|
durationMs = 4,
|
||||||
|
replayGainTrackAdjustment = 5.5f,
|
||||||
|
replayGainAlbumAdjustment = 6.6f,
|
||||||
|
musicBrainzId = "Song MBID A",
|
||||||
|
name = "Song Name A",
|
||||||
|
sortName = "Song Sort Name A",
|
||||||
|
track = 7,
|
||||||
|
disc = 8,
|
||||||
|
subtitle = "Subtitle A",
|
||||||
|
date = Date.from("2020-10-10"),
|
||||||
|
albumMusicBrainzId = "Album MBID A",
|
||||||
|
albumName = "Album Name A",
|
||||||
|
albumSortName = "Album Sort Name A",
|
||||||
|
releaseTypes = listOf("Release Type A"),
|
||||||
|
artistMusicBrainzIds = listOf("Artist MBID A"),
|
||||||
|
artistNames = listOf("Artist Name A"),
|
||||||
|
artistSortNames = listOf("Artist Sort Name A"),
|
||||||
|
albumArtistMusicBrainzIds = listOf("Album Artist MBID A"),
|
||||||
|
albumArtistNames = listOf("Album Artist Name A"),
|
||||||
|
albumArtistSortNames = listOf("Album Artist Sort Name A"),
|
||||||
|
genreNames = listOf("Genre Name A"),
|
||||||
|
)
|
||||||
|
|
||||||
|
val CACHED_SONG_B =
|
||||||
|
CachedSong(
|
||||||
|
mediaStoreId = 9,
|
||||||
|
dateAdded = 10,
|
||||||
|
dateModified = 11,
|
||||||
|
size = 12,
|
||||||
|
durationMs = 13,
|
||||||
|
replayGainTrackAdjustment = 14.14f,
|
||||||
|
replayGainAlbumAdjustment = 15.15f,
|
||||||
|
musicBrainzId = "Song MBID B",
|
||||||
|
name = "Song Name B",
|
||||||
|
sortName = "Song Sort Name B",
|
||||||
|
track = 16,
|
||||||
|
disc = 17,
|
||||||
|
subtitle = "Subtitle B",
|
||||||
|
date = Date.from("2021-11-11"),
|
||||||
|
albumMusicBrainzId = "Album MBID B",
|
||||||
|
albumName = "Album Name B",
|
||||||
|
albumSortName = "Album Sort Name B",
|
||||||
|
releaseTypes = listOf("Release Type B"),
|
||||||
|
artistMusicBrainzIds = listOf("Artist MBID B"),
|
||||||
|
artistNames = listOf("Artist Name B"),
|
||||||
|
artistSortNames = listOf("Artist Sort Name B"),
|
||||||
|
albumArtistMusicBrainzIds = listOf("Album Artist MBID B"),
|
||||||
|
albumArtistNames = listOf("Album Artist Name B"),
|
||||||
|
albumArtistSortNames = listOf("Album Artist Sort Name B"),
|
||||||
|
genreNames = listOf("Genre Name B"),
|
||||||
|
)
|
||||||
|
|
||||||
|
val RAW_SONG_B =
|
||||||
|
RawSong(
|
||||||
|
mediaStoreId = 9,
|
||||||
|
dateAdded = 10,
|
||||||
|
dateModified = 11,
|
||||||
|
size = 12,
|
||||||
|
durationMs = 13,
|
||||||
|
replayGainTrackAdjustment = 14.14f,
|
||||||
|
replayGainAlbumAdjustment = 15.15f,
|
||||||
|
musicBrainzId = "Song MBID B",
|
||||||
|
name = "Song Name B",
|
||||||
|
sortName = "Song Sort Name B",
|
||||||
|
track = 16,
|
||||||
|
disc = 17,
|
||||||
|
subtitle = "Subtitle B",
|
||||||
|
date = Date.from("2021-11-11"),
|
||||||
|
albumMusicBrainzId = "Album MBID B",
|
||||||
|
albumName = "Album Name B",
|
||||||
|
albumSortName = "Album Sort Name B",
|
||||||
|
releaseTypes = listOf("Release Type B"),
|
||||||
|
artistMusicBrainzIds = listOf("Artist MBID B"),
|
||||||
|
artistNames = listOf("Artist Name B"),
|
||||||
|
artistSortNames = listOf("Artist Sort Name B"),
|
||||||
|
albumArtistMusicBrainzIds = listOf("Album Artist MBID B"),
|
||||||
|
albumArtistNames = listOf("Album Artist Name B"),
|
||||||
|
albumArtistSortNames = listOf("Album Artist Sort Name B"),
|
||||||
|
genreNames = listOf("Genre Name B"),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue