blob: fe9cc5e6a534e9c0f28c8d7e2ded0bc75566e8c2 [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/formatter.h>
#include <fidl/lexer.h>
#include <fidl/parser.h>
#include <fidl/source_file.h>
#include <fidl/tree_visitor.h>
#include <unittest/unittest.h>
#include <regex>
#include "examples.h"
#include "test_library.h"
namespace {
std::map<std::string, std::string> formatted_output_;
void InitializeContents() {
for (auto element : Examples::map()) {
TestLibrary library(element.first, element.second);
std::unique_ptr<fidl::raw::File> ast;
library.Parse(&ast);
fidl::raw::FormattingTreeVisitor visitor;
visitor.OnFile(ast);
formatted_output_[element.first] = *visitor.formatted_output();
}
}
// Tests that repeatedly applying the formatter results in no change.
bool idempotence_test() {
BEGIN_TEST;
for (auto element : formatted_output_) {
TestLibrary library(element.first, element.second);
std::unique_ptr<fidl::raw::File> ast;
EXPECT_TRUE(library.Parse(&ast));
fidl::raw::FormattingTreeVisitor visitor;
visitor.OnFile(ast);
EXPECT_STR_EQ(element.second.c_str(), visitor.formatted_output()->c_str(),
"Applying formatting multiple times produces different results");
}
END_TEST;
}
bool basic_formatting_rules_test() {
BEGIN_TEST;
std::regex trailing_ws(".*\\s+$");
std::regex top_level_decl("^\\s*(?:struct|enum|union)\\s+.*");
std::regex attribute("\\s*\\[[A-Za-z]+\\]\\s*");
std::regex comment("\\s*//.*");
// Break the output into lines
for (auto element : formatted_output_) {
std::stringstream ss(element.second);
std::string line;
std::vector<std::string> lines;
while (std::getline(ss, line, '\n')) {
lines.push_back(line);
// RULE: No trailing whitespace
ASSERT_FALSE(std::regex_search(line, trailing_ws), "Trailing whitespace found");
// RULE: No tab characters
ASSERT_TRUE(line.find_first_of('\t') == std::string::npos, "Tab character found");
// RULE: 4 space indents (at least)
ASSERT_TRUE(!isspace(line[0]) || line.find_first_of(" ") == 0, "<4 space indent found");
}
// RULE: Separate top-level declarations for struct, enum, and union with one
// blank line.
for (size_t i = 0; i < lines.size(); i++) {
if (std::regex_search(lines[i], top_level_decl)) {
// Just means there is a top-level decl on the first line.
if (i == 0) {
continue;
}
size_t line_to_check = i - 1;
// Back up to before attributes and comments.
while (std::regex_search(lines[line_to_check], attribute) ||
std::regex_search(lines[line_to_check], comment)) {
line_to_check--;
ASSERT_GE(line_to_check, 0);
}
std::string full = lines[i - 1] + lines[i];
ASSERT_EQ(lines[line_to_check].size(), 0, "No blank line found before top level decl");
}
}
// RULE: End the file with exactly one newline (no blank lines at the end).
ASSERT_NE(lines[lines.size() - 1].size(), 0, "No newline at EOF");
}
END_TEST;
}
bool golden_file_test() {
BEGIN_TEST;
std::string good_output;
std::string formatted_bad_output;
for (auto element : Examples::map()) {
if (element.first.find("testdata/goodformat.test.fidl") != std::string::npos) {
good_output = Examples::map()[element.first];
} else if (element.first.find("testdata/badformat.fidl") != std::string::npos) {
formatted_bad_output = formatted_output_[element.first];
}
}
ASSERT_GT(good_output.size(), 0);
ASSERT_GT(formatted_bad_output.size(), 0);
ASSERT_STR_EQ(good_output.c_str(), formatted_bad_output.c_str(),
"Formatting for badformat.fidl looks weird");
END_TEST;
}
} // namespace
BEGIN_TEST_CASE(formatter_tests)
InitializeContents();
RUN_TEST(idempotence_test)
RUN_TEST(basic_formatting_rules_test)
RUN_TEST(golden_file_test)
END_TEST_CASE(formatter_tests)