123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180 |
- /*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- package com.android.launcher3.tapl;
- import android.os.SystemClock;
- import com.android.launcher3.testing.TestProtocol;
- import java.util.ArrayList;
- import java.util.HashMap;
- import java.util.List;
- import java.util.Map;
- import java.util.regex.Pattern;
- /**
- * Utility class to verify expected events.
- */
- public class LogEventChecker {
- private final LauncherInstrumentation mLauncher;
- // Map from an event sequence name to an ordered list of expected events in that sequence.
- private final ListMap<Pattern> mExpectedEvents = new ListMap<>();
- LogEventChecker(LauncherInstrumentation launcher) {
- mLauncher = launcher;
- }
- boolean start() {
- mExpectedEvents.clear();
- return mLauncher.getTestInfo(TestProtocol.REQUEST_START_EVENT_LOGGING) != null;
- }
- void expectPattern(String sequence, Pattern pattern) {
- mExpectedEvents.add(sequence, pattern);
- }
- // Waits for the expected number of events and returns them.
- private ListMap<String> finishSync(long waitForExpectedCountMs) {
- final long startTime = SystemClock.uptimeMillis();
- // Event strings with '/' separating the sequence and the event.
- ArrayList<String> rawEvents;
- while (true) {
- rawEvents = mLauncher.getTestInfo(TestProtocol.REQUEST_GET_TEST_EVENTS)
- .getStringArrayList(TestProtocol.TEST_INFO_RESPONSE_FIELD);
- final int expectedCount = mExpectedEvents.entrySet()
- .stream().mapToInt(e -> e.getValue().size()).sum();
- if (rawEvents.size() >= expectedCount
- || SystemClock.uptimeMillis() > startTime + waitForExpectedCountMs) {
- break;
- }
- SystemClock.sleep(100);
- }
- finishNoWait();
- // Parse raw events into a map.
- final ListMap<String> eventSequences = new ListMap<>();
- for (String rawEvent : rawEvents) {
- final String[] split = rawEvent.split("/");
- eventSequences.add(split[0], split[1]);
- }
- return eventSequences;
- }
- void finishNoWait() {
- mLauncher.getTestInfo(TestProtocol.REQUEST_STOP_EVENT_LOGGING);
- }
- String verify(long waitForExpectedCountMs, boolean successfulGesture) {
- final ListMap<String> actualEvents = finishSync(waitForExpectedCountMs);
- final StringBuilder sb = new StringBuilder();
- boolean hasMismatches = false;
- for (Map.Entry<String, List<Pattern>> expectedEvents : mExpectedEvents.entrySet()) {
- String sequence = expectedEvents.getKey();
- List<String> actual = new ArrayList<>(actualEvents.getNonNull(sequence));
- final int mismatchPosition = getMismatchPosition(expectedEvents.getValue(), actual);
- hasMismatches = hasMismatches
- || mismatchPosition != -1 && !ignoreMistatch(successfulGesture, sequence);
- formatSequenceWithMismatch(
- sb,
- sequence,
- expectedEvents.getValue(),
- actual,
- mismatchPosition);
- }
- // Check for unexpected event sequences in the actual data.
- for (String actualNamedSequence : actualEvents.keySet()) {
- if (!mExpectedEvents.containsKey(actualNamedSequence)) {
- hasMismatches = hasMismatches
- || !ignoreMistatch(successfulGesture, actualNamedSequence);
- formatSequenceWithMismatch(
- sb,
- actualNamedSequence,
- new ArrayList<>(),
- actualEvents.get(actualNamedSequence),
- 0);
- }
- }
- return hasMismatches ? "mismatching events: " + sb.toString() : null;
- }
- // Workaround for b/154157191
- private static boolean ignoreMistatch(boolean successfulGesture, String sequence) {
- // b/156287114
- return false;
- // return TestProtocol.SEQUENCE_TIS.equals(sequence) && successfulGesture;
- }
- // If the list of actual events matches the list of expected events, returns -1, otherwise
- // the position of the mismatch.
- private static int getMismatchPosition(List<Pattern> expected, List<String> actual) {
- for (int i = 0; i < expected.size(); ++i) {
- if (i >= actual.size()
- || !expected.get(i).matcher(actual.get(i)).find()) {
- return i;
- }
- }
- if (actual.size() > expected.size()) return expected.size();
- return -1;
- }
- private static void formatSequenceWithMismatch(
- StringBuilder sb,
- String sequenceName,
- List<Pattern> expected,
- List<String> actualEvents,
- int mismatchPosition) {
- sb.append("\n>> SEQUENCE " + sequenceName + " - "
- + (mismatchPosition == -1 ? "MATCH" : "MISMATCH"));
- sb.append("\n EXPECTED:");
- formatEventListWithMismatch(sb, expected, mismatchPosition);
- sb.append("\n ACTUAL:");
- formatEventListWithMismatch(sb, actualEvents, mismatchPosition);
- }
- private static void formatEventListWithMismatch(StringBuilder sb, List events, int position) {
- for (int i = 0; i < events.size(); ++i) {
- sb.append("\n | ");
- sb.append(i == position ? "---> " : " ");
- sb.append(events.get(i).toString());
- }
- if (position == events.size()) sb.append("\n | ---> (end)");
- }
- private static class ListMap<T> extends HashMap<String, List<T>> {
- void add(String key, T value) {
- getNonNull(key).add(value);
- }
- List<T> getNonNull(String key) {
- List<T> list = get(key);
- if (list == null) {
- list = new ArrayList<>();
- put(key, list);
- }
- return list;
- }
- }
- }
|