1 //===- unittest/Format/FormatTestJson.cpp - Formatting tests for Json -===// 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-json" 15 16 namespace clang { 17 namespace format { 18 19 class FormatTestJson : 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 26 tooling::Replacements Replaces; 27 28 // Mock up what ClangFormat.cpp will do for JSON by adding a variable 29 // to trick JSON into being JavaScript 30 if (Style.isJson() && !Style.DisableFormat) { 31 auto Err = Replaces.add( 32 tooling::Replacement(tooling::Replacement("", 0, 0, "x = "))); 33 if (Err) 34 llvm::errs() << "Bad Json variable insertion\n"; 35 } 36 auto ChangedCode = applyAllReplacements(Code, Replaces); 37 if (!ChangedCode) 38 llvm::errs() << "Bad Json varibale replacement\n"; 39 StringRef NewCode = *ChangedCode; 40 41 std::vector<tooling::Range> Ranges(1, tooling::Range(0, NewCode.size())); 42 Replaces = reformat(Style, NewCode, Ranges); 43 auto Result = applyAllReplacements(NewCode, Replaces); 44 EXPECT_TRUE(static_cast<bool>(Result)); 45 LLVM_DEBUG(llvm::errs() << "\n" << *Result << "\n\n"); 46 return *Result; 47 } 48 49 static std::string 50 format(llvm::StringRef Code, 51 const FormatStyle &Style = getLLVMStyle(FormatStyle::LK_Json)) { 52 return format(Code, 0, Code.size(), Style); 53 } 54 55 static FormatStyle getStyleWithColumns(unsigned ColumnLimit) { 56 FormatStyle Style = getLLVMStyle(FormatStyle::LK_Json); 57 Style.ColumnLimit = ColumnLimit; 58 return Style; 59 } 60 61 static void verifyFormatStable(llvm::StringRef Code, 62 const FormatStyle &Style) { 63 EXPECT_EQ(Code.str(), format(Code, Style)) << "Expected code is not stable"; 64 } 65 66 static void 67 verifyFormat(llvm::StringRef Code, 68 const FormatStyle &Style = getLLVMStyle(FormatStyle::LK_Json)) { 69 verifyFormatStable(Code, Style); 70 EXPECT_EQ(Code.str(), format(test::messUp(Code), Style)); 71 } 72 }; 73 74 TEST_F(FormatTestJson, JsonRecord) { 75 verifyFormat("{}"); 76 verifyFormat("{\n" 77 " \"name\": 1\n" 78 "}"); 79 verifyFormat("{\n" 80 " \"name\": \"Foo\"\n" 81 "}"); 82 verifyFormat("{\n" 83 " \"name\": {\n" 84 " \"value\": 1\n" 85 " }\n" 86 "}"); 87 verifyFormat("{\n" 88 " \"name\": {\n" 89 " \"value\": 1\n" 90 " },\n" 91 " \"name\": {\n" 92 " \"value\": 2\n" 93 " }\n" 94 "}"); 95 verifyFormat("{\n" 96 " \"name\": {\n" 97 " \"value\": [\n" 98 " 1,\n" 99 " 2,\n" 100 " ]\n" 101 " }\n" 102 "}"); 103 verifyFormat("{\n" 104 " \"name\": {\n" 105 " \"value\": [\n" 106 " \"name\": {\n" 107 " \"value\": 1\n" 108 " },\n" 109 " \"name\": {\n" 110 " \"value\": 2\n" 111 " }\n" 112 " ]\n" 113 " }\n" 114 "}"); 115 verifyFormat(R"({ 116 "firstName": "John", 117 "lastName": "Smith", 118 "isAlive": true, 119 "age": 27, 120 "address": { 121 "streetAddress": "21 2nd Street", 122 "city": "New York", 123 "state": "NY", 124 "postalCode": "10021-3100" 125 }, 126 "phoneNumbers": [ 127 { 128 "type": "home", 129 "number": "212 555-1234" 130 }, 131 { 132 "type": "office", 133 "number": "646 555-4567" 134 } 135 ], 136 "children": [], 137 "spouse": null 138 })"); 139 } 140 141 TEST_F(FormatTestJson, JsonArray) { 142 verifyFormat("[]"); 143 verifyFormat("[\n" 144 " 1\n" 145 "]"); 146 verifyFormat("[\n" 147 " 1,\n" 148 " 2\n" 149 "]"); 150 verifyFormat("[\n" 151 " {},\n" 152 " {}\n" 153 "]"); 154 verifyFormat("[\n" 155 " {\n" 156 " \"name\": 1\n" 157 " },\n" 158 " {}\n" 159 "]"); 160 } 161 162 TEST_F(FormatTestJson, JsonArrayOneLine) { 163 FormatStyle Style = getLLVMStyle(FormatStyle::LK_Json); 164 Style.BreakArrays = false; 165 Style.SpacesInContainerLiterals = false; 166 verifyFormat("[]", Style); 167 verifyFormat("[1]", Style); 168 verifyFormat("[1, 2]", Style); 169 verifyFormat("[1, 2, 3]", Style); 170 verifyFormat("[1, 2, 3, 4]", Style); 171 verifyFormat("[1, 2, 3, 4, 5]", Style); 172 173 verifyFormat("[\n" 174 " 1,\n" 175 " 2,\n" 176 " {\n" 177 " A: 1\n" 178 " }\n" 179 "]", 180 Style); 181 } 182 183 TEST_F(FormatTestJson, JsonNoStringSplit) { 184 FormatStyle Style = getLLVMStyle(FormatStyle::LK_Json); 185 Style.IndentWidth = 4; 186 verifyFormat( 187 "[\n" 188 " {\n" 189 " " 190 "\"naaaaaaaa\": \"foooooooooooooooooooooo oooooooooooooooooooooo\"\n" 191 " },\n" 192 " {}\n" 193 "]", 194 Style); 195 verifyFormat("[\n" 196 " {\n" 197 " " 198 "\"naaaaaaaa\": " 199 "\"foooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo" 200 "oooooooooooooooooooooooooo\"\n" 201 " },\n" 202 " {}\n" 203 "]", 204 Style); 205 206 Style.ColumnLimit = 80; 207 verifyFormat("[\n" 208 " {\n" 209 " " 210 "\"naaaaaaaa\":\n" 211 " " 212 "\"foooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo" 213 "oooooooooooooooooooooooooo\"\n" 214 " },\n" 215 " {}\n" 216 "]", 217 Style); 218 } 219 220 TEST_F(FormatTestJson, DisableJsonFormat) { 221 FormatStyle Style = getLLVMStyle(FormatStyle::LK_Json); 222 verifyFormatStable("{}", Style); 223 verifyFormatStable("{\n" 224 " \"name\": 1\n" 225 "}", 226 Style); 227 228 // Since we have to disable formatting to run this test, we shall refrain from 229 // calling test::messUp lest we change the unformatted code and cannot format 230 // it back to how it started. 231 Style.DisableFormat = true; 232 verifyFormatStable("{}", Style); 233 verifyFormatStable("{\n" 234 " \"name\": 1\n" 235 "}", 236 Style); 237 } 238 239 TEST_F(FormatTestJson, SpaceBeforeJsonColon) { 240 FormatStyle Style = getLLVMStyle(FormatStyle::LK_Json); 241 verifyFormatStable("{\n" 242 " \"name\": 1\n" 243 "}", 244 Style); 245 246 Style.SpaceBeforeJsonColon = true; 247 verifyFormatStable("{}", Style); 248 verifyFormatStable("{\n" 249 " \"name\" : 1\n" 250 "}", 251 Style); 252 } 253 254 } // namespace format 255 } // end namespace clang 256