xref: /llvm-project/clang/unittests/Format/FormatTestJson.cpp (revision af98f3b1f4db065ff82b50a9689511dd3223655b)
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, JsonArrayOneLine) {
163   FormatStyle Style = getLLVMStyle(FormatStyle::LK_Json);
164   Style.BreakArrays = false;
165   Style.SpacesInContainerLiterals = false;
166   verifyFormat("[]", Style);
167   verifyFormat("[1]", Style);
168   verifyFormat("[1, 2]", Style);
169   verifyFormat("[1, 2, 3]", Style);
170   verifyFormat("[1, 2, 3, 4]", Style);
171   verifyFormat("[1, 2, 3, 4, 5]", Style);
172 
173   verifyFormat("[\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(FormatStyle::LK_Json);
185   Style.IndentWidth = 4;
186   verifyFormat(
187       "[\n"
188       "    {\n"
189       "        "
190       "\"naaaaaaaa\": \"foooooooooooooooooooooo oooooooooooooooooooooo\"\n"
191       "    },\n"
192       "    {}\n"
193       "]",
194       Style);
195   verifyFormat("[\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("[\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(FormatStyle::LK_Json);
222   verifyFormatStable("{}", Style);
223   verifyFormatStable("{\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("{}", Style);
233   verifyFormatStable("{\n"
234                      "  \"name\": 1\n"
235                      "}",
236                      Style);
237 }
238 
239 TEST_F(FormatTestJson, SpaceBeforeJsonColon) {
240   FormatStyle Style = getLLVMStyle(FormatStyle::LK_Json);
241   verifyFormatStable("{\n"
242                      "  \"name\": 1\n"
243                      "}",
244                      Style);
245 
246   Style.SpaceBeforeJsonColon = true;
247   verifyFormatStable("{}", Style);
248   verifyFormatStable("{\n"
249                      "  \"name\" : 1\n"
250                      "}",
251                      Style);
252 }
253 
254 } // namespace format
255 } // end namespace clang
256