blob: 43fa481e0ba0693e0f7eb1ade2ea8dd9363f0ab2 [file] [log] [blame]
// Copyright 2018 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Check that we can decode things that we can encode.
#include <fidl/test/misc/cpp/fidl.h>
#include <lib/fidl/internal.h>
#include <iostream>
#include "gtest/gtest.h"
#include "lib/fidl/cpp/clone.h"
namespace fidl {
namespace test {
namespace misc {
namespace {
template <class Output, class Input>
Output RoundTrip(const Input& input) {
const ::fidl::FidlStructField fake_input_interface_fields[] = {
::fidl::FidlStructField(Input::FidlType, 16),
};
const fidl_type_t fake_input_interface_struct{
::fidl::FidlCodedStruct(fake_input_interface_fields, 1,
16 + CodingTraits<Input>::encoded_size, "Input")};
const ::fidl::FidlStructField fake_output_interface_fields[] = {
::fidl::FidlStructField(Output::FidlType, 16),
};
const fidl_type_t fake_output_interface_struct{::fidl::FidlCodedStruct(
fake_output_interface_fields, 1, 16 + CodingTraits<Output>::encoded_size,
"Output")};
fidl::Encoder enc(0xfefefefe);
auto ofs = enc.Alloc(CodingTraits<Input>::encoded_size);
fidl::Clone(input).Encode(&enc, ofs);
auto msg = enc.GetMessage();
const char* err_msg = nullptr;
EXPECT_EQ(ZX_OK, msg.Validate(&fake_input_interface_struct, &err_msg))
<< err_msg;
EXPECT_EQ(ZX_OK, msg.Decode(&fake_output_interface_struct, &err_msg))
<< err_msg;
fidl::Decoder dec(std::move(msg));
Output output;
Output::Decode(&dec, &output, ofs);
return output;
}
TEST(SimpleStruct, SerializeAndDeserialize) {
Int64Struct input{1};
EXPECT_EQ(input, RoundTrip<Int64Struct>(input));
}
bool cmp_payload(const uint8_t* actual, size_t actual_size,
const uint8_t* expected, size_t expected_size) {
bool pass = true;
for (size_t i = 0; i < actual_size && i < expected_size; i++) {
if (actual[i] != expected[i]) {
pass = false;
std::cout << std::dec << "element[" << i << "]: " << std::hex
<< "actual=0x" << +actual[i] << " "
<< "expected=0x" << +expected[i] << "\n";
}
}
if (actual_size != expected_size) {
pass = false;
std::cout << std::dec << "element[...]: "
<< "actual.size=" << +actual_size << " "
<< "expected.size=" << +expected_size << "\n";
}
return pass;
}
template <class Input>
bool ValueToBytes(const Input& input, const std::vector<uint8_t>& expected) {
fidl::Encoder enc(0xfefefefe);
auto offset = enc.Alloc(CodingTraits<Input>::encoded_size);
fidl::Clone(input).Encode(&enc, offset);
auto msg = enc.GetMessage();
auto payload = msg.payload();
return cmp_payload(
reinterpret_cast<const uint8_t*>(payload.data()), payload.actual(),
reinterpret_cast<const uint8_t*>(expected.data()), expected.size());
}
TEST(SimpleTable, CheckEmptyTable) {
SimpleTable input;
auto expected = std::vector<uint8_t>{
0, 0, 0, 0, 0, 0, 0, 0, // max ordinal
255, 255, 255, 255, 255, 255, 255, 255, // alloc present
};
EXPECT_TRUE(ValueToBytes(input, expected));
}
std::vector<uint8_t> kSimpleTable_X_42_Y_67 = std::vector<uint8_t>{
5, 0, 0, 0,
0, 0, 0, 0, // max ordinal
255, 255, 255, 255,
255, 255, 255, 255, // alloc present
8, 0, 0, 0,
0, 0, 0, 0, // envelope 1: num bytes / num handles
255, 255, 255, 255,
255, 255, 255, 255, // alloc present
0, 0, 0, 0,
0, 0, 0, 0, // envelope 2: num bytes / num handles
0, 0, 0, 0,
0, 0, 0, 0, // no alloc
0, 0, 0, 0,
0, 0, 0, 0, // envelope 3: num bytes / num handles
0, 0, 0, 0,
0, 0, 0, 0, // no alloc
0, 0, 0, 0,
0, 0, 0, 0, // envelope 4: num bytes / num handles
0, 0, 0, 0,
0, 0, 0, 0, // no alloc
8, 0, 0, 0,
0, 0, 0, 0, // envelope 5: num bytes / num handles
255, 255, 255, 255,
255, 255, 255, 255, // alloc present
42, 0, 0, 0,
0, 0, 0, 0, // field X
67, 0, 0, 0,
0, 0, 0, 0, // field Y
};
TEST(SimpleTable, CheckBytesWithXY) {
SimpleTable input;
input.set_x(42);
input.set_y(67);
EXPECT_TRUE(ValueToBytes(input, kSimpleTable_X_42_Y_67));
}
TEST(SimpleTable, SerializeAndDeserialize) {
SimpleTable input;
input.set_x(1);
EXPECT_EQ(input, RoundTrip<SimpleTable>(input));
// OlderSimpleTable is an abbreviated ('old') version of SimpleTable:
// We should be able to decode to it.
EXPECT_EQ(1, *RoundTrip<OlderSimpleTable>(input).x());
// NewerSimpleTable is an extended ('new') version of SimpleTable:
// We should be able to decode to it.
EXPECT_EQ(1, *RoundTrip<NewerSimpleTable>(input).x());
}
TEST(SimpleTable, SerializeAndDeserializeWithReserved) {
SimpleTable input;
input.set_y(1);
EXPECT_EQ(input, RoundTrip<SimpleTable>(input));
// OlderSimpleTable is an abbreviated ('old') version of SimpleTable:
// We should be able to decode to it (but since it doesn't have y,
// we can't ask for that!)
EXPECT_FALSE(RoundTrip<OlderSimpleTable>(input).has_x());
// NewerSimpleTable is an extended ('new') version of SimpleTable:
// We should be able to decode to it.
EXPECT_EQ(1, *RoundTrip<NewerSimpleTable>(input).y());
}
TEST(Empty, SerializeAndDeserialize) {
Empty input{};
EXPECT_EQ(input, RoundTrip<Empty>(input));
}
TEST(Empty, CheckBytes) {
Empty input;
auto expected = std::vector<uint8_t>{
0, // empty struct zero field
0, 0, 0, 0, 0, 0, 0, // 7 bytes of padding
};
EXPECT_TRUE(ValueToBytes(input, expected));
}
TEST(EmptyStructSandwich, SerializeAndDeserialize) {
EmptyStructSandwich input{
.before = "before",
.after = "after",
};
EXPECT_EQ(input, RoundTrip<EmptyStructSandwich>(input));
}
TEST(EmptyStructSandwich, CheckBytes) {
EmptyStructSandwich input{.before = "before", .after = "after"};
auto expected = std::vector<uint8_t>{
6, 0, 0, 0, 0, 0, 0, 0, // length of "before"
255, 255, 255, 255, 255, 255, 255, 255, // "before" is present
0, // empty struct zero field
0, 0, 0, 0, 0, 0, 0, // 7 bytes of padding
5, 0, 0, 0, 0, 0, 0, 0, // length of "world"
255, 255, 255, 255, 255, 255, 255, 255, // "after" is present
'b', 'e', 'f', 'o', 'r', 'e', // "before" string
0, 0, // 2 bytes of padding
'a', 'f', 't', 'e', 'r', // "after" string
0, 0, 0, // 3 bytes of padding
};
EXPECT_TRUE(ValueToBytes(input, expected));
}
TEST(XUnion, Empty) {
SampleXUnion input;
auto expected = std::vector<uint8_t>{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // xunion discriminator + padding
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // num bytes + num handles
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // envelope data is absent
};
EXPECT_TRUE(ValueToBytes(input, expected));
}
TEST(XUnion, Int32) {
SampleXUnion input;
input.set_i(0xdeadbeef);
auto expected = std::vector<uint8_t>{
0xa5, 0x47, 0xdf, 0x29, 0x00, 0x00, 0x00, 0x00, // xunion discriminator + padding
0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // num bytes + num handles
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // envelope data is present
0xef, 0xbe, 0xad, 0xde, 0x00, 0x00, 0x00, 0x00, // envelope content (0xdeadbeef) + padding
};
EXPECT_TRUE(ValueToBytes(input, expected));
}
TEST(XUnion, SimpleUnion) {
SimpleUnion su;
su.set_str("hello");
SampleXUnion input;
input.set_su(std::move(su));
auto expected = std::vector<uint8_t>{
0x53, 0x76, 0x31, 0x6f, 0x00, 0x00, 0x00, 0x00, // xunion discriminator + padding
0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // num bytes + num handles
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // envelope data is present
// secondary object 0
0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // union discriminant + padding
0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // string size
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // string pointer is present
// secondary object 1
'h', 'e', 'l', 'l', 'o', 0x00, 0x00, 0x00, // string: "hello"
};
EXPECT_TRUE(ValueToBytes(input, expected));
}
TEST(XUnion, SimpleTable) {
SimpleTable st;
st.set_x(42);
st.set_y(67);
SampleXUnion input;
input.set_st(std::move(st));
auto expected = std::vector<uint8_t>{
0xdd, 0x2c, 0x65, 0x30, 0x00, 0x00, 0x00, 0x00, // xunion discriminator + padding
0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // num bytes + num handles
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // envelope data is present
// <table data follows>
};
expected.insert(expected.end(), kSimpleTable_X_42_Y_67.cbegin(),
kSimpleTable_X_42_Y_67.cend());
EXPECT_TRUE(ValueToBytes(input, expected));
}
TEST(XUnion, SerializeAndDeserializeEmpty) {
SampleXUnion input;
EXPECT_EQ(input, RoundTrip<SampleXUnion>(input));
}
TEST(XUnion, SerializeAndDeserializeInt32) {
SampleXUnion input;
input.set_i(0xdeadbeef);
EXPECT_EQ(input, RoundTrip<SampleXUnion>(input));
}
TEST(XUnion, SerializeAndDeserializeSimpleUnion) {
SimpleUnion su;
su.set_str("hello");
SampleXUnion input;
input.set_su(std::move(su));
EXPECT_EQ(input, RoundTrip<SampleXUnion>(input));
}
TEST(XUnion, SerializeAndDeserializeSimpleTable) {
SimpleTable st;
st.set_x(42);
st.set_y(67);
SampleXUnion input;
input.set_st(std::move(st));
EXPECT_EQ(input, RoundTrip<SampleXUnion>(input));
}
TEST(XUnionContainer, XUnionPointer) {
auto xu = std::make_unique<SampleXUnion>();
xu->set_i(0xdeadbeef);
XUnionContainer input;
input.before = "before";
input.after = "after";
input.xu = std::move(xu);
auto expected = std::vector<uint8_t>{
0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // "before" length
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // "before" presence
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // xunion is present
0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // "after" length
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // "before" presence
// secondary object 1: "before"
'b', 'e', 'f', 'o', 'r', 'e', 0x00, 0x00,
// secondary object 2: xunion
0xa5, 0x47, 0xdf, 0x29, 0x00, 0x00, 0x00, 0x00, // xunion discriminator + padding
0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // num bytes + num handles
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // envelope data is present
// secondary object 3: xunion content
0xef, 0xbe, 0xad, 0xde, 0x00, 0x00, 0x00, 0x00, // xunion envelope content (0xdeadbeef) + padding
// secondary object 4: "after"
'a', 'f', 't', 'e', 'r', 0x00, 0x00, 0x00,
};
EXPECT_TRUE(ValueToBytes(input, expected));
}
TEST(XUnionContainer, SerializeAndDeserialize) {
auto xu = std::make_unique<SampleXUnion>();
xu->set_i(0xdeadbeef);
XUnionContainer input;
input.before = "before";
input.after = "after";
input.xu = std::move(xu);
EXPECT_EQ(input, RoundTrip<XUnionContainer>(input));
}
} // namespace
} // namespace misc
} // namespace test
} // namespace fidl