| //===- unittest/Format/FormatTestRawStrings.cpp - Formatting unit tests ---===// |
| // |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| // See https://llvm.org/LICENSE.txt for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "clang/Format/Format.h" |
| |
| #include "../Tooling/ReplacementTest.h" |
| #include "FormatTestUtils.h" |
| |
| #include "llvm/Support/Debug.h" |
| #include "llvm/Support/MemoryBuffer.h" |
| #include "gtest/gtest.h" |
| |
| #define DEBUG_TYPE "format-test" |
| |
| using clang::tooling::ReplacementTest; |
| using clang::tooling::toReplacements; |
| |
| namespace clang { |
| namespace format { |
| namespace { |
| |
| class FormatTestRawStrings : public ::testing::Test { |
| protected: |
| enum StatusCheck { SC_ExpectComplete, SC_ExpectIncomplete, SC_DoNotCheck }; |
| |
| std::string format(llvm::StringRef Code, |
| const FormatStyle &Style = getLLVMStyle(), |
| StatusCheck CheckComplete = SC_ExpectComplete) { |
| LLVM_DEBUG(llvm::errs() << "---\n"); |
| LLVM_DEBUG(llvm::errs() << Code << "\n\n"); |
| std::vector<tooling::Range> Ranges(1, tooling::Range(0, Code.size())); |
| FormattingAttemptStatus Status; |
| tooling::Replacements Replaces = |
| reformat(Style, Code, Ranges, "<stdin>", &Status); |
| if (CheckComplete != SC_DoNotCheck) { |
| bool ExpectedCompleteFormat = CheckComplete == SC_ExpectComplete; |
| EXPECT_EQ(ExpectedCompleteFormat, Status.FormatComplete) |
| << Code << "\n\n"; |
| } |
| ReplacementCount = Replaces.size(); |
| auto Result = applyAllReplacements(Code, Replaces); |
| EXPECT_TRUE(static_cast<bool>(Result)); |
| LLVM_DEBUG(llvm::errs() << "\n" << *Result << "\n\n"); |
| return *Result; |
| } |
| |
| FormatStyle getStyleWithColumns(FormatStyle Style, unsigned ColumnLimit) { |
| Style.ColumnLimit = ColumnLimit; |
| return Style; |
| } |
| |
| FormatStyle getLLVMStyleWithColumns(unsigned ColumnLimit) { |
| return getStyleWithColumns(getLLVMStyle(), ColumnLimit); |
| } |
| |
| int ReplacementCount; |
| |
| FormatStyle getRawStringPbStyleWithColumns(unsigned ColumnLimit) { |
| FormatStyle Style = getLLVMStyle(); |
| Style.ColumnLimit = ColumnLimit; |
| Style.RawStringFormats = { |
| { |
| /*Language=*/FormatStyle::LK_TextProto, |
| /*Delimiters=*/{"pb"}, |
| /*EnclosingFunctions=*/{}, |
| /*CanonicalDelimiter=*/"", |
| /*BasedOnStyle=*/"google", |
| }, |
| }; |
| return Style; |
| } |
| |
| FormatStyle getRawStringLLVMCppStyleBasedOn(std::string BasedOnStyle) { |
| FormatStyle Style = getLLVMStyle(); |
| Style.RawStringFormats = { |
| { |
| /*Language=*/FormatStyle::LK_Cpp, |
| /*Delimiters=*/{"cpp"}, |
| /*EnclosingFunctions=*/{}, |
| /*CanonicalDelimiter=*/"", |
| BasedOnStyle, |
| }, |
| }; |
| return Style; |
| } |
| |
| FormatStyle getRawStringGoogleCppStyleBasedOn(std::string BasedOnStyle) { |
| FormatStyle Style = getGoogleStyle(FormatStyle::LK_Cpp); |
| Style.RawStringFormats = { |
| { |
| /*Language=*/FormatStyle::LK_Cpp, |
| /*Delimiters=*/{"cpp"}, |
| /*EnclosingFunctions=*/{}, |
| /*CanonicalDelimiter=*/"", |
| BasedOnStyle, |
| }, |
| }; |
| return Style; |
| } |
| |
| // Gcc 4.8 doesn't support raw string literals in macros, which breaks some |
| // build bots. We use this function instead. |
| void expect_eq(const std::string Expected, const std::string Actual) { |
| EXPECT_EQ(Expected, Actual); |
| } |
| }; |
| |
| TEST_F(FormatTestRawStrings, ReformatsAccordingToBaseStyle) { |
| // llvm style puts '*' on the right. |
| // google style puts '*' on the left. |
| |
| // Use the llvm style if the raw string style has no BasedOnStyle. |
| expect_eq(R"test(int *i = R"cpp(int *p = nullptr;)cpp")test", |
| format(R"test(int * i = R"cpp(int * p = nullptr;)cpp")test", |
| getRawStringLLVMCppStyleBasedOn(""))); |
| |
| // Use the google style if the raw string style has BasedOnStyle=google. |
| expect_eq(R"test(int *i = R"cpp(int* p = nullptr;)cpp")test", |
| format(R"test(int * i = R"cpp(int * p = nullptr;)cpp")test", |
| getRawStringLLVMCppStyleBasedOn("google"))); |
| |
| // Use the llvm style if the raw string style has no BasedOnStyle=llvm. |
| expect_eq(R"test(int* i = R"cpp(int *p = nullptr;)cpp")test", |
| format(R"test(int * i = R"cpp(int * p = nullptr;)cpp")test", |
| getRawStringGoogleCppStyleBasedOn("llvm"))); |
| } |
| |
| TEST_F(FormatTestRawStrings, UsesConfigurationOverBaseStyle) { |
| // llvm style puts '*' on the right. |
| // google style puts '*' on the left. |
| |
| // Uses the configured google style inside raw strings even if BasedOnStyle in |
| // the raw string format is llvm. |
| FormatStyle Style = getGoogleStyle(FormatStyle::LK_Cpp); |
| EXPECT_EQ(0, parseConfiguration("---\n" |
| "Language: Cpp\n" |
| "BasedOnStyle: Google", |
| &Style) |
| .value()); |
| Style.RawStringFormats = {{ |
| FormatStyle::LK_Cpp, |
| {"cpp"}, |
| {}, |
| /*CanonicalDelimiter=*/"", |
| /*BasedOnStyle=*/"llvm", |
| }}; |
| expect_eq(R"test(int* i = R"cpp(int* j = 0;)cpp";)test", |
| format(R"test(int * i = R"cpp(int * j = 0;)cpp";)test", Style)); |
| } |
| |
| TEST_F(FormatTestRawStrings, MatchesDelimitersCaseSensitively) { |
| // Don't touch the 'PB' raw string, format the 'pb' raw string. |
| expect_eq(R"test( |
| s = R"PB(item:1)PB"; |
| t = R"pb(item: 1)pb";)test", |
| format(R"test( |
| s = R"PB(item:1)PB"; |
| t = R"pb(item:1)pb";)test", |
| getRawStringPbStyleWithColumns(40))); |
| } |
| |
| TEST_F(FormatTestRawStrings, RespectsClangFormatOff) { |
| expect_eq(R"test( |
| // clang-format off |
| s = R"pb(item: 1)pb"; |
| // clang-format on |
| t = R"pb(item: 1)pb";)test", |
| format(R"test( |
| // clang-format off |
| s = R"pb(item: 1)pb"; |
| // clang-format on |
| t = R"pb(item: 1)pb";)test", |
| getRawStringPbStyleWithColumns(40))); |
| } |
| |
| TEST_F(FormatTestRawStrings, ReformatsShortRawStringsOnSingleLine) { |
| expect_eq(R"test(P p = TP(R"pb()pb");)test", |
| format(R"test(P p = TP(R"pb( )pb");)test", |
| getRawStringPbStyleWithColumns(40))); |
| expect_eq(R"test(P p = TP(R"pb(item_1: 1)pb");)test", |
| format(R"test(P p = TP(R"pb(item_1:1)pb");)test", |
| getRawStringPbStyleWithColumns(40))); |
| expect_eq(R"test(P p = TP(R"pb(item_1: 1)pb");)test", |
| format(R"test(P p = TP(R"pb( item_1 : 1 )pb");)test", |
| getRawStringPbStyleWithColumns(40))); |
| expect_eq(R"test(P p = TP(R"pb(item_1: 1 item_2: 2)pb");)test", |
| format(R"test(P p = TP(R"pb(item_1:1 item_2:2)pb");)test", |
| getRawStringPbStyleWithColumns(40))); |
| // Merge two short lines into one. |
| expect_eq(R"test( |
| std::string s = R"pb( |
| item_1: 1 item_2: 2 |
| )pb"; |
| )test", |
| format(R"test( |
| std::string s = R"pb( |
| item_1:1 |
| item_2:2 |
| )pb"; |
| )test", |
| getRawStringPbStyleWithColumns(40))); |
| } |
| |
| TEST_F(FormatTestRawStrings, BreaksShortRawStringsWhenNeeded) { |
| // The raw string contains multiple submessage entries, so break for |
| // readability. |
| expect_eq(R"test( |
| P p = TP(R"pb(item_1 < 1 > |
| item_2: { 2 })pb");)test", |
| format( |
| R"test( |
| P p = TP(R"pb(item_1<1> item_2:{2})pb");)test", |
| getRawStringPbStyleWithColumns(40))); |
| } |
| |
| TEST_F(FormatTestRawStrings, BreaksRawStringsExceedingColumnLimit) { |
| expect_eq(R"test( |
| P p = TPPPPPPPPPPPPPPP( |
| R"pb(item_1: 1, item_2: 2)pb");)test", |
| format(R"test( |
| P p = TPPPPPPPPPPPPPPP(R"pb(item_1: 1, item_2: 2)pb");)test", |
| getRawStringPbStyleWithColumns(40))); |
| |
| expect_eq(R"test( |
| P p = |
| TPPPPPPPPPPPPPPP( |
| R"pb(item_1: 1, |
| item_2: 2, |
| item_3: 3)pb");)test", |
| format(R"test( |
| P p = TPPPPPPPPPPPPPPP(R"pb(item_1: 1, item_2: 2, item_3: 3)pb");)test", |
| getRawStringPbStyleWithColumns(40))); |
| |
| expect_eq(R"test( |
| P p = TP(R"pb(item_1 < 1 > |
| item_2: < 2 > |
| item_3 {})pb");)test", |
| format(R"test( |
| P p = TP(R"pb(item_1<1> item_2:<2> item_3{ })pb");)test", |
| getRawStringPbStyleWithColumns(40))); |
| |
| expect_eq( |
| R"test( |
| P p = TP(R"pb(item_1: 1, |
| item_2: 2, |
| item_3: 3, |
| item_4: 4)pb");)test", |
| format( |
| R"test( |
| P p = TP(R"pb(item_1: 1, item_2: 2, item_3: 3, item_4: 4)pb");)test", |
| getRawStringPbStyleWithColumns(40))); |
| |
| expect_eq(R"test( |
| P p = TPPPPPPPPPPPPPPP( |
| R"pb(item_1 < 1 >, |
| item_2: { 2 }, |
| item_3: < 3 >, |
| item_4: { 4 })pb");)test", |
| format(R"test( |
| P p = TPPPPPPPPPPPPPPP(R"pb(item_1<1>, item_2: {2}, item_3: <3>, item_4:{4})pb");)test", |
| getRawStringPbStyleWithColumns(40))); |
| |
| // Breaks before a short raw string exceeding the column limit. |
| expect_eq(R"test( |
| FFFFFFFFFFFFFFFFFFFFFFFFFFF( |
| R"pb(key: 1)pb"); |
| P p = TPPPPPPPPPPPPPPPPPPPP( |
| R"pb(key: 2)pb"); |
| auto TPPPPPPPPPPPPPPPPPPPP = |
| R"pb(key: 3)pb"; |
| P p = TPPPPPPPPPPPPPPPPPPPP( |
| R"pb(i: 1, j: 2)pb"); |
| |
| int f(string s) { |
| FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF( |
| R"pb(key: 1)pb"); |
| P p = TPPPPPPPPPPPPPPPPPPPP( |
| R"pb(key: 2)pb"); |
| auto TPPPPPPPPPPPPPPPPPPPP = |
| R"pb(key: 3)pb"; |
| if (s.empty()) |
| P p = TPPPPPPPPPPPPPPPPPPPP( |
| R"pb(i: 1, j: 2)pb"); |
| } |
| )test", |
| format(R"test( |
| FFFFFFFFFFFFFFFFFFFFFFFFFFF(R"pb(key:1)pb"); |
| P p = TPPPPPPPPPPPPPPPPPPPP(R"pb(key:2)pb"); |
| auto TPPPPPPPPPPPPPPPPPPPP = R"pb(key:3)pb"; |
| P p = TPPPPPPPPPPPPPPPPPPPP(R"pb(i: 1, j:2)pb"); |
| |
| int f(string s) { |
| FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF(R"pb(key:1)pb"); |
| P p = TPPPPPPPPPPPPPPPPPPPP(R"pb(key:2)pb"); |
| auto TPPPPPPPPPPPPPPPPPPPP = R"pb(key:3)pb"; |
| if (s.empty()) |
| P p = TPPPPPPPPPPPPPPPPPPPP(R"pb(i: 1, j:2)pb"); |
| } |
| )test", |
| getRawStringPbStyleWithColumns(40))); |
| } |
| |
| TEST_F(FormatTestRawStrings, FormatsRawStringArguments) { |
| expect_eq(R"test( |
| P p = TP(R"pb(key { 1 })pb", param_2);)test", |
| format(R"test( |
| P p = TP(R"pb(key{1})pb",param_2);)test", |
| getRawStringPbStyleWithColumns(40))); |
| |
| expect_eq(R"test( |
| PPPPPPPPPPPPP(R"pb(keykeyk)pb", |
| param_2);)test", |
| format(R"test( |
| PPPPPPPPPPPPP(R"pb(keykeyk)pb", param_2);)test", |
| getRawStringPbStyleWithColumns(40))); |
| |
| expect_eq(R"test( |
| P p = TP( |
| R"pb(item: { i: 1, s: 's' } |
| item: { i: 2, s: 't' })pb");)test", |
| format(R"test( |
| P p = TP(R"pb(item: {i: 1, s: 's'} item: {i: 2, s: 't'})pb");)test", |
| getRawStringPbStyleWithColumns(40))); |
| expect_eq(R"test( |
| FFFFFFFFFFFFFFFFFFF( |
| R"pb(key: "value")pb", |
| R"pb(key2: "value")pb");)test", |
| format(R"test( |
| FFFFFFFFFFFFFFFFFFF(R"pb(key: "value")pb", R"pb(key2: "value")pb");)test", |
| getRawStringPbStyleWithColumns(40))); |
| |
| // Formats the first out of two arguments. |
| expect_eq(R"test( |
| FFFFFFFF(R"pb(key: 1)pb", argument2); |
| struct S { |
| const s = |
| f(R"pb(key: 1)pb", argument2); |
| void f() { |
| if (gol) |
| return g(R"pb(key: 1)pb", |
| 132789237); |
| return g(R"pb(key: 1)pb", "172893"); |
| } |
| };)test", |
| format(R"test( |
| FFFFFFFF(R"pb(key:1)pb", argument2); |
| struct S { |
| const s = f(R"pb(key:1)pb", argument2); |
| void f() { |
| if (gol) |
| return g(R"pb(key:1)pb", 132789237); |
| return g(R"pb(key:1)pb", "172893"); |
| } |
| };)test", |
| getRawStringPbStyleWithColumns(40))); |
| |
| // Formats the second out of two arguments. |
| expect_eq(R"test( |
| FFFFFFFF(argument1, R"pb(key: 2)pb"); |
| struct S { |
| const s = |
| f(argument1, R"pb(key: 2)pb"); |
| void f() { |
| if (gol) |
| return g(12784137, |
| R"pb(key: 2)pb"); |
| return g(17283122, R"pb(key: 2)pb"); |
| } |
| };)test", |
| format(R"test( |
| FFFFFFFF(argument1, R"pb(key:2)pb"); |
| struct S { |
| const s = f(argument1, R"pb(key:2)pb"); |
| void f() { |
| if (gol) |
| return g(12784137, R"pb(key:2)pb"); |
| return g(17283122, R"pb(key:2)pb"); |
| } |
| };)test", |
| getRawStringPbStyleWithColumns(40))); |
| |
| // Formats two short raw string arguments. |
| expect_eq(R"test( |
| FFFFF(R"pb(key: 1)pb", R"pb(key: 2)pb");)test", |
| format(R"test( |
| FFFFF(R"pb(key:1)pb", R"pb(key:2)pb");)test", |
| getRawStringPbStyleWithColumns(40))); |
| // TODO(krasimir): The original source code fits on one line, so the |
| // non-optimizing formatter is chosen. But after the formatting in protos is |
| // made, the code doesn't fit on one line anymore and further formatting |
| // splits it. |
| // |
| // Should we disable raw string formatting for the non-optimizing formatter? |
| expect_eq(R"test( |
| FFFFFFF(R"pb(key: 1)pb", R"pb(key: 2)pb");)test", |
| format(R"test( |
| FFFFFFF(R"pb(key:1)pb", R"pb(key:2)pb");)test", |
| getRawStringPbStyleWithColumns(40))); |
| |
| // Formats two short raw string arguments, puts second on newline. |
| expect_eq(R"test( |
| FFFFFFFF(R"pb(key: 1)pb", |
| R"pb(key: 2)pb");)test", |
| format(R"test( |
| FFFFFFFF(R"pb(key:1)pb", R"pb(key:2)pb");)test", |
| getRawStringPbStyleWithColumns(40))); |
| |
| // Formats both arguments. |
| expect_eq(R"test( |
| FFFFFFFF(R"pb(key: 1)pb", |
| R"pb(key: 2)pb"); |
| struct S { |
| const s = f(R"pb(key: 1)pb", |
| R"pb(key: 2)pb"); |
| void f() { |
| if (gol) |
| return g(R"pb(key: 1)pb", |
| R"pb(key: 2)pb"); |
| return g(R"pb(k1)pb", R"pb(k2)pb"); |
| } |
| };)test", |
| format(R"test( |
| FFFFFFFF(R"pb(key:1)pb", R"pb(key:2)pb"); |
| struct S { |
| const s = f(R"pb(key:1)pb", R"pb(key:2)pb"); |
| void f() { |
| if (gol) |
| return g(R"pb(key:1)pb", R"pb(key:2)pb"); |
| return g(R"pb( k1 )pb", R"pb( k2 )pb"); |
| } |
| };)test", |
| getRawStringPbStyleWithColumns(40))); |
| } |
| |
| TEST_F(FormatTestRawStrings, RawStringStartingWithNewlines) { |
| expect_eq(R"test( |
| std::string s = R"pb( |
| item_1: 1 |
| )pb"; |
| )test", |
| format(R"test( |
| std::string s = R"pb( |
| item_1:1 |
| )pb"; |
| )test", |
| getRawStringPbStyleWithColumns(40))); |
| |
| expect_eq(R"test( |
| std::string s = R"pb( |
| |
| item_1: 1 |
| )pb"; |
| )test", |
| format(R"test( |
| std::string s = R"pb( |
| |
| item_1:1 |
| )pb"; |
| )test", |
| getRawStringPbStyleWithColumns(40))); |
| |
| expect_eq(R"test( |
| std::string s = R"pb( |
| item_1: 1 |
| )pb"; |
| )test", |
| format(R"test( |
| std::string s = R"pb( |
| item_1:1 |
| |
| )pb"; |
| )test", |
| getRawStringPbStyleWithColumns(40))); |
| |
| expect_eq(R"test( |
| std::string s = R"pb( |
| item_1: 1, |
| item_2: 2 |
| )pb"; |
| )test", |
| format(R"test( |
| std::string s = R"pb( |
| item_1:1, item_2:2 |
| )pb"; |
| )test", |
| getRawStringPbStyleWithColumns(40))); |
| |
| expect_eq(R"test( |
| std::string s = R"pb( |
| book { |
| title: "Alice's Adventures" |
| author: "Lewis Caroll" |
| } |
| book { |
| title: "Peter Pan" |
| author: "J. M. Barrie" |
| } |
| )pb"; |
| )test", |
| format(R"test( |
| std::string s = R"pb( |
| book { title: "Alice's Adventures" author: "Lewis Caroll" } |
| book { title: "Peter Pan" author: "J. M. Barrie" } |
| )pb"; |
| )test", |
| getRawStringPbStyleWithColumns(40))); |
| } |
| |
| TEST_F(FormatTestRawStrings, BreaksBeforeRawStrings) { |
| expect_eq(R"test( |
| ASSERT_TRUE( |
| ParseFromString(R"pb(item_1: 1)pb"), |
| ptr);)test", |
| format(R"test( |
| ASSERT_TRUE(ParseFromString(R"pb(item_1: 1)pb"), ptr);)test", |
| getRawStringPbStyleWithColumns(40))); |
| |
| expect_eq(R"test( |
| ASSERT_TRUE(toolong::ParseFromString( |
| R"pb(item_1: 1)pb"), |
| ptr);)test", |
| format(R"test( |
| ASSERT_TRUE(toolong::ParseFromString(R"pb(item_1: 1)pb"), ptr);)test", |
| getRawStringPbStyleWithColumns(40))); |
| |
| expect_eq(R"test( |
| ASSERT_TRUE(ParseFromString( |
| R"pb(item_1: 1, |
| item_2: 2)pb"), |
| ptr);)test", |
| format(R"test( |
| ASSERT_TRUE(ParseFromString(R"pb(item_1: 1, item_2: 2)pb"), ptr);)test", |
| getRawStringPbStyleWithColumns(40))); |
| |
| expect_eq(R"test( |
| ASSERT_TRUE( |
| ParseFromString( |
| R"pb(item_1: 1 item_2: 2)pb"), |
| ptr);)test", |
| format(R"test( |
| ASSERT_TRUE(ParseFromString(R"pb(item_1: 1 item_2: 2)pb"), ptr);)test", |
| getRawStringPbStyleWithColumns(40))); |
| } |
| |
| TEST_F(FormatTestRawStrings, RawStringsInOperands) { |
| // Formats the raw string first operand of a binary operator expression. |
| expect_eq(R"test(auto S = R"pb(item_1: 1)pb" + rest;)test", |
| format(R"test(auto S = R"pb(item_1:1)pb" + rest;)test", |
| getRawStringPbStyleWithColumns(40))); |
| |
| expect_eq(R"test( |
| auto S = R"pb(item_1: 1, item_2: 2)pb" + |
| rest;)test", |
| format(R"test( |
| auto S = R"pb(item_1:1,item_2:2)pb"+rest;)test", |
| getRawStringPbStyleWithColumns(40))); |
| |
| expect_eq(R"test( |
| auto S = |
| R"pb(item_1: 1 item_2: 2)pb" + rest;)test", |
| format(R"test( |
| auto S = R"pb(item_1:1 item_2:2)pb"+rest;)test", |
| getRawStringPbStyleWithColumns(40))); |
| |
| // `rest` fits on the line after )pb", but forced on newline since the raw |
| // string literal is multiline. |
| expect_eq(R"test( |
| auto S = R"pb(item_1: 1, |
| item_2: 2, |
| item_3: 3)pb" + |
| rest;)test", |
| format(R"test( |
| auto S = R"pb(item_1:1,item_2:2,item_3:3)pb"+rest;)test", |
| getRawStringPbStyleWithColumns(40))); |
| |
| expect_eq(R"test( |
| auto S = R"pb(item_1: 1, |
| item_2: 2, |
| item_3: 3)pb" + |
| longlongrest;)test", |
| format(R"test( |
| auto S = R"pb(item_1:1,item_2:2,item_3:3)pb"+longlongrest;)test", |
| getRawStringPbStyleWithColumns(40))); |
| |
| // Formats the raw string second operand of a binary operator expression. |
| expect_eq(R"test(auto S = first + R"pb(item_1: 1)pb";)test", |
| format(R"test(auto S = first + R"pb(item_1:1)pb";)test", |
| getRawStringPbStyleWithColumns(40))); |
| |
| expect_eq(R"test( |
| auto S = first + R"pb(item_1: 1, |
| item_2: 2)pb";)test", |
| format(R"test( |
| auto S = first+R"pb(item_1:1,item_2:2)pb";)test", |
| getRawStringPbStyleWithColumns(40))); |
| |
| expect_eq(R"test( |
| auto S = first + R"pb(item_1: 1 |
| item_2: 2)pb";)test", |
| format(R"test( |
| auto S = first+R"pb(item_1:1 item_2:2)pb";)test", |
| getRawStringPbStyleWithColumns(40))); |
| |
| expect_eq(R"test( |
| auto S = R"pb(item_1: 1, |
| item_2: 2, |
| item_3: 3)pb" + |
| rest;)test", |
| format(R"test( |
| auto S = R"pb(item_1:1,item_2:2,item_3:3)pb"+rest;)test", |
| getRawStringPbStyleWithColumns(40))); |
| |
| expect_eq(R"test( |
| auto S = R"pb(item_1: 1, |
| item_2: 2, |
| item_3: 3)pb" + |
| longlongrest;)test", |
| format(R"test( |
| auto S = R"pb(item_1:1,item_2:2,item_3:3)pb"+longlongrest;)test", |
| getRawStringPbStyleWithColumns(40))); |
| |
| // Formats the raw string operands in expressions. |
| expect_eq(R"test( |
| auto S = R"pb(item_1: 1)pb" + |
| R"pb(item_2: 2)pb"; |
| )test", |
| format(R"test( |
| auto S=R"pb(item_1:1)pb"+R"pb(item_2:2)pb"; |
| )test", |
| getRawStringPbStyleWithColumns(40))); |
| |
| expect_eq(R"test( |
| auto S = R"pb(item_1: 1)pb" + |
| R"pb(item_2: 2)pb" + |
| R"pb(item_3: 3)pb"; |
| )test", |
| format(R"test( |
| auto S=R"pb(item_1:1)pb"+R"pb(item_2:2)pb"+R"pb(item_3:3)pb"; |
| )test", |
| getRawStringPbStyleWithColumns(40))); |
| |
| expect_eq(R"test( |
| auto S = (count < 3) |
| ? R"pb(item_1: 1)pb" |
| : R"pb(item_2: 2)pb"; |
| )test", |
| format(R"test( |
| auto S=(count<3)?R"pb(item_1:1)pb":R"pb(item_2:2)pb"; |
| )test", |
| getRawStringPbStyleWithColumns(40))); |
| |
| expect_eq(R"test( |
| auto S = |
| (count < 3) |
| ? R"pb(item_1: 1, item_2: 2)pb" |
| : R"pb(item_3: 3)pb"; |
| )test", |
| format(R"test( |
| auto S=(count<3)?R"pb(item_1:1,item_2:2)pb":R"pb(item_3:3)pb"; |
| )test", |
| getRawStringPbStyleWithColumns(40))); |
| |
| expect_eq(R"test( |
| auto S = |
| (count < 3) |
| ? R"pb(item_1: 1)pb" |
| : R"pb(item_2: 2, item_3: 3)pb"; |
| )test", |
| format(R"test( |
| auto S=(count<3)?R"pb(item_1:1)pb":R"pb(item_2:2,item_3:3)pb"; |
| )test", |
| getRawStringPbStyleWithColumns(40))); |
| } |
| |
| TEST_F(FormatTestRawStrings, PrefixAndSuffixAlignment) { |
| // Keep the suffix at the end of line if not on newline. |
| expect_eq(R"test( |
| int s() { |
| auto S = PTP( |
| R"pb( |
| item_1: 1, |
| item_2: 2)pb"); |
| })test", |
| format(R"test( |
| int s() { |
| auto S = PTP( |
| R"pb( |
| item_1: 1, |
| item_2: 2)pb"); |
| })test", |
| getRawStringPbStyleWithColumns(20))); |
| |
| // Align the suffix with the surrounding indent if the prefix is not on |
| // a line of its own. |
| expect_eq(R"test( |
| int s() { |
| auto S = PTP(R"pb( |
| item_1: 1, |
| item_2: 2 |
| )pb"); |
| })test", |
| format(R"test( |
| int s() { |
| auto S = PTP(R"pb( |
| item_1: 1, |
| item_2: 2 |
| )pb"); |
| })test", |
| getRawStringPbStyleWithColumns(20))); |
| |
| // Align the prefix with the suffix if both the prefix and suffix are on a |
| // line of their own. |
| expect_eq(R"test( |
| int s() { |
| auto S = PTP( |
| R"pb( |
| item_1: 1, |
| item_2: 2, |
| )pb"); |
| })test", |
| format(R"test( |
| int s() { |
| auto S = PTP( |
| R"pb( |
| item_1: 1, |
| item_2: 2, |
| )pb"); |
| })test", |
| getRawStringPbStyleWithColumns(20))); |
| } |
| |
| TEST_F(FormatTestRawStrings, EstimatesPenalty) { |
| // The penalty for characters exceeding the column limit in the raw string |
| // forces 'hh' to be put on a newline. |
| expect_eq(R"test( |
| ff(gggggg, |
| hh(R"pb(key { |
| i1: k1 |
| i2: k2 |
| })pb")); |
| )test", |
| format(R"test( |
| ff(gggggg, hh(R"pb(key { |
| i1: k1 |
| i2: k2 |
| })pb")); |
| )test", |
| getRawStringPbStyleWithColumns(20))); |
| } |
| |
| TEST_F(FormatTestRawStrings, DontFormatNonRawStrings) { |
| expect_eq(R"test(a = R"pb(key:value)";)test", |
| format(R"test(a = R"pb(key:value)";)test", |
| getRawStringPbStyleWithColumns(20))); |
| } |
| |
| TEST_F(FormatTestRawStrings, FormatsRawStringsWithEnclosingFunctionName) { |
| FormatStyle Style = getRawStringPbStyleWithColumns(40); |
| Style.RawStringFormats[0].EnclosingFunctions.push_back("PARSE_TEXT_PROTO"); |
| Style.RawStringFormats[0].EnclosingFunctions.push_back("ParseTextProto"); |
| expect_eq(R"test(a = PARSE_TEXT_PROTO(R"(key: value)");)test", |
| format(R"test(a = PARSE_TEXT_PROTO(R"(key:value)");)test", Style)); |
| |
| expect_eq(R"test( |
| a = PARSE_TEXT_PROTO /**/ ( |
| /**/ R"(key: value)");)test", |
| format(R"test( |
| a = PARSE_TEXT_PROTO/**/(/**/R"(key:value)");)test", |
| Style)); |
| |
| expect_eq(R"test( |
| a = ParseTextProto<ProtoType>( |
| R"(key: value)");)test", |
| format(R"test( |
| a = ParseTextProto<ProtoType>(R"(key:value)");)test", |
| Style)); |
| } |
| |
| TEST_F(FormatTestRawStrings, UpdatesToCanonicalDelimiters) { |
| FormatStyle Style = getRawStringPbStyleWithColumns(35); |
| Style.RawStringFormats[0].CanonicalDelimiter = "proto"; |
| Style.RawStringFormats[0].EnclosingFunctions.push_back("PARSE_TEXT_PROTO"); |
| |
| expect_eq(R"test(a = R"proto(key: value)proto";)test", |
| format(R"test(a = R"pb(key:value)pb";)test", Style)); |
| |
| expect_eq(R"test(PARSE_TEXT_PROTO(R"proto(key: value)proto");)test", |
| format(R"test(PARSE_TEXT_PROTO(R"(key:value)");)test", Style)); |
| |
| // Don't update to canonical delimiter if it occurs as a raw string suffix in |
| // the raw string content. |
| expect_eq(R"test(a = R"pb(key: ")proto")pb";)test", |
| format(R"test(a = R"pb(key:")proto")pb";)test", Style)); |
| } |
| |
| TEST_F(FormatTestRawStrings, PenalizesPrefixExcessChars) { |
| FormatStyle Style = getRawStringPbStyleWithColumns(60); |
| |
| // The '(' in R"pb is at column 60, no break. |
| expect_eq(R"test( |
| xxxxxxxaaaaax wwwwwww = _Verxrrrrrrrr(PARSE_TEXT_PROTO(R"pb( |
| Category: aaaaaaaaaaaaaaaaaaaaaaaaaa |
| )pb")); |
| )test", |
| format(R"test( |
| xxxxxxxaaaaax wwwwwww = _Verxrrrrrrrr(PARSE_TEXT_PROTO(R"pb( |
| Category: aaaaaaaaaaaaaaaaaaaaaaaaaa |
| )pb")); |
| )test", |
| Style)); |
| // The '(' in R"pb is at column 61, break. |
| expect_eq(R"test( |
| xxxxxxxaaaaax wwwwwww = |
| _Verxrrrrrrrrr(PARSE_TEXT_PROTO(R"pb( |
| Category: aaaaaaaaaaaaaaaaaaaaaaaaaa |
| )pb")); |
| )test", |
| format(R"test( |
| xxxxxxxaaaaax wwwwwww = _Verxrrrrrrrrr(PARSE_TEXT_PROTO(R"pb( |
| Category: aaaaaaaaaaaaaaaaaaaaaaaaaa |
| )pb")); |
| )test", |
| Style)); |
| } |
| |
| TEST_F(FormatTestRawStrings, KeepsRBraceFolloedByMoreLBracesOnSameLine) { |
| FormatStyle Style = getRawStringPbStyleWithColumns(80); |
| |
| expect_eq( |
| R"test( |
| int f() { |
| if (1) { |
| TTTTTTTTTTTTTTTTTTTTT s = PARSE_TEXT_PROTO(R"pb( |
| ttttttttt { |
| ppppppppppppp { |
| [cccccccccc.pppppppppppppp.TTTTTTTTTTTTTTTTTTTT] { field_1: "123_1" } |
| [cccccccccc.pppppppppppppp.TTTTTTTTTTTTTTTTTTTT] { field_2: "123_2" } |
| } |
| } |
| )pb"); |
| } |
| } |
| )test", |
| format( |
| R"test( |
| int f() { |
| if (1) { |
| TTTTTTTTTTTTTTTTTTTTT s = PARSE_TEXT_PROTO(R"pb( |
| ttttttttt { |
| ppppppppppppp { |
| [cccccccccc.pppppppppppppp.TTTTTTTTTTTTTTTTTTTT] { field_1: "123_1" } |
| [cccccccccc.pppppppppppppp.TTTTTTTTTTTTTTTTTTTT] { field_2: "123_2" }}} |
| )pb"); |
| } |
| } |
| )test", |
| Style)); |
| } |
| |
| TEST_F(FormatTestRawStrings, |
| DoNotFormatUnrecognizedDelimitersInRecognizedFunctions) { |
| FormatStyle Style = getRawStringPbStyleWithColumns(60); |
| Style.RawStringFormats[0].EnclosingFunctions.push_back("EqualsProto"); |
| // EqualsProto is a recognized function, but the Raw delimiter is |
| // unrecognized. Do not touch the string in this case, since it might be |
| // special. |
| expect_eq(R"test( |
| void f() { |
| aaaaaaaaa(bbbbbbbbb, EqualsProto(R"Raw( |
| item { |
| key: value |
| } |
| )Raw")); |
| })test", |
| format(R"test( |
| void f() { |
| aaaaaaaaa(bbbbbbbbb, EqualsProto(R"Raw( |
| item { |
| key: value |
| } |
| )Raw")); |
| })test", |
| Style)); |
| } |
| |
| TEST_F(FormatTestRawStrings, |
| BreaksBeforeNextParamAfterMultilineRawStringParam) { |
| FormatStyle Style = getRawStringPbStyleWithColumns(60); |
| expect_eq(R"test( |
| int f() { |
| int a = g(x, R"pb( |
| key: 1 # |
| key: 2 |
| )pb", |
| 3, 4); |
| } |
| )test", |
| format(R"test( |
| int f() { |
| int a = g(x, R"pb( |
| key: 1 # |
| key: 2 |
| )pb", 3, 4); |
| } |
| )test", |
| Style)); |
| |
| // Breaks after a parent of a multiline param. |
| expect_eq(R"test( |
| int f() { |
| int a = g(x, h(R"pb( |
| key: 1 # |
| key: 2 |
| )pb"), |
| 3, 4); |
| } |
| )test", |
| format(R"test( |
| int f() { |
| int a = g(x, h(R"pb( |
| key: 1 # |
| key: 2 |
| )pb"), 3, 4); |
| } |
| )test", |
| Style)); |
| |
| expect_eq(R"test( |
| int f() { |
| int a = g(x, |
| h(R"pb( |
| key: 1 # |
| key: 2 |
| )pb", |
| 2), |
| 3, 4); |
| } |
| )test", |
| format(R"test( |
| int f() { |
| int a = g(x, h(R"pb( |
| key: 1 # |
| key: 2 |
| )pb", 2), 3, 4); |
| } |
| )test", |
| Style)); |
| // Breaks if formatting introduces a multiline raw string. |
| expect_eq(R"test( |
| int f() { |
| int a = g(x, R"pb(key1: value111111111 |
| key2: value2222222222)pb", |
| 3, 4); |
| } |
| )test", |
| format(R"test( |
| int f() { |
| int a = g(x, R"pb(key1: value111111111 key2: value2222222222)pb", 3, 4); |
| } |
| )test", |
| Style)); |
| // Does not force a break after an original multiline param that is |
| // reformatterd as on single line. |
| expect_eq(R"test( |
| int f() { |
| int a = g(R"pb(key: 1)pb", 2); |
| })test", |
| format(R"test( |
| int f() { |
| int a = g(R"pb(key: |
| 1)pb", 2); |
| })test", |
| Style)); |
| } |
| |
| TEST_F(FormatTestRawStrings, IndentsLastParamAfterNewline) { |
| FormatStyle Style = getRawStringPbStyleWithColumns(60); |
| expect_eq(R"test( |
| fffffffffffffffffffff("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", |
| R"pb( |
| b: c |
| )pb");)test", |
| format(R"test( |
| fffffffffffffffffffff("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", |
| R"pb( |
| b: c |
| )pb");)test", |
| Style)); |
| } |
| } // end namespace |
| } // end namespace format |
| } // end namespace clang |