Loading automotive/vehicle/aidl/impl/default_config/JsonConfigLoader/include/JsonConfigLoader.h +9 −3 Original line number Diff line number Diff line Loading @@ -89,7 +89,8 @@ class JsonValueParser final { // The main class to parse a VHAL config file in JSON format. class JsonConfigParser { public: android::base::Result<std::vector<ConfigDeclaration>> parseJsonConfig(std::istream& is); android::base::Result<std::unordered_map<int32_t, ConfigDeclaration>> parseJsonConfig( std::istream& is); private: JsonValueParser mValueParser; Loading Loading @@ -155,8 +156,13 @@ class JsonConfigLoader final { public: JsonConfigLoader(); // Loads a JSON file stream and parses it to a list of ConfigDeclarations. android::base::Result<std::vector<ConfigDeclaration>> loadPropConfig(std::istream& is); // Loads a JSON file stream and parses it to a map from propId to ConfigDeclarations. android::base::Result<std::unordered_map<int32_t, ConfigDeclaration>> loadPropConfig( std::istream& is); // Loads a JSON config file and parses it to a map from propId to ConfigDeclarations. android::base::Result<std::unordered_map<int32_t, ConfigDeclaration>> loadPropConfig( const std::string& configPath); private: std::unique_ptr<jsonconfigloader_impl::JsonConfigParser> mParser; Loading automotive/vehicle/aidl/impl/default_config/JsonConfigLoader/src/JsonConfigLoader.cpp +24 −6 Original line number Diff line number Diff line Loading @@ -25,6 +25,7 @@ #endif // ENABLE_VEHICLE_HAL_TEST_PROPERTIES #include <android-base/strings.h> #include <fstream> namespace android { namespace hardware { Loading Loading @@ -509,25 +510,32 @@ std::optional<ConfigDeclaration> JsonConfigParser::parseEachProperty( return configDecl; } Result<std::vector<ConfigDeclaration>> JsonConfigParser::parseJsonConfig(std::istream& is) { Result<std::unordered_map<int32_t, ConfigDeclaration>> JsonConfigParser::parseJsonConfig( std::istream& is) { Json::CharReaderBuilder builder; Json::Value root; std::vector<ConfigDeclaration> configs; std::unordered_map<int32_t, ConfigDeclaration> configsByPropId; std::string errs; if (!Json::parseFromStream(builder, is, &root, &errs)) { return Error() << "Failed to parse property config file as JSON, error: " << errs; } if (!root.isObject()) { return Error() << "root element must be an object"; } if (!root.isMember("properties") || !root["properties"].isArray()) { return Error() << "Missing 'properties' field in root or the field is not an array"; } Json::Value properties = root["properties"]; std::vector<std::string> errors; for (unsigned int i = 0; i < properties.size(); i++) { if (auto maybeConfig = parseEachProperty(properties[i], &errors); maybeConfig.has_value()) { configs.push_back(std::move(maybeConfig.value())); configsByPropId[maybeConfig.value().config.prop] = std::move(maybeConfig.value()); } } if (!errors.empty()) { return Error() << android::base::Join(errors, '\n'); } return configs; return configsByPropId; } } // namespace jsonconfigloader_impl Loading @@ -536,11 +544,21 @@ JsonConfigLoader::JsonConfigLoader() { mParser = std::make_unique<jsonconfigloader_impl::JsonConfigParser>(); } android::base::Result<std::vector<ConfigDeclaration>> JsonConfigLoader::loadPropConfig( std::istream& is) { android::base::Result<std::unordered_map<int32_t, ConfigDeclaration>> JsonConfigLoader::loadPropConfig(std::istream& is) { return mParser->parseJsonConfig(is); } android::base::Result<std::unordered_map<int32_t, ConfigDeclaration>> JsonConfigLoader::loadPropConfig(const std::string& configPath) { std::ifstream ifs(configPath.c_str()); if (!ifs) { return android::base::Error() << "couldn't open " << configPath << " for parsing."; } return loadPropConfig(ifs); } } // namespace vehicle } // namespace automotive } // namespace hardware Loading automotive/vehicle/aidl/impl/default_config/JsonConfigLoader/test/JsonConfigLoaderUnitTest.cpp +75 −45 Original line number Diff line number Diff line Loading @@ -38,7 +38,7 @@ class JsonConfigLoaderUnitTest : public ::testing::Test { JsonConfigLoader mLoader; }; TEST_F(JsonConfigLoaderUnitTest, TestBasic) { TEST_F(JsonConfigLoaderUnitTest, testBasic) { std::istringstream iss(R"( { "properties": [{ Loading @@ -53,11 +53,39 @@ TEST_F(JsonConfigLoaderUnitTest, TestBasic) { auto configs = result.value(); ASSERT_EQ(configs.size(), 1u); ASSERT_EQ(configs.begin()->second.config.prop, 291504388); } TEST_F(JsonConfigLoaderUnitTest, testRootNotObject) { std::istringstream iss(R"( [] )"); ASSERT_FALSE(mLoader.loadPropConfig(iss).ok()) << "root is not an object must cause error"; } TEST_F(JsonConfigLoaderUnitTest, testMissingPropertiesField) { std::istringstream iss(R"( { "abcd": 1234 } )"); ASSERT_FALSE(mLoader.loadPropConfig(iss).ok()) << "Missing 'properties' field must cause error"; } TEST_F(JsonConfigLoaderUnitTest, testPropertiesFieldNotArray) { std::istringstream iss(R"( { "properties': {'a': 'b'} } )"); ASSERT_EQ(configs[0].config.prop, 291504388); ASSERT_FALSE(mLoader.loadPropConfig(iss).ok()) << "'properties' field is not an array must cause error"; } TEST_F(JsonConfigLoaderUnitTest, TestPropertyIsEnum) { TEST_F(JsonConfigLoaderUnitTest, testPropertyIsEnum) { std::istringstream iss(R"( { "properties": [{ Loading @@ -72,11 +100,10 @@ TEST_F(JsonConfigLoaderUnitTest, TestPropertyIsEnum) { auto configs = result.value(); ASSERT_EQ(configs.size(), 1u); ASSERT_EQ(configs[0].config.prop, toInt(VehicleProperty::INFO_FUEL_CAPACITY)); ASSERT_EQ(configs.begin()->second.config.prop, toInt(VehicleProperty::INFO_FUEL_CAPACITY)); } TEST_F(JsonConfigLoaderUnitTest, TestPropertyEnum_FailInvalidEnum) { TEST_F(JsonConfigLoaderUnitTest, testPropertyEnum_FailInvalidEnum) { std::istringstream iss(R"( { "properties": [{ Loading @@ -89,7 +116,7 @@ TEST_F(JsonConfigLoaderUnitTest, TestPropertyEnum_FailInvalidEnum) { << "Invalid VehicleProperty enum must cause error"; } TEST_F(JsonConfigLoaderUnitTest, TestPropertyEnum_FailInvalidType) { TEST_F(JsonConfigLoaderUnitTest, testPropertyEnum_FailInvalidType) { std::istringstream iss(R"( { "properties": [{ Loading @@ -102,7 +129,7 @@ TEST_F(JsonConfigLoaderUnitTest, TestPropertyEnum_FailInvalidType) { << "Invalid VehicleProperty type must cause error"; } TEST_F(JsonConfigLoaderUnitTest, TestProperty_FailInvalidJson) { TEST_F(JsonConfigLoaderUnitTest, testProperty_FailInvalidJson) { std::istringstream iss(R"( { "properties": [{ Loading @@ -112,7 +139,7 @@ TEST_F(JsonConfigLoaderUnitTest, TestProperty_FailInvalidJson) { ASSERT_FALSE(mLoader.loadPropConfig(iss).ok()) << "Invalid JSON format must cause error"; } TEST_F(JsonConfigLoaderUnitTest, TestConfigArray) { TEST_F(JsonConfigLoaderUnitTest, testConfigArray) { std::istringstream iss(R"( { "properties": [{ Loading @@ -128,10 +155,10 @@ TEST_F(JsonConfigLoaderUnitTest, TestConfigArray) { auto configs = result.value(); ASSERT_EQ(configs.size(), 1u); ASSERT_EQ(configs[0].config.configArray, std::vector<int>({1, 2, 3})); ASSERT_EQ(configs.begin()->second.config.configArray, std::vector<int>({1, 2, 3})); } TEST_F(JsonConfigLoaderUnitTest, TestConfigArrayConstants) { TEST_F(JsonConfigLoaderUnitTest, testConfigArrayConstants) { std::istringstream iss(R"( { "properties": [{ Loading @@ -147,11 +174,12 @@ TEST_F(JsonConfigLoaderUnitTest, TestConfigArrayConstants) { auto configs = result.value(); ASSERT_EQ(configs.size(), 1u); ASSERT_EQ(configs[0].config.configArray, std::vector<int>({1, 2, FUEL_DOOR_REAR_LEFT})); ASSERT_EQ(configs.begin()->second.config.configArray, std::vector<int>({1, 2, FUEL_DOOR_REAR_LEFT})); } // We have special logic to deal with GALLON and US_GALLON since they share the same value. TEST_F(JsonConfigLoaderUnitTest, TestConfigArrayUnitGallon) { TEST_F(JsonConfigLoaderUnitTest, testConfigArrayUnitGallon) { std::istringstream iss(R"( { "properties": [{ Loading @@ -166,7 +194,7 @@ TEST_F(JsonConfigLoaderUnitTest, TestConfigArrayUnitGallon) { ASSERT_TRUE(result.ok()) << result.error().message(); } TEST_F(JsonConfigLoaderUnitTest, TestConfigArrayUnitUsGallon) { TEST_F(JsonConfigLoaderUnitTest, testConfigArrayUnitUsGallon) { std::istringstream iss(R"( { "properties": [{ Loading @@ -181,7 +209,7 @@ TEST_F(JsonConfigLoaderUnitTest, TestConfigArrayUnitUsGallon) { ASSERT_TRUE(result.ok()) << result.error().message(); } TEST_F(JsonConfigLoaderUnitTest, TestConfigArray_FailInvalidEnum) { TEST_F(JsonConfigLoaderUnitTest, testConfigArray_FailInvalidEnum) { std::istringstream iss(R"( { "properties": [{ Loading @@ -195,7 +223,7 @@ TEST_F(JsonConfigLoaderUnitTest, TestConfigArray_FailInvalidEnum) { << "Invalid enum in ConfigArray must cause error"; } TEST_F(JsonConfigLoaderUnitTest, TestConfigArray_FailNotArray) { TEST_F(JsonConfigLoaderUnitTest, testConfigArray_FailNotArray) { std::istringstream iss(R"( { "properties": [{ Loading @@ -209,7 +237,7 @@ TEST_F(JsonConfigLoaderUnitTest, TestConfigArray_FailNotArray) { << "ConfigArray is not an array must cause error"; } TEST_F(JsonConfigLoaderUnitTest, TestConfigString) { TEST_F(JsonConfigLoaderUnitTest, testConfigString) { std::istringstream iss(R"( { "properties": [{ Loading @@ -225,10 +253,10 @@ TEST_F(JsonConfigLoaderUnitTest, TestConfigString) { auto configs = result.value(); ASSERT_EQ(configs.size(), 1u); ASSERT_EQ(configs[0].config.configString, "test"); ASSERT_EQ(configs.begin()->second.config.configString, "test"); } TEST_F(JsonConfigLoaderUnitTest, TestConfigString_FailNotString) { TEST_F(JsonConfigLoaderUnitTest, testConfigString_FailNotString) { std::istringstream iss(R"( { "properties": [{ Loading @@ -242,7 +270,7 @@ TEST_F(JsonConfigLoaderUnitTest, TestConfigString_FailNotString) { << "ConfigString is not a String must cause error"; } TEST_F(JsonConfigLoaderUnitTest, TestCheckDefaultAccessChangeMode) { TEST_F(JsonConfigLoaderUnitTest, testCheckDefaultAccessChangeMode) { std::istringstream iss(R"( { "properties": [{ Loading @@ -257,12 +285,12 @@ TEST_F(JsonConfigLoaderUnitTest, TestCheckDefaultAccessChangeMode) { auto configs = result.value(); ASSERT_EQ(configs.size(), 1u); const VehiclePropConfig& propConfig = configs[0].config; const VehiclePropConfig& propConfig = configs.begin()->second.config; ASSERT_EQ(propConfig.access, VehiclePropertyAccess::READ); ASSERT_EQ(propConfig.changeMode, VehiclePropertyChangeMode::STATIC); } TEST_F(JsonConfigLoaderUnitTest, TestAccessOverride) { TEST_F(JsonConfigLoaderUnitTest, testAccessOverride) { std::istringstream iss(R"( { "properties": [{ Loading @@ -278,12 +306,12 @@ TEST_F(JsonConfigLoaderUnitTest, TestAccessOverride) { auto configs = result.value(); ASSERT_EQ(configs.size(), 1u); const VehiclePropConfig& propConfig = configs[0].config; const VehiclePropConfig& propConfig = configs.begin()->second.config; ASSERT_EQ(propConfig.access, VehiclePropertyAccess::WRITE); ASSERT_EQ(propConfig.changeMode, VehiclePropertyChangeMode::STATIC); } TEST_F(JsonConfigLoaderUnitTest, TestChangeModeOverride) { TEST_F(JsonConfigLoaderUnitTest, testChangeModeOverride) { std::istringstream iss(R"( { "properties": [{ Loading @@ -299,12 +327,12 @@ TEST_F(JsonConfigLoaderUnitTest, TestChangeModeOverride) { auto configs = result.value(); ASSERT_EQ(configs.size(), 1u); const VehiclePropConfig& propConfig = configs[0].config; const VehiclePropConfig& propConfig = configs.begin()->second.config; ASSERT_EQ(propConfig.access, VehiclePropertyAccess::READ); ASSERT_EQ(propConfig.changeMode, VehiclePropertyChangeMode::ON_CHANGE); } TEST_F(JsonConfigLoaderUnitTest, TestCustomProp) { TEST_F(JsonConfigLoaderUnitTest, testCustomProp) { std::istringstream iss(R"( { "properties": [{ Loading @@ -321,12 +349,12 @@ TEST_F(JsonConfigLoaderUnitTest, TestCustomProp) { auto configs = result.value(); ASSERT_EQ(configs.size(), 1u); const VehiclePropConfig& propConfig = configs[0].config; const VehiclePropConfig& propConfig = configs.begin()->second.config; ASSERT_EQ(propConfig.access, VehiclePropertyAccess::WRITE); ASSERT_EQ(propConfig.changeMode, VehiclePropertyChangeMode::ON_CHANGE); } TEST_F(JsonConfigLoaderUnitTest, TestCustomProp_FailMissingAccess) { TEST_F(JsonConfigLoaderUnitTest, testCustomProp_FailMissingAccess) { std::istringstream iss(R"( { "properties": [{ Loading @@ -340,7 +368,7 @@ TEST_F(JsonConfigLoaderUnitTest, TestCustomProp_FailMissingAccess) { << "Missing access for custom property must cause error"; } TEST_F(JsonConfigLoaderUnitTest, TestCustomProp_FailMissingChangeMode) { TEST_F(JsonConfigLoaderUnitTest, testCustomProp_FailMissingChangeMode) { std::istringstream iss(R"( { "properties": [{ Loading @@ -354,7 +382,7 @@ TEST_F(JsonConfigLoaderUnitTest, TestCustomProp_FailMissingChangeMode) { << "Missing change mode for custom property must cause error"; } TEST_F(JsonConfigLoaderUnitTest, TestMinSampleRate) { TEST_F(JsonConfigLoaderUnitTest, testMinSampleRate) { std::istringstream iss(R"( { "properties": [{ Loading @@ -370,10 +398,10 @@ TEST_F(JsonConfigLoaderUnitTest, TestMinSampleRate) { auto configs = result.value(); ASSERT_EQ(configs.size(), 1u); ASSERT_EQ(configs[0].config.minSampleRate, 1); ASSERT_EQ(configs.begin()->second.config.minSampleRate, 1); } TEST_F(JsonConfigLoaderUnitTest, TestMinSampleRate_FailInvalidType) { TEST_F(JsonConfigLoaderUnitTest, testMinSampleRate_FailInvalidType) { std::istringstream iss(R"( { "properties": [{ Loading @@ -387,7 +415,7 @@ TEST_F(JsonConfigLoaderUnitTest, TestMinSampleRate_FailInvalidType) { << "Wrong type for MinSampleRate must cause error"; } TEST_F(JsonConfigLoaderUnitTest, TestMaxSampleRate) { TEST_F(JsonConfigLoaderUnitTest, testMaxSampleRate) { std::istringstream iss(R"( { "properties": [{ Loading @@ -403,10 +431,10 @@ TEST_F(JsonConfigLoaderUnitTest, TestMaxSampleRate) { auto configs = result.value(); ASSERT_EQ(configs.size(), 1u); ASSERT_EQ(configs[0].config.maxSampleRate, 1); ASSERT_EQ(configs.begin()->second.config.maxSampleRate, 1); } TEST_F(JsonConfigLoaderUnitTest, TestMaxSampleRate_FailInvalidType) { TEST_F(JsonConfigLoaderUnitTest, testMaxSampleRate_FailInvalidType) { std::istringstream iss(R"( { "properties": [{ Loading @@ -420,7 +448,7 @@ TEST_F(JsonConfigLoaderUnitTest, TestMaxSampleRate_FailInvalidType) { << "Wrong type for MaxSampleRate must cause error"; } TEST_F(JsonConfigLoaderUnitTest, TestDefaultValue_Simple) { TEST_F(JsonConfigLoaderUnitTest, testDefaultValue_Simple) { std::istringstream iss(R"( { "properties": [{ Loading @@ -438,10 +466,10 @@ TEST_F(JsonConfigLoaderUnitTest, TestDefaultValue_Simple) { auto configs = result.value(); ASSERT_EQ(configs.size(), 1u); ASSERT_EQ(configs[0].initialValue.int32Values, std::vector<int32_t>({1, 2})); ASSERT_EQ(configs.begin()->second.initialValue.int32Values, std::vector<int32_t>({1, 2})); } TEST_F(JsonConfigLoaderUnitTest, TestDefaultValue_Mixed) { TEST_F(JsonConfigLoaderUnitTest, testDefaultValue_Mixed) { std::istringstream iss(R"( { "properties": [{ Loading @@ -463,7 +491,7 @@ TEST_F(JsonConfigLoaderUnitTest, TestDefaultValue_Mixed) { auto configs = result.value(); ASSERT_EQ(configs.size(), 1u); const RawPropValues& initialValue = configs[0].initialValue; const RawPropValues& initialValue = configs.begin()->second.initialValue; ASSERT_EQ(initialValue.int32Values, std::vector<int32_t>({1, FUEL_DOOR_REAR_LEFT})); ASSERT_EQ(initialValue.int64Values, std::vector<int64_t>({2, static_cast<int64_t>(FUEL_DOOR_REAR_LEFT)})); Loading @@ -472,7 +500,7 @@ TEST_F(JsonConfigLoaderUnitTest, TestDefaultValue_Mixed) { ASSERT_EQ(initialValue.stringValue, "abcd"); } TEST_F(JsonConfigLoaderUnitTest, TestDefaultValue_FailNotObject) { TEST_F(JsonConfigLoaderUnitTest, testDefaultValue_FailNotObject) { std::istringstream iss(R"( { "properties": [{ Loading @@ -486,7 +514,7 @@ TEST_F(JsonConfigLoaderUnitTest, TestDefaultValue_FailNotObject) { << "DefaultValue is not an object must cause error"; } TEST_F(JsonConfigLoaderUnitTest, TestDefaultValue_FailInvalidType) { TEST_F(JsonConfigLoaderUnitTest, testDefaultValue_FailInvalidType) { std::istringstream iss(R"( { "properties": [{ Loading Loading @@ -521,7 +549,7 @@ TEST_F(JsonConfigLoaderUnitTest, testAreas_Simple) { auto configs = result.value(); ASSERT_EQ(configs.size(), 1u); const VehiclePropConfig& config = configs[0].config; const VehiclePropConfig& config = configs.begin()->second.config; ASSERT_EQ(config.areaConfigs.size(), 1u); const VehicleAreaConfig& areaConfig = config.areaConfigs[0]; ASSERT_EQ(areaConfig.minInt32Value, 1); Loading Loading @@ -554,12 +582,14 @@ TEST_F(JsonConfigLoaderUnitTest, testAreas_DefaultValueForEachArea) { auto configs = result.value(); ASSERT_EQ(configs.size(), 1u); const VehiclePropConfig& config = configs[0].config; const VehiclePropConfig& config = configs.begin()->second.config; ASSERT_EQ(config.areaConfigs.size(), 2u); ASSERT_EQ(config.areaConfigs[0].areaId, HVAC_LEFT); ASSERT_EQ(config.areaConfigs[1].areaId, HVAC_RIGHT); ASSERT_EQ(configs[0].initialAreaValues[HVAC_LEFT], RawPropValues{.int32Values = {1}}); ASSERT_EQ(configs[0].initialAreaValues[HVAC_RIGHT], RawPropValues{.int32Values = {2}}); ASSERT_EQ(configs.begin()->second.initialAreaValues[HVAC_LEFT], RawPropValues{.int32Values = {1}}); ASSERT_EQ(configs.begin()->second.initialAreaValues[HVAC_RIGHT], RawPropValues{.int32Values = {2}}); } TEST_F(JsonConfigLoaderUnitTest, testAreas_FailInvalidTypeForOneAreaValue) { Loading automotive/vehicle/aidl/impl/default_config/config/Android.bp +24 −0 Original line number Diff line number Diff line Loading @@ -21,3 +21,27 @@ filegroup { name: "VehicleHalVendorClusterTestProperties_JSON", srcs: ["VendorClusterTestProperties.json"], } prebuilt_etc { name: "Prebuilt_VehicleHalDefaultProperties_JSON", filename_from_src: true, src: "DefaultProperties.json", sub_dir: "automotive/vhalconfig/", vendor: true, } prebuilt_etc { name: "Prebuilt_VehicleHalTestProperties_JSON", filename_from_src: true, src: "TestProperties.json", sub_dir: "automotive/vhalconfig/", vendor: true, } prebuilt_etc { name: "Prebuilt_VehicleHalVendorClusterTestProperties_JSON", filename_from_src: true, src: "VendorClusterTestProperties.json", sub_dir: "automotive/vhalconfig/", vendor: true, } automotive/vehicle/aidl/impl/default_config/test/DefaultConfigTest.cpp +6 −2 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ #include <gmock/gmock.h> #include <gtest/gtest.h> #include <fstream> #include <unordered_map> namespace android { namespace hardware { Loading @@ -45,7 +46,8 @@ std::string getTestFilePath(const char* filename) { return baseDir + "/" + filename; } Result<std::vector<ConfigDeclaration>> loadConfig(JsonConfigLoader& loader, const char* path) { Result<std::unordered_map<int32_t, ConfigDeclaration>> loadConfig(JsonConfigLoader& loader, const char* path) { std::string configPath = getTestFilePath(path); std::ifstream ifs(configPath.c_str()); if (!ifs) { Loading Loading @@ -89,7 +91,9 @@ TEST(DefaultConfigTest, TestCompatibleWithDefaultConfigHeader) { kVendorClusterTestPropertiesConfigFile})) { auto result = loadConfig(loader, file); ASSERT_TRUE(result.ok()) << result.error().message(); configsFromJson.insert(configsFromJson.end(), result.value().begin(), result.value().end()); for (auto& [propId, configDeclaration] : result.value()) { configsFromJson.push_back(configDeclaration); } } ASSERT_EQ(configsFromHeaderFile.size(), configsFromJson.size()); Loading Loading
automotive/vehicle/aidl/impl/default_config/JsonConfigLoader/include/JsonConfigLoader.h +9 −3 Original line number Diff line number Diff line Loading @@ -89,7 +89,8 @@ class JsonValueParser final { // The main class to parse a VHAL config file in JSON format. class JsonConfigParser { public: android::base::Result<std::vector<ConfigDeclaration>> parseJsonConfig(std::istream& is); android::base::Result<std::unordered_map<int32_t, ConfigDeclaration>> parseJsonConfig( std::istream& is); private: JsonValueParser mValueParser; Loading Loading @@ -155,8 +156,13 @@ class JsonConfigLoader final { public: JsonConfigLoader(); // Loads a JSON file stream and parses it to a list of ConfigDeclarations. android::base::Result<std::vector<ConfigDeclaration>> loadPropConfig(std::istream& is); // Loads a JSON file stream and parses it to a map from propId to ConfigDeclarations. android::base::Result<std::unordered_map<int32_t, ConfigDeclaration>> loadPropConfig( std::istream& is); // Loads a JSON config file and parses it to a map from propId to ConfigDeclarations. android::base::Result<std::unordered_map<int32_t, ConfigDeclaration>> loadPropConfig( const std::string& configPath); private: std::unique_ptr<jsonconfigloader_impl::JsonConfigParser> mParser; Loading
automotive/vehicle/aidl/impl/default_config/JsonConfigLoader/src/JsonConfigLoader.cpp +24 −6 Original line number Diff line number Diff line Loading @@ -25,6 +25,7 @@ #endif // ENABLE_VEHICLE_HAL_TEST_PROPERTIES #include <android-base/strings.h> #include <fstream> namespace android { namespace hardware { Loading Loading @@ -509,25 +510,32 @@ std::optional<ConfigDeclaration> JsonConfigParser::parseEachProperty( return configDecl; } Result<std::vector<ConfigDeclaration>> JsonConfigParser::parseJsonConfig(std::istream& is) { Result<std::unordered_map<int32_t, ConfigDeclaration>> JsonConfigParser::parseJsonConfig( std::istream& is) { Json::CharReaderBuilder builder; Json::Value root; std::vector<ConfigDeclaration> configs; std::unordered_map<int32_t, ConfigDeclaration> configsByPropId; std::string errs; if (!Json::parseFromStream(builder, is, &root, &errs)) { return Error() << "Failed to parse property config file as JSON, error: " << errs; } if (!root.isObject()) { return Error() << "root element must be an object"; } if (!root.isMember("properties") || !root["properties"].isArray()) { return Error() << "Missing 'properties' field in root or the field is not an array"; } Json::Value properties = root["properties"]; std::vector<std::string> errors; for (unsigned int i = 0; i < properties.size(); i++) { if (auto maybeConfig = parseEachProperty(properties[i], &errors); maybeConfig.has_value()) { configs.push_back(std::move(maybeConfig.value())); configsByPropId[maybeConfig.value().config.prop] = std::move(maybeConfig.value()); } } if (!errors.empty()) { return Error() << android::base::Join(errors, '\n'); } return configs; return configsByPropId; } } // namespace jsonconfigloader_impl Loading @@ -536,11 +544,21 @@ JsonConfigLoader::JsonConfigLoader() { mParser = std::make_unique<jsonconfigloader_impl::JsonConfigParser>(); } android::base::Result<std::vector<ConfigDeclaration>> JsonConfigLoader::loadPropConfig( std::istream& is) { android::base::Result<std::unordered_map<int32_t, ConfigDeclaration>> JsonConfigLoader::loadPropConfig(std::istream& is) { return mParser->parseJsonConfig(is); } android::base::Result<std::unordered_map<int32_t, ConfigDeclaration>> JsonConfigLoader::loadPropConfig(const std::string& configPath) { std::ifstream ifs(configPath.c_str()); if (!ifs) { return android::base::Error() << "couldn't open " << configPath << " for parsing."; } return loadPropConfig(ifs); } } // namespace vehicle } // namespace automotive } // namespace hardware Loading
automotive/vehicle/aidl/impl/default_config/JsonConfigLoader/test/JsonConfigLoaderUnitTest.cpp +75 −45 Original line number Diff line number Diff line Loading @@ -38,7 +38,7 @@ class JsonConfigLoaderUnitTest : public ::testing::Test { JsonConfigLoader mLoader; }; TEST_F(JsonConfigLoaderUnitTest, TestBasic) { TEST_F(JsonConfigLoaderUnitTest, testBasic) { std::istringstream iss(R"( { "properties": [{ Loading @@ -53,11 +53,39 @@ TEST_F(JsonConfigLoaderUnitTest, TestBasic) { auto configs = result.value(); ASSERT_EQ(configs.size(), 1u); ASSERT_EQ(configs.begin()->second.config.prop, 291504388); } TEST_F(JsonConfigLoaderUnitTest, testRootNotObject) { std::istringstream iss(R"( [] )"); ASSERT_FALSE(mLoader.loadPropConfig(iss).ok()) << "root is not an object must cause error"; } TEST_F(JsonConfigLoaderUnitTest, testMissingPropertiesField) { std::istringstream iss(R"( { "abcd": 1234 } )"); ASSERT_FALSE(mLoader.loadPropConfig(iss).ok()) << "Missing 'properties' field must cause error"; } TEST_F(JsonConfigLoaderUnitTest, testPropertiesFieldNotArray) { std::istringstream iss(R"( { "properties': {'a': 'b'} } )"); ASSERT_EQ(configs[0].config.prop, 291504388); ASSERT_FALSE(mLoader.loadPropConfig(iss).ok()) << "'properties' field is not an array must cause error"; } TEST_F(JsonConfigLoaderUnitTest, TestPropertyIsEnum) { TEST_F(JsonConfigLoaderUnitTest, testPropertyIsEnum) { std::istringstream iss(R"( { "properties": [{ Loading @@ -72,11 +100,10 @@ TEST_F(JsonConfigLoaderUnitTest, TestPropertyIsEnum) { auto configs = result.value(); ASSERT_EQ(configs.size(), 1u); ASSERT_EQ(configs[0].config.prop, toInt(VehicleProperty::INFO_FUEL_CAPACITY)); ASSERT_EQ(configs.begin()->second.config.prop, toInt(VehicleProperty::INFO_FUEL_CAPACITY)); } TEST_F(JsonConfigLoaderUnitTest, TestPropertyEnum_FailInvalidEnum) { TEST_F(JsonConfigLoaderUnitTest, testPropertyEnum_FailInvalidEnum) { std::istringstream iss(R"( { "properties": [{ Loading @@ -89,7 +116,7 @@ TEST_F(JsonConfigLoaderUnitTest, TestPropertyEnum_FailInvalidEnum) { << "Invalid VehicleProperty enum must cause error"; } TEST_F(JsonConfigLoaderUnitTest, TestPropertyEnum_FailInvalidType) { TEST_F(JsonConfigLoaderUnitTest, testPropertyEnum_FailInvalidType) { std::istringstream iss(R"( { "properties": [{ Loading @@ -102,7 +129,7 @@ TEST_F(JsonConfigLoaderUnitTest, TestPropertyEnum_FailInvalidType) { << "Invalid VehicleProperty type must cause error"; } TEST_F(JsonConfigLoaderUnitTest, TestProperty_FailInvalidJson) { TEST_F(JsonConfigLoaderUnitTest, testProperty_FailInvalidJson) { std::istringstream iss(R"( { "properties": [{ Loading @@ -112,7 +139,7 @@ TEST_F(JsonConfigLoaderUnitTest, TestProperty_FailInvalidJson) { ASSERT_FALSE(mLoader.loadPropConfig(iss).ok()) << "Invalid JSON format must cause error"; } TEST_F(JsonConfigLoaderUnitTest, TestConfigArray) { TEST_F(JsonConfigLoaderUnitTest, testConfigArray) { std::istringstream iss(R"( { "properties": [{ Loading @@ -128,10 +155,10 @@ TEST_F(JsonConfigLoaderUnitTest, TestConfigArray) { auto configs = result.value(); ASSERT_EQ(configs.size(), 1u); ASSERT_EQ(configs[0].config.configArray, std::vector<int>({1, 2, 3})); ASSERT_EQ(configs.begin()->second.config.configArray, std::vector<int>({1, 2, 3})); } TEST_F(JsonConfigLoaderUnitTest, TestConfigArrayConstants) { TEST_F(JsonConfigLoaderUnitTest, testConfigArrayConstants) { std::istringstream iss(R"( { "properties": [{ Loading @@ -147,11 +174,12 @@ TEST_F(JsonConfigLoaderUnitTest, TestConfigArrayConstants) { auto configs = result.value(); ASSERT_EQ(configs.size(), 1u); ASSERT_EQ(configs[0].config.configArray, std::vector<int>({1, 2, FUEL_DOOR_REAR_LEFT})); ASSERT_EQ(configs.begin()->second.config.configArray, std::vector<int>({1, 2, FUEL_DOOR_REAR_LEFT})); } // We have special logic to deal with GALLON and US_GALLON since they share the same value. TEST_F(JsonConfigLoaderUnitTest, TestConfigArrayUnitGallon) { TEST_F(JsonConfigLoaderUnitTest, testConfigArrayUnitGallon) { std::istringstream iss(R"( { "properties": [{ Loading @@ -166,7 +194,7 @@ TEST_F(JsonConfigLoaderUnitTest, TestConfigArrayUnitGallon) { ASSERT_TRUE(result.ok()) << result.error().message(); } TEST_F(JsonConfigLoaderUnitTest, TestConfigArrayUnitUsGallon) { TEST_F(JsonConfigLoaderUnitTest, testConfigArrayUnitUsGallon) { std::istringstream iss(R"( { "properties": [{ Loading @@ -181,7 +209,7 @@ TEST_F(JsonConfigLoaderUnitTest, TestConfigArrayUnitUsGallon) { ASSERT_TRUE(result.ok()) << result.error().message(); } TEST_F(JsonConfigLoaderUnitTest, TestConfigArray_FailInvalidEnum) { TEST_F(JsonConfigLoaderUnitTest, testConfigArray_FailInvalidEnum) { std::istringstream iss(R"( { "properties": [{ Loading @@ -195,7 +223,7 @@ TEST_F(JsonConfigLoaderUnitTest, TestConfigArray_FailInvalidEnum) { << "Invalid enum in ConfigArray must cause error"; } TEST_F(JsonConfigLoaderUnitTest, TestConfigArray_FailNotArray) { TEST_F(JsonConfigLoaderUnitTest, testConfigArray_FailNotArray) { std::istringstream iss(R"( { "properties": [{ Loading @@ -209,7 +237,7 @@ TEST_F(JsonConfigLoaderUnitTest, TestConfigArray_FailNotArray) { << "ConfigArray is not an array must cause error"; } TEST_F(JsonConfigLoaderUnitTest, TestConfigString) { TEST_F(JsonConfigLoaderUnitTest, testConfigString) { std::istringstream iss(R"( { "properties": [{ Loading @@ -225,10 +253,10 @@ TEST_F(JsonConfigLoaderUnitTest, TestConfigString) { auto configs = result.value(); ASSERT_EQ(configs.size(), 1u); ASSERT_EQ(configs[0].config.configString, "test"); ASSERT_EQ(configs.begin()->second.config.configString, "test"); } TEST_F(JsonConfigLoaderUnitTest, TestConfigString_FailNotString) { TEST_F(JsonConfigLoaderUnitTest, testConfigString_FailNotString) { std::istringstream iss(R"( { "properties": [{ Loading @@ -242,7 +270,7 @@ TEST_F(JsonConfigLoaderUnitTest, TestConfigString_FailNotString) { << "ConfigString is not a String must cause error"; } TEST_F(JsonConfigLoaderUnitTest, TestCheckDefaultAccessChangeMode) { TEST_F(JsonConfigLoaderUnitTest, testCheckDefaultAccessChangeMode) { std::istringstream iss(R"( { "properties": [{ Loading @@ -257,12 +285,12 @@ TEST_F(JsonConfigLoaderUnitTest, TestCheckDefaultAccessChangeMode) { auto configs = result.value(); ASSERT_EQ(configs.size(), 1u); const VehiclePropConfig& propConfig = configs[0].config; const VehiclePropConfig& propConfig = configs.begin()->second.config; ASSERT_EQ(propConfig.access, VehiclePropertyAccess::READ); ASSERT_EQ(propConfig.changeMode, VehiclePropertyChangeMode::STATIC); } TEST_F(JsonConfigLoaderUnitTest, TestAccessOverride) { TEST_F(JsonConfigLoaderUnitTest, testAccessOverride) { std::istringstream iss(R"( { "properties": [{ Loading @@ -278,12 +306,12 @@ TEST_F(JsonConfigLoaderUnitTest, TestAccessOverride) { auto configs = result.value(); ASSERT_EQ(configs.size(), 1u); const VehiclePropConfig& propConfig = configs[0].config; const VehiclePropConfig& propConfig = configs.begin()->second.config; ASSERT_EQ(propConfig.access, VehiclePropertyAccess::WRITE); ASSERT_EQ(propConfig.changeMode, VehiclePropertyChangeMode::STATIC); } TEST_F(JsonConfigLoaderUnitTest, TestChangeModeOverride) { TEST_F(JsonConfigLoaderUnitTest, testChangeModeOverride) { std::istringstream iss(R"( { "properties": [{ Loading @@ -299,12 +327,12 @@ TEST_F(JsonConfigLoaderUnitTest, TestChangeModeOverride) { auto configs = result.value(); ASSERT_EQ(configs.size(), 1u); const VehiclePropConfig& propConfig = configs[0].config; const VehiclePropConfig& propConfig = configs.begin()->second.config; ASSERT_EQ(propConfig.access, VehiclePropertyAccess::READ); ASSERT_EQ(propConfig.changeMode, VehiclePropertyChangeMode::ON_CHANGE); } TEST_F(JsonConfigLoaderUnitTest, TestCustomProp) { TEST_F(JsonConfigLoaderUnitTest, testCustomProp) { std::istringstream iss(R"( { "properties": [{ Loading @@ -321,12 +349,12 @@ TEST_F(JsonConfigLoaderUnitTest, TestCustomProp) { auto configs = result.value(); ASSERT_EQ(configs.size(), 1u); const VehiclePropConfig& propConfig = configs[0].config; const VehiclePropConfig& propConfig = configs.begin()->second.config; ASSERT_EQ(propConfig.access, VehiclePropertyAccess::WRITE); ASSERT_EQ(propConfig.changeMode, VehiclePropertyChangeMode::ON_CHANGE); } TEST_F(JsonConfigLoaderUnitTest, TestCustomProp_FailMissingAccess) { TEST_F(JsonConfigLoaderUnitTest, testCustomProp_FailMissingAccess) { std::istringstream iss(R"( { "properties": [{ Loading @@ -340,7 +368,7 @@ TEST_F(JsonConfigLoaderUnitTest, TestCustomProp_FailMissingAccess) { << "Missing access for custom property must cause error"; } TEST_F(JsonConfigLoaderUnitTest, TestCustomProp_FailMissingChangeMode) { TEST_F(JsonConfigLoaderUnitTest, testCustomProp_FailMissingChangeMode) { std::istringstream iss(R"( { "properties": [{ Loading @@ -354,7 +382,7 @@ TEST_F(JsonConfigLoaderUnitTest, TestCustomProp_FailMissingChangeMode) { << "Missing change mode for custom property must cause error"; } TEST_F(JsonConfigLoaderUnitTest, TestMinSampleRate) { TEST_F(JsonConfigLoaderUnitTest, testMinSampleRate) { std::istringstream iss(R"( { "properties": [{ Loading @@ -370,10 +398,10 @@ TEST_F(JsonConfigLoaderUnitTest, TestMinSampleRate) { auto configs = result.value(); ASSERT_EQ(configs.size(), 1u); ASSERT_EQ(configs[0].config.minSampleRate, 1); ASSERT_EQ(configs.begin()->second.config.minSampleRate, 1); } TEST_F(JsonConfigLoaderUnitTest, TestMinSampleRate_FailInvalidType) { TEST_F(JsonConfigLoaderUnitTest, testMinSampleRate_FailInvalidType) { std::istringstream iss(R"( { "properties": [{ Loading @@ -387,7 +415,7 @@ TEST_F(JsonConfigLoaderUnitTest, TestMinSampleRate_FailInvalidType) { << "Wrong type for MinSampleRate must cause error"; } TEST_F(JsonConfigLoaderUnitTest, TestMaxSampleRate) { TEST_F(JsonConfigLoaderUnitTest, testMaxSampleRate) { std::istringstream iss(R"( { "properties": [{ Loading @@ -403,10 +431,10 @@ TEST_F(JsonConfigLoaderUnitTest, TestMaxSampleRate) { auto configs = result.value(); ASSERT_EQ(configs.size(), 1u); ASSERT_EQ(configs[0].config.maxSampleRate, 1); ASSERT_EQ(configs.begin()->second.config.maxSampleRate, 1); } TEST_F(JsonConfigLoaderUnitTest, TestMaxSampleRate_FailInvalidType) { TEST_F(JsonConfigLoaderUnitTest, testMaxSampleRate_FailInvalidType) { std::istringstream iss(R"( { "properties": [{ Loading @@ -420,7 +448,7 @@ TEST_F(JsonConfigLoaderUnitTest, TestMaxSampleRate_FailInvalidType) { << "Wrong type for MaxSampleRate must cause error"; } TEST_F(JsonConfigLoaderUnitTest, TestDefaultValue_Simple) { TEST_F(JsonConfigLoaderUnitTest, testDefaultValue_Simple) { std::istringstream iss(R"( { "properties": [{ Loading @@ -438,10 +466,10 @@ TEST_F(JsonConfigLoaderUnitTest, TestDefaultValue_Simple) { auto configs = result.value(); ASSERT_EQ(configs.size(), 1u); ASSERT_EQ(configs[0].initialValue.int32Values, std::vector<int32_t>({1, 2})); ASSERT_EQ(configs.begin()->second.initialValue.int32Values, std::vector<int32_t>({1, 2})); } TEST_F(JsonConfigLoaderUnitTest, TestDefaultValue_Mixed) { TEST_F(JsonConfigLoaderUnitTest, testDefaultValue_Mixed) { std::istringstream iss(R"( { "properties": [{ Loading @@ -463,7 +491,7 @@ TEST_F(JsonConfigLoaderUnitTest, TestDefaultValue_Mixed) { auto configs = result.value(); ASSERT_EQ(configs.size(), 1u); const RawPropValues& initialValue = configs[0].initialValue; const RawPropValues& initialValue = configs.begin()->second.initialValue; ASSERT_EQ(initialValue.int32Values, std::vector<int32_t>({1, FUEL_DOOR_REAR_LEFT})); ASSERT_EQ(initialValue.int64Values, std::vector<int64_t>({2, static_cast<int64_t>(FUEL_DOOR_REAR_LEFT)})); Loading @@ -472,7 +500,7 @@ TEST_F(JsonConfigLoaderUnitTest, TestDefaultValue_Mixed) { ASSERT_EQ(initialValue.stringValue, "abcd"); } TEST_F(JsonConfigLoaderUnitTest, TestDefaultValue_FailNotObject) { TEST_F(JsonConfigLoaderUnitTest, testDefaultValue_FailNotObject) { std::istringstream iss(R"( { "properties": [{ Loading @@ -486,7 +514,7 @@ TEST_F(JsonConfigLoaderUnitTest, TestDefaultValue_FailNotObject) { << "DefaultValue is not an object must cause error"; } TEST_F(JsonConfigLoaderUnitTest, TestDefaultValue_FailInvalidType) { TEST_F(JsonConfigLoaderUnitTest, testDefaultValue_FailInvalidType) { std::istringstream iss(R"( { "properties": [{ Loading Loading @@ -521,7 +549,7 @@ TEST_F(JsonConfigLoaderUnitTest, testAreas_Simple) { auto configs = result.value(); ASSERT_EQ(configs.size(), 1u); const VehiclePropConfig& config = configs[0].config; const VehiclePropConfig& config = configs.begin()->second.config; ASSERT_EQ(config.areaConfigs.size(), 1u); const VehicleAreaConfig& areaConfig = config.areaConfigs[0]; ASSERT_EQ(areaConfig.minInt32Value, 1); Loading Loading @@ -554,12 +582,14 @@ TEST_F(JsonConfigLoaderUnitTest, testAreas_DefaultValueForEachArea) { auto configs = result.value(); ASSERT_EQ(configs.size(), 1u); const VehiclePropConfig& config = configs[0].config; const VehiclePropConfig& config = configs.begin()->second.config; ASSERT_EQ(config.areaConfigs.size(), 2u); ASSERT_EQ(config.areaConfigs[0].areaId, HVAC_LEFT); ASSERT_EQ(config.areaConfigs[1].areaId, HVAC_RIGHT); ASSERT_EQ(configs[0].initialAreaValues[HVAC_LEFT], RawPropValues{.int32Values = {1}}); ASSERT_EQ(configs[0].initialAreaValues[HVAC_RIGHT], RawPropValues{.int32Values = {2}}); ASSERT_EQ(configs.begin()->second.initialAreaValues[HVAC_LEFT], RawPropValues{.int32Values = {1}}); ASSERT_EQ(configs.begin()->second.initialAreaValues[HVAC_RIGHT], RawPropValues{.int32Values = {2}}); } TEST_F(JsonConfigLoaderUnitTest, testAreas_FailInvalidTypeForOneAreaValue) { Loading
automotive/vehicle/aidl/impl/default_config/config/Android.bp +24 −0 Original line number Diff line number Diff line Loading @@ -21,3 +21,27 @@ filegroup { name: "VehicleHalVendorClusterTestProperties_JSON", srcs: ["VendorClusterTestProperties.json"], } prebuilt_etc { name: "Prebuilt_VehicleHalDefaultProperties_JSON", filename_from_src: true, src: "DefaultProperties.json", sub_dir: "automotive/vhalconfig/", vendor: true, } prebuilt_etc { name: "Prebuilt_VehicleHalTestProperties_JSON", filename_from_src: true, src: "TestProperties.json", sub_dir: "automotive/vhalconfig/", vendor: true, } prebuilt_etc { name: "Prebuilt_VehicleHalVendorClusterTestProperties_JSON", filename_from_src: true, src: "VendorClusterTestProperties.json", sub_dir: "automotive/vhalconfig/", vendor: true, }
automotive/vehicle/aidl/impl/default_config/test/DefaultConfigTest.cpp +6 −2 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ #include <gmock/gmock.h> #include <gtest/gtest.h> #include <fstream> #include <unordered_map> namespace android { namespace hardware { Loading @@ -45,7 +46,8 @@ std::string getTestFilePath(const char* filename) { return baseDir + "/" + filename; } Result<std::vector<ConfigDeclaration>> loadConfig(JsonConfigLoader& loader, const char* path) { Result<std::unordered_map<int32_t, ConfigDeclaration>> loadConfig(JsonConfigLoader& loader, const char* path) { std::string configPath = getTestFilePath(path); std::ifstream ifs(configPath.c_str()); if (!ifs) { Loading Loading @@ -89,7 +91,9 @@ TEST(DefaultConfigTest, TestCompatibleWithDefaultConfigHeader) { kVendorClusterTestPropertiesConfigFile})) { auto result = loadConfig(loader, file); ASSERT_TRUE(result.ok()) << result.error().message(); configsFromJson.insert(configsFromJson.end(), result.value().begin(), result.value().end()); for (auto& [propId, configDeclaration] : result.value()) { configsFromJson.push_back(configDeclaration); } } ASSERT_EQ(configsFromHeaderFile.size(), configsFromJson.size()); Loading