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 } 37 auto ChangedCode = applyAllReplacements(Code, Replaces); 38 if (!ChangedCode) { 39 llvm::errs() << "Bad Json varibale replacement\n"; 40 } 41 StringRef NewCode = *ChangedCode; 42 43 std::vector<tooling::Range> Ranges(1, tooling::Range(0, NewCode.size())); 44 Replaces = reformat(Style, NewCode, Ranges); 45 auto Result = applyAllReplacements(NewCode, Replaces); 46 EXPECT_TRUE(static_cast<bool>(Result)); 47 LLVM_DEBUG(llvm::errs() << "\n" << *Result << "\n\n"); 48 return *Result; 49 } 50 51 static std::string 52 format(llvm::StringRef Code, 53 const FormatStyle &Style = getLLVMStyle(FormatStyle::LK_Json)) { 54 return format(Code, 0, Code.size(), Style); 55 } 56 57 static FormatStyle getStyleWithColumns(unsigned ColumnLimit) { 58 FormatStyle Style = getLLVMStyle(FormatStyle::LK_Json); 59 Style.ColumnLimit = ColumnLimit; 60 return Style; 61 } 62 63 static void verifyFormatStable(llvm::StringRef Code, 64 const FormatStyle &Style) { 65 EXPECT_EQ(Code.str(), format(Code, Style)) << "Expected code is not stable"; 66 } 67 68 static void 69 verifyFormat(llvm::StringRef Code, 70 const FormatStyle &Style = getLLVMStyle(FormatStyle::LK_Json)) { 71 verifyFormatStable(Code, Style); 72 EXPECT_EQ(Code.str(), format(test::messUp(Code), Style)); 73 } 74 }; 75 76 TEST_F(FormatTestJson, JsonRecord) { 77 verifyFormat("{}"); 78 verifyFormat("{\n" 79 " \"name\": 1\n" 80 "}"); 81 verifyFormat("{\n" 82 " \"name\": \"Foo\"\n" 83 "}"); 84 verifyFormat("{\n" 85 " \"name\": {\n" 86 " \"value\": 1\n" 87 " }\n" 88 "}"); 89 verifyFormat("{\n" 90 " \"name\": {\n" 91 " \"value\": 1\n" 92 " },\n" 93 " \"name\": {\n" 94 " \"value\": 2\n" 95 " }\n" 96 "}"); 97 verifyFormat("{\n" 98 " \"name\": {\n" 99 " \"value\": [\n" 100 " 1,\n" 101 " 2,\n" 102 " ]\n" 103 " }\n" 104 "}"); 105 verifyFormat("{\n" 106 " \"name\": {\n" 107 " \"value\": [\n" 108 " \"name\": {\n" 109 " \"value\": 1\n" 110 " },\n" 111 " \"name\": {\n" 112 " \"value\": 2\n" 113 " }\n" 114 " ]\n" 115 " }\n" 116 "}"); 117 verifyFormat(R"({ 118 "firstName": "John", 119 "lastName": "Smith", 120 "isAlive": true, 121 "age": 27, 122 "address": { 123 "streetAddress": "21 2nd Street", 124 "city": "New York", 125 "state": "NY", 126 "postalCode": "10021-3100" 127 }, 128 "phoneNumbers": [ 129 { 130 "type": "home", 131 "number": "212 555-1234" 132 }, 133 { 134 "type": "office", 135 "number": "646 555-4567" 136 } 137 ], 138 "children": [], 139 "spouse": null 140 })"); 141 } 142 143 TEST_F(FormatTestJson, JsonArray) { 144 verifyFormat("[]"); 145 verifyFormat("[\n" 146 " 1\n" 147 "]"); 148 verifyFormat("[\n" 149 " 1,\n" 150 " 2\n" 151 "]"); 152 verifyFormat("[\n" 153 " {},\n" 154 " {}\n" 155 "]"); 156 verifyFormat("[\n" 157 " {\n" 158 " \"name\": 1\n" 159 " },\n" 160 " {}\n" 161 "]"); 162 } 163 164 TEST_F(FormatTestJson, JsonNoStringSplit) { 165 FormatStyle Style = getLLVMStyle(FormatStyle::LK_Json); 166 Style.IndentWidth = 4; 167 verifyFormat( 168 "[\n" 169 " {\n" 170 " " 171 "\"naaaaaaaa\": \"foooooooooooooooooooooo oooooooooooooooooooooo\"\n" 172 " },\n" 173 " {}\n" 174 "]", 175 Style); 176 verifyFormat("[\n" 177 " {\n" 178 " " 179 "\"naaaaaaaa\": " 180 "\"foooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo" 181 "oooooooooooooooooooooooooo\"\n" 182 " },\n" 183 " {}\n" 184 "]", 185 Style); 186 187 Style.ColumnLimit = 80; 188 verifyFormat("[\n" 189 " {\n" 190 " " 191 "\"naaaaaaaa\":\n" 192 " " 193 "\"foooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo" 194 "oooooooooooooooooooooooooo\"\n" 195 " },\n" 196 " {}\n" 197 "]", 198 Style); 199 } 200 201 TEST_F(FormatTestJson, DisableJsonFormat) { 202 FormatStyle Style = getLLVMStyle(FormatStyle::LK_Json); 203 verifyFormatStable("{}", Style); 204 verifyFormatStable("{\n" 205 " \"name\": 1\n" 206 "}", 207 Style); 208 209 // Since we have to disable formatting to run this test, we shall refrain from 210 // calling test::messUp lest we change the unformatted code and cannot format 211 // it back to how it started. 212 Style.DisableFormat = true; 213 verifyFormatStable("{}", Style); 214 verifyFormatStable("{\n" 215 " \"name\": 1\n" 216 "}", 217 Style); 218 } 219 220 } // namespace format 221 } // end namespace clang 222