1 // Copyright 2019 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "chrome/browser/chromeos/printing/usb_printer_detector.h"
6
7 #include <utility>
8 #include <vector>
9
10 #include "base/bind.h"
11 #include "base/run_loop.h"
12 #include "base/test/task_environment.h"
13 #include "mojo/public/cpp/bindings/pending_remote.h"
14 #include "services/device/public/cpp/test/fake_usb_device_info.h"
15 #include "services/device/public/cpp/test/fake_usb_device_manager.h"
16 #include "services/device/public/mojom/usb_device.mojom.h"
17 #include "services/device/public/mojom/usb_manager.mojom.h"
18 #include "testing/gtest/include/gtest/gtest.h"
19
20 namespace chromeos {
21 namespace {
22
23 constexpr uint8_t kPrinterInterfaceClass = 7;
24 constexpr uint8_t kPrinterInterfaceSubclass = 1;
25 constexpr uint8_t kPrinterIppUsbProtocol = 4;
26
27 constexpr uint8_t kPrinterUsbProtocol = 0xff;
28 constexpr uint16_t kUsbVenderId = 0x02ad;
29 constexpr uint16_t kUsbProductId = 0x138c;
30 constexpr uint8_t kUsbDeviceClass = 0x09;
31
CreateFakeUsbPrinter(bool is_ipp_supported)32 scoped_refptr<device::FakeUsbDeviceInfo> CreateFakeUsbPrinter(
33 bool is_ipp_supported) {
34 std::vector<device::mojom::UsbConfigurationInfoPtr> configs;
35 configs.push_back(device::mojom::UsbConfigurationInfo::New());
36 configs[0]->interfaces.push_back(device::mojom::UsbInterfaceInfo::New());
37
38 auto alternate = device::mojom::UsbAlternateInterfaceInfo::New();
39 alternate->class_code = kPrinterInterfaceClass;
40 alternate->subclass_code = kPrinterInterfaceSubclass;
41 alternate->protocol_code =
42 is_ipp_supported ? kPrinterIppUsbProtocol : kPrinterUsbProtocol;
43
44 configs[0]->interfaces[0]->alternates.push_back(std::move(alternate));
45 return base::MakeRefCounted<device::FakeUsbDeviceInfo>(
46 kUsbVenderId, kUsbProductId, kUsbDeviceClass, std::move(configs));
47 }
48
49 class UsbPrinterDetectorTest : public testing::Test {
50 protected:
51 class FakePrinterDetectorClient {
52 public:
53 FakePrinterDetectorClient() = default;
54
WaitForPrinters()55 void WaitForPrinters() {
56 base::RunLoop run_loop;
57 done_callback_ = run_loop.QuitClosure();
58 run_loop.Run();
59 }
60
OnPrintersFound(const std::vector<PrinterDetector::DetectedPrinter> & printers)61 void OnPrintersFound(
62 const std::vector<PrinterDetector::DetectedPrinter>& printers) {
63 if (done_callback_)
64 std::move(done_callback_).Run();
65 }
66
67 private:
68 base::OnceClosure done_callback_;
69 };
70
UsbPrinterDetectorTest()71 UsbPrinterDetectorTest() {
72 mojo::PendingRemote<device::mojom::UsbDeviceManager> manager;
73 usb_manager_.AddReceiver(manager.InitWithNewPipeAndPassReceiver());
74
75 detector_ = UsbPrinterDetector::CreateForTesting(std::move(manager));
76 detector_->RegisterPrintersFoundCallback(
77 base::BindRepeating(&FakePrinterDetectorClient::OnPrintersFound,
78 base::Unretained(&detector_client_)));
79
80 fake_non_printer_ = base::MakeRefCounted<device::FakeUsbDeviceInfo>(
81 kUsbVenderId, kUsbProductId);
82 fake_printer_ = CreateFakeUsbPrinter(false);
83 fake_printer_ipp_ = CreateFakeUsbPrinter(true);
84
85 base::RunLoop().RunUntilIdle();
86 }
87
88 base::test::TaskEnvironment task_environment_;
89 std::unique_ptr<UsbPrinterDetector> detector_;
90 FakePrinterDetectorClient detector_client_;
91 device::FakeUsbDeviceManager usb_manager_;
92 scoped_refptr<device::FakeUsbDeviceInfo> fake_non_printer_;
93 scoped_refptr<device::FakeUsbDeviceInfo> fake_printer_;
94 scoped_refptr<device::FakeUsbDeviceInfo> fake_printer_ipp_;
95 };
96
97 // Test GetPrinters().
TEST_F(UsbPrinterDetectorTest,GetPrinters)98 TEST_F(UsbPrinterDetectorTest, GetPrinters) {
99 EXPECT_EQ(0u, detector_->GetPrinters().size());
100
101 usb_manager_.AddDevice(fake_non_printer_);
102 usb_manager_.AddDevice(fake_printer_);
103 usb_manager_.AddDevice(fake_printer_ipp_);
104
105 detector_client_.WaitForPrinters();
106 EXPECT_EQ(1u, detector_->GetPrinters().size());
107
108 detector_client_.WaitForPrinters();
109 EXPECT_EQ(2u, detector_->GetPrinters().size());
110 }
111
112 // Test OnPrintersFound callback on deviceAdded/Removed.
TEST_F(UsbPrinterDetectorTest,OnPrintersFoundCallback)113 TEST_F(UsbPrinterDetectorTest, OnPrintersFoundCallback) {
114 EXPECT_EQ(0u, detector_->GetPrinters().size());
115
116 usb_manager_.AddDevice(fake_non_printer_);
117 usb_manager_.AddDevice(fake_printer_);
118 usb_manager_.AddDevice(fake_printer_ipp_);
119
120 detector_client_.WaitForPrinters();
121 EXPECT_EQ(1u, detector_->GetPrinters().size());
122
123 detector_client_.WaitForPrinters();
124 EXPECT_EQ(2u, detector_->GetPrinters().size());
125
126 usb_manager_.RemoveDevice(fake_non_printer_);
127 usb_manager_.RemoveDevice(fake_printer_);
128 usb_manager_.RemoveDevice(fake_printer_ipp_);
129
130 detector_client_.WaitForPrinters();
131 EXPECT_EQ(1u, detector_->GetPrinters().size());
132
133 detector_client_.WaitForPrinters();
134 EXPECT_EQ(0u, detector_->GetPrinters().size());
135 }
136
137 } // namespace
138 } // namespace chromeos
139