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