// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include <algorithm>

#include "base/functional/bind.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/ref_counted.h"
#include "base/run_loop.h"
#include "base/test/mock_callback.h"
#include "base/test/task_environment.h"
#include "media/capture/video/video_capture_device_info.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "services/video_capture/public/cpp/mock_producer.h"
#include "services/video_capture/public/cpp/mock_video_frame_handler.h"
#include "services/video_capture/public/mojom/video_frame_handler.mojom.h"
#include "services/video_capture/shared_memory_virtual_device_mojo_adapter.h"
#include "services/video_capture/virtual_device_enabled_device_factory.h"
#include "testing/gtest/include/gtest/gtest.h"

using testing::_;
using testing::Mock;

namespace video_capture {

namespace {

const std::string kTestDeviceId = "/test/device";
const std::string kTestDeviceName = "Test Device";
const gfx::Size kTestFrameSize = {640 /* width */, 480 /* height */};
const media::VideoPixelFormat kTestPixelFormat =
    media::VideoPixelFormat::PIXEL_FORMAT_I420;

}  // anonymous namespace

class VirtualDeviceTest : public ::testing::Test {
 public:
  VirtualDeviceTest() = default;
  ~VirtualDeviceTest() override = default;

  void SetUp() override {
    device_info_.descriptor.device_id = kTestDeviceId;
    device_info_.descriptor.set_display_name(kTestDeviceName);
    mojo::Remote<mojom::Producer> producer;
    producer_ =
        std::make_unique<MockProducer>(producer.BindNewPipeAndPassReceiver());
    device_adapter_ = std::make_unique<SharedMemoryVirtualDeviceMojoAdapter>(
        std::move(producer));
  }

  void OnFrameBufferReceived(bool valid_buffer_expected, int32_t buffer_id) {
    if (!valid_buffer_expected) {
      EXPECT_EQ(-1, buffer_id);
      return;
    }

    EXPECT_NE(-1, buffer_id);
    received_buffer_ids_.push_back(buffer_id);
  }

  void VerifyAndGetMaxFrameBuffers() {
    base::RunLoop wait_loop;
    EXPECT_CALL(*producer_, DoOnNewBuffer(_, _, _))
        .Times(SharedMemoryVirtualDeviceMojoAdapter::
                   max_buffer_pool_buffer_count())
        .WillRepeatedly([](int32_t buffer_id,
                           media::mojom::VideoBufferHandlePtr* handle,
                           mojom::Producer::OnNewBufferCallback& callback) {
          std::move(callback).Run();
        });
    // Should receive valid buffer for up to the maximum buffer count.
    for (int i = 0;
         i <
         SharedMemoryVirtualDeviceMojoAdapter::max_buffer_pool_buffer_count();
         i++) {
      device_adapter_->RequestFrameBuffer(
          kTestFrameSize, kTestPixelFormat, nullptr,
          base::BindOnce(&VirtualDeviceTest::OnFrameBufferReceived,
                         base::Unretained(this),
                         true /* valid_buffer_expected */));
    }

    // No more buffer available. Invalid buffer id should be returned.
    device_adapter_->RequestFrameBuffer(
        kTestFrameSize, kTestPixelFormat, nullptr,
        base::BindOnce(&VirtualDeviceTest::OnFrameBufferReceived,
                       base::Unretained(this),
                       false /* valid_buffer_expected */));

    wait_loop.RunUntilIdle();
    Mock::VerifyAndClearExpectations(producer_.get());
    EXPECT_EQ(
        SharedMemoryVirtualDeviceMojoAdapter::max_buffer_pool_buffer_count(),
        static_cast<int>(received_buffer_ids_.size()));
  }

 protected:
  std::unique_ptr<SharedMemoryVirtualDeviceMojoAdapter> device_adapter_;
  // ID of buffers received and owned by the producer.
  std::vector<int> received_buffer_ids_;
  std::unique_ptr<MockProducer> producer_;

  media::mojom::VideoFrameInfoPtr CreateValidVideoFrameInfo() {
    auto info = media::mojom::VideoFrameInfo::New();
    info->pixel_format = kTestPixelFormat;
    info->coded_size = kTestFrameSize;
    info->visible_rect = gfx::Rect(kTestFrameSize);
    info->natural_size = kTestFrameSize;
    return info;
  }

