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.ContentKey
20 import com.android.compose.animation.scene.OverlayKey
21 import com.android.compose.animation.scene.OverscrollSpec
22 import com.android.compose.animation.scene.SceneKey
23 import com.android.compose.animation.scene.content.state.TransitionState
24 import com.google.common.truth.Fact.simpleFact
25 import com.google.common.truth.FailureMetadata
26 import com.google.common.truth.Subject
27 import com.google.common.truth.Subject.Factory
28 import com.google.common.truth.Truth
29 
30 /** Assert on a [TransitionState]. */
31 fun assertThat(state: TransitionState): TransitionStateSubject {
32     return Truth.assertAbout(TransitionStateSubject.transitionStates()).that(state)
33 }
34 
35 /** Assert on a [TransitionState.Transition.ChangeScene]. */
assertThatnull36 fun assertThat(transition: TransitionState.Transition.ChangeScene): SceneTransitionSubject {
37     return Truth.assertAbout(SceneTransitionSubject.sceneTransitions()).that(transition)
38 }
39 
40 /** Assert on a [TransitionState.Transition.ShowOrHideOverlay]. */
assertThatnull41 fun assertThat(
42     transition: TransitionState.Transition.ShowOrHideOverlay
43 ): ShowOrHideOverlayTransitionSubject {
44     return Truth.assertAbout(ShowOrHideOverlayTransitionSubject.showOrHideOverlayTransitions())
45         .that(transition)
46 }
47 
48 /** Assert on a [TransitionState.Transition.ReplaceOverlay]. */
assertThatnull49 fun assertThat(
50     transition: TransitionState.Transition.ReplaceOverlay
51 ): ReplaceOverlayTransitionSubject {
52     return Truth.assertAbout(ReplaceOverlayTransitionSubject.replaceOverlayTransitions())
53         .that(transition)
54 }
55 
56 class TransitionStateSubject
57 private constructor(metadata: FailureMetadata, private val actual: TransitionState) :
58     Subject(metadata, actual) {
hasCurrentScenenull59     fun hasCurrentScene(sceneKey: SceneKey) {
60         check("currentScene").that(actual.currentScene).isEqualTo(sceneKey)
61     }
62 
hasCurrentOverlaysnull63     fun hasCurrentOverlays(vararg overlays: OverlayKey) {
64         check("currentOverlays").that(actual.currentOverlays).containsExactlyElementsIn(overlays)
65     }
66 
isIdlenull67     fun isIdle(): TransitionState.Idle {
68         if (actual !is TransitionState.Idle) {
69             failWithActual(simpleFact("expected to be TransitionState.Idle"))
70         }
71 
72         return actual as TransitionState.Idle
73     }
74 
isSceneTransitionnull75     fun isSceneTransition(): TransitionState.Transition.ChangeScene {
76         if (actual !is TransitionState.Transition.ChangeScene) {
77             failWithActual(
78                 simpleFact("expected to be TransitionState.Transition.ChangeCurrentScene")
79             )
80         }
81 
82         return actual as TransitionState.Transition.ChangeScene
83     }
84 
isShowOrHideOverlayTransitionnull85     fun isShowOrHideOverlayTransition(): TransitionState.Transition.ShowOrHideOverlay {
86         if (actual !is TransitionState.Transition.ShowOrHideOverlay) {
87             failWithActual(
88                 simpleFact("expected to be TransitionState.Transition.ShowOrHideOverlay")
89             )
90         }
91 
92         return actual as TransitionState.Transition.ShowOrHideOverlay
93     }
94 
isReplaceOverlayTransitionnull95     fun isReplaceOverlayTransition(): TransitionState.Transition.ReplaceOverlay {
96         if (actual !is TransitionState.Transition.ReplaceOverlay) {
97             failWithActual(simpleFact("expected to be TransitionState.Transition.ReplaceOverlay"))
98         }
99 
100         return actual as TransitionState.Transition.ReplaceOverlay
101     }
102 
103     companion object {
actualnull104         fun transitionStates() = Factory { metadata, actual: TransitionState ->
105             TransitionStateSubject(metadata, actual)
106         }
107     }
108 }
109 
110 abstract class BaseTransitionSubject<T : TransitionState.Transition>(
111     metadata: FailureMetadata,
112     protected val actual: T,
113 ) : Subject(metadata, actual) {
hasCurrentScenenull114     fun hasCurrentScene(sceneKey: SceneKey) {
115         check("currentScene").that(actual.currentScene).isEqualTo(sceneKey)
116     }
117 
hasCurrentOverlaysnull118     fun hasCurrentOverlays(vararg overlays: OverlayKey) {
119         check("currentOverlays").that(actual.currentOverlays).containsExactlyElementsIn(overlays)
120     }
121 
hasProgressnull122     fun hasProgress(progress: Float, tolerance: Float = 0f) {
123         check("progress").that(actual.progress).isWithin(tolerance).of(progress)
124     }
125 
hasProgressVelocitynull126     fun hasProgressVelocity(progressVelocity: Float, tolerance: Float = 0f) {
127         check("progressVelocity")
128             .that(actual.progressVelocity)
129             .isWithin(tolerance)
130             .of(progressVelocity)
131     }
132 
hasPreviewProgressnull133     fun hasPreviewProgress(progress: Float, tolerance: Float = 0f) {
134         check("previewProgress").that(actual.previewProgress).isWithin(tolerance).of(progress)
135     }
136 
hasPreviewProgressVelocitynull137     fun hasPreviewProgressVelocity(progressVelocity: Float, tolerance: Float = 0f) {
138         check("previewProgressVelocity")
139             .that(actual.previewProgressVelocity)
140             .isWithin(tolerance)
141             .of(progressVelocity)
142     }
143 
isInPreviewStagenull144     fun isInPreviewStage() {
145         check("isInPreviewStage").that(actual.isInPreviewStage).isTrue()
146     }
147 
isNotInPreviewStagenull148     fun isNotInPreviewStage() {
149         check("isInPreviewStage").that(actual.isInPreviewStage).isFalse()
150     }
151 
isInitiatedByUserInputnull152     fun isInitiatedByUserInput() {
153         check("isInitiatedByUserInput").that(actual.isInitiatedByUserInput).isTrue()
154     }
155 
hasIsUserInputOngoingnull156     fun hasIsUserInputOngoing(isUserInputOngoing: Boolean) {
157         check("isUserInputOngoing").that(actual.isUserInputOngoing).isEqualTo(isUserInputOngoing)
158     }
159 
hasOverscrollSpecnull160     internal fun hasOverscrollSpec(): OverscrollSpec {
161         check("currentOverscrollSpec").that(actual.currentOverscrollSpec).isNotNull()
162         return actual.currentOverscrollSpec!!
163     }
164 
hasNoOverscrollSpecnull165     fun hasNoOverscrollSpec() {
166         check("currentOverscrollSpec").that(actual.currentOverscrollSpec).isNull()
167     }
168 
hasBouncingContentnull169     fun hasBouncingContent(content: ContentKey) {
170         val actual = actual
171         if (actual !is TransitionState.HasOverscrollProperties) {
172             failWithActual(simpleFact("expected to be ContentState.HasOverscrollProperties"))
173         }
174 
175         check("bouncingContent")
176             .that((actual as TransitionState.HasOverscrollProperties).bouncingContent)
177             .isEqualTo(content)
178     }
179 }
180 
181 class SceneTransitionSubject
182 private constructor(metadata: FailureMetadata, actual: TransitionState.Transition.ChangeScene) :
183     BaseTransitionSubject<TransitionState.Transition.ChangeScene>(metadata, actual) {
hasFromScenenull184     fun hasFromScene(sceneKey: SceneKey) {
185         check("fromScene").that(actual.fromScene).isEqualTo(sceneKey)
186     }
187 
hasToScenenull188     fun hasToScene(sceneKey: SceneKey) {
189         check("toScene").that(actual.toScene).isEqualTo(sceneKey)
190     }
191 
192     companion object {
sceneTransitionsnull193         fun sceneTransitions() =
194             Factory { metadata, actual: TransitionState.Transition.ChangeScene ->
195                 SceneTransitionSubject(metadata, actual)
196             }
197     }
198 }
199 
200 class ShowOrHideOverlayTransitionSubject
201 private constructor(
202     metadata: FailureMetadata,
203     actual: TransitionState.Transition.ShowOrHideOverlay,
204 ) : BaseTransitionSubject<TransitionState.Transition.ShowOrHideOverlay>(metadata, actual) {
hasFromOrToScenenull205     fun hasFromOrToScene(fromOrToScene: SceneKey) {
206         check("fromOrToScene").that(actual.fromOrToScene).isEqualTo(fromOrToScene)
207     }
208 
hasOverlaynull209     fun hasOverlay(overlay: OverlayKey) {
210         check("overlay").that(actual.overlay).isEqualTo(overlay)
211     }
212 
213     companion object {
showOrHideOverlayTransitionsnull214         fun showOrHideOverlayTransitions() =
215             Factory { metadata, actual: TransitionState.Transition.ShowOrHideOverlay ->
216                 ShowOrHideOverlayTransitionSubject(metadata, actual)
217             }
218     }
219 }
220 
221 class ReplaceOverlayTransitionSubject
222 private constructor(metadata: FailureMetadata, actual: TransitionState.Transition.ReplaceOverlay) :
223     BaseTransitionSubject<TransitionState.Transition.ReplaceOverlay>(metadata, actual) {
hasFromOverlaynull224     fun hasFromOverlay(fromOverlay: OverlayKey) {
225         check("fromOverlay").that(actual.fromOverlay).isEqualTo(fromOverlay)
226     }
227 
hasToOverlaynull228     fun hasToOverlay(toOverlay: OverlayKey) {
229         check("toOverlay").that(actual.toOverlay).isEqualTo(toOverlay)
230     }
231 
232     companion object {
replaceOverlayTransitionsnull233         fun replaceOverlayTransitions() =
234             Factory { metadata, actual: TransitionState.Transition.ReplaceOverlay ->
235                 ReplaceOverlayTransitionSubject(metadata, actual)
236             }
237     }
238 }
239