#include "Graph/Path.h" #include "Graph/ConstrainedBidiBFSVisitor.h" #include "Graph/BidirectionalBFS.h" #include #include #include #include using namespace std; using namespace boost; typedef adjacency_list Graph; typedef graph_traits::vertex_descriptor V; typedef graph_traits::edge_descriptor e; typedef std::vector< Path > PathList; static const size_t NO_MEM_LIMIT = std::numeric_limits::max(); namespace { class ConstrainedBidiBFSVisitorTest : public ::testing::Test { protected: Graph simpleAcyclicGraph; Graph simpleCyclicGraph; Graph cyclicGraph; ConstrainedBidiBFSVisitorTest() { add_edge(0, 1, simpleAcyclicGraph); add_edge(0, 2, simpleAcyclicGraph); add_edge(2, 3, simpleAcyclicGraph); add_edge(0, 1, simpleCyclicGraph); add_edge(1, 3, simpleCyclicGraph); add_edge(0, 2, simpleCyclicGraph); add_edge(2, 3, simpleCyclicGraph); add_edge(0, 1, cyclicGraph); add_edge(1, 2, cyclicGraph); add_edge(1, 3, cyclicGraph); add_edge(2, 3, cyclicGraph); add_edge(3, 4, cyclicGraph); add_edge(3, 5, cyclicGraph); add_edge(4, 5, cyclicGraph); add_edge(5, 6, cyclicGraph); } }; TEST_F(ConstrainedBidiBFSVisitorTest, IdentifyUniquePath) { ConstrainedBidiBFSVisitor visitor(simpleAcyclicGraph, 0, 3, 1, 1, 3, 2, NO_LIMIT, NO_MEM_LIMIT); bidirectionalBFS(simpleAcyclicGraph, 0, 3, visitor); Path uniquePath; PathSearchResult result = visitor.uniquePathToGoal(uniquePath); ASSERT_EQ(FOUND_PATH, result); ASSERT_EQ("0,2,3", uniquePath.str()); } TEST_F(ConstrainedBidiBFSVisitorTest, StartEqualsGoal) { ConstrainedBidiBFSVisitor visitor(simpleAcyclicGraph, 0, 0, 1, 1, 1, 2, NO_LIMIT, NO_MEM_LIMIT); bidirectionalBFS(simpleAcyclicGraph, 0, 0, visitor); Path uniquePath; PathSearchResult result = visitor.uniquePathToGoal(uniquePath); ASSERT_EQ(FOUND_PATH, result); ASSERT_EQ("0", uniquePath.str()); } TEST_F(ConstrainedBidiBFSVisitorTest, SingleEdgeToGoal) { ConstrainedBidiBFSVisitor visitor(simpleAcyclicGraph, 0, 1, 1, 1, 2, 2, NO_LIMIT, NO_MEM_LIMIT); bidirectionalBFS(simpleAcyclicGraph, 0, 1, visitor); Path uniquePath; PathSearchResult result = visitor.uniquePathToGoal(uniquePath); ASSERT_EQ(FOUND_PATH, result); ASSERT_EQ("0,1", uniquePath.str()); } TEST_F(ConstrainedBidiBFSVisitorTest, RespectMaxPathLength) { ConstrainedBidiBFSVisitor visitor(cyclicGraph, 0, 6, 4, 5, 6, 2, NO_LIMIT, NO_MEM_LIMIT); bidirectionalBFS(cyclicGraph, 0, 6, visitor); vector< Path > paths; PathSearchResult result = visitor.pathsToGoal(paths); // We expect the fourth path ("0,1,2,3,4,5,6") // to be excluded by the max path length limit (6). set expectedPaths; expectedPaths.insert("0,1,3,5,6"); expectedPaths.insert("0,1,2,3,5,6"); expectedPaths.insert("0,1,3,4,5,6"); EXPECT_EQ(FOUND_PATH, result); ASSERT_EQ(3u, paths.size()); // check that each path is one of the expected ones for (unsigned i = 0; i < 3; i++) ASSERT_TRUE(expectedPaths.find(paths[i].str()) != expectedPaths.end()); // check that each path is unique for (unsigned i = 0; i < 2; i++) ASSERT_TRUE(paths[i].str() != paths[i+1].str()); } TEST_F(ConstrainedBidiBFSVisitorTest, RespectMinPathLength) { ConstrainedBidiBFSVisitor visitor(cyclicGraph, 0, 6, 4, 6, 7, 2, NO_LIMIT, NO_MEM_LIMIT); bidirectionalBFS(cyclicGraph, 0, 6, visitor); vector< Path > paths; PathSearchResult result = visitor.pathsToGoal(paths); // We expect the first path ("0,1,3,5,6") // to be excluded by the min path length limit (6). set expectedPaths; expectedPaths.insert("0,1,2,3,5,6"); expectedPaths.insert("0,1,3,4,5,6"); expectedPaths.insert("0,1,2,3,4,5,6"); EXPECT_EQ(FOUND_PATH, result); ASSERT_EQ(3u, paths.size()); // check that each path is one of the expected ones for (unsigned i = 0; i < 3; i++) ASSERT_TRUE(expectedPaths.find(paths[i].str()) != expectedPaths.end()); // check that each path is unique for (unsigned i = 0; i < 2; i++) ASSERT_TRUE(paths[i].str() != paths[i+1].str()); } TEST_F(ConstrainedBidiBFSVisitorTest, RespectMaxPathsLimit) { ConstrainedBidiBFSVisitor visitor(simpleCyclicGraph, 0, 3, 1, 1, 3, 2, NO_LIMIT, NO_MEM_LIMIT); bidirectionalBFS(simpleCyclicGraph, 0, 3, visitor); Path uniquePath; EXPECT_EQ(visitor.uniquePathToGoal(uniquePath), TOO_MANY_PATHS); } TEST_F(ConstrainedBidiBFSVisitorTest, ReturnMultiplePaths) { ConstrainedBidiBFSVisitor visitor(simpleCyclicGraph, 0, 3, 2, 1, 3, 2, NO_LIMIT, NO_MEM_LIMIT); bidirectionalBFS(simpleCyclicGraph, 0, 3, visitor); PathList paths; PathSearchResult result = visitor.pathsToGoal(paths); EXPECT_EQ(FOUND_PATH, result); ASSERT_EQ(2u, paths.size()); string path1 = paths[0].str(); string path2 = paths[1].str(); EXPECT_TRUE(path1 != path2); ASSERT_TRUE(path1 == "0,1,3" || path1 == "0,2,3"); ASSERT_TRUE(path2 == "0,1,3" || path2 == "0,2,3"); } TEST_F(ConstrainedBidiBFSVisitorTest, RespectMaxBranches) { ConstrainedBidiBFSVisitor visitor(simpleCyclicGraph, 0, 3, 2, 1, 3, 1, NO_LIMIT, NO_MEM_LIMIT); bidirectionalBFS(simpleCyclicGraph, 0, 3, visitor); PathList paths; PathSearchResult result = visitor.pathsToGoal(paths); EXPECT_EQ(TOO_MANY_BRANCHES, result); EXPECT_EQ(0u, paths.size()); // expect early exit from traversal EXPECT_EQ(3u, visitor.getNumNodesVisited()); } TEST_F(ConstrainedBidiBFSVisitorTest, NoLimitForBranches) { ConstrainedBidiBFSVisitor visitor(simpleCyclicGraph, 0, 3, 2, 1, 3, NO_LIMIT, NO_LIMIT, NO_MEM_LIMIT); bidirectionalBFS(simpleCyclicGraph, 0, 3, visitor); PathList paths; PathSearchResult result = visitor.pathsToGoal(paths); EXPECT_EQ(FOUND_PATH, result); ASSERT_EQ(2u, paths.size()); string path1 = paths[0].str(); string path2 = paths[1].str(); EXPECT_TRUE(path1 != path2); ASSERT_TRUE(path1 == "0,1,3" || path1 == "0,2,3"); ASSERT_TRUE(path2 == "0,1,3" || path2 == "0,2,3"); } }