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 = getGoogleStyle(FormatStyle::LK_CSharp)) { |
36 | return format(Code, 0, Code.size(), Style); |
37 | } |
38 | |
39 | static FormatStyle getStyleWithColumns(unsigned ColumnLimit) { |
40 | FormatStyle Style = getGoogleStyle(FormatStyle::LK_CSharp); |
41 | Style.ColumnLimit = ColumnLimit; |
42 | return Style; |
43 | } |
44 | |
45 | static void verifyFormat( |
46 | llvm::StringRef Code, |
47 | const FormatStyle &Style = getGoogleStyle(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 | " void f() {}\n" |
56 | " int g() { return 0; }\n" |
57 | " void h() {\n" |
58 | " while (true) f();\n" |
59 | " for (;;) f();\n" |
60 | " if (true) f();\n" |
61 | " }\n" |
62 | "}"); |
63 | } |
64 | |
65 | TEST_F(FormatTestCSharp, AccessModifiers) { |
66 | verifyFormat("public String toString() {}"); |
67 | verifyFormat("private String toString() {}"); |
68 | verifyFormat("protected String toString() {}"); |
69 | verifyFormat("internal String toString() {}"); |
70 | |
71 | verifyFormat("public override String toString() {}"); |
72 | verifyFormat("private override String toString() {}"); |
73 | verifyFormat("protected override String toString() {}"); |
74 | verifyFormat("internal override String toString() {}"); |
75 | |
76 | verifyFormat("internal static String toString() {}"); |
77 | } |
78 | |
79 | TEST_F(FormatTestCSharp, NoStringLiteralBreaks) { |
80 | verifyFormat("foo(" |
81 | "\"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" |
82 | "aaaaaa\");"); |
83 | } |
84 | |
85 | TEST_F(FormatTestCSharp, CSharpVerbatiumStringLiterals) { |
86 | verifyFormat("foo(@\"aaaaaaaa\\abc\\aaaa\");"); |
87 | // @"ABC\" + ToString("B") - handle embedded \ in literal string at |
88 | // the end |
89 | // |
90 | /* |
91 | * After removal of Lexer change we are currently not able |
92 | * To handle these cases |
93 | verifyFormat("string s = @\"ABC\\\" + ToString(\"B\");"); |
94 | verifyFormat("string s = @\"ABC\"\"DEF\"\"GHI\""); |
95 | verifyFormat("string s = @\"ABC\"\"DEF\"\"\""); |
96 | verifyFormat("string s = @\"ABC\"\"DEF\"\"\" + abc"); |
97 | */ |
98 | } |
99 | |
100 | TEST_F(FormatTestCSharp, CSharpInterpolatedStringLiterals) { |
101 | verifyFormat("foo($\"aaaaaaaa{aaa}aaaa\");"); |
102 | verifyFormat("foo($\"aaaa{A}\");"); |
103 | verifyFormat( |
104 | "foo($\"aaaa{A}" |
105 | "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\");"); |
106 | verifyFormat("Name = $\"{firstName} {lastName}\";"); |
107 | |
108 | // $"ABC\" + ToString("B") - handle embedded \ in literal string at |
109 | // the end |
110 | verifyFormat("string s = $\"A{abc}BC\" + ToString(\"B\");"); |
111 | verifyFormat("$\"{domain}\\\\{user}\""); |
112 | verifyFormat( |
113 | "var verbatimInterpolated = $@\"C:\\Users\\{userName}\\Documents\\\";"); |
114 | } |
115 | |
116 | TEST_F(FormatTestCSharp, CSharpFatArrows) { |
117 | verifyFormat("Task serverTask = Task.Run(async() => {"); |
118 | verifyFormat("public override string ToString() => \"{Name}\\{Age}\";"); |
119 | } |
120 | |
121 | TEST_F(FormatTestCSharp, CSharpNullConditional) { |
122 | verifyFormat( |
123 | "public Person(string firstName, string lastName, int? age=null)"); |
124 | |
125 | verifyFormat("switch(args?.Length)"); |
126 | |
127 | verifyFormat("public static void Main(string[] args) { string dirPath " |
128 | "= args?[0]; }"); |
129 | } |
130 | |
131 | TEST_F(FormatTestCSharp, Attributes) { |
132 | verifyFormat("[STAThread]\n" |
133 | "static void\n" |
134 | "Main(string[] args) {}"); |
135 | |
136 | verifyFormat("[TestMethod]\n" |
137 | "private class Test {}"); |
138 | |
139 | verifyFormat("[TestMethod]\n" |
140 | "protected class Test {}"); |
141 | |
142 | verifyFormat("[TestMethod]\n" |
143 | "internal class Test {}"); |
144 | |
145 | verifyFormat("[TestMethod]\n" |
146 | "class Test {}"); |
147 | |
148 | verifyFormat("[TestMethod]\n" |
149 | "[DeploymentItem(\"Test.txt\")]\n" |
150 | "public class Test {}"); |
151 | |
152 | verifyFormat("[System.AttributeUsage(System.AttributeTargets.Method)]\n" |
153 | "[System.Runtime.InteropServices.ComVisible(true)]\n" |
154 | "public sealed class STAThreadAttribute : Attribute {}"); |
155 | |
156 | verifyFormat("[Verb(\"start\", HelpText = \"Starts the server listening on " |
157 | "provided port\")]\n" |
158 | "class Test {}"); |
159 | |
160 | verifyFormat("[TestMethod]\n" |
161 | "public string Host {\n set;\n get;\n}"); |
162 | |
163 | verifyFormat("[TestMethod(\"start\", HelpText = \"Starts the server " |
164 | "listening on provided host\")]\n" |
165 | "public string Host {\n set;\n get;\n}"); |
166 | } |
167 | |
168 | TEST_F(FormatTestCSharp, CSharpRegions) { |
169 | verifyFormat("#region aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa aaaaaaaaaaaaaaaaa " |
170 | "aaaaaaaaaaaaaaa long region"); |
171 | } |
172 | |
173 | TEST_F(FormatTestCSharp, CSharpKeyWordEscaping) { |
174 | verifyFormat("public enum var { none, @string, bool, @enum }"); |
175 | } |
176 | |
177 | TEST_F(FormatTestCSharp, CSharpNullCoalescing) { |
178 | verifyFormat("var test = ABC ?? DEF"); |
179 | verifyFormat("string myname = name ?? \"ABC\";"); |
180 | verifyFormat("return _name ?? \"DEF\";"); |
181 | } |
182 | |
183 | } // namespace format |
184 | } // end namespace clang |
185 | |