| // 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 <locale.h> |
| |
| #include <fidl/flat_ast.h> |
| #include <fidl/lexer.h> |
| #include <fidl/parser.h> |
| #include <fidl/raw_ast.h> |
| #include <fidl/source_file.h> |
| #include <zxtest/zxtest.h> |
| |
| #include "error_test.h" |
| #include "fidl/diagnostics.h" |
| #include "fidl/experimental_flags.h" |
| #include "test_library.h" |
| |
| namespace { |
| |
| using fidl::flat::GetType; |
| |
| TEST(HandleTests, GoodHandleRightsTest) { |
| fidl::ExperimentalFlags experimental_flags; |
| auto library = WithLibraryZx(R"FIDL( |
| library example; |
| |
| using zx; |
| |
| resource struct MyStruct { |
| zx.handle:<THREAD, zx.rights.DUPLICATE | zx.rights.TRANSFER> h; |
| }; |
| )FIDL", |
| std::move(experimental_flags)); |
| ASSERT_COMPILED_AND_CONVERT(library); |
| |
| const auto& h_type_ctor = library.LookupStruct("MyStruct")->members[0].type_ctor; |
| |
| std::visit(fidl::utils::matchers{[&](const std::unique_ptr<fidl::flat::TypeConstructorOld>& t) { |
| EXPECT_TRUE(t->handle_subtype_identifier.has_value()); |
| EXPECT_EQ("THREAD", |
| t->handle_subtype_identifier.value().span()->data()); |
| }, |
| [](const std::unique_ptr<fidl::flat::TypeConstructorNew>& t) { |
| assert(false && "uncoverted copy should be used"); |
| }}, |
| h_type_ctor); |
| |
| auto h_type = GetType(h_type_ctor); |
| 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) { |
| fidl::ExperimentalFlags experimental_flags; |
| |
| auto library = WithLibraryZx(R"FIDL( |
| library example; |
| |
| using zx; |
| |
| resource struct MyStruct { |
| zx.handle:VMO h; |
| }; |
| )FIDL", |
| std::move(experimental_flags)); |
| |
| ASSERT_COMPILED_AND_CONVERT(library); |
| |
| const auto& h_type_ctor = library.LookupStruct("MyStruct")->members[0].type_ctor; |
| auto h_type = GetType(h_type_ctor); |
| 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); |
| |
| std::visit(fidl::utils::matchers{ |
| [&](const std::unique_ptr<fidl::flat::TypeConstructorOld>& t) { |
| EXPECT_TRUE(t->handle_subtype_identifier.has_value()); |
| ASSERT_TRUE(t->handle_subtype_identifier.value().span()->data() == "VMO"); |
| }, |
| [](const std::unique_ptr<fidl::flat::TypeConstructorNew>& t) { |
| assert(false && "uncoverted copy should be used"); |
| }}, |
| h_type_ctor); |
| 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/71536): implement client/server end in the new syntax |
| TEST(HandleTests, BadInvalidHandleRightsTest) { |
| fidl::ExperimentalFlags experimental_flags; |
| experimental_flags.SetFlag(fidl::ExperimentalFlags::Flag::kAllowNewSyntax); |
| |
| auto library = WithLibraryZx(R"FIDL( |
| library example; |
| |
| using zx; |
| |
| protocol P { |
| Method(struct { h zx.handle:<VMO, 1>; }); // rights must be zx.rights-typed. |
| }; |
| )FIDL", |
| std::move(experimental_flags)); |
| |
| // NOTE(fxbug.dev/72924): we provide a more general error because there are multiple |
| // possible interpretations. |
| ASSERT_ERRORED_TWICE_DURING_COMPILE(library, fidl::ErrConstantCannotBeInterpretedAsType, |
| fidl::ErrUnexpectedConstraint); |
| } |
| |
| TEST(HandleTests, BadInvalidHandleRightsTestOld) { |
| fidl::ExperimentalFlags experimental_flags; |
| |
| auto library = WithLibraryZx(R"FIDL( |
| library example; |
| |
| using zx; |
| |
| protocol P { |
| Method(zx.handle:<VMO, 1> h); // rights must be zx.rights-typed. |
| }; |
| )FIDL", |
| std::move(experimental_flags)); |
| |
| ASSERT_ERRORED_TWICE_DURING_COMPILE(library, fidl::ErrConstantCannotBeInterpretedAsType, |
| fidl::ErrCouldNotResolveHandleRights); |
| } |
| |
| TEST(HandleTests, GoodPlainHandleTest) { |
| fidl::ExperimentalFlags experimental_flags; |
| |
| auto library = WithLibraryZx(R"FIDL( |
| library example; |
| |
| using zx; |
| |
| resource struct MyStruct { |
| zx.handle h; |
| }; |
| )FIDL", |
| std::move(experimental_flags)); |
| ASSERT_COMPILED_AND_CONVERT(library); |
| |
| const auto& h_type_ctor = library.LookupStruct("MyStruct")->members[0].type_ctor; |
| |
| auto h_type = GetType(h_type_ctor); |
| 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) { |
| fidl::ExperimentalFlags experimental_flags; |
| |
| auto library = WithLibraryZx(R"FIDL( |
| library example; |
| |
| using zx; |
| |
| resource struct MyStruct { |
| zx.handle:THREAD a; |
| zx.handle:<PROCESS> b; |
| zx.handle:<VMO, zx.rights.TRANSFER> c; |
| }; |
| )FIDL", |
| std::move(experimental_flags)); |
| |
| ASSERT_COMPILED_AND_CONVERT(library); |
| const auto& a = library.LookupStruct("MyStruct")->members[0].type_ctor; |
| auto a_type = GetType(a); |
| 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 = GetType(b); |
| 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 = GetType(c); |
| 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) { |
| fidl::ExperimentalFlags experimental_flags; |
| experimental_flags.SetFlag(fidl::ExperimentalFlags::Flag::kAllowNewSyntax); |
| |
| auto library = WithLibraryZx(R"FIDL( |
| library example; |
| |
| using zx; |
| |
| type MyStruct = struct { |
| a zx.handle:ZIPPY; |
| }; |
| )FIDL", |
| std::move(experimental_flags)); |
| |
| // NOTE(fxbug.dev/72924): we provide a more general error because there are multiple |
| // possible interpretations. |
| ASSERT_ERRORED_DURING_COMPILE(library, fidl::ErrUnexpectedConstraint); |
| } |
| |
| TEST(HandleTests, BadInvalidFidlDefinedHandleSubtypeOld) { |
| fidl::ExperimentalFlags experimental_flags; |
| |
| auto library = WithLibraryZx(R"FIDL( |
| library example; |
| |
| using zx; |
| |
| struct MyStruct { |
| zx.handle:ZIPPY a; |
| }; |
| )FIDL", |
| std::move(experimental_flags)); |
| |
| ASSERT_ERRORED_DURING_COMPILE(library, fidl::ErrCouldNotResolveHandleSubtype); |
| EXPECT_TRUE(library.errors()[0]->msg.find("ZIPPY") != std::string::npos); |
| } |
| |
| TEST(HandleTests, BadDisallowOldHandles) { |
| fidl::ExperimentalFlags experimental_flags; |
| experimental_flags.SetFlag(fidl::ExperimentalFlags::Flag::kAllowNewSyntax); |
| auto library = WithLibraryZx(R"FIDL( |
| library example; |
| |
| using zx; |
| |
| type MyStruct = struct { |
| h handle<vmo>; |
| }; |
| )FIDL", |
| experimental_flags); |
| // TODO(fxbug.dev/77101): provide a less confusing error |
| // NOTE(fxbug.dev/72924): the old syntax returns a different error because |
| // it tries to resolve the parameters before checking that handle points to |
| // a resource definition |
| ASSERT_ERRORED_DURING_COMPILE(library, fidl::ErrHandleNotResource); |
| } |
| |
| TEST(HandleTests, BadDisallowOldHandlesOld) { |
| auto library = WithLibraryZx(R"FIDL( |
| library example; |
| |
| using zx; |
| |
| struct MyStruct { |
| handle<vmo> h; |
| }; |
| )FIDL"); |
| // This looks like it's returning the correct error, but it's not - the unknown |
| // type here refers to `vmo` not `handle` |
| ASSERT_ERRORED_DURING_COMPILE(library, fidl::ErrUnknownType); |
| } |
| |
| // TODO(fxbug.dev/64629): Consider how we could validate resource_declaration without any use. |
| TEST(HandleTests, GoodResourceDefinitionOnlySubtypeNoRightsTest) { |
| fidl::ExperimentalFlags experimental_flags; |
| |
| TestLibrary library(R"FIDL( |
| library example; |
| |
| enum obj_type : uint32 { |
| NONE = 0; |
| VMO = 3; |
| }; |
| |
| resource_definition handle : uint32 { |
| properties { |
| obj_type subtype; |
| }; |
| }; |
| |
| resource struct MyStruct { |
| handle:<VMO> h; |
| }; |
| )FIDL", |
| std::move(experimental_flags)); |
| |
| ASSERT_COMPILED_AND_CONVERT(library); |
| |
| const auto& h_type_ctor = library.LookupStruct("MyStruct")->members[0].type_ctor; |
| auto h_type = GetType(h_type_ctor); |
| 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); |
| |
| std::visit(fidl::utils::matchers{ |
| [&](const std::unique_ptr<fidl::flat::TypeConstructorOld>& t) { |
| EXPECT_TRUE(t->handle_subtype_identifier.has_value()); |
| ASSERT_TRUE(t->handle_subtype_identifier.value().span()->data() == "VMO"); |
| }, |
| [](const std::unique_ptr<fidl::flat::TypeConstructorNew>& t) { |
| assert(false && "uncoverted copy should be used"); |
| }}, |
| h_type_ctor); |
| 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) { |
| fidl::ExperimentalFlags experimental_flags; |
| experimental_flags.SetFlag(fidl::ExperimentalFlags::Flag::kAllowNewSyntax); |
| |
| 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", |
| std::move(experimental_flags)); |
| |
| // TODO(fxbug.dev/75112): should include ErrResourceMissingRightsProperty |
| ASSERT_ERRORED_DURING_COMPILE(library, fidl::ErrUnexpectedConstraint); |
| } |
| |
| TEST(HandleTests, BadResourceDefinitionMissingRightsPropertyTestOld) { |
| fidl::ExperimentalFlags experimental_flags; |
| |
| TestLibrary library(R"FIDL( |
| library example; |
| |
| enum obj_type : uint32 { |
| NONE = 0; |
| VMO = 3; |
| }; |
| |
| resource_definition handle : uint32 { |
| properties { |
| obj_type subtype; |
| }; |
| }; |
| |
| resource struct MyStruct { |
| handle:<VMO, 1> h; |
| }; |
| )FIDL", |
| std::move(experimental_flags)); |
| |
| ASSERT_ERRORED_DURING_COMPILE(library, fidl::ErrCouldNotResolveHandleRights); |
| } |
| |
| // TODO(fxbug.dev/64629): Consider how we could validate resource_declaration without any use. |
| TEST(HandleTests, BadResourceDefinitionMissingSubtypePropertyTest) { |
| fidl::ExperimentalFlags experimental_flags; |
| experimental_flags.SetFlag(fidl::ExperimentalFlags::Flag::kAllowNewSyntax); |
| |
| TestLibrary library(R"FIDL( |
| library example; |
| |
| resource_definition handle : uint32 { |
| properties { |
| rights uint32; |
| }; |
| }; |
| |
| type MyStruct = resource struct { |
| h handle:VMO; |
| }; |
| )FIDL", |
| std::move(experimental_flags)); |
| |
| // TODO(fxbug.dev/75112): should include ErrResourceMissingSubtypeProperty |
| ASSERT_ERRORED_DURING_COMPILE(library, fidl::ErrUnexpectedConstraint); |
| } |
| |
| TEST(HandleTests, BadResourceDefinitionMissingSubtypePropertyTestOld) { |
| fidl::ExperimentalFlags experimental_flags; |
| |
| TestLibrary library(R"FIDL( |
| library example; |
| |
| resource_definition handle : uint32 { |
| properties { |
| uint32 rights; |
| }; |
| }; |
| |
| resource struct MyStruct { |
| handle:VMO h; |
| }; |
| )FIDL", |
| std::move(experimental_flags)); |
| |
| ASSERT_ERRORED_DURING_COMPILE(library, fidl::ErrCouldNotResolveHandleSubtype); |
| } |
| |
| // TODO(fxbug.dev/64629): Consider how we could validate resource_declaration without any use. |
| TEST(HandleTests, BadResourceSubtypeNotEnum) { |
| fidl::ExperimentalFlags experimental_flags; |
| experimental_flags.SetFlag(fidl::ExperimentalFlags::Flag::kAllowNewSyntax); |
| |
| 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", |
| std::move(experimental_flags)); |
| |
| // TODO(fxbug.dev/75112): should include ErrResourceSubtypePropertyMustReferToEnum |
| ASSERT_ERRORED_DURING_COMPILE(library, fidl::ErrUnexpectedConstraint); |
| } |
| |
| TEST(HandleTests, BadResourceSubtypeNotEnumOld) { |
| fidl::ExperimentalFlags experimental_flags; |
| |
| TestLibrary library(R"FIDL( |
| library example; |
| |
| struct obj_type {}; |
| |
| resource_definition handle : uint32 { |
| properties { |
| obj_type subtype; |
| }; |
| }; |
| |
| resource struct MyStruct { |
| handle:<VMO, 1> h; |
| }; |
| )FIDL", |
| experimental_flags); |
| |
| ASSERT_ERRORED_DURING_COMPILE(library, fidl::ErrCouldNotResolveHandleSubtype); |
| } |
| |
| TEST(HandleTests, BadNonIdentifierSubtype) { |
| fidl::ExperimentalFlags experimental_flags; |
| experimental_flags.SetFlag(fidl::ExperimentalFlags::Flag::kAllowNewSyntax); |
| |
| 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", |
| experimental_flags); |
| |
| // TODO(fxbug.dev/75112): should include ErrHandleSubtypeMustReferToResourceSubtype |
| ASSERT_ERRORED_DURING_COMPILE(library, fidl::ErrUnexpectedConstraint); |
| } |
| |
| TEST(HandleTests, BadNonIdentifierSubtypeOld) { |
| TestLibrary library(R"FIDL( |
| library example; |
| |
| enum obj_type : uint32 { |
| NONE = 0; |
| VMO = 3; |
| }; |
| |
| resource_definition handle : uint32 { |
| properties { |
| obj_type subtype; |
| }; |
| }; |
| |
| resource struct MyStruct { |
| handle:1? h; |
| }; |
| )FIDL"); |
| |
| // NOTE(fxbug.dev/72924): This is just a parse error in the old syntax, since |
| // we only allow identifiers as rights. Hence why |
| // ErrHandleSubtypeMustReferToResourceSubtype is only relevant in the new syntax. |
| ASSERT_ERRORED_DURING_COMPILE(library, fidl::ErrUnexpectedTokenOfKind); |
| } |
| |
| // TODO(fxbug.dev/64629): Consider how we could validate resource_declaration without any use. |
| TEST(HandleTests, BadResourceDefinitionNonBitsRights) { |
| fidl::ExperimentalFlags experimental_flags; |
| experimental_flags.SetFlag(fidl::ExperimentalFlags::Flag::kAllowNewSyntax); |
| |
| 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", |
| experimental_flags); |
| |
| // TODO(fxbug.dev/75112): should include ErrResourceMissingSubtypeProperty |
| ASSERT_ERRORED_DURING_COMPILE(library, fidl::ErrUnexpectedConstraint); |
| } |
| |
| TEST(HandleTests, BadResourceDefinitionNonBitsRightsOld) { |
| fidl::ExperimentalFlags experimental_flags; |
| |
| TestLibrary library(R"FIDL( |
| library example; |
| |
| enum obj_type : uint32 { |
| NONE = 0; |
| VMO = 3; |
| }; |
| |
| resource_definition handle : uint32 { |
| properties { |
| obj_type subtype; |
| string rights; |
| }; |
| }; |
| |
| resource struct MyStruct { |
| handle:<VMO, "hello"> h; |
| }; |
| )FIDL", |
| experimental_flags); |
| |
| ASSERT_ERRORED_DURING_COMPILE(library, fidl::ErrCouldNotResolveHandleRights); |
| } |
| |
| TEST(HandleTests, BadBareHandleNoConstraints) { |
| fidl::ExperimentalFlags experimental_flags; |
| experimental_flags.SetFlag(fidl::ExperimentalFlags::Flag::kAllowNewSyntax); |
| |
| TestLibrary library(R"FIDL( |
| library example; |
| |
| type MyStruct = resource struct { |
| h handle; |
| }; |
| )FIDL", |
| experimental_flags); |
| ASSERT_ERRORED_DURING_COMPILE(library, fidl::ErrHandleNotResource); |
| } |
| |
| TEST(HandleTests, BadBareHandleNoConstraintsOld) { |
| TestLibrary library(R"FIDL( |
| library example; |
| |
| resource struct MyStruct { |
| handle h; |
| }; |
| )FIDL"); |
| ASSERT_ERRORED_DURING_COMPILE(library, fidl::ErrHandleNotResource); |
| } |
| |
| TEST(HandleTests, BadBareHandleWithConstraintsOld) { |
| TestLibrary library(R"FIDL( |
| library example; |
| |
| resource struct MyStruct { |
| handle:VMO h; |
| }; |
| )FIDL"); |
| ASSERT_ERRORED_DURING_COMPILE(library, fidl::ErrHandleNotResource); |
| } |
| |
| TEST(HandleTests, BadBareHandleWithConstraints) { |
| fidl::ExperimentalFlags experimental_flags; |
| experimental_flags.SetFlag(fidl::ExperimentalFlags::Flag::kAllowNewSyntax); |
| TestLibrary library(R"FIDL( |
| library example; |
| |
| type MyStruct = resource struct { |
| h handle:VMO; |
| }; |
| )FIDL", |
| experimental_flags); |
| ASSERT_ERRORED_DURING_COMPILE(library, fidl::ErrHandleNotResource); |
| } |
| |
| TEST(HandleTests, BadBareHandleWithConstraintsThroughAliasOld) { |
| TestLibrary library(R"FIDL( |
| library example; |
| |
| alias my_handle = handle; |
| |
| resource struct MyStruct { |
| my_handle:VMO h; |
| }; |
| )FIDL"); |
| // NOTE(fxbug.dev/72924): The old syntax fails in a different way because of the way it parses |
| // handles, assuming that it's a size bound since it doesn't match "handle" exactly. |
| ASSERT_ERRORED_TWICE_DURING_COMPILE(library, fidl::ErrCouldNotParseSizeBound, |
| fidl::ErrHandleNotResource); |
| } |
| |
| TEST(HandleTests, BadBareHandleWithConstraintsThroughAlias) { |
| fidl::ExperimentalFlags experimental_flags; |
| experimental_flags.SetFlag(fidl::ExperimentalFlags::Flag::kAllowNewSyntax); |
| TestLibrary library(R"FIDL( |
| library example; |
| |
| alias my_handle = handle; |
| |
| type MyStruct = resource struct { |
| h my_handle:VMO; |
| }; |
| )FIDL", |
| experimental_flags); |
| ASSERT_ERRORED_DURING_COMPILE(library, fidl::ErrHandleNotResource); |
| } |
| |
| } // namespace |