• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <stddef.h>
6 #include <stdint.h>
7 #include <stdio.h>
8 #include <algorithm>
9 #include <string>
10 #include <utility>
11 #include <vector>
12 
13 #include "base/message_loop/message_loop.h"
14 #include "base/run_loop.h"
15 #include "base/threading/thread_task_runner_handle.h"
16 #include "mojo/public/c/system/macros.h"
17 #include "mojo/public/cpp/bindings/binding.h"
18 #include "mojo/public/cpp/bindings/connector.h"
19 #include "mojo/public/cpp/bindings/interface_ptr.h"
20 #include "mojo/public/cpp/bindings/lib/filter_chain.h"
21 #include "mojo/public/cpp/bindings/lib/router.h"
22 #include "mojo/public/cpp/bindings/lib/validation_errors.h"
23 #include "mojo/public/cpp/bindings/message.h"
24 #include "mojo/public/cpp/bindings/message_header_validator.h"
25 #include "mojo/public/cpp/bindings/tests/validation_test_input_parser.h"
26 #include "mojo/public/cpp/system/core.h"
27 #include "mojo/public/cpp/test_support/test_support.h"
28 #include "mojo/public/interfaces/bindings/tests/validation_test_associated_interfaces.mojom.h"
29 #include "mojo/public/interfaces/bindings/tests/validation_test_interfaces.mojom.h"
30 #include "testing/gtest/include/gtest/gtest.h"
31 
32 namespace mojo {
33 namespace test {
34 namespace {
35 
36 template <typename T>
Append(std::vector<uint8_t> * data_vector,T data)37 void Append(std::vector<uint8_t>* data_vector, T data) {
38   size_t pos = data_vector->size();
39   data_vector->resize(pos + sizeof(T));
40   memcpy(&(*data_vector)[pos], &data, sizeof(T));
41 }
42 
TestInputParser(const std::string & input,bool expected_result,const std::vector<uint8_t> & expected_data,size_t expected_num_handles)43 bool TestInputParser(const std::string& input,
44                      bool expected_result,
45                      const std::vector<uint8_t>& expected_data,
46                      size_t expected_num_handles) {
47   std::vector<uint8_t> data;
48   size_t num_handles;
49   std::string error_message;
50 
51   bool result =
52       ParseValidationTestInput(input, &data, &num_handles, &error_message);
53   if (expected_result) {
54     if (result && error_message.empty() && expected_data == data &&
55         expected_num_handles == num_handles) {
56       return true;
57     }
58 
59     // Compare with an empty string instead of checking |error_message.empty()|,
60     // so that the message will be printed out if the two are not equal.
61     EXPECT_EQ(std::string(), error_message);
62     EXPECT_EQ(expected_data, data);
63     EXPECT_EQ(expected_num_handles, num_handles);
64     return false;
65   }
66 
67   EXPECT_FALSE(error_message.empty());
68   return !result && !error_message.empty();
69 }
70 
GetMatchingTests(const std::vector<std::string> & names,const std::string & prefix)71 std::vector<std::string> GetMatchingTests(const std::vector<std::string>& names,
72                                           const std::string& prefix) {
73   const std::string suffix = ".data";
74   std::vector<std::string> tests;
75   for (size_t i = 0; i < names.size(); ++i) {
76     if (names[i].size() >= suffix.size() &&
77         names[i].substr(0, prefix.size()) == prefix &&
78         names[i].substr(names[i].size() - suffix.size()) == suffix)
79       tests.push_back(names[i].substr(0, names[i].size() - suffix.size()));
80   }
81   return tests;
82 }
83 
ReadFile(const std::string & path,std::string * result)84 bool ReadFile(const std::string& path, std::string* result) {
85   FILE* fp = OpenSourceRootRelativeFile(path.c_str());
86   if (!fp) {
87     ADD_FAILURE() << "File not found: " << path;
88     return false;
89   }
90   fseek(fp, 0, SEEK_END);
91   size_t size = static_cast<size_t>(ftell(fp));
92   if (size == 0) {
93     result->clear();
94     fclose(fp);
95     return true;
96   }
97   fseek(fp, 0, SEEK_SET);
98   result->resize(size);
99   size_t size_read = fread(&result->at(0), 1, size, fp);
100   fclose(fp);
101   return size == size_read;
102 }
103 
ReadAndParseDataFile(const std::string & path,std::vector<uint8_t> * data,size_t * num_handles)104 bool ReadAndParseDataFile(const std::string& path,
105                           std::vector<uint8_t>* data,
106                           size_t* num_handles) {
107   std::string input;
108   if (!ReadFile(path, &input))
109     return false;
110 
111   std::string error_message;
112   if (!ParseValidationTestInput(input, data, num_handles, &error_message)) {
113     ADD_FAILURE() << error_message;
114     return false;
115   }
116 
117   return true;
118 }
119 
ReadResultFile(const std::string & path,std::string * result)120 bool ReadResultFile(const std::string& path, std::string* result) {
121   if (!ReadFile(path, result))
122     return false;
123 
124   // Result files are new-line delimited text files. Remove any CRs.
125   result->erase(std::remove(result->begin(), result->end(), '\r'),
126                 result->end());
127 
128   // Remove trailing LFs.
129   size_t pos = result->find_last_not_of('\n');
130   if (pos == std::string::npos)
131     result->clear();
132   else
133     result->resize(pos + 1);
134 
135   return true;
136 }
137 
GetPath(const std::string & root,const std::string & suffix)138 std::string GetPath(const std::string& root, const std::string& suffix) {
139   return "mojo/public/interfaces/bindings/tests/data/validation/" + root +
140          suffix;
141 }
142 
143 // |message| should be a newly created object.
ReadTestCase(const std::string & test,Message * message,std::string * expected)144 bool ReadTestCase(const std::string& test,
145                   Message* message,
146                   std::string* expected) {
147   std::vector<uint8_t> data;
148   size_t num_handles;
149   if (!ReadAndParseDataFile(GetPath(test, ".data"), &data, &num_handles) ||
150       !ReadResultFile(GetPath(test, ".expected"), expected)) {
151     return false;
152   }
153 
154   message->Initialize(static_cast<uint32_t>(data.size()),
155                       false /* zero_initialized */);
156   if (!data.empty())
157     memcpy(message->mutable_data(), &data[0], data.size());
158   message->mutable_handles()->resize(num_handles);
159 
160   return true;
161 }
162 
RunValidationTests(const std::string & prefix,MessageReceiver * test_message_receiver)163 void RunValidationTests(const std::string& prefix,
164                         MessageReceiver* test_message_receiver) {
165   std::vector<std::string> names =
166       EnumerateSourceRootRelativeDirectory(GetPath("", ""));
167   std::vector<std::string> tests = GetMatchingTests(names, prefix);
168   ASSERT_FALSE(tests.empty());
169 
170   for (size_t i = 0; i < tests.size(); ++i) {
171     Message message;
172     std::string expected;
173     ASSERT_TRUE(ReadTestCase(tests[i], &message, &expected));
174 
175     std::string result;
176     base::RunLoop run_loop;
177     mojo::internal::ValidationErrorObserverForTesting observer(
178         run_loop.QuitClosure());
179     ignore_result(test_message_receiver->Accept(&message));
180     if (expected != "PASS")  // Observer only gets called on errors.
181       run_loop.Run();
182     if (observer.last_error() == mojo::internal::VALIDATION_ERROR_NONE)
183       result = "PASS";
184     else
185       result = mojo::internal::ValidationErrorToString(observer.last_error());
186 
187     EXPECT_EQ(expected, result) << "failed test: " << tests[i];
188   }
189 }
190 
191 class DummyMessageReceiver : public MessageReceiver {
192  public:
Accept(Message * message)193   bool Accept(Message* message) override {
194     return true;  // Any message is OK.
195   }
196 };
197 
198 class ValidationTest : public testing::Test {
199  public:
ValidationTest()200   ValidationTest() {}
201 
202  protected:
203   base::MessageLoop loop_;
204 };
205 
206 class ValidationIntegrationTest : public ValidationTest {
207  public:
ValidationIntegrationTest()208   ValidationIntegrationTest() : test_message_receiver_(nullptr) {}
209 
~ValidationIntegrationTest()210   ~ValidationIntegrationTest() override {}
211 
SetUp()212   void SetUp() override {
213     ScopedMessagePipeHandle tester_endpoint;
214     ASSERT_EQ(MOJO_RESULT_OK,
215               CreateMessagePipe(nullptr, &tester_endpoint, &testee_endpoint_));
216     test_message_receiver_ =
217         new TestMessageReceiver(this, std::move(tester_endpoint));
218   }
219 
TearDown()220   void TearDown() override {
221     delete test_message_receiver_;
222     test_message_receiver_ = nullptr;
223 
224     // Make sure that the other end receives the OnConnectionError()
225     // notification.
226     PumpMessages();
227   }
228 
test_message_receiver()229   MessageReceiver* test_message_receiver() { return test_message_receiver_; }
230 
testee_endpoint()231   ScopedMessagePipeHandle testee_endpoint() {
232     return std::move(testee_endpoint_);
233   }
234 
235  private:
236   class TestMessageReceiver : public MessageReceiver {
237    public:
TestMessageReceiver(ValidationIntegrationTest * owner,ScopedMessagePipeHandle handle)238     TestMessageReceiver(ValidationIntegrationTest* owner,
239                         ScopedMessagePipeHandle handle)
240         : owner_(owner),
241           connector_(std::move(handle),
242                      mojo::Connector::SINGLE_THREADED_SEND,
243                      base::ThreadTaskRunnerHandle::Get()) {
244       connector_.set_enforce_errors_from_incoming_receiver(false);
245     }
~TestMessageReceiver()246     ~TestMessageReceiver() override {}
247 
Accept(Message * message)248     bool Accept(Message* message) override {
249       return connector_.Accept(message);
250     }
251 
252    public:
253     ValidationIntegrationTest* owner_;
254     mojo::Connector connector_;
255   };
256 
PumpMessages()257   void PumpMessages() { base::RunLoop().RunUntilIdle(); }
258 
259   TestMessageReceiver* test_message_receiver_;
260   ScopedMessagePipeHandle testee_endpoint_;
261 };
262 
263 class IntegrationTestInterfaceImpl : public IntegrationTestInterface {
264  public:
~IntegrationTestInterfaceImpl()265   ~IntegrationTestInterfaceImpl() override {}
266 
Method0(BasicStructPtr param0,const Method0Callback & callback)267   void Method0(BasicStructPtr param0,
268                const Method0Callback& callback) override {
269     callback.Run(Array<uint8_t>::New(0u));
270   }
271 };
272 
TEST_F(ValidationTest,InputParser)273 TEST_F(ValidationTest, InputParser) {
274   {
275     // The parser, as well as Append() defined above, assumes that this code is
276     // running on a little-endian platform. Test whether that is true.
277     uint16_t x = 1;
278     ASSERT_EQ(1, *(reinterpret_cast<char*>(&x)));
279   }
280   {
281     // Test empty input.
282     std::string input;
283     std::vector<uint8_t> expected;
284 
285     EXPECT_TRUE(TestInputParser(input, true, expected, 0));
286   }
287   {
288     // Test input that only consists of comments and whitespaces.
289     std::string input = "    \t  // hello world \n\r \t// the answer is 42   ";
290     std::vector<uint8_t> expected;
291 
292     EXPECT_TRUE(TestInputParser(input, true, expected, 0));
293   }
294   {
295     std::string input =
296         "[u1]0x10// hello world !! \n\r  \t [u2]65535 \n"
297         "[u4]65536 [u8]0xFFFFFFFFFFFFFFFF 0 0Xff";
298     std::vector<uint8_t> expected;
299     Append(&expected, static_cast<uint8_t>(0x10));
300     Append(&expected, static_cast<uint16_t>(65535));
301     Append(&expected, static_cast<uint32_t>(65536));
302     Append(&expected, static_cast<uint64_t>(0xffffffffffffffff));
303     Append(&expected, static_cast<uint8_t>(0));
304     Append(&expected, static_cast<uint8_t>(0xff));
305 
306     EXPECT_TRUE(TestInputParser(input, true, expected, 0));
307   }
308   {
309     std::string input = "[s8]-0x800 [s1]-128\t[s2]+0 [s4]-40";
310     std::vector<uint8_t> expected;
311     Append(&expected, -static_cast<int64_t>(0x800));
312     Append(&expected, static_cast<int8_t>(-128));
313     Append(&expected, static_cast<int16_t>(0));
314     Append(&expected, static_cast<int32_t>(-40));
315 
316     EXPECT_TRUE(TestInputParser(input, true, expected, 0));
317   }
318   {
319     std::string input = "[b]00001011 [b]10000000  // hello world\r [b]00000000";
320     std::vector<uint8_t> expected;
321     Append(&expected, static_cast<uint8_t>(11));
322     Append(&expected, static_cast<uint8_t>(128));
323     Append(&expected, static_cast<uint8_t>(0));
324 
325     EXPECT_TRUE(TestInputParser(input, true, expected, 0));
326   }
327   {
328     std::string input = "[f]+.3e9 [d]-10.03";
329     std::vector<uint8_t> expected;
330     Append(&expected, +.3e9f);
331     Append(&expected, -10.03);
332 
333     EXPECT_TRUE(TestInputParser(input, true, expected, 0));
334   }
335   {
336     std::string input = "[dist4]foo 0 [dist8]bar 0 [anchr]foo [anchr]bar";
337     std::vector<uint8_t> expected;
338     Append(&expected, static_cast<uint32_t>(14));
339     Append(&expected, static_cast<uint8_t>(0));
340     Append(&expected, static_cast<uint64_t>(9));
341     Append(&expected, static_cast<uint8_t>(0));
342 
343     EXPECT_TRUE(TestInputParser(input, true, expected, 0));
344   }
345   {
346     std::string input = "// This message has handles! \n[handles]50 [u8]2";
347     std::vector<uint8_t> expected;
348     Append(&expected, static_cast<uint64_t>(2));
349 
350     EXPECT_TRUE(TestInputParser(input, true, expected, 50));
351   }
352 
353   // Test some failure cases.
354   {
355     const char* error_inputs[] = {"/ hello world",
356                                   "[u1]x",
357                                   "[u2]-1000",
358                                   "[u1]0x100",
359                                   "[s2]-0x8001",
360                                   "[b]1",
361                                   "[b]1111111k",
362                                   "[dist4]unmatched",
363                                   "[anchr]hello [dist8]hello",
364                                   "[dist4]a [dist4]a [anchr]a",
365                                   "[dist4]a [anchr]a [dist4]a [anchr]a",
366                                   "0 [handles]50",
367                                   nullptr};
368 
369     for (size_t i = 0; error_inputs[i]; ++i) {
370       std::vector<uint8_t> expected;
371       if (!TestInputParser(error_inputs[i], false, expected, 0))
372         ADD_FAILURE() << "Unexpected test result for: " << error_inputs[i];
373     }
374   }
375 }
376 
TEST_F(ValidationTest,Conformance)377 TEST_F(ValidationTest, Conformance) {
378   DummyMessageReceiver dummy_receiver;
379   mojo::internal::FilterChain validators(&dummy_receiver);
380   validators.Append<mojo::MessageHeaderValidator>();
381   validators.Append<ConformanceTestInterface::RequestValidator_>();
382 
383   RunValidationTests("conformance_", validators.GetHead());
384 }
385 
TEST_F(ValidationTest,AssociatedConformace)386 TEST_F(ValidationTest, AssociatedConformace) {
387   DummyMessageReceiver dummy_receiver;
388   mojo::internal::FilterChain validators(&dummy_receiver);
389   validators.Append<mojo::MessageHeaderValidator>();
390   validators.Append<AssociatedConformanceTestInterface::RequestValidator_>();
391 
392   RunValidationTests("associated_conformance_", validators.GetHead());
393 }
394 
395 // This test is similar to Conformance test but its goal is specifically
396 // do bounds-check testing of message validation. For example we test the
397 // detection of off-by-one errors in method ordinals.
TEST_F(ValidationTest,BoundsCheck)398 TEST_F(ValidationTest, BoundsCheck) {
399   DummyMessageReceiver dummy_receiver;
400   mojo::internal::FilterChain validators(&dummy_receiver);
401   validators.Append<mojo::MessageHeaderValidator>();
402   validators.Append<BoundsCheckTestInterface::RequestValidator_>();
403 
404   RunValidationTests("boundscheck_", validators.GetHead());
405 }
406 
407 // This test is similar to the Conformance test but for responses.
TEST_F(ValidationTest,ResponseConformance)408 TEST_F(ValidationTest, ResponseConformance) {
409   DummyMessageReceiver dummy_receiver;
410   mojo::internal::FilterChain validators(&dummy_receiver);
411   validators.Append<mojo::MessageHeaderValidator>();
412   validators.Append<ConformanceTestInterface::ResponseValidator_>();
413 
414   RunValidationTests("resp_conformance_", validators.GetHead());
415 }
416 
417 // This test is similar to the BoundsCheck test but for responses.
TEST_F(ValidationTest,ResponseBoundsCheck)418 TEST_F(ValidationTest, ResponseBoundsCheck) {
419   DummyMessageReceiver dummy_receiver;
420   mojo::internal::FilterChain validators(&dummy_receiver);
421   validators.Append<mojo::MessageHeaderValidator>();
422   validators.Append<BoundsCheckTestInterface::ResponseValidator_>();
423 
424   RunValidationTests("resp_boundscheck_", validators.GetHead());
425 }
426 
427 // Test that InterfacePtr<X> applies the correct validators and they don't
428 // conflict with each other:
429 //   - MessageHeaderValidator
430 //   - X::ResponseValidator_
TEST_F(ValidationIntegrationTest,InterfacePtr)431 TEST_F(ValidationIntegrationTest, InterfacePtr) {
432   IntegrationTestInterfacePtr interface_ptr = MakeProxy(
433       InterfacePtrInfo<IntegrationTestInterface>(testee_endpoint(), 0u));
434   interface_ptr.internal_state()->EnableTestingMode();
435 
436   RunValidationTests("integration_intf_resp", test_message_receiver());
437   RunValidationTests("integration_msghdr", test_message_receiver());
438 }
439 
440 // Test that Binding<X> applies the correct validators and they don't
441 // conflict with each other:
442 //   - MessageHeaderValidator
443 //   - X::RequestValidator_
TEST_F(ValidationIntegrationTest,Binding)444 TEST_F(ValidationIntegrationTest, Binding) {
445   IntegrationTestInterfaceImpl interface_impl;
446   Binding<IntegrationTestInterface> binding(
447       &interface_impl,
448       MakeRequest<IntegrationTestInterface>(testee_endpoint()));
449   binding.EnableTestingMode();
450 
451   RunValidationTests("integration_intf_rqst", test_message_receiver());
452   RunValidationTests("integration_msghdr", test_message_receiver());
453 }
454 
455 // Test pointer validation (specifically, that the encoded offset is 32-bit)
TEST_F(ValidationTest,ValidateEncodedPointer)456 TEST_F(ValidationTest, ValidateEncodedPointer) {
457   uint64_t offset;
458 
459   offset = 0ULL;
460   EXPECT_TRUE(mojo::internal::ValidateEncodedPointer(&offset));
461 
462   offset = 1ULL;
463   EXPECT_TRUE(mojo::internal::ValidateEncodedPointer(&offset));
464 
465   // offset must be <= 32-bit.
466   offset = std::numeric_limits<uint32_t>::max() + 1ULL;
467   EXPECT_FALSE(mojo::internal::ValidateEncodedPointer(&offset));
468 }
469 
470 // Tests the IsKnownEnumValue() function generated for BasicEnum.
TEST(EnumValueValidationTest,BasicEnum)471 TEST(EnumValueValidationTest, BasicEnum) {
472   // BasicEnum can have -3,0,1,10 as possible integral values.
473   EXPECT_FALSE(IsKnownEnumValue(static_cast<BasicEnum>(-4)));
474   EXPECT_TRUE(IsKnownEnumValue(static_cast<BasicEnum>(-3)));
475   EXPECT_FALSE(IsKnownEnumValue(static_cast<BasicEnum>(-2)));
476   EXPECT_FALSE(IsKnownEnumValue(static_cast<BasicEnum>(-1)));
477   EXPECT_TRUE(IsKnownEnumValue(static_cast<BasicEnum>(0)));
478   EXPECT_TRUE(IsKnownEnumValue(static_cast<BasicEnum>(1)));
479   EXPECT_FALSE(IsKnownEnumValue(static_cast<BasicEnum>(2)));
480   EXPECT_FALSE(IsKnownEnumValue(static_cast<BasicEnum>(9)));
481   // In the mojom, we represent this value as hex (0xa).
482   EXPECT_TRUE(IsKnownEnumValue(static_cast<BasicEnum>(10)));
483   EXPECT_FALSE(IsKnownEnumValue(static_cast<BasicEnum>(11)));
484 }
485 
486 // Tests the IsKnownEnumValue() method generated for StructWithEnum.
TEST(EnumValueValidationTest,EnumWithin)487 TEST(EnumValueValidationTest, EnumWithin) {
488   // StructWithEnum::EnumWithin can have [0,4] as possible integral values.
489   EXPECT_FALSE(IsKnownEnumValue(static_cast<StructWithEnum::EnumWithin>(-1)));
490   EXPECT_TRUE(IsKnownEnumValue(static_cast<StructWithEnum::EnumWithin>(0)));
491   EXPECT_TRUE(IsKnownEnumValue(static_cast<StructWithEnum::EnumWithin>(1)));
492   EXPECT_TRUE(IsKnownEnumValue(static_cast<StructWithEnum::EnumWithin>(2)));
493   EXPECT_TRUE(IsKnownEnumValue(static_cast<StructWithEnum::EnumWithin>(3)));
494   EXPECT_FALSE(IsKnownEnumValue(static_cast<StructWithEnum::EnumWithin>(4)));
495 }
496 
497 }  // namespace
498 }  // namespace test
499 }  // namespace mojo
500