1 /*
2 * Copyright 2024 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 package androidx.lifecycle.viewmodel.testing.internal
18
19 import androidx.lifecycle.DEFAULT_ARGS_KEY
20 import androidx.lifecycle.Lifecycle
21 import androidx.lifecycle.LifecycleOwner
22 import androidx.lifecycle.LifecycleRegistry
23 import androidx.lifecycle.SAVED_STATE_REGISTRY_OWNER_KEY
24 import androidx.lifecycle.VIEW_MODEL_STORE_OWNER_KEY
25 import androidx.lifecycle.ViewModel
26 import androidx.lifecycle.ViewModelStore
27 import androidx.lifecycle.ViewModelStoreOwner
28 import androidx.lifecycle.enableSavedStateHandles
29 import androidx.lifecycle.viewmodel.CreationExtras
30 import androidx.lifecycle.viewmodel.MutableCreationExtras
31 import androidx.lifecycle.viewmodel.testing.ViewModelScenario
32 import androidx.savedstate.SavedState
33 import androidx.savedstate.SavedStateRegistryController
34 import androidx.savedstate.SavedStateRegistryOwner
35 import androidx.savedstate.savedState
36
37 /**
38 * An internal implementation of [ViewModelStoreOwner], [LifecycleOwner], and
39 * [SavedStateRegistryOwner] used by [ViewModelScenario] as its default owner.
40 *
41 * This class provides the necessary infrastructure to manage a [ViewModel]'s lifecycle, saved
42 * state, and associated registry for testing purposes.
43 */
44 private class ViewModelScenarioOwner :
45 ViewModelStoreOwner, LifecycleOwner, SavedStateRegistryOwner {
46
47 override val viewModelStore = ViewModelStore()
48
49 val lifecycleRegistry = LifecycleRegistry.createUnsafe(owner = this)
50 override val lifecycle: Lifecycle = lifecycleRegistry
51
52 val savedStateRegistryController = SavedStateRegistryController.create(owner = this)
53 override val savedStateRegistry = savedStateRegistryController.savedStateRegistry
54 }
55
56 /**
57 * Creates a configured instance of [CreationExtras] for use in a [ViewModelScenario].
58 *
59 * This method sets up the necessary components to simulate and manage a [ViewModel]'s lifecycle and
60 * saved state in a test environment.
61 *
62 * It initializes required keys for state restoration and lifecycle management.
63 */
createScenarioExtrasnull64 internal fun createScenarioExtras(
65 initialExtras: CreationExtras = MutableCreationExtras(),
66 restoredState: SavedState = savedState(),
67 defaultArgs: SavedState = initialExtras[DEFAULT_ARGS_KEY] ?: savedState(),
68 ): CreationExtras {
69 val registryOwner = initialExtras[SAVED_STATE_REGISTRY_OWNER_KEY]
70 require(registryOwner == null || registryOwner is ViewModelScenarioOwner) {
71 "'SAVED_STATE_REGISTRY_OWNER_KEY' must be null or default, but was $registryOwner."
72 }
73
74 val storeOwner = initialExtras[VIEW_MODEL_STORE_OWNER_KEY]
75 require(storeOwner == null || storeOwner is ViewModelScenarioOwner) {
76 "'VIEW_MODEL_STORE_OWNER_KEY' must be null or default, but was $storeOwner."
77 }
78
79 val owner =
80 ViewModelScenarioOwner().apply {
81 savedStateRegistryController.performAttach()
82 enableSavedStateHandles()
83 savedStateRegistryController.performRestore(savedState = restoredState)
84 lifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_START)
85 }
86
87 return MutableCreationExtras(initialExtras).apply {
88 this[SAVED_STATE_REGISTRY_OWNER_KEY] = owner
89 this[VIEW_MODEL_STORE_OWNER_KEY] = owner
90 this[DEFAULT_ARGS_KEY] = defaultArgs
91 }
92 }
93
94 /**
95 * Saves the current state of [CreationExtras] associated with a [ViewModelScenario].
96 *
97 * This method captures the state of the [ViewModelScenarioOwner] from the
98 * [SAVED_STATE_REGISTRY_OWNER_KEY] and encodes it using platform-specific serialization.
99 */
saveScenarioExtrasnull100 internal fun saveScenarioExtras(extras: CreationExtras): SavedState {
101 val owner = extras[SAVED_STATE_REGISTRY_OWNER_KEY] as ViewModelScenarioOwner
102
103 val outState = savedState()
104 owner.savedStateRegistryController.performSave(outState)
105
106 return platformEncodeDecode(outState)
107 }
108
109 /**
110 * Encodes and decodes a [SavedState] using platform-specific algorithms. It ensures platform
111 * requirements during tests.
112 */
platformEncodeDecodenull113 internal expect fun platformEncodeDecode(savedState: SavedState): SavedState
114