blob: ca625067b3d1af357dad7e052608e4b92748cb61 [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 <sstream>
#include <gtest/gtest.h>
#include "tools/fidl/fidlc/src/diagnostics.h"
#include "tools/fidl/fidlc/src/utils.h"
#include "tools/fidl/fidlc/tests/test_library.h"
namespace fidlc {
namespace {
TEST(CanonicalNamesTests, BadCollision) {
TestLibrary library;
library.AddFile("bad/fi-0035.test.fidl");
library.ExpectFail(ErrNameCollisionCanonical, Element::Kind::kProtocol, "Color",
Element::Kind::kConst, "COLOR", "bad/fi-0035.test.fidl:6:7", "color");
ASSERT_COMPILER_DIAGNOSTICS(library);
}
TEST(CanonicalNamesTests, GoodCollisionFixRename) {
TestLibrary library;
library.AddFile("good/fi-0035.test.fidl");
ASSERT_COMPILED(library);
}
TEST(CanonicalNamesTests, GoodTopLevel) {
TestLibrary library(R"FIDL(
library example;
alias foobar = bool;
const f_oobar bool = true;
type fo_obar = struct {};
type foo_bar = struct {};
type foob_ar = table {};
type fooba_r = strict union {
1: x bool;
};
type FoObAr = strict enum {
A = 1;
};
type FooBaR = strict bits {
A = 1;
};
protocol FoObaR {};
service FOoBAR {};
)FIDL");
ASSERT_COMPILED(library);
}
TEST(CanonicalNamesTests, GoodAttributes) {
TestLibrary library(R"FIDL(
library example;
@foobar
@foo_bar
@f_o_o_b_a_r
type Example = struct {};
)FIDL");
ASSERT_COMPILED(library);
}
TEST(CanonicalNamesTests, GoodAttributeArguments) {
TestLibrary library(R"FIDL(
library example;
@some_attribute(foobar="", foo_bar="", f_o_o_b_a_r="")
type Example = struct {};
)FIDL");
ASSERT_COMPILED(library);
}
TEST(CanonicalNamesTests, GoodStructMembers) {
TestLibrary library(R"FIDL(
library example;
type Example = struct {
foobar bool;
foo_bar bool;
f_o_o_b_a_r bool;
};
)FIDL");
ASSERT_COMPILED(library);
}
TEST(CanonicalNamesTests, GoodTableMembers) {
TestLibrary library(R"FIDL(
library example;
type Example = table {
1: foobar bool;
2: foo_bar bool;
3: f_o_o_b_a_r bool;
};
)FIDL");
ASSERT_COMPILED(library);
}
TEST(CanonicalNamesTests, GoodUnionMembers) {
TestLibrary library(R"FIDL(
library example;
type Example = strict union {
1: foobar bool;
2: foo_bar bool;
3: f_o_o_b_a_r bool;
};
)FIDL");
ASSERT_COMPILED(library);
}
TEST(CanonicalNamesTests, GoodEnumMembers) {
TestLibrary library(R"FIDL(
library example;
type Example = strict enum {
foobar = 1;
foo_bar = 2;
f_o_o_b_a_r = 3;
};
)FIDL");
ASSERT_COMPILED(library);
}
TEST(CanonicalNamesTests, GoodBitsMembers) {
TestLibrary library(R"FIDL(
library example;
type Example = strict bits {
foobar = 1;
foo_bar = 2;
f_o_o_b_a_r = 4;
};
)FIDL");
ASSERT_COMPILED(library);
}
TEST(CanonicalNamesTests, GoodProtocolMethods) {
TestLibrary library(R"FIDL(
library example;
protocol Example {
foobar() -> ();
foo_bar() -> ();
f_o_o_b_a_r() -> ();
};
)FIDL");
ASSERT_COMPILED(library);
}
TEST(CanonicalNamesTests, GoodMethodParameters) {
TestLibrary library(R"FIDL(
library example;
protocol Example {
example(struct {
foobar bool;
foo_bar bool;
f_o_o_b_a_r bool;
}) -> ();
};
)FIDL");
ASSERT_COMPILED(library);
}
TEST(CanonicalNamesTests, GoodMethodResults) {
TestLibrary library(R"FIDL(
library example;
protocol Example {
example() -> (struct {
foobar bool;
foo_bar bool;
f_o_o_b_a_r bool;
});
};
)FIDL");
ASSERT_COMPILED(library);
}
TEST(CanonicalNamesTests, GoodServiceMembers) {
TestLibrary library(R"FIDL(
library example;
protocol P {};
service Example {
foobar client_end:P;
foo_bar client_end:P;
f_o_o_b_a_r client_end:P;
};
)FIDL");
ASSERT_COMPILED(library);
}
TEST(CanonicalNamesTests, GoodResourceProperties) {
TestLibrary library(R"FIDL(
library example;
resource_definition Example {
properties {
// This property is required for compilation, but is not otherwise under test.
subtype flexible enum : uint32 {};
foobar uint32;
foo_bar uint32;
f_o_o_b_a_r uint32;
};
};
)FIDL");
ASSERT_COMPILED(library);
}
TEST(CanonicalNamesTests, GoodUpperAcronym) {
TestLibrary library(R"FIDL(
library example;
type HTTPServer = struct {};
type httpserver = struct {};
)FIDL");
ASSERT_COMPILED(library);
}
TEST(CanonicalNamesTests, GoodCurrentLibrary) {
TestLibrary library(R"FIDL(
library example;
type example = struct {};
)FIDL");
ASSERT_COMPILED(library);
}
TEST(CanonicalNamesTests, GoodDependentLibrary) {
SharedAmongstLibraries shared;
TestLibrary dependency(&shared, "foobar.fidl", R"FIDL(
library foobar;
type Something = struct {};
)FIDL");
ASSERT_COMPILED(dependency);
TestLibrary library(&shared, "example.fidl", R"FIDL(
library example;
using foobar;
alias f_o_o_b_a_r = foobar.Something;
const f_oobar bool = true;
type fo_obar = struct {};
type foo_bar = struct {};
type foob_ar = table {};
type fooba_r = union { 1: x bool; };
type FoObAr = enum { A = 1; };
type FooBaR = bits { A = 1; };
protocol FoObaR {};
service FOoBAR {};
)FIDL");
ASSERT_COMPILED(library);
}
TEST(CanonicalNamesTests, BadTopLevel) {
using Kind = Element::Kind;
const std::pair<Kind, std::string_view> lower[] = {
{Kind::kAlias, "alias fooBar = bool;"},
{Kind::kConst, "const fooBar bool = true;"},
{Kind::kStruct, "type fooBar = struct {};"},
{Kind::kTable, "type fooBar = table {};"},
{Kind::kUnion, "type fooBar = union { 1: x bool; };"},
{Kind::kEnum, "type fooBar = enum { A = 1; };"},
{Kind::kBits, "type fooBar = bits { A = 1; };"},
{Kind::kProtocol, "protocol fooBar {};"},
{Kind::kService, "service fooBar {};"},
};
const std::pair<Kind, std::string_view> upper[] = {
{Kind::kAlias, "alias FooBar = bool;"},
{Kind::kConst, "const FooBar bool = true;"},
{Kind::kStruct, "type FooBar = struct {};"},
{Kind::kTable, "type FooBar = table {};"},
{Kind::kUnion, "type FooBar = union { 1: x bool; };"},
{Kind::kEnum, "type FooBar = enum { A = 1; };"},
{Kind::kBits, "type FooBar = bits { A = 1; };"},
{Kind::kProtocol, "protocol FooBar {};"},
{Kind::kService, "service FooBar {};"},
};
for (auto& [lowerKind, lowerLine] : lower) {
for (auto& [upperKind, upperLine] : upper) {
std::ostringstream s;
s << "library example;\n" << lowerLine << '\n' << upperLine << '\n';
const auto fidl = s.str();
SCOPED_TRACE(fidl);
TestLibrary library(fidl);
char location[20];
snprintf(location, sizeof location, "example.fidl:3:%zu", 1 + upperLine.find("FooBar"));
library.ExpectFail(ErrNameCollisionCanonical, lowerKind, "fooBar", upperKind, "FooBar",
location, "foo_bar");
ASSERT_COMPILER_DIAGNOSTICS(library);
}
}
}
TEST(CanonicalNamesTests, BadAttributes) {
TestLibrary library(R"FIDL(
library example;
@fooBar
@FooBar
type Example = struct {};
)FIDL");
library.ExpectFail(ErrDuplicateAttributeCanonical, "FooBar", "fooBar", "example.fidl:4:2",
"foo_bar");
ASSERT_COMPILER_DIAGNOSTICS(library);
}
TEST(CanonicalNamesTests, BadAttributeArguments) {
TestLibrary library(R"FIDL(
library example;
@some_attribute(fooBar="", FooBar="")
type Example = struct {};
)FIDL");
library.ExpectFail(ErrDuplicateAttributeArgCanonical, "some_attribute", "FooBar", "fooBar",
"example.fidl:4:17", "foo_bar");
ASSERT_COMPILER_DIAGNOSTICS(library);
}
TEST(CanonicalNamesTests, BadStructMembers) {
TestLibrary library(R"FIDL(
library example;
type MyStruct = struct {
myStructMember string;
MyStructMember uint64;
};
)FIDL");
library.ExpectFail(ErrNameCollisionCanonical, Element::Kind::kStructMember, "MyStructMember",
Element::Kind::kStructMember, "myStructMember", "example.fidl:5:5",
"my_struct_member");
ASSERT_COMPILER_DIAGNOSTICS(library);
}
TEST(CanonicalNamesTests, BadTableMembers) {
TestLibrary library(R"FIDL(
library example;
type MyTable = table {
1: myField bool;
2: MyField bool;
};
)FIDL");
library.ExpectFail(ErrNameCollisionCanonical, Element::Kind::kTableMember, "MyField",
Element::Kind::kTableMember, "myField", "example.fidl:5:8", "my_field");
ASSERT_COMPILER_DIAGNOSTICS(library);
}
TEST(CanonicalNamesTests, BadUnionMembers) {
TestLibrary library(R"FIDL(
library example;
type MyUnion = union {
1: myVariant bool;
2: MyVariant bool;
};
)FIDL");
library.ExpectFail(ErrNameCollisionCanonical, Element::Kind::kUnionMember, "MyVariant",
Element::Kind::kUnionMember, "myVariant", "example.fidl:5:8", "my_variant");
ASSERT_COMPILER_DIAGNOSTICS(library);
}
TEST(CanonicalNamesTests, BadEnumMembers) {
TestLibrary library(R"FIDL(
library example;
type Example = enum {
fooBar = 1;
FooBar = 2;
};
)FIDL");
library.ExpectFail(ErrNameCollisionCanonical, Element::Kind::kEnumMember, "FooBar",
Element::Kind::kEnumMember, "fooBar", "example.fidl:5:3", "foo_bar");
ASSERT_COMPILER_DIAGNOSTICS(library);
}
TEST(CanonicalNamesTests, BadBitsMembers) {
TestLibrary library(R"FIDL(
library example;
type MyBits = bits {
fooBar = 1;
FooBar = 2;
};
)FIDL");
library.ExpectFail(ErrNameCollisionCanonical, Element::Kind::kBitsMember, "FooBar",
Element::Kind::kBitsMember, "fooBar", "example.fidl:5:5", "foo_bar");
ASSERT_COMPILER_DIAGNOSTICS(library);
}
TEST(CanonicalNamesTests, BadProtocolMethods) {
TestLibrary library(R"FIDL(
library example;
protocol MyProtocol {
strict myMethod() -> ();
strict MyMethod() -> ();
};
)FIDL");
library.ExpectFail(ErrNameCollisionCanonical, Element::Kind::kProtocolMethod, "MyMethod",
Element::Kind::kProtocolMethod, "myMethod",
library.find_source_span("myMethod"), "my_method");
ASSERT_COMPILER_DIAGNOSTICS(library);
}
TEST(CanonicalNamesTests, BadMethodParameters) {
TestLibrary library(R"FIDL(
library example;
protocol Example {
example(struct { fooBar bool; FooBar bool; }) -> ();
};
)FIDL");
library.ExpectFail(ErrNameCollisionCanonical, Element::Kind::kStructMember, "FooBar",
Element::Kind::kStructMember, "fooBar", "example.fidl:5:20", "foo_bar");
ASSERT_COMPILER_DIAGNOSTICS(library);
}
TEST(CanonicalNamesTests, BadMethodResults) {
TestLibrary library(R"FIDL(
library example;
protocol Example {
example() -> (struct { fooBar bool; FooBar bool; });
};
)FIDL");
library.ExpectFail(ErrNameCollisionCanonical, Element::Kind::kStructMember, "FooBar",
Element::Kind::kStructMember, "fooBar", "example.fidl:5:26", "foo_bar");
ASSERT_COMPILER_DIAGNOSTICS(library);
}
TEST(CanonicalNamesTests, BadServiceMembers) {
TestLibrary library(R"FIDL(
library example;
protocol MyProtocol {};
service MyService {
myServiceMember client_end:MyProtocol;
MyServiceMember client_end:MyProtocol;
};
)FIDL");
library.ExpectFail(ErrNameCollisionCanonical, Element::Kind::kServiceMember, "MyServiceMember",
Element::Kind::kServiceMember, "myServiceMember", "example.fidl:7:5",
"my_service_member");
ASSERT_COMPILER_DIAGNOSTICS(library);
}
TEST(CanonicalNamesTests, BadResourceProperties) {
TestLibrary library(R"FIDL(
library example;
resource_definition MyResource : uint32 {
properties {
subtype flexible enum : uint32 {};
rights uint32;
Rights uint32;
};
};
)FIDL");
library.ExpectFail(ErrNameCollisionCanonical, Element::Kind::kResourceProperty, "Rights",
Element::Kind::kResourceProperty, "rights", "example.fidl:7:9", "rights");
ASSERT_COMPILER_DIAGNOSTICS(library);
}
TEST(CanonicalNamesTests, BadMemberValues) {
TestLibrary library;
library.AddFile("bad/fi-0054.test.fidl");
library.ExpectFail(ErrMemberNotFound, "enum 'Enum'", "FOO_BAR");
ASSERT_COMPILER_DIAGNOSTICS(library);
}
TEST(CanonicalNamesTests, BadUpperAcronym) {
TestLibrary library(R"FIDL(
library example;
type HTTPServer = struct {};
type HttpServer = struct {};
)FIDL");
library.ExpectFail(ErrNameCollisionCanonical, Element::Kind::kStruct, "HttpServer",
Element::Kind::kStruct, "HTTPServer", "example.fidl:4:6", "http_server");
ASSERT_COMPILER_DIAGNOSTICS(library);
}
TEST(CanonicalNamesTests, BadDependentLibrary) {
SharedAmongstLibraries shared;
TestLibrary dependency(&shared, "foobar.fidl", R"FIDL(
library foobar;
type Something = struct {};
)FIDL");
ASSERT_COMPILED(dependency);
TestLibrary library(&shared, "lib.fidl", R"FIDL(
library example;
using foobar;
alias FOOBAR = foobar.Something;
)FIDL");
library.ExpectFail(ErrDeclNameConflictsWithLibraryImportCanonical, "FOOBAR", "foobar");
ASSERT_COMPILER_DIAGNOSTICS(library);
}
TEST(CanonicalNamesTests, BadVariousCollisions) {
const auto base_names = {
"a", "a1", "x_single_start", "single_end_x", "x_single_both_x", "single_x_middle",
};
const auto functions = {
to_lower_snake_case,
to_upper_snake_case,
to_lower_camel_case,
to_upper_camel_case,
};
for (const auto base_name : base_names) {
for (const auto f1 : functions) {
for (const auto f2 : functions) {
std::ostringstream s;
std::string name1 = f1(base_name);
std::string name2 = f2(base_name);
s << "library example;\ntype " << name1 << " = struct {};\ntype " << name2
<< " = struct {};";
auto fidl = s.str();
SCOPED_TRACE(fidl);
TestLibrary library(fidl);
if (name1 == name2) {
library.ExpectFail(ErrNameCollision, Element::Kind::kStruct, name1,
Element::Kind::kStruct, "example.fidl:2:6");
} else if (name1 < name2) {
// We compile name1 first, and see that name2 collides with it.
library.ExpectFail(ErrNameCollisionCanonical, Element::Kind::kStruct, name2,
Element::Kind::kStruct, name1, "example.fidl:2:6",
canonicalize(name1));
} else {
// We compile name2 first, and see that name1 collides with it.
library.ExpectFail(ErrNameCollisionCanonical, Element::Kind::kStruct, name1,
Element::Kind::kStruct, name2, "example.fidl:3:6",
canonicalize(name1));
}
ASSERT_COMPILER_DIAGNOSTICS(library);
}
}
}
}
TEST(CanonicalNamesTests, BadConsecutiveUnderscores) {
TestLibrary library(R"FIDL(
library example;
type it_is_the_same = struct {};
type it__is___the____same = struct {};
)FIDL");
library.ExpectFail(ErrNameCollisionCanonical, Element::Kind::kStruct, "it_is_the_same",
Element::Kind::kStruct, "it__is___the____same", "example.fidl:5:6",
"it_is_the_same");
ASSERT_COMPILER_DIAGNOSTICS(library);
}
TEST(CanonicalNamesTests, BadInconsistentTypeSpelling) {
const auto decl_templates = {
"alias %s = bool;",
"type %s = struct {};",
"type %s = struct {};",
"type %s = table {};",
"type %s = union { 1: x bool; };",
"type %s = enum { A = 1; };",
"type %s = bits { A = 1; };",
};
const auto use_template = "type Example = struct { val %s; };";
const auto names = {
std::make_pair("foo_bar", "FOO_BAR"),
std::make_pair("FOO_BAR", "foo_bar"),
std::make_pair("fooBar", "FooBar"),
};
for (const auto decl_template : decl_templates) {
for (const auto& [decl_name, use_name] : names) {
std::string decl(decl_template), use(use_template);
decl.replace(decl.find("%s"), 2, decl_name);
use.replace(use.find("%s"), 2, use_name);
std::ostringstream s;
s << "library example;\n" << decl << '\n' << use;
auto fidl = s.str();
SCOPED_TRACE(fidl);
TestLibrary library(fidl);
library.ExpectFail(ErrNameNotFound, use_name, "example");
ASSERT_COMPILER_DIAGNOSTICS(library);
}
}
}
TEST(CanonicalNamesTests, BadInconsistentConstSpelling) {
const auto names = {
std::make_pair("foo_bar", "FOO_BAR"),
std::make_pair("FOO_BAR", "foo_bar"),
std::make_pair("fooBar", "FooBar"),
};
for (const auto& [decl_name, use_name] : names) {
std::ostringstream s;
s << "library example;\n"
<< "const " << decl_name << " bool = false;\n"
<< "const EXAMPLE bool = " << use_name << ";";
auto fidl = s.str();
TestLibrary library(fidl);
library.ExpectFail(ErrNameNotFound, use_name, "example");
ASSERT_COMPILER_DIAGNOSTICS(library);
}
}
TEST(CanonicalNamesTests, BadInconsistentEnumMemberSpelling) {
const auto names = {
std::make_pair("foo_bar", "FOO_BAR"),
std::make_pair("FOO_BAR", "foo_bar"),
std::make_pair("fooBar", "FooBar"),
};
for (const auto& [decl_name, use_name] : names) {
std::ostringstream s;
s << "library example;\n"
<< "type Enum = enum { " << decl_name << " = 1; };\n"
<< "const EXAMPLE Enum = Enum." << use_name << ";";
auto fidl = s.str();
SCOPED_TRACE(fidl);
TestLibrary library(fidl);
library.ExpectFail(ErrMemberNotFound, "enum 'Enum'", use_name);
ASSERT_COMPILER_DIAGNOSTICS(library);
}
}
TEST(CanonicalNamesTests, BadInconsistentBitsMemberSpelling) {
const auto names = {
std::make_pair("foo_bar", "FOO_BAR"),
std::make_pair("FOO_BAR", "foo_bar"),
std::make_pair("fooBar", "FooBar"),
};
for (const auto& [decl_name, use_name] : names) {
std::ostringstream s;
s << "library example;\n"
<< "type Bits = bits { " << decl_name << " = 1; };\n"
<< "const EXAMPLE Bits = Bits." << use_name << ";";
auto fidl = s.str();
SCOPED_TRACE(fidl);
TestLibrary library(fidl);
library.ExpectFail(ErrMemberNotFound, "bits 'Bits'", use_name);
ASSERT_COMPILER_DIAGNOSTICS(library);
}
}
} // namespace
} // namespace fidlc