blob: b6a30894f635937275d2e4539f88b646fa89351f [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 "src/lib/fidl_codec/semantic_parser.h"
#include <iostream>
#include <memory>
#include <sstream>
#include <string>
#include <vector>
#include <gtest/gtest.h>
#include "src/lib/fidl_codec/library_loader.h"
#include "src/lib/fidl_codec/library_loader_test_data.h"
#include "src/lib/fidl_codec/list_test_data.h"
#include "src/lib/fidl_codec/semantic_parser_test.h"
#include "src/lib/fidl_codec/wire_types.h"
namespace fidl_codec {
namespace semantic {
// Checks the semantic parser.
// Checks that we detects errors.
// Checks that we do a good recovery on errors (only a few tests display more than one error).
SemanticParserTest::SemanticParserTest() {
fidl_codec_test::SdkExamples sdk_examples;
fidl_codec_test::FidlcodecExamples other_examples;
// Loads all the files in sdk/core.fidl_json.txt.
for (const auto& element : sdk_examples.map()) {
library_loader_.AddContent(element.second, &err_);
}
// Load all the fidl_codec files.
for (const auto& element : other_examples.map()) {
library_loader_.AddContent(element.second, &err_);
}
}
void SemanticParserTest::SetUp() {}
TEST_F(SemanticParserTest, GlobalExample) {
// Checks that Directory::Open exists in fuchsia.io.
Library* library = library_loader_.GetLibraryFromName("fuchsia.io");
ASSERT_NE(library, nullptr);
library->DecodeTypes();
Protocol* protocol = nullptr;
library->GetProtocolByName("fuchsia.io/Directory", &protocol);
ASSERT_NE(protocol, nullptr);
ProtocolMethod* method = protocol->GetMethodByName("Open");
ASSERT_NE(method, nullptr);
// Checks that we currently don't have any semantic for Open.
ASSERT_EQ(method->semantic(), nullptr);
std::string text =
"library fuchsia.io {\n"
" Directory::Open {\n"
" request.object = handle / request.path;\n"
" }\n"
"}\n"
"library test.fidlcodec.sys {\n"
" Launcher::CreateComponent {\n"
" request.controller = HandleDescription('server-control', request.launch_info.url);\n"
" }\n"
"}\n";
ParserErrors parser_errors;
SemanticParser parser(&library_loader_, text, &parser_errors);
parser.ParseSemantic();
// Checks that we now have the right semantic.
ASSERT_NE(method->semantic(), nullptr);
std::stringstream ss;
method->semantic()->Dump(ss);
std::string result = ss.str();
ASSERT_EQ(result, "request.object = handle / request.path\n");
}
TEST_F(SemanticParserTest, CheckAssignments) {
std::string text =
"request.object = handle / request.path;\n"
"request.foo = handle;\n"
"request.bar = handle / request.other_path;\n"
"request.bar2 = handle : 'cloned';\n";
ParserErrors parser_errors;
SemanticParser parser(&library_loader_, text, &parser_errors);
MethodSemantic semantic;
while (!parser.IsEof()) {
parser.ParseAssignment(&semantic);
}
std::stringstream ss;
semantic.Dump(ss);
std::string result = ss.str();
ASSERT_EQ(result,
"request.object = handle / request.path\n"
"request.foo = handle\n"
"request.bar = handle / request.other_path\n"
"request.bar2 = handle : 'cloned'\n");
}
TEST_F(SemanticParserTest, CheckDisplay) {
std::string text =
" input_field: request.path;\n"
" result: request.object;\n"
" input_field: request.data.size ' bytes';\n"
" input_field: 'buffer of ' request.data.size ' bytes';\n"
" input_field: 'size = ' request.data.size;\n"
"}\n";
ProtocolMethod method;
ParserErrors parser_errors;
SemanticParser parser(&library_loader_, text, &parser_errors);
while (!parser.IsEof()) {
parser.ParseMethod(&method);
}
ASSERT_NE(method.short_display(), nullptr);
std::stringstream ss;
method.short_display()->Dump(ss);
std::string result = ss.str();
ASSERT_EQ(result,
"input_field: request.path;\n"
"input_field: request.data.size \" bytes\";\n"
"input_field: \"buffer of \" request.data.size \" bytes\";\n"
"input_field: \"size = \" request.data.size;\n"
"result: request.object;\n");
}
TEST_F(SemanticParserTest, EmptyText) {
std::string text = "";
std::stringstream error_stream;
ParserErrors parser_errors(error_stream);
SemanticParser parser(&library_loader_, text, &parser_errors);
MethodSemantic semantic;
parser.ParseSemantic();
std::string result = error_stream.str();
ASSERT_EQ(result, "");
}
TEST_F(SemanticParserTest, LibraryExpected) {
std::string text =
"xxx fuchsia.io {\n"
" Directory::Open {\n"
" request.object = handle / request.path;\n"
" }\n"
"}\n";
std::stringstream error_stream;
ParserErrors parser_errors(error_stream);
SemanticParser parser(&library_loader_, text, &parser_errors);
parser.ParseSemantic();
std::string result = error_stream.str();
ASSERT_EQ(result,
"xxx fuchsia.io {\n"
"^\n"
"1:1: Keyword 'library' expected.\n");
}
TEST_F(SemanticParserTest, LibraryNameExpected) {
std::string text =
"library {\n"
" Directory::Open {\n"
" request.object = handle / request.path;\n"
" }\n"
"}\n";
std::stringstream error_stream;
ParserErrors parser_errors(error_stream);
SemanticParser parser(&library_loader_, text, &parser_errors);
parser.ParseSemantic();
std::string result = error_stream.str();
ASSERT_EQ(result,
"library {\n"
" ^\n"
"1:9: Library name expected.\n");
}
TEST_F(SemanticParserTest, LibraryNotFound) {
std::string text =
"library fuchsia.xxx {\n"
" Directory::Open {\n"
" request.object = handle / request.path;\n"
" }\n"
"}\n";
std::stringstream error_stream;
ParserErrors parser_errors(error_stream);
SemanticParser parser(&library_loader_, text, &parser_errors);
parser.ParseSemantic();
std::string result = error_stream.str();
ASSERT_EQ(result,
"library fuchsia.xxx {\n"
" ^\n"
"1:9: Library fuchsia.xxx not found.\n");
}
TEST_F(SemanticParserTest, MissingLeftBrace1) {
std::string text =
"library fuchsia.io\n"
" Directory::Open {\n"
" request.object = handle / request.path;\n"
" }\n"
"}\n";
std::stringstream error_stream;
ParserErrors parser_errors(error_stream);
SemanticParser parser(&library_loader_, text, &parser_errors);
parser.ParseSemantic();
std::string result = error_stream.str();
ASSERT_EQ(result,
" Directory::Open {\n"
" ^\n"
"2:3: Symbol '{' expected.\n");
}
TEST_F(SemanticParserTest, ProtocolNameExpected) {
std::string text =
"library fuchsia.io {\n"
" ::Open {\n"
" request.object = handle / request.path;\n"
" }\n"
"}\n";
std::stringstream error_stream;
ParserErrors parser_errors(error_stream);
SemanticParser parser(&library_loader_, text, &parser_errors);
parser.ParseSemantic();
std::string result = error_stream.str();
ASSERT_EQ(result,
" ::Open {\n"
" ^\n"
"2:3: Protocol name expected.\n");
}
TEST_F(SemanticParserTest, ProtocolNotFound) {
std::string text =
"library fuchsia.io {\n"
" Xxx::Open {\n"
" request.object = handle / request.path;\n"
" }\n"
"}\n";
std::stringstream error_stream;
ParserErrors parser_errors(error_stream);
SemanticParser parser(&library_loader_, text, &parser_errors);
parser.ParseSemantic();
std::string result = error_stream.str();
ASSERT_EQ(result,
" Xxx::Open {\n"
" ^\n"
"2:3: Protocol Xxx not found in library fuchsia.io\n");
}
TEST_F(SemanticParserTest, DoubleColonExpected) {
std::string text =
"library fuchsia.io {\n"
" Directory Open {\n"
" request.object = handle / request.path;\n"
" }\n"
"}\n";
std::stringstream error_stream;
ParserErrors parser_errors(error_stream);
SemanticParser parser(&library_loader_, text, &parser_errors);
parser.ParseSemantic();
std::string result = error_stream.str();
ASSERT_EQ(result,
" Directory Open {\n"
" ^\n"
"2:13: Symbol '::' expected.\n");
}
TEST_F(SemanticParserTest, MethodNameExpected) {
std::string text =
"library fuchsia.io {\n"
" Directory:: {\n"
" request.object = handle / request.path;\n"
" }\n"
"}\n";
std::stringstream error_stream;
ParserErrors parser_errors(error_stream);
SemanticParser parser(&library_loader_, text, &parser_errors);
parser.ParseSemantic();
std::string result = error_stream.str();
ASSERT_EQ(result,
" Directory:: {\n"
" ^\n"
"2:15: Method name expected.\n");
}
TEST_F(SemanticParserTest, MethodNotFound) {
std::string text =
"library fuchsia.io {\n"
" Directory::Xxx {\n"
" request.object = handle / request.path;\n"
" }\n"
"}\n";
std::stringstream error_stream;
ParserErrors parser_errors(error_stream);
SemanticParser parser(&library_loader_, text, &parser_errors);
parser.ParseSemantic();
std::string result = error_stream.str();
ASSERT_EQ(result,
" Directory::Xxx {\n"
" ^\n"
"2:14: Method Xxx not found in protocol fuchsia.io/Directory\n");
}
TEST_F(SemanticParserTest, MissingLeftBrace2) {
std::string text =
"library fuchsia.io {\n"
" Directory::Open\n"
" request.object = handle / request.path;\n"
" }\n"
"}\n";
std::stringstream error_stream;
ParserErrors parser_errors(error_stream);
SemanticParser parser(&library_loader_, text, &parser_errors);
parser.ParseSemantic();
std::string result = error_stream.str();
ASSERT_EQ(result,
" request.object = handle / request.path;\n"
" ^\n"
"3:5: Symbol '{' expected.\n"
"}\n"
"^\n"
"5:1: Keyword 'library' expected.\n");
}
TEST_F(SemanticParserTest, InputFieldColonExpected) {
std::string text =
"library fuchsia.io {\n"
" Directory::Open {\n"
" input_field request.path;\n"
" result: request.object;\n"
" }\n"
"}\n";
std::stringstream error_stream;
ParserErrors parser_errors(error_stream);
SemanticParser parser(&library_loader_, text, &parser_errors);
parser.ParseSemantic();
std::string result = error_stream.str();
ASSERT_EQ(result,
" input_field request.path;\n"
" ^\n"
"3:17: Symbol ':' expected.\n");
}
TEST_F(SemanticParserTest, ResultColonExpected) {
std::string text =
"library fuchsia.io {\n"
" Directory::Open {\n"
" input_field: request.path;\n"
" result request.object;\n"
" }\n"
"}\n";
std::stringstream error_stream;
ParserErrors parser_errors(error_stream);
SemanticParser parser(&library_loader_, text, &parser_errors);
parser.ParseSemantic();
std::string result = error_stream.str();
ASSERT_EQ(result,
" result request.object;\n"
" ^\n"
"4:12: Symbol ':' expected.\n");
}
TEST_F(SemanticParserTest, InputFieldSemiColonExpected) {
std::string text =
"library fuchsia.io {\n"
" Directory::Open {\n"
" input_field: request.path\n"
" result: request.object;\n"
" }\n"
"}\n";
std::stringstream error_stream;
ParserErrors parser_errors(error_stream);
SemanticParser parser(&library_loader_, text, &parser_errors);
parser.ParseSemantic();
std::string result = error_stream.str();
ASSERT_EQ(result,
" result: request.object;\n"
" ^\n"
"4:5: Symbol ';' expected.\n");
}
TEST_F(SemanticParserTest, ResultSemiColonExpected) {
std::string text =
"library fuchsia.io {\n"
" Directory::Open {\n"
" input_field: request.path;\n"
" result: request.object\n"
" }\n"
"}\n";
std::stringstream error_stream;
ParserErrors parser_errors(error_stream);
SemanticParser parser(&library_loader_, text, &parser_errors);
parser.ParseSemantic();
std::string result = error_stream.str();
ASSERT_EQ(result,
" }\n"
" ^\n"
"5:3: Symbol ';' expected.\n");
}
TEST_F(SemanticParserTest, AssignmentExpected) {
std::string text =
"library fuchsia.io {\n"
" Directory::Open {\n"
" = handle / request.path;\n"
" }\n"
"}\n";
std::stringstream error_stream;
ParserErrors parser_errors(error_stream);
SemanticParser parser(&library_loader_, text, &parser_errors);
parser.ParseSemantic();
std::string result = error_stream.str();
ASSERT_EQ(result,
" = handle / request.path;\n"
" ^\n"
"3:5: Assignment expected.\n");
}
TEST_F(SemanticParserTest, FieldNameExpected) {
std::string text =
"library fuchsia.io {\n"
" Directory::Open {\n"
" request. = handle / request.path;\n"
" }\n"
"}\n";
std::stringstream error_stream;
ParserErrors parser_errors(error_stream);
SemanticParser parser(&library_loader_, text, &parser_errors);
parser.ParseSemantic();
std::string result = error_stream.str();
ASSERT_EQ(result,
" request. = handle / request.path;\n"
" ^\n"
"3:14: Field name expected.\n");
}
TEST_F(SemanticParserTest, EqualExpected) {
std::string text =
"library fuchsia.io {\n"
" Directory::Open {\n"
" request.object handle / request.path;\n"
" }\n"
"}\n";
std::stringstream error_stream;
ParserErrors parser_errors(error_stream);
SemanticParser parser(&library_loader_, text, &parser_errors);
parser.ParseSemantic();
std::string result = error_stream.str();
ASSERT_EQ(result,
" request.object handle / request.path;\n"
" ^\n"
"3:20: Symbol '=' expected.\n");
}
TEST_F(SemanticParserTest, ExpressionExpected1) {
std::string text =
"library fuchsia.io {\n"
" Directory::Open {\n"
" request.object =;\n"
" }\n"
"}\n";
std::stringstream error_stream;
ParserErrors parser_errors(error_stream);
SemanticParser parser(&library_loader_, text, &parser_errors);
parser.ParseSemantic();
std::string result = error_stream.str();
ASSERT_EQ(result,
" request.object =;\n"
" ^\n"
"3:21: Expression expected.\n");
}
TEST_F(SemanticParserTest, ExpressionExpected2) {
std::string text =
"library fuchsia.io {\n"
" Directory::Open {\n"
" request.object = handle /;\n"
" }\n"
"}\n";
std::stringstream error_stream;
ParserErrors parser_errors(error_stream);
SemanticParser parser(&library_loader_, text, &parser_errors);
parser.ParseSemantic();
std::string result = error_stream.str();
ASSERT_EQ(result,
" request.object = handle /;\n"
" ^\n"
"3:30: Expression expected.\n");
}
TEST_F(SemanticParserTest, ExpressionExpected3) {
std::string text =
"library fuchsia.io {\n"
" Directory::Open {\n"
" request.object = xxx;\n"
" }\n"
"}\n";
std::stringstream error_stream;
ParserErrors parser_errors(error_stream);
SemanticParser parser(&library_loader_, text, &parser_errors);
parser.ParseSemantic();
std::string result = error_stream.str();
ASSERT_EQ(result,
" request.object = xxx;\n"
" ^\n"
"3:22: Expression expected.\n");
}
TEST_F(SemanticParserTest, SemicolonExpected) {
std::string text =
"library fuchsia.io {\n"
" Directory::Open {\n"
" request.object = handle / request.path\n"
" }\n"
"}\n";
std::stringstream error_stream;
ParserErrors parser_errors(error_stream);
SemanticParser parser(&library_loader_, text, &parser_errors);
parser.ParseSemantic();
std::string result = error_stream.str();
ASSERT_EQ(result,
" }\n"
" ^\n"
"4:3: Symbol ';' expected.\n");
}
TEST_F(SemanticParserTest, HandleDescriptionTypo) {
std::string text =
"library test.fidlcodec.sys {\n"
" Launcher::CreateComponent {\n"
" request.controller = HandleDescriptions('server-control', request.launch_info.url);\n"
" }\n"
"}\n";
std::stringstream error_stream;
ParserErrors parser_errors(error_stream);
SemanticParser parser(&library_loader_, text, &parser_errors);
parser.ParseSemantic();
std::string result = error_stream.str();
ASSERT_EQ(
result,
" request.controller = HandleDescriptions('server-control', request.launch_info.url);\n"
" ^\n"
"3:25: Expression expected.\n");
}
TEST_F(SemanticParserTest, UnterminatedString) {
std::string text =
"library test.fidlcodec.sys {\n"
" Launcher::CreateComponent {\n"
" request.controller = HandleDescription('server-control, request.launch_info.url);\n"
" }\n"
"}\n";
std::stringstream error_stream;
ParserErrors parser_errors(error_stream);
SemanticParser parser(&library_loader_, text, &parser_errors);
parser.ParseSemantic();
std::string result = error_stream.str();
ASSERT_EQ(result,
" request.controller = HandleDescription('server-control, request.launch_info.url);\n"
" ^\n3:43: Unterminated string.\n"
" request.controller = HandleDescription('server-control, request.launch_info.url);\n"
" ^\n3:44: Symbol ',' expected.\n");
}
TEST_F(SemanticParserTest, LeftParenthesisExpected) {
std::string text =
"library test.fidlcodec.sys {\n"
" Launcher::CreateComponent {\n"
" request.controller = HandleDescription 'server-control', request.launch_info.url);\n"
" }\n"
"}\n";
std::stringstream error_stream;
ParserErrors parser_errors(error_stream);
SemanticParser parser(&library_loader_, text, &parser_errors);
parser.ParseSemantic();
std::string result = error_stream.str();
ASSERT_EQ(
result,
" request.controller = HandleDescription 'server-control', request.launch_info.url);\n"
" ^\n"
"3:43: Symbol '(' expected.\n");
}
TEST_F(SemanticParserTest, CommaExpected) {
std::string text =
"library test.fidlcodec.sys {\n"
" Launcher::CreateComponent {\n"
" request.controller = HandleDescription('server-control' request.launch_info.url);\n"
" }\n"
"}\n";
std::stringstream error_stream;
ParserErrors parser_errors(error_stream);
SemanticParser parser(&library_loader_, text, &parser_errors);
parser.ParseSemantic();
std::string result = error_stream.str();
ASSERT_EQ(result,
" request.controller = HandleDescription('server-control' request.launch_info.url);\n"
" ^\n"
"3:60: Symbol ',' expected.\n");
}
TEST_F(SemanticParserTest, RightParenthesisExpected) {
std::string text =
"library test.fidlcodec.sys {\n"
" Launcher::CreateComponent {\n"
" request.controller = HandleDescription('server-control', request.launch_info.url;\n"
" }\n"
"}\n";
std::stringstream error_stream;
ParserErrors parser_errors(error_stream);
SemanticParser parser(&library_loader_, text, &parser_errors);
parser.ParseSemantic();
std::string result = error_stream.str();
ASSERT_EQ(result,
" request.controller = HandleDescription('server-control', request.launch_info.url;\n"
" ^\n"
"3:84: Symbol ')' expected.\n");
}
} // namespace semantic
} // namespace fidl_codec