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