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, JsonNoStringSplit) { 163 FormatStyle Style = getLLVMStyle(FormatStyle::LK_Json); 164 Style.IndentWidth = 4; 165 verifyFormat( 166 "[\n" 167 " {\n" 168 " " 169 "\"naaaaaaaa\": \"foooooooooooooooooooooo oooooooooooooooooooooo\"\n" 170 " },\n" 171 " {}\n" 172 "]", 173 Style); 174 verifyFormat("[\n" 175 " {\n" 176 " " 177 "\"naaaaaaaa\": " 178 "\"foooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo" 179 "oooooooooooooooooooooooooo\"\n" 180 " },\n" 181 " {}\n" 182 "]", 183 Style); 184 185 Style.ColumnLimit = 80; 186 verifyFormat("[\n" 187 " {\n" 188 " " 189 "\"naaaaaaaa\":\n" 190 " " 191 "\"foooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo" 192 "oooooooooooooooooooooooooo\"\n" 193 " },\n" 194 " {}\n" 195 "]", 196 Style); 197 } 198 199 TEST_F(FormatTestJson, DisableJsonFormat) { 200 FormatStyle Style = getLLVMStyle(FormatStyle::LK_Json); 201 verifyFormatStable("{}", Style); 202 verifyFormatStable("{\n" 203 " \"name\": 1\n" 204 "}", 205 Style); 206 207 // Since we have to disable formatting to run this test, we shall refrain from 208 // calling test::messUp lest we change the unformatted code and cannot format 209 // it back to how it started. 210 Style.DisableFormat = true; 211 verifyFormatStable("{}", Style); 212 verifyFormatStable("{\n" 213 " \"name\": 1\n" 214 "}", 215 Style); 216 } 217 218 } // namespace format 219 } // end namespace clang 220