Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit df183795 authored by Jacky Wang's avatar Jacky Wang Committed by Android (Google) Code Review
Browse files

Merge "Provide a common test case for catalyst screens" into main

parents 63ff0454 37b361c2
Loading
Loading
Loading
Loading
+13 −0
Original line number Original line Diff line number Diff line
@@ -22,3 +22,16 @@ android_library {
    ],
    ],
    kotlincflags: ["-Xjvm-default=all"],
    kotlincflags: ["-Xjvm-default=all"],
}
}

android_library {
    name: "SettingsLibPreference-testutils",
    srcs: ["testutils/**/*.kt"],
    static_libs: [
        "SettingsLibPreference",
        "androidx.fragment_fragment-testing",
        "androidx.test.core",
        "androidx.test.ext.junit",
        "flag-junit",
        "truth",
    ],
}
+5 −2
Original line number Original line Diff line number Diff line
@@ -68,10 +68,13 @@ interface PreferenceBinding {
                preference.icon = null
                preference.icon = null
            }
            }
            val context = preference.context
            val context = preference.context
            val isPreferenceScreen = preference is PreferenceScreen
            preference.peekExtras()?.clear()
            preference.peekExtras()?.clear()
            extras(context)?.let { preference.extras.putAll(it) }
            extras(context)?.let { preference.extras.putAll(it) }
            preference.title = getPreferenceTitle(context)
            preference.title = getPreferenceTitle(context)
            if (!isPreferenceScreen) {
                preference.summary = getPreferenceSummary(context)
                preference.summary = getPreferenceSummary(context)
            }
            preference.isEnabled = isEnabled(context)
            preference.isEnabled = isEnabled(context)
            preference.isVisible =
            preference.isVisible =
                (this as? PreferenceAvailabilityProvider)?.isAvailable(context) != false
                (this as? PreferenceAvailabilityProvider)?.isAvailable(context) != false
@@ -81,7 +84,7 @@ interface PreferenceBinding {
            // dependency here. This simplifies dependency management and avoid the
            // dependency here. This simplifies dependency management and avoid the
            // IllegalStateException when call Preference.setDependency
            // IllegalStateException when call Preference.setDependency
            preference.dependency = null
            preference.dependency = null
            if (preference !is PreferenceScreen) { // avoid recursive loop when build graph
            if (!isPreferenceScreen) { // avoid recursive loop when build graph
                preference.fragment = (this as? PreferenceScreenCreator)?.fragmentClass()?.name
                preference.fragment = (this as? PreferenceScreenCreator)?.fragmentClass()?.name
                preference.intent = intent(context)
                preference.intent = intent(context)
            }
            }
+123 −0
Original line number Original line Diff line number Diff line
/*
 * Copyright (C) 2024 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.settingslib.preference

import android.content.Context
import android.platform.test.flag.junit.SetFlagsRule
import android.util.Log
import androidx.fragment.app.testing.FragmentScenario
import androidx.preference.Preference
import androidx.preference.PreferenceFragmentCompat
import androidx.preference.PreferenceGroup
import androidx.preference.PreferenceScreen
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.google.common.truth.Truth.assertThat
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith

/** Test case for catalyst screen. */
@RunWith(AndroidJUnit4::class)
abstract class CatalystScreenTestCase {
    @get:Rule val setFlagsRule = SetFlagsRule()

    protected val context: Context = ApplicationProvider.getApplicationContext()

    /** Catalyst screen. */
    protected abstract val preferenceScreenCreator: PreferenceScreenCreator

    /** Flag to control catalyst screen. */
    protected abstract val flagName: String

    /**
     * Test to compare the preference screen hierarchy between legacy screen (flag is disabled) and
     * catalyst screen (flag is enabled).
     */
    @Test
    fun migration() {
        enableCatalystScreen()
        assertThat(preferenceScreenCreator.isFlagEnabled(context)).isTrue()
        val catalystScreen = stringifyPreferenceScreen()
        Log.i("Catalyst", catalystScreen)

        disableCatalystScreen()
        assertThat(preferenceScreenCreator.isFlagEnabled(context)).isFalse()
        val legacyScreen = stringifyPreferenceScreen()

        assertThat(catalystScreen).isEqualTo(legacyScreen)
    }

    /**
     * Enables the catalyst screen.
     *
     * By default, enable the [flagName]. Override for more complex situation.
     */
    @Suppress("DEPRECATION")
    protected open fun enableCatalystScreen() {
        setFlagsRule.enableFlags(flagName)
    }

    /**
     * Disables the catalyst screen (legacy screen is shown).
     *
     * By default, disable the [flagName]. Override for more complex situation.
     */
    @Suppress("DEPRECATION")
    protected open fun disableCatalystScreen() {
        setFlagsRule.disableFlags(flagName)
    }

    private fun stringifyPreferenceScreen(): String {
        @Suppress("UNCHECKED_CAST")
        val clazz = preferenceScreenCreator.fragmentClass() as Class<PreferenceFragmentCompat>
        val builder = StringBuilder()
        FragmentScenario.launch(clazz).use {
            it.onFragment { fragment -> fragment.preferenceScreen.toString(builder) }
        }
        return builder.toString()
    }

    private fun Preference.toString(builder: StringBuilder, indent: String = "") {
        val clazz = javaClass
        builder.append(indent).append(clazz).append(" {\n")
        val indent2 = "$indent  "
        if (clazz != PreferenceScreen::class.java) {
            key?.let { builder.append(indent2).append("key: \"$it\"\n") }
        }
        title?.let { builder.append(indent2).append("title: \"$it\"\n") }
        summary?.let { builder.append(indent2).append("summary: \"$it\"\n") }
        fragment?.let { builder.append(indent2).append("fragment: \"$it\"\n") }
        builder.append(indent2).append("order: $order\n")
        builder.append(indent2).append("isCopyingEnabled: $isCopyingEnabled\n")
        builder.append(indent2).append("isEnabled: $isEnabled\n")
        builder.append(indent2).append("isIconSpaceReserved: $isIconSpaceReserved\n")
        if (clazz != Preference::class.java && clazz != PreferenceScreen::class.java) {
            builder.append(indent2).append("isPersistent: $isPersistent\n")
        }
        builder.append(indent2).append("isSelectable: $isSelectable\n")
        if (this is PreferenceGroup) {
            val count = preferenceCount
            builder.append(indent2).append("preferenceCount: $count\n")
            val indent4 = "$indent2  "
            for (index in 0..<count) {
                getPreference(index).toString(builder, indent4)
            }
        }
        builder.append(indent).append("}\n")
    }
}