| // Copyright 2017-2020 The Verible Authors. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| #include "common/analysis/lint_rule_status.h" |
| |
| #include <sstream> // IWYU pragma: keep // for ostringstream |
| #include <string> |
| #include <vector> |
| |
| #include "gtest/gtest.h" |
| #include "absl/strings/str_split.h" |
| #include "absl/strings/string_view.h" |
| #include "common/text/concrete_syntax_tree.h" |
| #include "common/text/token_info.h" |
| #include "common/text/tree_builder_test_util.h" |
| |
| namespace verible { |
| namespace { |
| |
| // Tests initialization of LintRuleStatus. |
| TEST(LintRuleStatusTest, Construction) { |
| std::set<LintViolation> violations; |
| LintRuleStatus status(violations, "RULE_NAME", "http://example.com/svstyle"); |
| EXPECT_TRUE(status.violations.empty()); |
| EXPECT_EQ(status.lint_rule_name, "RULE_NAME"); |
| EXPECT_EQ(status.url, "http://example.com/svstyle"); |
| EXPECT_TRUE(status.isOk()); |
| } |
| |
| // Tests adding violations to LintRuleStatus. |
| TEST(LintRuleStatusTest, ConstructWithViolation) { |
| const TokenInfo token(1, "1bad-id"); |
| std::set<LintViolation> violations({LintViolation(token, "invalid id")}); |
| LintRuleStatus status(violations, "RULE_NAME", "http://example.com/svstyle"); |
| EXPECT_FALSE(status.violations.empty()); |
| EXPECT_FALSE(status.isOk()); |
| } |
| |
| // Tests waiving violations and removing them from LintRuleStatus. |
| TEST(LintRuleStatusTest, WaiveViolations) { |
| const TokenInfo token(1, "1bad-id"); |
| std::set<LintViolation> violations({LintViolation(token, "invalid id")}); |
| LintRuleStatus status(violations, "RULE_NAME", "http://example.com/svstyle"); |
| EXPECT_FALSE(status.violations.empty()); |
| EXPECT_FALSE(status.isOk()); |
| // First, waive nothing. |
| status.WaiveViolations([](const LintViolation&) { return false; }); |
| EXPECT_FALSE(status.violations.empty()); |
| EXPECT_FALSE(status.isOk()); |
| // Second, waive everything. |
| status.WaiveViolations([](const LintViolation&) { return true; }); |
| EXPECT_TRUE(status.violations.empty()); |
| EXPECT_TRUE(status.isOk()); |
| } |
| |
| // Struct for checking expected formatting of a single Lint Violation |
| // Note that the filename produced by formatter is provided by LintStatusTest, |
| // which contains this struct. |
| struct LintViolationTest { |
| std::string reason; |
| TokenInfo token; |
| std::string expected_output; |
| }; |
| |
| // Struct for checking expected formatting of a LintRuleStatus |
| // TODO(b/136092807): leverage SynthesizedLexerTestData to produce |
| // expected findings. |
| struct LintStatusTest { |
| absl::string_view rule_name; |
| std::string url; |
| absl::string_view path; |
| absl::string_view text; |
| std::vector<LintViolationTest> violations; |
| }; |
| |
| void RunLintStatusTest(const LintStatusTest& test) { |
| // Dummy tree so we have something for test cases to point at |
| SymbolPtr root = Node(); |
| |
| LintRuleStatus status; |
| status.url = test.url; |
| status.lint_rule_name = test.rule_name; |
| for (const auto& violation_test : test.violations) { |
| status.violations.insert( |
| LintViolation(violation_test.token, violation_test.reason)); |
| } |
| |
| std::ostringstream ss; |
| |
| LintStatusFormatter formatter(test.text); |
| formatter.FormatLintRuleStatus(&ss, status, test.text, test.path); |
| auto result_parts = absl::StrSplit(ss.str(), '\n'); |
| auto part_iterator = result_parts.begin(); |
| |
| for (const auto& violation_test : test.violations) { |
| EXPECT_EQ(*part_iterator, violation_test.expected_output); |
| part_iterator++; |
| } |
| } |
| |
| TEST(LintRuleStatusFormatterTest, SimpleOutput) { |
| SymbolPtr root = Node(); |
| static const int dont_care_tag = 0; |
| constexpr absl::string_view text( |
| "This is some code\n" |
| "That you are looking at right now\n" |
| "It is nice code, make no mistake\n" |
| "Very nice"); |
| LintStatusTest test = { |
| "test-rule", |
| "http://foobar", |
| "some/path/to/somewhere.fvg", |
| text, |
| {{"reason1", TokenInfo(dont_care_tag, text.substr(0, 5)), |
| "some/path/to/somewhere.fvg:1:1: reason1 http://foobar [test-rule]"}, |
| {"reason2", TokenInfo(dont_care_tag, text.substr(21, 4)), |
| "some/path/to/somewhere.fvg:2:4: reason2 http://foobar [test-rule]"}}}; |
| |
| RunLintStatusTest(test); |
| } |
| |
| TEST(LintRuleStatusFormatterTest, NoOutput) { |
| SymbolPtr root = Node(); |
| LintStatusTest test = {"cool-rule", |
| "http://example.com/svstyle", |
| "some/path/to/somewhere.fvg", |
| "This is some code\n" |
| "That you are looking at right now\n" |
| "It is nice code, make no mistake\n" |
| "Very nice", |
| {}}; |
| |
| RunLintStatusTest(test); |
| } |
| |
| void RunLintStatusesTest(const LintStatusTest& test) { |
| // Dummy tree so we have something for test cases to point at |
| SymbolPtr root = Node(); |
| |
| std::vector<LintRuleStatus> statuses; |
| LintRuleStatus status0; |
| status0.url = test.url; |
| status0.lint_rule_name = test.rule_name; |
| |
| LintRuleStatus status1; |
| status1.url = test.url; |
| status1.lint_rule_name = test.rule_name; |
| |
| ASSERT_EQ(test.violations.size(), 2); |
| |
| // Insert the violations in the wrong order |
| status0.violations.insert( |
| LintViolation(test.violations[1].token, test.violations[1].reason)); |
| |
| status1.violations.insert( |
| LintViolation(test.violations[0].token, test.violations[0].reason)); |
| |
| statuses.push_back(status0); |
| statuses.push_back(status1); |
| |
| std::ostringstream ss; |
| |
| LintStatusFormatter formatter(test.text); |
| formatter.FormatLintRuleStatuses(&ss, statuses, test.text, test.path); |
| auto result_parts = absl::StrSplit(ss.str(), '\n'); |
| auto part_iterator = result_parts.begin(); |
| |
| for (const auto& violation_test : test.violations) { |
| EXPECT_EQ(*part_iterator, violation_test.expected_output); |
| part_iterator++; |
| } |
| } |
| |
| TEST(LintRuleStatusFormatterTest, MultipleStatusesSimpleOutput) { |
| SymbolPtr root = Node(); |
| static const int dont_care_tag = 0; |
| constexpr absl::string_view text( |
| "This is some code\n" |
| "That you are looking at right now\n" |
| "It is nice code, make no mistake\n" |
| "Very nice"); |
| LintStatusTest test = { |
| "test-rule", |
| "http://foobar", |
| "some/path/to/somewhere.fvg", |
| text, |
| {{"reason1", TokenInfo(dont_care_tag, text.substr(0, 5)), |
| "some/path/to/somewhere.fvg:1:1: reason1 http://foobar [test-rule]"}, |
| {"reason2", TokenInfo(dont_care_tag, text.substr(21, 4)), |
| "some/path/to/somewhere.fvg:2:4: reason2 http://foobar [test-rule]"}}}; |
| |
| RunLintStatusesTest(test); |
| } |
| |
| } // namespace |
| } // namespace verible |