xref: /llvm-project/clang/unittests/Format/FormatTestCSharp.cpp (revision a2f963bb61e3e83287ea9eecd39198051b0c1cef)
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 
75 TEST_F(FormatTestCSharp, AccessModifiers) {
76   verifyFormat("public String toString()\n"
77                "{\n"
78                "}");
79   verifyFormat("private String toString()\n"
80                "{\n"
81                "}");
82   verifyFormat("protected String toString()\n"
83                "{\n"
84                "}");
85   verifyFormat("internal String toString()\n"
86                "{\n"
87                "}");
88 
89   verifyFormat("public override String toString()\n"
90                "{\n"
91                "}");
92   verifyFormat("private override String toString()\n"
93                "{\n"
94                "}");
95   verifyFormat("protected override String toString()\n"
96                "{\n"
97                "}");
98   verifyFormat("internal override String toString()\n"
99                "{\n"
100                "}");
101 
102   verifyFormat("internal static String toString()\n"
103                "{\n"
104                "}");
105 }
106 
107 TEST_F(FormatTestCSharp, NoStringLiteralBreaks) {
108   verifyFormat("foo("
109                "\"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
110                "aaaaaa\");");
111 }
112 
113 TEST_F(FormatTestCSharp, CSharpVerbatiumStringLiterals) {
114   verifyFormat("foo(@\"aaaaaaaa\\abc\\aaaa\");");
115   // @"ABC\" + ToString("B") - handle embedded \ in literal string at
116   // the end
117   //
118   /*
119    * After removal of Lexer change we are currently not able
120    * To handle these cases
121    verifyFormat("string s = @\"ABC\\\" + ToString(\"B\");");
122    verifyFormat("string s = @\"ABC\"\"DEF\"\"GHI\"");
123    verifyFormat("string s = @\"ABC\"\"DEF\"\"\"");
124    verifyFormat("string s = @\"ABC\"\"DEF\"\"\" + abc");
125   */
126 }
127 
128 TEST_F(FormatTestCSharp, CSharpInterpolatedStringLiterals) {
129   verifyFormat("foo($\"aaaaaaaa{aaa}aaaa\");");
130   verifyFormat("foo($\"aaaa{A}\");");
131   verifyFormat(
132       "foo($\"aaaa{A}"
133       "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\");");
134   verifyFormat("Name = $\"{firstName} {lastName}\";");
135 
136   // $"ABC\" + ToString("B") - handle embedded \ in literal string at
137   // the end
138   verifyFormat("string s = $\"A{abc}BC\" + ToString(\"B\");");
139   verifyFormat("$\"{domain}\\\\{user}\"");
140   verifyFormat(
141       "var verbatimInterpolated = $@\"C:\\Users\\{userName}\\Documents\\\";");
142 }
143 
144 TEST_F(FormatTestCSharp, CSharpFatArrows) {
145   verifyFormat("Task serverTask = Task.Run(async() => {");
146   verifyFormat("public override string ToString() => \"{Name}\\{Age}\";");
147 }
148 
149 TEST_F(FormatTestCSharp, CSharpNullConditional) {
150   verifyFormat(
151       "public Person(string firstName, string lastName, int? age=null)");
152 
153   verifyFormat("switch(args?.Length)");
154 
155   verifyFormat("public static void Main(string[] args)\n"
156                "{\n"
157                "    string dirPath = args?[0];\n"
158                "}");
159 }
160 
161 TEST_F(FormatTestCSharp, Attributes) {
162   verifyFormat("[STAThread]\n"
163                "static void Main(string[] args)\n"
164                "{\n"
165                "}");
166 
167   verifyFormat("[TestMethod]\n"
168                "private class Test\n"
169                "{\n"
170                "}");
171 
172   verifyFormat("[TestMethod]\n"
173                "protected class Test\n"
174                "{\n"
175                "}");
176 
177   verifyFormat("[TestMethod]\n"
178                "internal class Test\n"
179                "{\n"
180                "}");
181 
182   verifyFormat("[TestMethod]\n"
183                "class Test\n"
184                "{\n"
185                "}");
186 
187   verifyFormat("[TestMethod]\n"
188                "[DeploymentItem(\"Test.txt\")]\n"
189                "public class Test\n"
190                "{\n"
191                "}");
192 
193   verifyFormat("[System.AttributeUsage(System.AttributeTargets.Method)]\n"
194                "[System.Runtime.InteropServices.ComVisible(true)]\n"
195                "public sealed class STAThreadAttribute : Attribute\n"
196                "{\n"
197                "}");
198 
199   verifyFormat("[Verb(\"start\", HelpText = \"Starts the server listening on "
200                "provided port\")]\n"
201                "class Test\n"
202                "{\n"
203                "}");
204 
205   verifyFormat("[TestMethod]\n"
206                "public string Host\n"
207                "{\n"
208                "    set;\n"
209                "    get;\n"
210                "}");
211 
212   verifyFormat("[TestMethod(\"start\", HelpText = \"Starts the server "
213                "listening on provided host\")]\n"
214                "public string Host\n"
215                "{\n"
216                "    set;\n"
217                "    get;\n"
218                "}");
219 }
220 
221 TEST_F(FormatTestCSharp, CSharpUsing) {
222   FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp);
223   Style.SpaceBeforeParens = FormatStyle::SBPO_Always;
224   verifyFormat("public void foo() {\n"
225                "  using (StreamWriter sw = new StreamWriter (filenameA)) {}\n"
226                "}",
227                Style);
228 
229   Style.SpaceBeforeParens = FormatStyle::SBPO_Never;
230   verifyFormat("public void foo() {\n"
231                "  using(StreamWriter sw = new StreamWriter(filenameB)) {}\n"
232                "}",
233                Style);
234 }
235 
236 TEST_F(FormatTestCSharp, CSharpRegions) {
237   verifyFormat("#region aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaa "
238                "aaaaaaaaaaaaaaa long region");
239 }
240 
241 TEST_F(FormatTestCSharp, CSharpKeyWordEscaping) {
242   verifyFormat("public enum var { none, @string, bool, @enum }");
243 }
244 
245 TEST_F(FormatTestCSharp, CSharpNullCoalescing) {
246   verifyFormat("var test = ABC ?? DEF");
247   verifyFormat("string myname = name ?? \"ABC\";");
248   verifyFormat("return _name ?? \"DEF\";");
249 }
250 
251 TEST_F(FormatTestCSharp, AttributesIndentation) {
252   FormatStyle Style = getMicrosoftStyle(FormatStyle::LK_CSharp);
253   Style.AlwaysBreakAfterReturnType = FormatStyle::RTBS_None;
254 
255   verifyFormat("[STAThread]\n"
256                "static void Main(string[] args)\n"
257                "{\n"
258                "}",
259                Style);
260 
261   verifyFormat("[STAThread]\n"
262                "void "
263                "veryLooooooooooooooongFunctionName(string[] args)\n"
264                "{\n"
265                "}",
266                Style);
267 
268   verifyFormat("[STAThread]\n"
269                "veryLoooooooooooooooooooongReturnType "
270                "veryLooooooooooooooongFunctionName(string[] args)\n"
271                "{\n"
272                "}",
273                Style);
274 
275   verifyFormat("[SuppressMessage(\"A\", \"B\", Justification = \"C\")]\n"
276                "public override X Y()\n"
277                "{\n"
278                "}\n",
279                Style);
280 
281   verifyFormat("[SuppressMessage]\n"
282                "public X Y()\n"
283                "{\n"
284                "}\n",
285                Style);
286 
287   verifyFormat("[SuppressMessage]\n"
288                "public override X Y()\n"
289                "{\n"
290                "}\n",
291                Style);
292 
293   verifyFormat("public A(B b) : base(b)\n"
294                "{\n"
295                "    [SuppressMessage]\n"
296                "    public override X Y()\n"
297                "    {\n"
298                "    }\n"
299                "}\n",
300                Style);
301 }
302 
303 } // namespace format
304 } // end namespace clang
305