1 // Copyright (c) 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 21 using testing::_; 22 using testing::Return; 23 24 using content::BrowserThread; 25 26 namespace { 27 28 class SerialApiTest : public ExtensionApiTest { 29 public: 30 SerialApiTest() {} 31 }; 32 33 } // namespace 34 35 namespace extensions { 36 37 class FakeSerialGetDevicesFunction : public AsyncExtensionFunction { 38 public: 39 virtual bool RunImpl() 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 55 class 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 127 class 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 145 ExtensionFunction* FakeSerialGetDevicesFunctionFactory() { 146 return new extensions::FakeSerialGetDevicesFunction(); 147 } 148 149 ExtensionFunction* 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) 173 IN_PROC_BROWSER_TEST_F(SerialApiTest, SerialFakeHardware) { 174 ResultCatcher catcher; 175 catcher.RestrictToProfile(browser()->profile()); 176 177 #if SIMULATE_SERIAL_PORTS 178 ASSERT_TRUE(ExtensionFunctionDispatcher::OverrideFunction( 179 "serial.getDevices", 180 FakeSerialGetDevicesFunctionFactory)); 181 ASSERT_TRUE(ExtensionFunctionDispatcher::OverrideFunction( 182 "serial.connect", 183 FakeSerialConnectFunctionFactory)); 184 #endif 185 186 ASSERT_TRUE(RunExtensionTest("serial/api")) << message_; 187 } 188 189 IN_PROC_BROWSER_TEST_F(SerialApiTest, SerialRealHardware) { 190 ResultCatcher catcher; 191 catcher.RestrictToProfile(browser()->profile()); 192 193 ASSERT_TRUE(RunExtensionTest("serial/real_hardware")) << message_; 194 } 195