summaryrefslogtreecommitdiff
path: root/android/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/RPCGenericTests.java
diff options
context:
space:
mode:
Diffstat (limited to 'android/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/RPCGenericTests.java')
-rw-r--r--android/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/RPCGenericTests.java662
1 files changed, 662 insertions, 0 deletions
diff --git a/android/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/RPCGenericTests.java b/android/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/RPCGenericTests.java
new file mode 100644
index 000000000..88dfeb1c6
--- /dev/null
+++ b/android/sdl_android/src/androidTest/java/com/smartdevicelink/test/rpc/RPCGenericTests.java
@@ -0,0 +1,662 @@
+package com.smartdevicelink.test.rpc;
+
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import com.smartdevicelink.proxy.rpc.enums.SystemCapabilityType;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlPullParserFactory;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Type;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+import static junit.framework.TestCase.assertNotNull;
+import static junit.framework.TestCase.assertTrue;
+import static junit.framework.TestCase.fail;
+
+@RunWith(AndroidJUnit4.class)
+public class RPCGenericTests {
+
+ private final String XML_FILE_NAME = "MOBILE_API.xml";
+ private final String RPC_PACKAGE_PREFIX = "com.smartdevicelink.proxy.rpc.";
+ private final String TEST_VALUES_CLASS = "com.smartdevicelink.test.TestValues";
+ private Map<String, List<Parameter>> rpcMandatoryParamsMapFromXml;
+ private Map<String, List<Parameter>> rpcAllParamsMapFromXml;
+
+ private class Parameter {
+ private String rpcName;
+ private String name;
+ private String type;
+ private Class<?> javaType;
+ private boolean isArray;
+ private boolean isMandatory;
+ private String setterName;
+ private String getterName1;
+ private String getterName2;
+ private Object value;
+ private boolean skip;
+
+
+ public Parameter setRPCName(String rpcName) {
+ this.rpcName = rpcName;
+ return this;
+ }
+
+ public Parameter setName(String name) {
+ this.name = name;
+ return this;
+ }
+
+ public Parameter setType(String type) {
+ this.type = type;
+ return this;
+ }
+
+ public Parameter setJavaType(Class<?> javaType) {
+ this.javaType = javaType;
+ return this;
+ }
+
+ public Parameter setArray(boolean array) {
+ isArray = array;
+ return this;
+ }
+
+ public Parameter setMandatory(boolean mandatory) {
+ isMandatory = mandatory;
+ return this;
+ }
+
+ public Parameter setSetterName(String setterName) {
+ this.setterName = setterName;
+ return this;
+ }
+
+ public Parameter setGetterName1(String getterName1) {
+ this.getterName1 = getterName1;
+ return this;
+ }
+
+ public Parameter setGetterName2(String getterName2) {
+ this.getterName2 = getterName2;
+ return this;
+ }
+
+ public void setValue(Object value) {
+ this.value = value;
+ }
+
+ public Parameter setSkip(boolean skip) {
+ this.skip = skip;
+ return this;
+ }
+ }
+
+ @Before
+ public void setUp(){
+ // Map that has keys correspond to the RPC names and values correspond to the params for that RPC.
+ rpcMandatoryParamsMapFromXml = getRPCParamsMap(XML_FILE_NAME, true);
+ rpcAllParamsMapFromXml = getRPCParamsMap(XML_FILE_NAME, false);
+ }
+
+ // This method parses the RPC spec xml file and returns a map that has
+ // keys correspond to the RPC names and values correspond to the params for that RPC
+ private Map<String, List<Parameter>> getRPCParamsMap(String fileName, boolean includeMandatoryOnly) {
+ Map<String, List<Parameter>> rpcParamsMap = new HashMap<>();
+ try {
+ InputStream stream = getInstrumentation().getTargetContext().getAssets().open(fileName);
+ XmlPullParserFactory xmlFactoryObject = XmlPullParserFactory.newInstance();
+ XmlPullParser myParser = xmlFactoryObject.newPullParser();
+ myParser.setInput(stream, null);
+ int event = myParser.getEventType();
+ String rpcName = null;
+ boolean ignoreRPC = false;
+ String setterMethodName;
+ String getterMethodName1;
+ String getterMethodName2;
+ Class<?> javaParamType;
+ boolean skipParam;
+ while (event != XmlPullParser.END_DOCUMENT) {
+ String name = myParser.getName();
+ switch (event){
+ case XmlPullParser.START_TAG:
+ // Store the RPC name in the map
+ if(name.equals("function") || name.equals("struct")){
+ rpcName = myParser.getAttributeValue(null,"name");
+ ignoreRPC = false;
+ if (name.equals("function") && myParser.getAttributeValue(null, "messagetype").equals("response") && !rpcName.contains("Response")){
+ rpcName += "Response";
+ }
+
+ // -------------- Exceptional cases because of mismatch between the RPC spec and the Android code --------------
+ if(rpcName.equals("SyncMsgVersion")){
+ rpcName = "SdlMsgVersion";
+ } else if(rpcName.equals("ShowConstantTBTResponse")){
+ rpcName = "ShowConstantTbtResponse";
+ } else if(rpcName.equals("OASISAddress")) {
+ rpcName = "OasisAddress";
+ } else if(rpcName.equals("ShowConstantTBT")) {
+ rpcName = "ShowConstantTbt";
+ } else if (rpcName.equals("EncodedSyncPData") || rpcName.equals("OnEncodedSyncPData") || rpcName.equals("EncodedSyncPDataResponse")){
+ ignoreRPC = true;
+ }
+ // -------------------------------------------------------------------------------------------------------------
+
+ if (!ignoreRPC) {
+ rpcParamsMap.put(rpcName, new ArrayList<Parameter>());
+ }
+ }
+ // Store the params for the current RPC in the map
+ if(name.equals("param") && myParser.getAttributeValue(null, "until") == null && !ignoreRPC){
+ setterMethodName = null;
+ getterMethodName1 = null;
+ getterMethodName2 = null;
+ javaParamType = null;
+ skipParam = false;
+ boolean isMandatory = Boolean.valueOf(myParser.getAttributeValue(null,"mandatory"));
+ if (isMandatory || !includeMandatoryOnly) {
+ String paramName = myParser.getAttributeValue(null, "name");
+ String paramType = myParser.getAttributeValue(null, "type");
+ boolean isArray = Boolean.valueOf(myParser.getAttributeValue(null, "array"));
+
+ // -------------- Exceptional cases because of mismatch between the RPC spec and the Android code --------------
+ if (paramName.equals("syncFileName")){
+ paramName = "sdlFileName";
+ } else if (paramName.equals("syncMsgVersion")){
+ paramName = "sdlMsgVersion";
+ } else if (paramName.equals("hmiPermissions")){
+ paramName = "hMIPermissions";
+ } else if (paramName.equals("resolution")){
+ paramName = "imageResolution";
+ } else if (paramName.equals("pressureTelltale")){
+ paramName = "pressureTellTale";
+ }
+
+ setterMethodName = "set" + paramName.substring(0, 1).toUpperCase() + paramName.substring(1);
+
+ if (paramType.equals("SyncMsgVersion")){
+ paramType = "SdlMsgVersion";
+ } else if (rpcName.equals("GPSData") && paramType.equals("Float")){
+ paramType = "Double";
+ } else if (rpcName.equals("TouchEvent") && paramType.equals("Integer") && isArray){
+ paramType = "Long";
+ } else if (paramType.equals("OASISAddress")) {
+ paramType = "OasisAddress";
+ } else if (rpcName.equals("VideoStreamingCapability") && paramType.equals("Float")) {
+ paramType = "Double";
+ } else if (rpcName.equals("UnsubscribeVehicleData") && setterMethodName.equals("setCloudAppVehicleID")) {
+ paramType = "boolean";
+ } else if (rpcName.equals("CancelInteraction") && setterMethodName.equals("setFunctionID")) {
+ setterMethodName = "setInteractionFunctionID";
+ } else if (rpcName.equals("NavigationCapability") && setterMethodName.equals("setGetWayPointsEnabled")) {
+ setterMethodName = "setWayPointsEnabled";
+ } else if (rpcName.equals("UnsubscribeWayPointsResponse") && setterMethodName.equals("setGetWayPointsEnabled")) {
+ setterMethodName = "setWayPointsEnabled";
+ } else if (rpcName.equals("HMICapabilities") && setterMethodName.equals("setNavigation")) {
+ setterMethodName = "setNavigationAvilable";
+ } else if (rpcName.equals("HMICapabilities") && setterMethodName.equals("setPhoneCall")) {
+ setterMethodName = "setPhoneCallAvilable";
+ } else if (rpcName.equals("HMICapabilities") && setterMethodName.equals("setDisplays")) {
+ setterMethodName = "setDisplaysCapabilityAvailable";
+ } else if (rpcName.equals("HMICapabilities")) {
+ setterMethodName += "Available";
+ } else if (rpcName.equals("VideoStreamingCapability") && setterMethodName.equals("setHapticSpatialDataSupported")) {
+ setterMethodName = "setIsHapticSpatialDataSupported";
+ } else if (rpcName.equals("OnDriverDistraction") && setterMethodName.equals("setLockScreenDismissalEnabled")) {
+ setterMethodName = "setLockscreenDismissibility";
+ paramType = "boolean";
+ } else if (rpcName.equals("OnDriverDistraction") && setterMethodName.equals("setLockScreenDismissalWarning")) {
+ setterMethodName = "setLockscreenWarningMessage";
+ } else if (rpcName.equals("PublishAppServiceResponse") && setterMethodName.equals("setAppServiceRecord")) {
+ setterMethodName = "setServiceRecord";
+ } else if (setterMethodName.equals("setFuelLevel_State")) {
+ setterMethodName = "setFuelLevelState";
+ } else if (rpcName.equals("LightCapabilities") && setterMethodName.equals("setRgbColorSpaceAvailable")) {
+ setterMethodName = "setRGBColorSpaceAvailable";
+ } else if (rpcName.equals("CloudAppProperties") && setterMethodName.equals("setEnabled")) {
+ paramType = "boolean";
+ } else if (rpcName.equals("DateTime") && setterMethodName.equals("setMillisecond")) {
+ setterMethodName = "setMilliSecond";
+ } else if (rpcName.equals("DateTime") && setterMethodName.equals("setTz_hour")) {
+ setterMethodName = "setTzHour";
+ } else if (rpcName.equals("DateTime") && setterMethodName.equals("setTz_minute")) {
+ setterMethodName = "setTzMinute";
+ } else if (rpcName.equals("PutFile") && setterMethodName.equals("setCrc")) {
+ setterMethodName = "setCRC";
+ paramType = "Long";
+ } else if (rpcName.equals("AppServiceManifest") && setterMethodName.equals("setHandledRPCs")) {
+ setterMethodName = "setHandledRpcs";
+ } else if (rpcName.equals("LocationDetails") && setterMethodName.equals("setHandledRPCs")) {
+ setterMethodName = "setHandledRpcs";
+ } else if (rpcName.equals("SendLocation") && setterMethodName.equals("setLongitudeDegrees")) {
+ paramType = "Double";
+ } else if (rpcName.equals("SendLocation") && setterMethodName.equals("setLatitudeDegrees")) {
+ paramType = "Double";
+ } else if (rpcName.equals("Grid") && setterMethodName.equals("setColspan")) {
+ setterMethodName = "setColSpan";
+ } else if (rpcName.equals("Grid") && setterMethodName.equals("setRowspan")) {
+ setterMethodName = "setRowSpan";
+ } else if (rpcName.equals("Grid") && setterMethodName.equals("setLevelspan")) {
+ setterMethodName = "setLevelSpan";
+ } else if (rpcName.equals("HeadLampStatus") && setterMethodName.equals("setAmbientLightSensorStatus")) {
+ setterMethodName = "setAmbientLightStatus";
+ } else if (rpcName.equals("GetVehicleData") && setterMethodName.equals("setCloudAppVehicleID")) {
+ paramType = "boolean";
+ } else if (rpcName.equals("GetVehicleDataResponse") && Arrays.asList("setInstantFuelConsumption", "setFuelLevel", "setSpeed", "setExternalTemperature", "setEngineTorque", "setAccPedalPosition", "setSteeringWheelAngle").contains(setterMethodName)) {
+ paramType = "Double";
+ } else if (rpcName.equals("RdsData") && setterMethodName.equals("setPS")) {
+ setterMethodName = "setProgramService";
+ } else if (rpcName.equals("RdsData") && setterMethodName.equals("setCT")) {
+ setterMethodName = "setClockText";
+ } else if (rpcName.equals("RdsData") && setterMethodName.equals("setRT")) {
+ setterMethodName = "setRadioText";
+ } else if (rpcName.equals("RdsData") && setterMethodName.equals("setPI")) {
+ setterMethodName = "setProgramIdentification";
+ } else if (rpcName.equals("RdsData") && setterMethodName.equals("setPTY")) {
+ setterMethodName = "setProgramType";
+ } else if (rpcName.equals("RdsData") && setterMethodName.equals("setTP")) {
+ setterMethodName = "setTrafficProgram";
+ } else if (rpcName.equals("RdsData") && setterMethodName.equals("setTA")) {
+ setterMethodName = "setTrafficAnnouncement";
+ } else if (rpcName.equals("RdsData") && setterMethodName.equals("setREG")) {
+ setterMethodName = "setRegion";
+ } else if (rpcName.equals("RadioControlCapabilities") && setterMethodName.equals("setSiriusxmRadioAvailable")) {
+ setterMethodName = "setSiriusXMRadioAvailable";
+ } else if (rpcName.equals("GetCloudAppPropertiesResponse") && setterMethodName.equals("setProperties")) {
+ setterMethodName = "setCloudAppProperties";
+ } else if (rpcName.equals("GetFileResponse") && setterMethodName.equals("setCrc")) {
+ setterMethodName = "setCRC";
+ } else if (rpcName.equals("RegisterAppInterfaceResponse") && setterMethodName.equals("setPcmStreamCapabilities")) {
+ setterMethodName = "setPcmStreamingCapabilities";
+ } else if (rpcName.equals("SubscribeVehicleData") && setterMethodName.equals("setElectronicParkBrakeStatus")) {
+ paramType = "boolean";
+ } else if (rpcName.equals("SubscribeVehicleData") && setterMethodName.equals("setCloudAppVehicleID")) {
+ paramType = "boolean";
+ } else if (rpcName.equals("ModuleInfo") && setterMethodName.equals("setLocation")) {
+ setterMethodName = "setModuleLocation";
+ } else if (rpcName.equals("ModuleInfo") && setterMethodName.equals("setServiceArea")) {
+ setterMethodName = "setModuleServiceArea";
+ } else if (rpcName.equals("ModuleInfo") && setterMethodName.equals("setAllowMultipleAccess")) {
+ setterMethodName = "setMultipleAccessAllowance";
+ } else if (rpcName.equals("OnVehicleData") && setterMethodName.equals("setSpeed")) {
+ paramType = "Double";
+ } else if (rpcName.equals("OnVehicleData") && setterMethodName.equals("setFuelLevel")) {
+ paramType = "Double";
+ } else if (rpcName.equals("OnVehicleData") && setterMethodName.equals("setInstantFuelConsumption")) {
+ paramType = "Double";
+ } else if (rpcName.equals("OnVehicleData") && setterMethodName.equals("setExternalTemperature")) {
+ paramType = "Double";
+ } else if (rpcName.equals("OnVehicleData") && setterMethodName.equals("setEngineTorque")) {
+ paramType = "Double";
+ } else if (rpcName.equals("OnVehicleData") && setterMethodName.equals("setAccPedalPosition")) {
+ paramType = "Double";
+ } else if (rpcName.equals("OnVehicleData") && setterMethodName.equals("setSteeringWheelAngle")) {
+ paramType = "Double";
+ } else if (rpcName.equals("GetInteriorVehicleDataConsentResponse") && setterMethodName.equals("setAllowed")) {
+ setterMethodName = "setAllowances";
+ } else if (rpcName.equals("SeatLocationCapability") && setterMethodName.equals("setColumns")) {
+ setterMethodName = "setCols";
+ } else if (rpcName.equals("ShowConstantTbt") && setterMethodName.equals("setDistanceToManeuver")) {
+ paramType = "Double";
+ } else if (rpcName.equals("ShowConstantTbt") && setterMethodName.equals("setDistanceToManeuverScale")) {
+ paramType = "Double";
+ } else if (rpcName.equals("SingleTireStatus") && setterMethodName.equals("setTpms")) {
+ setterMethodName = "setTPMS";
+ } else if (rpcName.equals("VehicleDataResult") && setterMethodName.equals("setOemCustomDataType")) {
+ setterMethodName = "setOEMCustomVehicleDataType";
+ } else if (rpcName.equals("SystemCapability") && !setterMethodName.equals("setSystemCapabilityType")) {
+ setterMethodName = "setCapabilityForType";
+ paramType = "SystemCapabilityType";
+ } else if (rpcName.equals("UnsubscribeWayPointsResponse") && paramName.equals("wayPoints")) {
+ skipParam = true;
+ } else if (rpcName.equals("UnsubscribeVehicleDataResponse") && paramName.equals("clusterModes")) {
+ skipParam = true;
+ } else if (rpcName.equals("ClimateControlCapabilities") && paramName.equals("currentTemperatureAvailable")) {
+ skipParam = true;
+ } else if (rpcName.equals("SubscribeVehicleDataResponse") && paramName.equals("clusterModes")) {
+ skipParam = true;
+ }
+
+ // -------------------------------------------------------------------------------------------------------------
+
+ javaParamType = findJavaTypeForParam(paramType, isArray);
+ getterMethodName1 = "get" + setterMethodName.substring(3);
+ if (paramType.equalsIgnoreCase("boolean")) {
+ getterMethodName2 = "is" + setterMethodName.substring(3);
+ }
+
+ Parameter param = new Parameter()
+ .setRPCName(rpcName)
+ .setName(paramName)
+ .setType(paramType)
+ .setJavaType(javaParamType)
+ .setArray(isArray)
+ .setMandatory(isMandatory)
+ .setSkip(skipParam)
+ .setSetterName(setterMethodName)
+ .setGetterName1(getterMethodName1)
+ .setGetterName2(getterMethodName2)
+ ;
+
+ rpcParamsMap.get(rpcName).add(param);
+ }
+ }
+ break;
+ }
+ event = myParser.next();
+ }
+ stream.close();
+ } catch (IOException | XmlPullParserException e) {
+ fail("Cannot parse mobile APIs XML file: " + e.getMessage());
+ }
+ return rpcParamsMap;
+ }
+
+ // This method makes sure that for every RPC, there is a constructor that has all the mandatory params
+ // It also checks if there are RPC in the XML file that don't exist in the code
+ @Test
+ public void testMandatoryParamsMatch() {
+ // List of RPC names that don't have a constructor that has all mandatory params
+ List<String> rpcsWithInvalidConstructor = new ArrayList<>();
+
+ // List of the RPC names that couldn't be found in code
+ // potentially because of a mismatch between name in the RPC spec xml file and name in code
+ List<String> rpcsFromXmlNotFoundInCode = new ArrayList<>();
+
+ // Loop through all RPCs that were loaded from RPC spec XML file
+ // and make sure that every RPC has a constructor that has all mandatory params
+ for (String rpcName : rpcMandatoryParamsMapFromXml.keySet()) {
+ Class aClass;
+ try {
+ aClass = Class.forName(RPC_PACKAGE_PREFIX + rpcName);
+ } catch (ClassNotFoundException e) {
+ e.printStackTrace();
+ rpcsFromXmlNotFoundInCode.add(rpcName);
+ continue;
+ }
+ List<String> mandatoryParamsListFromXML = new ArrayList<>();
+ for (Parameter param : rpcMandatoryParamsMapFromXml.get(rpcName)) {
+ String type = param.type;
+ // If the param is a list of objects, the type should be like "List<Object>"
+ if (param.isArray){
+ type = String.format("List<%s>", type);
+ }
+ mandatoryParamsListFromXML.add(type);
+ }
+ List<String> mandatoryParamsListFromCode = new ArrayList<>();
+ boolean rpcHasValidConstructor = false;
+ for (Constructor constructor : aClass.getConstructors()){
+ mandatoryParamsListFromCode.clear();
+ for (Type paramType : constructor.getGenericParameterTypes()){
+ String paramFullType = paramType.toString();
+ String paramSimpleType;
+
+ // If the param is a list of objects, the type should be like "List<Object>"
+ if (paramFullType.matches("java.util.List<.+>")) {
+ paramSimpleType = String.format("List<%s>", paramFullType.substring(paramFullType.lastIndexOf('.') + 1, paramFullType.length() - 1));
+ }
+ // If the param is a simple object for example "java.lang.String", the type should be the last part "String"
+ else if (!paramFullType.contains(">")){
+ paramSimpleType = paramFullType.substring(paramFullType.lastIndexOf('.') + 1, paramFullType.length());
+ }
+ else {
+ paramSimpleType = paramFullType;
+ }
+ mandatoryParamsListFromCode.add(paramSimpleType);
+ }
+ if (mandatoryParamsListFromCode.containsAll(mandatoryParamsListFromXML) && mandatoryParamsListFromXML.containsAll(mandatoryParamsListFromCode)){
+ rpcHasValidConstructor = true;
+ break;
+ }
+ }
+ if (!rpcHasValidConstructor){
+ rpcsWithInvalidConstructor.add(rpcName);
+ }
+ }
+ assertTrue("The following RPCs were not found in the code: " + rpcsFromXmlNotFoundInCode, rpcsFromXmlNotFoundInCode.isEmpty());
+ assertTrue("The following RPCs don't have a constructor that has all the mandatory params: " + rpcsWithInvalidConstructor, rpcsWithInvalidConstructor.isEmpty());
+ }
+
+ // This method returns the correct java reflection method in a specific class
+ private Method getMethod(Class aClass, Parameter parameter, String methodName, boolean isGetter) throws NoSuchMethodException {
+ Method method = null;
+ if (methodName == null) {
+ throw new NoSuchMethodException();
+ }
+ if (isGetter) {
+ if (parameter.rpcName.equals("SystemCapability") && !methodName.contains("SystemCapabilityType")) {
+ method = aClass.getMethod(methodName, SystemCapabilityType.class);
+ } else {
+ method = aClass.getMethod(methodName);
+ }
+ } else {
+ if (parameter.rpcName.equals("SystemCapability") && !methodName.contains("SystemCapabilityType")) {
+ method = aClass.getMethod(methodName, SystemCapabilityType.class, Object.class);
+ } else {
+ method = aClass.getMethod(methodName, parameter.javaType);
+ }
+ }
+ return method;
+ }
+
+ // This method returns the full Java type for a param
+ private Class<?> findJavaTypeForParam(String type, boolean isArray) {
+ String typeString = null;
+ Class<?> javaType = null;
+
+ // List of types that exist in java.lang.*
+ List<String> javaLangBuiltInTypes = Arrays.asList("String", "Integer", "Long", "Float", "Double", "Boolean");
+
+ // List of primitive types in java
+ List<String> javaLangPrimitiveTypes = Arrays.asList("int", "long", "float", "double", "boolean");
+
+ // Find the full Java type for the current param
+ try {
+ if (isArray) {
+ javaType = List.class;
+ } else if (javaLangPrimitiveTypes.contains(type)) {
+ if (type.equals("int")) {
+ javaType = int.class;
+ } else if (type.equals("long")) {
+ javaType = long.class;
+ } else if (type.equals("float")) {
+ javaType = float.class;
+ } else if (type.equals("double")) {
+ javaType = double.class;
+ } else if (type.equals("boolean")) {
+ javaType = boolean.class;
+ }
+ } else {
+ if (javaLangBuiltInTypes.contains(type)) {
+ typeString = "java.lang." + type;
+ } else {
+ typeString = RPC_PACKAGE_PREFIX + type;
+ }
+ javaType = Class.forName(typeString);
+ }
+
+ } catch (ClassNotFoundException e) {
+ // If the class was not found in the rpc package
+ // try to see if it can be found in enums package
+ typeString = RPC_PACKAGE_PREFIX + "enums." + type;
+ try {
+ javaType = Class.forName(typeString);
+ } catch (ClassNotFoundException e1) {
+ e1.printStackTrace();
+ }
+ }
+ assertNotNull("Java type cannot be found for: " + type, javaType);
+ return javaType;
+ }
+
+ // This method makes sure that for every RPC, the constructor that has the mandatory params is setting the values correctly
+ @Test
+ public void testMandatoryParamsValues() {
+ // List of RPC names that have a constructor which is not settings the values for the mandatory params correctly
+ List<String> rpcsWithInvalidConstructor = new ArrayList<>();
+
+ // Loop through all RPCs that were loaded from RPC spec XML file
+ // and make sure that the constructor that has the mandatory params is setting the values correctly
+ for (String rpcName : rpcMandatoryParamsMapFromXml.keySet()) {
+ Class aClass;
+ try {
+ aClass = Class.forName(RPC_PACKAGE_PREFIX + rpcName);
+ } catch (ClassNotFoundException e) {
+ fail(e.getMessage());
+ continue;
+ }
+
+ List<Parameter> parameters = rpcMandatoryParamsMapFromXml.get(rpcName);
+ List<Class<?>> mandatoryParamsTypes = new ArrayList<>();
+ List<Object> mandatoryParamsValues = new ArrayList<>();
+
+ // Loop through all mandatory params for the current RPC
+ // and try to find the full Java type for each param
+ // also assign a value for each param from TestValues class
+ for (Parameter param : parameters) {
+ String valueString = null;
+ Object value = null;
+
+ // Assign a value for the current param from TestValues based of the param type
+ try {
+ // --------------------------------------------- Exceptional cases ---------------------------------------------
+ // This case is exceptional because the setter changes the input if it is not all digits
+ if (rpcName.equals("DialNumber") && param.type.equals("String")){
+ value = "5558675309";
+ }
+ // -------------------------------------------------------------------------------------------------------------
+
+ if (value == null) {
+ valueString = "GENERAL_" + param.type.toUpperCase();
+ if (param.isArray){
+ valueString += "_LIST";
+ }
+ value = Class.forName(TEST_VALUES_CLASS).getDeclaredField(valueString).get(null);
+ }
+
+ } catch (ClassNotFoundException | NoSuchFieldException | IllegalAccessException e) {
+ e.printStackTrace();
+ fail("Value: " + valueString + " cannot be found for RPC: " + rpcName + ". Make sure that you declared that value in " + TEST_VALUES_CLASS);
+ }
+
+ mandatoryParamsTypes.add(param.javaType);
+ mandatoryParamsValues.add(value);
+ }
+
+
+ // Create an instance of the RPC object using the constructor that has all the mandatory params
+ Object instance = null;
+ try {
+ Constructor constructor = aClass.getConstructor(mandatoryParamsTypes.toArray(new Class<?>[mandatoryParamsTypes.size()]));
+ instance = constructor.newInstance(mandatoryParamsValues.toArray(new Object[mandatoryParamsValues.size()]));
+ } catch (NoSuchMethodException | IllegalAccessException | InstantiationException | InvocationTargetException e) {
+ e.printStackTrace();
+ fail("Constructor for RPC " + rpcName + " cannot be invoked. Make sure that the constructor parameters order and types are identical to the RPC specs");
+ }
+
+
+ // Loop through all getter methods for the instance and make sure that they are returning the expected values
+ if (instance != null) {
+ for (int i = 0; i < parameters.size(); i++) {
+ try {
+ Method getterMethod = getMethod(aClass, parameters.get(i), parameters.get(i).getterName1, true);
+ Object val = getterMethod.invoke(instance);
+ if (val == null || !val.equals(mandatoryParamsValues.get(i))) {
+ rpcsWithInvalidConstructor.add(rpcName);
+ break;
+ }
+ } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
+ e.printStackTrace();
+ fail("Method: " + parameters.get(i).getterName1 + " cannot be found for RPC: " + rpcName + ". Make sure that the method exists and that the parameters order and types are identical to the RPC specs");
+ }
+ }
+ }
+ }
+
+ assertTrue("The following RPCs have a constructor that is not setting the mandatory params correctly: " + rpcsWithInvalidConstructor, rpcsWithInvalidConstructor.isEmpty());
+ }
+
+ /**
+ * This method makes sure that for every param in every RPC:
+ * - A setter exists and its name matches the RPC spec
+ * - The setter return type matches the RPC type (to make RPCs chainable)
+ * - A getter exists and its name matches the RPC spec
+ */
+ @Test
+ public void testParamsSettersAndGetters() {
+ List<String> errors = new ArrayList<>();
+
+ // Loop through all RPCs that were loaded from RPC spec XML file
+ for (String rpcName : rpcAllParamsMapFromXml.keySet()) {
+ Class aClass;
+ try {
+ aClass = Class.forName(RPC_PACKAGE_PREFIX + rpcName);
+ } catch (ClassNotFoundException e) {
+ e.printStackTrace();
+ errors.add("Class not found for rpc: "+ rpcName + ". \n");
+ continue;
+ }
+
+ // Loop through all params for the current RPC and make sure everyone has a a setter and a getter
+ List<Parameter> parameters = rpcAllParamsMapFromXml.get(rpcName);
+ for (int i = 0; i < parameters.size(); i++) {
+ Parameter parameter = parameters.get(i);
+ if (parameter.skip) {
+ continue;
+ }
+
+ // Confirm that the setter is correct
+ try {
+ Method setterMethod = getMethod(aClass, parameter, parameter.setterName, false);
+ List<String> expectedReturnTypes = Arrays.asList(aClass.getName(), aClass.getSuperclass().getName());
+ String actualReturnType = setterMethod.getReturnType().getName();
+ if (!expectedReturnTypes.contains(actualReturnType)) {
+ String errMsg = rpcName + "." + parameter.setterName + "() is expected to return one of these types: " + expectedReturnTypes + " but it returns: " + actualReturnType + ". \n";
+ errors.add(errMsg);
+ }
+ } catch (NoSuchMethodException e) {
+ String errMsg = rpcName + "." + parameter.setterName + "(" + parameter.type + ")" + " cannot be found. Make sure that the method exists. \n";
+ errors.add(errMsg);
+ }
+
+ // Confirm that the getter is correct
+ Method getterMethod = null;
+ try {
+ // --------------------------------------------- Exceptional cases ---------------------------------------------
+ if (parameter.getterName1.contains("Avilable")) {
+ continue;
+ } else if (parameter.getterName1.equals("getSeats")) {
+ parameter.getterName1 = "getSeatLocations";
+ }
+ // -------------------------------------------------------------------------------------------------------------
+ getterMethod = getMethod(aClass, parameter, parameter.getterName1, true);
+ } catch (NoSuchMethodException e) {
+ try {
+ getterMethod = getMethod(aClass, parameter, parameter.getterName2, true);
+ } catch (NoSuchMethodException ex) {
+ ex.printStackTrace();
+ String errMsg = String.format(rpcName + "." + parameter.getterName1 + "()" + "%s" + " cannot be found. Make sure that the method exists. \n", parameter.type.equalsIgnoreCase("boolean")? "/" + parameter.getterName2 + "()" : "");
+ errors.add(errMsg);
+ }
+ }
+ }
+ }
+
+ assertTrue("There are " + errors.size() + " errors: \n" + errors, errors.isEmpty());
+ }
+}