blob: 0febe4fd3f44008434e8c8608fc6149b76f7a22d [file] [log] [blame]
// 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.
// This tests the VerilogLinter class and its associated functions, end-to-end.
//
// Tests for individual lint rules can be found in
// verilog/analysis/checkers/.
#include "verilog/analysis/verilog_linter.h"
#include <algorithm>
#include <array>
#include <fstream>
#include <iterator>
#include <memory>
#include <sstream> // IWYU pragma: keep // for ostringstream
#include <string>
#include <utility>
#include <vector>
#include "absl/status/status.h"
#include "absl/status/statusor.h"
#include "absl/strings/match.h"
#include "absl/strings/string_view.h"
#include "common/analysis/violation_handler.h"
#include "common/util/file_util.h"
#include "common/util/logging.h"
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "verilog/analysis/default_rules.h"
#include "verilog/analysis/verilog_analyzer.h"
#include "verilog/analysis/verilog_linter_configuration.h"
namespace verilog {
namespace {
using ::testing::EndsWith;
using ::testing::StartsWith;
using verible::ViolationFixer;
using verible::ViolationPrinter;
using verible::file::GetContents;
using verible::file::testing::ScopedTestFile;
class DefaultLinterConfigTestFixture {
public:
// Test code using the default rule set.
DefaultLinterConfigTestFixture() : config_() {
config_.UseRuleSet(RuleSet::kDefault);
}
protected:
LinterConfiguration config_;
};
class LintOneFileTest : public DefaultLinterConfigTestFixture,
public testing::Test {
public:
LintOneFileTest() = default;
};
// Tests that nonexistent file is handled as a fatal error.
TEST_F(LintOneFileTest, FileNotFound) {
std::ostringstream output;
ViolationPrinter violation_printer(&output);
const int exit_code =
LintOneFile(&output, "FileNotFound.sv", config_, &violation_printer, true,
false, false, false);
EXPECT_EQ(exit_code, 2);
}
// Tests that clean code exits 0 (success).
TEST_F(LintOneFileTest, LintCleanFiles) {
constexpr absl::string_view kTestCases[] = {
"", // empty file
"\n",
"class foo;\n"
"endclass : foo\n",
};
for (const auto test_code : kTestCases) {
const ScopedTestFile temp_file(testing::TempDir(), test_code);
{
std::ostringstream output;
ViolationPrinter violation_printer(&output);
const int exit_code =
LintOneFile(&output, temp_file.filename(), config_,
&violation_printer, true, false, false, false);
EXPECT_EQ(exit_code, 0);
EXPECT_TRUE(output.str().empty()); // silence
}
{ // enable additional error context printing
std::ostringstream output;
ViolationPrinter violation_printer(&output);
const int exit_code =
LintOneFile(&output, temp_file.filename(), config_,
&violation_printer, true, false, false, true);
EXPECT_EQ(exit_code, 0);
EXPECT_TRUE(output.str().empty()); // silence
}
}
}
// Tests that invalid code is handled according to 'parse_fatal' parameter.
TEST_F(LintOneFileTest, SyntaxError) {
constexpr absl::string_view kTestCases[] = {
"class foo;\n", // no endclass
"endclass : foo\n", // no begin class
"module 444bad_name; endmodule\n", // lexical error
};
for (const auto test_code : kTestCases) {
const ScopedTestFile temp_file(testing::TempDir(), test_code);
{ // continue even with syntax error
std::ostringstream output;
ViolationPrinter violation_printer(&output);
const int exit_code =
LintOneFile(&output, temp_file.filename(), config_,
&violation_printer, true, false, false, false);
EXPECT_EQ(exit_code, 0);
EXPECT_FALSE(output.str().empty());
}
{ // continue even with syntax error with additional error context
std::ostringstream output;
ViolationPrinter violation_printer(&output);
const int exit_code =
LintOneFile(&output, temp_file.filename(), config_,
&violation_printer, true, false, false, true);
EXPECT_EQ(exit_code, 0);
EXPECT_FALSE(output.str().empty());
}
{ // abort on syntax error
std::ostringstream output;
ViolationPrinter violation_printer(&output);
const int exit_code =
LintOneFile(&output, temp_file.filename(), config_,
&violation_printer, true, true, false, false);
EXPECT_EQ(exit_code, 1);
EXPECT_FALSE(output.str().empty());
}
{ // ignore syntax error
std::ostringstream output;
ViolationPrinter violation_printer(&output);
const int exit_code =
LintOneFile(&output, temp_file.filename(), config_,
&violation_printer, false, false, false, false);
EXPECT_EQ(exit_code, 0);
EXPECT_TRUE(output.str().empty()); // silence
}
}
}
TEST_F(LintOneFileTest, LintError) {
constexpr absl::string_view kTestCases[] = {
"task automatic foo;\n"
" $psprintf(\"blah\");\n" // forbidden function
"endtask\n",
};
for (const auto test_code : kTestCases) {
const ScopedTestFile temp_file(testing::TempDir(), test_code);
{ // continue even with lint error
std::ostringstream output;
ViolationPrinter violation_printer(&output);
const int exit_code =
LintOneFile(&output, temp_file.filename(), config_,
&violation_printer, true, false, false, false);
EXPECT_EQ(exit_code, 0) << "output:\n" << output.str();
EXPECT_FALSE(output.str().empty());
}
{ // abort on lint error
std::ostringstream output;
ViolationPrinter violation_printer(&output);
const int exit_code =
LintOneFile(&output, temp_file.filename(), config_,
&violation_printer, true, false, true, false);
EXPECT_EQ(exit_code, 1) << "output:\n" << output.str();
EXPECT_FALSE(output.str().empty());
}
}
}
class VerilogLinterTest : public DefaultLinterConfigTestFixture,
public testing::Test {
public:
// Test code using the default rule set.
VerilogLinterTest() = default;
protected:
// Returns diagnostic text from analyzing source code.
std::pair<absl::Status, std::string> LintAnalyzeText(
absl::string_view filename, absl::string_view content) const {
// Run the analyzer to produce a syntax tree from source code.
const auto analyzer = std::make_unique<VerilogAnalyzer>(content, filename);
const absl::Status status = ABSL_DIE_IF_NULL(analyzer)->Analyze();
std::ostringstream diagnostics;
if (!status.ok()) {
bool with_diagnostic_contex = false;
const std::vector<std::string> syntax_error_messages(
analyzer->LinterTokenErrorMessages(with_diagnostic_contex));
for (const auto& message : syntax_error_messages) {
diagnostics << message << std::endl;
}
with_diagnostic_contex = true;
const std::vector<std::string> syntax_error_messages_with_context(
analyzer->LinterTokenErrorMessages(with_diagnostic_contex));
for (const auto& message : syntax_error_messages_with_context) {
diagnostics << message << std::endl;
}
}
const auto& text_structure = analyzer->Data();
// For testing purposes we want the status returned to reflect
// lint success, so as long as we have a syntax tree (even if there
// are errors), run the lint checks.
const absl::StatusOr<std::vector<verible::LintRuleStatus>> lint_result =
VerilogLintTextStructure(filename, config_, text_structure);
verilog::ViolationPrinter violation_printer(&diagnostics);
const std::set<verible::LintViolationWithStatus> violations =
GetSortedViolations(lint_result.value());
violation_printer.HandleViolations(violations, text_structure.Contents(),
filename);
return {lint_result.status(), diagnostics.str()};
}
};
// This test verifies that VerilogLintTextStructure runs on an empty tree.
TEST_F(VerilogLinterTest, AnonymousEmptyTree) {
const auto diagnostics = LintAnalyzeText("", "");
EXPECT_TRUE(diagnostics.first.ok());
EXPECT_EQ(diagnostics.second, "");
}
// This test verifies that VerilogLintTextStructure runs on complete source,
// that is lint-clean.
TEST_F(VerilogLinterTest, NoLintViolation) {
const auto diagnostics = LintAnalyzeText("good.sv",
"task automatic foo;\n"
" $display(\"blah\");\n"
"endtask\n");
EXPECT_TRUE(diagnostics.first.ok());
EXPECT_EQ(diagnostics.second, "");
}
// This test verifies that VerilogLintTextStructure runs on complete source,
// with one syntax tree lint finding.
TEST_F(VerilogLinterTest, KnownTreeLintViolation) {
const auto diagnostics = LintAnalyzeText("bad.sv",
"task automatic foo;\n"
" $psprintf(\"blah\");\n"
"endtask\n");
EXPECT_TRUE(diagnostics.first.ok());
const auto expected =
"bad.sv:2:3-11: $psprintf is a forbidden system function "
"or task, please use $sformatf instead";
EXPECT_THAT(diagnostics.second, StartsWith(expected));
EXPECT_THAT(diagnostics.second, EndsWith("[invalid-system-task-function]\n"));
}
// This test verifies that VerilogLintTextStructure runs on complete source,
// with one syntax tree lint finding that is waived (next-line).
TEST_F(VerilogLinterTest, KnownTreeLintViolationWaivedNextLine) {
const auto diagnostics =
LintAnalyzeText("bad.sv",
"task automatic foo;\n"
" // verilog_lint: waive invalid-system-task-function\n"
" $psprintf(\"blah\");\n"
"endtask\n");
EXPECT_TRUE(diagnostics.first.ok());
EXPECT_EQ(diagnostics.second, "");
}
// This test verifies that VerilogLintTextStructure runs on complete source,
// with one syntax tree lint finding that is waived (same-line).
TEST_F(VerilogLinterTest, KnownTreeLintViolationWaivedSameLine) {
const auto diagnostics =
LintAnalyzeText("bad.sv",
"task automatic foo;\n"
" $psprintf(\"blah\"); // verilog_lint: waive "
"invalid-system-task-function\n"
"endtask\n");
EXPECT_TRUE(diagnostics.first.ok());
EXPECT_EQ(diagnostics.second, "");
}
// This test verifies that VerilogLintTextStructure runs on complete source,
// with one syntax tree lint finding that is waived (line-range).
TEST_F(VerilogLinterTest, KnownTreeLintViolationWaivedLineRange) {
const auto diagnostics = LintAnalyzeText(
"bad.sv",
"task automatic foo;\n"
" // verilog_lint: waive-start invalid-system-task-function\n"
" $psprintf(\"blah\");\n"
" // verilog_lint: waive-end invalid-system-task-function\n"
"endtask\n");
EXPECT_TRUE(diagnostics.first.ok());
EXPECT_EQ(diagnostics.second, "");
}
// This test verifies that VerilogLintTextStructure runs on complete source,
// with one token stream lint finding.
TEST_F(VerilogLinterTest, KnownTokenStreamLintViolation) {
using analysis::kDefaultRuleSet;
// TODO(fangism): Remove this conditional check or choose a different
// token-stream based lint rule that is enabled by default.
// (Just so happens that we may not want endif-comment enabled by default.)
if (std::find(std::begin(kDefaultRuleSet), std::end(kDefaultRuleSet),
"endif-comment") != std::end(kDefaultRuleSet)) {
const auto diagnostics = LintAnalyzeText("endif.sv",
"`ifdef SIM\n"
"module foo;\n"
"endmodule\n"
"`endif\n");
static const auto expect_message =
"endif.sv:4:1: `endif should be followed on the same line by a "
"comment that matches the opening `ifdef/`ifndef. (SIM) ";
EXPECT_TRUE(diagnostics.first.ok());
EXPECT_THAT(diagnostics.second, StartsWith(expect_message));
EXPECT_THAT(diagnostics.second, EndsWith("[endif-comment]\n"));
}
}
// This test verifies that VerilogLintTextStructure runs on complete source,
// with one line-lint-rule finding.
TEST_F(VerilogLinterTest, KnownLineLintViolation) {
const auto diagnostics = LintAnalyzeText("tab.sv",
"`include \"blah.svh\";\n"
"\n"
"module\ttab;\n" // bad tab here
"endmodule\n");
EXPECT_TRUE(diagnostics.first.ok());
EXPECT_THAT(diagnostics.second,
StartsWith("tab.sv:3:7: Use spaces, not tabs."));
EXPECT_THAT(diagnostics.second, EndsWith("[no-tabs]\n"));
}
// This test verifies that VerilogLintTextStructure runs on complete source,
// with one text structure lint rule finding (line-length).
TEST_F(VerilogLinterTest, KnownTextStructureLintViolation) {
const auto diagnostics = LintAnalyzeText(
"long.sv",
"module long;\n"
"initial xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx = "
"yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy[777777777777];\n"
"endmodule\n");
EXPECT_TRUE(diagnostics.first.ok());
EXPECT_THAT(diagnostics.second,
StartsWith("long.sv:2:101-114: Line length exceeds "
"max: 100; is: 114"));
EXPECT_THAT(diagnostics.second, EndsWith("[line-length]\n"));
}
// This test verifies that VerilogLintTextStructure runs on complete source,
// with one waived lint rule finding (line-length).
TEST_F(VerilogLinterTest, KnownTextStructureLintViolationWaived) {
const auto diagnostics = LintAnalyzeText(
"long.sv",
"module long;\n"
"initial xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx = "
"yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy[777777777777]; "
"// verilog_lint: waive line-length\n"
"endmodule\n");
EXPECT_TRUE(diagnostics.first.ok());
EXPECT_EQ(diagnostics.second, "");
}
// This test verifies that VerilogLintTextStructure runs on a module-body
// source, with one lint rule finding (line-length).
TEST_F(VerilogLinterTest, ModuleBodyLineLength) {
const auto diagnostics = LintAnalyzeText(
"module-body.sv",
"// verilog_syntax: parse-as-module-body\n"
"\n"
"initial xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx = "
"yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy[777777777777];\n");
EXPECT_TRUE(diagnostics.first.ok());
EXPECT_THAT(
diagnostics.second,
StartsWith("module-body.sv:3:101-114: Line length exceeds max: "));
EXPECT_THAT(diagnostics.second, EndsWith("[line-length]\n"));
}
// This test verifies that VerilogLintTextStructure runs on a module-body
// source, with one waived lint rule finding (line-length).
TEST_F(VerilogLinterTest, ModuleBodyLineLengthWaived) {
const auto diagnostics = LintAnalyzeText(
"module-body.sv",
"// verilog_syntax: parse-as-module-body\n"
"\n"
"initial xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx = "
"yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy[777777777777]; "
"// verilog_lint: waive line-length\n");
EXPECT_TRUE(diagnostics.first.ok());
EXPECT_EQ(diagnostics.second, "");
}
TEST_F(VerilogLinterTest, MultiByteUTF8CharactersAreOnlyCountedOnce) {
// Typical comment that might be found in verilog: some ASCII-art diagram
// except that the 'ˉ'-'overscore' is actually a two-byte UTF8 character.
constexpr char comment_with_utf8[] =
"module utf8_short;\n"
R"(initial a = 42; // __/ˉˉˉˉˉˉˉˉˉ\___/ˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉˉ\___/ˉˉˉˉˉ)"
"\nendmodule\n";
const auto diagnostics = LintAnalyzeText("utf8_short.sv", comment_with_utf8);
EXPECT_TRUE(diagnostics.first.ok());
EXPECT_EQ(diagnostics.second, "");
}
TEST(VerilogLinterDocumentationTest, AllRulesHelpDescriptions) {
std::ostringstream stream;
verilog::GetLintRuleDescriptionsHelpFlag(&stream, "all");
// Spot-check a few patterns, must mostly make sure generation
// works without any fatal errors.
EXPECT_TRUE(absl::StrContains(stream.str(), "line-length"));
EXPECT_TRUE(absl::StrContains(stream.str(), "posix-eof"));
EXPECT_TRUE(absl::StrContains(stream.str(), "Enabled by default:"));
}
TEST(VerilogLinterDocumentationTest, AllRulesMarkdown) {
std::ostringstream stream;
verilog::GetLintRuleDescriptionsMarkdown(&stream);
// Spot-check a few patterns, must mostly make sure generation
// works without any fatal errors.
EXPECT_TRUE(absl::StrContains(stream.str(), "line-length"));
EXPECT_TRUE(absl::StrContains(stream.str(), "posix-eof"));
EXPECT_TRUE(absl::StrContains(stream.str(), "Enabled by default:"));
}
class ViolationFixerTest : public testing::Test {
public:
ViolationFixerTest() : config_() {
config_.UseRuleSet(RuleSet::kNone);
config_.TurnOn("forbid-consecutive-null-statements");
config_.TurnOn("no-trailing-spaces");
config_.TurnOn("posix-eof");
}
protected:
LinterConfiguration config_;
absl::Status LintAnalyzeFixText(absl::string_view content,
ViolationFixer& violation_fixer,
std::string* fixed_content) const {
const ScopedTestFile temp_file(testing::TempDir(), content);
// Run the analyzer to produce a syntax tree from source code.
const auto analyzer =
std::make_unique<VerilogAnalyzer>(content, temp_file.filename());
const absl::Status status = ABSL_DIE_IF_NULL(analyzer)->Analyze();
const auto& text_structure = analyzer->Data();
const absl::StatusOr<std::vector<verible::LintRuleStatus>> lint_result =
VerilogLintTextStructure(temp_file.filename(), config_, text_structure);
const std::set<verible::LintViolationWithStatus> violations =
GetSortedViolations(lint_result.value());
violation_fixer.HandleViolations(violations, text_structure.Contents(),
temp_file.filename());
const auto ok = GetContents(temp_file.filename(), fixed_content);
return lint_result.status();
}
void DoFixerTest(
std::initializer_list<ViolationFixer::Answer> choices,
std::initializer_list<absl::string_view> expected_fixed_sources) const {
static constexpr std::array<const absl::string_view, 3> input_sources{
// Input source 0:
// :2:10: no-trailing-spaces
// :3:10: forbid-consecutive-null-statements
// :4:10: forbid-consecutive-null-statements
// :4:11: no-trailing-spaces
// :5:10: forbid-consecutive-null-statements
// :6:10: forbid-consecutive-null-statements
// :7:10: no-trailing-spaces
// :7:14: posix-eof
"module Autofix; \n"
" wire a;;\n"
" wire b;; \n"
" wire c;;\n"
" wire d;;\n"
"endmodule ",
// Input source 1:
// (no issues)
"module AutofixTwo;\n"
"endmodule\n",
// Input source 2:
// :1:21: forbid-consecutive-null-statements
// :2:10: no-trailing-spaces
"module AutofixThree;;\n"
" wire a; \n"
"endmodule\n",
};
EXPECT_EQ(expected_fixed_sources.size(), input_sources.size());
std::initializer_list<ViolationFixer::Answer>::iterator choice_it;
const ViolationFixer::AnswerChooser answer_chooser =
[&choice_it, &choices](const verible::LintViolation&,
absl::string_view) {
EXPECT_NE(choice_it, choices.end())
<< "AnswerChooser called more times than expected.";
return *choice_it++;
};
// In-place fixing
{
choice_it = choices.begin();
// intentionally unopened, diagnostics are discarded
std::ofstream diagnostics;
ViolationFixer violation_fixer(&diagnostics, nullptr, answer_chooser);
std::vector<std::string> fixed_sources(input_sources.size());
for (size_t i = 0; i < input_sources.size(); ++i) {
const absl::string_view input_source = input_sources[i];
std::string& fixed_source = fixed_sources[i];
const absl::Status status =
LintAnalyzeFixText(input_source, violation_fixer, &fixed_source);
EXPECT_TRUE(status.ok());
}
EXPECT_EQ(choice_it, choices.end())
<< "AnswerChooser called fewer times than expected.";
for (size_t i = 0; i < input_sources.size(); ++i) {
const std::string& fixed_source = fixed_sources[i];
const absl::string_view expected_fixed_source =
*(expected_fixed_sources.begin() + i);
EXPECT_EQ(fixed_source, expected_fixed_source);
}
}
// Patch generation
{
choice_it = choices.begin();
// intentionally unopened, diagnostics are discarded
std::ofstream diagnostics;
std::ostringstream patch;
ViolationFixer violation_fixer(&diagnostics, &patch, answer_chooser);
std::vector<std::string> fixed_sources(input_sources.size());
for (size_t i = 0; i < input_sources.size(); ++i) {
const absl::string_view input_source = input_sources[i];
std::string& fixed_source = fixed_sources[i];
const absl::Status status =
LintAnalyzeFixText(input_source, violation_fixer, &fixed_source);
EXPECT_TRUE(status.ok());
}
EXPECT_EQ(choice_it, choices.end())
<< "AnswerChooser called fewer times than expected.";
bool expect_empty_patch = true;
for (size_t i = 0; i < input_sources.size(); ++i) {
const absl::string_view input_source = input_sources[i];
const std::string& fixed_source = fixed_sources[i];
const absl::string_view expected_fixed_source =
*(expected_fixed_sources.begin() + i);
EXPECT_EQ(input_source, fixed_source);
if (input_source != expected_fixed_source) {
expect_empty_patch = false;
}
}
EXPECT_EQ(patch.str().empty(), expect_empty_patch);
}
}
};
TEST_F(ViolationFixerTest, ApplyAll) {
DoFixerTest(
{
{ViolationFixer::AnswerChoice::kApplyAll, 0},
},
{
"module Autofix;\n"
" wire a;\n"
" wire b;\n"
" wire c;\n"
" wire d;\n"
"endmodule\n",
"module AutofixTwo;\n"
"endmodule\n",
"module AutofixThree;\n"
" wire a;\n"
"endmodule\n",
});
}
TEST_F(ViolationFixerTest, RejectAll) {
DoFixerTest(
{
{ViolationFixer::AnswerChoice::kRejectAll, 0},
},
{
"module Autofix; \n"
" wire a;;\n"
" wire b;; \n"
" wire c;;\n"
" wire d;;\n"
"endmodule ",
"module AutofixTwo;\n"
"endmodule\n",
"module AutofixThree;;\n"
" wire a; \n"
"endmodule\n",
});
}
TEST_F(ViolationFixerTest, Reject) {
DoFixerTest(
{
{ViolationFixer::AnswerChoice::kReject, 0},
{ViolationFixer::AnswerChoice::kApplyAll, 0},
},
{
"module Autofix; \n"
" wire a;\n"
" wire b;\n"
" wire c;\n"
" wire d;\n"
"endmodule\n",
"module AutofixTwo;\n"
"endmodule\n",
"module AutofixThree;\n"
" wire a;\n"
"endmodule\n",
});
}
TEST_F(ViolationFixerTest, Apply) {
DoFixerTest(
{
{ViolationFixer::AnswerChoice::kApply, 0},
{ViolationFixer::AnswerChoice::kRejectAll, 0},
},
{
"module Autofix;\n"
" wire a;;\n"
" wire b;; \n"
" wire c;;\n"
" wire d;;\n"
"endmodule ",
"module AutofixTwo;\n"
"endmodule\n",
"module AutofixThree;;\n"
" wire a; \n"
"endmodule\n",
});
}
TEST_F(ViolationFixerTest, ApplyAllForRule) {
DoFixerTest(
{
// Input source 0:
// :2:10: no-trailing-spaces
{ViolationFixer::AnswerChoice::kApplyAllForRule},
// :3:10: forbid-consecutive-null-statements
{ViolationFixer::AnswerChoice::kReject},
// :4:10: forbid-consecutive-null-statements
{ViolationFixer::AnswerChoice::kReject},
// :4:11: no-trailing-spaces
// AUTOMATICALLY APPLIED due to kApplyAllForRule
// :5:10: forbid-consecutive-null-statements
{ViolationFixer::AnswerChoice::kReject},
// :6:10: forbid-consecutive-null-statements
{ViolationFixer::AnswerChoice::kReject},
// :7:10: no-trailing-spaces
// AUTOMATICALLY APPLIED due to kApplyAllForRule
// :7:14: posix-eof
{ViolationFixer::AnswerChoice::kReject},
// Input source 2:
// :1:21: forbid-consecutive-null-statements
{ViolationFixer::AnswerChoice::kReject},
// :2:10: no-trailing-spaces
// AUTOMATICALLY APPLIED due to kApplyAllForRule
},
{
"module Autofix;\n"
" wire a;;\n"
" wire b;;\n"
" wire c;;\n"
" wire d;;\n"
"endmodule",
"module AutofixTwo;\n"
"endmodule\n",
"module AutofixThree;;\n"
" wire a;\n"
"endmodule\n",
});
}
TEST_F(ViolationFixerTest, RejectAllForRule) {
DoFixerTest(
{
// Input source 0:
// :2:10: no-trailing-spaces
{ViolationFixer::AnswerChoice::kRejectAllForRule},
// :3:10: forbid-consecutive-null-statements
{ViolationFixer::AnswerChoice::kApply},
// :4:10: forbid-consecutive-null-statements
{ViolationFixer::AnswerChoice::kApply},
// :4:11: no-trailing-spaces
// AUTOMATICALLY REJECTED due to kApplyAllForRule
// :5:10: forbid-consecutive-null-statements
{ViolationFixer::AnswerChoice::kApply},
// :6:10: forbid-consecutive-null-statements
{ViolationFixer::AnswerChoice::kApply},
// :7:10: no-trailing-spaces
// AUTOMATICALLY REJECTED due to kApplyAllForRule
// :7:14: posix-eof
{ViolationFixer::AnswerChoice::kApply},
// Input source 2:
// :1:21: forbid-consecutive-null-statements
{ViolationFixer::AnswerChoice::kApply},
// :2:10: no-trailing-spaces
// AUTOMATICALLY REJECTED due to kApplyAllForRule
},
{
"module Autofix; \n"
" wire a;\n"
" wire b; \n"
" wire c;\n"
" wire d;\n"
"endmodule \n",
"module AutofixTwo;\n"
"endmodule\n",
"module AutofixThree;\n"
" wire a; \n"
"endmodule\n",
});
}
TEST_F(ViolationFixerTest, RejectAllForRuleApplyAllForRule) {
DoFixerTest(
{
// Input source 0:
// :2:10: no-trailing-spaces
{ViolationFixer::AnswerChoice::kRejectAllForRule},
// :3:10: forbid-consecutive-null-statements
{ViolationFixer::AnswerChoice::kApplyAllForRule},
// :4:10: forbid-consecutive-null-statements
// AUTOMATICALLY APPLIED due to kApplyAllForRule
// :4:11: no-trailing-spaces
// AUTOMATICALLY REJECTED due to kApplyAllForRule
// :5:10: forbid-consecutive-null-statements
// AUTOMATICALLY APPLIED due to kApplyAllForRule
// :6:10: forbid-consecutive-null-statements
// AUTOMATICALLY APPLIED due to kApplyAllForRule
// :7:10: no-trailing-spaces
// AUTOMATICALLY REJECTED due to kApplyAllForRule
// :7:14: posix-eof
{ViolationFixer::AnswerChoice::kReject},
// Input source 2:
// :1:21: forbid-consecutive-null-statements
// AUTOMATICALLY APPLIED due to kApplyAllForRule
// :2:10: no-trailing-spaces
// AUTOMATICALLY REJECTED due to kApplyAllForRule
},
{
"module Autofix; \n"
" wire a;\n"
" wire b; \n"
" wire c;\n"
" wire d;\n"
"endmodule ",
"module AutofixTwo;\n"
"endmodule\n",
"module AutofixThree;\n"
" wire a; \n"
"endmodule\n",
});
}
TEST_F(ViolationFixerTest, PrintFix) {
// Just checks that kPrintFix doesn't affect choices
DoFixerTest(
{
// Input source 0:
// :2:10: no-trailing-spaces
{ViolationFixer::AnswerChoice::kApply},
{ViolationFixer::AnswerChoice::kPrintFix},
{ViolationFixer::AnswerChoice::kPrintFix},
// :3:10: forbid-consecutive-null-statements
{ViolationFixer::AnswerChoice::kReject},
// :4:10: forbid-consecutive-null-statements
{ViolationFixer::AnswerChoice::kReject},
{ViolationFixer::AnswerChoice::kPrintFix},
// :4:11: no-trailing-spaces
{ViolationFixer::AnswerChoice::kApply},
{ViolationFixer::AnswerChoice::kPrintFix},
// :5:10: forbid-consecutive-null-statements
{ViolationFixer::AnswerChoice::kApply},
// :6:10: forbid-consecutive-null-statements
{ViolationFixer::AnswerChoice::kApply},
{ViolationFixer::AnswerChoice::kPrintFix},
{ViolationFixer::AnswerChoice::kPrintFix},
// :7:10: no-trailing-spaces
{ViolationFixer::AnswerChoice::kApply},
// :7:14: posix-eof
{ViolationFixer::AnswerChoice::kReject},
{ViolationFixer::AnswerChoice::kPrintFix},
// Input source 2:
// :1:21: forbid-consecutive-null-statements
{ViolationFixer::AnswerChoice::kApply},
{ViolationFixer::AnswerChoice::kPrintFix},
// :2:10: no-trailing-spaces
{ViolationFixer::AnswerChoice::kReject},
},
{
"module Autofix;\n"
" wire a;;\n"
" wire b;;\n"
" wire c;\n"
" wire d;\n"
"endmodule",
"module AutofixTwo;\n"
"endmodule\n",
"module AutofixThree;\n"
" wire a; \n"
"endmodule\n",
});
}
TEST_F(ViolationFixerTest, PrintAppliedFixes) {
// Just checks that kPrintAppliedFixes doesn't affect choices
DoFixerTest(
{
// Input source 0:
// :2:10: no-trailing-spaces
{ViolationFixer::AnswerChoice::kApply},
{ViolationFixer::AnswerChoice::kPrintAppliedFixes},
{ViolationFixer::AnswerChoice::kPrintAppliedFixes},
// :3:10: forbid-consecutive-null-statements
{ViolationFixer::AnswerChoice::kReject},
// :4:10: forbid-consecutive-null-staments
{ViolationFixer::AnswerChoice::kReject},
{ViolationFixer::AnswerChoice::kPrintAppliedFixes},
// :4:11: no-trailing-spaces
{ViolationFixer::AnswerChoice::kApply},
{ViolationFixer::AnswerChoice::kPrintAppliedFixes},
// :5:10: forbid-consecutive-null-statements
{ViolationFixer::AnswerChoice::kApply},
// :6:10: forbid-consecutive-null-statements
{ViolationFixer::AnswerChoice::kApply},
{ViolationFixer::AnswerChoice::kPrintAppliedFixes},
{ViolationFixer::AnswerChoice::kPrintAppliedFixes},
// :7:10: no-trailing-spaces
{ViolationFixer::AnswerChoice::kApply},
// :7:14: posix-eof
{ViolationFixer::AnswerChoice::kReject},
{ViolationFixer::AnswerChoice::kPrintAppliedFixes},
// Input source 2:
// :1:21: forbid-consecutive-null-statements
{ViolationFixer::AnswerChoice::kApply},
{ViolationFixer::AnswerChoice::kPrintAppliedFixes},
// :2:10: no-trailing-spaces
{ViolationFixer::AnswerChoice::kReject},
},
{
"module Autofix;\n"
" wire a;;\n"
" wire b;;\n"
" wire c;\n"
" wire d;\n"
"endmodule",
"module AutofixTwo;\n"
"endmodule\n",
"module AutofixThree;\n"
" wire a; \n"
"endmodule\n",
});
}
} // namespace
} // namespace verilog