| // Copyright 2018 The Chromium OS Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include <linux/cec-funcs.h> |
| |
| #include <memory> |
| #include <utility> |
| #include <vector> |
| |
| #include <base/bind.h> |
| #include <base/macros.h> |
| #include <gmock/gmock.h> |
| |
| #include "cecservice/cec_device_mock.h" |
| #include "cecservice/cec_fd_mock.h" |
| #include "cecservice/cec_manager.h" |
| #include "cecservice/udev_mock.h" |
| |
| using ::testing::_; |
| using ::testing::ByMove; |
| using ::testing::DoAll; |
| using ::testing::Invoke; |
| using ::testing::Mock; |
| using ::testing::NiceMock; |
| using ::testing::Return; |
| using ::testing::SaveArg; |
| using ::testing::SetArgPointee; |
| |
| namespace cecservice { |
| |
| namespace { |
| void Copy(std::vector<TvPowerStatus>* out, |
| const std::vector<TvPowerStatus>& in) { |
| *out = in; |
| } |
| } // namespace |
| |
| class CecManagerTest : public ::testing::Test { |
| public: |
| CecManagerTest(); |
| ~CecManagerTest() = default; |
| |
| protected: |
| CecDeviceFactoryMock cec_factory_mock_; |
| Udev::DeviceCallback device_added_callback_; |
| Udev::DeviceCallback device_removed_callback_; |
| std::unique_ptr<UdevMock> udev_mock_ = std::make_unique<UdevMock>(); |
| NiceMock<UdevFactoryMock> udev_factory_mock_; |
| |
| private: |
| DISALLOW_COPY_AND_ASSIGN(CecManagerTest); |
| }; |
| |
| CecManagerTest::CecManagerTest() { |
| ON_CALL(udev_factory_mock_, Create(_, _)) |
| .WillByDefault( |
| Invoke([&](const Udev::DeviceCallback& device_added_callback, |
| const Udev::DeviceCallback& device_removed_callback) { |
| device_added_callback_ = device_added_callback; |
| device_removed_callback_ = device_removed_callback; |
| |
| return std::move(udev_mock_); |
| })); |
| } |
| |
| TEST_F(CecManagerTest, TestEnumerateAndCreate) { |
| std::vector<base::FilePath> devices = {base::FilePath("/dev/cec0"), |
| base::FilePath("/dev/cec1")}; |
| EXPECT_CALL(*udev_mock_, EnumerateDevices(_)) |
| .WillOnce(DoAll(SetArgPointee<0>(devices), Return(true))); |
| |
| EXPECT_CALL(cec_factory_mock_, Create(base::FilePath("/dev/cec0"))) |
| .WillOnce(Return(ByMove(std::make_unique<CecDeviceMock>()))); |
| EXPECT_CALL(cec_factory_mock_, Create(base::FilePath("/dev/cec1"))) |
| .WillOnce(Return(ByMove(std::make_unique<CecDeviceMock>()))); |
| |
| auto cec_manager = |
| std::make_unique<CecManager>(udev_factory_mock_, cec_factory_mock_); |
| } |
| |
| TEST_F(CecManagerTest, TestAddRemoveDevice) { |
| EXPECT_CALL(*udev_mock_, EnumerateDevices(_)).WillOnce(Return(true)); |
| auto cec_manager = |
| std::make_unique<CecManager>(udev_factory_mock_, cec_factory_mock_); |
| |
| // Test device add. |
| CecDeviceMock* device_mock = nullptr; |
| EXPECT_CALL(cec_factory_mock_, Create(base::FilePath("/dev/cec0"))) |
| .WillOnce(Invoke([&](const base::FilePath&) { |
| auto mock = std::make_unique<CecDeviceMock>(); |
| device_mock = mock.get(); |
| return mock; |
| })); |
| device_added_callback_.Run(base::FilePath("/dev/cec0")); |
| |
| // Test removal. |
| EXPECT_CALL(*device_mock, DestructorCalled()); |
| // Remove device. |
| device_removed_callback_.Run(base::FilePath("/dev/cec0")); |
| // Make sure that the device is now destroyed. |
| EXPECT_TRUE(Mock::VerifyAndClearExpectations(device_mock)); |
| } |
| |
| TEST_F(CecManagerTest, TestCommandForwarding) { |
| std::vector<base::FilePath> devices = {base::FilePath("/dev/cec0")}; |
| EXPECT_CALL(*udev_mock_, EnumerateDevices(_)) |
| .WillOnce(DoAll(SetArgPointee<0>(devices), Return(true))); |
| |
| CecDeviceMock* device_mock = nullptr; |
| EXPECT_CALL(cec_factory_mock_, Create(base::FilePath("/dev/cec0"))) |
| .WillOnce(Invoke([&](const base::FilePath&) { |
| auto mock = std::make_unique<CecDeviceMock>(); |
| device_mock = mock.get(); |
| return mock; |
| })); |
| |
| auto cec_manager = |
| std::make_unique<CecManager>(udev_factory_mock_, cec_factory_mock_); |
| |
| EXPECT_CALL(*device_mock, SetStandBy()); |
| cec_manager->SetStandBy(); |
| |
| EXPECT_CALL(*device_mock, SetWakeUp()); |
| cec_manager->SetWakeUp(); |
| } |
| |
| TEST_F(CecManagerTest, TestPowerQuery) { |
| EXPECT_CALL(*udev_mock_, EnumerateDevices(_)) |
| .WillOnce(DoAll(SetArgPointee<0>(std::vector<base::FilePath>(1)), |
| Return(true))); |
| |
| CecDeviceMock* cec_mock = nullptr; |
| EXPECT_CALL(cec_factory_mock_, Create(_)) |
| .WillOnce(Invoke([&](const base::FilePath&) { |
| auto mock = std::make_unique<CecDeviceMock>(); |
| cec_mock = mock.get(); |
| return mock; |
| })); |
| |
| auto cec_manager = |
| std::make_unique<CecManager>(udev_factory_mock_, cec_factory_mock_); |
| |
| CecDevice::GetTvPowerStatusCallback callback; |
| EXPECT_CALL(*cec_mock, GetTvPowerStatus(_)).WillOnce(::SaveArg<0>(&callback)); |
| |
| std::vector<TvPowerStatus> result; |
| cec_manager->GetTvsPowerStatus(base::Bind(Copy, &result)); |
| |
| // Respond. |
| callback.Run(kTvPowerStatusToStandBy); |
| |
| ASSERT_EQ(1u, result.size()); |
| EXPECT_EQ(kTvPowerStatusToStandBy, result[0]); |
| } |
| |
| TEST_F(CecManagerTest, TestDeviceRemovalWhileTvPowerQueryIsOngoing) { |
| EXPECT_CALL(*udev_mock_, EnumerateDevices(_)) |
| .WillOnce(DoAll(SetArgPointee<0>(std::vector<base::FilePath>{ |
| base::FilePath("/dev/cec0")}), |
| Return(true))); |
| |
| EXPECT_CALL(cec_factory_mock_, Create(_)) |
| .WillOnce(Return(ByMove(std::make_unique<NiceMock<CecDeviceMock>>()))); |
| |
| auto cec_manager = |
| std::make_unique<CecManager>(udev_factory_mock_, cec_factory_mock_); |
| |
| // We expect to get a vector of length 0 in response, in order to check for |
| // that, set initial vector's length to 1. |
| std::vector<TvPowerStatus> result(1); |
| cec_manager->GetTvsPowerStatus(base::Bind(Copy, &result)); |
| |
| // Remove the device. |
| device_removed_callback_.Run(base::FilePath("/dev/cec0")); |
| |
| // We should get an empty answer. |
| EXPECT_EQ(0u, result.size()); |
| } |
| |
| } // namespace cecservice |