blob: e57faf89b4f5f7f033d5ceb5fd16ea4e4a949e67 [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 <gtest/gtest.h>
#include "tools/fidl/fidlc/src/diagnostics.h"
#include "tools/fidl/fidlc/src/names.h"
#include "tools/fidl/fidlc/tests/test_library.h"
namespace fidlc {
namespace {
TEST(AliasTests, BadDuplicateAlias) {
TestLibrary library(R"FIDL(
library example;
type Message = struct {
f alias_of_int16;
};
alias alias_of_int16 = int16;
alias alias_of_int16 = int16;
)FIDL");
library.ExpectFail(ErrNameCollision, Element::Kind::kAlias, "alias_of_int16",
Element::Kind::kAlias, "example.fidl:8:7");
ASSERT_COMPILER_DIAGNOSTICS(library);
}
TEST(AliasTests, GoodAliasOfStruct) {
TestLibrary library(R"FIDL(
library example;
type TypeDecl = struct {
field1 uint16;
field2 uint16;
};
alias AliasOfDecl = TypeDecl;
)FIDL");
ASSERT_COMPILED(library);
auto type_decl = library.LookupStruct("TypeDecl");
ASSERT_NE(type_decl, nullptr);
EXPECT_EQ(type_decl->members.size(), 2u);
ASSERT_TRUE(library.HasAlias("AliasOfDecl"));
}
TEST(AliasTests, GoodPrimitive) {
TestLibrary library(R"FIDL(
library example;
type Message = struct {
f alias_of_int16;
};
alias alias_of_int16 = int16;
)FIDL");
ASSERT_COMPILED(library);
auto msg = library.LookupStruct("Message");
ASSERT_NE(msg, nullptr);
ASSERT_EQ(msg->members.size(), 1u);
auto type = msg->members[0].type_ctor->type;
ASSERT_EQ(type->kind, Type::Kind::kPrimitive);
ASSERT_FALSE(type->IsNullable());
auto primitive_type = static_cast<const PrimitiveType*>(type);
ASSERT_EQ(primitive_type->subtype, PrimitiveSubtype::kInt16);
auto invocation = msg->members[0].type_ctor->resolved_params;
ASSERT_NE(invocation.from_alias, nullptr);
EXPECT_EQ(FullyQualifiedName(invocation.from_alias->name), "example/alias_of_int16");
EXPECT_EQ(invocation.element_type_resolved, nullptr);
EXPECT_EQ(invocation.size_resolved, nullptr);
EXPECT_EQ(invocation.nullability, Nullability::kNonnullable);
}
TEST(AliasTests, GoodPrimitiveAliasBeforeUse) {
TestLibrary library(R"FIDL(
library example;
alias alias_of_int16 = int16;
type Message = struct {
f alias_of_int16;
};
)FIDL");
ASSERT_COMPILED(library);
auto msg = library.LookupStruct("Message");
ASSERT_NE(msg, nullptr);
ASSERT_EQ(msg->members.size(), 1u);
auto type = msg->members[0].type_ctor->type;
ASSERT_EQ(type->kind, Type::Kind::kPrimitive);
ASSERT_FALSE(type->IsNullable());
auto primitive_type = static_cast<const PrimitiveType*>(type);
ASSERT_EQ(primitive_type->subtype, PrimitiveSubtype::kInt16);
auto invocation = msg->members[0].type_ctor->resolved_params;
ASSERT_NE(invocation.from_alias, nullptr);
EXPECT_EQ(FullyQualifiedName(invocation.from_alias->name), "example/alias_of_int16");
EXPECT_EQ(invocation.element_type_resolved, nullptr);
EXPECT_EQ(invocation.size_resolved, nullptr);
EXPECT_EQ(invocation.nullability, Nullability::kNonnullable);
}
TEST(AliasTests, BadSelfReferentialAlias) {
TestLibrary library(R"FIDL(
library example;
alias uint32 = uint32;
type Message = struct {
f uint32;
};
)FIDL");
library.ExpectFail(ErrIncludeCycle, "alias 'uint32' -> alias 'uint32'");
ASSERT_COMPILER_DIAGNOSTICS(library);
}
TEST(AliasTests, BadNoOptionalOnPrimitive) {
TestLibrary library;
library.AddFile("bad/fi-0156.test.fidl");
library.ExpectFail(ErrCannotBeOptional, "int16");
ASSERT_COMPILER_DIAGNOSTICS(library);
}
TEST(AliasTests, BadMultipleConstraintsOnPrimitive) {
TestLibrary library(R"FIDL(
library test.optionals;
type Bad = struct {
opt_num int64:<1, 2, 3>;
};
)FIDL");
library.ExpectFail(ErrTooManyConstraints, "int64", 0, 3);
ASSERT_COMPILER_DIAGNOSTICS(library);
}
TEST(AliasTests, BadInvalidSizeConstraintType) {
TestLibrary library;
library.AddFile("bad/fi-0101-a.test.fidl");
library.ExpectFail(ErrTypeCannotBeConvertedToType, "\"255\"", "string:3", "uint32");
library.ExpectFail(ErrCouldNotResolveSizeBound);
ASSERT_COMPILER_DIAGNOSTICS(library);
}
TEST(AliasTests, BadInvalidSizeConstraintIsNotValue) {
TestLibrary library;
library.AddFile("bad/fi-0101-b.test.fidl");
library.ExpectFail(ErrCouldNotResolveSizeBound);
ASSERT_COMPILER_DIAGNOSTICS(library);
}
TEST(AliasTests, BadNoOptionalOnAliasedPrimitive) {
TestLibrary library(R"FIDL(
library test.optionals;
alias alias = int64;
type Bad = struct {
opt_num alias:optional;
};
)FIDL");
library.ExpectFail(ErrCannotBeOptional, "alias");
ASSERT_COMPILER_DIAGNOSTICS(library);
}
TEST(AliasTests, GoodVectorParameterizedOnDecl) {
TestLibrary library(R"FIDL(
library example;
type Message = struct {
f alias_of_vector_of_string;
};
alias alias_of_vector_of_string = vector<string>;
)FIDL");
ASSERT_COMPILED(library);
auto msg = library.LookupStruct("Message");
ASSERT_NE(msg, nullptr);
ASSERT_EQ(msg->members.size(), 1u);
auto type = msg->members[0].type_ctor->type;
ASSERT_EQ(type->kind, Type::Kind::kVector);
ASSERT_FALSE(type->IsNullable());
auto vector_type = static_cast<const VectorType*>(type);
ASSERT_EQ(vector_type->element_type->kind, Type::Kind::kString);
ASSERT_EQ(vector_type->ElementCount(), SizeValue::Max().value);
auto invocation = msg->members[0].type_ctor->resolved_params;
ASSERT_NE(invocation.from_alias, nullptr);
EXPECT_EQ(FullyQualifiedName(invocation.from_alias->name), "example/alias_of_vector_of_string");
EXPECT_EQ(invocation.element_type_resolved, nullptr);
EXPECT_EQ(invocation.size_resolved, nullptr);
EXPECT_EQ(invocation.nullability, Nullability::kNonnullable);
}
TEST(AliasTests, BadVectorParameterizedOnUse) {
TestLibrary library(R"FIDL(
library example;
type Message = struct {
f alias_of_vector<uint8>;
};
alias alias_of_vector = vector;
)FIDL");
library.ExpectFail(ErrWrongNumberOfLayoutParameters, "alias_of_vector", 0, 1);
library.ExpectFail(ErrWrongNumberOfLayoutParameters, "vector", 1, 0);
ASSERT_COMPILER_DIAGNOSTICS(library);
}
TEST(AliasTests, BadVectorBoundedOnDecl) {
TestLibrary library(R"FIDL(
library example;
type Message = struct {
f alias_of_vector_max_8<string>;
};
alias alias_of_vector_max_8 = vector:8;
)FIDL");
library.ExpectFail(ErrWrongNumberOfLayoutParameters, "alias_of_vector_max_8", 0, 1);
library.ExpectFail(ErrWrongNumberOfLayoutParameters, "vector", 1, 0);
ASSERT_COMPILER_DIAGNOSTICS(library);
}
TEST(AliasTests, GoodVectorBoundedOnUse) {
TestLibrary library(R"FIDL(
library example;
type Message = struct {
f alias_of_vector_of_string:8;
};
alias alias_of_vector_of_string = vector<string>;
)FIDL");
ASSERT_COMPILED(library);
auto msg = library.LookupStruct("Message");
ASSERT_NE(msg, nullptr);
ASSERT_EQ(msg->members.size(), 1u);
auto type = msg->members[0].type_ctor->type;
ASSERT_EQ(type->kind, Type::Kind::kVector);
ASSERT_FALSE(type->IsNullable());
auto vector_type = static_cast<const VectorType*>(type);
ASSERT_EQ(vector_type->element_type->kind, Type::Kind::kString);
ASSERT_EQ(vector_type->ElementCount(), 8u);
auto invocation = msg->members[0].type_ctor->resolved_params;
ASSERT_NE(invocation.from_alias, nullptr);
EXPECT_EQ(FullyQualifiedName(invocation.from_alias->name), "example/alias_of_vector_of_string");
EXPECT_EQ(invocation.element_type_resolved, nullptr);
EXPECT_NE(invocation.size_resolved, nullptr);
EXPECT_EQ(invocation.size_resolved->value, 8u);
EXPECT_EQ(invocation.nullability, Nullability::kNonnullable);
}
TEST(AliasTests, GoodUnboundedVectorBoundTwice) {
TestLibrary library;
library.AddFile("good/fi-0158.test.fidl");
ASSERT_COMPILED(library);
}
TEST(AliasTests, GoodVectorNullableOnDecl) {
TestLibrary library(R"FIDL(
library example;
type Message = struct {
f alias_of_vector_of_string_nullable;
};
alias alias_of_vector_of_string_nullable = vector<string>:optional;
)FIDL");
ASSERT_COMPILED(library);
auto msg = library.LookupStruct("Message");
ASSERT_NE(msg, nullptr);
ASSERT_EQ(msg->members.size(), 1u);
auto type = msg->members[0].type_ctor->type;
ASSERT_EQ(type->kind, Type::Kind::kVector);
ASSERT_TRUE(type->IsNullable());
auto vector_type = static_cast<const VectorType*>(type);
ASSERT_EQ(vector_type->element_type->kind, Type::Kind::kString);
ASSERT_EQ(vector_type->ElementCount(), SizeValue::Max().value);
auto invocation = msg->members[0].type_ctor->resolved_params;
ASSERT_NE(invocation.from_alias, nullptr);
EXPECT_EQ(FullyQualifiedName(invocation.from_alias->name),
"example/alias_of_vector_of_string_nullable");
EXPECT_EQ(invocation.element_type_resolved, nullptr);
EXPECT_EQ(invocation.size_resolved, nullptr);
EXPECT_EQ(invocation.nullability, Nullability::kNonnullable);
}
TEST(AliasTests, GoodVectorNullableOnUse) {
TestLibrary library(R"FIDL(
library example;
type Message = struct {
f alias_of_vector_of_string:optional;
};
alias alias_of_vector_of_string = vector<string>;
)FIDL");
ASSERT_COMPILED(library);
auto msg = library.LookupStruct("Message");
ASSERT_NE(msg, nullptr);
ASSERT_EQ(msg->members.size(), 1u);
auto type = msg->members[0].type_ctor->type;
ASSERT_EQ(type->kind, Type::Kind::kVector);
ASSERT_TRUE(type->IsNullable());
auto vector_type = static_cast<const VectorType*>(type);
ASSERT_EQ(vector_type->element_type->kind, Type::Kind::kString);
ASSERT_EQ(vector_type->ElementCount(), SizeValue::Max().value);
auto invocation = msg->members[0].type_ctor->resolved_params;
ASSERT_NE(invocation.from_alias, nullptr);
EXPECT_EQ(FullyQualifiedName(invocation.from_alias->name), "example/alias_of_vector_of_string");
EXPECT_EQ(invocation.element_type_resolved, nullptr);
EXPECT_EQ(invocation.size_resolved, nullptr);
EXPECT_EQ(invocation.nullability, Nullability::kNullable);
}
TEST(AliasTests, BadCannotParameterizeTwice) {
TestLibrary library(R"FIDL(
library example;
type Message = struct {
f alias_of_vector_of_string<string>;
};
alias alias_of_vector_of_string = vector<string>;
)FIDL");
library.ExpectFail(ErrWrongNumberOfLayoutParameters, "alias_of_vector_of_string", 0, 1);
ASSERT_COMPILER_DIAGNOSTICS(library);
}
TEST(AliasTests, BadCannotBoundTwice) {
TestLibrary library;
library.AddFile("bad/fi-0158.test.fidl");
library.ExpectFail(ErrCannotBoundTwice, "ByteVec256");
ASSERT_COMPILER_DIAGNOSTICS(library);
}
TEST(AliasTests, BadCannotNullTwice) {
TestLibrary library;
library.AddFile("bad/fi-0160.test.fidl");
library.ExpectFail(ErrCannotIndicateOptionalTwice, "MyAlias");
ASSERT_COMPILER_DIAGNOSTICS(library);
}
TEST(AliasTests, GoodMultiFileAliasReference) {
TestLibrary library;
library.AddSource("first.fidl", R"FIDL(
library example;
type Protein = struct {
amino_acids AminoAcids;
};
)FIDL");
library.AddSource("second.fidl", R"FIDL(
library example;
alias AminoAcids = vector<uint64>:32;
)FIDL");
ASSERT_COMPILED(library);
}
TEST(AliasTests, GoodMultiFileNullableAliasReference) {
TestLibrary library;
library.AddSource("first.fidl", R"FIDL(
library example;
type Protein = struct {
amino_acids AminoAcids:optional;
};
)FIDL");
library.AddSource("second.fidl", R"FIDL(
library example;
alias AminoAcids = vector<uint64>:32;
)FIDL");
ASSERT_COMPILED(library);
}
TEST(AliasTests, BadRecursiveAlias) {
TestLibrary library(R"FIDL(
library example;
alias TheAlias = TheStruct;
type TheStruct = struct {
many_mini_me vector<TheAlias>;
};
)FIDL");
library.ExpectFail(ErrIncludeCycle, "alias 'TheAlias' -> struct 'TheStruct' -> alias 'TheAlias'");
ASSERT_COMPILER_DIAGNOSTICS(library);
}
TEST(AliasTests, BadCompoundIdentifier) {
TestLibrary library(R"FIDL(
library example;
alias foo.bar.baz = uint8;
)FIDL");
library.ExpectFail(ErrUnexpectedTokenOfKind, Token::KindAndSubkind(Token::Kind::kDot),
Token::KindAndSubkind(Token::Kind::kEqual));
ASSERT_COMPILER_DIAGNOSTICS(library);
}
TEST(AliasTests, GoodUsingLibrary) {
SharedAmongstLibraries shared;
TestLibrary dependency(&shared, "dependent.fidl", R"FIDL(
library dependent;
type Bar = struct {
s int8;
};
)FIDL");
ASSERT_COMPILED(dependency);
TestLibrary library(&shared, "example.fidl", R"FIDL(
library example;
using dependent;
alias Bar2 = dependent.Bar;
)FIDL");
ASSERT_COMPILED(library);
}
} // namespace
} // namespace fidlc