| // Copyright 2017 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "base/macros.h" |
| #include "base/run_loop.h" |
| #include "base/test/bind_test_util.h" |
| #include "base/test/scoped_task_environment.h" |
| #include "mojo/public/cpp/bindings/binding.h" |
| #include "mojo/public/cpp/bindings/tests/bindings_test_base.h" |
| #include "mojo/public/interfaces/bindings/tests/struct_with_traits.mojom.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| |
| namespace mojo { |
| namespace { |
| |
| class LazySerializationTest : public testing::Test { |
| public: |
| LazySerializationTest() {} |
| ~LazySerializationTest() override {} |
| |
| private: |
| base::test::ScopedTaskEnvironment task_environment_; |
| |
| DISALLOW_COPY_AND_ASSIGN(LazySerializationTest); |
| }; |
| |
| class TestUnserializedStructImpl : public test::TestUnserializedStruct { |
| public: |
| explicit TestUnserializedStructImpl( |
| test::TestUnserializedStructRequest request) |
| : binding_(this, std::move(request)) {} |
| ~TestUnserializedStructImpl() override {} |
| |
| // test::TestUnserializedStruct: |
| void PassUnserializedStruct( |
| const test::StructWithUnreachableTraitsImpl& s, |
| PassUnserializedStructCallback callback) override { |
| std::move(callback).Run(s); |
| } |
| |
| private: |
| mojo::Binding<test::TestUnserializedStruct> binding_; |
| |
| DISALLOW_COPY_AND_ASSIGN(TestUnserializedStructImpl); |
| }; |
| |
| class ForceSerializeTesterImpl : public test::ForceSerializeTester { |
| public: |
| ForceSerializeTesterImpl(test::ForceSerializeTesterRequest request) |
| : binding_(this, std::move(request)) {} |
| ~ForceSerializeTesterImpl() override = default; |
| |
| // test::ForceSerializeTester: |
| void SendForceSerializedStruct( |
| const test::StructForceSerializeImpl& s, |
| SendForceSerializedStructCallback callback) override { |
| std::move(callback).Run(s); |
| } |
| |
| void SendNestedForceSerializedStruct( |
| const test::StructNestedForceSerializeImpl& s, |
| SendNestedForceSerializedStructCallback callback) override { |
| std::move(callback).Run(s); |
| } |
| |
| private: |
| Binding<test::ForceSerializeTester> binding_; |
| |
| DISALLOW_COPY_AND_ASSIGN(ForceSerializeTesterImpl); |
| }; |
| |
| TEST_F(LazySerializationTest, NeverSerialize) { |
| // Basic sanity check to ensure that no messages are serialized by default in |
| // environments where lazy serialization is supported, on an interface which |
| // supports lazy serialization, and where both ends of the interface are in |
| // the same process. |
| |
| test::TestUnserializedStructPtr ptr; |
| TestUnserializedStructImpl impl(MakeRequest(&ptr)); |
| |
| const int32_t kTestMagicNumber = 42; |
| |
| test::StructWithUnreachableTraitsImpl data; |
| EXPECT_EQ(0, data.magic_number); |
| data.magic_number = kTestMagicNumber; |
| |
| // Send our data over the pipe and wait for it to come back. The value should |
| // be preserved. We know the data was never serialized because the |
| // StructTraits for this type will DCHECK if executed in any capacity. |
| int received_number = 0; |
| base::RunLoop loop; |
| ptr->PassUnserializedStruct( |
| data, base::Bind( |
| [](base::RunLoop* loop, int* received_number, |
| const test::StructWithUnreachableTraitsImpl& passed) { |
| *received_number = passed.magic_number; |
| loop->Quit(); |
| }, |
| &loop, &received_number)); |
| loop.Run(); |
| EXPECT_EQ(kTestMagicNumber, received_number); |
| } |
| |
| TEST_F(LazySerializationTest, ForceSerialize) { |
| // Verifies that the [force_serialize] attribute works as intended: i.e., even |
| // with lazy serialization enabled, messages which carry a force-serialized |
| // type will always serialize at call time. |
| |
| test::ForceSerializeTesterPtr tester; |
| ForceSerializeTesterImpl impl(mojo::MakeRequest(&tester)); |
| |
| constexpr int32_t kTestValue = 42; |
| |
| base::RunLoop loop; |
| test::StructForceSerializeImpl in; |
| in.set_value(kTestValue); |
| EXPECT_FALSE(in.was_serialized()); |
| EXPECT_FALSE(in.was_deserialized()); |
| tester->SendForceSerializedStruct( |
| in, base::BindLambdaForTesting( |
| [&](const test::StructForceSerializeImpl& passed) { |
| EXPECT_EQ(kTestValue, passed.value()); |
| EXPECT_TRUE(passed.was_deserialized()); |
| EXPECT_FALSE(passed.was_serialized()); |
| loop.Quit(); |
| })); |
| EXPECT_TRUE(in.was_serialized()); |
| EXPECT_FALSE(in.was_deserialized()); |
| loop.Run(); |
| EXPECT_TRUE(in.was_serialized()); |
| EXPECT_FALSE(in.was_deserialized()); |
| } |
| |
| TEST_F(LazySerializationTest, ForceSerializeNested) { |
| // Verifies that the [force_serialize] attribute works as intended in a nested |
| // context, i.e. when a force-serialized type is contained within a |
| // non-force-serialized type, |
| |
| test::ForceSerializeTesterPtr tester; |
| ForceSerializeTesterImpl impl(mojo::MakeRequest(&tester)); |
| |
| constexpr int32_t kTestValue = 42; |
| |
| base::RunLoop loop; |
| test::StructNestedForceSerializeImpl in; |
| in.force().set_value(kTestValue); |
| EXPECT_FALSE(in.was_serialized()); |
| EXPECT_FALSE(in.was_deserialized()); |
| tester->SendNestedForceSerializedStruct( |
| in, base::BindLambdaForTesting( |
| [&](const test::StructNestedForceSerializeImpl& passed) { |
| EXPECT_EQ(kTestValue, passed.force().value()); |
| EXPECT_TRUE(passed.was_deserialized()); |
| EXPECT_FALSE(passed.was_serialized()); |
| loop.Quit(); |
| })); |
| EXPECT_TRUE(in.was_serialized()); |
| EXPECT_FALSE(in.was_deserialized()); |
| loop.Run(); |
| EXPECT_TRUE(in.was_serialized()); |
| EXPECT_FALSE(in.was_deserialized()); |
| } |
| |
| } // namespace |
| } // namespace mojo |