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.h" 14#include "chrome/browser/extensions/extension_function_test_utils.h" 15#include "chrome/browser/extensions/extension_test_message_listener.h" 16#include "chrome/browser/ui/browser.h" 17#include "content/public/browser/browser_thread.h" 18#include "testing/gmock/include/gmock/gmock.h" 19 20using testing::_; 21using testing::Return; 22 23using content::BrowserThread; 24 25namespace { 26 27class SerialApiTest : public ExtensionApiTest { 28 public: 29 SerialApiTest() {} 30}; 31 32} // namespace 33 34namespace extensions { 35 36class FakeSerialGetPortsFunction : public AsyncExtensionFunction { 37 public: 38 virtual bool RunImpl() OVERRIDE { 39 base::ListValue* ports = new base::ListValue(); 40 ports->Append(Value::CreateStringValue("/dev/fakeserial")); 41 ports->Append(Value::CreateStringValue("\\\\COM800\\")); 42 SetResult(ports); 43 SendResponse(true); 44 return true; 45 } 46 protected: 47 virtual ~FakeSerialGetPortsFunction() {} 48}; 49 50class FakeEchoSerialConnection : public SerialConnection { 51 public: 52 explicit FakeEchoSerialConnection( 53 const std::string& port, 54 int bitrate, 55 const std::string& owner_extension_id) 56 : SerialConnection(port, bitrate, owner_extension_id), 57 opened_(true) { 58 Flush(); 59 opened_ = false; 60 } 61 62 virtual ~FakeEchoSerialConnection() { 63 } 64 65 virtual bool Open() { 66 DCHECK(!opened_); 67 opened_ = true; 68 return true; 69 } 70 71 virtual void Close() { 72 DCHECK(opened_); 73 } 74 75 virtual void Flush() { 76 DCHECK(opened_); 77 buffer_.clear(); 78 } 79 80 virtual int Read(scoped_refptr<net::IOBufferWithSize> io_buffer) { 81 DCHECK(io_buffer->data()); 82 83 if (buffer_.empty()) { 84 return 0; 85 } 86 char *data = io_buffer->data(); 87 int bytes_to_copy = io_buffer->size(); 88 while (bytes_to_copy-- && !buffer_.empty()) { 89 *data++ = buffer_.front(); 90 buffer_.pop_front(); 91 } 92 return io_buffer->size(); 93 } 94 95 virtual int Write(scoped_refptr<net::IOBuffer> io_buffer, int byte_count) { 96 DCHECK(io_buffer.get()); 97 DCHECK_GE(byte_count, 0); 98 99 char *data = io_buffer->data(); 100 int count = byte_count; 101 while (count--) 102 buffer_.push_back(*data++); 103 return byte_count; 104 } 105 106 MOCK_METHOD1(GetControlSignals, bool(ControlSignals &)); 107 MOCK_METHOD1(SetControlSignals, bool(const ControlSignals &)); 108 109 private: 110 bool opened_; 111 std::deque<char> buffer_; 112 113 DISALLOW_COPY_AND_ASSIGN(FakeEchoSerialConnection); 114}; 115 116class FakeSerialOpenFunction : public SerialOpenFunction { 117 protected: 118 virtual SerialConnection* CreateSerialConnection( 119 const std::string& port, 120 int bitrate, 121 const std::string& owner_extension_id) OVERRIDE { 122 FakeEchoSerialConnection* serial_connection = 123 new FakeEchoSerialConnection(port, bitrate, owner_extension_id); 124 EXPECT_CALL(*serial_connection, GetControlSignals(_)). 125 Times(1).WillOnce(Return(true)); 126 EXPECT_CALL(*serial_connection, SetControlSignals(_)). 127 Times(1).WillOnce(Return(true)); 128 return serial_connection; 129 } 130 virtual bool DoesPortExist(const std::string& port) OVERRIDE { 131 return true; 132 } 133 134 protected: 135 virtual ~FakeSerialOpenFunction() {} 136}; 137 138} // namespace extensions 139 140ExtensionFunction* FakeSerialGetPortsFunctionFactory() { 141 return new extensions::FakeSerialGetPortsFunction(); 142} 143 144ExtensionFunction* FakeSerialOpenFunctionFactory() { 145 return new extensions::FakeSerialOpenFunction(); 146} 147 148// Disable SIMULATE_SERIAL_PORTS only if all the following are true: 149// 150// 1. You have an Arduino or compatible board attached to your machine and 151// properly appearing as the first virtual serial port ("first" is very loosely 152// defined as whichever port shows up in serial.getPorts). We've tested only 153// the Atmega32u4 Breakout Board and Arduino Leonardo; note that both these 154// boards are based on the Atmel ATmega32u4, rather than the more common 155// Arduino '328p with either FTDI or '8/16u2 USB interfaces. TODO: test more 156// widely. 157// 158// 2. Your user has permission to read/write the port. For example, this might 159// mean that your user is in the "tty" or "uucp" group on Ubuntu flavors of 160// Linux, or else that the port's path (e.g., /dev/ttyACM0) has global 161// read/write permissions. 162// 163// 3. You have uploaded a program to the board that does a byte-for-byte echo 164// on the virtual serial port at 57600 bps. An example is at 165// chrome/test/data/extensions/api_test/serial/api/serial_arduino_test.ino. 166// 167#define SIMULATE_SERIAL_PORTS (1) 168IN_PROC_BROWSER_TEST_F(SerialApiTest, SerialFakeHardware) { 169 ResultCatcher catcher; 170 catcher.RestrictToProfile(browser()->profile()); 171 172#if SIMULATE_SERIAL_PORTS 173 ASSERT_TRUE(ExtensionFunctionDispatcher::OverrideFunction( 174 "serial.getPorts", 175 FakeSerialGetPortsFunctionFactory)); 176 ASSERT_TRUE(ExtensionFunctionDispatcher::OverrideFunction( 177 "serial.open", 178 FakeSerialOpenFunctionFactory)); 179#endif 180 181 ASSERT_TRUE(RunExtensionTest("serial/api")) << message_; 182} 183 184IN_PROC_BROWSER_TEST_F(SerialApiTest, SerialRealHardware) { 185 ResultCatcher catcher; 186 catcher.RestrictToProfile(browser()->profile()); 187 188 ASSERT_TRUE(RunExtensionTest("serial/real_hardware")) << message_; 189} 190