// Copyright 2018 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include #include #include "base/command_line.h" #include "base/unguessable_token.h" #include "content/browser/serial/serial_test_utils.h" #include "content/public/browser/content_browser_client.h" #include "content/public/browser/serial_chooser.h" #include "content/public/browser/serial_delegate.h" #include "content/public/common/content_client.h" #include "content/public/common/content_switches.h" #include "content/public/test/browser_test.h" #include "content/public/test/browser_test_utils.h" #include "content/public/test/content_browser_test.h" #include "content/public/test/content_browser_test_utils.h" #include "content/shell/browser/shell.h" #include "services/device/public/cpp/test/fake_serial_port_manager.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" using testing::_; using testing::ByMove; using testing::Exactly; using testing::Return; namespace content { namespace { class SerialTest : public ContentBrowserTest { public: SerialTest() { ON_CALL(delegate(), GetPortManager).WillByDefault(Return(&port_manager_)); } ~SerialTest() override = default; void SetUpCommandLine(base::CommandLine* command_line) override { ContentBrowserTest::SetUpCommandLine(command_line); command_line->AppendSwitch( switches::kEnableExperimentalWebPlatformFeatures); } void SetUpOnMainThread() override { original_client_ = SetBrowserClientForTesting(&test_client_); } void TearDownOnMainThread() override { if (original_client_) SetBrowserClientForTesting(original_client_); } MockSerialDelegate& delegate() { return test_client_.delegate(); } device::FakeSerialPortManager* port_manager() { return &port_manager_; } private: SerialTestContentBrowserClient test_client_; ContentBrowserClient* original_client_ = nullptr; device::FakeSerialPortManager port_manager_; }; } // namespace IN_PROC_BROWSER_TEST_F(SerialTest, GetPorts) { EXPECT_TRUE(NavigateToURL(shell(), GetTestUrl(nullptr, "simple_page.html"))); // Three ports are added but only two will have permission granted. for (size_t i = 0; i < 3; i++) { auto port = device::mojom::SerialPortInfo::New(); port->token = base::UnguessableToken::Create(); port_manager()->AddPort(std::move(port)); } EXPECT_CALL(delegate(), HasPortPermission(_, _)) .WillOnce(Return(true)) .WillOnce(Return(false)) .WillOnce(Return(true)); EXPECT_EQ( 2, EvalJs(shell(), R"(navigator.serial.getPorts().then(ports => ports.length))")); } IN_PROC_BROWSER_TEST_F(SerialTest, RequestPort) { EXPECT_TRUE(NavigateToURL(shell(), GetTestUrl(nullptr, "simple_page.html"))); EXPECT_CALL(delegate(), CanRequestPortPermission).WillOnce(Return(true)); auto port = device::mojom::SerialPortInfo::New(); port->token = base::UnguessableToken::Create(); EXPECT_CALL(delegate(), RunChooserInternal) .WillOnce(Return(ByMove(std::move(port)))); EXPECT_EQ(true, EvalJs(shell(), R"((async () => { let port = await navigator.serial.requestPort({}); return port instanceof SerialPort; })())")); } IN_PROC_BROWSER_TEST_F(SerialTest, DisallowRequestPort) { EXPECT_TRUE(NavigateToURL(shell(), GetTestUrl(nullptr, "simple_page.html"))); EXPECT_CALL(delegate(), CanRequestPortPermission(_)).WillOnce(Return(false)); EXPECT_CALL(delegate(), RunChooserInternal).Times(Exactly(0)); EXPECT_EQ(false, EvalJs(shell(), R"((async () => { try { await navigator.serial.requestPort({}); return true; } catch (e) { return false; } })())")); } } // namespace content