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(StringRef Code, unsigned Offset, unsigned Length, |
22 | 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(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(StringRef Code, const FormatStyle &Style) { |
62 | EXPECT_EQ(Code.str(), format(Code, Style)) << "Expected code is not stable" ; |
63 | } |
64 | |
65 | static void |
66 | verifyFormat(StringRef Code, |
67 | const FormatStyle &Style = getLLVMStyle(Language: FormatStyle::LK_Json)) { |
68 | verifyFormatStable(Code, Style); |
69 | EXPECT_EQ(Code.str(), format(test::messUp(Code), Style)); |
70 | } |
71 | }; |
72 | |
73 | TEST_F(FormatTestJson, JsonRecord) { |
74 | verifyFormat(Code: "{}" ); |
75 | verifyFormat(Code: "{\n" |
76 | " \"name\": 1\n" |
77 | "}" ); |
78 | verifyFormat(Code: "{\n" |
79 | " \"name\": \"Foo\"\n" |
80 | "}" ); |
81 | verifyFormat(Code: "{\n" |
82 | " \"name\": {\n" |
83 | " \"value\": 1\n" |
84 | " }\n" |
85 | "}" ); |
86 | verifyFormat(Code: "{\n" |
87 | " \"name\": {\n" |
88 | " \"value\": 1\n" |
89 | " },\n" |
90 | " \"name\": {\n" |
91 | " \"value\": 2\n" |
92 | " }\n" |
93 | "}" ); |
94 | verifyFormat(Code: "{\n" |
95 | " \"name\": {\n" |
96 | " \"value\": [\n" |
97 | " 1,\n" |
98 | " 2,\n" |
99 | " ]\n" |
100 | " }\n" |
101 | "}" ); |
102 | verifyFormat(Code: "{\n" |
103 | " \"name\": {\n" |
104 | " \"value\": [\n" |
105 | " \"name\": {\n" |
106 | " \"value\": 1\n" |
107 | " },\n" |
108 | " \"name\": {\n" |
109 | " \"value\": 2\n" |
110 | " }\n" |
111 | " ]\n" |
112 | " }\n" |
113 | "}" ); |
114 | verifyFormat(Code: R"({ |
115 | "firstName": "John", |
116 | "lastName": "Smith", |
117 | "isAlive": true, |
118 | "age": 27, |
119 | "address": { |
120 | "streetAddress": "21 2nd Street", |
121 | "city": "New York", |
122 | "state": "NY", |
123 | "postalCode": "10021-3100" |
124 | }, |
125 | "phoneNumbers": [ |
126 | { |
127 | "type": "home", |
128 | "number": "212 555-1234" |
129 | }, |
130 | { |
131 | "type": "office", |
132 | "number": "646 555-4567" |
133 | } |
134 | ], |
135 | "children": [], |
136 | "spouse": null |
137 | })" ); |
138 | } |
139 | |
140 | TEST_F(FormatTestJson, JsonArray) { |
141 | verifyFormat(Code: "[]" ); |
142 | verifyFormat(Code: "[\n" |
143 | " 1\n" |
144 | "]" ); |
145 | verifyFormat(Code: "[\n" |
146 | " 1,\n" |
147 | " 2\n" |
148 | "]" ); |
149 | verifyFormat(Code: "[\n" |
150 | " {},\n" |
151 | " {}\n" |
152 | "]" ); |
153 | verifyFormat(Code: "[\n" |
154 | " {\n" |
155 | " \"name\": 1\n" |
156 | " },\n" |
157 | " {}\n" |
158 | "]" ); |
159 | } |
160 | |
161 | TEST_F(FormatTestJson, JsonArrayOneLine) { |
162 | FormatStyle Style = getLLVMStyle(Language: FormatStyle::LK_Json); |
163 | Style.BreakArrays = false; |
164 | Style.SpacesInContainerLiterals = false; |
165 | verifyFormat(Code: "[]" , Style); |
166 | verifyFormat(Code: "[1]" , Style); |
167 | verifyFormat(Code: "[1, 2]" , Style); |
168 | verifyFormat(Code: "[1, 2, 3]" , Style); |
169 | verifyFormat(Code: "[1, 2, 3, 4]" , Style); |
170 | verifyFormat(Code: "[1, 2, 3, 4, 5]" , Style); |
171 | |
172 | verifyFormat(Code: "[\n" |
173 | " 1,\n" |
174 | " 2,\n" |
175 | " {\n" |
176 | " A: 1\n" |
177 | " }\n" |
178 | "]" , |
179 | Style); |
180 | } |
181 | |
182 | TEST_F(FormatTestJson, JsonNoStringSplit) { |
183 | FormatStyle Style = getLLVMStyle(Language: FormatStyle::LK_Json); |
184 | Style.IndentWidth = 4; |
185 | verifyFormat( |
186 | Code: "[\n" |
187 | " {\n" |
188 | " " |
189 | "\"naaaaaaaa\": \"foooooooooooooooooooooo oooooooooooooooooooooo\"\n" |
190 | " },\n" |
191 | " {}\n" |
192 | "]" , |
193 | Style); |
194 | verifyFormat(Code: "[\n" |
195 | " {\n" |
196 | " " |
197 | "\"naaaaaaaa\": " |
198 | "\"foooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo" |
199 | "oooooooooooooooooooooooooo\"\n" |
200 | " },\n" |
201 | " {}\n" |
202 | "]" , |
203 | Style); |
204 | |
205 | Style.ColumnLimit = 80; |
206 | verifyFormat(Code: "[\n" |
207 | " {\n" |
208 | " " |
209 | "\"naaaaaaaa\":\n" |
210 | " " |
211 | "\"foooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo" |
212 | "oooooooooooooooooooooooooo\"\n" |
213 | " },\n" |
214 | " {}\n" |
215 | "]" , |
216 | Style); |
217 | } |
218 | |
219 | TEST_F(FormatTestJson, DisableJsonFormat) { |
220 | FormatStyle Style = getLLVMStyle(Language: FormatStyle::LK_Json); |
221 | verifyFormatStable(Code: "{}" , Style); |
222 | verifyFormatStable(Code: "{\n" |
223 | " \"name\": 1\n" |
224 | "}" , |
225 | Style); |
226 | |
227 | // Since we have to disable formatting to run this test, we shall refrain from |
228 | // calling test::messUp lest we change the unformatted code and cannot format |
229 | // it back to how it started. |
230 | Style.DisableFormat = true; |
231 | verifyFormatStable(Code: "{}" , Style); |
232 | verifyFormatStable(Code: "{\n" |
233 | " \"name\": 1\n" |
234 | "}" , |
235 | Style); |
236 | } |
237 | |
238 | TEST_F(FormatTestJson, SpaceBeforeJsonColon) { |
239 | FormatStyle Style = getLLVMStyle(Language: FormatStyle::LK_Json); |
240 | verifyFormatStable(Code: "{\n" |
241 | " \"name\": 1\n" |
242 | "}" , |
243 | Style); |
244 | |
245 | Style.SpaceBeforeJsonColon = true; |
246 | verifyFormatStable(Code: "{}" , Style); |
247 | verifyFormatStable(Code: "{\n" |
248 | " \"name\" : 1\n" |
249 | "}" , |
250 | Style); |
251 | } |
252 | |
253 | TEST_F(FormatTestJson, StartsWithWhitespaces) { |
254 | FormatStyle Style = getLLVMStyle(Language: FormatStyle::LK_Json); |
255 | EXPECT_EQ("{\n" |
256 | " \"name\": 1\n" |
257 | "}" , |
258 | format(" {\n" |
259 | " \"name\": 1\n" |
260 | "}" , |
261 | Style)); |
262 | |
263 | // FIXME: The block below is over-indented. |
264 | EXPECT_EQ(" {\n" |
265 | " \"name\": 1\n" |
266 | " }" , |
267 | format("\n{\n" |
268 | " \"name\": 1\n" |
269 | "}" , |
270 | Style)); |
271 | } |
272 | |
273 | } // namespace format |
274 | } // end namespace clang |
275 | |