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 | R: 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, Code: NewCode, Ranges); |
43 | auto Result = applyAllReplacements(Code: 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(Language: FormatStyle::LK_Json)) { |
52 | return format(Code, Offset: 0, Length: Code.size(), Style); |
53 | } |
54 | |
55 | static FormatStyle getStyleWithColumns(unsigned ColumnLimit) { |
56 | FormatStyle Style = getLLVMStyle(Language: 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(Language: 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(Code: "{}" ); |
76 | verifyFormat(Code: "{\n" |
77 | " \"name\": 1\n" |
78 | "}" ); |
79 | verifyFormat(Code: "{\n" |
80 | " \"name\": \"Foo\"\n" |
81 | "}" ); |
82 | verifyFormat(Code: "{\n" |
83 | " \"name\": {\n" |
84 | " \"value\": 1\n" |
85 | " }\n" |
86 | "}" ); |
87 | verifyFormat(Code: "{\n" |
88 | " \"name\": {\n" |
89 | " \"value\": 1\n" |
90 | " },\n" |
91 | " \"name\": {\n" |
92 | " \"value\": 2\n" |
93 | " }\n" |
94 | "}" ); |
95 | verifyFormat(Code: "{\n" |
96 | " \"name\": {\n" |
97 | " \"value\": [\n" |
98 | " 1,\n" |
99 | " 2,\n" |
100 | " ]\n" |
101 | " }\n" |
102 | "}" ); |
103 | verifyFormat(Code: "{\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(Code: 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(Code: "[]" ); |
143 | verifyFormat(Code: "[\n" |
144 | " 1\n" |
145 | "]" ); |
146 | verifyFormat(Code: "[\n" |
147 | " 1,\n" |
148 | " 2\n" |
149 | "]" ); |
150 | verifyFormat(Code: "[\n" |
151 | " {},\n" |
152 | " {}\n" |
153 | "]" ); |
154 | verifyFormat(Code: "[\n" |
155 | " {\n" |
156 | " \"name\": 1\n" |
157 | " },\n" |
158 | " {}\n" |
159 | "]" ); |
160 | } |
161 | |
162 | TEST_F(FormatTestJson, JsonArrayOneLine) { |
163 | FormatStyle Style = getLLVMStyle(Language: FormatStyle::LK_Json); |
164 | Style.BreakArrays = false; |
165 | Style.SpacesInContainerLiterals = false; |
166 | verifyFormat(Code: "[]" , Style); |
167 | verifyFormat(Code: "[1]" , Style); |
168 | verifyFormat(Code: "[1, 2]" , Style); |
169 | verifyFormat(Code: "[1, 2, 3]" , Style); |
170 | verifyFormat(Code: "[1, 2, 3, 4]" , Style); |
171 | verifyFormat(Code: "[1, 2, 3, 4, 5]" , Style); |
172 | |
173 | verifyFormat(Code: "[\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(Language: FormatStyle::LK_Json); |
185 | Style.IndentWidth = 4; |
186 | verifyFormat( |
187 | Code: "[\n" |
188 | " {\n" |
189 | " " |
190 | "\"naaaaaaaa\": \"foooooooooooooooooooooo oooooooooooooooooooooo\"\n" |
191 | " },\n" |
192 | " {}\n" |
193 | "]" , |
194 | Style); |
195 | verifyFormat(Code: "[\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(Code: "[\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(Language: FormatStyle::LK_Json); |
222 | verifyFormatStable(Code: "{}" , Style); |
223 | verifyFormatStable(Code: "{\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(Code: "{}" , Style); |
233 | verifyFormatStable(Code: "{\n" |
234 | " \"name\": 1\n" |
235 | "}" , |
236 | Style); |
237 | } |
238 | |
239 | TEST_F(FormatTestJson, SpaceBeforeJsonColon) { |
240 | FormatStyle Style = getLLVMStyle(Language: FormatStyle::LK_Json); |
241 | verifyFormatStable(Code: "{\n" |
242 | " \"name\": 1\n" |
243 | "}" , |
244 | Style); |
245 | |
246 | Style.SpaceBeforeJsonColon = true; |
247 | verifyFormatStable(Code: "{}" , Style); |
248 | verifyFormatStable(Code: "{\n" |
249 | " \"name\" : 1\n" |
250 | "}" , |
251 | Style); |
252 | } |
253 | |
254 | TEST_F(FormatTestJson, StartsWithWhitespaces) { |
255 | FormatStyle Style = getLLVMStyle(Language: FormatStyle::LK_Json); |
256 | EXPECT_EQ("{\n" |
257 | " \"name\": 1\n" |
258 | "}" , |
259 | format(" {\n" |
260 | " \"name\": 1\n" |
261 | "}" , |
262 | Style)); |
263 | |
264 | // FIXME: The block below is over-indented. |
265 | EXPECT_EQ(" {\n" |
266 | " \"name\": 1\n" |
267 | " }" , |
268 | format("\n{\n" |
269 | " \"name\": 1\n" |
270 | "}" , |
271 | Style)); |
272 | } |
273 | |
274 | } // namespace format |
275 | } // end namespace clang |
276 | |