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