1 //===- DefinitionBlockSeparatorTest.cpp - Formatting unit tests -----------===//
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
7 //===----------------------------------------------------------------------===//
9 #include "FormatTestUtils.h"
10 #include "clang/Format/Format.h"
12 #include "llvm/Support/Debug.h"
13 #include "gtest/gtest.h"
15 #define DEBUG_TYPE "definition-block-separator-test"
21 class DefinitionBlockSeparatorTest
: public testing::Test
{
24 separateDefinitionBlocks(StringRef Code
,
25 const std::vector
<tooling::Range
> &Ranges
,
26 const FormatStyle
&Style
= getLLVMStyle()) {
27 LLVM_DEBUG(llvm::errs() << "---\n");
28 LLVM_DEBUG(llvm::errs() << Code
<< "\n\n");
29 tooling::Replacements Replaces
= reformat(Style
, Code
, Ranges
, "<stdin>");
30 auto Result
= applyAllReplacements(Code
, Replaces
);
31 EXPECT_TRUE(static_cast<bool>(Result
));
32 LLVM_DEBUG(llvm::errs() << "\n" << *Result
<< "\n\n");
37 separateDefinitionBlocks(StringRef Code
,
38 const FormatStyle
&Style
= getLLVMStyle()) {
39 return separateDefinitionBlocks(
41 /*Ranges=*/{1, tooling::Range(0, Code
.size())}, Style
);
44 static void _verifyFormat(const char *File
, int Line
, StringRef Code
,
45 const FormatStyle
&Style
= getLLVMStyle(),
46 StringRef ExpectedCode
= "", bool Inverse
= true) {
47 testing::ScopedTrace
t(File
, Line
, testing::Message() << Code
.str());
48 bool HasOriginalCode
= true;
49 if (ExpectedCode
== "") {
51 HasOriginalCode
= false;
54 EXPECT_EQ(ExpectedCode
, separateDefinitionBlocks(ExpectedCode
, Style
))
55 << "Expected code is not stable";
57 FormatStyle InverseStyle
= Style
;
58 if (Style
.SeparateDefinitionBlocks
== FormatStyle::SDS_Always
)
59 InverseStyle
.SeparateDefinitionBlocks
= FormatStyle::SDS_Never
;
61 InverseStyle
.SeparateDefinitionBlocks
= FormatStyle::SDS_Always
;
62 EXPECT_NE(ExpectedCode
,
63 separateDefinitionBlocks(ExpectedCode
, InverseStyle
))
64 << "Inverse formatting makes no difference";
66 std::string CodeToFormat
=
67 HasOriginalCode
? Code
.str() : removeEmptyLines(Code
);
68 std::string Result
= separateDefinitionBlocks(CodeToFormat
, Style
);
69 EXPECT_EQ(ExpectedCode
, Result
) << "Test failed. Formatted:\n" << Result
;
72 static std::string
removeEmptyLines(StringRef Code
) {
73 std::string Result
= "";
74 for (auto Char
: Code
.str()) {
76 auto LastChar
= Result
.back();
77 if ((Char
== '\n' && LastChar
== '\n') ||
78 (Char
== '\r' && (LastChar
== '\r' || LastChar
== '\n'))) {
82 Result
.push_back(Char
);
88 #define verifyFormat(...) _verifyFormat(__FILE__, __LINE__, __VA_ARGS__)
90 TEST_F(DefinitionBlockSeparatorTest
, Basic
) {
91 FormatStyle Style
= getLLVMStyle();
92 Style
.SeparateDefinitionBlocks
= FormatStyle::SDS_Always
;
93 verifyFormat("int foo(int i, int j) {\n"
98 "int bar(int j, int k) {\n"
104 verifyFormat("struct foo {\n"
113 verifyFormat("union foo {\n"
122 verifyFormat("class foo {\n"
131 verifyFormat("namespace foo {\n"
140 verifyFormat("enum Foo { FOO, BAR };\n"
142 "enum Bar { FOOBAR, BARFOO };",
145 FormatStyle BreakAfterReturnTypeStyle
= Style
;
146 BreakAfterReturnTypeStyle
.BreakAfterReturnType
= FormatStyle::RTBS_All
;
147 // Test uppercased long typename
148 verifyFormat("class Foo {\n"
150 " Bar(int t, int p) {\n"
156 " Foobar(int t, int p) {\n"
161 BreakAfterReturnTypeStyle
);
164 TEST_F(DefinitionBlockSeparatorTest
, FormatConflict
) {
165 FormatStyle Style
= getLLVMStyle();
166 Style
.SeparateDefinitionBlocks
= FormatStyle::SDS_Always
;
167 StringRef Code
= "class Test {\n"
169 " static void foo() {\n"
174 std::vector
<tooling::Range
> Ranges
= {1, tooling::Range(0, Code
.size())};
175 EXPECT_EQ(reformat(Style
, Code
, Ranges
, "<stdin>").size(), 0u);
178 TEST_F(DefinitionBlockSeparatorTest
, CommentBlock
) {
179 FormatStyle Style
= getLLVMStyle();
180 Style
.SeparateDefinitionBlocks
= FormatStyle::SDS_Always
;
181 std::string Prefix
= "enum Foo { FOO, BAR };\n"
187 "int foo(int i, int j) {\n"
191 std::string Suffix
= "enum Bar { FOOBAR, BARFOO };\n"
193 "/* Comment block in one line*/\n"
194 "int bar3(int j, int k) {\n"
199 std::string CommentedCode
= "/*\n"
200 "int bar2(int j, int k) {\n"
205 verifyFormat(removeEmptyLines(Prefix
) + "\n" + CommentedCode
+ "\n" +
206 removeEmptyLines(Suffix
),
207 Style
, Prefix
+ "\n" + CommentedCode
+ "\n" + Suffix
);
208 verifyFormat(removeEmptyLines(Prefix
) + "\n" + CommentedCode
+
209 removeEmptyLines(Suffix
),
210 Style
, Prefix
+ "\n" + CommentedCode
+ Suffix
);
213 TEST_F(DefinitionBlockSeparatorTest
, UntouchBlockStartStyle
) {
214 // Returns a std::pair of two strings, with the first one for passing into
215 // Always test and the second one be the expected result of the first string.
216 auto MakeUntouchTest
= [&](std::string BlockHeader
, std::string BlockChanger
,
217 std::string BlockFooter
, bool BlockEndNewLine
) {
218 std::string CodePart1
= "enum Foo { FOO, BAR };\n"
224 "int foo(int i, int j) {\n"
228 std::string CodePart2
= "/* Comment block in one line*/\n"
229 "enum Bar { FOOBAR, BARFOO };\n"
231 "int bar3(int j, int k) {\n"
236 std::string CodePart3
= "int bar2(int j, int k) {\n"
240 std::string ConcatAll
= BlockHeader
+ CodePart1
+ BlockChanger
+ CodePart2
+
241 BlockFooter
+ (BlockEndNewLine
? "\n" : "") +
243 return std::make_pair(BlockHeader
+ removeEmptyLines(CodePart1
) +
244 BlockChanger
+ removeEmptyLines(CodePart2
) +
245 BlockFooter
+ removeEmptyLines(CodePart3
),
249 FormatStyle AlwaysStyle
= getLLVMStyle();
250 AlwaysStyle
.SeparateDefinitionBlocks
= FormatStyle::SDS_Always
;
252 FormatStyle NeverStyle
= getLLVMStyle();
253 NeverStyle
.SeparateDefinitionBlocks
= FormatStyle::SDS_Never
;
255 auto TestKit
= MakeUntouchTest("/* FOOBAR */\n"
257 "\n#elifndef BAR\n\n", "\n#endif\n\n", false);
258 verifyFormat(TestKit
.first
, AlwaysStyle
, TestKit
.second
);
259 verifyFormat(TestKit
.second
, NeverStyle
, removeEmptyLines(TestKit
.second
));
261 TestKit
= MakeUntouchTest("/* FOOBAR */\n"
263 "#elifndef BAR\n", "#endif\n", false);
264 verifyFormat(TestKit
.first
, AlwaysStyle
, TestKit
.second
);
265 verifyFormat(TestKit
.second
, NeverStyle
, removeEmptyLines(TestKit
.second
));
267 TestKit
= MakeUntouchTest("namespace Ns {\n\n",
268 "\n} // namespace Ns\n\n"
270 "\n} // namespace\n", true);
271 verifyFormat(TestKit
.first
, AlwaysStyle
, TestKit
.second
);
272 verifyFormat(TestKit
.second
, NeverStyle
, removeEmptyLines(TestKit
.second
));
274 TestKit
= MakeUntouchTest("namespace Ns {\n",
275 "} // namespace Ns\n\n"
277 "} // namespace\n", true);
278 verifyFormat(TestKit
.first
, AlwaysStyle
, TestKit
.second
);
279 verifyFormat(TestKit
.second
, NeverStyle
, removeEmptyLines(TestKit
.second
));
282 TEST_F(DefinitionBlockSeparatorTest
, Always
) {
283 FormatStyle Style
= getLLVMStyle();
284 Style
.SeparateDefinitionBlocks
= FormatStyle::SDS_Always
;
286 verifyFormat("// clang-format off\n"
287 "template<class T>\n"
288 "concept C = not A<S<T>>;\n"
289 "// clang-format on\n"
294 std::string Prefix
= "namespace {\n";
295 std::string Infix
= "\n"
298 "enum Foo { FOO, BAR };\n"
304 "/*const*/ int foo(int i, int j) {\n"
312 "// Comment for function\n"
313 "// Comment line 2\n"
314 "// Comment line 3\n"
315 "int bar(int j, int k) {\n"
322 "int bar2(int j, int k) {\n"
327 "/* Comment block in one line*/\n"
328 "enum Bar { FOOBAR, BARFOO };\n"
330 "int bar3(int j, int k, const enum Bar b) {\n"
333 " if (struct S = getS()) {\n"
338 std::string Postfix
= "\n"
344 verifyFormat(Prefix
+ removeEmptyLines(Infix
) + removeEmptyLines(Postfix
),
345 Style
, Prefix
+ Infix
+ Postfix
);
348 TEST_F(DefinitionBlockSeparatorTest
, Never
) {
349 FormatStyle Style
= getLLVMStyle();
350 Style
.SeparateDefinitionBlocks
= FormatStyle::SDS_Never
;
351 std::string Prefix
= "namespace {\n";
352 std::string Postfix
= "// Enum test1\n"
354 "enum Foo { FOO, BAR };\n"
360 "/*const*/ int foo(int i, int j) {\n"
368 "// Comment for function\n"
369 "// Comment line 2\n"
370 "// Comment line 3\n"
371 "int bar(int j, int k) {\n"
378 "int bar2(int j, int k) {\n"
383 "/* Comment block in one line*/\n"
384 "enum Bar { FOOBAR, BARFOO };\n"
386 "int bar3(int j, int k, const enum Bar b) {\n"
389 " if (struct S = getS()) {\n"
395 verifyFormat(Prefix
+ "\n\n\n" + Postfix
, Style
,
396 Prefix
+ removeEmptyLines(Postfix
));
399 TEST_F(DefinitionBlockSeparatorTest
, OpeningBracketOwnsLine
) {
400 FormatStyle Style
= getLLVMStyle();
401 Style
.BreakBeforeBraces
= FormatStyle::BS_Allman
;
402 Style
.SeparateDefinitionBlocks
= FormatStyle::SDS_Always
;
403 verifyFormat("namespace NS\n"
417 "/*const*/ int foo(int i, int j)\n"
426 "// Comment for function\n"
427 "// Comment line 2\n"
428 "// Comment line 3\n"
429 "int bar(int j, int k)\n"
437 "int bar2(int j, int k)\n"
449 "int bar3(int j, int k, const enum Bar b)\n"
453 " if (struct S = getS())\n"
463 TEST_F(DefinitionBlockSeparatorTest
, TryBlocks
) {
464 FormatStyle Style
= getLLVMStyle();
465 Style
.BreakBeforeBraces
= FormatStyle::BS_Allman
;
466 Style
.SeparateDefinitionBlocks
= FormatStyle::SDS_Always
;
467 verifyFormat("void FunctionWithInternalTry()\n"
473 " catch (const std::exception &)\n"
477 Style
, "", /*Inverse=*/false);
478 verifyFormat("void FunctionWithTryBlock()\n"
483 "catch (const std::exception &)\n"
486 Style
, "", /*Inverse=*/false);
489 TEST_F(DefinitionBlockSeparatorTest
, Leave
) {
490 FormatStyle Style
= getLLVMStyle();
491 Style
.SeparateDefinitionBlocks
= FormatStyle::SDS_Leave
;
492 Style
.MaxEmptyLinesToKeep
= 3;
493 std::string LeaveAs
= "namespace {\n"
497 "enum Foo { FOO, BAR };\n"
503 "/*const*/ int foo(int i, int j) {\n"
511 "// Comment for function\n"
512 "// Comment line 2\n"
513 "// Comment line 3\n"
514 "int bar(int j, int k) {\n"
521 "int bar2(int j, int k) {\n"
526 "// Comment for inline enum\n"
527 "enum Bar { FOOBAR, BARFOO };\n"
528 "int bar3(int j, int k, const enum Bar b) {\n"
531 " if (struct S = getS()) {\n"
537 verifyFormat(LeaveAs
, Style
, LeaveAs
);
540 TEST_F(DefinitionBlockSeparatorTest
, CSharp
) {
541 FormatStyle Style
= getLLVMStyle(FormatStyle::LK_CSharp
);
542 Style
.SeparateDefinitionBlocks
= FormatStyle::SDS_Always
;
543 Style
.AllowShortFunctionsOnASingleLine
= FormatStyle::SFS_None
;
544 Style
.AllowShortEnumsOnASingleLine
= false;
545 verifyFormat("namespace {\r\n"
546 "public class SomeTinyClass {\r\n"
550 "public class AnotherTinyClass {\r\n"
554 "internal static String toString() {\r\n"
557 "// Comment for enum\r\n"
558 "public enum var {\r\n"
567 "static void Main(string[] args) {\r\n"
568 " Console.WriteLine(\"HelloWorld\");\r\n"
571 "static decimal Test() {\r\n"
575 "public class FoobarClass {\r\n"
581 TEST_F(DefinitionBlockSeparatorTest
, JavaScript
) {
582 FormatStyle Style
= getLLVMStyle(FormatStyle::LK_JavaScript
);
583 Style
.SeparateDefinitionBlocks
= FormatStyle::SDS_Always
;
584 Style
.AllowShortFunctionsOnASingleLine
= FormatStyle::SFS_None
;
585 Style
.AllowShortEnumsOnASingleLine
= false;
586 verifyFormat("export const enum Foo {\n"
591 "export function A() {\n"
594 "export default function B() {\n"
597 "export function C() {\n"
602 "export abstract class X {\n"
606 "export const enum Bar {\n"
613 } // namespace format