| OLD | NEW |
| (Empty) |
| 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 <stdint.h> | |
| 6 | |
| 7 #include "base/bind.h" | |
| 8 #include "base/files/file_path.h" | |
| 9 #include "base/macros.h" | |
| 10 #include "base/message_loop/message_loop.h" | |
| 11 #include "base/path_service.h" | |
| 12 #include "base/rand_util.h" | |
| 13 #include "base/run_loop.h" | |
| 14 #include "base/threading/thread.h" | |
| 15 #include "mojo/dart/embedder/dart_controller.h" | |
| 16 #include "mojo/dart/embedder/test/dart_test.h" | |
| 17 #include "mojo/dart/embedder/test/dart_to_cpp.mojom.h" | |
| 18 #include "mojo/public/cpp/bindings/strong_binding.h" | |
| 19 #include "mojo/public/cpp/system/core.h" | |
| 20 #include "mojo/public/cpp/system/macros.h" | |
| 21 #include "testing/gtest/include/gtest/gtest.h" | |
| 22 | |
| 23 namespace mojo { | |
| 24 namespace dart { | |
| 25 | |
| 26 // Global value updated by some checks to prevent compilers from optimizing | |
| 27 // reads out of existence. | |
| 28 uint32_t g_waste_accumulator = 0; | |
| 29 | |
| 30 namespace { | |
| 31 | |
| 32 // Negative numbers with different values in each byte, the last of | |
| 33 // which can survive promotion to double and back. | |
| 34 const int8_t kExpectedInt8Value = -65; | |
| 35 const int16_t kExpectedInt16Value = -16961; | |
| 36 const int32_t kExpectedInt32Value = -1145258561; | |
| 37 const int64_t kExpectedInt64Value = -77263311946305LL; | |
| 38 | |
| 39 // Positive numbers with different values in each byte, the last of | |
| 40 // which can survive promotion to double and back. | |
| 41 const uint8_t kExpectedUInt8Value = 65; | |
| 42 const uint16_t kExpectedUInt16Value = 16961; | |
| 43 const uint32_t kExpectedUInt32Value = 1145258561; | |
| 44 const uint64_t kExpectedUInt64Value = 77263311946305LL; | |
| 45 | |
| 46 // Double/float values, including special case constants. | |
| 47 const double kExpectedDoubleVal = 3.14159265358979323846; | |
| 48 const double kExpectedDoubleInf = std::numeric_limits<double>::infinity(); | |
| 49 const double kExpectedDoubleNan = std::numeric_limits<double>::quiet_NaN(); | |
| 50 const float kExpectedFloatVal = static_cast<float>(kExpectedDoubleVal); | |
| 51 const float kExpectedFloatInf = std::numeric_limits<float>::infinity(); | |
| 52 const float kExpectedFloatNan = std::numeric_limits<float>::quiet_NaN(); | |
| 53 | |
| 54 // NaN has the property that it is not equal to itself. | |
| 55 #define EXPECT_NAN(x) EXPECT_NE(x, x) | |
| 56 | |
| 57 void CheckDataPipe(MojoHandle data_pipe_handle) { | |
| 58 unsigned char buffer[100]; | |
| 59 uint32_t buffer_size = static_cast<uint32_t>(sizeof(buffer)); | |
| 60 MojoResult result = MojoReadData( | |
| 61 data_pipe_handle, buffer, &buffer_size, MOJO_READ_DATA_FLAG_NONE); | |
| 62 EXPECT_EQ(MOJO_RESULT_OK, result); | |
| 63 EXPECT_EQ(64u, buffer_size); | |
| 64 for (int i = 0; i < 64; ++i) { | |
| 65 EXPECT_EQ(i, buffer[i]); | |
| 66 } | |
| 67 } | |
| 68 | |
| 69 void CheckMessagePipe(MojoHandle message_pipe_handle) { | |
| 70 unsigned char buffer[100]; | |
| 71 uint32_t buffer_size = static_cast<uint32_t>(sizeof(buffer)); | |
| 72 MojoResult result = MojoReadMessage( | |
| 73 message_pipe_handle, buffer, &buffer_size, 0, 0, 0); | |
| 74 EXPECT_EQ(MOJO_RESULT_OK, result); | |
| 75 EXPECT_EQ(64u, buffer_size); | |
| 76 for (int i = 0; i < 64; ++i) { | |
| 77 EXPECT_EQ(255 - i, buffer[i]); | |
| 78 } | |
| 79 } | |
| 80 | |
| 81 dart_to_cpp::EchoArgsPtr BuildSampleEchoArgs() { | |
| 82 dart_to_cpp::EchoArgsPtr args(dart_to_cpp::EchoArgs::New()); | |
| 83 args->si64 = kExpectedInt64Value; | |
| 84 args->si32 = kExpectedInt32Value; | |
| 85 args->si16 = kExpectedInt16Value; | |
| 86 args->si8 = kExpectedInt8Value; | |
| 87 args->ui64 = kExpectedUInt64Value; | |
| 88 args->ui32 = kExpectedUInt32Value; | |
| 89 args->ui16 = kExpectedUInt16Value; | |
| 90 args->ui8 = kExpectedUInt8Value; | |
| 91 args->float_val = kExpectedFloatVal; | |
| 92 args->float_inf = kExpectedFloatInf; | |
| 93 args->float_nan = kExpectedFloatNan; | |
| 94 args->double_val = kExpectedDoubleVal; | |
| 95 args->double_inf = kExpectedDoubleInf; | |
| 96 args->double_nan = kExpectedDoubleNan; | |
| 97 args->name = "coming"; | |
| 98 auto string_array = Array<String>::New(3); | |
| 99 string_array[0] = "one"; | |
| 100 string_array[1] = "two"; | |
| 101 string_array[2] = "three"; | |
| 102 args->string_array = string_array.Pass(); | |
| 103 return args; | |
| 104 } | |
| 105 | |
| 106 void CheckSampleEchoArgs(const dart_to_cpp::EchoArgs& arg) { | |
| 107 EXPECT_EQ(kExpectedInt64Value, arg.si64); | |
| 108 EXPECT_EQ(kExpectedInt32Value, arg.si32); | |
| 109 EXPECT_EQ(kExpectedInt16Value, arg.si16); | |
| 110 EXPECT_EQ(kExpectedInt8Value, arg.si8); | |
| 111 EXPECT_EQ(kExpectedUInt64Value, arg.ui64); | |
| 112 EXPECT_EQ(kExpectedUInt32Value, arg.ui32); | |
| 113 EXPECT_EQ(kExpectedUInt16Value, arg.ui16); | |
| 114 EXPECT_EQ(kExpectedUInt8Value, arg.ui8); | |
| 115 EXPECT_EQ(kExpectedFloatVal, arg.float_val); | |
| 116 EXPECT_EQ(kExpectedFloatInf, arg.float_inf); | |
| 117 EXPECT_NAN(arg.float_nan); | |
| 118 EXPECT_EQ(kExpectedDoubleVal, arg.double_val); | |
| 119 EXPECT_EQ(kExpectedDoubleInf, arg.double_inf); | |
| 120 EXPECT_NAN(arg.double_nan); | |
| 121 EXPECT_EQ(std::string("coming"), arg.name.get()); | |
| 122 EXPECT_EQ(std::string("one"), arg.string_array[0].get()); | |
| 123 EXPECT_EQ(std::string("two"), arg.string_array[1].get()); | |
| 124 EXPECT_EQ(std::string("three"), arg.string_array[2].get()); | |
| 125 CheckDataPipe(arg.data_handle.get().value()); | |
| 126 CheckMessagePipe(arg.message_handle.get().value()); | |
| 127 } | |
| 128 | |
| 129 void CheckSampleEchoArgsList(const dart_to_cpp::EchoArgsListPtr& list) { | |
| 130 if (list.is_null()) | |
| 131 return; | |
| 132 CheckSampleEchoArgs(*list->item); | |
| 133 CheckSampleEchoArgsList(list->next); | |
| 134 } | |
| 135 | |
| 136 // Base Provider implementation class. It's expected that tests subclass and | |
| 137 // override the appropriate Provider functions. When test is done quit the | |
| 138 // run_loop(). | |
| 139 class CppSideConnection : public dart_to_cpp::CppSide { | |
| 140 public: | |
| 141 CppSideConnection() : | |
| 142 run_loop_(NULL), | |
| 143 dart_side_(NULL), | |
| 144 mishandled_messages_(0), | |
| 145 binding_(this) { | |
| 146 } | |
| 147 ~CppSideConnection() override {} | |
| 148 | |
| 149 void Bind(InterfaceRequest<dart_to_cpp::CppSide> request) { | |
| 150 binding_.Bind(request.Pass()); | |
| 151 } | |
| 152 | |
| 153 void set_run_loop(base::RunLoop* run_loop) { run_loop_ = run_loop; } | |
| 154 base::RunLoop* run_loop() { return run_loop_; } | |
| 155 | |
| 156 void set_dart_side(dart_to_cpp::DartSide* dart_side) { | |
| 157 dart_side_ = dart_side; | |
| 158 } | |
| 159 dart_to_cpp::DartSide* dart_side() { return dart_side_; } | |
| 160 | |
| 161 // dart_to_cpp::CppSide: | |
| 162 void StartTest() override { NOTREACHED(); } | |
| 163 | |
| 164 void TestFinished() override { NOTREACHED(); } | |
| 165 | |
| 166 void PingResponse() override { mishandled_messages_ += 1; } | |
| 167 | |
| 168 void EchoResponse(dart_to_cpp::EchoArgsListPtr list) override { | |
| 169 mishandled_messages_ += 1; | |
| 170 } | |
| 171 | |
| 172 protected: | |
| 173 base::RunLoop* run_loop_; | |
| 174 dart_to_cpp::DartSide* dart_side_; | |
| 175 int mishandled_messages_; | |
| 176 | |
| 177 private: | |
| 178 StrongBinding<dart_to_cpp::CppSide> binding_; | |
| 179 DISALLOW_COPY_AND_ASSIGN(CppSideConnection); | |
| 180 }; | |
| 181 | |
| 182 // Trivial test to verify a message sent from Dart is received. | |
| 183 class PingCppSideConnection : public CppSideConnection { | |
| 184 public: | |
| 185 PingCppSideConnection() : got_message_(false) {} | |
| 186 ~PingCppSideConnection() override {} | |
| 187 | |
| 188 // dart_to_cpp::CppSide: | |
| 189 void StartTest() override { | |
| 190 dart_side_->Ping(); | |
| 191 } | |
| 192 | |
| 193 void PingResponse() override { | |
| 194 got_message_ = true; | |
| 195 run_loop()->Quit(); | |
| 196 } | |
| 197 | |
| 198 bool DidSucceed() { | |
| 199 return got_message_ && !mishandled_messages_; | |
| 200 } | |
| 201 | |
| 202 private: | |
| 203 bool got_message_; | |
| 204 DISALLOW_COPY_AND_ASSIGN(PingCppSideConnection); | |
| 205 }; | |
| 206 | |
| 207 // Test that parameters are passed with correct values. | |
| 208 class EchoCppSideConnection : public CppSideConnection { | |
| 209 public: | |
| 210 EchoCppSideConnection() : | |
| 211 message_count_(0), | |
| 212 termination_seen_(false) { | |
| 213 } | |
| 214 ~EchoCppSideConnection() override {} | |
| 215 | |
| 216 // dart_to_cpp::CppSide: | |
| 217 void StartTest() override { | |
| 218 dart_side_->Echo(kExpectedMessageCount, BuildSampleEchoArgs()); | |
| 219 } | |
| 220 | |
| 221 void EchoResponse(dart_to_cpp::EchoArgsListPtr list) override { | |
| 222 const dart_to_cpp::EchoArgsPtr& special_arg = list->item; | |
| 223 message_count_ += 1; | |
| 224 EXPECT_EQ(-1, special_arg->si64); | |
| 225 EXPECT_EQ(-1, special_arg->si32); | |
| 226 EXPECT_EQ(-1, special_arg->si16); | |
| 227 EXPECT_EQ(-1, special_arg->si8); | |
| 228 EXPECT_EQ(std::string("going"), special_arg->name.To<std::string>()); | |
| 229 CheckSampleEchoArgsList(list->next); | |
| 230 } | |
| 231 | |
| 232 void TestFinished() override { | |
| 233 termination_seen_ = true; | |
| 234 run_loop()->Quit(); | |
| 235 } | |
| 236 | |
| 237 bool DidSucceed() { | |
| 238 return termination_seen_ && | |
| 239 !mishandled_messages_ && | |
| 240 message_count_ == kExpectedMessageCount; | |
| 241 } | |
| 242 | |
| 243 private: | |
| 244 static const int kExpectedMessageCount = 10; | |
| 245 int message_count_; | |
| 246 bool termination_seen_; | |
| 247 DISALLOW_COPY_AND_ASSIGN(EchoCppSideConnection); | |
| 248 }; | |
| 249 | |
| 250 } // namespace | |
| 251 | |
| 252 class DartToCppTest : public DartTest { | |
| 253 public: | |
| 254 DartToCppTest() {} | |
| 255 | |
| 256 bool RunTest(const std::string& test, CppSideConnection* cpp_side) { | |
| 257 // Putting Dart on its own thread so we can use Dart_RunLoop (called from | |
| 258 // DartController::RunDartScript) and base::RunLoop::Run together. Passing | |
| 259 // the thread to RunWithDartOnThread instead of inlining that function here | |
| 260 // so that we are sure the MessagePipe destructor runs and closes the | |
| 261 // handles on the C++ side before the Thread destructor runs and joins on | |
| 262 // the Dart thread. Closing the handles on the C++ side must happen first | |
| 263 // because it is the client, and therefore the Dart side will run and not | |
| 264 // join while handles are still open, until the C++ side closes them. | |
| 265 base::Thread dart_thread("dart"); | |
| 266 cpp_side->set_run_loop(&run_loop_); | |
| 267 return RunWithDartOnThread(&dart_thread, test, cpp_side); | |
| 268 } | |
| 269 | |
| 270 private: | |
| 271 base::MessageLoop loop; | |
| 272 base::RunLoop run_loop_; | |
| 273 | |
| 274 static void InitializeDartConfig(DartControllerConfig* config, | |
| 275 const std::string& test, | |
| 276 MojoHandle handle, | |
| 277 bool* unhandled_exception, | |
| 278 int64_t* closed_handles, | |
| 279 char** error) { | |
| 280 base::FilePath path; | |
| 281 PathService::Get(base::DIR_SOURCE_ROOT, &path); | |
| 282 path = path.AppendASCII("mojo") | |
| 283 .AppendASCII("dart") | |
| 284 .AppendASCII("embedder") | |
| 285 .AppendASCII("test") | |
| 286 .AppendASCII(test); | |
| 287 | |
| 288 // Setup the package root. | |
| 289 base::FilePath package_root; | |
| 290 PathService::Get(base::DIR_EXE, &package_root); | |
| 291 package_root = package_root.AppendASCII("gen") | |
| 292 .AppendASCII("dart-pkg") | |
| 293 .AppendASCII("packages"); | |
| 294 | |
| 295 | |
| 296 config->strict_compilation = true; | |
| 297 config->script_uri = path.AsUTF8Unsafe(); | |
| 298 config->package_root = package_root.AsUTF8Unsafe(); | |
| 299 config->callbacks.exception = base::Bind( | |
| 300 &ExceptionCallback, unhandled_exception, closed_handles); | |
| 301 config->entropy = GenerateEntropy; | |
| 302 config->handle = handle; | |
| 303 config->error = error; | |
| 304 } | |
| 305 | |
| 306 static void RunDartSide(const DartControllerConfig& config) { | |
| 307 DartController::RunDartScript(config); | |
| 308 } | |
| 309 | |
| 310 bool RunWithDartOnThread(base::Thread* dart_thread, | |
| 311 const std::string& test, | |
| 312 CppSideConnection* cpp_side) { | |
| 313 dart_to_cpp::DartSidePtr dart_side_ptr; | |
| 314 auto dart_side_request = GetProxy(&dart_side_ptr); | |
| 315 | |
| 316 dart_to_cpp::CppSidePtr cpp_side_ptr; | |
| 317 cpp_side->Bind(GetProxy(&cpp_side_ptr)); | |
| 318 dart_side_ptr->SetClient(cpp_side_ptr.Pass()); | |
| 319 | |
| 320 dart_side_ptr.internal_state()->router_for_testing()->EnableTestingMode(); | |
| 321 | |
| 322 cpp_side->set_dart_side(dart_side_ptr.get()); | |
| 323 | |
| 324 DartControllerConfig config; | |
| 325 char* error; | |
| 326 bool unhandled_exception = false; | |
| 327 int64_t closed_handles; | |
| 328 InitializeDartConfig( | |
| 329 &config, test, dart_side_request.PassMessagePipe().release().value(), | |
| 330 &unhandled_exception, &closed_handles, &error); | |
| 331 | |
| 332 dart_thread->Start(); | |
| 333 dart_thread->message_loop()->PostTask(FROM_HERE, | |
| 334 base::Bind(&RunDartSide, base::ConstRef(config))); | |
| 335 | |
| 336 run_loop_.Run(); | |
| 337 return unhandled_exception; | |
| 338 } | |
| 339 | |
| 340 DISALLOW_COPY_AND_ASSIGN(DartToCppTest); | |
| 341 }; | |
| 342 | |
| 343 TEST_F(DartToCppTest, Ping) { | |
| 344 PingCppSideConnection cpp_side_connection; | |
| 345 bool unhandled_exception = | |
| 346 RunTest("dart_to_cpp_tests.dart", &cpp_side_connection); | |
| 347 EXPECT_TRUE(cpp_side_connection.DidSucceed()); | |
| 348 EXPECT_FALSE(unhandled_exception); | |
| 349 } | |
| 350 | |
| 351 TEST_F(DartToCppTest, Echo) { | |
| 352 EchoCppSideConnection cpp_side_connection; | |
| 353 bool unhandled_exception = | |
| 354 RunTest("dart_to_cpp_tests.dart", &cpp_side_connection); | |
| 355 EXPECT_TRUE(cpp_side_connection.DidSucceed()); | |
| 356 EXPECT_FALSE(unhandled_exception); | |
| 357 } | |
| 358 | |
| 359 } // namespace dart | |
| 360 } // namespace mojo | |
| OLD | NEW |