Files
Lawnchair/tests/multivalentTests/src/com/android/launcher3/LauncherPrefsTest.kt
T
Brian Isganitis 9cbc478574 Split LauncherPrefs into abs class / impl.
Splitting allows easily making a fake that doesn't have to override the implementation details of LauncherPrefs. The fake should not deal with SharedPreferences.

LauncherPrefs could be an interface, but then the companion object has more limitations. The solution there is to have a dedicated object class, e.g. `LauncherPrefItems`. I went with an abs class to make the refactor simpler.

Flag: EXEMPT refactor
Bug: 369641781
Test: go/testedequals
Change-Id: I97a2d495d3b5fa892fa53a11fb3f7a7dfb98515b
2024-10-09 18:55:51 -04:00

231 lines
8.5 KiB
Kotlin

/*
* Copyright (C) 2023 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 com.android.launcher3
import android.content.Context
import android.content.SharedPreferences
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import androidx.test.platform.app.InstrumentationRegistry
import com.android.launcher3.LauncherPrefs.Companion.BOOT_AWARE_PREFS_KEY
import com.google.common.truth.Truth.assertThat
import java.util.concurrent.CountDownLatch
import java.util.concurrent.TimeUnit
import org.junit.Test
import org.junit.runner.RunWith
private val TEST_BOOLEAN_ITEM = LauncherPrefs.nonRestorableItem("1", false)
private val TEST_STRING_ITEM = LauncherPrefs.nonRestorableItem("2", "( ͡❛ ͜ʖ ͡❛)")
private val TEST_INT_ITEM = LauncherPrefs.nonRestorableItem("3", -1)
private val TEST_CONTEXTUAL_ITEM =
ContextualItem("4", true, { true }, EncryptionType.ENCRYPTED, Boolean::class.java)
private const val TEST_DEFAULT_VALUE = "default"
private const val TEST_PREF_KEY = "test_pref_key"
private const val WAIT_TIME_IN_SECONDS = 3L
@SmallTest
@RunWith(AndroidJUnit4::class)
class LauncherPrefsTest {
private val context by lazy { InstrumentationRegistry.getInstrumentation().targetContext }
private val launcherPrefs by lazy { LauncherPrefs.get(context) }
@Test
fun has_keyMissingFromLauncherPrefs_returnsFalse() {
assertThat(launcherPrefs.has(TEST_BOOLEAN_ITEM)).isFalse()
}
@Test
fun has_keyPresentInLauncherPrefs_returnsTrue() {
with(launcherPrefs) {
putSync(TEST_BOOLEAN_ITEM.to(TEST_BOOLEAN_ITEM.defaultValue))
assertThat(has(TEST_BOOLEAN_ITEM)).isTrue()
remove(TEST_BOOLEAN_ITEM)
}
}
@Test
fun addListener_listeningForStringItemUpdates_isCorrectlyNotifiedOfUpdates() {
val latch = CountDownLatch(1)
val listener = LauncherPrefChangeListener { latch.countDown() }
with(launcherPrefs) {
putSync(TEST_STRING_ITEM.to(TEST_STRING_ITEM.defaultValue))
addListener(listener, TEST_STRING_ITEM)
putSync(TEST_STRING_ITEM.to(TEST_STRING_ITEM.defaultValue + "abc"))
assertThat(latch.await(WAIT_TIME_IN_SECONDS, TimeUnit.SECONDS)).isTrue()
remove(TEST_STRING_ITEM)
}
}
@Test
fun removeListener_previouslyListeningForStringItemUpdates_isNoLongerNotifiedOfUpdates() {
val latch = CountDownLatch(1)
val listener = LauncherPrefChangeListener { latch.countDown() }
with(launcherPrefs) {
addListener(listener, TEST_STRING_ITEM)
removeListener(listener, TEST_STRING_ITEM)
putSync(TEST_STRING_ITEM.to(TEST_STRING_ITEM.defaultValue + "hello."))
// latch will be still be 1 (and await will return false) if the listener was not called
assertThat(latch.await(WAIT_TIME_IN_SECONDS, TimeUnit.SECONDS)).isFalse()
remove(TEST_STRING_ITEM)
}
}
@Test
fun addListenerAndRemoveListener_forMultipleItems_bothWorkProperly() {
var latch = CountDownLatch(3)
val listener = LauncherPrefChangeListener { latch.countDown() }
with(launcherPrefs) {
addListener(listener, TEST_INT_ITEM, TEST_STRING_ITEM, TEST_BOOLEAN_ITEM)
putSync(
TEST_INT_ITEM.to(TEST_INT_ITEM.defaultValue + 123),
TEST_STRING_ITEM.to(TEST_STRING_ITEM.defaultValue + "abc"),
TEST_BOOLEAN_ITEM.to(!TEST_BOOLEAN_ITEM.defaultValue),
)
assertThat(latch.await(WAIT_TIME_IN_SECONDS, TimeUnit.SECONDS)).isTrue()
removeListener(listener, TEST_INT_ITEM, TEST_STRING_ITEM, TEST_BOOLEAN_ITEM)
latch = CountDownLatch(1)
putSync(
TEST_INT_ITEM.to(TEST_INT_ITEM.defaultValue),
TEST_STRING_ITEM.to(TEST_STRING_ITEM.defaultValue),
TEST_BOOLEAN_ITEM.to(TEST_BOOLEAN_ITEM.defaultValue),
)
remove(TEST_INT_ITEM, TEST_STRING_ITEM, TEST_BOOLEAN_ITEM)
assertThat(latch.await(WAIT_TIME_IN_SECONDS, TimeUnit.SECONDS)).isFalse()
}
}
@Test
fun get_booleanItemNotInLauncherprefs_returnsDefaultValue() {
assertThat(launcherPrefs.get(TEST_BOOLEAN_ITEM)).isEqualTo(TEST_BOOLEAN_ITEM.defaultValue)
}
@Test
fun get_stringItemNotInLauncherPrefs_returnsDefaultValue() {
assertThat(launcherPrefs.get(TEST_STRING_ITEM)).isEqualTo(TEST_STRING_ITEM.defaultValue)
}
@Test
fun get_intItemNotInLauncherprefs_returnsDefaultValue() {
assertThat(launcherPrefs.get(TEST_INT_ITEM)).isEqualTo(TEST_INT_ITEM.defaultValue)
}
@Test
fun put_storesItemInLauncherPrefs_successfully() {
val notDefaultValue = !TEST_BOOLEAN_ITEM.defaultValue
with(launcherPrefs) {
putSync(TEST_BOOLEAN_ITEM.to(notDefaultValue))
assertThat(get(TEST_BOOLEAN_ITEM)).isEqualTo(notDefaultValue)
remove(TEST_BOOLEAN_ITEM)
}
}
@Test
fun put_storesListOfItemsInLauncherPrefs_successfully() {
with(launcherPrefs) {
putSync(
TEST_STRING_ITEM.to(TEST_STRING_ITEM.defaultValue),
TEST_INT_ITEM.to(TEST_INT_ITEM.defaultValue),
TEST_BOOLEAN_ITEM.to(TEST_BOOLEAN_ITEM.defaultValue),
)
assertThat(has(TEST_BOOLEAN_ITEM, TEST_INT_ITEM, TEST_STRING_ITEM)).isTrue()
remove(TEST_STRING_ITEM, TEST_INT_ITEM, TEST_BOOLEAN_ITEM)
}
}
@Test
fun remove_deletesItemFromLauncherPrefs_successfully() {
val notDefaultValue = !TEST_BOOLEAN_ITEM.defaultValue
with(launcherPrefs) {
putSync(TEST_BOOLEAN_ITEM.to(notDefaultValue))
remove(TEST_BOOLEAN_ITEM)
assertThat(get(TEST_BOOLEAN_ITEM)).isEqualTo(TEST_BOOLEAN_ITEM.defaultValue)
}
}
@Test
fun get_contextualItem_returnsCorrectDefault() {
assertThat(launcherPrefs.get(TEST_CONTEXTUAL_ITEM)).isTrue()
}
@Test
fun getItemSharedPrefFile_forNonRestorableItem_isCorrect() {
val nonRestorableItem = LauncherPrefs.nonRestorableItem(TEST_PREF_KEY, TEST_DEFAULT_VALUE)
assertThat(nonRestorableItem.sharedPrefFile).isEqualTo(LauncherFiles.DEVICE_PREFERENCES_KEY)
}
@Test
fun getItemSharedPrefFile_forBackedUpItem_isCorrect() {
val backedUpItem = LauncherPrefs.backedUpItem(TEST_PREF_KEY, TEST_DEFAULT_VALUE)
assertThat(backedUpItem.sharedPrefFile).isEqualTo(LauncherFiles.SHARED_PREFERENCES_KEY)
}
@Test
fun put_bootAwareItem_updatesDeviceProtectedStorage() {
val bootAwareItem =
LauncherPrefs.backedUpItem(
TEST_PREF_KEY,
TEST_DEFAULT_VALUE,
EncryptionType.DEVICE_PROTECTED,
)
val bootAwarePrefs: SharedPreferences =
context
.createDeviceProtectedStorageContext()
.getSharedPreferences(BOOT_AWARE_PREFS_KEY, Context.MODE_PRIVATE)
bootAwarePrefs.edit().remove(bootAwareItem.sharedPrefKey).commit()
launcherPrefs.putSync(bootAwareItem.to(bootAwareItem.defaultValue))
assertThat(bootAwarePrefs.contains(bootAwareItem.sharedPrefKey)).isTrue()
launcherPrefs.removeSync(bootAwareItem)
}
@Test
fun remove_bootAwareItem_removesFromDeviceProtectedStorage() {
val bootAwareItem =
LauncherPrefs.backedUpItem(
TEST_PREF_KEY,
TEST_DEFAULT_VALUE,
EncryptionType.DEVICE_PROTECTED,
)
val bootAwarePrefs: SharedPreferences =
context
.createDeviceProtectedStorageContext()
.getSharedPreferences(BOOT_AWARE_PREFS_KEY, Context.MODE_PRIVATE)
bootAwarePrefs
.edit()
.putString(bootAwareItem.sharedPrefKey, bootAwareItem.defaultValue)
.commit()
launcherPrefs.removeSync(bootAwareItem)
assertThat(bootAwarePrefs.contains(bootAwareItem.sharedPrefKey)).isFalse()
}
}