1 /* 2 * Copyright (C) 2018 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 package android.contentcaptureservice.cts; 17 18 import static android.contentcaptureservice.cts.Helper.MY_EPOCH; 19 import static android.contentcaptureservice.cts.Helper.TAG; 20 import static android.view.contentcapture.ContentCaptureEvent.TYPE_CONTEXT_UPDATED; 21 import static android.view.contentcapture.ContentCaptureEvent.TYPE_SESSION_PAUSED; 22 import static android.view.contentcapture.ContentCaptureEvent.TYPE_SESSION_RESUMED; 23 import static android.view.contentcapture.ContentCaptureEvent.TYPE_VIEW_APPEARED; 24 import static android.view.contentcapture.ContentCaptureEvent.TYPE_VIEW_DISAPPEARED; 25 import static android.view.contentcapture.ContentCaptureEvent.TYPE_VIEW_TEXT_CHANGED; 26 import static android.view.contentcapture.ContentCaptureEvent.TYPE_VIEW_TREE_APPEARED; 27 import static android.view.contentcapture.ContentCaptureEvent.TYPE_VIEW_TREE_APPEARING; 28 29 import static com.google.common.truth.Truth.assertThat; 30 import static com.google.common.truth.Truth.assertWithMessage; 31 32 import android.content.ComponentName; 33 import android.content.LocusId; 34 import android.contentcaptureservice.cts.CtsContentCaptureService.Session; 35 import android.util.Log; 36 import android.view.Display; 37 import android.view.View; 38 import android.view.autofill.AutofillId; 39 import android.view.contentcapture.ContentCaptureEvent; 40 import android.view.contentcapture.ContentCaptureSession; 41 import android.view.contentcapture.ContentCaptureSessionId; 42 import android.view.contentcapture.ViewNode; 43 44 import androidx.annotation.NonNull; 45 import androidx.annotation.Nullable; 46 47 import java.util.List; 48 49 /** 50 * Helper for common assertions. 51 */ 52 final class Assertions { 53 54 /** 55 * Asserts a session belongs to the right activity. 56 */ assertRightActivity(@onNull Session session, @NonNull ContentCaptureSessionId expectedSessionId, @NonNull AbstractContentCaptureActivity activity)57 public static void assertRightActivity(@NonNull Session session, 58 @NonNull ContentCaptureSessionId expectedSessionId, 59 @NonNull AbstractContentCaptureActivity activity) { 60 assertRightActivity(session, expectedSessionId, activity.getComponentName()); 61 } 62 63 /** 64 * Asserts a session belongs to the right activity. 65 */ assertRightActivity(@onNull Session session, @NonNull ContentCaptureSessionId expectedSessionId, @NonNull ComponentName componentName)66 public static void assertRightActivity(@NonNull Session session, 67 @NonNull ContentCaptureSessionId expectedSessionId, 68 @NonNull ComponentName componentName) { 69 assertWithMessage("wrong activity for %s", session) 70 .that(session.context.getActivityComponent()).isEqualTo(componentName); 71 // TODO(b/123540602): merge both or replace check above by: 72 // assertMainSessionContext(session, activity); 73 assertThat(session.id).isEqualTo(expectedSessionId); 74 } 75 76 /** 77 * Asserts the context of a main session. 78 */ assertMainSessionContext(@onNull Session session, @NonNull AbstractContentCaptureActivity activity)79 public static void assertMainSessionContext(@NonNull Session session, 80 @NonNull AbstractContentCaptureActivity activity) { 81 assertMainSessionContext(session, activity, /* expectedFlags= */ 0); 82 } 83 84 /** 85 * Asserts the context of a main session. 86 */ assertMainSessionContext(@onNull Session session, @NonNull AbstractContentCaptureActivity activity, int expectedFlags)87 public static void assertMainSessionContext(@NonNull Session session, 88 @NonNull AbstractContentCaptureActivity activity, int expectedFlags) { 89 assertWithMessage("no context on %s", session).that(session.context).isNotNull(); 90 assertWithMessage("wrong activity for %s", session) 91 .that(session.context.getActivityComponent()) 92 .isEqualTo(activity.getComponentName()); 93 assertWithMessage("context for session %s should have displayId", session) 94 .that(session.context.getDisplayId()).isNotEqualTo(Display.INVALID_DISPLAY); 95 assertWithMessage("wrong task id for session %s", session) 96 .that(session.context.getTaskId()).isEqualTo(activity.getRealTaskId()); 97 assertWithMessage("wrong flags on context for session %s", session) 98 .that(session.context.getFlags()).isEqualTo(expectedFlags); 99 assertWithMessage("context for session %s should not have ID", session) 100 .that(session.context.getLocusId()).isNull(); 101 assertWithMessage("context for session %s should not have extras", session) 102 .that(session.context.getExtras()).isNull(); 103 } 104 105 /** 106 * Asserts the invariants of a child session. 107 */ assertChildSessionContext(@onNull Session session)108 public static void assertChildSessionContext(@NonNull Session session) { 109 assertWithMessage("no context on %s", session).that(session.context).isNotNull(); 110 assertWithMessage("context for session %s should not have component", session) 111 .that(session.context.getActivityComponent()).isNull(); 112 assertWithMessage("context for session %s should not have displayId", session) 113 .that(session.context.getDisplayId()).isEqualTo(Display.INVALID_DISPLAY); 114 assertWithMessage("context for session %s should not have taskId", session) 115 .that(session.context.getTaskId()).isEqualTo(0); 116 assertWithMessage("context for session %s should not have flags", session) 117 .that(session.context.getFlags()).isEqualTo(0); 118 } 119 120 /** 121 * Asserts the invariants of a child session. 122 */ assertChildSessionContext(@onNull Session session, @NonNull String expectedId)123 public static void assertChildSessionContext(@NonNull Session session, 124 @NonNull String expectedId) { 125 assertChildSessionContext(session); 126 assertThat(session.context.getLocusId()).isEqualTo(new LocusId(expectedId)); 127 } 128 129 /** 130 * Asserts a session belongs to the right parent 131 */ assertRightRelationship(@onNull Session parent, @NonNull Session child)132 public static void assertRightRelationship(@NonNull Session parent, @NonNull Session child) { 133 final ContentCaptureSessionId expectedParentId = parent.id; 134 assertWithMessage("No id on parent session %s", parent).that(expectedParentId).isNotNull(); 135 assertWithMessage("No context on child session %s", child).that(child.context).isNotNull(); 136 final ContentCaptureSessionId actualParentId = child.context.getParentSessionId(); 137 assertWithMessage("No parent id on context %s of child session %s", child.context, child) 138 .that(actualParentId).isNotNull(); 139 assertWithMessage("id of parent session doesn't match child").that(actualParentId) 140 .isEqualTo(expectedParentId); 141 } 142 143 /** 144 * Asserts the contents of a {@link #TYPE_VIEW_APPEARED} event, without checking for parent id. 145 */ assertViewWithUnknownParentAppeared( @onNull List<ContentCaptureEvent> events, int index, @NonNull View expectedView)146 public static ViewNode assertViewWithUnknownParentAppeared( 147 @NonNull List<ContentCaptureEvent> events, int index, @NonNull View expectedView) { 148 return assertViewWithUnknownParentAppeared(events, index, expectedView, 149 /* expectedText= */ null); 150 } 151 152 /** 153 * Asserts the contents of a {@link #TYPE_VIEW_APPEARED} event for a decor view. 154 * 155 * <P>The decor view is typically internal, so there isn't much we can assert, other than its 156 * autofill id. 157 */ assertDecorViewAppeared(@onNull List<ContentCaptureEvent> events, int index, @NonNull View expectedDecorView)158 public static void assertDecorViewAppeared(@NonNull List<ContentCaptureEvent> events, 159 int index, @NonNull View expectedDecorView) { 160 final ContentCaptureEvent event = assertViewAppeared(events, index); 161 assertWithMessage("wrong autofill id on %s (%s)", event, index) 162 .that(event.getViewNode().getAutofillId()) 163 .isEqualTo(expectedDecorView.getAutofillId()); 164 } 165 166 /** 167 * Asserts the contents of a {@link #TYPE_VIEW_APPEARED} event, without checking for parent id. 168 */ assertViewWithUnknownParentAppeared( @onNull List<ContentCaptureEvent> events, int index, @NonNull View expectedView, @Nullable String expectedText)169 public static ViewNode assertViewWithUnknownParentAppeared( 170 @NonNull List<ContentCaptureEvent> events, int index, @NonNull View expectedView, 171 @Nullable String expectedText) { 172 final ContentCaptureEvent event = assertViewAppeared(events, index); 173 final ViewNode node = event.getViewNode(); 174 175 assertWithMessage("wrong class on %s (%s)", event, index).that(node.getClassName()) 176 .isEqualTo(expectedView.getClass().getName()); 177 assertWithMessage("wrong autofill id on %s (%s)", event, index).that(node.getAutofillId()) 178 .isEqualTo(expectedView.getAutofillId()); 179 180 if (expectedText != null) { 181 assertWithMessage("wrong text on %s (%s)", event, index).that(node.getText().toString()) 182 .isEqualTo(expectedText); 183 } 184 // TODO(b/123540602): test more fields, like resource id 185 return node; 186 } 187 188 /** 189 * Asserts the contents of a {@link #TYPE_VIEW_APPEARED} event, without checking for parent id. 190 */ assertViewAppeared(@onNull List<ContentCaptureEvent> events, int index)191 public static ContentCaptureEvent assertViewAppeared(@NonNull List<ContentCaptureEvent> events, 192 int index) { 193 final ContentCaptureEvent event = getEvent(events, index, TYPE_VIEW_APPEARED); 194 final ViewNode node = event.getViewNode(); 195 assertThat(node).isNotNull(); 196 return event; 197 } 198 199 /** 200 * Asserts the contents of a {@link #TYPE_VIEW_APPEARED} event. 201 */ assertViewAppeared(@onNull List<ContentCaptureEvent> events, int index, @NonNull View expectedView, @Nullable AutofillId expectedParentId, @Nullable String expectedText)202 public static void assertViewAppeared(@NonNull List<ContentCaptureEvent> events, int index, 203 @NonNull View expectedView, @Nullable AutofillId expectedParentId, 204 @Nullable String expectedText) { 205 final ViewNode node = assertViewWithUnknownParentAppeared(events, index, expectedView, 206 expectedText); 207 assertWithMessage("wrong parent autofill id on %s (%s)", events.get(index), index) 208 .that(node.getParentAutofillId()).isEqualTo(expectedParentId); 209 } 210 211 /** 212 * Asserts the contents of a {@link #TYPE_VIEW_APPEARED} event. 213 */ assertViewAppeared(@onNull List<ContentCaptureEvent> events, int index, @NonNull View expectedView, @Nullable AutofillId expectedParentId)214 public static void assertViewAppeared(@NonNull List<ContentCaptureEvent> events, int index, 215 @NonNull View expectedView, @Nullable AutofillId expectedParentId) { 216 assertViewAppeared(events, index, expectedView, expectedParentId, /* expectedText= */ null); 217 } 218 219 /** 220 * Asserts the contents of a {@link #TYPE_VIEW_APPEARED} event. 221 */ assertViewAppeared(@onNull List<ContentCaptureEvent> events, int index, @NonNull ContentCaptureSessionId expectedSessionId, @NonNull View expectedView, @Nullable AutofillId expectedParentId)222 public static void assertViewAppeared(@NonNull List<ContentCaptureEvent> events, int index, 223 @NonNull ContentCaptureSessionId expectedSessionId, 224 @NonNull View expectedView, @Nullable AutofillId expectedParentId) { 225 assertViewAppeared(events, index, expectedView, expectedParentId); 226 assertSessionId(expectedSessionId, expectedView); 227 } 228 229 /** 230 * Asserts the contents of a {@link #TYPE_VIEW_TREE_APPEARING} event. 231 */ assertViewTreeStarted(@onNull List<ContentCaptureEvent> events, int index)232 public static void assertViewTreeStarted(@NonNull List<ContentCaptureEvent> events, 233 int index) { 234 assertSessionLevelEvent(events, index, TYPE_VIEW_TREE_APPEARING); 235 } 236 237 /** 238 * Asserts the contents of a {@link #TYPE_VIEW_TREE_APPEARED} event. 239 */ assertViewTreeFinished(@onNull List<ContentCaptureEvent> events, int index)240 public static void assertViewTreeFinished(@NonNull List<ContentCaptureEvent> events, 241 int index) { 242 assertSessionLevelEvent(events, index, TYPE_VIEW_TREE_APPEARED); 243 } 244 assertSessionLevelEvent(@onNull List<ContentCaptureEvent> events, int index, int expectedType)245 private static void assertSessionLevelEvent(@NonNull List<ContentCaptureEvent> events, 246 int index, int expectedType) { 247 final ContentCaptureEvent event = getEvent(events, index, expectedType); 248 assertWithMessage("event %s (index %s) should not have a ViewNode", event, index) 249 .that(event.getViewNode()).isNull(); 250 assertWithMessage("event %s (index %s) should not have text", event, index) 251 .that(event.getViewNode()).isNull(); 252 assertWithMessage("event %s (index %s) should not have an autofillId", event, index) 253 .that(event.getId()).isNull(); 254 assertWithMessage("event %s (index %s) should not have autofillIds", event, index) 255 .that(event.getIds()).isNull(); 256 } 257 258 /** 259 * Asserts the contents of a {@link #TYPE_SESSION_RESUMED} event. 260 */ assertSessionResumed(@onNull List<ContentCaptureEvent> events, int index)261 public static void assertSessionResumed(@NonNull List<ContentCaptureEvent> events, 262 int index) { 263 assertSessionLevelEvent(events, index, TYPE_SESSION_RESUMED); 264 } 265 266 /** 267 * Asserts the contents of a {@link #TYPE_SESSION_PAUSED} event. 268 */ assertSessionPaused(@onNull List<ContentCaptureEvent> events, int index)269 public static void assertSessionPaused(@NonNull List<ContentCaptureEvent> events, 270 int index) { 271 assertSessionLevelEvent(events, index, TYPE_SESSION_PAUSED); 272 } 273 274 /** 275 * Asserts that a session for the given activity has no view-level events, just 276 * {@link #TYPE_SESSION_RESUMED} and {@link #TYPE_SESSION_PAUSED}. 277 */ assertNoViewLevelEvents(@onNull Session session, @NonNull AbstractContentCaptureActivity activity)278 public static void assertNoViewLevelEvents(@NonNull Session session, 279 @NonNull AbstractContentCaptureActivity activity) { 280 assertRightActivity(session, session.id, activity); 281 final List<ContentCaptureEvent> events = session.getEvents(); 282 Log.v(TAG, "events on " + activity + ": " + events); 283 assertThat(events).hasSize(2); 284 assertSessionResumed(events, 0); 285 assertSessionPaused(events, 1); 286 } 287 288 /** 289 * Asserts that a session for the given activity has events at all. 290 */ assertNoEvents(@onNull Session session, @NonNull ComponentName componentName)291 public static void assertNoEvents(@NonNull Session session, 292 @NonNull ComponentName componentName) { 293 assertRightActivity(session, session.id, componentName); 294 assertThat(session.getEvents()).isEmpty(); 295 } 296 297 /** 298 * Asserts that the events received by the service optionally contains the 299 * {@code TYPE_VIEW_DISAPPEARED} events, as they might have not been generated if the views 300 * disappeared after the activity stopped. 301 * 302 * @param events events received by the service. 303 * @param minimumSize size of events received if activity stopped before views disappeared 304 * @param expectedIds ids of views that might have disappeared. 305 * 306 * @return whether the view disappeared events were generated 307 */ 308 // TODO(b/123540067, 122315042): remove this method if we could make it deterministic, and 309 // inline the assertions (or rename / change its logic) assertViewsOptionallyDisappeared( @onNull List<ContentCaptureEvent> events, int minimumSize, @NonNull AutofillId... expectedIds)310 public static boolean assertViewsOptionallyDisappeared( 311 @NonNull List<ContentCaptureEvent> events, int minimumSize, 312 @NonNull AutofillId... expectedIds) { 313 final int actualSize = events.size(); 314 if (actualSize == minimumSize) { 315 // Activity stopped before TYPE_VIEW_DISAPPEARED were sent. 316 return false; 317 } 318 assertThat(events).hasSize(minimumSize + 1); 319 final ContentCaptureEvent batchDisappearEvent = events.get(minimumSize); 320 321 if (expectedIds.length == 1) { 322 assertWithMessage("Should have just one deleted id on %s", batchDisappearEvent) 323 .that(batchDisappearEvent.getIds()).isNull(); 324 assertWithMessage("wrong deleted id on %s", batchDisappearEvent) 325 .that(batchDisappearEvent.getId()).isEqualTo(expectedIds[0]); 326 } else { 327 assertWithMessage("Should not have individual deleted id on %s", batchDisappearEvent) 328 .that(batchDisappearEvent.getId()).isNull(); 329 final List<AutofillId> actualIds = batchDisappearEvent.getIds(); 330 assertWithMessage("wrong deleteds id on %s", batchDisappearEvent) 331 .that(actualIds).containsExactly((Object[]) expectedIds); 332 } 333 return true; 334 } 335 336 /** 337 * Asserts the contents of a {@link #TYPE_VIEW_APPEARED} event, without checking for parent 338 */ assertViewWithUnknownParentAppeared( @onNull List<ContentCaptureEvent> events, int index, @NonNull ContentCaptureSessionId expectedSessionId, @NonNull View expectedView)339 public static void assertViewWithUnknownParentAppeared( 340 @NonNull List<ContentCaptureEvent> events, int index, 341 @NonNull ContentCaptureSessionId expectedSessionId, @NonNull View expectedView) { 342 assertViewWithUnknownParentAppeared(events, index, expectedView); 343 assertSessionId(expectedSessionId, expectedView); 344 } 345 346 /** 347 * Asserts the contents of a {@link #TYPE_VIEW_DISAPPEARED} event for a single view. 348 */ assertViewDisappeared(@onNull List<ContentCaptureEvent> events, int index, @NonNull AutofillId expectedId)349 public static void assertViewDisappeared(@NonNull List<ContentCaptureEvent> events, int index, 350 @NonNull AutofillId expectedId) { 351 final ContentCaptureEvent event = assertCommonViewDisappearedProperties(events, index); 352 assertWithMessage("wrong autofillId on event %s (index %s)", event, index) 353 .that(event.getId()).isEqualTo(expectedId); 354 assertWithMessage("event %s (index %s) should not have autofillIds", event, index) 355 .that(event.getIds()).isNull(); 356 } 357 358 /** 359 * Asserts the contents of a {@link #TYPE_VIEW_DISAPPEARED} event for multiple views. 360 */ assertViewsDisappeared(@onNull List<ContentCaptureEvent> events, int index, @NonNull AutofillId... expectedIds)361 public static void assertViewsDisappeared(@NonNull List<ContentCaptureEvent> events, int index, 362 @NonNull AutofillId... expectedIds) { 363 final ContentCaptureEvent event = assertCommonViewDisappearedProperties(events, index); 364 final List<AutofillId> ids = event.getIds(); 365 assertWithMessage("no autofillIds on event %s (index %s)", event, index).that(ids) 366 .isNotNull(); 367 assertWithMessage("wrong autofillId on event %s (index %s)", event, index) 368 .that(ids).containsExactly((Object[]) expectedIds).inOrder(); 369 assertWithMessage("event %s (index %s) should not have autofillId", event, index) 370 .that(event.getId()).isNull(); 371 } 372 assertCommonViewDisappearedProperties( @onNull List<ContentCaptureEvent> events, int index)373 private static ContentCaptureEvent assertCommonViewDisappearedProperties( 374 @NonNull List<ContentCaptureEvent> events, int index) { 375 final ContentCaptureEvent event = getEvent(events, index, TYPE_VIEW_DISAPPEARED); 376 assertWithMessage("event %s (index %s) should not have a ViewNode", event, index) 377 .that(event.getViewNode()).isNull(); 378 assertWithMessage("event %s (index %s) should not have text", event, index) 379 .that(event.getText()).isNull(); 380 return event; 381 } 382 383 /** 384 * Asserts the contents of a {@link #TYPE_VIEW_APPEARED} event for a virtual node. 385 */ assertVirtualViewAppeared(@onNull List<ContentCaptureEvent> events, int index, @NonNull ContentCaptureSession session, @NonNull AutofillId parentId, int childId, @Nullable String expectedText)386 public static void assertVirtualViewAppeared(@NonNull List<ContentCaptureEvent> events, 387 int index, @NonNull ContentCaptureSession session, @NonNull AutofillId parentId, 388 int childId, @Nullable String expectedText) { 389 final ContentCaptureEvent event = getEvent(events, index, TYPE_VIEW_APPEARED); 390 final ViewNode node = event.getViewNode(); 391 assertThat(node).isNotNull(); 392 final AutofillId expectedId = session.newAutofillId(parentId, childId); 393 assertWithMessage("wrong autofill id on %s (index %s)", event, index) 394 .that(node.getAutofillId()).isEqualTo(expectedId); 395 if (expectedText != null) { 396 assertWithMessage("wrong text on %s(index %s) ", event, index) 397 .that(node.getText().toString()).isEqualTo(expectedText); 398 } else { 399 assertWithMessage("%s (index %s) should not have text", node, index) 400 .that(node.getText()).isNull(); 401 } 402 } 403 404 /** 405 * Asserts the contents of a {@link #TYPE_VIEW_DISAPPEARED} event for a virtual node. 406 */ assertVirtualViewDisappeared(@onNull List<ContentCaptureEvent> events, int index, @NonNull AutofillId parentId, @NonNull ContentCaptureSession session, long childId)407 public static void assertVirtualViewDisappeared(@NonNull List<ContentCaptureEvent> events, 408 int index, @NonNull AutofillId parentId, @NonNull ContentCaptureSession session, 409 long childId) { 410 assertViewDisappeared(events, index, session.newAutofillId(parentId, childId)); 411 } 412 413 /** 414 * Asserts the contents of a {@link #TYPE_VIEW_DISAPPEARED} event for many virtual nodes. 415 */ assertVirtualViewsDisappeared(@onNull List<ContentCaptureEvent> events, int index, @NonNull AutofillId parentId, @NonNull ContentCaptureSession session, long... childrenIds)416 public static void assertVirtualViewsDisappeared(@NonNull List<ContentCaptureEvent> events, 417 int index, @NonNull AutofillId parentId, @NonNull ContentCaptureSession session, 418 long... childrenIds) { 419 final int size = childrenIds.length; 420 final AutofillId[] expectedIds = new AutofillId[size]; 421 for (int i = 0; i < childrenIds.length; i++) { 422 expectedIds[i] = session.newAutofillId(parentId, childrenIds[i]); 423 } 424 assertViewsDisappeared(events, index, expectedIds); 425 } 426 427 /** 428 * Asserts a view has the given session id. 429 */ assertSessionId(@onNull ContentCaptureSessionId expectedSessionId, @NonNull View view)430 public static void assertSessionId(@NonNull ContentCaptureSessionId expectedSessionId, 431 @NonNull View view) { 432 assertThat(expectedSessionId).isNotNull(); 433 final ContentCaptureSession session = view.getContentCaptureSession(); 434 assertWithMessage("no session for view %s", view).that(session).isNotNull(); 435 assertWithMessage("wrong session id for for view %s", view) 436 .that(session.getContentCaptureSessionId()).isEqualTo(expectedSessionId); 437 } 438 439 /** 440 * Asserts the contents of a {@link #TYPE_VIEW_TEXT_CHANGED} event. 441 */ assertViewTextChanged(@onNull List<ContentCaptureEvent> events, int index, @NonNull AutofillId expectedId, @NonNull String expectedText)442 public static void assertViewTextChanged(@NonNull List<ContentCaptureEvent> events, int index, 443 @NonNull AutofillId expectedId, @NonNull String expectedText) { 444 final ContentCaptureEvent event = getEvent(events, index, TYPE_VIEW_TEXT_CHANGED); 445 assertWithMessage("Wrong id on %s (%s)", event, index).that(event.getId()) 446 .isEqualTo(expectedId); 447 assertWithMessage("Wrong text on %s (%s)", event, index).that(event.getText().toString()) 448 .isEqualTo(expectedText); 449 } 450 451 /** 452 * Asserts the basic contents of a {@link #TYPE_CONTEXT_UPDATED} event. 453 */ assertContextUpdated( @onNull List<ContentCaptureEvent> events, int index)454 public static ContentCaptureEvent assertContextUpdated( 455 @NonNull List<ContentCaptureEvent> events, int index) { 456 final ContentCaptureEvent event = getEvent(events, index, TYPE_CONTEXT_UPDATED); 457 assertWithMessage("event %s (index %s) should not have a ViewNode", event, index) 458 .that(event.getViewNode()).isNull(); 459 assertWithMessage("event %s (index %s) should not have text", event, index) 460 .that(event.getViewNode()).isNull(); 461 assertWithMessage("event %s (index %s) should not have an autofillId", event, index) 462 .that(event.getId()).isNull(); 463 assertWithMessage("event %s (index %s) should not have autofillIds", event, index) 464 .that(event.getIds()).isNull(); 465 return event; 466 } 467 468 /** 469 * Asserts the order a session was created or destroyed. 470 */ assertLifecycleOrder(int expectedOrder, @NonNull Session session, @NonNull LifecycleOrder type)471 public static void assertLifecycleOrder(int expectedOrder, @NonNull Session session, 472 @NonNull LifecycleOrder type) { 473 switch(type) { 474 case CREATION: 475 assertWithMessage("Wrong order of creation for session %s", session) 476 .that(session.creationOrder).isEqualTo(expectedOrder); 477 break; 478 case DESTRUCTION: 479 assertWithMessage("Wrong order of destruction for session %s", session) 480 .that(session.destructionOrder).isEqualTo(expectedOrder); 481 break; 482 default: 483 throw new IllegalArgumentException("Invalid type: " + type); 484 } 485 } 486 487 /** 488 * Gets the event at the given index, failing with the user-friendly message if necessary... 489 */ 490 @NonNull getEvent(@onNull List<ContentCaptureEvent> events, int index, int expectedType)491 private static ContentCaptureEvent getEvent(@NonNull List<ContentCaptureEvent> events, 492 int index, int expectedType) { 493 assertWithMessage("events is null").that(events).isNotNull(); 494 final ContentCaptureEvent event = events.get(index); 495 assertWithMessage("no event at index %s (size %s): %s", index, events.size(), events) 496 .that(event).isNotNull(); 497 final int actualType = event.getType(); 498 if (actualType != expectedType) { 499 throw new AssertionError(String.format( 500 "wrong event type (expected %s, actual is %s) at index %s: %s", 501 eventTypeAsString(expectedType), eventTypeAsString(actualType), index, event)); 502 } 503 assertWithMessage("invalid time on %s (index %s)", event, index).that(event.getEventTime()) 504 .isAtLeast(MY_EPOCH); 505 return event; 506 } 507 508 /** 509 * Gets an user-friendly description of the given event type. 510 */ 511 @NonNull eventTypeAsString(int type)512 public static String eventTypeAsString(int type) { 513 final String string; 514 switch (type) { 515 case TYPE_VIEW_APPEARED: 516 string = "APPEAR"; 517 break; 518 case TYPE_VIEW_DISAPPEARED: 519 string = "DISAPPEAR"; 520 break; 521 case TYPE_VIEW_TEXT_CHANGED: 522 string = "TEXT_CHANGE"; 523 break; 524 case TYPE_VIEW_TREE_APPEARING: 525 string = "TREE_START"; 526 break; 527 case TYPE_VIEW_TREE_APPEARED: 528 string = "TREE_END"; 529 break; 530 case TYPE_SESSION_PAUSED: 531 string = "PAUSED"; 532 break; 533 case TYPE_SESSION_RESUMED: 534 string = "RESUMED"; 535 break; 536 default: 537 return "UNKNOWN-" + type; 538 } 539 return String.format("%s-%d", string, type); 540 } 541 Assertions()542 private Assertions() { 543 throw new UnsupportedOperationException("contain static methods only"); 544 } 545 546 public enum LifecycleOrder { 547 CREATION, DESTRUCTION 548 } 549 } 550