| // Copyright 2017-2021 The Verible Authors. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| // |
| #include "common/formatting/layout_optimizer.h" |
| |
| #include <sstream> |
| #include <string> |
| #include <vector> |
| |
| #include "absl/strings/match.h" |
| #include "absl/strings/str_cat.h" |
| #include "absl/strings/str_split.h" |
| #include "absl/strings/string_view.h" |
| #include "common/formatting/basic_format_style.h" |
| #include "common/formatting/layout_optimizer_internal.h" |
| #include "common/formatting/token_partition_tree.h" |
| #include "common/formatting/token_partition_tree_test_utils.h" |
| #include "common/formatting/unwrapped_line.h" |
| #include "common/formatting/unwrapped_line_test_utils.h" |
| #include "common/strings/split.h" |
| #include "common/util/spacer.h" |
| #include "gtest/gtest.h" |
| |
| namespace verible { |
| |
| namespace { |
| |
| template <typename T> |
| std::string ToString(const T& value) { |
| std::ostringstream s; |
| s << value; |
| return s.str(); |
| } |
| |
| std::ostream& PrintIndented(std::ostream& stream, absl::string_view str, |
| int indentation) { |
| for (const auto& line : verible::SplitLinesKeepLineTerminator(str)) |
| stream << verible::Spacer(indentation) << line; |
| return stream; |
| } |
| |
| template <typename Value> |
| void PrintInvalidValueMessage(std::ostream& stream, |
| absl::string_view value_name, const Value& actual, |
| const Value& expected, int indentation = 0, |
| bool multiline = false) { |
| using ::testing::PrintToString; |
| using verible::Spacer; |
| |
| stream << Spacer(indentation) << "invalid " << value_name << ":\n"; |
| if (multiline) { |
| stream << Spacer(indentation) << " actual:\n"; |
| PrintIndented(stream, PrintToString(actual), indentation + 4) << "\n"; |
| stream << Spacer(indentation) << " expected:\n"; |
| PrintIndented(stream, PrintToString(expected), indentation + 4) << "\n"; |
| } else { |
| stream << Spacer(indentation) << " actual: " << actual << "\n" |
| << Spacer(indentation) << " expected: " << expected << "\n\n"; |
| } |
| } |
| |
| void ExpectLayoutFunctionsEqual(const LayoutFunction& actual, |
| const LayoutFunction& expected, int line_no) { |
| using ::testing::PrintToString; |
| std::ostringstream msg; |
| if (actual.size() != expected.size()) { |
| PrintInvalidValueMessage(msg, "size()", actual.size(), expected.size()); |
| } |
| |
| for (int i = 0; i < std::min(actual.size(), expected.size()); ++i) { |
| std::ostringstream segment_msg; |
| |
| if (actual[i].column != expected[i].column) { |
| PrintInvalidValueMessage(segment_msg, "column", actual[i].column, |
| expected[i].column, 2); |
| } |
| if (actual[i].intercept != expected[i].intercept) { |
| PrintInvalidValueMessage(segment_msg, "intercept", actual[i].intercept, |
| expected[i].intercept, 2); |
| } |
| if (actual[i].gradient != expected[i].gradient) { |
| PrintInvalidValueMessage(segment_msg, "gradient", actual[i].gradient, |
| expected[i].gradient, 2); |
| } |
| if (actual[i].span != expected[i].span) { |
| PrintInvalidValueMessage(segment_msg, "span", actual[i].span, |
| expected[i].span, 2); |
| } |
| auto layout_diff = DeepEqual(actual[i].layout, expected[i].layout); |
| if (layout_diff.left != nullptr) { |
| PrintInvalidValueMessage(segment_msg, "layout (fragment)", |
| *layout_diff.left, *layout_diff.right, 2, true); |
| } |
| |
| if (auto str = segment_msg.str(); !str.empty()) |
| msg << "segment[" << i << "]:\n" << str << "\n"; |
| } |
| |
| if (const auto str = msg.str(); !str.empty()) { |
| ADD_FAILURE_AT(__FILE__, line_no) << "LayoutFunctions differ.\nActual:\n" |
| << actual << "\nExpected:\n" |
| << expected << "\n\nDetails:\n\n" |
| << str; |
| } else { |
| SUCCEED(); |
| } |
| } |
| |
| BasicFormatStyle CreateStyle() { |
| BasicFormatStyle style; |
| // Hardcode everything to prevent failures when defaults change. |
| style.indentation_spaces = 2; |
| style.wrap_spaces = 4; |
| style.column_limit = 40; |
| style.over_column_limit_penalty = 100; |
| style.line_break_penalty = 2; |
| return style; |
| } |
| |
| TEST(LayoutTypeTest, ToString) { |
| EXPECT_EQ(ToString(LayoutType::kLine), "line"); |
| EXPECT_EQ(ToString(LayoutType::kJuxtaposition), "juxtaposition"); |
| EXPECT_EQ(ToString(LayoutType::kStack), "stack"); |
| EXPECT_EQ(ToString(static_cast<LayoutType>(-1)), "???"); |
| } |
| |
| bool TokenRangeEqual(const UnwrappedLine& left, const UnwrappedLine& right) { |
| return left.TokensRange() == right.TokensRange(); |
| } |
| |
| class LayoutTest : public ::testing::Test, public UnwrappedLineMemoryHandler { |
| public: |
| LayoutTest() |
| : sample_( |
| "short_line\n" |
| "loooooong_line"), |
| tokens_(absl::StrSplit(sample_, '\n')) { |
| for (const auto token : tokens_) { |
| ftokens_.emplace_back(TokenInfo{1, token}); |
| } |
| CreateTokenInfos(ftokens_); |
| } |
| |
| protected: |
| const std::string sample_; |
| const std::vector<absl::string_view> tokens_; |
| std::vector<TokenInfo> ftokens_; |
| }; |
| |
| TEST_F(LayoutTest, LineLayoutItemToString) { |
| const auto begin = pre_format_tokens_.begin(); |
| |
| UnwrappedLine short_line(0, begin); |
| short_line.SpanUpToToken(begin + 1); |
| UnwrappedLine long_line(0, begin + 1); |
| long_line.SpanUpToToken(begin + 2); |
| UnwrappedLine empty_line(0, begin); |
| |
| pre_format_tokens_[0].before.spaces_required = 1; |
| pre_format_tokens_[1].before.break_decision = SpacingOptions::MustWrap; |
| |
| { |
| LayoutItem item(short_line, 0); |
| EXPECT_EQ(ToString(item), |
| "[ short_line ], length: 10, indentation: 0, spacing: 1, must " |
| "wrap: no"); |
| } |
| { |
| LayoutItem item(short_line, 3); |
| EXPECT_EQ(ToString(item), |
| "[ short_line ], length: 10, indentation: 3, spacing: 1, must " |
| "wrap: no"); |
| } |
| { |
| LayoutItem item(long_line, 5); |
| EXPECT_EQ( |
| ToString(item), |
| "[ loooooong_line ], length: 14, indentation: 5, spacing: 0, must " |
| "wrap: YES"); |
| } |
| { |
| LayoutItem item(long_line, 7); |
| EXPECT_EQ( |
| ToString(item), |
| "[ loooooong_line ], length: 14, indentation: 7, spacing: 0, must " |
| "wrap: YES"); |
| } |
| { |
| LayoutItem item(empty_line, 11); |
| EXPECT_EQ(ToString(item), |
| "[ ], length: 0, indentation: 11, spacing: 0, must wrap: no"); |
| } |
| { |
| LayoutItem item(empty_line, 13); |
| EXPECT_EQ(ToString(item), |
| "[ ], length: 0, indentation: 13, spacing: 0, must wrap: no"); |
| } |
| } |
| |
| TEST_F(LayoutTest, JuxtapositionLayoutItemToString) { |
| { |
| LayoutItem item(LayoutType::kJuxtaposition, 3, false, 5); |
| EXPECT_EQ(ToString(item), |
| "[<juxtaposition>], indentation: 5, spacing: 3, must wrap: no"); |
| } |
| { |
| LayoutItem item(LayoutType::kJuxtaposition, 7, true, 11); |
| EXPECT_EQ(ToString(item), |
| "[<juxtaposition>], indentation: 11, spacing: 7, must wrap: YES"); |
| } |
| } |
| |
| TEST_F(LayoutTest, StackLayoutItemToString) { |
| { |
| LayoutItem item(LayoutType::kStack, 3, false, 5); |
| EXPECT_EQ(ToString(item), |
| "[<stack>], indentation: 5, spacing: 3, must wrap: no"); |
| } |
| { |
| LayoutItem item(LayoutType::kStack, 7, true, 11); |
| EXPECT_EQ(ToString(item), |
| "[<stack>], indentation: 11, spacing: 7, must wrap: YES"); |
| } |
| } |
| |
| TEST_F(LayoutTest, TokensRange) { |
| const auto begin = pre_format_tokens_.begin(); |
| |
| UnwrappedLine short_line(0, begin); |
| short_line.SpanUpToToken(begin + 1); |
| |
| LayoutItem layout_short(short_line); |
| |
| const auto tokens = layout_short.TokensRange(); |
| EXPECT_EQ(tokens.begin(), short_line.TokensRange().begin()); |
| EXPECT_EQ(tokens.end(), short_line.TokensRange().end()); |
| } |
| |
| TEST_F(LayoutTest, LineLayout) { |
| const auto begin = pre_format_tokens_.begin(); |
| |
| { |
| UnwrappedLine short_line(0, begin); |
| short_line.SpanUpToToken(begin + 1); |
| |
| LayoutItem layout(short_line); |
| EXPECT_EQ(layout.Type(), LayoutType::kLine); |
| EXPECT_EQ(layout.IndentationSpaces(), 0); |
| EXPECT_EQ(layout.SpacesBefore(), 0); |
| EXPECT_EQ(layout.MustWrap(), false); |
| EXPECT_EQ(layout.Length(), 10); |
| EXPECT_EQ(layout.Text(), "short_line"); |
| EXPECT_EQ(layout.TokensRange().begin(), begin); |
| EXPECT_EQ(layout.TokensRange().end(), begin + 1); |
| } |
| { |
| UnwrappedLine empty_line(0, begin); |
| |
| LayoutItem layout(empty_line); |
| EXPECT_EQ(layout.Type(), LayoutType::kLine); |
| EXPECT_EQ(layout.IndentationSpaces(), 0); |
| EXPECT_EQ(layout.SpacesBefore(), 0); |
| EXPECT_EQ(layout.MustWrap(), false); |
| EXPECT_EQ(layout.Length(), 0); |
| EXPECT_EQ(layout.Text(), ""); |
| EXPECT_EQ(layout.TokensRange().begin(), begin); |
| EXPECT_EQ(layout.TokensRange().end(), begin); |
| } |
| } |
| |
| TEST_F(LayoutTest, TestHorizontalAndVerticalLayouts) { |
| const auto spaces_before = 3; |
| |
| LayoutItem horizontal_layout(LayoutType::kJuxtaposition, spaces_before, |
| false); |
| EXPECT_EQ(horizontal_layout.Type(), LayoutType::kJuxtaposition); |
| EXPECT_EQ(horizontal_layout.SpacesBefore(), spaces_before); |
| EXPECT_EQ(horizontal_layout.MustWrap(), false); |
| |
| LayoutItem vertical_layout(LayoutType::kStack, spaces_before, true); |
| EXPECT_EQ(vertical_layout.Type(), LayoutType::kStack); |
| EXPECT_EQ(vertical_layout.SpacesBefore(), spaces_before); |
| EXPECT_EQ(vertical_layout.MustWrap(), true); |
| } |
| |
| class LayoutFunctionTest : public ::testing::Test { |
| public: |
| LayoutFunctionTest() |
| : layout_function_(LayoutFunction{{0, layout_, 10, 101.0F, 11}, |
| {1, layout_, 20, 202.0F, 22}, |
| {2, layout_, 30, 303.0F, 33}, |
| {3, layout_, 40, 404.0F, 44}, |
| {40, layout_, 50, 505.0F, 55}, |
| {50, layout_, 60, 606.0F, 66}}), |
| const_layout_function_(layout_function_) {} |
| |
| protected: |
| static const LayoutTree layout_; |
| LayoutFunction layout_function_; |
| const LayoutFunction const_layout_function_; |
| }; |
| const LayoutTree LayoutFunctionTest::layout_ = |
| LayoutTree(LayoutItem(LayoutType::kLine, 0, false)); |
| |
| TEST_F(LayoutFunctionTest, LayoutFunctionSegmentToString) { |
| EXPECT_EQ( |
| ToString(layout_function_[0]), |
| "[ 0] (101.000 + 11*x), span: 10, layout:\n" |
| " { ([ ], length: 0, indentation: 0, spacing: 0, must wrap: no) }"); |
| EXPECT_EQ( |
| ToString(layout_function_[5]), |
| "[ 50] (606.000 + 66*x), span: 60, layout:\n" |
| " { ([ ], length: 0, indentation: 0, spacing: 0, must wrap: no) }"); |
| } |
| |
| TEST_F(LayoutFunctionTest, LayoutFunctionToString) { |
| EXPECT_EQ(ToString(layout_function_), |
| "{\n" |
| " [ 0] ( 101.000 + 11*x), span: 10, layout:\n" |
| " { ([ ], length: 0, indentation: 0, spacing: 0, must " |
| "wrap: no) }\n" |
| " [ 1] ( 202.000 + 22*x), span: 20, layout:\n" |
| " { ([ ], length: 0, indentation: 0, spacing: 0, must " |
| "wrap: no) }\n" |
| " [ 2] ( 303.000 + 33*x), span: 30, layout:\n" |
| " { ([ ], length: 0, indentation: 0, spacing: 0, must " |
| "wrap: no) }\n" |
| " [ 3] ( 404.000 + 44*x), span: 40, layout:\n" |
| " { ([ ], length: 0, indentation: 0, spacing: 0, must " |
| "wrap: no) }\n" |
| " [ 40] ( 505.000 + 55*x), span: 50, layout:\n" |
| " { ([ ], length: 0, indentation: 0, spacing: 0, must " |
| "wrap: no) }\n" |
| " [ 50] ( 606.000 + 66*x), span: 60, layout:\n" |
| " { ([ ], length: 0, indentation: 0, spacing: 0, must " |
| "wrap: no) }\n" |
| "}"); |
| EXPECT_EQ(ToString(LayoutFunction{}), "{}"); |
| } |
| |
| TEST_F(LayoutFunctionTest, Size) { |
| EXPECT_EQ(layout_function_.size(), 6); |
| EXPECT_FALSE(layout_function_.empty()); |
| |
| EXPECT_EQ(const_layout_function_.size(), 6); |
| EXPECT_FALSE(const_layout_function_.empty()); |
| |
| LayoutFunction empty_layout_function{}; |
| EXPECT_EQ(empty_layout_function.size(), 0); |
| EXPECT_TRUE(empty_layout_function.empty()); |
| } |
| |
| TEST_F(LayoutFunctionTest, Iteration) { |
| static const auto columns = {0, 1, 2, 3, 40, 50}; |
| |
| { |
| auto it = layout_function_.begin(); |
| EXPECT_NE(it, layout_function_.end()); |
| EXPECT_EQ(it + 6, layout_function_.end()); |
| EXPECT_EQ(it->column, 0); |
| |
| auto column_it = columns.begin(); |
| for (auto& segment : layout_function_) { |
| EXPECT_EQ(segment.column, *column_it); |
| EXPECT_NE(column_it, columns.end()); |
| ++column_it; |
| } |
| EXPECT_EQ(column_it, columns.end()); |
| } |
| { |
| auto it = const_layout_function_.begin(); |
| EXPECT_NE(it, const_layout_function_.end()); |
| EXPECT_EQ(it + 6, const_layout_function_.end()); |
| EXPECT_EQ(it->column, 0); |
| |
| auto column_it = columns.begin(); |
| for (auto& segment : const_layout_function_) { |
| EXPECT_EQ(segment.column, *column_it); |
| EXPECT_NE(column_it, columns.end()); |
| ++column_it; |
| } |
| EXPECT_EQ(column_it, columns.end()); |
| } |
| { |
| LayoutFunction empty_layout_function{}; |
| |
| auto it = empty_layout_function.begin(); |
| EXPECT_EQ(it, empty_layout_function.end()); |
| for (auto& segment [[maybe_unused]] : empty_layout_function) { |
| EXPECT_FALSE(true); |
| } |
| } |
| } |
| |
| TEST_F(LayoutFunctionTest, AtOrToTheLeftOf) { |
| { |
| EXPECT_EQ(layout_function_.AtOrToTheLeftOf(0), layout_function_.begin()); |
| EXPECT_EQ(layout_function_.AtOrToTheLeftOf(1), |
| layout_function_.begin() + 1); |
| EXPECT_EQ(layout_function_.AtOrToTheLeftOf(2), |
| layout_function_.begin() + 2); |
| for (int i = 3; i < 40; ++i) { |
| EXPECT_EQ(layout_function_.AtOrToTheLeftOf(i), |
| layout_function_.begin() + 3) |
| << "i: " << i; |
| } |
| for (int i = 40; i < 50; ++i) { |
| EXPECT_EQ(layout_function_.AtOrToTheLeftOf(i), |
| layout_function_.begin() + 4) |
| << "i: " << i; |
| } |
| for (int i = 50; i < 70; ++i) { |
| EXPECT_EQ(layout_function_.AtOrToTheLeftOf(i), |
| layout_function_.begin() + 5) |
| << "i: " << i; |
| } |
| EXPECT_EQ(layout_function_.AtOrToTheLeftOf(std::numeric_limits<int>::max()), |
| layout_function_.begin() + 5); |
| } |
| { |
| LayoutFunction empty_layout_function{}; |
| EXPECT_EQ(empty_layout_function.AtOrToTheLeftOf(0), |
| empty_layout_function.end()); |
| EXPECT_EQ(empty_layout_function.AtOrToTheLeftOf(1), |
| empty_layout_function.end()); |
| EXPECT_EQ( |
| empty_layout_function.AtOrToTheLeftOf(std::numeric_limits<int>::max()), |
| empty_layout_function.end()); |
| } |
| { |
| EXPECT_EQ(const_layout_function_.AtOrToTheLeftOf(0), |
| const_layout_function_.begin()); |
| EXPECT_EQ(const_layout_function_.AtOrToTheLeftOf(1), |
| const_layout_function_.begin() + 1); |
| EXPECT_EQ(const_layout_function_.AtOrToTheLeftOf(2), |
| const_layout_function_.begin() + 2); |
| for (int i = 3; i < 40; ++i) { |
| EXPECT_EQ(const_layout_function_.AtOrToTheLeftOf(i), |
| const_layout_function_.begin() + 3) |
| << "i: " << i; |
| } |
| for (int i = 40; i < 50; ++i) { |
| EXPECT_EQ(const_layout_function_.AtOrToTheLeftOf(i), |
| const_layout_function_.begin() + 4) |
| << "i: " << i; |
| } |
| for (int i = 50; i < 70; ++i) { |
| EXPECT_EQ(const_layout_function_.AtOrToTheLeftOf(i), |
| const_layout_function_.begin() + 5) |
| << "i: " << i; |
| } |
| EXPECT_EQ( |
| const_layout_function_.AtOrToTheLeftOf(std::numeric_limits<int>::max()), |
| const_layout_function_.begin() + 5); |
| } |
| { |
| const LayoutFunction empty_layout_function{}; |
| EXPECT_EQ(empty_layout_function.AtOrToTheLeftOf(0), |
| empty_layout_function.end()); |
| EXPECT_EQ(empty_layout_function.AtOrToTheLeftOf(1), |
| empty_layout_function.end()); |
| EXPECT_EQ( |
| empty_layout_function.AtOrToTheLeftOf(std::numeric_limits<int>::max()), |
| empty_layout_function.end()); |
| } |
| } |
| |
| TEST_F(LayoutFunctionTest, Insertion) { |
| layout_function_.push_back({60, layout_, 1, 6.0F, 6}); |
| ASSERT_EQ(layout_function_.size(), 7); |
| EXPECT_EQ(layout_function_[6].column, 60); |
| |
| layout_function_.push_back({70, layout_, 1, 6.0F, 6}); |
| ASSERT_EQ(layout_function_.size(), 8); |
| EXPECT_EQ(layout_function_[6].column, 60); |
| EXPECT_EQ(layout_function_[7].column, 70); |
| |
| for (int i = 0; i < 6; ++i) { |
| EXPECT_EQ(layout_function_[i].column, const_layout_function_[i].column) |
| << "i: " << i; |
| } |
| } |
| |
| TEST_F(LayoutFunctionTest, Subscript) { |
| EXPECT_EQ(layout_function_[0].column, 0); |
| EXPECT_EQ(layout_function_[1].column, 1); |
| EXPECT_EQ(layout_function_[2].column, 2); |
| EXPECT_EQ(layout_function_[3].column, 3); |
| EXPECT_EQ(layout_function_[4].column, 40); |
| EXPECT_EQ(layout_function_[5].column, 50); |
| layout_function_[5].column += 5; |
| EXPECT_EQ(layout_function_[5].column, 55); |
| |
| EXPECT_EQ(const_layout_function_[0].column, 0); |
| EXPECT_EQ(const_layout_function_[1].column, 1); |
| EXPECT_EQ(const_layout_function_[2].column, 2); |
| EXPECT_EQ(const_layout_function_[3].column, 3); |
| EXPECT_EQ(const_layout_function_[4].column, 40); |
| EXPECT_EQ(const_layout_function_[5].column, 50); |
| } |
| |
| class LayoutFunctionIteratorTest : public LayoutFunctionTest {}; |
| |
| TEST_F(LayoutFunctionIteratorTest, ToString) { |
| { |
| std::ostringstream addr; |
| addr << &layout_function_; |
| EXPECT_EQ(ToString(layout_function_.begin()), |
| absl::StrCat(addr.str(), "[0/6]")); |
| EXPECT_EQ(ToString(layout_function_.end()), |
| absl::StrCat(addr.str(), "[6/6]")); |
| } |
| { |
| std::ostringstream addr; |
| addr << &const_layout_function_; |
| EXPECT_EQ(ToString(const_layout_function_.begin()), |
| absl::StrCat(addr.str(), "[0/6]")); |
| EXPECT_EQ(ToString(const_layout_function_.end()), |
| absl::StrCat(addr.str(), "[6/6]")); |
| } |
| { |
| LayoutFunction empty_layout_function{}; |
| std::ostringstream addr; |
| addr << &empty_layout_function; |
| EXPECT_EQ(ToString(empty_layout_function.begin()), |
| absl::StrCat(addr.str(), "[0/0]")); |
| EXPECT_EQ(ToString(empty_layout_function.end()), |
| absl::StrCat(addr.str(), "[0/0]")); |
| } |
| } |
| |
| TEST_F(LayoutFunctionIteratorTest, MoveToKnotAtOrToTheLeftOf) { |
| { |
| auto it = layout_function_.begin(); |
| |
| it.MoveToKnotAtOrToTheLeftOf(2); |
| EXPECT_EQ(it, layout_function_.begin() + 2); |
| it.MoveToKnotAtOrToTheLeftOf(0); |
| EXPECT_EQ(it, layout_function_.begin()); |
| it.MoveToKnotAtOrToTheLeftOf(std::numeric_limits<int>::max()); |
| EXPECT_EQ(it, layout_function_.begin() + 5); |
| it.MoveToKnotAtOrToTheLeftOf(1); |
| EXPECT_EQ(it, layout_function_.begin() + 1); |
| it.MoveToKnotAtOrToTheLeftOf(1); |
| EXPECT_EQ(it, layout_function_.begin() + 1); |
| for (int i = 3; i < 40; ++i) { |
| it.MoveToKnotAtOrToTheLeftOf(i); |
| EXPECT_EQ(it, layout_function_.begin() + 3) << "i: " << i; |
| } |
| for (int i = 50; i < 70; ++i) { |
| it.MoveToKnotAtOrToTheLeftOf(i); |
| EXPECT_EQ(it, layout_function_.begin() + 5) << "i: " << i; |
| } |
| for (int i = 49; i >= 40; --i) { |
| it.MoveToKnotAtOrToTheLeftOf(i); |
| EXPECT_EQ(it, layout_function_.begin() + 4) << "i: " << i; |
| } |
| } |
| { |
| LayoutFunction empty_layout_function{}; |
| auto it = empty_layout_function.begin(); |
| |
| it.MoveToKnotAtOrToTheLeftOf(0); |
| EXPECT_EQ(it, empty_layout_function.end()); |
| it.MoveToKnotAtOrToTheLeftOf(std::numeric_limits<int>::max()); |
| EXPECT_EQ(it, empty_layout_function.end()); |
| it.MoveToKnotAtOrToTheLeftOf(1); |
| EXPECT_EQ(it, empty_layout_function.end()); |
| } |
| |
| { |
| auto it = const_layout_function_.begin(); |
| |
| it.MoveToKnotAtOrToTheLeftOf(2); |
| EXPECT_EQ(it, const_layout_function_.begin() + 2); |
| it.MoveToKnotAtOrToTheLeftOf(0); |
| EXPECT_EQ(it, const_layout_function_.begin()); |
| it.MoveToKnotAtOrToTheLeftOf(std::numeric_limits<int>::max()); |
| EXPECT_EQ(it, const_layout_function_.begin() + 5); |
| it.MoveToKnotAtOrToTheLeftOf(1); |
| EXPECT_EQ(it, const_layout_function_.begin() + 1); |
| it.MoveToKnotAtOrToTheLeftOf(1); |
| EXPECT_EQ(it, const_layout_function_.begin() + 1); |
| for (int i = 3; i < 40; ++i) { |
| it.MoveToKnotAtOrToTheLeftOf(i); |
| EXPECT_EQ(it, const_layout_function_.begin() + 3) << "i: " << i; |
| } |
| for (int i = 50; i < 70; ++i) { |
| it.MoveToKnotAtOrToTheLeftOf(i); |
| EXPECT_EQ(it, const_layout_function_.begin() + 5) << "i: " << i; |
| } |
| for (int i = 49; i >= 40; --i) { |
| it.MoveToKnotAtOrToTheLeftOf(i); |
| EXPECT_EQ(it, const_layout_function_.begin() + 4) << "i: " << i; |
| } |
| } |
| { |
| const LayoutFunction empty_layout_function{}; |
| auto it = empty_layout_function.begin(); |
| |
| it.MoveToKnotAtOrToTheLeftOf(0); |
| EXPECT_EQ(it, empty_layout_function.end()); |
| it.MoveToKnotAtOrToTheLeftOf(std::numeric_limits<int>::max()); |
| EXPECT_EQ(it, empty_layout_function.end()); |
| it.MoveToKnotAtOrToTheLeftOf(1); |
| EXPECT_EQ(it, empty_layout_function.end()); |
| } |
| } |
| |
| TEST_F(LayoutFunctionIteratorTest, ContainerRelatedMethods) { |
| { |
| int i = 0; |
| auto it = layout_function_.begin(); |
| while (it != layout_function_.end()) { |
| EXPECT_EQ(&it.Container(), &layout_function_); |
| EXPECT_EQ(it.Index(), i); |
| EXPECT_FALSE(it.IsEnd()); |
| ++it; |
| ++i; |
| } |
| EXPECT_EQ(&it.Container(), &layout_function_); |
| EXPECT_EQ(it.Index(), i); |
| EXPECT_TRUE(it.IsEnd()); |
| } |
| { |
| int i = 0; |
| auto it = const_layout_function_.begin(); |
| while (it != const_layout_function_.end()) { |
| EXPECT_EQ(&it.Container(), &const_layout_function_); |
| EXPECT_EQ(it.Index(), i); |
| EXPECT_FALSE(it.IsEnd()); |
| ++it; |
| ++i; |
| } |
| EXPECT_EQ(&it.Container(), &const_layout_function_); |
| EXPECT_EQ(it.Index(), i); |
| EXPECT_TRUE(it.IsEnd()); |
| } |
| } |
| |
| class LayoutFunctionFactoryTest : public ::testing::Test, |
| public UnwrappedLineMemoryHandler { |
| public: |
| LayoutFunctionFactoryTest() |
| : sample_( |
| // : |10 : |20 : |30 : |40 |
| "This line is short.\n" |
| "This line is so long that it exceeds column limit.\n" |
| " Indented line with many spaces .\n" |
| |
| "One under 40 column limit (39 columns).\n" |
| "Exactly at 40 column limit (40 columns).\n" |
| "One over 40 column limit (41 characters).\n" |
| |
| "One under 30 limit (29 cols).\n" |
| "Exactly at 30 limit (30 cols).\n" |
| "One over 30 limit (31 columns).\n" |
| |
| "10 columns"), |
| tokens_( |
| absl::StrSplit(sample_, absl::ByAnyChar(" \n"), absl::SkipEmpty())), |
| style_(CreateStyle()), |
| factory_(LayoutFunctionFactory(style_)) { |
| // Create two sets of tokens |
| const size_t number_of_tokens_in_set = tokens_.size(); |
| ftokens_.reserve(number_of_tokens_in_set * 2); |
| for (const auto token : tokens_) ftokens_.emplace_back(TokenInfo{1, token}); |
| for (const auto token : tokens_) ftokens_.emplace_back(TokenInfo{1, token}); |
| |
| CreateTokenInfosExternalStringBuffer(ftokens_); |
| |
| auto must_wrap_pre_format_tokens = verible::make_range( |
| pre_format_tokens_.begin(), |
| pre_format_tokens_.begin() + number_of_tokens_in_set); |
| auto joinable_pre_format_tokens = verible::make_range( |
| pre_format_tokens_.begin() + number_of_tokens_in_set, |
| pre_format_tokens_.end()); |
| |
| // Setup pointers for OriginalLeadingSpaces() |
| auto must_wrap_token = must_wrap_pre_format_tokens.begin(); |
| auto joinable_token = joinable_pre_format_tokens.begin(); |
| const char* buffer_start = sample_.data(); |
| for (size_t i = 0; i < number_of_tokens_in_set; ++i) { |
| must_wrap_token->before.preserved_space_start = buffer_start; |
| joinable_token->before.preserved_space_start = buffer_start; |
| ++must_wrap_token; |
| ++joinable_token; |
| buffer_start = tokens_[i].end(); |
| } |
| |
| ProcessTokensAndCreateUnwrappedLines(true, &must_wrap_pre_format_tokens, |
| &lines_.uwlines_); |
| ProcessTokensAndCreateUnwrappedLines(false, &joinable_pre_format_tokens, |
| &joinable_lines_.uwlines_); |
| } |
| |
| protected: |
| using PreFormatTokensIterator = decltype(pre_format_tokens_)::iterator; |
| |
| static void ProcessTokensAndCreateUnwrappedLines( |
| bool first_on_line_must_wrap, |
| verible::iterator_range<PreFormatTokensIterator>* pftokens, |
| std::vector<UnwrappedLine>* uwlines) { |
| uwlines->emplace_back(0, pftokens->begin()); |
| for (auto token = pftokens->begin(); token != pftokens->end(); ++token) { |
| const auto leading_spaces = token->OriginalLeadingSpaces(); |
| |
| // First token in a line |
| if (absl::StrContains(leading_spaces, '\n')) { |
| if (first_on_line_must_wrap) |
| token->before.break_decision = SpacingOptions::MustWrap; |
| uwlines->back().SpanUpToToken(token); |
| uwlines->emplace_back(0, token); |
| } |
| |
| // Count spaces preceding the token and set spaces_required accordingly |
| auto last_non_space_offset = leading_spaces.find_last_not_of(' '); |
| if (last_non_space_offset != absl::string_view::npos) { |
| token->before.spaces_required = |
| leading_spaces.size() - 1 - last_non_space_offset; |
| } else { |
| token->before.spaces_required = leading_spaces.size(); |
| } |
| } |
| uwlines->back().SpanUpToToken(pftokens->end()); |
| } |
| |
| // Wrapper for UnwrappedLine vector with readable getter for each line |
| struct NamedUnwrappedLines { |
| const UnwrappedLine& Short() const { return uwlines_.at(0); } |
| const UnwrappedLine& Long() const { return uwlines_.at(1); } |
| const UnwrappedLine& Indented() const { return uwlines_.at(2); } |
| |
| const UnwrappedLine& OneUnder40Limit() const { return uwlines_.at(3); } |
| const UnwrappedLine& ExactlyAt40Limit() const { return uwlines_.at(4); } |
| const UnwrappedLine& OneOver40Limit() const { return uwlines_.at(5); } |
| |
| const UnwrappedLine& OneUnder30Limit() const { return uwlines_.at(6); } |
| const UnwrappedLine& ExactlyAt30Limit() const { return uwlines_.at(7); } |
| const UnwrappedLine& OneOver30Limit() const { return uwlines_.at(8); } |
| |
| const UnwrappedLine& Exactly10Columns() const { return uwlines_.at(9); } |
| |
| std::vector<UnwrappedLine> uwlines_; |
| }; |
| |
| const std::string sample_; |
| const std::vector<absl::string_view> tokens_; |
| std::vector<TokenInfo> ftokens_; |
| |
| NamedUnwrappedLines lines_; |
| NamedUnwrappedLines joinable_lines_; |
| |
| const BasicFormatStyle style_; |
| const LayoutFunctionFactory factory_; |
| }; |
| |
| TEST_F(LayoutFunctionFactoryTest, Line) { |
| using LT = LayoutTree; |
| using LI = LayoutItem; |
| |
| { |
| const auto lf = factory_.Line(lines_.Short()); |
| const auto expected_lf = LayoutFunction{ |
| {0, LT(LI(lines_.Short())), 19, 0.0F, 0}, |
| {21, LT(LI(lines_.Short())), 19, 0.0F, 100}, |
| }; |
| ExpectLayoutFunctionsEqual(lf, expected_lf, __LINE__); |
| } |
| |
| { |
| const auto lf = factory_.Line(lines_.Long()); |
| const auto expected_lf = LayoutFunction{ |
| {0, LT(LI(lines_.Long())), 50, 1000.0F, 100}, |
| }; |
| ExpectLayoutFunctionsEqual(lf, expected_lf, __LINE__); |
| } |
| { |
| const auto lf = factory_.Line(lines_.Indented()); |
| const auto expected_lf = LayoutFunction{ |
| {0, LT(LI(lines_.Indented())), 36, 0.0F, 0}, |
| {4, LT(LI(lines_.Indented())), 36, 0.0F, 100}, |
| }; |
| ExpectLayoutFunctionsEqual(lf, expected_lf, __LINE__); |
| } |
| { |
| const auto lf = factory_.Line(lines_.OneUnder40Limit()); |
| const auto expected_lf = LayoutFunction{ |
| {0, LT(LI(lines_.OneUnder40Limit())), 39, 0.0F, 0}, |
| {1, LT(LI(lines_.OneUnder40Limit())), 39, 0.0F, 100}, |
| }; |
| ExpectLayoutFunctionsEqual(lf, expected_lf, __LINE__); |
| } |
| { |
| const auto lf = factory_.Line(lines_.ExactlyAt40Limit()); |
| const auto expected_lf = LayoutFunction{ |
| {0, LT(LI(lines_.ExactlyAt40Limit())), 40, 0.0F, 100}, |
| }; |
| ExpectLayoutFunctionsEqual(lf, expected_lf, __LINE__); |
| } |
| { |
| const auto lf = factory_.Line(lines_.OneOver40Limit()); |
| const auto expected_lf = LayoutFunction{ |
| {0, LT(LI(lines_.OneOver40Limit())), 41, 100.0F, 100}, |
| }; |
| ExpectLayoutFunctionsEqual(lf, expected_lf, __LINE__); |
| } |
| } |
| |
| TEST_F(LayoutFunctionFactoryTest, Stack) { |
| using LT = LayoutTree; |
| using LI = LayoutItem; |
| |
| { |
| const auto lf = factory_.Stack({}); |
| const auto expected_lf = LayoutFunction{}; |
| ExpectLayoutFunctionsEqual(lf, expected_lf, __LINE__); |
| } |
| { |
| const auto line = factory_.Line(lines_.Short()); |
| const auto lf = factory_.Stack({line}); |
| const auto& expected_lf = line; |
| ExpectLayoutFunctionsEqual(lf, expected_lf, __LINE__); |
| } |
| { |
| const auto lf = factory_.Stack({ |
| factory_.Line(lines_.Short()), |
| factory_.Line(lines_.Exactly10Columns()), |
| }); |
| const auto expected_layout = LT(LI(LayoutType::kStack, 0, false), // |
| LT(LI(lines_.Short())), // |
| LT(LI(lines_.Exactly10Columns()))); |
| const auto expected_lf = LayoutFunction{ |
| {0, expected_layout, 10, 2.0F, 0}, |
| {21, expected_layout, 10, 2.0F, 100}, |
| {30, expected_layout, 10, 902.0F, 200}, |
| }; |
| ExpectLayoutFunctionsEqual(lf, expected_lf, __LINE__); |
| } |
| { |
| const auto lf = factory_.Stack({ |
| factory_.Line(lines_.Short()), |
| factory_.Line(lines_.Short()), |
| }); |
| const auto expected_layout = LT(LI(LayoutType::kStack, 0, false), // |
| LT(LI(lines_.Short())), // |
| LT(LI(lines_.Short()))); |
| const auto expected_lf = LayoutFunction{ |
| {0, expected_layout, 19, 2.0F, 0}, |
| {21, expected_layout, 19, 2.0F, 200}, |
| }; |
| ExpectLayoutFunctionsEqual(lf, expected_lf, __LINE__); |
| } |
| { |
| const auto lf = factory_.Stack({ |
| factory_.Line(lines_.Short()), |
| factory_.Line(lines_.Long()), |
| }); |
| const auto expected_layout = LT(LI(LayoutType::kStack, 0, false), // |
| LT(LI(lines_.Short())), // |
| LT(LI(lines_.Long()))); |
| const auto expected_lf = LayoutFunction{ |
| {0, expected_layout, 50, 1002.0F, 100}, |
| {21, expected_layout, 50, 3102.0F, 200}, |
| }; |
| ExpectLayoutFunctionsEqual(lf, expected_lf, __LINE__); |
| } |
| { |
| const auto lf = factory_.Stack({ |
| factory_.Line(lines_.Long()), |
| factory_.Line(lines_.Short()), |
| }); |
| const auto expected_layout = LT(LI(LayoutType::kStack, 0, true), // |
| LT(LI(lines_.Long())), // |
| LT(LI(lines_.Short()))); |
| const auto expected_lf = LayoutFunction{ |
| {0, expected_layout, 19, 1002.0F, 100}, |
| {21, expected_layout, 19, 3102.0F, 200}, |
| }; |
| ExpectLayoutFunctionsEqual(lf, expected_lf, __LINE__); |
| } |
| { |
| const auto lf = factory_.Stack({ |
| factory_.Line(lines_.Short()), |
| factory_.Line(lines_.Long()), |
| factory_.Line(lines_.Exactly10Columns()), |
| }); |
| const auto expected_layout = LT(LI(LayoutType::kStack, 0, false), // |
| LT(LI(lines_.Short())), // |
| LT(LI(lines_.Long())), // |
| LT(LI(lines_.Exactly10Columns()))); |
| const auto expected_lf = LayoutFunction{ |
| {0, expected_layout, 10, 1004.0F, 100}, |
| {21, expected_layout, 10, 3104.0F, 200}, |
| {30, expected_layout, 10, 4904.0F, 300}, |
| }; |
| ExpectLayoutFunctionsEqual(lf, expected_lf, __LINE__); |
| } |
| { |
| const auto lf = factory_.Stack({ |
| factory_.Line(lines_.Short()), |
| factory_.Line(lines_.Indented()), |
| }); |
| const auto expected_layout = LT(LI(LayoutType::kStack, 0, false), // |
| LT(LI(lines_.Short())), // |
| LT(LI(lines_.Indented()))); |
| const auto expected_lf = LayoutFunction{ |
| {0, expected_layout, 36, 2.0F, 0}, |
| {4, expected_layout, 36, 2.0F, 100}, |
| {21, expected_layout, 36, 1702.0F, 200}, |
| }; |
| ExpectLayoutFunctionsEqual(lf, expected_lf, __LINE__); |
| } |
| { |
| const auto lf = factory_.Stack({ |
| factory_.Line(lines_.Short()), |
| factory_.Line(lines_.OneUnder40Limit()), |
| }); |
| const auto expected_layout = LT(LI(LayoutType::kStack, 0, false), // |
| LT(LI(lines_.Short())), // |
| LT(LI(lines_.OneUnder40Limit()))); |
| const auto expected_lf = LayoutFunction{ |
| {0, expected_layout, 39, 2.0F, 0}, |
| {1, expected_layout, 39, 2.0F, 100}, |
| {21, expected_layout, 39, 2002.0F, 200}, |
| }; |
| ExpectLayoutFunctionsEqual(lf, expected_lf, __LINE__); |
| } |
| { |
| const auto lf = factory_.Stack({ |
| factory_.Line(lines_.Short()), |
| factory_.Line(lines_.OneOver40Limit()), |
| }); |
| const auto expected_layout = LT(LI(LayoutType::kStack, 0, false), // |
| LT(LI(lines_.Short())), // |
| LT(LI(lines_.OneOver40Limit()))); |
| const auto expected_lf = LayoutFunction{ |
| {0, expected_layout, 41, 102.0F, 100}, |
| {21, expected_layout, 41, 2202.0F, 200}, |
| }; |
| ExpectLayoutFunctionsEqual(lf, expected_lf, __LINE__); |
| } |
| { |
| const auto lf = factory_.Stack({ |
| factory_.Line(lines_.Short()), |
| factory_.Line(lines_.ExactlyAt40Limit()), |
| }); |
| const auto expected_layout = LT(LI(LayoutType::kStack, 0, false), // |
| LT(LI(lines_.Short())), // |
| LT(LI(lines_.ExactlyAt40Limit()))); |
| const auto expected_lf = LayoutFunction{ |
| {0, expected_layout, 40, 2.0F, 100}, |
| {21, expected_layout, 40, 2102.0F, 100}, |
| }; |
| } |
| { |
| const auto lf = factory_.Stack({ |
| factory_.Line(lines_.OneUnder40Limit()), |
| factory_.Line(lines_.Short()), |
| }); |
| const auto expected_layout = LT(LI(LayoutType::kStack, 0, true), // |
| LT(LI(lines_.OneUnder40Limit())), // |
| LT(LI(lines_.Short()))); |
| const auto expected_lf = LayoutFunction{ |
| {0, expected_layout, 19, 2.0F, 0}, |
| {1, expected_layout, 19, 2.0F, 100}, |
| {21, expected_layout, 19, 2002.0F, 200}, |
| }; |
| ExpectLayoutFunctionsEqual(lf, expected_lf, __LINE__); |
| } |
| { |
| const auto lf = factory_.Stack({ |
| factory_.Line(lines_.OneOver40Limit()), |
| factory_.Line(lines_.Short()), |
| }); |
| const auto expected_layout = LT(LI(LayoutType::kStack, 0, true), // |
| LT(LI(lines_.OneOver40Limit())), // |
| LT(LI(lines_.Short()))); |
| const auto expected_lf = LayoutFunction{ |
| {0, expected_layout, 19, 102.0F, 100}, |
| {21, expected_layout, 19, 2202.0F, 200}, |
| }; |
| ExpectLayoutFunctionsEqual(lf, expected_lf, __LINE__); |
| } |
| { |
| const auto lf = factory_.Stack({ |
| factory_.Line(lines_.ExactlyAt40Limit()), |
| factory_.Line(lines_.Short()), |
| }); |
| const auto expected_layout = LT(LI(LayoutType::kStack, 0, true), // |
| LT(LI(lines_.ExactlyAt40Limit())), // |
| LT(LI(lines_.Short()))); |
| const auto expected_lf = LayoutFunction{ |
| {0, expected_layout, 40, 2.0F, 100}, |
| {21, expected_layout, 40, 2102.0F, 100}, |
| }; |
| } |
| { |
| const auto lf = factory_.Stack({ |
| factory_.Line(lines_.Short()), |
| factory_.Line(lines_.Long()), |
| factory_.Stack({ |
| factory_.Line(lines_.Indented()), |
| factory_.Line(lines_.OneUnder40Limit()), |
| factory_.Line(lines_.ExactlyAt40Limit()), |
| factory_.Line(lines_.OneOver40Limit()), |
| factory_.Line(lines_.Exactly10Columns()), |
| }), |
| }); |
| const auto expected_layout = LT(LI(LayoutType::kStack, 0, false), // |
| LT(LI(lines_.Short())), // |
| LT(LI(lines_.Long())), // |
| LT(LI(lines_.Indented())), // |
| LT(LI(lines_.OneUnder40Limit())), // |
| LT(LI(lines_.ExactlyAt40Limit())), // |
| LT(LI(lines_.OneOver40Limit())), // |
| LT(LI(lines_.Exactly10Columns()))); |
| const auto expected_lf = LayoutFunction{ |
| {0, expected_layout, 10, 1112.0F, 300}, |
| {1, expected_layout, 10, 1412.0F, 400}, |
| {4, expected_layout, 10, 2612.0F, 500}, |
| {21, expected_layout, 10, 11112.0F, 600}, |
| {30, expected_layout, 10, 16512.0F, 700}, |
| }; |
| ExpectLayoutFunctionsEqual(lf, expected_lf, __LINE__); |
| } |
| { |
| // Expected result here is the same as in the test case above |
| const auto lf = factory_.Stack({ |
| factory_.Line(lines_.Short()), |
| factory_.Line(lines_.Long()), |
| factory_.Line(lines_.Indented()), |
| factory_.Stack({ |
| factory_.Line(lines_.OneUnder40Limit()), |
| factory_.Line(lines_.ExactlyAt40Limit()), |
| factory_.Line(lines_.OneOver40Limit()), |
| }), |
| factory_.Line(lines_.Exactly10Columns()), |
| }); |
| const auto expected_layout = LT(LI(LayoutType::kStack, 0, false), // |
| LT(LI(lines_.Short())), // |
| LT(LI(lines_.Long())), // |
| LT(LI(lines_.Indented())), // |
| LT(LI(lines_.OneUnder40Limit())), // |
| LT(LI(lines_.ExactlyAt40Limit())), // |
| LT(LI(lines_.OneOver40Limit())), // |
| LT(LI(lines_.Exactly10Columns()))); |
| const auto expected_lf = LayoutFunction{ |
| {0, expected_layout, 10, 1112.0F, 300}, |
| {1, expected_layout, 10, 1412.0F, 400}, |
| {4, expected_layout, 10, 2612.0F, 500}, |
| {21, expected_layout, 10, 11112.0F, 600}, |
| {30, expected_layout, 10, 16512.0F, 700}, |
| }; |
| ExpectLayoutFunctionsEqual(lf, expected_lf, __LINE__); |
| } |
| } |
| |
| TEST_F(LayoutFunctionFactoryTest, Juxtaposition) { |
| using LT = LayoutTree; |
| using LI = LayoutItem; |
| |
| static const auto kSampleStackLayout = |
| LT(LI(LayoutType::kStack, 0, false), // |
| LT(LI(lines_.Short())), // |
| LT(LI(lines_.Long())), // |
| LT(LI(lines_.Exactly10Columns()))); |
| // Result of: |
| // factory_.Stack({ |
| // factory_.Line(lines_.Short()), |
| // factory_.Line(lines_.Long()), |
| // factory_.Line(lines_.Exactly10Columns()), |
| // }); |
| static const auto kSampleStackLayoutFunction = LayoutFunction{ |
| {0, kSampleStackLayout, 10, 1004.0F, 100}, |
| {21, kSampleStackLayout, 10, 3104.0F, 200}, |
| {30, kSampleStackLayout, 10, 4904.0F, 300}, |
| }; |
| |
| { |
| const auto lf = factory_.Juxtaposition({}); |
| const auto expected_lf = LayoutFunction{}; |
| ExpectLayoutFunctionsEqual(lf, expected_lf, __LINE__); |
| } |
| { |
| const auto line = factory_.Line(lines_.Short()); |
| const auto lf = factory_.Juxtaposition({line}); |
| const auto& expected_lf = line; |
| ExpectLayoutFunctionsEqual(lf, expected_lf, __LINE__); |
| } |
| { |
| const auto lf = factory_.Juxtaposition({ |
| factory_.Line(lines_.Short()), |
| factory_.Line(joinable_lines_.Exactly10Columns()), |
| }); |
| const auto expected_layout = |
| LT(LI(LayoutType::kJuxtaposition, 0, false), // |
| LT(LI(lines_.Short())), // |
| LT(LI(joinable_lines_.Exactly10Columns()))); |
| const auto expected_lf = LayoutFunction{ |
| {0, expected_layout, 29, 0.0F, 0}, |
| {11, expected_layout, 29, 0.0F, 100}, |
| {21, expected_layout, 29, 1000.0F, 100}, |
| }; |
| ExpectLayoutFunctionsEqual(lf, expected_lf, __LINE__); |
| } |
| { |
| const auto lf = factory_.Juxtaposition({ |
| factory_.Line(lines_.Short()), |
| factory_.Line(joinable_lines_.Exactly10Columns()), |
| factory_.Line(joinable_lines_.Exactly10Columns()), |
| }); |
| const auto expected_layout = |
| LT(LI(LayoutType::kJuxtaposition, 0, false), // |
| LT(LI(lines_.Short())), // |
| LT(LI(joinable_lines_.Exactly10Columns())), // |
| LT(LI(joinable_lines_.Exactly10Columns()))); |
| const auto expected_lf = LayoutFunction{ |
| {0, expected_layout, 39, 0.0F, 0}, |
| {1, expected_layout, 39, 0.0F, 100}, |
| {11, expected_layout, 39, 1000.0F, 100}, |
| {21, expected_layout, 39, 2000.0F, 100}, |
| }; |
| ExpectLayoutFunctionsEqual(lf, expected_lf, __LINE__); |
| } |
| { |
| const auto lf = factory_.Juxtaposition({ |
| factory_.Line(lines_.Exactly10Columns()), |
| factory_.Line(joinable_lines_.Short()), |
| }); |
| const auto expected_layout = LT(LI(LayoutType::kJuxtaposition, 0, true), // |
| LT(LI(lines_.Exactly10Columns())), // |
| LT(LI(joinable_lines_.Short()))); |
| const auto expected_lf = LayoutFunction{ |
| {0, expected_layout, 29, 0.0F, 0}, |
| {11, expected_layout, 29, 0.0F, 100}, |
| {30, expected_layout, 29, 1900.0F, 100}, |
| }; |
| ExpectLayoutFunctionsEqual(lf, expected_lf, __LINE__); |
| } |
| { |
| const auto lf = factory_.Juxtaposition({ |
| factory_.Line(lines_.Short()), |
| factory_.Line(joinable_lines_.Indented()), |
| }); |
| const auto expected_layout = |
| LT(LI(LayoutType::kJuxtaposition, 0, false), // |
| LT(LI(lines_.Short())), // |
| LT(LI(joinable_lines_.Indented()))); |
| const auto expected_lf = LayoutFunction{ |
| {0, expected_layout, 63, 2300.0F, 100}, |
| {21, expected_layout, 63, 3600.0F, 100}, |
| }; |
| ExpectLayoutFunctionsEqual(lf, expected_lf, __LINE__); |
| } |
| { |
| const auto lf = factory_.Juxtaposition({ |
| factory_.Line(lines_.Indented()), |
| factory_.Line(joinable_lines_.Short()), |
| }); |
| const auto expected_layout = LT(LI(LayoutType::kJuxtaposition, 8, true), // |
| LT(LI(lines_.Indented())), // |
| LT(LI(joinable_lines_.Short()))); |
| const auto expected_lf = LayoutFunction{ |
| {0, expected_layout, 55, 1500.0F, 100}, |
| {4, expected_layout, 55, 1900.0F, 100}, |
| }; |
| ExpectLayoutFunctionsEqual(lf, expected_lf, __LINE__); |
| } |
| { |
| const auto lf = factory_.Juxtaposition({ |
| kSampleStackLayoutFunction, |
| factory_.Line(joinable_lines_.Short()), |
| }); |
| const auto expected_layout = |
| LT(LI(LayoutType::kJuxtaposition, 0, false), // |
| kSampleStackLayout, // |
| LT(LI(joinable_lines_.Short()))); |
| const auto expected_lf = LayoutFunction{ |
| {0, expected_layout, 29, 1004.0F, 100}, |
| {11, expected_layout, 29, 2104.0F, 200}, |
| {21, expected_layout, 29, 4104.0F, 300}, |
| {30, expected_layout, 29, 6804.0F, 300}, |
| }; |
| ExpectLayoutFunctionsEqual(lf, expected_lf, __LINE__); |
| } |
| { |
| const auto lf = factory_.Juxtaposition({ |
| factory_.Line(lines_.Short()), |
| kSampleStackLayoutFunction, |
| }); |
| const auto expected_layout = |
| LT(LI(LayoutType::kJuxtaposition, 0, false), // |
| LT(LI(lines_.Short())), // |
| kSampleStackLayout); |
| const auto expected_lf = LayoutFunction{ |
| {0, expected_layout, 29, 2904.0F, 100}, |
| {2, expected_layout, 29, 3104.0F, 200}, |
| {11, expected_layout, 29, 4904.0F, 300}, |
| {21, expected_layout, 29, 7904.0F, 300}, |
| }; |
| ExpectLayoutFunctionsEqual(lf, expected_lf, __LINE__); |
| } |
| { |
| const auto lf = factory_.Juxtaposition( |
| {factory_.Line(lines_.OneUnder30Limit()), |
| factory_.Line(joinable_lines_.Exactly10Columns())}); |
| const auto expected_layout = LT(LI(LayoutType::kJuxtaposition, 0, true), // |
| LT(LI(lines_.OneUnder30Limit())), // |
| LT(LI(joinable_lines_.Exactly10Columns()))); |
| const auto expected_lf = LayoutFunction{ |
| {0, expected_layout, 39, 0.0F, 0}, |
| {1, expected_layout, 39, 0.0F, 100}, |
| {11, expected_layout, 39, 1000.0F, 100}, |
| }; |
| ExpectLayoutFunctionsEqual(lf, expected_lf, __LINE__); |
| } |
| { |
| const auto lf = factory_.Juxtaposition( |
| {factory_.Line(lines_.ExactlyAt30Limit()), |
| factory_.Line(joinable_lines_.Exactly10Columns())}); |
| const auto expected_layout = LT(LI(LayoutType::kJuxtaposition, 0, true), // |
| LT(LI(lines_.ExactlyAt30Limit())), // |
| LT(LI(joinable_lines_.Exactly10Columns()))); |
| const auto expected_lf = LayoutFunction{ |
| {0, expected_layout, 40, 0.0F, 100}, |
| {10, expected_layout, 40, 1000.0F, 100}, |
| }; |
| ExpectLayoutFunctionsEqual(lf, expected_lf, __LINE__); |
| } |
| { |
| const auto lf = factory_.Juxtaposition( |
| {factory_.Line(lines_.OneOver30Limit()), |
| factory_.Line(joinable_lines_.Exactly10Columns())}); |
| const auto expected_layout = LT(LI(LayoutType::kJuxtaposition, 0, true), // |
| LT(LI(lines_.OneOver30Limit())), // |
| LT(LI(joinable_lines_.Exactly10Columns()))); |
| const auto expected_lf = LayoutFunction{ |
| {0, expected_layout, 41, 100.0F, 100}, |
| {9, expected_layout, 41, 1000.0F, 100}, |
| }; |
| ExpectLayoutFunctionsEqual(lf, expected_lf, __LINE__); |
| } |
| { |
| const auto lf = factory_.Juxtaposition({ |
| factory_.Line(lines_.Short()), |
| factory_.Line(joinable_lines_.Long()), |
| factory_.Juxtaposition({ |
| factory_.Line(joinable_lines_.Indented()), |
| factory_.Line(joinable_lines_.OneUnder40Limit()), |
| factory_.Line(joinable_lines_.ExactlyAt40Limit()), |
| factory_.Line(joinable_lines_.OneOver40Limit()), |
| factory_.Line(joinable_lines_.Exactly10Columns()), |
| }), |
| }); |
| const auto expected_layout = |
| LT(LI(LayoutType::kJuxtaposition, 0, false), // |
| LT(LI(lines_.Short())), // |
| LT(LI(joinable_lines_.Long())), // |
| LT(LI(joinable_lines_.Indented())), // |
| LT(LI(joinable_lines_.OneUnder40Limit())), // |
| LT(LI(joinable_lines_.ExactlyAt40Limit())), // |
| LT(LI(joinable_lines_.OneOver40Limit())), // |
| LT(LI(joinable_lines_.Exactly10Columns()))); |
| const auto expected_lf = LayoutFunction{ |
| {0, expected_layout, 243, 19500.0F, 100}, |
| {21, expected_layout, 243, 21600.0F, 100}, |
| }; |
| ExpectLayoutFunctionsEqual(lf, expected_lf, __LINE__); |
| } |
| { |
| // Expected result here is the same as in the test case above |
| const auto lf = factory_.Juxtaposition({ |
| factory_.Line(lines_.Short()), |
| factory_.Line(joinable_lines_.Long()), |
| factory_.Line(joinable_lines_.Indented()), |
| factory_.Juxtaposition({ |
| factory_.Line(joinable_lines_.OneUnder40Limit()), |
| factory_.Line(joinable_lines_.ExactlyAt40Limit()), |
| factory_.Line(joinable_lines_.OneOver40Limit()), |
| }), |
| factory_.Line(joinable_lines_.Exactly10Columns()), |
| }); |
| const auto expected_layout = |
| LT(LI(LayoutType::kJuxtaposition, 0, false), // |
| LT(LI(lines_.Short())), // |
| LT(LI(joinable_lines_.Long())), // |
| LT(LI(joinable_lines_.Indented())), // |
| LT(LI(joinable_lines_.OneUnder40Limit())), // |
| LT(LI(joinable_lines_.ExactlyAt40Limit())), // |
| LT(LI(joinable_lines_.OneOver40Limit())), // |
| LT(LI(joinable_lines_.Exactly10Columns()))); |
| const auto expected_lf = LayoutFunction{ |
| {0, expected_layout, 243, 19500.0F, 100}, |
| {21, expected_layout, 243, 21600.0F, 100}, |
| }; |
| ExpectLayoutFunctionsEqual(lf, expected_lf, __LINE__); |
| } |
| } |
| |
| TEST_F(LayoutFunctionFactoryTest, Choice) { |
| using LT = LayoutTree; |
| using LI = LayoutItem; |
| |
| struct ChoiceTestCase { |
| int line_no; |
| const std::initializer_list<LayoutFunction> choices; |
| const LayoutFunction expected; |
| }; |
| |
| // Layout doesn't really matter in this test |
| static const auto layout = LT(LI(LayoutType::kLine, 0, false)); |
| |
| static const ChoiceTestCase kTestCases[] = { |
| {__LINE__, {}, LayoutFunction{}}, |
| {__LINE__, |
| { |
| LayoutFunction{{0, layout, 10, 100.0F, 10}}, |
| }, |
| LayoutFunction{{0, layout, 10, 100.0F, 10}}}, |
| {__LINE__, |
| { |
| LayoutFunction{{0, layout, 10, 100.0F, 10}}, |
| LayoutFunction{{0, layout, 10, 200.0F, 10}}, |
| }, |
| LayoutFunction{{0, layout, 10, 100.0F, 10}}}, |
| {__LINE__, |
| { |
| LayoutFunction{{0, layout, 10, 200.0F, 10}}, |
| LayoutFunction{{0, layout, 10, 100.0F, 10}}, |
| }, |
| LayoutFunction{{0, layout, 10, 100.0F, 10}}}, |
| {__LINE__, |
| { |
| LayoutFunction{{0, layout, 10, 100.0F, 10}}, |
| LayoutFunction{{0, layout, 10, 100.0F, 10}}, |
| }, |
| LayoutFunction{{0, layout, 10, 100.0F, 10}}}, |
| {__LINE__, |
| { |
| LayoutFunction{{0, layout, 10, 100.0F, 1}}, |
| LayoutFunction{{0, layout, 10, 0.0F, 3}}, |
| }, |
| LayoutFunction{ |
| {0, layout, 10, 0.0F, 3}, |
| {50, layout, 10, 150.0F, 1}, |
| }}, |
| {__LINE__, |
| { |
| LayoutFunction{ |
| {0, layout, 10, 100.0F, 1}, |
| }, |
| LayoutFunction{ |
| {0, layout, 10, 0.0F, 3}, |
| {50, layout, 10, 150.0F, 0}, |
| }, |
| }, |
| LayoutFunction{ |
| {0, layout, 10, 0.0F, 3}, |
| {50, layout, 10, 150.0F, 0}, |
| }}, |
| {__LINE__, |
| { |
| LayoutFunction{ |
| {0, layout, 10, 100.0F, 1}, |
| }, |
| LayoutFunction{ |
| {0, layout, 10, 0.0F, 3}, |
| {50, layout, 10, 160.0F, 0}, |
| }, |
| }, |
| LayoutFunction{ |
| {0, layout, 10, 0.0F, 3}, |
| {50, layout, 10, 150.0F, 1}, |
| {60, layout, 10, 160.0F, 0}, |
| }}, |
| {__LINE__, |
| { |
| LayoutFunction{ |
| {0, layout, 10, 100.0F, 1}, |
| }, |
| LayoutFunction{ |
| {0, layout, 10, 0.0F, 3}, |
| {50, layout, 10, 160.0F, 0}, |
| }, |
| }, |
| LayoutFunction{ |
| {0, layout, 10, 0.0F, 3}, |
| {50, layout, 10, 150.0F, 1}, |
| {60, layout, 10, 160.0F, 0}, |
| }}, |
| {__LINE__, |
| { |
| LayoutFunction{ |
| {0, layout, 10, 100.0F, 1}, |
| {50, layout, 10, 150.0F, 0}, |
| }, |
| LayoutFunction{ |
| {0, layout, 10, 125.0F, 0}, |
| {75, layout, 10, 125.0F, 1}, |
| }, |
| }, |
| LayoutFunction{ |
| {0, layout, 10, 100.0F, 1}, |
| {25, layout, 10, 125.0F, 0}, |
| {75, layout, 10, 125.0F, 1}, |
| {100, layout, 10, 150.0F, 0}, |
| }}, |
| {__LINE__, |
| { |
| LayoutFunction{ |
| {0, layout, 1, 50.0F, 0}, |
| }, |
| LayoutFunction{ |
| {0, layout, 2, 0.0F, 10}, |
| }, |
| LayoutFunction{ |
| {0, layout, 3, 999.0F, 0}, |
| {10, layout, 3, 0.0F, 10}, |
| }, |
| LayoutFunction{ |
| {0, layout, 4, 999.0F, 0}, |
| {20, layout, 4, 0.0F, 10}, |
| }, |
| }, |
| LayoutFunction{ |
| {0, layout, 2, 0.0F, 10}, |
| {5, layout, 1, 50.0F, 0}, |
| {10, layout, 3, 0.0F, 10}, |
| {15, layout, 1, 50.0F, 0}, |
| {20, layout, 4, 0.0F, 10}, |
| {25, layout, 1, 50.0F, 0}, |
| }}, |
| }; |
| |
| for (const auto& test_case : kTestCases) { |
| const LayoutFunction choice_result = factory_.Choice(test_case.choices); |
| ExpectLayoutFunctionsEqual(choice_result, test_case.expected, |
| test_case.line_no); |
| } |
| } |
| |
| TEST_F(LayoutFunctionFactoryTest, Wrap) { |
| using LT = LayoutTree; |
| using LI = LayoutItem; |
| |
| { |
| const auto lf = factory_.Wrap({}); |
| const auto expected_lf = LayoutFunction{}; |
| ExpectLayoutFunctionsEqual(lf, expected_lf, __LINE__); |
| } |
| { |
| const auto lf = factory_.Wrap({ |
| factory_.Line(lines_.Short()), |
| }); |
| const auto expected_lf = factory_.Line(lines_.Short()); |
| ExpectLayoutFunctionsEqual(lf, expected_lf, __LINE__); |
| } |
| { |
| const auto lf = factory_.Wrap({ |
| factory_.Line(lines_.Exactly10Columns()), |
| factory_.Line(lines_.Short()), |
| factory_.Line(lines_.Short()), |
| }); |
| const auto expected_layout_vh = |
| LT(LI(LayoutType::kStack, 0, true), // |
| LT(LI(LayoutType::kJuxtaposition, 0, true), // |
| LI(lines_.Exactly10Columns()), // |
| LI(lines_.Short())), // |
| LI(lines_.Short())); |
| const auto expected_layout_h = |
| LT(LI(LayoutType::kJuxtaposition, 0, true), // |
| LI(lines_.Exactly10Columns()), // |
| LI(lines_.Short()), // |
| LI(lines_.Short())); |
| const auto expected_layout_v = LT(LI(LayoutType::kStack, 0, true), // |
| LI(lines_.Exactly10Columns()), // |
| LI(lines_.Short()), // |
| LI(lines_.Short())); |
| const auto expected_lf = LayoutFunction{ |
| {0, expected_layout_vh, 19, 2.0F, 0}, |
| {11, expected_layout_vh, 19, 2.0F, 100}, |
| {12, expected_layout_v, 19, 4.0F, 0}, |
| {21, expected_layout_v, 19, 4.0F, 200}, |
| {30, expected_layout_v, 19, 1804.0F, 300}, |
| {40, expected_layout_h, 48, 4800.0F, 100}, |
| }; |
| ExpectLayoutFunctionsEqual(lf, expected_lf, __LINE__); |
| } |
| { |
| const auto lf = factory_.Wrap({ |
| factory_.Line(lines_.Short()), |
| factory_.Line(lines_.Exactly10Columns()), |
| factory_.Line(lines_.Short()), |
| }); |
| const auto expected_layout_hv = |
| LT(LI(LayoutType::kJuxtaposition, 0, false), // |
| LT(LI(LayoutType::kStack, 0, false), // |
| LI(lines_.Short()), // |
| LI(lines_.Exactly10Columns())), // |
| LI(lines_.Short())); |
| const auto expected_layout_v = LT(LI(LayoutType::kStack, 0, false), // |
| LI(lines_.Short()), // |
| LI(lines_.Exactly10Columns()), // |
| LI(lines_.Short())); |
| const auto expected_lf = LayoutFunction{ |
| {0, expected_layout_hv, 29, 2.0F, 0}, |
| {11, expected_layout_hv, 29, 2.0F, 100}, |
| {12, expected_layout_v, 19, 4.0F, 0}, |
| {21, expected_layout_v, 19, 4.0F, 200}, |
| {30, expected_layout_v, 19, 1804.0F, 300}, |
| {40, expected_layout_hv, 29, 4802.0F, 200}, |
| }; |
| ExpectLayoutFunctionsEqual(lf, expected_lf, __LINE__); |
| } |
| { |
| const auto lf = factory_.Wrap({ |
| factory_.Line(lines_.OneUnder40Limit()), |
| factory_.Line(lines_.Short()), |
| }); |
| const auto expected_layout_h = |
| LT(LI(LayoutType::kJuxtaposition, 0, true), // |
| LI(lines_.OneUnder40Limit()), // |
| LI(lines_.Short())); |
| const auto expected_layout_v = LT(LI(LayoutType::kStack, 0, true), // |
| LI(lines_.OneUnder40Limit()), // |
| LI(lines_.Short())); |
| const auto expected_lf = LayoutFunction{ |
| {0, expected_layout_v, 19, 2.0F, 0}, |
| {1, expected_layout_v, 19, 2.0F, 100}, |
| {21, expected_layout_v, 19, 2002.0F, 200}, |
| {40, expected_layout_h, 58, 5800.0F, 100}, |
| }; |
| ExpectLayoutFunctionsEqual(lf, expected_lf, __LINE__); |
| } |
| { |
| const auto lf = factory_.Wrap({ |
| factory_.Line(lines_.ExactlyAt40Limit()), |
| factory_.Line(lines_.Short()), |
| }); |
| const auto expected_layout_h = |
| LT(LI(LayoutType::kJuxtaposition, 0, true), // |
| LI(lines_.ExactlyAt40Limit()), // |
| LI(lines_.Short())); |
| const auto expected_layout_v = LT(LI(LayoutType::kStack, 0, true), // |
| LI(lines_.ExactlyAt40Limit()), // |
| LI(lines_.Short())); |
| const auto expected_lf = LayoutFunction{ |
| {0, expected_layout_v, 19, 2.0F, 100}, |
| {21, expected_layout_v, 19, 2102.0F, 200}, |
| {40, expected_layout_h, 59, 5900.0F, 100}, |
| }; |
| ExpectLayoutFunctionsEqual(lf, expected_lf, __LINE__); |
| } |
| { |
| const auto lf = factory_.Wrap({ |
| factory_.Line(lines_.OneOver40Limit()), |
| factory_.Line(lines_.Short()), |
| }); |
| const auto expected_layout_h = |
| LT(LI(LayoutType::kJuxtaposition, 0, true), // |
| LI(lines_.OneOver40Limit()), // |
| LI(lines_.Short())); |
| const auto expected_layout_v = LT(LI(LayoutType::kStack, 0, true), // |
| LI(lines_.OneOver40Limit()), // |
| LI(lines_.Short())); |
| const auto expected_lf = LayoutFunction{ |
| {0, expected_layout_v, 19, 102.0F, 100}, |
| {21, expected_layout_v, 19, 2202.0F, 200}, |
| {40, expected_layout_h, 60, 6000.0F, 100}, |
| }; |
| ExpectLayoutFunctionsEqual(lf, expected_lf, __LINE__); |
| } |
| { |
| const auto lf = factory_.Wrap( |
| { |
| factory_.Line(lines_.OneOver40Limit()), |
| factory_.Line(lines_.Short()), |
| factory_.Line(lines_.Indented()), |
| }, |
| false, 7); |
| const auto expected_layout_vv = |
| LT(LI(LayoutType::kStack, 0, true), // |
| LI(lines_.OneOver40Limit()), // |
| LT(LI(LayoutType::kStack, 0, false, 7), // |
| LI(lines_.Short(), 0), // |
| LI(lines_.Indented(), 0))); |
| const auto expected_layout_vh = |
| LT(LI(LayoutType::kStack, 0, true), // |
| LT(LI(LayoutType::kJuxtaposition, 0, true), // |
| LI(lines_.OneOver40Limit(), 0), // |
| LI(lines_.Short(), 0)), |
| LI(lines_.Indented(), 7)); |
| const auto expected_lf = LayoutFunction{ |
| {0, expected_layout_vv, 43, 404.0F, 200}, |
| {14, expected_layout_vv, 43, 3204.0F, 300}, |
| {33, expected_layout_vh, 43, 8902.0F, 200}, |
| }; |
| ExpectLayoutFunctionsEqual(lf, expected_lf, __LINE__); |
| } |
| } |
| |
| TEST_F(LayoutFunctionFactoryTest, Indent) { |
| using LT = LayoutTree; |
| using LI = LayoutItem; |
| |
| { |
| const auto lf = |
| factory_.Indent(factory_.Line(lines_.Exactly10Columns()), 29); |
| const auto expected_layout = LT(LI(lines_.Exactly10Columns(), 29)); |
| const auto expected_lf = LayoutFunction{ |
| {0, expected_layout, 39, 0.0F, 0}, |
| {1, expected_layout, 39, 0.0F, 100}, |
| }; |
| ExpectLayoutFunctionsEqual(lf, expected_lf, __LINE__); |
| } |
| { |
| const auto lf = |
| factory_.Indent(factory_.Line(lines_.Exactly10Columns()), 30); |
| const auto expected_layout = LT(LI(lines_.Exactly10Columns(), 30)); |
| const auto expected_lf = LayoutFunction{ |
| {0, expected_layout, 40, 0.0F, 100}, |
| }; |
| ExpectLayoutFunctionsEqual(lf, expected_lf, __LINE__); |
| } |
| { |
| const auto lf = |
| factory_.Indent(factory_.Line(lines_.Exactly10Columns()), 31); |
| const auto expected_layout = LT(LI(lines_.Exactly10Columns(), 31)); |
| const auto expected_lf = LayoutFunction{ |
| {0, expected_layout, 41, 100.0F, 100}, |
| }; |
| ExpectLayoutFunctionsEqual(lf, expected_lf, __LINE__); |
| } |
| { |
| const auto lf = factory_.Indent(factory_.Line(lines_.Long()), 5); |
| const auto expected_layout = LT(LI(lines_.Long(), 5)); |
| const auto expected_lf = LayoutFunction{ |
| {0, expected_layout, 55, 1500.0F, 100}, |
| }; |
| ExpectLayoutFunctionsEqual(lf, expected_lf, __LINE__); |
| } |
| } |
| |
| TEST_F(LayoutFunctionFactoryTest, IndentWithOtherCombinators) { |
| using LT = LayoutTree; |
| using LI = LayoutItem; |
| |
| { |
| const auto lf = factory_.Juxtaposition({ |
| factory_.Line(lines_.Exactly10Columns()), |
| factory_.Indent(factory_.Line(joinable_lines_.Exactly10Columns()), 9), |
| factory_.Line(joinable_lines_.Exactly10Columns()), |
| }); |
| const auto expected_layout = |
| LT(LI(LayoutType::kJuxtaposition, 0, true), // |
| LI(lines_.Exactly10Columns(), 0), // |
| LI(joinable_lines_.Exactly10Columns(), 9), // |
| LI(joinable_lines_.Exactly10Columns(), 0)); |
| const auto expected_lf = LayoutFunction{ |
| {0, expected_layout, 39, 0.0F, 0}, |
| {1, expected_layout, 39, 0.0F, 100}, |
| {11, expected_layout, 39, 1000.0F, 100}, |
| {30, expected_layout, 39, 2900.0F, 100}, |
| }; |
| ExpectLayoutFunctionsEqual(lf, expected_lf, __LINE__); |
| } |
| { |
| const auto lf = factory_.Juxtaposition({ |
| factory_.Line(lines_.Exactly10Columns()), |
| factory_.Indent(factory_.Line(joinable_lines_.Exactly10Columns()), 10), |
| factory_.Line(joinable_lines_.Exactly10Columns()), |
| }); |
| const auto expected_layout = |
| LT(LI(LayoutType::kJuxtaposition, 0, true), // |
| LI(lines_.Exactly10Columns(), 0), // |
| LI(joinable_lines_.Exactly10Columns(), 10), // |
| LI(joinable_lines_.Exactly10Columns(), 0)); |
| const auto expected_lf = LayoutFunction{ |
| {0, expected_layout, 40, 0.0F, 100}, |
| {10, expected_layout, 40, 1000.0F, 100}, |
| {30, expected_layout, 40, 3000.0F, 100}, |
| }; |
| ExpectLayoutFunctionsEqual(lf, expected_lf, __LINE__); |
| } |
| { |
| const auto lf = factory_.Juxtaposition({ |
| factory_.Line(lines_.Exactly10Columns()), |
| factory_.Indent(factory_.Line(joinable_lines_.Exactly10Columns()), 11), |
| factory_.Line(joinable_lines_.Exactly10Columns()), |
| }); |
| const auto expected_layout = |
| LT(LI(LayoutType::kJuxtaposition, 0, true), // |
| LI(lines_.Exactly10Columns(), 0), // |
| LI(joinable_lines_.Exactly10Columns(), 11), // |
| LI(joinable_lines_.Exactly10Columns(), 0)); |
| const auto expected_lf = LayoutFunction{ |
| {0, expected_layout, 41, 100.0F, 100}, |
| {9, expected_layout, 41, 1000.0F, 100}, |
| {30, expected_layout, 41, 3100.0F, 100}, |
| }; |
| ExpectLayoutFunctionsEqual(lf, expected_lf, __LINE__); |
| } |
| |
| { |
| const auto lf = factory_.Stack({ |
| factory_.Line(lines_.Exactly10Columns()), |
| factory_.Indent(factory_.Line(lines_.Exactly10Columns()), 29), |
| factory_.Line(lines_.Exactly10Columns()), |
| }); |
| const auto expected_layout = LT(LI(LayoutType::kStack, 0, true), // |
| LI(lines_.Exactly10Columns(), 0), // |
| LI(lines_.Exactly10Columns(), 29), // |
| LI(lines_.Exactly10Columns(), 0)); |
| const auto expected_lf = LayoutFunction{ |
| {0, expected_layout, 10, 4.0F, 0}, |
| {1, expected_layout, 10, 4.0F, 100}, |
| {30, expected_layout, 10, 2904.0F, 300}, |
| }; |
| ExpectLayoutFunctionsEqual(lf, expected_lf, __LINE__); |
| } |
| { |
| const auto lf = factory_.Stack({ |
| factory_.Line(lines_.Exactly10Columns()), |
| factory_.Indent(factory_.Line(lines_.Exactly10Columns()), 30), |
| factory_.Line(lines_.Exactly10Columns()), |
| }); |
| const auto expected_layout = LT(LI(LayoutType::kStack, 0, true), // |
| LI(lines_.Exactly10Columns(), 0), // |
| LI(lines_.Exactly10Columns(), 30), // |
| LI(lines_.Exactly10Columns(), 0)); |
| const auto expected_lf = LayoutFunction{ |
| {0, expected_layout, 10, 4.0F, 100}, |
| {30, expected_layout, 10, 3004.0F, 300}, |
| }; |
| ExpectLayoutFunctionsEqual(lf, expected_lf, __LINE__); |
| } |
| { |
| const auto lf = factory_.Stack({ |
| factory_.Line(lines_.Exactly10Columns()), |
| factory_.Indent(factory_.Line(lines_.Exactly10Columns()), 31), |
| factory_.Line(lines_.Exactly10Columns()), |
| }); |
| const auto expected_layout = LT(LI(LayoutType::kStack, 0, true), // |
| LI(lines_.Exactly10Columns(), 0), // |
| LI(lines_.Exactly10Columns(), 31), // |
| LI(lines_.Exactly10Columns(), 0)); |
| const auto expected_lf = LayoutFunction{ |
| {0, expected_layout, 10, 104.0F, 100}, |
| {30, expected_layout, 10, 3104.0F, 300}, |
| }; |
| ExpectLayoutFunctionsEqual(lf, expected_lf, __LINE__); |
| } |
| |
| { |
| const auto lf = factory_.Wrap({ |
| factory_.Line(lines_.Short()), |
| factory_.Indent(factory_.Line(joinable_lines_.Short()), 1), |
| }); |
| const auto expected_layout_h = |
| LT(LI(LayoutType::kJuxtaposition, 0, false), // |
| LI(lines_.Short(), 0), // |
| LI(joinable_lines_.Short(), 1)); |
| const auto expected_layout_v = LT(LI(LayoutType::kStack, 0, false), // |
| LI(lines_.Short(), 0), // |
| LI(joinable_lines_.Short(), 1)); |
| const auto expected_lf = LayoutFunction{ |
| {0, expected_layout_h, 39, 0.0F, 0}, |
| {1, expected_layout_h, 39, 0.0F, 100}, |
| {2, expected_layout_v, 20, 2.0F, 0}, |
| {20, expected_layout_v, 20, 2.0F, 100}, |
| {21, expected_layout_v, 20, 102.0F, 200}, |
| {40, expected_layout_h, 39, 3900.0F, 100}, |
| }; |
| ExpectLayoutFunctionsEqual(lf, expected_lf, __LINE__); |
| } |
| { |
| const auto lf = factory_.Wrap({ |
| factory_.Line(lines_.Short()), |
| factory_.Indent(factory_.Line(joinable_lines_.Short()), 2), |
| }); |
| const auto expected_layout_h = |
| LT(LI(LayoutType::kJuxtaposition, 0, false), // |
| LI(lines_.Short(), 0), // |
| LI(joinable_lines_.Short(), 2)); |
| const auto expected_layout_v = LT(LI(LayoutType::kStack, 0, false), // |
| LI(lines_.Short(), 0), // |
| LI(joinable_lines_.Short(), 2)); |
| const auto expected_lf = LayoutFunction{ |
| {0, expected_layout_h, 40, 0.0F, 100}, |
| {1, expected_layout_v, 21, 2.0F, 0}, |
| {19, expected_layout_v, 21, 2.0F, 100}, |
| {21, expected_layout_v, 21, 202.0F, 200}, |
| {40, expected_layout_h, 40, 4000.0F, 100}, |
| }; |
| ExpectLayoutFunctionsEqual(lf, expected_lf, __LINE__); |
| } |
| { |
| const auto lf = factory_.Wrap({ |
| factory_.Line(lines_.Short()), |
| factory_.Indent(factory_.Line(joinable_lines_.Short()), 3), |
| }); |
| const auto expected_layout_h = |
| LT(LI(LayoutType::kJuxtaposition, 0, false), // |
| LI(lines_.Short(), 0), // |
| LI(joinable_lines_.Short(), 3)); |
| const auto expected_layout_v = LT(LI(LayoutType::kStack, 0, false), // |
| LI(lines_.Short(), 0), // |
| LI(joinable_lines_.Short(), 3)); |
| const auto expected_lf = LayoutFunction{ |
| {0, expected_layout_v, 22, 2.0F, 0}, |
| {18, expected_layout_v, 22, 2.0F, 100}, |
| {21, expected_layout_v, 22, 302.0F, 200}, |
| {40, expected_layout_h, 41, 4100.0F, 100}, |
| }; |
| ExpectLayoutFunctionsEqual(lf, expected_lf, __LINE__); |
| } |
| |
| { |
| const auto lf = factory_.Wrap({ |
| factory_.Indent(factory_.Line(lines_.Short()), 1), |
| factory_.Line(joinable_lines_.Short()), |
| }); |
| const auto expected_layout_h = |
| LT(LI(LayoutType::kJuxtaposition, 0, false), // |
| LI(lines_.Short(), 1), // |
| LI(joinable_lines_.Short(), 0)); |
| const auto expected_layout_v = LT(LI(LayoutType::kStack, 0, false), // |
| LI(lines_.Short(), 1), // |
| LI(joinable_lines_.Short(), 0)); |
| const auto expected_lf = LayoutFunction{ |
| {0, expected_layout_h, 39, 0.0F, 0}, |
| {1, expected_layout_h, 39, 0.0F, 100}, |
| {2, expected_layout_v, 19, 2.0F, 0}, |
| {20, expected_layout_v, 19, 2.0F, 100}, |
| {21, expected_layout_v, 19, 102.0F, 200}, |
| {40, expected_layout_h, 39, 3900.0F, 100}, |
| }; |
| ExpectLayoutFunctionsEqual(lf, expected_lf, __LINE__); |
| } |
| { |
| const auto lf = factory_.Wrap({ |
| factory_.Indent(factory_.Line(lines_.Short()), 2), |
| factory_.Line(joinable_lines_.Short()), |
| }); |
| const auto expected_layout_h = |
| LT(LI(LayoutType::kJuxtaposition, 0, false), // |
| LI(lines_.Short(), 2), // |
| LI(joinable_lines_.Short(), 0)); |
| const auto expected_layout_v = LT(LI(LayoutType::kStack, 0, false), // |
| LI(lines_.Short(), 2), // |
| LI(joinable_lines_.Short(), 0)); |
| const auto expected_lf = LayoutFunction{ |
| {0, expected_layout_h, 40, 0.0F, 100}, |
| {1, expected_layout_v, 19, 2.0F, 0}, |
| {19, expected_layout_v, 19, 2.0F, 100}, |
| {21, expected_layout_v, 19, 202.0F, 200}, |
| {40, expected_layout_h, 40, 4000.0F, 100}, |
| }; |
| ExpectLayoutFunctionsEqual(lf, expected_lf, __LINE__); |
| } |
| { |
| const auto lf = factory_.Wrap({ |
| factory_.Indent(factory_.Line(lines_.Short()), 3), |
| factory_.Line(joinable_lines_.Short()), |
| }); |
| const auto expected_layout_h = |
| LT(LI(LayoutType::kJuxtaposition, 0, false), // |
| LI(lines_.Short(), 3), // |
| LI(joinable_lines_.Short(), 0)); |
| const auto expected_layout_v = LT(LI(LayoutType::kStack, 0, false), // |
| LI(lines_.Short(), 3), // |
| LI(joinable_lines_.Short(), 0)); |
| const auto expected_lf = LayoutFunction{ |
| {0, expected_layout_v, 19, 2.0F, 0}, |
| {18, expected_layout_v, 19, 2.0F, 100}, |
| {21, expected_layout_v, 19, 302.0F, 200}, |
| {40, expected_layout_h, 41, 4100.0F, 100}, |
| }; |
| ExpectLayoutFunctionsEqual(lf, expected_lf, __LINE__); |
| } |
| } |
| |
| TEST_F(LayoutFunctionFactoryTest, DifferentLayoutsInDifferentSegments) { |
| using LT = LayoutTree; |
| using LI = LayoutItem; |
| |
| const auto juxtaposition_or_wrap = factory_.Choice({ |
| factory_.Juxtaposition({ |
| factory_.Line(joinable_lines_.OneUnder30Limit()), |
| factory_.Line(joinable_lines_.Exactly10Columns()), |
| }), |
| factory_.Stack({ |
| factory_.Line(joinable_lines_.OneUnder30Limit()), |
| factory_.Line(joinable_lines_.Exactly10Columns()), |
| }), |
| }); |
| |
| { |
| const auto expected_layout_h = |
| LT(LI(LayoutType::kJuxtaposition, 0, false), // |
| LI(joinable_lines_.OneUnder30Limit(), 0), // |
| LI(joinable_lines_.Exactly10Columns(), 0)); |
| const auto expected_layout_v = |
| LT(LI(LayoutType::kStack, 0, false), // |
| LI(joinable_lines_.OneUnder30Limit(), 0), // |
| LI(joinable_lines_.Exactly10Columns(), 0)); |
| const auto expected_lf = LayoutFunction{ |
| {0, expected_layout_h, 39, 0.0F, 0}, |
| {1, expected_layout_h, 39, 0.0F, 100}, |
| {2, expected_layout_v, 10, 2.0F, 0}, |
| {11, expected_layout_v, 10, 2.0F, 100}, |
| {30, expected_layout_v, 10, 1902.0F, 200}, |
| {40, expected_layout_h, 39, 3900.0F, 100}, |
| }; |
| ExpectLayoutFunctionsEqual(juxtaposition_or_wrap, expected_lf, __LINE__); |
| } |
| { |
| const auto lf = factory_.Stack({ |
| factory_.Line(joinable_lines_.Short()), |
| juxtaposition_or_wrap, |
| }); |
| const auto expected_layout_h = |
| LT(LI(LayoutType::kStack, 0, false), // |
| LI(joinable_lines_.Short(), 0), // |
| LT(LI(LayoutType::kJuxtaposition, 0, false), // |
| LI(joinable_lines_.OneUnder30Limit(), 0), // |
| LI(joinable_lines_.Exactly10Columns(), 0))); |
| const auto expected_layout_v = |
| LT(LI(LayoutType::kStack, 0, false), // |
| LI(joinable_lines_.Short(), 0), // |
| LI(joinable_lines_.OneUnder30Limit(), 0), // |
| LI(joinable_lines_.Exactly10Columns(), 0)); |
| const auto expected_lf = LayoutFunction{ |
| {0, expected_layout_h, 39, 2.0F, 0}, |
| {1, expected_layout_h, 39, 2.0F, 100}, |
| {2, expected_layout_v, 10, 4.0F, 0}, |
| {11, expected_layout_v, 10, 4.0F, 100}, |
| {21, expected_layout_v, 10, 1004.0F, 200}, |
| {30, expected_layout_v, 10, 2804.0F, 300}, |
| {40, expected_layout_h, 39, 5802.0F, 200}, |
| }; |
| ExpectLayoutFunctionsEqual(lf, expected_lf, __LINE__); |
| } |
| } |
| |
| class TreeReconstructorTest : public ::testing::Test, |
| public UnwrappedLineMemoryHandler { |
| public: |
| TreeReconstructorTest() |
| : sample_("first_line second_line third_line fourth_line"), |
| tokens_(absl::StrSplit(sample_, ' ')) { |
| for (const auto token : tokens_) { |
| ftokens_.emplace_back(TokenInfo{1, token}); |
| } |
| CreateTokenInfos(ftokens_); |
| } |
| |
| protected: |
| const std::string sample_; |
| const std::vector<absl::string_view> tokens_; |
| std::vector<TokenInfo> ftokens_; |
| }; |
| |
| TEST_F(TreeReconstructorTest, SingleLine) { |
| using TPT = TokenPartitionTreeBuilder; |
| using LT = LayoutTree; |
| using LI = LayoutItem; |
| |
| const auto tree_expected = |
| TPT(0, {0, 1}, PartitionPolicyEnum::kAlreadyFormatted) |
| .build(pre_format_tokens_); |
| |
| const auto layout_tree = LT(LI(tree_expected.Value())); |
| |
| auto optimized_tree = TokenPartitionTree(); |
| TreeReconstructor tree_reconstructor(0); |
| tree_reconstructor.TraverseTree(layout_tree); |
| tree_reconstructor.ReplaceTokenPartitionTreeNode(&optimized_tree); |
| |
| EXPECT_PRED_FORMAT2(TokenPartitionTreesEqualPredFormat, optimized_tree, |
| tree_expected); |
| } |
| |
| TEST_F(TreeReconstructorTest, HorizontalLayoutWithOneLine) { |
| using TPT = TokenPartitionTreeBuilder; |
| using LT = LayoutTree; |
| using LI = LayoutItem; |
| |
| const auto tree_expected = |
| TPT(0, {0, 1}, PartitionPolicyEnum::kAlreadyFormatted) |
| .build(pre_format_tokens_); |
| |
| const auto layout_tree = LT(LI(LayoutType::kJuxtaposition, 0, false), |
| LT(LI(tree_expected.Value()))); |
| |
| auto optimized_tree = TokenPartitionTree(); |
| TreeReconstructor tree_reconstructor(0); |
| tree_reconstructor.TraverseTree(layout_tree); |
| tree_reconstructor.ReplaceTokenPartitionTreeNode(&optimized_tree); |
| |
| EXPECT_PRED_FORMAT2(TokenPartitionTreesEqualPredFormat, optimized_tree, |
| tree_expected); |
| } |
| |
| TEST_F(TreeReconstructorTest, HorizontalLayoutSingleLines) { |
| const auto begin = pre_format_tokens_.begin(); |
| |
| UnwrappedLine left_line(0, begin); |
| left_line.SpanUpToToken(begin + 1); |
| UnwrappedLine right_line(0, begin + 1); |
| right_line.SpanUpToToken(begin + 2); |
| UnwrappedLine all(0, left_line.TokensRange().begin()); |
| all.SpanUpToToken(right_line.TokensRange().end()); |
| |
| const auto layout_tree = LayoutTree( |
| LayoutItem(LayoutType::kJuxtaposition, 0, |
| left_line.TokensRange().front().before.break_decision == |
| SpacingOptions::MustWrap), |
| LayoutTree(LayoutItem(left_line)), LayoutTree(LayoutItem(right_line))); |
| |
| TreeReconstructor tree_reconstructor(0); |
| tree_reconstructor.TraverseTree(layout_tree); |
| |
| auto optimized_tree = TokenPartitionTree(UnwrappedLine(0, begin)); |
| tree_reconstructor.ReplaceTokenPartitionTreeNode(&optimized_tree); |
| |
| using Tree = TokenPartitionTree; |
| const Tree tree_expected(all); |
| const auto diff = DeepEqual(optimized_tree, tree_expected, TokenRangeEqual); |
| EXPECT_EQ(diff.left, nullptr) << "Expected:\n" |
| << tree_expected << "\nGot:\n" |
| << optimized_tree << "\n"; |
| } |
| |
| TEST_F(TreeReconstructorTest, EmptyHorizontalLayout) { |
| const auto begin = pre_format_tokens_.begin(); |
| |
| UnwrappedLine upper_line(0, begin); |
| upper_line.SpanUpToToken(begin + 1); |
| UnwrappedLine lower_line(0, begin + 1); |
| lower_line.SpanUpToToken(begin + 2); |
| UnwrappedLine all(0, upper_line.TokensRange().begin()); |
| all.SpanUpToToken(lower_line.TokensRange().end()); |
| |
| const auto layout_tree = |
| LayoutTree(LayoutItem(LayoutType::kJuxtaposition, 0, false), |
| LayoutTree(LayoutItem(upper_line)), |
| LayoutTree(LayoutItem(LayoutType::kJuxtaposition, 0, false)), |
| LayoutTree(LayoutItem(lower_line))); |
| |
| TreeReconstructor tree_reconstructor(0); |
| tree_reconstructor.TraverseTree(layout_tree); |
| |
| auto optimized_tree = TokenPartitionTree{UnwrappedLine(0, begin)}; |
| tree_reconstructor.ReplaceTokenPartitionTreeNode(&optimized_tree); |
| |
| using Tree = TokenPartitionTree; |
| const Tree tree_expected{all}; |
| const auto diff = DeepEqual(optimized_tree, tree_expected, TokenRangeEqual); |
| EXPECT_EQ(diff.left, nullptr) << "Expected:\n" |
| << tree_expected << "\nGot:\n" |
| << optimized_tree << "\n"; |
| } |
| |
| TEST_F(TreeReconstructorTest, VerticalLayoutWithOneLine) { |
| const auto begin = pre_format_tokens_.begin(); |
| |
| UnwrappedLine uwline(0, begin); |
| uwline.SpanUpToToken(begin + 1); |
| |
| const auto layout_tree = LayoutTree(LayoutItem(LayoutType::kStack, 0, false), |
| LayoutTree(LayoutItem(uwline))); |
| |
| TreeReconstructor tree_reconstructor(0); |
| tree_reconstructor.TraverseTree(layout_tree); |
| |
| auto optimized_tree = TokenPartitionTree{UnwrappedLine(0, begin)}; |
| tree_reconstructor.ReplaceTokenPartitionTreeNode(&optimized_tree); |
| |
| using Tree = TokenPartitionTree; |
| const Tree tree_expected{uwline}; |
| const auto diff = DeepEqual(optimized_tree, tree_expected, TokenRangeEqual); |
| EXPECT_EQ(diff.left, nullptr) << "Expected:\n" |
| << tree_expected << "\nGot:\n" |
| << optimized_tree << "\n"; |
| } |
| |
| TEST_F(TreeReconstructorTest, VerticalLayoutSingleLines) { |
| const auto begin = pre_format_tokens_.begin(); |
| |
| UnwrappedLine upper_line(0, begin); |
| upper_line.SpanUpToToken(begin + 1); |
| UnwrappedLine lower_line(0, begin + 1); |
| lower_line.SpanUpToToken(begin + 2); |
| UnwrappedLine all(0, upper_line.TokensRange().begin()); |
| all.SpanUpToToken(lower_line.TokensRange().end()); |
| |
| const auto layout_tree = LayoutTree( |
| LayoutItem(LayoutType::kStack, 0, |
| upper_line.TokensRange().front().before.break_decision == |
| SpacingOptions::MustWrap), |
| LayoutTree(LayoutItem(upper_line)), LayoutTree(LayoutItem(lower_line))); |
| |
| TreeReconstructor tree_reconstructor(0); |
| tree_reconstructor.TraverseTree(layout_tree); |
| |
| auto optimized_tree = TokenPartitionTree{UnwrappedLine(0, begin)}; |
| tree_reconstructor.ReplaceTokenPartitionTreeNode(&optimized_tree); |
| |
| using Tree = TokenPartitionTree; |
| const Tree tree_expected{all, // |
| Tree{upper_line}, // |
| Tree{lower_line}}; |
| const auto diff = DeepEqual(optimized_tree, tree_expected, TokenRangeEqual); |
| EXPECT_EQ(diff.left, nullptr) << "Expected:\n" |
| << tree_expected << "\nGot:\n" |
| << optimized_tree << "\n"; |
| } |
| |
| TEST_F(TreeReconstructorTest, EmptyVerticalLayout) { |
| const auto begin = pre_format_tokens_.begin(); |
| |
| UnwrappedLine upper_line(0, begin); |
| upper_line.SpanUpToToken(begin + 1); |
| UnwrappedLine lower_line(0, begin + 1); |
| lower_line.SpanUpToToken(begin + 2); |
| UnwrappedLine all(0, upper_line.TokensRange().begin()); |
| all.SpanUpToToken(lower_line.TokensRange().end()); |
| |
| const auto layout_tree = |
| LayoutTree(LayoutItem(LayoutType::kStack, 0, false), |
| LayoutTree(LayoutItem(upper_line)), |
| LayoutTree(LayoutItem(LayoutType::kStack, 0, false)), |
| LayoutTree(LayoutItem(lower_line))); |
| |
| TreeReconstructor tree_reconstructor(0); |
| tree_reconstructor.TraverseTree(layout_tree); |
| |
| auto optimized_tree = TokenPartitionTree{UnwrappedLine(0, begin)}; |
| tree_reconstructor.ReplaceTokenPartitionTreeNode(&optimized_tree); |
| |
| using Tree = TokenPartitionTree; |
| const Tree tree_expected{all, // |
| Tree{upper_line}, // |
| Tree{lower_line}}; |
| const auto diff = DeepEqual(optimized_tree, tree_expected, TokenRangeEqual); |
| EXPECT_EQ(diff.left, nullptr) << "Expected:\n" |
| << tree_expected << "\nGot:\n" |
| << optimized_tree << "\n"; |
| } |
| |
| TEST_F(TreeReconstructorTest, VerticallyJoinHorizontalLayouts) { |
| const auto begin = pre_format_tokens_.begin(); |
| |
| UnwrappedLine first_line(0, begin); |
| first_line.SpanUpToToken(begin + 1); |
| UnwrappedLine second_line(0, begin + 1); |
| second_line.SpanUpToToken(begin + 2); |
| UnwrappedLine third_line(0, begin + 2); |
| third_line.SpanUpToToken(begin + 3); |
| UnwrappedLine fourth_line(0, begin + 3); |
| fourth_line.SpanUpToToken(begin + 4); |
| |
| UnwrappedLine upper_line(0, first_line.TokensRange().begin()); |
| upper_line.SpanUpToToken(second_line.TokensRange().end()); |
| UnwrappedLine lower_line(0, third_line.TokensRange().begin()); |
| lower_line.SpanUpToToken(fourth_line.TokensRange().end()); |
| |
| UnwrappedLine all(0, upper_line.TokensRange().begin()); |
| all.SpanUpToToken(lower_line.TokensRange().end()); |
| const LayoutTree layout_tree{ |
| LayoutItem(LayoutType::kStack, 0, false), |
| LayoutTree(LayoutItem(LayoutType::kJuxtaposition, 0, false), |
| LayoutTree(LayoutItem(first_line)), |
| LayoutTree(LayoutItem(second_line))), |
| LayoutTree(LayoutItem(LayoutType::kJuxtaposition, 0, false), |
| LayoutTree(LayoutItem(third_line)), |
| LayoutTree(LayoutItem(fourth_line)))}; |
| |
| TreeReconstructor tree_reconstructor(0); |
| tree_reconstructor.TraverseTree(layout_tree); |
| |
| auto optimized_tree = TokenPartitionTree{UnwrappedLine(0, begin)}; |
| tree_reconstructor.ReplaceTokenPartitionTreeNode(&optimized_tree); |
| |
| using Tree = TokenPartitionTree; |
| const Tree tree_expected{all, // |
| Tree{upper_line}, // |
| Tree{lower_line}}; |
| const auto diff = DeepEqual(optimized_tree, tree_expected, TokenRangeEqual); |
| EXPECT_EQ(diff.left, nullptr) << "Expected:\n" |
| << tree_expected << "\nGot:\n" |
| << optimized_tree << "\n"; |
| } |
| |
| TEST_F(TreeReconstructorTest, HorizontallyJoinVerticalLayouts) { |
| const auto begin = pre_format_tokens_.begin(); |
| |
| UnwrappedLine first_line(0, begin); |
| first_line.SpanUpToToken(begin + 1); |
| UnwrappedLine second_line(0, begin + 1); |
| second_line.SpanUpToToken(begin + 2); |
| UnwrappedLine third_line(0, begin + 2); |
| third_line.SpanUpToToken(begin + 3); |
| UnwrappedLine fourth_line(0, begin + 3); |
| fourth_line.SpanUpToToken(begin + 4); |
| |
| UnwrappedLine upper_line(0, first_line.TokensRange().begin()); |
| upper_line.SpanUpToToken(first_line.TokensRange().end()); |
| UnwrappedLine middle_line(0, second_line.TokensRange().begin()); |
| middle_line.SpanUpToToken(third_line.TokensRange().end()); |
| UnwrappedLine bottom_line(0, fourth_line.TokensRange().begin()); |
| bottom_line.SpanUpToToken(fourth_line.TokensRange().end()); |
| |
| UnwrappedLine all(0, upper_line.TokensRange().begin()); |
| all.SpanUpToToken(bottom_line.TokensRange().end()); |
| |
| const LayoutTree layout_tree{ |
| LayoutItem(LayoutType::kJuxtaposition, 0, false), |
| LayoutTree(LayoutItem(LayoutType::kStack, 0, false), |
| LayoutTree(LayoutItem(first_line)), |
| LayoutTree(LayoutItem(second_line))), |
| LayoutTree(LayoutItem(LayoutType::kStack, 0, false), |
| LayoutTree(LayoutItem(third_line)), |
| LayoutTree(LayoutItem(fourth_line)))}; |
| |
| TreeReconstructor tree_reconstructor(0); |
| tree_reconstructor.TraverseTree(layout_tree); |
| |
| auto optimized_tree = TokenPartitionTree{UnwrappedLine(0, begin)}; |
| tree_reconstructor.ReplaceTokenPartitionTreeNode(&optimized_tree); |
| |
| using Tree = TokenPartitionTree; |
| const Tree tree_expected{all, // |
| Tree{upper_line}, // |
| Tree{middle_line}, // |
| Tree{bottom_line}}; |
| const auto diff = DeepEqual(optimized_tree, tree_expected, TokenRangeEqual); |
| EXPECT_EQ(diff.left, nullptr) << "Expected:\n" |
| << tree_expected << "\nGot:\n" |
| << optimized_tree << "\n"; |
| } |
| |
| TEST_F(TreeReconstructorTest, IndentSingleLine) { |
| const auto begin = pre_format_tokens_.begin(); |
| |
| UnwrappedLine single_line(0, begin); |
| single_line.SpanUpToToken(begin + 1); |
| |
| const auto indent = 7; |
| LayoutTree layout_tree{LayoutItem(single_line)}; |
| layout_tree.Value().SetIndentationSpaces(indent); |
| |
| TreeReconstructor tree_reconstructor(0); |
| tree_reconstructor.TraverseTree(layout_tree); |
| |
| auto optimized_tree = TokenPartitionTree{UnwrappedLine(0, begin)}; |
| tree_reconstructor.ReplaceTokenPartitionTreeNode(&optimized_tree); |
| |
| using Tree = TokenPartitionTree; |
| const Tree tree_expected{single_line}; |
| const auto diff = DeepEqual(optimized_tree, tree_expected, TokenRangeEqual); |
| EXPECT_EQ(diff.left, nullptr) << "Expected:\n" |
| << tree_expected << "\nGot:\n" |
| << optimized_tree << "\n"; |
| |
| EXPECT_EQ(optimized_tree.Value().IndentationSpaces(), indent); |
| } |
| |
| TEST_F(TreeReconstructorTest, InlineSpacingReconstruction) { |
| using TPT = TokenPartitionTreeBuilder; |
| using LT = LayoutTree; |
| using LI = LayoutItem; |
| |
| const auto tree_expected = |
| TPT(1, PartitionPolicyEnum::kAlreadyFormatted, |
| { |
| TPT(0, {0, 1}, PartitionPolicyEnum::kInline), |
| TPT(2, {1, 2}, PartitionPolicyEnum::kInline), |
| TPT(3, {2, 3}, PartitionPolicyEnum::kInline), |
| }) |
| .build(pre_format_tokens_); |
| |
| const auto layout_tree = |
| LT(LI(LayoutType::kJuxtaposition, 1, true), // |
| LT(LI(tree_expected.Children()[0].Value(), true, 1)), // |
| LT(LI(tree_expected.Children()[1].Value())), // |
| LT(LI(tree_expected.Children()[2].Value()))); |
| |
| auto optimized_tree = TokenPartitionTree(); |
| |
| TreeReconstructor tree_reconstructor(0); |
| tree_reconstructor.TraverseTree(layout_tree); |
| tree_reconstructor.ReplaceTokenPartitionTreeNode(&optimized_tree); |
| |
| EXPECT_PRED_FORMAT2(TokenPartitionTreesEqualPredFormat, optimized_tree, |
| tree_expected); |
| } |
| |
| class OptimizeTokenPartitionTreeTest : public ::testing::Test, |
| public UnwrappedLineMemoryHandler { |
| public: |
| OptimizeTokenPartitionTreeTest() |
| : sample_( |
| "function_fffffffffff( type_a_aaaa, " |
| "type_b_bbbbb, type_c_cccccc, " |
| "type_d_dddddddd, type_e_eeeeeeee, type_f_ffff); " |
| "seven eight nine ten eleven twelve"), |
| tokens_(absl::StrSplit(sample_, ' ')) { |
| for (const auto token : tokens_) { |
| ftokens_.emplace_back(TokenInfo{1, token}); |
| } |
| CreateTokenInfos(ftokens_); |
| } |
| |
| protected: |
| const std::string sample_; |
| const std::vector<absl::string_view> tokens_; |
| std::vector<TokenInfo> ftokens_; |
| }; |
| |
| TEST_F(OptimizeTokenPartitionTreeTest, AppendToLineWithInlinePartitions) { |
| using TPT = TokenPartitionTreeBuilder; |
| using PP = PartitionPolicyEnum; |
| |
| auto tree = TPT(PP::kFitOnLineElseExpand, |
| { |
| TPT(PP::kAlreadyFormatted, |
| { |
| TPT(1, {7, 8}, PP::kInline), |
| TPT(3, {8, 9}, PP::kInline), |
| TPT(5, {9, 10}, PP::kInline), |
| }), |
| TPT(PP::kAlwaysExpand, |
| { |
| TPT({10, 11}, PP::kFitOnLineElseExpand), |
| TPT({11, 12}, PP::kFitOnLineElseExpand), |
| TPT({12, 13}, PP::kFitOnLineElseExpand), |
| }), |
| }) |
| .build(pre_format_tokens_); |
| |
| const auto expected_tree = TPT(PP::kAlwaysExpand, |
| { |
| TPT(1, PP::kAlreadyFormatted, |
| { |
| TPT(0, {7, 8}, PP::kInline), |
| TPT(3, {8, 9}, PP::kInline), |
| TPT(5, {9, 11}, PP::kInline), |
| }), |
| TPT(23, {11, 12}, PP::kAlreadyFormatted), |
| TPT(23, {12, 13}, PP::kAlreadyFormatted), |
| }) |
| .build(pre_format_tokens_); |
| |
| static const BasicFormatStyle style = CreateStyle(); |
| OptimizeTokenPartitionTree(style, &tree); |
| |
| EXPECT_PRED_FORMAT2(TokenPartitionTreesEqualPredFormat, tree, expected_tree); |
| } |
| |
| class TokenPartitionsLayoutOptimizerTest : public ::testing::Test, |
| public UnwrappedLineMemoryHandler { |
| public: |
| TokenPartitionsLayoutOptimizerTest() |
| : sample_( |
| // : |10 : |20 : |30 : |40 |
| "one two three four\n" |
| "eleven twelve thirteen fourteen\n"), |
| tokens_( |
| absl::StrSplit(sample_, absl::ByAnyChar(" \n"), absl::SkipEmpty())), |
| style_(CreateStyle()), |
| factory_(LayoutFunctionFactory(style_)) { |
| for (const auto token : tokens_) { |
| ftokens_.emplace_back(TokenInfo{1, token}); |
| } |
| CreateTokenInfosExternalStringBuffer(ftokens_); |
| ConnectPreFormatTokensPreservedSpaceStarts(sample_.data(), |
| &pre_format_tokens_); |
| |
| // Set token properties |
| for (auto token_it = pre_format_tokens_.begin(); |
| token_it != pre_format_tokens_.end(); ++token_it) { |
| const auto leading_spaces = token_it->OriginalLeadingSpaces(); |
| |
| // First token in a line |
| if (absl::StrContains(leading_spaces, '\n')) { |
| token_it->before.break_decision = SpacingOptions::MustWrap; |
| auto last_non_space_offset = leading_spaces.find_last_not_of(' '); |
| if (last_non_space_offset != absl::string_view::npos) { |
| token_it->before.spaces_required = |
| leading_spaces.size() - 1 - last_non_space_offset; |
| } |
| } else { |
| token_it->before.spaces_required = leading_spaces.size(); |
| } |
| } |
| pre_format_tokens_.front().before.break_decision = SpacingOptions::MustWrap; |
| } |
| |
| protected: |
| const std::string sample_; |
| const std::vector<absl::string_view> tokens_; |
| std::vector<TokenInfo> ftokens_; |
| const BasicFormatStyle style_; |
| const LayoutFunctionFactory factory_; |
| }; |
| |
| TEST_F(TokenPartitionsLayoutOptimizerTest, CalculateOptimalLayout) { |
| using TPT = TokenPartitionTreeBuilder; |
| using PP = PartitionPolicyEnum; |
| using LT = LayoutTree; |
| using LI = LayoutItem; |
| |
| const auto optimizer = TokenPartitionsLayoutOptimizer(style_); |
| |
| { |
| const auto tree = TPT(4, PP::kAlwaysExpand, |
| { |
| TPT(4, {0, 1}), |
| TPT(4, {1, 2}), |
| TPT(4, {2, 3}), |
| }) |
| .build(pre_format_tokens_); |
| |
| const auto expected_layout = LT(LI(LayoutType::kStack, 0, true), // |
| LT(LI(tree.Children()[0].Value())), // |
| LT(LI(tree.Children()[1].Value())), // |
| LT(LI(tree.Children()[2].Value()))); |
| const auto expected_lf = LayoutFunction{ |
| {0, expected_layout, 5, 4.0F, 0}, |
| {35, expected_layout, 5, 4.0F, 100}, |
| {37, expected_layout, 5, 204.0F, 300}, |
| }; |
| |
| const LayoutFunction lf = optimizer.CalculateOptimalLayout(tree); |
| ExpectLayoutFunctionsEqual(lf, expected_lf, __LINE__); |
| } |
| { |
| const auto tree = TPT(PP::kAlwaysExpand, |
| { |
| TPT(1, {0, 1}), |
| TPT(2, {1, 2}), |
| TPT(3, {2, 3}), |
| }) |
| .build(pre_format_tokens_); |
| |
| const auto expected_layout = LT(LI(LayoutType::kStack, 0, true), // |
| LT(LI(tree.Children()[0].Value(), 1)), // |
| LT(LI(tree.Children()[1].Value(), 2)), // |
| LT(LI(tree.Children()[2].Value(), 3))); |
| const auto expected_lf = LayoutFunction{ |
| {0, expected_layout, 8, 4.0F, 0}, |
| {32, expected_layout, 8, 4.0F, 100}, |
| {35, expected_layout, 8, 304.0F, 200}, |
| {36, expected_layout, 8, 504.0F, 300}, |
| }; |
| |
| const LayoutFunction lf = optimizer.CalculateOptimalLayout(tree); |
| ExpectLayoutFunctionsEqual(lf, expected_lf, __LINE__); |
| } |
| { |
| const auto tree = TPT(2, PP::kTabularAlignment, |
| { |
| TPT(2, {0, 1}, PP::kAlreadyFormatted), |
| TPT(2, {1, 2}, PP::kAlreadyFormatted), |
| TPT(2, {2, 3}, PP::kAlreadyFormatted), |
| }) |
| .build(pre_format_tokens_); |
| |
| const auto expected_layout = LT(LI(LayoutType::kStack, 0, true), // |
| LT(LI(tree.Children()[0].Value())), // |
| LT(LI(tree.Children()[1].Value())), // |
| LT(LI(tree.Children()[2].Value()))); |
| const auto expected_lf = LayoutFunction{ |
| {0, expected_layout, 5, 4.0F, 0}, |
| {35, expected_layout, 5, 4.0F, 100}, |
| {37, expected_layout, 5, 204.0F, 300}, |
| }; |
| |
| const LayoutFunction lf = optimizer.CalculateOptimalLayout(tree); |
| ExpectLayoutFunctionsEqual(lf, expected_lf, __LINE__); |
| } |
| { |
| const auto tree = TPT(PP::kTabularAlignment, |
| { |
| TPT(1, {0, 1}, PP::kAlreadyFormatted), |
| TPT(2, {1, 2}, PP::kAlreadyFormatted), |
| TPT(3, {2, 3}, PP::kAlreadyFormatted), |
| }) |
| .build(pre_format_tokens_); |
| |
| const auto expected_layout = LT(LI(LayoutType::kStack, 0, true), // |
| LT(LI(tree.Children()[0].Value(), 1)), // |
| LT(LI(tree.Children()[1].Value(), 2)), // |
| LT(LI(tree.Children()[2].Value(), 3))); |
| const auto expected_lf = LayoutFunction{ |
| {0, expected_layout, 8, 4.0F, 0}, |
| {32, expected_layout, 8, 4.0F, 100}, |
| {35, expected_layout, 8, 304.0F, 200}, |
| {36, expected_layout, 8, 504.0F, 300}, |
| }; |
| |
| const LayoutFunction lf = optimizer.CalculateOptimalLayout(tree); |
| ExpectLayoutFunctionsEqual(lf, expected_lf, __LINE__); |
| } |
| { |
| const auto tree = TPT(PP::kAppendFittingSubPartitions, |
| { |
| TPT(3, {0, 4}), |
| TPT(5, {4, 8}), |
| }) |
| .build(pre_format_tokens_); |
| |
| const auto expected_layout = LT(LI(LayoutType::kStack, 0, true), // |
| LT(LI(tree.Children()[0].Value())), // |
| LT(LI(tree.Children()[1].Value()))); |
| const auto expected_lf = LayoutFunction{ |
| {0, expected_layout, 31, 2.0F, 0}, |
| {9, expected_layout, 31, 2.0F, 100}, |
| {22, expected_layout, 31, 1302.0F, 200}, |
| }; |
| |
| const LayoutFunction lf = optimizer.CalculateOptimalLayout(tree); |
| ExpectLayoutFunctionsEqual(lf, expected_lf, __LINE__); |
| } |
| { |
| const auto tree = TPT(PP::kFitOnLineElseExpand, |
| { |
| TPT(3, {0, 4}), |
| TPT(5, {4, 8}), |
| }) |
| .build(pre_format_tokens_); |
| |
| const auto expected_layout = LT(LI(LayoutType::kStack, 0, true), // |
| LT(LI(tree.Children()[0].Value())), // |
| LT(LI(tree.Children()[1].Value()))); |
| const auto expected_lf = LayoutFunction{ |
| {0, expected_layout, 31, 2.0F, 0}, |
| {9, expected_layout, 31, 2.0F, 100}, |
| {22, expected_layout, 31, 1302.0F, 200}, |
| }; |
| |
| const LayoutFunction lf = optimizer.CalculateOptimalLayout(tree); |
| ExpectLayoutFunctionsEqual(lf, expected_lf, __LINE__); |
| } |
| { |
| const auto tree = TPT(PP::kAlreadyFormatted, |
| { |
| TPT(3, {0, 1}, PP::kInline), |
| TPT(5, {1, 2}, PP::kInline), |
| TPT(7, {2, 4}, PP::kInline), |
| }) |
| .build(pre_format_tokens_); |
| |
| const auto expected_layout = |
| LT(LI(LayoutType::kJuxtaposition, 3, true), |
| LT(LI(tree.Children()[0].Value(), true, 3)), |
| LT(LI(tree.Children()[1].Value(), false, 0)), |
| LT(LI(tree.Children()[2].Value(), false, 0))); |
| |
| const auto expected_lf = LayoutFunction{ |
| {0, expected_layout, 31, 0.0, 0}, |
| {9, expected_layout, 31, 0.0, 100}, |
| {26, expected_layout, 31, 1000.0, 100}, |
| {34, expected_layout, 31, 1300.0, 100}, |
| }; |
| |
| const LayoutFunction lf = optimizer.CalculateOptimalLayout(tree); |
| ExpectLayoutFunctionsEqual(lf, expected_lf, __LINE__); |
| } |
| } |
| |
| } // namespace |
| } // namespace verible |