js_to_cpp_unittest.cc revision 0de6073388f4e2780db8536178b129cd8f6ab386
1// Copyright 2014 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 "base/file_util.h" 6#include "base/files/file_path.h" 7#include "base/message_loop/message_loop.h" 8#include "base/run_loop.h" 9#include "base/strings/utf_string_conversions.h" 10#include "gin/public/isolate_holder.h" 11#include "mojo/apps/js/mojo_runner_delegate.h" 12#include "mojo/apps/js/test/js_to_cpp.mojom.h" 13#include "mojo/common/common_type_converters.h" 14#include "mojo/common/test/test_utils.h" 15#include "mojo/public/cpp/bindings/allocation_scope.h" 16#include "mojo/public/cpp/environment/environment.h" 17#include "mojo/public/cpp/system/core.h" 18#include "mojo/public/cpp/system/macros.h" 19#include "testing/gtest/include/gtest/gtest.h" 20 21namespace mojo { 22namespace js { 23namespace { 24 25// Negative numbers with different values in each byte, the last of 26// which can survive promotion to double and back. 27const int8 kExpectedInt8Value = -65; 28const int16 kExpectedInt16Value = -16961; 29const int32 kExpectedInt32Value = -1145258561; 30const int64 kExpectedInt64Value = -77263311946305LL; 31 32// Positive numbers with different values in each byte, the last of 33// which can survive promotion to double and back. 34const uint8 kExpectedUInt8Value = 65; 35const uint16 kExpectedUInt16Value = 16961; 36const uint32 kExpectedUInt32Value = 1145258561; 37const uint64 kExpectedUInt64Value = 77263311946305LL; 38 39// Double/float values, including special case constants. 40const double kExpectedDoubleVal = 3.14159265358979323846; 41const double kExpectedDoubleInf = std::numeric_limits<double>::infinity(); 42const double kExpectedDoubleNan = std::numeric_limits<double>::quiet_NaN(); 43const float kExpectedFloatVal = static_cast<float>(kExpectedDoubleVal); 44const float kExpectedFloatInf = std::numeric_limits<float>::infinity(); 45const float kExpectedFloatNan = std::numeric_limits<float>::quiet_NaN(); 46 47// NaN has the property that it is not equal to itself. 48#define EXPECT_NAN(x) EXPECT_NE(x, x) 49 50bool IsRunningOnIsolatedBot() { 51 // TODO(yzshen): Remove this check once isolated tests are supported on the 52 // Chromium waterfall. (http://crbug.com/351214) 53 const base::FilePath test_file_path( 54 test::GetFilePathForJSResource( 55 "mojo/public/interfaces/bindings/tests/sample_interfaces.mojom")); 56 if (!base::PathExists(test_file_path)) { 57 LOG(WARNING) << "Mojom binding files don't exist. Skipping the test."; 58 return true; 59 } 60 return false; 61} 62 63// NOTE: Callers will need to have established an AllocationScope, or you're 64// gonna have a bad time. 65js_to_cpp::EchoArgs BuildSampleEchoArgs() { 66 js_to_cpp::EchoArgs::Builder builder; 67 builder.set_si64(kExpectedInt64Value); 68 builder.set_si32(kExpectedInt32Value); 69 builder.set_si16(kExpectedInt16Value); 70 builder.set_si8(kExpectedInt8Value); 71 builder.set_ui64(kExpectedUInt64Value); 72 builder.set_ui32(kExpectedUInt32Value); 73 builder.set_ui16(kExpectedUInt16Value); 74 builder.set_ui8(kExpectedUInt8Value); 75 builder.set_float_val(kExpectedFloatVal); 76 builder.set_float_inf(kExpectedFloatInf); 77 builder.set_float_nan(kExpectedFloatNan); 78 builder.set_double_val(kExpectedDoubleVal); 79 builder.set_double_inf(kExpectedDoubleInf); 80 builder.set_double_nan(kExpectedDoubleNan); 81 builder.set_name("coming"); 82 mojo::Array<mojo::String>::Builder string_array(3); 83 string_array[0] = "one"; 84 string_array[1] = "two"; 85 string_array[2] = "three"; 86 builder.set_string_array(string_array.Finish()); 87 return builder.Finish(); 88} 89 90void CheckSampleEchoArgs(const js_to_cpp::EchoArgs& arg) { 91 EXPECT_EQ(kExpectedInt64Value, arg.si64()); 92 EXPECT_EQ(kExpectedInt32Value, arg.si32()); 93 EXPECT_EQ(kExpectedInt16Value, arg.si16()); 94 EXPECT_EQ(kExpectedInt8Value, arg.si8()); 95 EXPECT_EQ(kExpectedUInt64Value, arg.ui64()); 96 EXPECT_EQ(kExpectedUInt32Value, arg.ui32()); 97 EXPECT_EQ(kExpectedUInt16Value, arg.ui16()); 98 EXPECT_EQ(kExpectedUInt8Value, arg.ui8()); 99 EXPECT_EQ(kExpectedFloatVal, arg.float_val()); 100 EXPECT_EQ(kExpectedFloatInf, arg.float_inf()); 101 EXPECT_NAN(arg.float_nan()); 102 EXPECT_EQ(kExpectedDoubleVal, arg.double_val()); 103 EXPECT_EQ(kExpectedDoubleInf, arg.double_inf()); 104 EXPECT_NAN(arg.double_nan()); 105 EXPECT_EQ(std::string("coming"), arg.name().To<std::string>()); 106 EXPECT_EQ(std::string("one"), arg.string_array()[0].To<std::string>()); 107 EXPECT_EQ(std::string("two"), arg.string_array()[1].To<std::string>()); 108 EXPECT_EQ(std::string("three"), arg.string_array()[2].To<std::string>()); 109} 110 111// Base Provider implementation class. It's expected that tests subclass and 112// override the appropriate Provider functions. When test is done quit the 113// run_loop(). 114class CppSideConnection : public js_to_cpp::CppSide { 115 public: 116 CppSideConnection() : run_loop_(NULL), js_side_(NULL) { 117 } 118 virtual ~CppSideConnection() {} 119 120 void set_run_loop(base::RunLoop* run_loop) { run_loop_ = run_loop; } 121 base::RunLoop* run_loop() { return run_loop_; } 122 123 void set_js_side(js_to_cpp::JsSide* js_side) { js_side_ = js_side; } 124 js_to_cpp::JsSide* js_side() { return js_side_; } 125 126 // js_to_cpp::CppSide: 127 virtual void StartTest() OVERRIDE { 128 NOTREACHED(); 129 } 130 131 virtual void TestFinished() OVERRIDE { 132 NOTREACHED(); 133 } 134 135 virtual void PingResponse() OVERRIDE { 136 NOTREACHED(); 137 } 138 139 virtual void EchoResponse(const js_to_cpp::EchoArgs& arg1, 140 const js_to_cpp::EchoArgs& arg2) OVERRIDE { 141 NOTREACHED(); 142 } 143 144 virtual void BitFlipResponse(const js_to_cpp::EchoArgs& arg1) OVERRIDE { 145 NOTREACHED(); 146 } 147 148 protected: 149 base::RunLoop* run_loop_; 150 js_to_cpp::JsSide* js_side_; 151 152 private: 153 Environment environment; 154 DISALLOW_COPY_AND_ASSIGN(CppSideConnection); 155}; 156 157// Trivial test to verify a message sent from JS is received. 158class PingCppSideConnection : public CppSideConnection { 159 public: 160 explicit PingCppSideConnection() : got_message_(false) {} 161 virtual ~PingCppSideConnection() {} 162 163 // js_to_cpp::CppSide: 164 virtual void StartTest() OVERRIDE { 165 js_side_->Ping(); 166 } 167 168 virtual void PingResponse() OVERRIDE { 169 got_message_ = true; 170 run_loop()->Quit(); 171 } 172 173 bool DidSucceed() { 174 return got_message_; 175 } 176 177 private: 178 bool got_message_; 179 DISALLOW_COPY_AND_ASSIGN(PingCppSideConnection); 180}; 181 182// Test that parameters are passed with correct values. 183class EchoCppSideConnection : public CppSideConnection { 184 public: 185 explicit EchoCppSideConnection() : 186 message_count_(0), 187 termination_seen_(false) { 188 } 189 virtual ~EchoCppSideConnection() {} 190 191 // js_to_cpp::CppSide: 192 virtual void StartTest() OVERRIDE { 193 AllocationScope scope; 194 js_side_->Echo(kExpectedMessageCount, BuildSampleEchoArgs()); 195 } 196 197 virtual void EchoResponse(const js_to_cpp::EchoArgs& arg1, 198 const js_to_cpp::EchoArgs& arg2) OVERRIDE { 199 message_count_ += 1; 200 CheckSampleEchoArgs(arg1); 201 EXPECT_EQ(-1, arg2.si64()); 202 EXPECT_EQ(-1, arg2.si32()); 203 EXPECT_EQ(-1, arg2.si16()); 204 EXPECT_EQ(-1, arg2.si8()); 205 EXPECT_EQ(std::string("going"), arg2.name().To<std::string>()); 206 } 207 208 virtual void TestFinished() OVERRIDE { 209 termination_seen_ = true; 210 run_loop()->Quit(); 211 } 212 213 bool DidSucceed() { 214 return termination_seen_ && message_count_ == kExpectedMessageCount; 215 } 216 217 private: 218 static const int kExpectedMessageCount = 100; 219 int message_count_; 220 bool termination_seen_; 221 DISALLOW_COPY_AND_ASSIGN(EchoCppSideConnection); 222}; 223 224// Test that corrupted messages don't wreak havoc. 225class BitFlipCppSideConnection : public CppSideConnection { 226 public: 227 explicit BitFlipCppSideConnection() : termination_seen_(false) {} 228 virtual ~BitFlipCppSideConnection() {} 229 230 // js_to_cpp::CppSide: 231 virtual void StartTest() OVERRIDE { 232 AllocationScope scope; 233 js_side_->BitFlip(BuildSampleEchoArgs()); 234 } 235 236 virtual void BitFlipResponse(const js_to_cpp::EchoArgs& arg1) OVERRIDE { 237 // TODO(tsepez): How to check, may be corrupt in various ways. 238 } 239 240 virtual void TestFinished() OVERRIDE { 241 termination_seen_ = true; 242 run_loop()->Quit(); 243 } 244 245 bool DidSucceed() { 246 return termination_seen_; 247 } 248 249 private: 250 bool termination_seen_; 251 DISALLOW_COPY_AND_ASSIGN(BitFlipCppSideConnection); 252}; 253 254} // namespace 255 256class JsToCppTest : public testing::Test { 257 public: 258 JsToCppTest() {} 259 260 void RunTest(const std::string& test, CppSideConnection* cpp_side) { 261 cpp_side->set_run_loop(&run_loop_); 262 263 MessagePipe pipe; 264 js_to_cpp::JsSidePtr js_side = 265 MakeProxy<js_to_cpp::JsSide>(pipe.handle0.Pass()); 266 js_side->SetClient(cpp_side); 267 268 js_side.internal_state()->router()-> 269 set_enforce_errors_from_incoming_receiver(false); 270 271 cpp_side->set_js_side(js_side.get()); 272 273 gin::IsolateHolder instance(gin::IsolateHolder::kStrictMode); 274 apps::MojoRunnerDelegate delegate; 275 gin::ShellRunner runner(&delegate, instance.isolate()); 276 delegate.Start(&runner, pipe.handle1.release().value(), test); 277 278 run_loop_.Run(); 279 } 280 281 private: 282 base::MessageLoop loop; 283 base::RunLoop run_loop_; 284 285 DISALLOW_COPY_AND_ASSIGN(JsToCppTest); 286}; 287 288TEST_F(JsToCppTest, Ping) { 289 if (IsRunningOnIsolatedBot()) 290 return; 291 292 PingCppSideConnection cpp_side_connection; 293 RunTest("mojo/apps/js/test/js_to_cpp_unittest", &cpp_side_connection); 294 EXPECT_TRUE(cpp_side_connection.DidSucceed()); 295} 296 297TEST_F(JsToCppTest, Echo) { 298 if (IsRunningOnIsolatedBot()) 299 return; 300 301 EchoCppSideConnection cpp_side_connection; 302 RunTest("mojo/apps/js/test/js_to_cpp_unittest", &cpp_side_connection); 303 EXPECT_TRUE(cpp_side_connection.DidSucceed()); 304} 305 306// TODO(tsepez): Disabled due to http://crbug.com/366797. 307TEST_F(JsToCppTest, DISABLED_BitFlip) { 308 if (IsRunningOnIsolatedBot()) 309 return; 310 311 BitFlipCppSideConnection cpp_side_connection; 312 RunTest("mojo/apps/js/test/js_to_cpp_unittest", &cpp_side_connection); 313 EXPECT_TRUE(cpp_side_connection.DidSucceed()); 314} 315 316} // namespace js 317} // namespace mojo 318