Home | History | Annotate | Download | only in common
      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