| // 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 |