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:
format(llvm::StringRef Code,unsigned Offset,unsigned Length,const FormatStyle & Style)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
format(llvm::StringRef Code,const FormatStyle & Style=getLLVMStyle (FormatStyle::LK_Json))50 format(llvm::StringRef Code,
51 const FormatStyle &Style = getLLVMStyle(FormatStyle::LK_Json)) {
52 return format(Code, 0, Code.size(), Style);
53 }
54
getStyleWithColumns(unsigned ColumnLimit)55 static FormatStyle getStyleWithColumns(unsigned ColumnLimit) {
56 FormatStyle Style = getLLVMStyle(FormatStyle::LK_Json);
57 Style.ColumnLimit = ColumnLimit;
58 return Style;
59 }
60
verifyFormatStable(llvm::StringRef Code,const FormatStyle & Style)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
verifyFormat(llvm::StringRef Code,const FormatStyle & Style=getLLVMStyle (FormatStyle::LK_Json))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
TEST_F(FormatTestJson,JsonRecord)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
TEST_F(FormatTestJson,JsonArray)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
TEST_F(FormatTestJson,JsonNoStringSplit)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
TEST_F(FormatTestJson,DisableJsonFormat)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