Add checkPropValue in VehicleUtils.

Test: atest VehicleHalVehicleUtilsTest
Bug: 200737967

Change-Id: I0e6eed7d085af2a45448efa845e3e8f66c0a84ce
diff --git a/automotive/vehicle/aidl/impl/utils/common/include/VehicleUtils.h b/automotive/vehicle/aidl/impl/utils/common/include/VehicleUtils.h
index 63eb747..c3e8168 100644
--- a/automotive/vehicle/aidl/impl/utils/common/include/VehicleUtils.h
+++ b/automotive/vehicle/aidl/impl/utils/common/include/VehicleUtils.h
@@ -240,6 +240,46 @@
     return toScopedAStatus(result, getErrorCode(result), additionalErrorMsg);
 }
 
+// Check whether the value is valid according to config.
+// We check for the following:
+// *  If the type is INT32, {@code value.int32Values} must contain one element.
+// *  If the type is INT32_VEC, {@code value.int32Values} must contain at least one element.
+// *  If the type is INT64, {@code value.int64Values} must contain one element.
+// *  If the type is INT64_VEC, {@code value.int64Values} must contain at least one element.
+// *  If the type is FLOAT, {@code value.floatValues} must contain one element.
+// *  If the type is FLOAT_VEC, {@code value.floatValues} must contain at least one element.
+// *  If the type is MIXED, see checkVendorMixedPropValue.
+::android::base::Result<void> checkPropValue(
+        const ::aidl::android::hardware::automotive::vehicle::VehiclePropValue& value,
+        const ::aidl::android::hardware::automotive::vehicle::VehiclePropConfig* config);
+
+// Check whether the Mixed type value is valid according to config.
+// We check for the following:
+// *  configArray[1] + configArray[2] + configArray[3] must be equal to the number of
+//    {@code value.int32Values} elements.
+// *  configArray[4] + configArray[5] must be equal to the number of {@code value.int64Values}
+//    elements.
+// *  configArray[6] + configArray[7] must be equal to the number of {@code value.floatValues}
+//    elements.
+// *  configArray[8] must be equal to the number of {@code value.byteValues} elements.
+::android::base::Result<void> checkVendorMixedPropValue(
+        const ::aidl::android::hardware::automotive::vehicle::VehiclePropValue& value,
+        const ::aidl::android::hardware::automotive::vehicle::VehiclePropConfig* config);
+
+// Check whether the value is within the configured range.
+// We check for the following types:
+// *  If type is INT32 or INT32_VEC, all {@code value.int32Values} elements must be within
+//    {@code minInt32Value} and {@code maxInt32Value} if either of them is not 0.
+// *  If type is INT64 or INT64_VEC, all {@code value.int64Values} elements must be within
+//    {@code minInt64Value} and {@code maxInt64Value} if either of them is not 0.
+// *  If type is FLOAT or FLOAT_VEC, all {@code value.floatValues} elements must be within
+//    {@code minFloatValues} and {@code maxFloatValues} if either of them is not 0.
+// We don't check other types. If more checks are required, they should be added in VehicleHardware
+// implementation.
+::android::base::Result<void> checkValueRange(
+        const ::aidl::android::hardware::automotive::vehicle::VehiclePropValue& value,
+        const ::aidl::android::hardware::automotive::vehicle::VehicleAreaConfig* config);
+
 }  // namespace vehicle
 }  // namespace automotive
 }  // namespace hardware
