blob: 230a78dc054f48c3aa2fc2f8d495577eb4bb915c [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/names.h>
#include <zxtest/zxtest.h>
#include "error_test.h"
#include "test_library.h"
namespace {
TEST(AliasTests, BadDuplicateAliasAndUsing) {
TestLibrary library(R"FIDL(
library example;
struct Message {
alias_of_int16 f;
};
alias alias_of_int16 = int16;
using alias_of_int16 = int16;
)FIDL");
ASSERT_FALSE(library.Compile());
const auto& errors = library.errors();
ASSERT_EQ(1, errors.size());
ASSERT_ERR(errors[0], fidl::ErrNameCollision);
}
TEST(AliasTests, GoodPrimitive) {
TestLibrary library(R"FIDL(
library example;
struct Message {
alias_of_int16 f;
};
alias alias_of_int16 = int16;
)FIDL");
ASSERT_TRUE(library.Compile());
auto msg = library.LookupStruct("Message");
ASSERT_NOT_NULL(msg);
ASSERT_EQ(msg->members.size(), 1);
auto type = msg->members[0].type_ctor->type;
ASSERT_EQ(type->kind, fidl::flat::Type::Kind::kPrimitive);
ASSERT_EQ(type->nullability, fidl::types::Nullability::kNonnullable);
ASSERT_TRUE(msg->members[0].type_ctor->from_type_alias);
auto primitive_type = static_cast<const fidl::flat::PrimitiveType*>(type);
ASSERT_EQ(primitive_type->subtype, fidl::types::PrimitiveSubtype::kInt16);
auto from_type_alias = msg->members[0].type_ctor->from_type_alias.value();
EXPECT_STR_EQ(fidl::NameFlatName(from_type_alias.decl->name).c_str(), "example/alias_of_int16");
EXPECT_NULL(from_type_alias.maybe_arg_type);
EXPECT_NULL(from_type_alias.maybe_size);
EXPECT_EQ(from_type_alias.nullability, fidl::types::Nullability::kNonnullable);
}
TEST(AliasTests, GoodPrimitiveTypeAliasBeforeUse) {
TestLibrary library(R"FIDL(
library example;
alias alias_of_int16 = int16;
struct Message {
alias_of_int16 f;
};
)FIDL");
ASSERT_TRUE(library.Compile());
auto msg = library.LookupStruct("Message");
ASSERT_NOT_NULL(msg);
ASSERT_EQ(msg->members.size(), 1);
auto type = msg->members[0].type_ctor->type;
ASSERT_EQ(type->kind, fidl::flat::Type::Kind::kPrimitive);
ASSERT_EQ(type->nullability, fidl::types::Nullability::kNonnullable);
auto primitive_type = static_cast<const fidl::flat::PrimitiveType*>(type);
ASSERT_EQ(primitive_type->subtype, fidl::types::PrimitiveSubtype::kInt16);
auto from_type_alias = msg->members[0].type_ctor->from_type_alias.value();
EXPECT_STR_EQ(fidl::NameFlatName(from_type_alias.decl->name).c_str(), "example/alias_of_int16");
EXPECT_NULL(from_type_alias.maybe_arg_type);
EXPECT_NULL(from_type_alias.maybe_size);
EXPECT_EQ(from_type_alias.nullability, fidl::types::Nullability::kNonnullable);
}
TEST(AliasTests, BadPrimitiveTypeShadowing) {
TestLibrary library(R"FIDL(
library example;
alias uint32 = uint32;
struct Message {
uint32 f;
};
)FIDL");
ASSERT_FALSE(library.Compile());
const auto& errors = library.errors();
ASSERT_EQ(1, errors.size());
ASSERT_ERR(errors[0], fidl::ErrIncludeCycle);
}
TEST(AliasTests, BadNoOptionalOnPrimitive) {
TestLibrary library(R"FIDL(
library test.optionals;
struct Bad {
int64? opt_num;
};
)FIDL");
ASSERT_FALSE(library.Compile());
const auto& errors = library.errors();
ASSERT_EQ(1, errors.size());
ASSERT_ERR(errors[0], fidl::ErrCannotBeNullable);
ASSERT_SUBSTR(errors[0]->msg.c_str(), "int64");
}
TEST(AliasTests, BadNoOptionalOnAliasedPrimitive) {
TestLibrary library(R"FIDL(
library test.optionals;
alias alias = int64;
struct Bad {
alias? opt_num;
};
)FIDL");
ASSERT_FALSE(library.Compile());
const auto& errors = library.errors();
ASSERT_EQ(1, errors.size());
ASSERT_ERR(errors[0], fidl::ErrCannotBeNullable);
ASSERT_SUBSTR(errors[0]->msg.c_str(), "int64");
}
TEST(AliasTests, GoodVectorParametrizedOnDecl) {
TestLibrary library(R"FIDL(
library example;
struct Message {
alias_of_vector_of_string f;
};
alias alias_of_vector_of_string = vector<string>;
)FIDL");
ASSERT_TRUE(library.Compile());
auto msg = library.LookupStruct("Message");
ASSERT_NOT_NULL(msg);
ASSERT_EQ(msg->members.size(), 1);
auto type = msg->members[0].type_ctor->type;
ASSERT_EQ(type->kind, fidl::flat::Type::Kind::kVector);
ASSERT_EQ(type->nullability, fidl::types::Nullability::kNonnullable);
auto vector_type = static_cast<const fidl::flat::VectorType*>(type);
ASSERT_EQ(vector_type->element_type->kind, fidl::flat::Type::Kind::kString);
ASSERT_EQ(static_cast<uint32_t>(*vector_type->element_count),
static_cast<uint32_t>(fidl::flat::Size::Max()));
auto from_type_alias = msg->members[0].type_ctor->from_type_alias.value();
EXPECT_STR_EQ(fidl::NameFlatName(from_type_alias.decl->name).c_str(),
"example/alias_of_vector_of_string");
EXPECT_NULL(from_type_alias.maybe_arg_type);
EXPECT_NULL(from_type_alias.maybe_size);
EXPECT_EQ(from_type_alias.nullability, fidl::types::Nullability::kNonnullable);
}
TEST(AliasTests, BadVectorParametrizedOnUse) {
TestLibrary library(R"FIDL(
library example;
struct Message {
alias_of_vector<uint8> f;
};
alias alias_of_vector = vector;
)FIDL");
ASSERT_FALSE(library.Compile());
const auto& errors = library.errors();
ASSERT_EQ(errors.size(), 1);
ASSERT_ERR(errors[0], fidl::ErrMustBeParameterized);
}
TEST(AliasTests, BadVectorBoundedOnDecl) {
TestLibrary library(R"FIDL(
library example;
struct Message {
alias_of_vector_max_8<string> f;
};
alias alias_of_vector_max_8 = vector:8;
)FIDL");
ASSERT_FALSE(library.Compile());
const auto& errors = library.errors();
ASSERT_EQ(errors.size(), 1);
ASSERT_ERR(errors[0], fidl::ErrMustBeParameterized);
}
TEST(AliasTests, GoodVectorBoundedOnUse) {
TestLibrary library(R"FIDL(
library example;
struct Message {
alias_of_vector_of_string:8 f;
};
alias alias_of_vector_of_string = vector<string>;
)FIDL");
ASSERT_TRUE(library.Compile());
auto msg = library.LookupStruct("Message");
ASSERT_NOT_NULL(msg);
ASSERT_EQ(msg->members.size(), 1);
auto type = msg->members[0].type_ctor->type;
ASSERT_EQ(type->kind, fidl::flat::Type::Kind::kVector);
ASSERT_EQ(type->nullability, fidl::types::Nullability::kNonnullable);
auto vector_type = static_cast<const fidl::flat::VectorType*>(type);
ASSERT_EQ(vector_type->element_type->kind, fidl::flat::Type::Kind::kString);
ASSERT_EQ(static_cast<uint32_t>(*vector_type->element_count), 8u);
auto from_type_alias = msg->members[0].type_ctor->from_type_alias.value();
EXPECT_STR_EQ(fidl::NameFlatName(from_type_alias.decl->name).c_str(),
"example/alias_of_vector_of_string");
EXPECT_NULL(from_type_alias.maybe_arg_type);
EXPECT_NOT_NULL(from_type_alias.maybe_size);
EXPECT_EQ(static_cast<uint32_t>(*from_type_alias.maybe_size), 8u);
EXPECT_EQ(from_type_alias.nullability, fidl::types::Nullability::kNonnullable);
}
TEST(AliasTests, GoodVectorNullableOnDecl) {
TestLibrary library(R"FIDL(
library example;
struct Message {
alias_of_vector_of_string_nullable f;
};
alias alias_of_vector_of_string_nullable = vector<string>?;
)FIDL");
ASSERT_TRUE(library.Compile());
auto msg = library.LookupStruct("Message");
ASSERT_NOT_NULL(msg);
ASSERT_EQ(msg->members.size(), 1);
auto type = msg->members[0].type_ctor->type;
ASSERT_EQ(type->kind, fidl::flat::Type::Kind::kVector);
ASSERT_EQ(type->nullability, fidl::types::Nullability::kNullable);
auto vector_type = static_cast<const fidl::flat::VectorType*>(type);
ASSERT_EQ(vector_type->element_type->kind, fidl::flat::Type::Kind::kString);
ASSERT_EQ(static_cast<uint32_t>(*vector_type->element_count),
static_cast<uint32_t>(fidl::flat::Size::Max()));
auto from_type_alias = msg->members[0].type_ctor->from_type_alias.value();
EXPECT_STR_EQ(fidl::NameFlatName(from_type_alias.decl->name).c_str(),
"example/alias_of_vector_of_string_nullable");
EXPECT_NULL(from_type_alias.maybe_arg_type);
EXPECT_NULL(from_type_alias.maybe_size);
EXPECT_EQ(from_type_alias.nullability, fidl::types::Nullability::kNonnullable);
}
TEST(AliasTests, GoodVectorNullableOnUse) {
TestLibrary library(R"FIDL(
library example;
struct Message {
alias_of_vector_of_string? f;
};
alias alias_of_vector_of_string = vector<string>;
)FIDL");
ASSERT_TRUE(library.Compile());
auto msg = library.LookupStruct("Message");
ASSERT_NOT_NULL(msg);
ASSERT_EQ(msg->members.size(), 1);
auto type = msg->members[0].type_ctor->type;
ASSERT_EQ(type->kind, fidl::flat::Type::Kind::kVector);
ASSERT_EQ(type->nullability, fidl::types::Nullability::kNullable);
auto vector_type = static_cast<const fidl::flat::VectorType*>(type);
ASSERT_EQ(vector_type->element_type->kind, fidl::flat::Type::Kind::kString);
ASSERT_EQ(static_cast<uint32_t>(*vector_type->element_count),
static_cast<uint32_t>(fidl::flat::Size::Max()));
auto from_type_alias = msg->members[0].type_ctor->from_type_alias.value();
EXPECT_STR_EQ(fidl::NameFlatName(from_type_alias.decl->name).c_str(),
"example/alias_of_vector_of_string");
EXPECT_NULL(from_type_alias.maybe_arg_type);
EXPECT_NULL(from_type_alias.maybe_size);
EXPECT_EQ(from_type_alias.nullability, fidl::types::Nullability::kNullable);
}
TEST(AliasTests, BadCannotParametrizeTwice) {
TestLibrary library(R"FIDL(
library example;
struct Message {
alias_of_vector_of_string<string> f;
};
alias alias_of_vector_of_string = vector<string>;
)FIDL");
ASSERT_FALSE(library.Compile());
const auto& errors = library.errors();
ASSERT_EQ(errors.size(), 1);
ASSERT_ERR(errors[0], fidl::ErrCannotParametrizeTwice);
}
TEST(AliasTests, BadCannotBoundTwice) {
TestLibrary library(R"FIDL(
library example;
struct Message {
alias_of_vector_of_string_max_5:9 f;
};
alias alias_of_vector_of_string_max_5 = vector<string>:5;
)FIDL");
ASSERT_FALSE(library.Compile());
const auto& errors = library.errors();
ASSERT_EQ(errors.size(), 1);
ASSERT_ERR(errors[0], fidl::ErrCannotBoundTwice);
}
TEST(AliasTests, BadCannotNullTwice) {
TestLibrary library(R"FIDL(
library example;
struct Message {
alias_of_vector_nullable<string>? f;
};
alias alias_of_vector_nullable = vector?;
)FIDL");
ASSERT_FALSE(library.Compile());
const auto& errors = library.errors();
ASSERT_EQ(errors.size(), 2);
ASSERT_ERR(errors[0], fidl::ErrMustBeParameterized);
ASSERT_ERR(errors[1], fidl::ErrCannotIndicateNullabilityTwice);
}
TEST(AliasTests, GoodMultiFileAliasReference) {
TestLibrary library("first.fidl", R"FIDL(
library example;
struct Protein {
AminoAcids amino_acids;
};
)FIDL");
library.AddSource("second.fidl", R"FIDL(
library example;
alias AminoAcids = vector<uint64>:32;
)FIDL");
ASSERT_TRUE(library.Compile());
}
TEST(AliasTests, GoodMultiFileNullableAliasReference) {
TestLibrary library("first.fidl", R"FIDL(
library example;
struct Protein {
AminoAcids? amino_acids;
};
)FIDL");
library.AddSource("second.fidl", R"FIDL(
library example;
alias AminoAcids = vector<uint64>:32;
)FIDL");
ASSERT_TRUE(library.Compile());
}
TEST(AliasTests, BadRecursiveAlias) {
TestLibrary library("first.fidl", R"FIDL(
library example;
alias TheAlias = TheStruct;
struct TheStruct {
vector<TheAlias> many_mini_me;
};
)FIDL");
ASSERT_FALSE(library.Compile());
const auto& errors = library.errors();
ASSERT_EQ(1, errors.size());
// TODO(fxbug.dev/35218): once recursive type handling is improved, the error message should be
// more granular and should be asserted here.
}
TEST(AliasTests, BadCompoundIdentifier) {
TestLibrary library("test.fidl", R"FIDL(
library example;
alias foo.bar.baz = uint8;
)FIDL");
ASSERT_FALSE(library.Compile());
const auto& errors = library.errors();
ASSERT_EQ(1, errors.size());
}
TEST(AliasTests, GoodUsingLibrary) {
SharedAmongstLibraries shared;
TestLibrary dependency("dependent.fidl", R"FIDL(
library dependent;
struct Bar {
int8 s;
};
)FIDL",
&shared);
ASSERT_TRUE(dependency.Compile());
TestLibrary library("example.fidl", R"FIDL(
library example;
using dependent;
alias Bar2 = dependent.Bar;
)FIDL",
&shared);
ASSERT_TRUE(library.AddDependentLibrary(std::move(dependency)));
ASSERT_TRUE(library.Compile());
}
TEST(AliasTests, BadDisallowOldUsingSyntax) {
fidl::ExperimentalFlags experimental_flags;
experimental_flags.SetFlag(fidl::ExperimentalFlags::Flag::kDisallowOldUsingSyntax);
TestLibrary library(R"FIDL(
library example;
using alias_of_int16 = int16;
)FIDL",
std::move(experimental_flags));
ASSERT_ERRORED_DURING_COMPILE(library, fidl::ErrOldUsingSyntaxDeprecated);
}
} // namespace
// TODO(pascallouis): Test various handle parametrization scenarios, and
// capture maybe_handle_subtype into FromTypeAlias struct.
// As noted in the TypeAliasTypeTemplate, there is a bug currently where
// handle parametrization of a type template is not properly passed down,
// and as a result gets lost.