• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2023 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 package org.chromium.base.test.transit;
6 
7 import org.chromium.base.ThreadUtils;
8 
9 import java.util.ArrayList;
10 import java.util.List;
11 
12 /** Spot checks multiple {@link Condition}s to assert preconditions are still valid. */
13 public class ConditionChecker {
14 
15     /** The fulfillment status of a {@link Condition} being checked once. */
16     private static class ConditionCheckStatus {
17 
18         private final Condition mCondition;
19         private boolean mFulfilled;
20         private String mError;
21 
ConditionCheckStatus(Condition condition)22         private ConditionCheckStatus(Condition condition) {
23             mCondition = condition;
24         }
25 
update()26         private boolean update() {
27             try {
28                 boolean fulfilled;
29                 if (mCondition.isRunOnUiThread()) {
30                     // TODO(crbug.com/1489445): Post multiple checks in parallel, the UI thread will
31                     // run them sequentially.
32                     fulfilled = ThreadUtils.runOnUiThreadBlocking(mCondition::check);
33                 } else {
34                     fulfilled = mCondition.check();
35                 }
36 
37                 if (fulfilled) {
38                     reportFulfilled();
39                     return false;
40                 } else {
41                     reportUnfulfilled();
42                     return true;
43                 }
44             } catch (Exception e) {
45                 reportError(e);
46                 return true;
47             }
48         }
49 
reportFulfilled()50         private void reportFulfilled() {
51             mFulfilled = true;
52         }
53 
reportUnfulfilled()54         private void reportUnfulfilled() {
55             mFulfilled = false;
56         }
57 
reportError(Exception e)58         private void reportError(Exception e) {
59             mError = e.getMessage();
60         }
61 
isFulfilled()62         private boolean isFulfilled() {
63             return mFulfilled;
64         }
65 
getError()66         private String getError() {
67             return mError;
68         }
69     }
70 
71     /**
72      * Spot checks each of the {@link Condition}s.
73      *
74      * @param conditions the {@link Condition}s to check.
75      * @throws AssertionError if not all Conditions are fulfilled.
76      */
check(List<Condition> conditions)77     public static void check(List<Condition> conditions) {
78         boolean anyCriteriaMissing = false;
79         List<ConditionCheckStatus> checkStatuses = new ArrayList<>();
80         for (Condition condition : conditions) {
81             checkStatuses.add(new ConditionCheckStatus(condition));
82         }
83 
84         for (ConditionCheckStatus status : checkStatuses) {
85             anyCriteriaMissing |= status.update();
86         }
87 
88         if (anyCriteriaMissing) {
89             throw buildCheckConditionsException(checkStatuses);
90         }
91     }
92 
buildCheckConditionsException( List<ConditionCheckStatus> checkStatuses)93     private static AssertionError buildCheckConditionsException(
94             List<ConditionCheckStatus> checkStatuses) {
95         return new AssertionError(
96                 "Preconditions not fulfilled:\n" + createCheckConditionsSummary(checkStatuses));
97     }
98 
createCheckConditionsSummary(List<ConditionCheckStatus> checkStatuses)99     private static String createCheckConditionsSummary(List<ConditionCheckStatus> checkStatuses) {
100         StringBuilder detailsString = new StringBuilder();
101 
102         int i = 1;
103         for (ConditionCheckStatus checkStatus : checkStatuses) {
104             String conditionDescription = checkStatus.mCondition.getDescription();
105 
106             String error = checkStatus.getError();
107             String errorsString = null;
108             String statusString;
109             if (error != null) {
110                 errorsString = String.format(" {error: %s}", error);
111                 statusString = "[ERR ]";
112             } else {
113                 if (checkStatus.isFulfilled()) {
114                     statusString = "[OK  ]";
115                 } else {
116                     statusString = "[FAIL]";
117                 }
118             }
119 
120             detailsString
121                     .append("    [")
122                     .append(i)
123                     .append(" ")
124                     .append(statusString)
125                     .append(" ")
126                     .append(conditionDescription);
127             if (errorsString != null) {
128                 detailsString.append(" ").append(errorsString);
129             }
130             detailsString.append('\n');
131             i++;
132         }
133         return detailsString.toString();
134     }
135 }
136