Add unittest for HidlVhalClient.

Test: atest libvhalclient_test
Bug: 214635003
Change-Id: Ia248d7a9a108e9aae653afef2b30cbee58dc36e6
diff --git a/cpp/vhal/client/include/AidlVhalClient.h b/cpp/vhal/client/include/AidlVhalClient.h
index 196d25d..e1c28fb 100644
--- a/cpp/vhal/client/include/AidlVhalClient.h
+++ b/cpp/vhal/client/include/AidlVhalClient.h
@@ -38,11 +38,11 @@
 namespace automotive {
 namespace vhal {
 
-namespace test {
+namespace aidl_test {
 
 class AidlVhalClientTest;
 
-}
+}  // namespace aidl_test
 
 class GetSetValueClient;
 
@@ -79,7 +79,7 @@
             std::shared_ptr<ISubscriptionCallback> callback) override;
 
 private:
-    friend class test::AidlVhalClientTest;
+    friend class aidl_test::AidlVhalClientTest;
 
     class ILinkUnlinkToDeath {
     public:
diff --git a/cpp/vhal/client/include/HidlVhalClient.h b/cpp/vhal/client/include/HidlVhalClient.h
index 7354d1d..9d920d1 100644
--- a/cpp/vhal/client/include/HidlVhalClient.h
+++ b/cpp/vhal/client/include/HidlVhalClient.h
@@ -32,6 +32,12 @@
 namespace automotive {
 namespace vhal {
 
+namespace hidl_test {
+
+class HidlVhalClientTest;
+
+}  // namespace hidl_test
+
 class HidlVhalClient final : public IVhalClient {
 public:
     explicit HidlVhalClient(
@@ -63,6 +69,8 @@
             std::shared_ptr<ISubscriptionCallback> callback) override;
 
 private:
+    friend class hidl_test::HidlVhalClientTest;
+
     class DeathRecipient : public ::android::hardware::hidl_death_recipient {
     public:
         explicit DeathRecipient(HidlVhalClient* client);
diff --git a/cpp/vhal/client/test/AidlVhalClientTest.cpp b/cpp/vhal/client/test/AidlVhalClientTest.cpp
index 3523f42..ed285fc 100644
--- a/cpp/vhal/client/test/AidlVhalClientTest.cpp
+++ b/cpp/vhal/client/test/AidlVhalClientTest.cpp
@@ -32,7 +32,7 @@
 namespace frameworks {
 namespace automotive {
 namespace vhal {
-namespace test {
+namespace aidl_test {
 
 using ::android::base::Result;
 using ::android::hardware::automotive::vehicle::toInt;
@@ -866,7 +866,7 @@
     ASSERT_FALSE(result.ok());
 }
 
-}  // namespace test
+}  // namespace aidl_test
 }  // namespace vhal
 }  // namespace automotive
 }  // namespace frameworks
diff --git a/cpp/vhal/client/test/HidlVhalClientTest.cpp b/cpp/vhal/client/test/HidlVhalClientTest.cpp
new file mode 100644
index 0000000..c0c348d
--- /dev/null
+++ b/cpp/vhal/client/test/HidlVhalClientTest.cpp
@@ -0,0 +1,458 @@
+/*
+ * Copyright (C) 2022 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 "HidlHalPropValue.h"
+#include "HidlVhalClient.h"
+
+#include <aidl/android/hardware/automotive/vehicle/StatusCode.h>
+#include <android-base/result.h>
+#include <android/hardware/automotive/vehicle/2.0/IVehicle.h>
+#include <gtest/gtest.h>
+#include <utils/StrongPointer.h>
+
+#include <VehicleUtils.h>
+
+#include <vector>
+
+namespace android {
+namespace frameworks {
+namespace automotive {
+namespace vhal {
+namespace hidl_test {
+
+using ::android::sp;
+using ::android::base::Result;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::automotive::vehicle::toInt;
+using ::android::hardware::automotive::vehicle::V2_0::IVehicle;
+using ::android::hardware::automotive::vehicle::V2_0::IVehicleCallback;
+using ::android::hardware::automotive::vehicle::V2_0::StatusCode;
+using ::android::hardware::automotive::vehicle::V2_0::SubscribeFlags;
+using ::android::hardware::automotive::vehicle::V2_0::SubscribeOptions;
+using ::android::hardware::automotive::vehicle::V2_0::VehiclePropConfig;
+using ::android::hardware::automotive::vehicle::V2_0::VehiclePropValue;
+
+class MockVhal final : public IVehicle {
+public:
+    Return<void> getAllPropConfigs(IVehicle::getAllPropConfigs_cb callback) override {
+        callback(mPropConfigs);
+        return {};
+    }
+
+    Return<void> getPropConfigs(const hidl_vec<int32_t>& props,
+                                IVehicle::getPropConfigs_cb callback) override {
+        mGetPropConfigsProps = props;
+        callback(mStatus, mPropConfigs);
+        return {};
+    }
+
+    Return<void> get(const VehiclePropValue& requestPropValue, IVehicle::get_cb callback) override {
+        mRequestPropValue = requestPropValue;
+        callback(mStatus, mPropValue);
+        return {};
+    }
+
+    Return<StatusCode> set(const VehiclePropValue& value) override {
+        mRequestPropValue = value;
+        return mStatus;
+    }
+
+    Return<StatusCode> subscribe(const sp<IVehicleCallback>& callback,
+                                 const hidl_vec<SubscribeOptions>& options) override {
+        mSubscribedCallback = callback;
+        mSubscribeOptions = options;
+        return mStatus;
+    }
+
+    Return<StatusCode> unsubscribe([[maybe_unused]] const sp<IVehicleCallback>& callback,
+                                   int32_t propId) override {
+        mUnsubscribedPropId = propId;
+        return mStatus;
+    }
+
+    Return<void> debugDump([[maybe_unused]] IVehicle::debugDump_cb callback) override { return {}; }
+
+    // Test functions
+
+    void setPropConfigs(std::vector<VehiclePropConfig> configs) { mPropConfigs = configs; }
+
+    void setStatus(StatusCode status) { mStatus = status; }
+
+    void setVehiclePropValue(VehiclePropValue value) { mPropValue = value; }
+
+    std::vector<int32_t> getGetPropConfigsProps() { return mGetPropConfigsProps; }
+
+    VehiclePropValue getRequestPropValue() { return mRequestPropValue; }
+
+    std::vector<SubscribeOptions> getSubscribeOptions() { return mSubscribeOptions; }
+
+    int32_t getUnsubscribedPropId() { return mUnsubscribedPropId; }
+
+    void triggerOnPropertyEvent(const std::vector<VehiclePropValue>& values) {
+        mSubscribedCallback->onPropertyEvent(values);
+    }
+
+    void triggerSetErrorEvent(StatusCode status, int32_t propId, int32_t areaId) {
+        mSubscribedCallback->onPropertySetError(status, propId, areaId);
+    }
+
+private:
+    std::vector<VehiclePropConfig> mPropConfigs;
+    StatusCode mStatus = StatusCode::OK;
+    VehiclePropValue mPropValue;
+
+    std::vector<int32_t> mGetPropConfigsProps;
+    VehiclePropValue mRequestPropValue;
+    sp<IVehicleCallback> mSubscribedCallback;
+    std::vector<SubscribeOptions> mSubscribeOptions;
+    int32_t mUnsubscribedPropId;
+};
+
+class MockSubscriptionCallback final : public ISubscriptionCallback {
+public:
+    void onPropertyEvent(const std::vector<std::unique_ptr<IHalPropValue>>& values) override {
+        for (const auto& value : values) {
+            mEventPropIds.push_back(value->getPropId());
+        }
+    }
+    void onPropertySetError(const std::vector<HalPropError>& errors) override { mErrors = errors; }
+
+    std::vector<int32_t> getEventPropIds() { return mEventPropIds; }
+
+    std::vector<HalPropError> getErrors() { return mErrors; }
+
+private:
+    std::vector<int32_t> mEventPropIds;
+    std::vector<HalPropError> mErrors;
+};
+
+class HidlVhalClientTest : public ::testing::Test {
+protected:
+    constexpr static int32_t TEST_PROP_ID = 1;
+    constexpr static int32_t TEST_AREA_ID = 2;
+    constexpr static int32_t TEST_PROP_ID_2 = 3;
+
+    const VehiclePropValue TEST_VALUE{
+            .prop = TEST_PROP_ID,
+            .areaId = TEST_AREA_ID,
+            .value.int32Values = {1},
+    };
+
+    void SetUp() override {
+        mVhal = new MockVhal();
+        mVhalClient = std::make_unique<HidlVhalClient>(mVhal);
+    }
+
+    MockVhal* getVhal() { return mVhal.get(); }
+
+    HidlVhalClient* getClient() { return mVhalClient.get(); }
+
+    void triggerBinderDied() { mVhalClient->onBinderDied(); }
+
+private:
+    sp<MockVhal> mVhal;
+    std::unique_ptr<HidlVhalClient> mVhalClient;
+};
+
+TEST_F(HidlVhalClientTest, testGetValue) {
+    Result<std::unique_ptr<IHalPropValue>> result;
+    Result<std::unique_ptr<IHalPropValue>>* resultPtr = &result;
+    bool gotResult = false;
+    bool* gotResultPtr = &gotResult;
+    auto callback = std::make_shared<HidlVhalClient::GetValueCallbackFunc>(
+            [resultPtr, gotResultPtr](Result<std::unique_ptr<IHalPropValue>> r) {
+                *resultPtr = std::move(r);
+                *gotResultPtr = true;
+            });
+    getVhal()->setVehiclePropValue(TEST_VALUE);
+
+    getClient()->getValue(HidlHalPropValue(TEST_PROP_ID, TEST_AREA_ID), callback);
+
+    ASSERT_TRUE(gotResult);
+    ASSERT_EQ(getVhal()->getRequestPropValue().prop, TEST_PROP_ID);
+    ASSERT_EQ(getVhal()->getRequestPropValue().areaId, TEST_AREA_ID);
+    ASSERT_TRUE(result.ok());
+    auto gotValue = std::move(result.value());
+    ASSERT_EQ(gotValue->getPropId(), TEST_PROP_ID);
+    ASSERT_EQ(gotValue->getAreaId(), TEST_AREA_ID);
+    ASSERT_EQ(gotValue->getInt32Values(), std::vector<int32_t>({1}));
+}
+
+TEST_F(HidlVhalClientTest, testGetValueError) {
+    getVhal()->setStatus(StatusCode::INTERNAL_ERROR);
+
+    Result<std::unique_ptr<IHalPropValue>> result;
+    Result<std::unique_ptr<IHalPropValue>>* resultPtr = &result;
+    bool gotResult = false;
+    bool* gotResultPtr = &gotResult;
+    auto callback = std::make_shared<HidlVhalClient::GetValueCallbackFunc>(
+            [resultPtr, gotResultPtr](Result<std::unique_ptr<IHalPropValue>> r) {
+                *resultPtr = std::move(r);
+                *gotResultPtr = true;
+            });
+
+    getClient()->getValue(HidlHalPropValue(TEST_PROP_ID, TEST_AREA_ID), callback);
+
+    ASSERT_TRUE(gotResult);
+    ASSERT_FALSE(result.ok());
+}
+
+TEST_F(HidlVhalClientTest, testSetValue) {
+    Result<void> result;
+    Result<void>* resultPtr = &result;
+    bool gotResult = false;
+    bool* gotResultPtr = &gotResult;
+    auto callback = std::make_shared<HidlVhalClient::SetValueCallbackFunc>(
+            [resultPtr, gotResultPtr](Result<void> r) {
+                *resultPtr = std::move(r);
+                *gotResultPtr = true;
+            });
+
+    getClient()->setValue(HidlHalPropValue(TEST_PROP_ID, TEST_AREA_ID), callback);
+
+    ASSERT_TRUE(gotResult);
+    ASSERT_EQ(getVhal()->getRequestPropValue().prop, TEST_PROP_ID);
+    ASSERT_EQ(getVhal()->getRequestPropValue().areaId, TEST_AREA_ID);
+    ASSERT_TRUE(result.ok());
+}
+TEST_F(HidlVhalClientTest, testSetValueError) {
+    getVhal()->setStatus(StatusCode::INTERNAL_ERROR);
+
+    Result<void> result;
+    Result<void>* resultPtr = &result;
+    bool gotResult = false;
+    bool* gotResultPtr = &gotResult;
+    auto callback = std::make_shared<HidlVhalClient::SetValueCallbackFunc>(
+            [resultPtr, gotResultPtr](Result<void> r) {
+                *resultPtr = std::move(r);
+                *gotResultPtr = true;
+            });
+
+    getClient()->setValue(HidlHalPropValue(TEST_PROP_ID, TEST_AREA_ID), callback);
+
+    ASSERT_TRUE(gotResult);
+    ASSERT_FALSE(result.ok());
+}
+
+TEST_F(HidlVhalClientTest, testAddOnBinderDiedCallback) {
+    struct Result {
+        bool callbackOneCalled = false;
+        bool callbackTwoCalled = false;
+    } result;
+
+    getClient()->addOnBinderDiedCallback(std::make_shared<HidlVhalClient::OnBinderDiedCallbackFunc>(
+            [&result] { result.callbackOneCalled = true; }));
+    getClient()->addOnBinderDiedCallback(std::make_shared<HidlVhalClient::OnBinderDiedCallbackFunc>(
+            [&result] { result.callbackTwoCalled = true; }));
+    triggerBinderDied();
+
+    ASSERT_TRUE(result.callbackOneCalled);
+    ASSERT_TRUE(result.callbackTwoCalled);
+}
+
+TEST_F(HidlVhalClientTest, testRemoveOnBinderDiedCallback) {
+    struct Result {
+        bool callbackOneCalled = false;
+        bool callbackTwoCalled = false;
+    } result;
+
+    auto callbackOne = std::make_shared<HidlVhalClient::OnBinderDiedCallbackFunc>(
+            [&result] { result.callbackOneCalled = true; });
+    auto callbackTwo = std::make_shared<HidlVhalClient::OnBinderDiedCallbackFunc>(
+            [&result] { result.callbackTwoCalled = true; });
+    getClient()->addOnBinderDiedCallback(callbackOne);
+    getClient()->addOnBinderDiedCallback(callbackTwo);
+    getClient()->removeOnBinderDiedCallback(callbackOne);
+    triggerBinderDied();
+
+    ASSERT_FALSE(result.callbackOneCalled);
+    ASSERT_TRUE(result.callbackTwoCalled);
+}
+
+TEST_F(HidlVhalClientTest, testGetAllPropConfigs) {
+    getVhal()->setPropConfigs({
+            VehiclePropConfig{
+                    .prop = TEST_PROP_ID,
+                    .areaConfigs = {{
+                            .areaId = TEST_AREA_ID,
+                            .minInt32Value = 0,
+                            .maxInt32Value = 1,
+                    }},
+            },
+            VehiclePropConfig{
+                    .prop = TEST_PROP_ID_2,
+            },
+    });
+
+    auto result = getClient()->getAllPropConfigs();
+
+    ASSERT_TRUE(result.ok());
+    std::vector<std::unique_ptr<IHalPropConfig>> configs = std::move(result.value());
+
+    ASSERT_EQ(configs.size(), static_cast<size_t>(2));
+    ASSERT_EQ(configs[0]->getPropId(), TEST_PROP_ID);
+    ASSERT_EQ(configs[0]->getAreaConfigSize(), static_cast<size_t>(1));
+
+    const IHalAreaConfig* areaConfig = configs[0]->getAreaConfigs();
+    ASSERT_EQ(areaConfig->getAreaId(), TEST_AREA_ID);
+    ASSERT_EQ(areaConfig->getMinInt32Value(), 0);
+    ASSERT_EQ(areaConfig->getMaxInt32Value(), 1);
+
+    ASSERT_EQ(configs[1]->getPropId(), TEST_PROP_ID_2);
+    ASSERT_EQ(configs[1]->getAreaConfigSize(), static_cast<size_t>(0));
+}
+
+TEST_F(HidlVhalClientTest, testGetPropConfigs) {
+    getVhal()->setPropConfigs({
+            VehiclePropConfig{
+                    .prop = TEST_PROP_ID,
+                    .areaConfigs = {{
+                            .areaId = TEST_AREA_ID,
+                            .minInt32Value = 0,
+                            .maxInt32Value = 1,
+                    }},
+            },
+            VehiclePropConfig{
+                    .prop = TEST_PROP_ID_2,
+            },
+    });
+
+    std::vector<int32_t> propIds = {TEST_PROP_ID, TEST_PROP_ID_2};
+    auto result = getClient()->getPropConfigs(propIds);
+
+    ASSERT_EQ(getVhal()->getGetPropConfigsProps(), propIds);
+    ASSERT_TRUE(result.ok());
+    std::vector<std::unique_ptr<IHalPropConfig>> configs = std::move(result.value());
+
+    ASSERT_EQ(configs.size(), static_cast<size_t>(2));
+    ASSERT_EQ(configs[0]->getPropId(), TEST_PROP_ID);
+    ASSERT_EQ(configs[0]->getAreaConfigSize(), static_cast<size_t>(1));
+
+    const IHalAreaConfig* areaConfig = configs[0]->getAreaConfigs();
+    ASSERT_EQ(areaConfig->getAreaId(), TEST_AREA_ID);
+    ASSERT_EQ(areaConfig->getMinInt32Value(), 0);
+    ASSERT_EQ(areaConfig->getMaxInt32Value(), 1);
+
+    ASSERT_EQ(configs[1]->getPropId(), TEST_PROP_ID_2);
+    ASSERT_EQ(configs[1]->getAreaConfigSize(), static_cast<size_t>(0));
+}
+
+TEST_F(HidlVhalClientTest, testGetPropConfigsError) {
+    getVhal()->setStatus(StatusCode::INTERNAL_ERROR);
+
+    std::vector<int32_t> propIds = {TEST_PROP_ID, TEST_PROP_ID_2};
+    auto result = getClient()->getPropConfigs(propIds);
+
+    ASSERT_FALSE(result.ok());
+}
+
+TEST_F(HidlVhalClientTest, testSubscribe) {
+    std::vector<::aidl::android::hardware::automotive::vehicle::SubscribeOptions> options = {
+            {
+                    .propId = TEST_PROP_ID,
+                    .areaIds = {TEST_AREA_ID},
+                    .sampleRate = 1.0,
+            },
+            {
+                    .propId = TEST_PROP_ID_2,
+                    .sampleRate = 2.0,
+            },
+    };
+    std::vector<SubscribeOptions> hidlOptions = {
+            {
+                    .propId = TEST_PROP_ID,
+                    .flags = SubscribeFlags::UNDEFINED,
+                    .sampleRate = 1.0,
+            },
+            {
+                    .propId = TEST_PROP_ID_2,
+                    .flags = SubscribeFlags::UNDEFINED,
+                    .sampleRate = 2.0,
+            },
+    };
+
+    auto callback = std::make_shared<MockSubscriptionCallback>();
+    auto subscriptionClient = getClient()->getSubscriptionClient(callback);
+    auto result = subscriptionClient->subscribe(options);
+
+    ASSERT_TRUE(result.ok());
+    ASSERT_EQ(getVhal()->getSubscribeOptions(), hidlOptions);
+
+    getVhal()->triggerOnPropertyEvent(std::vector<VehiclePropValue>{
+            {
+                    .prop = TEST_PROP_ID,
+                    .areaId = TEST_AREA_ID,
+                    .value.int32Values = {1},
+            },
+    });
+
+    ASSERT_EQ(callback->getEventPropIds(), std::vector<int32_t>({TEST_PROP_ID}));
+
+    getVhal()->triggerSetErrorEvent(StatusCode::INTERNAL_ERROR, TEST_PROP_ID, TEST_AREA_ID);
+
+    auto errors = callback->getErrors();
+    ASSERT_EQ(errors.size(), static_cast<size_t>(1));
+    ASSERT_EQ(errors[0].propId, TEST_PROP_ID);
+    ASSERT_EQ(errors[0].areaId, TEST_AREA_ID);
+    ASSERT_EQ(errors[0].status,
+              ::aidl::android::hardware::automotive::vehicle::StatusCode::INTERNAL_ERROR);
+}
+
+TEST_F(HidlVhalClientTest, testSubscribeError) {
+    std::vector<::aidl::android::hardware::automotive::vehicle::SubscribeOptions> options = {
+            {
+                    .propId = TEST_PROP_ID,
+                    .areaIds = {TEST_AREA_ID},
+                    .sampleRate = 1.0,
+            },
+            {
+                    .propId = TEST_PROP_ID_2,
+                    .sampleRate = 2.0,
+            },
+    };
+
+    getVhal()->setStatus(StatusCode::INTERNAL_ERROR);
+    auto callback = std::make_shared<MockSubscriptionCallback>();
+    auto subscriptionClient = getClient()->getSubscriptionClient(callback);
+    auto result = subscriptionClient->subscribe(options);
+
+    ASSERT_FALSE(result.ok());
+}
+
+TEST_F(HidlVhalClientTest, testUnubscribe) {
+    auto callback = std::make_shared<MockSubscriptionCallback>();
+    auto subscriptionClient = getClient()->getSubscriptionClient(callback);
+    auto result = subscriptionClient->unsubscribe({TEST_PROP_ID});
+
+    ASSERT_TRUE(result.ok());
+    ASSERT_EQ(getVhal()->getUnsubscribedPropId(), TEST_PROP_ID);
+}
+
+TEST_F(HidlVhalClientTest, testUnubscribeError) {
+    getVhal()->setStatus(StatusCode::INTERNAL_ERROR);
+    auto callback = std::make_shared<MockSubscriptionCallback>();
+    auto subscriptionClient = getClient()->getSubscriptionClient(callback);
+    auto result = subscriptionClient->unsubscribe({TEST_PROP_ID});
+
+    ASSERT_FALSE(result.ok());
+}
+
+}  // namespace hidl_test
+}  // namespace vhal
+}  // namespace automotive
+}  // namespace frameworks
+}  // namespace android