blob: 33bdb97506ee350572557382a4a20553a523eb54 [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.
#include <fidl/tables_generator.h>
#include <zircon/assert.h>
#include <zxtest/zxtest.h>
#include "error_test.h"
#include "fidl/coded_ast.h"
#include "fidl/coded_types_generator.h"
#include "test_library.h"
namespace {
const fidl::coded::StructField& field(const fidl::coded::StructElement& element) {
ZX_ASSERT(std::holds_alternative<const fidl::coded::StructField>(element));
return std::get<const fidl::coded::StructField>(element);
}
const fidl::coded::StructPadding& padding(const fidl::coded::StructElement& element) {
ZX_ASSERT(std::holds_alternative<const fidl::coded::StructPadding>(element));
return std::get<const fidl::coded::StructPadding>(element);
}
TEST(CodedTypesGeneratorTests, GoodCodedTypesOfArrays) {
TestLibrary library(R"FIDL(library example;
type Arrays = struct {
prime array<uint8, 7>;
next_prime array<array<uint8, 7>, 11>;
next_next_prime array<array<array<uint8, 7>, 11>, 13>;
};
)FIDL");
ASSERT_COMPILED(library);
fidl::CodedTypesGenerator gen(library.compilation());
gen.CompileCodedTypes();
ASSERT_EQ(4, gen.coded_types().size());
auto type0 = gen.coded_types().at(0).get();
EXPECT_STREQ("uint8", type0->coded_name.c_str());
EXPECT_TRUE(type0->is_coding_needed);
ASSERT_EQ(fidl::coded::Type::Kind::kPrimitive, type0->kind);
auto type0_primitive = static_cast<const fidl::coded::PrimitiveType*>(type0);
EXPECT_EQ(fidl::types::PrimitiveSubtype::kUint8, type0_primitive->subtype);
auto type1 = gen.coded_types().at(1).get();
EXPECT_STREQ("Array7_5uint8", type1->coded_name.c_str());
EXPECT_TRUE(type1->is_coding_needed);
ASSERT_EQ(fidl::coded::Type::Kind::kArray, type1->kind);
auto type1_array = static_cast<const fidl::coded::ArrayType*>(type1);
EXPECT_EQ(1, type1_array->element_size_v2);
EXPECT_EQ(type0, type1_array->element_type);
auto type2 = gen.coded_types().at(2).get();
EXPECT_STREQ("Array77_13Array7_5uint8", type2->coded_name.c_str());
EXPECT_TRUE(type2->is_coding_needed);
ASSERT_EQ(fidl::coded::Type::Kind::kArray, type2->kind);
auto type2_array = static_cast<const fidl::coded::ArrayType*>(type2);
EXPECT_EQ(7 * 1, type2_array->element_size_v2);
EXPECT_EQ(type1, type2_array->element_type);
auto type3 = gen.coded_types().at(3).get();
EXPECT_STREQ("Array1001_23Array77_13Array7_5uint8", type3->coded_name.c_str());
EXPECT_TRUE(type3->is_coding_needed);
ASSERT_EQ(fidl::coded::Type::Kind::kArray, type3->kind);
auto type3_array = static_cast<const fidl::coded::ArrayType*>(type3);
EXPECT_EQ(11 * 7 * 1, type3_array->element_size_v2);
EXPECT_EQ(type2, type3_array->element_type);
}
TEST(CodedTypesGeneratorTests, GoodCodedTypesOfVectors) {
TestLibrary library(R"FIDL(library example;
type SomeStruct = struct {};
type Vectors = struct {
bytes1 vector<SomeStruct>:10;
bytes12 vector<vector<SomeStruct>:10>:20;
};
)FIDL");
ASSERT_COMPILED(library);
fidl::CodedTypesGenerator gen(library.compilation());
gen.CompileCodedTypes();
auto name_some_struct = fidl::flat::Name::Key(library.LookupLibrary("example"), "SomeStruct");
auto type_some_struct = gen.CodedTypeFor(name_some_struct);
ASSERT_NOT_NULL(type_some_struct);
EXPECT_STREQ("example_SomeStruct", type_some_struct->coded_name.c_str());
EXPECT_TRUE(type_some_struct->is_coding_needed);
ASSERT_EQ(fidl::coded::Type::Kind::kStruct, type_some_struct->kind);
auto type_some_struct_struct = static_cast<const fidl::coded::StructType*>(type_some_struct);
ASSERT_TRUE(type_some_struct_struct->is_empty);
ASSERT_EQ(0, type_some_struct_struct->elements.size());
EXPECT_STREQ("example/SomeStruct", type_some_struct_struct->qname.c_str());
EXPECT_FALSE(type_some_struct_struct->contains_envelope);
EXPECT_NULL(type_some_struct_struct->maybe_reference_type);
EXPECT_EQ(1, type_some_struct_struct->size_v2);
ASSERT_EQ(2, gen.coded_types().size());
auto type0 = gen.coded_types().at(0).get();
EXPECT_STREQ("Vector10nonnullable18example_SomeStruct", type0->coded_name.c_str());
EXPECT_TRUE(type0->is_coding_needed);
ASSERT_EQ(fidl::coded::Type::Kind::kVector, type0->kind);
auto type0_vector = static_cast<const fidl::coded::VectorType*>(type0);
EXPECT_EQ(type_some_struct, type0_vector->element_type);
EXPECT_EQ(10, type0_vector->max_count);
EXPECT_EQ(1, type0_vector->element_size_v2);
EXPECT_EQ(fidl::types::Nullability::kNonnullable, type0_vector->nullability);
EXPECT_EQ(fidl::coded::MemcpyCompatibility::kCanMemcpy,
type0_vector->element_memcpy_compatibility);
auto type1 = gen.coded_types().at(1).get();
EXPECT_STREQ("Vector20nonnullable39Vector10nonnullable18example_SomeStruct",
type1->coded_name.c_str());
EXPECT_TRUE(type1->is_coding_needed);
ASSERT_EQ(fidl::coded::Type::Kind::kVector, type1->kind);
auto type1_vector = static_cast<const fidl::coded::VectorType*>(type1);
EXPECT_EQ(type0, type1_vector->element_type);
EXPECT_EQ(20, type1_vector->max_count);
EXPECT_EQ(16, type1_vector->element_size_v2);
EXPECT_EQ(fidl::types::Nullability::kNonnullable, type1_vector->nullability);
EXPECT_EQ(fidl::coded::MemcpyCompatibility::kCannotMemcpy,
type1_vector->element_memcpy_compatibility);
}
TEST(CodedTypesGeneratorTests, GoodVectorEncodeMightMutate) {
TestLibrary library(R"FIDL(
library example;
using zx;
type Bits = bits : uint32 {
A = 1;
};
type Enum = enum : uint32 {
A = 1;
};
protocol P {};
type EmptyStruct = struct {};
type NeverMutateStruct = struct {
v1 uint32;
v2 Bits;
v3 Enum;
};
type PaddingStruct = struct {
v1 uint32;
v2 uint64;
};
type Table = resource table {};
type Union = resource union {
1: a uint32;
};
type Value = resource struct {
// The number in the name corresponds to the field index in the assertions below.
never0 vector<EmptyStruct>;
never1 vector<NeverMutateStruct>;
maybe2 vector<box<NeverMutateStruct>>;
maybe3 vector<PaddingStruct>;
maybe4 vector<vector<uint32>>;
maybe5 vector<string>;
maybe6 vector<zx.handle>;
maybe7 vector<server_end:P>;
maybe8 vector<client_end:P>;
maybe9 vector<Table>;
maybe10 vector<Union>;
};
)FIDL");
library.UseLibraryZx();
ASSERT_COMPILED(library);
auto str = library.LookupStruct("Value");
ASSERT_NOT_NULL(str);
auto elem_might_mutate = [&str](size_t index) {
const fidl::flat::VectorType* vec =
static_cast<const fidl::flat::VectorType*>(str->members.at(index).type_ctor->type);
return fidl::ComputeMemcpyCompatibility(vec->element_type);
};
// Note: these EXPECT_EQ are not in a loop so that they give more useful errors.
EXPECT_EQ(fidl::coded::MemcpyCompatibility::kCanMemcpy, elem_might_mutate(0));
EXPECT_EQ(fidl::coded::MemcpyCompatibility::kCanMemcpy, elem_might_mutate(1));
EXPECT_EQ(fidl::coded::MemcpyCompatibility::kCannotMemcpy, elem_might_mutate(2));
EXPECT_EQ(fidl::coded::MemcpyCompatibility::kCannotMemcpy, elem_might_mutate(3));
EXPECT_EQ(fidl::coded::MemcpyCompatibility::kCannotMemcpy, elem_might_mutate(4));
EXPECT_EQ(fidl::coded::MemcpyCompatibility::kCannotMemcpy, elem_might_mutate(5));
EXPECT_EQ(fidl::coded::MemcpyCompatibility::kCannotMemcpy, elem_might_mutate(6));
EXPECT_EQ(fidl::coded::MemcpyCompatibility::kCannotMemcpy, elem_might_mutate(7));
EXPECT_EQ(fidl::coded::MemcpyCompatibility::kCannotMemcpy, elem_might_mutate(8));
EXPECT_EQ(fidl::coded::MemcpyCompatibility::kCannotMemcpy, elem_might_mutate(9));
EXPECT_EQ(fidl::coded::MemcpyCompatibility::kCannotMemcpy, elem_might_mutate(10));
}
TEST(CodedTypesGeneratorTests, GoodCodedTypesOfProtocols) {
TestLibrary library(R"FIDL(library example;
protocol SomeProtocol {};
type OnReceivePayload = resource struct {
server server_end:SomeProtocol;
};
protocol UseOfProtocol {
Call(resource struct {
client client_end:SomeProtocol;
});
-> OnReceive(OnReceivePayload);
};
)FIDL");
ASSERT_COMPILED(library);
fidl::CodedTypesGenerator gen(library.compilation());
gen.CompileCodedTypes();
ASSERT_EQ(3, gen.coded_types().size());
auto type0 = gen.coded_types().at(0).get();
EXPECT_STREQ("Protocol20example_SomeProtocolnonnullable", type0->coded_name.c_str());
EXPECT_TRUE(type0->is_coding_needed);
EXPECT_EQ(4, type0->size_v2);
ASSERT_EQ(fidl::coded::Type::Kind::kProtocolHandle, type0->kind);
auto type0_ihandle = static_cast<const fidl::coded::ProtocolHandleType*>(type0);
ASSERT_EQ(fidl::types::Nullability::kNonnullable, type0_ihandle->nullability);
auto type1 = gen.coded_types().at(1).get();
EXPECT_STREQ("Request20example_SomeProtocolnonnullable", type1->coded_name.c_str());
EXPECT_TRUE(type1->is_coding_needed);
EXPECT_EQ(4, type1->size_v2);
ASSERT_EQ(fidl::coded::Type::Kind::kRequestHandle, type1->kind);
auto type1_ihandle = static_cast<const fidl::coded::RequestHandleType*>(type1);
ASSERT_EQ(fidl::types::Nullability::kNonnullable, type1_ihandle->nullability);
auto type2 = gen.coded_types().at(2).get();
EXPECT_STREQ("example_UseOfProtocolCallRequestMessage", type2->coded_name.c_str());
EXPECT_TRUE(type2->is_coding_needed);
EXPECT_EQ(4, type2->size_v2);
ASSERT_EQ(fidl::coded::Type::Kind::kStruct, type2->kind);
auto type2_message = static_cast<const fidl::coded::StructType*>(type2);
EXPECT_FALSE(type2_message->contains_envelope);
EXPECT_STREQ("example/UseOfProtocolCallRequestMessage", type2_message->qname.c_str());
EXPECT_EQ(1, type2_message->elements.size());
EXPECT_EQ(0, field(type2_message->elements.at(0)).offset_v2);
EXPECT_EQ(type0, field(type2_message->elements.at(0)).type);
auto named_payload_name =
fidl::flat::Name::Key(library.LookupLibrary("example"), "OnReceivePayload");
auto type_named_payload = gen.CodedTypeFor(named_payload_name);
ASSERT_NOT_NULL(type_named_payload);
EXPECT_STREQ("example_OnReceivePayload", type_named_payload->coded_name.c_str());
EXPECT_TRUE(type_named_payload->is_coding_needed);
EXPECT_EQ(4, type_named_payload->size_v2);
ASSERT_EQ(fidl::coded::Type::Kind::kStruct, type_named_payload->kind);
auto type_named_payload_message = static_cast<const fidl::coded::StructType*>(type_named_payload);
ASSERT_FALSE(type_named_payload_message->is_empty);
EXPECT_FALSE(type_named_payload_message->contains_envelope);
EXPECT_NULL(type_named_payload_message->maybe_reference_type);
EXPECT_STREQ("example/OnReceivePayload", type_named_payload_message->qname.c_str());
ASSERT_EQ(1, type_named_payload_message->elements.size());
EXPECT_EQ(0, field(type_named_payload_message->elements.at(0)).offset_v2);
EXPECT_EQ(type1, field(type_named_payload_message->elements.at(0)).type);
}
TEST(CodedTypesGeneratorTests, GoodCodedTypesOfProtocolErrorSyntax) {
TestLibrary library(R"FIDL(library example;
protocol SomeProtocol {};
protocol UseOfProtocol {
Method() -> (resource struct {
client client_end:SomeProtocol;
}) error uint32;
};
)FIDL");
ASSERT_COMPILED(library);
fidl::CodedTypesGenerator gen(library.compilation());
gen.CompileCodedTypes();
ASSERT_EQ(4, gen.coded_types().size());
auto type0 = gen.coded_types().at(0).get();
EXPECT_STREQ("example_UseOfProtocol_Method_ResultNullableRef", type0->coded_name.c_str());
EXPECT_TRUE(type0->is_coding_needed);
ASSERT_EQ(fidl::coded::Type::Kind::kXUnion, type0->kind);
auto type0_union = static_cast<const fidl::coded::XUnionType*>(type0);
ASSERT_EQ(fidl::types::Nullability::kNullable, type0_union->nullability);
EXPECT_EQ(16, type0->size_v2);
ASSERT_EQ(2, type0_union->fields.size());
auto type0_field0 = type0_union->fields.at(0);
EXPECT_STREQ("example_UseOfProtocol_Method_Response", type0_field0.type->coded_name.c_str());
auto type0_field1 = type0_union->fields.at(1);
EXPECT_STREQ("uint32", type0_field1.type->coded_name.c_str());
auto type2 = gen.coded_types().at(1).get();
EXPECT_STREQ("Protocol20example_SomeProtocolnonnullable", type2->coded_name.c_str());
EXPECT_TRUE(type2->is_coding_needed);
EXPECT_EQ(4, type2->size_v2);
ASSERT_EQ(fidl::coded::Type::Kind::kProtocolHandle, type2->kind);
auto type2_ihandle = static_cast<const fidl::coded::ProtocolHandleType*>(type2);
ASSERT_EQ(fidl::types::Nullability::kNonnullable, type2_ihandle->nullability);
auto type3 = gen.coded_types().at(2).get();
EXPECT_STREQ("uint32", type3->coded_name.c_str());
auto type5 = gen.coded_types().at(3).get();
EXPECT_STREQ("example_UseOfProtocolMethodResponseMessage", type5->coded_name.c_str());
EXPECT_TRUE(type5->is_coding_needed);
EXPECT_EQ(16, type5->size_v2);
ASSERT_EQ(fidl::coded::Type::Kind::kStruct, type5->kind);
auto type5_message = static_cast<const fidl::coded::StructType*>(type5);
EXPECT_TRUE(type5_message->contains_envelope);
EXPECT_STREQ("example/UseOfProtocolMethodResponseMessage", type5_message->qname.c_str());
EXPECT_EQ(1, type5_message->elements.size());
auto anon_payload_name =
fidl::flat::Name::Key(library.LookupLibrary("example"), "UseOfProtocol_Method_Response");
auto type_anon_payload = gen.CodedTypeFor(anon_payload_name);
ASSERT_NOT_NULL(type_anon_payload);
EXPECT_STREQ("example_UseOfProtocol_Method_Response", type_anon_payload->coded_name.c_str());
EXPECT_TRUE(type_anon_payload->is_coding_needed);
EXPECT_EQ(4, type_anon_payload->size_v2);
ASSERT_EQ(fidl::coded::Type::Kind::kStruct, type_anon_payload->kind);
auto type_anon_payload_message = static_cast<const fidl::coded::StructType*>(type_anon_payload);
ASSERT_FALSE(type_anon_payload_message->is_empty);
EXPECT_FALSE(type_anon_payload_message->contains_envelope);
EXPECT_NULL(type_anon_payload_message->maybe_reference_type);
EXPECT_STREQ("example/UseOfProtocol_Method_Response", type_anon_payload_message->qname.c_str());
ASSERT_EQ(1, type_anon_payload_message->elements.size());
EXPECT_EQ(0, field(type_anon_payload_message->elements.at(0)).offset_v2);
EXPECT_EQ(type2, field(type_anon_payload_message->elements.at(0)).type);
}
TEST(CodedTypesGeneratorTests, GoodCodedTypesGeneratedWrappers) {
TestLibrary library(R"FIDL(library example;
protocol ErrorSyntaxProtocol {
ErrorSyntaxMethod() -> (struct{}) error uint32;
};
)FIDL");
ASSERT_COMPILED(library);
fidl::CodedTypesGenerator gen(library.compilation());
gen.CompileCodedTypes();
ASSERT_EQ(3, gen.coded_types().size());
auto type0 = gen.coded_types().at(0).get();
EXPECT_STREQ("example_ErrorSyntaxProtocol_ErrorSyntaxMethod_ResultNullableRef",
type0->coded_name.c_str());
EXPECT_EQ(16, type0->size_v2);
auto type1 = gen.coded_types().at(1).get();
EXPECT_STREQ("uint32", type1->coded_name.c_str());
auto type2 = gen.coded_types().at(2).get();
EXPECT_STREQ("example_ErrorSyntaxProtocolErrorSyntaxMethodResponseMessage",
type2->coded_name.c_str());
EXPECT_EQ(16, type2->size_v2);
auto type2_message = static_cast<const fidl::coded::StructType*>(type2);
EXPECT_TRUE(type2_message->contains_envelope);
}
TEST(CodedTypesGeneratorTests, GoodCodedTypesOfProtocolEnds) {
TestLibrary library(R"FIDL(library example;
protocol SomeProtocol {};
protocol UseOfProtocolEnds {
ClientEnds(resource struct {
in client_end:SomeProtocol;
}) -> (resource struct {
out client_end:<SomeProtocol, optional>;
});
ServerEnds(resource struct {
in server_end:<SomeProtocol, optional>;
}) -> (resource struct {
out server_end:SomeProtocol;
});
};
)FIDL");
ASSERT_COMPILED(library);
fidl::CodedTypesGenerator gen(library.compilation());
gen.CompileCodedTypes();
ASSERT_EQ(8, gen.coded_types().size());
// ClientEnd request payload
auto type0 = gen.coded_types().at(3).get();
EXPECT_STREQ("Protocol20example_SomeProtocolnonnullable", type0->coded_name.c_str());
EXPECT_TRUE(type0->is_coding_needed);
EXPECT_EQ(4, type0->size_v2);
ASSERT_EQ(fidl::coded::Type::Kind::kProtocolHandle, type0->kind);
auto type0_ihandle = static_cast<const fidl::coded::ProtocolHandleType*>(type0);
EXPECT_EQ(fidl::types::Nullability::kNonnullable, type0_ihandle->nullability);
// ClientEnd request message
auto type1 = gen.coded_types().at(4).get();
EXPECT_STREQ("example_UseOfProtocolEndsClientEndsRequestMessage", type1->coded_name.c_str());
EXPECT_TRUE(type1->is_coding_needed);
EXPECT_EQ(4, type1->size_v2);
ASSERT_EQ(fidl::coded::Type::Kind::kStruct, type1->kind);
auto type1_message = static_cast<const fidl::coded::StructType*>(type1);
EXPECT_FALSE(type1_message->contains_envelope);
EXPECT_STREQ("example/UseOfProtocolEndsClientEndsRequestMessage", type1_message->qname.c_str());
EXPECT_EQ(1, type1_message->elements.size());
EXPECT_EQ(0, field(type1_message->elements.at(0)).offset_v2);
EXPECT_EQ(type0, field(type1_message->elements.at(0)).type);
// ClientEnd response payload
auto type2 = gen.coded_types().at(2).get();
EXPECT_STREQ("Protocol20example_SomeProtocolnullable", type2->coded_name.c_str());
EXPECT_TRUE(type2->is_coding_needed);
EXPECT_EQ(4, type2->size_v2);
ASSERT_EQ(fidl::coded::Type::Kind::kProtocolHandle, type2->kind);
auto type2_ihandle = static_cast<const fidl::coded::ProtocolHandleType*>(type2);
EXPECT_EQ(fidl::types::Nullability::kNullable, type2_ihandle->nullability);
// ClientEnd response message
auto type3 = gen.coded_types().at(5).get();
EXPECT_STREQ("example_UseOfProtocolEndsClientEndsResponseMessage", type3->coded_name.c_str());
EXPECT_TRUE(type3->is_coding_needed);
EXPECT_EQ(4, type3->size_v2);
ASSERT_EQ(fidl::coded::Type::Kind::kStruct, type3->kind);
auto type3_message = static_cast<const fidl::coded::StructType*>(type3);
EXPECT_FALSE(type3_message->contains_envelope);
EXPECT_STREQ("example/UseOfProtocolEndsClientEndsResponseMessage", type3_message->qname.c_str());
EXPECT_EQ(1, type3_message->elements.size());
EXPECT_EQ(0, field(type3_message->elements.at(0)).offset_v2);
EXPECT_EQ(type2, field(type3_message->elements.at(0)).type);
// ServerEnd request payload
auto type4 = gen.coded_types().at(1).get();
EXPECT_STREQ("Request20example_SomeProtocolnullable", type4->coded_name.c_str());
EXPECT_TRUE(type4->is_coding_needed);
EXPECT_EQ(4, type4->size_v2);
ASSERT_EQ(fidl::coded::Type::Kind::kRequestHandle, type4->kind);
auto type4_ihandle = static_cast<const fidl::coded::RequestHandleType*>(type4);
EXPECT_EQ(fidl::types::Nullability::kNullable, type4_ihandle->nullability);
// ServerEnd request message
auto type5 = gen.coded_types().at(6).get();
EXPECT_STREQ("example_UseOfProtocolEndsServerEndsRequestMessage", type5->coded_name.c_str());
EXPECT_TRUE(type5->is_coding_needed);
EXPECT_EQ(4, type5->size_v2);
ASSERT_EQ(fidl::coded::Type::Kind::kStruct, type5->kind);
auto type5_message = static_cast<const fidl::coded::StructType*>(type5);
EXPECT_FALSE(type5_message->contains_envelope);
EXPECT_STREQ("example/UseOfProtocolEndsServerEndsRequestMessage", type5_message->qname.c_str());
EXPECT_EQ(1, type5_message->elements.size());
EXPECT_EQ(0, field(type5_message->elements.at(0)).offset_v2);
EXPECT_EQ(type4, field(type5_message->elements.at(0)).type);
// ServerEnd response payload
auto type6 = gen.coded_types().at(0).get();
EXPECT_STREQ("Request20example_SomeProtocolnonnullable", type6->coded_name.c_str());
EXPECT_TRUE(type6->is_coding_needed);
EXPECT_EQ(4, type6->size_v2);
ASSERT_EQ(fidl::coded::Type::Kind::kRequestHandle, type6->kind);
auto type6_ihandle = static_cast<const fidl::coded::RequestHandleType*>(type6);
EXPECT_EQ(fidl::types::Nullability::kNonnullable, type6_ihandle->nullability);
// ServerEnd response message
auto type7 = gen.coded_types().at(7).get();
EXPECT_STREQ("example_UseOfProtocolEndsServerEndsResponseMessage", type7->coded_name.c_str());
EXPECT_TRUE(type7->is_coding_needed);
EXPECT_EQ(4, type7->size_v2);
ASSERT_EQ(fidl::coded::Type::Kind::kStruct, type7->kind);
auto type7_message = static_cast<const fidl::coded::StructType*>(type7);
EXPECT_FALSE(type7_message->contains_envelope);
EXPECT_STREQ("example/UseOfProtocolEndsServerEndsResponseMessage", type7_message->qname.c_str());
EXPECT_EQ(1, type7_message->elements.size());
EXPECT_EQ(0, field(type7_message->elements.at(0)).offset_v2);
EXPECT_EQ(type6, field(type7_message->elements.at(0)).type);
}
// The code between |CodedTypesOfUnions| and |CodedTypesOfNullableUnions| is now very similar
// because the compiler emits both the non-nullable and nullable union types regardless of whether
// it is used in the library in which it was defined.
TEST(CodedTypesGeneratorTests, GoodCodedTypesOfUnions) {
TestLibrary library(R"FIDL(library example;
type MyXUnion = strict union {
1: foo bool;
2: bar int32;
};
type MyXUnionStruct = struct {
u MyXUnion;
};
)FIDL");
ASSERT_COMPILED(library);
fidl::CodedTypesGenerator gen(library.compilation());
gen.CompileCodedTypes();
ASSERT_EQ(3, gen.coded_types().size());
auto type0 = gen.coded_types().at(0).get();
ASSERT_STREQ("example_MyXUnionNullableRef", type0->coded_name.c_str());
ASSERT_TRUE(type0->is_coding_needed);
ASSERT_EQ(fidl::coded::Type::Kind::kXUnion, type0->kind);
auto nullable_xunion = static_cast<const fidl::coded::XUnionType*>(type0);
ASSERT_EQ(fidl::types::Nullability::kNullable, nullable_xunion->nullability);
auto type1 = gen.coded_types().at(1).get();
ASSERT_STREQ("bool", type1->coded_name.c_str());
ASSERT_TRUE(type1->is_coding_needed);
ASSERT_EQ(fidl::coded::Type::Kind::kPrimitive, type1->kind);
auto type2_primitive = static_cast<const fidl::coded::PrimitiveType*>(type1);
ASSERT_EQ(fidl::types::PrimitiveSubtype::kBool, type2_primitive->subtype);
auto type2 = gen.coded_types().at(2).get();
ASSERT_STREQ("int32", type2->coded_name.c_str());
ASSERT_TRUE(type2->is_coding_needed);
ASSERT_EQ(fidl::coded::Type::Kind::kPrimitive, type2->kind);
auto type1_primitive = static_cast<const fidl::coded::PrimitiveType*>(type2);
ASSERT_EQ(fidl::types::PrimitiveSubtype::kInt32, type1_primitive->subtype);
auto name = fidl::flat::Name::Key(library.LookupLibrary("example"), "MyXUnion");
auto type = gen.CodedTypeFor(name);
ASSERT_NOT_NULL(type);
ASSERT_STREQ("example_MyXUnion", type->coded_name.c_str());
ASSERT_TRUE(type->is_coding_needed);
ASSERT_EQ(fidl::coded::Type::Kind::kXUnion, type->kind);
auto coded_xunion = static_cast<const fidl::coded::XUnionType*>(type);
ASSERT_EQ(2, coded_xunion->fields.size());
auto xunion_field0 = coded_xunion->fields.at(0);
ASSERT_EQ(fidl::coded::Type::Kind::kPrimitive, xunion_field0.type->kind);
auto xunion_field0_primitive = static_cast<const fidl::coded::PrimitiveType*>(xunion_field0.type);
ASSERT_EQ(fidl::types::PrimitiveSubtype::kBool, xunion_field0_primitive->subtype);
auto xunion_field1 = coded_xunion->fields.at(1);
ASSERT_EQ(fidl::coded::Type::Kind::kPrimitive, xunion_field1.type->kind);
auto xunion_field1_primitive = static_cast<const fidl::coded::PrimitiveType*>(xunion_field1.type);
ASSERT_EQ(fidl::types::PrimitiveSubtype::kInt32, xunion_field1_primitive->subtype);
ASSERT_STREQ("example/MyXUnion", coded_xunion->qname.c_str());
ASSERT_EQ(fidl::types::Nullability::kNonnullable, coded_xunion->nullability);
ASSERT_NOT_NULL(coded_xunion->maybe_reference_type);
auto struct_name = fidl::flat::Name::Key(library.LookupLibrary("example"), "MyXUnionStruct");
auto struct_type = gen.CodedTypeFor(struct_name);
ASSERT_NOT_NULL(struct_type);
ASSERT_STREQ("example_MyXUnionStruct", struct_type->coded_name.c_str());
ASSERT_TRUE(struct_type->is_coding_needed);
ASSERT_EQ(fidl::coded::Type::Kind::kStruct, struct_type->kind);
auto struct_type_struct = static_cast<const fidl::coded::StructType*>(struct_type);
ASSERT_FALSE(struct_type_struct->is_empty);
EXPECT_TRUE(struct_type_struct->contains_envelope);
}
// The code between |CodedTypesOfUnions| and |CodedTypesOfNullableUnions| is now very similar
// because the compiler emits both the non-nullable and nullable union types regardless of whether
// it is used in the library in which it was defined.
TEST(CodedTypesGeneratorTests, GoodCodedTypesOfNullableUnions) {
TestLibrary library(R"FIDL(library example;
type MyXUnion = strict union {
1: foo bool;
2: bar int32;
};
type Wrapper1 = struct {
xu MyXUnion:optional;
};
// This ensures that MyXUnion? doesn't show up twice in the coded types.
type Wrapper2 = struct {
xu MyXUnion:optional;
};
)FIDL");
ASSERT_COMPILED(library);
fidl::CodedTypesGenerator gen(library.compilation());
gen.CompileCodedTypes();
// 3 == size of {bool, int32, MyXUnion?}, which is all of the types used in
// the example.
ASSERT_EQ(3, gen.coded_types().size());
auto type0 = gen.coded_types().at(0).get();
ASSERT_STREQ("example_MyXUnionNullableRef", type0->coded_name.c_str());
ASSERT_TRUE(type0->is_coding_needed);
ASSERT_EQ(fidl::coded::Type::Kind::kXUnion, type0->kind);
auto nullable_xunion = static_cast<const fidl::coded::XUnionType*>(type0);
ASSERT_EQ(fidl::types::Nullability::kNullable, nullable_xunion->nullability);
auto type1 = gen.coded_types().at(1).get();
ASSERT_STREQ("bool", type1->coded_name.c_str());
ASSERT_TRUE(type1->is_coding_needed);
ASSERT_EQ(fidl::coded::Type::Kind::kPrimitive, type1->kind);
auto type2_primitive = static_cast<const fidl::coded::PrimitiveType*>(type1);
ASSERT_EQ(fidl::types::PrimitiveSubtype::kBool, type2_primitive->subtype);
auto type2 = gen.coded_types().at(2).get();
ASSERT_STREQ("int32", type2->coded_name.c_str());
ASSERT_TRUE(type2->is_coding_needed);
ASSERT_EQ(fidl::coded::Type::Kind::kPrimitive, type2->kind);
auto type1_primitive = static_cast<const fidl::coded::PrimitiveType*>(type2);
ASSERT_EQ(fidl::types::PrimitiveSubtype::kInt32, type1_primitive->subtype);
}
// This mostly exists to make sure that the same nullable objects aren't
// represented more than once in the coding tables.
TEST(CodedTypesGeneratorTests, GoodCodedTypesOfNullablePointers) {
TestLibrary library(R"FIDL(library example;
type MyStruct = struct {
foo bool;
bar int32;
};
type MyUnion = strict union {
1: foo bool;
2: bar int32;
};
type MyXUnion = flexible union {
1: foo bool;
2: bar int32;
};
type Wrapper1 = struct {
ms box<MyStruct>;
mu MyUnion:optional;
xu MyXUnion:optional;
};
// This ensures that MyXUnion? doesn't show up twice in the coded types.
type Wrapper2 = struct {
ms box<MyStruct>;
mu MyUnion:optional;
xu MyXUnion:optional;
};
)FIDL");
ASSERT_COMPILED(library);
fidl::CodedTypesGenerator gen(library.compilation());
gen.CompileCodedTypes();
// 5 == size of {bool, int32, MyStruct?, MyUnion?, MyXUnion?},
// which are all the coded types in the example.
ASSERT_EQ(5, gen.coded_types().size());
}
TEST(CodedTypesGeneratorTests, GoodCodedHandle) {
TestLibrary library(R"FIDL(library example;
type obj_type = strict enum : uint32 {
NONE = 0;
VMO = 3;
};
type rights = strict bits {
SOME_RIGHT = 1;
};
resource_definition handle : uint32 {
properties {
subtype obj_type;
rights rights;
};
};
type MyStruct = resource struct {
h handle:<VMO, rights.SOME_RIGHT>;
};
)FIDL");
ASSERT_COMPILED(library);
fidl::CodedTypesGenerator gen(library.compilation());
gen.CompileCodedTypes();
auto struct_name = fidl::flat::Name::Key(library.LookupLibrary("example"), "MyStruct");
auto struct_type = static_cast<const fidl::coded::StructType*>(gen.CodedTypeFor(struct_name));
auto handle_type =
static_cast<const fidl::coded::HandleType*>(field(struct_type->elements[0]).type);
ASSERT_EQ(fidl::types::HandleSubtype::kVmo, handle_type->subtype);
ASSERT_EQ(1, handle_type->rights);
ASSERT_EQ(fidl::types::Nullability::kNonnullable, handle_type->nullability);
}
TEST(CodedTypesGeneratorTests, GoodCodedTypesOfStructsWithPaddings) {
TestLibrary library(R"FIDL(library example;
type BoolAndInt32 = struct {
foo bool;
// 3 bytes of padding here.
bar int32;
};
type Complex = struct {
i32 int32;
b1 bool;
// 3 bytes of padding here.
i64 int64;
i16 int16;
// 6 bytes of padding here.
};
)FIDL");
ASSERT_COMPILED(library);
fidl::CodedTypesGenerator gen(library.compilation());
gen.CompileCodedTypes();
ASSERT_EQ(4, gen.coded_types().size());
auto type0 = gen.coded_types().at(0).get();
EXPECT_STREQ("int32", type0->coded_name.c_str());
EXPECT_TRUE(type0->is_coding_needed);
auto type1 = gen.coded_types().at(1).get();
EXPECT_STREQ("bool", type1->coded_name.c_str());
EXPECT_TRUE(type1->is_coding_needed);
auto type2 = gen.coded_types().at(2).get();
EXPECT_STREQ("int64", type2->coded_name.c_str());
EXPECT_TRUE(type2->is_coding_needed);
auto type3 = gen.coded_types().at(3).get();
EXPECT_STREQ("int16", type3->coded_name.c_str());
EXPECT_TRUE(type3->is_coding_needed);
auto name_bool_and_int32 =
fidl::flat::Name::Key(library.LookupLibrary("example"), "BoolAndInt32");
auto type_bool_and_int32 = gen.CodedTypeFor(name_bool_and_int32);
ASSERT_NOT_NULL(type_bool_and_int32);
EXPECT_STREQ("example_BoolAndInt32", type_bool_and_int32->coded_name.c_str());
auto type_bool_and_int32_struct =
static_cast<const fidl::coded::StructType*>(type_bool_and_int32);
ASSERT_FALSE(type_bool_and_int32_struct->is_empty);
ASSERT_EQ(type_bool_and_int32_struct->elements.size(), 2);
EXPECT_EQ(field(type_bool_and_int32_struct->elements[0]).type->kind,
fidl::coded::Type::Kind::kPrimitive);
EXPECT_EQ(field(type_bool_and_int32_struct->elements[0]).offset_v2, 0);
EXPECT_EQ(padding(type_bool_and_int32_struct->elements[1]).offset_v2, 0);
EXPECT_EQ(std::get<uint32_t>(padding(type_bool_and_int32_struct->elements[1]).mask), 0xffffff00);
auto name_complex = fidl::flat::Name::Key(library.LookupLibrary("example"), "Complex");
auto type_complex = gen.CodedTypeFor(name_complex);
ASSERT_NOT_NULL(type_complex);
EXPECT_STREQ("example_Complex", type_complex->coded_name.c_str());
auto type_complex_struct = static_cast<const fidl::coded::StructType*>(type_complex);
ASSERT_FALSE(type_complex_struct->is_empty);
ASSERT_EQ(type_complex_struct->elements.size(), 3);
EXPECT_EQ(field(type_complex_struct->elements[0]).type->kind,
fidl::coded::Type::Kind::kPrimitive);
EXPECT_EQ(field(type_complex_struct->elements[0]).offset_v2, 4);
EXPECT_EQ(padding(type_complex_struct->elements[1]).offset_v2, 4);
EXPECT_EQ(std::get<uint32_t>(padding(type_complex_struct->elements[1]).mask), 0xffffff00);
EXPECT_EQ(padding(type_complex_struct->elements[2]).offset_v2, 16);
EXPECT_EQ(std::get<uint64_t>(padding(type_complex_struct->elements[2]).mask),
0xffffffffffff0000ull);
}
TEST(CodedTypesGeneratorTests, GoodCodedTypesOfMultilevelNestedStructs) {
TestLibrary library(R"FIDL(library example;
// alignment 4
type Level0 = struct {
a int8;
//padding 3
b int32;
c int8;
// padding 3;
};
// alignment 8
type Level1 = struct {
l0 Level0;
// 4 bytes padding + 3 inside of Level0.
d uint64;
};
// alignment 8
type Level2 = struct {
l1 Level1;
e uint8;
// 7 bytes of padding.
};
)FIDL");
ASSERT_COMPILED(library);
fidl::CodedTypesGenerator gen(library.compilation());
gen.CompileCodedTypes();
auto name_level0 = fidl::flat::Name::Key(library.LookupLibrary("example"), "Level0");
auto type_level0 = gen.CodedTypeFor(name_level0);
ASSERT_NOT_NULL(type_level0);
auto struct_level0 = static_cast<const fidl::coded::StructType*>(type_level0);
ASSERT_FALSE(struct_level0->is_empty);
ASSERT_EQ(struct_level0->elements.size(), 2);
EXPECT_EQ(padding(struct_level0->elements[0]).offset_v2, 0);
EXPECT_EQ(std::get<uint32_t>(padding(struct_level0->elements[0]).mask), 0xffffff00);
EXPECT_EQ(padding(struct_level0->elements[1]).offset_v2, 8);
EXPECT_EQ(std::get<uint32_t>(padding(struct_level0->elements[1]).mask), 0xffffff00);
auto name_level1 = fidl::flat::Name::Key(library.LookupLibrary("example"), "Level1");
auto type_level1 = gen.CodedTypeFor(name_level1);
ASSERT_NOT_NULL(type_level1);
auto struct_level1 = static_cast<const fidl::coded::StructType*>(type_level1);
ASSERT_FALSE(struct_level1->is_empty);
ASSERT_EQ(struct_level1->elements.size(), 2);
EXPECT_EQ(padding(struct_level1->elements[0]).offset_v2, 0);
EXPECT_EQ(std::get<uint32_t>(padding(struct_level1->elements[0]).mask), 0xffffff00);
EXPECT_EQ(padding(struct_level1->elements[1]).offset_v2, 8);
EXPECT_EQ(std::get<uint64_t>(padding(struct_level1->elements[1]).mask), 0xffffffffffffff00);
auto name_level2 = fidl::flat::Name::Key(library.LookupLibrary("example"), "Level2");
auto type_level2 = gen.CodedTypeFor(name_level2);
ASSERT_NOT_NULL(type_level2);
auto struct_level2 = static_cast<const fidl::coded::StructType*>(type_level2);
ASSERT_FALSE(struct_level2->is_empty);
ASSERT_EQ(struct_level2->elements.size(), 3);
EXPECT_EQ(padding(struct_level2->elements[0]).offset_v2, 0);
EXPECT_EQ(std::get<uint32_t>(padding(struct_level2->elements[0]).mask), 0xffffff00);
EXPECT_EQ(padding(struct_level2->elements[1]).offset_v2, 8);
EXPECT_EQ(std::get<uint64_t>(padding(struct_level2->elements[1]).mask), 0xffffffffffffff00);
EXPECT_EQ(padding(struct_level2->elements[2]).offset_v2, 24);
EXPECT_EQ(std::get<uint64_t>(padding(struct_level2->elements[2]).mask), 0xffffffffffffff00);
}
TEST(CodedTypesGeneratorTests, GoodCodedTypesOfRecursiveOptionalStructs) {
TestLibrary library(R"FIDL(library example;
type OneLevelRecursiveOptionalStruct = struct {
val box<OneLevelRecursiveOptionalStruct>;
};
type TwoLevelRecursiveOptionalStructA = struct {
b TwoLevelRecursiveOptionalStructB;
};
type TwoLevelRecursiveOptionalStructB = struct {
a box<TwoLevelRecursiveOptionalStructA>;
};
)FIDL");
ASSERT_COMPILED(library);
fidl::CodedTypesGenerator gen(library.compilation());
gen.CompileCodedTypes();
auto name_one_level =
fidl::flat::Name::Key(library.LookupLibrary("example"), "OneLevelRecursiveOptionalStruct");
auto type_one_level = gen.CodedTypeFor(name_one_level);
ASSERT_NOT_NULL(type_one_level);
auto struct_one_level = static_cast<const fidl::coded::StructType*>(type_one_level);
ASSERT_FALSE(struct_one_level->is_empty);
ASSERT_EQ(struct_one_level->elements.size(), 1);
EXPECT_EQ(field(struct_one_level->elements[0]).type->kind,
fidl::coded::Type::Kind::kStructPointer);
ASSERT_SUBSTR(field(struct_one_level->elements[0]).type->coded_name.c_str(),
"OneLevelRecursiveOptionalStruct");
EXPECT_EQ(field(struct_one_level->elements[0]).offset_v2, 0);
auto name_two_level_b =
fidl::flat::Name::Key(library.LookupLibrary("example"), "TwoLevelRecursiveOptionalStructB");
auto type_two_level_b = gen.CodedTypeFor(name_two_level_b);
ASSERT_NOT_NULL(type_two_level_b);
auto struct_two_level_b = static_cast<const fidl::coded::StructType*>(type_two_level_b);
ASSERT_FALSE(struct_two_level_b->is_empty);
ASSERT_EQ(struct_two_level_b->elements.size(), 1);
EXPECT_EQ(field(struct_two_level_b->elements[0]).type->kind,
fidl::coded::Type::Kind::kStructPointer);
ASSERT_SUBSTR(field(struct_two_level_b->elements[0]).type->coded_name.c_str(),
"TwoLevelRecursiveOptionalStructA");
EXPECT_EQ(field(struct_two_level_b->elements[0]).offset_v2, 0);
// TwoLevelRecursiveOptionalStructA will be equivalent to TwoLevelRecursiveOptionalStructB
// because of flattening.
auto name_two_level_a =
fidl::flat::Name::Key(library.LookupLibrary("example"), "TwoLevelRecursiveOptionalStructA");
auto type_two_level_a = gen.CodedTypeFor(name_two_level_a);
ASSERT_NOT_NULL(type_two_level_a);
auto struct_two_level_a = static_cast<const fidl::coded::StructType*>(type_two_level_a);
ASSERT_FALSE(struct_two_level_a->is_empty);
ASSERT_EQ(struct_two_level_a->elements.size(), 1);
EXPECT_EQ(field(struct_two_level_a->elements[0]).type->kind,
fidl::coded::Type::Kind::kStructPointer);
ASSERT_SUBSTR(field(struct_two_level_a->elements[0]).type->coded_name.c_str(),
"TwoLevelRecursiveOptionalStructA");
EXPECT_EQ(field(struct_two_level_a->elements[0]).offset_v2, 0);
}
TEST(CodedTypesGeneratorTests, GoodCodedTypesOfReusedStructs) {
TestLibrary library(R"FIDL(library example;
// InnerStruct is reused and appears twice.
type InnerStruct = struct{
a int8;
// 1 byte padding
b int16;
};
type OuterStruct = struct {
a InnerStruct;
b InnerStruct;
};
)FIDL");
ASSERT_COMPILED(library);
fidl::CodedTypesGenerator gen(library.compilation());
gen.CompileCodedTypes();
auto name_inner_struct = fidl::flat::Name::Key(library.LookupLibrary("example"), "InnerStruct");
auto type_inner_struct = gen.CodedTypeFor(name_inner_struct);
ASSERT_NOT_NULL(type_inner_struct);
auto struct_inner_struct = static_cast<const fidl::coded::StructType*>(type_inner_struct);
ASSERT_FALSE(struct_inner_struct->is_empty);
ASSERT_EQ(struct_inner_struct->elements.size(), 1);
EXPECT_EQ(padding(struct_inner_struct->elements[0]).offset_v2, 0);
ASSERT_TRUE(std::get<uint16_t>(padding(struct_inner_struct->elements[0]).mask));
EXPECT_EQ(std::get<uint16_t>(padding(struct_inner_struct->elements[0]).mask), 0xff00);
auto name_outer_struct = fidl::flat::Name::Key(library.LookupLibrary("example"), "OuterStruct");
auto type_outer_struct = gen.CodedTypeFor(name_outer_struct);
ASSERT_NOT_NULL(type_outer_struct);
auto struct_outer_struct = static_cast<const fidl::coded::StructType*>(type_outer_struct);
ASSERT_FALSE(struct_outer_struct->is_empty);
ASSERT_EQ(struct_outer_struct->elements.size(), 2);
EXPECT_EQ(padding(struct_outer_struct->elements[0]).offset_v2, 0);
ASSERT_TRUE(std::get<uint16_t>(padding(struct_outer_struct->elements[0]).mask));
EXPECT_EQ(std::get<uint16_t>(padding(struct_outer_struct->elements[0]).mask), 0xff00);
EXPECT_EQ(padding(struct_outer_struct->elements[1]).offset_v2, 4);
ASSERT_TRUE(std::get<uint16_t>(padding(struct_outer_struct->elements[1]).mask));
EXPECT_EQ(std::get<uint16_t>(padding(struct_outer_struct->elements[1]).mask), 0xff00);
}
TEST(CodedTypesGeneratorTests, GoodCodedTypesOfOptionals) {
TestLibrary library(R"FIDL(
library example;
using zx;
type InnerStruct = struct {
a int8;
// 1 byte padding
b int16;
};
type SimpleUnion = union {
1: a int64;
};
type OuterStruct = resource struct {
a InnerStruct;
opt_handle zx.handle:optional;
opt_union SimpleUnion:optional;
b InnerStruct;
};
)FIDL");
library.UseLibraryZx();
ASSERT_COMPILED(library);
fidl::CodedTypesGenerator gen(library.compilation());
gen.CompileCodedTypes();
auto name_outer_struct = fidl::flat::Name::Key(library.LookupLibrary("example"), "OuterStruct");
auto type_outer_struct = gen.CodedTypeFor(name_outer_struct);
ASSERT_NOT_NULL(type_outer_struct);
auto struct_outer_struct = static_cast<const fidl::coded::StructType*>(type_outer_struct);
ASSERT_FALSE(struct_outer_struct->is_empty);
ASSERT_EQ(struct_outer_struct->elements.size(), 5);
EXPECT_EQ(padding(struct_outer_struct->elements[0]).offset_v2, 0);
EXPECT_EQ(std::get<uint16_t>(padding(struct_outer_struct->elements[0]).mask), 0xff00);
EXPECT_EQ(field(struct_outer_struct->elements[1]).type->kind, fidl::coded::Type::Kind::kHandle);
EXPECT_EQ(field(struct_outer_struct->elements[1]).offset_v2, 4);
EXPECT_EQ(field(struct_outer_struct->elements[2]).type->kind, fidl::coded::Type::Kind::kXUnion);
EXPECT_EQ(field(struct_outer_struct->elements[2]).offset_v2, 8);
EXPECT_EQ(padding(struct_outer_struct->elements[3]).offset_v2, 24);
EXPECT_EQ(std::get<uint16_t>(padding(struct_outer_struct->elements[3]).mask), 0xff00);
EXPECT_EQ(padding(struct_outer_struct->elements[4]).offset_v2, 28);
EXPECT_EQ(std::get<uint32_t>(padding(struct_outer_struct->elements[4]).mask), 0xffffffff);
}
// In the following example, we shadow the builtin `byte` alias to a struct.
// fidlc previous had a scoping bug where the `f1` field's `byte` type referred
// to the builtin rather than the struct. This has since been fixed. Here we
// test that the coding tables take the same interpretation, i.e. that they do
// not do their own lookups with different scoping rules.
TEST(CodedTypesGeneratorTests, GoodCodingTablesMatchScoping) {
TestLibrary library(R"FIDL(library example;
alias membertype = uint32;
type byte = struct {
@allow_deprecated_struct_defaults
member membertype = 1;
};
type container = struct {
f1 byte;
f2 bytes;
};
)FIDL");
ASSERT_COMPILED(library);
fidl::CodedTypesGenerator gen(library.compilation());
gen.CompileCodedTypes();
auto the_struct_name = fidl::flat::Name::Key(library.LookupLibrary("example"), "container");
auto the_coded_type = gen.CodedTypeFor(the_struct_name);
ASSERT_NOT_NULL(the_coded_type);
auto the_struct_coded_type = static_cast<const fidl::coded::StructType*>(the_coded_type);
ASSERT_FALSE(the_struct_coded_type->is_empty);
ASSERT_EQ(the_struct_coded_type->elements.size(), 2);
EXPECT_EQ(0xffffffff, std::get<uint32_t>(padding(the_struct_coded_type->elements[0]).mask));
EXPECT_EQ(fidl::coded::Type::Kind::kVector, field(the_struct_coded_type->elements[1]).type->kind);
}
TEST(CodedTypesGeneratorTests, GoodCodedTypesOfTables) {
TestLibrary library(R"FIDL(library example;
type MyTable = table {
1: foo bool;
2: bar int32;
3: baz array<bool, 42>;
};
)FIDL");
ASSERT_COMPILED(library);
fidl::CodedTypesGenerator gen(library.compilation());
gen.CompileCodedTypes();
ASSERT_EQ(3, gen.coded_types().size());
// This bool is used in the coding table of the MyTable table.
auto type0 = gen.coded_types().at(0).get();
EXPECT_STREQ("bool", type0->coded_name.c_str());
EXPECT_TRUE(type0->is_coding_needed);
ASSERT_EQ(fidl::coded::Type::Kind::kPrimitive, type0->kind);
auto type0_primitive = static_cast<const fidl::coded::PrimitiveType*>(type0);
EXPECT_EQ(fidl::types::PrimitiveSubtype::kBool, type0_primitive->subtype);
auto type1 = gen.coded_types().at(1).get();
EXPECT_STREQ("int32", type1->coded_name.c_str());
EXPECT_TRUE(type1->is_coding_needed);
ASSERT_EQ(fidl::coded::Type::Kind::kPrimitive, type1->kind);
auto type1_primitive = static_cast<const fidl::coded::PrimitiveType*>(type1);
EXPECT_EQ(fidl::types::PrimitiveSubtype::kInt32, type1_primitive->subtype);
auto type3 = gen.coded_types().at(2).get();
EXPECT_STREQ("Array42_4bool", type3->coded_name.c_str());
EXPECT_TRUE(type3->is_coding_needed);
ASSERT_EQ(fidl::coded::Type::Kind::kArray, type3->kind);
auto type3_array = static_cast<const fidl::coded::ArrayType*>(type3);
EXPECT_EQ(42, type3_array->size_v2);
ASSERT_EQ(fidl::coded::Type::Kind::kPrimitive, type3_array->element_type->kind);
auto type3_array_element_type =
static_cast<const fidl::coded::PrimitiveType*>(type3_array->element_type);
EXPECT_EQ(fidl::types::PrimitiveSubtype::kBool, type3_array_element_type->subtype);
auto name_table = fidl::flat::Name::Key(library.LookupLibrary("example"), "MyTable");
auto type_table = gen.CodedTypeFor(name_table);
ASSERT_NOT_NULL(type_table);
EXPECT_STREQ("example_MyTable", type_table->coded_name.c_str());
EXPECT_TRUE(type_table->is_coding_needed);
ASSERT_EQ(fidl::coded::Type::Kind::kTable, type_table->kind);
auto type_table_table = static_cast<const fidl::coded::TableType*>(type_table);
EXPECT_EQ(3, type_table_table->fields.size());
auto table_field0 = type_table_table->fields.at(0);
ASSERT_EQ(fidl::coded::Type::Kind::kPrimitive, table_field0.type->kind);
auto table_field0_primitive = static_cast<const fidl::coded::PrimitiveType*>(table_field0.type);
ASSERT_EQ(fidl::types::PrimitiveSubtype::kBool, table_field0_primitive->subtype);
auto table_field1 = type_table_table->fields.at(1);
ASSERT_EQ(fidl::coded::Type::Kind::kPrimitive, table_field1.type->kind);
auto table_field1_primitive = static_cast<const fidl::coded::PrimitiveType*>(table_field1.type);
ASSERT_EQ(fidl::types::PrimitiveSubtype::kInt32, table_field1_primitive->subtype);
auto table_field2 = type_table_table->fields.at(2);
ASSERT_EQ(fidl::coded::Type::Kind::kArray, table_field2.type->kind);
EXPECT_STREQ("example/MyTable", type_table_table->qname.c_str());
}
TEST(CodedTypesGeneratorTests, GoodCodedTypesOfBits) {
TestLibrary library(R"FIDL(library example;
type StrictBits = strict bits : uint8 {
HELLO = 0x1;
WORLD = 0x10;
};
type FlexibleBits = flexible bits : uint8 {
HELLO = 0x1;
WORLD = 0x10;
};
)FIDL");
ASSERT_COMPILED(library);
fidl::CodedTypesGenerator gen(library.compilation());
gen.CompileCodedTypes();
ASSERT_EQ(0, gen.coded_types().size());
{
auto name_bits = fidl::flat::Name::Key(library.LookupLibrary("example"), "StrictBits");
auto type_bits = gen.CodedTypeFor(name_bits);
ASSERT_NOT_NULL(type_bits);
EXPECT_STREQ("example_StrictBits", type_bits->coded_name.c_str());
EXPECT_TRUE(type_bits->is_coding_needed);
ASSERT_EQ(fidl::coded::Type::Kind::kBits, type_bits->kind);
auto type_bits_bits = static_cast<const fidl::coded::BitsType*>(type_bits);
EXPECT_EQ(fidl::types::PrimitiveSubtype::kUint8, type_bits_bits->subtype);
EXPECT_EQ(fidl::types::Strictness::kStrict, type_bits_bits->strictness);
EXPECT_EQ(0x1u | 0x10u, type_bits_bits->mask);
}
{
auto name_bits = fidl::flat::Name::Key(library.LookupLibrary("example"), "FlexibleBits");
auto type_bits = gen.CodedTypeFor(name_bits);
ASSERT_NOT_NULL(type_bits);
EXPECT_STREQ("example_FlexibleBits", type_bits->coded_name.c_str());
EXPECT_TRUE(type_bits->is_coding_needed);
ASSERT_EQ(fidl::coded::Type::Kind::kBits, type_bits->kind);
auto type_bits_bits = static_cast<const fidl::coded::BitsType*>(type_bits);
EXPECT_EQ(fidl::types::PrimitiveSubtype::kUint8, type_bits_bits->subtype);
EXPECT_EQ(fidl::types::Strictness::kFlexible, type_bits_bits->strictness);
EXPECT_EQ(0x1u | 0x10u, type_bits_bits->mask);
}
}
TEST(CodedTypesGeneratorTests, GoodCodedTypesOfStrictEnum) {
TestLibrary library(R"FIDL(library example;
type StrictEnum = strict enum : uint16 {
HELLO = 0x1;
WORLD = 0x10;
};
type FlexibleEnum = flexible enum : uint16 {
HELLO = 0x1;
WORLD = 0x10;
};
)FIDL");
ASSERT_COMPILED(library);
fidl::CodedTypesGenerator gen(library.compilation());
gen.CompileCodedTypes();
ASSERT_EQ(0, gen.coded_types().size());
{
auto name_enum = fidl::flat::Name::Key(library.LookupLibrary("example"), "StrictEnum");
auto type_enum = gen.CodedTypeFor(name_enum);
ASSERT_NOT_NULL(type_enum);
EXPECT_STREQ("example_StrictEnum", type_enum->coded_name.c_str());
EXPECT_TRUE(type_enum->is_coding_needed);
ASSERT_EQ(fidl::coded::Type::Kind::kEnum, type_enum->kind);
auto type_enum_enum = static_cast<const fidl::coded::EnumType*>(type_enum);
EXPECT_EQ(fidl::types::PrimitiveSubtype::kUint16, type_enum_enum->subtype);
EXPECT_EQ(fidl::types::Strictness::kStrict, type_enum_enum->strictness);
EXPECT_EQ(2, type_enum_enum->members.size());
EXPECT_EQ(0x1, type_enum_enum->members[0]);
EXPECT_EQ(0x10, type_enum_enum->members[1]);
}
{
auto name_enum = fidl::flat::Name::Key(library.LookupLibrary("example"), "FlexibleEnum");
auto type_enum = gen.CodedTypeFor(name_enum);
ASSERT_NOT_NULL(type_enum);
EXPECT_STREQ("example_FlexibleEnum", type_enum->coded_name.c_str());
EXPECT_TRUE(type_enum->is_coding_needed);
ASSERT_EQ(fidl::coded::Type::Kind::kEnum, type_enum->kind);
auto type_enum_enum = static_cast<const fidl::coded::EnumType*>(type_enum);
EXPECT_EQ(fidl::types::PrimitiveSubtype::kUint16, type_enum_enum->subtype);
EXPECT_EQ(fidl::types::Strictness::kFlexible, type_enum_enum->strictness);
}
}
TEST(CodedTypesGeneratorTests, GoodCodedTypesOfUnionsWithReverseOrdinals) {
TestLibrary library(R"FIDL(library example;
type First = struct {};
type Second = struct {};
type MyUnion = strict union {
3: second Second;
2: reserved;
1: first First;
};
)FIDL");
ASSERT_COMPILED(library);
fidl::CodedTypesGenerator gen(library.compilation());
gen.CompileCodedTypes();
auto name = fidl::flat::Name::Key(library.LookupLibrary("example"), "MyUnion");
auto type = gen.CodedTypeFor(name);
ASSERT_NOT_NULL(type);
EXPECT_STREQ("example_MyUnion", type->coded_name.c_str());
EXPECT_TRUE(type->is_coding_needed);
ASSERT_EQ(fidl::coded::Type::Kind::kXUnion, type->kind);
auto coded_union = static_cast<const fidl::coded::XUnionType*>(type);
ASSERT_EQ(3, coded_union->fields.size());
auto union_field0 = coded_union->fields.at(0);
ASSERT_NOT_NULL(union_field0.type);
auto union_field0_struct = static_cast<const fidl::coded::StructType*>(union_field0.type);
ASSERT_TRUE(union_field0_struct->is_empty);
EXPECT_STREQ("example/First", union_field0_struct->qname.c_str());
auto union_field1 = coded_union->fields.at(1);
ASSERT_NULL(union_field1.type);
auto union_field2 = coded_union->fields.at(2);
ASSERT_NOT_NULL(union_field2.type);
auto union_field2_struct = static_cast<const fidl::coded::StructType*>(union_field2.type);
ASSERT_TRUE(union_field2_struct->is_empty);
EXPECT_STREQ("example/Second", union_field2_struct->qname.c_str());
}
void check_duplicate_coded_type_names(const fidl::CodedTypesGenerator& gen) {
const auto types = gen.AllCodedTypes();
for (auto const& type : types) {
auto count = std::count_if(types.begin(), types.end(),
[&](auto& t) { return t->coded_name == type->coded_name; });
ASSERT_EQ(count, 1, "Duplicate coded type name.");
}
}
TEST(CodedTypesGeneratorTests, GoodDuplicateCodedTypesTwoUnions) {
TestLibrary library(R"FIDL(library example;
type U1 = strict union {
1: hs array<string, 2>;
};
type U2 = strict union {
1: hss array<array<string, 2>, 2>;
};
)FIDL");
ASSERT_COMPILED(library);
fidl::CodedTypesGenerator gen(library.compilation());
gen.CompileCodedTypes();
check_duplicate_coded_type_names(gen);
}
TEST(CodedTypesGeneratorTests, GoodDuplicateCodedTypesUnionArrayArray) {
TestLibrary library(R"FIDL(library example;
type Union = strict union {
1: hs array<string, 2>;
2: hss array<array<string, 2>, 2>;
};
)FIDL");
ASSERT_COMPILED(library);
fidl::CodedTypesGenerator gen(library.compilation());
gen.CompileCodedTypes();
check_duplicate_coded_type_names(gen);
}
TEST(CodedTypesGeneratorTests, GoodDuplicateCodedTypesUnionVectorArray) {
TestLibrary library(R"FIDL(library example;
type Union = strict union {
1: hs array<string, 2>;
2: hss vector<array<string, 2>>:2;
};
)FIDL");
ASSERT_COMPILED(library);
fidl::CodedTypesGenerator gen(library.compilation());
gen.CompileCodedTypes();
check_duplicate_coded_type_names(gen);
}
TEST(CodedTypesGeneratorTests, GoodDuplicateCodedTypesTableArrayArray) {
TestLibrary library(R"FIDL(library example;
type Table = table {
1: hs array<string, 2>;
2: hss array<array<string, 2>, 2>;
};
)FIDL");
ASSERT_COMPILED(library);
fidl::CodedTypesGenerator gen(library.compilation());
gen.CompileCodedTypes();
check_duplicate_coded_type_names(gen);
}
TEST(CodedTypesGeneratorTests, GoodUnionResourceness) {
TestLibrary library(R"FIDL(library example;
type ResourceUnion = strict resource union {
1: first bool;
};
type NonResourceUnion = strict union {
1: first bool;
};
)FIDL");
ASSERT_COMPILED(library);
fidl::CodedTypesGenerator gen(library.compilation());
gen.CompileCodedTypes();
{
auto name = fidl::flat::Name::Key(library.LookupLibrary("example"), "ResourceUnion");
auto type = gen.CodedTypeFor(name);
ASSERT_NOT_NULL(type);
ASSERT_EQ(fidl::coded::Type::Kind::kXUnion, type->kind);
auto coded_union = static_cast<const fidl::coded::XUnionType*>(type);
EXPECT_EQ(fidl::types::Resourceness::kResource, coded_union->resourceness);
}
{
auto name = fidl::flat::Name::Key(library.LookupLibrary("example"), "NonResourceUnion");
auto type = gen.CodedTypeFor(name);
ASSERT_NOT_NULL(type);
ASSERT_EQ(fidl::coded::Type::Kind::kXUnion, type->kind);
auto coded_union = static_cast<const fidl::coded::XUnionType*>(type);
EXPECT_EQ(fidl::types::Resourceness::kValue, coded_union->resourceness);
}
}
TEST(CodedTypesGeneratorTests, GoodTableResourceness) {
TestLibrary library(R"FIDL(library example;
type ResourceTable = resource table {
1: first bool;
};
type NonResourceTable = table {
1: first bool;
};
)FIDL");
ASSERT_COMPILED(library);
fidl::CodedTypesGenerator gen(library.compilation());
gen.CompileCodedTypes();
{
auto name = fidl::flat::Name::Key(library.LookupLibrary("example"), "ResourceTable");
auto type = gen.CodedTypeFor(name);
ASSERT_NOT_NULL(type);
ASSERT_EQ(fidl::coded::Type::Kind::kTable, type->kind);
auto coded_table = static_cast<const fidl::coded::TableType*>(type);
EXPECT_EQ(fidl::types::Resourceness::kResource, coded_table->resourceness);
}
{
auto name = fidl::flat::Name::Key(library.LookupLibrary("example"), "NonResourceTable");
auto type = gen.CodedTypeFor(name);
ASSERT_NOT_NULL(type);
ASSERT_EQ(fidl::coded::Type::Kind::kTable, type->kind);
auto coded_table = static_cast<const fidl::coded::TableType*>(type);
EXPECT_EQ(fidl::types::Resourceness::kValue, coded_table->resourceness);
}
}
TEST(CodedTypesGeneratorTests, GoodCodedTypesStructMessage) {
TestLibrary library(R"FIDL(library example;
type OnReceivePayload = struct {
arg bool;
};
protocol UseOfProtocol {
Call(struct {
arg1 bool;
arg2 bool;
});
-> OnReceive(OnReceivePayload);
};
)FIDL");
ASSERT_COMPILED(library);
fidl::CodedTypesGenerator gen(library.compilation());
gen.CompileCodedTypes();
ASSERT_EQ(2, gen.coded_types().size());
auto type0 = gen.coded_types().at(0).get();
EXPECT_STREQ("bool", type0->coded_name.c_str());
auto anon_payload = gen.coded_types().at(1).get();
EXPECT_STREQ("example_UseOfProtocolCallRequestMessage", anon_payload->coded_name.c_str());
EXPECT_TRUE(anon_payload->is_coding_needed);
EXPECT_EQ(2, anon_payload->size_v2);
ASSERT_EQ(fidl::coded::Type::Kind::kStruct, anon_payload->kind);
auto anon_payload_message = static_cast<const fidl::coded::StructType*>(anon_payload);
ASSERT_FALSE(anon_payload_message->is_empty);
EXPECT_FALSE(anon_payload_message->contains_envelope);
EXPECT_NULL(anon_payload_message->maybe_reference_type);
EXPECT_STREQ("example/UseOfProtocolCallRequestMessage", anon_payload_message->qname.c_str());
ASSERT_EQ(2, anon_payload_message->elements.size());
EXPECT_EQ(0, field(anon_payload_message->elements.at(0)).offset_v2);
EXPECT_EQ(1, field(anon_payload_message->elements.at(1)).offset_v2);
auto named_payload_name =
fidl::flat::Name::Key(library.LookupLibrary("example"), "OnReceivePayload");
auto type_named_payload = gen.CodedTypeFor(named_payload_name);
ASSERT_NOT_NULL(type_named_payload);
EXPECT_STREQ("example_OnReceivePayload", type_named_payload->coded_name.c_str());
EXPECT_TRUE(type_named_payload->is_coding_needed);
EXPECT_EQ(1, type_named_payload->size_v2);
ASSERT_EQ(fidl::coded::Type::Kind::kStruct, type_named_payload->kind);
auto type_named_payload_message = static_cast<const fidl::coded::StructType*>(type_named_payload);
ASSERT_FALSE(type_named_payload_message->is_empty);
EXPECT_FALSE(type_named_payload_message->contains_envelope);
EXPECT_NULL(type_named_payload_message->maybe_reference_type);
EXPECT_STREQ("example/OnReceivePayload", type_named_payload_message->qname.c_str());
EXPECT_EQ(1, type_named_payload_message->elements.size());
EXPECT_EQ(0, field(type_named_payload_message->elements.at(0)).offset_v2);
}
TEST(CodedTypesGeneratorTests, GoodCodedTypesStructMessageErrorSyntax) {
TestLibrary library(R"FIDL(library example;
protocol UseOfProtocol {
Method() -> (struct {
arg1 bool;
arg2 bool;
}) error uint32;
};
)FIDL");
ASSERT_COMPILED(library);
fidl::CodedTypesGenerator gen(library.compilation());
gen.CompileCodedTypes();
ASSERT_EQ(4, gen.coded_types().size());
auto type0 = gen.coded_types().at(0).get();
EXPECT_STREQ("example_UseOfProtocol_Method_ResultNullableRef", type0->coded_name.c_str());
EXPECT_TRUE(type0->is_coding_needed);
ASSERT_EQ(fidl::coded::Type::Kind::kXUnion, type0->kind);
auto type0_union = static_cast<const fidl::coded::XUnionType*>(type0);
ASSERT_EQ(fidl::types::Nullability::kNullable, type0_union->nullability);
EXPECT_EQ(16, type0->size_v2);
ASSERT_EQ(2, type0_union->fields.size());
auto type0_field0 = type0_union->fields.at(0);
EXPECT_STREQ("example_UseOfProtocol_Method_Response", type0_field0.type->coded_name.c_str());
auto type0_field1 = type0_union->fields.at(1);
EXPECT_STREQ("uint32", type0_field1.type->coded_name.c_str());
auto type2 = gen.coded_types().at(1).get();
EXPECT_STREQ("bool", type2->coded_name.c_str());
auto type3 = gen.coded_types().at(2).get();
EXPECT_STREQ("uint32", type3->coded_name.c_str());
auto type4 = gen.coded_types().at(3).get();
EXPECT_STREQ("example_UseOfProtocolMethodResponseMessage", type4->coded_name.c_str());
EXPECT_TRUE(type4->is_coding_needed);
EXPECT_EQ(16, type4->size_v2);
ASSERT_EQ(fidl::coded::Type::Kind::kStruct, type4->kind);
auto type4_message = static_cast<const fidl::coded::StructType*>(type4);
ASSERT_FALSE(type4_message->is_empty);
EXPECT_TRUE(type4_message->contains_envelope);
EXPECT_NULL(type4_message->maybe_reference_type);
EXPECT_STREQ("example/UseOfProtocolMethodResponseMessage", type4_message->qname.c_str());
ASSERT_EQ(1, type4_message->elements.size());
auto anon_payload_name =
fidl::flat::Name::Key(library.LookupLibrary("example"), "UseOfProtocol_Method_Response");
auto type_anon_payload = gen.CodedTypeFor(anon_payload_name);
ASSERT_NOT_NULL(type_anon_payload);
EXPECT_STREQ("example_UseOfProtocol_Method_Response", type_anon_payload->coded_name.c_str());
EXPECT_TRUE(type_anon_payload->is_coding_needed);
EXPECT_EQ(2, type_anon_payload->size_v2);
ASSERT_EQ(fidl::coded::Type::Kind::kStruct, type_anon_payload->kind);
auto type_anon_payload_message = static_cast<const fidl::coded::StructType*>(type_anon_payload);
ASSERT_FALSE(type_anon_payload_message->is_empty);
EXPECT_FALSE(type_anon_payload_message->contains_envelope);
EXPECT_NULL(type_anon_payload_message->maybe_reference_type);
EXPECT_STREQ("example/UseOfProtocol_Method_Response", type_anon_payload_message->qname.c_str());
ASSERT_EQ(2, type_anon_payload_message->elements.size());
EXPECT_EQ(0, field(type_anon_payload_message->elements.at(0)).offset_v2);
EXPECT_EQ(1, field(type_anon_payload_message->elements.at(1)).offset_v2);
}
TEST(CodedTypesGeneratorTests, GoodCodedTypesTableMessage) {
TestLibrary library(R"FIDL(library example;
type OnReceivePayload = table {
1: arg bool;
};
protocol UseOfProtocol {
Call(table {
1: arg1 bool;
2: arg2 bool;
});
-> OnReceive(OnReceivePayload);
};
)FIDL");
ASSERT_COMPILED(library);
fidl::CodedTypesGenerator gen(library.compilation());
gen.CompileCodedTypes();
ASSERT_EQ(2, gen.coded_types().size());
auto type0 = gen.coded_types().at(0).get();
EXPECT_STREQ("bool", type0->coded_name.c_str());
auto anon_payload = gen.coded_types().at(1).get();
EXPECT_STREQ("example_UseOfProtocolCallRequestMessage", anon_payload->coded_name.c_str());
EXPECT_TRUE(anon_payload->is_coding_needed);
EXPECT_EQ(16, anon_payload->size_v2);
ASSERT_EQ(fidl::coded::Type::Kind::kTable, anon_payload->kind);
auto anon_payload_message = static_cast<const fidl::coded::TableType*>(anon_payload);
EXPECT_EQ(fidl::types::Resourceness::kValue, anon_payload_message->resourceness);
EXPECT_STREQ("example/UseOfProtocolCallRequestMessage", anon_payload_message->qname.c_str());
ASSERT_EQ(2, anon_payload_message->fields.size());
EXPECT_EQ(1, anon_payload_message->fields.at(0).type->size_v2);
EXPECT_EQ(1, anon_payload_message->fields.at(1).type->size_v2);
auto named_payload_name =
fidl::flat::Name::Key(library.LookupLibrary("example"), "OnReceivePayload");
auto type_named_payload = gen.CodedTypeFor(named_payload_name);
ASSERT_NOT_NULL(type_named_payload);
EXPECT_STREQ("example_OnReceivePayload", type_named_payload->coded_name.c_str());
EXPECT_TRUE(type_named_payload->is_coding_needed);
EXPECT_EQ(16, type_named_payload->size_v2);
ASSERT_EQ(fidl::coded::Type::Kind::kTable, type_named_payload->kind);
auto type_named_payload_message = static_cast<const fidl::coded::TableType*>(type_named_payload);
EXPECT_EQ(fidl::types::Resourceness::kValue, type_named_payload_message->resourceness);
EXPECT_STREQ("example/OnReceivePayload", type_named_payload_message->qname.c_str());
ASSERT_EQ(1, type_named_payload_message->fields.size());
EXPECT_EQ(1, type_named_payload_message->fields.at(0).type->size_v2);
}
TEST(CodedTypesGeneratorTests, GoodCodedTypesTableMessageErrorSyntax) {
TestLibrary library(R"FIDL(library example;
protocol UseOfProtocol {
Method() -> (table {
1: arg1 bool;
2: arg2 bool;
}) error uint32;
};
)FIDL");
ASSERT_COMPILED(library);
fidl::CodedTypesGenerator gen(library.compilation());
gen.CompileCodedTypes();
ASSERT_EQ(4, gen.coded_types().size());
auto type0 = gen.coded_types().at(0).get();
EXPECT_STREQ("example_UseOfProtocol_Method_ResultNullableRef", type0->coded_name.c_str());
EXPECT_TRUE(type0->is_coding_needed);
ASSERT_EQ(fidl::coded::Type::Kind::kXUnion, type0->kind);
auto type0_union = static_cast<const fidl::coded::XUnionType*>(type0);
ASSERT_EQ(fidl::types::Nullability::kNullable, type0_union->nullability);
EXPECT_EQ(16, type0->size_v2);
ASSERT_EQ(2, type0_union->fields.size());
auto type0_field0 = type0_union->fields.at(0);
EXPECT_STREQ("example_UseOfProtocol_Method_Response", type0_field0.type->coded_name.c_str());
auto type0_field1 = type0_union->fields.at(1);
EXPECT_STREQ("uint32", type0_field1.type->coded_name.c_str());
auto type2 = gen.coded_types().at(1).get();
EXPECT_STREQ("bool", type2->coded_name.c_str());
auto type3 = gen.coded_types().at(2).get();
EXPECT_STREQ("uint32", type3->coded_name.c_str());
auto type4 = gen.coded_types().at(3).get();
EXPECT_STREQ("example_UseOfProtocolMethodResponseMessage", type4->coded_name.c_str());
EXPECT_TRUE(type4->is_coding_needed);
EXPECT_EQ(16, type4->size_v2);
ASSERT_EQ(fidl::coded::Type::Kind::kStruct, type4->kind);
auto type4_message = static_cast<const fidl::coded::StructType*>(type4);
EXPECT_TRUE(type4_message->contains_envelope);
EXPECT_STREQ("example/UseOfProtocolMethodResponseMessage", type4_message->qname.c_str());
ASSERT_EQ(1, type4_message->elements.size());
auto anon_payload_name =
fidl::flat::Name::Key(library.LookupLibrary("example"), "UseOfProtocol_Method_Response");
auto type_anon_payload = gen.CodedTypeFor(anon_payload_name);
ASSERT_NOT_NULL(type_anon_payload);
EXPECT_STREQ("example_UseOfProtocol_Method_Response", type_anon_payload->coded_name.c_str());
EXPECT_TRUE(type_anon_payload->is_coding_needed);
EXPECT_EQ(16, type_anon_payload->size_v2);
ASSERT_EQ(fidl::coded::Type::Kind::kTable, type_anon_payload->kind);
auto type_anon_payload_message = static_cast<const fidl::coded::TableType*>(type_anon_payload);
EXPECT_EQ(fidl::types::Resourceness::kValue, type_anon_payload_message->resourceness);
EXPECT_STREQ("example/UseOfProtocol_Method_Response", type_anon_payload_message->qname.c_str());
ASSERT_EQ(2, type_anon_payload_message->fields.size());
EXPECT_EQ(1, type_anon_payload_message->fields.at(0).type->size_v2);
EXPECT_EQ(1, type_anon_payload_message->fields.at(1).type->size_v2);
}
TEST(CodedTypesGeneratorTests, GoodCodedTypesUnionMessage) {
TestLibrary library(R"FIDL(library example;
type OnReceivePayload = strict union {
1: arg bool;
};
protocol UseOfProtocol {
Call(flexible union {
1: arg1 bool;
2: arg2 bool;
});
-> OnReceive(OnReceivePayload);
};
)FIDL");
ASSERT_COMPILED(library);
fidl::CodedTypesGenerator gen(library.compilation());
gen.CompileCodedTypes();
ASSERT_EQ(4, gen.coded_types().size());
auto type2 = gen.coded_types().at(2).get();
EXPECT_STREQ("bool", type2->coded_name.c_str());
auto anon_payload = gen.coded_types().at(3).get();
EXPECT_STREQ("example_UseOfProtocolCallRequestMessage", anon_payload->coded_name.c_str());
EXPECT_TRUE(anon_payload->is_coding_needed);
EXPECT_EQ(16, anon_payload->size_v2);
ASSERT_EQ(fidl::coded::Type::Kind::kXUnion, anon_payload->kind);
auto anon_payload_message = static_cast<const fidl::coded::XUnionType*>(anon_payload);
EXPECT_EQ(fidl::types::Nullability::kNonnullable, anon_payload_message->nullability);
EXPECT_EQ(fidl::types::Resourceness::kValue, anon_payload_message->resourceness);
EXPECT_STREQ("example/UseOfProtocolCallRequestMessage", anon_payload_message->qname.c_str());
ASSERT_EQ(2, anon_payload_message->fields.size());
EXPECT_EQ(1, anon_payload_message->fields.at(0).type->size_v2);
EXPECT_EQ(1, anon_payload_message->fields.at(1).type->size_v2);
auto named_payload_name =
fidl::flat::Name::Key(library.LookupLibrary("example"), "OnReceivePayload");
auto type_named_payload = gen.CodedTypeFor(named_payload_name);
ASSERT_NOT_NULL(type_named_payload);
EXPECT_STREQ("example_OnReceivePayload", type_named_payload->coded_name.c_str());
EXPECT_TRUE(type_named_payload->is_coding_needed);
EXPECT_EQ(16, type_named_payload->size_v2);
ASSERT_EQ(fidl::coded::Type::Kind::kXUnion, type_named_payload->kind);
auto type_named_payload_message = static_cast<const fidl::coded::XUnionType*>(type_named_payload);
EXPECT_EQ(fidl::types::Nullability::kNonnullable, type_named_payload_message->nullability);
EXPECT_EQ(fidl::types::Resourceness::kValue, type_named_payload_message->resourceness);
EXPECT_STREQ("example/OnReceivePayload", type_named_payload_message->qname.c_str());
ASSERT_EQ(1, type_named_payload_message->fields.size());
EXPECT_EQ(1, type_named_payload_message->fields.at(0).type->size_v2);
}
TEST(CodedTypesGeneratorTests, GoodCodedTypesUnionMessageErrorSyntax) {
TestLibrary library(R"FIDL(library example;
protocol UseOfProtocol {
Method() -> (strict union {
1: arg1 bool;
2: arg2 bool;
}) error uint32;
};
)FIDL");
ASSERT_COMPILED(library);
fidl::CodedTypesGenerator gen(library.compilation());
gen.CompileCodedTypes();
ASSERT_EQ(5, gen.coded_types().size());
auto type1 = gen.coded_types().at(1).get();
EXPECT_STREQ("example_UseOfProtocol_Method_ResultNullableRef", type1->coded_name.c_str());
EXPECT_TRUE(type1->is_coding_needed);
ASSERT_EQ(fidl::coded::Type::Kind::kXUnion, type1->kind);
auto type1_union = static_cast<const fidl::coded::XUnionType*>(type1);
ASSERT_EQ(fidl::types::Nullability::kNullable, type1_union->nullability);
EXPECT_EQ(16, type1->size_v2);
ASSERT_EQ(2, type1_union->fields.size());
auto type1_field0 = type1_union->fields.at(0);
EXPECT_STREQ("example_UseOfProtocol_Method_Response", type1_field0.type->coded_name.c_str());
auto type1_field1 = type1_union->fields.at(1);
EXPECT_STREQ("uint32", type1_field1.type->coded_name.c_str());
auto type4 = gen.coded_types().at(2).get();
EXPECT_STREQ("bool", type4->coded_name.c_str());
auto type5 = gen.coded_types().at(3).get();
EXPECT_STREQ("uint32", type5->coded_name.c_str());
auto type6 = gen.coded_types().at(4).get();
EXPECT_STREQ("example_UseOfProtocolMethodResponseMessage", type6->coded_name.c_str());
EXPECT_TRUE(type6->is_coding_needed);
EXPECT_EQ(16, type6->size_v2);
ASSERT_EQ(fidl::coded::Type::Kind::kStruct, type6->kind);
auto type6_message = static_cast<const fidl::coded::StructType*>(type6);
EXPECT_TRUE(type6_message->contains_envelope);
EXPECT_STREQ("example/UseOfProtocolMethodResponseMessage", type6_message->qname.c_str());
ASSERT_EQ(1, type6_message->elements.size());
auto anon_payload_name =
fidl::flat::Name::Key(library.LookupLibrary("example"), "UseOfProtocol_Method_Response");
auto type_anon_payload = gen.CodedTypeFor(anon_payload_name);
ASSERT_NOT_NULL(type_anon_payload);
EXPECT_STREQ("example_UseOfProtocol_Method_Response", type_anon_payload->coded_name.c_str());
EXPECT_TRUE(type_anon_payload->is_coding_needed);
EXPECT_EQ(16, type_anon_payload->size_v2);
ASSERT_EQ(fidl::coded::Type::Kind::kXUnion, type_anon_payload->kind);
auto type_anon_payload_message = static_cast<const fidl::coded::XUnionType*>(type_anon_payload);
EXPECT_EQ(fidl::types::Nullability::kNonnullable, type_anon_payload_message->nullability);
EXPECT_EQ(fidl::types::Resourceness::kValue, type_anon_payload_message->resourceness);
EXPECT_STREQ("example/UseOfProtocol_Method_Response", type_anon_payload_message->qname.c_str());
ASSERT_EQ(2, type_anon_payload_message->fields.size());
EXPECT_EQ(1, type_anon_payload_message->fields.at(0).type->size_v2);
EXPECT_EQ(1, type_anon_payload_message->fields.at(1).type->size_v2);
}
} // namespace