xref: /llvm-project/clang/unittests/Format/FormatTestJson.cpp (revision 1c58208d899285318c89e069268145c85ec33368)
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(StringRef Code,unsigned Offset,unsigned Length,const FormatStyle & Style)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           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(StringRef Code,const FormatStyle & Style=getLLVMStyle (FormatStyle::LK_Json))50   format(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(StringRef Code,const FormatStyle & Style)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
verifyFormat(StringRef Code,const FormatStyle & Style=getLLVMStyle (FormatStyle::LK_Json))66   verifyFormat(StringRef Code,
67                const FormatStyle &Style = getLLVMStyle(FormatStyle::LK_Json)) {
68     verifyFormatStable(Code, Style);
69     EXPECT_EQ(Code.str(), format(test::messUp(Code), Style));
70   }
71 };
72 
TEST_F(FormatTestJson,JsonRecord)73 TEST_F(FormatTestJson, JsonRecord) {
74   verifyFormat("{}");
75   verifyFormat("{\n"
76                "  \"name\": 1\n"
77                "}");
78   verifyFormat("{\n"
79                "  \"name\": \"Foo\"\n"
80                "}");
81   verifyFormat("{\n"
82                "  \"name\": {\n"
83                "    \"value\": 1\n"
84                "  }\n"
85                "}");
86   verifyFormat("{\n"
87                "  \"name\": {\n"
88                "    \"value\": 1\n"
89                "  },\n"
90                "  \"name\": {\n"
91                "    \"value\": 2\n"
92                "  }\n"
93                "}");
94   verifyFormat("{\n"
95                "  \"name\": {\n"
96                "    \"value\": [\n"
97                "      1,\n"
98                "      2,\n"
99                "    ]\n"
100                "  }\n"
101                "}");
102   verifyFormat("{\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(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 
TEST_F(FormatTestJson,JsonArray)140 TEST_F(FormatTestJson, JsonArray) {
141   verifyFormat("[]");
142   verifyFormat("[\n"
143                "  1\n"
144                "]");
145   verifyFormat("[\n"
146                "  1,\n"
147                "  2\n"
148                "]");
149   verifyFormat("[\n"
150                "  {},\n"
151                "  {}\n"
152                "]");
153   verifyFormat("[\n"
154                "  {\n"
155                "    \"name\": 1\n"
156                "  },\n"
157                "  {}\n"
158                "]");
159 }
160 
TEST_F(FormatTestJson,JsonArrayOneLine)161 TEST_F(FormatTestJson, JsonArrayOneLine) {
162   FormatStyle Style = getLLVMStyle(FormatStyle::LK_Json);
163   Style.BreakArrays = false;
164   Style.SpacesInContainerLiterals = false;
165   verifyFormat("[]", Style);
166   verifyFormat("[1]", Style);
167   verifyFormat("[1, 2]", Style);
168   verifyFormat("[1, 2, 3]", Style);
169   verifyFormat("[1, 2, 3, 4]", Style);
170   verifyFormat("[1, 2, 3, 4, 5]", Style);
171 
172   verifyFormat("[\n"
173                "  1,\n"
174                "  2,\n"
175                "  {\n"
176                "    A: 1\n"
177                "  }\n"
178                "]",
179                Style);
180 }
181 
TEST_F(FormatTestJson,JsonNoStringSplit)182 TEST_F(FormatTestJson, JsonNoStringSplit) {
183   FormatStyle Style = getLLVMStyle(FormatStyle::LK_Json);
184   Style.IndentWidth = 4;
185   verifyFormat(
186       "[\n"
187       "    {\n"
188       "        "
189       "\"naaaaaaaa\": \"foooooooooooooooooooooo oooooooooooooooooooooo\"\n"
190       "    },\n"
191       "    {}\n"
192       "]",
193       Style);
194   verifyFormat("[\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("[\n"
207                "    {\n"
208                "        "
209                "\"naaaaaaaa\":\n"
210                "            "
211                "\"foooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo"
212                "oooooooooooooooooooooooooo\"\n"
213                "    },\n"
214                "    {}\n"
215                "]",
216                Style);
217 }
218 
TEST_F(FormatTestJson,DisableJsonFormat)219 TEST_F(FormatTestJson, DisableJsonFormat) {
220   FormatStyle Style = getLLVMStyle(FormatStyle::LK_Json);
221   verifyFormatStable("{}", Style);
222   verifyFormatStable("{\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("{}", Style);
232   verifyFormatStable("{\n"
233                      "  \"name\": 1\n"
234                      "}",
235                      Style);
236 }
237 
TEST_F(FormatTestJson,SpaceBeforeJsonColon)238 TEST_F(FormatTestJson, SpaceBeforeJsonColon) {
239   FormatStyle Style = getLLVMStyle(FormatStyle::LK_Json);
240   verifyFormatStable("{\n"
241                      "  \"name\": 1\n"
242                      "}",
243                      Style);
244 
245   Style.SpaceBeforeJsonColon = true;
246   verifyFormatStable("{}", Style);
247   verifyFormatStable("{\n"
248                      "  \"name\" : 1\n"
249                      "}",
250                      Style);
251 }
252 
TEST_F(FormatTestJson,StartsWithWhitespaces)253 TEST_F(FormatTestJson, StartsWithWhitespaces) {
254   FormatStyle Style = getLLVMStyle(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