Paul Hoad | cbb726d | 2019-03-21 13:09:22 +0000 | [diff] [blame] | 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 |