 private:
  base::test::SingleThreadTaskEnvironment task_environment_;
  media::VideoCaptureDeviceInfo device_info_;
};

TEST_F(VirtualDeviceTest, OnFrameReadyInBufferWithoutReceiver) {
  // Obtain maximum number of buffers.
  VerifyAndGetMaxFrameBuffers();

  base::RunLoop wait_loop;

  // Release one buffer back to the pool, no consumer hold since there is no
  // receiver.
  device_adapter_->OnFrameReadyInBuffer(received_buffer_ids_.at(0),
                                        CreateValidVideoFrameInfo());

  // Verify there is a buffer available now, without creating a new
  // buffer.
  EXPECT_CALL(*producer_, DoOnNewBuffer(_, _, _)).Times(0);
  device_adapter_->RequestFrameBuffer(
      kTestFrameSize, kTestPixelFormat, nullptr,
      base::BindOnce(&VirtualDeviceTest::OnFrameBufferReceived,
                     base::Unretained(this), true /* valid_buffer_expected */));

  wait_loop.RunUntilIdle();
}

TEST_F(VirtualDeviceTest, OnFrameReadyInBufferWithReceiver) {
  // Obtain maximum number of buffers for the producer.
  VerifyAndGetMaxFrameBuffers();

  // Release all buffers back to consumer, then back to the pool
  // after |Receiver::OnFrameReadyInBuffer| is invoked.
  base::RunLoop wait_loop;
  mojo::PendingRemote<mojom::VideoFrameHandler> handler_remote;
  MockVideoFrameHandler video_frame_handler(
      handler_remote.InitWithNewPipeAndPassReceiver());
  EXPECT_CALL(video_frame_handler, OnStarted());
  EXPECT_CALL(video_frame_handler, DoOnNewBuffer(_, _))
      .Times(
          SharedMemoryVirtualDeviceMojoAdapter::max_buffer_pool_buffer_count());
  EXPECT_CALL(video_frame_handler, DoOnFrameReadyInBuffer(_, _, _))
      .Times(
          SharedMemoryVirtualDeviceMojoAdapter::max_buffer_pool_buffer_count());
  device_adapter_->Start(media::VideoCaptureParams(),
                         std::move(handler_remote));
  for (auto buffer_id : received_buffer_ids_) {
    device_adapter_->OnFrameReadyInBuffer(buffer_id,
                                          CreateValidVideoFrameInfo());
  }
  wait_loop.RunUntilIdle();
  Mock::VerifyAndClearExpectations(&video_frame_handler);

  // Verify that requesting a buffer doesn't create a new one, will reuse
  // the available buffer in the pool.
  base::RunLoop wait_loop2;
  EXPECT_CALL(*producer_, DoOnNewBuffer(_, _, _)).Times(0);
  base::MockCallback<
      mojom::SharedMemoryVirtualDevice::RequestFrameBufferCallback>
      request_frame_buffer_callback;
  EXPECT_CALL(request_frame_buffer_callback, Run)
      .Times(1)
      .WillOnce([this](int32_t buffer_id) {
        // Verify that the returned |buffer_id| is a known buffer ID.
        EXPECT_TRUE(std::ranges::contains(received_buffer_ids_, buffer_id));
      });
  device_adapter_->RequestFrameBuffer(kTestFrameSize, kTestPixelFormat, nullptr,
                                      request_frame_buffer_callback.Get());
  wait_loop2.RunUntilIdle();

  // Verify that when stopping the device, the receiver receives calls to
  // OnBufferRetired() followed by a single call to OnStopped().
  base::RunLoop wait_for_stopped_loop;
  {
    testing::InSequence s;
    EXPECT_CALL(video_frame_handler, DoOnBufferRetired)
        .Times(SharedMemoryVirtualDeviceMojoAdapter::
                   max_buffer_pool_buffer_count());
    EXPECT_CALL(video_frame_handler, OnStopped())
        .WillOnce([&wait_for_stopped_loop]() { wait_for_stopped_loop.Quit(); });
  }
  device_adapter_->Stop();
  wait_for_stopped_loop.Run();
}

class MockDeviceFactory : public DeviceFactory {
 public:
  MockDeviceFactory() = default;
  ~MockDeviceFactory() override = default;

