| // 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 "verilog/analysis/verilog_linter_configuration.h" |
| |
| #include <cstddef> |
| #include <iosfwd> |
| #include <map> |
| #include <string> |
| #include <type_traits> |
| #include <utility> |
| #include <vector> |
| |
| #include "gmock/gmock.h" |
| #include "gtest/gtest.h" |
| #include "absl/strings/string_view.h" |
| #include "common/analysis/line_lint_rule.h" |
| #include "common/analysis/lint_rule_status.h" |
| #include "common/analysis/syntax_tree_lint_rule.h" |
| #include "common/analysis/text_structure_lint_rule.h" |
| #include "common/analysis/token_stream_lint_rule.h" |
| #include "common/strings/line_column_map.h" |
| #include "common/text/concrete_syntax_leaf.h" |
| #include "common/text/concrete_syntax_tree.h" |
| #include "common/text/syntax_tree_context.h" |
| #include "common/text/text_structure.h" |
| #include "common/text/token_info.h" |
| #include "common/text/tree_builder_test_util.h" |
| #include "verilog/analysis/default_rules.h" |
| #include "verilog/analysis/descriptions.h" |
| #include "verilog/analysis/lint_rule_registry.h" |
| #include "verilog/analysis/verilog_linter.h" |
| |
| namespace verilog { |
| namespace { |
| |
| using verible::LineLintRule; |
| using verible::SyntaxTreeLintRule; |
| using verible::TextStructureLintRule; |
| using verible::TextStructureView; |
| using verible::TokenStreamLintRule; |
| |
| using testing::IsEmpty; |
| using testing::SizeIs; |
| |
| class TestRuleBase : public SyntaxTreeLintRule { |
| public: |
| void HandleLeaf(const verible::SyntaxTreeLeaf& leaf, |
| const verible::SyntaxTreeContext& context) override {} |
| void HandleNode(const verible::SyntaxTreeNode& node, |
| const verible::SyntaxTreeContext& context) override {} |
| verible::LintRuleStatus Report() const override { |
| return verible::LintRuleStatus(); |
| } |
| }; |
| |
| class TestRule1 : public TestRuleBase { |
| public: |
| using rule_type = SyntaxTreeLintRule; |
| static absl::string_view Name() { return "test-rule-1"; } |
| static std::string GetDescription(analysis::DescriptionType) { |
| return "TestRule1"; |
| } |
| }; |
| |
| class TestRule2 : public TestRuleBase { |
| public: |
| using rule_type = SyntaxTreeLintRule; |
| static absl::string_view Name() { return "test-rule-2"; } |
| static std::string GetDescription(analysis::DescriptionType) { |
| return "TestRule2"; |
| } |
| }; |
| |
| class TestRule3 : public TokenStreamLintRule { |
| public: |
| using rule_type = TokenStreamLintRule; |
| static absl::string_view Name() { return "test-rule-3"; } |
| |
| static std::string GetDescription(analysis::DescriptionType) { |
| return "TestRule3"; |
| } |
| |
| void HandleToken(const verible::TokenInfo&) override {} |
| |
| verible::LintRuleStatus Report() const override { |
| return verible::LintRuleStatus(); |
| } |
| }; |
| |
| class TestRule4 : public LineLintRule { |
| public: |
| using rule_type = LineLintRule; |
| static absl::string_view Name() { return "test-rule-4"; } |
| |
| static std::string GetDescription(analysis::DescriptionType) { |
| return "TestRule4"; |
| } |
| |
| void HandleLine(absl::string_view) override {} |
| |
| verible::LintRuleStatus Report() const override { |
| return verible::LintRuleStatus(); |
| } |
| }; |
| |
| class TestRule5 : public TextStructureLintRule { |
| public: |
| using rule_type = TextStructureLintRule; |
| static absl::string_view Name() { return "test-rule-5"; } |
| |
| static std::string GetDescription(analysis::DescriptionType) { |
| return "TestRule1"; |
| } |
| |
| void Lint(const TextStructureView&, absl::string_view) override {} |
| |
| verible::LintRuleStatus Report() const override { |
| return verible::LintRuleStatus(); |
| } |
| }; |
| |
| VERILOG_REGISTER_LINT_RULE(TestRule1); |
| VERILOG_REGISTER_LINT_RULE(TestRule2); |
| VERILOG_REGISTER_LINT_RULE(TestRule3); |
| VERILOG_REGISTER_LINT_RULE(TestRule4); |
| VERILOG_REGISTER_LINT_RULE(TestRule5); |
| |
| // Dummy text structure with a single empty root node for syntax tree. |
| class FakeTextStructureView : public TextStructureView { |
| public: |
| FakeTextStructureView() : TextStructureView("") { |
| syntax_tree_ = verible::Node(); |
| } |
| }; |
| |
| // Don't care about line numbers for these tests. |
| static const verible::LineColumnMap dummy_map(""); |
| |
| // Don't care about file name for these tests. |
| static const char filename[] = ""; |
| |
| TEST(ProjectPolicyTest, MatchesAnyPath) { |
| struct TestCase { |
| ProjectPolicy policy; |
| absl::string_view filename; |
| const char* expected_match; |
| }; |
| const TestCase kTestCases[] = { |
| {{"policyX", {}, {}, {}, {}, {}}, "filename", nullptr}, |
| {{"policyX", {"file"}, {}, {}, {}, {}}, "filename", "file"}, |
| {{"policyX", {"not-a-match"}, {}, {}, {}, {}}, "filename", nullptr}, |
| {{"policyX", {"xxxx", "yyyy"}, {}, {}, {}, {}}, "file/name.txt", nullptr}, |
| {{"policyX", {"xxxx", "name"}, {}, {}, {}, {}}, "file/name.txt", "name"}, |
| {{"policyX", {"xxxx", "file"}, {}, {}, {}, {}}, "file/name.txt", "file"}, |
| {{"policyX", {"name", "file"}, {}, {}, {}, {}}, "file/name.txt", "name"}, |
| }; |
| for (const auto& test : kTestCases) { |
| const char* match = test.policy.MatchesAnyPath(test.filename); |
| if (test.expected_match != nullptr) { |
| EXPECT_EQ(absl::string_view(match), test.expected_match); |
| } else { |
| EXPECT_EQ(match, nullptr); |
| } |
| } |
| } |
| |
| TEST(ProjectPolicyTest, MatchesAnyExclusions) { |
| struct TestCase { |
| ProjectPolicy policy; |
| absl::string_view filename; |
| const char* expected_match; |
| }; |
| const TestCase kTestCases[] = { |
| {{"policyX", {}, {}, {}, {}, {}}, "filename", nullptr}, |
| {{"policyX", {}, {"file"}, {}, {}, {}}, "filename", "file"}, |
| {{"policyX", {}, {"not-a-match"}, {}, {}, {}}, "filename", nullptr}, |
| {{"policyX", {}, {"xxxx", "yyyy"}, {}, {}, {}}, "file/name.txt", nullptr}, |
| {{"policyX", {}, {"xxxx", "name"}, {}, {}, {}}, "file/name.txt", "name"}, |
| {{"policyX", {}, {"xxxx", "file"}, {}, {}, {}}, "file/name.txt", "file"}, |
| {{"policyX", {}, {"name", "file"}, {}, {}, {}}, "file/name.txt", "name"}, |
| }; |
| for (const auto& test : kTestCases) { |
| const char* match = test.policy.MatchesAnyExclusions(test.filename); |
| if (test.expected_match != nullptr) { |
| EXPECT_EQ(absl::string_view(match), test.expected_match); |
| } else { |
| EXPECT_EQ(match, nullptr); |
| } |
| } |
| } |
| |
| TEST(ProjectPolicyTest, IsValid) { |
| const std::pair<ProjectPolicy, bool> kTestCases[] = { |
| {{"policyX", {"path"}, {}, {"owner"}, {"test-rule-1"}, {}}, true}, |
| {{"policyX", {"path"}, {}, {"owner"}, {}, {"test-rule-1"}}, true}, |
| {{"policyX", {"path"}, {}, {"owner"}, {"test-rule-1"}, {"test-rule-2"}}, |
| true}, |
| {{"policyX", {"path"}, {}, {"owner"}, {"not-a-test-rule"}, {}}, false}, |
| {{"policyX", {"path"}, {}, {"owner"}, {}, {"not-a-test-rule"}}, false}, |
| {{"policyX", |
| {"path"}, |
| {}, |
| {"owner"}, |
| {"test-rule-1", "not-a-test-rule"}, |
| {}}, |
| false}, |
| {{"policyX", |
| {"path"}, |
| {}, |
| {"owner"}, |
| {}, |
| {"not-a-test-rule", "test-rule-1"}}, |
| false}, |
| }; |
| for (const auto& test : kTestCases) { |
| EXPECT_EQ(test.first.IsValid(), test.second); |
| } |
| } |
| |
| TEST(ProjectPolicyTest, ListPathGlobs) { |
| const std::pair<ProjectPolicy, absl::string_view> kTestCases[] = { |
| {{"policyX", {}, {}, {}, {}, {}}, ""}, |
| {{"policyX", {"path"}, {}, {}, {}, {}}, "*path*"}, |
| {{"policyX", {"path1", "path2"}, {}, {}, {}, {}}, "*path1* | *path2*"}, |
| {{"policyX", {"pa/th1", "pa/th2"}, {}, {}, {}, {}}, |
| "*pa/th1* | *pa/th2*"}, |
| }; |
| for (const auto& test : kTestCases) { |
| EXPECT_EQ(test.first.ListPathGlobs(), test.second); |
| } |
| } |
| |
| // Confirms that each syntax tree rule yields a set of results. |
| TEST(VerilogSyntaxTreeLinterConfigurationTest, AddsExpectedNumber) { |
| LinterConfiguration config; |
| EXPECT_FALSE(config.RuleIsOn("test-rule-1")); |
| EXPECT_FALSE(config.RuleIsOn("test-rule-2")); |
| |
| config.TurnOn("test-rule-1"); |
| EXPECT_TRUE(config.RuleIsOn("test-rule-1")); |
| EXPECT_FALSE(config.RuleIsOn("test-rule-2")); |
| |
| config.TurnOn("test-rule-2"); |
| EXPECT_TRUE(config.RuleIsOn("test-rule-1")); |
| EXPECT_TRUE(config.RuleIsOn("test-rule-2")); |
| EXPECT_THAT(config.ActiveRuleIds(), SizeIs(2)); |
| |
| VerilogLinter linter; |
| EXPECT_TRUE(linter.Configure(config, filename).ok()); |
| FakeTextStructureView text_structure; |
| linter.Lint(text_structure, filename); |
| |
| auto status = linter.ReportStatus(dummy_map, text_structure.Contents()); |
| EXPECT_THAT(status, SizeIs(2)); |
| } |
| |
| // Confirms that each token stream rule yields a set of results. |
| TEST(VerilogTokenStreamLinterConfigurationTest, AddsExpectedNumber) { |
| LinterConfiguration config; |
| EXPECT_FALSE(config.RuleIsOn("test-rule-3")); |
| config.TurnOn("test-rule-3"); |
| EXPECT_TRUE(config.RuleIsOn("test-rule-3")); |
| EXPECT_THAT(config.ActiveRuleIds(), SizeIs(1)); |
| |
| VerilogLinter linter; |
| EXPECT_TRUE(linter.Configure(config, filename).ok()); |
| FakeTextStructureView text_structure; |
| linter.Lint(text_structure, filename); |
| |
| auto status = linter.ReportStatus(dummy_map, text_structure.Contents()); |
| EXPECT_THAT(status, SizeIs(1)); |
| } |
| |
| // Confirms that each line-based rule yields a set of results. |
| TEST(VerilogLineLinterConfigurationTest, AddsExpectedNumber) { |
| LinterConfiguration config; |
| EXPECT_FALSE(config.RuleIsOn("test-rule-4")); |
| config.TurnOn("test-rule-4"); |
| EXPECT_TRUE(config.RuleIsOn("test-rule-4")); |
| EXPECT_THAT(config.ActiveRuleIds(), SizeIs(1)); |
| |
| VerilogLinter linter; |
| EXPECT_TRUE(linter.Configure(config, filename).ok()); |
| FakeTextStructureView text_structure; |
| linter.Lint(text_structure, filename); |
| |
| auto status = linter.ReportStatus(dummy_map, text_structure.Contents()); |
| EXPECT_THAT(status, SizeIs(1)); |
| } |
| |
| // Confirms that each text-structure rule yields a set of results. |
| TEST(VerilogTextStructureLinterConfigurationTest, AddsExpectedNumber) { |
| LinterConfiguration config; |
| EXPECT_FALSE(config.RuleIsOn("test-rule-5")); |
| config.TurnOn("test-rule-5"); |
| EXPECT_TRUE(config.RuleIsOn("test-rule-5")); |
| EXPECT_THAT(config.ActiveRuleIds(), SizeIs(1)); |
| |
| VerilogLinter linter; |
| EXPECT_TRUE(linter.Configure(config, filename).ok()); |
| FakeTextStructureView text_structure; |
| linter.Lint(text_structure, filename); |
| |
| auto status = linter.ReportStatus(dummy_map, text_structure.Contents()); |
| EXPECT_THAT(status, SizeIs(1)); |
| } |
| |
| // Verifies that turning on-off rules works. |
| TEST(VerilogSyntaxTreeLinterConfigurationTest, TurnOnTurnOff) { |
| LinterConfiguration config; |
| EXPECT_THAT(config.ActiveRuleIds(), IsEmpty()); |
| config.TurnOn("test-rule-1"); |
| EXPECT_TRUE(config.RuleIsOn("test-rule-1")); |
| config.TurnOff("test-rule-1"); |
| EXPECT_FALSE(config.RuleIsOn("test-rule-1")); |
| EXPECT_THAT(config.ActiveRuleIds(), IsEmpty()); |
| |
| VerilogLinter linter; |
| EXPECT_TRUE(linter.Configure(config, filename).ok()); |
| FakeTextStructureView text_structure; |
| linter.Lint(text_structure, filename); |
| |
| auto status = linter.ReportStatus(dummy_map, text_structure.Contents()); |
| EXPECT_THAT(status, IsEmpty()); |
| } |
| |
| TEST(LinterConfigurationTest, ComparisonOperatorSameElement) { |
| LinterConfiguration config1, config2; |
| EXPECT_EQ(config1, config2); |
| config1.TurnOn("rule-x"); |
| EXPECT_NE(config1, config2); |
| config2.TurnOn("rule-x"); |
| EXPECT_EQ(config1, config2); |
| config1.TurnOff("rule-x"); |
| EXPECT_NE(config1, config2); |
| config2.TurnOff("rule-x"); |
| EXPECT_EQ(config1, config2); |
| } |
| |
| TEST(LinterConfigurationTest, ComparisonSameDifferentElement) { |
| LinterConfiguration config1, config2; |
| config1.TurnOn("rule-x"); |
| EXPECT_NE(config1, config2); |
| config2.TurnOn("rule-y"); |
| EXPECT_NE(config1, config2); |
| config1.TurnOff("rule-x"); |
| EXPECT_NE(config1, config2); |
| config2.TurnOff("rule-y"); |
| EXPECT_EQ(config1, config2); |
| } |
| |
| TEST(LinterConfigurationTest, StreamOperator) { |
| LinterConfiguration config; |
| { |
| std::ostringstream stream; |
| stream << config; |
| EXPECT_EQ(stream.str(), "{ }"); |
| } |
| config.TurnOn("rule-abc"); |
| { |
| std::ostringstream stream; |
| stream << config; |
| EXPECT_EQ(stream.str(), "{ rule-abc }"); |
| } |
| config.TurnOn("rule-xyz"); |
| { |
| std::ostringstream stream; |
| stream << config; |
| EXPECT_EQ(stream.str(), "{ rule-abc, rule-xyz }"); |
| } |
| config.TurnOff("rule-abc"); |
| { |
| std::ostringstream stream; |
| stream << config; |
| EXPECT_EQ(stream.str(), "{ rule-xyz }"); |
| } |
| config.TurnOff("rule-xyz"); |
| { |
| std::ostringstream stream; |
| stream << config; |
| EXPECT_EQ(stream.str(), "{ }"); |
| } |
| } |
| |
| TEST(VerilogSyntaxTreeLinterConfigurationTest, DefaultEmpty) { |
| LinterConfiguration config; |
| EXPECT_THAT(config.ActiveRuleIds(), IsEmpty()); |
| |
| VerilogLinter linter; |
| EXPECT_TRUE(linter.Configure(config, filename).ok()); |
| FakeTextStructureView text_structure; |
| linter.Lint(text_structure, filename); |
| |
| auto status = linter.ReportStatus(dummy_map, text_structure.Contents()); |
| EXPECT_THAT(status, IsEmpty()); |
| } |
| |
| TEST(VerilogSyntaxTreeLinterConfigurationTest, UseRuleSetAll) { |
| LinterConfiguration config; |
| config.UseRuleSet(RuleSet::kAll); |
| |
| auto expected_size = analysis::RegisteredSyntaxTreeRulesNames().size() + |
| analysis::RegisteredTokenStreamRulesNames().size() + |
| analysis::RegisteredTextStructureRulesNames().size() + |
| analysis::RegisteredLineRulesNames().size(); |
| EXPECT_THAT(config.ActiveRuleIds(), SizeIs(expected_size)); |
| |
| VerilogLinter linter; |
| EXPECT_TRUE(linter.Configure(config, filename).ok()); |
| FakeTextStructureView text_structure; |
| linter.Lint(text_structure, filename); |
| |
| auto status = linter.ReportStatus(dummy_map, text_structure.Contents()); |
| EXPECT_THAT(status, SizeIs(expected_size)); |
| } |
| |
| TEST(VerilogSyntaxTreeLinterConfigurationTest, UseRuleSetNone) { |
| LinterConfiguration config; |
| config.UseRuleSet(RuleSet::kNone); |
| EXPECT_THAT(config.ActiveRuleIds(), IsEmpty()); |
| |
| VerilogLinter linter; |
| EXPECT_TRUE(linter.Configure(config, filename).ok()); |
| FakeTextStructureView text_structure; |
| linter.Lint(text_structure, filename); |
| |
| auto status = linter.ReportStatus(dummy_map, text_structure.Contents()); |
| EXPECT_THAT(status, IsEmpty()); |
| } |
| |
| TEST(VerilogSyntaxTreeLinterConfigurationTest, NoneResets) { |
| LinterConfiguration config; |
| config.TurnOn("test-rule-1"); |
| config.TurnOn("test-rule-2"); |
| config.TurnOn("test-rule-3"); |
| config.TurnOn("test-rule-4"); |
| config.UseRuleSet(RuleSet::kNone); |
| EXPECT_THAT(config.ActiveRuleIds(), IsEmpty()); |
| |
| VerilogLinter linter; |
| EXPECT_TRUE(linter.Configure(config, filename).ok()); |
| FakeTextStructureView text_structure; |
| linter.Lint(text_structure, filename); |
| |
| auto status = linter.ReportStatus(dummy_map, text_structure.Contents()); |
| EXPECT_THAT(status, IsEmpty()); |
| } |
| |
| TEST(VerilogSyntaxTreeLinterConfigurationTest, UseRuleSetDefault) { |
| LinterConfiguration config; |
| config.UseRuleSet(RuleSet::kDefault); |
| |
| VerilogLinter linter; |
| EXPECT_TRUE(linter.Configure(config, filename).ok()); |
| FakeTextStructureView text_structure; |
| linter.Lint(text_structure, filename); |
| |
| auto status = linter.ReportStatus(dummy_map, text_structure.Contents()); |
| auto expected_size = std::extent<decltype(analysis::kDefaultRuleSet)>::value; |
| EXPECT_THAT(config.ActiveRuleIds(), SizeIs(expected_size)); |
| EXPECT_THAT(status, SizeIs(expected_size)); |
| } |
| |
| // Tests that empty policy doesn't cause any change in configuration. |
| TEST(LinterConfigurationUseProjectPolicyTest, BlankPolicyBlankFilename) { |
| LinterConfiguration config, default_config; |
| ProjectPolicy policy; |
| config.UseProjectPolicy(policy, ""); |
| EXPECT_EQ(config, default_config); |
| } |
| |
| // Test single rule can be enabled with path matching. |
| TEST(LinterConfigurationUseProjectPolicyTest, EnableRule) { |
| LinterConfiguration config; |
| ProjectPolicy policy{"policyX", {"path"}, {}, {"owner"}, {}, {"wanted-rule"}}; |
| EXPECT_FALSE(config.RuleIsOn("wanted-rule")); |
| config.UseProjectPolicy(policy, "some/path/foo"); |
| EXPECT_TRUE(config.RuleIsOn("wanted-rule")); |
| } |
| |
| // Test that rule is not enabled because path does not match. |
| TEST(LinterConfigurationUseProjectPolicyTest, EnableFilePathNotMatched) { |
| LinterConfiguration config; |
| ProjectPolicy policy{"policyX", {"not-gonna-match"}, {}, {"owner"}, |
| {}, {"wanted-rule"}}; |
| EXPECT_FALSE(config.RuleIsOn("wanted-rule")); |
| config.UseProjectPolicy(policy, "some/path/foo"); |
| EXPECT_FALSE(config.RuleIsOn("wanted-rule")); |
| } |
| |
| // Test single rule can be disabled with path matching. |
| TEST(LinterConfigurationUseProjectPolicyTest, DisableRule) { |
| LinterConfiguration config; |
| config.TurnOn("unwanted-rule"); |
| ProjectPolicy policy{"policyX", {"path"}, {}, |
| {"owner"}, {"unwanted-rule"}, {}}; |
| EXPECT_TRUE(config.RuleIsOn("unwanted-rule")); |
| config.UseProjectPolicy(policy, "some/path/foo"); |
| EXPECT_FALSE(config.RuleIsOn("unwanted-rule")); |
| } |
| |
| // Test that rule remains enabled because path does not match. |
| TEST(LinterConfigurationUseProjectPolicyTest, DisableRulePathNotMatched) { |
| LinterConfiguration config; |
| config.TurnOn("unwanted-rule"); |
| ProjectPolicy policy{"policyX", {"does-not-match"}, {}, |
| {"owner"}, {"unwanted-rule"}, {}}; |
| EXPECT_TRUE(config.RuleIsOn("unwanted-rule")); |
| config.UseProjectPolicy(policy, "some/path/foo"); |
| EXPECT_TRUE(config.RuleIsOn("unwanted-rule")); |
| } |
| |
| // Test that enabling a rule takes precedence over disabling. |
| TEST(LinterConfigurationUseProjectPolicyTest, EnableRuleWins) { |
| LinterConfiguration config; |
| // Same rule is disabled and enabled. |
| ProjectPolicy policy{"policyX", {"path"}, {}, |
| {"owner"}, {"wanted-rule"}, {"wanted-rule"}}; |
| EXPECT_FALSE(config.RuleIsOn("wanted-rule")); |
| config.UseProjectPolicy(policy, "some/path/foo"); |
| EXPECT_TRUE(config.RuleIsOn("wanted-rule")); |
| } |
| |
| // |
| // Tests for parse/unparse on RuleSet |
| // |
| TEST(RuleSetTest, ParseRuleSetSuccess) { |
| std::string none_text = "none"; |
| std::string all_text = "all"; |
| std::string default_text = "default"; |
| |
| std::string none_error = ""; |
| std::string all_error = ""; |
| std::string default_error = ""; |
| |
| RuleSet none_destination, all_destination, default_destination; |
| |
| bool none_result = AbslParseFlag(none_text, &none_destination, &none_error); |
| bool all_result = AbslParseFlag(all_text, &all_destination, &all_error); |
| bool default_result = |
| AbslParseFlag(default_text, &default_destination, &default_error); |
| |
| EXPECT_TRUE(none_result); |
| EXPECT_EQ(none_error, ""); |
| EXPECT_EQ(none_destination, RuleSet::kNone); |
| |
| EXPECT_TRUE(all_result); |
| EXPECT_EQ(all_error, ""); |
| EXPECT_EQ(all_destination, RuleSet::kAll); |
| |
| EXPECT_TRUE(default_result); |
| EXPECT_EQ(default_error, ""); |
| EXPECT_EQ(default_destination, RuleSet::kDefault); |
| } |
| |
| TEST(RuleSetTest, ParseRuleSetError) { |
| std::string bad_text = "fdsfdfds"; |
| std::string error = ""; |
| |
| RuleSet rule_result; |
| bool result = AbslParseFlag(bad_text, &rule_result, &error); |
| EXPECT_FALSE(result); |
| EXPECT_NE(error, ""); |
| } |
| |
| TEST(RuleSetTest, UnparseRuleSetSuccess) { |
| EXPECT_EQ("none", AbslUnparseFlag(RuleSet::kNone)); |
| EXPECT_EQ("default", AbslUnparseFlag(RuleSet::kDefault)); |
| EXPECT_EQ("all", AbslUnparseFlag(RuleSet::kAll)); |
| } |
| |
| // |
| // Tests for parse / unparse on RuleBundle |
| // |
| TEST(RuleBundleTest, UnparseRuleBundleSeveral) { |
| RuleBundle bundle = {{{"flag1", {true, ""}}, {"flag2", {true, ""}}}}; |
| std::string expected_comma = "flag2,flag1"; |
| std::string expected_newline = "flag2\nflag1"; |
| |
| std::string result_comma = bundle.UnparseConfiguration(','); |
| EXPECT_EQ(result_comma, expected_comma); |
| |
| std::string result_newline = bundle.UnparseConfiguration('\n'); |
| EXPECT_EQ(result_newline, expected_newline); |
| } |
| |
| TEST(RuleBundleTest, UnparseRuleBundleSeveralTurnOff) { |
| RuleBundle bundle = {{{"flag1", {false, ""}}, {"flag2", {true, ""}}}}; |
| std::string expected_comma = "flag2,-flag1"; |
| std::string expected_newline = "flag2\n-flag1"; |
| |
| std::string result_comma = bundle.UnparseConfiguration(','); |
| EXPECT_EQ(result_comma, expected_comma); |
| |
| std::string result_newline = bundle.UnparseConfiguration('\n'); |
| EXPECT_EQ(result_newline, expected_newline); |
| } |
| |
| TEST(RuleBundleTest, UnparseRuleBundleSeveralConfiguration) { |
| RuleBundle bundle = {{{"flag1", {false, "foo"}}, {"flag2", {true, "bar"}}}}; |
| std::string expected_comma = "flag2=bar,-flag1=foo"; |
| std::string expected_newline = "flag2=bar\n-flag1=foo"; |
| |
| std::string result_comma = bundle.UnparseConfiguration(','); |
| EXPECT_EQ(result_comma, expected_comma); |
| |
| std::string result_newline = bundle.UnparseConfiguration('\n'); |
| EXPECT_EQ(result_newline, expected_newline); |
| } |
| |
| TEST(RuleBundleTest, UnparseRuleBundleEmpty) { |
| RuleBundle bundle = {}; |
| std::string expected = ""; |
| |
| std::string result_comma = bundle.UnparseConfiguration(','); |
| EXPECT_EQ(result_comma, expected); |
| |
| std::string result_newline = bundle.UnparseConfiguration('\n'); |
| EXPECT_EQ(result_newline, expected); |
| } |
| |
| TEST(RuleBundleTest, ParseRuleBundleEmpty) { |
| std::string text = ""; |
| RuleBundle bundle; |
| std::string error; |
| bool success = bundle.ParseConfiguration(text, ',', &error); |
| EXPECT_TRUE(success) << error; |
| EXPECT_TRUE(error.empty()); |
| EXPECT_TRUE(bundle.rules.empty()); |
| } |
| |
| TEST(RuleBundleTest, ParseRuleBundleAcceptSeveral) { |
| // Allow for an optional '+' to enable a rule for symmetry with '-' disable |
| std::string text = "test-rule-1,test-rule-2,+test-rule-3"; |
| RuleBundle bundle; |
| std::string error; |
| bool success = bundle.ParseConfiguration(text, ',', &error); |
| ASSERT_TRUE(success) << error; |
| ASSERT_THAT(bundle.rules, SizeIs(3)); |
| EXPECT_TRUE(error.empty()); |
| EXPECT_TRUE(bundle.rules["test-rule-1"].enabled); |
| EXPECT_TRUE(bundle.rules["test-rule-2"].enabled); |
| EXPECT_TRUE(bundle.rules["test-rule-3"].enabled); |
| } |
| |
| TEST(RuleBundleTest, ParseRuleBundleAcceptConfiguration) { |
| auto text = "test-rule-1=foo,test-rule-2=,test-rule-3,-test-rule-4=bar"; |
| RuleBundle bundle; |
| std::string error; |
| bool success = bundle.ParseConfiguration(text, ',', &error); |
| ASSERT_TRUE(success) << error; |
| ASSERT_THAT(bundle.rules, SizeIs(4)); |
| EXPECT_TRUE(error.empty()); |
| |
| EXPECT_TRUE(bundle.rules["test-rule-1"].enabled); |
| EXPECT_EQ("foo", bundle.rules["test-rule-1"].configuration); |
| |
| EXPECT_TRUE(bundle.rules["test-rule-2"].enabled); |
| EXPECT_TRUE(bundle.rules["test-rule-2"].configuration.empty()); |
| |
| EXPECT_TRUE(bundle.rules["test-rule-3"].enabled); |
| EXPECT_TRUE(bundle.rules["test-rule-3"].configuration.empty()); |
| |
| EXPECT_FALSE(bundle.rules["test-rule-4"].enabled); |
| EXPECT_EQ("bar", bundle.rules["test-rule-4"].configuration); |
| } |
| |
| TEST(RuleBundleTest, ParseRuleBundleAcceptOne) { |
| std::string text = "test-rule-1"; |
| RuleBundle bundle; |
| std::string error; |
| bool success = bundle.ParseConfiguration(text, ',', &error); |
| EXPECT_TRUE(error.empty()); |
| ASSERT_TRUE(success) << error; |
| ASSERT_THAT(bundle.rules, SizeIs(1)); |
| EXPECT_TRUE(bundle.rules["test-rule-1"].enabled); |
| } |
| |
| TEST(RuleBundleTest, ParseRuleWhitespaceAroundAllowed) { |
| std::string text = "\t test-rule-1 \t, +test-rule-2=foo:bar \t"; |
| RuleBundle bundle; |
| std::string error; |
| bool success = bundle.ParseConfiguration(text, ',', &error); |
| EXPECT_TRUE(error.empty()); |
| ASSERT_TRUE(success) << error; |
| ASSERT_THAT(bundle.rules, SizeIs(2)); |
| EXPECT_TRUE(bundle.rules["test-rule-1"].enabled); |
| EXPECT_TRUE(bundle.rules["test-rule-2"].enabled); |
| EXPECT_EQ("foo:bar", bundle.rules["test-rule-2"].configuration); |
| } |
| |
| TEST(RuleBundleTest, ParseRuleBundleAcceptSeveralTurnOff) { |
| std::string text = "test-rule-1,-test-rule-2"; |
| RuleBundle bundle; |
| std::string error; |
| bool success = bundle.ParseConfiguration(text, ',', &error); |
| ASSERT_TRUE(success) << error; |
| ASSERT_THAT(bundle.rules, SizeIs(2)); |
| EXPECT_TRUE(error.empty()); |
| EXPECT_TRUE(bundle.rules["test-rule-1"].enabled); |
| EXPECT_FALSE(bundle.rules["test-rule-2"].enabled); |
| } |
| |
| TEST(RuleBundleTest, ParseRuleBundleAcceptOneTurnOff) { |
| std::string text = "-test-rule-1"; |
| RuleBundle bundle; |
| std::string error; |
| bool success = bundle.ParseConfiguration(text, ',', &error); |
| ASSERT_TRUE(success) << error; |
| ASSERT_THAT(bundle.rules, SizeIs(1)); |
| EXPECT_TRUE(error.empty()); |
| EXPECT_FALSE(bundle.rules["test-rule-1"].enabled); |
| } |
| |
| TEST(RuleBundleTest, ParseRuleBundleReject) { |
| std::string text = "test-rule-1,bad-flag"; |
| RuleBundle bundle; |
| std::string error; |
| bool success = bundle.ParseConfiguration(text, ',', &error); |
| EXPECT_FALSE(success); |
| EXPECT_EQ(error, "invalid flag \"bad-flag\""); |
| } |
| |
| TEST(RuleBundleTest, ParseRuleBundleAcceptMultiline) { |
| std::string text = "test-rule-1\n-test-rule-2"; |
| RuleBundle bundle; |
| std::string error; |
| bool success = bundle.ParseConfiguration(text, '\n', &error); |
| ASSERT_TRUE(success) << error; |
| ASSERT_THAT(bundle.rules, SizeIs(2)); |
| EXPECT_TRUE(error.empty()); |
| EXPECT_TRUE(bundle.rules["test-rule-1"].enabled); |
| EXPECT_FALSE(bundle.rules["test-rule-2"].enabled); |
| } |
| |
| TEST(RuleBundleTest, ParseRuleBundleRejectMultiline) { |
| std::string text = "test-rule-1\nbad-flag\n-test-rule-2"; |
| RuleBundle bundle; |
| std::string error; |
| bool success = bundle.ParseConfiguration(text, '\n', &error); |
| EXPECT_FALSE(success); |
| EXPECT_EQ(error, "invalid flag \"bad-flag\""); |
| } |
| |
| TEST(RuleBundleTest, ParseRuleBundleSkipComments) { |
| const std::string text = |
| " # some comment after whitespace\n" |
| "# more comment\n" |
| "test-rule-1\n" |
| "-test-rule-2 # some comment\n" |
| "+test-rule-3=bar:baz # config-comment\n"; |
| { |
| RuleBundle bundle; |
| std::string error; |
| bool success = bundle.ParseConfiguration(text, '\n', &error); |
| ASSERT_TRUE(success) << error; |
| ASSERT_THAT(bundle.rules, SizeIs(3)); |
| EXPECT_TRUE(error.empty()); |
| EXPECT_TRUE(bundle.rules["test-rule-1"].enabled); |
| EXPECT_FALSE(bundle.rules["test-rule-2"].enabled); |
| EXPECT_TRUE(bundle.rules["test-rule-3"].enabled); |
| EXPECT_EQ("bar:baz", bundle.rules["test-rule-3"].configuration); |
| } |
| } |
| |
| // ConfigureFromOptions Tests |
| TEST(ConfigureFromOptionsTest, Basic) { |
| LinterConfiguration config; |
| |
| LinterOptions options = {.ruleset = RuleSet::kAll, |
| .rules = RuleBundle(), |
| .config_file = "-", |
| .config_file_is_custom = false, |
| .rules_config_search = false, |
| .linting_start_file = "filename", |
| .waiver_files = "filename"}; |
| |
| auto status = config.ConfigureFromOptions(options); |
| EXPECT_TRUE(status.ok()); |
| } |
| |
| TEST(ConfigureFromOptionsTest, RulesNumber) { |
| LinterConfiguration config; |
| |
| LinterOptions options = {.ruleset = RuleSet::kAll, |
| .rules = RuleBundle(), |
| .config_file = "-", |
| .config_file_is_custom = false, |
| .rules_config_search = false, |
| .linting_start_file = "filename", |
| .waiver_files = "filename"}; |
| |
| auto status = config.ConfigureFromOptions(options); |
| EXPECT_TRUE(status.ok()); |
| |
| // Should enable all rules because uses kAll ruleset and an empty rulebundle |
| auto expected_size = analysis::RegisteredSyntaxTreeRulesNames().size() + |
| analysis::RegisteredTokenStreamRulesNames().size() + |
| analysis::RegisteredTextStructureRulesNames().size() + |
| analysis::RegisteredLineRulesNames().size(); |
| EXPECT_THAT(config.ActiveRuleIds(), SizeIs(expected_size)); |
| } |
| |
| TEST(ConfigureFromOptionsTest, RulesSelective) { |
| LinterConfiguration config; |
| |
| RuleBundle bundle = { |
| {{analysis::RegisteredSyntaxTreeRulesNames()[0], {false, ""}}}}; |
| |
| LinterOptions options = {.ruleset = RuleSet::kAll, |
| .rules = bundle, |
| .config_file = "-", |
| .config_file_is_custom = false, |
| .rules_config_search = false, |
| .linting_start_file = "filename", |
| .waiver_files = "filename"}; |
| |
| auto status = config.ConfigureFromOptions(options); |
| EXPECT_TRUE(status.ok()); |
| |
| // Should enable all rules - 1 because uses kAll ruleset and a rulebundle |
| // with one rule disabled |
| auto expected_size = analysis::RegisteredSyntaxTreeRulesNames().size() + |
| analysis::RegisteredTokenStreamRulesNames().size() + |
| analysis::RegisteredTextStructureRulesNames().size() + |
| analysis::RegisteredLineRulesNames().size() - 1; |
| |
| EXPECT_THAT(config.ActiveRuleIds(), SizeIs(expected_size)); |
| } |
| // TODO: LinterOptions could be refactored to store the content |
| // of the configuration files. After this is made it will be possible to |
| // test the configuration that is applied after reading the files. |
| |
| } // namespace |
| } // namespace verilog |