blob: 017552a021526c0d97ddf7e2fe5f1a87b9843b73 [file] [log] [blame]
/*
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License
*/
package android.content.res.loader.test
import android.graphics.Color
import android.graphics.drawable.BitmapDrawable
import android.graphics.drawable.ColorDrawable
import com.google.common.truth.Truth.assertThat
import org.junit.Assert.assertEquals
import org.junit.Assert.assertNotEquals
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.Parameterized
/**
* Tests generic ResourceLoader behavior. Intentionally abstract in its test methodology because
* the behavior being verified isn't specific to any resource type. As long as it can pass an
* equals check.
*
* Currently tests strings and dimens since String and any Number seemed most relevant to verify.
*/
@RunWith(Parameterized::class)
class ResourceLoaderValuesTest : ResourceLoaderTestBase() {
companion object {
@Parameterized.Parameters(name = "{1} {0}")
@JvmStatic
fun parameters(): Array<Any> {
val parameters = mutableListOf<Parameter>()
// R.string
parameters += Parameter(
{ getString(android.R.string.cancel) },
"stringOne", { "SomeRidiculouslyUnlikelyStringOne" },
"stringTwo", { "SomeRidiculouslyUnlikelyStringTwo" },
listOf(DataType.APK, DataType.ARSC)
)
// R.dimen
parameters += Parameter(
{ resources.getDimensionPixelSize(android.R.dimen.app_icon_size) },
"dimenOne", { 564716.dpToPx(resources) },
"dimenTwo", { 565717.dpToPx(resources) },
listOf(DataType.APK, DataType.ARSC)
)
// File in the assets directory
parameters += Parameter(
{ assets.open("Asset.txt").reader().readText() },
"assetOne", { "assetOne" },
"assetTwo", { "assetTwo" },
listOf(DataType.ASSET)
)
// From assets directory returning file descriptor
parameters += Parameter(
{ assets.openFd("Asset.txt").readText() },
"assetOne", { "assetOne" },
"assetTwo", { "assetTwo" },
listOf(DataType.ASSET_FD)
)
// From root directory returning file descriptor
parameters += Parameter(
{ assets.openNonAssetFd("NonAsset.txt").readText() },
"NonAssetOne", { "NonAssetOne" },
"NonAssetTwo", { "NonAssetTwo" },
listOf(DataType.NON_ASSET)
)
// Asset as compiled XML drawable
parameters += Parameter(
{ (getDrawable(R.drawable.non_asset_drawable) as ColorDrawable).color },
"nonAssetDrawableOne", { Color.parseColor("#A3C3E3") },
"nonAssetDrawableTwo", { Color.parseColor("#3A3C3E") },
listOf(DataType.NON_ASSET_DRAWABLE)
)
// Asset as compiled bitmap drawable
parameters += Parameter(
{
(getDrawable(R.drawable.non_asset_bitmap) as BitmapDrawable)
.bitmap.getColor(0, 0).toArgb()
},
"nonAssetBitmapGreen", { Color.GREEN },
"nonAssetBitmapBlue", { Color.BLUE },
listOf(DataType.NON_ASSET_BITMAP)
)
// Asset as compiled XML layout
parameters += Parameter(
{ getLayout(R.layout.layout).advanceToRoot().name },
"layoutOne", { "RelativeLayout" },
"layoutTwo", { "LinearLayout" },
listOf(DataType.NON_ASSET_LAYOUT)
)
// Isolated resource split
parameters += Parameter(
{ getString(R.string.split_overlaid) },
"split_one", { "Split ONE Overlaid" },
"split_two", { "Split TWO Overlaid" },
listOf(DataType.SPLIT)
)
return parameters.flatMap { parameter ->
parameter.dataTypes.map { dataType ->
arrayOf(dataType, parameter)
}
}.toTypedArray()
}
}
@Suppress("LateinitVarOverridesLateinitVar")
@field:Parameterized.Parameter(0)
override lateinit var dataType: DataType
@field:Parameterized.Parameter(1)
lateinit var parameter: Parameter
private val valueOne by lazy { parameter.valueOne(this) }
private val valueTwo by lazy { parameter.valueTwo(this) }
private fun openOne() = parameter.loaderOne.openLoader()
private fun openTwo() = parameter.loaderTwo.openLoader()
// Class method for syntax highlighting purposes
private fun getValue() = parameter.getValue(this)
@Test
fun verifyValueUniqueness() {
// Ensure the parameters are valid in case of coding errors
assertNotEquals(valueOne, getValue())
assertNotEquals(valueTwo, getValue())
assertNotEquals(valueOne, valueTwo)
}
@Test
fun addMultipleLoaders() {
val originalValue = getValue()
val testOne = openOne()
val testTwo = openTwo()
addLoader(testOne, testTwo)
assertEquals(valueTwo, getValue())
removeLoader(testTwo)
assertEquals(valueOne, getValue())
removeLoader(testOne)
assertEquals(originalValue, getValue())
}
@Test
fun setMultipleLoaders() {
val originalValue = getValue()
val testOne = openOne()
val testTwo = openTwo()
setLoaders(testOne, testTwo)
assertEquals(valueTwo, getValue())
removeLoader(testTwo)
assertEquals(valueOne, getValue())
setLoaders()
assertEquals(originalValue, getValue())
}
@Test
fun getLoadersContainsAll() {
val testOne = openOne()
val testTwo = openTwo()
addLoader(testOne, testTwo)
assertThat(getLoaders()).containsAllOf(testOne, testTwo)
}
@Test
fun getLoadersDoesNotLeakMutability() {
val originalValue = getValue()
val testOne = openOne()
val testTwo = openTwo()
addLoader(testOne)
assertEquals(valueOne, getValue())
val loaders = getLoaders()
loaders += testTwo
assertEquals(valueOne, getValue())
removeLoader(testOne)
assertEquals(originalValue, getValue())
}
@Test(expected = IllegalArgumentException::class)
fun alreadyAddedThrows() {
val testOne = openOne()
val testTwo = openTwo()
addLoader(testOne)
addLoader(testTwo)
addLoader(testOne)
}
@Test(expected = IllegalArgumentException::class)
fun alreadyAddedAndSetThrows() {
val testOne = openOne()
val testTwo = openTwo()
addLoader(testOne)
addLoader(testTwo)
setLoaders(testTwo)
}
@Test
fun repeatedRemoveSucceeds() {
val originalValue = getValue()
val testOne = openOne()
addLoader(testOne)
assertNotEquals(originalValue, getValue())
removeLoader(testOne)
assertEquals(originalValue, getValue())
removeLoader(testOne)
assertEquals(originalValue, getValue())
}
@Test
fun addToFront() {
val testOne = openOne()
val testTwo = openTwo()
addLoader(testOne)
assertEquals(valueOne, getValue())
addLoader(testTwo, 0)
assertEquals(valueOne, getValue())
// Remove top loader, so previously added to front should now resolve
removeLoader(testOne)
assertEquals(valueTwo, getValue())
}
@Test
fun addToEnd() {
val testOne = openOne()
val testTwo = openTwo()
addLoader(testOne)
assertEquals(valueOne, getValue())
addLoader(testTwo, 1)
assertEquals(valueTwo, getValue())
}
@Test(expected = IndexOutOfBoundsException::class)
fun addPastEnd() {
val testOne = openOne()
val testTwo = openTwo()
addLoader(testOne)
assertEquals(valueOne, getValue())
addLoader(testTwo, 2)
}
@Test(expected = IndexOutOfBoundsException::class)
fun addBeforeFront() {
val testOne = openOne()
val testTwo = openTwo()
addLoader(testOne)
assertEquals(valueOne, getValue())
addLoader(testTwo, -1)
}
@Test
fun reorder() {
val originalValue = getValue()
val testOne = openOne()
val testTwo = openTwo()
addLoader(testOne, testTwo)
assertEquals(valueTwo, getValue())
removeLoader(testOne)
assertEquals(valueTwo, getValue())
addLoader(testOne)
assertEquals(valueOne, getValue())
removeLoader(testTwo)
assertEquals(valueOne, getValue())
removeLoader(testOne)
assertEquals(originalValue, getValue())
}
data class Parameter(
val getValue: ResourceLoaderValuesTest.() -> Any,
val loaderOne: String,
val valueOne: ResourceLoaderValuesTest.() -> Any,
val loaderTwo: String,
val valueTwo: ResourceLoaderValuesTest.() -> Any,
val dataTypes: List<DataType>
) {
override fun toString(): String {
val prefix = loaderOne.commonPrefixWith(loaderTwo)
return "$prefix${loaderOne.removePrefix(prefix)}|${loaderTwo.removePrefix(prefix)}"
}
}
}