Chromium Code Reviews| Index: mojo/public/cpp/bindings/tests/validation_unittest.cc |
| diff --git a/mojo/public/cpp/bindings/tests/validation_unittest.cc b/mojo/public/cpp/bindings/tests/validation_unittest.cc |
| index f111091472309c9e0b19aa7faf14f03f908a486c..699f17fa7e3cf484e4af043ff44b072af052a82f 100644 |
| --- a/mojo/public/cpp/bindings/tests/validation_unittest.cc |
| +++ b/mojo/public/cpp/bindings/tests/validation_unittest.cc |
| @@ -5,14 +5,23 @@ |
| #include <stdio.h> |
| #include <algorithm> |
| -#include <sstream> |
| #include <string> |
| #include <vector> |
| +#include "mojo/public/cpp/bindings/interface_impl.h" |
| +#include "mojo/public/cpp/bindings/interface_ptr.h" |
| +#include "mojo/public/cpp/bindings/lib/connector.h" |
| +#include "mojo/public/cpp/bindings/lib/filter_chain.h" |
| #include "mojo/public/cpp/bindings/lib/message_header_validator.h" |
| +#include "mojo/public/cpp/bindings/lib/router.h" |
| #include "mojo/public/cpp/bindings/lib/validation_errors.h" |
| +#include "mojo/public/cpp/bindings/message.h" |
| #include "mojo/public/cpp/bindings/tests/validation_test_input_parser.h" |
| +#include "mojo/public/cpp/environment/environment.h" |
| +#include "mojo/public/cpp/system/core.h" |
| #include "mojo/public/cpp/test_support/test_support.h" |
| +#include "mojo/public/cpp/utility/run_loop.h" |
| +#include "mojo/public/interfaces/bindings/tests/validation_test_interfaces.mojom.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| namespace mojo { |
| @@ -116,23 +125,51 @@ bool ReadResultFile(const std::string& path, std::string* result) { |
| } |
| std::string GetPath(const std::string& root, const std::string& suffix) { |
| - return "mojo/public/interfaces/bindings/tests/data/" + root + suffix; |
| + return "mojo/public/interfaces/bindings/tests/data/validation/" + |
| + root + suffix; |
| } |
| -void RunValidationTest(const std::string& root, std::string (*func)(Message*)) { |
| +// |message| should be a newly created object. |
| +bool ReadTestCase(const std::string& test, |
| + Message* message, |
| + std::string* expected) { |
| std::vector<uint8_t> data; |
| - ASSERT_TRUE(ReadAndParseDataFile(GetPath(root, ".data"), &data)); |
| - |
| - std::string expected; |
| - ASSERT_TRUE(ReadResultFile(GetPath(root, ".expected"), &expected)); |
| + if (!ReadAndParseDataFile(GetPath(test, ".data"), &data) || |
| + !ReadResultFile(GetPath(test, ".expected"), expected)) { |
| + return false; |
| + } |
| - Message message; |
| - message.AllocUninitializedData(static_cast<uint32_t>(data.size())); |
| + message->AllocUninitializedData(static_cast<uint32_t>(data.size())); |
| if (!data.empty()) |
| - memcpy(message.mutable_data(), &data[0], data.size()); |
| + memcpy(message->mutable_data(), &data[0], data.size()); |
| + |
| + // TODO(yzshen): add support to specify the number of handles associated with |
| + // the message. |
| + |
| + return true; |
| +} |
| - std::string result = func(&message); |
| - EXPECT_EQ(expected, result) << "failed test: " << root; |
| +void RunValidationTests(const std::string& prefix, |
| + MessageReceiver* test_message_receiver) { |
| + std::vector<std::string> names = |
| + EnumerateSourceRootRelativeDirectory(GetPath("", "")); |
| + std::vector<std::string> tests = GetMatchingTests(names, prefix); |
| + |
| + for (size_t i = 0; i < tests.size(); ++i) { |
| + Message message; |
| + std::string expected; |
| + ASSERT_TRUE(ReadTestCase(tests[i], &message, &expected)); |
| + |
| + std::string result; |
| + mojo::internal::ValidationErrorObserverForTesting observer; |
| + test_message_receiver->Accept(&message); |
| + if (observer.last_error() == mojo::internal::VALIDATION_ERROR_NONE) |
| + result = "PASS"; |
| + else |
| + result = mojo::internal::ValidationErrorToString(observer.last_error()); |
| + |
| + EXPECT_EQ(expected, result) << "failed test: " << tests[i]; |
| + } |
| } |
| class DummyMessageReceiver : public MessageReceiver { |
| @@ -142,23 +179,94 @@ class DummyMessageReceiver : public MessageReceiver { |
| } |
| }; |
| -std::string DumpMessageHeader(Message* message) { |
| - internal::ValidationErrorObserverForTesting observer; |
| - DummyMessageReceiver not_reached_receiver; |
| - internal::MessageHeaderValidator validator(¬_reached_receiver); |
| - bool rv = validator.Accept(message); |
| - if (!rv) { |
| - EXPECT_NE(internal::VALIDATION_ERROR_NONE, observer.last_error()); |
| - return internal::ValidationErrorToString(observer.last_error()); |
| +class ValidationIntegrationTest : public testing::Test { |
| + public: |
| + ValidationIntegrationTest() : test_message_receiver_(NULL) { |
| } |
| - std::ostringstream os; |
| - os << "num_bytes: " << message->header()->num_bytes << "\n" |
| - << "num_fields: " << message->header()->num_fields << "\n" |
| - << "name: " << message->header()->name << "\n" |
| - << "flags: " << message->header()->flags; |
| - return os.str(); |
| -} |
| + virtual ~ValidationIntegrationTest() { |
| + } |
| + |
| + virtual void SetUp() MOJO_OVERRIDE { |
| + ScopedMessagePipeHandle tester_endpoint; |
| + ASSERT_EQ(MOJO_RESULT_OK, |
| + CreateMessagePipe(&tester_endpoint, &testee_endpoint_)); |
| + test_message_receiver_ = |
| + new TestMessageReceiver(this, tester_endpoint.Pass()); |
| + } |
| + |
| + virtual void TearDown() MOJO_OVERRIDE { |
| + delete test_message_receiver_; |
| + test_message_receiver_ = NULL; |
| + |
| + // Make sure that the other end receives the OnConnectionError() |
| + // notification. |
| + PumpMessages(); |
| + } |
| + |
| + MessageReceiver* test_message_receiver() { |
| + return test_message_receiver_; |
| + } |
| + |
| + ScopedMessagePipeHandle testee_endpoint() { |
| + return testee_endpoint_.Pass(); |
| + } |
| + |
| + private: |
| + class TestMessageReceiver : public MessageReceiver { |
| + public: |
| + TestMessageReceiver(ValidationIntegrationTest* owner, |
| + ScopedMessagePipeHandle handle) |
| + : owner_(owner), |
| + connector_(handle.Pass()) { |
| + |
|
darin (slow to review)
2014/06/12 23:06:56
nit: nuke extra newline
yzshen1
2014/06/12 23:12:21
Done.
|
| + } |
| + virtual ~TestMessageReceiver() { |
| + } |
| + |
| + virtual bool Accept(Message* message) MOJO_OVERRIDE { |
| + bool rv = connector_.Accept(message); |
| + owner_->PumpMessages(); |
| + return rv; |
| + } |
| + |
| + public: |
| + ValidationIntegrationTest* owner_; |
| + mojo::internal::Connector connector_; |
| + }; |
| + |
| + void PumpMessages() { |
| + loop_.RunUntilIdle(); |
| + } |
| + |
| + Environment env_; |
| + RunLoop loop_; |
| + TestMessageReceiver* test_message_receiver_; |
| + ScopedMessagePipeHandle testee_endpoint_; |
| +}; |
| + |
| +class IntegrationTestInterface1Client : public IntegrationTestInterface1 { |
| + public: |
| + virtual ~IntegrationTestInterface1Client() { |
| + } |
| + |
| + virtual void Method0(BasicStructPtr param0) MOJO_OVERRIDE { |
| + } |
| +}; |
| + |
| +class IntegrationTestInterface1Impl |
| + : public InterfaceImpl<IntegrationTestInterface1> { |
| + public: |
| + virtual ~IntegrationTestInterface1Impl() { |
| + } |
| + |
| + virtual void Method0(BasicStructPtr param0) MOJO_OVERRIDE { |
| + } |
| + |
| + virtual void OnConnectionError() MOJO_OVERRIDE { |
| + delete this; |
| + } |
| +}; |
| TEST(ValidationTest, InputParser) { |
| { |
| @@ -254,15 +362,45 @@ TEST(ValidationTest, InputParser) { |
| } |
| } |
| -TEST(ValidationTest, TestAll) { |
| - std::vector<std::string> names = |
| - EnumerateSourceRootRelativeDirectory(GetPath("", "")); |
| +TEST(ValidationTest, Conformance) { |
| + DummyMessageReceiver dummy_receiver; |
| + mojo::internal::FilterChain validators(&dummy_receiver); |
| + validators.Append<mojo::internal::MessageHeaderValidator>(); |
| + validators.Append<ConformanceTestInterface::RequestValidator_>(); |
| + |
| + // TODO(yzshen): add more conformance tests. |
| + RunValidationTests("conformance_", validators.GetHead()); |
| +} |
| + |
| +TEST_F(ValidationIntegrationTest, InterfacePtr) { |
| + // Test that InterfacePtr<X> applies the correct validators and they don't |
| + // conflict with each other: |
| + // - MessageHeaderValidator |
| + // - X::Client::RequestValidator_ |
| + // - X::ResponseValidator_ |
| + |
| + IntegrationTestInterface1Client interface1_client; |
| + IntegrationTestInterface2Ptr interface2_ptr = |
| + MakeProxy<IntegrationTestInterface2>(testee_endpoint().Pass()); |
| + interface2_ptr.set_client(&interface1_client); |
| + interface2_ptr.internal_state()->router()->EnableTestingMode(); |
| + |
| + RunValidationTests("integration_", test_message_receiver()); |
| +} |
| + |
| +TEST_F(ValidationIntegrationTest, InterfaceImpl) { |
| + // Test that InterfaceImpl<X> applies the correct validators and they don't |
| + // conflict with each other: |
| + // - MessageHeaderValidator |
| + // - X::RequestValidator_ |
| + // - X::Client::ResponseValidator_ |
| - std::vector<std::string> header_tests = |
| - GetMatchingTests(names, "validate_header_"); |
| + // |interface1_impl| will delete itself when the pipe is closed. |
| + IntegrationTestInterface1Impl* interface1_impl = |
| + BindToPipe(new IntegrationTestInterface1Impl(), testee_endpoint().Pass()); |
| + interface1_impl->internal_state()->router()->EnableTestingMode(); |
| - for (size_t i = 0; i < header_tests.size(); ++i) |
| - RunValidationTest(header_tests[i], &DumpMessageHeader); |
| + RunValidationTests("integration_", test_message_receiver()); |
| } |
| } // namespace |