678 lines · cpp
1//===- unittest/Format/FormatTestProto.cpp --------------------------------===//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-exception6//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"15 16namespace clang {17namespace format {18 19class FormatTestProto : public testing::Test {20protected: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 std::vector<tooling::Range> Ranges(1, tooling::Range(Offset, Length));26 tooling::Replacements Replaces = reformat(Style, Code, Ranges);27 auto Result = applyAllReplacements(Code, Replaces);28 EXPECT_TRUE(static_cast<bool>(Result));29 LLVM_DEBUG(llvm::errs() << "\n" << *Result << "\n\n");30 return *Result;31 }32 33 static std::string format(StringRef Code) {34 FormatStyle Style = getGoogleStyle(FormatStyle::LK_Proto);35 Style.ColumnLimit = 60; // To make writing tests easier.36 return format(Code, 0, Code.size(), Style);37 }38 39 static void verifyFormat(StringRef Code) {40 EXPECT_EQ(Code.str(), format(Code)) << "Expected code is not stable";41 EXPECT_EQ(Code.str(), format(test::messUp(Code)));42 }43};44 45TEST_F(FormatTestProto, FormatsMessages) {46 verifyFormat("message SomeMessage {\n"47 " required int32 field1 = 1;\n"48 "}");49 verifyFormat("message SomeMessage {\n"50 " required .absolute.Reference field1 = 1;\n"51 "}");52 verifyFormat("message SomeMessage {\n"53 " required int32 field1 = 1;\n"54 " optional string field2 = 2 [default = \"2\"]\n"55 "}");56 57 verifyFormat("message SomeMessage {\n"58 " optional really.really.long.qualified.type.aaa.aaaaaaa\n"59 " fiiiiiiiiiiiiiiiiiiiiiiiiield = 1;\n"60 " optional\n"61 " really.really.long.qualified.type.aaa.aaaaaaa.aaaaaaaa\n"62 " another_fiiiiiiiiiiiiiiiiiiiiield = 2;\n"63 "}");64 verifyFormat("message SomeMessage {\n"65 " map<string, Project> projects = 1;\n"66 " optional map<string, int32> size_projects = 2;\n"67 " map<int, really.really.really.long.qualified.type.nameeee>\n"68 " projects = 3;\n"69 " map<int, really.really.really.really.long.qualified.type\n"70 " .nameeee> projects = 4;\n"71 " map<int,\n"72 " reallyreallyreallyreallyreallyreallyreallylongname>\n"73 " projects = 5;\n"74 " map<int, Project>\n"75 " longlonglonglonglonglonglonglonglonglongonglon = 6;\n"76 " map<releleallyreallyreallyreallyreallyreallyreallylongname,\n"77 " int> projects = 7;\n"78 " map<releleallyreallyreallyreallyreallyreallyreallylongname,\n"79 " releleallyreallyreallyreallyreallyreallyreallylongname>\n"80 " releleallyreallyreallyreallyreallyreallyreallylongnam =\n"81 " 8;\n"82 " map<relele.llyreal.yreallyr.allyreally.eallyreal\n"83 " .sauenirylongname,\n"84 " really.really.really.really.long.qualified.type\n"85 " .nameeee> projects = 9;\n"86 "}");87}88 89TEST_F(FormatTestProto, KeywordsInOtherLanguages) {90 verifyFormat("optional string operator = 1;");91}92 93TEST_F(FormatTestProto, FormatsEnums) {94 verifyFormat("enum Type {\n"95 " UNKNOWN = 0;\n"96 " TYPE_A = 1;\n"97 " TYPE_B = 2;\n"98 "};");99 verifyFormat("enum Type {\n"100 " UNKNOWN = 0 [(some_options) = { a: aa, b: bb }];\n"101 "};");102 verifyFormat("enum Type {\n"103 " UNKNOWN = 0 [(some_options) = {\n"104 " a: aa, // wrap\n"105 " b: bb\n"106 " }];\n"107 "};");108}109 110TEST_F(FormatTestProto, EnumAsFieldName) {111 verifyFormat("message SomeMessage {\n"112 " required int32 enum = 1;\n"113 "}");114}115 116TEST_F(FormatTestProto, CaseAsFieldName) {117 verifyFormat("message SomeMessage {\n"118 " required string case = 1;\n"119 " repeated int32 fizz = 2;\n"120 "}");121}122 123TEST_F(FormatTestProto, UnderstandsReturns) {124 verifyFormat("rpc Search(SearchRequest) returns (SearchResponse);");125}126 127TEST_F(FormatTestProto, MessageFieldAttributes) {128 verifyFormat("optional string test = 1 [default = \"test\"];");129 verifyFormat("optional bool a = 1 [default = true, deprecated = true];");130 verifyFormat("optional LongMessageType long_proto_field = 1 [\n"131 " default = REALLY_REALLY_LONG_CONSTANT_VALUE,\n"132 " deprecated = true\n"133 "];");134 verifyFormat("optional LongMessageType long_proto_field = 1\n"135 " [default = REALLY_REALLY_LONG_CONSTANT_VALUE];");136 verifyFormat("repeated double value = 1\n"137 " [(aaaaaaa.aaaaaaaaa) = { aaaaaaaaaaaaaaaaa: AAAAAAAA }];");138 verifyFormat("repeated double value = 1 [(aaaaaaa.aaaaaaaaa) = {\n"139 " aaaaaaaaaaaaaaaa: AAAAAAAAAA,\n"140 " bbbbbbbbbbbbbbbb: BBBBBBBBBB\n"141 "}];");142 verifyFormat("repeated double value = 1 [(aaaaaaa.aaaaaaaaa) = {\n"143 " aaaaaaaaaaaaaaaa: AAAAAAAAAA\n"144 " bbbbbbbbbbbbbbbb: BBBBBBBBBB\n"145 "}];");146 verifyFormat("repeated double value = 1 [\n"147 " (aaaaaaa.aaaaaaaaa) = {\n"148 " aaaaaaaaaaaaaaaa: AAAAAAAAAA\n"149 " bbbbbbbbbbbbbbbb: BBBBBBBBBB\n"150 " },\n"151 " (bbbbbbb.bbbbbbbbb) = {\n"152 " aaaaaaaaaaaaaaaa: AAAAAAAAAA\n"153 " bbbbbbbbbbbbbbbb: BBBBBBBBBB\n"154 " }\n"155 "];");156 verifyFormat("repeated double value = 1 [(aaaaaaa.aaaaaaaaa) = {\n"157 " type: \"AAAAAAAAAA\"\n"158 " is: \"AAAAAAAAAA\"\n"159 " or: \"BBBBBBBBBB\"\n"160 "}];");161 verifyFormat("repeated double value = 1 [(aaaaaaa.aaaaaaaaa) = {\n"162 " aaaaaaaaaaaaaaaa: AAAAAAAAAA,\n"163 " bbbbbbb: BBBB,\n"164 " bbbb: BBB\n"165 "}];");166 verifyFormat("optional AAA aaa = 1 [\n"167 " foo = {\n"168 " key: 'a' //\n"169 " },\n"170 " bar = {\n"171 " key: 'a' //\n"172 " }\n"173 "];");174 verifyFormat("optional string test = 1 [default = \"test\"\n"175 " \"test\"];");176 verifyFormat("optional Aaaaaaaa aaaaaaaa = 12 [\n"177 " (aaa) = aaaa,\n"178 " (bbbbbbbbbbbbbbbbbbbbbbbbbb) = {\n"179 " aaaaaaaaaaaaaaaaa: true,\n"180 " aaaaaaaaaaaaaaaa: true\n"181 " }\n"182 "];");183 verifyFormat("extensions 20 [(proto2.type) = 'Aaaa.bbbb'];");184 verifyFormat("extensions 20\n"185 " [(proto3.type) = 'Aaaa.bbbb', (aaa.Aaa) = 'aaa.bbb'];");186 verifyFormat("extensions 123 [\n"187 " (aaa) = aaaa,\n"188 " (bbbbbbbbbbbbbbbbbbbbbbbbbb) = {\n"189 " aaaaaaaaaaaaaaaaa: true,\n"190 " aaaaaaaaaaaaaaaa: true\n"191 " }\n"192 "];");193 verifyFormat("repeated A a = 1 [(annotation).int32.repeated.test = true];");194}195 196TEST_F(FormatTestProto, DoesntWrapFileOptions) {197 EXPECT_EQ(198 "option java_package = "199 "\"some.really.long.package.that.exceeds.the.column.limit\";",200 format("option java_package = "201 "\"some.really.long.package.that.exceeds.the.column.limit\";"));202}203 204TEST_F(FormatTestProto, TrailingCommentAfterFileOption) {205 verifyFormat("option java_package = \"foo.pkg\"; // comment");206}207 208TEST_F(FormatTestProto, FormatsOptions) {209 verifyFormat("option (MyProto.options) = {\n"210 " field_a: OK\n"211 " field_b: \"OK\"\n"212 " field_c: \"OK\"\n"213 " msg_field: { field_d: 123 }\n"214 "};");215 verifyFormat("option (MyProto.options) = {\n"216 " field_a: OK\n"217 " field_b: \"OK\"\n"218 " field_c: \"OK\"\n"219 " msg_field: { field_d: 123 field_e: OK }\n"220 "};");221 verifyFormat("option (MyProto.options) = {\n"222 " field_a: OK // Comment\n"223 " field_b: \"OK\"\n"224 " field_c: \"OK\"\n"225 " msg_field: { field_d: 123 }\n"226 "};");227 verifyFormat("option (MyProto.options) = {\n"228 " field_c: \"OK\"\n"229 " msg_field { field_d: 123 }\n"230 "};");231 verifyFormat("option (MyProto.options) = {\n"232 " field_a: OK\n"233 " field_b { field_c: OK }\n"234 " field_d: OKOKOK\n"235 " field_e: OK\n"236 "}");237 238 // Support syntax with <> instead of {}.239 verifyFormat("option (MyProto.options) = {\n"240 " field_c: \"OK\",\n"241 " msg_field: < field_d: 123 >\n"242 " empty: <>\n"243 " empty <>\n"244 "};");245 246 verifyFormat("option (MyProto.options) = {\n"247 " field_a: OK\n"248 " field_b < field_c: OK >\n"249 " field_d: OKOKOK\n"250 " field_e: OK\n"251 "}");252 253 verifyFormat("option (MyProto.options) = {\n"254 " msg_field: <>\n"255 " field_c: \"OK\",\n"256 " msg_field: < field_d: 123 >\n"257 " field_e: OK\n"258 " msg_field: < field_d: 12 >\n"259 "};");260 261 verifyFormat("option (MyProto.options) = <\n"262 " field_a: OK\n"263 " field_b: \"OK\"\n"264 " field_c: 1\n"265 " field_d: 12.5\n"266 " field_e: OK\n"267 ">;");268 269 verifyFormat("option (MyProto.options) = <\n"270 " field_a: OK,\n"271 " field_b: \"OK\",\n"272 " field_c: 1,\n"273 " field_d: 12.5,\n"274 " field_e: OK,\n"275 ">;");276 277 verifyFormat("option (MyProto.options) = <\n"278 " field_a: \"OK\"\n"279 " msg_field: { field_b: OK }\n"280 " field_g: OK\n"281 " field_g: OK\n"282 " field_g: OK\n"283 ">;");284 285 verifyFormat("option (MyProto.options) = <\n"286 " field_a: \"OK\"\n"287 " msg_field <\n"288 " field_b: OK\n"289 " field_c: OK\n"290 " field_d: OK\n"291 " field_e: OK\n"292 " field_f: OK\n"293 " >\n"294 " field_g: OK\n"295 ">;");296 297 verifyFormat("option (MyProto.options) = <\n"298 " field_a: \"OK\"\n"299 " msg_field <\n"300 " field_b: OK,\n"301 " field_c: OK,\n"302 " field_d: OK,\n"303 " field_e: OK,\n"304 " field_f: OK\n"305 " >\n"306 " field_g: OK\n"307 ">;");308 309 verifyFormat("option (MyProto.options) = <\n"310 " field_a: \"OK\"\n"311 " msg_field: <\n"312 " field_b: OK\n"313 " field_c: OK\n"314 " field_d: OK\n"315 " field_e: OK\n"316 " field_f: OK\n"317 " >\n"318 " field_g: OK\n"319 ">;");320 321 verifyFormat("option (MyProto.options) = <\n"322 " field_a: \"OK\"\n"323 " msg_field: {\n"324 " field_b: OK\n"325 " field_c: OK\n"326 " field_d: OK\n"327 " field_e: OK\n"328 " field_f: OK\n"329 " }\n"330 " field_g: OK\n"331 ">;");332 333 verifyFormat("option (MyProto.options) = <\n"334 " field_a: \"OK\"\n"335 " msg_field {\n"336 " field_b: OK\n"337 " field_c: OK\n"338 " field_d: OK\n"339 " field_e: OK\n"340 " field_f: OK\n"341 " }\n"342 " field_g: OK\n"343 ">;");344 345 verifyFormat("option (MyProto.options) = {\n"346 " field_a: \"OK\"\n"347 " msg_field <\n"348 " field_b: OK\n"349 " field_c: OK\n"350 " field_d: OK\n"351 " field_e: OK\n"352 " field_f: OK\n"353 " >\n"354 " field_g: OK\n"355 "};");356 357 verifyFormat("option (MyProto.options) = {\n"358 " field_a: \"OK\"\n"359 " msg_field: <\n"360 " field_b: OK\n"361 " field_c: OK\n"362 " field_d: OK\n"363 " field_e: OK\n"364 " field_f: OK\n"365 " >\n"366 " field_g: OK\n"367 "};");368 369 verifyFormat("option (MyProto.options) = <\n"370 " field_a: \"OK\"\n"371 " msg_field {\n"372 " field_b: OK\n"373 " field_c: OK\n"374 " field_d: OK\n"375 " msg_field <\n"376 " field_A: 1\n"377 " field_B: 2\n"378 " field_C: 3\n"379 " field_D: 4\n"380 " field_E: 5\n"381 " >\n"382 " msg_field < field_A: 1 field_B: 2 field_C: 3 f_D: 4 >\n"383 " field_e: OK\n"384 " field_f: OK\n"385 " }\n"386 " field_g: OK\n"387 ">;");388 389 verifyFormat("option (MyProto.options) = <\n"390 " data1 < key1: value1 >\n"391 " data2 { key2: value2 }\n"392 ">;");393 394 verifyFormat("option (MyProto.options) = <\n"395 " app_id: 'com.javax.swing.salsa.latino'\n"396 " head_id: 1\n"397 " data < key: value >\n"398 ">;");399 400 verifyFormat("option (MyProto.options) = {\n"401 " app_id: 'com.javax.swing.salsa.latino'\n"402 " head_id: 1\n"403 " headheadheadheadheadhead_id: 1\n"404 " product_data { product { 1 } }\n"405 "};");406}407 408TEST_F(FormatTestProto, DoesntWrapPackageStatements) {409 verifyFormat(410 "package"411 " some.really.long.package.that.exceeds.the.column.limit00000000;");412}413 414TEST_F(FormatTestProto, TrailingCommentAfterPackage) {415 verifyFormat("package foo.pkg; // comment");416}417 418TEST_F(FormatTestProto, FormatsService) {419 verifyFormat("service SearchService {\n"420 " rpc Search(SearchRequest) returns (SearchResponse) {\n"421 " option foo = true;\n"422 " }\n"423 "};");424}425 426TEST_F(FormatTestProto, ExtendingMessage) {427 verifyFormat("extend .foo.Bar {}");428}429 430TEST_F(FormatTestProto, FormatsImports) {431 verifyFormat("import \"a.proto\";\n"432 "import \"b.proto\";\n"433 "// comment\n"434 "message A {}");435 436 verifyFormat("import public \"a.proto\";\n"437 "import \"b.proto\";\n"438 "// comment\n"439 "message A {}");440 441 // Missing semicolons should not confuse clang-format.442 verifyFormat("import \"a.proto\"\n"443 "import \"b.proto\"\n"444 "// comment\n"445 "message A {}");446}447 448TEST_F(FormatTestProto, KeepsLongStringLiteralsOnSameLine) {449 verifyFormat(450 "option (MyProto.options) = {\n"451 " foo: {\n"452 " text: \"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaasaaaaaaaa\"\n"453 " }\n"454 "}");455}456 457TEST_F(FormatTestProto, FormatsOptionsExtensions) {458 verifyFormat("option (MyProto.options) = {\n"459 " msg_field: { field_d: 123 }\n"460 " [ext.t/u] { key: value }\n"461 " key: value\n"462 " [t.u/v] <\n"463 " [ext] { key: value }\n"464 " >\n"465 "};");466}467 468TEST_F(FormatTestProto, SpacesAroundPercents) {469 verifyFormat("option (MyProto.options) = {\n"470 " key: %lld\n"471 " key: 0x%04x\n"472 " key: \"%d %d\"\n"473 "};");474}475 476TEST_F(FormatTestProto, FormatsRepeatedListInitializersInOptions) {477 verifyFormat("option (MyProto.options) = {\n"478 " key: item\n"479 " keys: [\n"480 " 'ala',\n"481 " 'bala',\n"482 " 'porto',\n"483 " 'kala',\n"484 " 'too',\n"485 " 'long',\n"486 " 'long',\n"487 " 'long'\n"488 " ]\n"489 " key: [ item ]\n"490 " msg {\n"491 " key: item\n"492 " keys: [\n"493 " 'ala',\n"494 " 'bala',\n"495 " 'porto',\n"496 " 'kala',\n"497 " 'too',\n"498 " 'long',\n"499 " 'long'\n"500 " ]\n"501 " }\n"502 " key: value\n"503 "};");504}505 506TEST_F(FormatTestProto, AcceptsOperatorAsKeyInOptions) {507 verifyFormat("option (MyProto.options) = {\n"508 " bbbbbbbbb: <\n"509 " ccccccccccccccccccccccc: <\n"510 " operator: 1\n"511 " operator: 2\n"512 " operator: 3\n"513 " operator { key: value }\n"514 " >\n"515 " >\n"516 "};");517}518 519TEST_F(FormatTestProto, BreaksEntriesOfSubmessagesContainingSubmessages) {520 // The column limit allows for the keys submessage to be put on 1 line, but we521 // break it since it contains a submessage an another entry.522 verifyFormat("option (MyProto.options) = {\n"523 " key: valueeeeeeee\n"524 " keys: {\n"525 " item: 'aaaaaaaaaaaaaaaa'\n"526 " sub <>\n"527 " }\n"528 "}");529 verifyFormat("option (MyProto.options) = {\n"530 " key: valueeeeeeee\n"531 " keys: {\n"532 " item: 'aaaaaaaaaaaaaaaa'\n"533 " sub {}\n"534 " }\n"535 "}");536 verifyFormat("option (MyProto.options) = {\n"537 " key: valueeeeeeee\n"538 " keys: {\n"539 " sub {}\n"540 " sub: <>\n"541 " sub: []\n"542 " }\n"543 "}");544 verifyFormat("option (MyProto.options) = {\n"545 " key: valueeeeeeee\n"546 " keys: {\n"547 " item: 'aaaaaaaaaaa'\n"548 " sub { msg: 1 }\n"549 " }\n"550 "}");551 verifyFormat("option (MyProto.options) = {\n"552 " key: valueeeeeeee\n"553 " keys: {\n"554 " item: 'aaaaaaaaaaa'\n"555 " sub: { msg: 1 }\n"556 " }\n"557 "}");558 verifyFormat("option (MyProto.options) = {\n"559 " key: valueeeeeeee\n"560 " keys: {\n"561 " item: 'aaaaaaaaaaa'\n"562 " sub < msg: 1 >\n"563 " }\n"564 "}");565 verifyFormat("option (MyProto.options) = {\n"566 " key: valueeeeeeee\n"567 " keys: {\n"568 " item: 'aaaaaaaaaaa'\n"569 " sub: [ msg: 1 ]\n"570 " }\n"571 "}");572 verifyFormat("option (MyProto.options) = {\n"573 " key: valueeeeeeee\n"574 " keys: <\n"575 " item: 'aaaaaaaaaaa'\n"576 " sub: [ 1, 2 ]\n"577 " >\n"578 "}");579 verifyFormat("option (MyProto.options) = {\n"580 " key: valueeeeeeee\n"581 " keys: {\n"582 " sub {}\n"583 " item: 'aaaaaaaaaaaaaaaa'\n"584 " }\n"585 "}");586 verifyFormat("option (MyProto.options) = {\n"587 " key: valueeeeeeee\n"588 " keys: {\n"589 " sub: []\n"590 " item: 'aaaaaaaaaaaaaaaa'\n"591 " }\n"592 "}");593 verifyFormat("option (MyProto.options) = {\n"594 " key: valueeeeeeee\n"595 " keys: {\n"596 " sub <>\n"597 " item: 'aaaaaaaaaaaaaaaa'\n"598 " }\n"599 "}");600 verifyFormat("option (MyProto.options) = {\n"601 " key: valueeeeeeee\n"602 " keys: {\n"603 " sub { key: value }\n"604 " item: 'aaaaaaaaaaaaaaaa'\n"605 " }\n"606 "}");607 verifyFormat("option (MyProto.options) = {\n"608 " key: valueeeeeeee\n"609 " keys: {\n"610 " sub: [ 1, 2 ]\n"611 " item: 'aaaaaaaaaaaaaaaa'\n"612 " }\n"613 "}");614 verifyFormat("option (MyProto.options) = {\n"615 " key: valueeeeeeee\n"616 " keys: {\n"617 " sub < sub_2: {} >\n"618 " item: 'aaaaaaaaaaaaaaaa'\n"619 " }\n"620 "}");621 verifyFormat("option (MyProto.options) = {\n"622 " key: valueeeeeeee\n"623 " keys: {\n"624 " item: data\n"625 " sub: [ 1, 2 ]\n"626 " item: 'aaaaaaaaaaaaaaaa'\n"627 " }\n"628 "}");629 verifyFormat("option (MyProto.options) = {\n"630 " key: valueeeeeeee\n"631 " keys: {\n"632 " item: data\n"633 " sub < sub_2: {} >\n"634 " item: 'aaaaaaaaaaaaaaaa'\n"635 " }\n"636 "}");637 verifyFormat("option (MyProto.options) = {\n"638 " sub: {\n"639 " key: valueeeeeeee\n"640 " keys: {\n"641 " sub: [ 1, 2 ]\n"642 " item: 'aaaaaaaaaaaaaaaa'\n"643 " }\n"644 " }\n"645 "}");646}647 648TEST_F(FormatTestProto, PreventBreaksBetweenKeyAndSubmessages) {649 verifyFormat("option (MyProto.options) = {\n"650 " submessage: {\n"651 " key: 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'\n"652 " }\n"653 "}");654 verifyFormat("option (MyProto.options) = {\n"655 " submessage {\n"656 " key: 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'\n"657 " }\n"658 "}");659 verifyFormat("option (MyProto.options) = {\n"660 " submessage: <\n"661 " key: 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'\n"662 " >\n"663 "}");664 verifyFormat("option (MyProto.options) = {\n"665 " submessage <\n"666 " key: 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'\n"667 " >\n"668 "}");669 verifyFormat("option (MyProto.options) = {\n"670 " repeatedd: [\n"671 " 'eyaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'\n"672 " ]\n"673 "}");674}675 676} // namespace format677} // end namespace clang678