blob: d772b9f2052f513be368edd777fca108c0c63acc [file] [log] [blame]
// Copyright 2019 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/names.h>
#include <fidl/parser.h>
#include <fidl/source_file.h>
#include <zxtest/zxtest.h>
#include "error_test.h"
#include "test_library.h"
namespace {
TEST(UnionTests, GoodKeywordsAsFieldNames) {
TestLibrary library(R"FIDL(
library test;
struct struct {
bool field;
};
union Foo {
1: int64 union;
2: bool library;
3: uint32 uint32;
4: struct member;
};
)FIDL");
ASSERT_COMPILED_AND_CONVERT(library);
}
TEST(UnionTests, GoodRecursiveUnion) {
TestLibrary library(R"FIDL(
library test;
union Value {
1: bool bool_value;
2: vector<Value?> list_value;
};
)FIDL");
ASSERT_COMPILED_AND_CONVERT(library);
}
TEST(UnionTests, GoodMutuallyRecursive) {
TestLibrary library(R"FIDL(
library test;
union Foo {
1: Bar bar;
};
struct Bar {
Foo? foo;
};
)FIDL");
ASSERT_COMPILED_AND_CONVERT(library);
}
TEST(UnionTests, GoodFlexibleUnion) {
TestLibrary library(R"FIDL(
library test;
flexible union Foo {
1: string bar;
};
)FIDL");
ASSERT_COMPILED_AND_CONVERT(library);
}
TEST(UnionTests, GoodStrictUnion) {
TestLibrary library(R"FIDL(
library test;
strict union Foo {
1: string bar;
};
)FIDL");
ASSERT_COMPILED_AND_CONVERT(library);
}
TEST(UnionTests, BadMustHaveExplicitOrdinalsOld) {
TestLibrary library(R"FIDL(
library test;
union Foo {
int64 foo;
vector<uint32>:10 bar;
};
)FIDL");
ASSERT_ERRORED_TWICE_DURING_COMPILE(library, fidl::ErrMissingOrdinalBeforeType,
fidl::ErrMissingOrdinalBeforeType);
}
TEST(UnionTests, BadMustHaveExplicitOrdinals) {
fidl::ExperimentalFlags experimental_flags;
experimental_flags.SetFlag(fidl::ExperimentalFlags::Flag::kAllowNewSyntax);
TestLibrary library(R"FIDL(
library test;
type Foo = strict union {
foo int64;
bar vector<uint32>:10;
};
)FIDL",
std::move(experimental_flags));
ASSERT_ERRORED_TWICE_DURING_COMPILE(library, fidl::ErrMissingOrdinalBeforeType,
fidl::ErrMissingOrdinalBeforeType);
}
TEST(UnionTests, GoodExplicitOrdinals) {
TestLibrary library(R"FIDL(
library test;
union Foo {
1: int64 foo;
2: vector<uint32>:10 bar;
};
)FIDL");
ASSERT_COMPILED_AND_CONVERT(library);
auto fidl_union = library.LookupUnion("Foo");
ASSERT_NOT_NULL(fidl_union);
ASSERT_EQ(fidl_union->members.size(), 2);
auto& member0 = fidl_union->members[0];
EXPECT_NOT_NULL(member0.maybe_used);
EXPECT_EQ(member0.ordinal->value, 1);
auto& member1 = fidl_union->members[1];
EXPECT_NOT_NULL(member1.maybe_used);
EXPECT_EQ(member1.ordinal->value, 2);
}
TEST(UnionTests, GoodOrdinalsWithReserved) {
TestLibrary library(R"FIDL(
library test;
union Foo {
1: reserved;
2: int64 foo;
3: reserved;
4: vector<uint32>:10 bar;
5: reserved;
};
)FIDL");
ASSERT_COMPILED_AND_CONVERT(library);
auto fidl_union = library.LookupUnion("Foo");
ASSERT_NOT_NULL(fidl_union);
ASSERT_EQ(fidl_union->members.size(), 5);
auto& member0 = fidl_union->members[0];
EXPECT_NULL(member0.maybe_used);
EXPECT_EQ(member0.ordinal->value, 1);
auto& member1 = fidl_union->members[1];
EXPECT_NOT_NULL(member1.maybe_used);
EXPECT_EQ(member1.ordinal->value, 2);
auto& member2 = fidl_union->members[2];
EXPECT_NULL(member2.maybe_used);
EXPECT_EQ(member2.ordinal->value, 3);
auto& member3 = fidl_union->members[3];
EXPECT_NOT_NULL(member3.maybe_used);
EXPECT_EQ(member3.ordinal->value, 4);
auto& member4 = fidl_union->members[4];
EXPECT_NULL(member4.maybe_used);
EXPECT_EQ(member4.ordinal->value, 5);
}
TEST(UnionTests, GoodOrdinalsOutOfOrder) {
TestLibrary library(R"FIDL(
library test;
union Foo {
5: int64 foo;
2: vector<uint32>:10 bar;
3: reserved;
1: reserved;
4: uint32 baz;
};
)FIDL");
ASSERT_COMPILED_AND_CONVERT(library);
auto fidl_union = library.LookupUnion("Foo");
ASSERT_NOT_NULL(fidl_union);
ASSERT_EQ(fidl_union->members.size(), 5);
auto& member0 = fidl_union->members[0];
EXPECT_NOT_NULL(member0.maybe_used);
EXPECT_EQ(member0.ordinal->value, 5);
auto& member1 = fidl_union->members[1];
EXPECT_NOT_NULL(member1.maybe_used);
EXPECT_EQ(member1.ordinal->value, 2);
auto& member2 = fidl_union->members[2];
EXPECT_NULL(member2.maybe_used);
EXPECT_EQ(member2.ordinal->value, 3);
auto& member3 = fidl_union->members[3];
EXPECT_NULL(member3.maybe_used);
EXPECT_EQ(member3.ordinal->value, 1);
auto& member4 = fidl_union->members[4];
EXPECT_NOT_NULL(member4.maybe_used);
EXPECT_EQ(member4.ordinal->value, 4);
}
TEST(UnionTests, BadOrdinalOutOfBoundsOld) {
TestLibrary library(R"FIDL(
library test;
union Foo {
-1: uint32 foo;
};
)FIDL");
ASSERT_ERRORED_DURING_COMPILE(library, fidl::ErrOrdinalOutOfBound);
}
TEST(UnionTests, BadOrdinalOutOfBounds) {
fidl::ExperimentalFlags experimental_flags;
experimental_flags.SetFlag(fidl::ExperimentalFlags::Flag::kAllowNewSyntax);
TestLibrary library(R"FIDL(
library test;
type Foo = strict union {
-1: uint32 foo;
};
)FIDL",
std::move(experimental_flags));
ASSERT_ERRORED_DURING_COMPILE(library, fidl::ErrOrdinalOutOfBound);
}
TEST(UnionTests, BadOrdinalsMustBeUniqueOld) {
TestLibrary library(R"FIDL(
library test;
union Foo {
1: reserved;
1: uint64 x;
};
)FIDL");
ASSERT_ERRORED_DURING_COMPILE(library, fidl::ErrDuplicateUnionMemberOrdinal);
}
TEST(UnionTests, BadOrdinalsMustBeUnique) {
fidl::ExperimentalFlags experimental_flags;
experimental_flags.SetFlag(fidl::ExperimentalFlags::Flag::kAllowNewSyntax);
TestLibrary library(R"FIDL(
library test;
type Foo = strict union {
1: reserved;
1: uint64 x;
};
)FIDL",
std::move(experimental_flags));
ASSERT_ERRORED_DURING_COMPILE(library, fidl::ErrDuplicateUnionMemberOrdinal);
}
TEST(UnionTests, BadMemberNamesMustBeUniqueOld) {
TestLibrary library(R"FIDL(
library test;
union Duplicates {
1: string s;
2: int32 s;
};
)FIDL");
ASSERT_ERRORED_DURING_COMPILE(library, fidl::ErrDuplicateUnionMemberName);
}
TEST(UnionTests, BadMemberNamesMustBeUnique) {
fidl::ExperimentalFlags experimental_flags;
experimental_flags.SetFlag(fidl::ExperimentalFlags::Flag::kAllowNewSyntax);
TestLibrary library(R"FIDL(
library test;
type Duplicates = strict union {
1: s string;
2: s int32;
};
)FIDL",
std::move(experimental_flags));
ASSERT_ERRORED_DURING_COMPILE(library, fidl::ErrDuplicateUnionMemberName);
}
TEST(UnionTests, BadCannotStartAtZeroOld) {
TestLibrary library(R"FIDL(
library test;
union Foo {
0: uint32 foo;
1: uint64 bar;
};
)FIDL");
ASSERT_ERRORED_DURING_COMPILE(library, fidl::ErrOrdinalsMustStartAtOne);
}
TEST(UnionTests, BadCannotStartAtZero) {
fidl::ExperimentalFlags experimental_flags;
experimental_flags.SetFlag(fidl::ExperimentalFlags::Flag::kAllowNewSyntax);
TestLibrary library(R"FIDL(
library test;
type Foo = strict union {
0: foo uint32;
1: bar uint64;
};
)FIDL",
std::move(experimental_flags));
ASSERT_ERRORED_DURING_COMPILE(library, fidl::ErrOrdinalsMustStartAtOne);
}
TEST(UnionTests, BadDefaultNotAllowedOld) {
TestLibrary library(R"FIDL(
library test;
union Foo {
1: int64 t = 1;
};
)FIDL");
ASSERT_ERRORED_DURING_COMPILE(library, fidl::ErrDefaultsOnUnionsNotSupported);
}
// NOTE(fxbug.dev/72924): we lose the default specific error in the new syntax.
TEST(UnionTests, BadDefaultNotAllowed) {
fidl::ExperimentalFlags experimental_flags;
experimental_flags.SetFlag(fidl::ExperimentalFlags::Flag::kAllowNewSyntax);
TestLibrary library(R"FIDL(
library test;
type Foo = strict union {
1: t int64 = 1;
};
)FIDL",
std::move(experimental_flags));
// NOTE(fxbug.dev/72924): we lose the default specific error in the new syntax.
// TODO(fxbug.dev/72924): the second error doesn't make any sense
ASSERT_ERRORED_TWICE_DURING_COMPILE(library, fidl::ErrUnexpectedTokenOfKind,
fidl::ErrMissingOrdinalBeforeType);
}
TEST(UnionTests, BadMustBeDenseOld) {
TestLibrary library(R"FIDL(
library example;
union Example {
1: int64 first;
3: int64 third;
};
)FIDL");
ASSERT_ERRORED_DURING_COMPILE(library, fidl::ErrNonDenseOrdinal);
ASSERT_SUBSTR(library.errors().at(0)->msg.c_str(), "2");
}
TEST(UnionTests, BadMustBeDense) {
fidl::ExperimentalFlags experimental_flags;
experimental_flags.SetFlag(fidl::ExperimentalFlags::Flag::kAllowNewSyntax);
TestLibrary library(R"FIDL(
library example;
type Example = strict union {
1: first int64;
3: third int64;
};
)FIDL",
std::move(experimental_flags));
ASSERT_ERRORED_DURING_COMPILE(library, fidl::ErrNonDenseOrdinal);
ASSERT_SUBSTR(library.errors().at(0)->msg.c_str(), "2");
}
TEST(UnionTests, BadMustHaveNonReservedMemberOld) {
TestLibrary library(R"FIDL(
library example;
union Foo {
2: reserved;
1: reserved;
};
)FIDL");
ASSERT_ERRORED_DURING_COMPILE(library, fidl::ErrMustHaveNonReservedMember);
}
TEST(UnionTests, BadMustHaveNonReservedMember) {
fidl::ExperimentalFlags experimental_flags;
experimental_flags.SetFlag(fidl::ExperimentalFlags::Flag::kAllowNewSyntax);
TestLibrary library(R"FIDL(
library example;
type Foo = strict union {
2: reserved;
1: reserved;
};
)FIDL",
std::move(experimental_flags));
ASSERT_ERRORED_DURING_COMPILE(library, fidl::ErrMustHaveNonReservedMember);
}
TEST(UnionTests, BadNoNullableMembersOld) {
TestLibrary library(R"FIDL(
library example;
union Foo {
1: string? bar;
};
)FIDL");
ASSERT_ERRORED_DURING_COMPILE(library, fidl::ErrNullableUnionMember);
}
TEST(UnionTests, BadNoNullableMembers) {
fidl::ExperimentalFlags experimental_flags;
experimental_flags.SetFlag(fidl::ExperimentalFlags::Flag::kAllowNewSyntax);
TestLibrary library(R"FIDL(
library example;
type Foo = strict union {
1: bar string:optional;
};
)FIDL",
std::move(experimental_flags));
// NOTE(fxbug.dev/72924): we get a more general error in the new syntax
ASSERT_ERRORED_DURING_COMPILE(library, fidl::ErrNullableOrdinaledMember);
}
TEST(UnionTests, BadNoDirectlyRecursiveUnionsOld) {
TestLibrary library(R"FIDL(
library example;
union Value {
1: Value value;
};
)FIDL");
ASSERT_ERRORED_DURING_COMPILE(library, fidl::ErrIncludeCycle);
}
TEST(UnionTests, BadNoDirectlyRecursiveUnions) {
fidl::ExperimentalFlags experimental_flags;
experimental_flags.SetFlag(fidl::ExperimentalFlags::Flag::kAllowNewSyntax);
TestLibrary library(R"FIDL(
library example;
type Value = strict union {
1: value Value;
};
)FIDL",
std::move(experimental_flags));
ASSERT_ERRORED_DURING_COMPILE(library, fidl::ErrIncludeCycle);
}
TEST(UnionTests, BadEmptyUnionOld) {
TestLibrary library(R"FIDL(
library example;
union Foo {};
)FIDL");
ASSERT_ERRORED_DURING_COMPILE(library, fidl::ErrMustHaveNonReservedMember);
}
TEST(UnionTests, BadEmptyUnion) {
fidl::ExperimentalFlags experimental_flags;
experimental_flags.SetFlag(fidl::ExperimentalFlags::Flag::kAllowNewSyntax);
TestLibrary library(R"FIDL(
library example;
type Foo = strict union {};
)FIDL",
std::move(experimental_flags));
ASSERT_ERRORED_DURING_COMPILE(library, fidl::ErrMustHaveNonReservedMember);
}
TEST(UnionTests, GoodErrorSyntaxExplicitOrdinalsOld) {
TestLibrary error_library(R"FIDL(
library example;
protocol Example {
Method() -> () error int32;
};
)FIDL");
ASSERT_TRUE(error_library.Compile());
const fidl::flat::Union* error_union = error_library.LookupUnion("Example_Method_Result");
ASSERT_NOT_NULL(error_union);
ASSERT_EQ(error_union->members.front().ordinal->value, 1);
ASSERT_EQ(error_union->members.back().ordinal->value, 2);
}
TEST(UnionTests, GoodErrorSyntaxExplicitOrdinals) {
fidl::ExperimentalFlags experimental_flags;
experimental_flags.SetFlag(fidl::ExperimentalFlags::Flag::kAllowNewSyntax);
TestLibrary error_library(R"FIDL(
library example;
protocol Example {
Method() -> () error int32;
};
)FIDL",
std::move(experimental_flags));
ASSERT_TRUE(error_library.Compile());
const fidl::flat::Union* error_union = error_library.LookupUnion("Example_Method_Result");
ASSERT_NOT_NULL(error_union);
ASSERT_EQ(error_union->members.front().ordinal->value, 1);
ASSERT_EQ(error_union->members.back().ordinal->value, 2);
}
TEST(UnionTests, BadNoSelectorOld) {
TestLibrary library(R"FIDL(
library example;
union Foo {
[Selector = "v2"] 1: string v;
};
)FIDL");
ASSERT_ERRORED_DURING_COMPILE(library, fidl::ErrInvalidAttributePlacement);
ASSERT_SUBSTR(library.errors()[0]->msg.c_str(), "Selector");
}
TEST(UnionTests, BadNoSelector) {
fidl::ExperimentalFlags experimental_flags;
experimental_flags.SetFlag(fidl::ExperimentalFlags::Flag::kAllowNewSyntax);
TestLibrary library(R"FIDL(
library example;
type Foo = strict union {
[Selector = "v2"] 1: v string;
};
)FIDL",
std::move(experimental_flags));
// TODO(fxbug.dev/72924): this should become ErrInvalidAttributePlacement
// as before once attributes are implemented.
ASSERT_ERRORED_DURING_COMPILE(library, fidl::ErrMissingOrdinalBeforeType);
}
// TODO(fxbug.dev/70247): as we clean up the migration, it will probably have
// been long enough that we can remove this error and the special handling for
// "xunion"
TEST(UnionTests, BadDeprecatedXUnionError) {
{
TestLibrary library(R"FIDL(
library test;
xunion Foo {
1: string foo;
};
)FIDL");
ASSERT_ERRORED_DURING_COMPILE(library, fidl::ErrXunionDeprecated);
}
{
TestLibrary library(R"FIDL(
library test;
flexible xunion FlexibleFoo {
1: string foo;
};
)FIDL");
ASSERT_ERRORED_DURING_COMPILE(library, fidl::ErrXunionDeprecated);
}
{
TestLibrary library(R"FIDL(
library test;
strict xunion StrictFoo {
1: string foo;
};
)FIDL");
ASSERT_ERRORED_DURING_COMPILE(library, fidl::ErrStrictXunionDeprecated);
}
}
} // namespace