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:
format(llvm::StringRef Code,unsigned Offset,unsigned Length,const FormatStyle & Style)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
format(llvm::StringRef Code,const FormatStyle & Style=getMicrosoftStyle (FormatStyle::LK_CSharp))34 format(llvm::StringRef Code,
35 const FormatStyle &Style = getMicrosoftStyle(FormatStyle::LK_CSharp)) {
36 return format(Code, 0, Code.size(), Style);
37 }
38
getStyleWithColumns(unsigned ColumnLimit)39 static FormatStyle getStyleWithColumns(unsigned ColumnLimit) {
40 FormatStyle Style = getMicrosoftStyle(FormatStyle::LK_CSharp);
41 Style.ColumnLimit = ColumnLimit;
42 return Style;
43 }
44
verifyFormat(llvm::StringRef Code,const FormatStyle & Style=getMicrosoftStyle (FormatStyle::LK_CSharp))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
TEST_F(FormatTestCSharp,CSharpClass)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
TEST_F(FormatTestCSharp,AccessModifiers)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
TEST_F(FormatTestCSharp,NoStringLiteralBreaks)107 TEST_F(FormatTestCSharp, NoStringLiteralBreaks) {
108 verifyFormat("foo("
109 "\"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
110 "aaaaaa\");");
111 }
112
TEST_F(FormatTestCSharp,CSharpVerbatiumStringLiterals)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
TEST_F(FormatTestCSharp,CSharpInterpolatedStringLiterals)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
TEST_F(FormatTestCSharp,CSharpFatArrows)144 TEST_F(FormatTestCSharp, CSharpFatArrows) {
145 verifyFormat("Task serverTask = Task.Run(async() => {");
146 verifyFormat("public override string ToString() => \"{Name}\\{Age}\";");
147 }
148
TEST_F(FormatTestCSharp,CSharpNullConditional)149 TEST_F(FormatTestCSharp, CSharpNullConditional) {
150 FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp);
151 Style.SpaceBeforeParens = FormatStyle::SBPO_Always;
152
153 verifyFormat(
154 "public Person(string firstName, string lastName, int? age=null)");
155
156 verifyFormat("foo () {\n"
157 " switch (args?.Length) {}\n"
158 "}",
159 Style);
160
161 verifyFormat("switch (args?.Length) {}", Style);
162
163 verifyFormat("public static void Main(string[] args)\n"
164 "{\n"
165 " string dirPath = args?[0];\n"
166 "}");
167
168 Style.SpaceBeforeParens = FormatStyle::SBPO_Never;
169
170 verifyFormat("switch(args?.Length) {}", Style);
171 }
172
TEST_F(FormatTestCSharp,Attributes)173 TEST_F(FormatTestCSharp, Attributes) {
174 verifyFormat("[STAThread]\n"
175 "static void Main(string[] args)\n"
176 "{\n"
177 "}");
178
179 verifyFormat("[TestMethod]\n"
180 "private class Test\n"
181 "{\n"
182 "}");
183
184 verifyFormat("[TestMethod]\n"
185 "protected class Test\n"
186 "{\n"
187 "}");
188
189 verifyFormat("[TestMethod]\n"
190 "internal class Test\n"
191 "{\n"
192 "}");
193
194 verifyFormat("[TestMethod]\n"
195 "class Test\n"
196 "{\n"
197 "}");
198
199 verifyFormat("[TestMethod]\n"
200 "[DeploymentItem(\"Test.txt\")]\n"
201 "public class Test\n"
202 "{\n"
203 "}");
204
205 verifyFormat("[System.AttributeUsage(System.AttributeTargets.Method)]\n"
206 "[System.Runtime.InteropServices.ComVisible(true)]\n"
207 "public sealed class STAThreadAttribute : Attribute\n"
208 "{\n"
209 "}");
210
211 verifyFormat("[Verb(\"start\", HelpText = \"Starts the server listening on "
212 "provided port\")]\n"
213 "class Test\n"
214 "{\n"
215 "}");
216
217 verifyFormat("[TestMethod]\n"
218 "public string Host\n"
219 "{\n"
220 " set;\n"
221 " get;\n"
222 "}");
223
224 verifyFormat("[TestMethod(\"start\", HelpText = \"Starts the server "
225 "listening on provided host\")]\n"
226 "public string Host\n"
227 "{\n"
228 " set;\n"
229 " get;\n"
230 "}");
231 }
232
TEST_F(FormatTestCSharp,CSharpUsing)233 TEST_F(FormatTestCSharp, CSharpUsing) {
234 FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp);
235 Style.SpaceBeforeParens = FormatStyle::SBPO_Always;
236 verifyFormat("public void foo () {\n"
237 " using (StreamWriter sw = new StreamWriter (filenameA)) {}\n"
238 "}",
239 Style);
240
241 verifyFormat("using (StreamWriter sw = new StreamWriter (filenameB)) {}",
242 Style);
243
244 Style.SpaceBeforeParens = FormatStyle::SBPO_Never;
245 verifyFormat("public void foo() {\n"
246 " using(StreamWriter sw = new StreamWriter(filenameB)) {}\n"
247 "}",
248 Style);
249
250 verifyFormat("using(StreamWriter sw = new StreamWriter(filenameB)) {}",
251 Style);
252 }
253
TEST_F(FormatTestCSharp,CSharpRegions)254 TEST_F(FormatTestCSharp, CSharpRegions) {
255 verifyFormat("#region aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaa "
256 "aaaaaaaaaaaaaaa long region");
257 }
258
TEST_F(FormatTestCSharp,CSharpKeyWordEscaping)259 TEST_F(FormatTestCSharp, CSharpKeyWordEscaping) {
260 verifyFormat("public enum var { none, @string, bool, @enum }");
261 }
262
TEST_F(FormatTestCSharp,CSharpNullCoalescing)263 TEST_F(FormatTestCSharp, CSharpNullCoalescing) {
264 verifyFormat("var test = ABC ?? DEF");
265 verifyFormat("string myname = name ?? \"ABC\";");
266 verifyFormat("return _name ?? \"DEF\";");
267 }
268
TEST_F(FormatTestCSharp,AttributesIndentation)269 TEST_F(FormatTestCSharp, AttributesIndentation) {
270 FormatStyle Style = getMicrosoftStyle(FormatStyle::LK_CSharp);
271 Style.AlwaysBreakAfterReturnType = FormatStyle::RTBS_None;
272
273 verifyFormat("[STAThread]\n"
274 "static void Main(string[] args)\n"
275 "{\n"
276 "}",
277 Style);
278
279 verifyFormat("[STAThread]\n"
280 "void "
281 "veryLooooooooooooooongFunctionName(string[] args)\n"
282 "{\n"
283 "}",
284 Style);
285
286 verifyFormat("[STAThread]\n"
287 "veryLoooooooooooooooooooongReturnType "
288 "veryLooooooooooooooongFunctionName(string[] args)\n"
289 "{\n"
290 "}",
291 Style);
292
293 verifyFormat("[SuppressMessage(\"A\", \"B\", Justification = \"C\")]\n"
294 "public override X Y()\n"
295 "{\n"
296 "}\n",
297 Style);
298
299 verifyFormat("[SuppressMessage]\n"
300 "public X Y()\n"
301 "{\n"
302 "}\n",
303 Style);
304
305 verifyFormat("[SuppressMessage]\n"
306 "public override X Y()\n"
307 "{\n"
308 "}\n",
309 Style);
310
311 verifyFormat("public A(B b) : base(b)\n"
312 "{\n"
313 " [SuppressMessage]\n"
314 " public override X Y()\n"
315 " {\n"
316 " }\n"
317 "}\n",
318 Style);
319
320 verifyFormat("public A : Base\n"
321 "{\n"
322 "}\n"
323 "[Test]\n"
324 "public Foo()\n"
325 "{\n"
326 "}\n",
327 Style);
328
329 verifyFormat("namespace\n"
330 "{\n"
331 "public A : Base\n"
332 "{\n"
333 "}\n"
334 "[Test]\n"
335 "public Foo()\n"
336 "{\n"
337 "}\n"
338 "}\n",
339 Style);
340 }
341
TEST_F(FormatTestCSharp,CSharpSpaceBefore)342 TEST_F(FormatTestCSharp, CSharpSpaceBefore) {
343 FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp);
344 Style.SpaceBeforeParens = FormatStyle::SBPO_Always;
345
346 verifyFormat("List<string> list;", Style);
347 verifyFormat("Dictionary<string, string> dict;", Style);
348
349 verifyFormat("for (int i = 0; i < size (); i++) {\n"
350 "}",
351 Style);
352 verifyFormat("foreach (var x in y) {\n"
353 "}",
354 Style);
355 verifyFormat("switch (x) {}", Style);
356 verifyFormat("do {\n"
357 "} while (x);",
358 Style);
359
360 Style.SpaceBeforeParens = FormatStyle::SBPO_Never;
361
362 verifyFormat("List<string> list;", Style);
363 verifyFormat("Dictionary<string, string> dict;", Style);
364
365 verifyFormat("for(int i = 0; i < size(); i++) {\n"
366 "}",
367 Style);
368 verifyFormat("foreach(var x in y) {\n"
369 "}",
370 Style);
371 verifyFormat("switch(x) {}", Style);
372 verifyFormat("do {\n"
373 "} while(x);",
374 Style);
375 }
376
377 } // namespace format
378 } // end namespace clang
379