1// Copyright 2012 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 <deque> 6#include <string> 7#include <vector> 8 9#include "base/memory/scoped_ptr.h" 10#include "chrome/browser/extensions/api/serial/serial_api.h" 11#include "chrome/browser/extensions/api/serial/serial_connection.h" 12#include "chrome/browser/extensions/extension_apitest.h" 13#include "chrome/browser/extensions/extension_function_test_utils.h" 14#include "chrome/browser/extensions/extension_test_message_listener.h" 15#include "chrome/browser/ui/browser.h" 16#include "chrome/common/extensions/api/serial.h" 17#include "content/public/browser/browser_thread.h" 18#include "extensions/browser/extension_function.h" 19#include "testing/gmock/include/gmock/gmock.h" 20 21using testing::_; 22using testing::Return; 23 24using content::BrowserThread; 25 26namespace { 27 28class SerialApiTest : public ExtensionApiTest { 29 public: 30 SerialApiTest() {} 31}; 32 33} // namespace 34 35namespace extensions { 36 37class FakeSerialGetDevicesFunction : public AsyncExtensionFunction { 38 public: 39 virtual bool RunAsync() OVERRIDE { 40 base::ListValue* devices = new base::ListValue(); 41 base::DictionaryValue* device0 = new base::DictionaryValue(); 42 device0->SetString("path", "/dev/fakeserial"); 43 base::DictionaryValue* device1 = new base::DictionaryValue(); 44 device1->SetString("path", "\\\\COM800\\"); 45 devices->Append(device0); 46 devices->Append(device1); 47 SetResult(devices); 48 SendResponse(true); 49 return true; 50 } 51 protected: 52 virtual ~FakeSerialGetDevicesFunction() {} 53}; 54 55class FakeEchoSerialConnection : public SerialConnection { 56 public: 57 explicit FakeEchoSerialConnection( 58 const std::string& port, 59 const std::string& owner_extension_id) 60 : SerialConnection(port, owner_extension_id), 61 opened_(false) { 62 } 63 64 virtual ~FakeEchoSerialConnection() { 65 } 66 67 virtual void Open(const OpenCompleteCallback& callback) { 68 DCHECK(!opened_); 69 opened_ = true; 70 callback.Run(true); 71 } 72 73 virtual bool Configure(const api::serial::ConnectionOptions& options) { 74 return true; 75 } 76 77 virtual void Close() { 78 DCHECK(opened_); 79 } 80 81 virtual bool Receive(const ReceiveCompleteCallback& callback) { 82 read_callback_ = callback; 83 return true; 84 } 85 86 virtual bool Send(const std::string& data, 87 const SendCompleteCallback& callback) { 88 callback.Run(data.length(), api::serial::SEND_ERROR_NONE); 89 if (!read_callback_.is_null()) { 90 read_callback_.Run(data, api::serial::RECEIVE_ERROR_NONE); 91 } 92 return true; 93 } 94 95 virtual bool GetControlSignals(api::serial::DeviceControlSignals* signals) 96 const { 97 signals->dcd = true; 98 signals->cts = true; 99 signals->ri = true; 100 signals->dsr = true; 101 return true; 102 } 103 104 virtual bool GetInfo(api::serial::ConnectionInfo* info) const { 105 info->paused = false; 106 info->persistent = false; 107 info->buffer_size = 4096; 108 info->receive_timeout = 0; 109 info->send_timeout = 0; 110 info->bitrate.reset(new int(9600)); 111 info->data_bits = api::serial::DATA_BITS_EIGHT; 112 info->parity_bit = api::serial::PARITY_BIT_NO; 113 info->stop_bits = api::serial::STOP_BITS_ONE; 114 info->cts_flow_control.reset(new bool(false)); 115 return true; 116 } 117 118 MOCK_METHOD1(SetControlSignals, bool(const api::serial::HostControlSignals&)); 119 120 private: 121 bool opened_; 122 ReceiveCompleteCallback read_callback_; 123 124 DISALLOW_COPY_AND_ASSIGN(FakeEchoSerialConnection); 125}; 126 127class FakeSerialConnectFunction : public api::SerialConnectFunction { 128 protected: 129 virtual SerialConnection* CreateSerialConnection( 130 const std::string& port, 131 const std::string& owner_extension_id) const OVERRIDE { 132 FakeEchoSerialConnection* serial_connection = 133 new FakeEchoSerialConnection(port, owner_extension_id); 134 EXPECT_CALL(*serial_connection, SetControlSignals(_)). 135 Times(1).WillOnce(Return(true)); 136 return serial_connection; 137 } 138 139 protected: 140 virtual ~FakeSerialConnectFunction() {} 141}; 142 143} // namespace extensions 144 145ExtensionFunction* FakeSerialGetDevicesFunctionFactory() { 146 return new extensions::FakeSerialGetDevicesFunction(); 147} 148 149ExtensionFunction* FakeSerialConnectFunctionFactory() { 150 return new extensions::FakeSerialConnectFunction(); 151} 152 153// Disable SIMULATE_SERIAL_PORTS only if all the following are true: 154// 155// 1. You have an Arduino or compatible board attached to your machine and 156// properly appearing as the first virtual serial port ("first" is very loosely 157// defined as whichever port shows up in serial.getPorts). We've tested only 158// the Atmega32u4 Breakout Board and Arduino Leonardo; note that both these 159// boards are based on the Atmel ATmega32u4, rather than the more common 160// Arduino '328p with either FTDI or '8/16u2 USB interfaces. TODO: test more 161// widely. 162// 163// 2. Your user has permission to read/write the port. For example, this might 164// mean that your user is in the "tty" or "uucp" group on Ubuntu flavors of 165// Linux, or else that the port's path (e.g., /dev/ttyACM0) has global 166// read/write permissions. 167// 168// 3. You have uploaded a program to the board that does a byte-for-byte echo 169// on the virtual serial port at 57600 bps. An example is at 170// chrome/test/data/extensions/api_test/serial/api/serial_arduino_test.ino. 171// 172#define SIMULATE_SERIAL_PORTS (1) 173IN_PROC_BROWSER_TEST_F(SerialApiTest, SerialFakeHardware) { 174 ResultCatcher catcher; 175 catcher.RestrictToProfile(browser()->profile()); 176 177#if SIMULATE_SERIAL_PORTS 178 ASSERT_TRUE(extensions::ExtensionFunctionDispatcher::OverrideFunction( 179 "serial.getDevices", FakeSerialGetDevicesFunctionFactory)); 180 ASSERT_TRUE(extensions::ExtensionFunctionDispatcher::OverrideFunction( 181 "serial.connect", FakeSerialConnectFunctionFactory)); 182#endif 183 184 ASSERT_TRUE(RunExtensionTest("serial/api")) << message_; 185} 186 187IN_PROC_BROWSER_TEST_F(SerialApiTest, SerialRealHardware) { 188 ResultCatcher catcher; 189 catcher.RestrictToProfile(browser()->profile()); 190 191 ASSERT_TRUE(RunExtensionTest("serial/real_hardware")) << message_; 192} 193