// Copyright 2016 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 <memory> #include <string> #include <unordered_map> #include <vector> #include "base/message_loop/message_loop.h" #include "mojo/public/cpp/bindings/binding.h" #include "mojo/public/cpp/bindings/lib/fixed_buffer.h" #include "mojo/public/cpp/bindings/lib/serialization.h" #include "mojo/public/interfaces/bindings/tests/test_data_view.mojom.h" #include "testing/gtest/include/gtest/gtest.h" namespace mojo { namespace test { namespace data_view { namespace { class DataViewTest : public testing::Test { private: base::MessageLoop message_loop_; }; struct DataViewHolder { std::unique_ptr<TestStructDataView> data_view; mojo::Message message; mojo::internal::SerializationContext context; }; std::unique_ptr<DataViewHolder> SerializeTestStruct(TestStructPtr input) { auto result = std::make_unique<DataViewHolder>(); result->message = Message(0, 0, 0, 0, nullptr); internal::TestStruct_Data::BufferWriter writer; mojo::internal::Serialize<TestStructDataView>( input, result->message.payload_buffer(), &writer, &result->context); result->data_view = std::make_unique<TestStructDataView>(writer.data(), &result->context); return result; } class TestInterfaceImpl : public TestInterface { public: explicit TestInterfaceImpl(TestInterfaceRequest request) : binding_(this, std::move(request)) {} ~TestInterfaceImpl() override {} // TestInterface implementation: void Echo(int32_t value, const EchoCallback& callback) override { callback.Run(value); } private: Binding<TestInterface> binding_; }; } // namespace TEST_F(DataViewTest, String) { TestStructPtr obj(TestStruct::New()); obj->f_string = "hello"; auto data_view_holder = SerializeTestStruct(std::move(obj)); auto& data_view = *data_view_holder->data_view; StringDataView string_data_view; data_view.GetFStringDataView(&string_data_view); ASSERT_FALSE(string_data_view.is_null()); EXPECT_EQ(std::string("hello"), std::string(string_data_view.storage(), string_data_view.size())); } TEST_F(DataViewTest, NestedStruct) { TestStructPtr obj(TestStruct::New()); obj->f_struct = NestedStruct::New(); obj->f_struct->f_int32 = 42; auto data_view_holder = SerializeTestStruct(std::move(obj)); auto& data_view = *data_view_holder->data_view; NestedStructDataView struct_data_view; data_view.GetFStructDataView(&struct_data_view); ASSERT_FALSE(struct_data_view.is_null()); EXPECT_EQ(42, struct_data_view.f_int32()); } TEST_F(DataViewTest, NativeStruct) { TestStructPtr obj(TestStruct::New()); obj->f_native_struct = native::NativeStruct::New(); obj->f_native_struct->data = std::vector<uint8_t>({3, 2, 1}); auto data_view_holder = SerializeTestStruct(std::move(obj)); auto& data_view = *data_view_holder->data_view; native::NativeStructDataView struct_data_view; data_view.GetFNativeStructDataView(&struct_data_view); ArrayDataView<uint8_t> data_data_view; struct_data_view.GetDataDataView(&data_data_view); ASSERT_FALSE(data_data_view.is_null()); ASSERT_EQ(3u, data_data_view.size()); EXPECT_EQ(3, data_data_view[0]); EXPECT_EQ(2, data_data_view[1]); EXPECT_EQ(1, data_data_view[2]); EXPECT_EQ(3, *data_data_view.data()); } TEST_F(DataViewTest, BoolArray) { TestStructPtr obj(TestStruct::New()); obj->f_bool_array = {true, false}; auto data_view_holder = SerializeTestStruct(std::move(obj)); auto& data_view = *data_view_holder->data_view; ArrayDataView<bool> array_data_view; data_view.GetFBoolArrayDataView(&array_data_view); ASSERT_FALSE(array_data_view.is_null()); ASSERT_EQ(2u, array_data_view.size()); EXPECT_TRUE(array_data_view[0]); EXPECT_FALSE(array_data_view[1]); } TEST_F(DataViewTest, IntegerArray) { TestStructPtr obj(TestStruct::New()); obj->f_int32_array = {1024, 128}; auto data_view_holder = SerializeTestStruct(std::move(obj)); auto& data_view = *data_view_holder->data_view; ArrayDataView<int32_t> array_data_view; data_view.GetFInt32ArrayDataView(&array_data_view); ASSERT_FALSE(array_data_view.is_null()); ASSERT_EQ(2u, array_data_view.size()); EXPECT_EQ(1024, array_data_view[0]); EXPECT_EQ(128, array_data_view[1]); EXPECT_EQ(1024, *array_data_view.data()); } TEST_F(DataViewTest, EnumArray) { TestStructPtr obj(TestStruct::New()); obj->f_enum_array = {TestEnum::VALUE_1, TestEnum::VALUE_0}; auto data_view_holder = SerializeTestStruct(std::move(obj)); auto& data_view = *data_view_holder->data_view; ArrayDataView<TestEnum> array_data_view; data_view.GetFEnumArrayDataView(&array_data_view); ASSERT_FALSE(array_data_view.is_null()); ASSERT_EQ(2u, array_data_view.size()); EXPECT_EQ(TestEnum::VALUE_1, array_data_view[0]); EXPECT_EQ(TestEnum::VALUE_0, array_data_view[1]); EXPECT_EQ(TestEnum::VALUE_0, *(array_data_view.data() + 1)); TestEnum output; ASSERT_TRUE(array_data_view.Read(0, &output)); EXPECT_EQ(TestEnum::VALUE_1, output); } TEST_F(DataViewTest, InterfaceArray) { TestInterfacePtrInfo ptr_info; TestInterfaceImpl impl(MakeRequest(&ptr_info)); TestStructPtr obj(TestStruct::New()); obj->f_interface_array.push_back(std::move(ptr_info)); auto data_view_holder = SerializeTestStruct(std::move(obj)); auto& data_view = *data_view_holder->data_view; ArrayDataView<TestInterfacePtrDataView> array_data_view; data_view.GetFInterfaceArrayDataView(&array_data_view); ASSERT_FALSE(array_data_view.is_null()); ASSERT_EQ(1u, array_data_view.size()); TestInterfacePtr ptr2 = array_data_view.Take<TestInterfacePtr>(0); ASSERT_TRUE(ptr2); int32_t result = 0; ASSERT_TRUE(ptr2->Echo(42, &result)); EXPECT_EQ(42, result); } TEST_F(DataViewTest, NestedArray) { TestStructPtr obj(TestStruct::New()); obj->f_nested_array = {{3, 4}, {2}}; auto data_view_holder = SerializeTestStruct(std::move(obj)); auto& data_view = *data_view_holder->data_view; ArrayDataView<ArrayDataView<int32_t>> array_data_view; data_view.GetFNestedArrayDataView(&array_data_view); ASSERT_FALSE(array_data_view.is_null()); ASSERT_EQ(2u, array_data_view.size()); ArrayDataView<int32_t> nested_array_data_view; array_data_view.GetDataView(0, &nested_array_data_view); ASSERT_FALSE(nested_array_data_view.is_null()); ASSERT_EQ(2u, nested_array_data_view.size()); EXPECT_EQ(4, nested_array_data_view[1]); std::vector<int32_t> vec; ASSERT_TRUE(array_data_view.Read(1, &vec)); ASSERT_EQ(1u, vec.size()); EXPECT_EQ(2, vec[0]); } TEST_F(DataViewTest, StructArray) { NestedStructPtr nested_struct(NestedStruct::New()); nested_struct->f_int32 = 42; TestStructPtr obj(TestStruct::New()); obj->f_struct_array.push_back(std::move(nested_struct)); auto data_view_holder = SerializeTestStruct(std::move(obj)); auto& data_view = *data_view_holder->data_view; ArrayDataView<NestedStructDataView> array_data_view; data_view.GetFStructArrayDataView(&array_data_view); ASSERT_FALSE(array_data_view.is_null()); ASSERT_EQ(1u, array_data_view.size()); NestedStructDataView struct_data_view; array_data_view.GetDataView(0, &struct_data_view); ASSERT_FALSE(struct_data_view.is_null()); EXPECT_EQ(42, struct_data_view.f_int32()); NestedStructPtr nested_struct2; ASSERT_TRUE(array_data_view.Read(0, &nested_struct2)); ASSERT_TRUE(nested_struct2); EXPECT_EQ(42, nested_struct2->f_int32); } TEST_F(DataViewTest, Map) { TestStructPtr obj(TestStruct::New()); obj->f_map["1"] = 1; obj->f_map["2"] = 2; auto data_view_holder = SerializeTestStruct(std::move(obj)); auto& data_view = *data_view_holder->data_view; MapDataView<StringDataView, int32_t> map_data_view; data_view.GetFMapDataView(&map_data_view); ASSERT_FALSE(map_data_view.is_null()); ASSERT_EQ(2u, map_data_view.size()); ASSERT_FALSE(map_data_view.keys().is_null()); ASSERT_EQ(2u, map_data_view.keys().size()); ASSERT_FALSE(map_data_view.values().is_null()); ASSERT_EQ(2u, map_data_view.values().size()); std::vector<std::string> keys; ASSERT_TRUE(map_data_view.ReadKeys(&keys)); std::vector<int32_t> values; ASSERT_TRUE(map_data_view.ReadValues(&values)); std::unordered_map<std::string, int32_t> map; for (size_t i = 0; i < 2; ++i) map[keys[i]] = values[i]; EXPECT_EQ(1, map["1"]); EXPECT_EQ(2, map["2"]); } TEST_F(DataViewTest, UnionArray) { TestUnionPtr union_ptr(TestUnion::New()); union_ptr->set_f_int32(1024); TestStructPtr obj(TestStruct::New()); obj->f_union_array.push_back(std::move(union_ptr)); auto data_view_holder = SerializeTestStruct(std::move(obj)); auto& data_view = *data_view_holder->data_view; ArrayDataView<TestUnionDataView> array_data_view; data_view.GetFUnionArrayDataView(&array_data_view); ASSERT_FALSE(array_data_view.is_null()); ASSERT_EQ(1u, array_data_view.size()); TestUnionDataView union_data_view; array_data_view.GetDataView(0, &union_data_view); ASSERT_FALSE(union_data_view.is_null()); TestUnionPtr union_ptr2; ASSERT_TRUE(array_data_view.Read(0, &union_ptr2)); ASSERT_TRUE(union_ptr2->is_f_int32()); EXPECT_EQ(1024, union_ptr2->get_f_int32()); } } // namespace data_view } // namespace test } // namespace mojo