blob: 7289875c578d7208c579cbcadef0848b7eb36f0a [file] [log] [blame]
// Copyright 2022 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 <optional>
#include <gtest/gtest.h>
#include "tools/fidl/fidlc/src/diagnostics.h"
#include "tools/fidl/fidlc/src/versioning_types.h"
#include "tools/fidl/fidlc/tests/test_library.h"
// This file tests the behavior of the @available attribute. See also
// decomposition_tests.cc and availability_interleaving_tests.cc.
namespace fidlc {
namespace {
// Largest numeric version accepted by Version::Parse.
const std::string kMaxNumericVersion = std::to_string((1ull << 63) - 1);
TEST(VersioningTests, GoodUnversionedPlatformOneComponent) {
TestLibrary library(R"FIDL(
library example;
)FIDL");
ASSERT_COMPILED(library);
auto example = library.LookupLibrary("example");
EXPECT_TRUE(example->platform.value().is_unversioned());
}
TEST(VersioningTests, GoodUnversionedPlatformTwoComponents) {
TestLibrary library(R"FIDL(
library example.something;
)FIDL");
ASSERT_COMPILED(library);
auto example = library.LookupLibrary("example.something");
EXPECT_TRUE(example->platform.value().is_unversioned());
}
TEST(VersioningTests, GoodImplicitPlatformOneComponent) {
TestLibrary library(R"FIDL(
@available(added=1)
library example;
)FIDL");
library.SelectVersion("example", "HEAD");
ASSERT_COMPILED(library);
auto example = library.LookupLibrary("example");
EXPECT_EQ(example->platform, Platform::Parse("example").value());
EXPECT_FALSE(example->platform.value().is_unversioned());
}
TEST(VersioningTests, GoodImplicitPlatformTwoComponents) {
TestLibrary library(R"FIDL(
@available(added=1)
library example.something;
)FIDL");
library.SelectVersion("example", "HEAD");
ASSERT_COMPILED(library);
auto example = library.LookupLibrary("example.something");
EXPECT_EQ(example->platform, Platform::Parse("example").value());
EXPECT_FALSE(example->platform.value().is_unversioned());
}
TEST(VersioningTests, GoodExplicitPlatform) {
TestLibrary library(R"FIDL(
@available(platform="someplatform", added=HEAD)
library example;
)FIDL");
library.SelectVersion("someplatform", "HEAD");
ASSERT_COMPILED(library);
auto example = library.LookupLibrary("example");
EXPECT_EQ(example->platform, Platform::Parse("someplatform").value());
EXPECT_FALSE(example->platform.value().is_unversioned());
}
TEST(VersioningTests, BadInvalidPlatform) {
TestLibrary library;
library.AddFile("bad/fi-0152.test.fidl");
library.SelectVersion("test", "HEAD");
library.ExpectFail(ErrInvalidPlatform, "Spaces are not allowed");
ASSERT_COMPILER_DIAGNOSTICS(library);
}
TEST(VersioningTests, BadReservedPlatform) {
TestLibrary library;
library.AddFile("bad/fi-0208.test.fidl");
library.ExpectFail(ErrReservedPlatform, "unversioned");
ASSERT_COMPILER_DIAGNOSTICS(library);
}
TEST(VersioningTests, BadExplicitPlatformNoVersionSelected) {
TestLibrary library;
library.AddFile("bad/fi-0201.test.fidl");
library.ExpectFail(ErrPlatformVersionNotSelected, "test.bad.fi0201",
Platform::Parse("foo").value());
ASSERT_COMPILER_DIAGNOSTICS(library);
}
TEST(VersioningTests, BadImplicitPlatformNoVersionSelected) {
TestLibrary library(R"FIDL(
@available(added=1)
library example.something;
)FIDL");
library.ExpectFail(ErrPlatformVersionNotSelected, "example.something",
Platform::Parse("example").value());
ASSERT_COMPILER_DIAGNOSTICS(library);
}
TEST(VersioningTests, BadAttributeOnMultipleLibraryDeclarationsAgree) {
TestLibrary library;
library.AddSource("first.fidl", R"FIDL(
@available(added=1)
library example;
)FIDL");
library.AddSource("second.fidl", R"FIDL(
@available(added=1)
library example;
)FIDL");
library.SelectVersion("example", "HEAD");
library.ExpectFail(ErrDuplicateAttribute, "available", "first.fidl:2:2");
ASSERT_COMPILER_DIAGNOSTICS(library);
}
TEST(VersioningTests, BadAttributeOnMultipleLibraryDeclarationsDisagree) {
TestLibrary library;
library.AddSource("first.fidl", R"FIDL(
@available(added=1)
library example;
)FIDL");
library.AddSource("second.fidl", R"FIDL(
@available(added=2)
library example;
)FIDL");
library.SelectVersion("example", "HEAD");
library.ExpectFail(ErrDuplicateAttribute, "available", "first.fidl:2:2");
ASSERT_COMPILER_DIAGNOSTICS(library);
}
TEST(VersioningTests, BadAttributeOnMultipleLibraryDeclarationsHead) {
TestLibrary library;
library.AddSource("first.fidl", R"FIDL(
@available(added=HEAD)
library example;
)FIDL");
library.AddSource("second.fidl", R"FIDL(
@available(added=HEAD)
library example;
)FIDL");
library.SelectVersion("example", "HEAD");
// TODO(https://fxbug.dev/42062904): Check for duplicate attributes earlier in
// compilation so that this is ErrDuplicateAttribute instead.
library.ExpectFail(ErrReferenceInLibraryAttribute);
ASSERT_COMPILER_DIAGNOSTICS(library);
}
TEST(VersioningTests, GoodLibraryDefault) {
auto source = R"FIDL(
library example;
)FIDL";
for (auto version : {"1", "2", kMaxNumericVersion.c_str(), "HEAD", "LEGACY"}) {
TestLibrary library(source);
library.SelectVersion("example", version);
ASSERT_COMPILED(library);
}
}
TEST(VersioningTests, GoodLibraryAddedAtHead) {
auto source = R"FIDL(
@available(added=HEAD)
library example;
)FIDL";
for (auto version : {"1", "2", kMaxNumericVersion.c_str(), "HEAD", "LEGACY"}) {
TestLibrary library(source);
library.SelectVersion("example", version);
ASSERT_COMPILED(library);
}
}
TEST(VersioningTests, GoodLibraryAddedAtOne) {
auto source = R"FIDL(
@available(added=1)
library example;
)FIDL";
{
TestLibrary library(source);
library.SelectVersion("example", "1");
ASSERT_COMPILED(library);
}
{
TestLibrary library(source);
library.SelectVersion("example", "2");
ASSERT_COMPILED(library);
}
{
TestLibrary library(source);
library.SelectVersion("example", kMaxNumericVersion);
ASSERT_COMPILED(library);
}
{
TestLibrary library(source);
library.SelectVersion("example", "HEAD");
ASSERT_COMPILED(library);
}
{
TestLibrary library(source);
library.SelectVersion("example", "LEGACY");
ASSERT_COMPILED(library);
}
}
TEST(VersioningTests, GoodLibraryAddedAndRemoved) {
auto source = R"FIDL(
@available(added=1, removed=2)
library example;
)FIDL";
for (auto version : {"1", "2", kMaxNumericVersion.c_str(), "HEAD", "LEGACY"}) {
TestLibrary library(source);
library.SelectVersion("example", version);
ASSERT_COMPILED(library);
}
}
TEST(VersioningTests, GoodLibraryAddedAndDeprecatedAndRemoved) {
auto source = R"FIDL(
@available(added=1, deprecated=2, removed=HEAD)
library example;
)FIDL";
for (auto version : {"1", "2", kMaxNumericVersion.c_str(), "HEAD", "LEGACY"}) {
TestLibrary library(source);
library.SelectVersion("example", version);
ASSERT_COMPILED(library);
}
}
TEST(VersioningTests, GoodLibraryAddedAndRemovedLegacyFalse) {
auto source = R"FIDL(
@available(added=1, removed=2, legacy=false)
library example;
)FIDL";
for (auto version : {"1", "2", kMaxNumericVersion.c_str(), "HEAD", "LEGACY"}) {
TestLibrary library(source);
library.SelectVersion("example", version);
ASSERT_COMPILED(library);
}
}
TEST(VersioningTests, GoodLibraryAddedAndRemovedLegacyTrue) {
auto source = R"FIDL(
@available(added=1, removed=2, legacy=true)
library example;
)FIDL";
for (auto version : {"1", "2", kMaxNumericVersion.c_str(), "HEAD", "LEGACY"}) {
TestLibrary library(source);
library.SelectVersion("example", version);
ASSERT_COMPILED(library);
}
}
TEST(VersioningTests, GoodDeclAddedAtHead) {
auto source = R"FIDL(
@available(added=1)
library example;
@available(added=HEAD)
type Foo = struct {};
)FIDL";
{
TestLibrary library(source);
library.SelectVersion("example", "1");
ASSERT_COMPILED(library);
ASSERT_EQ(library.LookupStruct("Foo"), nullptr);
}
{
TestLibrary library(source);
library.SelectVersion("example", "2");
ASSERT_COMPILED(library);
ASSERT_EQ(library.LookupStruct("Foo"), nullptr);
}
{
TestLibrary library(source);
library.SelectVersion("example", kMaxNumericVersion);
ASSERT_COMPILED(library);
ASSERT_EQ(library.LookupStruct("Foo"), nullptr);
}
{
TestLibrary library(source);
library.SelectVersion("example", "HEAD");
ASSERT_COMPILED(library);
ASSERT_NE(library.LookupStruct("Foo"), nullptr);
}
{
TestLibrary library(source);
library.SelectVersion("example", "LEGACY");
ASSERT_COMPILED(library);
ASSERT_NE(library.LookupStruct("Foo"), nullptr);
}
}
TEST(VersioningTests, GoodDeclAddedAtOne) {
auto source = R"FIDL(
@available(added=1)
library example;
@available(added=1)
type Foo = struct {};
)FIDL";
{
TestLibrary library(source);
library.SelectVersion("example", "1");
ASSERT_COMPILED(library);
ASSERT_NE(library.LookupStruct("Foo"), nullptr);
}
{
TestLibrary library(source);
library.SelectVersion("example", "2");
ASSERT_COMPILED(library);
ASSERT_NE(library.LookupStruct("Foo"), nullptr);
}
{
TestLibrary library(source);
library.SelectVersion("example", kMaxNumericVersion);
ASSERT_COMPILED(library);
ASSERT_NE(library.LookupStruct("Foo"), nullptr);
}
{
TestLibrary library(source);
library.SelectVersion("example", "HEAD");
ASSERT_COMPILED(library);
ASSERT_NE(library.LookupStruct("Foo"), nullptr);
}
{
TestLibrary library(source);
library.SelectVersion("example", "LEGACY");
ASSERT_COMPILED(library);
ASSERT_NE(library.LookupStruct("Foo"), nullptr);
}
}
TEST(VersioningTests, GoodDeclAddedAndRemoved) {
auto source = R"FIDL(
@available(added=1)
library example;
@available(added=1, removed=2)
type Foo = struct {};
)FIDL";
{
TestLibrary library(source);
library.SelectVersion("example", "1");
ASSERT_COMPILED(library);
ASSERT_NE(library.LookupStruct("Foo"), nullptr);
}
{
TestLibrary library(source);
library.SelectVersion("example", "2");
ASSERT_COMPILED(library);
ASSERT_EQ(library.LookupStruct("Foo"), nullptr);
}
{
TestLibrary library(source);
library.SelectVersion("example", kMaxNumericVersion);
ASSERT_COMPILED(library);
ASSERT_EQ(library.LookupStruct("Foo"), nullptr);
}
{
TestLibrary library(source);
library.SelectVersion("example", "HEAD");
ASSERT_COMPILED(library);
ASSERT_EQ(library.LookupStruct("Foo"), nullptr);
}
{
TestLibrary library(source);
library.SelectVersion("example", "LEGACY");
ASSERT_COMPILED(library);
ASSERT_EQ(library.LookupStruct("Foo"), nullptr);
}
}
TEST(VersioningTests, GoodDeclAddedAndReplaced) {
auto source = R"FIDL(
@available(added=1)
library example;
@available(added=1, replaced=2)
type Foo = struct {};
@available(added=2)
type Foo = table {};
)FIDL";
{
TestLibrary library(source);
library.SelectVersion("example", "1");
ASSERT_COMPILED(library);
ASSERT_NE(library.LookupStruct("Foo"), nullptr);
}
{
TestLibrary library(source);
library.SelectVersion("example", "2");
ASSERT_COMPILED(library);
ASSERT_EQ(library.LookupStruct("Foo"), nullptr);
ASSERT_NE(library.LookupTable("Foo"), nullptr);
}
{
TestLibrary library(source);
library.SelectVersion("example", kMaxNumericVersion);
ASSERT_COMPILED(library);
ASSERT_EQ(library.LookupStruct("Foo"), nullptr);
ASSERT_NE(library.LookupTable("Foo"), nullptr);
}
{
TestLibrary library(source);
library.SelectVersion("example", "HEAD");
ASSERT_COMPILED(library);
ASSERT_EQ(library.LookupStruct("Foo"), nullptr);
ASSERT_NE(library.LookupTable("Foo"), nullptr);
}
{
TestLibrary library(source);
library.SelectVersion("example", "LEGACY");
ASSERT_COMPILED(library);
ASSERT_EQ(library.LookupStruct("Foo"), nullptr);
ASSERT_NE(library.LookupTable("Foo"), nullptr);
}
}
TEST(VersioningTests, GoodDeclAddedAndDeprecatedAndRemoved) {
auto source = R"FIDL(
@available(added=1)
library example;
@available(added=1, deprecated=2, removed=HEAD)
type Foo = struct {};
)FIDL";
{
TestLibrary library(source);
library.SelectVersion("example", "1");
ASSERT_COMPILED(library);
ASSERT_NE(library.LookupStruct("Foo"), nullptr);
EXPECT_FALSE(library.LookupStruct("Foo")->availability.is_deprecated());
}
{
TestLibrary library(source);
library.SelectVersion("example", "2");
ASSERT_COMPILED(library);
ASSERT_NE(library.LookupStruct("Foo"), nullptr);
EXPECT_TRUE(library.LookupStruct("Foo")->availability.is_deprecated());
}
{
TestLibrary library(source);
library.SelectVersion("example", kMaxNumericVersion);
ASSERT_COMPILED(library);
ASSERT_NE(library.LookupStruct("Foo"), nullptr);
EXPECT_TRUE(library.LookupStruct("Foo")->availability.is_deprecated());
}
{
TestLibrary library(source);
library.SelectVersion("example", "HEAD");
ASSERT_COMPILED(library);
ASSERT_EQ(library.LookupStruct("Foo"), nullptr);
}
{
TestLibrary library(source);
library.SelectVersion("example", "LEGACY");
ASSERT_COMPILED(library);
ASSERT_EQ(library.LookupStruct("Foo"), nullptr);
}
}
TEST(VersioningTests, GoodDeclAddedAndRemovedLegacy) {
auto source = R"FIDL(
@available(added=1)
library example;
@available(added=1, removed=2, legacy=true)
type Foo = struct {};
)FIDL";
{
TestLibrary library(source);
library.SelectVersion("example", "1");
ASSERT_COMPILED(library);
ASSERT_NE(library.LookupStruct("Foo"), nullptr);
}
{
TestLibrary library(source);
library.SelectVersion("example", "2");
ASSERT_COMPILED(library);
ASSERT_EQ(library.LookupStruct("Foo"), nullptr);
}
{
TestLibrary library(source);
library.SelectVersion("example", kMaxNumericVersion);
ASSERT_COMPILED(library);
ASSERT_EQ(library.LookupStruct("Foo"), nullptr);
}
{
TestLibrary library(source);
library.SelectVersion("example", "HEAD");
ASSERT_COMPILED(library);
ASSERT_EQ(library.LookupStruct("Foo"), nullptr);
}
{
TestLibrary library(source);
library.SelectVersion("example", "LEGACY");
ASSERT_COMPILED(library);
// The decl is re-added at LEGACY.
ASSERT_NE(library.LookupStruct("Foo"), nullptr);
}
}
TEST(VersioningTests, GoodMemberAddedAtHead) {
auto source = R"FIDL(
@available(added=1)
library example;
type Foo = struct {
@available(added=HEAD)
member string;
};
)FIDL";
{
TestLibrary library(source);
library.SelectVersion("example", "1");
ASSERT_COMPILED(library);
ASSERT_NE(library.LookupStruct("Foo"), nullptr);
ASSERT_EQ(library.LookupStruct("Foo")->members.size(), 0u);
}
{
TestLibrary library(source);
library.SelectVersion("example", "2");
ASSERT_COMPILED(library);
ASSERT_NE(library.LookupStruct("Foo"), nullptr);
ASSERT_EQ(library.LookupStruct("Foo")->members.size(), 0u);
}
{
TestLibrary library(source);
library.SelectVersion("example", kMaxNumericVersion);
ASSERT_COMPILED(library);
ASSERT_NE(library.LookupStruct("Foo"), nullptr);
ASSERT_EQ(library.LookupStruct("Foo")->members.size(), 0u);
}
{
TestLibrary library(source);
library.SelectVersion("example", "HEAD");
ASSERT_COMPILED(library);
ASSERT_NE(library.LookupStruct("Foo"), nullptr);
ASSERT_EQ(library.LookupStruct("Foo")->members.size(), 1u);
}
{
TestLibrary library(source);
library.SelectVersion("example", "LEGACY");
ASSERT_COMPILED(library);
ASSERT_NE(library.LookupStruct("Foo"), nullptr);
ASSERT_EQ(library.LookupStruct("Foo")->members.size(), 1u);
}
}
TEST(VersioningTests, GoodMemberAddedAtOne) {
auto source = R"FIDL(
@available(added=1)
library example;
type Foo = struct {
@available(added=1)
member string;
};
)FIDL";
{
TestLibrary library(source);
library.SelectVersion("example", "1");
ASSERT_COMPILED(library);
ASSERT_NE(library.LookupStruct("Foo"), nullptr);
ASSERT_EQ(library.LookupStruct("Foo")->members.size(), 1u);
}
{
TestLibrary library(source);
library.SelectVersion("example", "2");
ASSERT_COMPILED(library);
ASSERT_NE(library.LookupStruct("Foo"), nullptr);
ASSERT_EQ(library.LookupStruct("Foo")->members.size(), 1u);
}
{
TestLibrary library(source);
library.SelectVersion("example", kMaxNumericVersion);
ASSERT_COMPILED(library);
ASSERT_NE(library.LookupStruct("Foo"), nullptr);
ASSERT_EQ(library.LookupStruct("Foo")->members.size(), 1u);
}
{
TestLibrary library(source);
library.SelectVersion("example", "HEAD");
ASSERT_COMPILED(library);
ASSERT_NE(library.LookupStruct("Foo"), nullptr);
ASSERT_EQ(library.LookupStruct("Foo")->members.size(), 1u);
}
{
TestLibrary library(source);
library.SelectVersion("example", "LEGACY");
ASSERT_COMPILED(library);
ASSERT_NE(library.LookupStruct("Foo"), nullptr);
ASSERT_EQ(library.LookupStruct("Foo")->members.size(), 1u);
}
}
TEST(VersioningTests, GoodMemberAddedAndRemoved) {
auto source = R"FIDL(
@available(added=1)
library example;
type Foo = struct {
@available(added=1, removed=2)
member string;
};
)FIDL";
{
TestLibrary library(source);
library.SelectVersion("example", "1");
ASSERT_COMPILED(library);
ASSERT_NE(library.LookupStruct("Foo"), nullptr);
ASSERT_EQ(library.LookupStruct("Foo")->members.size(), 1u);
}
{
TestLibrary library(source);
library.SelectVersion("example", "2");
ASSERT_COMPILED(library);
ASSERT_NE(library.LookupStruct("Foo"), nullptr);
ASSERT_EQ(library.LookupStruct("Foo")->members.size(), 0u);
}
{
TestLibrary library(source);
library.SelectVersion("example", kMaxNumericVersion);
ASSERT_COMPILED(library);
ASSERT_NE(library.LookupStruct("Foo"), nullptr);
ASSERT_EQ(library.LookupStruct("Foo")->members.size(), 0u);
}
{
TestLibrary library(source);
library.SelectVersion("example", "HEAD");
ASSERT_COMPILED(library);
ASSERT_NE(library.LookupStruct("Foo"), nullptr);
ASSERT_EQ(library.LookupStruct("Foo")->members.size(), 0u);
}
{
TestLibrary library(source);
library.SelectVersion("example", "LEGACY");
ASSERT_COMPILED(library);
ASSERT_NE(library.LookupStruct("Foo"), nullptr);
ASSERT_EQ(library.LookupStruct("Foo")->members.size(), 0u);
}
}
TEST(VersioningTests, GoodMemberAddedAndReplaced) {
auto source = R"FIDL(
@available(added=1)
library example;
type Foo = struct {
@available(added=1, replaced=2)
member string;
@available(added=2)
member uint32;
};
)FIDL";
{
TestLibrary library(source);
library.SelectVersion("example", "1");
ASSERT_COMPILED(library);
ASSERT_NE(library.LookupStruct("Foo"), nullptr);
ASSERT_EQ(library.LookupStruct("Foo")->members.size(), 1u);
ASSERT_EQ(library.LookupStruct("Foo")->members.front().type_ctor->type->kind,
Type::Kind::kString);
}
{
TestLibrary library(source);
library.SelectVersion("example", "2");
ASSERT_COMPILED(library);
ASSERT_NE(library.LookupStruct("Foo"), nullptr);
ASSERT_EQ(library.LookupStruct("Foo")->members.size(), 1u);
ASSERT_EQ(library.LookupStruct("Foo")->members.front().type_ctor->type->kind,
Type::Kind::kPrimitive);
}
{
TestLibrary library(source);
library.SelectVersion("example", kMaxNumericVersion);
ASSERT_COMPILED(library);
ASSERT_NE(library.LookupStruct("Foo"), nullptr);
ASSERT_EQ(library.LookupStruct("Foo")->members.size(), 1u);
ASSERT_EQ(library.LookupStruct("Foo")->members.front().type_ctor->type->kind,
Type::Kind::kPrimitive);
}
{
TestLibrary library(source);
library.SelectVersion("example", "HEAD");
ASSERT_COMPILED(library);
ASSERT_NE(library.LookupStruct("Foo"), nullptr);
ASSERT_EQ(library.LookupStruct("Foo")->members.size(), 1u);
ASSERT_EQ(library.LookupStruct("Foo")->members.front().type_ctor->type->kind,
Type::Kind::kPrimitive);
}
{
TestLibrary library(source);
library.SelectVersion("example", "LEGACY");
ASSERT_COMPILED(library);
ASSERT_NE(library.LookupStruct("Foo"), nullptr);
ASSERT_EQ(library.LookupStruct("Foo")->members.size(), 1u);
ASSERT_EQ(library.LookupStruct("Foo")->members.front().type_ctor->type->kind,
Type::Kind::kPrimitive);
}
}
TEST(VersioningTests, GoodMemberAddedAndDeprecatedAndRemoved) {
auto source = R"FIDL(
@available(added=1)
library example;
type Foo = struct {
@available(added=1, deprecated=2, removed=HEAD)
member string;
};
)FIDL";
{
TestLibrary library(source);
library.SelectVersion("example", "1");
ASSERT_COMPILED(library);
ASSERT_NE(library.LookupStruct("Foo"), nullptr);
ASSERT_EQ(library.LookupStruct("Foo")->members.size(), 1u);
EXPECT_FALSE(library.LookupStruct("Foo")->members.front().availability.is_deprecated());
}
{
TestLibrary library(source);
library.SelectVersion("example", "2");
ASSERT_COMPILED(library);
ASSERT_NE(library.LookupStruct("Foo"), nullptr);
ASSERT_EQ(library.LookupStruct("Foo")->members.size(), 1u);
EXPECT_TRUE(library.LookupStruct("Foo")->members.front().availability.is_deprecated());
}
{
TestLibrary library(source);
library.SelectVersion("example", kMaxNumericVersion);
ASSERT_COMPILED(library);
ASSERT_NE(library.LookupStruct("Foo"), nullptr);
ASSERT_EQ(library.LookupStruct("Foo")->members.size(), 1u);
EXPECT_TRUE(library.LookupStruct("Foo")->members.front().availability.is_deprecated());
}
{
TestLibrary library(source);
library.SelectVersion("example", "HEAD");
ASSERT_COMPILED(library);
ASSERT_NE(library.LookupStruct("Foo"), nullptr);
ASSERT_EQ(library.LookupStruct("Foo")->members.size(), 0u);
}
{
TestLibrary library(source);
library.SelectVersion("example", "LEGACY");
ASSERT_COMPILED(library);
ASSERT_NE(library.LookupStruct("Foo"), nullptr);
ASSERT_EQ(library.LookupStruct("Foo")->members.size(), 0u);
}
}
TEST(VersioningTests, GoodMemberAddedAndRemovedLegacy) {
auto source = R"FIDL(
@available(added=1)
library example;
type Foo = struct {
@available(added=1, removed=2, legacy=true)
member string;
};
)FIDL";
{
TestLibrary library(source);
library.SelectVersion("example", "1");
ASSERT_COMPILED(library);
ASSERT_NE(library.LookupStruct("Foo"), nullptr);
ASSERT_EQ(library.LookupStruct("Foo")->members.size(), 1u);
}
{
TestLibrary library(source);
library.SelectVersion("example", "2");
ASSERT_COMPILED(library);
ASSERT_NE(library.LookupStruct("Foo"), nullptr);
ASSERT_EQ(library.LookupStruct("Foo")->members.size(), 0u);
}
{
TestLibrary library(source);
library.SelectVersion("example", kMaxNumericVersion);
ASSERT_COMPILED(library);
ASSERT_NE(library.LookupStruct("Foo"), nullptr);
ASSERT_EQ(library.LookupStruct("Foo")->members.size(), 0u);
}
{
TestLibrary library(source);
library.SelectVersion("example", "HEAD");
ASSERT_COMPILED(library);
ASSERT_NE(library.LookupStruct("Foo"), nullptr);
ASSERT_EQ(library.LookupStruct("Foo")->members.size(), 0u);
}
{
TestLibrary library(source);
library.SelectVersion("example", "LEGACY");
ASSERT_COMPILED(library);
ASSERT_NE(library.LookupStruct("Foo"), nullptr);
// The member is re-added at LEGACY.
ASSERT_EQ(library.LookupStruct("Foo")->members.size(), 1u);
}
}
TEST(VersioningTests, GoodAllArgumentsOnLibrary) {
TestLibrary library(R"FIDL(
@available(platform="notexample", added=1, deprecated=2, removed=3, note="use xyz instead", legacy=false)
library example;
)FIDL");
library.SelectVersion("notexample", "1");
ASSERT_COMPILED(library);
}
TEST(VersioningTests, GoodAllArgumentsOnDecl) {
TestLibrary library(R"FIDL(
@available(added=1)
library example;
@available(added=1, deprecated=2, removed=3, note="use xyz instead", legacy=false)
type Foo = struct {};
)FIDL");
library.SelectVersion("example", "1");
ASSERT_COMPILED(library);
}
TEST(VersioningTests, GoodAllArgumentsOnMember) {
TestLibrary library(R"FIDL(
@available(added=1)
library example;
type Foo = struct {
@available(added=1, deprecated=2, removed=3, note="use xyz instead", legacy=false)
member string;
};
)FIDL");
library.SelectVersion("example", "1");
ASSERT_COMPILED(library);
}
TEST(VersioningTests, GoodAttributeOnEverything) {
TestLibrary library(R"FIDL(
@available(added=1)
library example;
@available(added=1)
const CONST uint32 = 1;
@available(added=1)
alias Alias = string;
// TODO(https://fxbug.dev/42158155): Uncomment.
// @available(added=1)
// type Type = string;
@available(added=1)
type Bits = bits {
@available(added=1)
MEMBER = 1;
};
@available(added=1)
type Enum = enum {
@available(added=1)
MEMBER = 1;
};
@available(added=1)
type Struct = struct {
@available(added=1)
member string;
};
@available(added=1)
type Table = table {
@available(added=1)
1: member string;
};
@available(added=1)
type Union = union {
@available(added=1)
1: member string;
};
@available(added=1)
protocol ProtocolToCompose {};
@available(added=1)
protocol Protocol {
@available(added=1)
compose ProtocolToCompose;
@available(added=1)
Method() -> ();
};
@available(added=1)
service Service {
@available(added=1)
member client_end:Protocol;
};
@available(added=1)
resource_definition Resource : uint32 {
properties {
@available(added=1)
subtype flexible enum : uint32 {};
};
};
)FIDL");
library.SelectVersion("example", "1");
ASSERT_COMPILED(library);
auto& unfiltered_decls = library.LookupLibrary("example")->declaration_order;
auto& filtered_decls = library.declaration_order();
// Because everything has the same availability, nothing gets split.
EXPECT_EQ(unfiltered_decls.size(), filtered_decls.size());
}
// TODO(https://fxbug.dev/42146818): Currently attributes `@HERE type Foo = struct {};` and
// `type Foo = @HERE struct {};` are interchangeable. We just disallow using
// both at once (ErrRedundantAttributePlacement). However, @available on the
// anonymous layout is confusing so maybe we should rethink this design.
TEST(VersioningTests, GoodAttributeOnAnonymousLayoutTopLevel) {
auto source = R"FIDL(
@available(added=1)
library example;
type Foo = @available(added=2) struct {};
)FIDL";
{
TestLibrary library(source);
library.SelectVersion("example", "1");
ASSERT_COMPILED(library);
ASSERT_EQ(library.LookupStruct("Foo"), nullptr);
}
{
TestLibrary library(source);
library.SelectVersion("example", "2");
ASSERT_COMPILED(library);
ASSERT_NE(library.LookupStruct("Foo"), nullptr);
}
}
TEST(VersioningTests, BadAttributeOnAnonymousLayoutInMember) {
TestLibrary library(R"FIDL(
@available(added=1)
library example;
type Foo = struct {
member @available(added=2) struct {};
};
)FIDL");
library.SelectVersion("example", "HEAD");
library.ExpectFail(ErrInvalidAttributePlacement, "available");
ASSERT_COMPILER_DIAGNOSTICS(library);
}
TEST(VersioningTests, BadInvalidVersionBelowMin) {
TestLibrary library(R"FIDL(
@available(added=0)
library example;
)FIDL");
library.SelectVersion("example", "HEAD");
library.ExpectFail(ErrInvalidVersion, 0);
ASSERT_COMPILER_DIAGNOSTICS(library);
}
TEST(VersioningTests, BadInvalidVersionAboveMaxNumeric) {
TestLibrary library(R"FIDL(
@available(added=9223372036854775808) // 2^63
library example;
)FIDL");
library.SelectVersion("example", "HEAD");
library.ExpectFail(ErrInvalidVersion, 9223372036854775808u);
ASSERT_COMPILER_DIAGNOSTICS(library);
}
TEST(VersioningTests, BadInvalidVersionBeforeHeadOrdinal) {
TestLibrary library(R"FIDL(
@available(added=18446744073709551613) // 2^64-3
library example;
)FIDL");
library.SelectVersion("example", "HEAD");
library.ExpectFail(ErrInvalidVersion, 18446744073709551613u);
ASSERT_COMPILER_DIAGNOSTICS(library);
}
TEST(VersioningTests, GoodVersionHeadOrdinal) {
TestLibrary library(R"FIDL(
@available(added=18446744073709551614) // 2^64-2
library example;
)FIDL");
library.SelectVersion("example", "HEAD");
ASSERT_COMPILED(library);
}
TEST(VersioningTests, BadInvalidVersionLegacyOrdinal) {
TestLibrary library(R"FIDL(
@available(added=18446744073709551615) // 2^64-1
library example;
)FIDL");
library.SelectVersion("example", "HEAD");
library.ExpectFail(ErrInvalidVersion, 18446744073709551615u);
ASSERT_COMPILER_DIAGNOSTICS(library);
}
TEST(VersioningTests, BadInvalidVersionAfterLegacyOrdinal) {
TestLibrary library(R"FIDL(
@available(added=18446744073709551616) // 2^64
library example;
)FIDL");
library.SelectVersion("example", "HEAD");
library.ExpectFail(ErrCouldNotResolveAttributeArg);
library.ExpectFail(ErrConstantOverflowsType, "18446744073709551616", "uint64");
ASSERT_COMPILER_DIAGNOSTICS(library);
}
TEST(VersioningTests, BadInvalidVersionLegacy) {
TestLibrary library(R"FIDL(
@available(added=LEGACY)
library example;
)FIDL");
library.SelectVersion("example", "HEAD");
library.ExpectFail(ErrAttributeArgRequiresLiteral, "added", "available");
ASSERT_COMPILER_DIAGNOSTICS(library);
}
TEST(VersioningTests, BadInvalidVersionNegative) {
TestLibrary library(R"FIDL(
@available(added=-1)
library example;
)FIDL");
library.SelectVersion("example", "HEAD");
library.ExpectFail(ErrCouldNotResolveAttributeArg);
library.ExpectFail(ErrConstantOverflowsType, "-1", "uint64");
ASSERT_COMPILER_DIAGNOSTICS(library);
}
TEST(VersioningTests, BadNoArguments) {
TestLibrary library;
library.AddFile("bad/fi-0147.test.fidl");
library.SelectVersion("test", "HEAD");
library.ExpectFail(ErrAvailableMissingArguments);
ASSERT_COMPILER_DIAGNOSTICS(library);
}
TEST(VersioningTests, BadLibraryMissingAddedOnlyRemoved) {
TestLibrary library;
library.AddFile("bad/fi-0150-a.test.fidl");
library.SelectVersion("test", "HEAD");
library.ExpectFail(ErrLibraryAvailabilityMissingAdded);
ASSERT_COMPILER_DIAGNOSTICS(library);
}
TEST(VersioningTests, BadLibraryMissingAddedOnlyPlatform) {
TestLibrary library;
library.AddFile("bad/fi-0150-b.test.fidl");
library.SelectVersion("foo", "HEAD");
library.ExpectFail(ErrLibraryAvailabilityMissingAdded);
ASSERT_COMPILER_DIAGNOSTICS(library);
}
TEST(VersioningTests, BadLibraryReplaced) {
TestLibrary library;
library.AddFile("bad/fi-0204.test.fidl");
library.SelectVersion("test", "HEAD");
library.ExpectFail(ErrLibraryReplaced);
ASSERT_COMPILER_DIAGNOSTICS(library);
}
TEST(VersioningTests, BadNoteWithoutDeprecation) {
TestLibrary library;
library.AddFile("bad/fi-0148.test.fidl");
library.SelectVersion("test", "HEAD");
library.ExpectFail(ErrNoteWithoutDeprecation);
ASSERT_COMPILER_DIAGNOSTICS(library);
}
TEST(VersioningTests, BadRemovedAndReplaced) {
TestLibrary library;
library.AddFile("bad/fi-0203.test.fidl");
library.SelectVersion("test", "HEAD");
library.ExpectFail(ErrRemovedAndReplaced);
ASSERT_COMPILER_DIAGNOSTICS(library);
}
TEST(VersioningTests, BadPlatformNotOnLibrary) {
TestLibrary library(R"FIDL(
@available(added=1)
library example;
@available(platform="bad")
type Foo = struct {};
)FIDL");
library.SelectVersion("example", "HEAD");
library.ExpectFail(ErrPlatformNotOnLibrary);
ASSERT_COMPILER_DIAGNOSTICS(library);
}
TEST(VersioningTests, BadUseInUnversionedLibrary) {
TestLibrary library;
library.AddFile("bad/fi-0151.test.fidl");
library.SelectVersion("test", "HEAD");
library.ExpectFail(ErrMissingLibraryAvailability, "test.bad.fi0151");
ASSERT_COMPILER_DIAGNOSTICS(library);
}
TEST(VersioningTests, BadUseInUnversionedLibraryReportedOncePerAttribute) {
TestLibrary library(R"FIDL(
library example;
@available(added=1)
type Foo = struct {
@available(added=2)
member1 bool;
member2 bool;
};
)FIDL");
library.SelectVersion("example", "HEAD");
// Note: Only twice, not a third time for member2.
library.ExpectFail(ErrMissingLibraryAvailability, "example");
library.ExpectFail(ErrMissingLibraryAvailability, "example");
ASSERT_COMPILER_DIAGNOSTICS(library);
}
TEST(VersioningTests, BadAddedEqualsRemoved) {
TestLibrary library;
library.AddFile("bad/fi-0154-a.test.fidl");
library.SelectVersion("test", "HEAD");
library.ExpectFail(ErrInvalidAvailabilityOrder, "added < removed");
ASSERT_COMPILER_DIAGNOSTICS(library);
}
TEST(VersioningTests, BadAddedEqualsReplaced) {
TestLibrary library(R"FIDL(
@available(added=1)
library example;
@available(added=2, replaced=2)
type Foo = struct {};
)FIDL");
library.SelectVersion("example", "HEAD");
library.ExpectFail(ErrInvalidAvailabilityOrder, "added < replaced");
ASSERT_COMPILER_DIAGNOSTICS(library);
}
TEST(VersioningTests, BadAddedGreaterThanRemoved) {
TestLibrary library(R"FIDL(
@available(added=2, removed=1)
library example;
)FIDL");
library.SelectVersion("example", "HEAD");
library.ExpectFail(ErrInvalidAvailabilityOrder, "added < removed");
ASSERT_COMPILER_DIAGNOSTICS(library);
}
TEST(VersioningTests, BadAddedGreaterThanReplaced) {
TestLibrary library(R"FIDL(
@available(added=1)
library example;
@available(added=3, replaced=2)
type Foo = struct {};
)FIDL");
library.SelectVersion("example", "HEAD");
library.ExpectFail(ErrInvalidAvailabilityOrder, "added < replaced");
ASSERT_COMPILER_DIAGNOSTICS(library);
}
TEST(VersioningTests, GoodAddedEqualsDeprecated) {
TestLibrary library(R"FIDL(
@available(added=1, deprecated=1)
library example;
)FIDL");
library.SelectVersion("example", "1");
ASSERT_COMPILED(library);
}
TEST(VersioningTests, BadAddedGreaterThanDeprecated) {
TestLibrary library(R"FIDL(
@available(added=2, deprecated=1)
library example;
)FIDL");
library.SelectVersion("example", "HEAD");
library.ExpectFail(ErrInvalidAvailabilityOrder, "added <= deprecated");
ASSERT_COMPILER_DIAGNOSTICS(library);
}
TEST(VersioningTests, BadDeprecatedEqualsRemoved) {
TestLibrary library;
library.AddFile("bad/fi-0154-b.test.fidl");
library.SelectVersion("test", "HEAD");
library.ExpectFail(ErrInvalidAvailabilityOrder, "added <= deprecated < removed");
ASSERT_COMPILER_DIAGNOSTICS(library);
}
TEST(VersioningTests, BadDeprecatedEqualsReplaced) {
TestLibrary library(R"FIDL(
@available(added=1)
library example;
@available(added=1, deprecated=2, replaced=2)
type Foo = struct {};
)FIDL");
library.SelectVersion("example", "HEAD");
library.ExpectFail(ErrInvalidAvailabilityOrder, "added <= deprecated < replaced");
ASSERT_COMPILER_DIAGNOSTICS(library);
}
TEST(VersioningTests, BadDeprecatedGreaterThanRemoved) {
TestLibrary library(R"FIDL(
@available(added=1, deprecated=3, removed=2)
library example;
)FIDL");
library.SelectVersion("example", "HEAD");
library.ExpectFail(ErrInvalidAvailabilityOrder, "added <= deprecated < removed");
ASSERT_COMPILER_DIAGNOSTICS(library);
}
TEST(VersioningTests, BadDeprecatedGreaterThanReplaced) {
TestLibrary library(R"FIDL(
@available(added=1)
library example;
@available(added=1, deprecated=3, replaced=2)
type Foo = struct {};
)FIDL");
library.SelectVersion("example", "HEAD");
library.ExpectFail(ErrInvalidAvailabilityOrder, "added <= deprecated < replaced");
ASSERT_COMPILER_DIAGNOSTICS(library);
}
TEST(VersioningTests, BadLegacyTrueNotRemoved) {
TestLibrary library(R"FIDL(
@available(added=1, legacy=true)
library example;
)FIDL");
library.SelectVersion("example", "HEAD");
library.ExpectFail(ErrLegacyWithoutRemoval, "legacy");
ASSERT_COMPILER_DIAGNOSTICS(library);
}
TEST(VersioningTests, BadLegacyFalseNotRemoved) {
TestLibrary library(R"FIDL(
@available(added=1, legacy=false)
library example;
)FIDL");
library.SelectVersion("example", "HEAD");
library.ExpectFail(ErrLegacyWithoutRemoval, "legacy");
ASSERT_COMPILER_DIAGNOSTICS(library);
}
TEST(VersioningTests, BadLegacyTrueNotRemovedMethod) {
TestLibrary library;
library.AddFile("bad/fi-0182.test.fidl");
library.SelectVersion("test", "HEAD");
library.ExpectFail(ErrLegacyWithoutRemoval, "legacy");
ASSERT_COMPILER_DIAGNOSTICS(library);
}
TEST(VersioningTests, GoodRedundantWithParent) {
TestLibrary library(R"FIDL(
@available(added=2, deprecated=4, removed=6)
library example;
@available(added=2, deprecated=4, removed=6)
type Foo = struct {};
)FIDL");
library.SelectVersion("example", "2");
ASSERT_COMPILED(library);
}
TEST(VersioningTests, BadAddedBeforeParentAdded) {
TestLibrary library;
library.AddFile("bad/fi-0155-a.test.fidl");
library.SelectVersion("test", "HEAD");
library.ExpectFail(ErrAvailabilityConflictsWithParent, "added", "1", "added", "2",
"bad/fi-0155-a.test.fidl:4:12", "added", "before", "added");
ASSERT_COMPILER_DIAGNOSTICS(library);
}
TEST(VersioningTests, GoodAddedWhenParentDeprecated) {
TestLibrary library(R"FIDL(
@available(added=2, deprecated=4, removed=6)
library example;
@available(added=4)
type Foo = struct {};
)FIDL");
library.SelectVersion("example", "4");
ASSERT_COMPILED(library);
auto foo = library.LookupStruct("Foo");
ASSERT_NE(foo, nullptr);
EXPECT_TRUE(foo->availability.is_deprecated());
}
TEST(VersioningTests, GoodAddedAfterParentDeprecated) {
TestLibrary library(R"FIDL(
@available(added=2, deprecated=4, removed=6)
library example;
@available(added=5)
type Foo = struct {};
)FIDL");
library.SelectVersion("example", "5");
ASSERT_COMPILED(library);
auto foo = library.LookupStruct("Foo");
ASSERT_NE(foo, nullptr);
EXPECT_TRUE(foo->availability.is_deprecated());
}
TEST(VersioningTests, BadAddedWhenParentRemoved) {
TestLibrary library;
library.AddFile("bad/fi-0155-b.test.fidl");
library.SelectVersion("test", "HEAD");
library.ExpectFail(ErrAvailabilityConflictsWithParent, "added", "4", "removed", "4",
"bad/fi-0155-b.test.fidl:4:35", "added", "after", "removed");
ASSERT_COMPILER_DIAGNOSTICS(library);
}
TEST(VersioningTests, BadAddedWhenParentReplaced) {
TestLibrary library(R"FIDL(
@available(added=1)
library example;
@available(added=2, deprecated=4, replaced=6)
type Foo = struct {
@available(added=6)
member bool;
};
@available(added=6)
type Foo = struct {};
)FIDL");
library.SelectVersion("example", "HEAD");
library.ExpectFail(ErrAvailabilityConflictsWithParent, "added", "6", "replaced", "6",
"example.fidl:5:35", "added", "after", "replaced");
ASSERT_COMPILER_DIAGNOSTICS(library);
}
TEST(VersioningTests, BadAddedAfterParentRemoved) {
TestLibrary library(R"FIDL(
@available(added=2, deprecated=4, removed=6)
library example;
@available(added=7)
type Foo = struct {};
)FIDL");
library.SelectVersion("example", "HEAD");
library.ExpectFail(ErrAvailabilityConflictsWithParent, "added", "7", "removed", "6",
"example.fidl:2:35", "added", "after", "removed");
ASSERT_COMPILER_DIAGNOSTICS(library);
}
TEST(VersioningTests, BadAddedAfterParentReplaced) {
TestLibrary library(R"FIDL(
@available(added=1)
library example;
@available(added=2, deprecated=4, replaced=6)
type Foo = struct {
@available(added=7)
member bool;
};
@available(added=6)
type Foo = struct {};
)FIDL");
library.SelectVersion("example", "HEAD");
library.ExpectFail(ErrAvailabilityConflictsWithParent, "added", "7", "replaced", "6",
"example.fidl:5:35", "added", "after", "replaced");
ASSERT_COMPILER_DIAGNOSTICS(library);
}
TEST(VersioningTests, BadDeprecatedBeforeParentAdded) {
TestLibrary library(R"FIDL(
@available(added=2, deprecated=4, removed=6)
library example;
@available(deprecated=1)
type Foo = struct {};
)FIDL");
library.SelectVersion("example", "HEAD");
library.ExpectFail(ErrAvailabilityConflictsWithParent, "deprecated", "1", "added", "2",
"example.fidl:2:12", "deprecated", "before", "added");
ASSERT_COMPILER_DIAGNOSTICS(library);
}
TEST(VersioningTests, GoodDeprecatedWhenParentAdded) {
TestLibrary library(R"FIDL(
@available(added=2, removed=6) // never deprecated
library example;
@available(deprecated=2)
type Foo = struct {};
)FIDL");
library.SelectVersion("example", "2");
ASSERT_COMPILED(library);
auto foo = library.LookupStruct("Foo");
ASSERT_NE(foo, nullptr);
EXPECT_TRUE(foo->availability.is_deprecated());
}
TEST(VersioningTests, GoodDeprecatedBeforeParentDeprecated) {
TestLibrary library(R"FIDL(
@available(added=2, deprecated=4, removed=6)
library example;
@available(deprecated=3)
type Foo = struct {};
)FIDL");
library.SelectVersion("example", "3");
ASSERT_COMPILED(library);
auto foo = library.LookupStruct("Foo");
ASSERT_NE(foo, nullptr);
EXPECT_TRUE(foo->availability.is_deprecated());
}
TEST(VersioningTests, BadDeprecatedAfterParentDeprecated) {
TestLibrary library(R"FIDL(
@available(added=2, deprecated=4, removed=6)
library example;
@available(deprecated=5)
type Foo = struct {};
)FIDL");
library.SelectVersion("example", "HEAD");
library.ExpectFail(ErrAvailabilityConflictsWithParent, "deprecated", "5", "deprecated", "4",
"example.fidl:2:21", "deprecated", "after", "deprecated");
ASSERT_COMPILER_DIAGNOSTICS(library);
}
TEST(VersioningTests, BadDeprecatedWhenParentRemoved) {
TestLibrary library(R"FIDL(
@available(added=2, deprecated=4, removed=6)
library example;
@available(deprecated=6)
type Foo = struct {};
)FIDL");
library.SelectVersion("example", "HEAD");
library.ExpectFail(ErrAvailabilityConflictsWithParent, "deprecated", "6", "removed", "6",
"example.fidl:2:35", "deprecated", "after", "removed");
ASSERT_COMPILER_DIAGNOSTICS(library);
}
TEST(VersioningTests, BadDeprecatedWhenParentReplaced) {
TestLibrary library(R"FIDL(
@available(added=1)
library example;
@available(added=2, deprecated=4, replaced=6)
type Foo = struct {
@available(deprecated=6)
member bool;
};
@available(added=6)
type Foo = struct {};
)FIDL");
library.SelectVersion("example", "HEAD");
library.ExpectFail(ErrAvailabilityConflictsWithParent, "deprecated", "6", "replaced", "6",
"example.fidl:5:35", "deprecated", "after", "replaced");
ASSERT_COMPILER_DIAGNOSTICS(library);
}
TEST(VersioningTests, BadDeprecatedAfterParentRemoved) {
TestLibrary library(R"FIDL(
@available(added=2, deprecated=4, removed=6)
library example;
@available(deprecated=7)
type Foo = struct {};
)FIDL");
library.SelectVersion("example", "HEAD");
library.ExpectFail(ErrAvailabilityConflictsWithParent, "deprecated", "7", "removed", "6",
"example.fidl:2:35", "deprecated", "after", "removed");
ASSERT_COMPILER_DIAGNOSTICS(library);
}
TEST(VersioningTests, BadDeprecatedAfterParentReplaced) {
TestLibrary library(R"FIDL(
@available(added=1)
library example;
@available(added=2, deprecated=4, replaced=6)
type Foo = struct {
@available(deprecated=7)
member bool;
};
@available(added=6)
type Foo = struct {};
)FIDL");
library.SelectVersion("example", "HEAD");
library.ExpectFail(ErrAvailabilityConflictsWithParent, "deprecated", "7", "replaced", "6",
"example.fidl:5:35", "deprecated", "after", "replaced");
ASSERT_COMPILER_DIAGNOSTICS(library);
}
TEST(VersioningTests, BadRemovedBeforeParentAdded) {
TestLibrary library(R"FIDL(
@available(added=2, deprecated=4, removed=6)
library example;
@available(removed=1)
type Foo = struct {};
)FIDL");
library.SelectVersion("example", "HEAD");
library.ExpectFail(ErrAvailabilityConflictsWithParent, "removed", "1", "added", "2",
"example.fidl:2:12", "removed", "before", "added");
ASSERT_COMPILER_DIAGNOSTICS(library);
}
TEST(VersioningTests, BadReplacedBeforeParentAdded) {
TestLibrary library(R"FIDL(
@available(added=1)
library example;
@available(added=2, deprecated=4, removed=6)
type Foo = struct {
@available(replaced=1)
member bool;
};
)FIDL");
library.SelectVersion("example", "HEAD");
library.ExpectFail(ErrAvailabilityConflictsWithParent, "replaced", "1", "added", "2",
"example.fidl:5:12", "replaced", "before", "added");
ASSERT_COMPILER_DIAGNOSTICS(library);
}
TEST(VersioningTests, BadRemovedWhenParentAdded) {
TestLibrary library(R"FIDL(
@available(added=2, deprecated=4, removed=6)
library example;
@available(removed=2)
type Foo = struct {};
)FIDL");
library.SelectVersion("example", "HEAD");
library.ExpectFail(ErrAvailabilityConflictsWithParent, "removed", "2", "added", "2",
"example.fidl:2:12", "removed", "before", "added");
ASSERT_COMPILER_DIAGNOSTICS(library);
}
TEST(VersioningTests, BadReplacedWhenParentAdded) {
TestLibrary library(R"FIDL(
@available(added=1)
library example;
@available(added=2, deprecated=4, removed=6)
type Foo = struct {
@available(replaced=2)
member bool;
};
)FIDL");
library.SelectVersion("example", "HEAD");
library.ExpectFail(ErrAvailabilityConflictsWithParent, "replaced", "2", "added", "2",
"example.fidl:5:12", "replaced", "before", "added");
ASSERT_COMPILER_DIAGNOSTICS(library);
}
TEST(VersioningTests, GoodRemovedBeforeParentDeprecated) {
TestLibrary library(R"FIDL(
@available(added=2, deprecated=4, removed=6)
library example;
@available(removed=3)
type Foo = struct {};
)FIDL");
library.SelectVersion("example", "2");
ASSERT_COMPILED(library);
auto foo = library.LookupStruct("Foo");
ASSERT_NE(foo, nullptr);
EXPECT_FALSE(foo->availability.is_deprecated());
}
TEST(VersioningTests, GoodReplacedBeforeParentDeprecated) {
TestLibrary library(R"FIDL(
@available(added=1)
library example;
@available(added=2, deprecated=4, removed=6)
type Foo = struct {
@available(replaced=3)
member bool;
@available(added=3)
member uint32;
};
)FIDL");
library.SelectVersion("example", "2");
ASSERT_COMPILED(library);
auto foo = library.LookupStruct("Foo");
ASSERT_NE(foo, nullptr);
EXPECT_FALSE(foo->availability.is_deprecated());
}
TEST(VersioningTests, GoodRemovedWhenParentDeprecated) {
TestLibrary library(R"FIDL(
@available(added=2, deprecated=4, removed=6)
library example;
@available(removed=4)
type Foo = struct {};
)FIDL");
library.SelectVersion("example", "3");
ASSERT_COMPILED(library);
auto foo = library.LookupStruct("Foo");
ASSERT_NE(foo, nullptr);
EXPECT_FALSE(foo->availability.is_deprecated());
}
TEST(VersioningTests, GoodReplacedWhenParentDeprecated) {
TestLibrary library(R"FIDL(
@available(added=1)
library example;
@available(added=2, deprecated=4, removed=6)
type Foo = struct {
@available(replaced=4)
member bool;
@available(added=4)
member uint32;
};
)FIDL");
library.SelectVersion("example", "3");
ASSERT_COMPILED(library);
auto foo = library.LookupStruct("Foo");
ASSERT_NE(foo, nullptr);
EXPECT_FALSE(foo->availability.is_deprecated());
}
TEST(VersioningTests, GoodRemovedAfterParentDeprecated) {
TestLibrary library(R"FIDL(
@available(added=2, deprecated=4, removed=6)
library example;
@available(removed=5)
type Foo = struct {};
)FIDL");
library.SelectVersion("example", "4");
ASSERT_COMPILED(library);
auto foo = library.LookupStruct("Foo");
ASSERT_NE(foo, nullptr);
EXPECT_TRUE(foo->availability.is_deprecated());
}
TEST(VersioningTests, GoodReplacedAfterParentDeprecated) {
TestLibrary library(R"FIDL(
@available(added=1)
library example;
@available(added=2, deprecated=4, removed=6)
type Foo = struct {
@available(replaced=5)
member bool;
@available(added=5)
member uint32;
};
)FIDL");
library.SelectVersion("example", "4");
ASSERT_COMPILED(library);
auto foo = library.LookupStruct("Foo");
ASSERT_NE(foo, nullptr);
EXPECT_TRUE(foo->availability.is_deprecated());
}
TEST(VersioningTests, BadRemovedAfterParentRemoved) {
TestLibrary library(R"FIDL(
@available(added=2, deprecated=4, removed=6)
library example;
@available(removed=7)
type Foo = struct {};
)FIDL");
library.SelectVersion("example", "HEAD");
library.ExpectFail(ErrAvailabilityConflictsWithParent, "removed", "7", "removed", "6",
"example.fidl:2:35", "removed", "after", "removed");
ASSERT_COMPILER_DIAGNOSTICS(library);
}
TEST(VersioningTests, BadRemovedAfterParentReplaced) {
TestLibrary library(R"FIDL(
@available(added=1)
library example;
@available(added=2, deprecated=4, replaced=6)
type Foo = struct {
@available(removed=7)
member bool;
};
@available(added=6)
type Foo = struct {};
)FIDL");
library.SelectVersion("example", "HEAD");
library.ExpectFail(ErrAvailabilityConflictsWithParent, "removed", "7", "replaced", "6",
"example.fidl:5:35", "removed", "after", "replaced");
ASSERT_COMPILER_DIAGNOSTICS(library);
}
TEST(VersioningTests, BadReplacedAfterParentRemoved) {
TestLibrary library(R"FIDL(
@available(added=1)
library example;
@available(added=2, deprecated=4, removed=6)
type Foo = struct {
@available(replaced=7)
member bool;
};
)FIDL");
library.SelectVersion("example", "HEAD");
library.ExpectFail(ErrAvailabilityConflictsWithParent, "replaced", "7", "removed", "6",
"example.fidl:5:35", "replaced", "after", "removed");
ASSERT_COMPILER_DIAGNOSTICS(library);
}
TEST(VersioningTests, BadReplacedAfterParentReplaced) {
TestLibrary library(R"FIDL(
@available(added=1)
library example;
@available(added=2, deprecated=4, replaced=6)
type Foo = struct {
@available(replaced=7)
member bool;
};
@available(added=6)
type Foo = struct {};
)FIDL");
library.SelectVersion("example", "HEAD");
library.ExpectFail(ErrAvailabilityConflictsWithParent, "replaced", "7", "replaced", "6",
"example.fidl:5:35", "replaced", "after", "replaced");
ASSERT_COMPILER_DIAGNOSTICS(library);
}
TEST(VersioningTests, GoodRemovedWhenParentReplaced) {
TestLibrary library(R"FIDL(
@available(added=1)
library example;
@available(added=2, deprecated=4, replaced=6)
type Foo = struct {
@available(added=2, deprecated=4, removed=6)
member bool;
};
@available(added=6)
type Foo = struct {};
)FIDL");
library.SelectVersion("example", "6");
ASSERT_COMPILED(library);
auto foo = library.LookupStruct("Foo");
ASSERT_NE(foo, nullptr);
EXPECT_TRUE(foo->members.empty());
}
TEST(VersioningTests, BadReplacedWhenParentRemoved) {
TestLibrary library(R"FIDL(
@available(added=1)
library example;
@available(added=2, deprecated=4, removed=6)
type Foo = struct {
@available(added=2, deprecated=4, replaced=6)
member bool;
};
)FIDL");
library.SelectVersion("example", "HEAD");
library.ExpectFail(ErrReplacedWithoutReplacement, "member", Version::From(6).value());
ASSERT_COMPILER_DIAGNOSTICS(library);
}
TEST(VersioningTests, BadReplacedWhenParentReplaced) {
TestLibrary library(R"FIDL(
@available(added=1)
library example;
@available(added=2, deprecated=4, replaced=6)
type Foo = struct {
@available(added=2, deprecated=4, replaced=6)
member bool;
};
@available(added=6)
type Foo = struct {};
)FIDL");
library.SelectVersion("example", "HEAD");
library.ExpectFail(ErrReplacedWithoutReplacement, "member", Version::From(6).value());
ASSERT_COMPILER_DIAGNOSTICS(library);
}
TEST(VersioningTests, GoodLegacyParentNotRemovedChildFalse) {
TestLibrary library(R"FIDL(
@available(added=2, deprecated=4)
library example;
@available(removed=6, legacy=false)
type Foo = struct {};
)FIDL");
library.SelectVersion("example", "LEGACY");
ASSERT_COMPILED(library);
ASSERT_EQ(library.LookupStruct("Foo"), nullptr);
}
TEST(VersioningTests, GoodLegacyParentNotRemovedChildTrue) {
TestLibrary library(R"FIDL(
@available(added=2, deprecated=4)
library example;
@available(removed=6, legacy=true)
type Foo = struct {};
)FIDL");
library.SelectVersion("example", "LEGACY");
ASSERT_COMPILED(library);
ASSERT_NE(library.LookupStruct("Foo"), nullptr);
}
TEST(VersioningTests, GoodLegacyParentFalseChildFalse) {
TestLibrary library(R"FIDL(
@available(added=2, deprecated=4, removed=6, legacy=false)
library example;
@available(legacy=false)
type Foo = struct {};
)FIDL");
library.SelectVersion("example", "LEGACY");
ASSERT_COMPILED(library);
ASSERT_EQ(library.LookupStruct("Foo"), nullptr);
}
TEST(VersioningTests, BadLegacyParentFalseChildTrue) {
TestLibrary library(R"FIDL(
@available(added=2, deprecated=4, removed=6, legacy=false)
library example;
@available(legacy=true)
type Foo = struct {};
)FIDL");
library.SelectVersion("example", "HEAD");
library.ExpectFail(ErrLegacyConflictsWithParent, "legacy", "true", "removed", "6",
"example.fidl:2:35");
ASSERT_COMPILER_DIAGNOSTICS(library);
}
TEST(VersioningTests, BadLegacyParentFalseChildTrueMethod) {
TestLibrary library;
library.AddFile("bad/fi-0183.test.fidl");
library.SelectVersion("test", "HEAD");
library.ExpectFail(ErrLegacyConflictsWithParent, "legacy", "true", "removed", "3",
"bad/fi-0183.test.fidl:7:12");
ASSERT_COMPILER_DIAGNOSTICS(library);
}
TEST(VersioningTests, GoodLegacyParentTrueChildTrue) {
TestLibrary library(R"FIDL(
@available(added=2, deprecated=4, removed=6, legacy=true)
library example;
@available(legacy=true)
type Foo = struct {};
)FIDL");
library.SelectVersion("example", "LEGACY");
ASSERT_COMPILED(library);
ASSERT_NE(library.LookupStruct("Foo"), nullptr);
}
TEST(VersioningTests, GoodLegacyParentTrueChildFalse) {
TestLibrary library(R"FIDL(
@available(added=2, deprecated=4, removed=6, legacy=true)
library example;
@available(legacy=false)
type Foo = struct {};
)FIDL");
library.SelectVersion("example", "LEGACY");
ASSERT_COMPILED(library);
ASSERT_EQ(library.LookupStruct("Foo"), nullptr);
}
TEST(VersioningTests, GoodMemberInheritsFromParent) {
TestLibrary library(R"FIDL(
@available(added=1)
library example;
@available(added=2)
type Foo = struct {
@available(deprecated=3)
member1 bool;
};
)FIDL");
library.SelectVersion("example", "2");
ASSERT_COMPILED(library);
auto foo = library.LookupStruct("Foo");
ASSERT_NE(foo, nullptr);
EXPECT_EQ(foo->members.size(), 1u);
}
TEST(VersioningTests, GoodComplexInheritance) {
// The following libraries all define a struct Bar with effective availability
// @available(added=2, deprecated=3, removed=4, legacy=true) in different ways.
std::vector<const char*> sources;
// Direct annotation.
sources.push_back(R"FIDL(
@available(added=1)
library example;
@available(added=2, deprecated=3, removed=4, legacy=true)
type Bar = struct {};
)FIDL");
// Fully inherit from library declaration.
sources.push_back(R"FIDL(
@available(added=2, deprecated=3, removed=4, legacy=true)
library example;
type Bar = struct {};
)FIDL");
// Partially inherit from library declaration.
sources.push_back(R"FIDL(
@available(added=1, deprecated=3)
library example;
@available(added=2, removed=4, legacy=true)
type Bar = struct {};
)FIDL");
// Inherit from parent.
sources.push_back(R"FIDL(
@available(added=1)
library example;
@available(added=2, deprecated=3, removed=4, legacy=true)
type Foo = struct {
member @generated_name("Bar") struct {};
};
)FIDL");
// Inherit from member.
sources.push_back(R"FIDL(
@available(added=1)
library example;
type Foo = struct {
@available(added=2, deprecated=3, removed=4, legacy=true)
member @generated_name("Bar") struct {};
};
)FIDL");
// Inherit from multiple, forward.
sources.push_back(R"FIDL(
@available(added=2)
library example;
@available(deprecated=3)
type Foo = struct {
@available(removed=4, legacy=true)
member @generated_name("Bar") struct {};
};
)FIDL");
// Inherit from multiple, backward.
sources.push_back(R"FIDL(
@available(added=1, removed=4, legacy=true)
library example;
@available(deprecated=3)
type Foo = struct {
@available(added=2)
member @generated_name("Bar") struct {};
};
)FIDL");
// Inherit from multiple, mixed.
sources.push_back(R"FIDL(
@available(added=1)
library example;
@available(added=2)
type Foo = struct {
@available(deprecated=3, removed=4, legacy=true)
member @generated_name("Bar") struct {};
};
)FIDL");
// Inherit via nested layouts.
sources.push_back(R"FIDL(
@available(added=1)
library example;
@available(added=2)
type Foo = struct {
@available(deprecated=3)
member1 struct {
@available(removed=4, legacy=true)
member2 struct {
member3 @generated_name("Bar") struct {};
};
};
};
)FIDL");
// Inherit via nested type constructors.
sources.push_back(R"FIDL(
@available(added=1)
library example;
@available(added=2)
type Foo = struct {
@available(deprecated=3, removed=4, legacy=true)
member1 vector<vector<vector<@generated_name("Bar") struct{}>>>;
};
)FIDL");
for (auto& source : sources) {
{
TestLibrary library(source);
library.SelectVersion("example", "1");
ASSERT_COMPILED(library);
auto bar = library.LookupStruct("Bar");
ASSERT_EQ(bar, nullptr);
}
{
TestLibrary library(source);
library.SelectVersion("example", "2");
ASSERT_COMPILED(library);
auto bar = library.LookupStruct("Bar");
ASSERT_NE(bar, nullptr);
EXPECT_FALSE(bar->availability.is_deprecated());
}
{
TestLibrary library(source);
library.SelectVersion("example", "3");
ASSERT_COMPILED(library);
auto bar = library.LookupStruct("Bar");
ASSERT_NE(bar, nullptr);
EXPECT_TRUE(bar->availability.is_deprecated());
}
{
TestLibrary library(source);
library.SelectVersion("example", "4");
ASSERT_COMPILED(library);
auto bar = library.LookupStruct("Bar");
ASSERT_EQ(bar, nullptr);
}
{
TestLibrary library(source);
library.SelectVersion("example", "LEGACY");
ASSERT_COMPILED(library);
auto bar = library.LookupStruct("Bar");
ASSERT_NE(bar, nullptr);
}
}
}
TEST(VersioningTests, BadDeclConflictsWithParent) {
TestLibrary library(R"FIDL( // L1
@available(added=2) // L2
library example; // L3
// L4
@available(added=1) // L5
type Foo = struct {};
)FIDL");
library.SelectVersion("example", "HEAD");
library.ExpectFail(ErrAvailabilityConflictsWithParent, "added", "1", "added", "2",
"example.fidl:2:12", "added", "before", "added");
ASSERT_COMPILER_DIAGNOSTICS(library);
EXPECT_EQ(library.errors()[0]->span.position().line, 5);
}
TEST(VersioningTests, BadMemberConflictsWithParent) {
TestLibrary library(R"FIDL( // L1
@available(added=1) // L2
library example; // L3
// L4
@available(added=2) // L5
type Foo = struct { // L6
@available(added=1) // L7
member1 bool;
};
)FIDL");
library.SelectVersion("example", "HEAD");
library.ExpectFail(ErrAvailabilityConflictsWithParent, "added", "1", "added", "2",
"example.fidl:5:12", "added", "before", "added");
ASSERT_COMPILER_DIAGNOSTICS(library);
EXPECT_EQ(library.errors()[0]->span.position().line, 7);
}
TEST(VersioningTests, BadMemberConflictsWithGrandParent) {
TestLibrary library(R"FIDL( // L1
@available(added=2) // L2
library example; // L3
// L4
@available(removed=3) // L5
type Foo = struct { // L6
@available(added=1) // L7
member1 bool;
};
)FIDL");
library.SelectVersion("example", "HEAD");
library.ExpectFail(ErrAvailabilityConflictsWithParent, "added", "1", "added", "2",
"example.fidl:2:12", "added", "before", "added");
ASSERT_COMPILER_DIAGNOSTICS(library);
EXPECT_EQ(library.errors()[0]->span.position().line, 7);
}
TEST(VersioningTests, BadMemberConflictsWithGrandParentThroughAnonymous) {
TestLibrary library(R"FIDL( // L1
@available(added=1) // L2
library example; // L3
// L4
@available(added=2) // L5
type Foo = struct { // L6
member1 struct { // L7
@available(removed=1) // L8
member2 bool;
};
};
)FIDL");
library.SelectVersion("example", "HEAD");
library.ExpectFail(ErrAvailabilityConflictsWithParent, "removed", "1", "added", "2",
"example.fidl:5:12", "removed", "before", "added");
ASSERT_COMPILER_DIAGNOSTICS(library);
EXPECT_EQ(library.errors()[0]->span.position().line, 8);
}
TEST(VersioningTests, BadLegacyConflictsWithRemoved) {
TestLibrary library(R"FIDL( // L1
@available(added=1, removed=2) // L2
library example; // L3
// L4
@available(legacy=true) // L5
type Foo = struct {};
)FIDL");
library.SelectVersion("example", "HEAD");
library.ExpectFail(ErrLegacyConflictsWithParent, "legacy", "true", "removed", "2",
"example.fidl:2:21");
ASSERT_COMPILER_DIAGNOSTICS(library);
EXPECT_EQ(library.errors()[0]->span.position().line, 5);
}
TEST(VersioningTests, BadRemovedWithReplacement) {
TestLibrary library;
library.AddFile("bad/fi-0205.test.fidl");
library.SelectVersion("test", "HEAD");
library.ExpectFail(ErrRemovedWithReplacement, "Bar", Version::From(2).value(),
"bad/fi-0205.test.fidl:11:14");
ASSERT_COMPILER_DIAGNOSTICS(library);
}
TEST(VersioningTests, BadRemovedNamedToAnonymous) {
TestLibrary library(R"FIDL(
@available(added=1)
library example;
@available(removed=2)
type Foo = struct {};
type Bar = struct {
@available(added=2)
foo struct {};
};
)FIDL");
library.SelectVersion("example", "HEAD");
library.ExpectFail(ErrRemovedWithReplacement, "Foo", Version::From(2).value(),
"example.fidl:10:9");
ASSERT_COMPILER_DIAGNOSTICS(library);
}
TEST(VersioningTests, GoodRemovedAnonymousToNamed) {
auto source = R"FIDL(
@available(added=1)
library example;
type Bar = struct {
// The anonymous type "Foo" inherits removed=2, but removed/replaced
// does not apply to inherited availabilities.
@available(removed=2)
foo struct {};
};
@available(added=2)
type Foo = table {};
)FIDL";
{
TestLibrary library(source);
library.SelectVersion("example", "1");
ASSERT_COMPILED(library);
EXPECT_NE(library.LookupStruct("Foo"), nullptr);
EXPECT_EQ(library.LookupTable("Foo"), nullptr);
}
{
TestLibrary library(source);
library.SelectVersion("example", "2");
ASSERT_COMPILED(library);
EXPECT_EQ(library.LookupStruct("Foo"), nullptr);
EXPECT_NE(library.LookupTable("Foo"), nullptr);
}
}
TEST(VersioningTests, GoodRemovedAnonymousToAnonymous) {
auto source = R"FIDL(
@available(added=1)
library example;
type Bar1 = struct {
// The anonymous type "Foo" inherits removed=2, but removed/replaced
// does not apply to inherited availabilities.
@available(removed=2)
foo struct {};
};
type Bar2 = struct {
@available(added=2)
foo table {};
};
)FIDL";
{
TestLibrary library(source);
library.SelectVersion("example", "1");
ASSERT_COMPILED(library);
EXPECT_NE(library.LookupStruct("Foo"), nullptr);
EXPECT_EQ(library.LookupTable("Foo"), nullptr);
}
{
TestLibrary library(source);
library.SelectVersion("example", "2");
ASSERT_COMPILED(library);
EXPECT_EQ(library.LookupStruct("Foo"), nullptr);
EXPECT_NE(library.LookupTable("Foo"), nullptr);
}
}
TEST(VersioningTests, BadReplacedWithoutReplacement) {
TestLibrary library;
library.AddFile("bad/fi-0206.test.fidl");
library.SelectVersion("test", "HEAD");
library.ExpectFail(ErrReplacedWithoutReplacement, "Bar", Version::From(2).value());
ASSERT_COMPILER_DIAGNOSTICS(library);
}
TEST(VersioningTests, GoodAnonymousReplacedWithoutReplacement) {
auto source = R"FIDL(
@available(added=1)
library example;
type Bar = struct {
// The anonymous type "Foo" inherits replaced=2, but removed/replaced
// validation does not apply to inherited availabilities.
@available(replaced=2)
foo struct {};
@available(added=2)
foo string;
};
)FIDL";
{
TestLibrary library(source);
library.SelectVersion("example", "1");
ASSERT_COMPILED(library);
EXPECT_NE(library.LookupStruct("Foo"), nullptr);
}
{
TestLibrary library(source);
library.SelectVersion("example", "2");
ASSERT_COMPILED(library);
EXPECT_EQ(library.LookupStruct("Foo"), nullptr);
}
}
TEST(VersioningTests, GoodReplacedNamedToAnonymous) {
auto source = R"FIDL(
@available(added=1)
library example;
@available(replaced=2)
type Foo = struct {};
type Bar = struct {
@available(added=2)
foo table {};
};
)FIDL";
{
TestLibrary library(source);
library.SelectVersion("example", "1");
ASSERT_COMPILED(library);
EXPECT_NE(library.LookupStruct("Foo"), nullptr);
EXPECT_EQ(library.LookupTable("Foo"), nullptr);
}
{
TestLibrary library(source);
library.SelectVersion("example", "2");
ASSERT_COMPILED(library);
EXPECT_EQ(library.LookupStruct("Foo"), nullptr);
EXPECT_NE(library.LookupTable("Foo"), nullptr);
}
}
TEST(VersioningTests, GoodReplacedAnonymousToNamed) {
auto source = R"FIDL(
@available(added=1)
library example;
type Bar = struct {
@available(replaced=2)
foo struct {};
@available(added=2)
foo string;
};
@available(added=2)
type Foo = table {};
)FIDL";
{
TestLibrary library(source);
library.SelectVersion("example", "1");
ASSERT_COMPILED(library);
EXPECT_NE(library.LookupStruct("Foo"), nullptr);
EXPECT_EQ(library.LookupTable("Foo"), nullptr);
}
{
TestLibrary library(source);
library.SelectVersion("example", "2");
ASSERT_COMPILED(library);
EXPECT_EQ(library.LookupStruct("Foo"), nullptr);
EXPECT_NE(library.LookupTable("Foo"), nullptr);
}
}
TEST(VersioningTests, GoodReplacedAnonymousToAnonymous) {
auto source = R"FIDL(
@available(added=1)
library example;
type Bar1 = struct {
@available(replaced=2)
foo struct {};
@available(added=2)
foo string;
};
type Bar2 = struct {
@available(added=2)
foo table {};
};
)FIDL";
{
TestLibrary library(source);
library.SelectVersion("example", "1");
ASSERT_COMPILED(library);
EXPECT_NE(library.LookupStruct("Foo"), nullptr);
EXPECT_EQ(library.LookupTable("Foo"), nullptr);
}
{
TestLibrary library(source);
library.SelectVersion("example", "2");
ASSERT_COMPILED(library);
EXPECT_EQ(library.LookupStruct("Foo"), nullptr);
EXPECT_NE(library.LookupTable("Foo"), nullptr);
}
}
TEST(VersioningTests, GoodReplacedTwice) {
auto source = R"FIDL(
@available(added=1)
library example;
@available(replaced=2)
type Foo = struct {};
@available(added=2, replaced=3)
type Foo = table {};
@available(added=3)
type Foo = union {};
)FIDL";
{
TestLibrary library(source);
library.SelectVersion("example", "1");
ASSERT_COMPILED(library);
EXPECT_NE(library.LookupStruct("Foo"), nullptr);
EXPECT_EQ(library.LookupTable("Foo"), nullptr);
EXPECT_EQ(library.LookupUnion("Foo"), nullptr);
}
{
TestLibrary library(source);
library.SelectVersion("example", "2");
ASSERT_COMPILED(library);
EXPECT_EQ(library.LookupStruct("Foo"), nullptr);
EXPECT_NE(library.LookupTable("Foo"), nullptr);
EXPECT_EQ(library.LookupUnion("Foo"), nullptr);
}
{
TestLibrary library(source);
library.SelectVersion("example", "3");
ASSERT_COMPILED(library);
EXPECT_EQ(library.LookupStruct("Foo"), nullptr);
EXPECT_EQ(library.LookupTable("Foo"), nullptr);
EXPECT_NE(library.LookupUnion("Foo"), nullptr);
}
}
TEST(VersioningTests, GoodNonOverlappingNamesNoGap) {
auto source = R"FIDL(
@available(added=1)
library example;
@available(replaced=2)
type Foo = struct {};
@available(added=2)
type Foo = table {};
)FIDL";
{
TestLibrary library(source);
library.SelectVersion("example", "1");
ASSERT_COMPILED(library);
EXPECT_NE(library.LookupStruct("Foo"), nullptr);
EXPECT_EQ(library.LookupTable("Foo"), nullptr);
}
{
TestLibrary library(source);
library.SelectVersion("example", "2");
ASSERT_COMPILED(library);
EXPECT_EQ(library.LookupStruct("Foo"), nullptr);
EXPECT_NE(library.LookupTable("Foo"), nullptr);
}
}
TEST(VersioningTests, GoodNonOverlappingNamesWithGap) {
auto source = R"FIDL(
@available(added=1)
library example;
@available(removed=2)
type Foo = struct {};
@available(added=3)
type Foo = table {};
)FIDL";
{
TestLibrary library(source);
library.SelectVersion("example", "1");
ASSERT_COMPILED(library);
EXPECT_NE(library.LookupStruct("Foo"), nullptr);
EXPECT_EQ(library.LookupTable("Foo"), nullptr);
}
{
TestLibrary library(source);
library.SelectVersion("example", "2");
ASSERT_COMPILED(library);
EXPECT_EQ(library.LookupStruct("Foo"), nullptr);
EXPECT_EQ(library.LookupTable("Foo"), nullptr);
}
{
TestLibrary library(source);
library.SelectVersion("example", "3");
ASSERT_COMPILED(library);
EXPECT_EQ(library.LookupStruct("Foo"), nullptr);
EXPECT_NE(library.LookupTable("Foo"), nullptr);
}
}
TEST(VersioningTests, GoodNonOverlappingNamesNoGapCanonical) {
auto source = R"FIDL(
@available(added=1)
library example;
@available(removed=2)
type foo = struct {};
@available(added=2)
type FOO = table {};
)FIDL";
{
TestLibrary library(source);
library.SelectVersion("example", "1");
ASSERT_COMPILED(library);
EXPECT_NE(library.LookupStruct("foo"), nullptr);
EXPECT_EQ(library.LookupTable("FOO"), nullptr);
}
{
TestLibrary library(source);
library.SelectVersion("example", "2");
ASSERT_COMPILED(library);
EXPECT_EQ(library.LookupStruct("foo"), nullptr);
EXPECT_NE(library.LookupTable("FOO"), nullptr);
}
}
TEST(VersioningTests, GoodNonOverlappingNamesWithGapCanonical) {
auto source = R"FIDL(
@available(added=1)
library example;
@available(removed=2)
type foo = struct {};
@available(added=3)
type FOO = table {};
)FIDL";
{
TestLibrary library(source);
library.SelectVersion("example", "1");
ASSERT_COMPILED(library);
EXPECT_NE(library.LookupStruct("foo"), nullptr);
EXPECT_EQ(library.LookupTable("FOO"), nullptr);
}
{
TestLibrary library(source);
library.SelectVersion("example", "2");
ASSERT_COMPILED(library);
EXPECT_EQ(library.LookupStruct("foo"), nullptr);
EXPECT_EQ(library.LookupTable("FOO"), nullptr);
}
{
TestLibrary library(source);
library.SelectVersion("example", "3");
ASSERT_COMPILED(library);
EXPECT_EQ(library.LookupStruct("foo"), nullptr);
EXPECT_NE(library.LookupTable("FOO"), nullptr);
}
}
TEST(VersioningTests, BadOverlappingNamesEqualToOther) {
TestLibrary library(R"FIDL(
@available(added=1)
library example;
type Foo = struct {};
type Foo = table {};
)FIDL");
library.SelectVersion("example", "HEAD");
library.ExpectFail(ErrNameCollision, Element::Kind::kTable, "Foo", Element::Kind::kStruct,
"example.fidl:5:6");
ASSERT_COMPILER_DIAGNOSTICS(library);
}
TEST(VersioningTests, BadOverlappingNamesEqualToOtherLegacy) {
TestLibrary library(R"FIDL(
@available(added=1)
library example;
@available(removed=2, legacy=true)
type Foo = struct {};
@available(removed=2, legacy=true)
type Foo = table {};
)FIDL");
library.SelectVersion("example", "HEAD");
library.ExpectFail(ErrNameCollision, Element::Kind::kTable, "Foo", Element::Kind::kStruct,
"example.fidl:6:6");
ASSERT_COMPILER_DIAGNOSTICS(library);
}
TEST(VersioningTests, BadOverlappingNamesEqualToOtherCanonical) {
TestLibrary library(R"FIDL(
@available(added=1)
library example;
type foo = struct {};
type FOO = table {};
)FIDL");
library.SelectVersion("example", "HEAD");
library.ExpectFail(ErrNameCollisionCanonical, Element::Kind::kStruct, "foo",
Element::Kind::kTable, "FOO", "example.fidl:6:6", "foo");
ASSERT_COMPILER_DIAGNOSTICS(library);
}
TEST(VersioningTests, BadOverlappingNamesSimple) {
TestLibrary library;
library.AddFile("bad/fi-0036.test.fidl");
library.SelectVersion("test", "HEAD");
library.ExpectFail(ErrNameOverlap, Element::Kind::kEnum, "Color", Element::Kind::kEnum,
"bad/fi-0036.test.fidl:7:6",
VersionSet(VersionRange(Version::From(2).value(), Version::PosInf())),
Platform::Parse("test").value());
ASSERT_COMPILER_DIAGNOSTICS(library);
}
TEST(VersioningTests, GoodOverlappingNamesSimpleFixAvailability) {
TestLibrary library;
library.AddFile("good/fi-0036.test.fidl");
library.SelectVersion("test", "HEAD");
ASSERT_COMPILED(library);
}
TEST(VersioningTests, BadOverlappingNamesSimpleCanonical) {
TestLibrary library;
library.AddFile("bad/fi-0037.test.fidl");
library.SelectVersion("test", "HEAD");
library.ExpectFail(ErrNameOverlapCanonical, Element::Kind::kProtocol, "Color",
Element::Kind::kConst, "COLOR", "bad/fi-0037.test.fidl:7:7", "color",
VersionSet(VersionRange(Version::From(2).value(), Version::PosInf())),
Platform::Parse("test").value());
ASSERT_COMPILER_DIAGNOSTICS(library);
}
TEST(VersioningTests, GoodOverlappingNamesSimpleCanonicalFixRename) {
TestLibrary library;
library.AddFile("good/fi-0037.test.fidl");
library.SelectVersion("test", "HEAD");
ASSERT_COMPILED(library);
}
TEST(VersioningTests, BadOverlappingNamesContainsOther) {
TestLibrary library(R"FIDL(
@available(added=1)
library example;
type Foo = struct {};
@available(removed=2)
type Foo = table {};
)FIDL");
library.SelectVersion("example", "HEAD");
library.ExpectFail(ErrNameOverlap, Element::Kind::kTable, "Foo", Element::Kind::kStruct,
"example.fidl:5:6",
VersionSet(VersionRange(Version::From(1).value(), Version::From(2).value())),
Platform::Parse("example").value());
ASSERT_COMPILER_DIAGNOSTICS(library);
}
TEST(VersioningTests, BadOverlappingNamesContainsOtherCanonical) {
TestLibrary library(R"FIDL(
@available(added=1)
library example;
type foo = struct {};
@available(removed=2)
type FOO = table {};
)FIDL");
library.SelectVersion("example", "HEAD");
library.ExpectFail(ErrNameOverlapCanonical, Element::Kind::kStruct, "foo", Element::Kind::kTable,
"FOO", "example.fidl:7:6", "foo",
VersionSet(VersionRange(Version::From(1).value(), Version::From(2).value())),
Platform::Parse("example").value());
ASSERT_COMPILER_DIAGNOSTICS(library);
}
TEST(VersioningTests, BadOverlappingNamesIntersectsOther) {
TestLibrary library(R"FIDL(
@available(added=1)
library example;
@available(removed=5)
type Foo = struct {};
@available(added=3)
type Foo = table {};
)FIDL");
library.SelectVersion("example", "HEAD");
library.ExpectFail(ErrNameOverlap, Element::Kind::kTable, "Foo", Element::Kind::kStruct,
"example.fidl:6:6",
VersionSet(VersionRange(Version::From(3).value(), Version::From(5).value())),
Platform::Parse("example").value());
ASSERT_COMPILER_DIAGNOSTICS(library);
}
TEST(VersioningTests, BadOverlappingNamesIntersectsOtherCanonical) {
TestLibrary library(R"FIDL(
@available(added=1)
library example;
@available(removed=5)
type foo = struct {};
@available(added=3)
type FOO = table {};
)FIDL");
library.SelectVersion("example", "HEAD");
library.ExpectFail(ErrNameOverlapCanonical, Element::Kind::kStruct, "foo", Element::Kind::kTable,
"FOO", "example.fidl:8:6", "foo",
VersionSet(VersionRange(Version::From(3).value(), Version::From(5).value())),
Platform::Parse("example").value());
ASSERT_COMPILER_DIAGNOSTICS(library);
}
TEST(VersioningTests, BadOverlappingNamesJustAtLegacy) {
TestLibrary library(R"FIDL(
@available(added=1)
library example;
@available(replaced=2, legacy=true)
type Foo = struct {};
@available(added=2, removed=3, legacy=true)
type Foo = table {};
)FIDL");
library.SelectVersion("example", "HEAD");
library.ExpectFail(ErrNameOverlap, Element::Kind::kTable, "Foo", Element::Kind::kStruct,
"example.fidl:6:6",
VersionSet(VersionRange(Version::Legacy(), Version::PosInf())),
Platform::Parse("example").value());
ASSERT_COMPILER_DIAGNOSTICS(library);
}
TEST(VersioningTests, BadOverlappingNamesJustAtLegacyCanonical) {
TestLibrary library(R"FIDL(
@available(added=1)
library example;
@available(removed=2, legacy=true)
type foo = struct {};
@available(added=2, removed=3, legacy=true)
type FOO = table {};
)FIDL");
library.SelectVersion("example", "HEAD");
library.ExpectFail(ErrNameOverlapCanonical, Element::Kind::kStruct, "foo", Element::Kind::kTable,
"FOO", "example.fidl:8:6", "foo",
VersionSet(VersionRange(Version::Legacy(), Version::PosInf())),
Platform::Parse("example").value());
ASSERT_COMPILER_DIAGNOSTICS(library);
}
TEST(VersioningTests, BadOverlappingNamesIntersectAtLegacy) {
TestLibrary library(R"FIDL(
@available(added=1)
library example;
@available(replaced=2, legacy=true)
type Foo = struct {};
@available(added=2)
type Foo = table {};
)FIDL");
library.SelectVersion("example", "HEAD");
library.ExpectFail(ErrNameOverlap, Element::Kind::kTable, "Foo", Element::Kind::kStruct,
"example.fidl:6:6",
VersionSet(VersionRange(Version::Legacy(), Version::PosInf())),
Platform::Parse("example").value());
ASSERT_COMPILER_DIAGNOSTICS(library);
}
TEST(VersioningTests, BadOverlappingNamesIntersectAtLegacyCanonical) {
TestLibrary library(R"FIDL(
@available(added=1)
library example;
@available(removed=2, legacy=true)
type foo = struct {};
@available(added=2)
type FOO = table {};
)FIDL");
library.SelectVersion("example", "HEAD");
library.ExpectFail(ErrNameOverlapCanonical, Element::Kind::kStruct, "foo", Element::Kind::kTable,
"FOO", "example.fidl:8:6", "foo",
VersionSet(VersionRange(Version::Legacy(), Version::PosInf())),
Platform::Parse("example").value());
ASSERT_COMPILER_DIAGNOSTICS(library);
}
TEST(VersioningTests, BadOverlappingNamesMultiple) {
TestLibrary library(R"FIDL(
@available(added=1)
library example;
type Foo = struct {};
@available(added=3)
type Foo = table {};
@available(added=HEAD)
const Foo uint32 = 0;
)FIDL");
library.SelectVersion("example", "HEAD");
library.ExpectFail(ErrNameOverlap, Element::Kind::kStruct, "Foo", Element::Kind::kConst,
"example.fidl:9:7",
VersionSet(VersionRange(Version::Head(), Version::PosInf())),
Platform::Parse("example").value());
library.ExpectFail(ErrNameOverlap, Element::Kind::kTable, "Foo", Element::Kind::kStruct,
"example.fidl:5:6",
VersionSet(VersionRange(Version::From(3).value(), Version::PosInf())),
Platform::Parse("example").value());
ASSERT_COMPILER_DIAGNOSTICS(library);
}
TEST(VersioningTests, BadOverlappingNamesRecursive) {
TestLibrary library(R"FIDL(
@available(added=1)
library example;
@available(added=1, removed=5)
type Foo = struct { member box<Foo>; };
@available(added=3, removed=7)
type Foo = struct { member box<Foo>; };
)FIDL");
library.SelectVersion("example", "HEAD");
library.ExpectFail(ErrNameOverlap, Element::Kind::kStruct, "Foo", Element::Kind::kStruct,
"example.fidl:6:6",
VersionSet(VersionRange(Version::From(3).value(), Version::From(5).value())),
Platform::Parse("example").value());
ASSERT_COMPILER_DIAGNOSTICS(library);
}
TEST(VersioningTests, BadOverlappingMemberNamesEqualToOther) {
TestLibrary library(R"FIDL(
@available(added=1)
library example;
type Foo = struct {
member bool;
member bool;
};
)FIDL");
library.SelectVersion("example", "HEAD");
library.ExpectFail(ErrNameCollision, Element::Kind::kStructMember, "member",
Element::Kind::kStructMember, "example.fidl:6:5");
ASSERT_COMPILER_DIAGNOSTICS(library);
}
TEST(VersioningTests, BadOverlappingMemberNamesEqualToOtherLegacy) {
TestLibrary library(R"FIDL(
@available(added=1)
library example;
type Foo = struct {
@available(removed=2, legacy=true)
member bool;
@available(removed=2, legacy=true)
member bool;
};
)FIDL");
library.SelectVersion("example", "HEAD");
library.ExpectFail(ErrNameCollision, Element::Kind::kStructMember, "member",
Element::Kind::kStructMember, "example.fidl:7:5");
ASSERT_COMPILER_DIAGNOSTICS(library);
}
TEST(VersioningTests, BadOverlappingMemberNamesEqualToOtherCanonical) {
TestLibrary library(R"FIDL(
@available(added=1)
library example;
type Foo = struct {
member bool;
MEMBER bool;
};
)FIDL");
library.SelectVersion("example", "HEAD");
library.ExpectFail(ErrNameCollisionCanonical, Element::Kind::kStructMember, "MEMBER",
Element::Kind::kStructMember, "member", "example.fidl:6:5", "member");
ASSERT_COMPILER_DIAGNOSTICS(library);
}
TEST(VersioningTests, BadOverlappingMemberNamesContainsOther) {
TestLibrary library(R"FIDL(
@available(added=1)
library example;
type Foo = struct {
member bool;
@available(removed=2)
member bool;
};
)FIDL");
library.SelectVersion("example", "HEAD");
library.ExpectFail(ErrNameOverlap, Element::Kind::kStructMember, "member",
Element::Kind::kStructMember, "example.fidl:6:5",
VersionSet(VersionRange(Version::From(1).value(), Version::From(2).value())),
Platform::Parse("example").value());
ASSERT_COMPILER_DIAGNOSTICS(library);
}
TEST(VersioningTests, BadOverlappingMemberNamesContainsOtherCanonical) {
TestLibrary library(R"FIDL(
@available(added=1)
library example;
type Foo = struct {
member bool;
@available(removed=2)
MEMBER bool;
};
)FIDL");
library.SelectVersion("example", "HEAD");
library.ExpectFail(ErrNameOverlapCanonical, Element::Kind::kStructMember, "MEMBER",
Element::Kind::kStructMember, "member", "example.fidl:6:5", "member",
VersionSet(VersionRange(Version::From(1).value(), Version::From(2).value())),
Platform::Parse("example").value());
ASSERT_COMPILER_DIAGNOSTICS(library);
}
TEST(VersioningTests, BadOverlappingMemberNamesIntersectsOther) {
TestLibrary library(R"FIDL(
@available(added=1)
library example;
type Foo = struct {
@available(removed=5)
member bool;
@available(added=3)
member bool;
};
)FIDL");
library.SelectVersion("example", "HEAD");
library.ExpectFail(ErrNameOverlap, Element::Kind::kStructMember, "member",
Element::Kind::kStructMember, "example.fidl:7:5",
VersionSet(VersionRange(Version::From(3).value(), Version::From(5).value())),
Platform::Parse("example").value());
ASSERT_COMPILER_DIAGNOSTICS(library);
}
TEST(VersioningTests, BadOverlappingMemberNamesIntersectsOtherCanonical) {
TestLibrary library(R"FIDL(
@available(added=1)
library example;
type Foo = struct {
@available(removed=5)
member bool;
@available(added=3)
MEMBER bool;
};
)FIDL");
library.SelectVersion("example", "HEAD");
library.ExpectFail(ErrNameOverlapCanonical, Element::Kind::kStructMember, "MEMBER",
Element::Kind::kStructMember, "member", "example.fidl:7:5", "member",
VersionSet(VersionRange(Version::From(3).value(), Version::From(5).value())),
Platform::Parse("example").value());
ASSERT_COMPILER_DIAGNOSTICS(library);
}
TEST(VersioningTests, BadOverlappingMemberNamesJustAtLegacy) {
TestLibrary library(R"FIDL(
@available(added=1)
library example;
type Foo = struct {
@available(replaced=2, legacy=true)
member bool;
@available(added=2, removed=3, legacy=true)
member bool;
};
)FIDL");
library.SelectVersion("example", "HEAD");
library.ExpectFail(ErrNameOverlap, Element::Kind::kStructMember, "member",
Element::Kind::kStructMember, "example.fidl:7:5",
VersionSet(VersionRange(Version::Legacy(), Version::PosInf())),
Platform::Parse("example").value());
ASSERT_COMPILER_DIAGNOSTICS(library);
}
TEST(VersioningTests, BadOverlappingMemberNamesJustAtLegacyCanonical) {
TestLibrary library(R"FIDL(
@available(added=1)
library example;
type Foo = struct {
@available(removed=2, legacy=true)
member bool;
@available(added=2, removed=3, legacy=true)
MEMBER bool;
};
)FIDL");
library.SelectVersion("example", "HEAD");
library.ExpectFail(ErrNameOverlapCanonical, Element::Kind::kStructMember, "MEMBER",
Element::Kind::kStructMember, "member", "example.fidl:7:5", "member",
VersionSet(VersionRange(Version::Legacy(), Version::PosInf())),
Platform::Parse("example").value());
ASSERT_COMPILER_DIAGNOSTICS(library);
}
TEST(VersioningTests, BadOverlappingMemberNamesIntersectAtLegacy) {
TestLibrary library(R"FIDL(
@available(added=1)
library example;
type Foo = struct {
@available(replaced=2, legacy=true)
member bool;
@available(added=2)
member bool;
};
)FIDL");
library.SelectVersion("example", "HEAD");
library.ExpectFail(ErrNameOverlap, Element::Kind::kStructMember, "member",
Element::Kind::kStructMember, "example.fidl:7:5",
VersionSet(VersionRange(Version::Legacy(), Version::PosInf())),
Platform::Parse("example").value());
ASSERT_COMPILER_DIAGNOSTICS(library);
}
TEST(VersioningTests, BadOverlappingMemberNamesIntersectAtLegacyCanonical) {
TestLibrary library(R"FIDL(
@available(added=1)
library example;
type Foo = struct {
@available(removed=2, legacy=true)
member bool;
@available(added=2)
MEMBER bool;
};
)FIDL");
library.SelectVersion("example", "HEAD");
library.ExpectFail(ErrNameOverlapCanonical, Element::Kind::kStructMember, "MEMBER",
Element::Kind::kStructMember, "member", "example.fidl:7:5", "member",
VersionSet(VersionRange(Version::Legacy(), Version::PosInf())),
Platform::Parse("example").value());
ASSERT_COMPILER_DIAGNOSTICS(library);
}
TEST(VersioningTests, BadOverlappingMemberNamesMultiple) {
TestLibrary library(R"FIDL(
@available(added=1)
library example;
type Foo = struct {
member bool;
@available(added=3)
member bool;
@available(added=HEAD)
member bool;
};
)FIDL");
library.SelectVersion("example", "HEAD");
library.ExpectFail(ErrNameOverlap, Element::Kind::kStructMember, "member",
Element::Kind::kStructMember, "example.fidl:6:5",
VersionSet(VersionRange(Version::From(3).value(), Version::PosInf())),
Platform::Parse("example").value());
library.ExpectFail(ErrNameOverlap, Element::Kind::kStructMember, "member",
Element::Kind::kStructMember, "example.fidl:6:5",
VersionSet(VersionRange(Version::Head(), Version::PosInf())),
Platform::Parse("example").value());
ASSERT_COMPILER_DIAGNOSTICS(library);
}
TEST(VersioningTests, BadOverlappingMemberNamesMultipleCanonical) {
TestLibrary library(R"FIDL(
@available(added=1)
library example;
type Foo = struct {
member bool;
@available(added=3)
Member bool;
@available(added=HEAD)
MEMBER bool;
};
)FIDL");
library.SelectVersion("example", "HEAD");
library.ExpectFail(ErrNameOverlapCanonical, Element::Kind::kStructMember, "Member",
Element::Kind::kStructMember, "member", "example.fidl:6:5", "member",
VersionSet(VersionRange(Version::From(3).value(), Version::PosInf())),
Platform::Parse("example").value());
library.ExpectFail(ErrNameOverlapCanonical, Element::Kind::kStructMember, "MEMBER",
Element::Kind::kStructMember, "member", "example.fidl:6:5", "member",
VersionSet(VersionRange(Version::Head(), Version::PosInf())),
Platform::Parse("example").value());
ASSERT_COMPILER_DIAGNOSTICS(library);
}
// TODO(https://fxbug.dev/42052719): Generalize this with more comprehensive tests in
// availability_interleaving_tests.cc.
TEST(VersioningTests, GoodRegularDeprecatedReferencesVersionedDeprecated) {
TestLibrary library(R"FIDL(
@available(added=1)
library example;
@deprecated
const FOO uint32 = BAR;
@available(deprecated=1)
const BAR uint32 = 1;
)FIDL");
library.SelectVersion("example", "HEAD");
ASSERT_COMPILED(library);
}
// Previously this errored due to incorrect logic in deprecation checks.
TEST(VersioningTests, GoodDeprecationLogicRegression1) {
TestLibrary library(R"FIDL(
@available(added=1)
library example;
@available(deprecated=1, removed=3)
type Foo = struct {};
@available(deprecated=1, removed=3)
type Bar = struct {
foo Foo;
@available(added=2)
ensure_split_at_v2 string;
};
)FIDL");
library.SelectVersion("example", "HEAD");
ASSERT_COMPILED(library);
}
// Previously this crashed due to incorrect logic in deprecation checks.
TEST(VersioningTests, BadDeprecationLogicRegression2) {
TestLibrary library(R"FIDL(
@available(added=1)
library example;
@available(deprecated=1)
type Foo = struct {};
@available(deprecated=1, removed=3)
type Bar = struct {
foo Foo;
@available(added=2)
ensure_split_at_v2 string;
};
)FIDL");
library.SelectVersion("example", "HEAD");
ASSERT_COMPILED(library);
}
TEST(VersioningTests, GoodMultipleFiles) {
TestLibrary library;
library.AddSource("overview.fidl", R"FIDL(
/// Some doc comment.
@available(added=1)
library example;
)FIDL");
library.AddSource("first.fidl", R"FIDL(
library example;
@available(added=2)
type Foo = struct {
bar box<Bar>;
};
)FIDL");
library.AddSource("second.fidl", R"FIDL(
library example;
@available(added=2)
type Bar = struct {
foo box<Foo>;
};
)FIDL");
library.SelectVersion("example", "HEAD");
ASSERT_COMPILED(library);
ASSERT_NE(library.LookupStruct("Foo"), nullptr);
ASSERT_NE(library.LookupStruct("Bar"), nullptr);
}
TEST(VersioningTests, GoodSplitByDeclInExternalLibrary) {
SharedAmongstLibraries shared;
shared.SelectVersion("platform", "HEAD");
TestLibrary dependency(&shared, "dependency.fidl", R"FIDL(
@available(added=1)
library platform.dependency;
type Foo = struct {
@available(added=2)
member string;
};
)FIDL");
ASSERT_COMPILED(dependency);
TestLibrary example(&shared, "example.fidl", R"FIDL(
@available(added=1)
library platform.example;
using platform.dependency;
type ShouldBeSplit = struct {
foo platform.dependency.Foo;
};
)FIDL");
ASSERT_COMPILED(example);
}
TEST(VersioningTests, GoodMultiplePlatformsBasic) {
SharedAmongstLibraries shared;
shared.SelectVersion("dependency", "3");
shared.SelectVersion("example", "HEAD");
TestLibrary dependency(&shared, "dependency.fidl", R"FIDL(
@available(added=2)
library dependency;
@available(added=3, deprecated=4, removed=5)
type Foo = struct {};
)FIDL");
ASSERT_COMPILED(dependency);
TestLibrary example(&shared, "example.fidl", R"FIDL(
@available(added=1)
library example;
using dependency;
type Foo = struct {
@available(deprecated=5)
dep dependency.Foo;
};
)FIDL");
ASSERT_COMPILED(example);
}
TEST(VersioningTests, GoodMultiplePlatformsExplicitPlatform) {
SharedAmongstLibraries shared;
shared.SelectVersion("xyz", "3");
shared.SelectVersion("example", "HEAD");
TestLibrary dependency(&shared, "dependency.fidl", R"FIDL(
@available(platform="xyz", added=1)
library dependency;
@available(added=3, removed=4)
type Foo = struct {};
)FIDL");
ASSERT_COMPILED(dependency);
TestLibrary example(&shared, "example.fidl", R"FIDL(
@available(added=1)
library example;
using dependency;
alias Foo = dependency.Foo;
)FIDL");
ASSERT_COMPILED(example);
}
TEST(VersioningTests, GoodMultiplePlatformsUsesCorrectDecl) {
SharedAmongstLibraries shared;
shared.SelectVersion("dependency", "4");
shared.SelectVersion("example", "1");
TestLibrary dependency(&shared, "dependency.fidl", R"FIDL(
@available(added=2)
library dependency;
@available(deprecated=3, replaced=4)
type Foo = resource struct {};
@available(added=4, removed=5)
type Foo = table {};
)FIDL");
ASSERT_COMPILED(dependency);
TestLibrary example(&shared, "example.fidl", R"FIDL(
@available(added=1)
library example;
using dependency;
type Foo = struct {
dep dependency.Foo;
};
)FIDL");
ASSERT_COMPILED(example);
auto foo = example.LookupStruct("Foo");
ASSERT_NE(foo, nullptr);
ASSERT_EQ(foo->members.size(), 1u);
auto member_type = foo->members[0].type_ctor->type;
ASSERT_EQ(member_type->kind, Type::Kind::kIdentifier);
auto identifier_type = static_cast<const IdentifierType*>(member_type);
EXPECT_EQ(identifier_type->type_decl->kind, Decl::Kind::kTable);
}
TEST(VersioningTests, BadMultiplePlatformsNameNotFound) {
SharedAmongstLibraries shared;
shared.SelectVersion("dependency", "HEAD");
shared.SelectVersion("example", "HEAD");
TestLibrary dependency(&shared, "dependency.fidl", R"FIDL(
@available(added=2)
library dependency;
@available(added=3, removed=5)
type Foo = struct {};
)FIDL");
ASSERT_COMPILED(dependency);
TestLibrary example(&shared, "example.fidl", R"FIDL(
@available(added=1)
library example;
using dependency;
type Foo = struct {
@available(deprecated=5)
dep dependency.Foo;
};
)FIDL");
example.ExpectFail(ErrNameNotFound, "Foo", "dependency");
example.ExpectFail(ErrNameNotFound, "Foo", "dependency");
ASSERT_COMPILER_DIAGNOSTICS(example);
}
TEST(VersioningTests, GoodMixVersionedAndUnversioned) {
SharedAmongstLibraries shared;
shared.SelectVersion("example", "1");
TestLibrary versioned(&shared, "versioned.fidl", R"FIDL(
@available(added=1, removed=2)
library example.versioned;
type Foo = struct {};
)FIDL");
ASSERT_COMPILED(versioned);
TestLibrary not_versioned(&shared, "not_versioned.fidl", R"FIDL(
library example.notversioned;
using example.versioned;
alias Foo = example.versioned.Foo;
)FIDL");
ASSERT_COMPILED(not_versioned);
// The example.notversioned library is considered added=HEAD in the special
// "unversioned" platform. (If it were instead in the "example" platform, it
// would appear empty because we're using `--available example:1`.)
ASSERT_NE(not_versioned.LookupAlias("Foo"), nullptr);
}
} // namespace
} // namespace fidlc