diff --git a/automotive/vehicle/aidl/impl/utils/common/src/VehicleUtils.cpp b/automotive/vehicle/aidl/impl/utils/common/src/VehicleUtils.cpp
new file mode 100644
index 0000000..5abde8d
--- /dev/null
+++ b/automotive/vehicle/aidl/impl/utils/common/src/VehicleUtils.cpp
@@ -0,0 +1,210 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "VehicleUtils.h"
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+
+using ::aidl::android::hardware::automotive::vehicle::VehicleAreaConfig;
+using ::aidl::android::hardware::automotive::vehicle::VehiclePropConfig;
+using ::aidl::android::hardware::automotive::vehicle::VehiclePropertyGroup;
+using ::aidl::android::hardware::automotive::vehicle::VehiclePropertyType;
+using ::aidl::android::hardware::automotive::vehicle::VehiclePropValue;
+using ::android::base::Error;
+using ::android::base::Result;
+using ::ndk::ScopedAStatus;
+
+Result<void> checkPropValue(const VehiclePropValue& value, const VehiclePropConfig* config) {
+    int32_t property = value.prop;
+    VehiclePropertyType type = getPropType(property);
+    switch (type) {
+        case VehiclePropertyType::BOOLEAN:
+            [[fallthrough]];
+        case VehiclePropertyType::INT32:
+            if (value.value.int32Values.size() != 1) {
+                return Error() << "expect 1 int32Values for INT32 type";
+            }
+            break;
+        case VehiclePropertyType::INT32_VEC:
+            if (value.value.int32Values.size() < 1) {
+                return Error() << "expect >=1 int32Values for INT32_VEC type";
+            }
+            break;
+        case VehiclePropertyType::INT64:
+            if (value.value.int64Values.size() != 1) {
+                return Error() << "expect 1 int64Values for INT64 type";
+            }
+            break;
+        case VehiclePropertyType::INT64_VEC:
+            if (value.value.int64Values.size() < 1) {
+                return Error() << "expect >=1 int64Values for INT64_VEC type";
+            }
+            break;
+        case VehiclePropertyType::FLOAT:
+            if (value.value.floatValues.size() != 1) {
+                return Error() << "expect 1 floatValues for FLOAT type";
+            }
+            break;
+        case VehiclePropertyType::FLOAT_VEC:
+            if (value.value.floatValues.size() < 1) {
+                return Error() << "expect >=1 floatValues for FLOAT_VEC type";
+            }
+            break;
+        case VehiclePropertyType::BYTES:
+            // We allow setting an empty bytes array.
+            break;
+        case VehiclePropertyType::STRING:
+            // We allow setting an empty string.
+            break;
+        case VehiclePropertyType::MIXED:
+            if (getPropGroup(property) == VehiclePropertyGroup::VENDOR) {
+                // We only checks vendor mixed properties.
+                return checkVendorMixedPropValue(value, config);
+            }
+            break;
+        default:
+            return Error() << "unknown property type: " << toInt(type);
+    }
+    return {};
+}
+
+Result<void> checkVendorMixedPropValue(const VehiclePropValue& value,
+                                       const VehiclePropConfig* config) {
+    auto configArray = config->configArray;
+    // configArray[0], 1 indicates the property has a String value, we allow the string value to
+    // be empty.
+
+    size_t int32Count = 0;
+    // configArray[1], 1 indicates the property has a Boolean value.
+    if (configArray[1] == 1) {
+        int32Count++;
+    }
+    // configArray[2], 1 indicates the property has an Integer value.
+    if (configArray[2] == 1) {
+        int32Count++;
+    }
+    // configArray[3], the number indicates the size of Integer[] in the property.
+    int32Count += static_cast<size_t>(configArray[3]);
+    size_t int32Size = value.value.int32Values.size();
+    if (int32Size != int32Count) {
+        return Error() << "invalid mixed property, got " << int32Size << " int32Values, expect "
+                       << int32Count;
+    }
+
+    size_t int64Count = 0;
+    // configArray[4], 1 indicates the property has a Long value.
+    if (configArray[4] == 1) {
+        int64Count++;
+    }
+    // configArray[5], the number indicates the size of Long[] in the property.
+    int64Count += static_cast<size_t>(configArray[5]);
+    size_t int64Size = value.value.int64Values.size();
+    if (int64Size != int64Count) {
+        return Error() << "invalid mixed property, got " << int64Size << " int64Values, expect "
+                       << int64Count;
+    }
+
+    size_t floatCount = 0;
+    // configArray[6], 1 indicates the property has a Float value.
+    if (configArray[6] == 1) {
+        floatCount++;
+    }
+    // configArray[7], the number indicates the size of Float[] in the property.
+    floatCount += static_cast<size_t>(configArray[7]);
+    size_t floatSize = value.value.floatValues.size();
+    if (floatSize != floatCount) {
+        return Error() << "invalid mixed property, got " << floatSize << " floatValues, expect "
+                       << floatCount;
+    }
+
+    // configArray[8], the number indicates the size of byte[] in the property.
+    size_t byteSize = value.value.byteValues.size();
+    size_t byteCount = static_cast<size_t>(configArray[8]);
+    if (byteCount != 0 && byteSize != byteCount) {
+        return Error() << "invalid mixed property, got " << byteSize << " byteValues, expect "
+                       << byteCount;
+    }
+    return {};
+}
+
+Result<void> checkValueRange(const VehiclePropValue& value, const VehicleAreaConfig* areaConfig) {
+    if (areaConfig == nullptr) {
+        return {};
+    }
+    int32_t property = value.prop;
+    VehiclePropertyType type = getPropType(property);
+    switch (type) {
+        case VehiclePropertyType::INT32:
+            [[fallthrough]];
+        case VehiclePropertyType::INT32_VEC:
+            if (areaConfig->minInt32Value == 0 && areaConfig->maxInt32Value == 0) {
+                break;
+            }
+            for (int32_t int32Value : value.value.int32Values) {
+                if (int32Value < areaConfig->minInt32Value ||
+                    int32Value > areaConfig->maxInt32Value) {
+                    return Error() << "int32Value: " << int32Value
+                                   << " out of range, min: " << areaConfig->minInt32Value
+                                   << " max: " << areaConfig->maxInt32Value;
+                }
+            }
+            break;
+        case VehiclePropertyType::INT64:
+            [[fallthrough]];
+        case VehiclePropertyType::INT64_VEC:
+            if (areaConfig->minInt64Value == 0 && areaConfig->maxInt64Value == 0) {
+                break;
+            }
+            for (int64_t int64Value : value.value.int64Values) {
+                if (int64Value < areaConfig->minInt64Value ||
+                    int64Value > areaConfig->maxInt64Value) {
+                    return Error() << "int64Value: " << int64Value
+                                   << " out of range, min: " << areaConfig->minInt64Value
+                                   << " max: " << areaConfig->maxInt64Value;
+                }
+            }
+            break;
+        case VehiclePropertyType::FLOAT:
+            [[fallthrough]];
+        case VehiclePropertyType::FLOAT_VEC:
+            if (areaConfig->minFloatValue == 0.f && areaConfig->maxFloatValue == 0.f) {
+                break;
+            }
+            for (float floatValue : value.value.floatValues) {
+                if (floatValue < areaConfig->minFloatValue ||
+                    floatValue > areaConfig->maxFloatValue) {
+                    return Error() << "floatValue: " << floatValue
+                                   << " out of range, min: " << areaConfig->minFloatValue
+                                   << " max: " << areaConfig->maxFloatValue;
+                }
+            }
+            break;
+        default:
+            // We don't check the rest of property types. Additional logic needs to be added if
+            // required in VehicleHardware, e.g. you might want to check the range for mixed
+            // property.
+            break;
+    }
+    return {};
+}
+
+}  // namespace vehicle
+}  // namespace automotive
+}  // namespace hardware
+}  // namespace android
diff --git a/automotive/vehicle/aidl/impl/utils/common/test/Android.bp b/automotive/vehicle/aidl/impl/utils/common/test/Android.bp
index dd43712..250b331 100644
--- a/automotive/vehicle/aidl/impl/utils/common/test/Android.bp
+++ b/automotive/vehicle/aidl/impl/utils/common/test/Android.bp
@@ -27,6 +27,7 @@
         "libgtest",
         "libgmock",
     ],
