xref: /llvm-project/clang/unittests/Format/FormatTestBase.h (revision ddbe6c412bab3fe7a3ffaf6f42c49849a518b4c6)
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