| // 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 <gtest/gtest.h> |
| |
| #include "tools/fidl/fidlc/src/attribute_schema.h" |
| #include "tools/fidl/fidlc/src/diagnostics.h" |
| #include "tools/fidl/fidlc/src/flat_ast.h" |
| #include "tools/fidl/fidlc/tests/test_library.h" |
| |
| namespace fidlc { |
| namespace { |
| |
| TEST(AttributesTests, GoodPlacementOfAttributes) { |
| SharedAmongstLibraries shared; |
| TestLibrary dependency(&shared, "exampleusing.fidl", R"FIDL( |
| library exampleusing; |
| |
| @on_dep_struct |
| type Empty = struct {}; |
| )FIDL"); |
| ASSERT_COMPILED(dependency); |
| |
| TestLibrary library(&shared, "example.fidl", R"FIDL( |
| @on_library |
| library example; |
| |
| using exampleusing; |
| |
| @on_bits |
| type ExampleBits = bits { |
| @on_bits_member |
| MEMBER = 1; |
| }; |
| |
| @on_const |
| const EXAMPLE_CONST uint32 = 0; |
| |
| @on_enum |
| type ExampleEnum = enum { |
| @on_enum_member |
| MEMBER = 1; |
| }; |
| |
| @on_protocol |
| protocol ExampleChildProtocol { |
| @on_method |
| Method(struct { @on_parameter arg exampleusing.Empty; }); |
| }; |
| |
| @on_protocol |
| protocol ExampleParentProtocol { |
| @on_compose |
| compose ExampleChildProtocol; |
| }; |
| |
| @on_service |
| service ExampleService { |
| @on_service_member |
| member client_end:ExampleParentProtocol; |
| }; |
| |
| @on_struct |
| type ExampleStruct = struct { |
| @on_struct_member |
| member uint32; |
| }; |
| |
| @on_table |
| type ExampleTable = table { |
| @on_table_member |
| 1: member uint32; |
| }; |
| |
| @on_alias |
| alias ExampleAlias = uint32; |
| |
| @on_union |
| type ExampleUnion = union { |
| @on_union_member |
| 1: variant uint32; |
| }; |
| )FIDL"); |
| ASSERT_COMPILED(library); |
| |
| EXPECT_TRUE(library.attributes()->Get("on_library")); |
| |
| auto example_bits = library.LookupBits("ExampleBits"); |
| ASSERT_NE(example_bits, nullptr); |
| EXPECT_TRUE(example_bits->attributes->Get("on_bits")); |
| EXPECT_TRUE(example_bits->members.front().attributes->Get("on_bits_member")); |
| |
| auto example_const = library.LookupConstant("EXAMPLE_CONST"); |
| ASSERT_NE(example_const, nullptr); |
| EXPECT_TRUE(example_const->attributes->Get("on_const")); |
| |
| auto example_enum = library.LookupEnum("ExampleEnum"); |
| ASSERT_NE(example_enum, nullptr); |
| EXPECT_TRUE(example_enum->attributes->Get("on_enum")); |
| EXPECT_TRUE(example_enum->members.front().attributes->Get("on_enum_member")); |
| |
| auto example_child_protocol = library.LookupProtocol("ExampleChildProtocol"); |
| ASSERT_NE(example_child_protocol, nullptr); |
| EXPECT_TRUE(example_child_protocol->attributes->Get("on_protocol")); |
| EXPECT_TRUE(example_child_protocol->methods.front().attributes->Get("on_method")); |
| ASSERT_NE(example_child_protocol->methods.front().maybe_request.get(), nullptr); |
| |
| auto id = static_cast<const IdentifierType*>( |
| example_child_protocol->methods.front().maybe_request->type); |
| auto as_struct = static_cast<const Struct*>(id->type_decl); |
| EXPECT_TRUE(as_struct->members.front().attributes->Get("on_parameter")); |
| |
| auto example_parent_protocol = library.LookupProtocol("ExampleParentProtocol"); |
| ASSERT_NE(example_parent_protocol, nullptr); |
| EXPECT_TRUE(example_parent_protocol->attributes->Get("on_protocol")); |
| EXPECT_TRUE(example_parent_protocol->composed_protocols.front().attributes->Get("on_compose")); |
| |
| auto example_service = library.LookupService("ExampleService"); |
| ASSERT_NE(example_service, nullptr); |
| EXPECT_TRUE(example_service->attributes->Get("on_service")); |
| EXPECT_TRUE(example_service->members.front().attributes->Get("on_service_member")); |
| |
| auto example_struct = library.LookupStruct("ExampleStruct"); |
| ASSERT_NE(example_struct, nullptr); |
| EXPECT_TRUE(example_struct->attributes->Get("on_struct")); |
| EXPECT_TRUE(example_struct->members.front().attributes->Get("on_struct_member")); |
| |
| auto example_table = library.LookupTable("ExampleTable"); |
| ASSERT_NE(example_table, nullptr); |
| EXPECT_TRUE(example_table->attributes->Get("on_table")); |
| EXPECT_TRUE(example_table->members.front().attributes->Get("on_table_member")); |
| |
| auto example_alias = library.LookupAlias("ExampleAlias"); |
| ASSERT_NE(example_alias, nullptr); |
| EXPECT_TRUE(example_alias->attributes->Get("on_alias")); |
| |
| auto example_union = library.LookupUnion("ExampleUnion"); |
| ASSERT_NE(example_union, nullptr); |
| EXPECT_TRUE(example_union->attributes->Get("on_union")); |
| EXPECT_TRUE(example_union->members.front().attributes->Get("on_union_member")); |
| } |
| |
| TEST(AttributesTests, GoodOfficialAttributes) { |
| TestLibrary library(R"FIDL( |
| @no_doc |
| library example; |
| |
| /// For EXAMPLE_CONSTANT |
| @no_doc |
| @deprecated("Note") |
| const EXAMPLE_CONSTANT string = "foo"; |
| |
| /// For ExampleEnum |
| @deprecated("Reason") |
| type ExampleEnum = flexible enum { |
| A = 1; |
| /// For EnumMember |
| @unknown |
| B = 2; |
| }; |
| |
| /// For ExampleStruct |
| @max_bytes("1234") |
| @max_handles("5678") |
| type ExampleStruct = resource struct { |
| data @generated_name("CustomName") table { |
| 1: a uint8; |
| }; |
| }; |
| |
| /// For ExampleProtocol |
| @discoverable |
| @transport("Syscall") |
| protocol ExampleProtocol { |
| /// For ExampleMethod |
| @internal |
| @selector("Bar") |
| ExampleMethod(); |
| }; |
| |
| /// For ExampleService |
| @foo("ExampleService") |
| @no_doc |
| service ExampleService { |
| /// For ExampleProtocol |
| @foo("ExampleProtocol") |
| @no_doc |
| p client_end:ExampleProtocol; |
| }; |
| )FIDL"); |
| ASSERT_COMPILED(library); |
| |
| EXPECT_TRUE(library.attributes()->Get("no_doc")); |
| |
| auto example_const = library.LookupConstant("EXAMPLE_CONSTANT"); |
| ASSERT_NE(example_const, nullptr); |
| EXPECT_TRUE(example_const->attributes->Get("no_doc")); |
| EXPECT_TRUE(example_const->attributes->Get("doc")->GetArg("value")); |
| auto& const_doc_value = static_cast<const DocCommentConstantValue&>( |
| example_const->attributes->Get("doc")->GetArg("value")->value->Value()); |
| EXPECT_EQ(const_doc_value.MakeContents(), " For EXAMPLE_CONSTANT\n"); |
| EXPECT_TRUE(example_const->attributes->Get("deprecated")->GetArg("value")); |
| auto& const_str_value = static_cast<const StringConstantValue&>( |
| example_const->attributes->Get("deprecated")->GetArg("value")->value->Value()); |
| EXPECT_EQ(const_str_value.MakeContents(), "Note"); |
| |
| auto example_enum = library.LookupEnum("ExampleEnum"); |
| ASSERT_NE(example_enum, nullptr); |
| EXPECT_TRUE(example_enum->attributes->Get("doc")->GetArg("value")); |
| auto& enum_doc_value = static_cast<const DocCommentConstantValue&>( |
| example_enum->attributes->Get("doc")->GetArg("value")->value->Value()); |
| EXPECT_EQ(enum_doc_value.MakeContents(), " For ExampleEnum\n"); |
| EXPECT_TRUE(example_enum->attributes->Get("deprecated")->GetArg("value")); |
| auto& enum_str_value = static_cast<const StringConstantValue&>( |
| example_enum->attributes->Get("deprecated")->GetArg("value")->value->Value()); |
| EXPECT_EQ(enum_str_value.MakeContents(), "Reason"); |
| EXPECT_TRUE(example_enum->members.back().attributes->Get("unknown")); |
| |
| auto example_struct = library.LookupStruct("ExampleStruct"); |
| ASSERT_NE(example_struct, nullptr); |
| EXPECT_TRUE(example_struct->attributes->Get("doc")->GetArg("value")); |
| auto& struct_doc_value = static_cast<const DocCommentConstantValue&>( |
| example_struct->attributes->Get("doc")->GetArg("value")->value->Value()); |
| EXPECT_EQ(struct_doc_value.MakeContents(), " For ExampleStruct\n"); |
| EXPECT_TRUE(example_struct->attributes->Get("max_bytes")->GetArg("value")); |
| auto& struct_str_value1 = static_cast<const StringConstantValue&>( |
| example_struct->attributes->Get("max_bytes")->GetArg("value")->value->Value()); |
| EXPECT_EQ(struct_str_value1.MakeContents(), "1234"); |
| EXPECT_TRUE(example_struct->attributes->Get("max_handles")->GetArg("value")); |
| auto& struct_str_value2 = static_cast<const StringConstantValue&>( |
| example_struct->attributes->Get("max_handles")->GetArg("value")->value->Value()); |
| EXPECT_EQ(struct_str_value2.MakeContents(), "5678"); |
| |
| auto example_anon = library.LookupTable("CustomName"); |
| ASSERT_NE(example_anon, nullptr); |
| EXPECT_TRUE(example_anon->attributes->Get("generated_name")); |
| |
| auto& generated_name_value = static_cast<const StringConstantValue&>( |
| example_anon->attributes->Get("generated_name")->GetArg("value")->value->Value()); |
| EXPECT_EQ(generated_name_value.MakeContents(), "CustomName"); |
| |
| auto example_protocol = library.LookupProtocol("ExampleProtocol"); |
| ASSERT_NE(example_protocol, nullptr); |
| EXPECT_TRUE(example_protocol->attributes->Get("discoverable")); |
| EXPECT_TRUE(example_protocol->attributes->Get("doc")->GetArg("value")); |
| auto& protocol_doc_value = static_cast<const DocCommentConstantValue&>( |
| example_protocol->attributes->Get("doc")->GetArg("value")->value->Value()); |
| EXPECT_EQ(protocol_doc_value.MakeContents(), " For ExampleProtocol\n"); |
| EXPECT_TRUE(example_protocol->attributes->Get("transport")->GetArg("value")); |
| auto& protocol_str_value = static_cast<const StringConstantValue&>( |
| example_protocol->attributes->Get("transport")->GetArg("value")->value->Value()); |
| EXPECT_EQ(protocol_str_value.MakeContents(), "Syscall"); |
| |
| auto& example_method = example_protocol->methods.front(); |
| EXPECT_TRUE(example_method.attributes->Get("internal")); |
| EXPECT_TRUE(example_method.attributes->Get("doc")->GetArg("value")); |
| auto& method_doc_value = static_cast<const DocCommentConstantValue&>( |
| example_method.attributes->Get("doc")->GetArg("value")->value->Value()); |
| EXPECT_EQ(method_doc_value.MakeContents(), " For ExampleMethod\n"); |
| EXPECT_TRUE(example_method.attributes->Get("selector")->GetArg("value")); |
| auto& method_str_value = static_cast<const StringConstantValue&>( |
| example_method.attributes->Get("selector")->GetArg("value")->value->Value()); |
| EXPECT_EQ(method_str_value.MakeContents(), "Bar"); |
| |
| auto example_service = library.LookupService("ExampleService"); |
| ASSERT_NE(example_service, nullptr); |
| EXPECT_TRUE(example_service->attributes->Get("no_doc")); |
| EXPECT_TRUE(example_service->attributes->Get("doc")->GetArg("value")); |
| auto& service_doc_value = static_cast<const DocCommentConstantValue&>( |
| example_service->attributes->Get("doc")->GetArg("value")->value->Value()); |
| EXPECT_EQ(service_doc_value.MakeContents(), " For ExampleService\n"); |
| EXPECT_TRUE(example_service->attributes->Get("foo")->GetArg("value")); |
| auto& service_str_value = static_cast<const StringConstantValue&>( |
| example_service->attributes->Get("foo")->GetArg("value")->value->Value()); |
| EXPECT_EQ(service_str_value.MakeContents(), "ExampleService"); |
| |
| auto& example_service_member = example_service->members.front(); |
| EXPECT_TRUE(example_service_member.attributes->Get("no_doc")); |
| EXPECT_TRUE(example_service_member.attributes->Get("doc")->GetArg("value")); |
| auto& service_member_doc_value = static_cast<const DocCommentConstantValue&>( |
| example_service_member.attributes->Get("doc")->GetArg("value")->value->Value()); |
| EXPECT_EQ(service_member_doc_value.MakeContents(), " For ExampleProtocol\n"); |
| EXPECT_TRUE(example_service_member.attributes->Get("foo")->GetArg("value")); |
| auto& service_member_str_value = static_cast<const StringConstantValue&>( |
| example_service_member.attributes->Get("foo")->GetArg("value")->value->Value()); |
| EXPECT_EQ(service_member_str_value.MakeContents(), "ExampleProtocol"); |
| } |
| |
| TEST(AttributesTests, BadNoAttributeOnUsingNotEventDoc) { |
| SharedAmongstLibraries shared; |
| TestLibrary dependency(&shared); |
| dependency.AddFile("bad/fi-0045-a.test.fidl"); |
| ASSERT_COMPILED(dependency); |
| TestLibrary library(&shared); |
| library.AddFile("bad/fi-0045-b.test.fidl"); |
| library.ExpectFail(ErrAttributesNotAllowedOnLibraryImport); |
| ASSERT_COMPILER_DIAGNOSTICS(library); |
| } |
| |
| // Test that a duplicate attribute is caught, and nicely reported. |
| TEST(AttributesTests, BadNoTwoSameAttribute) { |
| TestLibrary library(R"FIDL( |
| library fidl.test.dupattributes; |
| |
| @dup("first") |
| @dup("second") |
| protocol A { |
| MethodA(); |
| }; |
| )FIDL"); |
| library.ExpectFail(ErrDuplicateAttribute, "dup", "example.fidl:4:2"); |
| ASSERT_COMPILER_DIAGNOSTICS(library); |
| } |
| |
| // Test that attributes with the same canonical form are considered duplicates. |
| TEST(AttributesTests, BadNoTwoSameAttributeCanonical) { |
| TestLibrary library; |
| library.AddFile("bad/fi-0123.test.fidl"); |
| library.ExpectFail(ErrDuplicateAttributeCanonical, "CustomAttribute", "custom_attribute", |
| "bad/fi-0123.test.fidl:6:2", "custom_attribute"); |
| ASSERT_COMPILER_DIAGNOSTICS(library); |
| } |
| |
| TEST(AttributesTests, GoodDocAttribute) { |
| TestLibrary library; |
| library.AddFile("good/fi-0028-b.test.fidl"); |
| |
| ASSERT_COMPILED(library); |
| } |
| |
| // Test that doc comments and doc attributes clash are properly checked. |
| TEST(AttributesTests, BadNoTwoSameDocAttribute) { |
| TestLibrary library(R"FIDL( |
| library fidl.test.dupattributes; |
| |
| /// first |
| @doc("second") |
| protocol A { |
| MethodA(); |
| }; |
| )FIDL"); |
| library.ExpectFail(ErrDuplicateAttribute, "doc", "generated:1:1"); |
| ASSERT_COMPILER_DIAGNOSTICS(library); |
| } |
| |
| TEST(AttributesTests, BadNoTwoSameAttributeOnLibrary) { |
| TestLibrary library; |
| library.AddSource("first.fidl", R"FIDL( |
| @dup("first") |
| library fidl.test.dupattributes; |
| )FIDL"); |
| library.AddSource("second.fidl", R"FIDL( |
| @dup("second") |
| library fidl.test.dupattributes; |
| )FIDL"); |
| library.ExpectFail(ErrDuplicateAttribute, "dup", "first.fidl:2:2"); |
| ASSERT_COMPILER_DIAGNOSTICS(library); |
| } |
| |
| // Test that a close attribute is caught. |
| TEST(AttributesTests, WarnOnCloseToOfficialAttribute) { |
| TestLibrary library; |
| library.AddFile("bad/fi-0145.test.fidl"); |
| |
| library.ExpectWarn(WarnAttributeTypo, "duc", "doc"); |
| ASSERT_COMPILER_DIAGNOSTICS(library); |
| } |
| |
| TEST(AttributesTests, GoodNotTooCloseUnofficialAttribute) { |
| TestLibrary library; |
| library.AddFile("good/fi-0145.test.fidl"); |
| |
| ASSERT_COMPILED(library); |
| auto example_protocol = library.LookupProtocol("Example"); |
| ASSERT_NE(example_protocol, nullptr); |
| EXPECT_TRUE(example_protocol->attributes->Get("duck")); |
| auto& struct_str_value1 = static_cast<const StringConstantValue&>( |
| example_protocol->attributes->Get("duck")->GetArg("value")->value->Value()); |
| EXPECT_EQ(struct_str_value1.MakeContents(), "quack"); |
| } |
| |
| // Ensures we detect typos early enough that we still report them, even if there |
| // were other compilation errors. |
| TEST(AttributesTests, WarnOnCloseAttributeWithOtherErrors) { |
| TestLibrary library(R"FIDL( |
| @available(platform="foo", added=1) |
| library fidl.test; |
| |
| @available(added=1, removed=2) |
| type Foo = struct {}; |
| |
| // This actually gets added at 1 because we misspelled "available". |
| @availabe(added=2) |
| type Foo = resource struct {}; |
| )FIDL"); |
| library.SelectVersion("foo", "1"); |
| library.ExpectWarn(WarnAttributeTypo, "availabe", "available"); |
| library.ExpectFail(ErrNameOverlap, Element::Kind::kStruct, "Foo", Element::Kind::kStruct, |
| "example.fidl:6:6", |
| VersionSet(VersionRange(Version::From(1).value(), Version::From(2).value())), |
| Platform::Parse("foo").value()); |
| ASSERT_COMPILER_DIAGNOSTICS(library); |
| } |
| |
| // This tests our ability to treat warnings as errors. It is here because this |
| // is the most convenient warning. |
| TEST(AttributesTests, BadWarningsAsErrors) { |
| TestLibrary library(R"FIDL( |
| library fidl.test; |
| |
| @duc("should be doc") |
| protocol A { |
| MethodA(); |
| }; |
| )FIDL"); |
| library.set_warnings_as_errors(true); |
| ASSERT_FALSE(library.Compile()); |
| ASSERT_EQ(library.warnings().size(), 0u); |
| ASSERT_EQ(library.errors().size(), 1u); |
| ASSERT_EQ(library.errors()[0]->def.msg, WarnAttributeTypo.msg); |
| } |
| |
| TEST(AttributesTests, BadUnknownArgument) { |
| TestLibrary library; |
| library.AddFile("bad/fi-0129.test.fidl"); |
| library.SelectVersion("test", "HEAD"); |
| library.ExpectFail(ErrUnknownAttributeArg, "available", "discontinued"); |
| ASSERT_COMPILER_DIAGNOSTICS(library); |
| } |
| |
| TEST(AttributesTests, BadEmptyTransport) { |
| TestLibrary library; |
| library.AddFile("bad/fi-0128.test.fidl"); |
| library.ExpectFail(ErrMissingRequiredAnonymousAttributeArg, "transport"); |
| ASSERT_COMPILER_DIAGNOSTICS(library); |
| } |
| |
| TEST(AttributesTests, BadUnrecognizedTransport) { |
| TestLibrary library; |
| library.AddFile("bad/fi-0142.test.fidl"); |
| library.ExpectFail(ErrInvalidTransportType, "Invalid", |
| std::set<std::string_view>{"Banjo", "Channel", "Driver", "Syscall"}); |
| ASSERT_COMPILER_DIAGNOSTICS(library); |
| } |
| |
| TEST(AttributesTests, GoodChannelTransport) { |
| TestLibrary library(R"FIDL( |
| library fidl.test.transportattributes; |
| |
| @transport("Channel") |
| protocol A { |
| MethodA(); |
| }; |
| )FIDL"); |
| ASSERT_COMPILED(library); |
| } |
| |
| TEST(AttributesTests, GoodSyscallTransport) { |
| TestLibrary library(R"FIDL( |
| library fidl.test.transportattributes; |
| |
| @transport("Syscall") |
| protocol A { |
| MethodA(); |
| }; |
| )FIDL"); |
| ASSERT_COMPILED(library); |
| } |
| |
| TEST(AttributesTests, BadMultipleTransports) { |
| TestLibrary library(R"FIDL( |
| library fidl.test.transportattributes; |
| |
| @transport("Channel, Syscall") |
| protocol A { |
| MethodA(); |
| }; |
| )FIDL"); |
| library.ExpectFail(ErrInvalidTransportType, "Channel, Syscall", |
| std::set<std::string_view>{"Banjo", "Channel", "Driver", "Syscall"}); |
| ASSERT_COMPILER_DIAGNOSTICS(library); |
| } |
| |
| TEST(AttributesTests, BadUnknownInvalidPlacementOnUnion) { |
| TestLibrary library(R"FIDL( |
| library fidl.test; |
| |
| @unknown |
| type U = flexible union { |
| 1: a int32; |
| }; |
| )FIDL"); |
| |
| library.ExpectFail(ErrInvalidAttributePlacement, "unknown"); |
| ASSERT_COMPILER_DIAGNOSTICS(library); |
| } |
| |
| TEST(AttributesTests, BadUnknownInvalidPlacementOnUnionMember) { |
| TestLibrary library(R"FIDL( |
| library fidl.test; |
| |
| type U = flexible union { |
| @unknown 1: a int32; |
| }; |
| )FIDL"); |
| |
| library.ExpectFail(ErrInvalidAttributePlacement, "unknown"); |
| ASSERT_COMPILER_DIAGNOSTICS(library); |
| } |
| |
| TEST(AttributesTests, BadUnknownInvalidPlacementOnBitsMember) { |
| TestLibrary library(R"FIDL( |
| library fidl.test; |
| |
| type B = flexible bits : uint32 { |
| @unknown A = 0x1; |
| }; |
| )FIDL"); |
| |
| library.ExpectFail(ErrInvalidAttributePlacement, "unknown"); |
| ASSERT_COMPILER_DIAGNOSTICS(library); |
| } |
| |
| TEST(AttributesTests, BadUnknownInvalidOnStrictEnumMember) { |
| TestLibrary library; |
| library.AddFile("bad/fi-0071.test.fidl"); |
| library.ExpectFail(ErrUnknownAttributeOnStrictEnumMember); |
| ASSERT_COMPILER_DIAGNOSTICS(library); |
| } |
| |
| TEST(AttributesTests, BadIncorrectPlacementLayout) { |
| TestLibrary library(R"FIDL( |
| @selector("test") // 1 |
| library fidl.test; |
| |
| @selector("test") // 2 |
| const MyConst uint32 = 0; |
| |
| @selector("test") // 3 |
| type MyEnum = enum { |
| @selector("test") // 4 |
| MyMember = 5; |
| }; |
| |
| @selector("test") // 5 |
| type MyStruct = struct { |
| @selector("test") // 6 |
| MyMember int32; |
| }; |
| |
| @selector("test") // 7 |
| type MyUnion = union { |
| @selector("test") // 8 |
| 1: MyMember int32; |
| }; |
| |
| @selector("test") // 9 |
| type MyTable = table { |
| @selector("test") // 10 |
| 1: MyMember int32; |
| }; |
| |
| @selector("test") // 11 |
| protocol MyProtocol { |
| @selector("test") // no error, this placement is allowed |
| MyMethod(); |
| }; |
| )FIDL"); |
| for (int i = 0; i < 11; i++) { |
| library.ExpectFail(ErrInvalidAttributePlacement, "selector"); |
| } |
| ASSERT_COMPILER_DIAGNOSTICS(library); |
| } |
| |
| TEST(AttributesTests, BadSingleDeprecatedAttribute) { |
| TestLibrary library; |
| library.AddFile("bad/fi-0121.test.fidl"); |
| library.ExpectFail(ErrDeprecatedAttribute, "example_deprecated_attribute"); |
| ASSERT_COMPILER_DIAGNOSTICS(library); |
| } |
| |
| TEST(AttributesTests, BadDeprecatedAttributes) { |
| TestLibrary library(R"FIDL( |
| library fidl.test; |
| |
| @example_deprecated_attribute |
| type MyStruct = struct {}; |
| |
| @example_deprecated_attribute |
| protocol MyOtherProtocol { |
| MyMethod(); |
| }; |
| |
| @example_deprecated_attribute |
| protocol MyProtocol { |
| MyMethod(); |
| }; |
| )FIDL"); |
| for (int i = 0; i < 3; i++) { |
| library.ExpectFail(ErrDeprecatedAttribute, "example_deprecated_attribute"); |
| } |
| ASSERT_COMPILER_DIAGNOSTICS(library); |
| } |
| |
| constexpr ErrorDef<123> TestErrIncorrectNumberOfMembers("incorrect number of members"); |
| |
| bool MustHaveThreeMembers(Reporter* reporter, const ExperimentalFlagSet flags, |
| const Attribute* attribute, const Element* element) { |
| switch (element->kind) { |
| case Element::Kind::kStruct: { |
| auto struct_decl = static_cast<const Struct*>(element); |
| if (struct_decl->members.size() != 3) { |
| return reporter->Fail(TestErrIncorrectNumberOfMembers, attribute->span); |
| } |
| return true; |
| } |
| default: |
| return reporter->Fail(ErrInvalidAttributePlacement, attribute->span, attribute); |
| } |
| } |
| |
| TEST(AttributesTests, BadConstraintOnlyThreeMembersOnStruct) { |
| TestLibrary library(R"FIDL( |
| library fidl.test; |
| |
| @must_have_three_members |
| type MyStruct = struct { |
| one int64; |
| two int64; |
| three int64; |
| oh_no_four int64; |
| }; |
| )FIDL"); |
| library.AddAttributeSchema("must_have_three_members").Constrain(MustHaveThreeMembers); |
| library.ExpectFail(TestErrIncorrectNumberOfMembers); |
| ASSERT_COMPILER_DIAGNOSTICS(library); |
| } |
| |
| TEST(AttributesTests, BadConstraintOnlyThreeMembersOnMethod) { |
| TestLibrary library(R"FIDL( |
| library fidl.test; |
| |
| protocol MyProtocol { |
| @must_have_three_members MyMethod(); |
| }; |
| )FIDL"); |
| library.AddAttributeSchema("must_have_three_members").Constrain(MustHaveThreeMembers); |
| library.ExpectFail(ErrInvalidAttributePlacement, "must_have_three_members"); |
| ASSERT_COMPILER_DIAGNOSTICS(library); |
| } |
| |
| TEST(AttributesTests, BadConstraintOnlyThreeMembersOnProtocol) { |
| TestLibrary library(R"FIDL( |
| library fidl.test; |
| |
| @must_have_three_members |
| protocol MyProtocol { |
| MyMethod(); |
| MySecondMethod(); |
| }; |
| )FIDL"); |
| library.AddAttributeSchema("must_have_three_members").Constrain(MustHaveThreeMembers); |
| library.ExpectFail(ErrInvalidAttributePlacement, "must_have_three_members"); |
| ASSERT_COMPILER_DIAGNOSTICS(library); |
| } |
| |
| TEST(AttributesTests, BadAttributeValue) { |
| TestLibrary library; |
| library.AddFile("bad/fi-0132.test.fidl"); |
| library.ExpectFail(ErrAttributeDisallowsArgs, "unknown"); |
| ASSERT_COMPILER_DIAGNOSTICS(library); |
| } |
| |
| TEST(AttributesTests, BadSelectorIncorrectPlacement) { |
| TestLibrary library; |
| library.AddFile("bad/fi-0120-a.test.fidl"); |
| library.ExpectFail(ErrInvalidAttributePlacement, "selector"); |
| ASSERT_COMPILER_DIAGNOSTICS(library); |
| } |
| |
| TEST(AttributesTests, BadParameterAttributeIncorrectPlacement) { |
| TestLibrary library(R"FIDL( |
| library fidl.test; |
| |
| protocol ExampleProtocol { |
| Method(struct { arg exampleusing.Empty; } @on_parameter); |
| }; |
| )FIDL"); |
| library.ExpectFail(ErrUnexpectedTokenOfKind, Token::KindAndSubkind(Token::Kind::kAt), |
| Token::KindAndSubkind(Token::Kind::kRightParen)); |
| ASSERT_COMPILER_DIAGNOSTICS(library); |
| } |
| |
| TEST(AttributesTests, BadDuplicateAttributePlacement) { |
| TestLibrary library; |
| library.AddFile("bad/fi-0023.noformat.test.fidl"); |
| library.ExpectFail(ErrRedundantAttributePlacement); |
| ASSERT_COMPILER_DIAGNOSTICS(library); |
| } |
| |
| TEST(AttributesTests, GoodLayoutAttributePlacements) { |
| TestLibrary library(R"FIDL( |
| library fidl.test; |
| |
| @foo |
| type Foo = struct {}; |
| |
| type Bar = @bar struct {}; |
| |
| protocol MyProtocol { |
| MyMethod(@baz struct { |
| inner_layout @qux struct {}; |
| }); |
| }; |
| )FIDL"); |
| ASSERT_COMPILED(library); |
| |
| auto foo = library.LookupStruct("Foo"); |
| ASSERT_NE(foo, nullptr); |
| EXPECT_TRUE(foo->attributes->Get("foo")); |
| |
| auto bar = library.LookupStruct("Bar"); |
| ASSERT_NE(bar, nullptr); |
| EXPECT_TRUE(bar->attributes->Get("bar")); |
| |
| auto req = library.LookupStruct("MyProtocolMyMethodRequest"); |
| ASSERT_NE(req, nullptr); |
| EXPECT_TRUE(req->attributes->Get("baz")); |
| |
| auto inner = library.LookupStruct("InnerLayout"); |
| ASSERT_NE(inner, nullptr); |
| EXPECT_TRUE(inner->attributes->Get("qux")); |
| } |
| |
| TEST(AttributesTests, BadNoArgumentsEmptyParens) { |
| TestLibrary library; |
| library.AddFile("bad/fi-0014.noformat.test.fidl"); |
| library.ExpectFail(ErrAttributeWithEmptyParens); |
| ASSERT_COMPILER_DIAGNOSTICS(library); |
| } |
| |
| TEST(AttributesTests, GoodMultipleArguments) { |
| TestLibrary library(R"FIDL( |
| library example; |
| |
| @foo(bar="abc", baz="def") |
| type MyStruct = struct {}; |
| )FIDL"); |
| ASSERT_COMPILED(library); |
| |
| auto example_struct = library.LookupStruct("MyStruct"); |
| ASSERT_NE(example_struct, nullptr); |
| EXPECT_TRUE(example_struct->attributes->Get("foo")); |
| EXPECT_TRUE(example_struct->attributes->Get("foo")->GetArg("bar")); |
| EXPECT_EQ(example_struct->attributes->Get("foo")->GetArg("bar")->value->span.data(), "\"abc\""); |
| EXPECT_TRUE(example_struct->attributes->Get("foo")->GetArg("baz")); |
| EXPECT_EQ(example_struct->attributes->Get("foo")->GetArg("baz")->value->span.data(), "\"def\""); |
| } |
| |
| TEST(AttributesTests, BadMultipleArgumentsWithNoNames) { |
| TestLibrary library; |
| library.AddFile("bad/fi-0015.noformat.test.fidl"); |
| library.ExpectFail(ErrAttributeArgsMustAllBeNamed); |
| ASSERT_COMPILER_DIAGNOSTICS(library); |
| } |
| |
| TEST(AttributesTests, BadMultipleArgumentsSomeNamesUnnamedStringArgFirst) { |
| TestLibrary library(R"FIDL( |
| library example; |
| |
| @foo("abc", bar="def") |
| type MyStruct = struct {}; |
| )FIDL"); |
| |
| library.ExpectFail(ErrAttributeArgsMustAllBeNamed); |
| ASSERT_COMPILER_DIAGNOSTICS(library); |
| } |
| |
| TEST(AttributesTests, BadMultipleArgumentsSomeNamesUnnamedStringArgSecond) { |
| TestLibrary library(R"FIDL( |
| library example; |
| |
| @foo(bar="abc", "def") |
| type MyStruct = struct {}; |
| )FIDL"); |
| // TODO(https://fxbug.dev/42063565): If an unnamed string argument follows a named |
| // argument, it incorrectly produces ErrUnexpectedTokenOfKind instead of |
| // ErrAttributeArgsMustAllBeNamed. |
| library.ExpectFail(ErrUnexpectedTokenOfKind, Token::KindAndSubkind(Token::Kind::kStringLiteral), |
| Token::KindAndSubkind(Token::Kind::kIdentifier)); |
| ASSERT_COMPILER_DIAGNOSTICS(library); |
| } |
| |
| TEST(AttributesTests, BadMultipleArgumentsSomeNamesUnnamedIdentifierArgFirst) { |
| TestLibrary library(R"FIDL( |
| library example; |
| |
| @foo("abc", bar=def) |
| type MyStruct = struct {}; |
| )FIDL"); |
| library.ExpectFail(ErrAttributeArgsMustAllBeNamed); |
| ASSERT_COMPILER_DIAGNOSTICS(library); |
| } |
| |
| TEST(AttributesTests, BadMultipleArgumentsSomeNamesUnnamedIdentifierArgSecond) { |
| TestLibrary library(R"FIDL( |
| library example; |
| |
| @foo(bar="abc", def) |
| type MyStruct = struct {}; |
| )FIDL"); |
| // TODO(https://fxbug.dev/42063565): If an unnamed identifier argument follows a named |
| // argument, it incorrectly produces ErrUnexpectedTokenOfKind and |
| // ErrUnexpectedToken instead of ErrAttributeArgsMustAllBeNamed. |
| library.ExpectFail(ErrUnexpectedTokenOfKind, Token::KindAndSubkind(Token::Kind::kRightParen), |
| Token::KindAndSubkind(Token::Kind::kEqual)); |
| library.ExpectFail(ErrUnexpectedToken); |
| ASSERT_COMPILER_DIAGNOSTICS(library); |
| } |
| |
| TEST(AttributesTests, BadMultipleArgumentsDuplicateNames) { |
| TestLibrary library; |
| library.AddFile("bad/fi-0130.test.fidl"); |
| library.ExpectFail(ErrDuplicateAttributeArg, "custom_attribute", "custom_arg", |
| "bad/fi-0130.test.fidl:6:19"); |
| ASSERT_COMPILER_DIAGNOSTICS(library); |
| } |
| |
| TEST(AttributesTests, BadMultipleArgumentsDuplicateCanonicalNames) { |
| TestLibrary library; |
| library.AddFile("bad/fi-0131.test.fidl"); |
| library.ExpectFail(ErrDuplicateAttributeArgCanonical, "custom_attribute", "CustomArg", |
| "custom_arg", "bad/fi-0131.test.fidl:6:19", "custom_arg"); |
| ASSERT_COMPILER_DIAGNOSTICS(library); |
| } |
| |
| TEST(AttributesTests, GoodSingleArgumentIsNotNamed) { |
| TestLibrary library(R"FIDL( |
| library example; |
| |
| @foo("bar") |
| type MyStruct = struct {}; |
| )FIDL"); |
| ASSERT_COMPILED(library); |
| } |
| |
| TEST(AttributesTests, GoodSingleArgumentIsNamedWithoutSchema) { |
| TestLibrary library(R"FIDL( |
| library example; |
| |
| @foo(a="bar") |
| type MyStruct = struct {}; |
| )FIDL"); |
| ASSERT_COMPILED(library); |
| } |
| |
| TEST(AttributesTests, GoodSingleSchemaArgument) { |
| TestLibrary library(R"FIDL( |
| library example; |
| |
| @foo("bar") |
| type MyStruct = struct {}; |
| )FIDL"); |
| library.AddAttributeSchema("foo").AddArg( |
| "value", |
| AttributeArgSchema(ConstantValue::Kind::kString, AttributeArgSchema::Optionality::kRequired)); |
| ASSERT_COMPILED(library); |
| } |
| |
| TEST(AttributesTests, GoodSingleSchemaArgumentWithInferredName) { |
| TestLibrary library(R"FIDL( |
| library example; |
| |
| @foo("bar") |
| type MyStruct = struct {}; |
| )FIDL"); |
| library.AddAttributeSchema("foo").AddArg( |
| "inferrable", |
| AttributeArgSchema(ConstantValue::Kind::kString, AttributeArgSchema::Optionality::kRequired)); |
| ASSERT_COMPILED(library); |
| |
| auto example_struct = library.LookupStruct("MyStruct"); |
| ASSERT_NE(example_struct, nullptr); |
| EXPECT_TRUE(example_struct->attributes->Get("foo")); |
| EXPECT_TRUE(example_struct->attributes->Get("foo")->GetArg("inferrable")); |
| } |
| |
| // If a schema is provided (ie, this is an "official" FIDL attribute), and it specifies that only |
| // a single optional argument is allowed, respect both the inclusion and omission of that argument. |
| TEST(AttributesTests, GoodSingleSchemaArgumentRespectOptionality) { |
| TestLibrary library(R"FIDL( |
| library example; |
| |
| @foo("bar") |
| type MyStruct = struct {}; |
| |
| @foo |
| type MyOtherStruct = struct {}; |
| )FIDL"); |
| library.AddAttributeSchema("foo").AddArg( |
| "value", |
| AttributeArgSchema(ConstantValue::Kind::kString, AttributeArgSchema::Optionality::kOptional)); |
| ASSERT_COMPILED(library); |
| } |
| |
| // If a schema is provided (ie, this is an "official" FIDL attribute), and it specifies that only |
| // a single argument is allowed, naming that argument is an error. |
| TEST(AttributesTests, BadSingleSchemaArgumentIsNamed) { |
| TestLibrary library; |
| library.AddFile("bad/fi-0125.test.fidl"); |
| library.ExpectFail(ErrAttributeArgMustNotBeNamed); |
| ASSERT_COMPILER_DIAGNOSTICS(library); |
| } |
| |
| // If a schema is provided (ie, this is an "official" FIDL attribute), and it specifies that |
| // multiple arguments are allowed, a single unnamed argument is an error. |
| TEST(AttributesTests, BadSingleSchemaArgumentIsNotNamed) { |
| TestLibrary library; |
| library.AddFile("bad/fi-0126.test.fidl"); |
| library.SelectVersion("test", "HEAD"); |
| // Here we are demonstrating ErrAttributeArgNotNamed. There is another error |
| // because @available is the only attribute that takes multiple arguments, and |
| // omitting the required "added" causes another error. |
| library.ExpectFail(ErrAttributeArgNotNamed, "1"); |
| library.ExpectFail(ErrLibraryAvailabilityMissingAdded); |
| ASSERT_COMPILER_DIAGNOSTICS(library); |
| } |
| |
| TEST(AttributesTests, GoodMultipleSchemaArgumentsRequiredOnly) { |
| TestLibrary library(R"FIDL( |
| library fidl.test; |
| |
| @multiple_args(first="foo", second="bar") |
| type MyStruct = struct {}; |
| |
| // Order independent. |
| @multiple_args(second="bar", first="foo") |
| type MyOtherStruct = struct {}; |
| )FIDL"); |
| library.AddAttributeSchema("multiple_args") |
| .AddArg("first", AttributeArgSchema(ConstantValue::Kind::kString, |
| AttributeArgSchema::Optionality::kRequired)) |
| .AddArg("second", AttributeArgSchema(ConstantValue::Kind::kString, |
| AttributeArgSchema::Optionality::kRequired)); |
| ASSERT_COMPILED(library); |
| } |
| |
| TEST(AttributesTests, GoodMultipleSchemaArgumentsOptionalOnly) { |
| TestLibrary library(R"FIDL( |
| library fidl.test; |
| |
| @multiple_args(first="foo", second="bar") |
| type MyStruct = struct {}; |
| |
| // Order independent. |
| @multiple_args(second="bar", first="foo") |
| type MyStruct2 = struct {}; |
| |
| // Only 1 argument present. |
| @multiple_args(first="foo") |
| type MyStruct3 = struct {}; |
| @multiple_args(second="bar") |
| type MyStruct4 = struct {}; |
| |
| // No arguments at all. |
| @multiple_args |
| type MyStruct5 = struct {}; |
| )FIDL"); |
| library.AddAttributeSchema("multiple_args") |
| .AddArg("first", AttributeArgSchema(ConstantValue::Kind::kString, |
| AttributeArgSchema::Optionality::kOptional)) |
| .AddArg("second", AttributeArgSchema(ConstantValue::Kind::kString, |
| AttributeArgSchema::Optionality::kOptional)); |
| ASSERT_COMPILED(library); |
| } |
| |
| TEST(AttributesTests, GoodMultipleSchemaArgumentsRequiredAndOptional) { |
| TestLibrary library(R"FIDL( |
| library fidl.test; |
| |
| @multiple_args(first="foo", second="bar") |
| type MyStruct = struct {}; |
| |
| // Order independent. |
| @multiple_args(second="bar", first="foo") |
| type MyStruct2 = struct {}; |
| |
| // Only 1 argument present. |
| @multiple_args(first="foo") |
| type MyStruct3 = struct {}; |
| )FIDL"); |
| library.AddAttributeSchema("multiple_args") |
| .AddArg("first", AttributeArgSchema(ConstantValue::Kind::kString, |
| AttributeArgSchema::Optionality::kRequired)) |
| .AddArg("second", AttributeArgSchema(ConstantValue::Kind::kString, |
| AttributeArgSchema::Optionality::kOptional)); |
| ASSERT_COMPILED(library); |
| } |
| |
| TEST(AttributesTests, BadMultipleSchemaArgumentsRequiredMissing) { |
| TestLibrary library; |
| library.AddFile("bad/fi-0127.test.fidl"); |
| library.AddAttributeSchema("has_required_arg") |
| .AddArg("required", AttributeArgSchema(ConstantValue::Kind::kString, |
| AttributeArgSchema::Optionality::kRequired)) |
| .AddArg("optional", AttributeArgSchema(ConstantValue::Kind::kString, |
| AttributeArgSchema::Optionality::kOptional)); |
| library.ExpectFail(ErrMissingRequiredAttributeArg, "has_required_arg", "required"); |
| ASSERT_COMPILER_DIAGNOSTICS(library); |
| } |
| |
| TEST(AttributesTests, GoodLiteralTypesWithoutSchema) { |
| TestLibrary library(R"FIDL( |
| library example; |
| |
| @attr(foo="abc", bar=true, baz=false) |
| type MyStruct = struct {}; |
| )FIDL"); |
| ASSERT_COMPILED(library); |
| |
| auto example_struct = library.LookupStruct("MyStruct"); |
| ASSERT_NE(example_struct, nullptr); |
| EXPECT_TRUE(example_struct->attributes->Get("attr")); |
| |
| // Check `foo` arg. |
| EXPECT_TRUE(example_struct->attributes->Get("attr")->GetArg("foo")); |
| const auto& foo = example_struct->attributes->Get("attr")->GetArg("foo")->value; |
| EXPECT_EQ(foo->span.data(), "\"abc\""); |
| ASSERT_EQ(foo->kind, Constant::Kind::kLiteral); |
| |
| std::unique_ptr<ConstantValue> resolved_foo; |
| EXPECT_TRUE(foo->Value().Convert(ConstantValue::Kind::kString, &resolved_foo)); |
| |
| // Check `baz` arg. |
| EXPECT_TRUE(example_struct->attributes->Get("attr")->GetArg("baz")); |
| const auto& baz = example_struct->attributes->Get("attr")->GetArg("baz")->value; |
| EXPECT_EQ(baz->span.data(), "false"); |
| ASSERT_EQ(baz->kind, Constant::Kind::kLiteral); |
| |
| std::unique_ptr<ConstantValue> resolved_baz; |
| EXPECT_TRUE(baz->Value().Convert(ConstantValue::Kind::kBool, &resolved_baz)); |
| } |
| |
| TEST(AttributesTests, BadLiteralNumericTypesWithoutSchema) { |
| TestLibrary library; |
| library.AddFile("bad/fi-0124.test.fidl"); |
| library.ExpectFail(ErrCanOnlyUseStringOrBool, "foo", "my_custom_attr"); |
| library.ExpectFail(ErrCanOnlyUseStringOrBool, "bar", "my_custom_attr"); |
| ASSERT_COMPILER_DIAGNOSTICS(library); |
| } |
| |
| TEST(AttributesTests, GoodReferencedTypesWithoutSchema) { |
| TestLibrary library(R"FIDL( |
| library example; |
| |
| const foo string:3 = "abc"; |
| const bar bool = true; |
| const baz bool = false; |
| |
| @attr(foo=foo, bar=bar, baz=baz) |
| type MyStruct = struct {}; |
| )FIDL"); |
| ASSERT_COMPILED(library); |
| |
| auto example_struct = library.LookupStruct("MyStruct"); |
| ASSERT_NE(example_struct, nullptr); |
| EXPECT_TRUE(example_struct->attributes->Get("attr")); |
| |
| // Check `foo` arg. |
| EXPECT_TRUE(example_struct->attributes->Get("attr")->GetArg("foo")); |
| const auto& foo = example_struct->attributes->Get("attr")->GetArg("foo")->value; |
| EXPECT_EQ(foo->span.data(), "foo"); |
| ASSERT_EQ(foo->kind, Constant::Kind::kIdentifier); |
| |
| std::unique_ptr<ConstantValue> resolved_foo; |
| EXPECT_TRUE(foo->Value().Convert(ConstantValue::Kind::kString, &resolved_foo)); |
| EXPECT_EQ(static_cast<StringConstantValue*>(resolved_foo.get())->MakeContents(), "abc"); |
| |
| // Check `bar` arg. |
| EXPECT_TRUE(example_struct->attributes->Get("attr")->GetArg("bar")); |
| const auto& bar = example_struct->attributes->Get("attr")->GetArg("bar")->value; |
| EXPECT_EQ(bar->span.data(), "bar"); |
| ASSERT_EQ(bar->kind, Constant::Kind::kIdentifier); |
| |
| std::unique_ptr<ConstantValue> resolved_bar; |
| EXPECT_TRUE(bar->Value().Convert(ConstantValue::Kind::kBool, &resolved_bar)); |
| EXPECT_TRUE(static_cast<BoolConstantValue*>(resolved_bar.get())->value); |
| |
| // Check `baz` arg. |
| EXPECT_TRUE(example_struct->attributes->Get("attr")->GetArg("baz")); |
| const auto& baz = example_struct->attributes->Get("attr")->GetArg("baz")->value; |
| EXPECT_EQ(baz->span.data(), "baz"); |
| ASSERT_EQ(baz->kind, Constant::Kind::kIdentifier); |
| |
| std::unique_ptr<ConstantValue> resolved_baz; |
| EXPECT_TRUE(baz->Value().Convert(ConstantValue::Kind::kBool, &resolved_baz)); |
| EXPECT_TRUE(!static_cast<BoolConstantValue*>(resolved_baz.get())->value); |
| } |
| |
| TEST(AttributesTests, BadReferencedNumericTypesWithoutSchema) { |
| TestLibrary library(R"FIDL( |
| library example; |
| |
| const foo int8 = -1; |
| const bar float32 = -2.3; |
| |
| @attr(foo=foo, bar=bar) |
| type MyStruct = struct {}; |
| )FIDL"); |
| library.ExpectFail(ErrCanOnlyUseStringOrBool, "foo", "attr"); |
| library.ExpectFail(ErrCanOnlyUseStringOrBool, "bar", "attr"); |
| ASSERT_COMPILER_DIAGNOSTICS(library); |
| } |
| |
| TEST(AttributesTests, GoodLiteralTypesWithSchema) { |
| TestLibrary library(R"FIDL( |
| library fidl.test; |
| |
| @attr( |
| string="foo", |
| bool=true, |
| int8=-1, |
| int16=-2, |
| int32=-3, |
| int64=-4, |
| uint8=1, |
| uint16=2, |
| uint32=3, |
| uint64=4, |
| usize64=5, |
| uintptr64=6, |
| uchar=7, |
| float32=1.2, |
| float64=-3.4) |
| type MyStruct = struct {}; |
| )FIDL"); |
| library.AddAttributeSchema("attr") |
| .AddArg("string", AttributeArgSchema(ConstantValue::Kind::kString)) |
| .AddArg("bool", AttributeArgSchema(ConstantValue::Kind::kBool)) |
| .AddArg("int8", AttributeArgSchema(ConstantValue::Kind::kInt8)) |
| .AddArg("int16", AttributeArgSchema(ConstantValue::Kind::kInt16)) |
| .AddArg("int32", AttributeArgSchema(ConstantValue::Kind::kInt32)) |
| .AddArg("int64", AttributeArgSchema(ConstantValue::Kind::kInt64)) |
| .AddArg("uint8", AttributeArgSchema(ConstantValue::Kind::kUint8)) |
| .AddArg("uint16", AttributeArgSchema(ConstantValue::Kind::kUint16)) |
| .AddArg("uint32", AttributeArgSchema(ConstantValue::Kind::kUint32)) |
| .AddArg("uint64", AttributeArgSchema(ConstantValue::Kind::kUint64)) |
| .AddArg("usize64", AttributeArgSchema(ConstantValue::Kind::kZxUsize64)) |
| .AddArg("uintptr64", AttributeArgSchema(ConstantValue::Kind::kZxUintptr64)) |
| .AddArg("uchar", AttributeArgSchema(ConstantValue::Kind::kZxUchar)) |
| .AddArg("float32", AttributeArgSchema(ConstantValue::Kind::kFloat32)) |
| .AddArg("float64", AttributeArgSchema(ConstantValue::Kind::kFloat64)); |
| ASSERT_COMPILED(library); |
| |
| auto example_struct = library.LookupStruct("MyStruct"); |
| ASSERT_NE(example_struct, nullptr); |
| EXPECT_TRUE(example_struct->attributes->Get("attr")); |
| |
| // Check `string` arg. |
| EXPECT_TRUE(example_struct->attributes->Get("attr")->GetArg("string")); |
| const auto& string_val = example_struct->attributes->Get("attr")->GetArg("string")->value; |
| EXPECT_EQ(string_val->span.data(), "\"foo\""); |
| ASSERT_EQ(string_val->kind, Constant::Kind::kLiteral); |
| |
| std::unique_ptr<ConstantValue> resolved_string; |
| EXPECT_TRUE(string_val->Value().Convert(ConstantValue::Kind::kString, &resolved_string)); |
| EXPECT_EQ(static_cast<StringConstantValue*>(resolved_string.get())->MakeContents(), "foo"); |
| |
| // Check `bool` arg. |
| EXPECT_TRUE(example_struct->attributes->Get("attr")->GetArg("bool")); |
| const auto& bool_val = example_struct->attributes->Get("attr")->GetArg("bool")->value; |
| EXPECT_EQ(bool_val->span.data(), "true"); |
| ASSERT_EQ(bool_val->kind, Constant::Kind::kLiteral); |
| |
| std::unique_ptr<ConstantValue> resolved_bool; |
| EXPECT_TRUE(bool_val->Value().Convert(ConstantValue::Kind::kBool, &resolved_bool)); |
| EXPECT_EQ(static_cast<BoolConstantValue*>(resolved_bool.get())->value, true); |
| |
| // Check `int8` arg. |
| EXPECT_TRUE(example_struct->attributes->Get("attr")->GetArg("int8")); |
| const auto& int8_val = example_struct->attributes->Get("attr")->GetArg("int8")->value; |
| EXPECT_EQ(int8_val->span.data(), "-1"); |
| ASSERT_EQ(int8_val->kind, Constant::Kind::kLiteral); |
| |
| std::unique_ptr<ConstantValue> resolved_int8; |
| EXPECT_TRUE(int8_val->Value().Convert(ConstantValue::Kind::kInt8, &resolved_int8)); |
| EXPECT_EQ(static_cast<NumericConstantValue<int8_t>*>(resolved_int8.get())->value, -1); |
| |
| // Check `int16` arg. |
| EXPECT_TRUE(example_struct->attributes->Get("attr")->GetArg("int16")); |
| const auto& int16_val = example_struct->attributes->Get("attr")->GetArg("int16")->value; |
| EXPECT_EQ(int16_val->span.data(), "-2"); |
| ASSERT_EQ(int16_val->kind, Constant::Kind::kLiteral); |
| |
| std::unique_ptr<ConstantValue> resolved_int16; |
| EXPECT_TRUE(int16_val->Value().Convert(ConstantValue::Kind::kInt16, &resolved_int16)); |
| EXPECT_EQ(static_cast<NumericConstantValue<int16_t>*>(resolved_int16.get())->value, -2); |
| |
| // Check `int32` arg. |
| EXPECT_TRUE(example_struct->attributes->Get("attr")->GetArg("int32")); |
| const auto& int32_val = example_struct->attributes->Get("attr")->GetArg("int32")->value; |
| EXPECT_EQ(int32_val->span.data(), "-3"); |
| ASSERT_EQ(int32_val->kind, Constant::Kind::kLiteral); |
| |
| std::unique_ptr<ConstantValue> resolved_int32; |
| EXPECT_TRUE(int32_val->Value().Convert(ConstantValue::Kind::kInt32, &resolved_int32)); |
| EXPECT_EQ(static_cast<NumericConstantValue<int32_t>*>(resolved_int32.get())->value, -3); |
| |
| // Check `int64` arg. |
| EXPECT_TRUE(example_struct->attributes->Get("attr")->GetArg("int64")); |
| const auto& int64_val = example_struct->attributes->Get("attr")->GetArg("int64")->value; |
| EXPECT_EQ(int64_val->span.data(), "-4"); |
| ASSERT_EQ(int64_val->kind, Constant::Kind::kLiteral); |
| |
| std::unique_ptr<ConstantValue> resolved_int64; |
| EXPECT_TRUE(int64_val->Value().Convert(ConstantValue::Kind::kInt64, &resolved_int64)); |
| EXPECT_EQ(static_cast<NumericConstantValue<int64_t>*>(resolved_int64.get())->value, -4); |
| |
| // Check `uint8` arg. |
| EXPECT_TRUE(example_struct->attributes->Get("attr")->GetArg("uint8")); |
| const auto& uint8_val = example_struct->attributes->Get("attr")->GetArg("uint8")->value; |
| EXPECT_EQ(uint8_val->span.data(), "1"); |
| ASSERT_EQ(uint8_val->kind, Constant::Kind::kLiteral); |
| |
| std::unique_ptr<ConstantValue> resolved_uint8; |
| EXPECT_TRUE(uint8_val->Value().Convert(ConstantValue::Kind::kUint8, &resolved_uint8)); |
| EXPECT_EQ(static_cast<NumericConstantValue<uint8_t>*>(resolved_uint8.get())->value, 1u); |
| |
| // Check `uint16` arg. |
| EXPECT_TRUE(example_struct->attributes->Get("attr")->GetArg("uint16")); |
| const auto& uint16_val = example_struct->attributes->Get("attr")->GetArg("uint16")->value; |
| EXPECT_EQ(uint16_val->span.data(), "2"); |
| ASSERT_EQ(uint16_val->kind, Constant::Kind::kLiteral); |
| |
| std::unique_ptr<ConstantValue> resolved_uint16; |
| EXPECT_TRUE(uint16_val->Value().Convert(ConstantValue::Kind::kUint16, &resolved_uint16)); |
| EXPECT_EQ(static_cast<NumericConstantValue<uint16_t>*>(resolved_uint16.get())->value, 2u); |
| |
| // Check `uint32` arg. |
| EXPECT_TRUE(example_struct->attributes->Get("attr")->GetArg("uint32")); |
| const auto& uint32_val = example_struct->attributes->Get("attr")->GetArg("uint32")->value; |
| EXPECT_EQ(uint32_val->span.data(), "3"); |
| ASSERT_EQ(uint32_val->kind, Constant::Kind::kLiteral); |
| |
| std::unique_ptr<ConstantValue> resolved_uint32; |
| EXPECT_TRUE(uint32_val->Value().Convert(ConstantValue::Kind::kUint32, &resolved_uint32)); |
| EXPECT_EQ(static_cast<NumericConstantValue<uint32_t>*>(resolved_uint32.get())->value, 3u); |
| |
| // Check `uint64` arg. |
| EXPECT_TRUE(example_struct->attributes->Get("attr")->GetArg("uint64")); |
| const auto& uint64_val = example_struct->attributes->Get("attr")->GetArg("uint64")->value; |
| EXPECT_EQ(uint64_val->span.data(), "4"); |
| ASSERT_EQ(uint64_val->kind, Constant::Kind::kLiteral); |
| |
| std::unique_ptr<ConstantValue> resolved_uint64; |
| EXPECT_TRUE(uint64_val->Value().Convert(ConstantValue::Kind::kUint64, &resolved_uint64)); |
| EXPECT_EQ(static_cast<NumericConstantValue<uint64_t>*>(resolved_uint64.get())->value, 4u); |
| |
| // Check `usize64` arg. |
| EXPECT_TRUE(example_struct->attributes->Get("attr")->GetArg("usize64")); |
| const auto& usize_val = example_struct->attributes->Get("attr")->GetArg("usize64")->value; |
| EXPECT_EQ(usize_val->span.data(), "5"); |
| ASSERT_EQ(usize_val->kind, Constant::Kind::kLiteral); |
| |
| std::unique_ptr<ConstantValue> resolved_usize; |
| EXPECT_TRUE(usize_val->Value().Convert(ConstantValue::Kind::kZxUsize64, &resolved_usize)); |
| EXPECT_EQ(static_cast<NumericConstantValue<uint64_t>*>(resolved_usize.get())->value, 5u); |
| |
| // Check `uintptr64` arg. |
| EXPECT_TRUE(example_struct->attributes->Get("attr")->GetArg("uintptr64")); |
| const auto& uintptr_val = example_struct->attributes->Get("attr")->GetArg("uintptr64")->value; |
| EXPECT_EQ(uintptr_val->span.data(), "6"); |
| ASSERT_EQ(uintptr_val->kind, Constant::Kind::kLiteral); |
| |
| std::unique_ptr<ConstantValue> resolved_uintptr; |
| EXPECT_TRUE(uintptr_val->Value().Convert(ConstantValue::Kind::kZxUintptr64, &resolved_uintptr)); |
| EXPECT_EQ(static_cast<NumericConstantValue<uint64_t>*>(resolved_uintptr.get())->value, 6u); |
| |
| // Check `uchar` arg. |
| EXPECT_TRUE(example_struct->attributes->Get("attr")->GetArg("uchar")); |
| const auto& uchar_val = example_struct->attributes->Get("attr")->GetArg("uchar")->value; |
| EXPECT_EQ(uchar_val->span.data(), "7"); |
| ASSERT_EQ(uchar_val->kind, Constant::Kind::kLiteral); |
| |
| std::unique_ptr<ConstantValue> resolved_uchar; |
| EXPECT_TRUE(uchar_val->Value().Convert(ConstantValue::Kind::kZxUchar, &resolved_uchar)); |
| EXPECT_EQ(static_cast<NumericConstantValue<uint8_t>*>(resolved_uchar.get())->value, 7u); |
| |
| // Check `float32` arg. |
| EXPECT_TRUE(example_struct->attributes->Get("attr")->GetArg("float32")); |
| const auto& float32_val = example_struct->attributes->Get("attr")->GetArg("float32")->value; |
| EXPECT_EQ(float32_val->span.data(), "1.2"); |
| ASSERT_EQ(float32_val->kind, Constant::Kind::kLiteral); |
| |
| std::unique_ptr<ConstantValue> resolved_float32; |
| EXPECT_TRUE(float32_val->Value().Convert(ConstantValue::Kind::kFloat32, &resolved_float32)); |
| EXPECT_TRUE(static_cast<NumericConstantValue<float>*>(resolved_float32.get())->value > 1.1); |
| EXPECT_TRUE(static_cast<NumericConstantValue<float>*>(resolved_float32.get())->value < 1.3); |
| |
| // Check `float64` arg. |
| EXPECT_TRUE(example_struct->attributes->Get("attr")->GetArg("float64")); |
| const auto& float64_val = example_struct->attributes->Get("attr")->GetArg("float64")->value; |
| EXPECT_EQ(float64_val->span.data(), "-3.4"); |
| ASSERT_EQ(float64_val->kind, Constant::Kind::kLiteral); |
| |
| std::unique_ptr<ConstantValue> resolved_float64; |
| EXPECT_TRUE(float64_val->Value().Convert(ConstantValue::Kind::kFloat64, &resolved_float64)); |
| EXPECT_TRUE(static_cast<NumericConstantValue<double>*>(resolved_float64.get())->value > -3.5); |
| EXPECT_TRUE(static_cast<NumericConstantValue<double>*>(resolved_float64.get())->value < -3.3); |
| } |
| |
| TEST(AttributesTests, BadInvalidLiteralStringTypeWithSchema) { |
| TestLibrary library(R"FIDL( |
| library example; |
| |
| @attr(true) |
| type MyStruct = struct {}; |
| )FIDL"); |
| library.AddAttributeSchema("attr").AddArg("string", |
| AttributeArgSchema(ConstantValue::Kind::kString)); |
| library.ExpectFail(ErrTypeCannotBeConvertedToType, "true", "bool", "string"); |
| library.ExpectFail(ErrCouldNotResolveAttributeArg); |
| ASSERT_COMPILER_DIAGNOSTICS(library); |
| } |
| |
| TEST(AttributesTests, BadInvalidLiteralBoolTypeWithSchema) { |
| TestLibrary library(R"FIDL( |
| library example; |
| |
| @attr("foo") |
| type MyStruct = struct {}; |
| )FIDL"); |
| library.AddAttributeSchema("attr").AddArg("bool", AttributeArgSchema(ConstantValue::Kind::kBool)); |
| library.ExpectFail(ErrTypeCannotBeConvertedToType, "\"foo\"", "string:3", "bool"); |
| library.ExpectFail(ErrCouldNotResolveAttributeArg); |
| ASSERT_COMPILER_DIAGNOSTICS(library); |
| } |
| |
| TEST(AttributesTests, BadInvalidLiteralNumericTypeWithSchema) { |
| TestLibrary library(R"FIDL( |
| library example; |
| |
| @attr(-1) |
| type MyStruct = struct {}; |
| )FIDL"); |
| library.AddAttributeSchema("attr").AddArg("uint8", |
| AttributeArgSchema(ConstantValue::Kind::kUint8)); |
| library.ExpectFail(ErrConstantOverflowsType, "-1", "uint8"); |
| library.ExpectFail(ErrCouldNotResolveAttributeArg); |
| ASSERT_COMPILER_DIAGNOSTICS(library); |
| } |
| |
| TEST(AttributesTests, BadInvalidLiteralWithRealSchema) { |
| TestLibrary library; |
| library.AddFile("bad/fi-0065-c.test.fidl"); |
| library.ExpectFail(ErrTypeCannotBeConvertedToType, "3840912312901827381273", "untyped numeric", |
| "string"); |
| library.ExpectFail(ErrCouldNotResolveAttributeArg); |
| ASSERT_COMPILER_DIAGNOSTICS(library); |
| } |
| |
| TEST(AttributesTests, GoodReferencedTypesWithSchema) { |
| TestLibrary library(R"FIDL( |
| library fidl.test; |
| |
| const string fidl.string = "foo"; |
| const bool fidl.bool = true; |
| const int8 fidl.int8 = -1; |
| const int16 fidl.int16 = -2; |
| const int32 fidl.int32 = -3; |
| type int64 = enum : fidl.int64 { |
| MEMBER = -4; |
| }; |
| const uint8 fidl.uint8 = 1; |
| const uint16 fidl.uint16 = 2; |
| const uint32 fidl.uint32 = 3; |
| type uint64 = bits : fidl.uint64 { |
| MEMBER = 4; |
| }; |
| const usize64 fidl.usize64 = 5; |
| const uintptr64 fidl.uintptr64 = 6; |
| const uchar fidl.uchar = 7; |
| const float32 fidl.float32 = 1.2; |
| const float64 fidl.float64 = -3.4; |
| |
| @attr( |
| string=string, |
| bool=bool, |
| int8=int8, |
| int16=int16, |
| int32=int32, |
| int64=int64.MEMBER, |
| uint8=uint8, |
| uint16=uint16, |
| uint32=uint32, |
| uint64=uint64.MEMBER, |
| usize64=usize64, |
| uintptr64=uintptr64, |
| uchar=uchar, |
| float32=float32, |
| float64=float64) |
| type MyStruct = struct {}; |
| )FIDL"); |
| library.AddAttributeSchema("attr") |
| .AddArg("string", AttributeArgSchema(ConstantValue::Kind::kString)) |
| .AddArg("bool", AttributeArgSchema(ConstantValue::Kind::kBool)) |
| .AddArg("int8", AttributeArgSchema(ConstantValue::Kind::kInt8)) |
| .AddArg("int16", AttributeArgSchema(ConstantValue::Kind::kInt16)) |
| .AddArg("int32", AttributeArgSchema(ConstantValue::Kind::kInt32)) |
| .AddArg("int64", AttributeArgSchema(ConstantValue::Kind::kInt64)) |
| .AddArg("uint8", AttributeArgSchema(ConstantValue::Kind::kUint8)) |
| .AddArg("uint16", AttributeArgSchema(ConstantValue::Kind::kUint16)) |
| .AddArg("uint32", AttributeArgSchema(ConstantValue::Kind::kUint32)) |
| .AddArg("uint64", AttributeArgSchema(ConstantValue::Kind::kUint64)) |
| .AddArg("usize64", AttributeArgSchema(ConstantValue::Kind::kZxUsize64)) |
| .AddArg("uintptr64", AttributeArgSchema(ConstantValue::Kind::kZxUintptr64)) |
| .AddArg("uchar", AttributeArgSchema(ConstantValue::Kind::kZxUchar)) |
| .AddArg("float32", AttributeArgSchema(ConstantValue::Kind::kFloat32)) |
| .AddArg("float64", AttributeArgSchema(ConstantValue::Kind::kFloat64)); |
| |
| // For the use of usize64, uintptr64, and uchar. |
| library.EnableFlag(ExperimentalFlag::kZxCTypes); |
| |
| ASSERT_COMPILED(library); |
| |
| auto example_struct = library.LookupStruct("MyStruct"); |
| ASSERT_NE(example_struct, nullptr); |
| EXPECT_TRUE(example_struct->attributes->Get("attr")); |
| |
| // Check `string` arg. |
| EXPECT_TRUE(example_struct->attributes->Get("attr")->GetArg("string")); |
| const auto& string_val = example_struct->attributes->Get("attr")->GetArg("string")->value; |
| EXPECT_EQ(string_val->span.data(), "string"); |
| ASSERT_EQ(string_val->kind, Constant::Kind::kIdentifier); |
| |
| std::unique_ptr<ConstantValue> resolved_string; |
| EXPECT_TRUE(string_val->Value().Convert(ConstantValue::Kind::kString, &resolved_string)); |
| EXPECT_EQ(static_cast<StringConstantValue*>(resolved_string.get())->MakeContents(), "foo"); |
| |
| // Check `bool` arg. |
| EXPECT_TRUE(example_struct->attributes->Get("attr")->GetArg("bool")); |
| const auto& bool_val = example_struct->attributes->Get("attr")->GetArg("bool")->value; |
| EXPECT_EQ(bool_val->span.data(), "bool"); |
| ASSERT_EQ(bool_val->kind, Constant::Kind::kIdentifier); |
| |
| std::unique_ptr<ConstantValue> resolved_bool; |
| EXPECT_TRUE(bool_val->Value().Convert(ConstantValue::Kind::kBool, &resolved_bool)); |
| EXPECT_EQ(static_cast<BoolConstantValue*>(resolved_bool.get())->value, true); |
| |
| // Check `int8` arg. |
| EXPECT_TRUE(example_struct->attributes->Get("attr")->GetArg("int8")); |
| const auto& int8_val = example_struct->attributes->Get("attr")->GetArg("int8")->value; |
| EXPECT_EQ(int8_val->span.data(), "int8"); |
| ASSERT_EQ(int8_val->kind, Constant::Kind::kIdentifier); |
| |
| std::unique_ptr<ConstantValue> resolved_int8; |
| EXPECT_TRUE(int8_val->Value().Convert(ConstantValue::Kind::kInt8, &resolved_int8)); |
| EXPECT_EQ(static_cast<NumericConstantValue<int8_t>*>(resolved_int8.get())->value, -1); |
| |
| // Check `int16` arg. |
| EXPECT_TRUE(example_struct->attributes->Get("attr")->GetArg("int16")); |
| const auto& int16_val = example_struct->attributes->Get("attr")->GetArg("int16")->value; |
| EXPECT_EQ(int16_val->span.data(), "int16"); |
| ASSERT_EQ(int16_val->kind, Constant::Kind::kIdentifier); |
| |
| std::unique_ptr<ConstantValue> resolved_int16; |
| EXPECT_TRUE(int16_val->Value().Convert(ConstantValue::Kind::kInt16, &resolved_int16)); |
| EXPECT_EQ(static_cast<NumericConstantValue<int16_t>*>(resolved_int16.get())->value, -2); |
| |
| // Check `int32` arg. |
| EXPECT_TRUE(example_struct->attributes->Get("attr")->GetArg("int32")); |
| const auto& int32_val = example_struct->attributes->Get("attr")->GetArg("int32")->value; |
| EXPECT_EQ(int32_val->span.data(), "int32"); |
| ASSERT_EQ(int32_val->kind, Constant::Kind::kIdentifier); |
| |
| std::unique_ptr<ConstantValue> resolved_int32; |
| EXPECT_TRUE(int32_val->Value().Convert(ConstantValue::Kind::kInt32, &resolved_int32)); |
| EXPECT_EQ(static_cast<NumericConstantValue<int32_t>*>(resolved_int32.get())->value, -3); |
| |
| // Check `int64` arg. |
| EXPECT_TRUE(example_struct->attributes->Get("attr")->GetArg("int64")); |
| const auto& int64_val = example_struct->attributes->Get("attr")->GetArg("int64")->value; |
| EXPECT_EQ(int64_val->span.data(), "int64.MEMBER"); |
| ASSERT_EQ(int64_val->kind, Constant::Kind::kIdentifier); |
| |
| std::unique_ptr<ConstantValue> resolved_int64; |
| EXPECT_TRUE(int64_val->Value().Convert(ConstantValue::Kind::kInt64, &resolved_int64)); |
| EXPECT_EQ(static_cast<NumericConstantValue<int64_t>*>(resolved_int64.get())->value, -4); |
| |
| // Check `uint8` arg. |
| EXPECT_TRUE(example_struct->attributes->Get("attr")->GetArg("uint8")); |
| const auto& uint8_val = example_struct->attributes->Get("attr")->GetArg("uint8")->value; |
| EXPECT_EQ(uint8_val->span.data(), "uint8"); |
| ASSERT_EQ(uint8_val->kind, Constant::Kind::kIdentifier); |
| |
| std::unique_ptr<ConstantValue> resolved_uint8; |
| EXPECT_TRUE(uint8_val->Value().Convert(ConstantValue::Kind::kUint8, &resolved_uint8)); |
| EXPECT_EQ(static_cast<NumericConstantValue<uint8_t>*>(resolved_uint8.get())->value, 1u); |
| |
| // Check `uint16` arg. |
| EXPECT_TRUE(example_struct->attributes->Get("attr")->GetArg("uint16")); |
| const auto& uint16_val = example_struct->attributes->Get("attr")->GetArg("uint16")->value; |
| EXPECT_EQ(uint16_val->span.data(), "uint16"); |
| ASSERT_EQ(uint16_val->kind, Constant::Kind::kIdentifier); |
| |
| std::unique_ptr<ConstantValue> resolved_uint16; |
| EXPECT_TRUE(uint16_val->Value().Convert(ConstantValue::Kind::kUint16, &resolved_uint16)); |
| EXPECT_EQ(static_cast<NumericConstantValue<uint16_t>*>(resolved_uint16.get())->value, 2u); |
| |
| // Check `uint32` arg. |
| EXPECT_TRUE(example_struct->attributes->Get("attr")->GetArg("uint32")); |
| const auto& uint32_val = example_struct->attributes->Get("attr")->GetArg("uint32")->value; |
| EXPECT_EQ(uint32_val->span.data(), "uint32"); |
| ASSERT_EQ(uint32_val->kind, Constant::Kind::kIdentifier); |
| |
| std::unique_ptr<ConstantValue> resolved_uint32; |
| EXPECT_TRUE(uint32_val->Value().Convert(ConstantValue::Kind::kUint32, &resolved_uint32)); |
| EXPECT_EQ(static_cast<NumericConstantValue<uint32_t>*>(resolved_uint32.get())->value, 3u); |
| |
| // Check `uint64` arg. |
| EXPECT_TRUE(example_struct->attributes->Get("attr")->GetArg("uint64")); |
| const auto& uint64_val = example_struct->attributes->Get("attr")->GetArg("uint64")->value; |
| EXPECT_EQ(uint64_val->span.data(), "uint64.MEMBER"); |
| ASSERT_EQ(uint64_val->kind, Constant::Kind::kIdentifier); |
| |
| std::unique_ptr<ConstantValue> resolved_uint64; |
| EXPECT_TRUE(uint64_val->Value().Convert(ConstantValue::Kind::kUint64, &resolved_uint64)); |
| EXPECT_EQ(static_cast<NumericConstantValue<uint64_t>*>(resolved_uint64.get())->value, 4u); |
| |
| // Check `usize64` arg. |
| EXPECT_TRUE(example_struct->attributes->Get("attr")->GetArg("usize64")); |
| const auto& usize_val = example_struct->attributes->Get("attr")->GetArg("usize64")->value; |
| EXPECT_EQ(usize_val->span.data(), "usize64"); |
| ASSERT_EQ(usize_val->kind, Constant::Kind::kIdentifier); |
| |
| std::unique_ptr<ConstantValue> resolved_usize; |
| EXPECT_TRUE(usize_val->Value().Convert(ConstantValue::Kind::kZxUsize64, &resolved_usize)); |
| EXPECT_EQ(static_cast<NumericConstantValue<uint64_t>*>(resolved_usize.get())->value, 5u); |
| |
| // Check `uintptr64` arg. |
| EXPECT_TRUE(example_struct->attributes->Get("attr")->GetArg("uintptr64")); |
| const auto& uintptr_val = example_struct->attributes->Get("attr")->GetArg("uintptr64")->value; |
| EXPECT_EQ(uintptr_val->span.data(), "uintptr64"); |
| ASSERT_EQ(uintptr_val->kind, Constant::Kind::kIdentifier); |
| |
| std::unique_ptr<ConstantValue> resolved_uintptr; |
| EXPECT_TRUE(uintptr_val->Value().Convert(ConstantValue::Kind::kZxUintptr64, &resolved_uintptr)); |
| EXPECT_EQ(static_cast<NumericConstantValue<uint64_t>*>(resolved_uintptr.get())->value, 6u); |
| |
| // Check `uchar` arg. |
| EXPECT_TRUE(example_struct->attributes->Get("attr")->GetArg("uchar")); |
| const auto& uchar_val = example_struct->attributes->Get("attr")->GetArg("uchar")->value; |
| EXPECT_EQ(uchar_val->span.data(), "uchar"); |
| ASSERT_EQ(uchar_val->kind, Constant::Kind::kIdentifier); |
| |
| std::unique_ptr<ConstantValue> resolved_uchar; |
| EXPECT_TRUE(uchar_val->Value().Convert(ConstantValue::Kind::kZxUchar, &resolved_uchar)); |
| EXPECT_EQ(static_cast<NumericConstantValue<uint8_t>*>(resolved_uchar.get())->value, 7u); |
| |
| // Check `float32` arg. |
| EXPECT_TRUE(example_struct->attributes->Get("attr")->GetArg("float32")); |
| const auto& float32_val = example_struct->attributes->Get("attr")->GetArg("float32")->value; |
| EXPECT_EQ(float32_val->span.data(), "float32"); |
| ASSERT_EQ(float32_val->kind, Constant::Kind::kIdentifier); |
| |
| std::unique_ptr<ConstantValue> resolved_float32; |
| EXPECT_TRUE(float32_val->Value().Convert(ConstantValue::Kind::kFloat32, &resolved_float32)); |
| EXPECT_TRUE(static_cast<NumericConstantValue<float>*>(resolved_float32.get())->value > 1.1); |
| EXPECT_TRUE(static_cast<NumericConstantValue<float>*>(resolved_float32.get())->value < 1.3); |
| |
| // Check `float64` arg. |
| EXPECT_TRUE(example_struct->attributes->Get("attr")->GetArg("float64")); |
| const auto& float64_val = example_struct->attributes->Get("attr")->GetArg("float64")->value; |
| EXPECT_EQ(float64_val->span.data(), "float64"); |
| ASSERT_EQ(float64_val->kind, Constant::Kind::kIdentifier); |
| |
| std::unique_ptr<ConstantValue> resolved_float64; |
| EXPECT_TRUE(float64_val->Value().Convert(ConstantValue::Kind::kFloat64, &resolved_float64)); |
| EXPECT_TRUE(static_cast<NumericConstantValue<double>*>(resolved_float64.get())->value > -3.5); |
| EXPECT_TRUE(static_cast<NumericConstantValue<double>*>(resolved_float64.get())->value < -3.3); |
| } |
| |
| TEST(AttributesTests, BadInvalidReferencedStringTypeWithSchema) { |
| TestLibrary library(R"FIDL( |
| library example; |
| |
| const foo bool = true; |
| |
| @attr(foo) |
| type MyStruct = struct {}; |
| )FIDL"); |
| library.AddAttributeSchema("attr").AddArg("string", |
| AttributeArgSchema(ConstantValue::Kind::kString)); |
| library.ExpectFail(ErrTypeCannotBeConvertedToType, "example/foo", "bool", "string"); |
| library.ExpectFail(ErrCouldNotResolveAttributeArg); |
| ASSERT_COMPILER_DIAGNOSTICS(library); |
| } |
| |
| TEST(AttributesTests, BadInvalidReferencedBoolTypeWithSchema) { |
| TestLibrary library(R"FIDL( |
| library example; |
| |
| const foo string:3 = "foo"; |
| |
| @attr(foo) |
| type MyStruct = struct {}; |
| )FIDL"); |
| library.AddAttributeSchema("attr").AddArg("bool", AttributeArgSchema(ConstantValue::Kind::kBool)); |
| library.ExpectFail(ErrTypeCannotBeConvertedToType, "example/foo", "string:3", "bool"); |
| library.ExpectFail(ErrCouldNotResolveAttributeArg); |
| ASSERT_COMPILER_DIAGNOSTICS(library); |
| } |
| |
| TEST(AttributesTests, BadInvalidReferencedNumericTypeWithSchema) { |
| TestLibrary library(R"FIDL( |
| library example; |
| |
| const foo uint16 = 259; |
| |
| @attr(foo) |
| type MyStruct = struct {}; |
| )FIDL"); |
| library.AddAttributeSchema("attr").AddArg("int8", AttributeArgSchema(ConstantValue::Kind::kInt8)); |
| library.ExpectFail(ErrTypeCannotBeConvertedToType, "example/foo", "uint16", "int8"); |
| library.ExpectFail(ErrCouldNotResolveAttributeArg); |
| ASSERT_COMPILER_DIAGNOSTICS(library); |
| } |
| |
| TEST(AttributesTests, GoodCompileEarlyAttributeLiteralArgument) { |
| TestLibrary library(R"FIDL( |
| library example; |
| |
| @attr(1) |
| type MyStruct = struct {}; |
| )FIDL"); |
| library.AddAttributeSchema("attr") |
| .AddArg("int8", AttributeArgSchema(ConstantValue::Kind::kUint8)) |
| .CompileEarly(); |
| ASSERT_COMPILED(library); |
| } |
| |
| TEST(AttributesTests, BadCompileEarlyAttributeReferencedArgument) { |
| TestLibrary library(R"FIDL( |
| library example; |
| |
| @attr(BAD) |
| type MyStruct = struct {}; |
| |
| const BAD uint8 = 1; |
| )FIDL"); |
| library.AddAttributeSchema("attr") |
| .AddArg("int8", AttributeArgSchema(ConstantValue::Kind::kUint8)) |
| .CompileEarly(); |
| library.ExpectFail(ErrAttributeArgRequiresLiteral, "int8", "attr"); |
| ASSERT_COMPILER_DIAGNOSTICS(library); |
| } |
| |
| TEST(AttributesTests, GoodAnonymousArgumentGetsNamedValue) { |
| TestLibrary library(R"FIDL( |
| library example; |
| |
| @attr("abc") |
| type MyStruct = struct {}; |
| )FIDL"); |
| ASSERT_COMPILED(library); |
| |
| auto example_struct = library.LookupStruct("MyStruct"); |
| ASSERT_NE(example_struct, nullptr); |
| ASSERT_EQ(example_struct->attributes->attributes.size(), 1u); |
| ASSERT_EQ(example_struct->attributes->attributes[0]->args.size(), 1u); |
| EXPECT_EQ(example_struct->attributes->attributes[0]->args[0]->name.value().data(), "value"); |
| } |
| |
| TEST(AttributesTests, GoodSingleNamedArgumentKeepsName) { |
| TestLibrary library(R"FIDL( |
| library example; |
| |
| @attr(foo="abc") |
| type MyStruct = struct {}; |
| )FIDL"); |
| ASSERT_COMPILED(library); |
| |
| auto example_struct = library.LookupStruct("MyStruct"); |
| ASSERT_NE(example_struct, nullptr); |
| ASSERT_EQ(example_struct->attributes->attributes.size(), 1u); |
| ASSERT_EQ(example_struct->attributes->attributes[0]->args.size(), 1u); |
| EXPECT_EQ(example_struct->attributes->attributes[0]->args[0]->name.value().data(), "foo"); |
| } |
| |
| TEST(AttributesTests, BadReferencesNonexistentConstWithoutSchema) { |
| TestLibrary library(R"FIDL( |
| library example; |
| |
| @foo(nonexistent) |
| type MyStruct = struct {}; |
| )FIDL"); |
| library.ExpectFail(ErrNameNotFound, "nonexistent", "example"); |
| ASSERT_COMPILER_DIAGNOSTICS(library); |
| } |
| |
| TEST(AttributesTests, BadReferencesNonexistentConstWithSingleArgSchema) { |
| TestLibrary library(R"FIDL( |
| library example; |
| |
| @foo(nonexistent) |
| type MyStruct = struct {}; |
| )FIDL"); |
| library.AddAttributeSchema("foo").AddArg("value", AttributeArgSchema(ConstantValue::Kind::kBool)); |
| library.ExpectFail(ErrNameNotFound, "nonexistent", "example"); |
| ASSERT_COMPILER_DIAGNOSTICS(library); |
| } |
| |
| TEST(AttributesTests, BadReferencesNonexistentConstWithMultipleArgSchema) { |
| TestLibrary library(R"FIDL( |
| library example; |
| |
| @foo(nonexistent) |
| type MyStruct = struct {}; |
| )FIDL"); |
| library.AddAttributeSchema("foo") |
| .AddArg("first", AttributeArgSchema(ConstantValue::Kind::kBool)) |
| .AddArg("second", AttributeArgSchema(ConstantValue::Kind::kBool)); |
| library.ExpectFail(ErrNameNotFound, "nonexistent", "example"); |
| ASSERT_COMPILER_DIAGNOSTICS(library); |
| } |
| |
| TEST(AttributesTests, BadReferencesInvalidConstWithoutSchema) { |
| TestLibrary library(R"FIDL( |
| library example; |
| |
| @foo(BAD) |
| type MyStruct = struct {}; |
| |
| const BAD bool = "not a bool"; |
| )FIDL"); |
| library.ExpectFail(ErrCouldNotResolveAttributeArg); |
| library.ExpectFail(ErrCannotResolveConstantValue); |
| library.ExpectFail(ErrTypeCannotBeConvertedToType, "\"not a bool\"", "string:10", "bool"); |
| ASSERT_COMPILER_DIAGNOSTICS(library); |
| } |
| |
| TEST(AttributesTests, BadReferencesInvalidConstWithSingleArgSchema) { |
| TestLibrary library(R"FIDL( |
| library example; |
| |
| @foo(BAD) |
| type MyStruct = struct {}; |
| |
| const BAD bool = "not a bool"; |
| )FIDL"); |
| library.AddAttributeSchema("foo").AddArg("value", AttributeArgSchema(ConstantValue::Kind::kBool)); |
| library.ExpectFail(ErrCouldNotResolveAttributeArg); |
| library.ExpectFail(ErrCannotResolveConstantValue); |
| library.ExpectFail(ErrTypeCannotBeConvertedToType, "\"not a bool\"", "string:10", "bool"); |
| ASSERT_COMPILER_DIAGNOSTICS(library); |
| } |
| |
| TEST(AttributesTests, BadReferencesInvalidConstWithMultipleArgSchema) { |
| TestLibrary library(R"FIDL( |
| library example; |
| |
| @foo(BAD) |
| type MyStruct = struct {}; |
| |
| const BAD bool = "not a bool"; |
| )FIDL"); |
| library.AddAttributeSchema("foo") |
| .AddArg("first", AttributeArgSchema(ConstantValue::Kind::kBool)) |
| .AddArg("second", AttributeArgSchema(ConstantValue::Kind::kBool)); |
| library.ExpectFail(ErrAttributeArgNotNamed, "BAD"); |
| library.ExpectFail(ErrCannotResolveConstantValue); |
| library.ExpectFail(ErrTypeCannotBeConvertedToType, "\"not a bool\"", "string:10", "bool"); |
| ASSERT_COMPILER_DIAGNOSTICS(library); |
| } |
| |
| TEST(AttributesTests, BadSelfReferenceWithoutSchemaBool) { |
| TestLibrary library(R"FIDL( |
| library example; |
| |
| @foo(BAR) |
| const BAR bool = true; |
| )FIDL"); |
| library.ExpectFail(ErrCouldNotResolveAttributeArg); |
| library.ExpectFail(ErrIncludeCycle, "const 'BAR' -> const 'BAR'"); |
| ASSERT_COMPILER_DIAGNOSTICS(library); |
| } |
| |
| TEST(AttributesTests, BadSelfReferenceWithoutSchemaString) { |
| TestLibrary library(R"FIDL( |
| library example; |
| |
| @foo(BAR) |
| const BAR string = "bar"; |
| )FIDL"); |
| library.ExpectFail(ErrCouldNotResolveAttributeArg); |
| library.ExpectFail(ErrIncludeCycle, "const 'BAR' -> const 'BAR'"); |
| ASSERT_COMPILER_DIAGNOSTICS(library); |
| } |
| |
| TEST(AttributesTests, BadSelfReferenceWithSchema) { |
| TestLibrary library(R"FIDL( |
| library example; |
| |
| @foo(BAR) |
| const BAR bool = true; |
| )FIDL"); |
| library.AddAttributeSchema("foo").AddArg("value", AttributeArgSchema(ConstantValue::Kind::kBool)); |
| library.ExpectFail(ErrCouldNotResolveAttributeArg); |
| library.ExpectFail(ErrIncludeCycle, "const 'BAR' -> const 'BAR'"); |
| ASSERT_COMPILER_DIAGNOSTICS(library); |
| } |
| |
| TEST(AttributesTests, BadMutualReferenceWithoutSchemaBool) { |
| TestLibrary library(R"FIDL( |
| library example; |
| |
| @foo(SECOND) |
| const FIRST bool = true; |
| @foo(FIRST) |
| const SECOND bool = false; |
| )FIDL"); |
| library.ExpectFail(ErrIncludeCycle, "const 'FIRST' -> const 'SECOND' -> const 'FIRST'"); |
| library.ExpectFail(ErrCouldNotResolveAttributeArg); |
| ASSERT_COMPILER_DIAGNOSTICS(library); |
| } |
| |
| TEST(AttributesTests, BadMutualReferenceWithoutSchemaString) { |
| TestLibrary library(R"FIDL( |
| library example; |
| |
| @foo(SECOND) |
| const FIRST string = "first"; |
| @foo(FIRST) |
| const SECOND string = "second"; |
| )FIDL"); |
| library.ExpectFail(ErrIncludeCycle, "const 'FIRST' -> const 'SECOND' -> const 'FIRST'"); |
| library.ExpectFail(ErrCouldNotResolveAttributeArg); |
| ASSERT_COMPILER_DIAGNOSTICS(library); |
| } |
| |
| TEST(AttributesTests, BadMutualReferenceWithSchema) { |
| TestLibrary library(R"FIDL( |
| library example; |
| |
| @foo(SECOND) |
| const FIRST bool = true; |
| @foo(FIRST) |
| const SECOND bool = false; |
| )FIDL"); |
| library.AddAttributeSchema("foo").AddArg("value", AttributeArgSchema(ConstantValue::Kind::kBool)); |
| library.ExpectFail(ErrIncludeCycle, "const 'FIRST' -> const 'SECOND' -> const 'FIRST'"); |
| library.ExpectFail(ErrCouldNotResolveAttributeArg); |
| ASSERT_COMPILER_DIAGNOSTICS(library); |
| } |
| |
| TEST(AttributesTests, BadLibraryReferencesNonexistentConst) { |
| TestLibrary library(R"FIDL( |
| @foo(nonexistent) |
| library example; |
| )FIDL"); |
| library.ExpectFail(ErrNameNotFound, "nonexistent", "example"); |
| ASSERT_COMPILER_DIAGNOSTICS(library); |
| } |
| |
| TEST(AttributesTests, BadLibraryReferencesConst) { |
| TestLibrary library(R"FIDL( |
| @foo(BAR) |
| library example; |
| |
| const BAR bool = true; |
| )FIDL"); |
| library.ExpectFail(ErrReferenceInLibraryAttribute); |
| ASSERT_COMPILER_DIAGNOSTICS(library); |
| } |
| |
| TEST(AttributesTests, BadLibraryReferencesExternalConst) { |
| SharedAmongstLibraries shared; |
| TestLibrary dependency(&shared, "dependency.fidl", R"FIDL( |
| library dependency; |
| |
| const BAR bool = true; |
| )FIDL"); |
| ASSERT_COMPILED(dependency); |
| |
| TestLibrary library(&shared, "example.fidl", R"FIDL( |
| @foo(dependency.BAR) |
| library example; |
| |
| using dependency; |
| )FIDL"); |
| library.ExpectFail(ErrReferenceInLibraryAttribute); |
| ASSERT_COMPILER_DIAGNOSTICS(library); |
| } |
| |
| TEST(AttributesTests, GoodDiscoverableImplicitName) { |
| TestLibrary library(R"FIDL( |
| library example; |
| |
| @discoverable |
| protocol Foo {}; |
| )FIDL"); |
| ASSERT_COMPILED(library); |
| } |
| |
| TEST(AttributesTests, GoodDiscoverableExplicitName) { |
| for (auto name : {"example.Foo", "notexample.NotFoo", "not.example.NotFoo"}) { |
| std::string library_str = R"FIDL( |
| library example; |
| |
| @discoverable("%1") |
| protocol Foo {}; |
| )FIDL"; |
| library_str.replace(library_str.find("%1"), 2, name); |
| TestLibrary library(library_str); |
| ASSERT_COMPILED(library); |
| } |
| } |
| |
| TEST(AttributesTests, BadDiscoverableInvalidName) { |
| for (auto name : {"", "example/Foo", "Foo", "not example.Not Foo"}) { |
| std::string library_str = R"FIDL( |
| library example; |
| |
| @discoverable("%1") |
| protocol Foo {}; |
| )FIDL"; |
| library_str.replace(library_str.find("%1"), 2, name); |
| TestLibrary library(library_str); |
| library.ExpectFail(ErrInvalidDiscoverableName, name); |
| ASSERT_COMPILER_DIAGNOSTICS(library); |
| } |
| } |
| |
| TEST(AttributesTests, BadDiscoverableInvalidNameErrcat) { |
| TestLibrary library; |
| library.AddFile("bad/fi-0135.test.fidl"); |
| library.ExpectFail(ErrInvalidDiscoverableName, "test.bad.fi0135/Parser"); |
| ASSERT_COMPILER_DIAGNOSTICS(library); |
| } |
| |
| // The @result attribute was originally used to implement method error results. |
| // It no longer does anything. This test just makes sure it doesn't cause a crash. |
| TEST(AttributesTests, GoodResultAttribute) { |
| TestLibrary library(R"FIDL( |
| library example; |
| |
| @result |
| type Foo = union { |
| 1: s string; |
| }; |
| )FIDL"); |
| ASSERT_COMPILED(library); |
| } |
| |
| } // namespace |
| } // namespace fidlc |