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 
62     @AutoValue.Builder
63     public static abstract class Builder<T> {
64 
setId(String id)65         public abstract Builder<T> setId(String id);
66 
setPredicate(BiPredicate<T, T> predicate)67         public abstract Builder<T> setPredicate(BiPredicate<T, T> predicate);
68 
expectedValuesBuilder()69         public abstract ImmutableMap.Builder<Integer, T> expectedValuesBuilder();
70 
addRequiredValue(Integer performanceClass, T expectedValue)71         public Builder<T> addRequiredValue(Integer performanceClass, T expectedValue) {
72             this.expectedValuesBuilder().put(performanceClass, expectedValue);
73             return this;
74         }
75 
build()76         public abstract RequiredMeasurement<T> build();
77     }
78 
meetsPerformanceClass(int mediaPerformanceClass)79     public final RequirementConstants.Result meetsPerformanceClass(int mediaPerformanceClass)
80             throws IllegalStateException {
81 
82         if (!this.measuredValueSet) {
83             throw new IllegalStateException("measured value not set for required measurement "
84                 + this.id());
85         }
86 
87         if (!this.expectedValues().containsKey(mediaPerformanceClass)) {
88             return RequirementConstants.Result.NA;
89         } else if (this.measuredValue == null || !this.predicate().test(this.measuredValue,
90                 this.expectedValues().get(mediaPerformanceClass))) {
91             return RequirementConstants.Result.UNMET;
92         } else {
93             return RequirementConstants.Result.MET;
94         }
95     }
96 
97     /**
98      * @return map PerfomenaceClass to result if that performance class has been met
99      */
getPerformanceClass()100     public Map<Integer, RequirementConstants.Result> getPerformanceClass() {
101         Map<Integer, RequirementConstants.Result> perfClassResults = new HashMap<>();
102         for (Integer pc: this.expectedValues().keySet()) {
103             perfClassResults.put(pc, this.meetsPerformanceClass(pc));
104         }
105         return perfClassResults;
106     }
107 
108     @Override
toString()109     public final String toString() {
110         return "Required Measurement with:"
111             + "\n\tId: " + this.id()
112             + "\n\tPredicate: " + this.predicate()
113             + "\n\tMeasured Value: " + this.measuredValue
114             + "\n\tExpected Values: " + this.expectedValues();
115     }
116 
writeValue(ReportLog log)117     public void writeValue(ReportLog log) throws IllegalStateException {
118 
119         if (!this.measuredValueSet) {
120             throw new IllegalStateException("measured value not set for required measurement "
121                 + this.id());
122         }
123 
124         if (this.measuredValue == null) {
125             log.addValue(this.id(), "<nullptr>", ResultType.NEUTRAL, ResultUnit.NONE);
126         } else if (this.measuredValue instanceof Integer) {
127             log.addValue(this.id(), (int)this.measuredValue, ResultType.NEUTRAL, ResultUnit.NONE);
128         } else if (this.measuredValue instanceof Long) {
129             log.addValue(this.id(), (long)this.measuredValue, ResultType.NEUTRAL, ResultUnit.NONE);
130         } else if (this.measuredValue instanceof Float) {
131             log.addValue(this.id(), (float)this.measuredValue, ResultType.NEUTRAL, ResultUnit.NONE);
132         } else if (this.measuredValue instanceof Double) {
133             log.addValue(this.id(), (double)this.measuredValue, ResultType.NEUTRAL,
134                 ResultUnit.NONE);
135         } else if (this.measuredValue instanceof Boolean) {
136             log.addValue(this.id(), (boolean)this.measuredValue, ResultType.NEUTRAL,
137                 ResultUnit.NONE);
138         } else if (this.measuredValue instanceof String) {
139             log.addValue(this.id(), (String)this.measuredValue, ResultType.NEUTRAL,
140                 ResultUnit.NONE);
141         } else {
142             // reporting all other types as Strings using toString()
143             log.addValue(this.id(), this.measuredValue.toString(), ResultType.NEUTRAL,
144                 ResultUnit.NONE);
145         }
146     }
147 }
148