blob: cfb4906a223aae5e670e8ba3b5679a62c6e2a146 [file] [log] [blame]
// 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