blob: aad3e60aa81428aa53c8546a0ca04b3fa0e3b54c [file]
// Copyright 2017-2026 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.
// Test cases in this file should be *insensitive* to wrapping penalties.
// Penalty-sensitive tests belong in formatter-tuning_test.cc.
// Thematic end-to-end cases live in sibling formatter_*_test.cc files.
// New GitHub-issue regressions belong in formatter_issue_regression_test.cc.
#include "verible/verilog/formatting/formatter.h"
#include <memory>
#include <sstream>
#include <string_view>
#include "absl/log/die_if_null.h"
#include "absl/status/status.h"
#include "gtest/gtest.h"
#include "verible/common/text/text-structure.h"
#include "verible/common/util/logging.h"
#include "verible/verilog/analysis/verilog-analyzer.h"
#include "verible/verilog/formatting/format-style.h"
#include "verible/verilog/formatting/formatter-test-utils.h"
namespace verilog {
namespace formatter {
// private, extern function in formatter.cc, directly tested here.
extern absl::Status VerifyFormatting(
const verible::TextStructureView &text_structure,
std::string_view formatted_output, std::string_view filename);
namespace {
static constexpr VerilogPreprocess::Config kDefaultPreprocess;
using absl::StatusCode;
TEST(VerifyFormattingTest, NoError) {
const std::string_view code("class c;endclass\n");
const std::unique_ptr<VerilogAnalyzer> analyzer =
VerilogAnalyzer::AnalyzeAutomaticMode(code, "<file>", kDefaultPreprocess);
const auto &text_structure = ABSL_DIE_IF_NULL(analyzer)->Data();
const auto status = VerifyFormatting(text_structure, code, "<filename>");
EXPECT_OK(status);
}
// Tests that un-lexable outputs are caught as errors.
TEST(VerifyFormattingTest, LexError) {
const std::string_view code("class c;endclass\n");
const std::unique_ptr<VerilogAnalyzer> analyzer =
VerilogAnalyzer::AnalyzeAutomaticMode(code, "<file>", kDefaultPreprocess);
const auto &text_structure = ABSL_DIE_IF_NULL(analyzer)->Data();
const std::string_view bad_code("1class c;endclass\n"); // lexical error
const auto status = VerifyFormatting(text_structure, bad_code, "<filename>");
EXPECT_FALSE(status.ok());
EXPECT_EQ(status.code(), StatusCode::kDataLoss);
}
// Tests that un-parseable outputs are caught as errors.
TEST(VerifyFormattingTest, ParseError) {
const std::string_view code("class c;endclass\n");
const std::unique_ptr<VerilogAnalyzer> analyzer =
VerilogAnalyzer::AnalyzeAutomaticMode(code, "<file>", kDefaultPreprocess);
const auto &text_structure = ABSL_DIE_IF_NULL(analyzer)->Data();
const std::string_view bad_code("classc;endclass\n"); // syntax error
const auto status = VerifyFormatting(text_structure, bad_code, "<filename>");
EXPECT_FALSE(status.ok());
EXPECT_EQ(status.code(), StatusCode::kDataLoss);
}
// Tests that lexical differences are caught as errors.
TEST(VerifyFormattingTest, LexicalDifference) {
const std::string_view code("class c;endclass\n");
const std::unique_ptr<VerilogAnalyzer> analyzer =
VerilogAnalyzer::AnalyzeAutomaticMode(code, "<file>", kDefaultPreprocess);
const auto &text_structure = ABSL_DIE_IF_NULL(analyzer)->Data();
const std::string_view bad_code("class c;;endclass\n"); // different tokens
const auto status = VerifyFormatting(text_structure, bad_code, "<filename>");
EXPECT_FALSE(status.ok());
EXPECT_EQ(status.code(), StatusCode::kDataLoss);
}
TEST(FormatterTest, FormatCustomStyleTest) {
static constexpr FormatterTestCase kTestCases[] = {
{"", ""},
{"module m;wire w;endmodule\n",
"module m;\n"
" wire w;\n"
"endmodule\n"},
};
FormatStyle style;
style.column_limit = 40;
style.indentation_spaces = 10; // unconventional indentation
style.wrap_spaces = 4;
for (const auto &test_case : kTestCases) {
VLOG(1) << "code-to-format:\n" << test_case.input << "<EOF>";
std::ostringstream stream;
const auto status =
FormatVerilog(test_case.input, "<filename>", style, stream);
EXPECT_OK(status);
EXPECT_EQ(stream.str(), test_case.expected) << "code:\n" << test_case.input;
}
}
// Small smoke subset; thematic cases live in sibling formatter_*_test.cc files.
static constexpr FormatterTestCase kSmokeFormatterTestCases[] = {
{"", ""},
{"\n", "\n"},
{"\n\n", "\n\n"},
{"\t//comment\n", "//comment\n"},
{"\t/*comment*/\n", "/*comment*/\n"},
{"\t/*multi-line\ncomment*/\n", "/*multi-line\ncomment*/\n"},
};
TEST(FormatterEndToEndTest, SmokeFormatterTestCases) {
RunFormatterTestCases40(kSmokeFormatterTestCases);
}
} // namespace
} // namespace formatter
} // namespace verilog