xref: /llvm-project/clang/unittests/Format/FormatTestTextProto.cpp (revision 8b4bc76a2323961f6f8502e0d5249e53ac41c6ac)
1 //===- unittest/Format/FormatTestProto.cpp --------------------------------===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 
10 #include "FormatTestUtils.h"
11 #include "clang/Format/Format.h"
12 #include "llvm/Support/Debug.h"
13 #include "gtest/gtest.h"
14 
15 #define DEBUG_TYPE "format-test"
16 
17 namespace clang {
18 namespace format {
19 
20 class FormatTestTextProto : public ::testing::Test {
21 protected:
22   static std::string format(llvm::StringRef Code, unsigned Offset,
23                             unsigned Length, const FormatStyle &Style) {
24     DEBUG(llvm::errs() << "---\n");
25     DEBUG(llvm::errs() << Code << "\n\n");
26     std::vector<tooling::Range> Ranges(1, tooling::Range(Offset, Length));
27     tooling::Replacements Replaces = reformat(Style, Code, Ranges);
28     auto Result = applyAllReplacements(Code, Replaces);
29     EXPECT_TRUE(static_cast<bool>(Result));
30     DEBUG(llvm::errs() << "\n" << *Result << "\n\n");
31     return *Result;
32   }
33 
34   static std::string format(llvm::StringRef Code, const FormatStyle &Style) {
35     return format(Code, 0, Code.size(), Style);
36   }
37 
38   static void verifyFormat(llvm::StringRef Code, const FormatStyle &Style) {
39     EXPECT_EQ(Code.str(), format(Code, Style)) << "Expected code is not stable";
40     EXPECT_EQ(Code.str(), format(test::messUp(Code), Style));
41   }
42 
43   static void verifyFormat(llvm::StringRef Code) {
44     FormatStyle Style = getGoogleStyle(FormatStyle::LK_TextProto);
45     Style.ColumnLimit = 60; // To make writing tests easier.
46     verifyFormat(Code, Style);
47   }
48 };
49 
50 TEST_F(FormatTestTextProto, KeepsTopLevelEntriesFittingALine) {
51   verifyFormat("field_a: OK field_b: OK field_c: OK field_d: OK field_e: OK");
52 }
53 
54 TEST_F(FormatTestTextProto, SupportsMessageFields) {
55   verifyFormat("msg_field: {}");
56 
57   verifyFormat("msg_field: { field_a: A }");
58 
59   verifyFormat("msg_field: { field_a: \"OK\" field_b: 123 }");
60 
61   verifyFormat("msg_field: {\n"
62                "  field_a: 1\n"
63                "  field_b: OK\n"
64                "  field_c: \"OK\"\n"
65                "  field_d: 123\n"
66                "  field_e: 23\n"
67                "}");
68 
69   verifyFormat("msg_field {}");
70 
71   verifyFormat("msg_field { field_a: A }");
72 
73   verifyFormat("msg_field { field_a: \"OK\" field_b: 123 }");
74 
75   verifyFormat("msg_field {\n"
76                "  field_a: 1\n"
77                "  field_b: OK\n"
78                "  field_c: \"OK\"\n"
79                "  field_d: 123\n"
80                "  field_e: 23.0\n"
81                "  field_f: false\n"
82                "  field_g: 'lala'\n"
83                "  field_h: 1234.567e-89\n"
84                "}");
85 
86   verifyFormat("msg_field: { msg_field { field_a: 1 } }");
87 
88   verifyFormat("id: \"ala.bala\"\n"
89                "item { type: ITEM_A rank: 1 score: 90.0 }\n"
90                "item { type: ITEM_B rank: 2 score: 70.5 }\n"
91                "item {\n"
92                "  type: ITEM_A\n"
93                "  rank: 3\n"
94                "  score: 20.0\n"
95                "  description: \"the third item has a description\"\n"
96                "}");
97 }
98 
99 TEST_F(FormatTestTextProto, AvoidsTopLevelBinPacking) {
100   verifyFormat("field_a: OK\n"
101                "field_b: OK\n"
102                "field_c: OK\n"
103                "field_d: OK\n"
104                "field_e: OK\n"
105                "field_f: OK");
106 
107   verifyFormat("field_a: OK\n"
108                "field_b: \"OK\"\n"
109                "field_c: \"OK\"\n"
110                "msg_field: { field_d: 123 }\n"
111                "field_e: OK\n"
112                "field_f: OK");
113 
114   verifyFormat("field_a: OK\n"
115                "field_b: \"OK\"\n"
116                "field_c: \"OK\"\n"
117                "msg_field: { field_d: 123 field_e: OK }");
118 
119   verifyFormat("a: {\n"
120                "  field_a: OK\n"
121                "  field_b { field_c: OK }\n"
122                "  field_d: OKOKOK\n"
123                "  field_e: OK\n"
124                "}");
125 
126   verifyFormat("field_a: OK,\n"
127                "field_b { field_c: OK },\n"
128                "field_d: OKOKOK,\n"
129                "field_e: OK");
130 }
131 
132 TEST_F(FormatTestTextProto, AddsNewlinesAfterTrailingComments) {
133   verifyFormat("field_a: OK  // Comment\n"
134                "field_b: 1");
135 
136   verifyFormat("field_a: OK\n"
137                "msg_field: {\n"
138                "  field_b: OK  // Comment\n"
139                "}");
140 
141   verifyFormat("field_a: OK\n"
142                "msg_field {\n"
143                "  field_b: OK  // Comment\n"
144                "}");
145 }
146 
147 TEST_F(FormatTestTextProto, ImplicitStringLiteralConcatenation) {
148   verifyFormat("field_a: 'aaaaa'\n"
149                "         'bbbbb'");
150   verifyFormat("field_a: \"aaaaa\"\n"
151                "         \"bbbbb\"");
152   FormatStyle Style = getGoogleStyle(FormatStyle::LK_TextProto);
153   Style.AlwaysBreakBeforeMultilineStrings = true;
154   verifyFormat("field_a:\n"
155                "    'aaaaa'\n"
156                "    'bbbbb'",
157                Style);
158   verifyFormat("field_a:\n"
159                "    \"aaaaa\"\n"
160                "    \"bbbbb\"",
161                Style);
162 }
163 
164 TEST_F(FormatTestTextProto, SupportsAngleBracketMessageFields) {
165   // Single-line tests
166   verifyFormat("msg_field <>");
167   verifyFormat("msg_field: <>");
168   verifyFormat("msg_field < field_a: OK >");
169   verifyFormat("msg_field: < field_a: 123 >");
170   verifyFormat("msg_field < field_a <> >");
171   verifyFormat("msg_field < field_a < field_b <> > >");
172   verifyFormat("msg_field: < field_a < field_b: <> > >");
173   verifyFormat("msg_field < field_a: OK, field_b: \"OK\" >");
174   verifyFormat("msg_field < field_a: OK field_b: <>, field_c: OK >");
175   verifyFormat("msg_field < field_a { field_b: 1 }, field_c: < f_d: 2 > >");
176   verifyFormat("msg_field: < field_a: OK, field_b: \"OK\" >");
177   verifyFormat("msg_field: < field_a: OK field_b: <>, field_c: OK >");
178   verifyFormat("msg_field: < field_a { field_b: 1 }, field_c: < fd_d: 2 > >");
179   verifyFormat("field_a: \"OK\", msg_field: < field_b: 123 >, field_c: {}");
180   verifyFormat("field_a < field_b: 1 >, msg_fid: < fiel_b: 123 >, field_c <>");
181   verifyFormat("field_a < field_b: 1 > msg_fied: < field_b: 123 > field_c <>");
182   verifyFormat("field < field < field: <> >, field <> > field: < field: 1 >");
183 
184   // Multiple lines tests
185   verifyFormat("msg_field <\n"
186                "  field_a: OK\n"
187                "  field_b: \"OK\"\n"
188                "  field_c: 1\n"
189                "  field_d: 12.5\n"
190                "  field_e: OK\n"
191                ">");
192 
193   verifyFormat("msg_field: <>\n"
194                "field_c: \"OK\",\n"
195                "msg_field: < field_d: 123 >\n"
196                "field_e: OK\n"
197                "msg_field: < field_d: 12 >");
198 
199   verifyFormat("field_a: OK,\n"
200                "field_b < field_c: OK >,\n"
201                "field_d: < 12.5 >,\n"
202                "field_e: OK");
203 
204   verifyFormat("field_a: OK\n"
205                "field_b < field_c: OK >\n"
206                "field_d: < 12.5 >\n"
207                "field_e: OKOKOK");
208 
209   verifyFormat("msg_field <\n"
210                "  field_a: OK,\n"
211                "  field_b < field_c: OK >,\n"
212                "  field_d: < 12.5 >,\n"
213                "  field_e: OK\n"
214                ">");
215 
216   verifyFormat("msg_field <\n"
217                "  field_a: < field: OK >,\n"
218                "  field_b < field_c: OK >,\n"
219                "  field_d: < 12.5 >,\n"
220                "  field_e: OK,\n"
221                ">");
222 
223   verifyFormat("msg_field: <\n"
224                "  field_a: \"OK\"\n"
225                "  msg_field: { field_b: OK }\n"
226                "  field_g: OK\n"
227                "  field_g: OK\n"
228                "  field_g: OK\n"
229                ">");
230 
231   verifyFormat("field_a {\n"
232                "  field_d: ok\n"
233                "  field_b: < field_c: 1 >\n"
234                "  field_d: ok\n"
235                "  field_d: ok\n"
236                "}");
237 
238   verifyFormat("field_a: {\n"
239                "  field_d: ok\n"
240                "  field_b: < field_c: 1 >\n"
241                "  field_d: ok\n"
242                "  field_d: ok\n"
243                "}");
244 
245   verifyFormat("field_a: < f1: 1, f2: <> >\n"
246                "field_b <\n"
247                "  field_b1: <>\n"
248                "  field_b2: ok,\n"
249                "  field_b3: <\n"
250                "    field_x {}  // Comment\n"
251                "    field_y: { field_z: 1 }\n"
252                "    field_w: ok\n"
253                "  >\n"
254                "  field {\n"
255                "    field_x <>  // Comment\n"
256                "    field_y: < field_z: 1 >\n"
257                "    field_w: ok\n"
258                "    msg_field: <\n"
259                "      field: <>\n"
260                "      field: < field: 1 >\n"
261                "      field: < field: 2 >\n"
262                "      field: < field: 3 >\n"
263                "      field: < field: 4 >\n"
264                "      field: ok\n"
265                "    >\n"
266                "  }\n"
267                ">\n"
268                "field: OK,\n"
269                "field_c < field < field <> > >");
270 
271   verifyFormat("app_id: 'com.javax.swing.salsa.latino'\n"
272                "head_id: 1\n"
273                "data < key: value >");
274 
275   verifyFormat("app_id: 'com.javax.swing.salsa.latino'\n"
276                "head_id: 1\n"
277                "data < key: value >\n"
278                "tail_id: 2");
279 
280   verifyFormat("app_id: 'com.javax.swing.salsa.latino'\n"
281                "head_id: 1\n"
282                "data < key: value >\n"
283                "data { key: value }");
284 
285   verifyFormat("app {\n"
286                "  app_id: 'com.javax.swing.salsa.latino'\n"
287                "  head_id: 1\n"
288                "  data < key: value >\n"
289                "}");
290 
291   verifyFormat("app: {\n"
292                "  app_id: 'com.javax.swing.salsa.latino'\n"
293                "  head_id: 1\n"
294                "  data < key: value >\n"
295                "}");
296 
297   verifyFormat("app_id: 'com.javax.swing.salsa.latino'\n"
298                "headheadheadheadheadhead_id: 1\n"
299                "product_data { product { 1 } }");
300 
301   verifyFormat("app_id: 'com.javax.swing.salsa.latino'\n"
302                "headheadheadheadheadhead_id: 1\n"
303                "product_data < product { 1 } >");
304 
305   verifyFormat("app_id: 'com.javax.swing.salsa.latino'\n"
306                "headheadheadheadheadhead_id: 1\n"
307                "product_data < product < 1 > >");
308 
309   verifyFormat("app <\n"
310                "  app_id: 'com.javax.swing.salsa.latino'\n"
311                "  headheadheadheadheadhead_id: 1\n"
312                "  product_data < product { 1 } >\n"
313                ">");
314 
315   verifyFormat("dcccwrnfioeruvginerurneitinfo {\n"
316                "  exte3nsionrnfvui { key: value }\n"
317                "}");
318 }
319 
320 TEST_F(FormatTestTextProto, DiscardsUnbreakableTailIfCanBreakAfter) {
321   // The two closing braces count towards the string UnbreakableTailLength, but
322   // since we have broken after the corresponding opening braces, we don't
323   // consider that length for string breaking.
324   verifyFormat(
325       "foo: {\n"
326       "  bar: {\n"
327       "    text: \"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\"\n"
328       "  }\n"
329       "}");
330 }
331 
332 TEST_F(FormatTestTextProto, KeepsLongStringLiteralsOnSameLine) {
333   verifyFormat(
334       "foo: {\n"
335       "  text: \"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasaaaaaaaaaa\"\n"
336       "}");
337 }
338 
339 TEST_F(FormatTestTextProto, KeepsCommentsIndentedInList) {
340   verifyFormat("aaaaaaaaaa: 100\n"
341                "bbbbbbbbbbbbbbbbbbbbbbbbbbb: 200\n"
342                "# Single line comment for stuff here.\n"
343                "cccccccccccccccccccccccc: 3849\n"
344                "# Multiline comment for stuff here.\n"
345                "# Multiline comment for stuff here.\n"
346                "# Multiline comment for stuff here.\n"
347                "cccccccccccccccccccccccc: 3849");
348 }
349 
350 TEST_F(FormatTestTextProto, FormatsExtensions) {
351   verifyFormat("[type] { key: value }");
352   verifyFormat("[type] {\n"
353                "  keyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy: value\n"
354                "}");
355   verifyFormat("[type.type] { key: value }");
356   verifyFormat("[type.type] < key: value >");
357   verifyFormat("[type.type/type.type] { key: value }");
358   verifyFormat("msg {\n"
359                "  [type.type] { key: value }\n"
360                "}");
361   verifyFormat("msg {\n"
362                "  [type.type] {\n"
363                "    keyyyyyyyyyyyyyy: valuuuuuuuuuuuuuuuuuuuuuuuuue\n"
364                "  }\n"
365                "}");
366   verifyFormat("key: value\n"
367                "[a.b] { key: value }");
368   verifyFormat("msg: <\n"
369                "  key: value\n"
370                "  [a.b.c/d.e]: < key: value >\n"
371                "  [f.g]: <\n"
372                "    key: valueeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee\n"
373                "    key: {}\n"
374                "  >\n"
375                "  key {}\n"
376                "  [h.i.j] < key: value >\n"
377                "  [a]: {\n"
378                "    [b.c]: {}\n"
379                "    [d] <>\n"
380                "    [e/f]: 1\n"
381                "  }\n"
382                ">");
383   verifyFormat("[longg.long.long.long.long.long.long.long.long.long.long\n"
384                "     .longg.longlong] { key: value }");
385   verifyFormat("[longg.long.long.long.long.long.long.long.long.long.long\n"
386                "     .longg.longlong] {\n"
387                "  key: value\n"
388                "  key: value\n"
389                "  key: value\n"
390                "  key: value\n"
391                "}");
392   verifyFormat("[longg.long.long.long.long.long.long.long.long.long\n"
393                "     .long/longg.longlong] { key: value }");
394   verifyFormat("[aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/\n"
395                " bbbbbbbbbbbbbb] { key: value }");
396   // These go over the column limit intentionally, since the alternative
397   // [aa..a\n] is worse.
398   verifyFormat("[aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa] {\n"
399                "  key: value\n"
400                "}");
401   verifyFormat("[aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa] {\n"
402                "  [type.type] {\n"
403                "    keyyyyyyyyyyyyyy: valuuuuuuuuuuuuuuuuuuuuuuuuue\n"
404                "  }\n"
405                "}");
406   verifyFormat("[aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/\n"
407                " bbbbbbb] {\n"
408                "  [type.type] {\n"
409                "    keyyyyyyyyyyyyyy: valuuuuuuuuuuuuuuuuuuuuuuuuue\n"
410                "  }\n"
411                "}");
412   verifyFormat(
413       "aaaaaaaaaaaaaaa {\n"
414       "  bbbbbb {\n"
415       "    [a.b/cy] {\n"
416       "      eeeeeeeeeeeee: \"The lazy coo cat jumps over the lazy hot dog\"\n"
417       "    }\n"
418       "  }\n"
419       "}");
420 }
421 
422 TEST_F(FormatTestTextProto, SpacesAroundPercents) {
423   verifyFormat("key: %d");
424   verifyFormat("key: 0x%04x");
425   verifyFormat("key: \"%d %d\"");
426 }
427 
428 TEST_F(FormatTestTextProto, FormatsRepeatedListInitializers) {
429   verifyFormat("keys: []");
430   verifyFormat("keys: [ 1 ]");
431   verifyFormat("keys: [ 'ala', 'bala' ]");
432   verifyFormat("keys:\n"
433                "    [ 'ala', 'bala', 'porto', 'kala', 'too', 'long', 'ng' ]");
434   verifyFormat("key: item\n"
435                "keys: [\n"
436                "  'ala',\n"
437                "  'bala',\n"
438                "  'porto',\n"
439                "  'kala',\n"
440                "  'too',\n"
441                "  'long',\n"
442                "  'long',\n"
443                "  'long'\n"
444                "]\n"
445                "key: item\n"
446                "msg {\n"
447                "  key: item\n"
448                "  keys: [\n"
449                "    'ala',\n"
450                "    'bala',\n"
451                "    'porto',\n"
452                "    'kala',\n"
453                "    'too',\n"
454                "    'long',\n"
455                "    'long'\n"
456                "  ]\n"
457                "}\n"
458                "key: value"
459                );
460   FormatStyle Style = getGoogleStyle(FormatStyle::LK_TextProto);
461   Style.ColumnLimit = 60; // To make writing tests easier.
462   Style.Cpp11BracedListStyle = true;
463   verifyFormat("keys: [1]", Style);
464 }
465 
466 TEST_F(FormatTestTextProto, AcceptsOperatorAsKey) {
467   verifyFormat("aaaaaaaaaaa: <\n"
468                "  bbbbbbbbb: <\n"
469                "    ccccccccccccccccccccccc: <\n"
470                "      operator: 1\n"
471                "      operator: 2\n"
472                "      operator: 3\n"
473                "      operator { key: value }\n"
474                "    >\n"
475                "  >\n"
476                ">");
477 }
478 
479 TEST_F(FormatTestTextProto, BreaksConsecutiveStringLiterals) {
480   verifyFormat("ala: \"str1\"\n"
481                "     \"str2\"\n");
482 }
483 
484 TEST_F(FormatTestTextProto, PutsMultipleEntriesInExtensionsOnNewlines) {
485   FormatStyle Style = getGoogleStyle(FormatStyle::LK_TextProto);
486   verifyFormat("pppppppppp: {\n"
487                "  ssssss: \"http://example.com/blahblahblah\"\n"
488                "  ppppppp: \"sssss/MMMMMMMMMMMM\"\n"
489                "  [ns.sssss.eeeeeeeee.eeeeeeeeeeeeeee] { begin: 24 end: 252 }\n"
490                "  [ns.sssss.eeeeeeeee.eeeeeeeeeeeeeee] {\n"
491                "    begin: 24\n"
492                "    end: 252\n"
493                "    key: value\n"
494                "    key: value\n"
495                "  }\n"
496                "}", Style);
497 }
498 
499 TEST_F(FormatTestTextProto, BreaksAfterBraceFollowedByClosingBraceOnNextLine) {
500   FormatStyle Style = getGoogleStyle(FormatStyle::LK_TextProto);
501   Style.ColumnLimit = 60;
502   verifyFormat("keys: [\n"
503                "  data: { item: 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' }\n"
504                "]");
505   verifyFormat("keys: <\n"
506                "  data: { item: 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' }\n"
507                ">");
508 }
509 
510 } // end namespace tooling
511 } // end namespace clang
512