blob: ae43eaacbf3c117e100525caefa630d7962d9705 [file] [log] [blame]
// Copyright 2018 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <fidl/diagnostics.h>
#include <fidl/flat/attribute_schema.h>
#include <fidl/flat_ast.h>
#include <fidl/lexer.h>
#include <fidl/parser.h>
#include <fidl/reporter.h>
#include <fidl/source_file.h>
#include <zxtest/zxtest.h>
#include "error_test.h"
#include "test_library.h"
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_reserved_member
2: reserved;
};
@on_type_alias
alias ExampleTypeAlias = uint32;
@on_union
type ExampleUnion = union {
@on_union_member
1: variant uint32;
@on_reserved_member
2: reserved;
};
)FIDL");
ASSERT_COMPILED(library);
EXPECT_TRUE(library.attributes()->Get("on_library"));
auto example_bits = library.LookupBits("ExampleBits");
ASSERT_NOT_NULL(example_bits);
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_NOT_NULL(example_const);
EXPECT_TRUE(example_const->attributes->Get("on_const"));
auto example_enum = library.LookupEnum("ExampleEnum");
ASSERT_NOT_NULL(example_enum);
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_NOT_NULL(example_child_protocol);
EXPECT_TRUE(example_child_protocol->attributes->Get("on_protocol"));
EXPECT_TRUE(example_child_protocol->methods.front().attributes->Get("on_method"));
ASSERT_NOT_NULL(example_child_protocol->methods.front().maybe_request.get());
auto id = static_cast<const fidl::flat::IdentifierType*>(
example_child_protocol->methods.front().maybe_request->type);
auto as_struct = static_cast<const fidl::flat::Struct*>(id->type_decl);
EXPECT_TRUE(as_struct->members.front().attributes->Get("on_parameter"));
auto example_parent_protocol = library.LookupProtocol("ExampleParentProtocol");
ASSERT_NOT_NULL(example_parent_protocol);
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_NOT_NULL(example_service);
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_NOT_NULL(example_struct);
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_NOT_NULL(example_table);
EXPECT_TRUE(example_table->attributes->Get("on_table"));
EXPECT_TRUE(example_table->members.front().attributes->Get("on_table_member"));
EXPECT_TRUE(example_table->members.back().attributes->Get("on_reserved_member"));
auto example_type_alias = library.LookupTypeAlias("ExampleTypeAlias");
ASSERT_NOT_NULL(example_type_alias);
EXPECT_TRUE(example_type_alias->attributes->Get("on_type_alias"));
auto example_union = library.LookupUnion("ExampleUnion");
ASSERT_NOT_NULL(example_union);
EXPECT_TRUE(example_union->attributes->Get("on_union"));
EXPECT_TRUE(example_union->members.front().attributes->Get("on_union_member"));
EXPECT_TRUE(example_union->members.back().attributes->Get("on_reserved_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
@for_deprecated_c_bindings
@transport("Syscall")
protocol ExampleProtocol {
/// For ExampleMethod
@internal
@selector("Bar")
@transitional
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_NOT_NULL(example_const);
EXPECT_TRUE(example_const->attributes->Get("no_doc"));
EXPECT_TRUE(example_const->attributes->Get("doc")->GetArg("value"));
auto& const_doc_value = static_cast<const fidl::flat::DocCommentConstantValue&>(
example_const->attributes->Get("doc")->GetArg("value")->value->Value());
EXPECT_STREQ(const_doc_value.MakeContents(), " For EXAMPLE_CONSTANT\n");
EXPECT_TRUE(example_const->attributes->Get("deprecated")->GetArg("value"));
auto& const_str_value = static_cast<const fidl::flat::StringConstantValue&>(
example_const->attributes->Get("deprecated")->GetArg("value")->value->Value());
EXPECT_STREQ(const_str_value.MakeContents(), "Note");
auto example_enum = library.LookupEnum("ExampleEnum");
ASSERT_NOT_NULL(example_enum);
EXPECT_TRUE(example_enum->attributes->Get("doc")->GetArg("value"));
auto& enum_doc_value = static_cast<const fidl::flat::DocCommentConstantValue&>(
example_enum->attributes->Get("doc")->GetArg("value")->value->Value());
EXPECT_STREQ(enum_doc_value.MakeContents(), " For ExampleEnum\n");
EXPECT_TRUE(example_enum->attributes->Get("deprecated")->GetArg("value"));
auto& enum_str_value = static_cast<const fidl::flat::StringConstantValue&>(
example_enum->attributes->Get("deprecated")->GetArg("value")->value->Value());
EXPECT_STREQ(enum_str_value.MakeContents(), "Reason");
EXPECT_TRUE(example_enum->members.back().attributes->Get("unknown"));
auto example_struct = library.LookupStruct("ExampleStruct");
ASSERT_NOT_NULL(example_struct);
EXPECT_TRUE(example_struct->attributes->Get("doc")->GetArg("value"));
auto& struct_doc_value = static_cast<const fidl::flat::DocCommentConstantValue&>(
example_struct->attributes->Get("doc")->GetArg("value")->value->Value());
EXPECT_STREQ(struct_doc_value.MakeContents(), " For ExampleStruct\n");
EXPECT_TRUE(example_struct->attributes->Get("max_bytes")->GetArg("value"));
auto& struct_str_value1 = static_cast<const fidl::flat::StringConstantValue&>(
example_struct->attributes->Get("max_bytes")->GetArg("value")->value->Value());
EXPECT_STREQ(struct_str_value1.MakeContents(), "1234");
EXPECT_TRUE(example_struct->attributes->Get("max_handles")->GetArg("value"));
auto& struct_str_value2 = static_cast<const fidl::flat::StringConstantValue&>(
example_struct->attributes->Get("max_handles")->GetArg("value")->value->Value());
EXPECT_STREQ(struct_str_value2.MakeContents(), "5678");
auto example_anon = library.LookupTable("CustomName");
ASSERT_NOT_NULL(example_anon);
EXPECT_TRUE(example_anon->attributes->Get("generated_name"));
auto& generated_name_value = static_cast<const fidl::flat::StringConstantValue&>(
example_anon->attributes->Get("generated_name")->GetArg("value")->value->Value());
EXPECT_STREQ(generated_name_value.MakeContents(), "CustomName");
auto example_protocol = library.LookupProtocol("ExampleProtocol");
ASSERT_NOT_NULL(example_protocol);
EXPECT_TRUE(example_protocol->attributes->Get("discoverable"));
EXPECT_TRUE(example_protocol->attributes->Get("for_deprecated_c_bindings"));
EXPECT_TRUE(example_protocol->attributes->Get("doc")->GetArg("value"));
auto& protocol_doc_value = static_cast<const fidl::flat::DocCommentConstantValue&>(
example_protocol->attributes->Get("doc")->GetArg("value")->value->Value());
EXPECT_STREQ(protocol_doc_value.MakeContents(), " For ExampleProtocol\n");
EXPECT_TRUE(example_protocol->attributes->Get("transport")->GetArg("value"));
auto& protocol_str_value = static_cast<const fidl::flat::StringConstantValue&>(
example_protocol->attributes->Get("transport")->GetArg("value")->value->Value());
EXPECT_STREQ(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("transitional"));
EXPECT_TRUE(example_method.attributes->Get("doc")->GetArg("value"));
auto& method_doc_value = static_cast<const fidl::flat::DocCommentConstantValue&>(
example_method.attributes->Get("doc")->GetArg("value")->value->Value());
EXPECT_STREQ(method_doc_value.MakeContents(), " For ExampleMethod\n");
EXPECT_TRUE(example_method.attributes->Get("selector")->GetArg("value"));
auto& method_str_value = static_cast<const fidl::flat::StringConstantValue&>(
example_method.attributes->Get("selector")->GetArg("value")->value->Value());
EXPECT_STREQ(method_str_value.MakeContents(), "Bar");
auto example_service = library.LookupService("ExampleService");
ASSERT_NOT_NULL(example_service);
EXPECT_TRUE(example_service->attributes->Get("no_doc"));
EXPECT_TRUE(example_service->attributes->Get("doc")->GetArg("value"));
auto& service_doc_value = static_cast<const fidl::flat::DocCommentConstantValue&>(
example_service->attributes->Get("doc")->GetArg("value")->value->Value());
EXPECT_STREQ(service_doc_value.MakeContents(), " For ExampleService\n");
EXPECT_TRUE(example_service->attributes->Get("foo")->GetArg("value"));
auto& service_str_value = static_cast<const fidl::flat::StringConstantValue&>(
example_service->attributes->Get("foo")->GetArg("value")->value->Value());
EXPECT_STREQ(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 fidl::flat::DocCommentConstantValue&>(
example_service_member.attributes->Get("doc")->GetArg("value")->value->Value());
EXPECT_STREQ(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 fidl::flat::StringConstantValue&>(
example_service_member.attributes->Get("foo")->GetArg("value")->value->Value());
EXPECT_STREQ(service_member_str_value.MakeContents(), "ExampleProtocol");
}
TEST(AttributesTests, BadNoAttributeOnUsingNotEventDoc) {
TestLibrary library(R"FIDL(
library example;
/// nope
@no_attribute_on_using
@even_doc
using we.should.not.care;
)FIDL");
ASSERT_ERRORED_DURING_COMPILE(library, fidl::ErrAttributesNotAllowedOnLibraryImport);
ASSERT_SUBSTR(library.errors()[0]->msg.c_str(), "doc");
ASSERT_SUBSTR(library.errors()[0]->msg.c_str(), "no_attribute_on_using");
ASSERT_SUBSTR(library.errors()[0]->msg.c_str(), "even_doc");
}
// 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");
ASSERT_ERRORED_DURING_COMPILE(library, fidl::ErrDuplicateAttribute);
ASSERT_SUBSTR(library.errors()[0]->msg.c_str(), "dup");
}
// Test that attributes with the same canonical form are considered duplicates.
TEST(AttributesTests, BadNoTwoSameAttributeCanonical) {
TestLibrary library(R"FIDL(
library fidl.test.dupattributes;
@TheSame("first")
@The_same("second")
protocol A {
MethodA();
};
)FIDL");
ASSERT_ERRORED_DURING_COMPILE(library, fidl::ErrDuplicateAttributeCanonical);
ASSERT_SUBSTR(library.errors()[0]->msg.c_str(), "canonical form 'the_same'");
}
// 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");
ASSERT_ERRORED_DURING_COMPILE(library, fidl::ErrDuplicateAttribute);
ASSERT_SUBSTR(library.errors()[0]->msg.c_str(), "doc");
}
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");
ASSERT_ERRORED_DURING_COMPILE(library, fidl::ErrDuplicateAttribute);
ASSERT_SUBSTR(library.errors()[0]->msg.c_str(), "dup");
}
// Test that a close attribute is caught.
TEST(AttributesTests, WarnOnCloseAttribute) {
TestLibrary library(R"FIDL(
library fidl.test;
@duc("should be doc")
protocol A {
MethodA();
};
)FIDL");
ASSERT_WARNED_DURING_COMPILE(library, fidl::WarnAttributeTypo);
EXPECT_SUBSTR(library.warnings()[0]->msg.c_str(), "duc");
EXPECT_SUBSTR(library.warnings()[0]->msg.c_str(), "doc");
}
// 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(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");
ASSERT_FALSE(library.Compile());
ASSERT_EQ(library.errors().size(), 1);
EXPECT_ERR(library.errors()[0], fidl::ErrNameOverlap);
ASSERT_EQ(library.warnings().size(), 1);
ASSERT_ERR(library.warnings()[0], fidl::WarnAttributeTypo);
EXPECT_SUBSTR(library.warnings()[0]->msg.c_str(), "availabe");
EXPECT_SUBSTR(library.warnings()[0]->msg.c_str(), "available");
}
// 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_ERRORED_DURING_COMPILE(library, fidl::WarnAttributeTypo);
ASSERT_SUBSTR(library.errors()[0]->msg.c_str(), "duc");
ASSERT_SUBSTR(library.errors()[0]->msg.c_str(), "doc");
}
TEST(AttributesTests, BadEmptyTransport) {
TestLibrary library(R"FIDL(
library fidl.test.transportattributes;
@transport
protocol A {
MethodA();
};
)FIDL");
ASSERT_ERRORED_DURING_COMPILE(library, fidl::ErrMissingRequiredAnonymousAttributeArg);
}
TEST(AttributesTests, BadBogusTransport) {
TestLibrary library(R"FIDL(
library fidl.test.transportattributes;
@transport("Bogus")
protocol A {
MethodA();
};
)FIDL");
ASSERT_ERRORED_DURING_COMPILE(library, fidl::ErrInvalidTransportType);
}
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");
ASSERT_ERRORED_DURING_COMPILE(library, fidl::ErrInvalidTransportType);
}
TEST(AttributesTests, BadTransitionalInvalidPlacement) {
TestLibrary library(R"FIDL(
library fidl.test;
@transitional
protocol MyProtocol {
MyMethod();
};
)FIDL");
ASSERT_ERRORED_DURING_COMPILE(library, fidl::ErrInvalidAttributePlacement);
ASSERT_SUBSTR(library.errors()[0]->msg.c_str(), "transitional");
}
TEST(AttributesTests, BadUnknownInvalidPlacementOnUnion) {
TestLibrary library(R"FIDL(
library fidl.test;
@unknown
type U = flexible union {
1: a int32;
};
)FIDL");
ASSERT_ERRORED_DURING_COMPILE(library, fidl::ErrInvalidAttributePlacement);
ASSERT_SUBSTR(library.errors()[0]->msg.c_str(), "unknown");
}
TEST(AttributesTests, BadUnknownInvalidPlacementOnUnionMember) {
TestLibrary library(R"FIDL(
library fidl.test;
type U = flexible union {
@unknown 1: a int32;
};
)FIDL");
ASSERT_ERRORED_DURING_COMPILE(library, fidl::ErrInvalidAttributePlacement);
ASSERT_SUBSTR(library.errors()[0]->msg.c_str(), "unknown");
}
TEST(AttributesTests, BadUnknownInvalidPlacementOnBitsMember) {
TestLibrary library(R"FIDL(
library fidl.test;
type B = flexible bits : uint32 {
@unknown A = 0x1;
};
)FIDL");
ASSERT_ERRORED_DURING_COMPILE(library, fidl::ErrInvalidAttributePlacement);
ASSERT_SUBSTR(library.errors()[0]->msg.c_str(), "unknown");
}
TEST(AttributesTests, BadUnknownInvalidOnStrictEnumMember) {
TestLibrary library(R"FIDL(
library fidl.test;
type E = strict enum : uint32 {
@unknown A = 1;
};
)FIDL");
ASSERT_ERRORED_DURING_COMPILE(library, fidl::ErrUnknownAttributeOnStrictEnumMember);
ASSERT_SUBSTR(library.errors()[0]->msg.c_str(), "unknown");
}
TEST(AttributesTests, BadTransitionalOnEnum) {
TestLibrary library(R"FIDL(library fidl.test;
@transitional
type E = strict enum : uint32 {
A = 1;
};
)FIDL");
ASSERT_ERRORED_DURING_COMPILE(library, fidl::ErrInvalidAttributePlacement);
ASSERT_SUBSTR(library.errors()[0]->msg.c_str(), "transitional");
}
TEST(AttributesTests, BadIncorrectPlacementLayout) {
TestLibrary library(R"FIDL(
@for_deprecated_c_bindings // 1
library fidl.test;
@for_deprecated_c_bindings // 2
const MyConst int32 = 0;
@for_deprecated_c_bindings // 3
type MyEnum = enum {
@for_deprecated_c_bindings // 4
MyMember = 5;
};
@for_deprecated_c_bindings // no error, this placement is allowed
type MyStruct = struct {
@for_deprecated_c_bindings // 5
MyMember int32;
};
@for_deprecated_c_bindings // 6
type MyUnion = union {
@for_deprecated_c_bindings // 7
1: MyMember int32;
};
@for_deprecated_c_bindings // 8
type MyTable = table {
@for_deprecated_c_bindings // 9
1: MyMember int32;
};
@for_deprecated_c_bindings // no error, this placement is allowed
protocol MyProtocol {
@for_deprecated_c_bindings // 10
MyMethod();
};
)FIDL");
EXPECT_FALSE(library.Compile());
const auto& errors = library.errors();
ASSERT_EQ(errors.size(), 10);
for (const auto& error : errors) {
ASSERT_ERR(error, fidl::ErrInvalidAttributePlacement);
ASSERT_SUBSTR(error->msg.c_str(), "for_deprecated_c_bindings");
}
}
TEST(AttributesTests, BadDeprecatedAttributes) {
TestLibrary library(R"FIDL(
library fidl.test;
@layout("Simple")
type MyStruct = struct {};
@layout("Complex")
protocol MyOtherProtocol {
MyMethod();
};
@layout("Simple")
protocol MyProtocol {
MyMethod();
};
)FIDL");
EXPECT_FALSE(library.Compile());
const auto& errors = library.errors();
ASSERT_EQ(errors.size(), 3);
for (size_t i = 0; i < errors.size(); i++) {
ASSERT_ERR(errors[i], fidl::ErrDeprecatedAttribute);
}
}
bool MustHaveThreeMembers(fidl::Reporter* reporter, const fidl::flat::Attribute* attribute,
const fidl::flat::Element* element) {
switch (element->kind) {
case fidl::flat::Element::Kind::kStruct: {
auto struct_decl = static_cast<const fidl::flat::Struct*>(element);
return struct_decl->members.size() == 3;
}
default:
return false;
}
}
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);
ASSERT_ERRORED_DURING_COMPILE(library, fidl::ErrAttributeConstraintNotSatisfied);
ASSERT_SUBSTR(library.errors()[0]->msg.c_str(), "must_have_three_members");
}
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);
ASSERT_ERRORED_DURING_COMPILE(library, fidl::ErrAttributeConstraintNotSatisfied);
ASSERT_SUBSTR(library.errors()[0]->msg.c_str(), "must_have_three_members");
}
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);
ASSERT_ERRORED_DURING_COMPILE(library, fidl::ErrAttributeConstraintNotSatisfied);
ASSERT_SUBSTR(library.errors()[0]->msg.c_str(), "must_have_three_members");
}
TEST(AttributesTests, BadMaxBytes) {
TestLibrary library(R"FIDL(
library fidl.test;
@max_bytes("27")
type MyTable = table {
1: here bool;
};
)FIDL");
ASSERT_ERRORED_DURING_COMPILE(library, fidl::ErrTooManyBytes);
ASSERT_SUBSTR(library.errors()[0]->msg.c_str(), "27"); // 27 allowed
ASSERT_SUBSTR(library.errors()[0]->msg.c_str(), "40"); // 40 found
}
TEST(AttributesTests, BadMaxBytesBoundTooBig) {
TestLibrary library(R"FIDL(
library fidl.test;
@max_bytes("4294967296") // 2^32
type MyTable = table {
1: u uint8;
};
)FIDL");
ASSERT_ERRORED_DURING_COMPILE(library, fidl::ErrBoundIsTooBig);
}
TEST(AttributesTests, BadMaxBytesUnableToParseBound) {
TestLibrary library(R"FIDL(
library fidl.test;
@max_bytes("invalid")
type MyTable = table {
1: u uint8;
};
)FIDL");
ASSERT_ERRORED_DURING_COMPILE(library, fidl::ErrUnableToParseBound);
}
TEST(AttributesTests, BadMaxHandles) {
TestLibrary library(R"FIDL(
library fidl.test;
using zx;
@max_handles("2")
type MyUnion = resource union {
1: hello uint8;
2: world array<uint8,8>;
3: foo vector<zx.handle:VMO>:6;
};
)FIDL");
library.UseLibraryZx();
ASSERT_ERRORED_DURING_COMPILE(library, fidl::ErrTooManyHandles);
ASSERT_SUBSTR(library.errors()[0]->msg.c_str(), "2"); // 2 allowed
ASSERT_SUBSTR(library.errors()[0]->msg.c_str(), "6"); // 6 found
}
TEST(AttributesTests, BadAttributeValue) {
TestLibrary library(R"FIDL(
library fidl.test;
@for_deprecated_c_bindings("Complex")
protocol P {
Method();
};
)FIDL");
ASSERT_ERRORED_DURING_COMPILE(library, fidl::ErrAttributeDisallowsArgs);
}
TEST(AttributesTests, BadSelectorIncorrectPlacement) {
TestLibrary library(R"FIDL(
library fidl.test;
@selector("Nonsense")
type MyUnion = union {
1: hello uint8;
};
)FIDL");
ASSERT_ERRORED_DURING_COMPILE(library, fidl::ErrInvalidAttributePlacement);
}
TEST(AttributesTests, BadParameterAttributeIncorrectPlacement) {
TestLibrary library(R"FIDL(
library fidl.test;
protocol ExampleProtocol {
Method(struct { arg exampleusing.Empty; } @on_parameter);
};
)FIDL");
ASSERT_ERRORED_DURING_COMPILE(library, fidl::ErrUnexpectedTokenOfKind);
}
TEST(AttributesTests, BadDuplicateAttributePlacement) {
TestLibrary library(R"FIDL(
library fidl.test;
@foo
type Foo = @bar struct {};
)FIDL");
ASSERT_ERRORED_DURING_COMPILE(library, fidl::ErrRedundantAttributePlacement);
}
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_NOT_NULL(foo);
EXPECT_TRUE(foo->attributes->Get("foo"));
auto bar = library.LookupStruct("Bar");
ASSERT_NOT_NULL(bar);
EXPECT_TRUE(bar->attributes->Get("bar"));
auto req = library.LookupStruct("MyProtocolMyMethodRequest");
ASSERT_NOT_NULL(req);
EXPECT_TRUE(req->attributes->Get("baz"));
auto inner = library.LookupStruct("InnerLayout");
ASSERT_NOT_NULL(inner);
EXPECT_TRUE(inner->attributes->Get("qux"));
}
TEST(AttributesTests, BadNoArgumentsEmptyParens) {
TestLibrary library(R"FIDL(
library fidl.test;
@for_deprecated_c_bindings()
type MyStruct = struct {};
)FIDL");
ASSERT_ERRORED_DURING_COMPILE(library, fidl::ErrAttributeWithEmptyParens);
}
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_NOT_NULL(example_struct);
EXPECT_TRUE(example_struct->attributes->Get("foo"));
EXPECT_TRUE(example_struct->attributes->Get("foo")->GetArg("bar"));
EXPECT_STREQ(example_struct->attributes->Get("foo")->GetArg("bar")->value->span.data(),
"\"abc\"");
EXPECT_TRUE(example_struct->attributes->Get("foo")->GetArg("baz"));
EXPECT_STREQ(example_struct->attributes->Get("foo")->GetArg("baz")->value->span.data(),
"\"def\"");
}
TEST(AttributesTests, BadMultipleArgumentsWithNoNames) {
TestLibrary library(R"FIDL(
library example;
@foo("abc", "def")
type MyStruct = struct {};
)FIDL");
ASSERT_ERRORED_DURING_COMPILE(library, fidl::ErrAttributeArgsMustAllBeNamed);
}
TEST(AttributesTests, BadMultipleArgumentsDuplicateNames) {
TestLibrary library(R"FIDL(
library example;
@foo(bar="abc", bar="def")
type MyStruct = struct {};
)FIDL");
ASSERT_ERRORED_DURING_COMPILE(library, fidl::ErrDuplicateAttributeArg);
}
TEST(AttributesTests, BadMultipleArgumentsDuplicateCanonicalNames) {
TestLibrary library(R"FIDL(
library example;
@foo(Bar_baz="abc", bar__baz="def")
type MyStruct = struct {};
)FIDL");
ASSERT_ERRORED_DURING_COMPILE(library, fidl::ErrDuplicateAttributeArgCanonical);
ASSERT_SUBSTR(library.errors()[0]->msg.c_str(), "canonical form 'bar_baz'");
}
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",
fidl::flat::AttributeArgSchema(fidl::flat::ConstantValue::Kind::kString,
fidl::flat::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",
fidl::flat::AttributeArgSchema(fidl::flat::ConstantValue::Kind::kString,
fidl::flat::AttributeArgSchema::Optionality::kRequired));
ASSERT_COMPILED(library);
auto example_struct = library.LookupStruct("MyStruct");
ASSERT_NOT_NULL(example_struct);
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",
fidl::flat::AttributeArgSchema(fidl::flat::ConstantValue::Kind::kString,
fidl::flat::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(R"FIDL(
library example;
@foo(value="bar")
type MyStruct = struct {};
)FIDL");
library.AddAttributeSchema("foo").AddArg(
"value",
fidl::flat::AttributeArgSchema(fidl::flat::ConstantValue::Kind::kString,
fidl::flat::AttributeArgSchema::Optionality::kRequired));
ASSERT_ERRORED_DURING_COMPILE(library, fidl::ErrAttributeArgMustNotBeNamed);
}
// 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(R"FIDL(
library example;
@foo("bar")
type MyStruct = struct {};
)FIDL");
library.AddAttributeSchema("foo")
.AddArg("value", fidl::flat::AttributeArgSchema(
fidl::flat::ConstantValue::Kind::kString,
fidl::flat::AttributeArgSchema::Optionality::kRequired))
.AddArg("other", fidl::flat::AttributeArgSchema(
fidl::flat::ConstantValue::Kind::kString,
fidl::flat::AttributeArgSchema::Optionality::kOptional));
ASSERT_ERRORED_DURING_COMPILE(library, fidl::ErrAttributeArgNotNamed);
}
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", fidl::flat::AttributeArgSchema(
fidl::flat::ConstantValue::Kind::kString,
fidl::flat::AttributeArgSchema::Optionality::kRequired))
.AddArg("second", fidl::flat::AttributeArgSchema(
fidl::flat::ConstantValue::Kind::kString,
fidl::flat::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", fidl::flat::AttributeArgSchema(
fidl::flat::ConstantValue::Kind::kString,
fidl::flat::AttributeArgSchema::Optionality::kOptional))
.AddArg("second", fidl::flat::AttributeArgSchema(
fidl::flat::ConstantValue::Kind::kString,
fidl::flat::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", fidl::flat::AttributeArgSchema(
fidl::flat::ConstantValue::Kind::kString,
fidl::flat::AttributeArgSchema::Optionality::kRequired))
.AddArg("second", fidl::flat::AttributeArgSchema(
fidl::flat::ConstantValue::Kind::kString,
fidl::flat::AttributeArgSchema::Optionality::kOptional));
ASSERT_COMPILED(library);
}
TEST(AttributesTests, BadMultipleSchemaArgumentsRequiredMissing) {
TestLibrary library(R"FIDL(
library fidl.test;
@multiple_args(optional="foo")
type MyStruct = struct {};
)FIDL");
library.AddAttributeSchema("multiple_args")
.AddArg("required", fidl::flat::AttributeArgSchema(
fidl::flat::ConstantValue::Kind::kString,
fidl::flat::AttributeArgSchema::Optionality::kRequired))
.AddArg("optional", fidl::flat::AttributeArgSchema(
fidl::flat::ConstantValue::Kind::kString,
fidl::flat::AttributeArgSchema::Optionality::kOptional));
ASSERT_ERRORED_DURING_COMPILE(library, fidl::ErrMissingRequiredAttributeArg);
ASSERT_SUBSTR(library.errors()[0]->msg.c_str(), "multiple_args");
}
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_NOT_NULL(example_struct);
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_STREQ(foo->span.data(), "\"abc\"");
ASSERT_EQ(foo->kind, fidl::flat::Constant::Kind::kLiteral);
std::unique_ptr<fidl::flat::ConstantValue> resolved_foo;
EXPECT_TRUE(foo->Value().Convert(fidl::flat::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_STREQ(baz->span.data(), "false");
ASSERT_EQ(baz->kind, fidl::flat::Constant::Kind::kLiteral);
std::unique_ptr<fidl::flat::ConstantValue> resolved_baz;
EXPECT_TRUE(baz->Value().Convert(fidl::flat::ConstantValue::Kind::kBool, &resolved_baz));
}
TEST(AttributesTests, BadLiteralNumericTypesWithoutSchema) {
TestLibrary library(R"FIDL(
library example;
@attr(foo=1, bar=2.3)
type MyStruct = struct {};
)FIDL");
ASSERT_ERRORED_TWICE_DURING_COMPILE(library, fidl::ErrCanOnlyUseStringOrBool,
fidl::ErrCanOnlyUseStringOrBool);
}
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_NOT_NULL(example_struct);
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_STREQ(foo->span.data(), "foo");
ASSERT_EQ(foo->kind, fidl::flat::Constant::Kind::kIdentifier);
std::unique_ptr<fidl::flat::ConstantValue> resolved_foo;
EXPECT_TRUE(foo->Value().Convert(fidl::flat::ConstantValue::Kind::kString, &resolved_foo));
EXPECT_STREQ(static_cast<fidl::flat::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_STREQ(bar->span.data(), "bar");
ASSERT_EQ(bar->kind, fidl::flat::Constant::Kind::kIdentifier);
std::unique_ptr<fidl::flat::ConstantValue> resolved_bar;
EXPECT_TRUE(bar->Value().Convert(fidl::flat::ConstantValue::Kind::kBool, &resolved_bar));
EXPECT_TRUE(static_cast<fidl::flat::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_STREQ(baz->span.data(), "baz");
ASSERT_EQ(baz->kind, fidl::flat::Constant::Kind::kIdentifier);
std::unique_ptr<fidl::flat::ConstantValue> resolved_baz;
EXPECT_TRUE(baz->Value().Convert(fidl::flat::ConstantValue::Kind::kBool, &resolved_baz));
EXPECT_TRUE(!static_cast<fidl::flat::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");
ASSERT_ERRORED_TWICE_DURING_COMPILE(library, fidl::ErrCanOnlyUseStringOrBool,
fidl::ErrCanOnlyUseStringOrBool);
}
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,
float32=1.2,
float64=-3.4)
type MyStruct = struct {};
)FIDL");
library.AddAttributeSchema("attr")
.AddArg("string", fidl::flat::AttributeArgSchema(fidl::flat::ConstantValue::Kind::kString))
.AddArg("bool", fidl::flat::AttributeArgSchema(fidl::flat::ConstantValue::Kind::kBool))
.AddArg("int8", fidl::flat::AttributeArgSchema(fidl::flat::ConstantValue::Kind::kInt8))
.AddArg("int16", fidl::flat::AttributeArgSchema(fidl::flat::ConstantValue::Kind::kInt16))
.AddArg("int32", fidl::flat::AttributeArgSchema(fidl::flat::ConstantValue::Kind::kInt32))
.AddArg("int64", fidl::flat::AttributeArgSchema(fidl::flat::ConstantValue::Kind::kInt64))
.AddArg("uint8", fidl::flat::AttributeArgSchema(fidl::flat::ConstantValue::Kind::kUint8))
.AddArg("uint16", fidl::flat::AttributeArgSchema(fidl::flat::ConstantValue::Kind::kUint16))
.AddArg("uint32", fidl::flat::AttributeArgSchema(fidl::flat::ConstantValue::Kind::kUint32))
.AddArg("uint64", fidl::flat::AttributeArgSchema(fidl::flat::ConstantValue::Kind::kUint64))
.AddArg("float32", fidl::flat::AttributeArgSchema(fidl::flat::ConstantValue::Kind::kFloat32))
.AddArg("float64", fidl::flat::AttributeArgSchema(fidl::flat::ConstantValue::Kind::kFloat64));
ASSERT_COMPILED(library);
auto example_struct = library.LookupStruct("MyStruct");
ASSERT_NOT_NULL(example_struct);
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_STREQ(string_val->span.data(), "\"foo\"");
ASSERT_EQ(string_val->kind, fidl::flat::Constant::Kind::kLiteral);
std::unique_ptr<fidl::flat::ConstantValue> resolved_string;
EXPECT_TRUE(
string_val->Value().Convert(fidl::flat::ConstantValue::Kind::kString, &resolved_string));
EXPECT_STREQ(static_cast<fidl::flat::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_STREQ(bool_val->span.data(), "true");
ASSERT_EQ(bool_val->kind, fidl::flat::Constant::Kind::kLiteral);
std::unique_ptr<fidl::flat::ConstantValue> resolved_bool;
EXPECT_TRUE(bool_val->Value().Convert(fidl::flat::ConstantValue::Kind::kBool, &resolved_bool));
EXPECT_EQ(static_cast<fidl::flat::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_STREQ(int8_val->span.data(), "-1");
ASSERT_EQ(int8_val->kind, fidl::flat::Constant::Kind::kLiteral);
std::unique_ptr<fidl::flat::ConstantValue> resolved_int8;
EXPECT_TRUE(int8_val->Value().Convert(fidl::flat::ConstantValue::Kind::kInt8, &resolved_int8));
EXPECT_EQ(static_cast<fidl::flat::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_STREQ(int16_val->span.data(), "-2");
ASSERT_EQ(int16_val->kind, fidl::flat::Constant::Kind::kLiteral);
std::unique_ptr<fidl::flat::ConstantValue> resolved_int16;
EXPECT_TRUE(int16_val->Value().Convert(fidl::flat::ConstantValue::Kind::kInt16, &resolved_int16));
EXPECT_EQ(static_cast<fidl::flat::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_STREQ(int32_val->span.data(), "-3");
ASSERT_EQ(int32_val->kind, fidl::flat::Constant::Kind::kLiteral);
std::unique_ptr<fidl::flat::ConstantValue> resolved_int32;
EXPECT_TRUE(int32_val->Value().Convert(fidl::flat::ConstantValue::Kind::kInt32, &resolved_int32));
EXPECT_EQ(static_cast<fidl::flat::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_STREQ(int64_val->span.data(), "-4");
ASSERT_EQ(int64_val->kind, fidl::flat::Constant::Kind::kLiteral);
std::unique_ptr<fidl::flat::ConstantValue> resolved_int64;
EXPECT_TRUE(int64_val->Value().Convert(fidl::flat::ConstantValue::Kind::kInt64, &resolved_int64));
EXPECT_EQ(static_cast<fidl::flat::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_STREQ(uint8_val->span.data(), "1");
ASSERT_EQ(uint8_val->kind, fidl::flat::Constant::Kind::kLiteral);
std::unique_ptr<fidl::flat::ConstantValue> resolved_uint8;
EXPECT_TRUE(uint8_val->Value().Convert(fidl::flat::ConstantValue::Kind::kUint8, &resolved_uint8));
EXPECT_EQ(static_cast<fidl::flat::NumericConstantValue<uint8_t>*>(resolved_uint8.get())->value,
1);
// 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_STREQ(uint16_val->span.data(), "2");
ASSERT_EQ(uint16_val->kind, fidl::flat::Constant::Kind::kLiteral);
std::unique_ptr<fidl::flat::ConstantValue> resolved_uint16;
EXPECT_TRUE(
uint16_val->Value().Convert(fidl::flat::ConstantValue::Kind::kUint16, &resolved_uint16));
EXPECT_EQ(static_cast<fidl::flat::NumericConstantValue<uint16_t>*>(resolved_uint16.get())->value,
2);
// 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_STREQ(uint32_val->span.data(), "3");
ASSERT_EQ(uint32_val->kind, fidl::flat::Constant::Kind::kLiteral);
std::unique_ptr<fidl::flat::ConstantValue> resolved_uint32;
EXPECT_TRUE(
uint32_val->Value().Convert(fidl::flat::ConstantValue::Kind::kUint32, &resolved_uint32));
EXPECT_EQ(static_cast<fidl::flat::NumericConstantValue<uint32_t>*>(resolved_uint32.get())->value,
3);
// 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_STREQ(uint64_val->span.data(), "4");
ASSERT_EQ(uint64_val->kind, fidl::flat::Constant::Kind::kLiteral);
std::unique_ptr<fidl::flat::ConstantValue> resolved_uint64;
EXPECT_TRUE(
uint64_val->Value().Convert(fidl::flat::ConstantValue::Kind::kUint64, &resolved_uint64));
EXPECT_EQ(static_cast<fidl::flat::NumericConstantValue<uint64_t>*>(resolved_uint64.get())->value,
4);
// 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_STREQ(float32_val->span.data(), "1.2");
ASSERT_EQ(float32_val->kind, fidl::flat::Constant::Kind::kLiteral);
std::unique_ptr<fidl::flat::ConstantValue> resolved_float32;
EXPECT_TRUE(
float32_val->Value().Convert(fidl::flat::ConstantValue::Kind::kFloat32, &resolved_float32));
EXPECT_TRUE(static_cast<fidl::flat::NumericConstantValue<float>*>(resolved_float32.get())->value >
1.1);
EXPECT_TRUE(static_cast<fidl::flat::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_STREQ(float64_val->span.data(), "-3.4");
ASSERT_EQ(float64_val->kind, fidl::flat::Constant::Kind::kLiteral);
std::unique_ptr<fidl::flat::ConstantValue> resolved_float64;
EXPECT_TRUE(
float64_val->Value().Convert(fidl::flat::ConstantValue::Kind::kFloat64, &resolved_float64));
EXPECT_TRUE(
static_cast<fidl::flat::NumericConstantValue<double>*>(resolved_float64.get())->value > -3.5);
EXPECT_TRUE(
static_cast<fidl::flat::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", fidl::flat::AttributeArgSchema(fidl::flat::ConstantValue::Kind::kString));
ASSERT_ERRORED_TWICE_DURING_COMPILE(library, fidl::ErrTypeCannotBeConvertedToType,
fidl::ErrCouldNotResolveAttributeArg);
}
TEST(AttributesTests, BadInvalidLiteralBoolTypeWithSchema) {
TestLibrary library(R"FIDL(
library example;
@attr("foo")
type MyStruct = struct {};
)FIDL");
library.AddAttributeSchema("attr").AddArg(
"bool", fidl::flat::AttributeArgSchema(fidl::flat::ConstantValue::Kind::kBool));
ASSERT_ERRORED_TWICE_DURING_COMPILE(library, fidl::ErrTypeCannotBeConvertedToType,
fidl::ErrCouldNotResolveAttributeArg);
}
TEST(AttributesTests, BadInvalidLiteralNumericTypeWithSchema) {
TestLibrary library(R"FIDL(
library example;
@attr(-1)
type MyStruct = struct {};
)FIDL");
library.AddAttributeSchema("attr").AddArg(
"uint8", fidl::flat::AttributeArgSchema(fidl::flat::ConstantValue::Kind::kUint8));
ASSERT_ERRORED_TWICE_DURING_COMPILE(library, fidl::ErrConstantOverflowsType,
fidl::ErrCouldNotResolveAttributeArg);
}
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 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,
float32=float32,
float64=float64)
type MyStruct = struct {};
)FIDL");
library.AddAttributeSchema("attr")
.AddArg("string", fidl::flat::AttributeArgSchema(fidl::flat::ConstantValue::Kind::kString))
.AddArg("bool", fidl::flat::AttributeArgSchema(fidl::flat::ConstantValue::Kind::kBool))
.AddArg("int8", fidl::flat::AttributeArgSchema(fidl::flat::ConstantValue::Kind::kInt8))
.AddArg("int16", fidl::flat::AttributeArgSchema(fidl::flat::ConstantValue::Kind::kInt16))
.AddArg("int32", fidl::flat::AttributeArgSchema(fidl::flat::ConstantValue::Kind::kInt32))
.AddArg("int64", fidl::flat::AttributeArgSchema(fidl::flat::ConstantValue::Kind::kInt64))
.AddArg("uint8", fidl::flat::AttributeArgSchema(fidl::flat::ConstantValue::Kind::kUint8))
.AddArg("uint16", fidl::flat::AttributeArgSchema(fidl::flat::ConstantValue::Kind::kUint16))
.AddArg("uint32", fidl::flat::AttributeArgSchema(fidl::flat::ConstantValue::Kind::kUint32))
.AddArg("uint64", fidl::flat::AttributeArgSchema(fidl::flat::ConstantValue::Kind::kUint64))
.AddArg("float32", fidl::flat::AttributeArgSchema(fidl::flat::ConstantValue::Kind::kFloat32))
.AddArg("float64", fidl::flat::AttributeArgSchema(fidl::flat::ConstantValue::Kind::kFloat64));
ASSERT_COMPILED(library);
auto example_struct = library.LookupStruct("MyStruct");
ASSERT_NOT_NULL(example_struct);
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_STREQ(string_val->span.data(), "string");
ASSERT_EQ(string_val->kind, fidl::flat::Constant::Kind::kIdentifier);
std::unique_ptr<fidl::flat::ConstantValue> resolved_string;
EXPECT_TRUE(
string_val->Value().Convert(fidl::flat::ConstantValue::Kind::kString, &resolved_string));
EXPECT_STREQ(static_cast<fidl::flat::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_STREQ(bool_val->span.data(), "bool");
ASSERT_EQ(bool_val->kind, fidl::flat::Constant::Kind::kIdentifier);
std::unique_ptr<fidl::flat::ConstantValue> resolved_bool;
EXPECT_TRUE(bool_val->Value().Convert(fidl::flat::ConstantValue::Kind::kBool, &resolved_bool));
EXPECT_EQ(static_cast<fidl::flat::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_STREQ(int8_val->span.data(), "int8");
ASSERT_EQ(int8_val->kind, fidl::flat::Constant::Kind::kIdentifier);
std::unique_ptr<fidl::flat::ConstantValue> resolved_int8;
EXPECT_TRUE(int8_val->Value().Convert(fidl::flat::ConstantValue::Kind::kInt8, &resolved_int8));
EXPECT_EQ(static_cast<fidl::flat::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_STREQ(int16_val->span.data(), "int16");
ASSERT_EQ(int16_val->kind, fidl::flat::Constant::Kind::kIdentifier);
std::unique_ptr<fidl::flat::ConstantValue> resolved_int16;
EXPECT_TRUE(int16_val->Value().Convert(fidl::flat::ConstantValue::Kind::kInt16, &resolved_int16));
EXPECT_EQ(static_cast<fidl::flat::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_STREQ(int32_val->span.data(), "int32");
ASSERT_EQ(int32_val->kind, fidl::flat::Constant::Kind::kIdentifier);
std::unique_ptr<fidl::flat::ConstantValue> resolved_int32;
EXPECT_TRUE(int32_val->Value().Convert(fidl::flat::ConstantValue::Kind::kInt32, &resolved_int32));
EXPECT_EQ(static_cast<fidl::flat::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_STREQ(int64_val->span.data(), "int64.MEMBER");
ASSERT_EQ(int64_val->kind, fidl::flat::Constant::Kind::kIdentifier);
std::unique_ptr<fidl::flat::ConstantValue> resolved_int64;
EXPECT_TRUE(int64_val->Value().Convert(fidl::flat::ConstantValue::Kind::kInt64, &resolved_int64));
EXPECT_EQ(static_cast<fidl::flat::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_STREQ(uint8_val->span.data(), "uint8");
ASSERT_EQ(uint8_val->kind, fidl::flat::Constant::Kind::kIdentifier);
std::unique_ptr<fidl::flat::ConstantValue> resolved_uint8;
EXPECT_TRUE(uint8_val->Value().Convert(fidl::flat::ConstantValue::Kind::kUint8, &resolved_uint8));
EXPECT_EQ(static_cast<fidl::flat::NumericConstantValue<uint8_t>*>(resolved_uint8.get())->value,
1);
// 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_STREQ(uint16_val->span.data(), "uint16");
ASSERT_EQ(uint16_val->kind, fidl::flat::Constant::Kind::kIdentifier);
std::unique_ptr<fidl::flat::ConstantValue> resolved_uint16;
EXPECT_TRUE(
uint16_val->Value().Convert(fidl::flat::ConstantValue::Kind::kUint16, &resolved_uint16));
EXPECT_EQ(static_cast<fidl::flat::NumericConstantValue<uint16_t>*>(resolved_uint16.get())->value,
2);
// 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_STREQ(uint32_val->span.data(), "uint32");
ASSERT_EQ(uint32_val->kind, fidl::flat::Constant::Kind::kIdentifier);
std::unique_ptr<fidl::flat::ConstantValue> resolved_uint32;
EXPECT_TRUE(
uint32_val->Value().Convert(fidl::flat::ConstantValue::Kind::kUint32, &resolved_uint32));
EXPECT_EQ(static_cast<fidl::flat::NumericConstantValue<uint32_t>*>(resolved_uint32.get())->value,
3);
// 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_STREQ(uint64_val->span.data(), "uint64.MEMBER");
ASSERT_EQ(uint64_val->kind, fidl::flat::Constant::Kind::kIdentifier);
std::unique_ptr<fidl::flat::ConstantValue> resolved_uint64;
EXPECT_TRUE(
uint64_val->Value().Convert(fidl::flat::ConstantValue::Kind::kUint64, &resolved_uint64));
EXPECT_EQ(static_cast<fidl::flat::NumericConstantValue<uint64_t>*>(resolved_uint64.get())->value,
4);
// 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_STREQ(float32_val->span.data(), "float32");
ASSERT_EQ(float32_val->kind, fidl::flat::Constant::Kind::kIdentifier);
std::unique_ptr<fidl::flat::ConstantValue> resolved_float32;
EXPECT_TRUE(
float32_val->Value().Convert(fidl::flat::ConstantValue::Kind::kFloat32, &resolved_float32));
EXPECT_TRUE(static_cast<fidl::flat::NumericConstantValue<float>*>(resolved_float32.get())->value >
1.1);
EXPECT_TRUE(static_cast<fidl::flat::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_STREQ(float64_val->span.data(), "float64");
ASSERT_EQ(float64_val->kind, fidl::flat::Constant::Kind::kIdentifier);
std::unique_ptr<fidl::flat::ConstantValue> resolved_float64;
EXPECT_TRUE(
float64_val->Value().Convert(fidl::flat::ConstantValue::Kind::kFloat64, &resolved_float64));
EXPECT_TRUE(
static_cast<fidl::flat::NumericConstantValue<double>*>(resolved_float64.get())->value > -3.5);
EXPECT_TRUE(
static_cast<fidl::flat::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", fidl::flat::AttributeArgSchema(fidl::flat::ConstantValue::Kind::kString));
ASSERT_ERRORED_TWICE_DURING_COMPILE(library, fidl::ErrTypeCannotBeConvertedToType,
fidl::ErrCouldNotResolveAttributeArg);
}
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", fidl::flat::AttributeArgSchema(fidl::flat::ConstantValue::Kind::kBool));
ASSERT_ERRORED_TWICE_DURING_COMPILE(library, fidl::ErrTypeCannotBeConvertedToType,
fidl::ErrCouldNotResolveAttributeArg);
}
TEST(AttributesTests, BadInvalidReferencedNumericTypeWithSchema) {
TestLibrary library(R"FIDL(
library example;
const foo uint16 = 259;
@attr(foo)
type MyStruct = struct {};
)FIDL");
library.AddAttributeSchema("attr").AddArg(
"int8", fidl::flat::AttributeArgSchema(fidl::flat::ConstantValue::Kind::kInt8));
ASSERT_ERRORED_TWICE_DURING_COMPILE(library, fidl::ErrTypeCannotBeConvertedToType,
fidl::ErrCouldNotResolveAttributeArg);
}
TEST(AttributesTests, GoodCompileEarlyAttributeLiteralArgument) {
TestLibrary library(R"FIDL(
library example;
@attr(1)
type MyStruct = struct {};
)FIDL");
library.AddAttributeSchema("attr")
.AddArg("int8", fidl::flat::AttributeArgSchema(fidl::flat::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", fidl::flat::AttributeArgSchema(fidl::flat::ConstantValue::Kind::kUint8))
.CompileEarly();
ASSERT_ERRORED_DURING_COMPILE(library, fidl::ErrAttributeArgRequiresLiteral);
}
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_NOT_NULL(example_struct);
ASSERT_EQ(example_struct->attributes->attributes.size(), 1);
ASSERT_EQ(example_struct->attributes->attributes[0]->args.size(), 1);
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_NOT_NULL(example_struct);
ASSERT_EQ(example_struct->attributes->attributes.size(), 1);
ASSERT_EQ(example_struct->attributes->attributes[0]->args.size(), 1);
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");
ASSERT_ERRORED_DURING_COMPILE(library, fidl::ErrNameNotFound);
}
TEST(AttributesTests, BadReferencesNonexistentConstWithSchema) {
TestLibrary library(R"FIDL(
library example;
@foo(nonexistent)
type MyStruct = struct {};
)FIDL");
library.AddAttributeSchema("foo").AddArg(
"value", fidl::flat::AttributeArgSchema(fidl::flat::ConstantValue::Kind::kBool));
ASSERT_ERRORED_DURING_COMPILE(library, fidl::ErrNameNotFound);
}
TEST(AttributesTests, BadReferencesInvalidConstWithoutSchema) {
TestLibrary library(R"FIDL(
library example;
@foo(BAD)
type MyStruct = struct {};
const BAD bool = "not a bool";
)FIDL");
ASSERT_FALSE(library.Compile());
ASSERT_EQ(library.errors().size(), 3);
EXPECT_ERR(library.errors()[0], fidl::ErrTypeCannotBeConvertedToType);
EXPECT_ERR(library.errors()[1], fidl::ErrCannotResolveConstantValue);
EXPECT_ERR(library.errors()[2], fidl::ErrCouldNotResolveAttributeArg);
}
TEST(AttributesTests, BadReferencesInvalidConstWithSchema) {
TestLibrary library(R"FIDL(
library example;
@foo(BAD)
type MyStruct = struct {};
const BAD bool = "not a bool";
)FIDL");
library.AddAttributeSchema("foo").AddArg(
"value", fidl::flat::AttributeArgSchema(fidl::flat::ConstantValue::Kind::kBool));
ASSERT_FALSE(library.Compile());
ASSERT_EQ(library.errors().size(), 3);
EXPECT_ERR(library.errors()[0], fidl::ErrTypeCannotBeConvertedToType);
EXPECT_ERR(library.errors()[1], fidl::ErrCannotResolveConstantValue);
EXPECT_ERR(library.errors()[2], fidl::ErrCouldNotResolveAttributeArg);
}
TEST(AttributesTests, BadSelfReferenceWithoutSchemaBool) {
TestLibrary library(R"FIDL(
library example;
@foo(BAR)
const BAR bool = true;
)FIDL");
ASSERT_ERRORED_TWICE_DURING_COMPILE(library, fidl::ErrIncludeCycle,
fidl::ErrCouldNotResolveAttributeArg);
ASSERT_SUBSTR(library.errors()[0]->msg.c_str(), "const 'BAR' -> const 'BAR'");
}
TEST(AttributesTests, BadSelfReferenceWithoutSchemaString) {
TestLibrary library(R"FIDL(
library example;
@foo(BAR)
const BAR string = "bar";
)FIDL");
ASSERT_ERRORED_TWICE_DURING_COMPILE(library, fidl::ErrIncludeCycle,
fidl::ErrCouldNotResolveAttributeArg);
ASSERT_SUBSTR(library.errors()[0]->msg.c_str(), "const 'BAR' -> const 'BAR'");
}
TEST(AttributesTests, BadSelfReferenceWithSchema) {
TestLibrary library(R"FIDL(
library example;
@foo(BAR)
const BAR bool = true;
)FIDL");
library.AddAttributeSchema("foo").AddArg(
"value", fidl::flat::AttributeArgSchema(fidl::flat::ConstantValue::Kind::kBool));
ASSERT_ERRORED_TWICE_DURING_COMPILE(library, fidl::ErrIncludeCycle,
fidl::ErrCouldNotResolveAttributeArg);
ASSERT_SUBSTR(library.errors()[0]->msg.c_str(), "const 'BAR' -> const 'BAR'");
}
TEST(AttributesTests, BadMutualReferenceWithoutSchemaBool) {
TestLibrary library(R"FIDL(
library example;
@foo(SECOND)
const FIRST bool = true;
@foo(FIRST)
const SECOND bool = false;
)FIDL");
ASSERT_ERRORED_TWICE_DURING_COMPILE(library, fidl::ErrIncludeCycle,
fidl::ErrCouldNotResolveAttributeArg);
ASSERT_SUBSTR(library.errors()[0]->msg.c_str(),
"const 'FIRST' -> const 'SECOND' -> const 'FIRST'");
}
TEST(AttributesTests, BadMutualReferenceWithoutSchemaString) {
TestLibrary library(R"FIDL(
library example;
@foo(SECOND)
const FIRST string = "first";
@foo(FIRST)
const SECOND string = "second";
)FIDL");
ASSERT_ERRORED_TWICE_DURING_COMPILE(library, fidl::ErrIncludeCycle,
fidl::ErrCouldNotResolveAttributeArg);
ASSERT_SUBSTR(library.errors()[0]->msg.c_str(),
"const 'FIRST' -> const 'SECOND' -> const 'FIRST'");
}
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", fidl::flat::AttributeArgSchema(fidl::flat::ConstantValue::Kind::kBool));
ASSERT_ERRORED_TWICE_DURING_COMPILE(library, fidl::ErrIncludeCycle,
fidl::ErrCouldNotResolveAttributeArg);
ASSERT_SUBSTR(library.errors()[0]->msg.c_str(),
"const 'FIRST' -> const 'SECOND' -> const 'FIRST'");
}
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);
ASSERT_ERRORED_DURING_COMPILE(library, fidl::ErrInvalidDiscoverableName);
}
}
} // namespace