blob: dd316357de2dce1e6d597277eacc7ec32835e1fc [file] [log] [blame]
// 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/util/vector_tree_iterators.h"
#include <cstddef>
#include <iterator>
#include <sstream>
#include <type_traits>
#include <vector>
#include "absl/strings/str_join.h"
#include "common/util/tree_operations.h"
#include "common/util/vector_tree.h"
#include "gmock/gmock.h"
#include "gtest/gtest.h"
namespace verible {
// Iterator value printers used by Google Test
template <typename TreeType>
static void PrintTo(const VectorTreeLeavesIterator<TreeType>& it,
std::ostream* os) {
*os << "VectorTreeLeavesIterator(" << *it << ")";
}
template <typename TreeType>
static void PrintTo(const VectorTreePreOrderIterator<TreeType>& it,
std::ostream* os) {
*os << "VectorTreePreOrderIterator(" << *it << ")";
}
template <typename TreeType>
static void PrintTo(const VectorTreePostOrderIterator<TreeType>& it,
std::ostream* os) {
*os << "VectorTreePostOrderIterator(" << *it << ")";
}
namespace {
using Tree = verible::VectorTree<int>;
template <typename Iterator, typename TreeType>
void ExpectForwardIterator(TreeType* node, TreeType* next_node) {
EXPECT_TRUE(std::is_default_constructible_v<Iterator>);
EXPECT_TRUE(std::is_copy_constructible_v<Iterator>);
EXPECT_TRUE(std::is_copy_assignable_v<Iterator>);
EXPECT_TRUE(std::is_destructible_v<Iterator>);
EXPECT_TRUE(std::is_swappable_v<Iterator>);
Iterator node_it(node), next_node_it(next_node);
Iterator node_it_2(node);
// i == j
EXPECT_TRUE(node_it == node_it_2);
// i != j
EXPECT_TRUE(node_it != next_node_it);
// *i
EXPECT_EQ(&(*node_it), node);
EXPECT_EQ(&(*next_node_it), next_node);
// i->member
EXPECT_EQ(next_node_it->Value(), next_node->Value());
// ++i
{
auto i = node_it;
EXPECT_EQ(++i, next_node_it);
EXPECT_EQ(i, next_node_it);
EXPECT_NE(i, node_it);
}
// i++
{
auto i = node_it;
EXPECT_EQ(i++, node_it);
EXPECT_EQ(i, next_node_it);
EXPECT_NE(i, node_it);
}
// *i++
{
auto i = node_it;
EXPECT_EQ(&(*i++), node);
EXPECT_EQ(i, next_node_it);
EXPECT_NE(i, node_it);
}
if constexpr (!std::is_const_v<typename Iterator::value_type>) {
auto tree = Tree(0, //
Tree(1), //
Tree(2));
auto other_tree = Tree(200, //
Tree(2001), //
Tree(2002));
auto it = Iterator(&tree.Children()[1]);
// *i = j
*it = other_tree;
EXPECT_EQ(tree.Children()[1].Value(), 200);
}
}
TEST(VectorTreeIteratorTest, ForwardIteratorInterface) {
auto tree = Tree(0, //
Tree(1), //
Tree(2, //
Tree(21), //
Tree(22), //
Tree(23)), //
Tree(3));
ExpectForwardIterator<VectorTreeLeavesIterator<Tree>>(
&tree.Children()[0], &tree.Children()[1].Children()[0]);
ExpectForwardIterator<VectorTreeLeavesIterator<const Tree>>(
&tree.Children()[0], &tree.Children()[1].Children()[0]);
ExpectForwardIterator<VectorTreePreOrderIterator<Tree>>(&tree.Children()[0],
&tree.Children()[1]);
ExpectForwardIterator<VectorTreePreOrderIterator<const Tree>>(
&tree.Children()[0], &tree.Children()[1]);
ExpectForwardIterator<VectorTreePostOrderIterator<Tree>>(
&tree.Children()[0], &tree.Children()[1].Children()[0]);
ExpectForwardIterator<VectorTreePostOrderIterator<const Tree>>(
&tree.Children()[0], &tree.Children()[1].Children()[0]);
}
struct TestCaseData {
Tree tree;
// RootNodeTraversal test data
struct {
std::vector<int> expected_sequence_leaves;
std::vector<int> expected_sequence_pre_order;
std::vector<int> expected_sequence_post_order;
} root_node_traversal;
// SubtreeTraversal and IteratorSubtreeTraversal test data
struct {
std::vector<size_t> subtree_path;
std::vector<int> expected_sequence_leaves;
std::vector<int> expected_sequence_pre_order;
std::vector<int> expected_sequence_post_order;
} subtree_traversal;
};
static const TestCaseData kTestCasesData[] = {
{
Tree(0),
// RootNodeTraversal test data
{
{0},
{0},
{0},
},
// SubtreeTraversal and IteratorSubtreeTraversal test data (skipped)
{},
},
{
Tree(0, //
Tree(1), //
Tree(2), //
Tree(3)),
// RootNodeTraversal test data
{
{1, 2, 3},
{0, 1, 2, 3},
{1, 2, 3, 0},
},
// SubtreeTraversal and IteratorSubtreeTraversal test data
{
{0}, // subtree path
{1},
{1},
{1},
},
},
{
Tree(0, //
Tree(1, //
Tree(11, //
Tree(111, //
Tree(1111))))),
// RootNodeTraversal test data
{
{1111},
{0, 1, 11, 111, 1111},
{1111, 111, 11, 1, 0},
},
// SubtreeTraversal and IteratorSubtreeTraversal test data
{
{0, 0}, // subtree path
{1111},
{11, 111, 1111},
{1111, 111, 11},
},
},
{
Tree(0, //
Tree(1, //
Tree(11, //
Tree(111), //
Tree(112)), //
Tree(12), //
Tree(13)), //
Tree(2, //
Tree(21), //
Tree(22), //
Tree(23, //
Tree(231), //
Tree(232))), //
Tree(3)),
// RootNodeTraversal test data
{
{111, 112, 12, 13, 21, 22, 231, 232, 3},
{0, 1, 11, 111, 112, 12, 13, 2, 21, 22, 23, 231, 232, 3},
{111, 112, 11, 12, 13, 1, 21, 22, 231, 232, 23, 2, 3, 0},
},
// SubtreeTraversal and IteratorSubtreeTraversal test data
{
{0}, // subtree path
{111, 112, 12, 13},
{1, 11, 111, 112, 12, 13},
{111, 112, 11, 12, 13, 1},
},
},
{
Tree(0, //
Tree(1), //
Tree(2, //
Tree(21, //
Tree(211), //
Tree(212)), //
Tree(22), //
Tree(23)), //
Tree(3, //
Tree(31), //
Tree(32), //
Tree(33, //
Tree(331), //
Tree(332)))),
// RootNodeTraversal test data
{
{1, 211, 212, 22, 23, 31, 32, 331, 332},
{0, 1, 2, 21, 211, 212, 22, 23, 3, 31, 32, 33, 331, 332},
{1, 211, 212, 21, 22, 23, 2, 31, 32, 331, 332, 33, 3, 0},
},
// SubtreeTraversal and IteratorSubtreeTraversal test data
{
{2}, // subtree path
{31, 32, 331, 332},
{3, 31, 32, 33, 331, 332},
{31, 32, 331, 332, 33, 3},
},
},
};
template <typename NodesRange, typename ValuesRange>
void ExpectNodesRangesValuesEq(const NodesRange& nodes,
const ValuesRange& expected_values) {
auto expected_it = expected_values.begin();
for (const auto& node : nodes) {
EXPECT_NE(expected_it, expected_values.end());
EXPECT_EQ(node.Value(), *expected_it);
++expected_it;
}
EXPECT_EQ(expected_it, expected_values.end());
}
TEST(VectorTreeIteratorTest, RootNodeTraversal) {
for (const auto& data : kTestCasesData) {
std::ostringstream trace_msg;
trace_msg << "Input tree:\n" << data.tree;
SCOPED_TRACE(trace_msg.str());
{
SCOPED_TRACE("VectorTreeLeavesTraversal");
ExpectNodesRangesValuesEq(
VectorTreeLeavesTraversal(data.tree),
data.root_node_traversal.expected_sequence_leaves);
}
{
SCOPED_TRACE("VectorTreePreOrderTraversal");
ExpectNodesRangesValuesEq(
VectorTreePreOrderTraversal(data.tree),
data.root_node_traversal.expected_sequence_pre_order);
}
{
SCOPED_TRACE("VectorTreePostOrderTraversal");
ExpectNodesRangesValuesEq(
VectorTreePostOrderTraversal(data.tree),
data.root_node_traversal.expected_sequence_post_order);
}
}
}
TEST(VectorTreeIteratorTest, SubtreeTraversal) {
for (const auto& data : kTestCasesData) {
const auto subtree_path = data.subtree_traversal.subtree_path;
if (subtree_path.empty()) continue;
const auto& subtree =
DescendPath(data.tree, subtree_path.begin(), subtree_path.end());
std::ostringstream trace_msg;
trace_msg << "Input tree:\n"
<< data.tree
<< "\nSubtree path: " << absl::StrJoin(subtree_path, ".");
SCOPED_TRACE(trace_msg.str());
{
SCOPED_TRACE("VectorTreeLeavesTraversal");
ExpectNodesRangesValuesEq(
VectorTreeLeavesTraversal(subtree),
data.subtree_traversal.expected_sequence_leaves);
}
{
SCOPED_TRACE("VectorTreePreOrderTraversal");
ExpectNodesRangesValuesEq(
VectorTreePreOrderTraversal(subtree),
data.subtree_traversal.expected_sequence_pre_order);
}
{
SCOPED_TRACE("VectorTreePostOrderTraversal");
ExpectNodesRangesValuesEq(
VectorTreePostOrderTraversal(subtree),
data.subtree_traversal.expected_sequence_post_order);
}
}
}
TEST(VectorTreeIteratorTest, IteratorSubtreeTraversal) {
for (const auto& data : kTestCasesData) {
const auto subtree_path = data.subtree_traversal.subtree_path;
if (subtree_path.empty()) continue;
const auto& subtree =
DescendPath(data.tree, subtree_path.begin(), subtree_path.end());
std::ostringstream trace_msg;
trace_msg << "Input tree:\n"
<< data.tree
<< "\nSubtree path: " << absl::StrJoin(subtree_path, ".");
SCOPED_TRACE(trace_msg.str());
// VectorTreeLeavesIterator doesn't support subranges
{
SCOPED_TRACE("VectorTreePreOrderIterator");
ExpectNodesRangesValuesEq(
VectorTreePreOrderIterator(&subtree),
data.subtree_traversal.expected_sequence_pre_order);
}
{
SCOPED_TRACE("VectorTreePostOrderIterator");
ExpectNodesRangesValuesEq(
VectorTreePostOrderIterator(&subtree),
data.subtree_traversal.expected_sequence_post_order);
}
}
}
} // namespace
} // namespace verible