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-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // This file defines the base class for format tests. 10 // 11 //===----------------------------------------------------------------------===// 12 13 #ifndef LLVM_CLANG_UNITTESTS_FORMAT_FORMATTESTBASE_H 14 #define LLVM_CLANG_UNITTESTS_FORMAT_FORMATTESTBASE_H 15 16 #include "FormatTestUtils.h" 17 18 #include "clang/Format/Format.h" 19 #include "llvm/Support/Debug.h" 20 #include "gtest/gtest.h" 21 22 namespace clang { 23 namespace format { 24 namespace test { 25 26 #define DEBUG_TYPE "format-test-base" 27 28 class FormatTestBase : public testing::Test { 29 protected: 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 ? Ranges 47 : 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 void 129 _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 /// \brief 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_TYPE 150 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 test 160 } // namespace format 161 } // namespace clang 162 163 #endif 164