+    header_libs: ["VehicleHalTestUtilHeaders"],
     defaults: ["VehicleHalDefaults"],
     test_suites: ["device-tests"],
 }
diff --git a/automotive/vehicle/aidl/impl/utils/common/test/VehicleUtilsTest.cpp b/automotive/vehicle/aidl/impl/utils/common/test/VehicleUtilsTest.cpp
index 131eb3b..de8b26d 100644
--- a/automotive/vehicle/aidl/impl/utils/common/test/VehicleUtilsTest.cpp
+++ b/automotive/vehicle/aidl/impl/utils/common/test/VehicleUtilsTest.cpp
@@ -16,6 +16,7 @@
 
 #include <ConcurrentQueue.h>
 #include <PropertyUtils.h>
+#include <TestPropertyUtils.h>
 #include <VehicleUtils.h>
 
 #include <gtest/gtest.h>
@@ -29,6 +30,8 @@
 namespace automotive {
 namespace vehicle {
 
+namespace {
+
 using ::aidl::android::hardware::automotive::vehicle::VehicleArea;
 using ::aidl::android::hardware::automotive::vehicle::VehicleAreaConfig;
 using ::aidl::android::hardware::automotive::vehicle::VehiclePropConfig;
@@ -37,6 +40,427 @@
 using ::aidl::android::hardware::automotive::vehicle::VehiclePropertyType;
 using ::aidl::android::hardware::automotive::vehicle::VehiclePropValue;
 
+struct InvalidPropValueTestCase {
+    std::string name;
+    VehiclePropValue value;
+    bool valid = false;
+    VehiclePropConfig config;
+};
+
+constexpr int32_t int32Prop = toInt(VehicleProperty::INFO_MODEL_YEAR);
+constexpr int32_t int32VecProp = toInt(VehicleProperty::INFO_FUEL_TYPE);
+constexpr int32_t int64Prop = toInt(VehicleProperty::ANDROID_EPOCH_TIME);
+constexpr int32_t int64VecProp = toInt(VehicleProperty::WHEEL_TICK);
+constexpr int32_t floatProp = toInt(VehicleProperty::ENV_OUTSIDE_TEMPERATURE);
+constexpr int32_t floatVecProp = toInt(VehicleProperty::HVAC_TEMPERATURE_VALUE_SUGGESTION);
+
+std::vector<InvalidPropValueTestCase> getInvalidPropValuesTestCases() {
+    return std::vector<InvalidPropValueTestCase>(
+            {
+                    InvalidPropValueTestCase{
+                            .name = "int32_normal",
+                            .value =
+                                    {
+                                            .prop = int32Prop,
+                                            .value.int32Values = {0},
+                                    },
+                            .valid = true,
+                    },
+                    InvalidPropValueTestCase{
+                            .name = "int32_no_value",
+                            .value =
+                                    {
+                                            .prop = int32Prop,
+                                    },
+                    },
+                    InvalidPropValueTestCase{
+                            .name = "int32_more_than_one_value",
+                            .value =
+                                    {
+                                            .prop = int32Prop,
+                                            .value.int32Values = {0, 1},
+                                    },
+                    },
+                    InvalidPropValueTestCase{
+                            .name = "int32_vec_normal",
+                            .value =
+                                    {
+                                            .prop = int32VecProp,
+                                            .value.int32Values = {0, 1},
+                                    },
+                            .valid = true,
+                    },
+                    InvalidPropValueTestCase{
+                            .name = "int32_vec_no_value",
+                            .value =
+                                    {
+                                            .prop = int32VecProp,
+                                    },
+                    },
+                    InvalidPropValueTestCase{
+                            .name = "int64_normal",
+                            .value =
+                                    {
+                                            .prop = int64Prop,
+                                            .value.int64Values = {0},
+                                    },
+                            .valid = true,
+                    },
+                    InvalidPropValueTestCase{
+                            .name = "int64_no_value",
+                            .value =
+                                    {
+                                            .prop = int64Prop,
+                                    },
+                    },
+                    InvalidPropValueTestCase{
+                            .name = "int64_more_than_one_value",
+                            .value =
+                                    {
+                                            .prop = int64Prop,
+                                            .value.int64Values = {0, 1},
+                                    },
+                    },
+                    InvalidPropValueTestCase{
+                            .name = "int64_vec_normal",
+                            .value =
+                                    {
+                                            .prop = int64VecProp,
+                                            .value.int64Values = {0, 1},
+                                    },
+                            .valid = true,
+                    },
+                    InvalidPropValueTestCase{
+                            .name = "int64_vec_no_value",
+                            .value =
+                                    {
+                                            .prop = int64VecProp,
+                                    },
+                    },
+                    InvalidPropValueTestCase{
+                            .name = "float_normal",
+                            .value =
+                                    {
+                                            .prop = floatProp,
+                                            .value.floatValues = {0.0},
+                                    },
+                            .valid = true,
+                    },
+                    InvalidPropValueTestCase{
+                            .name = "float_no_value",
+                            .value =
+                                    {
+                                            .prop = floatProp,
+                                    },
+                    },
+                    InvalidPropValueTestCase{
+                            .name = "float_more_than_one_value",
+                            .value =
+                                    {
+                                            .prop = floatProp,
+                                            .value.floatValues = {0.0, 1.0},
+                                    },
+                    },
+                    InvalidPropValueTestCase{
+                            .name = "float_vec_normal",
+                            .value =
+                                    {
+                                            .prop = floatVecProp,
+                                            .value.floatValues = {0.0, 1.0},
+                                    },
+                            .valid = true,
+                    },
+                    InvalidPropValueTestCase{
+                            .name = "float_vec_no_value",
+                            .value =
+                                    {
+                                            .prop = floatVecProp,
+                                    },
+                    },
+                    InvalidPropValueTestCase{
+                            .name = "mixed_normal",
+                            .value =
+                                    {
+                                            .prop = kMixedTypePropertyForTest,
+                                            // Expect 3 values.
+                                            .value.int32Values = {0, 1, 2},
+                                            // Expect 2 values.
+                                            .value.int64Values = {0, 1},
+                                            // Expect 2 values.
+                                            .value.floatValues = {0.0, 1.0},
+                                            // Expect 1 value.
+                                            .value.byteValues = {static_cast<uint8_t>(0)},
+                                    },
+                            .config =
+                                    {
+                                            .prop = kMixedTypePropertyForTest,
+                                            .configArray = {0, 1, 1, 1, 1, 1, 1, 1, 1},
+                                    },
+                            .valid = true,
+                    },
+                    InvalidPropValueTestCase{
+                            .name = "mixed_mismatch_int32_values_count",
+                            .value =
+                                    {
+                                            .prop = kMixedTypePropertyForTest,
+                                            // Expect 3 values.
+                                            .value.int32Values = {0, 1},
+                                            // Expect 2 values.
+                                            .value.int64Values = {0, 1},
+                                            // Expect 2 values.
+                                            .value.floatValues = {0.0, 1.0},
+                                            // Expect 1 value.
+                                            .value.byteValues = {static_cast<uint8_t>(0)},
+                                    },
+                            .config =
+                                    {
+                                            .prop = kMixedTypePropertyForTest,
+                                            .configArray = {0, 1, 1, 1, 1, 1, 1, 1, 1},
+                                    },
+                    },
+                    InvalidPropValueTestCase{
+                            .name = "mixed_mismatch_int64_values_count",
+                            .value =
+                                    {
+                                            .prop = kMixedTypePropertyForTest,
+                                            // Expect 3 values.
+                                            .value.int32Values = {0, 1, 2},
+                                            // Expect 2 values.
+                                            .value.int64Values = {0},
+                                            // Expect 2 values.
+                                            .value.floatValues = {0.0, 1.0},
+                                            // Expect 1 value.
+                                            .value.byteValues = {static_cast<uint8_t>(0)},
+                                    },
+                            .config =
+                                    {
+                                            .prop = kMixedTypePropertyForTest,
+                                            .configArray = {0, 1, 1, 1, 1, 1, 1, 1, 1},
+                                    },
+                    },
+                    InvalidPropValueTestCase{
+                            .name = "mixed_mismatch_float_values_count",
+                            .value =
+                                    {
+                                            .prop = kMixedTypePropertyForTest,
+                                            // Expect 3 values.
+                                            .value.int32Values = {0, 1, 2},
+                                            // Expect 2 values.
+                                            .value.int64Values = {0, 1},
+                                            // Expect 2 values.
+                                            .value.floatValues = {0.0},
+                                            // Expect 1 value.
+                                            .value.byteValues = {static_cast<uint8_t>(0)},
+                                    },
+                            .config =
+                                    {
+                                            .prop = kMixedTypePropertyForTest,
+                                            .configArray = {0, 1, 1, 1, 1, 1, 1, 1, 1},
+                                    },
+                    },
+                    InvalidPropValueTestCase{
+                            .name = "mixed_mismatch_byte_values_count",
+                            .value =
+                                    {
+                                            .prop = kMixedTypePropertyForTest,
+                                            // Expect 3 values.
+                                            .value.int32Values = {0, 1, 2},
+                                            // Expect 2 values.
+                                            .value.int64Values = {0, 1},
+                                            // Expect 2 values.
+                                            .value.floatValues = {0.0, 1.0},
+                                            // Expect 1 value.
+                                            .value.byteValues = {static_cast<uint8_t>(0),
+                                                                 static_cast<uint8_t>(1)},
+                                    },
+                            .config =
+                                    {
+                                            .prop = kMixedTypePropertyForTest,
+                                            .configArray = {0, 1, 1, 1, 1, 1, 1, 1, 1},
+                                    },
+                    },
+            });
+}
+
+struct InvalidValueRangeTestCase {
+    std::string name;
+    VehiclePropValue value;
+    bool valid = false;
+    VehicleAreaConfig config;
+};
+
+std::vector<InvalidValueRangeTestCase> getInvalidValueRangeTestCases() {
+    return std::vector<InvalidValueRangeTestCase>({{
+            InvalidValueRangeTestCase{
+                    .name = "int32_normal",
+                    .value =
+                            {
+                                    .prop = int32Prop,
+                                    .value.int32Values = {0},
+                            },
+                    .valid = true,
+                    .config =
+                            {
+                                    .minInt32Value = 0,
+                                    .maxInt32Value = 10,
+                            },
+            },
+            InvalidValueRangeTestCase{
+                    .name = "int32_vec_normal",
+                    .value =
+                            {
+                                    .prop = int32VecProp,
+                                    .value.int32Values = {0, 1},
+                            },
+                    .valid = true,
+                    .config =
+                            {
+                                    .minInt32Value = 0,
+                                    .maxInt32Value = 10,
+                            },
+            },
+            InvalidValueRangeTestCase{
+                    .name = "int32_vec_underflow",
+                    .value =
+                            {
+                                    .prop = int32VecProp,
+                                    .value.int32Values = {-1, 1},
+                            },
+
+                    .config =
+                            {
+                                    .minInt32Value = 0,
+                                    .maxInt32Value = 10,
+                            },
+            },
+            InvalidValueRangeTestCase{
+                    .name = "int32_vec_overflow",
+                    .value =
+                            {
+                                    .prop = int32VecProp,
+                                    .value.int32Values = {0, 100},
+                            },
+                    .config =
+                            {
+                                    .minInt32Value = 0,
+                                    .maxInt32Value = 10,
+                            },
+            },
+            InvalidValueRangeTestCase{
+                    .name = "int64_normal",
+                    .value =
+                            {
+                                    .prop = int64Prop,
+                                    .value.int64Values = {0},
+                            },
+                    .valid = true,
+                    .config =
+                            {
+                                    .minInt64Value = 0,
+                                    .maxInt64Value = 10,
+                            },
+            },
+            InvalidValueRangeTestCase{
+                    .name = "int64_vec_normal",
+                    .value =
+                            {
+                                    .prop = int64VecProp,
+                                    .value.int64Values = {0, 1},
+                            },
+                    .valid = true,
+                    .config =
+                            {
+                                    .minInt64Value = 0,
+                                    .maxInt64Value = 10,
+                            },
+            },
+            InvalidValueRangeTestCase{
+                    .name = "int64_vec_underflow",
+                    .value =
+                            {
+                                    .prop = int64VecProp,
+                                    .value.int64Values = {-1, 1},
+                            },
+
+                    .config =
+                            {
+                                    .minInt64Value = 0,
+                                    .maxInt64Value = 10,
+                            },
+            },
+            InvalidValueRangeTestCase{
+                    .name = "int64_vec_overflow",
+                    .value =
+                            {
+                                    .prop = int64VecProp,
+                                    .value.int64Values = {0, 100},
+                            },
+                    .config =
+                            {
+                                    .minInt64Value = 0,
+                                    .maxInt64Value = 10,
+                            },
+            },
+            InvalidValueRangeTestCase{
+                    .name = "float_normal",
+                    .value =
+                            {
+                                    .prop = floatProp,
+                                    .value.floatValues = {0.0},
+                            },
+                    .valid = true,
+                    .config =
+                            {
+                                    .minFloatValue = 0.0,
+                                    .maxFloatValue = 10.0,
+                            },
+            },
+            InvalidValueRangeTestCase{
+                    .name = "float_vec_normal",
+                    .value =
+                            {
+                                    .prop = floatVecProp,
+                                    .value.floatValues = {0.0, 10.0},
+                            },
+                    .valid = true,
+                    .config =
+                            {
+                                    .minFloatValue = 0.0,
+                                    .maxFloatValue = 10.0,
+                            },
+            },
+            InvalidValueRangeTestCase{
+                    .name = "float_vec_underflow",
+                    .value =
+                            {
+                                    .prop = floatVecProp,
+                                    .value.floatValues = {-0.1, 1.1},
+                            },
+
+                    .config =
+                            {
+                                    .minFloatValue = 0.0,
+                                    .maxFloatValue = 10.0,
+                            },
+            },
+            InvalidValueRangeTestCase{
+                    .name = "float_vec_overflow",
+                    .value =
+                            {
+                                    .prop = floatVecProp,
+                                    .value.floatValues = {0.0, 10.1},
+                            },
+                    .config =
+                            {
+                                    .minFloatValue = 0.0,
+                                    .maxFloatValue = 10.0,
+                            },
+            },
+    }});
+}
+
+}  // namespace
+
 TEST(VehicleUtilsTest, testToInt) {
     int areaGlobal = toInt(VehicleArea::GLOBAL);
 
@@ -335,6 +759,40 @@
     t.join();
 }
 
+class InvalidPropValueTest : public testing::TestWithParam<InvalidPropValueTestCase> {};
+
+INSTANTIATE_TEST_SUITE_P(InvalidPropValueTests, InvalidPropValueTest,
+                         testing::ValuesIn(getInvalidPropValuesTestCases()),
+                         [](const testing::TestParamInfo<InvalidPropValueTest::ParamType>& info) {
+                             return info.param.name;
+                         });
+
+TEST_P(InvalidPropValueTest, testCheckPropValue) {
+    InvalidPropValueTestCase tc = GetParam();
+
+    // Config is not used for non-mixed types.
+    auto result = checkPropValue(tc.value, &tc.config);
+
+    ASSERT_EQ(tc.valid, result.ok());
+}
+
+class InvalidValueRangeTest : public testing::TestWithParam<InvalidValueRangeTestCase> {};
+
+INSTANTIATE_TEST_SUITE_P(InvalidValueRangeTests, InvalidValueRangeTest,
+                         testing::ValuesIn(getInvalidValueRangeTestCases()),
+                         [](const testing::TestParamInfo<InvalidValueRangeTest::ParamType>& info) {
+                             return info.param.name;
+                         });
+
+TEST_P(InvalidValueRangeTest, testCheckValueRange) {
+    InvalidValueRangeTestCase tc = GetParam();
+
+    // Config is not used for non-mixed types.
+    auto result = checkValueRange(tc.value, &tc.config);
+
+    ASSERT_EQ(tc.valid, result.ok());
+}
+
 }  // namespace vehicle
 }  // namespace automotive
 }  // namespace hardware