xref: /llvm-project/clang/unittests/Format/FormatTestCSharp.cpp (revision 63395cb0b69dee69ec5d5d0d552482c607861178)
1 //===- unittest/Format/FormatTestCSharp.cpp - Formatting tests for CSharp -===//
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 #include "FormatTestUtils.h"
10 #include "clang/Format/Format.h"
11 #include "llvm/Support/Debug.h"
12 #include "gtest/gtest.h"
13 
14 #define DEBUG_TYPE "format-test"
15 
16 namespace clang {
17 namespace format {
18 
19 class FormatTestCSharp : public ::testing::Test {
20 protected:
21   static std::string format(llvm::StringRef Code, unsigned Offset,
22                             unsigned Length, const FormatStyle &Style) {
23     LLVM_DEBUG(llvm::errs() << "---\n");
24     LLVM_DEBUG(llvm::errs() << Code << "\n\n");
25     std::vector<tooling::Range> Ranges(1, tooling::Range(Offset, Length));
26     tooling::Replacements Replaces = reformat(Style, Code, Ranges);
27     auto Result = applyAllReplacements(Code, Replaces);
28     EXPECT_TRUE(static_cast<bool>(Result));
29     LLVM_DEBUG(llvm::errs() << "\n" << *Result << "\n\n");
30     return *Result;
31   }
32 
33   static std::string
34   format(llvm::StringRef Code,
35          const FormatStyle &Style = getMicrosoftStyle(FormatStyle::LK_CSharp)) {
36     return format(Code, 0, Code.size(), Style);
37   }
38 
39   static FormatStyle getStyleWithColumns(unsigned ColumnLimit) {
40     FormatStyle Style = getMicrosoftStyle(FormatStyle::LK_CSharp);
41     Style.ColumnLimit = ColumnLimit;
42     return Style;
43   }
44 
45   static void verifyFormat(
46       llvm::StringRef Code,
47       const FormatStyle &Style = getMicrosoftStyle(FormatStyle::LK_CSharp)) {
48     EXPECT_EQ(Code.str(), format(Code, Style)) << "Expected code is not stable";
49     EXPECT_EQ(Code.str(), format(test::messUp(Code), Style));
50   }
51 };
52 
53 TEST_F(FormatTestCSharp, CSharpClass) {
54   verifyFormat("public class SomeClass\n"
55                "{\n"
56                "    void f()\n"
57                "    {\n"
58                "    }\n"
59                "    int g()\n"
60                "    {\n"
61                "        return 0;\n"
62                "    }\n"
63                "    void h()\n"
64                "    {\n"
65                "        while (true)\n"
66                "            f();\n"
67                "        for (;;)\n"
68                "            f();\n"
69                "        if (true)\n"
70                "            f();\n"
71                "    }\n"
72                "}");
73 
74   // Ensure that small and empty classes are handled correctly with condensed
75   // (Google C++-like) brace-breaking style.
76   FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp);
77   Style.BreakBeforeBraces = FormatStyle::BS_Attach;
78 
79   verifyFormat("public class SomeEmptyClass {}", Style);
80 
81   verifyFormat("public class SomeTinyClass {\n"
82                "  int X;\n"
83                "}",
84                Style);
85   verifyFormat("private class SomeTinyClass {\n"
86                "  int X;\n"
87                "}",
88                Style);
89   verifyFormat("protected class SomeTinyClass {\n"
90                "  int X;\n"
91                "}",
92                Style);
93   verifyFormat("internal class SomeTinyClass {\n"
94                "  int X;\n"
95                "}",
96                Style);
97 }
98 
99 TEST_F(FormatTestCSharp, AccessModifiers) {
100   verifyFormat("public String toString()\n"
101                "{\n"
102                "}");
103   verifyFormat("private String toString()\n"
104                "{\n"
105                "}");
106   verifyFormat("protected String toString()\n"
107                "{\n"
108                "}");
109   verifyFormat("internal String toString()\n"
110                "{\n"
111                "}");
112 
113   verifyFormat("public override String toString()\n"
114                "{\n"
115                "}");
116   verifyFormat("private override String toString()\n"
117                "{\n"
118                "}");
119   verifyFormat("protected override String toString()\n"
120                "{\n"
121                "}");
122   verifyFormat("internal override String toString()\n"
123                "{\n"
124                "}");
125 
126   verifyFormat("internal static String toString()\n"
127                "{\n"
128                "}");
129 }
130 
131 TEST_F(FormatTestCSharp, NoStringLiteralBreaks) {
132   verifyFormat("foo("
133                "\"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
134                "aaaaaa\");");
135 }
136 
137 TEST_F(FormatTestCSharp, CSharpVerbatiumStringLiterals) {
138   verifyFormat("foo(@\"aaaaaaaa\\abc\\aaaa\");");
139   // @"ABC\" + ToString("B") - handle embedded \ in literal string at
140   // the end
141   //
142   /*
143    * After removal of Lexer change we are currently not able
144    * To handle these cases
145    verifyFormat("string s = @\"ABC\\\" + ToString(\"B\");");
146    verifyFormat("string s = @\"ABC\"\"DEF\"\"GHI\"");
147    verifyFormat("string s = @\"ABC\"\"DEF\"\"\"");
148    verifyFormat("string s = @\"ABC\"\"DEF\"\"\" + abc");
149   */
150 }
151 
152 TEST_F(FormatTestCSharp, CSharpInterpolatedStringLiterals) {
153   verifyFormat("foo($\"aaaaaaaa{aaa}aaaa\");");
154   verifyFormat("foo($\"aaaa{A}\");");
155   verifyFormat(
156       "foo($\"aaaa{A}"
157       "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\");");
158   verifyFormat("Name = $\"{firstName} {lastName}\";");
159 
160   // $"ABC\" + ToString("B") - handle embedded \ in literal string at
161   // the end
162   verifyFormat("string s = $\"A{abc}BC\" + ToString(\"B\");");
163   verifyFormat("$\"{domain}\\\\{user}\"");
164   verifyFormat(
165       "var verbatimInterpolated = $@\"C:\\Users\\{userName}\\Documents\\\";");
166 }
167 
168 TEST_F(FormatTestCSharp, CSharpFatArrows) {
169   verifyFormat("Task serverTask = Task.Run(async() => {");
170   verifyFormat("public override string ToString() => \"{Name}\\{Age}\";");
171 }
172 
173 TEST_F(FormatTestCSharp, CSharpConditionalExpressions) {
174   FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp);
175   // conditional expression is not seen as a NullConditional.
176   verifyFormat("var y = A < B ? -1 : 1;", Style);
177 }
178 
179 TEST_F(FormatTestCSharp, CSharpNullConditional) {
180   FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp);
181   Style.SpaceBeforeParens = FormatStyle::SBPO_Always;
182 
183   verifyFormat(
184       "public Person(string firstName, string lastName, int? age = null)");
185 
186   verifyFormat("foo () {\n"
187                "  switch (args?.Length) {}\n"
188                "}",
189                Style);
190 
191   verifyFormat("switch (args?.Length) {}", Style);
192 
193   verifyFormat("public static void Main(string[] args)\n"
194                "{\n"
195                "    string dirPath = args?[0];\n"
196                "}");
197 
198   Style.SpaceBeforeParens = FormatStyle::SBPO_Never;
199 
200   verifyFormat("switch(args?.Length) {}", Style);
201 }
202 
203 TEST_F(FormatTestCSharp, Attributes) {
204   verifyFormat("[STAThread]\n"
205                "static void Main(string[] args)\n"
206                "{\n"
207                "}");
208 
209   verifyFormat("[TestMethod]\n"
210                "private class Test\n"
211                "{\n"
212                "}");
213 
214   verifyFormat("[TestMethod]\n"
215                "protected class Test\n"
216                "{\n"
217                "}");
218 
219   verifyFormat("[TestMethod]\n"
220                "internal class Test\n"
221                "{\n"
222                "}");
223 
224   verifyFormat("[TestMethod]\n"
225                "class Test\n"
226                "{\n"
227                "}");
228 
229   verifyFormat("[TestMethod]\n"
230                "[DeploymentItem(\"Test.txt\")]\n"
231                "public class Test\n"
232                "{\n"
233                "}");
234 
235   verifyFormat("[System.AttributeUsage(System.AttributeTargets.Method)]\n"
236                "[System.Runtime.InteropServices.ComVisible(true)]\n"
237                "public sealed class STAThreadAttribute : Attribute\n"
238                "{\n"
239                "}");
240 
241   verifyFormat("[Verb(\"start\", HelpText = \"Starts the server listening on "
242                "provided port\")]\n"
243                "class Test\n"
244                "{\n"
245                "}");
246 
247   verifyFormat("[TestMethod]\n"
248                "public string Host { set; get; }");
249 
250   // Adjacent properties should not cause line wrapping issues
251   verifyFormat("[JsonProperty(\"foo\")]\n"
252                "public string Foo { set; get; }\n"
253                "[JsonProperty(\"bar\")]\n"
254                "public string Bar { set; get; }\n"
255                "[JsonProperty(\"bar\")]\n"
256                "protected string Bar { set; get; }\n"
257                "[JsonProperty(\"bar\")]\n"
258                "internal string Bar { set; get; }");
259 
260   // Multiple attributes should always be split (not just the first ones)
261   verifyFormat("[XmlIgnore]\n"
262                "[JsonProperty(\"foo\")]\n"
263                "public string Foo { set; get; }");
264 
265   verifyFormat("[XmlIgnore]\n"
266                "[JsonProperty(\"foo\")]\n"
267                "public string Foo { set; get; }\n"
268                "[XmlIgnore]\n"
269                "[JsonProperty(\"bar\")]\n"
270                "public string Bar { set; get; }");
271 
272   verifyFormat("[XmlIgnore]\n"
273                "[ScriptIgnore]\n"
274                "[JsonProperty(\"foo\")]\n"
275                "public string Foo { set; get; }\n"
276                "[XmlIgnore]\n"
277                "[ScriptIgnore]\n"
278                "[JsonProperty(\"bar\")]\n"
279                "public string Bar { set; get; }");
280 
281   verifyFormat("[TestMethod(\"start\", HelpText = \"Starts the server "
282                "listening on provided host\")]\n"
283                "public string Host { set; get; }");
284 
285   verifyFormat(
286       "[DllImport(\"Hello\", EntryPoint = \"hello_world\")]\n"
287       "// The const char* returned by hello_world must not be deleted.\n"
288       "private static extern IntPtr HelloFromCpp();)");
289 
290   // Class attributes go on their own line and do not affect layout of
291   // interfaces. Line wrapping decisions previously caused each interface to be
292   // on its own line.
293   verifyFormat("[SomeAttribute]\n"
294                "[SomeOtherAttribute]\n"
295                "public class A : IShape, IAnimal, IVehicle\n"
296                "{\n"
297                "    int X;\n"
298                "}");
299 
300   // Attributes in a method declaration do not cause line wrapping.
301   verifyFormat("void MethodA([In][Out] ref double x)\n"
302                "{\n"
303                "}");
304 
305   verifyFormat("void MethodA([In, Out] ref double x)\n"
306                "{\n"
307                "}");
308 
309   verifyFormat("void MethodA([In, Out] double[] x)\n"
310                "{\n"
311                "}");
312 
313   verifyFormat("void MethodA([In] double[] x)\n"
314                "{\n"
315                "}");
316 
317   verifyFormat("void MethodA(int[] x)\n"
318                "{\n"
319                "}");
320   verifyFormat("void MethodA(int[][] x)\n"
321                "{\n"
322                "}");
323   verifyFormat("void MethodA([] x)\n"
324                "{\n"
325                "}");
326 
327   verifyFormat("public void Log([CallerLineNumber] int line = -1, "
328                "[CallerFilePath] string path = null,\n"
329                "                [CallerMemberName] string name = null)\n"
330                "{\n"
331                "}");
332 
333   // [] in an attribute do not cause premature line wrapping or indenting.
334   verifyFormat(R"(//
335 public class A
336 {
337     [SomeAttribute(new[] { RED, GREEN, BLUE }, -1.0f, 1.0f)]
338     [DoNotSerialize]
339     public Data MemberVariable;
340 })");
341 
342   //  Unwrappable lines go on a line of their own.
343   // 'target:' is not treated as a label.
344   // Modify Style to enforce a column limit.
345   FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp);
346   Style.ColumnLimit = 10;
347   verifyFormat(R"([assembly:InternalsVisibleTo(
348     "SomeAssembly, PublicKey=SomePublicKeyThatExceedsTheColumnLimit")])",
349                Style);
350 }
351 
352 TEST_F(FormatTestCSharp, CSharpUsing) {
353   FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp);
354   Style.SpaceBeforeParens = FormatStyle::SBPO_Always;
355   verifyFormat("public void foo () {\n"
356                "  using (StreamWriter sw = new StreamWriter (filenameA)) {}\n"
357                "  using () {}\n"
358                "}",
359                Style);
360 
361   // Ensure clang-format affects top-level snippets correctly.
362   verifyFormat("using (StreamWriter sw = new StreamWriter (filenameB)) {}",
363                Style);
364 
365   Style.SpaceBeforeParens = FormatStyle::SBPO_Never;
366   verifyFormat("public void foo() {\n"
367                "  using(StreamWriter sw = new StreamWriter(filenameB)) {}\n"
368                "  using() {}\n"
369                "}",
370                Style);
371 
372   // Ensure clang-format affects top-level snippets correctly.
373   verifyFormat("using(StreamWriter sw = new StreamWriter(filenameB)) {}",
374                Style);
375 
376   Style.SpaceBeforeParens = FormatStyle::SBPO_ControlStatements;
377   verifyFormat("public void foo() {\n"
378                "  using (StreamWriter sw = new StreamWriter(filenameA)) {}\n"
379                "  using () {}\n"
380                "}",
381                Style);
382 
383   // Ensure clang-format affects top-level snippets correctly.
384   verifyFormat("using (StreamWriter sw = new StreamWriter(filenameB)) {}",
385                Style);
386 
387   Style.SpaceBeforeParens = FormatStyle::SBPO_NonEmptyParentheses;
388   verifyFormat("public void foo() {\n"
389                "  using (StreamWriter sw = new StreamWriter (filenameA)) {}\n"
390                "  using() {}\n"
391                "}",
392                Style);
393 
394   // Ensure clang-format affects top-level snippets correctly.
395   verifyFormat("using (StreamWriter sw = new StreamWriter (filenameB)) {}",
396                Style);
397 }
398 
399 TEST_F(FormatTestCSharp, CSharpRegions) {
400   verifyFormat("#region aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaa "
401                "aaaaaaaaaaaaaaa long region");
402 }
403 
404 TEST_F(FormatTestCSharp, CSharpKeyWordEscaping) {
405   // AfterEnum is true by default.
406   verifyFormat("public enum var\n"
407                "{\n"
408                "    none,\n"
409                "    @string,\n"
410                "    bool,\n"
411                "    @enum\n"
412                "}");
413 }
414 
415 TEST_F(FormatTestCSharp, CSharpNullCoalescing) {
416   verifyFormat("var test = ABC ?? DEF");
417   verifyFormat("string myname = name ?? \"ABC\";");
418   verifyFormat("return _name ?? \"DEF\";");
419 }
420 
421 TEST_F(FormatTestCSharp, CSharpNullCoalescingAssignment) {
422   FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp);
423   Style.SpaceBeforeAssignmentOperators = true;
424 
425   verifyFormat(R"(test ??= ABC;)", Style);
426   verifyFormat(R"(test ??= true;)", Style);
427 
428   Style.SpaceBeforeAssignmentOperators = false;
429 
430   verifyFormat(R"(test??= ABC;)", Style);
431   verifyFormat(R"(test??= true;)", Style);
432 }
433 
434 TEST_F(FormatTestCSharp, CSharpNullForgiving) {
435   FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp);
436 
437   verifyFormat("var test = null!;", Style);
438   verifyFormat("string test = someFunctionCall()! + \"ABC\"!", Style);
439   verifyFormat("int test = (1! + 2 + bar! + foo())!", Style);
440   verifyFormat(R"(test ??= !foo!;)", Style);
441   verifyFormat("test = !bar! ?? !foo!;", Style);
442   verifyFormat("bool test = !(!true && !true! || !null && !null! || !false && "
443                "!false! && !bar()! + (!foo()))!",
444                Style);
445 
446   // Check that line break keeps identifier with the bang.
447   Style.ColumnLimit = 14;
448 
449   verifyFormat("var test =\n"
450                "    foo!;",
451                Style);
452 }
453 
454 TEST_F(FormatTestCSharp, AttributesIndentation) {
455   FormatStyle Style = getMicrosoftStyle(FormatStyle::LK_CSharp);
456   Style.AlwaysBreakAfterReturnType = FormatStyle::RTBS_None;
457 
458   verifyFormat("[STAThread]\n"
459                "static void Main(string[] args)\n"
460                "{\n"
461                "}",
462                Style);
463 
464   verifyFormat("[STAThread]\n"
465                "void "
466                "veryLooooooooooooooongFunctionName(string[] args)\n"
467                "{\n"
468                "}",
469                Style);
470 
471   verifyFormat("[STAThread]\n"
472                "veryLoooooooooooooooooooongReturnType "
473                "veryLooooooooooooooongFunctionName(string[] args)\n"
474                "{\n"
475                "}",
476                Style);
477 
478   verifyFormat("[SuppressMessage(\"A\", \"B\", Justification = \"C\")]\n"
479                "public override X Y()\n"
480                "{\n"
481                "}\n",
482                Style);
483 
484   verifyFormat("[SuppressMessage]\n"
485                "public X Y()\n"
486                "{\n"
487                "}\n",
488                Style);
489 
490   verifyFormat("[SuppressMessage]\n"
491                "public override X Y()\n"
492                "{\n"
493                "}\n",
494                Style);
495 
496   verifyFormat("public A(B b) : base(b)\n"
497                "{\n"
498                "    [SuppressMessage]\n"
499                "    public override X Y()\n"
500                "    {\n"
501                "    }\n"
502                "}\n",
503                Style);
504 
505   verifyFormat("public A : Base\n"
506                "{\n"
507                "}\n"
508                "[Test]\n"
509                "public Foo()\n"
510                "{\n"
511                "}\n",
512                Style);
513 
514   verifyFormat("namespace\n"
515                "{\n"
516                "public A : Base\n"
517                "{\n"
518                "}\n"
519                "[Test]\n"
520                "public Foo()\n"
521                "{\n"
522                "}\n"
523                "}\n",
524                Style);
525 }
526 
527 TEST_F(FormatTestCSharp, CSharpSpaceBefore) {
528   FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp);
529   Style.SpaceBeforeParens = FormatStyle::SBPO_Always;
530 
531   verifyFormat("List<string> list;", Style);
532   verifyFormat("Dictionary<string, string> dict;", Style);
533 
534   verifyFormat("for (int i = 0; i < size (); i++) {\n"
535                "}",
536                Style);
537   verifyFormat("foreach (var x in y) {\n"
538                "}",
539                Style);
540   verifyFormat("switch (x) {}", Style);
541   verifyFormat("do {\n"
542                "} while (x);",
543                Style);
544 
545   Style.SpaceBeforeParens = FormatStyle::SBPO_Never;
546 
547   verifyFormat("List<string> list;", Style);
548   verifyFormat("Dictionary<string, string> dict;", Style);
549 
550   verifyFormat("for(int i = 0; i < size(); i++) {\n"
551                "}",
552                Style);
553   verifyFormat("foreach(var x in y) {\n"
554                "}",
555                Style);
556   verifyFormat("switch(x) {}", Style);
557   verifyFormat("do {\n"
558                "} while(x);",
559                Style);
560 }
561 
562 TEST_F(FormatTestCSharp, CSharpSpaceAfterCStyleCast) {
563   FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp);
564 
565   verifyFormat("(int)x / y;", Style);
566 
567   Style.SpaceAfterCStyleCast = true;
568   verifyFormat("(int) x / y;", Style);
569 }
570 
571 TEST_F(FormatTestCSharp, CSharpEscapedQuotesInVerbatimStrings) {
572   FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp);
573 
574   verifyFormat(R"(string str = @"""";)", Style);
575   verifyFormat(R"(string str = @"""Hello world""";)", Style);
576   verifyFormat(R"(string str = $@"""Hello {friend}""";)", Style);
577   verifyFormat(R"(return $@"Foo ""/foo?f={Request.Query["f"]}""";)", Style);
578   verifyFormat(R"(return @$"Foo ""/foo?f={Request.Query["f"]}""";)", Style);
579   verifyFormat(R"(return @$"path\to\{specifiedFile}")", Style);
580 }
581 
582 TEST_F(FormatTestCSharp, CSharpQuotesInInterpolatedStrings) {
583   FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp);
584 
585   verifyFormat(R"(string str1 = $"{null ?? "null"}";)", Style);
586   verifyFormat(R"(string str2 = $"{{{braceCount} braces";)", Style);
587   verifyFormat(R"(string str3 = $"{braceCount}}} braces";)", Style);
588 }
589 
590 TEST_F(FormatTestCSharp, CSharpNewlinesInVerbatimStrings) {
591   // Use MS style as Google Style inserts a line break before multiline strings.
592 
593   // verifyFormat does not understand multiline C# string-literals
594   // so check the format explicitly.
595 
596   FormatStyle Style = getMicrosoftStyle(FormatStyle::LK_CSharp);
597 
598   std::string Code = R"(string s1 = $@"some code:
599   class {className} {{
600     {className}() {{}}
601   }}";)";
602 
603   EXPECT_EQ(Code, format(Code, Style));
604 
605   // Multiline string in the middle of a function call.
606   Code = R"(
607 var x = foo(className, $@"some code:
608   class {className} {{
609     {className}() {{}}
610   }}",
611             y);)"; // y aligned with `className` arg.
612 
613   EXPECT_EQ(Code, format(Code, Style));
614 
615   // Interpolated string with embedded multiline string.
616   Code = R"(Console.WriteLine($"{string.Join(@",
617 		", values)}");)";
618 
619   EXPECT_EQ(Code, format(Code, Style));
620 }
621 
622 TEST_F(FormatTestCSharp, CSharpNewOperator) {
623   FormatStyle Style = getLLVMStyle(FormatStyle::LK_CSharp);
624 
625   verifyFormat("public void F() {\n"
626                "  var v = new C(() => { var t = 5; });\n"
627                "}",
628                Style);
629   verifyFormat("public void F() {\n"
630                "  var v = new C(() => {\n"
631                "    try {\n"
632                "    } catch {\n"
633                "      var t = 5;\n"
634                "    }\n"
635                "  });\n"
636                "}",
637                Style);
638 }
639 
640 TEST_F(FormatTestCSharp, CSharpLambdas) {
641   FormatStyle GoogleStyle = getGoogleStyle(FormatStyle::LK_CSharp);
642   FormatStyle MicrosoftStyle = getMicrosoftStyle(FormatStyle::LK_CSharp);
643 
644   verifyFormat(R"(//
645 class MyClass {
646   Action<string> greet = name => {
647     string greeting = $"Hello {name}!";
648     Console.WriteLine(greeting);
649   };
650 })",
651                GoogleStyle);
652 
653   // Microsoft Style:
654   // https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/statements-expressions-operators/lambda-expressions#statement-lambdas
655   verifyFormat(R"(//
656 class MyClass
657 {
658     Action<string> greet = name =>
659     {
660         string greeting = $"Hello {name}!";
661         Console.WriteLine(greeting);
662     };
663 })",
664                MicrosoftStyle);
665 
666   verifyFormat("void bar()\n"
667                "{\n"
668                "    Function(Val, (Action)(() =>\n"
669                "                           {\n"
670                "                               lock (mylock)\n"
671                "                               {\n"
672                "                                   if (true)\n"
673                "                                   {\n"
674                "                                       A.Remove(item);\n"
675                "                                   }\n"
676                "                               }\n"
677                "                           }));\n"
678                "}",
679                MicrosoftStyle);
680 
681   verifyFormat("void baz()\n"
682                "{\n"
683                "    Function(Val, (Action)(() =>\n"
684                "                           {\n"
685                "                               using (var a = new Lock())\n"
686                "                               {\n"
687                "                                   if (true)\n"
688                "                                   {\n"
689                "                                       A.Remove(item);\n"
690                "                                   }\n"
691                "                               }\n"
692                "                           }));\n"
693                "}",
694                MicrosoftStyle);
695 
696   verifyFormat("void baz()\n"
697                "{\n"
698                "    Function(Val, (Action)(() =>\n"
699                "                           {\n"
700                "                               if (true)\n"
701                "                               {\n"
702                "                                   A.Remove(item);\n"
703                "                               }\n"
704                "                           }));\n"
705                "}",
706                MicrosoftStyle);
707 
708   verifyFormat("void baz()\n"
709                "{\n"
710                "    Function(Val, (Action)(() =>\n"
711                "                           {\n"
712                "                               do\n"
713                "                               {\n"
714                "                                   A.Remove(item);\n"
715                "                               } while (true)\n"
716                "                           }));\n"
717                "}",
718                MicrosoftStyle);
719 
720   verifyFormat("void baz()\n"
721                "{\n"
722                "    Function(Val, (Action)(() =>\n"
723                "                           { A.Remove(item); }));\n"
724                "}",
725                MicrosoftStyle);
726 
727   verifyFormat("void bar()\n"
728                "{\n"
729                "    Function(Val, (() =>\n"
730                "                   {\n"
731                "                       lock (mylock)\n"
732                "                       {\n"
733                "                           if (true)\n"
734                "                           {\n"
735                "                               A.Remove(item);\n"
736                "                           }\n"
737                "                       }\n"
738                "                   }));\n"
739                "}",
740                MicrosoftStyle);
741   verifyFormat("void bar()\n"
742                "{\n"
743                "    Function((() =>\n"
744                "              {\n"
745                "                  lock (mylock)\n"
746                "                  {\n"
747                "                      if (true)\n"
748                "                      {\n"
749                "                          A.Remove(item);\n"
750                "                      }\n"
751                "                  }\n"
752                "              }));\n"
753                "}",
754                MicrosoftStyle);
755 
756   MicrosoftStyle.IndentWidth = 2;
757   verifyFormat("void bar()\n"
758                "{\n"
759                "  Function((() =>\n"
760                "            {\n"
761                "              lock (mylock)\n"
762                "              {\n"
763                "                if (true)\n"
764                "                {\n"
765                "                  A.Remove(item);\n"
766                "                }\n"
767                "              }\n"
768                "            }));\n"
769                "}",
770                MicrosoftStyle);
771   verifyFormat("void bar() {\n"
772                "  Function((() => {\n"
773                "    lock (mylock) {\n"
774                "      if (true) {\n"
775                "        A.Remove(item);\n"
776                "      }\n"
777                "    }\n"
778                "  }));\n"
779                "}",
780                GoogleStyle);
781 }
782 
783 TEST_F(FormatTestCSharp, CSharpLambdasDontBreakFollowingCodeAlignment) {
784   FormatStyle GoogleStyle = getGoogleStyle(FormatStyle::LK_CSharp);
785   FormatStyle MicrosoftStyle = getMicrosoftStyle(FormatStyle::LK_CSharp);
786 
787   verifyFormat(R"(//
788 public class Sample
789 {
790     public void Test()
791     {
792         while (true)
793         {
794             preBindEnumerators.RemoveAll(enumerator => !enumerator.MoveNext());
795             CodeThatFollowsLambda();
796             IsWellAligned();
797         }
798     }
799 })",
800                MicrosoftStyle);
801 
802   verifyFormat(R"(//
803 public class Sample {
804   public void Test() {
805     while (true) {
806       preBindEnumerators.RemoveAll(enumerator => !enumerator.MoveNext());
807       CodeThatFollowsLambda();
808       IsWellAligned();
809     }
810   }
811 })",
812                GoogleStyle);
813 }
814 
815 TEST_F(FormatTestCSharp, CSharpLambdasComplexLambdasDontBreakAlignment) {
816   FormatStyle GoogleStyle = getGoogleStyle(FormatStyle::LK_CSharp);
817   FormatStyle MicrosoftStyle = getMicrosoftStyle(FormatStyle::LK_CSharp);
818 
819   verifyFormat(R"(//
820 public class Test
821 {
822     private static void ComplexLambda(BuildReport protoReport)
823     {
824         allSelectedScenes =
825             veryVeryLongCollectionNameThatPutsTheLineLenghtAboveTheThresholds.Where(scene => scene.enabled)
826                 .Select(scene => scene.path)
827                 .ToArray();
828         if (allSelectedScenes.Count == 0)
829         {
830             return;
831         }
832         Functions();
833         AreWell();
834         Aligned();
835         AfterLambdaBlock();
836     }
837 })",
838                MicrosoftStyle);
839 
840   verifyFormat(R"(//
841 public class Test {
842   private static void ComplexLambda(BuildReport protoReport) {
843     allSelectedScenes = veryVeryLongCollectionNameThatPutsTheLineLenghtAboveTheThresholds
844                             .Where(scene => scene.enabled)
845                             .Select(scene => scene.path)
846                             .ToArray();
847     if (allSelectedScenes.Count == 0) {
848       return;
849     }
850     Functions();
851     AreWell();
852     Aligned();
853     AfterLambdaBlock();
854   }
855 })",
856                GoogleStyle);
857 }
858 
859 TEST_F(FormatTestCSharp, CSharpLambdasMulipleLambdasDontBreakAlignment) {
860   FormatStyle GoogleStyle = getGoogleStyle(FormatStyle::LK_CSharp);
861   FormatStyle MicrosoftStyle = getMicrosoftStyle(FormatStyle::LK_CSharp);
862 
863   verifyFormat(R"(//
864 public class Test
865 {
866     private static void MultipleLambdas(BuildReport protoReport)
867     {
868         allSelectedScenes =
869             veryVeryLongCollectionNameThatPutsTheLineLenghtAboveTheThresholds.Where(scene => scene.enabled)
870                 .Select(scene => scene.path)
871                 .ToArray();
872         preBindEnumerators.RemoveAll(enumerator => !enumerator.MoveNext());
873         if (allSelectedScenes.Count == 0)
874         {
875             return;
876         }
877         Functions();
878         AreWell();
879         Aligned();
880         AfterLambdaBlock();
881     }
882 })",
883                MicrosoftStyle);
884 
885   verifyFormat(R"(//
886 public class Test {
887   private static void MultipleLambdas(BuildReport protoReport) {
888     allSelectedScenes = veryVeryLongCollectionNameThatPutsTheLineLenghtAboveTheThresholds
889                             .Where(scene => scene.enabled)
890                             .Select(scene => scene.path)
891                             .ToArray();
892     preBindEnumerators.RemoveAll(enumerator => !enumerator.MoveNext());
893     if (allSelectedScenes.Count == 0) {
894       return;
895     }
896     Functions();
897     AreWell();
898     Aligned();
899     AfterLambdaBlock();
900   }
901 })",
902                GoogleStyle);
903 }
904 
905 TEST_F(FormatTestCSharp, CSharpObjectInitializers) {
906   FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp);
907 
908   // Start code fragments with a comment line so that C++ raw string literals
909   // as seen are identical to expected formatted code.
910 
911   verifyFormat(R"(//
912 Shape[] shapes = new[] {
913   new Circle {
914     Radius = 2.7281,
915     Colour = Colours.Red,
916   },
917   new Square {
918     Side = 101.1,
919     Colour = Colours.Yellow,
920   },
921 };)",
922                Style);
923 
924   // Omitted final `,`s will change the formatting.
925   verifyFormat(R"(//
926 Shape[] shapes = new[] { new Circle { Radius = 2.7281, Colour = Colours.Red },
927                          new Square { Side = 101.1, Colour = Colours.Yellow } };)",
928                Style);
929 
930   // Lambdas can be supplied as initialiser arguments.
931   verifyFormat(R"(//
932 private Transformer _transformer = new X.Y {
933   Filler = (Shape shape) => { return new Transform.Fill(shape, RED); },
934   Scaler = (Shape shape) => { return new Transform.Resize(shape, 0.1); },
935 };)",
936                Style);
937 
938   // Dictionary initialisation.
939   verifyFormat(R"(//
940 var myDict = new Dictionary<string, string> {
941   ["name"] = _donald,
942   ["age"] = Convert.ToString(DateTime.Today.Year - 1934),
943   ["type"] = _duck,
944 };)",
945                Style);
946 }
947 
948 TEST_F(FormatTestCSharp, CSharpArrayInitializers) {
949   FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp);
950 
951   verifyFormat(R"(//
952 private MySet<Node>[] setPoints = {
953   new Point<Node>(),
954   new Point<Node>(),
955 };)",
956                Style);
957 }
958 
959 TEST_F(FormatTestCSharp, CSharpNamedArguments) {
960   FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp);
961 
962   verifyFormat(R"(//
963 PrintOrderDetails(orderNum: 31, productName: "Red Mug", sellerName: "Gift Shop");)",
964                Style);
965 
966   // Ensure that trailing comments do not cause problems.
967   verifyFormat(R"(//
968 PrintOrderDetails(orderNum: 31, productName: "Red Mug",  // comment
969                   sellerName: "Gift Shop");)",
970                Style);
971 
972   verifyFormat(R"(foreach (var tickCount in task.Begin(seed: 0)) {)", Style);
973 }
974 
975 TEST_F(FormatTestCSharp, CSharpPropertyAccessors) {
976   FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp);
977 
978   verifyFormat("int Value { get }", Style);
979   verifyFormat("int Value { get; }", Style);
980   verifyFormat("int Value { internal get; }", Style);
981   verifyFormat("int Value { get; } = 0", Style);
982   verifyFormat("int Value { set }", Style);
983   verifyFormat("int Value { set; }", Style);
984   verifyFormat("int Value { init; }", Style);
985   verifyFormat("int Value { internal set; }", Style);
986   verifyFormat("int Value { set; } = 0", Style);
987   verifyFormat("int Value { get; set }", Style);
988   verifyFormat("int Value { get; init; }", Style);
989   verifyFormat("int Value { set; get }", Style);
990   verifyFormat("int Value { get; private set; }", Style);
991   verifyFormat("int Value { get; set; }", Style);
992   verifyFormat("int Value { get; set; } = 0", Style);
993   verifyFormat("int Value { internal get; internal set; }", Style);
994 
995   // Do not wrap expression body definitions.
996   verifyFormat(R"(//
997 public string Name {
998   get => _name;
999   set => _name = value;
1000 })",
1001                Style);
1002   verifyFormat(R"(//
1003 public string Name {
1004   init => _name = value;
1005   get => _name;
1006 })",
1007                Style);
1008   verifyFormat(R"(//
1009 public string Name {
1010   set => _name = value;
1011   get => _name;
1012 })",
1013                Style);
1014 
1015   // Examples taken from
1016   // https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/properties
1017   verifyFormat(R"(
1018 // Expression body definitions
1019 public class SaleItem {
1020   public decimal Price {
1021     get => _cost;
1022     set => _cost = value;
1023   }
1024 })",
1025                Style);
1026 
1027   verifyFormat(R"(
1028 // Properties with backing fields
1029 class TimePeriod {
1030   public double Hours {
1031     get { return _seconds / 3600; }
1032     set {
1033       if (value < 0 || value > 24)
1034         throw new ArgumentOutOfRangeException($"{nameof(value)} must be between 0 and 24.");
1035       _seconds = value * 3600;
1036     }
1037   }
1038 })",
1039                Style);
1040 
1041   verifyFormat(R"(
1042 // Auto-implemented properties
1043 public class SaleItem {
1044   public decimal Price { get; set; }
1045 })",
1046                Style);
1047 
1048   // Add column limit to wrap long lines.
1049   Style.ColumnLimit = 100;
1050 
1051   // Examples with assignment to default value.
1052   verifyFormat(R"(
1053 // Long assignment to default value
1054 class MyClass {
1055   public override VeryLongNamedTypeIndeed VeryLongNamedValue { get; set } =
1056       VeryLongNamedTypeIndeed.Create(DefaultFirstArgument, DefaultSecondArgument,
1057                                      DefaultThirdArgument);
1058 })",
1059                Style);
1060 
1061   verifyFormat(R"(
1062 // Long assignment to default value with expression body
1063 class MyClass {
1064   public override VeryLongNamedTypeIndeed VeryLongNamedValue {
1065     get => veryLongNamedField;
1066     set => veryLongNamedField = value;
1067   } = VeryLongNamedTypeIndeed.Create(DefaultFirstArgument, DefaultSecondArgument,
1068                                      DefaultThirdArgument);
1069 })",
1070                Style);
1071 
1072   // Brace wrapping and single-lining of accessor can be controlled by config.
1073   Style.AllowShortBlocksOnASingleLine = FormatStyle::SBS_Never;
1074   Style.BreakBeforeBraces = FormatStyle::BS_Custom;
1075   Style.BraceWrapping.AfterFunction = true;
1076 
1077   verifyFormat(R"(//
1078 class TimePeriod {
1079   public double Hours
1080   {
1081     get {
1082       return _seconds / 3600;
1083     }
1084     set {
1085       _seconds = value * 3600;
1086     }
1087   }
1088 })",
1089                Style);
1090 
1091   // Microsoft style trivial property accessors have no line break before the
1092   // opening brace.
1093   auto MicrosoftStyle = getMicrosoftStyle(FormatStyle::LK_CSharp);
1094   verifyFormat(R"(//
1095 public class SaleItem
1096 {
1097     public decimal Price { get; set; }
1098 })",
1099                MicrosoftStyle);
1100 }
1101 
1102 TEST_F(FormatTestCSharp, DefaultLiteral) {
1103   FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp);
1104 
1105   verifyFormat(
1106       "T[] InitializeArray<T>(int length, T initialValue = default) {}", Style);
1107   verifyFormat("System.Numerics.Complex fillValue = default;", Style);
1108   verifyFormat("int Value { get } = default;", Style);
1109   verifyFormat("int Value { get } = default!;", Style);
1110   verifyFormat(R"(//
1111 public record Person {
1112   public string GetInit { get; init; } = default!;
1113 };)",
1114                Style);
1115   verifyFormat(R"(//
1116 public record Person {
1117   public string GetSet { get; set; } = default!;
1118 };)",
1119                Style);
1120 }
1121 
1122 TEST_F(FormatTestCSharp, CSharpSpaces) {
1123   FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp);
1124   Style.SpaceBeforeSquareBrackets = false;
1125   Style.SpacesInSquareBrackets = false;
1126   Style.SpaceBeforeCpp11BracedList = true;
1127   Style.Cpp11BracedListStyle = false;
1128   Style.SpacesInContainerLiterals = false;
1129   Style.SpaceAfterCStyleCast = false;
1130 
1131   verifyFormat(R"(new Car { "Door", 0.1 })", Style);
1132   verifyFormat(R"(new Car { 0.1, "Door" })", Style);
1133   verifyFormat(R"(new string[] { "A" })", Style);
1134   verifyFormat(R"(new string[] {})", Style);
1135   verifyFormat(R"(new Car { someVariableName })", Style);
1136   verifyFormat(R"(new Car { someVariableName })", Style);
1137   verifyFormat(R"(new Dictionary<string, string> { ["Key"] = "Value" };)",
1138                Style);
1139   verifyFormat(R"(Apply(x => x.Name, x => () => x.ID);)", Style);
1140   verifyFormat(R"(bool[] xs = { true, true };)", Style);
1141   verifyFormat(R"(taskContext.Factory.Run(async () => doThing(args);)", Style);
1142   verifyFormat(R"(catch (TestException) when (innerFinallyExecuted))", Style);
1143   verifyFormat(R"(private float[,] Values;)", Style);
1144   verifyFormat(R"(Result this[Index x] => Foo(x);)", Style);
1145 
1146   verifyFormat(R"(char[,,] rawCharArray = MakeCharacterGrid();)", Style);
1147   verifyFormat(R"(var (key, value))", Style);
1148 
1149   // `&&` is not seen as a reference.
1150   verifyFormat(R"(A == typeof(X) && someBool)", Style);
1151 
1152   // Not seen as a C-style cast.
1153   verifyFormat(R"(//
1154 foreach ((A a, B b) in someList) {
1155 })",
1156                Style);
1157 
1158   // space after lock in `lock (processes)`.
1159   verifyFormat("lock (process)", Style);
1160 
1161   Style.SpacesInSquareBrackets = true;
1162   verifyFormat(R"(private float[ , ] Values;)", Style);
1163   verifyFormat(R"(string dirPath = args?[ 0 ];)", Style);
1164   verifyFormat(R"(char[ ,, ] rawCharArray = MakeCharacterGrid();)", Style);
1165 
1166   // Method returning tuple
1167   verifyFormat(R"(public (string name, int age) methodTuple() {})", Style);
1168   verifyFormat(R"(private (string name, int age) methodTuple() {})", Style);
1169   verifyFormat(R"(protected (string name, int age) methodTuple() {})", Style);
1170   verifyFormat(R"(virtual (string name, int age) methodTuple() {})", Style);
1171   verifyFormat(R"(extern (string name, int age) methodTuple() {})", Style);
1172   verifyFormat(R"(static (string name, int age) methodTuple() {})", Style);
1173   verifyFormat(R"(internal (string name, int age) methodTuple() {})", Style);
1174   verifyFormat(R"(abstract (string name, int age) methodTuple() {})", Style);
1175   verifyFormat(R"(sealed (string name, int age) methodTuple() {})", Style);
1176   verifyFormat(R"(override (string name, int age) methodTuple() {})", Style);
1177   verifyFormat(R"(async (string name, int age) methodTuple() {})", Style);
1178   verifyFormat(R"(unsafe (string name, int age) methodTuple() {})", Style);
1179 
1180   Style.SpacesInSquareBrackets = false;
1181   Style.SpaceBeforeSquareBrackets = true;
1182   verifyFormat("return a is [1, 2, 3];", Style);
1183   verifyFormat("return a is [..];", Style);
1184   Style.SpaceBeforeSquareBrackets = false;
1185   verifyFormat("return a is [1, 2, 3];", Style);
1186   verifyFormat("return a is [..];", Style);
1187 }
1188 
1189 TEST_F(FormatTestCSharp, CSharpNullableTypes) {
1190   FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp);
1191   Style.SpacesInSquareBrackets = false;
1192 
1193   verifyFormat(R"(//
1194 public class A {
1195   void foo() {
1196     int? value = some.bar();
1197   }
1198 })",
1199                Style); // int? is nullable not a conditional expression.
1200 
1201   verifyFormat(R"(void foo(int? x, int? y, int? z) {})",
1202                Style); // Nullables in function definitions.
1203 
1204   verifyFormat(R"(public float? Value;)", Style); // no space before `?`.
1205 
1206   verifyFormat(R"(int?[] arr = new int?[10];)",
1207                Style); // An array of a nullable type.
1208 
1209   verifyFormat(R"(var x = (int?)y;)", Style); // Cast to a nullable type.
1210 
1211   verifyFormat(R"(var x = new MyContainer<int?>();)", Style); // Generics.
1212 
1213   verifyFormat(R"(//
1214 public interface I {
1215   int? Function();
1216 })",
1217                Style); // Interface methods.
1218 
1219   Style.ColumnLimit = 10;
1220   verifyFormat(R"(//
1221 public VeryLongType? Function(
1222     int arg1,
1223     int arg2) {
1224   //
1225 })",
1226                Style); // ? sticks with identifier.
1227 }
1228 
1229 TEST_F(FormatTestCSharp, CSharpArraySubscripts) {
1230   FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp);
1231 
1232   // Do not format array subscript operators as attributes.
1233   verifyFormat(R"(//
1234 if (someThings[index].Contains(myThing)) {
1235 })",
1236                Style);
1237 
1238   verifyFormat(R"(//
1239 if (someThings[i][j][k].Contains(myThing)) {
1240 })",
1241                Style);
1242 }
1243 
1244 TEST_F(FormatTestCSharp, CSharpGenericTypeConstraints) {
1245   FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp);
1246 
1247   EXPECT_TRUE(Style.BraceWrapping.SplitEmptyRecord);
1248 
1249   verifyFormat("class ItemFactory<T>\n"
1250                "    where T : new() {\n"
1251                "}",
1252                Style);
1253 
1254   verifyFormat("class Dictionary<TKey, TVal>\n"
1255                "    where TKey : IComparable<TKey>\n"
1256                "    where TVal : IMyInterface {\n"
1257                "  public void MyMethod<T>(T t)\n"
1258                "      where T : IMyInterface {\n"
1259                "    doThing();\n"
1260                "  }\n"
1261                "}",
1262                Style);
1263 
1264   verifyFormat("class ItemFactory<T>\n"
1265                "    where T : new(), IAnInterface<T>, IAnotherInterface<T>, "
1266                "IAnotherInterfaceStill<T> {\n"
1267                "}",
1268                Style);
1269 
1270   Style.ColumnLimit = 50; // Force lines to be wrapped.
1271   verifyFormat(R"(//
1272 class ItemFactory<T, U>
1273     where T : new(),
1274               IAnInterface<T>,
1275               IAnotherInterface<T, U>,
1276               IAnotherInterfaceStill<T, U> {
1277 })",
1278                Style);
1279 
1280   // In other languages `where` can be used as a normal identifier.
1281   // This example is in C++!
1282   verifyFormat(R"(//
1283 class A {
1284   int f(int where) {}
1285 };)",
1286                getGoogleStyle(FormatStyle::LK_Cpp));
1287 }
1288 
1289 TEST_F(FormatTestCSharp, CSharpAfterEnum) {
1290   FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp);
1291   Style.BreakBeforeBraces = FormatStyle::BS_Custom;
1292   Style.BraceWrapping.AfterEnum = false;
1293   Style.AllowShortEnumsOnASingleLine = false;
1294 
1295   verifyFormat("enum MyEnum {\n"
1296                "  Foo,\n"
1297                "  Bar,\n"
1298                "}",
1299                Style);
1300   verifyFormat("internal enum MyEnum {\n"
1301                "  Foo,\n"
1302                "  Bar,\n"
1303                "}",
1304                Style);
1305   verifyFormat("public enum MyEnum {\n"
1306                "  Foo,\n"
1307                "  Bar,\n"
1308                "}",
1309                Style);
1310   verifyFormat("protected enum MyEnum {\n"
1311                "  Foo,\n"
1312                "  Bar,\n"
1313                "}",
1314                Style);
1315   verifyFormat("private enum MyEnum {\n"
1316                "  Foo,\n"
1317                "  Bar,\n"
1318                "}",
1319                Style);
1320 
1321   Style.BraceWrapping.AfterEnum = true;
1322   Style.AllowShortEnumsOnASingleLine = false;
1323 
1324   verifyFormat("enum MyEnum\n"
1325                "{\n"
1326                "  Foo,\n"
1327                "  Bar,\n"
1328                "}",
1329                Style);
1330   verifyFormat("internal enum MyEnum\n"
1331                "{\n"
1332                "  Foo,\n"
1333                "  Bar,\n"
1334                "}",
1335                Style);
1336   verifyFormat("public enum MyEnum\n"
1337                "{\n"
1338                "  Foo,\n"
1339                "  Bar,\n"
1340                "}",
1341                Style);
1342   verifyFormat("protected enum MyEnum\n"
1343                "{\n"
1344                "  Foo,\n"
1345                "  Bar,\n"
1346                "}",
1347                Style);
1348   verifyFormat("private enum MyEnum\n"
1349                "{\n"
1350                "  Foo,\n"
1351                "  Bar,\n"
1352                "}",
1353                Style);
1354   verifyFormat("/* Foo */ private enum MyEnum\n"
1355                "{\n"
1356                "  Foo,\n"
1357                "  Bar,\n"
1358                "}",
1359                Style);
1360   verifyFormat("/* Foo */ /* Bar */ private enum MyEnum\n"
1361                "{\n"
1362                "  Foo,\n"
1363                "  Bar,\n"
1364                "}",
1365                Style);
1366 }
1367 
1368 TEST_F(FormatTestCSharp, CSharpAfterClass) {
1369   FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp);
1370   Style.BreakBeforeBraces = FormatStyle::BS_Custom;
1371   Style.BraceWrapping.AfterClass = false;
1372 
1373   verifyFormat("class MyClass {\n"
1374                "  int a;\n"
1375                "  int b;\n"
1376                "}",
1377                Style);
1378   verifyFormat("internal class MyClass {\n"
1379                "  int a;\n"
1380                "  int b;\n"
1381                "}",
1382                Style);
1383   verifyFormat("public class MyClass {\n"
1384                "  int a;\n"
1385                "  int b;\n"
1386                "}",
1387                Style);
1388   verifyFormat("protected class MyClass {\n"
1389                "  int a;\n"
1390                "  int b;\n"
1391                "}",
1392                Style);
1393   verifyFormat("private class MyClass {\n"
1394                "  int a;\n"
1395                "  int b;\n"
1396                "}",
1397                Style);
1398 
1399   verifyFormat("interface Interface {\n"
1400                "  int a;\n"
1401                "  int b;\n"
1402                "}",
1403                Style);
1404   verifyFormat("internal interface Interface {\n"
1405                "  int a;\n"
1406                "  int b;\n"
1407                "}",
1408                Style);
1409   verifyFormat("public interface Interface {\n"
1410                "  int a;\n"
1411                "  int b;\n"
1412                "}",
1413                Style);
1414   verifyFormat("protected interface Interface {\n"
1415                "  int a;\n"
1416                "  int b;\n"
1417                "}",
1418                Style);
1419   verifyFormat("private interface Interface {\n"
1420                "  int a;\n"
1421                "  int b;\n"
1422                "}",
1423                Style);
1424 
1425   Style.BraceWrapping.AfterClass = true;
1426 
1427   verifyFormat("class MyClass\n"
1428                "{\n"
1429                "  int a;\n"
1430                "  int b;\n"
1431                "}",
1432                Style);
1433   verifyFormat("internal class MyClass\n"
1434                "{\n"
1435                "  int a;\n"
1436                "  int b;\n"
1437                "}",
1438                Style);
1439   verifyFormat("public class MyClass\n"
1440                "{\n"
1441                "  int a;\n"
1442                "  int b;\n"
1443                "}",
1444                Style);
1445   verifyFormat("protected class MyClass\n"
1446                "{\n"
1447                "  int a;\n"
1448                "  int b;\n"
1449                "}",
1450                Style);
1451   verifyFormat("private class MyClass\n"
1452                "{\n"
1453                "  int a;\n"
1454                "  int b;\n"
1455                "}",
1456                Style);
1457 
1458   verifyFormat("interface MyInterface\n"
1459                "{\n"
1460                "  int a;\n"
1461                "  int b;\n"
1462                "}",
1463                Style);
1464   verifyFormat("internal interface MyInterface\n"
1465                "{\n"
1466                "  int a;\n"
1467                "  int b;\n"
1468                "}",
1469                Style);
1470   verifyFormat("public interface MyInterface\n"
1471                "{\n"
1472                "  int a;\n"
1473                "  int b;\n"
1474                "}",
1475                Style);
1476   verifyFormat("protected interface MyInterface\n"
1477                "{\n"
1478                "  int a;\n"
1479                "  int b;\n"
1480                "}",
1481                Style);
1482   verifyFormat("private interface MyInterface\n"
1483                "{\n"
1484                "  int a;\n"
1485                "  int b;\n"
1486                "}",
1487                Style);
1488   verifyFormat("/* Foo */ private interface MyInterface\n"
1489                "{\n"
1490                "  int a;\n"
1491                "  int b;\n"
1492                "}",
1493                Style);
1494   verifyFormat("/* Foo */ /* Bar */ private interface MyInterface\n"
1495                "{\n"
1496                "  int a;\n"
1497                "  int b;\n"
1498                "}",
1499                Style);
1500 }
1501 
1502 TEST_F(FormatTestCSharp, NamespaceIndentation) {
1503   FormatStyle Style = getMicrosoftStyle(FormatStyle::LK_CSharp);
1504   Style.NamespaceIndentation = FormatStyle::NI_None;
1505 
1506   verifyFormat("namespace A\n"
1507                "{\n"
1508                "public interface Name1\n"
1509                "{\n"
1510                "}\n"
1511                "}\n",
1512                Style);
1513 
1514   verifyFormat("namespace A.B\n"
1515                "{\n"
1516                "public interface Name1\n"
1517                "{\n"
1518                "}\n"
1519                "}\n",
1520                Style);
1521 
1522   Style.NamespaceIndentation = FormatStyle::NI_Inner;
1523 
1524   verifyFormat("namespace A\n"
1525                "{\n"
1526                "namespace B\n"
1527                "{\n"
1528                "    public interface Name1\n"
1529                "    {\n"
1530                "    }\n"
1531                "}\n"
1532                "}\n",
1533                Style);
1534 
1535   Style.NamespaceIndentation = FormatStyle::NI_All;
1536 
1537   verifyFormat("namespace A.B\n"
1538                "{\n"
1539                "    public interface Name1\n"
1540                "    {\n"
1541                "    }\n"
1542                "}\n",
1543                Style);
1544 
1545   verifyFormat("namespace A\n"
1546                "{\n"
1547                "    namespace B\n"
1548                "    {\n"
1549                "        public interface Name1\n"
1550                "        {\n"
1551                "        }\n"
1552                "    }\n"
1553                "}\n",
1554                Style);
1555 }
1556 
1557 TEST_F(FormatTestCSharp, SwitchExpression) {
1558   FormatStyle Style = getMicrosoftStyle(FormatStyle::LK_CSharp);
1559   verifyFormat("int x = a switch {\n"
1560                "    1 => (0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0),\n"
1561                "    2 => 1,\n"
1562                "    _ => 2\n"
1563                "};\n",
1564                Style);
1565 }
1566 
1567 TEST_F(FormatTestCSharp, EmptyShortBlock) {
1568   auto Style = getLLVMStyle();
1569   Style.AllowShortBlocksOnASingleLine = FormatStyle::SBS_Empty;
1570 
1571   verifyFormat("try {\n"
1572                "  doA();\n"
1573                "} catch (Exception e) {\n"
1574                "  e.printStackTrace();\n"
1575                "}\n",
1576                Style);
1577 
1578   verifyFormat("try {\n"
1579                "  doA();\n"
1580                "} catch (Exception e) {}\n",
1581                Style);
1582 }
1583 
1584 TEST_F(FormatTestCSharp, ShortFunctions) {
1585   FormatStyle Style = getLLVMStyle(FormatStyle::LK_CSharp);
1586   Style.NamespaceIndentation = FormatStyle::NI_All;
1587   Style.AllowShortFunctionsOnASingleLine = FormatStyle::SFS_Inline;
1588   verifyFormat("interface Interface {\n"
1589                "  void f() { return; }\n"
1590                "};",
1591                Style);
1592   verifyFormat("public interface Interface {\n"
1593                "  void f() { return; }\n"
1594                "};",
1595                Style);
1596   verifyFormat("namespace {\n"
1597                "  void f() {\n"
1598                "    return;\n"
1599                "  }\n"
1600                "};",
1601                Style);
1602   // "union" is not a keyword in C#.
1603   verifyFormat("namespace union {\n"
1604                "  void f() {\n"
1605                "    return;\n"
1606                "  }\n"
1607                "};",
1608                Style);
1609 }
1610 
1611 TEST_F(FormatTestCSharp, BrokenBrackets) {
1612   EXPECT_NE("", format("int where b <")); // reduced from crasher
1613 }
1614 
1615 } // namespace format
1616 } // end namespace clang
1617