| //===- unittest/Format/FormatTestProto.cpp --------------------------------===// |
| // |
| // The LLVM Compiler Infrastructure |
| // |
| // This file is distributed under the University of Illinois Open Source |
| // License. See LICENSE.TXT for details. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "FormatTestUtils.h" |
| #include "clang/Format/Format.h" |
| #include "llvm/Support/Debug.h" |
| #include "gtest/gtest.h" |
| |
| #define DEBUG_TYPE "format-test" |
| |
| namespace clang { |
| namespace format { |
| |
| class FormatTestProto : public ::testing::Test { |
| protected: |
| static std::string format(llvm::StringRef Code, unsigned Offset, |
| unsigned Length, const FormatStyle &Style) { |
| DEBUG(llvm::errs() << "---\n"); |
| DEBUG(llvm::errs() << Code << "\n\n"); |
| std::vector<tooling::Range> Ranges(1, tooling::Range(Offset, Length)); |
| tooling::Replacements Replaces = reformat(Style, Code, Ranges); |
| auto Result = applyAllReplacements(Code, Replaces); |
| EXPECT_TRUE(static_cast<bool>(Result)); |
| DEBUG(llvm::errs() << "\n" << *Result << "\n\n"); |
| return *Result; |
| } |
| |
| static std::string format(llvm::StringRef Code) { |
| FormatStyle Style = getGoogleStyle(FormatStyle::LK_Proto); |
| Style.ColumnLimit = 60; // To make writing tests easier. |
| return format(Code, 0, Code.size(), Style); |
| } |
| |
| static void verifyFormat(llvm::StringRef Code) { |
| EXPECT_EQ(Code.str(), format(test::messUp(Code))); |
| } |
| }; |
| |
| TEST_F(FormatTestProto, FormatsMessages) { |
| verifyFormat("message SomeMessage {\n" |
| " required int32 field1 = 1;\n" |
| "}"); |
| verifyFormat("message SomeMessage {\n" |
| " required .absolute.Reference field1 = 1;\n" |
| "}"); |
| verifyFormat("message SomeMessage {\n" |
| " required int32 field1 = 1;\n" |
| " optional string field2 = 2 [default = \"2\"]\n" |
| "}"); |
| |
| verifyFormat("message SomeMessage {\n" |
| " optional really.really.long.qualified.type.aaa.aaaaaaa\n" |
| " fiiiiiiiiiiiiiiiiiiiiiiiiield = 1;\n" |
| " optional\n" |
| " really.really.long.qualified.type.aaa.aaaaaaa.aaaaaaaa\n" |
| " another_fiiiiiiiiiiiiiiiiiiiiield = 2;\n" |
| "}"); |
| } |
| |
| TEST_F(FormatTestProto, KeywordsInOtherLanguages) { |
| verifyFormat("optional string operator = 1;"); |
| } |
| |
| TEST_F(FormatTestProto, FormatsEnums) { |
| verifyFormat("enum Type {\n" |
| " UNKNOWN = 0;\n" |
| " TYPE_A = 1;\n" |
| " TYPE_B = 2;\n" |
| "};"); |
| verifyFormat("enum Type {\n" |
| " UNKNOWN = 0 [(some_options) = {a: aa, b: bb}];\n" |
| "};"); |
| verifyFormat("enum Type {\n" |
| " UNKNOWN = 0 [(some_options) = {\n" |
| " a: aa, // wrap\n" |
| " b: bb\n" |
| " }];\n" |
| "};"); |
| } |
| |
| TEST_F(FormatTestProto, UnderstandsReturns) { |
| verifyFormat("rpc Search(SearchRequest) returns (SearchResponse);"); |
| } |
| |
| TEST_F(FormatTestProto, MessageFieldAttributes) { |
| verifyFormat("optional string test = 1 [default = \"test\"];"); |
| verifyFormat("optional bool a = 1 [default = true, deprecated = true];"); |
| verifyFormat("optional LongMessageType long_proto_field = 1 [\n" |
| " default = REALLY_REALLY_LONG_CONSTANT_VALUE,\n" |
| " deprecated = true\n" |
| "];"); |
| verifyFormat("optional LongMessageType long_proto_field = 1\n" |
| " [default = REALLY_REALLY_LONG_CONSTANT_VALUE];"); |
| verifyFormat("repeated double value = 1\n" |
| " [(aaaaaaa.aaaaaaaaa) = {aaaaaaaaaaaaaaaaa: AAAAAAAA}];"); |
| verifyFormat("repeated double value = 1 [(aaaaaaa.aaaaaaaaa) = {\n" |
| " aaaaaaaaaaaaaaaa: AAAAAAAAAA,\n" |
| " bbbbbbbbbbbbbbbb: BBBBBBBBBB\n" |
| "}];"); |
| verifyFormat("repeated double value = 1 [(aaaaaaa.aaaaaaaaa) = {\n" |
| " aaaaaaaaaaaaaaaa: AAAAAAAAAA\n" |
| " bbbbbbbbbbbbbbbb: BBBBBBBBBB\n" |
| "}];"); |
| verifyFormat("repeated double value = 1 [\n" |
| " (aaaaaaa.aaaaaaaaa) = {\n" |
| " aaaaaaaaaaaaaaaa: AAAAAAAAAA\n" |
| " bbbbbbbbbbbbbbbb: BBBBBBBBBB\n" |
| " },\n" |
| " (bbbbbbb.bbbbbbbbb) = {\n" |
| " aaaaaaaaaaaaaaaa: AAAAAAAAAA\n" |
| " bbbbbbbbbbbbbbbb: BBBBBBBBBB\n" |
| " }\n" |
| "];"); |
| verifyFormat("repeated double value = 1 [(aaaaaaa.aaaaaaaaa) = {\n" |
| " type: \"AAAAAAAAAA\"\n" |
| " is: \"AAAAAAAAAA\"\n" |
| " or: \"BBBBBBBBBB\"\n" |
| "}];"); |
| verifyFormat("repeated double value = 1 [(aaaaaaa.aaaaaaaaa) = {\n" |
| " aaaaaaaaaaaaaaaa: AAAAAAAAAA,\n" |
| " bbbbbbb: BBBB,\n" |
| " bbbb: BBB\n" |
| "}];"); |
| verifyFormat("optional AAA aaa = 1 [\n" |
| " foo = {\n" |
| " key: 'a' //\n" |
| " },\n" |
| " bar = {\n" |
| " key: 'a' //\n" |
| " }\n" |
| "];"); |
| } |
| |
| TEST_F(FormatTestProto, DoesntWrapFileOptions) { |
| EXPECT_EQ( |
| "option java_package = " |
| "\"some.really.long.package.that.exceeds.the.column.limit\";", |
| format("option java_package = " |
| "\"some.really.long.package.that.exceeds.the.column.limit\";")); |
| } |
| |
| TEST_F(FormatTestProto, FormatsOptions) { |
| verifyFormat("option (MyProto.options) = {\n" |
| " field_a: OK\n" |
| " field_b: \"OK\"\n" |
| " field_c: \"OK\"\n" |
| " msg_field: {field_d: 123}\n" |
| "};"); |
| verifyFormat("option (MyProto.options) = {\n" |
| " field_a: OK\n" |
| " field_b: \"OK\"\n" |
| " field_c: \"OK\"\n" |
| " msg_field: {field_d: 123 field_e: OK}\n" |
| "};"); |
| verifyFormat("option (MyProto.options) = {\n" |
| " field_a: OK // Comment\n" |
| " field_b: \"OK\"\n" |
| " field_c: \"OK\"\n" |
| " msg_field: {field_d: 123}\n" |
| "};"); |
| verifyFormat("option (MyProto.options) = {\n" |
| " field_c: \"OK\"\n" |
| " msg_field{field_d: 123}\n" |
| "};"); |
| |
| // Support syntax with <> instead of {}. |
| verifyFormat("option (MyProto.options) = {\n" |
| " field_c: \"OK\",\n" |
| " msg_field: <field_d: 123>\n" |
| "};"); |
| } |
| |
| TEST_F(FormatTestProto, FormatsService) { |
| verifyFormat("service SearchService {\n" |
| " rpc Search(SearchRequest) returns (SearchResponse) {\n" |
| " option foo = true;\n" |
| " }\n" |
| "};"); |
| } |
| |
| TEST_F(FormatTestProto, ExtendingMessage) { |
| verifyFormat("extend .foo.Bar {\n" |
| "}"); |
| } |
| |
| TEST_F(FormatTestProto, FormatsImports) { |
| verifyFormat("import \"a.proto\";\n" |
| "import \"b.proto\";\n" |
| "// comment\n" |
| "message A {\n" |
| "}"); |
| |
| verifyFormat("import public \"a.proto\";\n" |
| "import \"b.proto\";\n" |
| "// comment\n" |
| "message A {\n" |
| "}"); |
| |
| // Missing semicolons should not confuse clang-format. |
| verifyFormat("import \"a.proto\"\n" |
| "import \"b.proto\"\n" |
| "// comment\n" |
| "message A {\n" |
| "}"); |
| } |
| |
| } // end namespace tooling |
| } // end namespace clang |