| // 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) |