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