1 // Copyright 2018 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 <string>
6 #include <utility>
7 
8 #include "base/command_line.h"
9 #include "base/unguessable_token.h"
10 #include "content/browser/serial/serial_test_utils.h"
11 #include "content/public/browser/content_browser_client.h"
12 #include "content/public/browser/serial_chooser.h"
13 #include "content/public/browser/serial_delegate.h"
14 #include "content/public/common/content_client.h"
15 #include "content/public/common/content_switches.h"
16 #include "content/public/test/browser_test.h"
17 #include "content/public/test/browser_test_utils.h"
18 #include "content/public/test/content_browser_test.h"
19 #include "content/public/test/content_browser_test_utils.h"
20 #include "content/shell/browser/shell.h"
21 #include "services/device/public/cpp/test/fake_serial_port_manager.h"
22 #include "testing/gmock/include/gmock/gmock.h"
23 #include "testing/gtest/include/gtest/gtest.h"
24 
25 using testing::_;
26 using testing::ByMove;
27 using testing::Exactly;
28 using testing::Return;
29 
30 namespace content {
31 
32 namespace {
33 
34 class SerialTest : public ContentBrowserTest {
35  public:
SerialTest()36   SerialTest() {
37     ON_CALL(delegate(), GetPortManager).WillByDefault(Return(&port_manager_));
38   }
39 
40   ~SerialTest() override = default;
41 
SetUpCommandLine(base::CommandLine * command_line)42   void SetUpCommandLine(base::CommandLine* command_line) override {
43     ContentBrowserTest::SetUpCommandLine(command_line);
44     command_line->AppendSwitch(
45         switches::kEnableExperimentalWebPlatformFeatures);
46   }
47 
SetUpOnMainThread()48   void SetUpOnMainThread() override {
49     original_client_ = SetBrowserClientForTesting(&test_client_);
50   }
51 
TearDownOnMainThread()52   void TearDownOnMainThread() override {
53     if (original_client_)
54       SetBrowserClientForTesting(original_client_);
55   }
56 
delegate()57   MockSerialDelegate& delegate() { return test_client_.delegate(); }
port_manager()58   device::FakeSerialPortManager* port_manager() { return &port_manager_; }
59 
60  private:
61   SerialTestContentBrowserClient test_client_;
62   ContentBrowserClient* original_client_ = nullptr;
63   device::FakeSerialPortManager port_manager_;
64 };
65 
66 }  // namespace
67 
IN_PROC_BROWSER_TEST_F(SerialTest,GetPorts)68 IN_PROC_BROWSER_TEST_F(SerialTest, GetPorts) {
69   EXPECT_TRUE(NavigateToURL(shell(), GetTestUrl(nullptr, "simple_page.html")));
70 
71   // Three ports are added but only two will have permission granted.
72   for (size_t i = 0; i < 3; i++) {
73     auto port = device::mojom::SerialPortInfo::New();
74     port->token = base::UnguessableToken::Create();
75     port_manager()->AddPort(std::move(port));
76   }
77 
78   EXPECT_CALL(delegate(), HasPortPermission(_, _))
79       .WillOnce(Return(true))
80       .WillOnce(Return(false))
81       .WillOnce(Return(true));
82 
83   EXPECT_EQ(
84       2, EvalJs(shell(),
85                 R"(navigator.serial.getPorts().then(ports => ports.length))"));
86 }
87 
IN_PROC_BROWSER_TEST_F(SerialTest,RequestPort)88 IN_PROC_BROWSER_TEST_F(SerialTest, RequestPort) {
89   EXPECT_TRUE(NavigateToURL(shell(), GetTestUrl(nullptr, "simple_page.html")));
90 
91   EXPECT_CALL(delegate(), CanRequestPortPermission).WillOnce(Return(true));
92 
93   auto port = device::mojom::SerialPortInfo::New();
94   port->token = base::UnguessableToken::Create();
95   EXPECT_CALL(delegate(), RunChooserInternal)
96       .WillOnce(Return(ByMove(std::move(port))));
97 
98   EXPECT_EQ(true, EvalJs(shell(),
99                          R"((async () => {
100                            let port = await navigator.serial.requestPort({});
101                            return port instanceof SerialPort;
102                          })())"));
103 }
104 
IN_PROC_BROWSER_TEST_F(SerialTest,DisallowRequestPort)105 IN_PROC_BROWSER_TEST_F(SerialTest, DisallowRequestPort) {
106   EXPECT_TRUE(NavigateToURL(shell(), GetTestUrl(nullptr, "simple_page.html")));
107 
108   EXPECT_CALL(delegate(), CanRequestPortPermission(_)).WillOnce(Return(false));
109   EXPECT_CALL(delegate(), RunChooserInternal).Times(Exactly(0));
110 
111   EXPECT_EQ(false, EvalJs(shell(),
112                           R"((async () => {
113                             try {
114                               await navigator.serial.requestPort({});
115                               return true;
116                             } catch (e) {
117                               return false;
118                             }
119                           })())"));
120 }
121 
122 }  // namespace content
123