Simplify tests

This commit is contained in:
Robert Haschke 2021-04-01 00:17:43 +02:00
parent 4e09d78239
commit dc8cd34b86

View File

@ -138,234 +138,184 @@ unsigned int ForwardMockup::id_ = 0;
unsigned int BackwardMockup::id_ = 0; unsigned int BackwardMockup::id_ = 0;
unsigned int Connect::id_ = 0; unsigned int Connect::id_ = 0;
void resetIds() { struct TestBase : public testing::Test
GeneratorMockup::id_ = 0; {
ForwardMockup::id_ = 0; Task task;
BackwardMockup::id_ = 0; TestBase() {
Connect::id_ = 0; resetIds();
} task.setRobotModel(getModel());
}
template <typename C, typename S> void resetIds() {
auto add(C& container, S* stage) -> S* { GeneratorMockup::id_ = 0;
Stage::pointer ptr{ stage }; ForwardMockup::id_ = 0;
container.add(std::move(ptr)); BackwardMockup::id_ = 0;
return stage; Connect::id_ = 0;
} }
template <typename C, typename S>
auto add(C& container, S* stage) -> S* {
container.add(Stage::pointer(stage));
return stage;
}
};
using ConnectConnect = TestBase;
// https://github.com/ros-planning/moveit_task_constructor/issues/182 // https://github.com/ros-planning/moveit_task_constructor/issues/182
TEST(ConnectConnect, SuccSucc) { TEST_F(ConnectConnect, SuccSucc) {
resetIds(); add(task, new GeneratorMockup({ 1, 2, 3 }));
add(task, new Connect());
add(task, new GeneratorMockup({ 10, 20 }));
add(task, new Connect());
add(task, new GeneratorMockup());
Task t; EXPECT_TRUE(task.plan());
t.setRobotModel(getModel()); ASSERT_EQ(task.solutions().size(), 3u * 2u);
t.add(Stage::pointer(new GeneratorMockup({ 1, 2, 3 })));
t.add(Stage::pointer(new Connect()));
t.add(Stage::pointer(new GeneratorMockup({ 10, 20 })));
t.add(Stage::pointer(new Connect()));
t.add(Stage::pointer(new GeneratorMockup()));
EXPECT_TRUE(t.plan());
ASSERT_EQ(t.solutions().size(), 3u * 2u);
std::vector<double> expected_costs = { 11, 12, 13, 21, 22, 23 }; std::vector<double> expected_costs = { 11, 12, 13, 21, 22, 23 };
auto expected_cost = expected_costs.begin(); auto expected_cost = expected_costs.begin();
for (const auto& s : t.solutions()) { for (const auto& s : task.solutions()) {
EXPECT_EQ(s->cost(), *expected_cost); EXPECT_EQ(s->cost(), *expected_cost);
++expected_cost; ++expected_cost;
} }
} }
// https://github.com/ros-planning/moveit_task_constructor/issues/218 // https://github.com/ros-planning/moveit_task_constructor/issues/218
TEST(ConnectConnect, FailSucc) { TEST_F(ConnectConnect, FailSucc) {
resetIds(); add(task, new GeneratorMockup());
Task t; add(task, new Connect({ inf }, true));
t.setRobotModel(getModel()); add(task, new GeneratorMockup());
t.add(Stage::pointer(new GeneratorMockup())); add(task, new Connect());
t.add(Stage::pointer(new Connect({ inf }, true))); add(task, new GeneratorMockup());
t.add(Stage::pointer(new GeneratorMockup())); add(task, new ForwardDummy());
t.add(Stage::pointer(new Connect()));
t.add(Stage::pointer(new GeneratorMockup()));
t.add(Stage::pointer(new ForwardDummy()));
EXPECT_FALSE(t.plan()); EXPECT_FALSE(task.plan());
} }
TEST(Pruning, PropagatorFailure) { using Pruning = TestBase;
resetIds(); TEST_F(Pruning, PropagatorFailure) {
Task t; auto back = add(task, new BackwardMockup());
t.setRobotModel(getModel()); add(task, new GeneratorMockup({ 0 }));
BackwardMockup* b; add(task, new ForwardMockup({ inf }));
t.add(Stage::pointer(b = new BackwardMockup()));
t.add(Stage::pointer(new GeneratorMockup({ 0 })));
t.add(Stage::pointer(new ForwardMockup({ inf })));
EXPECT_FALSE(t.plan()); EXPECT_FALSE(task.plan());
ASSERT_EQ(task.solutions().size(), 0);
ASSERT_EQ(t.solutions().size(), 0);
// ForwardMockup fails, so the backward stage should never compute // ForwardMockup fails, so the backward stage should never compute
EXPECT_EQ(b->calls_, 0); EXPECT_EQ(back->calls_, 0);
} }
TEST(Pruning, PruningMultiForward) { TEST_F(Pruning, PruningMultiForward) {
resetIds(); add(task, new BackwardMockup());
Task t; add(task, new BackwardMockup());
t.setRobotModel(getModel()); add(task, new GeneratorMockup());
t.add(Stage::pointer(new BackwardMockup()));
t.add(Stage::pointer(new BackwardMockup()));
t.add(Stage::pointer(new GeneratorMockup()));
// spawn two solutions for the only incoming state // spawn two solutions for the only incoming state
t.add(Stage::pointer(new ForwardMockup({ 0, 0 }, 2))); add(task, new ForwardMockup({ 0, 0 }, 2));
// fail to extend the second solution // fail to extend the second solution
t.add(Stage::pointer(new ForwardMockup({ 0, inf }))); add(task, new ForwardMockup({ 0, inf }));
EXPECT_TRUE(t.plan()); EXPECT_TRUE(task.plan());
// the second (infeasible) solution in the last stage must not disable // the second (infeasible) solution in the last stage must not disable
// the earlier partial solution just because they share stage solutions // the earlier partial solution just because they share stage solutions
ASSERT_EQ(t.solutions().size(), 1); ASSERT_EQ(task.solutions().size(), 1);
EXPECT_EQ((*t.solutions().begin())->cost(), 0u); EXPECT_EQ((*task.solutions().begin())->cost(), 0u);
} }
TEST(Pruning, ConnectConnectForward) { TEST_F(Pruning, ConnectConnectForward) {
resetIds(); add(task, new GeneratorMockup());
Task t; auto c1 = add(task, new Connect({ inf, 0 })); // 1st attempt is a failue
t.setRobotModel(getModel()); add(task, new GeneratorMockup({ 0, 10, 20 }));
Connect *c1, *c2; add(task, new ForwardMockup());
t.add(Stage::pointer(new GeneratorMockup())); auto c2 = add(task, new Connect());
t.add(Stage::pointer(c1 = new Connect({ inf, 0 }))); // 1st attempt is a failure add(task, new GeneratorMockup({ 1, 2, 3 }));
t.add(Stage::pointer(new GeneratorMockup({ 0, 10, 20 })));
t.add(Stage::pointer(new ForwardMockup()));
t.add(Stage::pointer(c2 = new Connect()));
t.add(Stage::pointer(new GeneratorMockup({ 1, 2, 3 })));
t.plan(); task.plan();
ASSERT_EQ(t.solutions().size(), 3u * 2u); ASSERT_EQ(task.solutions().size(), 3u * 2u);
std::vector<double> expected_costs = { 11, 12, 13, 21, 22, 23 }; std::vector<double> expected_costs = { 11, 12, 13, 21, 22, 23 };
auto expected_cost = expected_costs.begin(); auto expected_cost = expected_costs.begin();
for (const auto& s : t.solutions()) { for (const auto& s : task.solutions()) {
EXPECT_EQ(s->cost(), *expected_cost); EXPECT_EQ(s->cost(), *expected_cost);
++expected_cost; ++expected_cost;
} }
EXPECT_EQ(c1->calls_, 3u); EXPECT_EQ(c1->calls_, 3u);
EXPECT_EQ(c2->calls_, 6u); EXPECT_EQ(c2->calls_, 6u); // expect 6 instead of 9 calls
} }
TEST(Pruning, ConnectConnectBackward) { TEST_F(Pruning, ConnectConnectBackward) {
resetIds(); add(task, new GeneratorMockup({ 1, 2, 3 }));
Task t; auto c1 = add(task, new Connect());
t.setRobotModel(getModel()); add(task, new BackwardMockup());
Connect *c1, *c2; add(task, new GeneratorMockup({ 0, inf, 10, 20 })); // 2nd is a dummy to postpone creation of 3rd
t.add(Stage::pointer(new GeneratorMockup({ 1, 2, 3 }))); auto c2 = add(task, new Connect({ inf, 0 })); // 1st attempt is a failure
t.add(Stage::pointer(c1 = new Connect())); add(task, new GeneratorMockup());
t.add(Stage::pointer(new BackwardMockup()));
t.add(Stage::pointer(new GeneratorMockup({ 0, inf, 10, 20 }))); // 2nd is a dummy to postpone creation of 3rd
t.add(Stage::pointer(c2 = new Connect({ inf, 0 }))); // 1st attempt is a failure
t.add(Stage::pointer(new GeneratorMockup()));
t.plan(); task.plan();
ASSERT_EQ(t.solutions().size(), 3u * 2u); ASSERT_EQ(task.solutions().size(), 3u * 2u);
std::vector<double> expected_costs = { 11, 12, 13, 21, 22, 23 }; std::vector<double> expected_costs = { 11, 12, 13, 21, 22, 23 };
auto expected_cost = expected_costs.begin(); auto expected_cost = expected_costs.begin();
for (const auto& s : t.solutions()) { for (const auto& s : task.solutions()) {
EXPECT_EQ(s->cost(), *expected_cost); EXPECT_EQ(s->cost(), *expected_cost);
++expected_cost; ++expected_cost;
} }
EXPECT_EQ(c1->calls_, 6u); // expect 6 instead of 9 calls
EXPECT_EQ(c2->calls_, 3u); EXPECT_EQ(c2->calls_, 3u);
EXPECT_EQ(c1->calls_, 6u);
} }
TEST(Pruning, PropagateInsideContainerBoundaries) { TEST_F(Pruning, PropagateIntoContainer) {
resetIds(); add(task, new BackwardMockup({ inf }));
Task t; add(task, new GeneratorMockup({ 0 }));
t.setRobotModel(getModel());
add(t, new BackwardMockup({ inf }));
add(t, new GeneratorMockup({ 0 }));
auto c{ std::make_unique<SerialContainer>() };
auto con = add(*c, new Connect());
add(*c, new GeneratorMockup({ 0 }));
t.add(std::move(c));
EXPECT_FALSE(t.plan()); auto inner = add(task, new SerialContainer());
auto con = add(*inner, new Connect());
add(*inner, new GeneratorMockup({ 0 }));
EXPECT_FALSE(task.plan());
// the failure in the backward stage (outside the container) // the failure in the backward stage (outside the container)
// should prune the expected computation of con // should prune the expected computation of con inside the container
EXPECT_EQ(con->calls_, 0); EXPECT_EQ(con->calls_, 0);
} }
TEST(Pruning, PropagateOutsideContainerBoundaries) { TEST_F(Pruning, PropagateFromContainerPull) {
resetIds(); auto back = add(task, new BackwardMockup());
Task t; add(task, new BackwardMockup());
t.setRobotModel(getModel()); add(task, new GeneratorMockup({ 0 }));
auto back = add(t, new BackwardMockup());
add(t, new BackwardMockup());
add(t, new GeneratorMockup({ 0 }));
auto c{ std::make_unique<SerialContainer>() };
add(*c, new ForwardMockup({ inf }));
add(*c, new ForwardMockup());
t.add(std::move(c));
EXPECT_FALSE(t.plan()); auto inner = add(task, new SerialContainer());
add(*inner, new ForwardMockup());
add(*inner, new ForwardMockup({ inf }));
EXPECT_FALSE(task.plan());
// the failure inside the container should prune computing of back // the failure inside the container should prune computing of back
EXPECT_EQ(back->calls_, 0); EXPECT_EQ(back->calls_, 0);
} }
TEST(Pruning, PropagateOutsideParallelContainerBoundariesSinglePathPull) { TEST_F(Pruning, PropagateFromContainerPush) {
resetIds(); auto inner = add(task, new SerialContainer());
Task t; add(*inner, new BackwardMockup({ inf }));
t.setRobotModel(getModel());
auto back = add(t, new BackwardMockup()); add(task, new GeneratorMockup({ 0 }));
add(t, new GeneratorMockup({ 0 })); auto con = add(task, new Connect());
auto c{ new Alternatives }; add(task, new GeneratorMockup({ 0 }));
add(*c, new ForwardMockup({ inf }));
add(t, c);
EXPECT_FALSE(t.plan()); EXPECT_FALSE(task.plan());
// the failure in Alternatives must prune computing back // the failure inside container should prune computing of con
EXPECT_EQ(back->calls_, 0);
}
TEST(Pruning, PropagateOutsideParallelContainerBoundariesSinglePathPush) {
resetIds();
Task t;
t.setRobotModel(getModel());
auto c{ new SerialContainer };
add(*c, new BackwardMockup({ inf }));
add(*c, new GeneratorMockup({ 0 }));
add(t, c);
auto con = add(t, new Connect());
add(t, new GeneratorMockup({ 0 }));
EXPECT_FALSE(t.plan());
// currently this is trivially true because containers only push full solutions
// (so c never contributes a solution con could operate on), but it might change
// in the future and the failure inside the container must still prune computing con
EXPECT_EQ(con->calls_, 0); EXPECT_EQ(con->calls_, 0);
} }
TEST(Pruning, PropagateOutsideParallelContainerBoundariesMultiplePaths) { TEST_F(Pruning, PropagateFromParallelContainerMultiplePaths) {
resetIds(); auto back = add(task, new BackwardMockup());
Task t; add(task, new GeneratorMockup({ 0 }));
t.setRobotModel(getModel()); auto inner = add(task, new Alternatives());
auto back = add(t, new BackwardMockup()); add(*inner, new ForwardMockup({ inf }));
add(t, new GeneratorMockup({ 0 })); auto serial = add(*inner, new SerialContainer());
auto c{ new Alternatives }; add(*serial, new Connect());
auto s1{ new SerialContainer }; add(*serial, new GeneratorMockup({ 0 }));
add(*s1, new Connect());
add(*s1, new GeneratorMockup({ 0 }));
add(*c, s1);
add(*c, new ForwardMockup({ inf }));
add(t, c);
EXPECT_TRUE(t.plan()); EXPECT_TRUE(task.plan());
// the failure in one branch of Alternatives must not prune computing back // the failure in one branch of Alternatives must not prune computing back
EXPECT_EQ(back->calls_, 1); EXPECT_EQ(back->calls_, 1);