Home | History | Annotate | Download | only in tests
      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 <stdio.h>
      6 
      7 #include <algorithm>
      8 #include <string>
      9 #include <vector>
     10 
     11 #include "mojo/public/c/system/macros.h"
     12 #include "mojo/public/cpp/bindings/interface_impl.h"
     13 #include "mojo/public/cpp/bindings/interface_ptr.h"
     14 #include "mojo/public/cpp/bindings/lib/connector.h"
     15 #include "mojo/public/cpp/bindings/lib/filter_chain.h"
     16 #include "mojo/public/cpp/bindings/lib/message_header_validator.h"
     17 #include "mojo/public/cpp/bindings/lib/router.h"
     18 #include "mojo/public/cpp/bindings/lib/validation_errors.h"
     19 #include "mojo/public/cpp/bindings/message.h"
     20 #include "mojo/public/cpp/bindings/tests/validation_test_input_parser.h"
     21 #include "mojo/public/cpp/environment/environment.h"
     22 #include "mojo/public/cpp/system/core.h"
     23 #include "mojo/public/cpp/test_support/test_support.h"
     24 #include "mojo/public/cpp/utility/run_loop.h"
     25 #include "mojo/public/interfaces/bindings/tests/validation_test_interfaces.mojom.h"
     26 #include "testing/gtest/include/gtest/gtest.h"
     27 
     28 namespace mojo {
     29 namespace test {
     30 namespace {
     31 
     32 template <typename T>
     33 void Append(std::vector<uint8_t>* data_vector, T data) {
     34   size_t pos = data_vector->size();
     35   data_vector->resize(pos + sizeof(T));
     36   memcpy(&(*data_vector)[pos], &data, sizeof(T));
     37 }
     38 
     39 bool TestInputParser(const std::string& input,
     40                      bool expected_result,
     41                      const std::vector<uint8_t>& expected_data,
     42                      size_t expected_num_handles) {
     43   std::vector<uint8_t> data;
     44   size_t num_handles;
     45   std::string error_message;
     46 
     47   bool result = ParseValidationTestInput(input, &data, &num_handles,
     48                                          &error_message);
     49   if (expected_result) {
     50     if (result && error_message.empty() &&
     51         expected_data == data && expected_num_handles == num_handles) {
     52       return true;
     53     }
     54 
     55     // Compare with an empty string instead of checking |error_message.empty()|,
     56     // so that the message will be printed out if the two are not equal.
     57     EXPECT_EQ(std::string(), error_message);
     58     EXPECT_EQ(expected_data, data);
     59     EXPECT_EQ(expected_num_handles, num_handles);
     60     return false;
     61   }
     62 
     63   EXPECT_FALSE(error_message.empty());
     64   return !result && !error_message.empty();
     65 }
     66 
     67 std::vector<std::string> GetMatchingTests(const std::vector<std::string>& names,
     68                                           const std::string& prefix) {
     69   const std::string suffix = ".data";
     70   std::vector<std::string> tests;
     71   for (size_t i = 0; i < names.size(); ++i) {
     72     if (names[i].size() >= suffix.size() &&
     73         names[i].substr(0, prefix.size()) == prefix &&
     74         names[i].substr(names[i].size() - suffix.size()) == suffix)
     75       tests.push_back(names[i].substr(0, names[i].size() - suffix.size()));
     76   }
     77   return tests;
     78 }
     79 
     80 bool ReadFile(const std::string& path, std::string* result) {
     81   FILE* fp = OpenSourceRootRelativeFile(path.c_str());
     82   if (!fp) {
     83     ADD_FAILURE() << "File not found: " << path;
     84     return false;
     85   }
     86   fseek(fp, 0, SEEK_END);
     87   size_t size = static_cast<size_t>(ftell(fp));
     88   if (size == 0) {
     89     result->clear();
     90     fclose(fp);
     91     return true;
     92   }
     93   fseek(fp, 0, SEEK_SET);
     94   result->resize(size);
     95   size_t size_read = fread(&result->at(0), 1, size, fp);
     96   fclose(fp);
     97   return size == size_read;
     98 }
     99 
    100 bool ReadAndParseDataFile(const std::string& path,
    101                           std::vector<uint8_t>* data,
    102                           size_t* num_handles) {
    103   std::string input;
    104   if (!ReadFile(path, &input))
    105     return false;
    106 
    107   std::string error_message;
    108   if (!ParseValidationTestInput(input, data, num_handles, &error_message)) {
    109     ADD_FAILURE() << error_message;
    110     return false;
    111   }
    112 
    113   return true;
    114 }
    115 
    116 bool ReadResultFile(const std::string& path, std::string* result) {
    117   if (!ReadFile(path, result))
    118     return false;
    119 
    120   // Result files are new-line delimited text files. Remove any CRs.
    121   result->erase(std::remove(result->begin(), result->end(), '\r'),
    122                 result->end());
    123 
    124   // Remove trailing LFs.
    125   size_t pos = result->find_last_not_of('\n');
    126   if (pos == std::string::npos)
    127     result->clear();
    128   else
    129     result->resize(pos + 1);
    130 
    131   return true;
    132 }
    133 
    134 std::string GetPath(const std::string& root, const std::string& suffix) {
    135   return "mojo/public/interfaces/bindings/tests/data/validation/" +
    136       root + suffix;
    137 }
    138 
    139 // |message| should be a newly created object.
    140 bool ReadTestCase(const std::string& test,
    141                   Message* message,
    142                   std::string* expected) {
    143   std::vector<uint8_t> data;
    144   size_t num_handles;
    145   if (!ReadAndParseDataFile(GetPath(test, ".data"), &data, &num_handles) ||
    146       !ReadResultFile(GetPath(test, ".expected"), expected)) {
    147     return false;
    148   }
    149 
    150   message->AllocUninitializedData(static_cast<uint32_t>(data.size()));
    151   if (!data.empty())
    152     memcpy(message->mutable_data(), &data[0], data.size());
    153   message->mutable_handles()->resize(num_handles);
    154 
    155   return true;
    156 }
    157 
    158 void RunValidationTests(const std::string& prefix,
    159                         MessageReceiver* test_message_receiver) {
    160   std::vector<std::string> names =
    161       EnumerateSourceRootRelativeDirectory(GetPath("", ""));
    162   std::vector<std::string> tests = GetMatchingTests(names, prefix);
    163 
    164   for (size_t i = 0; i < tests.size(); ++i) {
    165     Message message;
    166     std::string expected;
    167     ASSERT_TRUE(ReadTestCase(tests[i], &message, &expected));
    168 
    169     std::string result;
    170     mojo::internal::ValidationErrorObserverForTesting observer;
    171     bool unused MOJO_ALLOW_UNUSED = test_message_receiver->Accept(&message);
    172     if (observer.last_error() == mojo::internal::VALIDATION_ERROR_NONE)
    173       result = "PASS";
    174     else
    175       result = mojo::internal::ValidationErrorToString(observer.last_error());
    176 
    177     EXPECT_EQ(expected, result) << "failed test: " << tests[i];
    178   }
    179 }
    180 
    181 class DummyMessageReceiver : public MessageReceiver {
    182  public:
    183   virtual bool Accept(Message* message) MOJO_OVERRIDE {
    184     return true;  // Any message is OK.
    185   }
    186 };
    187 
    188 class ValidationTest : public testing::Test {
    189  public:
    190   virtual ~ValidationTest() {
    191   }
    192 
    193  private:
    194   Environment env_;
    195 };
    196 
    197 class ValidationIntegrationTest : public ValidationTest {
    198  public:
    199   ValidationIntegrationTest() : test_message_receiver_(NULL) {
    200   }
    201 
    202   virtual ~ValidationIntegrationTest() {
    203   }
    204 
    205   virtual void SetUp() MOJO_OVERRIDE {
    206     ScopedMessagePipeHandle tester_endpoint;
    207     ASSERT_EQ(MOJO_RESULT_OK,
    208               CreateMessagePipe(NULL, &tester_endpoint, &testee_endpoint_));
    209     test_message_receiver_ =
    210         new TestMessageReceiver(this, tester_endpoint.Pass());
    211   }
    212 
    213   virtual void TearDown() MOJO_OVERRIDE {
    214     delete test_message_receiver_;
    215     test_message_receiver_ = NULL;
    216 
    217     // Make sure that the other end receives the OnConnectionError()
    218     // notification.
    219     PumpMessages();
    220   }
    221 
    222   MessageReceiver* test_message_receiver() {
    223     return test_message_receiver_;
    224   }
    225 
    226   ScopedMessagePipeHandle testee_endpoint() {
    227     return testee_endpoint_.Pass();
    228   }
    229 
    230  private:
    231   class TestMessageReceiver : public MessageReceiver {
    232    public:
    233     TestMessageReceiver(ValidationIntegrationTest* owner,
    234                         ScopedMessagePipeHandle handle)
    235         : owner_(owner),
    236           connector_(handle.Pass()) {
    237     }
    238     virtual ~TestMessageReceiver() {
    239     }
    240 
    241     virtual bool Accept(Message* message) MOJO_OVERRIDE {
    242       bool rv = connector_.Accept(message);
    243       owner_->PumpMessages();
    244       return rv;
    245     }
    246 
    247    public:
    248     ValidationIntegrationTest* owner_;
    249     mojo::internal::Connector connector_;
    250   };
    251 
    252   void PumpMessages() {
    253     loop_.RunUntilIdle();
    254   }
    255 
    256   RunLoop loop_;
    257   TestMessageReceiver* test_message_receiver_;
    258   ScopedMessagePipeHandle testee_endpoint_;
    259 };
    260 
    261 class IntegrationTestInterface1Client : public IntegrationTestInterface1 {
    262  public:
    263   virtual ~IntegrationTestInterface1Client() {
    264   }
    265 
    266   virtual void Method0(BasicStructPtr param0) MOJO_OVERRIDE {
    267   }
    268 };
    269 
    270 class IntegrationTestInterface1Impl
    271     : public InterfaceImpl<IntegrationTestInterface1> {
    272  public:
    273   virtual ~IntegrationTestInterface1Impl() {
    274   }
    275 
    276   virtual void Method0(BasicStructPtr param0) MOJO_OVERRIDE {
    277   }
    278 };
    279 
    280 TEST_F(ValidationTest, InputParser) {
    281   {
    282     // The parser, as well as Append() defined above, assumes that this code is
    283     // running on a little-endian platform. Test whether that is true.
    284     uint16_t x = 1;
    285     ASSERT_EQ(1, *(reinterpret_cast<char*>(&x)));
    286   }
    287   {
    288     // Test empty input.
    289     std::string input;
    290     std::vector<uint8_t> expected;
    291 
    292     EXPECT_TRUE(TestInputParser(input, true, expected, 0));
    293   }
    294   {
    295     // Test input that only consists of comments and whitespaces.
    296     std::string input = "    \t  // hello world \n\r \t// the answer is 42   ";
    297     std::vector<uint8_t> expected;
    298 
    299     EXPECT_TRUE(TestInputParser(input, true, expected, 0));
    300   }
    301   {
    302     std::string input = "[u1]0x10// hello world !! \n\r  \t [u2]65535 \n"
    303                         "[u4]65536 [u8]0xFFFFFFFFFFFFFFFF 0 0Xff";
    304     std::vector<uint8_t> expected;
    305     Append(&expected, static_cast<uint8_t>(0x10));
    306     Append(&expected, static_cast<uint16_t>(65535));
    307     Append(&expected, static_cast<uint32_t>(65536));
    308     Append(&expected, static_cast<uint64_t>(0xffffffffffffffff));
    309     Append(&expected, static_cast<uint8_t>(0));
    310     Append(&expected, static_cast<uint8_t>(0xff));
    311 
    312     EXPECT_TRUE(TestInputParser(input, true, expected, 0));
    313   }
    314   {
    315     std::string input = "[s8]-0x800 [s1]-128\t[s2]+0 [s4]-40";
    316     std::vector<uint8_t> expected;
    317     Append(&expected, -static_cast<int64_t>(0x800));
    318     Append(&expected, static_cast<int8_t>(-128));
    319     Append(&expected, static_cast<int16_t>(0));
    320     Append(&expected, static_cast<int32_t>(-40));
    321 
    322     EXPECT_TRUE(TestInputParser(input, true, expected, 0));
    323   }
    324   {
    325     std::string input = "[b]00001011 [b]10000000  // hello world\r [b]00000000";
    326     std::vector<uint8_t> expected;
    327     Append(&expected, static_cast<uint8_t>(11));
    328     Append(&expected, static_cast<uint8_t>(128));
    329     Append(&expected, static_cast<uint8_t>(0));
    330 
    331     EXPECT_TRUE(TestInputParser(input, true, expected, 0));
    332   }
    333   {
    334     std::string input = "[f]+.3e9 [d]-10.03";
    335     std::vector<uint8_t> expected;
    336     Append(&expected, +.3e9f);
    337     Append(&expected, -10.03);
    338 
    339     EXPECT_TRUE(TestInputParser(input, true, expected, 0));
    340   }
    341   {
    342     std::string input = "[dist4]foo 0 [dist8]bar 0 [anchr]foo [anchr]bar";
    343     std::vector<uint8_t> expected;
    344     Append(&expected, static_cast<uint32_t>(14));
    345     Append(&expected, static_cast<uint8_t>(0));
    346     Append(&expected, static_cast<uint64_t>(9));
    347     Append(&expected, static_cast<uint8_t>(0));
    348 
    349     EXPECT_TRUE(TestInputParser(input, true, expected, 0));
    350   }
    351   {
    352     std::string input = "// This message has handles! \n[handles]50 [u8]2";
    353     std::vector<uint8_t> expected;
    354     Append(&expected, static_cast<uint64_t>(2));
    355 
    356     EXPECT_TRUE(TestInputParser(input, true, expected, 50));
    357   }
    358 
    359   // Test some failure cases.
    360   {
    361     const char* error_inputs[] = {
    362       "/ hello world",
    363       "[u1]x",
    364       "[u2]-1000",
    365       "[u1]0x100",
    366       "[s2]-0x8001",
    367       "[b]1",
    368       "[b]1111111k",
    369       "[dist4]unmatched",
    370       "[anchr]hello [dist8]hello",
    371       "[dist4]a [dist4]a [anchr]a",
    372       "[dist4]a [anchr]a [dist4]a [anchr]a",
    373       "0 [handles]50",
    374       NULL
    375     };
    376 
    377     for (size_t i = 0; error_inputs[i]; ++i) {
    378       std::vector<uint8_t> expected;
    379       if (!TestInputParser(error_inputs[i], false, expected, 0))
    380         ADD_FAILURE() << "Unexpected test result for: " << error_inputs[i];
    381     }
    382   }
    383 }
    384 
    385 TEST_F(ValidationTest, Conformance) {
    386   DummyMessageReceiver dummy_receiver;
    387   mojo::internal::FilterChain validators(&dummy_receiver);
    388   validators.Append<mojo::internal::MessageHeaderValidator>();
    389   validators.Append<ConformanceTestInterface::RequestValidator_>();
    390 
    391   RunValidationTests("conformance_", validators.GetHead());
    392 }
    393 
    394 TEST_F(ValidationTest, NotImplemented) {
    395   DummyMessageReceiver dummy_receiver;
    396   mojo::internal::FilterChain validators(&dummy_receiver);
    397   validators.Append<mojo::internal::MessageHeaderValidator>();
    398   validators.Append<ConformanceTestInterface::RequestValidator_>();
    399 
    400   RunValidationTests("not_implemented_", validators.GetHead());
    401 }
    402 
    403 TEST_F(ValidationIntegrationTest, InterfacePtr) {
    404   // Test that InterfacePtr<X> applies the correct validators and they don't
    405   // conflict with each other:
    406   //   - MessageHeaderValidator
    407   //   - X::Client::RequestValidator_
    408   //   - X::ResponseValidator_
    409 
    410   IntegrationTestInterface1Client interface1_client;
    411   IntegrationTestInterface2Ptr interface2_ptr =
    412       MakeProxy<IntegrationTestInterface2>(testee_endpoint().Pass());
    413   interface2_ptr.set_client(&interface1_client);
    414   interface2_ptr.internal_state()->router_for_testing()->EnableTestingMode();
    415 
    416   RunValidationTests("integration_", test_message_receiver());
    417 }
    418 
    419 TEST_F(ValidationIntegrationTest, InterfaceImpl) {
    420   // Test that InterfaceImpl<X> applies the correct validators and they don't
    421   // conflict with each other:
    422   //   - MessageHeaderValidator
    423   //   - X::RequestValidator_
    424   //   - X::Client::ResponseValidator_
    425 
    426   // |interface1_impl| will delete itself when the pipe is closed.
    427   IntegrationTestInterface1Impl* interface1_impl =
    428       BindToPipe(new IntegrationTestInterface1Impl(), testee_endpoint().Pass());
    429   interface1_impl->internal_state()->router()->EnableTestingMode();
    430 
    431   RunValidationTests("integration_", test_message_receiver());
    432 }
    433 
    434 }  // namespace
    435 }  // namespace test
    436 }  // namespace mojo
    437