blob: 0fa781eeeb4faa251661d5d2fd357515f39ce8f1 [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;
type struct = struct {
field bool;
};
type Foo = strict union {
1: union int64;
2: library bool;
3: uint32 uint32;
4: member struct;
5: reserved bool;
};
)FIDL");
ASSERT_COMPILED(library);
auto type_decl = library.LookupUnion("Foo");
ASSERT_NOT_NULL(type_decl);
EXPECT_EQ(type_decl->members.size(), 5);
}
TEST(UnionTests, GoodRecursiveUnion) {
TestLibrary library(R"FIDL(library test;
type Value = strict union {
1: bool_value bool;
2: list_value vector<Value:optional>;
};
)FIDL");
ASSERT_COMPILED(library);
}
TEST(UnionTests, GoodMutuallyRecursive) {
TestLibrary library(R"FIDL(library test;
type Foo = strict union {
1: bar Bar;
};
type Bar = struct {
foo Foo:optional;
};
)FIDL");
ASSERT_COMPILED(library);
}
TEST(UnionTests, GoodFlexibleUnion) {
TestLibrary library(R"FIDL(library test;
type Foo = flexible union {
1: bar string;
};
)FIDL");
ASSERT_COMPILED(library);
}
TEST(UnionTests, GoodStrictUnion) {
TestLibrary library(R"FIDL(library test;
type Foo = strict union {
1: bar string;
};
)FIDL");
ASSERT_COMPILED(library);
}
TEST(UnionTests, BadMustHaveExplicitOrdinals) {
TestLibrary library(R"FIDL(
library test;
type Foo = strict union {
foo int64;
bar vector<uint32>:10;
};
)FIDL");
ASSERT_ERRORED_TWICE_DURING_COMPILE(library, fidl::ErrMissingOrdinalBeforeMember,
fidl::ErrMissingOrdinalBeforeMember);
}
TEST(UnionTests, GoodExplicitOrdinals) {
TestLibrary library(R"FIDL(library test;
type Foo = strict union {
1: foo int64;
2: bar vector<uint32>:10;
};
)FIDL");
ASSERT_COMPILED(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;
type Foo = strict union {
1: reserved;
2: foo int64;
3: reserved;
4: bar vector<uint32>:10;
5: reserved;
};
)FIDL");
ASSERT_COMPILED(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;
type Foo = strict union {
5: foo int64;
2: bar vector<uint32>:10;
3: reserved;
1: reserved;
4: baz uint32;
};
)FIDL");
ASSERT_COMPILED(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, BadOrdinalOutOfBounds) {
TestLibrary library(R"FIDL(
library test;
type Foo = strict union {
-1: uint32 foo;
};
)FIDL");
ASSERT_ERRORED_DURING_COMPILE(library, fidl::ErrOrdinalOutOfBound);
}
TEST(UnionTests, BadOrdinalsMustBeUnique) {
TestLibrary library(R"FIDL(
library test;
type Foo = strict union {
1: reserved;
1: x uint64;
};
)FIDL");
ASSERT_ERRORED_DURING_COMPILE(library, fidl::ErrDuplicateUnionMemberOrdinal);
}
TEST(UnionTests, BadMemberNamesMustBeUnique) {
TestLibrary library(R"FIDL(
library test;
type Duplicates = strict union {
1: s string;
2: s int32;
};
)FIDL");
ASSERT_ERRORED_DURING_COMPILE(library, fidl::ErrDuplicateUnionMemberName);
}
TEST(UnionTests, BadCannotStartAtZero) {
TestLibrary library(R"FIDL(
library test;
type Foo = strict union {
0: foo uint32;
1: bar uint64;
};
)FIDL");
ASSERT_ERRORED_DURING_COMPILE(library, fidl::ErrOrdinalsMustStartAtOne);
}
TEST(UnionTests, BadDefaultNotAllowed) {
TestLibrary library(R"FIDL(
library test;
type Foo = strict union {
1: t int64 = 1;
};
)FIDL");
ASSERT_ERRORED_TWICE_DURING_COMPILE(library, fidl::ErrUnexpectedTokenOfKind,
fidl::ErrMissingOrdinalBeforeMember);
}
TEST(UnionTests, BadMustBeDense) {
TestLibrary library(R"FIDL(
library example;
type Example = strict union {
1: first int64;
3: third int64;
};
)FIDL");
ASSERT_ERRORED_DURING_COMPILE(library, fidl::ErrNonDenseOrdinal);
ASSERT_SUBSTR(library.errors().at(0)->msg.c_str(), "2");
}
TEST(UnionTests, BadMustHaveNonReservedMember) {
TestLibrary library(R"FIDL(
library example;
type Foo = strict union {
2: reserved;
1: reserved;
};
)FIDL");
ASSERT_ERRORED_DURING_COMPILE(library, fidl::ErrMustHaveNonReservedMember);
}
TEST(UnionTests, BadNoNullableMembers) {
TestLibrary library(R"FIDL(
library example;
type Foo = strict union {
1: bar string:optional;
};
)FIDL");
ASSERT_ERRORED_DURING_COMPILE(library, fidl::ErrOptionalUnionMember);
}
TEST(UnionTests, BadNoDirectlyRecursiveUnions) {
TestLibrary library(R"FIDL(
library example;
type Value = strict union {
1: value Value;
};
)FIDL");
ASSERT_ERRORED_DURING_COMPILE(library, fidl::ErrIncludeCycle);
}
TEST(UnionTests, BadEmptyUnion) {
TestLibrary library(R"FIDL(
library example;
type Foo = strict union {};
)FIDL");
ASSERT_ERRORED_DURING_COMPILE(library, fidl::ErrMustHaveNonReservedMember);
}
TEST(UnionTests, GoodErrorSyntaxExplicitOrdinals) {
TestLibrary library(R"FIDL(library example;
protocol Example {
Method() -> (struct {}) error int32;
};
)FIDL");
ASSERT_COMPILED(library);
const fidl::flat::Union* error_union = 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, BadNoSelector) {
TestLibrary library(R"FIDL(
library example;
type Foo = strict union {
@selector("v2") 1: v string;
};
)FIDL");
ASSERT_ERRORED_DURING_COMPILE(library, fidl::ErrInvalidAttributePlacement);
}
} // namespace