blob: 54d9b4c32c4f83a35981a2068ed0a5ad69be8e0c [file] [log] [blame]
// Copyright 2020 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <fidl/flat_ast.h>
#include <fidl/lexer.h>
#include <fidl/parser.h>
#include <fidl/raw_ast.h>
#include <fidl/source_file.h>
#include <locale.h>
#include <zxtest/zxtest.h>
#include "error_test.h"
#include "fidl/diagnostics.h"
#include "fidl/experimental_flags.h"
#include "test_library.h"
namespace {
TEST(HandleTests, GoodHandleRightsTest) {
TestLibrary library(R"FIDL(
library example;
using zx;
type MyStruct = resource struct {
h zx.handle:<THREAD, zx.rights.DUPLICATE | zx.rights.TRANSFER>;
};
)FIDL");
library.UseLibraryZx();
ASSERT_COMPILED(library);
const auto& h_type_ctor = library.LookupStruct("MyStruct")->members[0].type_ctor;
EXPECT_TRUE(h_type_ctor->resolved_params.subtype_raw != nullptr);
EXPECT_EQ("THREAD", h_type_ctor->resolved_params.subtype_raw->span.data());
auto h_type = h_type_ctor->type;
ASSERT_NOT_NULL(h_type);
ASSERT_EQ(h_type->kind, fidl::flat::Type::Kind::kHandle);
auto handle_type = static_cast<const fidl::flat::HandleType*>(h_type);
EXPECT_EQ(2, handle_type->obj_type);
EXPECT_EQ(
static_cast<const fidl::flat::NumericConstantValue<uint32_t>*>(handle_type->rights)->value,
3);
}
TEST(HandleTests, GoodNoHandleRightsTest) {
TestLibrary library(R"FIDL(
library example;
using zx;
type MyStruct = resource struct {
h zx.handle:VMO;
};
)FIDL");
library.UseLibraryZx();
ASSERT_COMPILED(library);
const auto& h_type_ctor = library.LookupStruct("MyStruct")->members[0].type_ctor;
auto h_type = h_type_ctor->type;
ASSERT_NOT_NULL(h_type);
ASSERT_EQ(h_type->kind, fidl::flat::Type::Kind::kHandle);
auto handle_type = static_cast<const fidl::flat::HandleType*>(h_type);
EXPECT_TRUE(h_type_ctor->resolved_params.subtype_raw != nullptr);
EXPECT_EQ("VMO", h_type_ctor->resolved_params.subtype_raw->span.data());
EXPECT_EQ(3, handle_type->obj_type);
EXPECT_EQ(
static_cast<const fidl::flat::NumericConstantValue<uint32_t>*>(handle_type->rights)->value,
fidl::flat::kHandleSameRights);
}
TEST(HandleTests, BadInvalidHandleRightsTest) {
TestLibrary library(R"FIDL(
library example;
using zx;
protocol P {
Method(struct { h zx.handle:<VMO, 1>; }); // rights must be zx.rights-typed.
};
)FIDL");
library.UseLibraryZx();
// NOTE(fxbug.dev/72924): we provide a more general error because there are multiple
// possible interpretations.
ASSERT_ERRORED_TWICE_DURING_COMPILE(library, fidl::ErrTypeCannotBeConvertedToType,
fidl::ErrUnexpectedConstraint);
}
TEST(HandleTests, GoodPlainHandleTest) {
TestLibrary library(R"FIDL(
library example;
using zx;
type MyStruct = resource struct {
h zx.handle;
};
)FIDL");
library.UseLibraryZx();
ASSERT_COMPILED(library);
const auto& h_type_ctor = library.LookupStruct("MyStruct")->members[0].type_ctor;
auto h_type = h_type_ctor->type;
ASSERT_NOT_NULL(h_type);
ASSERT_EQ(h_type->kind, fidl::flat::Type::Kind::kHandle);
auto handle_type = static_cast<const fidl::flat::HandleType*>(h_type);
EXPECT_EQ(0, handle_type->obj_type);
EXPECT_EQ(
static_cast<const fidl::flat::NumericConstantValue<uint32_t>*>(handle_type->rights)->value,
fidl::flat::kHandleSameRights);
}
TEST(HandleTests, GoodHandleFidlDefinedTest) {
TestLibrary library(R"FIDL(
library example;
using zx;
type MyStruct = resource struct {
a zx.handle:THREAD;
b zx.handle:<PROCESS>;
c zx.handle:<VMO, zx.rights.TRANSFER>;
};
)FIDL");
library.UseLibraryZx();
ASSERT_COMPILED(library);
const auto& a = library.LookupStruct("MyStruct")->members[0].type_ctor;
auto a_type = a->type;
ASSERT_NOT_NULL(a_type);
ASSERT_EQ(a_type->kind, fidl::flat::Type::Kind::kHandle);
auto a_handle_type = static_cast<const fidl::flat::HandleType*>(a_type);
EXPECT_EQ(2, a_handle_type->obj_type);
EXPECT_EQ(static_cast<const fidl::flat::HandleRights*>(a_handle_type->rights)->value,
fidl::flat::kHandleSameRights);
const auto& b = library.LookupStruct("MyStruct")->members[1].type_ctor;
auto b_type = b->type;
ASSERT_NOT_NULL(b_type);
ASSERT_EQ(b_type->kind, fidl::flat::Type::Kind::kHandle);
auto b_handle_type = static_cast<const fidl::flat::HandleType*>(b_type);
EXPECT_EQ(1, b_handle_type->obj_type);
EXPECT_EQ(static_cast<const fidl::flat::HandleRights*>(b_handle_type->rights)->value,
fidl::flat::kHandleSameRights);
const auto& c = library.LookupStruct("MyStruct")->members[2].type_ctor;
auto c_type = c->type;
ASSERT_NOT_NULL(c_type);
ASSERT_EQ(c_type->kind, fidl::flat::Type::Kind::kHandle);
auto c_handle_type = static_cast<const fidl::flat::HandleType*>(c_type);
EXPECT_EQ(3, c_handle_type->obj_type);
ASSERT_NOT_NULL(c_handle_type->rights);
EXPECT_EQ(static_cast<const fidl::flat::HandleRights*>(c_handle_type->rights)->value, 2);
}
TEST(HandleTests, BadInvalidFidlDefinedHandleSubtype) {
TestLibrary library(R"FIDL(
library example;
using zx;
type MyStruct = struct {
a zx.handle:ZIPPY;
};
)FIDL");
library.UseLibraryZx();
ASSERT_ERRORED_DURING_COMPILE(library, fidl::ErrNameNotFound);
}
TEST(HandleTests, BadDisallowOldHandles) {
TestLibrary library(R"FIDL(
library example;
using zx;
type MyStruct = struct {
h handle<vmo>;
};
)FIDL");
library.UseLibraryZx();
ASSERT_ERRORED_TWICE_DURING_COMPILE(library, fidl::ErrNameNotFound, fidl::ErrNameNotFound);
EXPECT_SUBSTR(library.errors()[0]->msg.c_str(), "cannot find 'handle'");
EXPECT_SUBSTR(library.errors()[1]->msg.c_str(), "cannot find 'vmo'");
}
// TODO(fxbug.dev/64629): Consider how we could validate resource_declaration without any use.
TEST(HandleTests, GoodResourceDefinitionOnlySubtypeNoRightsTest) {
TestLibrary library(R"FIDL(library example;
type obj_type = strict enum : uint32 {
NONE = 0;
VMO = 3;
};
resource_definition handle : uint32 {
properties {
subtype obj_type;
};
};
type MyStruct = resource struct {
h handle:VMO;
};
)FIDL");
ASSERT_COMPILED(library);
const auto& h_type_ctor = library.LookupStruct("MyStruct")->members[0].type_ctor;
auto h_type = h_type_ctor->type;
ASSERT_NOT_NULL(h_type);
ASSERT_EQ(h_type->kind, fidl::flat::Type::Kind::kHandle);
auto handle_type = static_cast<const fidl::flat::HandleType*>(h_type);
EXPECT_TRUE(h_type_ctor->resolved_params.subtype_raw != nullptr);
ASSERT_TRUE(h_type_ctor->resolved_params.subtype_raw->span.data() == "VMO");
EXPECT_EQ(3, handle_type->obj_type);
EXPECT_EQ(
static_cast<const fidl::flat::NumericConstantValue<uint32_t>*>(handle_type->rights)->value,
fidl::flat::kHandleSameRights);
}
// TODO(fxbug.dev/64629): Consider how we could validate resource_declaration without any use.
TEST(HandleTests, BadResourceDefinitionMissingRightsPropertyTest) {
TestLibrary library(R"FIDL(
library example;
type obj_type = enum : uint32 {
NONE = 0;
VMO = 3;
};
resource_definition handle : uint32 {
properties {
subtype obj_type;
};
};
type MyStruct = resource struct {
h handle:<VMO, 1>;
};
)FIDL");
// TODO(fxbug.dev/75112): should include ErrResourceMissingRightsProperty
ASSERT_ERRORED_DURING_COMPILE(library, fidl::ErrUnexpectedConstraint);
}
// TODO(fxbug.dev/64629): Consider how we could validate resource_declaration without any use.
TEST(HandleTests, BadResourceDefinitionMissingSubtypePropertyTest) {
TestLibrary library(R"FIDL(
library example;
resource_definition handle : uint32 {
properties {
rights uint32;
};
};
type MyStruct = resource struct {
h handle:VMO;
};
)FIDL");
// TODO(fxbug.dev/75112): should include ErrResourceMissingSubtypeProperty
ASSERT_ERRORED_DURING_COMPILE(library, fidl::ErrNameNotFound);
}
// TODO(fxbug.dev/64629): Consider how we could validate resource_declaration without any use.
TEST(HandleTests, BadResourceSubtypeNotEnum) {
TestLibrary library(R"FIDL(
library example;
type obj_type = struct {};
resource_definition handle : uint32 {
properties {
subtype obj_type;
};
};
type MyStruct = resource struct {
h handle:<VMO, 1>;
};
)FIDL");
// TODO(fxbug.dev/75112): should include ErrResourceSubtypePropertyMustReferToEnum
ASSERT_ERRORED_DURING_COMPILE(library, fidl::ErrNameNotFound);
}
TEST(HandleTests, BadNonIdentifierSubtype) {
TestLibrary library(R"FIDL(
library example;
type obj_type = enum : uint32 {
NONE = 0;
VMO = 3;
};
resource_definition handle : uint32 {
properties {
subtype obj_type;
};
};
type MyStruct = resource struct {
h handle:<1, optional>;
};
)FIDL");
// TODO(fxbug.dev/75112): should include ErrHandleSubtypeMustReferToResourceSubtype
ASSERT_ERRORED_TWICE_DURING_COMPILE(library, fidl::ErrTypeCannotBeConvertedToType,
fidl::ErrUnexpectedConstraint);
}
// TODO(fxbug.dev/64629): Consider how we could validate resource_declaration without any use.
TEST(HandleTests, BadResourceDefinitionNonBitsRights) {
TestLibrary library(R"FIDL(
library example;
type obj_type = enum : uint32 {
NONE = 0;
VMO = 3;
};
resource_definition handle : uint32 {
properties {
subtype obj_type;
rights string;
};
};
type MyStruct = resource struct {
h handle:<VMO, "hello">;
};
)FIDL");
// TODO(fxbug.dev/75112): should include ErrResourceRightsPropertyMustReferToBits
ASSERT_ERRORED_DURING_COMPILE(library, fidl::ErrUnexpectedConstraint);
}
TEST(HandleTests, BadBareHandleNoConstraints) {
TestLibrary library(R"FIDL(
library example;
type MyStruct = resource struct {
h handle;
};
)FIDL");
ASSERT_ERRORED_DURING_COMPILE(library, fidl::ErrNameNotFound);
}
TEST(HandleTests, BadBareHandleWithConstraints) {
TestLibrary library(R"FIDL(
library example;
type MyStruct = resource struct {
h handle:VMO;
};
)FIDL");
ASSERT_ERRORED_TWICE_DURING_COMPILE(library, fidl::ErrNameNotFound, fidl::ErrNameNotFound);
}
TEST(HandleTests, BadBareHandleWithConstraintsThroughAlias) {
TestLibrary library(R"FIDL(
library example;
alias my_handle = handle;
type MyStruct = resource struct {
h my_handle:VMO;
};
)FIDL");
ASSERT_ERRORED_TWICE_DURING_COMPILE(library, fidl::ErrNameNotFound, fidl::ErrNameNotFound);
}
} // namespace