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 20 using testing::_; 21 using testing::Return; 22 23 using content::BrowserThread; 24 25 namespace { 26 27 class SerialApiTest : public ExtensionApiTest { 28 public: 29 SerialApiTest() {} 30 }; 31 32 } // namespace 33 34 namespace extensions { 35 36 class 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 50 class 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 116 class 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 140 ExtensionFunction* FakeSerialGetPortsFunctionFactory() { 141 return new extensions::FakeSerialGetPortsFunction(); 142 } 143 144 ExtensionFunction* 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) 168 IN_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 184 IN_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