xref: /llvm-project/clang/unittests/Format/FormatTestBase.h (revision ddbe6c412bab3fe7a3ffaf6f42c49849a518b4c6)
1f8d10d5aSManuel Klimek //===- unittest/Format/FormatTestBase.h - Formatting test base classs -----===//
2f8d10d5aSManuel Klimek //
3f8d10d5aSManuel Klimek // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4f8d10d5aSManuel Klimek // See https://llvm.org/LICENSE.txt for license information.
5f8d10d5aSManuel Klimek // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6f8d10d5aSManuel Klimek //
7f8d10d5aSManuel Klimek //===----------------------------------------------------------------------===//
8f8d10d5aSManuel Klimek //
9f8d10d5aSManuel Klimek //  This file defines the base class for format tests.
10f8d10d5aSManuel Klimek //
11f8d10d5aSManuel Klimek //===----------------------------------------------------------------------===//
12f8d10d5aSManuel Klimek 
13f8d10d5aSManuel Klimek #ifndef LLVM_CLANG_UNITTESTS_FORMAT_FORMATTESTBASE_H
14f8d10d5aSManuel Klimek #define LLVM_CLANG_UNITTESTS_FORMAT_FORMATTESTBASE_H
15f8d10d5aSManuel Klimek 
16f8d10d5aSManuel Klimek #include "FormatTestUtils.h"
17f8d10d5aSManuel Klimek 
18f8d10d5aSManuel Klimek #include "clang/Format/Format.h"
19f8d10d5aSManuel Klimek #include "llvm/Support/Debug.h"
20f8d10d5aSManuel Klimek #include "gtest/gtest.h"
21f8d10d5aSManuel Klimek 
22f8d10d5aSManuel Klimek namespace clang {
23f8d10d5aSManuel Klimek namespace format {
24f8d10d5aSManuel Klimek namespace test {
25f8d10d5aSManuel Klimek 
26f8d10d5aSManuel Klimek #define DEBUG_TYPE "format-test-base"
27f8d10d5aSManuel Klimek 
281c58208dSOwen Pan class FormatTestBase : public testing::Test {
29f8d10d5aSManuel Klimek protected:
30f8d10d5aSManuel Klimek   enum StatusCheck { SC_ExpectComplete, SC_ExpectIncomplete, SC_DoNotCheck };
31f8d10d5aSManuel Klimek 
32f8d10d5aSManuel Klimek   virtual FormatStyle getDefaultStyle() const { return getLLVMStyle(); }
33f8d10d5aSManuel Klimek 
341c58208dSOwen Pan   virtual std::string messUp(StringRef Code) const {
356cef3254Ssstwcw     return test::messUp(Code);
366cef3254Ssstwcw   }
376cef3254Ssstwcw 
381c58208dSOwen Pan   std::string format(StringRef Code,
39f8d10d5aSManuel Klimek                      const std::optional<FormatStyle> &Style = {},
40f8d10d5aSManuel Klimek                      StatusCheck CheckComplete = SC_ExpectComplete,
41f8d10d5aSManuel Klimek                      const std::vector<tooling::Range> &Ranges = {}) {
42f8d10d5aSManuel Klimek     LLVM_DEBUG(llvm::errs() << "---\n");
43f8d10d5aSManuel Klimek     LLVM_DEBUG(llvm::errs() << Code << "\n\n");
44f8d10d5aSManuel Klimek     auto NonEmptyRanges =
45f8d10d5aSManuel Klimek         !Ranges.empty()
46f8d10d5aSManuel Klimek             ? Ranges
47f8d10d5aSManuel Klimek             : std::vector<tooling::Range>{1, tooling::Range(0, Code.size())};
48f8d10d5aSManuel Klimek     auto UsedStyle = Style ? Style.value() : getDefaultStyle();
49f8d10d5aSManuel Klimek     FormattingAttemptStatus Status;
50f8d10d5aSManuel Klimek     tooling::Replacements Replaces =
51f8d10d5aSManuel Klimek         reformat(UsedStyle, Code, NonEmptyRanges, "<stdin>", &Status);
52f8d10d5aSManuel Klimek     if (CheckComplete != SC_DoNotCheck) {
53f8d10d5aSManuel Klimek       bool ExpectedCompleteFormat = CheckComplete == SC_ExpectComplete;
54f8d10d5aSManuel Klimek       EXPECT_EQ(ExpectedCompleteFormat, Status.FormatComplete)
55f8d10d5aSManuel Klimek           << Code << "\n\n";
56f8d10d5aSManuel Klimek     }
57f8d10d5aSManuel Klimek     ReplacementCount = Replaces.size();
58f8d10d5aSManuel Klimek     auto Result = applyAllReplacements(Code, Replaces);
59f8d10d5aSManuel Klimek     EXPECT_TRUE(static_cast<bool>(Result));
60f8d10d5aSManuel Klimek     LLVM_DEBUG(llvm::errs() << "\n" << *Result << "\n\n");
61f8d10d5aSManuel Klimek     return *Result;
62f8d10d5aSManuel Klimek   }
63f8d10d5aSManuel Klimek 
64*ddbe6c41SOwen Pan   FormatStyle getStyleWithColumns(FormatStyle Style,
65*ddbe6c41SOwen Pan                                   unsigned ColumnLimit) const {
66f8d10d5aSManuel Klimek     Style.ColumnLimit = ColumnLimit;
67f8d10d5aSManuel Klimek     return Style;
68f8d10d5aSManuel Klimek   }
69f8d10d5aSManuel Klimek 
70*ddbe6c41SOwen Pan   FormatStyle getLLVMStyleWithColumns(unsigned ColumnLimit) const {
71f8d10d5aSManuel Klimek     return getStyleWithColumns(getLLVMStyle(), ColumnLimit);
72f8d10d5aSManuel Klimek   }
73f8d10d5aSManuel Klimek 
74*ddbe6c41SOwen Pan   FormatStyle getGoogleStyleWithColumns(unsigned ColumnLimit) const {
75f8d10d5aSManuel Klimek     return getStyleWithColumns(getGoogleStyle(), ColumnLimit);
76f8d10d5aSManuel Klimek   }
77f8d10d5aSManuel Klimek 
78*ddbe6c41SOwen Pan   FormatStyle getTextProtoStyleWithColumns(unsigned ColumnLimit) const {
79*ddbe6c41SOwen Pan     return getStyleWithColumns(getGoogleStyle(FormatStyle::LK_TextProto),
80*ddbe6c41SOwen Pan                                ColumnLimit);
81f8d10d5aSManuel Klimek   }
82f8d10d5aSManuel Klimek 
831c58208dSOwen Pan   bool _verifyFormat(const char *File, int Line, StringRef Expected,
841c58208dSOwen Pan                      StringRef Code,
85f8d10d5aSManuel Klimek                      const std::optional<FormatStyle> &Style = {},
86f8d10d5aSManuel Klimek                      const std::vector<tooling::Range> &Ranges = {}) {
871c58208dSOwen Pan     testing::ScopedTrace t(File, Line, testing::Message() << Code.str());
887ecbf6c3SOwen     const auto ExpectedCode{Expected.str()};
897ecbf6c3SOwen     auto FormattedCode{format(Code, Style, SC_ExpectComplete, Ranges)};
907ecbf6c3SOwen     EXPECT_EQ(ExpectedCode, FormattedCode);
917ecbf6c3SOwen     if (ExpectedCode != FormattedCode)
927ecbf6c3SOwen       return false;
93c8521451SOwen Pan     if (Expected != Code) {
947ecbf6c3SOwen       FormattedCode = format(Expected, Style, SC_ExpectComplete, Ranges);
957ecbf6c3SOwen       EXPECT_EQ(ExpectedCode, FormattedCode) << "Expected code is not stable";
967ecbf6c3SOwen       if (ExpectedCode != FormattedCode)
977ecbf6c3SOwen         return false;
98c8521451SOwen Pan     }
99f8d10d5aSManuel Klimek     auto UsedStyle = Style ? Style.value() : getDefaultStyle();
100f8d10d5aSManuel Klimek     if (UsedStyle.Language == FormatStyle::LK_Cpp) {
101f8d10d5aSManuel Klimek       // Objective-C++ is a superset of C++, so everything checked for C++
102f8d10d5aSManuel Klimek       // needs to be checked for Objective-C++ as well.
103f8d10d5aSManuel Klimek       FormatStyle ObjCStyle = UsedStyle;
104f8d10d5aSManuel Klimek       ObjCStyle.Language = FormatStyle::LK_ObjC;
105f8d10d5aSManuel Klimek       // FIXME: Additional messUp is superfluous.
1067ecbf6c3SOwen       FormattedCode = format(Code, ObjCStyle, SC_ExpectComplete, Ranges);
1077ecbf6c3SOwen       EXPECT_EQ(ExpectedCode, FormattedCode);
1087ecbf6c3SOwen       if (ExpectedCode != FormattedCode)
1097ecbf6c3SOwen         return false;
110f8d10d5aSManuel Klimek     }
1117ecbf6c3SOwen     return true;
112f8d10d5aSManuel Klimek   }
113f8d10d5aSManuel Klimek 
1141c58208dSOwen Pan   void _verifyFormat(const char *File, int Line, StringRef Code,
115f8d10d5aSManuel Klimek                      const std::optional<FormatStyle> &Style = {}) {
1167ecbf6c3SOwen     if (!_verifyFormat(File, Line, Code, Code, Style))
1177ecbf6c3SOwen       return;
1186982f1fcSOwen Pan     if (const auto MessedUpCode{messUp(Code)}; MessedUpCode != Code)
1196982f1fcSOwen Pan       _verifyFormat(File, Line, Code, MessedUpCode, Style);
120f8d10d5aSManuel Klimek   }
121f8d10d5aSManuel Klimek 
1221c58208dSOwen Pan   void _verifyIncompleteFormat(const char *File, int Line, StringRef Code,
123f8d10d5aSManuel Klimek                                const std::optional<FormatStyle> &Style = {}) {
1241c58208dSOwen Pan     testing::ScopedTrace t(File, Line, testing::Message() << Code.str());
1256cef3254Ssstwcw     EXPECT_EQ(Code.str(), format(messUp(Code), Style, SC_ExpectIncomplete));
126f8d10d5aSManuel Klimek   }
127f8d10d5aSManuel Klimek 
128f8d10d5aSManuel Klimek   void
1291c58208dSOwen Pan   _verifyIndependentOfContext(const char *File, int Line, StringRef Text,
130f8d10d5aSManuel Klimek                               const std::optional<FormatStyle> &Style = {}) {
131f8d10d5aSManuel Klimek     _verifyFormat(File, Line, Text, Style);
1321c58208dSOwen Pan     _verifyFormat(File, Line, Twine("void f() { " + Text + " }").str(), Style);
133f8d10d5aSManuel Klimek   }
134f8d10d5aSManuel Klimek 
1351c58208dSOwen Pan   void _verifyNoChange(const char *File, int Line, StringRef Code,
13620b4df1eSOwen Pan                        const std::optional<FormatStyle> &Style = {}) {
13720b4df1eSOwen Pan     _verifyFormat(File, Line, Code, Code, Style);
13820b4df1eSOwen Pan   }
13920b4df1eSOwen Pan 
140f8d10d5aSManuel Klimek   /// \brief Verify that clang-format does not crash on the given input.
1411c58208dSOwen Pan   void verifyNoCrash(StringRef Code,
142f8d10d5aSManuel Klimek                      const std::optional<FormatStyle> &Style = {}) {
143f8d10d5aSManuel Klimek     format(Code, Style, SC_DoNotCheck);
144f8d10d5aSManuel Klimek   }
145f8d10d5aSManuel Klimek 
146f8d10d5aSManuel Klimek   int ReplacementCount;
147f8d10d5aSManuel Klimek };
148f8d10d5aSManuel Klimek 
149f8d10d5aSManuel Klimek #undef DEBUG_TYPE
150f8d10d5aSManuel Klimek 
151f8d10d5aSManuel Klimek #define verifyIndependentOfContext(...)                                        \
152f8d10d5aSManuel Klimek   _verifyIndependentOfContext(__FILE__, __LINE__, __VA_ARGS__)
153f8d10d5aSManuel Klimek #define verifyIncompleteFormat(...)                                            \
154f8d10d5aSManuel Klimek   _verifyIncompleteFormat(__FILE__, __LINE__, __VA_ARGS__)
15520b4df1eSOwen Pan #define verifyNoChange(...) _verifyNoChange(__FILE__, __LINE__, __VA_ARGS__)
156f8d10d5aSManuel Klimek #define verifyFormat(...) _verifyFormat(__FILE__, __LINE__, __VA_ARGS__)
157f8d10d5aSManuel Klimek #define verifyGoogleFormat(Code) verifyFormat(Code, getGoogleStyle())
158f8d10d5aSManuel Klimek 
159f8d10d5aSManuel Klimek } // namespace test
160f8d10d5aSManuel Klimek } // namespace format
161f8d10d5aSManuel Klimek } // namespace clang
162f8d10d5aSManuel Klimek 
163f8d10d5aSManuel Klimek #endif
164