  MOCK_METHOD(void,
              GetDeviceInfos,
              (GetDeviceInfosCallback callback),
              (override));
  MOCK_METHOD(void,
              CreateDevice,
              (const std::string& device_id, CreateDeviceCallback callback),
              (override));
  MOCK_METHOD(void, StopDevice, (const std::string device_id), (override));
  MOCK_METHOD(void,
              AddSharedMemoryVirtualDevice,
              (const media::VideoCaptureDeviceInfo& device_info,
               mojo::PendingRemote<mojom::Producer> producer,
               mojo::PendingReceiver<mojom::SharedMemoryVirtualDevice>
                   virtual_device_receiver),
              (override));
  MOCK_METHOD(void,
              AddTextureVirtualDevice,
              (const media::VideoCaptureDeviceInfo& device_info,
               mojo::PendingReceiver<mojom::TextureVirtualDevice>
                   virtual_device_receiver),
              (override));
  MOCK_METHOD(void,
              AddGpuMemoryBufferVirtualDevice,
              (const media::VideoCaptureDeviceInfo& device_info,
               mojo::PendingReceiver<mojom::GpuMemoryBufferVirtualDevice>
                   virtual_device_receiver),
              (override));
  MOCK_METHOD(void,
              RegisterVirtualDevicesChangedObserver,
              (mojo::PendingRemote<mojom::DevicesChangedObserver> observer,
               bool raise_event_if_virtual_devices_already_present),
              (override));
#if BUILDFLAG(IS_WIN)
  MOCK_METHOD(void, OnGpuInfoUpdate, (const CHROME_LUID& luid), (override));
#endif
};

class VirtualDeviceEnabledDeviceFactoryTest : public ::testing::Test {
 protected:
  VirtualDeviceEnabledDeviceFactoryTest() {
    auto mock_factory = std::make_unique<MockDeviceFactory>();
    mock_factory_ = mock_factory.get();
    factory_ = std::make_unique<VirtualDeviceEnabledDeviceFactory>(
        std::move(mock_factory));
  }

  ~VirtualDeviceEnabledDeviceFactoryTest() override = default;

