164 lines · c
1//===- unittest/Format/FormatTestBase.h - Formatting test base classs -----===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9// This file defines the base class for format tests.10//11//===----------------------------------------------------------------------===//12 13#ifndef LLVM_CLANG_UNITTESTS_FORMAT_FORMATTESTBASE_H14#define LLVM_CLANG_UNITTESTS_FORMAT_FORMATTESTBASE_H15 16#include "FormatTestUtils.h"17 18#include "clang/Format/Format.h"19#include "llvm/Support/Debug.h"20#include "gtest/gtest.h"21 22namespace clang {23namespace format {24namespace test {25 26#define DEBUG_TYPE "format-test-base"27 28class FormatTestBase : public testing::Test {29protected:30 enum StatusCheck { SC_ExpectComplete, SC_ExpectIncomplete, SC_DoNotCheck };31 32 virtual FormatStyle getDefaultStyle() const { return getLLVMStyle(); }33 34 virtual std::string messUp(StringRef Code) const {35 return test::messUp(Code);36 }37 38 std::string format(StringRef Code,39 const std::optional<FormatStyle> &Style = {},40 StatusCheck CheckComplete = SC_ExpectComplete,41 const std::vector<tooling::Range> &Ranges = {}) {42 LLVM_DEBUG(llvm::errs() << "---\n");43 LLVM_DEBUG(llvm::errs() << Code << "\n\n");44 auto NonEmptyRanges =45 !Ranges.empty()46 ? Ranges47 : std::vector<tooling::Range>{1, tooling::Range(0, Code.size())};48 auto UsedStyle = Style ? Style.value() : getDefaultStyle();49 FormattingAttemptStatus Status;50 tooling::Replacements Replaces =51 reformat(UsedStyle, Code, NonEmptyRanges, "<stdin>", &Status);52 if (CheckComplete != SC_DoNotCheck) {53 bool ExpectedCompleteFormat = CheckComplete == SC_ExpectComplete;54 EXPECT_EQ(ExpectedCompleteFormat, Status.FormatComplete)55 << Code << "\n\n";56 }57 ReplacementCount = Replaces.size();58 auto Result = applyAllReplacements(Code, Replaces);59 EXPECT_TRUE(static_cast<bool>(Result));60 LLVM_DEBUG(llvm::errs() << "\n" << *Result << "\n\n");61 return *Result;62 }63 64 FormatStyle getStyleWithColumns(FormatStyle Style,65 unsigned ColumnLimit) const {66 Style.ColumnLimit = ColumnLimit;67 return Style;68 }69 70 FormatStyle getLLVMStyleWithColumns(unsigned ColumnLimit) const {71 return getStyleWithColumns(getLLVMStyle(), ColumnLimit);72 }73 74 FormatStyle getGoogleStyleWithColumns(unsigned ColumnLimit) const {75 return getStyleWithColumns(getGoogleStyle(), ColumnLimit);76 }77 78 FormatStyle getTextProtoStyleWithColumns(unsigned ColumnLimit) const {79 return getStyleWithColumns(getGoogleStyle(FormatStyle::LK_TextProto),80 ColumnLimit);81 }82 83 bool _verifyFormat(const char *File, int Line, StringRef Expected,84 StringRef Code,85 const std::optional<FormatStyle> &Style = {},86 const std::vector<tooling::Range> &Ranges = {}) {87 testing::ScopedTrace t(File, Line, testing::Message() << Code.str());88 const auto ExpectedCode{Expected.str()};89 auto FormattedCode{format(Code, Style, SC_ExpectComplete, Ranges)};90 EXPECT_EQ(ExpectedCode, FormattedCode);91 if (ExpectedCode != FormattedCode)92 return false;93 if (Expected != Code) {94 FormattedCode = format(Expected, Style, SC_ExpectComplete, Ranges);95 EXPECT_EQ(ExpectedCode, FormattedCode) << "Expected code is not stable";96 if (ExpectedCode != FormattedCode)97 return false;98 }99 auto UsedStyle = Style ? Style.value() : getDefaultStyle();100 if (UsedStyle.Language == FormatStyle::LK_Cpp) {101 // Objective-C++ is a superset of C++, so everything checked for C++102 // needs to be checked for Objective-C++ as well.103 FormatStyle ObjCStyle = UsedStyle;104 ObjCStyle.Language = FormatStyle::LK_ObjC;105 // FIXME: Additional messUp is superfluous.106 FormattedCode = format(Code, ObjCStyle, SC_ExpectComplete, Ranges);107 EXPECT_EQ(ExpectedCode, FormattedCode);108 if (ExpectedCode != FormattedCode)109 return false;110 }111 return true;112 }113 114 void _verifyFormat(const char *File, int Line, StringRef Code,115 const std::optional<FormatStyle> &Style = {}) {116 if (!_verifyFormat(File, Line, Code, Code, Style))117 return;118 if (const auto MessedUpCode{messUp(Code)}; MessedUpCode != Code)119 _verifyFormat(File, Line, Code, MessedUpCode, Style);120 }121 122 void _verifyIncompleteFormat(const char *File, int Line, StringRef Code,123 const std::optional<FormatStyle> &Style = {}) {124 testing::ScopedTrace t(File, Line, testing::Message() << Code.str());125 EXPECT_EQ(Code.str(), format(messUp(Code), Style, SC_ExpectIncomplete));126 }127 128 void129 _verifyIndependentOfContext(const char *File, int Line, StringRef Text,130 const std::optional<FormatStyle> &Style = {}) {131 _verifyFormat(File, Line, Text, Style);132 _verifyFormat(File, Line, Twine("void f() { " + Text + " }").str(), Style);133 }134 135 void _verifyNoChange(const char *File, int Line, StringRef Code,136 const std::optional<FormatStyle> &Style = {}) {137 _verifyFormat(File, Line, Code, Code, Style);138 }139 140 /// Verify that clang-format does not crash on the given input.141 void verifyNoCrash(StringRef Code,142 const std::optional<FormatStyle> &Style = {}) {143 format(Code, Style, SC_DoNotCheck);144 }145 146 int ReplacementCount;147};148 149#undef DEBUG_TYPE150 151#define verifyIndependentOfContext(...) \152 _verifyIndependentOfContext(__FILE__, __LINE__, __VA_ARGS__)153#define verifyIncompleteFormat(...) \154 _verifyIncompleteFormat(__FILE__, __LINE__, __VA_ARGS__)155#define verifyNoChange(...) _verifyNoChange(__FILE__, __LINE__, __VA_ARGS__)156#define verifyFormat(...) _verifyFormat(__FILE__, __LINE__, __VA_ARGS__)157#define verifyGoogleFormat(Code) verifyFormat(Code, getGoogleStyle())158 159} // namespace test160} // namespace format161} // namespace clang162 163#endif164