1 // Copyright 2016 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/files/file_path.h" 6 #include "base/files/scoped_temp_dir.h" 7 #include "base/memory/ptr_util.h" 8 #include "base/message_loop/message_loop.h" 9 #include "base/numerics/safe_math.h" 10 #include "base/run_loop.h" 11 #include "base/strings/utf_string_conversions.h" 12 #include "base/values.h" 13 #include "mojo/common/test_common_custom_types.mojom.h" 14 #include "mojo/public/cpp/bindings/binding.h" 15 #include "testing/gtest/include/gtest/gtest.h" 16 17 namespace mojo { 18 namespace common { 19 namespace test { 20 namespace { 21 22 template <typename T> 23 struct BounceTestTraits { 24 static void ExpectEquality(const T& a, const T& b) { 25 EXPECT_EQ(a, b); 26 } 27 }; 28 29 template <typename T> 30 struct PassTraits { 31 using Type = const T&; 32 }; 33 34 template <> 35 struct PassTraits<base::Time> { 36 using Type = base::Time; 37 }; 38 39 template <> 40 struct PassTraits<base::TimeDelta> { 41 using Type = base::TimeDelta; 42 }; 43 44 template <> 45 struct PassTraits<base::TimeTicks> { 46 using Type = base::TimeTicks; 47 }; 48 49 template <typename T> 50 void DoExpectResponse(T* expected_value, 51 const base::Closure& closure, 52 typename PassTraits<T>::Type value) { 53 BounceTestTraits<T>::ExpectEquality(*expected_value, value); 54 closure.Run(); 55 } 56 57 template <typename T> 58 base::Callback<void(typename PassTraits<T>::Type)> ExpectResponse( 59 T* expected_value, 60 const base::Closure& closure) { 61 return base::Bind(&DoExpectResponse<T>, expected_value, closure); 62 } 63 64 class TestFilePathImpl : public TestFilePath { 65 public: 66 explicit TestFilePathImpl(TestFilePathRequest request) 67 : binding_(this, std::move(request)) {} 68 69 // TestFilePath implementation: 70 void BounceFilePath(const base::FilePath& in, 71 const BounceFilePathCallback& callback) override { 72 callback.Run(in); 73 } 74 75 private: 76 mojo::Binding<TestFilePath> binding_; 77 }; 78 79 class TestUnguessableTokenImpl : public TestUnguessableToken { 80 public: 81 explicit TestUnguessableTokenImpl(TestUnguessableTokenRequest request) 82 : binding_(this, std::move(request)) {} 83 84 // TestUnguessableToken implementation: 85 void BounceNonce(const base::UnguessableToken& in, 86 const BounceNonceCallback& callback) override { 87 callback.Run(in); 88 } 89 90 private: 91 mojo::Binding<TestUnguessableToken> binding_; 92 }; 93 94 class TestTimeImpl : public TestTime { 95 public: 96 explicit TestTimeImpl(TestTimeRequest request) 97 : binding_(this, std::move(request)) {} 98 99 // TestTime implementation: 100 void BounceTime(base::Time in, const BounceTimeCallback& callback) override { 101 callback.Run(in); 102 } 103 104 void BounceTimeDelta(base::TimeDelta in, 105 const BounceTimeDeltaCallback& callback) override { 106 callback.Run(in); 107 } 108 109 void BounceTimeTicks(base::TimeTicks in, 110 const BounceTimeTicksCallback& callback) override { 111 callback.Run(in); 112 } 113 114 private: 115 mojo::Binding<TestTime> binding_; 116 }; 117 118 class TestValueImpl : public TestValue { 119 public: 120 explicit TestValueImpl(TestValueRequest request) 121 : binding_(this, std::move(request)) {} 122 123 // TestValue implementation: 124 void BounceDictionaryValue( 125 std::unique_ptr<base::DictionaryValue> in, 126 const BounceDictionaryValueCallback& callback) override { 127 callback.Run(std::move(in)); 128 } 129 130 void BounceListValue(std::unique_ptr<base::ListValue> in, 131 const BounceListValueCallback& callback) override { 132 callback.Run(std::move(in)); 133 } 134 135 void BounceValue(std::unique_ptr<base::Value> in, 136 const BounceValueCallback& callback) override { 137 callback.Run(std::move(in)); 138 } 139 140 private: 141 mojo::Binding<TestValue> binding_; 142 }; 143 144 class TestString16Impl : public TestString16 { 145 public: 146 explicit TestString16Impl(TestString16Request request) 147 : binding_(this, std::move(request)) {} 148 149 // TestString16 implementation: 150 void BounceString16(const base::string16& in, 151 const BounceString16Callback& callback) override { 152 callback.Run(in); 153 } 154 155 private: 156 mojo::Binding<TestString16> binding_; 157 }; 158 159 class TestFileImpl : public TestFile { 160 public: 161 explicit TestFileImpl(TestFileRequest request) 162 : binding_(this, std::move(request)) {} 163 164 // TestFile implementation: 165 void BounceFile(base::File in, const BounceFileCallback& callback) override { 166 callback.Run(std::move(in)); 167 } 168 169 private: 170 mojo::Binding<TestFile> binding_; 171 }; 172 173 class TestTextDirectionImpl : public TestTextDirection { 174 public: 175 explicit TestTextDirectionImpl(TestTextDirectionRequest request) 176 : binding_(this, std::move(request)) {} 177 178 // TestTextDirection: 179 void BounceTextDirection( 180 base::i18n::TextDirection in, 181 const BounceTextDirectionCallback& callback) override { 182 callback.Run(in); 183 } 184 185 private: 186 mojo::Binding<TestTextDirection> binding_; 187 }; 188 189 class CommonCustomTypesTest : public testing::Test { 190 protected: 191 CommonCustomTypesTest() {} 192 ~CommonCustomTypesTest() override {} 193 194 private: 195 base::MessageLoop message_loop_; 196 197 DISALLOW_COPY_AND_ASSIGN(CommonCustomTypesTest); 198 }; 199 200 } // namespace 201 202 TEST_F(CommonCustomTypesTest, FilePath) { 203 base::RunLoop run_loop; 204 205 TestFilePathPtr ptr; 206 TestFilePathImpl impl(MakeRequest(&ptr)); 207 208 base::FilePath dir(FILE_PATH_LITERAL("hello")); 209 base::FilePath file = dir.Append(FILE_PATH_LITERAL("world")); 210 211 ptr->BounceFilePath(file, ExpectResponse(&file, run_loop.QuitClosure())); 212 213 run_loop.Run(); 214 } 215 216 TEST_F(CommonCustomTypesTest, UnguessableToken) { 217 base::RunLoop run_loop; 218 219 TestUnguessableTokenPtr ptr; 220 TestUnguessableTokenImpl impl(MakeRequest(&ptr)); 221 222 base::UnguessableToken token = base::UnguessableToken::Create(); 223 224 ptr->BounceNonce(token, ExpectResponse(&token, run_loop.QuitClosure())); 225 226 run_loop.Run(); 227 } 228 229 TEST_F(CommonCustomTypesTest, Time) { 230 base::RunLoop run_loop; 231 232 TestTimePtr ptr; 233 TestTimeImpl impl(MakeRequest(&ptr)); 234 235 base::Time t = base::Time::Now(); 236 237 ptr->BounceTime(t, ExpectResponse(&t, run_loop.QuitClosure())); 238 239 run_loop.Run(); 240 } 241 242 TEST_F(CommonCustomTypesTest, TimeDelta) { 243 base::RunLoop run_loop; 244 245 TestTimePtr ptr; 246 TestTimeImpl impl(MakeRequest(&ptr)); 247 248 base::TimeDelta t = base::TimeDelta::FromDays(123); 249 250 ptr->BounceTimeDelta(t, ExpectResponse(&t, run_loop.QuitClosure())); 251 252 run_loop.Run(); 253 } 254 255 TEST_F(CommonCustomTypesTest, TimeTicks) { 256 base::RunLoop run_loop; 257 258 TestTimePtr ptr; 259 TestTimeImpl impl(MakeRequest(&ptr)); 260 261 base::TimeTicks t = base::TimeTicks::Now(); 262 263 ptr->BounceTimeTicks(t, ExpectResponse(&t, run_loop.QuitClosure())); 264 265 run_loop.Run(); 266 } 267 268 TEST_F(CommonCustomTypesTest, Value) { 269 TestValuePtr ptr; 270 TestValueImpl impl(MakeRequest(&ptr)); 271 272 std::unique_ptr<base::Value> output; 273 274 ASSERT_TRUE(ptr->BounceValue(nullptr, &output)); 275 EXPECT_FALSE(output); 276 277 std::unique_ptr<base::Value> input = base::Value::CreateNullValue(); 278 ASSERT_TRUE(ptr->BounceValue(input->CreateDeepCopy(), &output)); 279 EXPECT_TRUE(base::Value::Equals(input.get(), output.get())); 280 281 input = base::MakeUnique<base::Value>(123); 282 ASSERT_TRUE(ptr->BounceValue(input->CreateDeepCopy(), &output)); 283 EXPECT_TRUE(base::Value::Equals(input.get(), output.get())); 284 285 input = base::MakeUnique<base::Value>(1.23); 286 ASSERT_TRUE(ptr->BounceValue(input->CreateDeepCopy(), &output)); 287 EXPECT_TRUE(base::Value::Equals(input.get(), output.get())); 288 289 input = base::MakeUnique<base::Value>(false); 290 ASSERT_TRUE(ptr->BounceValue(input->CreateDeepCopy(), &output)); 291 EXPECT_TRUE(base::Value::Equals(input.get(), output.get())); 292 293 input = base::MakeUnique<base::Value>("test string"); 294 ASSERT_TRUE(ptr->BounceValue(input->CreateDeepCopy(), &output)); 295 EXPECT_TRUE(base::Value::Equals(input.get(), output.get())); 296 297 input = base::BinaryValue::CreateWithCopiedBuffer("mojo", 4); 298 ASSERT_TRUE(ptr->BounceValue(input->CreateDeepCopy(), &output)); 299 EXPECT_TRUE(base::Value::Equals(input.get(), output.get())); 300 301 auto dict = base::MakeUnique<base::DictionaryValue>(); 302 dict->SetBoolean("bool", false); 303 dict->SetInteger("int", 2); 304 dict->SetString("string", "some string"); 305 dict->SetBoolean("nested.bool", true); 306 dict->SetInteger("nested.int", 9); 307 dict->Set("some_binary", 308 base::BinaryValue::CreateWithCopiedBuffer("mojo", 4)); 309 dict->Set("null_value", base::Value::CreateNullValue()); 310 dict->SetIntegerWithoutPathExpansion("non_nested.int", 10); 311 { 312 std::unique_ptr<base::ListValue> dict_list(new base::ListValue()); 313 dict_list->AppendString("string"); 314 dict_list->AppendBoolean(true); 315 dict->Set("list", std::move(dict_list)); 316 } 317 318 std::unique_ptr<base::DictionaryValue> dict_output; 319 ASSERT_TRUE(ptr->BounceDictionaryValue(dict->CreateDeepCopy(), &dict_output)); 320 EXPECT_TRUE(base::Value::Equals(dict.get(), dict_output.get())); 321 322 input = std::move(dict); 323 ASSERT_TRUE(ptr->BounceValue(input->CreateDeepCopy(), &output)); 324 EXPECT_TRUE(base::Value::Equals(input.get(), output.get())); 325 326 auto list = base::MakeUnique<base::ListValue>(); 327 list->AppendString("string"); 328 list->AppendDouble(42.1); 329 list->AppendBoolean(true); 330 list->Append(base::BinaryValue::CreateWithCopiedBuffer("mojo", 4)); 331 list->Append(base::Value::CreateNullValue()); 332 { 333 std::unique_ptr<base::DictionaryValue> list_dict( 334 new base::DictionaryValue()); 335 list_dict->SetString("string", "str"); 336 list->Append(std::move(list_dict)); 337 } 338 std::unique_ptr<base::ListValue> list_output; 339 ASSERT_TRUE(ptr->BounceListValue(list->CreateDeepCopy(), &list_output)); 340 EXPECT_TRUE(base::Value::Equals(list.get(), list_output.get())); 341 342 input = std::move(list); 343 ASSERT_TRUE(ptr->BounceValue(input->CreateDeepCopy(), &output)); 344 ASSERT_TRUE(base::Value::Equals(input.get(), output.get())); 345 } 346 347 TEST_F(CommonCustomTypesTest, String16) { 348 base::RunLoop run_loop; 349 350 TestString16Ptr ptr; 351 TestString16Impl impl(MakeRequest(&ptr)); 352 353 base::string16 str16 = base::ASCIIToUTF16("hello world"); 354 355 ptr->BounceString16(str16, ExpectResponse(&str16, run_loop.QuitClosure())); 356 357 run_loop.Run(); 358 } 359 360 TEST_F(CommonCustomTypesTest, EmptyString16) { 361 base::RunLoop run_loop; 362 363 TestString16Ptr ptr; 364 TestString16Impl impl(MakeRequest(&ptr)); 365 366 base::string16 str16; 367 368 ptr->BounceString16(str16, ExpectResponse(&str16, run_loop.QuitClosure())); 369 370 run_loop.Run(); 371 } 372 373 TEST_F(CommonCustomTypesTest, File) { 374 base::ScopedTempDir temp_dir; 375 ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); 376 377 TestFilePtr ptr; 378 TestFileImpl impl(MakeRequest(&ptr)); 379 380 base::File file( 381 temp_dir.GetPath().AppendASCII("test_file.txt"), 382 base::File::FLAG_CREATE | base::File::FLAG_WRITE | base::File::FLAG_READ); 383 const base::StringPiece test_content = 384 "A test string to be stored in a test file"; 385 file.WriteAtCurrentPos( 386 test_content.data(), 387 base::CheckedNumeric<int>(test_content.size()).ValueOrDie()); 388 389 base::File file_out; 390 ASSERT_TRUE(ptr->BounceFile(std::move(file), &file_out)); 391 std::vector<char> content(test_content.size()); 392 ASSERT_TRUE(file_out.IsValid()); 393 ASSERT_EQ(static_cast<int>(test_content.size()), 394 file_out.Read( 395 0, content.data(), 396 base::CheckedNumeric<int>(test_content.size()).ValueOrDie())); 397 EXPECT_EQ(test_content, 398 base::StringPiece(content.data(), test_content.size())); 399 } 400 401 TEST_F(CommonCustomTypesTest, InvalidFile) { 402 TestFilePtr ptr; 403 TestFileImpl impl(MakeRequest(&ptr)); 404 405 base::ScopedTempDir temp_dir; 406 ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); 407 // Test that |file_out| is set to an invalid file. 408 base::File file_out( 409 temp_dir.GetPath().AppendASCII("test_file.txt"), 410 base::File::FLAG_CREATE | base::File::FLAG_WRITE | base::File::FLAG_READ); 411 412 ASSERT_TRUE(ptr->BounceFile(base::File(), &file_out)); 413 EXPECT_FALSE(file_out.IsValid()); 414 } 415 416 TEST_F(CommonCustomTypesTest, TextDirection) { 417 base::i18n::TextDirection kTestDirections[] = {base::i18n::LEFT_TO_RIGHT, 418 base::i18n::RIGHT_TO_LEFT, 419 base::i18n::UNKNOWN_DIRECTION}; 420 421 TestTextDirectionPtr ptr; 422 TestTextDirectionImpl impl(MakeRequest(&ptr)); 423 424 for (size_t i = 0; i < arraysize(kTestDirections); i++) { 425 base::i18n::TextDirection direction_out; 426 ASSERT_TRUE(ptr->BounceTextDirection(kTestDirections[i], &direction_out)); 427 EXPECT_EQ(kTestDirections[i], direction_out); 428 } 429 } 430 431 } // namespace test 432 } // namespace common 433 } // namespace mojo 434