1 /*
<lambda>null2 * Copyright (C) 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 com.android.compose.animation.scene.subjects
18
19 import com.android.compose.animation.scene.OverlayKey
20 import com.android.compose.animation.scene.SceneKey
21 import com.android.compose.animation.scene.content.state.TransitionState
22 import com.android.mechanics.GestureContext
23 import com.google.common.truth.Fact.simpleFact
24 import com.google.common.truth.FailureMetadata
25 import com.google.common.truth.Subject
26 import com.google.common.truth.Subject.Factory
27 import com.google.common.truth.Truth
28
29 /** Assert on a [TransitionState]. */
30 fun assertThat(state: TransitionState): TransitionStateSubject {
31 return Truth.assertAbout(TransitionStateSubject.transitionStates()).that(state)
32 }
33
34 /** Assert on a [TransitionState.Transition.ChangeScene]. */
assertThatnull35 fun assertThat(transition: TransitionState.Transition.ChangeScene): SceneTransitionSubject {
36 return Truth.assertAbout(SceneTransitionSubject.sceneTransitions()).that(transition)
37 }
38
39 /** Assert on a [TransitionState.Transition.ShowOrHideOverlay]. */
assertThatnull40 fun assertThat(
41 transition: TransitionState.Transition.ShowOrHideOverlay
42 ): ShowOrHideOverlayTransitionSubject {
43 return Truth.assertAbout(ShowOrHideOverlayTransitionSubject.showOrHideOverlayTransitions())
44 .that(transition)
45 }
46
47 /** Assert on a [TransitionState.Transition.ReplaceOverlay]. */
assertThatnull48 fun assertThat(
49 transition: TransitionState.Transition.ReplaceOverlay
50 ): ReplaceOverlayTransitionSubject {
51 return Truth.assertAbout(ReplaceOverlayTransitionSubject.replaceOverlayTransitions())
52 .that(transition)
53 }
54
55 class TransitionStateSubject
56 private constructor(metadata: FailureMetadata, private val actual: TransitionState) :
57 Subject(metadata, actual) {
hasCurrentScenenull58 fun hasCurrentScene(sceneKey: SceneKey) {
59 check("currentScene").that(actual.currentScene).isEqualTo(sceneKey)
60 }
61
hasCurrentOverlaysnull62 fun hasCurrentOverlays(vararg overlays: OverlayKey) {
63 check("currentOverlays").that(actual.currentOverlays).containsExactlyElementsIn(overlays)
64 }
65
isIdlenull66 fun isIdle(): TransitionState.Idle {
67 if (actual !is TransitionState.Idle) {
68 failWithActual(simpleFact("expected to be TransitionState.Idle"))
69 }
70
71 return actual as TransitionState.Idle
72 }
73
isSceneTransitionnull74 fun isSceneTransition(): TransitionState.Transition.ChangeScene {
75 if (actual !is TransitionState.Transition.ChangeScene) {
76 failWithActual(
77 simpleFact("expected to be TransitionState.Transition.ChangeCurrentScene")
78 )
79 }
80
81 return actual as TransitionState.Transition.ChangeScene
82 }
83
isShowOrHideOverlayTransitionnull84 fun isShowOrHideOverlayTransition(): TransitionState.Transition.ShowOrHideOverlay {
85 if (actual !is TransitionState.Transition.ShowOrHideOverlay) {
86 failWithActual(
87 simpleFact("expected to be TransitionState.Transition.ShowOrHideOverlay")
88 )
89 }
90
91 return actual as TransitionState.Transition.ShowOrHideOverlay
92 }
93
isReplaceOverlayTransitionnull94 fun isReplaceOverlayTransition(): TransitionState.Transition.ReplaceOverlay {
95 if (actual !is TransitionState.Transition.ReplaceOverlay) {
96 failWithActual(simpleFact("expected to be TransitionState.Transition.ReplaceOverlay"))
97 }
98
99 return actual as TransitionState.Transition.ReplaceOverlay
100 }
101
hasGestureContextnull102 fun hasGestureContext(): GestureContext {
103 if (actual !is TransitionState.Transition) {
104 failWithActual(simpleFact("expected to be TransitionState.Transition"))
105 }
106
107 val gestureContext = ((actual as TransitionState.Transition).gestureContext)
108 check("transition.gestureContext").that(gestureContext).isNotNull()
109
110 return checkNotNull(gestureContext)
111 }
112
113 companion object {
actualnull114 fun transitionStates() = Factory { metadata, actual: TransitionState? ->
115 TransitionStateSubject(metadata, actual!!)
116 }
117 }
118 }
119
120 abstract class BaseTransitionSubject<T : TransitionState.Transition>(
121 metadata: FailureMetadata,
122 protected val actual: T,
123 ) : Subject(metadata, actual) {
hasCurrentScenenull124 fun hasCurrentScene(sceneKey: SceneKey) {
125 check("currentScene").that(actual.currentScene).isEqualTo(sceneKey)
126 }
127
hasCurrentOverlaysnull128 fun hasCurrentOverlays(vararg overlays: OverlayKey) {
129 check("currentOverlays").that(actual.currentOverlays).containsExactlyElementsIn(overlays)
130 }
131
hasProgressnull132 fun hasProgress(progress: Float, tolerance: Float = 0.01f) {
133 check("progress").that(actual.progress).isWithin(tolerance).of(progress)
134 }
135
hasProgressVelocitynull136 fun hasProgressVelocity(progressVelocity: Float, tolerance: Float = 0.01f) {
137 check("progressVelocity")
138 .that(actual.progressVelocity)
139 .isWithin(tolerance)
140 .of(progressVelocity)
141 }
142
hasPreviewProgressnull143 fun hasPreviewProgress(progress: Float, tolerance: Float = 0.01f) {
144 check("previewProgress").that(actual.previewProgress).isWithin(tolerance).of(progress)
145 }
146
hasPreviewProgressVelocitynull147 fun hasPreviewProgressVelocity(progressVelocity: Float, tolerance: Float = 0.01f) {
148 check("previewProgressVelocity")
149 .that(actual.previewProgressVelocity)
150 .isWithin(tolerance)
151 .of(progressVelocity)
152 }
153
isInPreviewStagenull154 fun isInPreviewStage() {
155 check("isInPreviewStage").that(actual.isInPreviewStage).isTrue()
156 }
157
isNotInPreviewStagenull158 fun isNotInPreviewStage() {
159 check("isInPreviewStage").that(actual.isInPreviewStage).isFalse()
160 }
161
isInitiatedByUserInputnull162 fun isInitiatedByUserInput() {
163 check("isInitiatedByUserInput").that(actual.isInitiatedByUserInput).isTrue()
164 }
165
hasIsUserInputOngoingnull166 fun hasIsUserInputOngoing(isUserInputOngoing: Boolean) {
167 check("isUserInputOngoing").that(actual.isUserInputOngoing).isEqualTo(isUserInputOngoing)
168 }
169 }
170
171 class SceneTransitionSubject
172 private constructor(metadata: FailureMetadata, actual: TransitionState.Transition.ChangeScene) :
173 BaseTransitionSubject<TransitionState.Transition.ChangeScene>(metadata, actual) {
hasFromScenenull174 fun hasFromScene(sceneKey: SceneKey) {
175 check("fromScene").that(actual.fromScene).isEqualTo(sceneKey)
176 }
177
hasToScenenull178 fun hasToScene(sceneKey: SceneKey) {
179 check("toScene").that(actual.toScene).isEqualTo(sceneKey)
180 }
181
182 companion object {
sceneTransitionsnull183 fun sceneTransitions() =
184 Factory { metadata, actual: TransitionState.Transition.ChangeScene? ->
185 SceneTransitionSubject(metadata, actual!!)
186 }
187 }
188 }
189
190 class ShowOrHideOverlayTransitionSubject
191 private constructor(
192 metadata: FailureMetadata,
193 actual: TransitionState.Transition.ShowOrHideOverlay,
194 ) : BaseTransitionSubject<TransitionState.Transition.ShowOrHideOverlay>(metadata, actual) {
hasFromOrToScenenull195 fun hasFromOrToScene(fromOrToScene: SceneKey) {
196 check("fromOrToScene").that(actual.fromOrToScene).isEqualTo(fromOrToScene)
197 }
198
hasOverlaynull199 fun hasOverlay(overlay: OverlayKey) {
200 check("overlay").that(actual.overlay).isEqualTo(overlay)
201 }
202
203 companion object {
showOrHideOverlayTransitionsnull204 fun showOrHideOverlayTransitions() =
205 Factory { metadata, actual: TransitionState.Transition.ShowOrHideOverlay? ->
206 ShowOrHideOverlayTransitionSubject(metadata, actual!!)
207 }
208 }
209 }
210
211 class ReplaceOverlayTransitionSubject
212 private constructor(metadata: FailureMetadata, actual: TransitionState.Transition.ReplaceOverlay) :
213 BaseTransitionSubject<TransitionState.Transition.ReplaceOverlay>(metadata, actual) {
hasFromOverlaynull214 fun hasFromOverlay(fromOverlay: OverlayKey) {
215 check("fromOverlay").that(actual.fromOverlay).isEqualTo(fromOverlay)
216 }
217
hasToOverlaynull218 fun hasToOverlay(toOverlay: OverlayKey) {
219 check("toOverlay").that(actual.toOverlay).isEqualTo(toOverlay)
220 }
221
222 companion object {
replaceOverlayTransitionsnull223 fun replaceOverlayTransitions() =
224 Factory { metadata, actual: TransitionState.Transition.ReplaceOverlay? ->
225 ReplaceOverlayTransitionSubject(metadata, actual!!)
226 }
227 }
228 }
229