| // Copyright 2018 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include <fidl/flat_ast.h> |
| #include <fidl/lexer.h> |
| #include <fidl/parser.h> |
| #include <fidl/source_file.h> |
| #include <zxtest/zxtest.h> |
| |
| #include "error_test.h" |
| #include "test_library.h" |
| |
| namespace { |
| |
| TEST(ProtocolTests, valid_empty_protocol) { |
| TestLibrary library(R"FIDL( |
| library example; |
| |
| protocol Empty {}; |
| |
| )FIDL"); |
| ASSERT_TRUE(library.Compile()); |
| |
| auto protocol = library.LookupProtocol("Empty"); |
| ASSERT_NOT_NULL(protocol); |
| |
| EXPECT_EQ(protocol->methods.size(), 0); |
| EXPECT_EQ(protocol->all_methods.size(), 0); |
| } |
| |
| TEST(ProtocolTests, valid_compose_method) { |
| TestLibrary library(R"FIDL( |
| library example; |
| |
| protocol HasComposeMethod1 { |
| compose(); |
| }; |
| |
| protocol HasComposeMethod2 { |
| compose() -> (); |
| }; |
| |
| )FIDL"); |
| ASSERT_TRUE(library.Compile()); |
| |
| auto protocol1 = library.LookupProtocol("HasComposeMethod1"); |
| ASSERT_NOT_NULL(protocol1); |
| EXPECT_EQ(protocol1->methods.size(), 1); |
| EXPECT_EQ(protocol1->all_methods.size(), 1); |
| |
| auto protocol2 = library.LookupProtocol("HasComposeMethod2"); |
| ASSERT_NOT_NULL(protocol2); |
| EXPECT_EQ(protocol2->methods.size(), 1); |
| EXPECT_EQ(protocol2->all_methods.size(), 1); |
| } |
| |
| TEST(ProtocolTests, valid_protocol_composition) { |
| TestLibrary library(R"FIDL( |
| library example; |
| |
| protocol A { |
| MethodA(); |
| }; |
| |
| protocol B { |
| compose A; |
| MethodB(); |
| }; |
| |
| protocol C { |
| compose A; |
| MethodC(); |
| }; |
| |
| protocol D { |
| compose B; |
| compose C; |
| MethodD(); |
| }; |
| |
| )FIDL"); |
| ASSERT_TRUE(library.Compile()); |
| |
| auto protocol_a = library.LookupProtocol("A"); |
| ASSERT_NOT_NULL(protocol_a); |
| EXPECT_EQ(protocol_a->methods.size(), 1); |
| EXPECT_EQ(protocol_a->all_methods.size(), 1); |
| |
| auto protocol_b = library.LookupProtocol("B"); |
| ASSERT_NOT_NULL(protocol_b); |
| EXPECT_EQ(protocol_b->methods.size(), 1); |
| EXPECT_EQ(protocol_b->all_methods.size(), 2); |
| |
| auto protocol_c = library.LookupProtocol("C"); |
| ASSERT_NOT_NULL(protocol_c); |
| EXPECT_EQ(protocol_c->methods.size(), 1); |
| EXPECT_EQ(protocol_c->all_methods.size(), 2); |
| |
| auto protocol_d = library.LookupProtocol("D"); |
| ASSERT_NOT_NULL(protocol_d); |
| EXPECT_EQ(protocol_d->methods.size(), 1); |
| EXPECT_EQ(protocol_d->all_methods.size(), 4); |
| } |
| |
| TEST(ProtocolTests, invalid_colon_syntax_is_not_supported) { |
| TestLibrary library(R"FIDL( |
| library example; |
| |
| protocol Parent {}; |
| protocol Child : Parent {}; |
| |
| )FIDL"); |
| ASSERT_FALSE(library.Compile()); |
| const auto& errors = library.errors(); |
| ASSERT_EQ(errors.size(), 1); |
| ASSERT_ERR(errors[0], fidl::ErrUnexpectedTokenOfKind); |
| } |
| |
| TEST(ProtocolTests, invalid_doc_comment_outside_attribute_list) { |
| TestLibrary library(R"FIDL( |
| library example; |
| |
| protocol WellDocumented { |
| Method(); |
| /// Misplaced doc comment |
| }; |
| |
| )FIDL"); |
| ASSERT_FALSE(library.Compile()); |
| const auto& errors = library.errors(); |
| ASSERT_EQ(errors.size(), 1); |
| ASSERT_ERR(errors[0], fidl::ErrExpectedProtocolMember); |
| } |
| |
| TEST(ProtocolTests, invalid_cannot_attach_attributes_to_compose) { |
| TestLibrary library(R"FIDL( |
| library example; |
| |
| protocol Child { |
| [NoCantDo] compose Parent; |
| }; |
| |
| )FIDL"); |
| ASSERT_FALSE(library.Compile()); |
| const auto& errors = library.errors(); |
| ASSERT_EQ(errors.size(), 1); |
| ASSERT_ERR(errors[0], fidl::ErrCannotAttachAttributesToCompose); |
| } |
| |
| TEST(ProtocolTests, invalid_cannot_compose_yourself) { |
| TestLibrary library(R"FIDL( |
| library example; |
| |
| protocol Narcisse { |
| compose Narcisse; |
| }; |
| |
| )FIDL"); |
| ASSERT_FALSE(library.Compile()); |
| const auto& errors = library.errors(); |
| ASSERT_EQ(errors.size(), 1); |
| ASSERT_ERR(errors[0], fidl::ErrIncludeCycle); |
| } |
| |
| TEST(ProtocolTests, invalid_cannot_compose_twice_the_same_protocol) { |
| TestLibrary library(R"FIDL( |
| library example; |
| |
| protocol Parent { |
| Method(); |
| }; |
| |
| protocol Child { |
| compose Parent; |
| compose Parent; |
| }; |
| |
| )FIDL"); |
| ASSERT_FALSE(library.Compile()); |
| const auto& errors = library.errors(); |
| ASSERT_EQ(errors.size(), 1); |
| ASSERT_ERR(errors[0], fidl::ErrProtocolComposedMultipleTimes); |
| } |
| |
| TEST(ProtocolTests, invalid_cannot_compose_missing_protocol) { |
| TestLibrary library(R"FIDL( |
| library example; |
| |
| protocol Child { |
| compose MissingParent; |
| }; |
| |
| )FIDL"); |
| ASSERT_FALSE(library.Compile()); |
| const auto& errors = library.errors(); |
| ASSERT_EQ(errors.size(), 1); |
| ASSERT_ERR(errors[0], fidl::ErrUnknownType); |
| ASSERT_SUBSTR(errors[0]->msg.c_str(), "MissingParent"); |
| } |
| |
| TEST(ProtocolTests, invalid_cannot_compose_non_protocol) { |
| TestLibrary library(R"FIDL( |
| library example; |
| |
| struct S {}; |
| protocol P { |
| compose S; |
| }; |
| )FIDL"); |
| ASSERT_FALSE(library.Compile()); |
| const auto& errors = library.errors(); |
| ASSERT_EQ(errors.size(), 1); |
| ASSERT_ERR(errors[0], fidl::ErrComposingNonProtocol); |
| } |
| |
| TEST(ProtocolTests, invalid_cannot_use_ordinals_in_protocol_declaration) { |
| TestLibrary library(R"FIDL( |
| library example; |
| |
| protocol NoMoreOrdinals { |
| 42: NiceTry(); |
| }; |
| |
| )FIDL"); |
| ASSERT_FALSE(library.Compile()); |
| const auto& errors = library.errors(); |
| ASSERT_EQ(errors.size(), 1); |
| ASSERT_ERR(errors[0], fidl::ErrExpectedProtocolMember); |
| } |
| |
| TEST(ProtocolTests, invalid_no_other_pragma_than_compose) { |
| TestLibrary library(R"FIDL( |
| library example; |
| |
| protocol Wrong { |
| not_compose Something; |
| }; |
| |
| )FIDL"); |
| ASSERT_FALSE(library.Compile()); |
| const auto& errors = library.errors(); |
| ASSERT_EQ(errors.size(), 1); |
| ASSERT_ERR(errors[0], fidl::ErrUnrecognizedProtocolMember); |
| } |
| |
| TEST(ProtocolTests, invalid_composed_protocols_have_clashing_names) { |
| TestLibrary library(R"FIDL( |
| library example; |
| |
| protocol A { |
| MethodA(); |
| }; |
| |
| protocol B { |
| compose A; |
| MethodB(); |
| }; |
| |
| protocol C { |
| compose A; |
| MethodC(); |
| }; |
| |
| protocol D { |
| compose B; |
| compose C; |
| MethodD(); |
| MethodA(); |
| }; |
| )FIDL"); |
| ASSERT_FALSE(library.Compile()); |
| const auto& errors = library.errors(); |
| ASSERT_EQ(errors.size(), 1); |
| ASSERT_ERR(errors[0], fidl::ErrDuplicateMethodName); |
| } |
| |
| // See GetGeneratedOrdinal64ForTesting in test_library.h |
| TEST(ProtocolTests, invalid_composed_protocols_have_clashing_ordinals) { |
| TestLibrary library(R"FIDL( |
| library methodhasher; |
| |
| protocol SpecialComposed { |
| ClashOne(); |
| }; |
| |
| protocol Special { |
| compose SpecialComposed; |
| ClashTwo(); |
| }; |
| )FIDL"); |
| ASSERT_FALSE(library.Compile()); |
| const auto& errors = library.errors(); |
| ASSERT_EQ(errors.size(), 1); |
| ASSERT_ERR(errors[0], fidl::ErrDuplicateMethodOrdinal); |
| ASSERT_SUBSTR(errors[0]->msg.c_str(), "ClashTwo_"); |
| } |
| |
| TEST(ProtocolTests, invalid_simple_constraint_applies_to_composed_methods_too) { |
| TestLibrary library(R"FIDL( |
| library example; |
| |
| protocol NotSimple { |
| Complex(vector<uint64> arg); |
| }; |
| |
| [ForDeprecatedCBindings] |
| protocol YearningForSimplicity { |
| compose NotSimple; |
| Simple(); |
| }; |
| )FIDL"); |
| ASSERT_FALSE(library.Compile()); |
| const auto& errors = library.errors(); |
| ASSERT_EQ(errors.size(), 1); |
| ASSERT_ERR(errors[0], fidl::ErrMemberMustBeSimple); |
| ASSERT_SUBSTR(errors[0]->msg.c_str(), "arg"); |
| } |
| |
| TEST(ProtocolTests, invalid_request_must_be_protocol) { |
| TestLibrary library(R"FIDL( |
| library example; |
| |
| struct S {}; |
| protocol P { |
| Method(request<S> r); |
| }; |
| )FIDL"); |
| ASSERT_FALSE(library.Compile()); |
| const auto& errors = library.errors(); |
| ASSERT_EQ(errors.size(), 1); |
| ASSERT_ERR(errors[0], fidl::ErrMustBeAProtocol); |
| } |
| |
| TEST(ProtocolTests, invalid_request_must_be_parameterized) { |
| TestLibrary library(R"FIDL( |
| library example; |
| |
| protocol P { |
| Method(request r); |
| }; |
| )FIDL"); |
| ASSERT_FALSE(library.Compile()); |
| const auto& errors = library.errors(); |
| ASSERT_EQ(errors.size(), 1); |
| ASSERT_ERR(errors[0], fidl::ErrMustBeParameterized); |
| } |
| |
| TEST(ProtocolTests, invalid_request_cannot_have_size) { |
| TestLibrary library(R"FIDL( |
| library example; |
| |
| protocol P {}; |
| struct S { |
| request<P>:0 p; |
| }; |
| )FIDL"); |
| ASSERT_FALSE(library.Compile()); |
| const auto& errors = library.errors(); |
| ASSERT_EQ(errors.size(), 1); |
| ASSERT_ERR(errors[0], fidl::ErrCannotHaveSize); |
| } |
| |
| TEST(ProtocolTests, invalid_duplicate_parameter_name) { |
| TestLibrary library(R"FIDL( |
| library example; |
| |
| protocol P { |
| MethodWithDuplicateParams(uint8 foo, uint8 foo); |
| }; |
| )FIDL"); |
| ASSERT_FALSE(library.Compile()); |
| const auto& errors = library.errors(); |
| ASSERT_EQ(errors.size(), 1); |
| ASSERT_ERR(errors[0], fidl::ErrDuplicateMethodParameterName); |
| } |
| |
| } // namespace |