CarDiagnosticConstantsTest.java revision 99e1a7555a9521c33203b68c5ab5bd1c039ee712
17b13666563e9c8603afe917043b35ec2b29c8ee4Enrico Granata/* 27b13666563e9c8603afe917043b35ec2b29c8ee4Enrico Granata * Copyright (C) 2017 The Android Open Source Project 37b13666563e9c8603afe917043b35ec2b29c8ee4Enrico Granata * 47b13666563e9c8603afe917043b35ec2b29c8ee4Enrico Granata * Licensed under the Apache License, Version 2.0 (the "License"); 57b13666563e9c8603afe917043b35ec2b29c8ee4Enrico Granata * you may not use this file except in compliance with the License. 67b13666563e9c8603afe917043b35ec2b29c8ee4Enrico Granata * You may obtain a copy of the License at 77b13666563e9c8603afe917043b35ec2b29c8ee4Enrico Granata * 87b13666563e9c8603afe917043b35ec2b29c8ee4Enrico Granata * http://www.apache.org/licenses/LICENSE-2.0 97b13666563e9c8603afe917043b35ec2b29c8ee4Enrico Granata * 107b13666563e9c8603afe917043b35ec2b29c8ee4Enrico Granata * Unless required by applicable law or agreed to in writing, software 117b13666563e9c8603afe917043b35ec2b29c8ee4Enrico Granata * distributed under the License is distributed on an "AS IS" BASIS, 127b13666563e9c8603afe917043b35ec2b29c8ee4Enrico Granata * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 137b13666563e9c8603afe917043b35ec2b29c8ee4Enrico Granata * See the License for the specific language governing permissions and 147b13666563e9c8603afe917043b35ec2b29c8ee4Enrico Granata * limitations under the License. 157b13666563e9c8603afe917043b35ec2b29c8ee4Enrico Granata */ 167b13666563e9c8603afe917043b35ec2b29c8ee4Enrico Granata 177b13666563e9c8603afe917043b35ec2b29c8ee4Enrico Granatapackage com.android.car.test; 187b13666563e9c8603afe917043b35ec2b29c8ee4Enrico Granata 197b13666563e9c8603afe917043b35ec2b29c8ee4Enrico Granataimport android.test.suitebuilder.annotation.MediumTest; 207b13666563e9c8603afe917043b35ec2b29c8ee4Enrico Granataimport android.util.Log; 217b13666563e9c8603afe917043b35ec2b29c8ee4Enrico Granata 227b13666563e9c8603afe917043b35ec2b29c8ee4Enrico Granataimport java.lang.reflect.Field; 237b13666563e9c8603afe917043b35ec2b29c8ee4Enrico Granataimport java.lang.reflect.Modifier; 247b13666563e9c8603afe917043b35ec2b29c8ee4Enrico Granataimport java.util.Arrays; 257b13666563e9c8603afe917043b35ec2b29c8ee4Enrico Granataimport java.util.HashMap; 267b13666563e9c8603afe917043b35ec2b29c8ee4Enrico Granataimport java.util.Map; 277b13666563e9c8603afe917043b35ec2b29c8ee4Enrico Granata 287b13666563e9c8603afe917043b35ec2b29c8ee4Enrico Granataimport junit.framework.TestCase; 297b13666563e9c8603afe917043b35ec2b29c8ee4Enrico Granata 307b13666563e9c8603afe917043b35ec2b29c8ee4Enrico Granata/** 317b13666563e9c8603afe917043b35ec2b29c8ee4Enrico Granata * Validates that diagnostic constants in CarService and Vehicle HAL have the same value 327b13666563e9c8603afe917043b35ec2b29c8ee4Enrico Granata * This is an important assumption to validate because we do not perform any mapping between 337b13666563e9c8603afe917043b35ec2b29c8ee4Enrico Granata * the two layers, instead relying on the constants on both sides having identical values. 347b13666563e9c8603afe917043b35ec2b29c8ee4Enrico Granata */ 357b13666563e9c8603afe917043b35ec2b29c8ee4Enrico Granata@MediumTest 367b13666563e9c8603afe917043b35ec2b29c8ee4Enrico Granatapublic class CarDiagnosticConstantsTest extends TestCase { 377b13666563e9c8603afe917043b35ec2b29c8ee4Enrico Granata static final String TAG = CarDiagnosticConstantsTest.class.getSimpleName(); 387b13666563e9c8603afe917043b35ec2b29c8ee4Enrico Granata 397b13666563e9c8603afe917043b35ec2b29c8ee4Enrico Granata static class MismatchException extends Exception { 4064fb54b08e2172a89ca025e94de37b3f9e08359cEnrico Granata private static String dumpClass(Class<?> clazz) { 4164fb54b08e2172a89ca025e94de37b3f9e08359cEnrico Granata StringBuilder builder = new StringBuilder(clazz.getName() + "{\n"); 4264fb54b08e2172a89ca025e94de37b3f9e08359cEnrico Granata Arrays.stream(clazz.getFields()).forEach((Field field) -> { 4364fb54b08e2172a89ca025e94de37b3f9e08359cEnrico Granata builder.append('\t').append(field.toString()).append('\n'); 4464fb54b08e2172a89ca025e94de37b3f9e08359cEnrico Granata }); 4564fb54b08e2172a89ca025e94de37b3f9e08359cEnrico Granata return builder.append('}').toString(); 4664fb54b08e2172a89ca025e94de37b3f9e08359cEnrico Granata } 4764fb54b08e2172a89ca025e94de37b3f9e08359cEnrico Granata 4864fb54b08e2172a89ca025e94de37b3f9e08359cEnrico Granata private static void logClasses(Class<?> clazz1, Class<?> clazz2) { 4964fb54b08e2172a89ca025e94de37b3f9e08359cEnrico Granata Log.d(TAG, "MismatchException. class1: " + dumpClass(clazz1)); 5064fb54b08e2172a89ca025e94de37b3f9e08359cEnrico Granata Log.d(TAG, "MismatchException. class2: " + dumpClass(clazz2)); 5164fb54b08e2172a89ca025e94de37b3f9e08359cEnrico Granata } 5264fb54b08e2172a89ca025e94de37b3f9e08359cEnrico Granata 537b13666563e9c8603afe917043b35ec2b29c8ee4Enrico Granata MismatchException(String message) { 547b13666563e9c8603afe917043b35ec2b29c8ee4Enrico Granata super(message); 557b13666563e9c8603afe917043b35ec2b29c8ee4Enrico Granata } 567b13666563e9c8603afe917043b35ec2b29c8ee4Enrico Granata 577b13666563e9c8603afe917043b35ec2b29c8ee4Enrico Granata static MismatchException fieldValueMismatch(Class<?> clazz1, Class<?> clazz2, String name, 587b13666563e9c8603afe917043b35ec2b29c8ee4Enrico Granata int value1, int value2) { 5964fb54b08e2172a89ca025e94de37b3f9e08359cEnrico Granata logClasses(clazz1, clazz2); 607b13666563e9c8603afe917043b35ec2b29c8ee4Enrico Granata return new MismatchException("In comparison of " + clazz1 + " and " + clazz2 + 617b13666563e9c8603afe917043b35ec2b29c8ee4Enrico Granata " field " + name + " had different values " + value1 + " vs. " + value2); 627b13666563e9c8603afe917043b35ec2b29c8ee4Enrico Granata } 637b13666563e9c8603afe917043b35ec2b29c8ee4Enrico Granata 647b13666563e9c8603afe917043b35ec2b29c8ee4Enrico Granata static MismatchException fieldsOnlyInClass1(Class<?> clazz1, Class<?> clazz2, 657b13666563e9c8603afe917043b35ec2b29c8ee4Enrico Granata Map<String, Integer> fields) { 6664fb54b08e2172a89ca025e94de37b3f9e08359cEnrico Granata logClasses(clazz1, clazz2); 677b13666563e9c8603afe917043b35ec2b29c8ee4Enrico Granata return new MismatchException("In comparison of " + clazz1 + " and " + clazz2 + 687b13666563e9c8603afe917043b35ec2b29c8ee4Enrico Granata " some fields were only found in the first class:\n" + 697b13666563e9c8603afe917043b35ec2b29c8ee4Enrico Granata fields.keySet().stream().reduce("", 707b13666563e9c8603afe917043b35ec2b29c8ee4Enrico Granata (String s, String t) -> s + "\n" + t)); 717b13666563e9c8603afe917043b35ec2b29c8ee4Enrico Granata } 727b13666563e9c8603afe917043b35ec2b29c8ee4Enrico Granata 737b13666563e9c8603afe917043b35ec2b29c8ee4Enrico Granata static MismatchException fieldOnlyInClass2(Class<?> clazz1, Class<?> clazz2, String field) { 7464fb54b08e2172a89ca025e94de37b3f9e08359cEnrico Granata logClasses(clazz1, clazz2); 757b13666563e9c8603afe917043b35ec2b29c8ee4Enrico Granata return new MismatchException("In comparison of " + clazz1 + " and " + clazz2 + 767b13666563e9c8603afe917043b35ec2b29c8ee4Enrico Granata " field " + field + " was not found in both classes"); 777b13666563e9c8603afe917043b35ec2b29c8ee4Enrico Granata } 787b13666563e9c8603afe917043b35ec2b29c8ee4Enrico Granata } 797b13666563e9c8603afe917043b35ec2b29c8ee4Enrico Granata 807b13666563e9c8603afe917043b35ec2b29c8ee4Enrico Granata static boolean isPublicStaticFinalInt(Field field) { 817b13666563e9c8603afe917043b35ec2b29c8ee4Enrico Granata final int modifiers = field.getModifiers(); 827b13666563e9c8603afe917043b35ec2b29c8ee4Enrico Granata final boolean isPublic = (modifiers & Modifier.PUBLIC) == Modifier.PUBLIC; 837b13666563e9c8603afe917043b35ec2b29c8ee4Enrico Granata final boolean isStatic = (modifiers & Modifier.STATIC) == Modifier.STATIC; 847b13666563e9c8603afe917043b35ec2b29c8ee4Enrico Granata final boolean isFinal = (modifiers & Modifier.FINAL) == Modifier.FINAL; 857b13666563e9c8603afe917043b35ec2b29c8ee4Enrico Granata if (isPublic && isStatic && isFinal) { 867b13666563e9c8603afe917043b35ec2b29c8ee4Enrico Granata return field.getType() == int.class; 877b13666563e9c8603afe917043b35ec2b29c8ee4Enrico Granata } 887b13666563e9c8603afe917043b35ec2b29c8ee4Enrico Granata return false; 897b13666563e9c8603afe917043b35ec2b29c8ee4Enrico Granata } 907b13666563e9c8603afe917043b35ec2b29c8ee4Enrico Granata 917b13666563e9c8603afe917043b35ec2b29c8ee4Enrico Granata static void validateMatch(Class<?> clazz1, Class<?> clazz2) throws Exception { 927b13666563e9c8603afe917043b35ec2b29c8ee4Enrico Granata Map<String, Integer> fields = new HashMap<>(); 937b13666563e9c8603afe917043b35ec2b29c8ee4Enrico Granata 947b13666563e9c8603afe917043b35ec2b29c8ee4Enrico Granata // add all the fields in the first class to a map 9564fb54b08e2172a89ca025e94de37b3f9e08359cEnrico Granata Arrays.stream(clazz1.getFields()).filter( 967b13666563e9c8603afe917043b35ec2b29c8ee4Enrico Granata CarDiagnosticConstantsTest::isPublicStaticFinalInt).forEach( (Field field) -> { 977b13666563e9c8603afe917043b35ec2b29c8ee4Enrico Granata final String name = field.getName(); 987b13666563e9c8603afe917043b35ec2b29c8ee4Enrico Granata try { 997b13666563e9c8603afe917043b35ec2b29c8ee4Enrico Granata fields.put(name, field.getInt(null)); 1007b13666563e9c8603afe917043b35ec2b29c8ee4Enrico Granata } catch (IllegalAccessException e) { 1017b13666563e9c8603afe917043b35ec2b29c8ee4Enrico Granata // this will practically never happen because we checked that it is a 1027b13666563e9c8603afe917043b35ec2b29c8ee4Enrico Granata // public static final field before reading from it 1037b13666563e9c8603afe917043b35ec2b29c8ee4Enrico Granata Log.wtf(TAG, String.format("attempt to access field %s threw exception", 1047b13666563e9c8603afe917043b35ec2b29c8ee4Enrico Granata field.toString()), e); 1057b13666563e9c8603afe917043b35ec2b29c8ee4Enrico Granata } 1067b13666563e9c8603afe917043b35ec2b29c8ee4Enrico Granata }); 1077b13666563e9c8603afe917043b35ec2b29c8ee4Enrico Granata 1087b13666563e9c8603afe917043b35ec2b29c8ee4Enrico Granata // check for all fields in the second class, and remove matches from the map 10964fb54b08e2172a89ca025e94de37b3f9e08359cEnrico Granata for (Field field2 : clazz2.getFields()) { 1107b13666563e9c8603afe917043b35ec2b29c8ee4Enrico Granata if (isPublicStaticFinalInt(field2)) { 1117b13666563e9c8603afe917043b35ec2b29c8ee4Enrico Granata final String name = field2.getName(); 1127b13666563e9c8603afe917043b35ec2b29c8ee4Enrico Granata if (fields.containsKey(name)) { 1137b13666563e9c8603afe917043b35ec2b29c8ee4Enrico Granata try { 1147b13666563e9c8603afe917043b35ec2b29c8ee4Enrico Granata final int value2 = field2.getInt(null); 1157b13666563e9c8603afe917043b35ec2b29c8ee4Enrico Granata final int value1 = fields.getOrDefault(name, value2+1); 1167b13666563e9c8603afe917043b35ec2b29c8ee4Enrico Granata if (value2 != value1) { 1177b13666563e9c8603afe917043b35ec2b29c8ee4Enrico Granata throw MismatchException.fieldValueMismatch(clazz1, clazz2, 1187b13666563e9c8603afe917043b35ec2b29c8ee4Enrico Granata field2.getName(), value1, value2); 1197b13666563e9c8603afe917043b35ec2b29c8ee4Enrico Granata } 1207b13666563e9c8603afe917043b35ec2b29c8ee4Enrico Granata fields.remove(name); 1217b13666563e9c8603afe917043b35ec2b29c8ee4Enrico Granata } catch (IllegalAccessException e) { 1227b13666563e9c8603afe917043b35ec2b29c8ee4Enrico Granata // this will practically never happen because we checked that it is a 1237b13666563e9c8603afe917043b35ec2b29c8ee4Enrico Granata // public static final field before reading from it 1247b13666563e9c8603afe917043b35ec2b29c8ee4Enrico Granata Log.wtf(TAG, String.format("attempt to access field %s threw exception", 1257b13666563e9c8603afe917043b35ec2b29c8ee4Enrico Granata field2.toString()), e); 1267b13666563e9c8603afe917043b35ec2b29c8ee4Enrico Granata throw e; 1277b13666563e9c8603afe917043b35ec2b29c8ee4Enrico Granata } 1287b13666563e9c8603afe917043b35ec2b29c8ee4Enrico Granata } else { 1297b13666563e9c8603afe917043b35ec2b29c8ee4Enrico Granata throw MismatchException.fieldOnlyInClass2(clazz1, clazz2, name); 1307b13666563e9c8603afe917043b35ec2b29c8ee4Enrico Granata } 1317b13666563e9c8603afe917043b35ec2b29c8ee4Enrico Granata } 1327b13666563e9c8603afe917043b35ec2b29c8ee4Enrico Granata } 1337b13666563e9c8603afe917043b35ec2b29c8ee4Enrico Granata 1347b13666563e9c8603afe917043b35ec2b29c8ee4Enrico Granata // if anything is left, we didn't find some fields in the second class 1357b13666563e9c8603afe917043b35ec2b29c8ee4Enrico Granata if (!fields.isEmpty()) { 1367b13666563e9c8603afe917043b35ec2b29c8ee4Enrico Granata throw MismatchException.fieldsOnlyInClass1(clazz1, clazz2, fields); 1377b13666563e9c8603afe917043b35ec2b29c8ee4Enrico Granata } 1387b13666563e9c8603afe917043b35ec2b29c8ee4Enrico Granata } 1397b13666563e9c8603afe917043b35ec2b29c8ee4Enrico Granata 1407b13666563e9c8603afe917043b35ec2b29c8ee4Enrico Granata public void testFuelSystemStatus() throws Exception { 14199e1a7555a9521c33203b68c5ab5bd1c039ee712Pavel Maltsev validateMatch(android.hardware.automotive.vehicle.V2_0.Obd2FuelSystemStatus.class, 1427b13666563e9c8603afe917043b35ec2b29c8ee4Enrico Granata android.car.diagnostic.CarDiagnosticEvent.FuelSystemStatus.class); 1437b13666563e9c8603afe917043b35ec2b29c8ee4Enrico Granata } 1447b13666563e9c8603afe917043b35ec2b29c8ee4Enrico Granata 1457b13666563e9c8603afe917043b35ec2b29c8ee4Enrico Granata public void testFuelType() throws Exception { 14699e1a7555a9521c33203b68c5ab5bd1c039ee712Pavel Maltsev validateMatch(android.hardware.automotive.vehicle.V2_0.Obd2FuelType.class, 1477b13666563e9c8603afe917043b35ec2b29c8ee4Enrico Granata android.car.diagnostic.CarDiagnosticEvent.FuelType.class); 1487b13666563e9c8603afe917043b35ec2b29c8ee4Enrico Granata } 1497b13666563e9c8603afe917043b35ec2b29c8ee4Enrico Granata 1507b13666563e9c8603afe917043b35ec2b29c8ee4Enrico Granata public void testSecondaryAirStatus() throws Exception { 15199e1a7555a9521c33203b68c5ab5bd1c039ee712Pavel Maltsev validateMatch(android.hardware.automotive.vehicle.V2_0.Obd2SecondaryAirStatus.class, 1527b13666563e9c8603afe917043b35ec2b29c8ee4Enrico Granata android.car.diagnostic.CarDiagnosticEvent.SecondaryAirStatus.class); 1537b13666563e9c8603afe917043b35ec2b29c8ee4Enrico Granata } 1547b13666563e9c8603afe917043b35ec2b29c8ee4Enrico Granata 1557b13666563e9c8603afe917043b35ec2b29c8ee4Enrico Granata public void testIgnitionMonitors() throws Exception { 15699e1a7555a9521c33203b68c5ab5bd1c039ee712Pavel Maltsev validateMatch(android.hardware.automotive.vehicle.V2_0.Obd2CommonIgnitionMonitors.class, 1577b13666563e9c8603afe917043b35ec2b29c8ee4Enrico Granata android.car.diagnostic.CarDiagnosticEvent.CommonIgnitionMonitors.class); 1587b13666563e9c8603afe917043b35ec2b29c8ee4Enrico Granata 15999e1a7555a9521c33203b68c5ab5bd1c039ee712Pavel Maltsev validateMatch(android.hardware.automotive.vehicle.V2_0.Obd2CompressionIgnitionMonitors.class, 1607b13666563e9c8603afe917043b35ec2b29c8ee4Enrico Granata android.car.diagnostic.CarDiagnosticEvent.CompressionIgnitionMonitors.class); 1617b13666563e9c8603afe917043b35ec2b29c8ee4Enrico Granata 16299e1a7555a9521c33203b68c5ab5bd1c039ee712Pavel Maltsev validateMatch(android.hardware.automotive.vehicle.V2_0.Obd2SparkIgnitionMonitors.class, 1637b13666563e9c8603afe917043b35ec2b29c8ee4Enrico Granata android.car.diagnostic.CarDiagnosticEvent.SparkIgnitionMonitors.class); 1647b13666563e9c8603afe917043b35ec2b29c8ee4Enrico Granata } 1657b13666563e9c8603afe917043b35ec2b29c8ee4Enrico Granata} 166