blob: 51909601d8634d84b87bb0403d98c7a3d4ef6100 [file] [log] [blame]
// Copyright 2017-2022 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/util/tree_operations.h"
#include <charconv>
#include <initializer_list>
#include <list>
#include <string>
#include <vector>
#include "absl/strings/str_cat.h"
#include "absl/strings/str_format.h"
#include "absl/strings/str_join.h"
#include "absl/strings/string_view.h"
#include "common/util/spacer.h"
#include "gmock/gmock.h"
#include "gtest/gtest.h"
namespace verible {
namespace {
// Recursively verifies two trees.
// Not intended for direct use - use the other VerifyTree with
// EXPECT_PRED_FORMAT2 instead.
template <typename T>
testing::AssertionResult VerifyTree(const T& actual, const T& expected,
const std::vector<size_t>& path) {
const bool id_ok = actual.id() == expected.id();
const bool children_count_ok =
actual.Children().size() == expected.Children().size();
if (!id_ok || !children_count_ok) {
auto err = testing::AssertionFailure();
err << "Node mismatch at path: {"
<< absl::StrJoin(path.begin(), path.end(), ",") << "}\n";
if (!id_ok) {
err << "Invalid ID:\n"
<< " Actual: \"" << actual.id() << "\"\n"
<< " Expected: \"" << expected.id() << "\"\n";
}
if (!children_count_ok) {
err << "Invalid Children count:\n"
<< " Actual: " << actual.Children().size() << "\n"
<< " Expected: " << expected.Children().size() << "\n";
}
return err;
}
if (actual.Children().size() != 0) {
auto actual_child = actual.Children().begin();
auto expected_child = expected.Children().begin();
auto child_path = path;
child_path.push_back(0);
for (size_t i = 0; i < actual.Children().size(); ++i) {
const auto result =
VerifyTree(*actual_child, *expected_child, child_path);
if (!result) return result;
++actual_child;
++expected_child;
++child_path.back();
}
}
return testing::AssertionSuccess();
}
// Recursively verifies two trees.
// This verification function is intended for use with EXPECT_PRED_FORMAT2.
template <typename T>
testing::AssertionResult VerifyTree(const char* actual_expr,
const char* expected_expr, const T& actual,
const T& expected) {
auto result = VerifyTree(actual, expected, {});
if (!result) {
result << "\n"
<< "Actual tree:\n"
<< actual << "\n"
<< "Expected tree:\n"
<< expected << "\n";
}
return result;
}
// Alias to `ThisType` if `Derived` is void; alias to `Derived` otherwise.
template <class Derived, class ThisType>
using DerivedOrThis =
std::conditional_t<std::is_void_v<Derived>, ThisType, Derived>;
// Definitions of sample tree node types:
template <template <class...> class Container, class Derived = void>
class SimpleNode {
using ThisType = DerivedOrThis<Derived, SimpleNode<Container, Derived>>;
public:
using ChildrenType = Container<ThisType>;
SimpleNode(absl::string_view id, ChildrenType&& children = {})
: children_(std::move(children)), id_(id) {
Relink();
}
ChildrenType& Children() { return children_; }
const ChildrenType& Children() const { return children_; }
// Debug/test functions:
const std::string& id() const { return id_; }
void set_id(std::string&& new_id) { id_ = new_id; }
bool operator==(const ThisType& other) const { return this == &other; }
friend std::ostream& operator<<(std::ostream& stream, const ThisType& self) {
self.PrintRecursively(stream, 0);
return stream;
}
friend std::ostream& operator<<(std::ostream& stream,
const ThisType* self_ptr) {
if (self_ptr == nullptr) {
return stream << "nullptr";
}
return stream << absl::StreamFormat("%p (%s; parent=%p)\n", self_ptr,
self_ptr->id_, self_ptr->parent_);
}
// Updates parent pointers in children.
void Relink() {
for (auto& child : children_) {
child.Relink();
child.parent_ = static_cast<ThisType*>(this);
}
}
protected:
void PrintRecursively(std::ostream& stream, int depth = 0) const {
stream << verible::Spacer(4 * depth)
<< absl::StreamFormat("@%p (%s; parent=%p)\n",
static_cast<const ThisType*>(this), id_,
parent_);
for (const auto& child : Children()) {
child.PrintRecursively(stream, depth + 1);
}
}
ChildrenType children_;
std::string id_; // Exposed in subclasses as value
ThisType* parent_ = nullptr; // Exposed in subclasses
};
template <template <class...> class Container, class Derived = void>
class NodeWithValue
: public SimpleNode<
Container,
DerivedOrThis<Derived, NodeWithValue<Container, Derived>>> {
using ThisType = DerivedOrThis<Derived, NodeWithValue>;
using Base = SimpleNode<Container, ThisType>;
public:
using Base::Base;
using typename Base::ChildrenType;
std::string& Value() { return this->id_; }
const std::string& Value() const { return this->id_; }
};
template <template <class...> class Container, class Derived = void>
class NodeWithParent
: public SimpleNode<
Container,
DerivedOrThis<Derived, NodeWithParent<Container, Derived>>> {
using ThisType = DerivedOrThis<Derived, NodeWithParent>;
using Base = SimpleNode<Container, ThisType>;
public:
using Base::Base;
using typename Base::ChildrenType;
ThisType* Parent() { return this->parent_; }
const ThisType* Parent() const { return this->parent_; }
};
template <template <class...> class Container, class Derived = void>
class NodeWithParentAndValue
: public NodeWithParent<
Container,
DerivedOrThis<Derived, NodeWithParentAndValue<Container, Derived>>> {
using ThisType = DerivedOrThis<Derived, NodeWithParentAndValue>;
using Base = NodeWithParent<Container, ThisType>;
public:
using Base::Base;
using typename Base::ChildrenType;
std::string& Value() { return this->id_; }
const std::string& Value() const { return this->id_; }
};
// "Other" node type. Has different value type and is not related to other test
// trees.
class IntNode {
public:
IntNode() {}
IntNode(int value, std::initializer_list<IntNode> children = {})
: value_(value), children_(children) {}
const int& Value() const { return value_; }
const std::vector<IntNode>& Children() const { return children_; }
std::vector<IntNode>& Children() { return children_; }
const int& id() const { return value_; }
friend std::ostream& operator<<(std::ostream& stream, const IntNode& self) {
self.PrintRecursively(stream, 0);
return stream;
}
friend std::ostream& operator<<(std::ostream& stream,
const IntNode* self_ptr) {
if (self_ptr == nullptr) {
return stream << "nullptr";
}
return stream << absl::StreamFormat("%p (%d)\n", self_ptr,
self_ptr->value_);
}
private:
void PrintRecursively(std::ostream& stream, int depth = 0) const {
stream << verible::Spacer(4 * depth)
<< absl::StreamFormat("@%p (%d)\n", this, value_);
for (const auto& child : Children()) {
child.PrintRecursively(stream, depth + 1);
}
}
int value_;
std::vector<IntNode> children_;
};
// Test suites:
template <class Node>
class TreeTest : public ::testing::Test {
public:
TreeTest() {}
using N = Node;
N root = N("root", {N("0"), //
N("1", {N("1.0")}), //
N("2", {N("2.0", {N("2.0.0")}), //
N("2.1", {N("2.1.0")})}), //
N("3", {N("3.0", {N("3.0.0", {N("3.0.0.0")}), //
N("3.0.1", {N("3.0.1.0")})}), //
N("3.1", {N("3.1.0", {N("3.1.0.0")}), //
N("3.1.1", {N("3.1.1.0")})}), //
N("3.2", {N("3.2.0", {N("3.2.0.0")}), //
N("3.2.1", {N("3.2.1.0")})})})});
Node& NodeAt(std::initializer_list<size_t> child_indexes) {
Node* subnode = &root;
for (auto index : child_indexes) {
CHECK_GE(index, 0);
CHECK_LT(index, subnode->Children().size());
subnode = &*std::next(subnode->Children().begin(), index);
}
return *subnode;
}
};
template <class Node>
class SimpleNodeTest : public TreeTest<Node> {};
using SimpleNodeTestTypes =
::testing::Types<SimpleNode<std::vector>, //
NodeWithValue<std::vector>, //
NodeWithParent<std::vector>, //
NodeWithParentAndValue<std::vector>, //
SimpleNode<std::list>, //
NodeWithValue<std::list>, //
NodeWithParent<std::list>, //
NodeWithParentAndValue<std::list>, //
const SimpleNode<std::vector>, //
const NodeWithValue<std::vector>, //
const NodeWithParent<std::vector>, //
const NodeWithParentAndValue<std::vector>, //
const SimpleNode<std::list>, //
const NodeWithValue<std::list>, //
const NodeWithParent<std::list>, //
const NodeWithParentAndValue<std::list>>;
TYPED_TEST_SUITE(SimpleNodeTest, SimpleNodeTestTypes);
template <class Node>
class NodeWithValueTest : public TreeTest<Node> {};
using NodeWithValueTestTypes =
::testing::Types<NodeWithValue<std::vector>, //
NodeWithParentAndValue<std::vector>, //
NodeWithValue<std::list>, //
NodeWithParentAndValue<std::list>, //
const NodeWithValue<std::vector>, //
const NodeWithParentAndValue<std::vector>, //
const NodeWithValue<std::list>, //
const NodeWithParentAndValue<std::list>>;
TYPED_TEST_SUITE(NodeWithValueTest, NodeWithValueTestTypes);
template <class Node>
class NodeWithParentTest : public TreeTest<Node> {};
using NodeWithParentTestTypes =
::testing::Types<NodeWithParent<std::vector>, //
NodeWithParentAndValue<std::vector>, //
NodeWithParent<std::list>, //
NodeWithParentAndValue<std::list>, //
const NodeWithParent<std::vector>, //
const NodeWithParentAndValue<std::vector>, //
const NodeWithParent<std::list>, //
const NodeWithParentAndValue<std::list>>;
TYPED_TEST_SUITE(NodeWithParentTest, NodeWithParentTestTypes);
template <class Node>
class NodeWithParentAndValueTest : public TreeTest<Node> {};
using NodeWithParentAndValueTestTypes =
::testing::Types<NodeWithParentAndValue<std::vector>, //
NodeWithParentAndValue<std::list>, //
const NodeWithParentAndValue<std::vector>, //
const NodeWithParentAndValue<std::list>>;
TYPED_TEST_SUITE(NodeWithParentAndValueTest, NodeWithParentAndValueTestTypes);
// Tests:
TEST(Misc, TreeNodeTraits) {
struct NodeWithCustomContainerType {
using subnodes_type = std::initializer_list<NodeWithCustomContainerType>;
const std::vector<NodeWithCustomContainerType>& Children() const {
return children_;
}
private:
std::vector<NodeWithCustomContainerType> children_;
};
{
using Traits = TreeNodeTraits<NodeWithCustomContainerType>;
static_assert(Traits::available == true);
static_assert(Traits::Children::available == true);
static_assert(
std::is_same_v<typename Traits::Children::container_type,
std::initializer_list<NodeWithCustomContainerType>>);
}
{
using Traits = TreeNodeTraits<const NodeWithCustomContainerType>;
static_assert(Traits::available == true);
static_assert(Traits::Children::available == true);
static_assert(
std::is_same_v<typename Traits::Children::container_type,
std::initializer_list<NodeWithCustomContainerType>>);
}
}
TYPED_TEST(SimpleNodeTest, TreeNodeTraits) {
// This test passes if it compiles without errors.
using Traits = TreeNodeTraits<TypeParam>;
static_assert(Traits::available == true);
static_assert(Traits::Children::available == true);
static_assert(std::is_same_v<typename Traits::Children::container_type,
typename TypeParam::ChildrenType>);
}
TYPED_TEST(NodeWithValueTest, TreeNodeTraits) {
// This test passes if it compiles without errors.
using Traits = TreeNodeTraits<TypeParam>;
static_assert(Traits::Value::available == true);
static_assert(std::is_same_v<typename Traits::Value::type, std::string>);
static_assert(
std::is_same_v<typename Traits::Value::reference,
verible::match_const_t<std::string, TypeParam>&>);
static_assert(std::is_same_v<typename Traits::Value::const_reference,
const std::string&>);
}
TYPED_TEST(NodeWithParentTest, TreeNodeTraits) {
// This test passes if it compiles without errors.
using Traits = TreeNodeTraits<TypeParam>;
static_assert(Traits::Parent::available == true);
}
TYPED_TEST(SimpleNodeTest, is_leaf) {
EXPECT_FALSE(is_leaf(this->root));
EXPECT_TRUE(is_leaf(this->NodeAt({0})));
EXPECT_FALSE(is_leaf(this->NodeAt({1})));
EXPECT_TRUE(is_leaf(this->NodeAt({1, 0})));
EXPECT_FALSE(is_leaf(this->NodeAt({2})));
EXPECT_FALSE(is_leaf(this->NodeAt({2, 0})));
EXPECT_TRUE(is_leaf(this->NodeAt({2, 0, 0})));
EXPECT_FALSE(is_leaf(this->NodeAt({2, 1})));
EXPECT_TRUE(is_leaf(this->NodeAt({2, 1, 0})));
EXPECT_FALSE(is_leaf(this->NodeAt({3})));
EXPECT_FALSE(is_leaf(this->NodeAt({3, 0})));
EXPECT_FALSE(is_leaf(this->NodeAt({3, 0, 0})));
EXPECT_TRUE(is_leaf(this->NodeAt({3, 0, 0, 0})));
EXPECT_FALSE(is_leaf(this->NodeAt({3, 0, 1})));
EXPECT_TRUE(is_leaf(this->NodeAt({3, 0, 1, 0})));
}
TYPED_TEST(SimpleNodeTest, DescendPath) {
{
const std::vector<size_t> path = {0};
EXPECT_EQ(DescendPath(this->root, path.begin(), path.end()),
this->NodeAt({0}));
}
{
const std::vector<size_t> path = {1, 0};
EXPECT_EQ(DescendPath(this->root, path.begin(), path.end()),
this->NodeAt({1, 0}));
}
{
const std::vector<size_t> path = {1};
EXPECT_EQ(DescendPath(this->NodeAt({2}), path.begin(), path.end()),
this->NodeAt({2, 1}));
}
}
TYPED_TEST(SimpleNodeTest, LeftmostDescendant) {
EXPECT_EQ(LeftmostDescendant(this->root), this->root.Children().front());
EXPECT_EQ(LeftmostDescendant(this->root.Children().back()),
this->NodeAt({3, 0, 0, 0}));
EXPECT_EQ(LeftmostDescendant(this->NodeAt({2, 1, 0})),
this->NodeAt({2, 1, 0}));
}
TYPED_TEST(SimpleNodeTest, RightmostDescendant) {
EXPECT_EQ(RightmostDescendant(this->root), this->NodeAt({3, 2, 1, 0}));
EXPECT_EQ(RightmostDescendant(this->root.Children().back()),
this->NodeAt({3, 2, 1, 0}));
EXPECT_EQ(RightmostDescendant(this->NodeAt({2, 1, 0})),
this->NodeAt({2, 1, 0}));
}
TYPED_TEST(SimpleNodeTest, ApplyPreOrderWithNode) {
using NodeRef = std::add_lvalue_reference_t<TypeParam>;
{
static const std::vector<std::string> expected_visited_values = {
"root", "0", "1", "1.0", "2", "2.0", "2.0.0",
"2.1", "2.1.0", "3", "3.0", "3.0.0", "3.0.0.0", "3.0.1",
"3.0.1.0", "3.1", "3.1.0", "3.1.0.0", "3.1.1", "3.1.1.0", "3.2",
"3.2.0", "3.2.0.0", "3.2.1", "3.2.1.0"};
std::vector<std::string> visited_values;
ApplyPreOrder(this->root,
[&](NodeRef node) { visited_values.push_back(node.id()); });
EXPECT_EQ(visited_values, expected_visited_values);
}
// Test for mutable nodes only
if constexpr (!std::is_const_v<TypeParam>) {
// Modify
ApplyPreOrder(this->root, [&](NodeRef node) {
node.set_id(absl::StrCat(node.id(), "-new"));
});
// Verify
static const std::vector<std::string> expected_visited_values = {
"root-new", "0-new", "1-new", "1.0-new", "2-new",
"2.0-new", "2.0.0-new", "2.1-new", "2.1.0-new", "3-new",
"3.0-new", "3.0.0-new", "3.0.0.0-new", "3.0.1-new", "3.0.1.0-new",
"3.1-new", "3.1.0-new", "3.1.0.0-new", "3.1.1-new", "3.1.1.0-new",
"3.2-new", "3.2.0-new", "3.2.0.0-new", "3.2.1-new", "3.2.1.0-new"};
std::vector<std::string> visited_values;
ApplyPreOrder(this->root,
[&](NodeRef node) { visited_values.push_back(node.id()); });
EXPECT_EQ(visited_values, expected_visited_values);
}
}
TYPED_TEST(SimpleNodeTest, ApplyPostOrderWithNode) {
using NodeRef = std::add_lvalue_reference_t<TypeParam>;
{
static const std::vector<std::string> expected_visited_values = {
"0", "1.0", "1", "2.0.0", "2.0", "2.1.0", "2.1",
"2", "3.0.0.0", "3.0.0", "3.0.1.0", "3.0.1", "3.0", "3.1.0.0",
"3.1.0", "3.1.1.0", "3.1.1", "3.1", "3.2.0.0", "3.2.0", "3.2.1.0",
"3.2.1", "3.2", "3", "root"};
std::vector<std::string> visited_values;
ApplyPostOrder(this->root,
[&](NodeRef node) { visited_values.push_back(node.id()); });
EXPECT_EQ(visited_values, expected_visited_values);
}
// Test for mutable nodes only
if constexpr (!std::is_const_v<TypeParam>) {
// Modify
ApplyPostOrder(this->root, [&](NodeRef node) {
node.set_id(absl::StrCat(node.id(), "-new"));
});
// Verify
static const std::vector<std::string> expected_visited_values = {
"0-new", "1.0-new", "1-new", "2.0.0-new", "2.0-new",
"2.1.0-new", "2.1-new", "2-new", "3.0.0.0-new", "3.0.0-new",
"3.0.1.0-new", "3.0.1-new", "3.0-new", "3.1.0.0-new", "3.1.0-new",
"3.1.1.0-new", "3.1.1-new", "3.1-new", "3.2.0.0-new", "3.2.0-new",
"3.2.1.0-new", "3.2.1-new", "3.2-new", "3-new", "root-new"};
std::vector<std::string> visited_values;
ApplyPostOrder(this->root,
[&](NodeRef node) { visited_values.push_back(node.id()); });
EXPECT_EQ(visited_values, expected_visited_values);
}
}
TYPED_TEST(NodeWithValueTest, ApplyPreOrderWithValue) {
{
static const std::vector<std::string> expected_visited_values = {
"root", "0", "1", "1.0", "2", "2.0", "2.0.0",
"2.1", "2.1.0", "3", "3.0", "3.0.0", "3.0.0.0", "3.0.1",
"3.0.1.0", "3.1", "3.1.0", "3.1.0.0", "3.1.1", "3.1.1.0", "3.2",
"3.2.0", "3.2.0.0", "3.2.1", "3.2.1.0"};
std::vector<std::string> visited_values;
ApplyPreOrder(this->root, [&](const std::string& value) {
visited_values.push_back(value);
});
EXPECT_EQ(visited_values, expected_visited_values);
}
// Test for mutable nodes only
if constexpr (!std::is_const_v<TypeParam>) {
// Modify
ApplyPreOrder(this->root,
[&](std::string& value) { absl::StrAppend(&value, "-new"); });
// Verify
static const std::vector<std::string> expected_visited_values = {
"root-new", "0-new", "1-new", "1.0-new", "2-new",
"2.0-new", "2.0.0-new", "2.1-new", "2.1.0-new", "3-new",
"3.0-new", "3.0.0-new", "3.0.0.0-new", "3.0.1-new", "3.0.1.0-new",
"3.1-new", "3.1.0-new", "3.1.0.0-new", "3.1.1-new", "3.1.1.0-new",
"3.2-new", "3.2.0-new", "3.2.0.0-new", "3.2.1-new", "3.2.1.0-new"};
std::vector<std::string> visited_values;
ApplyPreOrder(this->root, [&](const std::string& value) {
visited_values.push_back(value);
});
EXPECT_EQ(visited_values, expected_visited_values);
}
}
TYPED_TEST(NodeWithValueTest, ApplyPostOrderWithValue) {
{
static const std::vector<std::string> expected_visited_values = {
"0", "1.0", "1", "2.0.0", "2.0", "2.1.0", "2.1",
"2", "3.0.0.0", "3.0.0", "3.0.1.0", "3.0.1", "3.0", "3.1.0.0",
"3.1.0", "3.1.1.0", "3.1.1", "3.1", "3.2.0.0", "3.2.0", "3.2.1.0",
"3.2.1", "3.2", "3", "root"};
std::vector<std::string> visited_values;
ApplyPostOrder(this->root, [&](const std::string& value) {
visited_values.push_back(value);
});
EXPECT_EQ(visited_values, expected_visited_values);
}
// Test for mutable nodes only
if constexpr (!std::is_const_v<TypeParam>) {
// Modify
ApplyPostOrder(this->root, [&](std::string& value) {
absl::StrAppend(&value, "-new");
});
// Verify
static const std::vector<std::string> expected_visited_values = {
"0-new", "1.0-new", "1-new", "2.0.0-new", "2.0-new",
"2.1.0-new", "2.1-new", "2-new", "3.0.0.0-new", "3.0.0-new",
"3.0.1.0-new", "3.0.1-new", "3.0-new", "3.1.0.0-new", "3.1.0-new",
"3.1.1.0-new", "3.1.1-new", "3.1-new", "3.2.0.0-new", "3.2.0-new",
"3.2.1.0-new", "3.2.1-new", "3.2-new", "3-new", "root-new"};
std::vector<std::string> visited_values;
ApplyPostOrder(this->root, [&](const std::string& value) {
visited_values.push_back(value);
});
EXPECT_EQ(visited_values, expected_visited_values);
}
}
TYPED_TEST(NodeWithParentTest, BirthRank) {
EXPECT_EQ(BirthRank(this->root), 0);
EXPECT_EQ(BirthRank(this->NodeAt({0})), 0);
EXPECT_EQ(BirthRank(this->NodeAt({1})), 1);
EXPECT_EQ(BirthRank(this->NodeAt({1, 0})), 0);
EXPECT_EQ(BirthRank(this->NodeAt({2})), 2);
EXPECT_EQ(BirthRank(this->NodeAt({2, 0})), 0);
EXPECT_EQ(BirthRank(this->NodeAt({2, 0, 0})), 0);
EXPECT_EQ(BirthRank(this->NodeAt({2, 1})), 1);
EXPECT_EQ(BirthRank(this->NodeAt({2, 1, 0})), 0);
EXPECT_EQ(BirthRank(this->NodeAt({3})), 3);
EXPECT_EQ(BirthRank(this->NodeAt({3, 0})), 0);
EXPECT_EQ(BirthRank(this->NodeAt({3, 0, 0})), 0);
EXPECT_EQ(BirthRank(this->NodeAt({3, 0, 0, 0})), 0);
EXPECT_EQ(BirthRank(this->NodeAt({3, 0, 1})), 1);
EXPECT_EQ(BirthRank(this->NodeAt({3, 0, 1, 0})), 0);
EXPECT_EQ(BirthRank(this->NodeAt({3, 1})), 1);
EXPECT_EQ(BirthRank(this->NodeAt({3, 1, 0})), 0);
EXPECT_EQ(BirthRank(this->NodeAt({3, 1, 0, 0})), 0);
EXPECT_EQ(BirthRank(this->NodeAt({3, 1, 1})), 1);
EXPECT_EQ(BirthRank(this->NodeAt({3, 1, 1, 0})), 0);
EXPECT_EQ(BirthRank(this->NodeAt({3, 2})), 2);
EXPECT_EQ(BirthRank(this->NodeAt({3, 2, 0})), 0);
EXPECT_EQ(BirthRank(this->NodeAt({3, 2, 0, 0})), 0);
EXPECT_EQ(BirthRank(this->NodeAt({3, 2, 1})), 1);
EXPECT_EQ(BirthRank(this->NodeAt({3, 2, 1, 0})), 0);
}
TYPED_TEST(NodeWithParentTest, NumAncestors) {
EXPECT_EQ(NumAncestors(this->root), 0);
EXPECT_EQ(NumAncestors(this->NodeAt({0})), 1);
EXPECT_EQ(NumAncestors(this->NodeAt({1})), 1);
EXPECT_EQ(NumAncestors(this->NodeAt({1, 0})), 2);
EXPECT_EQ(NumAncestors(this->NodeAt({2})), 1);
EXPECT_EQ(NumAncestors(this->NodeAt({2, 0})), 2);
EXPECT_EQ(NumAncestors(this->NodeAt({2, 0, 0})), 3);
EXPECT_EQ(NumAncestors(this->NodeAt({2, 1})), 2);
EXPECT_EQ(NumAncestors(this->NodeAt({2, 1, 0})), 3);
EXPECT_EQ(NumAncestors(this->NodeAt({3})), 1);
EXPECT_EQ(NumAncestors(this->NodeAt({3, 0})), 2);
EXPECT_EQ(NumAncestors(this->NodeAt({3, 0, 0})), 3);
EXPECT_EQ(NumAncestors(this->NodeAt({3, 0, 0, 0})), 4);
EXPECT_EQ(NumAncestors(this->NodeAt({3, 0, 1})), 3);
EXPECT_EQ(NumAncestors(this->NodeAt({3, 0, 1, 0})), 4);
EXPECT_EQ(NumAncestors(this->NodeAt({3, 1})), 2);
EXPECT_EQ(NumAncestors(this->NodeAt({3, 1, 0})), 3);
EXPECT_EQ(NumAncestors(this->NodeAt({3, 1, 0, 0})), 4);
EXPECT_EQ(NumAncestors(this->NodeAt({3, 1, 1})), 3);
EXPECT_EQ(NumAncestors(this->NodeAt({3, 1, 1, 0})), 4);
EXPECT_EQ(NumAncestors(this->NodeAt({3, 2})), 2);
EXPECT_EQ(NumAncestors(this->NodeAt({3, 2, 0})), 3);
EXPECT_EQ(NumAncestors(this->NodeAt({3, 2, 0, 0})), 4);
EXPECT_EQ(NumAncestors(this->NodeAt({3, 2, 1})), 3);
EXPECT_EQ(NumAncestors(this->NodeAt({3, 2, 1, 0})), 4);
}
TYPED_TEST(NodeWithParentTest, Root) {
EXPECT_EQ(Root(this->root), this->root);
EXPECT_EQ(Root(this->NodeAt({0})), this->root);
EXPECT_EQ(Root(this->NodeAt({1})), this->root);
EXPECT_EQ(Root(this->NodeAt({1, 0})), this->root);
EXPECT_EQ(Root(this->NodeAt({2})), this->root);
EXPECT_EQ(Root(this->NodeAt({2, 0})), this->root);
EXPECT_EQ(Root(this->NodeAt({2, 0, 0})), this->root);
EXPECT_EQ(Root(this->NodeAt({2, 1})), this->root);
EXPECT_EQ(Root(this->NodeAt({2, 1, 0})), this->root);
EXPECT_EQ(Root(this->NodeAt({3})), this->root);
EXPECT_EQ(Root(this->NodeAt({3, 0})), this->root);
EXPECT_EQ(Root(this->NodeAt({3, 0, 0})), this->root);
EXPECT_EQ(Root(this->NodeAt({3, 0, 0, 0})), this->root);
EXPECT_EQ(Root(this->NodeAt({3, 0, 1})), this->root);
EXPECT_EQ(Root(this->NodeAt({3, 0, 1, 0})), this->root);
EXPECT_EQ(Root(this->NodeAt({3, 1})), this->root);
EXPECT_EQ(Root(this->NodeAt({3, 1, 0})), this->root);
EXPECT_EQ(Root(this->NodeAt({3, 1, 0, 0})), this->root);
EXPECT_EQ(Root(this->NodeAt({3, 1, 1})), this->root);
EXPECT_EQ(Root(this->NodeAt({3, 1, 1, 0})), this->root);
EXPECT_EQ(Root(this->NodeAt({3, 2})), this->root);
EXPECT_EQ(Root(this->NodeAt({3, 2, 0})), this->root);
EXPECT_EQ(Root(this->NodeAt({3, 2, 0, 0})), this->root);
EXPECT_EQ(Root(this->NodeAt({3, 2, 1})), this->root);
EXPECT_EQ(Root(this->NodeAt({3, 2, 1, 0})), this->root);
}
TYPED_TEST(NodeWithParentTest, IsFirstChild) {
EXPECT_TRUE(IsFirstChild(this->root));
EXPECT_TRUE(IsFirstChild(this->NodeAt({0})));
EXPECT_FALSE(IsFirstChild(this->NodeAt({1})));
EXPECT_TRUE(IsFirstChild(this->NodeAt({1, 0})));
EXPECT_FALSE(IsFirstChild(this->NodeAt({2})));
EXPECT_TRUE(IsFirstChild(this->NodeAt({2, 0})));
EXPECT_TRUE(IsFirstChild(this->NodeAt({2, 0, 0})));
EXPECT_FALSE(IsFirstChild(this->NodeAt({2, 1})));
EXPECT_TRUE(IsFirstChild(this->NodeAt({2, 1, 0})));
EXPECT_FALSE(IsFirstChild(this->NodeAt({3})));
EXPECT_TRUE(IsFirstChild(this->NodeAt({3, 0})));
EXPECT_TRUE(IsFirstChild(this->NodeAt({3, 0, 0})));
EXPECT_TRUE(IsFirstChild(this->NodeAt({3, 0, 0, 0})));
EXPECT_FALSE(IsFirstChild(this->NodeAt({3, 0, 1})));
EXPECT_TRUE(IsFirstChild(this->NodeAt({3, 0, 1, 0})));
EXPECT_FALSE(IsFirstChild(this->NodeAt({3, 1})));
EXPECT_TRUE(IsFirstChild(this->NodeAt({3, 1, 0})));
EXPECT_TRUE(IsFirstChild(this->NodeAt({3, 1, 0, 0})));
EXPECT_FALSE(IsFirstChild(this->NodeAt({3, 1, 1})));
EXPECT_TRUE(IsFirstChild(this->NodeAt({3, 1, 1, 0})));
EXPECT_FALSE(IsFirstChild(this->NodeAt({3, 2})));
EXPECT_TRUE(IsFirstChild(this->NodeAt({3, 2, 0})));
EXPECT_TRUE(IsFirstChild(this->NodeAt({3, 2, 0, 0})));
EXPECT_FALSE(IsFirstChild(this->NodeAt({3, 2, 1})));
EXPECT_TRUE(IsFirstChild(this->NodeAt({3, 2, 1, 0})));
}
TYPED_TEST(NodeWithParentTest, IsLastChild) {
EXPECT_TRUE(IsLastChild(this->root));
EXPECT_FALSE(IsLastChild(this->NodeAt({0})));
EXPECT_FALSE(IsLastChild(this->NodeAt({1})));
EXPECT_TRUE(IsLastChild(this->NodeAt({1, 0})));
EXPECT_FALSE(IsLastChild(this->NodeAt({2})));
EXPECT_FALSE(IsLastChild(this->NodeAt({2, 0})));
EXPECT_TRUE(IsLastChild(this->NodeAt({2, 0, 0})));
EXPECT_TRUE(IsLastChild(this->NodeAt({2, 1})));
EXPECT_TRUE(IsLastChild(this->NodeAt({2, 1, 0})));
EXPECT_TRUE(IsLastChild(this->NodeAt({3})));
EXPECT_FALSE(IsLastChild(this->NodeAt({3, 0})));
EXPECT_FALSE(IsLastChild(this->NodeAt({3, 0, 0})));
EXPECT_TRUE(IsLastChild(this->NodeAt({3, 0, 0, 0})));
EXPECT_TRUE(IsLastChild(this->NodeAt({3, 0, 1})));
EXPECT_TRUE(IsLastChild(this->NodeAt({3, 0, 1, 0})));
EXPECT_FALSE(IsLastChild(this->NodeAt({3, 1})));
EXPECT_FALSE(IsLastChild(this->NodeAt({3, 1, 0})));
EXPECT_TRUE(IsLastChild(this->NodeAt({3, 1, 0, 0})));
EXPECT_TRUE(IsLastChild(this->NodeAt({3, 1, 1})));
EXPECT_TRUE(IsLastChild(this->NodeAt({3, 1, 1, 0})));
EXPECT_TRUE(IsLastChild(this->NodeAt({3, 2})));
EXPECT_FALSE(IsLastChild(this->NodeAt({3, 2, 0})));
EXPECT_TRUE(IsLastChild(this->NodeAt({3, 2, 0, 0})));
EXPECT_TRUE(IsLastChild(this->NodeAt({3, 2, 1})));
EXPECT_TRUE(IsLastChild(this->NodeAt({3, 2, 1, 0})));
}
TYPED_TEST(NodeWithParentTest, HasAncestor) {
EXPECT_FALSE(HasAncestor(this->root, &this->root));
EXPECT_TRUE(HasAncestor(this->NodeAt({0}), &this->root));
EXPECT_TRUE(HasAncestor(this->NodeAt({1}), &this->root));
EXPECT_TRUE(HasAncestor(this->NodeAt({1, 0}), &this->root));
EXPECT_TRUE(HasAncestor(this->NodeAt({2}), &this->root));
EXPECT_TRUE(HasAncestor(this->NodeAt({2, 0}), &this->root));
EXPECT_TRUE(HasAncestor(this->NodeAt({2, 0, 0}), &this->root));
EXPECT_TRUE(HasAncestor(this->NodeAt({2, 1}), &this->root));
EXPECT_TRUE(HasAncestor(this->NodeAt({2, 1, 0}), &this->root));
EXPECT_TRUE(HasAncestor(this->NodeAt({3}), &this->root));
EXPECT_TRUE(HasAncestor(this->NodeAt({3, 0}), &this->root));
EXPECT_TRUE(HasAncestor(this->NodeAt({3, 0, 0}), &this->root));
EXPECT_TRUE(HasAncestor(this->NodeAt({3, 0, 0, 0}), &this->root));
EXPECT_TRUE(HasAncestor(this->NodeAt({3, 0, 1}), &this->root));
EXPECT_TRUE(HasAncestor(this->NodeAt({3, 0, 1, 0}), &this->root));
EXPECT_TRUE(HasAncestor(this->NodeAt({3, 1}), &this->root));
EXPECT_TRUE(HasAncestor(this->NodeAt({3, 1, 0}), &this->root));
EXPECT_TRUE(HasAncestor(this->NodeAt({3, 1, 0, 0}), &this->root));
EXPECT_TRUE(HasAncestor(this->NodeAt({3, 1, 1}), &this->root));
EXPECT_TRUE(HasAncestor(this->NodeAt({3, 1, 1, 0}), &this->root));
EXPECT_TRUE(HasAncestor(this->NodeAt({3, 2}), &this->root));
EXPECT_TRUE(HasAncestor(this->NodeAt({3, 2, 0}), &this->root));
EXPECT_TRUE(HasAncestor(this->NodeAt({3, 2, 0, 0}), &this->root));
EXPECT_TRUE(HasAncestor(this->NodeAt({3, 2, 1}), &this->root));
EXPECT_TRUE(HasAncestor(this->NodeAt({3, 2, 1, 0}), &this->root));
EXPECT_FALSE(HasAncestor(this->root, &this->NodeAt({2})));
EXPECT_FALSE(HasAncestor(this->NodeAt({0}), &this->NodeAt({2})));
EXPECT_FALSE(HasAncestor(this->NodeAt({1}), &this->NodeAt({2})));
EXPECT_FALSE(HasAncestor(this->NodeAt({1, 0}), &this->NodeAt({2})));
EXPECT_FALSE(HasAncestor(this->NodeAt({2}), &this->NodeAt({2})));
EXPECT_TRUE(HasAncestor(this->NodeAt({2, 0}), &this->NodeAt({2})));
EXPECT_TRUE(HasAncestor(this->NodeAt({2, 0, 0}), &this->NodeAt({2})));
EXPECT_TRUE(HasAncestor(this->NodeAt({2, 1}), &this->NodeAt({2})));
EXPECT_TRUE(HasAncestor(this->NodeAt({2, 1, 0}), &this->NodeAt({2})));
EXPECT_FALSE(HasAncestor(this->NodeAt({3}), &this->NodeAt({2})));
EXPECT_FALSE(HasAncestor(this->NodeAt({3, 0}), &this->NodeAt({2})));
EXPECT_FALSE(HasAncestor(this->NodeAt({3, 0, 0}), &this->NodeAt({2})));
EXPECT_FALSE(HasAncestor(this->NodeAt({3, 0, 0, 0}), &this->NodeAt({2})));
EXPECT_FALSE(HasAncestor(this->NodeAt({3, 0, 1}), &this->NodeAt({2})));
EXPECT_FALSE(HasAncestor(this->NodeAt({3, 0, 1, 0}), &this->NodeAt({2})));
EXPECT_FALSE(HasAncestor(this->NodeAt({3, 1}), &this->NodeAt({2})));
EXPECT_FALSE(HasAncestor(this->NodeAt({3, 1, 0}), &this->NodeAt({2})));
EXPECT_FALSE(HasAncestor(this->NodeAt({3, 1, 0, 0}), &this->NodeAt({2})));
EXPECT_FALSE(HasAncestor(this->NodeAt({3, 1, 1}), &this->NodeAt({2})));
EXPECT_FALSE(HasAncestor(this->NodeAt({3, 1, 1, 0}), &this->NodeAt({2})));
EXPECT_FALSE(HasAncestor(this->NodeAt({3, 2}), &this->NodeAt({2})));
EXPECT_FALSE(HasAncestor(this->NodeAt({3, 2, 0}), &this->NodeAt({2})));
EXPECT_FALSE(HasAncestor(this->NodeAt({3, 2, 0, 0}), &this->NodeAt({2})));
EXPECT_FALSE(HasAncestor(this->NodeAt({3, 2, 1}), &this->NodeAt({2})));
EXPECT_FALSE(HasAncestor(this->NodeAt({3, 2, 1, 0}), &this->NodeAt({2})));
EXPECT_FALSE(HasAncestor(this->root, &this->NodeAt({1, 0})));
EXPECT_FALSE(HasAncestor(this->NodeAt({0}), &this->NodeAt({1, 0})));
EXPECT_FALSE(HasAncestor(this->NodeAt({1}), &this->NodeAt({1, 0})));
EXPECT_FALSE(HasAncestor(this->NodeAt({1, 0}), &this->NodeAt({1, 0})));
EXPECT_FALSE(HasAncestor(this->NodeAt({2}), &this->NodeAt({1, 0})));
EXPECT_FALSE(HasAncestor(this->NodeAt({2, 0}), &this->NodeAt({1, 0})));
EXPECT_FALSE(HasAncestor(this->NodeAt({2, 0, 0}), &this->NodeAt({1, 0})));
EXPECT_FALSE(HasAncestor(this->NodeAt({2, 1}), &this->NodeAt({1, 0})));
EXPECT_FALSE(HasAncestor(this->NodeAt({2, 1, 0}), &this->NodeAt({1, 0})));
EXPECT_FALSE(HasAncestor(this->NodeAt({3}), &this->NodeAt({1, 0})));
EXPECT_FALSE(HasAncestor(this->NodeAt({3, 0}), &this->NodeAt({1, 0})));
EXPECT_FALSE(HasAncestor(this->NodeAt({3, 0, 0}), &this->NodeAt({1, 0})));
EXPECT_FALSE(HasAncestor(this->NodeAt({3, 0, 0, 0}), &this->NodeAt({1, 0})));
EXPECT_FALSE(HasAncestor(this->NodeAt({3, 0, 1}), &this->NodeAt({1, 0})));
EXPECT_FALSE(HasAncestor(this->NodeAt({3, 0, 1, 0}), &this->NodeAt({1, 0})));
EXPECT_FALSE(HasAncestor(this->NodeAt({3, 1}), &this->NodeAt({1, 0})));
EXPECT_FALSE(HasAncestor(this->NodeAt({3, 1, 0}), &this->NodeAt({1, 0})));
EXPECT_FALSE(HasAncestor(this->NodeAt({3, 1, 0, 0}), &this->NodeAt({1, 0})));
EXPECT_FALSE(HasAncestor(this->NodeAt({3, 1, 1}), &this->NodeAt({1, 0})));
EXPECT_FALSE(HasAncestor(this->NodeAt({3, 1, 1, 0}), &this->NodeAt({1, 0})));
EXPECT_FALSE(HasAncestor(this->NodeAt({3, 2}), &this->NodeAt({1, 0})));
EXPECT_FALSE(HasAncestor(this->NodeAt({3, 2, 0}), &this->NodeAt({1, 0})));
EXPECT_FALSE(HasAncestor(this->NodeAt({3, 2, 0, 0}), &this->NodeAt({1, 0})));
EXPECT_FALSE(HasAncestor(this->NodeAt({3, 2, 1}), &this->NodeAt({1, 0})));
EXPECT_FALSE(HasAncestor(this->NodeAt({3, 2, 1, 0}), &this->NodeAt({1, 0})));
}
template <class TestSuite>
void TestPath(TestSuite* test_suite, std::initializer_list<size_t> node_path) {
auto& node = test_suite->NodeAt(node_path);
{
std::vector<size_t> calculated_path;
Path(node, calculated_path);
EXPECT_THAT(calculated_path, ::testing::ElementsAreArray(node_path))
<< "Path container: std::vector<size_t>";
}
{
std::list<size_t> calculated_path;
Path(node, calculated_path);
EXPECT_THAT(calculated_path, ::testing::ElementsAreArray(node_path))
<< "Path container: std::list<size_t>";
}
}
TYPED_TEST(NodeWithParentTest, Path) {
TestPath(this, {});
TestPath(this, {0});
TestPath(this, {1});
TestPath(this, {1, 0});
TestPath(this, {2});
TestPath(this, {2, 0});
TestPath(this, {2, 0, 0});
TestPath(this, {2, 1});
TestPath(this, {2, 1, 0});
TestPath(this, {3});
TestPath(this, {3, 0});
TestPath(this, {3, 0, 0});
TestPath(this, {3, 0, 0, 0});
TestPath(this, {3, 0, 1});
TestPath(this, {3, 0, 1, 0});
TestPath(this, {3, 1});
TestPath(this, {3, 1, 0});
TestPath(this, {3, 1, 0, 0});
TestPath(this, {3, 1, 1});
TestPath(this, {3, 1, 1, 0});
TestPath(this, {3, 2});
TestPath(this, {3, 2, 0});
TestPath(this, {3, 2, 0, 0});
TestPath(this, {3, 2, 1});
TestPath(this, {3, 2, 1, 0});
}
template <class TestSuite>
void TestNodePath(TestSuite* test_suite,
std::initializer_list<size_t> node_path,
absl::string_view expected_string) {
auto& node = test_suite->NodeAt(node_path);
std::ostringstream output;
output << NodePath(node);
EXPECT_EQ(output.str(), expected_string);
}
TYPED_TEST(NodeWithParentTest, NodePath) {
TestNodePath(this, {}, "{}");
TestNodePath(this, {0}, "{0}");
TestNodePath(this, {1}, "{1}");
TestNodePath(this, {1, 0}, "{1,0}");
TestNodePath(this, {2}, "{2}");
TestNodePath(this, {2, 0}, "{2,0}");
TestNodePath(this, {2, 0, 0}, "{2,0,0}");
TestNodePath(this, {2, 1}, "{2,1}");
TestNodePath(this, {2, 1, 0}, "{2,1,0}");
TestNodePath(this, {3}, "{3}");
TestNodePath(this, {3, 0}, "{3,0}");
TestNodePath(this, {3, 0, 0}, "{3,0,0}");
TestNodePath(this, {3, 0, 0, 0}, "{3,0,0,0}");
TestNodePath(this, {3, 0, 1}, "{3,0,1}");
TestNodePath(this, {3, 0, 1, 0}, "{3,0,1,0}");
TestNodePath(this, {3, 1}, "{3,1}");
TestNodePath(this, {3, 1, 0}, "{3,1,0}");
TestNodePath(this, {3, 1, 0, 0}, "{3,1,0,0}");
TestNodePath(this, {3, 1, 1}, "{3,1,1}");
TestNodePath(this, {3, 1, 1, 0}, "{3,1,1,0}");
TestNodePath(this, {3, 2}, "{3,2}");
TestNodePath(this, {3, 2, 0}, "{3,2,0}");
TestNodePath(this, {3, 2, 0, 0}, "{3,2,0,0}");
TestNodePath(this, {3, 2, 1}, "{3,2,1}");
TestNodePath(this, {3, 2, 1, 0}, "{3,2,1,0}");
}
TYPED_TEST(NodeWithValueTest, PrintTreeWithCustomPrinter) {
{
std::ostringstream output;
PrintTree(
this->root, &output,
[](std::ostream& stream, const std::string& value) -> std::ostream& {
return stream << "value=" << value;
});
static const absl::string_view expected_output =
"{ (value=root)\n"
" { (value=0) }\n"
" { (value=1)\n"
" { (value=1.0) }\n"
" }\n"
" { (value=2)\n"
" { (value=2.0)\n"
" { (value=2.0.0) }\n"
" }\n"
" { (value=2.1)\n"
" { (value=2.1.0) }\n"
" }\n"
" }\n"
" { (value=3)\n"
" { (value=3.0)\n"
" { (value=3.0.0)\n"
" { (value=3.0.0.0) }\n"
" }\n"
" { (value=3.0.1)\n"
" { (value=3.0.1.0) }\n"
" }\n"
" }\n"
" { (value=3.1)\n"
" { (value=3.1.0)\n"
" { (value=3.1.0.0) }\n"
" }\n"
" { (value=3.1.1)\n"
" { (value=3.1.1.0) }\n"
" }\n"
" }\n"
" { (value=3.2)\n"
" { (value=3.2.0)\n"
" { (value=3.2.0.0) }\n"
" }\n"
" { (value=3.2.1)\n"
" { (value=3.2.1.0) }\n"
" }\n"
" }\n"
" }\n"
"}";
EXPECT_EQ(output.str(), expected_output);
}
{
std::ostringstream output;
PrintTree(
this->NodeAt({3, 1}), &output,
[](std::ostream& stream, const std::string& value) -> std::ostream& {
return stream << "value=" << value;
});
static const absl::string_view expected_output =
"{ (value=3.1)\n"
" { (value=3.1.0)\n"
" { (value=3.1.0.0) }\n"
" }\n"
" { (value=3.1.1)\n"
" { (value=3.1.1.0) }\n"
" }\n"
"}";
EXPECT_EQ(output.str(), expected_output);
}
}
TYPED_TEST(NodeWithValueTest, PrintTree) {
{
std::ostringstream output;
PrintTree(this->root, &output);
static const absl::string_view expected_output =
"{ (root)\n"
" { (0) }\n"
" { (1)\n"
" { (1.0) }\n"
" }\n"
" { (2)\n"
" { (2.0)\n"
" { (2.0.0) }\n"
" }\n"
" { (2.1)\n"
" { (2.1.0) }\n"
" }\n"
" }\n"
" { (3)\n"
" { (3.0)\n"
" { (3.0.0)\n"
" { (3.0.0.0) }\n"
" }\n"
" { (3.0.1)\n"
" { (3.0.1.0) }\n"
" }\n"
" }\n"
" { (3.1)\n"
" { (3.1.0)\n"
" { (3.1.0.0) }\n"
" }\n"
" { (3.1.1)\n"
" { (3.1.1.0) }\n"
" }\n"
" }\n"
" { (3.2)\n"
" { (3.2.0)\n"
" { (3.2.0.0) }\n"
" }\n"
" { (3.2.1)\n"
" { (3.2.1.0) }\n"
" }\n"
" }\n"
" }\n"
"}";
EXPECT_EQ(output.str(), expected_output);
}
{
std::ostringstream output;
PrintTree(this->NodeAt({3, 1}), &output);
static const absl::string_view expected_output =
"{ (3.1)\n"
" { (3.1.0)\n"
" { (3.1.0.0) }\n"
" }\n"
" { (3.1.1)\n"
" { (3.1.1.0) }\n"
" }\n"
"}";
EXPECT_EQ(output.str(), expected_output);
}
}
TYPED_TEST(NodeWithParentTest, NextSibling) {
EXPECT_EQ(NextSibling(this->root), nullptr);
EXPECT_EQ(NextSibling(this->NodeAt({0})), &this->NodeAt({1}));
EXPECT_EQ(NextSibling(this->NodeAt({1})), &this->NodeAt({2}));
EXPECT_EQ(NextSibling(this->NodeAt({1, 0})), nullptr);
EXPECT_EQ(NextSibling(this->NodeAt({2})), &this->NodeAt({3}));
EXPECT_EQ(NextSibling(this->NodeAt({2, 0})), &this->NodeAt({2, 1}));
EXPECT_EQ(NextSibling(this->NodeAt({2, 0, 0})), nullptr);
EXPECT_EQ(NextSibling(this->NodeAt({2, 1})), nullptr);
EXPECT_EQ(NextSibling(this->NodeAt({2, 1, 0})), nullptr);
EXPECT_EQ(NextSibling(this->NodeAt({3})), nullptr);
EXPECT_EQ(NextSibling(this->NodeAt({3, 0})), &this->NodeAt({3, 1}));
EXPECT_EQ(NextSibling(this->NodeAt({3, 0, 0})), &this->NodeAt({3, 0, 1}));
EXPECT_EQ(NextSibling(this->NodeAt({3, 0, 0, 0})), nullptr);
EXPECT_EQ(NextSibling(this->NodeAt({3, 0, 1})), nullptr);
EXPECT_EQ(NextSibling(this->NodeAt({3, 0, 1, 0})), nullptr);
EXPECT_EQ(NextSibling(this->NodeAt({3, 1})), &this->NodeAt({3, 2}));
EXPECT_EQ(NextSibling(this->NodeAt({3, 1, 0})), &this->NodeAt({3, 1, 1}));
EXPECT_EQ(NextSibling(this->NodeAt({3, 1, 0, 0})), nullptr);
EXPECT_EQ(NextSibling(this->NodeAt({3, 1, 1})), nullptr);
EXPECT_EQ(NextSibling(this->NodeAt({3, 1, 1, 0})), nullptr);
EXPECT_EQ(NextSibling(this->NodeAt({3, 2})), nullptr);
EXPECT_EQ(NextSibling(this->NodeAt({3, 2, 0})), &this->NodeAt({3, 2, 1}));
EXPECT_EQ(NextSibling(this->NodeAt({3, 2, 0, 0})), nullptr);
EXPECT_EQ(NextSibling(this->NodeAt({3, 2, 1})), nullptr);
EXPECT_EQ(NextSibling(this->NodeAt({3, 2, 1, 0})), nullptr);
}
TYPED_TEST(NodeWithParentTest, PreviousSibling) {
EXPECT_EQ(PreviousSibling(this->root), nullptr);
EXPECT_EQ(PreviousSibling(this->NodeAt({0})), nullptr);
EXPECT_EQ(PreviousSibling(this->NodeAt({1})), &this->NodeAt({0}));
EXPECT_EQ(PreviousSibling(this->NodeAt({1, 0})), nullptr);
EXPECT_EQ(PreviousSibling(this->NodeAt({2})), &this->NodeAt({1}));
EXPECT_EQ(PreviousSibling(this->NodeAt({2, 0})), nullptr);
EXPECT_EQ(PreviousSibling(this->NodeAt({2, 0, 0})), nullptr);
EXPECT_EQ(PreviousSibling(this->NodeAt({2, 1})), &this->NodeAt({2, 0}));
EXPECT_EQ(PreviousSibling(this->NodeAt({2, 1, 0})), nullptr);
EXPECT_EQ(PreviousSibling(this->NodeAt({3})), &this->NodeAt({2}));
EXPECT_EQ(PreviousSibling(this->NodeAt({3, 0})), nullptr);
EXPECT_EQ(PreviousSibling(this->NodeAt({3, 0, 0})), nullptr);
EXPECT_EQ(PreviousSibling(this->NodeAt({3, 0, 0, 0})), nullptr);
EXPECT_EQ(PreviousSibling(this->NodeAt({3, 0, 1})), &this->NodeAt({3, 0, 0}));
EXPECT_EQ(PreviousSibling(this->NodeAt({3, 0, 1, 0})), nullptr);
EXPECT_EQ(PreviousSibling(this->NodeAt({3, 1})), &this->NodeAt({3, 0}));
EXPECT_EQ(PreviousSibling(this->NodeAt({3, 1, 0})), nullptr);
EXPECT_EQ(PreviousSibling(this->NodeAt({3, 1, 0, 0})), nullptr);
EXPECT_EQ(PreviousSibling(this->NodeAt({3, 1, 1})), &this->NodeAt({3, 1, 0}));
EXPECT_EQ(PreviousSibling(this->NodeAt({3, 1, 1, 0})), nullptr);
EXPECT_EQ(PreviousSibling(this->NodeAt({3, 2})), &this->NodeAt({3, 1}));
EXPECT_EQ(PreviousSibling(this->NodeAt({3, 2, 0})), nullptr);
EXPECT_EQ(PreviousSibling(this->NodeAt({3, 2, 0, 0})), nullptr);
EXPECT_EQ(PreviousSibling(this->NodeAt({3, 2, 1})), &this->NodeAt({3, 2, 0}));
EXPECT_EQ(PreviousSibling(this->NodeAt({3, 2, 1, 0})), nullptr);
}
TYPED_TEST(NodeWithParentTest, NextLeaf) {
EXPECT_EQ(NextLeaf(this->root), nullptr);
EXPECT_EQ(NextLeaf(this->NodeAt({0})), &this->NodeAt({1, 0}));
EXPECT_EQ(NextLeaf(this->NodeAt({1})), &this->NodeAt({2, 0, 0}));
EXPECT_EQ(NextLeaf(this->NodeAt({1, 0})), &this->NodeAt({2, 0, 0}));
EXPECT_EQ(NextLeaf(this->NodeAt({2})), &this->NodeAt({3, 0, 0, 0}));
EXPECT_EQ(NextLeaf(this->NodeAt({2, 0})), &this->NodeAt({2, 1, 0}));
EXPECT_EQ(NextLeaf(this->NodeAt({2, 0, 0})), &this->NodeAt({2, 1, 0}));
EXPECT_EQ(NextLeaf(this->NodeAt({2, 1})), &this->NodeAt({3, 0, 0, 0}));
EXPECT_EQ(NextLeaf(this->NodeAt({2, 1, 0})), &this->NodeAt({3, 0, 0, 0}));
EXPECT_EQ(NextLeaf(this->NodeAt({3})), nullptr);
EXPECT_EQ(NextLeaf(this->NodeAt({3, 0})), &this->NodeAt({3, 1, 0, 0}));
EXPECT_EQ(NextLeaf(this->NodeAt({3, 0, 0})), &this->NodeAt({3, 0, 1, 0}));
EXPECT_EQ(NextLeaf(this->NodeAt({3, 0, 0, 0})), &this->NodeAt({3, 0, 1, 0}));
EXPECT_EQ(NextLeaf(this->NodeAt({3, 0, 1})), &this->NodeAt({3, 1, 0, 0}));
EXPECT_EQ(NextLeaf(this->NodeAt({3, 0, 1, 0})), &this->NodeAt({3, 1, 0, 0}));
EXPECT_EQ(NextLeaf(this->NodeAt({3, 1})), &this->NodeAt({3, 2, 0, 0}));
EXPECT_EQ(NextLeaf(this->NodeAt({3, 1, 0})), &this->NodeAt({3, 1, 1, 0}));
EXPECT_EQ(NextLeaf(this->NodeAt({3, 1, 0, 0})), &this->NodeAt({3, 1, 1, 0}));
EXPECT_EQ(NextLeaf(this->NodeAt({3, 1, 1})), &this->NodeAt({3, 2, 0, 0}));
EXPECT_EQ(NextLeaf(this->NodeAt({3, 1, 1, 0})), &this->NodeAt({3, 2, 0, 0}));
EXPECT_EQ(NextLeaf(this->NodeAt({3, 2})), nullptr);
EXPECT_EQ(NextLeaf(this->NodeAt({3, 2, 0})), &this->NodeAt({3, 2, 1, 0}));
EXPECT_EQ(NextLeaf(this->NodeAt({3, 2, 0, 0})), &this->NodeAt({3, 2, 1, 0}));
EXPECT_EQ(NextLeaf(this->NodeAt({3, 2, 1})), nullptr);
EXPECT_EQ(NextLeaf(this->NodeAt({3, 2, 1, 0})), nullptr);
}
TYPED_TEST(NodeWithParentTest, PreviousLeaf) {
EXPECT_EQ(PreviousLeaf(this->root), nullptr);
EXPECT_EQ(PreviousLeaf(this->NodeAt({0})), nullptr);
EXPECT_EQ(PreviousLeaf(this->NodeAt({1})), &this->NodeAt({0}));
EXPECT_EQ(PreviousLeaf(this->NodeAt({1, 0})), &this->NodeAt({0}));
EXPECT_EQ(PreviousLeaf(this->NodeAt({2})), &this->NodeAt({1, 0}));
EXPECT_EQ(PreviousLeaf(this->NodeAt({2, 0})), &this->NodeAt({1, 0}));
EXPECT_EQ(PreviousLeaf(this->NodeAt({2, 0, 0})), &this->NodeAt({1, 0}));
EXPECT_EQ(PreviousLeaf(this->NodeAt({2, 1})), &this->NodeAt({2, 0, 0}));
EXPECT_EQ(PreviousLeaf(this->NodeAt({2, 1, 0})), &this->NodeAt({2, 0, 0}));
EXPECT_EQ(PreviousLeaf(this->NodeAt({3})), &this->NodeAt({2, 1, 0}));
EXPECT_EQ(PreviousLeaf(this->NodeAt({3, 0})), &this->NodeAt({2, 1, 0}));
EXPECT_EQ(PreviousLeaf(this->NodeAt({3, 0, 0})), &this->NodeAt({2, 1, 0}));
EXPECT_EQ(PreviousLeaf(this->NodeAt({3, 0, 0, 0})), &this->NodeAt({2, 1, 0}));
EXPECT_EQ(PreviousLeaf(this->NodeAt({3, 0, 1})), &this->NodeAt({3, 0, 0, 0}));
EXPECT_EQ(PreviousLeaf(this->NodeAt({3, 0, 1, 0})),
&this->NodeAt({3, 0, 0, 0}));
EXPECT_EQ(PreviousLeaf(this->NodeAt({3, 1})), &this->NodeAt({3, 0, 1, 0}));
EXPECT_EQ(PreviousLeaf(this->NodeAt({3, 1, 0})), &this->NodeAt({3, 0, 1, 0}));
EXPECT_EQ(PreviousLeaf(this->NodeAt({3, 1, 0, 0})),
&this->NodeAt({3, 0, 1, 0}));
EXPECT_EQ(PreviousLeaf(this->NodeAt({3, 1, 1})), &this->NodeAt({3, 1, 0, 0}));
EXPECT_EQ(PreviousLeaf(this->NodeAt({3, 1, 1, 0})),
&this->NodeAt({3, 1, 0, 0}));
EXPECT_EQ(PreviousLeaf(this->NodeAt({3, 2})), &this->NodeAt({3, 1, 1, 0}));
EXPECT_EQ(PreviousLeaf(this->NodeAt({3, 2, 0})), &this->NodeAt({3, 1, 1, 0}));
EXPECT_EQ(PreviousLeaf(this->NodeAt({3, 2, 0, 0})),
&this->NodeAt({3, 1, 1, 0}));
EXPECT_EQ(PreviousLeaf(this->NodeAt({3, 2, 1})), &this->NodeAt({3, 2, 0, 0}));
EXPECT_EQ(PreviousLeaf(this->NodeAt({3, 2, 1, 0})),
&this->NodeAt({3, 2, 0, 0}));
}
TYPED_TEST(NodeWithParentTest, RemoveSelfFromParent) {
using N = TypeParam;
// Const nodes are not supported
if constexpr (!std::is_const_v<TypeParam>) {
RemoveSelfFromParent(this->NodeAt({2}));
EXPECT_PRED_FORMAT2(
VerifyTree, this->root,
N("root", {N("0"), //
N("1", {N("1.0")}), //
N("3", {N("3.0", {N("3.0.0", {N("3.0.0.0")}), //
N("3.0.1", {N("3.0.1.0")})}), //
N("3.1", {N("3.1.0", {N("3.1.0.0")}), //
N("3.1.1", {N("3.1.1.0")})}), //
N("3.2", {N("3.2.0", {N("3.2.0.0")}), //
N("3.2.1", {N("3.2.1.0")})})})}));
this->root.Relink();
RemoveSelfFromParent(this->NodeAt({2, 1}));
EXPECT_PRED_FORMAT2(
VerifyTree, this->root,
N("root", {N("0"), //
N("1", {N("1.0")}), //
N("3", {N("3.0", {N("3.0.0", {N("3.0.0.0")}), //
N("3.0.1", {N("3.0.1.0")})}), //
N("3.2", {N("3.2.0", {N("3.2.0.0")}), //
N("3.2.1", {N("3.2.1.0")})})})}));
this->root.Relink();
RemoveSelfFromParent(this->NodeAt({0}));
EXPECT_PRED_FORMAT2(
VerifyTree, this->root,
N("root", {N("1", {N("1.0")}), //
N("3", {N("3.0", {N("3.0.0", {N("3.0.0.0")}), //
N("3.0.1", {N("3.0.1.0")})}), //
N("3.2", {N("3.2.0", {N("3.2.0.0")}), //
N("3.2.1", {N("3.2.1.0")})})})}));
}
}
TYPED_TEST(SimpleNodeTest, HoistOnlyChild) {
using N = TypeParam;
// Const nodes are not supported
if constexpr (!std::is_const_v<TypeParam>) {
HoistOnlyChild(this->NodeAt({2, 0}));
EXPECT_PRED_FORMAT2(
VerifyTree, this->root,
N("root", {N("0"), //
N("1", {N("1.0")}), //
N("2", {N("2.0.0"), //
N("2.1", {N("2.1.0")})}), //
N("3", {N("3.0", {N("3.0.0", {N("3.0.0.0")}), //
N("3.0.1", {N("3.0.1.0")})}), //
N("3.1", {N("3.1.0", {N("3.1.0.0")}), //
N("3.1.1", {N("3.1.1.0")})}), //
N("3.2", {N("3.2.0", {N("3.2.0.0")}), //
N("3.2.1", {N("3.2.1.0")})})})}));
HoistOnlyChild(this->NodeAt({3}));
EXPECT_PRED_FORMAT2(
VerifyTree, this->root,
N("root", {N("0"), //
N("1", {N("1.0")}), //
N("2", {N("2.0.0"), //
N("2.1", {N("2.1.0")})}), //
N("3", {N("3.0", {N("3.0.0", {N("3.0.0.0")}), //
N("3.0.1", {N("3.0.1.0")})}), //
N("3.1", {N("3.1.0", {N("3.1.0.0")}), //
N("3.1.1", {N("3.1.1.0")})}), //
N("3.2", {N("3.2.0", {N("3.2.0.0")}), //
N("3.2.1", {N("3.2.1.0")})})})}));
// remove "3.1" and "3.2"
this->NodeAt({3}).Children().erase(
std::next(this->NodeAt({3}).Children().begin(), 1),
this->NodeAt({3}).Children().end());
// remove "3.0.1"
this->NodeAt({3, 0}).Children().erase(
std::next(this->NodeAt({3, 0}).Children().begin(), 1));
EXPECT_PRED_FORMAT2(
VerifyTree, this->root,
N("root", {N("0"), //
N("1", {N("1.0")}), //
N("2", {N("2.0.0"), //
N("2.1", {N("2.1.0")})}), //
N("3", {N("3.0", {N("3.0.0", {N("3.0.0.0")})})})}));
HoistOnlyChild(this->NodeAt({3}));
EXPECT_PRED_FORMAT2(VerifyTree, this->root,
N("root", {N("0"), //
N("1", {N("1.0")}), //
N("2", {N("2.0.0"), //
N("2.1", {N("2.1.0")})}), //
N("3.0", {N("3.0.0", {N("3.0.0.0")})})}));
HoistOnlyChild(this->NodeAt({3}));
EXPECT_PRED_FORMAT2(VerifyTree, this->root,
N("root", {N("0"), //
N("1", {N("1.0")}), //
N("2", {N("2.0.0"), //
N("2.1", {N("2.1.0")})}), //
N("3.0.0", {N("3.0.0.0")})}));
HoistOnlyChild(this->NodeAt({3}));
EXPECT_PRED_FORMAT2(VerifyTree, this->root,
N("root", {N("0"), //
N("1", {N("1.0")}), //
N("2", {N("2.0.0"), //
N("2.1", {N("2.1.0")})}), //
N("3.0.0.0")}));
}
}
TYPED_TEST(SimpleNodeTest, FlattenOnce) {
using N = TypeParam;
// Const nodes are not supported
if constexpr (!std::is_const_v<TypeParam>) {
FlattenOnce(this->NodeAt({3}));
EXPECT_PRED_FORMAT2(VerifyTree, this->root,
N("root", {N("0"), //
N("1", {N("1.0")}), //
N("2", {N("2.0", {N("2.0.0")}), //
N("2.1", {N("2.1.0")})}), //
N("3", {N("3.0.0", {N("3.0.0.0")}), //
N("3.0.1", {N("3.0.1.0")}), //
N("3.1.0", {N("3.1.0.0")}), //
N("3.1.1", {N("3.1.1.0")}), //
N("3.2.0", {N("3.2.0.0")}), //
N("3.2.1", {N("3.2.1.0")})})}));
// This should change nothing
FlattenOnce(this->NodeAt({0}));
EXPECT_PRED_FORMAT2(VerifyTree, this->root,
N("root", {N("0"), //
N("1", {N("1.0")}), //
N("2", {N("2.0", {N("2.0.0")}), //
N("2.1", {N("2.1.0")})}), //
N("3", {N("3.0.0", {N("3.0.0.0")}), //
N("3.0.1", {N("3.0.1.0")}), //
N("3.1.0", {N("3.1.0.0")}), //
N("3.1.1", {N("3.1.1.0")}), //
N("3.2.0", {N("3.2.0.0")}), //
N("3.2.1", {N("3.2.1.0")})})}));
FlattenOnce(this->root);
EXPECT_PRED_FORMAT2(VerifyTree, this->root,
N("root", { //
N("1.0"), //
N("2.0", {N("2.0.0")}), //
N("2.1", {N("2.1.0")}), //
N("3.0.0", {N("3.0.0.0")}), //
N("3.0.1", {N("3.0.1.0")}), //
N("3.1.0", {N("3.1.0.0")}), //
N("3.1.1", {N("3.1.1.0")}), //
N("3.2.0", {N("3.2.0.0")}), //
N("3.2.1", {N("3.2.1.0")})}));
}
}
TYPED_TEST(SimpleNodeTest, FlattenOnlyChildrenWithChildren) {
using N = TypeParam;
// Const nodes are not supported
if constexpr (!std::is_const_v<TypeParam>) {
FlattenOnlyChildrenWithChildren(this->root);
EXPECT_PRED_FORMAT2(VerifyTree, this->root,
N("root", {N("0"), //
N("1.0"), //
N("2.0", {N("2.0.0")}), //
N("2.1", {N("2.1.0")}), //
N("3.0", {N("3.0.0", {N("3.0.0.0")}), //
N("3.0.1", {N("3.0.1.0")})}), //
N("3.1", {N("3.1.0", {N("3.1.0.0")}), //
N("3.1.1", {N("3.1.1.0")})}), //
N("3.2", {N("3.2.0", {N("3.2.0.0")}), //
N("3.2.1", {N("3.2.1.0")})})}));
// This should change nothing
FlattenOnlyChildrenWithChildren(this->NodeAt({0}));
EXPECT_PRED_FORMAT2(VerifyTree, this->root,
N("root", {N("0"), //
N("1.0"), //
N("2.0", {N("2.0.0")}), //
N("2.1", {N("2.1.0")}), //
N("3.0", {N("3.0.0", {N("3.0.0.0")}), //
N("3.0.1", {N("3.0.1.0")})}), //
N("3.1", {N("3.1.0", {N("3.1.0.0")}), //
N("3.1.1", {N("3.1.1.0")})}), //
N("3.2", {N("3.2.0", {N("3.2.0.0")}), //
N("3.2.1", {N("3.2.1.0")})})}));
FlattenOnlyChildrenWithChildren(this->root);
EXPECT_PRED_FORMAT2(VerifyTree, this->root,
N("root", {N("0"), //
N("1.0"), //
N("2.0.0"), //
N("2.1.0"), //
N("3.0.0", {N("3.0.0.0")}), //
N("3.0.1", {N("3.0.1.0")}), //
N("3.1.0", {N("3.1.0.0")}), //
N("3.1.1", {N("3.1.1.0")}), //
N("3.2.0", {N("3.2.0.0")}), //
N("3.2.1", {N("3.2.1.0")})}));
}
}
TYPED_TEST(SimpleNodeTest, FlattenOneChild) {
using N = TypeParam;
// Const nodes are not supported
if constexpr (!std::is_const_v<TypeParam>) {
FlattenOneChild(this->NodeAt({3}), 1);
EXPECT_PRED_FORMAT2(
VerifyTree, this->root,
N("root", {N("0"), //
N("1", {N("1.0")}), //
N("2", {N("2.0", {N("2.0.0")}), //
N("2.1", {N("2.1.0")})}), //
N("3", {N("3.0", {N("3.0.0", {N("3.0.0.0")}), //
N("3.0.1", {N("3.0.1.0")})}), //
N("3.1.0", {N("3.1.0.0")}), //
N("3.1.1", {N("3.1.1.0")}), //
N("3.2", {N("3.2.0", {N("3.2.0.0")}), //
N("3.2.1", {N("3.2.1.0")})})})}));
FlattenOneChild(this->NodeAt({1}), 0);
EXPECT_PRED_FORMAT2(
VerifyTree, this->root,
N("root", {N("0"), //
N("1"), //
N("2", {N("2.0", {N("2.0.0")}), //
N("2.1", {N("2.1.0")})}), //
N("3", {N("3.0", {N("3.0.0", {N("3.0.0.0")}), //
N("3.0.1", {N("3.0.1.0")})}), //
N("3.1.0", {N("3.1.0.0")}), //
N("3.1.1", {N("3.1.1.0")}), //
N("3.2", {N("3.2.0", {N("3.2.0.0")}), //
N("3.2.1", {N("3.2.1.0")})})})}));
}
}
TYPED_TEST(NodeWithValueTest, MergeConsecutiveSiblings) {
using N = TypeParam;
// Const nodes are not supported
if constexpr (!std::is_const_v<TypeParam>) {
MergeConsecutiveSiblings(this->NodeAt({3}), 1,
[](std::string* v0, const std::string& v1) {
absl::StrAppend(v0, "+", v1);
});
EXPECT_PRED_FORMAT2(
VerifyTree, this->root,
N("root", {N("0"), //
N("1", {N("1.0")}), //
N("2", {N("2.0", {N("2.0.0")}), //
N("2.1", {N("2.1.0")})}), //
N("3", {N("3.0", {N("3.0.0", {N("3.0.0.0")}), //
N("3.0.1", {N("3.0.1.0")})}), //
N("3.1+3.2", {N("3.1.0", {N("3.1.0.0")}), //
N("3.1.1", {N("3.1.1.0")}), //
N("3.2.0", {N("3.2.0.0")}), //
N("3.2.1", {N("3.2.1.0")})})})}));
MergeConsecutiveSiblings(this->NodeAt({3}), 0,
[](std::string* v0, const std::string& v1) {
absl::StrAppend(v0, "+", v1);
});
EXPECT_PRED_FORMAT2(
VerifyTree, this->root,
N("root", {N("0"), //
N("1", {N("1.0")}), //
N("2", {N("2.0", {N("2.0.0")}), //
N("2.1", {N("2.1.0")})}), //
N("3", {N("3.0+3.1+3.2", {N("3.0.0", {N("3.0.0.0")}), //
N("3.0.1", {N("3.0.1.0")}), //
N("3.1.0", {N("3.1.0.0")}), //
N("3.1.1", {N("3.1.1.0")}), //
N("3.2.0", {N("3.2.0.0")}), //
N("3.2.1", {N("3.2.1.0")})})})}));
MergeConsecutiveSiblings(this->root, 0,
[](std::string* v0, const std::string& v1) {
absl::StrAppend(v0, "+", v1);
});
EXPECT_PRED_FORMAT2(
VerifyTree, this->root,
N("root", {N("0+1", {N("1.0")}), //
N("2", {N("2.0", {N("2.0.0")}), //
N("2.1", {N("2.1.0")})}), //
N("3", {N("3.0+3.1+3.2", {N("3.0.0", {N("3.0.0.0")}), //
N("3.0.1", {N("3.0.1.0")}), //
N("3.1.0", {N("3.1.0.0")}), //
N("3.1.1", {N("3.1.1.0")}), //
N("3.2.0", {N("3.2.0.0")}), //
N("3.2.1", {N("3.2.1.0")})})})}));
}
}
TYPED_TEST(NodeWithParentTest, NearestCommonAncestor) {
EXPECT_EQ(NearestCommonAncestor( //
this->NodeAt({0}), //
this->NodeAt({1})),
&this->NodeAt({}));
EXPECT_EQ(NearestCommonAncestor( //
this->NodeAt({3, 1}), //
this->NodeAt({3, 2, 1, 0})),
&this->NodeAt({3}));
EXPECT_EQ(NearestCommonAncestor( //
this->NodeAt({3, 1}), //
this->NodeAt({3, 1, 1, 0})),
&this->NodeAt({3, 1}));
EXPECT_EQ(NearestCommonAncestor( //
this->NodeAt({2, 0, 0}), //
this->NodeAt({3, 2, 1, 0})),
&this->NodeAt({}));
EXPECT_EQ(NearestCommonAncestor( //
this->NodeAt({}), //
this->NodeAt({3, 2, 1, 0})),
&this->NodeAt({}));
using N = TypeParam;
N other_tree = N("", {N("A"), //
N("C", {N("CA")}), //
N("G", {N("GA", {N("GAA")}), //
N("GC", {N("GCA")})}), //
N("T", {N("TA", {N("TAA", {N("TAAA")}), //
N("TAC", {N("TACA")})}), //
N("TC", {N("TCA", {N("TCAA")}), //
N("TCC", {N("TCCA")})}), //
N("TG", {N("TGA", {N("TGAA")}), //
N("TGC", {N("TGCA")})})})});
EXPECT_EQ(NearestCommonAncestor( //
other_tree.Children().front(), //
this->NodeAt({0})),
nullptr);
}
TYPED_TEST(SimpleNodeTest, AdoptSubtree) {
using N = TypeParam;
// Const nodes are not supported
if constexpr (!std::is_const_v<TypeParam>) {
AdoptSubtree(this->NodeAt({2}), N("2.2"));
EXPECT_PRED_FORMAT2(
VerifyTree, this->root,
N("root", {N("0"), //
N("1", {N("1.0")}), //
N("2", {N("2.0", {N("2.0.0")}), //
N("2.1", {N("2.1.0")}), //
N("2.2")}), //
N("3", {N("3.0", {N("3.0.0", {N("3.0.0.0")}), //
N("3.0.1", {N("3.0.1.0")})}), //
N("3.1", {N("3.1.0", {N("3.1.0.0")}), //
N("3.1.1", {N("3.1.1.0")})}), //
N("3.2", {N("3.2.0", {N("3.2.0.0")}), //
N("3.2.1", {N("3.2.1.0")})})})}));
AdoptSubtree(this->NodeAt({2}), N("2.3", {N("2.3.0"), N("2.3.1")}),
N("2.4"));
EXPECT_PRED_FORMAT2(
VerifyTree, this->root,
N("root", {N("0"), //
N("1", {N("1.0")}), //
N("2", {N("2.0", {N("2.0.0")}), //
N("2.1", {N("2.1.0")}), //
N("2.2"), //
N("2.3", {N("2.3.0"), N("2.3.1")}), //
N("2.4")}), //
N("3", {N("3.0", {N("3.0.0", {N("3.0.0.0")}), //
N("3.0.1", {N("3.0.1.0")})}), //
N("3.1", {N("3.1.0", {N("3.1.0.0")}), //
N("3.1.1", {N("3.1.1.0")})}), //
N("3.2", {N("3.2.0", {N("3.2.0.0")}), //
N("3.2.1", {N("3.2.1.0")})})})}));
N other_tree = N("", {N("A"), //
N("C", {N("CA")}), //
N("G", {N("GA", {N("GAA")}), //
N("GC", {N("GCA")})}), //
N("T", {N("TA", {N("TAA", {N("TAAA")}), //
N("TAC", {N("TACA")})}), //
N("TC", {N("TCA", {N("TCAA")}), //
N("TCC", {N("TCCA")})}), //
N("TG", {N("TGA", {N("TGAA")}), //
N("TGC", {N("TGCA")})})})});
AdoptSubtree(this->root, std::move(other_tree));
EXPECT_PRED_FORMAT2(
VerifyTree, this->root,
N("root", {N("0"), //
N("1", {N("1.0")}), //
N("2", {N("2.0", {N("2.0.0")}), //
N("2.1", {N("2.1.0")}), //
N("2.2"), //
N("2.3", {N("2.3.0"), N("2.3.1")}), //
N("2.4")}), //
N("3", {N("3.0", {N("3.0.0", {N("3.0.0.0")}), //
N("3.0.1", {N("3.0.1.0")})}), //
N("3.1", {N("3.1.0", {N("3.1.0.0")}), //
N("3.1.1", {N("3.1.1.0")})}), //
N("3.2", {N("3.2.0", {N("3.2.0.0")}), //
N("3.2.1", {N("3.2.1.0")})})}), //
N("", {N("A"), //
N("C", {N("CA")}), //
N("G", {N("GA", {N("GAA")}), //
N("GC", {N("GCA")})}), //
N("T", {N("TA", {N("TAA", {N("TAAA")}), //
N("TAC", {N("TACA")})}), //
N("TC", {N("TCA", {N("TCAA")}), //
N("TCC", {N("TCCA")})}), //
N("TG", {N("TGA", {N("TGAA")}), //
N("TGC", {N("TGCA")})})})})}));
}
}
TYPED_TEST(SimpleNodeTest, AdoptSubtreesFrom) {
using N = TypeParam;
// Const nodes are not supported
if constexpr (!std::is_const_v<TypeParam>) {
N other_tree = N("", {N("A"), //
N("C", {N("CA")}), //
N("G", {N("GA", {N("GAA")}), //
N("GC", {N("GCA")})}), //
N("T", {N("TA", {N("TAA", {N("TAAA")}), //
N("TAC", {N("TACA")})}), //
N("TC", {N("TCA", {N("TCAA")}), //
N("TCC", {N("TCCA")})}), //
N("TG", {N("TGA", {N("TGAA")}), //
N("TGC", {N("TGCA")})})})});
AdoptSubtreesFrom(this->root, &other_tree);
EXPECT_PRED_FORMAT2(
VerifyTree, this->root,
N("root", {N("0"), //
N("1", {N("1.0")}), //
N("2", {N("2.0", {N("2.0.0")}), //
N("2.1", {N("2.1.0")})}), //
N("3", {N("3.0", {N("3.0.0", {N("3.0.0.0")}), //
N("3.0.1", {N("3.0.1.0")})}), //
N("3.1", {N("3.1.0", {N("3.1.0.0")}), //
N("3.1.1", {N("3.1.1.0")})}), //
N("3.2", {N("3.2.0", {N("3.2.0.0")}), //
N("3.2.1", {N("3.2.1.0")})})}), //
N("A"), //
N("C", {N("CA")}), //
N("G", {N("GA", {N("GAA")}), //
N("GC", {N("GCA")})}), //
N("T", {N("TA", {N("TAA", {N("TAAA")}), //
N("TAC", {N("TACA")})}), //
N("TC", {N("TCA", {N("TCAA")}), //
N("TCC", {N("TCCA")})}), //
N("TG", {N("TGA", {N("TGAA")}), //
N("TGC", {N("TGCA")})})})}));
EXPECT_PRED_FORMAT2(VerifyTree, other_tree, N(""));
AdoptSubtreesFrom(this->NodeAt({1, 0}), &this->NodeAt({3, 0}));
EXPECT_PRED_FORMAT2(
VerifyTree, this->root,
N("root", {N("0"), //
N("1", {N("1.0", {N("3.0.0", {N("3.0.0.0")}), //
N("3.0.1", {N("3.0.1.0")})})}), //
N("2", {N("2.0", {N("2.0.0")}), //
N("2.1", {N("2.1.0")})}), //
N("3", {N("3.0"), //
N("3.1", {N("3.1.0", {N("3.1.0.0")}), //
N("3.1.1", {N("3.1.1.0")})}), //
N("3.2", {N("3.2.0", {N("3.2.0.0")}), //
N("3.2.1", {N("3.2.1.0")})})}), //
N("A"), //
N("C", {N("CA")}), //
N("G", {N("GA", {N("GAA")}), //
N("GC", {N("GCA")})}), //
N("T", {N("TA", {N("TAA", {N("TAAA")}), //
N("TAC", {N("TACA")})}), //
N("TC", {N("TCA", {N("TCAA")}), //
N("TCC", {N("TCCA")})}), //
N("TG", {N("TGA", {N("TGAA")}), //
N("TGC", {N("TGCA")})})})}));
}
}
TYPED_TEST(SimpleNodeTest, Transform) {
using N = TypeParam;
IntNode id_lengths_tree = Transform<IntNode>(
this->root, [](const N& node) -> int { return node.id().size(); });
EXPECT_PRED_FORMAT2(
VerifyTree, id_lengths_tree,
IntNode(4, {IntNode(1), //
IntNode(1, {IntNode(3)}), //
IntNode(1, {IntNode(3, {IntNode(5)}), //
IntNode(3, {IntNode(5)})}), //
IntNode(1, {IntNode(3, {IntNode(5, {IntNode(7)}), //
IntNode(5, {IntNode(7)})}), //
IntNode(3, {IntNode(5, {IntNode(7)}), //
IntNode(5, {IntNode(7)})}), //
IntNode(3, {IntNode(5, {IntNode(7)}), //
IntNode(5, {IntNode(7)})})})}));
N censored_id_tree = Transform<std::remove_const_t<N>>(
id_lengths_tree, [](const IntNode& node) -> std::string {
return std::string(node.id(), 'x');
});
EXPECT_PRED_FORMAT2(
VerifyTree, censored_id_tree,
N("xxxx", {N("x"), //
N("x", {N("xxx")}), //
N("x", {N("xxx", {N("xxxxx")}), //
N("xxx", {N("xxxxx")})}), //
N("x", {N("xxx", {N("xxxxx", {N("xxxxxxx")}), //
N("xxxxx", {N("xxxxxxx")})}), //
N("xxx", {N("xxxxx", {N("xxxxxxx")}), //
N("xxxxx", {N("xxxxxxx")})}), //
N("xxx", {N("xxxxx", {N("xxxxxxx")}), //
N("xxxxx", {N("xxxxxxx")})})})}));
}
TYPED_TEST(NodeWithValueTest, DeepEqual) {
using N = TypeParam;
{
N copy = this->root;
const auto diff = DeepEqual(this->root, copy);
EXPECT_EQ(diff.left, nullptr);
EXPECT_EQ(diff.right, nullptr);
}
{
N censored_id_tree =
N("xxxx", {N("x"), //
N("x", {N("xxx")}), //
N("x", {N("xxx", {N("xxxxx")}), //
N("xxx", {N("xxxxx")})}), //
N("x", {N("xxx", {N("xxxxx", {N("xxxxxxx")}), //
N("xxxxx", {N("xxxxxxx")})}), //
N("xxx", {N("xxxxx", {N("xxxxxxx")}), //
N("xxxxx", {N("xxxxxxx")})}), //
N("xxx", {N("xxxxx", {N("xxxxxxx")}), //
N("xxxxx", {N("xxxxxxx")})})})});
const auto diff = DeepEqual(this->root, censored_id_tree,
[](const std::string& l, const std::string& r) {
return l.size() == r.size();
});
EXPECT_EQ(diff.left, nullptr);
EXPECT_EQ(diff.right, nullptr);
}
{
IntNode id_lengths_tree =
IntNode(4, {IntNode(1), //
IntNode(1, {IntNode(3)}), //
IntNode(1, {IntNode(3, {IntNode(5)}), //
IntNode(3, {IntNode(5)})}), //
IntNode(1, {IntNode(3, {IntNode(5, {IntNode(7)}), //
IntNode(5, {IntNode(7)})}), //
IntNode(3, {IntNode(5, {IntNode(7)}), //
IntNode(5, {IntNode(7)})}), //
IntNode(3, {IntNode(5, {IntNode(7)}), //
IntNode(5, {IntNode(7)})})})});
const auto diff = DeepEqual(this->root, id_lengths_tree,
[](const std::string& l, const int& r) {
return static_cast<int>(l.size()) == r;
});
EXPECT_EQ(diff.left, nullptr);
EXPECT_EQ(diff.right, nullptr);
}
{
std::remove_const_t<N> copy = this->root;
auto n2 = std::next(copy.Children().begin(), 2);
auto n21 = std::next(n2->Children().begin(), 1);
auto n3 = std::next(copy.Children().begin(), 3);
auto n31 = std::next(n3->Children().begin(), 1);
n21->set_id("foo");
n31->set_id("bar");
const auto diff = DeepEqual(this->root, copy);
EXPECT_EQ(diff.left, &this->NodeAt({2, 1}));
EXPECT_EQ(diff.right, &*n21);
}
{
N censored_id_tree =
N("xxxx", {N("x"), //
N("x", {N("xxx")}), //
N("x", {N("xxx", {N("xxxxx")}), //
N("xxx", {N("xxxxx")})}), //
N("x", {N("xxx", {N("xxxxx", {N("xxxxxxx")}), //
N("xxxxx", {N("xxxxxxx")})}), //
N("xxx", {N("xxxxx", {N("xxxxxxx")}), //
N("xxxxx", {N("xxxxxxx")})}), //
N("xxx", {N("xxxxx", {N("xxxxxxx")}), //
N("xxxxx", {N("WRONG")})})})});
auto n3 = std::next(censored_id_tree.Children().begin(), 3);
auto n32 = std::next(n3->Children().begin(), 2);
auto n321 = std::next(n32->Children().begin(), 1);
auto n3210 = n321->Children().begin();
const auto diff = DeepEqual(this->root, censored_id_tree,
[](const std::string& l, const std::string& r) {
return l.size() == r.size();
});
EXPECT_EQ(diff.left, &this->NodeAt({3, 2, 1, 0}));
EXPECT_EQ(diff.right, &*n3210);
}
{
IntNode id_lengths_tree =
IntNode(4, {IntNode(42), //
IntNode(1, {IntNode(3)}), //
IntNode(1, {IntNode(3, {IntNode(5)}), //
IntNode(3, {IntNode(5)})}), //
IntNode(1, {IntNode(3, {IntNode(5, {IntNode(7)}), //
IntNode(5, {IntNode(7)})}), //
IntNode(3, {IntNode(5, {IntNode(7)}), //
IntNode(5, {IntNode(9999)})}), //
IntNode(3, {IntNode(5, {IntNode(7)}), //
IntNode(999, {IntNode(7)})})})});
const auto diff = DeepEqual(this->root, id_lengths_tree,
[](const std::string& l, const int& r) {
return static_cast<int>(l.size()) == r;
});
EXPECT_EQ(diff.left, &this->NodeAt({0}));
EXPECT_EQ(diff.right, &*id_lengths_tree.Children().begin());
}
{
N other = N("root", {N("0"), //
N("1", {N("1.0")}), //
// Missing subtree:
// N("2", {N("2.0", {N("2.0.0")}),
// N("2.1", {N("2.1.0")})}),
N("3", {N("3.0", {N("3.0.0", {N("3.0.0.0")}), //
N("3.0.1", {N("3.0.1.0")})}), //
N("3.1", {N("3.1.0", {N("3.1.0.0")}), //
N("3.1.1", {N("3.1.1.0")})}), //
N("3.2", {N("3.2.0", {N("3.2.0.0")}), //
N("3.2.1", {N("3.2.1.0")})})})});
const auto diff = DeepEqual(this->root, other);
EXPECT_EQ(diff.left, &this->root);
EXPECT_EQ(diff.right, &other);
}
}
TYPED_TEST(NodeWithValueTest, StructureEqual) {
using N = IntNode;
{
static const IntNode matching_tree =
N(0, {N(1), //
N(2, {N(21)}), //
N(3, {N(31, {N(311)}), //
N(32, {N(321)})}), //
N(4, {N(41, {N(411, {N(4111)}), //
N(412, {N(4121)})}), //
N(42, {N(421, {N(4211)}), //
N(422, {N(4221)})}), //
N(43, {N(431, {N(4311)}), //
N(432, {N(4321)})})})});
auto result = StructureEqual(this->root, matching_tree);
EXPECT_EQ(result.left, nullptr);
EXPECT_EQ(result.right, nullptr);
}
{
static const IntNode matching_tree =
N(0, {N(1), //
N(2, {N(21)}), //
N(3, {N(31, {N(311)}), //
N(32, {N(321)})}), //
N(4, {N(41, {N(411, {N(4111)}), //
N(412, {N(4121)})}), //
// Missing subtree:
// N(42, {N(421, {N(4211)}),
// N(422, {N(4221)})}),
N(43, {N(431, {N(4311)}), //
N(432, {N(4321)})})})});
auto result = StructureEqual(this->root, matching_tree);
EXPECT_EQ(result.left, &this->NodeAt({3}));
EXPECT_EQ(result.right, &matching_tree.Children()[3]);
}
{
static const IntNode matching_tree =
N(0, {N(1), //
N(2, {N(21)}), //
N(3, {N(31, {N(311)}), //
N(32, {N(321)}), //
// Extra subtree:
N(33, {N(331)})}), //
N(4, {N(41, {N(411, {N(4111)}), //
N(412, {N(4121)})}), //
N(42, {N(421, {N(4211)}), //
N(422, {N(4221)})}), //
N(43, {N(431, {N(4311)}), //
N(432, {N(4321)})})})});
auto result = StructureEqual(this->root, matching_tree);
EXPECT_EQ(result.left, &this->NodeAt({2}));
EXPECT_EQ(result.right, &matching_tree.Children()[2]);
}
{
static const IntNode matching_tree =
N(0, {N(1), //
N(2, {N(21)}), //
N(3, {N(31, {N(311)}), //
N(32, {N(321)}), //
// Extra subtree:
N(33, {N(331)})}), //
N(4, {N(41, {N(411, {N(4111)}), //
N(412, {N(4121)})}), //
// Missing subtree:
// N(42, {N(421, {N(4211)}),
// N(422, {N(4221)})}),
N(43, {N(431, {N(4311)}), //
N(432, {N(4321)})})})});
auto result = StructureEqual(this->root, matching_tree);
EXPECT_EQ(result.left, &this->NodeAt({2}));
EXPECT_EQ(result.right, &matching_tree.Children()[2]);
}
}
} // namespace
} // namespace verible