gtsam/gtsam/base/tests/testTreeTraversal.cpp

156 lines
5.1 KiB
C++

/* ----------------------------------------------------------------------------
* GTSAM Copyright 2010, Georgia Tech Research Corporation,
* Atlanta, Georgia 30332-0415
* All Rights Reserved
* Authors: Frank Dellaert, et al. (see THANKS for the full author list)
* See LICENSE for the license information
* -------------------------------------------------------------------------- */
/**
* @file testTreeTraversal
* @brief Unit tests for tree traversal, cloning, and printing
* @author Richard Roberts
*/
#include <CppUnitLite/TestHarness.h>
#include <gtsam/base/TestableAssertions.h>
#include <gtsam/base/treeTraversal-inst.h>
#include <vector>
#include <list>
#include <memory>
using namespace gtsam;
struct TestNode {
typedef std::shared_ptr<TestNode> shared_ptr;
int data;
std::vector<shared_ptr> children;
TestNode() : data(-1) {}
TestNode(int data) : data(data) {}
};
struct TestForest {
typedef TestNode Node;
typedef Node::shared_ptr sharedNode;
FastVector<sharedNode> roots_;
const FastVector<sharedNode>& roots() const { return roots_; }
};
TestForest makeTestForest() {
// 0 1
// / |
// 2 3
// |
// 4
TestForest forest;
forest.roots_.push_back(std::make_shared<TestNode>(0));
forest.roots_.push_back(std::make_shared<TestNode>(1));
forest.roots_[0]->children.push_back(std::make_shared<TestNode>(2));
forest.roots_[0]->children.push_back(std::make_shared<TestNode>(3));
forest.roots_[0]->children[1]->children.push_back(std::make_shared<TestNode>(4));
return forest;
}
/* ************************************************************************* */
struct PreOrderVisitor {
// This visitor stores the nodes visited so the visit order can be checked later. It also returns
// the current node index as the data and checks that the parent index properly matches the index
// referenced in the node.
std::list<int> visited;
bool parentsMatched;
PreOrderVisitor() : parentsMatched(true) {}
int operator()(const TestNode::shared_ptr& node, int parentData) {
visited.push_back(node->data);
// Check parent index
const int expectedParentIndex =
node->data == 0 ? -1 :
node->data == 1 ? -1 :
node->data == 2 ? 0 :
node->data == 3 ? 0 :
node->data == 4 ? 3 :
node->data == 10 ? 0 :
(parentsMatched = false, -1);
if(expectedParentIndex != parentData)
parentsMatched = false;
return node->data;
}
};
/* ************************************************************************* */
struct PostOrderVisitor {
// This visitor stores the nodes visited so the visit order can be checked later.
std::list<int> visited;
void operator()(const TestNode::shared_ptr& node, int myData) {
visited.push_back(node->data);
}
};
/* ************************************************************************* */
std::list<int> getPreorder(const TestForest& forest) {
std::list<int> result;
PreOrderVisitor preVisitor;
int rootData = -1;
treeTraversal::DepthFirstForest(forest, rootData, preVisitor);
result = preVisitor.visited;
return result;
}
/* ************************************************************************* */
TEST(treeTraversal, DepthFirst)
{
// Get test forest
TestForest testForest = makeTestForest();
// Expected visit order
const std::list<int> preOrderExpected{0, 2, 3, 4, 1};
const std::list<int> postOrderExpected{2, 4, 3, 0, 1};
// Actual visit order
PreOrderVisitor preVisitor;
PostOrderVisitor postVisitor;
int rootData = -1;
treeTraversal::DepthFirstForest(testForest, rootData, preVisitor, postVisitor);
EXPECT(preVisitor.parentsMatched);
EXPECT(assert_container_equality(preOrderExpected, preVisitor.visited));
EXPECT(assert_container_equality(postOrderExpected, postVisitor.visited));
}
/* ************************************************************************* */
TEST(treeTraversal, CloneForest)
{
// Get test forest
TestForest testForest1 = makeTestForest();
TestForest testForest2;
testForest2.roots_ = treeTraversal::CloneForest(testForest1);
// Check that the original and clone both are expected
const std::list<int> preOrder1Expected{0, 2, 3, 4, 1};
std::list<int> preOrder1Actual = getPreorder(testForest1);
std::list<int> preOrder2Actual = getPreorder(testForest2);
EXPECT(assert_container_equality(preOrder1Expected, preOrder1Actual));
EXPECT(assert_container_equality(preOrder1Expected, preOrder2Actual));
// Modify clone - should not modify original
testForest2.roots_[0]->children[1]->data = 10;
const std::list<int> preOrderModifiedExpected{0, 2, 10, 4, 1};
// Check that original is the same and only the clone is modified
std::list<int> preOrder1ModActual = getPreorder(testForest1);
std::list<int> preOrder2ModActual = getPreorder(testForest2);
EXPECT(assert_container_equality(preOrder1Expected, preOrder1ModActual));
EXPECT(assert_container_equality(preOrderModifiedExpected, preOrder2ModActual));
}
/* ************************************************************************* */
int main() {
TestResult tr;
return TestRegistry::runAllTests(tr);
}
/* ************************************************************************* */