blob: 2c9673b93baae6f16b4fd3746dfcff644c3c797b [file] [log] [blame]
// Copyright 2018 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/parser.h>
#include <fidl/source_file.h>
#include <unittest/unittest.h>
#include "test_library.h"
namespace {
static bool Compiles(const std::string& source_code,
std::vector<std::string>* out_errors = nullptr) {
auto library = TestLibrary("test.fidl", source_code);
const bool success = library.Compile();
if (out_errors) {
*out_errors = library.errors();
}
return success;
}
bool compiling() {
BEGIN_TEST;
std::vector<std::string> errors;
// Populated fields.
EXPECT_TRUE(Compiles(R"FIDL(
library fidl.test.xunions;
xunion Foo {
int64 i;
};
)FIDL"));
// Reserved and populated fields.
EXPECT_TRUE(Compiles(R"FIDL(
library fidl.test.xunions;
xunion Foo {
1: reserved;
2: int64 x;
};
)FIDL"));
EXPECT_TRUE(Compiles(R"FIDL(
library fidl.test.xunions;
xunion Foo {
1: int64 x;
2: reserved;
};
)FIDL"));
// Out of order fields.
EXPECT_TRUE(Compiles(R"FIDL(
library fidl.test.xunions;
xunion Foo {
3: reserved;
1: uint32 x;
2: reserved;
};
)FIDL"));
// Must have a non reserved field.
EXPECT_FALSE(Compiles(R"FIDL(
library fidl.test.xunions;
xunion Foo {
1: reserved;
2: reserved;
3: reserved;
};
)FIDL",
&errors));
EXPECT_EQ(errors.size(), 1u);
ASSERT_STR_STR(errors.at(0).c_str(), "must have at least one non reserved member");
// Duplicate ordinals.
EXPECT_FALSE(Compiles(R"FIDL(
library fidl.test.xunions;
xunion Foo {
1: reserved;
1: uint64 x;
};
)FIDL",
&errors));
EXPECT_EQ(errors.size(), 1u);
ASSERT_STR_STR(errors.at(0).c_str(), "Multiple xunion fields with the same ordinal");
// Missing ordinals.
EXPECT_FALSE(Compiles(R"FIDL(
library fidl.test.xunions;
xunion Foo {
1: uint32 x;
3: reserved;
};
)FIDL",
&errors));
EXPECT_EQ(errors.size(), 1u);
ASSERT_STR_STR(errors.at(0).c_str(),
"missing ordinal 2 (ordinals must be dense); consider marking it reserved");
// No zero ordinals.
EXPECT_FALSE(Compiles(R"FIDL(
library fidl.test.xunions;
xunion Foo {
2: int32 y;
0: int64 x;
};
)FIDL",
&errors));
EXPECT_EQ(errors.size(), 1u);
ASSERT_STR_STR(errors.at(0).c_str(), "ordinals must start at 1");
// Explicit ordinals are valid.
EXPECT_TRUE(Compiles(R"FIDL(
library fidl.test.xunions;
xunion Foo {
1: int64 x;
};
)FIDL"));
// Cannot mix explicit/hashed ordinals
EXPECT_FALSE(Compiles(R"FIDL(
library fidl.test.xunions;
xunion Foo {
int32 y;
1: int64 x;
};
)FIDL",
&errors));
EXPECT_EQ(errors.size(), 1u);
ASSERT_STR_STR(errors.at(0).c_str(), "cannot mix explicit and implicit ordinals");
// Keywords as field names.
EXPECT_TRUE(Compiles(R"FIDL(
library fidl.test.xunions;
struct struct {
bool field;
};
xunion Foo {
int64 xunion;
bool library;
uint32 uint32;
struct member;
};
)FIDL"));
// Recursion is allowed.
EXPECT_TRUE(Compiles(R"FIDL(
library fidl.test.xunions;
xunion Value {
bool bool_value;
vector<Value?> list_value;
};
)FIDL"));
// Mutual recursion is allowed.
EXPECT_TRUE(Compiles(R"FIDL(
library fidl.test.xunions;
xunion Foo {
Bar bar;
};
struct Bar {
Foo? foo;
};
)FIDL"));
END_TEST;
}
bool no_directly_recursive_xunions() {
BEGIN_TEST;
TestLibrary library(R"FIDL(
library example;
xunion Value {
Value value;
};
)FIDL");
ASSERT_FALSE(library.Compile());
auto errors = library.errors();
ASSERT_EQ(errors.size(), 1);
ASSERT_STR_STR(errors[0].c_str(), "There is an includes-cycle in declarations");
END_TEST;
}
bool invalid_empty_xunions() {
BEGIN_TEST;
TestLibrary library(R"FIDL(
library example;
xunion Foo {};
)FIDL");
ASSERT_FALSE(library.Compile());
auto errors = library.errors();
ASSERT_EQ(errors.size(), 1);
ASSERT_STR_STR(errors[0].c_str(), "must have at least one non reserved member");
END_TEST;
}
bool union_xunion_same_ordinals_explicit() {
BEGIN_TEST;
TestLibrary xunion_library(R"FIDL(
library example;
xunion Foo {
1: int8 bar;
};
)FIDL");
ASSERT_TRUE(xunion_library.Compile());
TestLibrary union_library(R"FIDL(
library example;
union Foo {
1: int8 bar;
};
)FIDL");
ASSERT_TRUE(union_library.Compile());
const fidl::flat::XUnion* ex_xunion = xunion_library.LookupXUnion("Foo");
const fidl::flat::Union* ex_union = union_library.LookupUnion("Foo");
ASSERT_NOT_NULL(ex_xunion);
ASSERT_NOT_NULL(ex_union);
ASSERT_EQ(ex_union->members.front().xunion_ordinal->value, 1);
ASSERT_EQ(ex_xunion->members.front().ordinal->value, 1);
END_TEST;
}
bool error_syntax_explicit_ordinals() {
BEGIN_TEST;
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().xunion_ordinal->value, 1);
ASSERT_EQ(error_union->members.back().xunion_ordinal->value, 2);
END_TEST;
}
bool no_nullable_members_in_xunions() {
BEGIN_TEST;
TestLibrary library(R"FIDL(
library example;
xunion Foo {
string? bar;
};
)FIDL");
ASSERT_FALSE(library.Compile());
auto errors = library.errors();
ASSERT_EQ(errors.size(), 1);
ASSERT_STR_STR(errors[0].c_str(), "Extensible union members cannot be nullable");
END_TEST;
}
} // namespace
BEGIN_TEST_CASE(xunion_tests)
RUN_TEST(compiling)
RUN_TEST(no_directly_recursive_xunions)
RUN_TEST(invalid_empty_xunions)
RUN_TEST(union_xunion_same_ordinals_explicit)
RUN_TEST(error_syntax_explicit_ordinals)
RUN_TEST(no_nullable_members_in_xunions)
END_TEST_CASE(xunion_tests)