blob: 031de143389f869f3c4af9105b6230533089104c [file] [log] [blame]
Paul Hoadcbb726d2019-03-21 13:09:22 +00001//===- 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
16namespace clang {
17namespace format {
18
19class FormatTestCSharp : public ::testing::Test {
20protected:
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,
Paul Hoada2f963b2019-10-04 07:56:49 +000035 const FormatStyle &Style = getMicrosoftStyle(FormatStyle::LK_CSharp)) {
Paul Hoadcbb726d2019-03-21 13:09:22 +000036 return format(Code, 0, Code.size(), Style);
37 }
38
39 static FormatStyle getStyleWithColumns(unsigned ColumnLimit) {
Paul Hoada2f963b2019-10-04 07:56:49 +000040 FormatStyle Style = getMicrosoftStyle(FormatStyle::LK_CSharp);
Paul Hoadcbb726d2019-03-21 13:09:22 +000041 Style.ColumnLimit = ColumnLimit;
42 return Style;
43 }
44
45 static void verifyFormat(
46 llvm::StringRef Code,
Paul Hoada2f963b2019-10-04 07:56:49 +000047 const FormatStyle &Style = getMicrosoftStyle(FormatStyle::LK_CSharp)) {
Paul Hoadcbb726d2019-03-21 13:09:22 +000048 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
53TEST_F(FormatTestCSharp, CSharpClass) {
Paul Hoada2f963b2019-10-04 07:56:49 +000054 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"
Paul Hoadcbb726d2019-03-21 13:09:22 +000072 "}");
73}
74
75TEST_F(FormatTestCSharp, AccessModifiers) {
Paul Hoada2f963b2019-10-04 07:56:49 +000076 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 "}");
Paul Hoadcbb726d2019-03-21 13:09:22 +000088
Paul Hoada2f963b2019-10-04 07:56:49 +000089 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 "}");
Paul Hoadcbb726d2019-03-21 13:09:22 +0000101
Paul Hoada2f963b2019-10-04 07:56:49 +0000102 verifyFormat("internal static String toString()\n"
103 "{\n"
104 "}");
Paul Hoadcbb726d2019-03-21 13:09:22 +0000105}
106
107TEST_F(FormatTestCSharp, NoStringLiteralBreaks) {
108 verifyFormat("foo("
109 "\"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
110 "aaaaaa\");");
111}
112
113TEST_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
128TEST_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
144TEST_F(FormatTestCSharp, CSharpFatArrows) {
145 verifyFormat("Task serverTask = Task.Run(async() => {");
146 verifyFormat("public override string ToString() => \"{Name}\\{Age}\";");
147}
148
149TEST_F(FormatTestCSharp, CSharpNullConditional) {
150 verifyFormat(
151 "public Person(string firstName, string lastName, int? age=null)");
152
153 verifyFormat("switch(args?.Length)");
154
Paul Hoada2f963b2019-10-04 07:56:49 +0000155 verifyFormat("public static void Main(string[] args)\n"
156 "{\n"
157 " string dirPath = args?[0];\n"
158 "}");
Paul Hoadcbb726d2019-03-21 13:09:22 +0000159}
160
161TEST_F(FormatTestCSharp, Attributes) {
162 verifyFormat("[STAThread]\n"
Paul Hoada2f963b2019-10-04 07:56:49 +0000163 "static void Main(string[] args)\n"
164 "{\n"
165 "}");
Paul Hoadcbb726d2019-03-21 13:09:22 +0000166
167 verifyFormat("[TestMethod]\n"
Paul Hoada2f963b2019-10-04 07:56:49 +0000168 "private class Test\n"
169 "{\n"
170 "}");
Paul Hoadcbb726d2019-03-21 13:09:22 +0000171
172 verifyFormat("[TestMethod]\n"
Paul Hoada2f963b2019-10-04 07:56:49 +0000173 "protected class Test\n"
174 "{\n"
175 "}");
Paul Hoadcbb726d2019-03-21 13:09:22 +0000176
177 verifyFormat("[TestMethod]\n"
Paul Hoada2f963b2019-10-04 07:56:49 +0000178 "internal class Test\n"
179 "{\n"
180 "}");
Paul Hoadcbb726d2019-03-21 13:09:22 +0000181
182 verifyFormat("[TestMethod]\n"
Paul Hoada2f963b2019-10-04 07:56:49 +0000183 "class Test\n"
184 "{\n"
185 "}");
Paul Hoadcbb726d2019-03-21 13:09:22 +0000186
187 verifyFormat("[TestMethod]\n"
188 "[DeploymentItem(\"Test.txt\")]\n"
Paul Hoada2f963b2019-10-04 07:56:49 +0000189 "public class Test\n"
190 "{\n"
191 "}");
Paul Hoadcbb726d2019-03-21 13:09:22 +0000192
193 verifyFormat("[System.AttributeUsage(System.AttributeTargets.Method)]\n"
194 "[System.Runtime.InteropServices.ComVisible(true)]\n"
Paul Hoada2f963b2019-10-04 07:56:49 +0000195 "public sealed class STAThreadAttribute : Attribute\n"
196 "{\n"
197 "}");
Paul Hoadcbb726d2019-03-21 13:09:22 +0000198
199 verifyFormat("[Verb(\"start\", HelpText = \"Starts the server listening on "
200 "provided port\")]\n"
Paul Hoada2f963b2019-10-04 07:56:49 +0000201 "class Test\n"
202 "{\n"
203 "}");
Paul Hoadcbb726d2019-03-21 13:09:22 +0000204
205 verifyFormat("[TestMethod]\n"
Paul Hoada2f963b2019-10-04 07:56:49 +0000206 "public string Host\n"
207 "{\n"
208 " set;\n"
209 " get;\n"
210 "}");
Paul Hoadcbb726d2019-03-21 13:09:22 +0000211
212 verifyFormat("[TestMethod(\"start\", HelpText = \"Starts the server "
213 "listening on provided host\")]\n"
Paul Hoada2f963b2019-10-04 07:56:49 +0000214 "public string Host\n"
215 "{\n"
216 " set;\n"
217 " get;\n"
218 "}");
Paul Hoadcbb726d2019-03-21 13:09:22 +0000219}
220
Paul Hoad719087b2019-09-12 10:18:53 +0000221TEST_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
Paul Hoadcbb726d2019-03-21 13:09:22 +0000236TEST_F(FormatTestCSharp, CSharpRegions) {
237 verifyFormat("#region aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaa "
238 "aaaaaaaaaaaaaaa long region");
239}
240
241TEST_F(FormatTestCSharp, CSharpKeyWordEscaping) {
242 verifyFormat("public enum var { none, @string, bool, @enum }");
243}
244
245TEST_F(FormatTestCSharp, CSharpNullCoalescing) {
246 verifyFormat("var test = ABC ?? DEF");
247 verifyFormat("string myname = name ?? \"ABC\";");
248 verifyFormat("return _name ?? \"DEF\";");
249}
250
Paul Hoada2f963b2019-10-04 07:56:49 +0000251TEST_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
Paul Hoadcbb726d2019-03-21 13:09:22 +0000303} // namespace format
304} // end namespace clang