blob: 3fb4a2828ac1b9788001931440c3306056ca684a [file] [log] [blame]
// Copyright 2014 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 <string.h>
#include "mojo/public/cpp/bindings/lib/fixed_buffer.h"
#include "mojo/public/cpp/environment/environment.h"
#include "mojo/public/cpp/system/message_pipe.h"
#include "mojo/public/interfaces/bindings/tests/test_structs.mojom.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace mojo {
namespace test {
namespace {
RectPtr MakeRect(int32_t factor = 1) {
RectPtr rect(Rect::New());
rect->x = 1 * factor;
rect->y = 2 * factor;
rect->width = 10 * factor;
rect->height = 20 * factor;
return rect.Pass();
}
void CheckRect(const Rect& rect, int32_t factor = 1) {
EXPECT_EQ(1 * factor, rect.x);
EXPECT_EQ(2 * factor, rect.y);
EXPECT_EQ(10 * factor, rect.width);
EXPECT_EQ(20 * factor, rect.height);
}
MultiVersionStructPtr MakeMultiVersionStruct() {
MultiVersionStructPtr output(MultiVersionStruct::New());
output->f_int32 = 123;
output->f_rect = MakeRect(5);
output->f_string = "hello";
output->f_array = Array<int8_t>(3);
output->f_array[0] = 10;
output->f_array[1] = 9;
output->f_array[2] = 8;
MessagePipe pipe;
output->f_message_pipe = pipe.handle0.Pass();
output->f_int16 = 42;
return output.Pass();
}
template <typename U, typename T>
U SerializeAndDeserialize(T input) {
typedef typename mojo::internal::WrapperTraits<T>::DataType InputDataType;
typedef typename mojo::internal::WrapperTraits<U>::DataType OutputDataType;
size_t size = GetSerializedSize_(input);
mojo::internal::FixedBuffer buf(size + 32);
InputDataType data;
Serialize_(input.Pass(), &buf, &data);
std::vector<Handle> handles;
data->EncodePointersAndHandles(&handles);
// Set the subsequent area to a special value, so that we can find out if we
// mistakenly access the area.
void* subsequent_area = buf.Allocate(32);
memset(subsequent_area, 0xAA, 32);
OutputDataType output_data = reinterpret_cast<OutputDataType>(data);
output_data->DecodePointersAndHandles(&handles);
U output;
Deserialize_(output_data, &output);
return output.Pass();
}
class StructTest : public testing::Test {
public:
~StructTest() override {}
private:
Environment env_;
};
} // namespace
TEST_F(StructTest, Rect) {
RectPtr rect;
EXPECT_TRUE(rect.is_null());
EXPECT_TRUE(!rect);
EXPECT_FALSE(rect);
rect = nullptr;
EXPECT_TRUE(rect.is_null());
EXPECT_TRUE(!rect);
EXPECT_FALSE(rect);
rect = MakeRect();
EXPECT_FALSE(rect.is_null());
EXPECT_FALSE(!rect);
EXPECT_TRUE(rect);
RectPtr null_rect = nullptr;
EXPECT_TRUE(null_rect.is_null());
EXPECT_TRUE(!null_rect);
EXPECT_FALSE(null_rect);
CheckRect(*rect);
}
TEST_F(StructTest, Clone) {
NamedRegionPtr region;
NamedRegionPtr clone_region = region.Clone();
EXPECT_TRUE(clone_region.is_null());
region = NamedRegion::New();
clone_region = region.Clone();
EXPECT_TRUE(clone_region->name.is_null());
EXPECT_TRUE(clone_region->rects.is_null());
region->name = "hello world";
clone_region = region.Clone();
EXPECT_EQ(region->name, clone_region->name);
region->rects = Array<RectPtr>(2);
region->rects[1] = MakeRect();
clone_region = region.Clone();
EXPECT_EQ(2u, clone_region->rects.size());
EXPECT_TRUE(clone_region->rects[0].is_null());
CheckRect(*clone_region->rects[1]);
// NoDefaultFieldValues contains handles, so Clone() is not available, but
// NoDefaultFieldValuesPtr should still compile.
NoDefaultFieldValuesPtr no_default_field_values(NoDefaultFieldValues::New());
EXPECT_FALSE(no_default_field_values->f13.is_valid());
}
// Serialization test of a struct with no pointer or handle members.
TEST_F(StructTest, Serialization_Basic) {
RectPtr rect(MakeRect());
size_t size = GetSerializedSize_(rect);
EXPECT_EQ(8U + 16U, size);
mojo::internal::FixedBuffer buf(size);
internal::Rect_Data* data;
Serialize_(rect.Pass(), &buf, &data);
RectPtr rect2;
Deserialize_(data, &rect2);
CheckRect(*rect2);
}
// Construction of a struct with struct pointers from null.
TEST_F(StructTest, Construction_StructPointers) {
RectPairPtr pair;
EXPECT_TRUE(pair.is_null());
pair = RectPair::New();
EXPECT_FALSE(pair.is_null());
EXPECT_TRUE(pair->first.is_null());
EXPECT_TRUE(pair->first.is_null());
pair = nullptr;
EXPECT_TRUE(pair.is_null());
}
// Serialization test of a struct with struct pointers.
TEST_F(StructTest, Serialization_StructPointers) {
RectPairPtr pair(RectPair::New());
pair->first = MakeRect();
pair->second = MakeRect();
size_t size = GetSerializedSize_(pair);
EXPECT_EQ(8U + 16U + 2 * (8U + 16U), size);
mojo::internal::FixedBuffer buf(size);
internal::RectPair_Data* data;
Serialize_(pair.Pass(), &buf, &data);
RectPairPtr pair2;
Deserialize_(data, &pair2);
CheckRect(*pair2->first);
CheckRect(*pair2->second);
}
// Serialization test of a struct with an array member.
TEST_F(StructTest, Serialization_ArrayPointers) {
NamedRegionPtr region(NamedRegion::New());
region->name = "region";
region->rects = Array<RectPtr>::New(4);
for (size_t i = 0; i < region->rects.size(); ++i)
region->rects[i] = MakeRect(static_cast<int32_t>(i) + 1);
size_t size = GetSerializedSize_(region);
EXPECT_EQ(8U + // header
8U + // name pointer
8U + // rects pointer
8U + // name header
8U + // name payload (rounded up)
8U + // rects header
4 * 8U + // rects payload (four pointers)
4 * (8U + // rect header
16U), // rect payload (four ints)
size);
mojo::internal::FixedBuffer buf(size);
internal::NamedRegion_Data* data;
Serialize_(region.Pass(), &buf, &data);
NamedRegionPtr region2;
Deserialize_(data, &region2);
EXPECT_EQ(String("region"), region2->name);
EXPECT_EQ(4U, region2->rects.size());
for (size_t i = 0; i < region2->rects.size(); ++i)
CheckRect(*region2->rects[i], static_cast<int32_t>(i) + 1);
}
// Serialization test of a struct with null array pointers.
TEST_F(StructTest, Serialization_NullArrayPointers) {
NamedRegionPtr region(NamedRegion::New());
EXPECT_TRUE(region->name.is_null());
EXPECT_TRUE(region->rects.is_null());
size_t size = GetSerializedSize_(region);
EXPECT_EQ(8U + // header
8U + // name pointer
8U, // rects pointer
size);
mojo::internal::FixedBuffer buf(size);
internal::NamedRegion_Data* data;
Serialize_(region.Pass(), &buf, &data);
NamedRegionPtr region2;
Deserialize_(data, &region2);
EXPECT_TRUE(region2->name.is_null());
EXPECT_TRUE(region2->rects.is_null());
}
// Tests deserializing structs as a newer version.
TEST_F(StructTest, Versioning_OldToNew) {
{
MultiVersionStructV0Ptr input(MultiVersionStructV0::New());
input->f_int32 = 123;
MultiVersionStructPtr expected_output(MultiVersionStruct::New());
expected_output->f_int32 = 123;
MultiVersionStructPtr output =
SerializeAndDeserialize<MultiVersionStructPtr>(input.Pass());
EXPECT_TRUE(output);
EXPECT_TRUE(output->Equals(*expected_output));
}
{
MultiVersionStructV1Ptr input(MultiVersionStructV1::New());
input->f_int32 = 123;
input->f_rect = MakeRect(5);
MultiVersionStructPtr expected_output(MultiVersionStruct::New());
expected_output->f_int32 = 123;
expected_output->f_rect = MakeRect(5);
MultiVersionStructPtr output =
SerializeAndDeserialize<MultiVersionStructPtr>(input.Pass());
EXPECT_TRUE(output);
EXPECT_TRUE(output->Equals(*expected_output));
}
{
MultiVersionStructV3Ptr input(MultiVersionStructV3::New());
input->f_int32 = 123;
input->f_rect = MakeRect(5);
input->f_string = "hello";
MultiVersionStructPtr expected_output(MultiVersionStruct::New());
expected_output->f_int32 = 123;
expected_output->f_rect = MakeRect(5);
expected_output->f_string = "hello";
MultiVersionStructPtr output =
SerializeAndDeserialize<MultiVersionStructPtr>(input.Pass());
EXPECT_TRUE(output);
EXPECT_TRUE(output->Equals(*expected_output));
}
{
MultiVersionStructV5Ptr input(MultiVersionStructV5::New());
input->f_int32 = 123;
input->f_rect = MakeRect(5);
input->f_string = "hello";
input->f_array = Array<int8_t>(3);
input->f_array[0] = 10;
input->f_array[1] = 9;
input->f_array[2] = 8;
MultiVersionStructPtr expected_output(MultiVersionStruct::New());
expected_output->f_int32 = 123;
expected_output->f_rect = MakeRect(5);
expected_output->f_string = "hello";
expected_output->f_array = Array<int8_t>(3);
expected_output->f_array[0] = 10;
expected_output->f_array[1] = 9;
expected_output->f_array[2] = 8;
MultiVersionStructPtr output =
SerializeAndDeserialize<MultiVersionStructPtr>(input.Pass());
EXPECT_TRUE(output);
EXPECT_TRUE(output->Equals(*expected_output));
}
{
MultiVersionStructV7Ptr input(MultiVersionStructV7::New());
input->f_int32 = 123;
input->f_rect = MakeRect(5);
input->f_string = "hello";
input->f_array = Array<int8_t>(3);
input->f_array[0] = 10;
input->f_array[1] = 9;
input->f_array[2] = 8;
MessagePipe pipe;
input->f_message_pipe = pipe.handle0.Pass();
MultiVersionStructPtr expected_output(MultiVersionStruct::New());
expected_output->f_int32 = 123;
expected_output->f_rect = MakeRect(5);
expected_output->f_string = "hello";
expected_output->f_array = Array<int8_t>(3);
expected_output->f_array[0] = 10;
expected_output->f_array[1] = 9;
expected_output->f_array[2] = 8;
// Save the raw handle value separately so that we can compare later.
MojoHandle expected_handle = input->f_message_pipe.get().value();
MultiVersionStructPtr output =
SerializeAndDeserialize<MultiVersionStructPtr>(input.Pass());
EXPECT_TRUE(output);
EXPECT_EQ(expected_handle, output->f_message_pipe.get().value());
output->f_message_pipe.reset();
EXPECT_TRUE(output->Equals(*expected_output));
}
}
// Tests deserializing structs as an older version.
TEST_F(StructTest, Versioning_NewToOld) {
{
MultiVersionStructPtr input = MakeMultiVersionStruct();
MultiVersionStructV7Ptr expected_output(MultiVersionStructV7::New());
expected_output->f_int32 = 123;
expected_output->f_rect = MakeRect(5);
expected_output->f_string = "hello";
expected_output->f_array = Array<int8_t>(3);
expected_output->f_array[0] = 10;
expected_output->f_array[1] = 9;
expected_output->f_array[2] = 8;
// Save the raw handle value separately so that we can compare later.
MojoHandle expected_handle = input->f_message_pipe.get().value();
MultiVersionStructV7Ptr output =
SerializeAndDeserialize<MultiVersionStructV7Ptr>(input.Pass());
EXPECT_TRUE(output);
EXPECT_EQ(expected_handle, output->f_message_pipe.get().value());
output->f_message_pipe.reset();
EXPECT_TRUE(output->Equals(*expected_output));
}
{
MultiVersionStructPtr input = MakeMultiVersionStruct();
MultiVersionStructV5Ptr expected_output(MultiVersionStructV5::New());
expected_output->f_int32 = 123;
expected_output->f_rect = MakeRect(5);
expected_output->f_string = "hello";
expected_output->f_array = Array<int8_t>(3);
expected_output->f_array[0] = 10;
expected_output->f_array[1] = 9;
expected_output->f_array[2] = 8;
MultiVersionStructV5Ptr output =
SerializeAndDeserialize<MultiVersionStructV5Ptr>(input.Pass());
EXPECT_TRUE(output);
EXPECT_TRUE(output->Equals(*expected_output));
}
{
MultiVersionStructPtr input = MakeMultiVersionStruct();
MultiVersionStructV3Ptr expected_output(MultiVersionStructV3::New());
expected_output->f_int32 = 123;
expected_output->f_rect = MakeRect(5);
expected_output->f_string = "hello";
MultiVersionStructV3Ptr output =
SerializeAndDeserialize<MultiVersionStructV3Ptr>(input.Pass());
EXPECT_TRUE(output);
EXPECT_TRUE(output->Equals(*expected_output));
}
{
MultiVersionStructPtr input = MakeMultiVersionStruct();
MultiVersionStructV1Ptr expected_output(MultiVersionStructV1::New());
expected_output->f_int32 = 123;
expected_output->f_rect = MakeRect(5);
MultiVersionStructV1Ptr output =
SerializeAndDeserialize<MultiVersionStructV1Ptr>(input.Pass());
EXPECT_TRUE(output);
EXPECT_TRUE(output->Equals(*expected_output));
}
{
MultiVersionStructPtr input = MakeMultiVersionStruct();
MultiVersionStructV0Ptr expected_output(MultiVersionStructV0::New());
expected_output->f_int32 = 123;
MultiVersionStructV0Ptr output =
SerializeAndDeserialize<MultiVersionStructV0Ptr>(input.Pass());
EXPECT_TRUE(output);
EXPECT_TRUE(output->Equals(*expected_output));
}
}
} // namespace test
} // namespace mojo