blob: 98dd2b86b3c9269a028f1e5a055bb7826d170472 [file] [log] [blame]
// Copyright 2020 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/flat_ast.h>
#include <fidl/lexer.h>
#include <fidl/parser.h>
#include <fidl/source_file.h>
#include <zxtest/zxtest.h>
#include "error_test.h"
#include "fidl/diagnostics.h"
#include "test_library.h"
namespace {
void invalid_resource_modifier(const std::string& type, const std::string& definition) {
std::string fidl_library = "library example;\n\n" + definition + "\n";
fidl::ExperimentalFlags experimental_flags;
experimental_flags.SetFlag(fidl::ExperimentalFlags::Flag::kAllowNewSyntax);
TestLibrary library(fidl_library, experimental_flags);
ASSERT_ERRORED_DURING_COMPILE(library, fidl::ErrCannotSpecifyModifier);
ASSERT_SUBSTR(library.errors()[0]->msg.c_str(), "resource");
ASSERT_SUBSTR(library.errors()[0]->msg.c_str(), type);
}
void invalid_resource_modifier_old(const std::string& type, const std::string& definition) {
std::string fidl_library = "library example;\n\n" + definition + "\n";
TestLibrary library(fidl_library);
ASSERT_ERRORED_DURING_COMPILE(library, fidl::ErrCannotSpecifyModifier);
ASSERT_SUBSTR(library.errors()[0]->msg.c_str(), "resource");
ASSERT_SUBSTR(library.errors()[0]->msg.c_str(), type);
}
TEST(ResourcenessTests, BadBitsResourceness) {
invalid_resource_modifier("bits", R"FIDL(
type Foo = resource bits {
BAR = 0x1;
};
)FIDL");
}
TEST(ResourcenessTests, BadBitsResourcenessOld) {
invalid_resource_modifier_old("bits", R"FIDL(
resource bits Foo {
BAR = 0x1;
};
)FIDL");
}
TEST(ResourcenessTests, BadEnumResourceness) {
invalid_resource_modifier("enum", R"FIDL(
type Foo = resource enum {
BAR = 1;
};
)FIDL");
}
TEST(ResourcenessTests, BadEnumResourcenessOld) {
invalid_resource_modifier_old("enum", R"FIDL(
resource enum Foo {
BAR = 1;
};
)FIDL");
}
// NOTE(fxbug.dev/72924): we don't parse resource in this position in the
// new syntax.
TEST(ResourcenessTests, BadConstResourceness) {
fidl::ExperimentalFlags experimental_flags;
experimental_flags.SetFlag(fidl::ExperimentalFlags::Flag::kAllowNewSyntax);
TestLibrary library(R"FIDL(
library example;
resource const BAR uint32 = 1;
)FIDL",
experimental_flags);
ASSERT_ERRORED_DURING_COMPILE(library, fidl::ErrExpectedDeclaration);
}
TEST(ResourcenessTests, BadConstResourcenessOld) {
invalid_resource_modifier_old("const", R"FIDL(
resource const uint32 BAR = 1;
)FIDL");
}
// NOTE(fxbug.dev/72924): we don't parse resource in this position in the
// new syntax.
TEST(ResourcenessTests, BadProtocolResourceness) {
fidl::ExperimentalFlags experimental_flags;
experimental_flags.SetFlag(fidl::ExperimentalFlags::Flag::kAllowNewSyntax);
TestLibrary library(R"FIDL(
library example;
resource protocol Foo {};
)FIDL",
experimental_flags);
ASSERT_ERRORED_DURING_COMPILE(library, fidl::ErrExpectedDeclaration);
}
TEST(ResourcenessTests, BadProtocolResourcenessOld) {
invalid_resource_modifier_old("protocol", R"FIDL(
resource protocol Foo {};
)FIDL");
}
// NOTE(fxbug.dev/72924): we don't parse resource in this position in the
// new syntax.
TEST(ResourcenessTests, BadAliasResourceness) {
fidl::ExperimentalFlags experimental_flags;
experimental_flags.SetFlag(fidl::ExperimentalFlags::Flag::kAllowNewSyntax);
TestLibrary library(R"FIDL(
library example;
resource alias B = bool;
)FIDL",
experimental_flags);
ASSERT_ERRORED_DURING_COMPILE(library, fidl::ErrExpectedDeclaration);
}
TEST(ResourcenessTests, BadAliasResourcenessOld) {
invalid_resource_modifier_old("alias", R"FIDL(
resource alias B = bool;
)FIDL");
}
TEST(ResourcenessTests, BadDuplicateModifier) {
fidl::ExperimentalFlags experimental_flags;
experimental_flags.SetFlag(fidl::ExperimentalFlags::Flag::kAllowNewSyntax);
TestLibrary library(R"FIDL(
library example;
type One = resource struct {};
type Two = resource resource struct {}; // line 5
type Three = resource resource resource struct {}; // line 6
)FIDL",
experimental_flags);
ASSERT_FALSE(library.Compile());
const auto& errors = library.errors();
ASSERT_EQ(errors.size(), 3);
ASSERT_ERR(errors[0], fidl::ErrDuplicateModifier);
EXPECT_EQ(errors[0]->span->position().line, 5);
ASSERT_SUBSTR(errors[0]->msg.c_str(), "resource");
ASSERT_ERR(errors[1], fidl::ErrDuplicateModifier);
EXPECT_EQ(errors[1]->span->position().line, 6);
ASSERT_SUBSTR(errors[1]->msg.c_str(), "resource");
ASSERT_ERR(errors[2], fidl::ErrDuplicateModifier);
EXPECT_EQ(errors[2]->span->position().line, 6);
ASSERT_SUBSTR(errors[2]->msg.c_str(), "resource");
}
TEST(ResourcenessTests, BadDuplicateModifierOld) {
TestLibrary library(R"FIDL(
library example;
resource struct One {};
resource resource struct Two {}; // line 5
resource resource resource struct Three {}; // line 6
)FIDL");
ASSERT_FALSE(library.Compile());
const auto& errors = library.errors();
ASSERT_EQ(errors.size(), 3);
ASSERT_ERR(errors[0], fidl::ErrDuplicateModifier);
EXPECT_EQ(errors[0]->span->position().line, 5);
ASSERT_SUBSTR(errors[0]->msg.c_str(), "resource");
ASSERT_ERR(errors[1], fidl::ErrDuplicateModifier);
EXPECT_EQ(errors[1]->span->position().line, 6);
ASSERT_SUBSTR(errors[1]->msg.c_str(), "resource");
ASSERT_ERR(errors[2], fidl::ErrDuplicateModifier);
EXPECT_EQ(errors[2]->span->position().line, 6);
ASSERT_SUBSTR(errors[2]->msg.c_str(), "resource");
}
TEST(ResourcenessTests, GoodResourceStruct) {
for (const std::string& definition : {
"resource struct Foo {};",
"resource struct Foo { bool b; };",
"using zx;\nresource struct Foo { zx.handle h; };",
"using zx;\nresource struct Foo { array<zx.handle>:1 a; };",
"using zx;\nresource struct Foo { vector<zx.handle> v; };",
}) {
std::string fidl_library = "library example;\n\n" + definition + "\n";
auto library = WithLibraryZx(fidl_library);
ASSERT_COMPILED_AND_CONVERT(library);
EXPECT_EQ(library.LookupStruct("Foo")->resourceness, fidl::types::Resourceness::kResource, "%s",
fidl_library.c_str());
}
}
TEST(ResourcenessTests, GoodResourceTable) {
for (const std::string& definition : {
"resource table Foo {};",
"resource table Foo { 1: bool b; };",
"using zx;\nresource table Foo { 1: zx.handle h; };",
"using zx;\nresource table Foo { 1: array<zx.handle>:1 a; };",
"using zx;\nresource table Foo { 1: vector<zx.handle> v; };",
}) {
std::string fidl_library = "library example;\n\n" + definition + "\n";
auto library = WithLibraryZx(fidl_library);
ASSERT_COMPILED_AND_CONVERT(library);
EXPECT_EQ(library.LookupTable("Foo")->resourceness, fidl::types::Resourceness::kResource, "%s",
fidl_library.c_str());
}
}
TEST(ResourcenessTests, GoodResourceUnion) {
for (const std::string& definition : {
"resource union Foo { 1: bool b; };",
"using zx;\nresource union Foo { 1: zx.handle h; };",
"using zx;\nresource union Foo { 1: array<zx.handle>:1 a; };",
"using zx;\nresource union Foo { 1: vector<zx.handle> v; };",
}) {
std::string fidl_library = "library example;\n\n" + definition + "\n";
auto library = WithLibraryZx(fidl_library);
;
ASSERT_COMPILED_AND_CONVERT(library);
EXPECT_EQ(library.LookupUnion("Foo")->resourceness, fidl::types::Resourceness::kResource, "%s",
fidl_library.c_str());
}
}
TEST(ResourcenessTests, BadHandlesInValueStruct) {
fidl::ExperimentalFlags experimental_flags;
experimental_flags.SetFlag(fidl::ExperimentalFlags::Flag::kAllowNewSyntax);
for (const std::string& definition : {
"type Foo = struct { bad_member zx.handle; };",
"type Foo = struct { bad_member zx.handle:optional; };",
"type Foo = struct { bad_member array<zx.handle, 1>; };",
"type Foo = struct { bad_member vector<zx.handle>; };",
"type Foo = struct { bad_member vector<zx.handle>:0; };",
}) {
std::string fidl_library = "library example;\nusing zx;\n\n" + definition + "\n";
auto library = WithLibraryZx(fidl_library, experimental_flags);
ASSERT_ERRORED_DURING_COMPILE(library, fidl::ErrTypeMustBeResource);
ASSERT_SUBSTR(library.errors()[0]->msg.c_str(), "Foo", "%s", fidl_library.c_str());
ASSERT_SUBSTR(library.errors()[0]->msg.c_str(), "bad_member", "%s", fidl_library.c_str());
}
}
TEST(ResourcenessTests, BadHandlesInValueStructOld) {
for (const std::string& definition : {
"struct Foo { zx.handle bad_member; };",
"struct Foo { zx.handle? bad_member; };",
"struct Foo { array<zx.handle>:1 bad_member; };",
"struct Foo { vector<zx.handle> bad_member; };",
"struct Foo { vector<zx.handle>:0 bad_member; };",
}) {
std::string fidl_library = "library example;\nusing zx;\n\n" + definition + "\n";
auto library = WithLibraryZx(fidl_library);
ASSERT_ERRORED_DURING_COMPILE(library, fidl::ErrTypeMustBeResource);
ASSERT_SUBSTR(library.errors()[0]->msg.c_str(), "Foo", "%s", fidl_library.c_str());
ASSERT_SUBSTR(library.errors()[0]->msg.c_str(), "bad_member", "%s", fidl_library.c_str());
}
}
TEST(ResourcenessTests, BadHandlesInValueTable) {
fidl::ExperimentalFlags experimental_flags;
experimental_flags.SetFlag(fidl::ExperimentalFlags::Flag::kAllowNewSyntax);
for (const std::string& definition : {
"type Foo = table { 1: bad_member zx.handle; };",
"type Foo = table { 1: bad_member array<zx.handle, 1>; };",
"type Foo = table { 1: bad_member vector<zx.handle>; };",
"type Foo = table { 1: bad_member vector<zx.handle>:0; };",
}) {
std::string fidl_library = "library example;\nusing zx;\n\n" + definition + "\n";
auto library = WithLibraryZx(fidl_library, experimental_flags);
ASSERT_ERRORED_DURING_COMPILE(library, fidl::ErrTypeMustBeResource);
ASSERT_SUBSTR(library.errors()[0]->msg.c_str(), "Foo", "%s", fidl_library.c_str());
ASSERT_SUBSTR(library.errors()[0]->msg.c_str(), "bad_member", "%s", fidl_library.c_str());
}
}
TEST(ResourcenessTests, BadHandlesInValueTableOld) {
for (const std::string& definition : {
"table Foo { 1: zx.handle bad_member; };",
"table Foo { 1: array<zx.handle>:1 bad_member; };",
"table Foo { 1: vector<zx.handle> bad_member; };",
"table Foo { 1: vector<zx.handle>:0 bad_member; };",
}) {
std::string fidl_library = "library example;\nusing zx;\n\n" + definition + "\n";
auto library = WithLibraryZx(fidl_library);
ASSERT_ERRORED_DURING_COMPILE(library, fidl::ErrTypeMustBeResource);
ASSERT_SUBSTR(library.errors()[0]->msg.c_str(), "Foo", "%s", fidl_library.c_str());
ASSERT_SUBSTR(library.errors()[0]->msg.c_str(), "bad_member", "%s", fidl_library.c_str());
}
}
TEST(ResourcenessTests, BadHandlesInValueUnion) {
fidl::ExperimentalFlags experimental_flags;
experimental_flags.SetFlag(fidl::ExperimentalFlags::Flag::kAllowNewSyntax);
for (const std::string& definition : {
"type Foo = union { 1: bad_member zx.handle; };",
"type Foo = union { 1: bad_member array<zx.handle, 1>; };",
"type Foo = union { 1: bad_member vector<zx.handle>; };",
"type Foo = union { 1: bad_member vector<zx.handle>:0; };",
}) {
std::string fidl_library = "library example;\nusing zx;\n\n" + definition + "\n";
auto library = WithLibraryZx(fidl_library, experimental_flags);
ASSERT_ERRORED_DURING_COMPILE(library, fidl::ErrTypeMustBeResource);
ASSERT_SUBSTR(library.errors()[0]->msg.c_str(), "Foo", "%s", fidl_library.c_str());
ASSERT_SUBSTR(library.errors()[0]->msg.c_str(), "bad_member", "%s", fidl_library.c_str());
;
}
}
TEST(ResourcenessTests, BadHandlesInValueUnionOld) {
for (const std::string& definition : {
"union Foo { 1: zx.handle bad_member; };",
"union Foo { 1: array<zx.handle>:1 bad_member; };",
"union Foo { 1: vector<zx.handle> bad_member; };",
"union Foo { 1: vector<zx.handle>:0 bad_member; };",
}) {
std::string fidl_library = "library example;\nusing zx;\n\n" + definition + "\n";
auto library = WithLibraryZx(fidl_library);
ASSERT_ERRORED_DURING_COMPILE(library, fidl::ErrTypeMustBeResource);
ASSERT_SUBSTR(library.errors()[0]->msg.c_str(), "Foo", "%s", fidl_library.c_str());
ASSERT_SUBSTR(library.errors()[0]->msg.c_str(), "bad_member", "%s", fidl_library.c_str());
;
}
}
TEST(ResourcenessTests, BadProtocolsInValueType) {
fidl::ExperimentalFlags experimental_flags;
experimental_flags.SetFlag(fidl::ExperimentalFlags::Flag::kAllowNewSyntax);
for (const std::string& definition : {
"type Foo = struct { bad_member client_end:Protocol; };",
"type Foo = struct { bad_member client_end:<Protocol, optional>; };",
"type Foo = struct { bad_member server_end:Protocol; };",
"type Foo = struct { bad_member server_end:<Protocol, optional>; };",
}) {
std::string fidl_library = R"FIDL(
library example;
using zx;
protocol Protocol {};
)FIDL" + definition + "\n";
auto library = WithLibraryZx(fidl_library, experimental_flags);
ASSERT_ERRORED_DURING_COMPILE(library, fidl::ErrTypeMustBeResource);
ASSERT_SUBSTR(library.errors()[0]->msg.c_str(), "Foo", "%s", fidl_library.c_str());
ASSERT_SUBSTR(library.errors()[0]->msg.c_str(), "bad_member", "%s", fidl_library.c_str());
;
}
}
TEST(ResourcenessTests, BadProtocolsInValueTypeOld) {
for (const std::string& definition : {
"struct Foo { Protocol bad_member; };",
"struct Foo { Protocol? bad_member; };",
"struct Foo { request<Protocol> bad_member; };",
"struct Foo { request<Protocol>? bad_member; };",
}) {
std::string fidl_library = R"FIDL(
library example;
protocol Protocol {};
)FIDL" + definition + "\n";
TestLibrary library(fidl_library);
ASSERT_ERRORED_DURING_COMPILE(library, fidl::ErrTypeMustBeResource);
ASSERT_SUBSTR(library.errors()[0]->msg.c_str(), "Foo", "%s", fidl_library.c_str());
ASSERT_SUBSTR(library.errors()[0]->msg.c_str(), "bad_member", "%s", fidl_library.c_str());
;
}
}
TEST(ResourcenessTests, BadResourceTypesInValueType) {
fidl::ExperimentalFlags experimental_flags;
experimental_flags.SetFlag(fidl::ExperimentalFlags::Flag::kAllowNewSyntax);
for (const std::string& definition : {
"type Foo = struct { bad_member ResourceStruct; };",
"type Foo = struct { bad_member ResourceStruct:optional; };",
"type Foo = struct { bad_member ResourceTable; };",
"type Foo = struct { bad_member ResourceUnion; };",
"type Foo = struct { bad_member ResourceUnion:optional; };",
}) {
std::string fidl_library = R"FIDL(
library example;
type ResourceStruct = resource struct {};
type ResourceTable = resource table {};
type ResourceUnion = resource union { 1: b bool; };
)FIDL" + definition + "\n";
auto library = WithLibraryZx(fidl_library, experimental_flags);
ASSERT_ERRORED_DURING_COMPILE(library, fidl::ErrTypeMustBeResource);
ASSERT_SUBSTR(library.errors()[0]->msg.c_str(), "Foo", "%s", fidl_library.c_str());
ASSERT_SUBSTR(library.errors()[0]->msg.c_str(), "bad_member", "%s", fidl_library.c_str());
;
}
}
TEST(ResourcenessTests, BadResourceTypesInValueTypeOld) {
for (const std::string& definition : {
"struct Foo { ResourceStruct bad_member; };",
"struct Foo { ResourceStruct? bad_member; };",
"struct Foo { ResourceTable bad_member; };",
"struct Foo { ResourceUnion bad_member; };",
"struct Foo { ResourceUnion? bad_member; };",
}) {
std::string fidl_library = R"FIDL(
library example;
resource struct ResourceStruct {};
resource table ResourceTable {};
resource union ResourceUnion { 1: bool b; };
)FIDL" + definition + "\n";
TestLibrary library(fidl_library);
ASSERT_ERRORED_DURING_COMPILE(library, fidl::ErrTypeMustBeResource);
ASSERT_SUBSTR(library.errors()[0]->msg.c_str(), "Foo", "%s", fidl_library.c_str());
ASSERT_SUBSTR(library.errors()[0]->msg.c_str(), "bad_member", "%s", fidl_library.c_str());
;
}
}
TEST(ResourcenessTests, BadResourceAliasesInValueType) {
fidl::ExperimentalFlags experimental_flags;
experimental_flags.SetFlag(fidl::ExperimentalFlags::Flag::kAllowNewSyntax);
for (const std::string& definition : {
"type Foo = struct { bad_member HandleAlias; };",
"type Foo = struct { bad_member ProtocolAlias; };",
"type Foo = struct { bad_member ResourceStructAlias; };",
"type Foo = struct { bad_member ResourceTableAlias; };",
"type Foo = struct { bad_member ResourceUnionAlias; };",
}) {
std::string fidl_library = R"FIDL(
library example;
using zx;
alias HandleAlias = zx.handle;
alias ProtocolAlias = client_end:Protocol;
alias ResourceStructAlias = ResourceStruct;
alias ResourceTableAlias = ResourceStruct;
alias ResourceUnionAlias = ResourceStruct;
protocol Protocol {};
type ResourceStruct = resource struct {};
type ResourceTable = resource table {};
type ResourceUnion = resource union { 1: b bool; };
)FIDL" + definition + "\n";
auto library = WithLibraryZx(fidl_library, experimental_flags);
ASSERT_ERRORED_DURING_COMPILE(library, fidl::ErrTypeMustBeResource);
ASSERT_SUBSTR(library.errors()[0]->msg.c_str(), "Foo", "%s", fidl_library.c_str());
ASSERT_SUBSTR(library.errors()[0]->msg.c_str(), "bad_member", "%s", fidl_library.c_str());
;
}
}
TEST(ResourcenessTests, BadResourceAliasesInValueTypeOld) {
for (const std::string& definition : {
"struct Foo { HandleAlias bad_member; };",
"struct Foo { ProtocolAlias bad_member; };",
"struct Foo { ResourceStructAlias bad_member; };",
"struct Foo { ResourceTableAlias bad_member; };",
"struct Foo { ResourceUnionAlias bad_member; };",
}) {
std::string fidl_library = R"FIDL(
library example;
using zx;
alias HandleAlias = zx.handle;
alias ProtocolAlias = Protocol;
alias ResourceStructAlias = ResourceStruct;
alias ResourceTableAlias = ResourceStruct;
alias ResourceUnionAlias = ResourceStruct;
protocol Protocol {};
resource struct ResourceStruct {};
resource table ResourceTable {};
resource union ResourceUnion { 1: bool b; };
)FIDL" + definition + "\n";
auto library = WithLibraryZx(fidl_library);
ASSERT_ERRORED_DURING_COMPILE(library, fidl::ErrTypeMustBeResource);
ASSERT_SUBSTR(library.errors()[0]->msg.c_str(), "Foo", "%s", fidl_library.c_str());
ASSERT_SUBSTR(library.errors()[0]->msg.c_str(), "bad_member", "%s", fidl_library.c_str());
;
}
}
TEST(ResourcenessTests, BadResourcesInNestedContainers) {
fidl::ExperimentalFlags experimental_flags;
experimental_flags.SetFlag(fidl::ExperimentalFlags::Flag::kAllowNewSyntax);
for (const std::string& definition : {
"type Foo = struct { bad_member vector<vector<zx.handle>>; };",
"type Foo = struct { bad_member vector<vector<zx.handle:optional>>; };",
"type Foo = struct { bad_member vector<vector<client_end:Protocol>>; };",
"type Foo = struct { bad_member vector<vector<ResourceStruct>>; };",
"type Foo = struct { bad_member vector<vector<ResourceTable>>; };",
"type Foo = struct { bad_member vector<vector<ResourceUnion>>; };",
"type Foo = struct { bad_member "
"vector<array<vector<ResourceStruct>:optional,2>>:optional; };",
}) {
std::string fidl_library = R"FIDL(
library example;
using zx;
protocol Protocol {};
type ResourceStruct = resource struct {};
type ResourceTable = resource table {};
type ResourceUnion = resource union { 1: b bool; };
)FIDL" + definition + "\n";
auto library = WithLibraryZx(fidl_library, experimental_flags);
ASSERT_ERRORED_DURING_COMPILE(library, fidl::ErrTypeMustBeResource);
ASSERT_SUBSTR(library.errors()[0]->msg.c_str(), "Foo", "%s", fidl_library.c_str());
ASSERT_SUBSTR(library.errors()[0]->msg.c_str(), "bad_member", "%s", fidl_library.c_str());
;
}
}
TEST(ResourcenessTests, BadResourcesInNestedContainersOld) {
for (const std::string& definition : {
"struct Foo { vector<vector<zx.handle>> bad_member; };",
"struct Foo { vector<vector<zx.handle?>> bad_member; };",
"struct Foo { vector<vector<Protocol>> bad_member; };",
"struct Foo { vector<vector<ResourceStruct>> bad_member; };",
"struct Foo { vector<vector<ResourceTable>> bad_member; };",
"struct Foo { vector<vector<ResourceUnion>> bad_member; };",
"struct Foo { vector<array<vector<ResourceStruct>?>:2>? bad_member; };",
}) {
std::string fidl_library = R"FIDL(
library example;
using zx;
protocol Protocol {};
resource struct ResourceStruct {};
resource table ResourceTable {};
resource union ResourceUnion { 1: bool b; };
)FIDL" + definition + "\n";
auto library = WithLibraryZx(fidl_library);
ASSERT_ERRORED_DURING_COMPILE(library, fidl::ErrTypeMustBeResource);
ASSERT_SUBSTR(library.errors()[0]->msg.c_str(), "Foo", "%s", fidl_library.c_str());
ASSERT_SUBSTR(library.errors()[0]->msg.c_str(), "bad_member", "%s", fidl_library.c_str());
;
}
}
TEST(ResourcenessTests, BadMultipleResourceTypesInValueType) {
fidl::ExperimentalFlags experimental_flags;
experimental_flags.SetFlag(fidl::ExperimentalFlags::Flag::kAllowNewSyntax);
auto library = WithLibraryZx(R"FIDL(
library example;
using zx;
type Foo = struct {
first zx.handle;
second zx.handle:optional;
third ResourceStruct;
};
type ResourceStruct = resource struct {};
)FIDL",
experimental_flags);
ASSERT_FALSE(library.Compile());
const auto& errors = library.errors();
ASSERT_EQ(errors.size(), 3);
ASSERT_ERR(errors[0], fidl::ErrTypeMustBeResource);
ASSERT_SUBSTR(errors[0]->msg.c_str(), "Foo");
ASSERT_SUBSTR(errors[0]->msg.c_str(), "first");
ASSERT_ERR(errors[1], fidl::ErrTypeMustBeResource);
ASSERT_SUBSTR(errors[1]->msg.c_str(), "Foo");
ASSERT_SUBSTR(errors[1]->msg.c_str(), "second");
ASSERT_ERR(errors[2], fidl::ErrTypeMustBeResource);
ASSERT_SUBSTR(errors[2]->msg.c_str(), "Foo");
ASSERT_SUBSTR(errors[2]->msg.c_str(), "third");
}
TEST(ResourcenessTests, BadMultipleResourceTypesInValueTypeOld) {
std::string fidl_library = R"FIDL(
library example;
using zx;
struct Foo {
zx.handle first;
zx.handle? second;
ResourceStruct third;
};
resource struct ResourceStruct {};
)FIDL";
auto library = WithLibraryZx(fidl_library);
ASSERT_FALSE(library.Compile());
const auto& errors = library.errors();
ASSERT_EQ(errors.size(), 3);
ASSERT_ERR(errors[0], fidl::ErrTypeMustBeResource);
ASSERT_SUBSTR(errors[0]->msg.c_str(), "Foo");
ASSERT_SUBSTR(errors[0]->msg.c_str(), "first");
ASSERT_ERR(errors[1], fidl::ErrTypeMustBeResource);
ASSERT_SUBSTR(errors[1]->msg.c_str(), "Foo");
ASSERT_SUBSTR(errors[1]->msg.c_str(), "second");
ASSERT_ERR(errors[2], fidl::ErrTypeMustBeResource);
ASSERT_SUBSTR(errors[2]->msg.c_str(), "Foo");
ASSERT_SUBSTR(errors[2]->msg.c_str(), "third");
}
TEST(ResourcenessTests, GoodTransitiveResourceMember) {
std::string fidl_library = R"FIDL(
library example;
resource struct Top {
Middle middle;
};
resource struct Middle {
Bottom bottom;
};
resource struct Bottom {};
)FIDL";
TestLibrary library(fidl_library);
ASSERT_COMPILED_AND_CONVERT(library);
EXPECT_EQ(library.LookupStruct("Top")->resourceness, fidl::types::Resourceness::kResource);
}
TEST(ResourcenessTests, BadTransitiveResourceMember) {
fidl::ExperimentalFlags experimental_flags;
experimental_flags.SetFlag(fidl::ExperimentalFlags::Flag::kAllowNewSyntax);
TestLibrary library(R"FIDL(
library example;
type Top = struct {
middle Middle;
};
type Middle = struct {
bottom Bottom;
};
type Bottom = resource struct {};
)FIDL",
experimental_flags);
ASSERT_ERRORED_TWICE_DURING_COMPILE(library, fidl::ErrTypeMustBeResource,
fidl::ErrTypeMustBeResource);
// `Middle` must be a resource because it includes `bottom`, a *nominal* resource.
ASSERT_SUBSTR(library.errors()[0]->msg.c_str(), "Middle");
ASSERT_SUBSTR(library.errors()[0]->msg.c_str(), "bottom");
// `Top` must be a resource because it includes `middle`, an *effective* resource.
ASSERT_SUBSTR(library.errors()[1]->msg.c_str(), "Top");
ASSERT_SUBSTR(library.errors()[1]->msg.c_str(), "middle");
}
TEST(ResourcenessTests, BadTransitiveResourceMemberOld) {
std::string fidl_library = R"FIDL(
library example;
struct Top {
Middle middle;
};
struct Middle {
Bottom bottom;
};
resource struct Bottom {};
)FIDL";
TestLibrary library(fidl_library);
ASSERT_ERRORED_TWICE_DURING_COMPILE(library, fidl::ErrTypeMustBeResource,
fidl::ErrTypeMustBeResource);
// `Middle` must be a resource because it includes `bottom`, a *nominal* resource.
ASSERT_SUBSTR(library.errors()[0]->msg.c_str(), "Middle");
ASSERT_SUBSTR(library.errors()[0]->msg.c_str(), "bottom");
// `Top` must be a resource because it includes `middle`, an *effective* resource.
ASSERT_SUBSTR(library.errors()[1]->msg.c_str(), "Top");
ASSERT_SUBSTR(library.errors()[1]->msg.c_str(), "middle");
}
TEST(ResourcenessTests, GoodRecursiveValueTypes) {
std::string fidl_library = R"FIDL(
library example;
struct Ouro {
Boros? b;
};
struct Boros {
Ouro? o;
};
)FIDL";
TestLibrary library(fidl_library);
ASSERT_COMPILED_AND_CONVERT(library);
}
TEST(ResourcenessTests, GoodRecursiveResourceTypes) {
std::string fidl_library = R"FIDL(
library example;
resource struct Ouro {
Boros? b;
};
resource struct Boros {
Ouro? o;
};
)FIDL";
TestLibrary library(fidl_library);
ASSERT_COMPILED_AND_CONVERT(library);
}
TEST(ResourcenessTests, BadRecursiveResourceTypes) {
fidl::ExperimentalFlags experimental_flags;
experimental_flags.SetFlag(fidl::ExperimentalFlags::Flag::kAllowNewSyntax);
TestLibrary library(R"FIDL(
library example;
type Ouro = resource struct {
b Boros:optional;
};
type Boros = struct {
bad_member Ouro:optional;
};
)FIDL",
experimental_flags);
ASSERT_ERRORED_DURING_COMPILE(library, fidl::ErrTypeMustBeResource);
ASSERT_SUBSTR(library.errors()[0]->msg.c_str(), "Boros");
ASSERT_SUBSTR(library.errors()[0]->msg.c_str(), "bad_member");
}
TEST(ResourcenessTests, BadRecursiveResourceTypesOld) {
std::string fidl_library = R"FIDL(
library example;
resource struct Ouro {
Boros? b;
};
struct Boros {
Ouro? bad_member;
};
)FIDL";
TestLibrary library(fidl_library);
ASSERT_ERRORED_DURING_COMPILE(library, fidl::ErrTypeMustBeResource);
ASSERT_SUBSTR(library.errors()[0]->msg.c_str(), "Boros");
ASSERT_SUBSTR(library.errors()[0]->msg.c_str(), "bad_member");
}
TEST(ResourcenessTests, GoodStrictResourceOrderIndependent) {
TestLibrary library(R"FIDL(
library example;
strict resource union SR { 1: bool b; };
resource strict union RS { 1: bool b; };
)FIDL");
ASSERT_COMPILED_AND_CONVERT(library);
const auto strict_resource = library.LookupUnion("SR");
EXPECT_EQ(strict_resource->strictness, fidl::types::Strictness::kStrict);
EXPECT_EQ(strict_resource->resourceness, fidl::types::Resourceness::kResource);
const auto resource_strict = library.LookupUnion("RS");
EXPECT_EQ(resource_strict->strictness, fidl::types::Strictness::kStrict);
EXPECT_EQ(resource_strict->resourceness, fidl::types::Resourceness::kResource);
}
} // namespace