blob: b7bd743b08ba1bd341c200141043dae00468a92b [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.
#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