• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2022 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 android.mediapc.cts.common;
18 
19 import com.android.compatibility.common.util.ReportLog;
20 import com.android.compatibility.common.util.ResultType;
21 import com.android.compatibility.common.util.ResultUnit;
22 
23 import com.google.auto.value.AutoValue;
24 import com.google.common.collect.ImmutableMap;
25 
26 import java.util.HashMap;
27 import java.util.Map;
28 import java.util.function.BiPredicate;
29 
30 /**
31  * A specific measurement for a Performance Class requirement.
32  */
33 @AutoValue
34 public abstract class RequiredMeasurement<T> {
35     private static final String TAG = RequiredMeasurement.class.getSimpleName();
36 
37     private T measuredValue;  // Note this is not part of the equals calculations
38     private boolean measuredValueSet = false;
39 
builder()40     public static <T> Builder<T> builder() {
41         return new AutoValue_RequiredMeasurement.Builder<T>();
42     }
43 
id()44     public abstract String id();
45 
46     /**
47      * Tests if the measured value satisfies the  expected value(eg >=)
48      * measuredValue, expectedValue
49      */
predicate()50     public abstract BiPredicate<T, T> predicate();
51 
52     /**
53      * Maps MPC level to the expected value.
54      */
expectedValues()55     public abstract ImmutableMap<Integer, T> expectedValues();
56 
setMeasuredValue(T measuredValue)57     public void setMeasuredValue(T measuredValue) {
58         this.measuredValueSet = true;
59         this.measuredValue = measuredValue;
60     }
61 
getMeasuredValue()62     T getMeasuredValue() {
63         if (!measuredValueSet) {
64             throw new IllegalStateException(
65                     "tried to get measured value before it was set for measurement " + id());
66         }
67         return measuredValue;
68     }
69 
isMeasuredValueSet()70     boolean isMeasuredValueSet() {
71         return measuredValueSet;
72     }
73 
74     @AutoValue.Builder
75     public static abstract class Builder<T> {
76 
setId(String id)77         public abstract Builder<T> setId(String id);
78 
setPredicate(BiPredicate<T, T> predicate)79         public abstract Builder<T> setPredicate(BiPredicate<T, T> predicate);
80 
expectedValuesBuilder()81         public abstract ImmutableMap.Builder<Integer, T> expectedValuesBuilder();
82 
addRequiredValue(Integer performanceClass, T expectedValue)83         public Builder<T> addRequiredValue(Integer performanceClass, T expectedValue) {
84             this.expectedValuesBuilder().put(performanceClass, expectedValue);
85             return this;
86         }
87 
build()88         public abstract RequiredMeasurement<T> build();
89     }
90 
91     /** Is this requirement measurement valid for the given performance class */
appliesToPerformanceClass(int mediaPerformanceClass)92     public final boolean appliesToPerformanceClass(int mediaPerformanceClass) {
93         return expectedValues().containsKey(mediaPerformanceClass);
94     }
95 
meetsPerformanceClass(int mediaPerformanceClass)96     public final RequirementConstants.Result meetsPerformanceClass(int mediaPerformanceClass)
97             throws IllegalStateException {
98 
99         if (expectedValues().isEmpty()) {
100             return RequirementConstants.Result.NA;
101         } else if (!this.measuredValueSet) {
102             throw new IllegalStateException("measured value not set for required measurement "
103                 + this.id());
104         }
105 
106         if (!this.expectedValues().containsKey(mediaPerformanceClass)) {
107             return RequirementConstants.Result.NA;
108         } else if (this.measuredValue == null || !this.predicate().test(this.measuredValue,
109                 this.expectedValues().get(mediaPerformanceClass))) {
110             return RequirementConstants.Result.UNMET;
111         } else {
112             return RequirementConstants.Result.MET;
113         }
114     }
115 
116     /**
117      * @return map PerfomenaceClass to result if that performance class has been met
118      */
getPerformanceClass()119     public Map<Integer, RequirementConstants.Result> getPerformanceClass() {
120         Map<Integer, RequirementConstants.Result> perfClassResults = new HashMap<>();
121         for (Integer pc: this.expectedValues().keySet()) {
122             perfClassResults.put(pc, this.meetsPerformanceClass(pc));
123         }
124         return perfClassResults;
125     }
126 
127     @Override
toString()128     public final String toString() {
129         return "Required Measurement with:"
130             + "\n\tId: " + this.id()
131             + "\n\tPredicate: " + this.predicate()
132             + "\n\tMeasured Value: " + this.measuredValue
133             + "\n\tExpected Values: " + this.expectedValues();
134     }
135 
writeValue(ReportLog log)136     public void writeValue(ReportLog log) throws IllegalStateException {
137 
138         if (expectedValues().isEmpty()) {
139             // Some requirements include extra measurements when testing at a higher performance
140             // class. For these measurements, when testing at lower performance classes, the
141             // generated code may produce a correspoding RequiredMeasurement with an empty expected
142             // value map. If so, the measurement should just be ignored.
143             return;
144         } else if (!this.measuredValueSet) {
145             throw new IllegalStateException("measured value not set for required measurement:\n"
146                 + this);
147         }
148 
149         if (this.measuredValue == null) {
150             log.addValue(this.id(), "<nullptr>", ResultType.NEUTRAL, ResultUnit.NONE);
151         } else if (this.measuredValue instanceof Integer) {
152             log.addValue(this.id(), (int)this.measuredValue, ResultType.NEUTRAL, ResultUnit.NONE);
153         } else if (this.measuredValue instanceof Long) {
154             log.addValue(this.id(), (long)this.measuredValue, ResultType.NEUTRAL, ResultUnit.NONE);
155         } else if (this.measuredValue instanceof Float) {
156             log.addValue(this.id(), (float)this.measuredValue, ResultType.NEUTRAL, ResultUnit.NONE);
157         } else if (this.measuredValue instanceof Double) {
158             log.addValue(this.id(), (double)this.measuredValue, ResultType.NEUTRAL,
159                 ResultUnit.NONE);
160         } else if (this.measuredValue instanceof Boolean) {
161             log.addValue(this.id(), (boolean)this.measuredValue, ResultType.NEUTRAL,
162                 ResultUnit.NONE);
163         } else if (this.measuredValue instanceof String) {
164             log.addValue(this.id(), (String)this.measuredValue, ResultType.NEUTRAL,
165                 ResultUnit.NONE);
166         } else {
167             // reporting all other types as Strings using toString()
168             log.addValue(this.id(), this.measuredValue.toString(), ResultType.NEUTRAL,
169                 ResultUnit.NONE);
170         }
171     }
172 
173 }
174