  base::test::SingleThreadTaskEnvironment task_environment_;
  std::unique_ptr<VirtualDeviceEnabledDeviceFactory> factory_;
  raw_ptr<MockDeviceFactory> mock_factory_ = nullptr;
};

class VirtualDeviceEnabledDeviceFactoryWithoutWrappedFactoryTest
    : public ::testing::Test {
 protected:
  base::test::SingleThreadTaskEnvironment task_environment_;
  std::unique_ptr<VirtualDeviceEnabledDeviceFactory> factory_ =
      std::make_unique<VirtualDeviceEnabledDeviceFactory>(nullptr);
};

TEST_F(VirtualDeviceEnabledDeviceFactoryWithoutWrappedFactoryTest,
       ReturnsNoDevicesWithoutRegisteredVirtualDevices) {
  base::MockCallback<DeviceFactory::GetDeviceInfosCallback> infos_callback;
  EXPECT_CALL(infos_callback, Run)
      .WillOnce([](const std::vector<media::VideoCaptureDeviceInfo>& infos) {
        EXPECT_TRUE(infos.empty());
      });
  factory_->GetDeviceInfos(infos_callback.Get());

  base::MockCallback<DeviceFactory::CreateDeviceCallback> create_callback;
  EXPECT_CALL(create_callback, Run)
      .WillOnce([](DeviceFactory::DeviceInfo info) {
        EXPECT_EQ(
            info.result_code,
            media::VideoCaptureError::kVideoCaptureSystemDeviceIdNotFound);
        EXPECT_EQ(info.device, nullptr);
      });
  factory_->CreateDevice("virtual-chromium-missing-device",
                         create_callback.Get());
}

TEST_F(VirtualDeviceEnabledDeviceFactoryWithoutWrappedFactoryTest,
       RegistersAndCreatesVirtualDevice) {
  const std::string device_id = "virtual-chromium-test-device";
  media::VideoCaptureDeviceInfo device_info;
  device_info.descriptor.device_id = device_id;

  mojo::PendingRemote<mojom::Producer> producer;
  MockProducer mock_producer(producer.InitWithNewPipeAndPassReceiver());
  mojo::Remote<mojom::SharedMemoryVirtualDevice> virtual_device;
  factory_->AddSharedMemoryVirtualDevice(
      device_info, std::move(producer),
      virtual_device.BindNewPipeAndPassReceiver());
  virtual_device.FlushForTesting();
  ASSERT_TRUE(virtual_device.is_connected());

  base::MockCallback<DeviceFactory::GetDeviceInfosCallback> infos_callback;
  EXPECT_CALL(infos_callback, Run)
      .WillOnce([&](const std::vector<media::VideoCaptureDeviceInfo>& infos) {
        ASSERT_EQ(infos.size(), 1u);
        EXPECT_EQ(infos.front().descriptor.device_id, device_id);
      });
  factory_->GetDeviceInfos(infos_callback.Get());

  base::MockCallback<DeviceFactory::CreateDeviceCallback> create_callback;
  EXPECT_CALL(create_callback, Run)
      .WillOnce([](DeviceFactory::DeviceInfo info) {
        EXPECT_EQ(info.result_code, media::VideoCaptureError::kNone);
        EXPECT_NE(info.device, nullptr);
      });
  factory_->CreateDevice(device_id, create_callback.Get());
}

// Tests that when an underlying device creation succeeds, any old virtual
// device connection with the same device ID is severed.
TEST_F(VirtualDeviceEnabledDeviceFactoryTest,
       CreateDeviceSucceedsOldVirtualDeviceConnectionSevered) {
  const std::string device_id = "virtual-chromium-test-device";

  // Register the virtual device first by having GetDeviceInfos return empty
  EXPECT_CALL(*mock_factory_, GetDeviceInfos)
      .WillOnce([](DeviceFactory::GetDeviceInfosCallback callback) {
        std::move(callback).Run(std::vector<media::VideoCaptureDeviceInfo>());
      });

  media::VideoCaptureDeviceInfo device_info;
  device_info.descriptor.device_id = device_id;
  mojo::PendingRemote<mojom::Producer> producer;
  MockProducer mock_producer(producer.InitWithNewPipeAndPassReceiver());
  mojo::Remote<mojom::SharedMemoryVirtualDevice> virtual_device;

  factory_->AddSharedMemoryVirtualDevice(
      device_info, std::move(producer),
      virtual_device.BindNewPipeAndPassReceiver());
  virtual_device.FlushForTesting();

  // Call CreateDevice, mock the underlying factory to succeed
  base::RunLoop run_loop;
  EXPECT_CALL(*mock_factory_, CreateDevice(device_id, _))
      .WillOnce([](const std::string& device_id,
                   DeviceFactory::CreateDeviceCallback callback) {
        DeviceFactory::DeviceInfo info{nullptr,
                                       media::VideoCaptureError::kNone};
        std::move(callback).Run(std::move(info));
      });

  base::MockCallback<DeviceFactory::CreateDeviceCallback> create_callback;
  EXPECT_CALL(create_callback, Run)
      .WillOnce([&run_loop](DeviceFactory::DeviceInfo info) {
        EXPECT_EQ(info.result_code, media::VideoCaptureError::kNone);
        run_loop.Quit();
      });

  factory_->CreateDevice(device_id, create_callback.Get());
  run_loop.Run();

  // Verify that the virtual device connection is severed
  base::RunLoop disconnect_loop;
  virtual_device.set_disconnect_handler(disconnect_loop.QuitClosure());
  disconnect_loop.Run();

  EXPECT_FALSE(virtual_device.is_connected());
}

// Tests that when an underlying device creation fails with
// kVideoCaptureSystemDeviceIdNotFound, the factory falls back to the registered
// virtual device and does NOT sever its connection.
TEST_F(VirtualDeviceEnabledDeviceFactoryTest,
       CreateDeviceFailsOldVirtualDeviceConnectionNotSevered) {
  const std::string device_id = "virtual-chromium-test-device";

  // Register the virtual device first
  EXPECT_CALL(*mock_factory_, GetDeviceInfos)
      .WillOnce([](DeviceFactory::GetDeviceInfosCallback callback) {
        std::move(callback).Run(std::vector<media::VideoCaptureDeviceInfo>());
      });

  media::VideoCaptureDeviceInfo device_info;
  device_info.descriptor.device_id = device_id;
  mojo::PendingRemote<mojom::Producer> producer;
  MockProducer mock_producer(producer.InitWithNewPipeAndPassReceiver());
  mojo::Remote<mojom::SharedMemoryVirtualDevice> virtual_device;

  factory_->AddSharedMemoryVirtualDevice(
      device_info, std::move(producer),
      virtual_device.BindNewPipeAndPassReceiver());
  virtual_device.FlushForTesting();

  // Call CreateDevice, mock the underlying factory to fail with
  // kVideoCaptureSystemDeviceIdNotFound
  base::RunLoop run_loop;
  EXPECT_CALL(*mock_factory_, CreateDevice(device_id, _))
      .WillOnce([](const std::string& device_id,
                   DeviceFactory::CreateDeviceCallback callback) {
        DeviceFactory::DeviceInfo info{
            nullptr,
            media::VideoCaptureError::kVideoCaptureSystemDeviceIdNotFound};
        std::move(callback).Run(std::move(info));
      });

  base::MockCallback<DeviceFactory::CreateDeviceCallback> create_callback;
  EXPECT_CALL(create_callback, Run)
      .WillOnce([&run_loop](DeviceFactory::DeviceInfo info) {
        // Falls back to the virtual device, so it should succeed!
        EXPECT_EQ(info.result_code, media::VideoCaptureError::kNone);
        EXPECT_NE(info.device, nullptr);
        run_loop.Quit();
      });

  factory_->CreateDevice(device_id, create_callback.Get());
  run_loop.Run();

  // Verify that the virtual device is NOT severed
  virtual_device.FlushForTesting();
  EXPECT_TRUE(virtual_device.is_connected());
}

// Tests that when an underlying device creation fails with
// kVideoCaptureSystemDeviceIdNotFound, and no virtual device is registered with
// that ID, the factory returns the original failure.
TEST_F(VirtualDeviceEnabledDeviceFactoryTest,
       CreateDeviceFailsNoVirtualDeviceFallback) {
  const std::string device_id = "virtual-chromium-test-device";

  // Call CreateDevice without registering any virtual device
  base::RunLoop run_loop;
  EXPECT_CALL(*mock_factory_, CreateDevice(device_id, _))
      .WillOnce([](const std::string& device_id,
                   DeviceFactory::CreateDeviceCallback callback) {
        DeviceFactory::DeviceInfo info{
            nullptr,
            media::VideoCaptureError::kVideoCaptureSystemDeviceIdNotFound};
        std::move(callback).Run(std::move(info));
      });

  base::MockCallback<DeviceFactory::CreateDeviceCallback> create_callback;
  EXPECT_CALL(create_callback, Run)
      .WillOnce([&run_loop](DeviceFactory::DeviceInfo info) {
        // Returns the original failure since there is no fallback
        EXPECT_EQ(
            info.result_code,
            media::VideoCaptureError::kVideoCaptureSystemDeviceIdNotFound);
        EXPECT_EQ(info.device, nullptr);
        run_loop.Quit();
      });

  factory_->CreateDevice(device_id, create_callback.Get());
  run_loop.Run();
}

// Tests that when an underlying device creation fails with an error other than
// not found, any old virtual device connection is severed and the factory
// returns the failure (no fallback).
TEST_F(VirtualDeviceEnabledDeviceFactoryTest,
       CreateDeviceFailsWithOtherErrorOldVirtualDeviceSevered) {
  const std::string device_id = "virtual-chromium-test-device";

  // Register the virtual device first
  EXPECT_CALL(*mock_factory_, GetDeviceInfos)
      .WillOnce([](DeviceFactory::GetDeviceInfosCallback callback) {
        std::move(callback).Run(std::vector<media::VideoCaptureDeviceInfo>());
      });

  media::VideoCaptureDeviceInfo device_info;
  device_info.descriptor.device_id = device_id;
  mojo::PendingRemote<mojom::Producer> producer;
  MockProducer mock_producer(producer.InitWithNewPipeAndPassReceiver());
  mojo::Remote<mojom::SharedMemoryVirtualDevice> virtual_device;

  factory_->AddSharedMemoryVirtualDevice(
      device_info, std::move(producer),
      virtual_device.BindNewPipeAndPassReceiver());
  virtual_device.FlushForTesting();
  ASSERT_TRUE(virtual_device.is_connected());

  // Call CreateDevice, mock underlying factory to fail with a different error
  // (e.g. SecondCreateDenied)
  base::RunLoop run_loop;
  EXPECT_CALL(*mock_factory_, CreateDevice(device_id, _))
      .WillOnce([](const std::string& device_id,
                   DeviceFactory::CreateDeviceCallback callback) {
        DeviceFactory::DeviceInfo info{
            nullptr, media::VideoCaptureError::
                         kVideoCaptureDeviceFactorySecondCreateDenied};
        std::move(callback).Run(std::move(info));
      });

  base::MockCallback<DeviceFactory::CreateDeviceCallback> create_callback;
  EXPECT_CALL(create_callback, Run)
      .WillOnce([&run_loop](DeviceFactory::DeviceInfo info) {
        // Returns the failure code, no fallback should occur!
        EXPECT_EQ(info.result_code,
                  media::VideoCaptureError::
                      kVideoCaptureDeviceFactorySecondCreateDenied);
        EXPECT_EQ(info.device, nullptr);
        run_loop.Quit();
      });

  factory_->CreateDevice(device_id, create_callback.Get());
  run_loop.Run();

  // Verify that the virtual device connection is severed
  base::RunLoop disconnect_loop;
  virtual_device.set_disconnect_handler(disconnect_loop.QuitClosure());
  disconnect_loop.Run();

  EXPECT_FALSE(virtual_device.is_connected());
}

TEST_F(VirtualDeviceEnabledDeviceFactoryTest,
       RejectVirtualDeviceWithInvalidIdPrefix) {
  media::VideoCaptureDeviceInfo device_info;
  device_info.descriptor.device_id = "invalid-id";
  device_info.descriptor.set_display_name("Test Device");

  mojo::PendingRemote<mojom::Producer> producer;
  MockProducer mock_producer(producer.InitWithNewPipeAndPassReceiver());
  mojo::Remote<mojom::SharedMemoryVirtualDevice> virtual_device;

  factory_->AddSharedMemoryVirtualDevice(
      device_info, std::move(producer),
      virtual_device.BindNewPipeAndPassReceiver());

  base::RunLoop disconnect_loop;
  virtual_device.set_disconnect_handler(disconnect_loop.QuitClosure());
  disconnect_loop.Run();

  EXPECT_FALSE(virtual_device.is_connected());
}

TEST_F(VirtualDeviceEnabledDeviceFactoryTest,
       RejectVirtualDeviceWithInvalidModelId) {
  media::VideoCaptureDeviceInfo device_info;
  device_info.descriptor.device_id = "chromium-virtual";
  device_info.descriptor.model_id = "0123:4567";

  mojo::PendingRemote<mojom::Producer> producer;
  MockProducer mock_producer(producer.InitWithNewPipeAndPassReceiver());
  mojo::Remote<mojom::SharedMemoryVirtualDevice> virtual_device;

  factory_->AddSharedMemoryVirtualDevice(
      device_info, std::move(producer),
      virtual_device.BindNewPipeAndPassReceiver());

  base::RunLoop disconnect_loop;
  virtual_device.set_disconnect_handler(disconnect_loop.QuitClosure());
  disconnect_loop.Run();

  EXPECT_FALSE(virtual_device.is_connected());
}

TEST_F(VirtualDeviceEnabledDeviceFactoryTest,
       RejectVirtualDeviceWithForbiddenDisplayNamePrefix) {
  media::VideoCaptureDeviceInfo device_info;
  device_info.descriptor.device_id = "virtual-chromium-device";
  device_info.descriptor.set_display_name("Real Camera");

  mojo::PendingRemote<mojom::Producer> producer;
  MockProducer mock_producer(producer.InitWithNewPipeAndPassReceiver());
  mojo::Remote<mojom::SharedMemoryVirtualDevice> virtual_device;

  factory_->AddSharedMemoryVirtualDevice(
      device_info, std::move(producer),
      virtual_device.BindNewPipeAndPassReceiver());

  base::RunLoop disconnect_loop;
  virtual_device.set_disconnect_handler(disconnect_loop.QuitClosure());
  disconnect_loop.Run();

  EXPECT_FALSE(virtual_device.is_connected());
}

}  // namespace video_capture
