blob: 33a91d0a791df6791eb4efe6649641882f79c34c [file] [log] [blame]
// Copyright 2024 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 <gtest/gtest.h>
#include "tools/fidl/fidlc/tests/test_library.h"
// This file tests how FIDL versioning distinguishes "removal" from
// "replacement", and validation that replacement is done correctly.
// Tests are run for all the versions given in INSTANTIATE_TEST_SUITE_P.
namespace fidlc {
namespace {
class VersioningReplacementTest : public testing::TestWithParam<Version> {};
const Version V1 = Version::From(1).value();
const Version V2 = Version::From(2).value();
const Version V3 = Version::From(3).value();
INSTANTIATE_TEST_SUITE_P(VersioningReplacementTests, VersioningReplacementTest,
testing::Values(V1, V2, V3),
[](auto info) { return info.param.ToString(); });
TEST_P(VersioningReplacementTest, GoodDeclRemoved) {
TestLibrary library(R"FIDL(
@available(added=1)
library example;
@available(removed=2)
type Foo = struct {};
)FIDL");
library.SelectVersion("example", GetParam());
ASSERT_COMPILED(library);
EXPECT_EQ(library.HasStruct("Foo"), GetParam() == V1);
}
TEST_P(VersioningReplacementTest, BadDeclRemoved) {
TestLibrary library(R"FIDL(
@available(added=1)
library example;
@available(removed=2)
type Foo = struct {};
@available(added=2)
type Foo = resource struct {};
)FIDL");
library.SelectVersion("example", GetParam());
library.ExpectFail(ErrInvalidRemoved, "struct 'Foo'", V2, "example.fidl:9:6");
ASSERT_COMPILER_DIAGNOSTICS(library);
}
TEST_P(VersioningReplacementTest, GoodDeclReplaced) {
TestLibrary library(R"FIDL(
@available(added=1)
library example;
@available(replaced=2)
type Foo = struct {};
@available(added=2)
type Foo = resource struct {};
)FIDL");
library.SelectVersion("example", GetParam());
ASSERT_COMPILED(library);
EXPECT_EQ(library.LookupStruct("Foo")->resourceness,
GetParam() == V1 ? Resourceness::kValue : Resourceness::kResource);
}
TEST_P(VersioningReplacementTest, BadDeclReplaced) {
TestLibrary library(R"FIDL(
@available(added=1)
library example;
@available(replaced=2)
type Foo = struct {};
)FIDL");
library.SelectVersion("example", GetParam());
library.ExpectFail(ErrInvalidReplaced, "struct 'Foo'", V2);
ASSERT_COMPILER_DIAGNOSTICS(library);
}
TEST_P(VersioningReplacementTest, GoodMemberRemoved) {
TestLibrary library(R"FIDL(
@available(added=1)
library example;
type Foo = table {
@available(removed=2)
1: bar string;
};
)FIDL");
library.SelectVersion("example", GetParam());
ASSERT_COMPILED(library);
EXPECT_EQ(library.LookupTable("Foo")->members.size(), GetParam() == V1 ? 1u : 0u);
}
TEST_P(VersioningReplacementTest, BadMemberRemoved) {
TestLibrary library(R"FIDL(
@available(added=1)
library example;
type Foo = table {
@available(removed=2)
1: bar string;
@available(added=2)
1: bar uint32;
};
)FIDL");
library.SelectVersion("example", GetParam());
library.ExpectFail(ErrInvalidRemoved, "table member 'bar'", V2, "example.fidl:9:8");
ASSERT_COMPILER_DIAGNOSTICS(library);
}
TEST_P(VersioningReplacementTest, GoodMemberReplaced) {
TestLibrary library(R"FIDL(
@available(added=1)
library example;
type Foo = table {
@available(replaced=2)
1: bar string;
@available(added=2)
1: bar uint32;
};
)FIDL");
library.SelectVersion("example", GetParam());
ASSERT_COMPILED(library);
EXPECT_EQ(library.LookupTable("Foo")->members.front().type_ctor->type->kind,
GetParam() == V1 ? Type::Kind::kString : Type::Kind::kPrimitive);
}
TEST_P(VersioningReplacementTest, BadMemberReplaced) {
TestLibrary library(R"FIDL(
@available(added=1)
library example;
type Foo = table {
@available(replaced=2)
1: bar string;
};
)FIDL");
library.SelectVersion("example", GetParam());
library.ExpectFail(ErrInvalidReplaced, "table member 'bar'", V2);
ASSERT_COMPILER_DIAGNOSTICS(library);
}
TEST_P(VersioningReplacementTest, GoodMethodRemoved) {
TestLibrary library(R"FIDL(
@available(added=1)
library example;
protocol Foo {
@available(removed=2)
Bar();
};
)FIDL");
library.SelectVersion("example", GetParam());
ASSERT_COMPILED(library);
EXPECT_EQ(library.LookupProtocol("Foo")->methods.size(), GetParam() == V1 ? 1u : 0u);
}
TEST_P(VersioningReplacementTest, BadMethodRemoved) {
TestLibrary library;
library.SelectVersion("test", GetParam());
library.AddFile("bad/fi-0205.test.fidl");
library.ExpectFail(ErrInvalidRemoved, "protocol method 'Bar'", V2, "bad/fi-0205.test.fidl:11:14");
ASSERT_COMPILER_DIAGNOSTICS(library);
}
TEST_P(VersioningReplacementTest, GoodMethodReplaced) {
TestLibrary library(R"FIDL(
@available(added=1)
library example;
protocol Foo {
@available(replaced=2)
strict Bar();
@available(added=2)
flexible Bar();
};
)FIDL");
library.SelectVersion("example", GetParam());
ASSERT_COMPILED(library);
EXPECT_EQ(library.LookupProtocol("Foo")->methods[0].strictness,
GetParam() == V1 ? Strictness::kStrict : Strictness::kFlexible);
}
TEST_P(VersioningReplacementTest, BadMethodReplaced) {
TestLibrary library;
library.AddFile("bad/fi-0206.test.fidl");
library.SelectVersion("test", GetParam());
library.ExpectFail(ErrInvalidReplaced, "protocol method 'Bar'", V2);
ASSERT_COMPILER_DIAGNOSTICS(library);
}
TEST_P(VersioningReplacementTest, BadMethodRemovedNewCompose) {
TestLibrary library(R"FIDL(
@available(added=1)
library example;
protocol Protocol {
@available(removed=2)
Method();
@available(added=2)
compose Base;
};
protocol Base {
@selector("example/Protocol.Method")
Method();
};
)FIDL");
library.SelectVersion("example", GetParam());
library.ExpectFail(ErrInvalidRemoved, "protocol method 'Method'", V2, "example.fidl:15:3");
ASSERT_COMPILER_DIAGNOSTICS(library);
}
TEST_P(VersioningReplacementTest, GoodMethodReplacedNewCompose) {
TestLibrary library(R"FIDL(
@available(added=1)
library example;
protocol Protocol {
@available(replaced=2)
Method();
@available(added=2)
compose Base;
};
protocol Base {
@selector("example/Protocol.Method")
Method();
};
)FIDL");
library.SelectVersion("example", GetParam());
ASSERT_COMPILED(library);
EXPECT_EQ(library.LookupProtocol("Protocol")->all_methods[0].composed != nullptr,
GetParam() >= V2);
}
TEST_P(VersioningReplacementTest, BadMethodRemovedExistingCompose) {
TestLibrary library(R"FIDL(
@available(added=1)
library example;
protocol Protocol {
@available(removed=2)
Method();
compose Base;
};
protocol Base {
@available(added=2)
@selector("example/Protocol.Method")
Method();
};
)FIDL");
library.SelectVersion("example", GetParam());
library.ExpectFail(ErrInvalidRemoved, "protocol method 'Method'", V2, "example.fidl:15:3");
ASSERT_COMPILER_DIAGNOSTICS(library);
}
TEST_P(VersioningReplacementTest, GoodMethodReplacedExistingCompose) {
TestLibrary library(R"FIDL(
@available(added=1)
library example;
protocol Protocol {
@available(replaced=2)
Method();
compose Base;
};
protocol Base {
@available(added=2)
@selector("example/Protocol.Method")
Method();
};
)FIDL");
library.SelectVersion("example", GetParam());
ASSERT_COMPILED(library);
EXPECT_EQ(library.LookupProtocol("Protocol")->all_methods[0].composed != nullptr,
GetParam() >= V2);
}
TEST_P(VersioningReplacementTest, BadComposeRemovedNewMethod) {
TestLibrary library(R"FIDL(
@available(added=1)
library example;
protocol Protocol {
@available(removed=2)
compose Base;
@available(added=2)
Method();
};
protocol Base {
@selector("example/Protocol.Method")
Method();
};
)FIDL");
library.SelectVersion("example", GetParam());
library.ExpectFail(ErrInvalidRemoved, "protocol method 'Method'", V2, "example.fidl:10:3");
ASSERT_COMPILER_DIAGNOSTICS(library);
}
TEST_P(VersioningReplacementTest, GoodComposeReplacedNewMethod) {
TestLibrary library(R"FIDL(
@available(added=1)
library example;
protocol Protocol {
@available(replaced=2)
compose Base;
@available(added=2)
Method();
};
protocol Base {
@selector("example/Protocol.Method")
Method();
};
)FIDL");
library.SelectVersion("example", GetParam());
ASSERT_COMPILED(library);
EXPECT_EQ(library.LookupProtocol("Protocol")->all_methods[0].composed != nullptr,
GetParam() == V1);
}
TEST_P(VersioningReplacementTest, BadComposeRemovedNewMethodComposeeSimultaneouslyRemoved) {
TestLibrary library(R"FIDL(
@available(added=1)
library example;
protocol Protocol {
@available(removed=2)
compose Base;
@available(added=2)
Method();
};
@available(removed=2)
protocol Base {
@selector("example/Protocol.Method")
Method();
};
)FIDL");
library.SelectVersion("example", GetParam());
library.ExpectFail(ErrInvalidRemoved, "protocol method 'Method'", V2, "example.fidl:10:3");
ASSERT_COMPILER_DIAGNOSTICS(library);
}
TEST_P(VersioningReplacementTest, GoodComposeReplacedNewMethodComposeeSimultaneouslyRemoved) {
TestLibrary library(R"FIDL(
@available(added=1)
library example;
protocol Protocol {
@available(replaced=2)
compose Base;
@available(added=2)
Method();
};
@available(removed=2)
protocol Base {
@selector("example/Protocol.Method")
Method();
};
)FIDL");
library.SelectVersion("example", GetParam());
ASSERT_COMPILED(library);
EXPECT_EQ(library.LookupProtocol("Protocol")->all_methods[0].composed != nullptr,
GetParam() == V1);
}
TEST_P(VersioningReplacementTest, BadComposeRemovedNewCompose) {
TestLibrary library(R"FIDL(
@available(added=1)
library example;
protocol Protocol {
@available(removed=2)
compose Foo;
@available(added=2)
compose Bar;
};
protocol Foo {
@selector("selector/for.Method")
Method();
};
protocol Bar {
@selector("selector/for.Method")
Method();
};
)FIDL");
library.SelectVersion("example", GetParam());
library.ExpectFail(ErrInvalidRemoved, "protocol method 'Method'", V2, "example.fidl:20:3");
ASSERT_COMPILER_DIAGNOSTICS(library);
}
TEST_P(VersioningReplacementTest, GoodComposeReplacedNewCompose) {
TestLibrary library(R"FIDL(
@available(added=1)
library example;
protocol Protocol {
@available(replaced=2)
compose Foo;
@available(added=2)
compose Bar;
};
protocol Foo {
@selector("selector/for.Method")
Method();
};
protocol Bar {
@selector("selector/for.Method")
Method();
};
)FIDL");
library.SelectVersion("example", GetParam());
ASSERT_COMPILED(library);
EXPECT_EQ(library.LookupProtocol("Protocol")->all_methods[0].owning_protocol->GetName(),
GetParam() == V1 ? "Foo" : "Bar");
}
TEST_P(VersioningReplacementTest, BadComposeRemovedNewComposeComposeeSimultaneouslyRemoved) {
TestLibrary library(R"FIDL(
@available(added=1)
library example;
protocol Protocol {
@available(removed=2)
compose Foo;
@available(added=2)
compose Bar;
};
@available(removed=2)
protocol Foo {
@selector("selector/for.Method")
Method();
};
protocol Bar {
@selector("selector/for.Method")
Method();
};
)FIDL");
library.SelectVersion("example", GetParam());
library.ExpectFail(ErrInvalidRemoved, "protocol method 'Method'", V2, "example.fidl:21:3");
ASSERT_COMPILER_DIAGNOSTICS(library);
}
TEST_P(VersioningReplacementTest, GoodComposeReplacedNewComposeComposeeSimultaneouslyRemoved) {
TestLibrary library(R"FIDL(
@available(added=1)
library example;
protocol Protocol {
@available(replaced=2)
compose Foo;
@available(added=2)
compose Bar;
};
@available(removed=2)
protocol Foo {
@selector("selector/for.Method")
Method();
};
protocol Bar {
@selector("selector/for.Method")
Method();
};
)FIDL");
library.SelectVersion("example", GetParam());
ASSERT_COMPILED(library);
EXPECT_EQ(library.LookupProtocol("Protocol")->all_methods[0].owning_protocol->GetName(),
GetParam() == V1 ? "Foo" : "Bar");
}
// No "Good" version because it would have to be replaced in Base (already
// tested by BadMethodRemoved), causing a name collision with Protocol.Method.
TEST_P(VersioningReplacementTest, BadComposedMethodRemovedNewMethod) {
TestLibrary library(R"FIDL(
@available(added=1)
library example;
protocol Protocol {
compose Base;
@available(added=2)
Method();
};
protocol Base {
@available(removed=2)
@selector("example/Protocol.Method")
Method();
};
)FIDL");
library.SelectVersion("example", GetParam());
library.ExpectFail(ErrInvalidRemoved, "protocol method 'Method'", V2, "example.fidl:9:3");
ASSERT_COMPILER_DIAGNOSTICS(library);
}
TEST_P(VersioningReplacementTest, BadMethodRemovedTransitiveCompose) {
TestLibrary library(R"FIDL(
@available(added=1)
library example;
protocol Protocol {
@available(removed=2)
Method();
compose Intermediate;
};
protocol Intermediate {
@available(added=2)
compose Base;
};
protocol Base {
@selector("example/Protocol.Method")
Method();
};
)FIDL");
library.SelectVersion("example", GetParam());
library.ExpectFail(ErrInvalidRemoved, "protocol method 'Method'", V2, "example.fidl:19:3");
ASSERT_COMPILER_DIAGNOSTICS(library);
}
TEST_P(VersioningReplacementTest, GoodMethodReplacedTransitiveCompose) {
TestLibrary library(R"FIDL(
@available(added=1)
library example;
protocol Protocol {
@available(replaced=2)
Method();
compose Intermediate;
};
protocol Intermediate {
@available(added=2)
compose Base;
};
protocol Base {
@selector("example/Protocol.Method")
Method();
};
)FIDL");
library.SelectVersion("example", GetParam());
ASSERT_COMPILED(library);
EXPECT_EQ(library.LookupProtocol("Protocol")->all_methods[0].owning_protocol->GetName(),
GetParam() == V1 ? "Protocol" : "Base");
}
TEST_P(VersioningReplacementTest, BadMethodAndComposeRemovedHybrid) {
TestLibrary library(R"FIDL(
@available(added=1)
library example;
protocol Protocol {
@available(removed=2)
compose AB;
@available(removed=2)
@selector("selector/for.C")
C();
@available(added=2)
@selector("selector/for.A")
A();
@available(added=2)
compose BC;
};
protocol AB {
@selector("selector/for.A")
A();
@selector("selector/for.B")
B();
};
protocol BC {
@selector("selector/for.B")
B();
@selector("selector/for.C")
C();
};
)FIDL");
library.SelectVersion("example", GetParam());
library.ExpectFail(ErrInvalidRemoved, "protocol method 'B'", V2, "example.fidl:28:3");
library.ExpectFail(ErrInvalidRemoved, "protocol method 'A'", V2, "example.fidl:14:3");
library.ExpectFail(ErrInvalidRemoved, "protocol method 'C'", V2, "example.fidl:30:3");
ASSERT_COMPILER_DIAGNOSTICS(library);
}
TEST_P(VersioningReplacementTest, GoodMethodAndComposeReplacedHybrid) {
TestLibrary library(R"FIDL(
@available(added=1)
library example;
protocol Protocol {
@available(replaced=2)
compose AB;
@available(replaced=2)
@selector("selector/for.C")
C();
@available(added=2)
@selector("selector/for.A")
A();
@available(added=2)
compose BC;
};
protocol AB {
@selector("selector/for.A")
A();
@selector("selector/for.B")
B();
};
protocol BC {
@selector("selector/for.B")
B();
@selector("selector/for.C")
C();
};
)FIDL");
library.SelectVersion("example", GetParam());
ASSERT_COMPILED(library);
EXPECT_EQ(library.LookupProtocol("Protocol")->all_methods.size(), 3u);
}
TEST_P(VersioningReplacementTest, GoodReplacedTwice) {
TestLibrary library(R"FIDL(
@available(added=1)
library example;
@available(replaced=2)
type Foo = struct {};
@available(added=2, replaced=3)
type Foo = struct {};
@available(added=3)
type Foo = struct {};
)FIDL");
library.SelectVersion("example", GetParam());
ASSERT_COMPILED(library);
}
TEST_P(VersioningReplacementTest, GoodAllDeclsReplacedAndRemoved) {
TestLibrary library(R"FIDL(
@available(added=1)
library example;
@available(replaced=2)
const CONST uint32 = 1;
@available(added=2, removed=3)
const CONST uint32 = 1;
@available(replaced=2)
alias Alias = string;
@available(added=2, removed=3)
alias Alias = string;
// TODO(https://fxbug.dev/42158155): Uncomment.
// @available(replaced=2)
// type Type = string;
// @available(added=2, removed=2)
// type Type = string;
@available(replaced=2)
type Bits = bits {};
@available(added=2, removed=3)
type Bits = bits {};
@available(replaced=2)
type Enum = enum {};
@available(added=2, removed=3)
type Enum = enum {};
@available(replaced=2)
type Struct = struct {};
@available(added=2, removed=3)
type Struct = struct {};
@available(replaced=2)
type Table = table {};
@available(added=2, removed=3)
type Table = table {};
@available(replaced=2)
type Union = union {};
@available(added=2, removed=3)
type Union = union {};
@available(replaced=2)
protocol Protocol {};
@available(added=2, removed=3)
protocol Protocol {};
@available(replaced=2)
service Service {};
@available(added=2, removed=3)
service Service {};
@available(replaced=2)
resource_definition Resource : uint32 { properties { subtype flexible enum : uint32 {}; }; };
@available(added=2, removed=3)
resource_definition Resource : uint32 { properties { subtype flexible enum : uint32 {}; }; };
)FIDL");
library.SelectVersion("example", GetParam());
ASSERT_COMPILED(library);
EXPECT_EQ(library.declaration_order().size(), GetParam() <= V2 ? 11u : 0u);
}
TEST_P(VersioningReplacementTest, GoodAllMembersReplacedAndRemoved) {
TestLibrary library(R"FIDL(
@available(added=1)
library example;
type Bits = bits {
@available(replaced=2)
MEMBER = 1;
@available(added=2, removed=3)
MEMBER = 1;
};
type Enum = enum {
@available(replaced=2)
MEMBER = 1;
@available(added=2, removed=3)
MEMBER = 1;
};
type Struct = struct {
@available(replaced=2)
member uint32;
@available(added=2, removed=3)
member uint32;
};
type Table = table {
@available(replaced=2)
1: member uint32;
@available(added=2, removed=3)
1: member uint32;
};
type Union = union {
@available(replaced=2)
1: member uint32;
@available(added=2, removed=3)
1: member uint32;
};
protocol Protocol {
@available(replaced=2)
Member();
@available(added=2, removed=3)
Member();
};
service Service {
@available(replaced=2)
member client_end:Protocol;
@available(added=2, removed=3)
member client_end:Protocol;
};
)FIDL");
library.SelectVersion("example", GetParam());
ASSERT_COMPILED(library);
auto num_members = GetParam() <= V2 ? 1u : 0u;
EXPECT_EQ(library.LookupBits("Bits")->members.size(), num_members);
EXPECT_EQ(library.LookupEnum("Enum")->members.size(), num_members);
EXPECT_EQ(library.LookupStruct("Struct")->members.size(), num_members);
EXPECT_EQ(library.LookupTable("Table")->members.size(), num_members);
EXPECT_EQ(library.LookupUnion("Union")->members.size(), num_members);
EXPECT_EQ(library.LookupProtocol("Protocol")->methods.size(), num_members);
EXPECT_EQ(library.LookupService("Service")->members.size(), num_members);
}
TEST_P(VersioningReplacementTest, GoodAllMembersReplacedAndRenamed) {
TestLibrary library(R"FIDL(
@available(added=1)
library example;
type Bits = bits {
@available(replaced=2, renamed="NEW")
OLD = 1;
@available(added=2)
NEW = 1;
};
type Enum = enum {
@available(replaced=2, renamed="NEW")
OLD = 1;
@available(added=2)
NEW = 1;
};
type Struct = struct {
@available(replaced=2, renamed="new")
old uint32;
@available(added=2)
new uint32;
};
type Table = table {
@available(replaced=2, renamed="new")
1: old uint32;
@available(added=2)
1: new uint32;
};
type Union = union {
@available(replaced=2, renamed="new")
1: old uint32;
@available(added=2)
1: new uint32;
};
protocol Protocol {
@available(replaced=2, renamed="New")
Old();
@available(added=2)
@selector("Old")
New();
};
service Service {
@available(replaced=2, renamed="new")
old client_end:Protocol;
@available(added=2)
new client_end:Protocol;
};
)FIDL");
library.SelectVersion("example", GetParam());
ASSERT_COMPILED(library);
EXPECT_EQ(library.LookupBits("Bits")->members.size(), 1u);
EXPECT_EQ(library.LookupEnum("Enum")->members.size(), 1u);
EXPECT_EQ(library.LookupStruct("Struct")->members.size(), 1u);
EXPECT_EQ(library.LookupTable("Table")->members.size(), 1u);
EXPECT_EQ(library.LookupUnion("Union")->members.size(), 1u);
EXPECT_EQ(library.LookupProtocol("Protocol")->methods.size(), 1u);
EXPECT_EQ(library.LookupService("Service")->members.size(), 1u);
bool old = GetParam() == V1;
EXPECT_EQ(library.LookupBits("Bits")->members[0].GetName(), old ? "OLD" : "NEW");
EXPECT_EQ(library.LookupEnum("Enum")->members[0].GetName(), old ? "OLD" : "NEW");
EXPECT_EQ(library.LookupStruct("Struct")->members[0].GetName(), old ? "old" : "new");
EXPECT_EQ(library.LookupTable("Table")->members[0].GetName(), old ? "old" : "new");
EXPECT_EQ(library.LookupUnion("Union")->members[0].GetName(), old ? "old" : "new");
EXPECT_EQ(library.LookupProtocol("Protocol")->methods[0].GetName(), old ? "Old" : "New");
EXPECT_EQ(library.LookupService("Service")->members[0].GetName(), old ? "old" : "new");
}
TEST_P(VersioningReplacementTest, 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", GetParam());
library.ExpectFail(ErrInvalidRemoved, "struct 'Foo'", V2, "example.fidl:10:9");
ASSERT_COMPILER_DIAGNOSTICS(library);
}
TEST_P(VersioningReplacementTest, GoodRemovedAnonymousToNamed) {
TestLibrary library(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");
library.SelectVersion("example", GetParam());
ASSERT_COMPILED(library);
EXPECT_EQ(library.HasStruct("Foo"), GetParam() == V1);
EXPECT_EQ(library.HasTable("Foo"), GetParam() >= V2);
}
TEST_P(VersioningReplacementTest, GoodRemovedAnonymousToAnonymous) {
TestLibrary library(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");
library.SelectVersion("example", GetParam());
ASSERT_COMPILED(library);
EXPECT_EQ(library.HasStruct("Foo"), GetParam() == V1);
EXPECT_EQ(library.HasTable("Foo"), GetParam() >= V2);
}
TEST_P(VersioningReplacementTest, GoodReplacedNamedToAnonymous) {
TestLibrary library(R"FIDL(
@available(added=1)
library example;
@available(replaced=2)
type Foo = struct {};
type Bar = struct {
@available(added=2)
foo table {};
};
)FIDL");
library.SelectVersion("example", GetParam());
ASSERT_COMPILED(library);
EXPECT_EQ(library.HasStruct("Foo"), GetParam() == V1);
EXPECT_EQ(library.HasTable("Foo"), GetParam() >= V2);
}
TEST_P(VersioningReplacementTest, GoodReplacedAnonymousToNamed) {
TestLibrary library(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");
library.SelectVersion("example", GetParam());
ASSERT_COMPILED(library);
EXPECT_EQ(library.HasStruct("Foo"), GetParam() == V1);
EXPECT_EQ(library.HasTable("Foo"), GetParam() >= V2);
}
TEST_P(VersioningReplacementTest, GoodReplacedAnonymousToAnonymous) {
TestLibrary library(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");
library.SelectVersion("example", GetParam());
ASSERT_COMPILED(library);
EXPECT_EQ(library.HasStruct("Foo"), GetParam() == V1);
EXPECT_EQ(library.HasTable("Foo"), GetParam() >= V2);
}
TEST_P(VersioningReplacementTest, GoodReplacedAnonymousToNothing) {
TestLibrary library(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");
library.SelectVersion("example", GetParam());
ASSERT_COMPILED(library);
EXPECT_EQ(library.HasStruct("Foo"), GetParam() == V1);
}
TEST_P(VersioningReplacementTest, GoodMemberRemovedAndRenamed) {
TestLibrary library(R"FIDL(
@available(added=1)
library example;
type Foo = table {
@available(removed=2, renamed="old_bar")
1: bar string;
};
)FIDL");
library.SelectVersion("example", GetParam());
ASSERT_COMPILED(library);
auto foo = library.LookupTable("Foo");
EXPECT_EQ(foo->members.size(), GetParam() == V1 ? 1u : 0u);
// TODO(https://fxbug.dev/42085274): Assert "old_bar" exists when targeting both 1 and >1.
if (GetParam() == V1) {
EXPECT_EQ(foo->members[0].GetName(), "bar");
}
}
TEST_P(VersioningReplacementTest, GoodMemberRemovedAndRenamedNameReused) {
TestLibrary library(R"FIDL(
@available(added=1)
library example;
type Foo = table {
@available(removed=2, renamed="old_bar")
1: bar string;
@available(added=2)
2: bar uint32;
};
)FIDL");
library.SelectVersion("example", GetParam());
ASSERT_COMPILED(library);
auto foo = library.LookupTable("Foo");
EXPECT_EQ(foo->members.size(), 1u);
// TODO(https://fxbug.dev/42085274): Assert "old_bar" exists when targeting both 1 and >1.
EXPECT_EQ(foo->members[0].type_ctor->type->kind,
GetParam() == V1 ? Type::Kind::kString : Type::Kind::kPrimitive);
}
TEST_P(VersioningReplacementTest, BadMemberRemovedAndRenamedNameAlreadyUsedExisting) {
TestLibrary library(R"FIDL(
@available(added=1)
library example;
type Foo = table {
@available(removed=2, renamed="old_bar")
1: bar string;
2: old_bar uint32;
};
)FIDL");
library.SelectVersion("example", GetParam());
library.ExpectFail(ErrInvalidRemovedAndRenamed, "table member 'bar'", V2, "old_bar",
"example.fidl:8:8");
ASSERT_COMPILER_DIAGNOSTICS(library);
}
TEST_P(VersioningReplacementTest, BadMemberRemovedAndRenamedNameAlreadyUsedNew) {
TestLibrary library(R"FIDL(
@available(added=1)
library example;
type Foo = table {
@available(removed=2, renamed="old_bar")
1: bar string;
@available(added=2)
2: old_bar uint32;
};
)FIDL");
library.SelectVersion("example", GetParam());
library.ExpectFail(ErrInvalidRemovedAndRenamed, "table member 'bar'", V2, "old_bar",
"example.fidl:9:8");
ASSERT_COMPILER_DIAGNOSTICS(library);
}
TEST_P(VersioningReplacementTest, BadMethodRemovedAndRenamed) {
TestLibrary library;
library.AddFile("bad/fi-0214.test.fidl");
library.SelectVersion("test", GetParam());
library.ExpectFail(ErrInvalidRemovedAndRenamed, "protocol method 'OldName'", V2, "NewName",
"bad/fi-0214.test.fidl:12:14");
ASSERT_COMPILER_DIAGNOSTICS(library);
}
TEST_P(VersioningReplacementTest, BadMethodReplacedAndRenamed) {
TestLibrary library;
library.AddFile("bad/fi-0215.test.fidl");
library.SelectVersion("test", GetParam());
library.ExpectFail(ErrInvalidReplacedAndRenamed, "protocol method 'OldName'", V2, "NewName");
ASSERT_COMPILER_DIAGNOSTICS(library);
}
TEST_P(VersioningReplacementTest, BadBitsMemberRemovedAbi) {
TestLibrary library(R"FIDL(
@available(added=1)
library example;
type Foo = bits {
@available(removed=2)
A = 1;
@available(added=2)
B = 1;
};
)FIDL");
library.SelectVersion("example", GetParam());
library.ExpectFail(ErrInvalidRemovedAbi, "bits member 'A'", V2, AbiKind::kValue, 1,
"example.fidl:9:5", "B");
ASSERT_COMPILER_DIAGNOSTICS(library);
}
TEST_P(VersioningReplacementTest, BadBitsMemberReplacedAbi) {
TestLibrary library(R"FIDL(
@available(added=1)
library example;
type Foo = bits {
@available(replaced=2)
A = 1;
@available(added=2)
A = 2;
};
)FIDL");
library.SelectVersion("example", GetParam());
library.ExpectFail(ErrInvalidReplacedAbi, "bits member 'A'", V2, AbiKind::kValue, 1, 2,
"example.fidl:9:5");
ASSERT_COMPILER_DIAGNOSTICS(library);
}
TEST_P(VersioningReplacementTest, BadEnumMemberRemovedAbi) {
TestLibrary library(R"FIDL(
@available(added=1)
library example;
type Foo = enum {
@available(removed=2)
A = 1;
@available(added=2)
B = 1;
};
)FIDL");
library.SelectVersion("example", GetParam());
library.ExpectFail(ErrInvalidRemovedAbi, "enum member 'A'", V2, AbiKind::kValue, 1,
"example.fidl:9:5", "B");
ASSERT_COMPILER_DIAGNOSTICS(library);
}
TEST_P(VersioningReplacementTest, BadEnumMemberReplacedAbi) {
TestLibrary library(R"FIDL(
@available(added=1)
library example;
type Foo = enum {
@available(replaced=2)
A = 1;
@available(added=2)
A = 2;
};
)FIDL");
library.SelectVersion("example", GetParam());
library.ExpectFail(ErrInvalidReplacedAbi, "enum member 'A'", V2, AbiKind::kValue, 1, 2,
"example.fidl:9:5");
ASSERT_COMPILER_DIAGNOSTICS(library);
}
TEST_P(VersioningReplacementTest, BadStructMemberRemovedAbi) {
TestLibrary library(R"FIDL(
@available(added=1)
library example;
type Foo = struct {
@available(removed=2)
bar uint32;
@available(added=2)
baz uint32;
};
)FIDL");
library.SelectVersion("example", GetParam());
library.ExpectFail(ErrInvalidRemovedAbi, "struct member 'bar'", V2, AbiKind::kOffset, 0,
"example.fidl:9:5", "baz");
ASSERT_COMPILER_DIAGNOSTICS(library);
}
TEST_P(VersioningReplacementTest, BadStructMemberReplacedAbi) {
TestLibrary library(R"FIDL(
@available(added=1)
library example;
type Foo = struct {
@available(replaced=2)
bar uint32;
gap uint32;
@available(added=2)
bar uint32;
};
)FIDL");
library.SelectVersion("example", GetParam());
library.ExpectFail(ErrInvalidReplacedAbi, "struct member 'bar'", V2, AbiKind::kOffset, 0, 4,
"example.fidl:10:5");
ASSERT_COMPILER_DIAGNOSTICS(library);
}
TEST_P(VersioningReplacementTest, BadTableMemberRemovedAbi) {
TestLibrary library(R"FIDL(
@available(added=1)
library example;
type Foo = table {
@available(removed=2)
1: bar uint32;
@available(added=2)
1: baz uint32;
};
)FIDL");
library.SelectVersion("example", GetParam());
library.ExpectFail(ErrInvalidRemovedAbi, "table member 'bar'", V2, AbiKind::kOrdinal, 1,
"example.fidl:9:8", "baz");
ASSERT_COMPILER_DIAGNOSTICS(library);
}
TEST_P(VersioningReplacementTest, BadTableMemberReplacedAbi) {
TestLibrary library(R"FIDL(
@available(added=1)
library example;
type Foo = table {
@available(replaced=2)
1: bar uint32;
@available(added=2)
2: bar uint32;
};
)FIDL");
library.SelectVersion("example", GetParam());
library.ExpectFail(ErrInvalidReplacedAbi, "table member 'bar'", V2, AbiKind::kOrdinal, 1, 2,
"example.fidl:9:8");
ASSERT_COMPILER_DIAGNOSTICS(library);
}
TEST_P(VersioningReplacementTest, BadUnionMemberRemovedAbi) {
TestLibrary library(R"FIDL(
@available(added=1)
library example;
type Foo = union {
@available(removed=2)
1: bar uint32;
@available(added=2)
1: baz uint32;
};
)FIDL");
library.SelectVersion("example", GetParam());
library.ExpectFail(ErrInvalidRemovedAbi, "union member 'bar'", V2, AbiKind::kOrdinal, 1,
"example.fidl:9:8", "baz");
ASSERT_COMPILER_DIAGNOSTICS(library);
}
TEST_P(VersioningReplacementTest, BadUnionMemberReplacedAbi) {
TestLibrary library(R"FIDL(
@available(added=1)
library example;
type Foo = union {
@available(replaced=2)
1: bar uint32;
@available(added=2)
2: bar uint32;
};
)FIDL");
library.SelectVersion("example", GetParam());
library.ExpectFail(ErrInvalidReplacedAbi, "union member 'bar'", V2, AbiKind::kOrdinal, 1, 2,
"example.fidl:9:8");
ASSERT_COMPILER_DIAGNOSTICS(library);
}
TEST_P(VersioningReplacementTest, BadOverlayMemberRemovedAbi) {
TestLibrary library(R"FIDL(
@available(added=1)
library example;
type Foo = strict overlay {
@available(removed=2)
1: bar uint32;
@available(added=2)
1: baz uint32;
};
)FIDL");
library.EnableFlag(ExperimentalFlag::kZxCTypes);
library.SelectVersion("example", GetParam());
library.ExpectFail(ErrInvalidRemovedAbi, "overlay member 'bar'", V2, AbiKind::kOrdinal, 1,
"example.fidl:9:8", "baz");
ASSERT_COMPILER_DIAGNOSTICS(library);
}
TEST_P(VersioningReplacementTest, BadOverlayMemberReplacedAbi) {
TestLibrary library(R"FIDL(
@available(added=1)
library example;
type Foo = strict overlay {
@available(replaced=2)
1: bar uint32;
@available(added=2)
2: bar uint32;
};
)FIDL");
library.EnableFlag(ExperimentalFlag::kZxCTypes);
library.SelectVersion("example", GetParam());
library.ExpectFail(ErrInvalidReplacedAbi, "overlay member 'bar'", V2, AbiKind::kOrdinal, 1, 2,
"example.fidl:9:8");
ASSERT_COMPILER_DIAGNOSTICS(library);
}
TEST_P(VersioningReplacementTest, BadMethodRemovedAbi) {
TestLibrary library;
library.AddFile("bad/fi-0216.test.fidl");
library.SelectVersion("test", GetParam());
library.ExpectFail(ErrInvalidRemovedAbi, "protocol method 'Bar'", V2, AbiKind::kSelector,
"test.bad.fi0216/Foo.Bar", "bad/fi-0216.test.fidl:13:14", "Qux");
ASSERT_COMPILER_DIAGNOSTICS(library);
}
TEST_P(VersioningReplacementTest, BadMethodReplacedAbi) {
TestLibrary library;
library.AddFile("bad/fi-0217.test.fidl");
library.SelectVersion("test", GetParam());
library.ExpectFail(ErrInvalidReplacedAbi, "protocol method 'Bar'", V2, AbiKind::kSelector,
"test.bad.fi0217/Foo.Bar", "test.bad.fi0217/Foo.NotBar",
"bad/fi-0217.test.fidl:13:14");
ASSERT_COMPILER_DIAGNOSTICS(library);
}
} // namespace
} // namespace fidlc