/* * Unit tests for PriorityQueue data structure. * * Depends on the Boost.Test unit test framework. * Tested with Boost v1.74, available from https://www.boost.org/ */ #include #include #include #include #include #include #include #define BOOST_TEST_MODULE priority_queue #include #include "priority_queue.hpp" BOOST_AUTO_TEST_SUITE(test_priority_queue) BOOST_AUTO_TEST_CASE(test_empty) { using Queue = mwmatching::PriorityQueue; Queue q; BOOST_TEST(q.empty() == true); } BOOST_AUTO_TEST_CASE(test_single) { using Queue = mwmatching::PriorityQueue; Queue q; Queue::Node n1; BOOST_TEST(n1.valid() == false); q.insert(&n1, 5, "a"); BOOST_TEST(n1.valid() == true); BOOST_TEST(n1.prio() == 5); BOOST_TEST(q.empty() == false); BOOST_TEST(q.min_prio() == 5); BOOST_TEST(q.min_elem() == std::string("a")); q.set_prio(&n1, 3); BOOST_TEST(n1.prio() == 3); BOOST_TEST(q.min_prio() == 3); BOOST_TEST(q.min_elem() == std::string("a")); q.remove(&n1); BOOST_TEST(n1.valid() == false); BOOST_TEST(q.empty() == true); } BOOST_AUTO_TEST_CASE(test_simple) { using Queue = mwmatching::PriorityQueue; Queue q; Queue::Node nodes[10]; q.insert(&nodes[0], 9, 'a'); BOOST_TEST(q.min_prio() == 9); BOOST_TEST(q.min_elem() == 'a'); q.insert(&nodes[1], 4, 'b'); BOOST_TEST(q.min_prio() == 4); BOOST_TEST(q.min_elem() == 'b'); q.insert(&nodes[2], 7, 'c'); BOOST_TEST(q.min_prio() == 4); BOOST_TEST(q.min_elem() == 'b'); q.insert(&nodes[3], 5, 'd'); BOOST_TEST(q.min_prio() == 4); BOOST_TEST(q.min_elem() == 'b'); q.insert(&nodes[4], 8, 'e'); BOOST_TEST(q.min_prio() == 4); BOOST_TEST(q.min_elem() == 'b'); q.insert(&nodes[5], 6, 'f'); BOOST_TEST(q.min_prio() == 4); BOOST_TEST(q.min_elem() == 'b'); q.insert(&nodes[6], 4, 'g'); q.insert(&nodes[7], 5, 'h'); q.insert(&nodes[8], 2, 'i'); BOOST_TEST(q.min_prio() == 2); BOOST_TEST(q.min_elem() == 'i'); q.insert(&nodes[9], 6, 'j'); BOOST_TEST(q.min_prio() == 2); BOOST_TEST(q.min_elem() == 'i'); q.set_prio(&nodes[2], 1); BOOST_TEST(q.min_prio() == 1); BOOST_TEST(q.min_elem() == 'c'); q.set_prio(&nodes[4], 3); BOOST_TEST(q.min_prio() == 1); BOOST_TEST(q.min_elem() == 'c'); q.remove(&nodes[2]); BOOST_TEST(q.min_prio() == 2); BOOST_TEST(q.min_elem() == 'i'); q.remove(&nodes[8]); BOOST_TEST(q.min_prio() == 3); BOOST_TEST(q.min_elem() == 'e'); q.remove(&nodes[4]); q.remove(&nodes[1]); BOOST_TEST(q.min_prio() == 4); BOOST_TEST(q.min_elem() == 'g'); q.remove(&nodes[3]); q.remove(&nodes[9]); BOOST_TEST(q.min_prio() == 4); BOOST_TEST(q.min_elem() == 'g'); q.remove(&nodes[6]); BOOST_TEST(q.min_prio() == 5); BOOST_TEST(q.min_elem() == 'h'); BOOST_TEST(q.empty() == false); q.clear(); BOOST_TEST(q.empty() == true); } BOOST_AUTO_TEST_CASE(test_increase_prio) { using Queue = mwmatching::PriorityQueue; Queue q; Queue::Node n1; q.insert(&n1, 5, 'a'); q.set_prio(&n1, 8); BOOST_TEST(n1.prio() == 8); BOOST_TEST(q.min_prio() == 8); q.clear(); Queue::Node n2, n3, n4; q.insert(&n1, 9, 'A'); q.insert(&n2, 4, 'b'); q.insert(&n3, 7, 'c'); q.insert(&n4, 5, 'd'); BOOST_TEST(q.min_prio() == 4); BOOST_TEST(q.min_elem() == 'b'); q.set_prio(&n2, 8); BOOST_TEST(n2.prio() == 8); BOOST_TEST(q.min_elem() == 'd'); BOOST_TEST(q.min_prio() == 5); q.set_prio(&n3, 10); BOOST_TEST(n3.prio() == 10); BOOST_TEST(q.min_elem() == 'd'); q.remove(&n4); BOOST_TEST(q.min_elem() == 'b'); q.remove(&n2); BOOST_TEST(q.min_prio() == 9); BOOST_TEST(q.min_elem() == 'A'); q.remove(&n1); BOOST_TEST(q.min_elem() == 'c'); BOOST_TEST(q.min_prio() == 10); q.remove(&n3); BOOST_TEST(q.empty() == true); } BOOST_AUTO_TEST_CASE(test_random) { using Queue = mwmatching::PriorityQueue; Queue q; const int num_elem = 1000; std::vector, int, int>> elems; int next_data = 0; std::mt19937 rng(34567); auto check = [&q,&elems]() { int min_prio = q.min_prio(); int min_data = q.min_elem(); int best_prio = INT_MAX; bool found = false; for (const auto& v : elems) { int this_prio = std::get<1>(v); int this_data = std::get<2>(v); best_prio = std::min(best_prio, this_prio); if ((this_prio == min_prio) && (this_data == min_data)) { found = true; } } BOOST_TEST(found == true); BOOST_TEST(min_prio == best_prio); }; for (int i = 0; i < num_elem; ++i) { ++next_data; int prio = std::uniform_int_distribution<>(0, 1000000)(rng); std::unique_ptr nptr(new Queue::Node); q.insert(nptr.get(), prio, next_data); elems.push_back(std::make_tuple(std::move(nptr), prio, next_data)); check(); } for (int i = 0; i < 10000; ++i) { int p = std::uniform_int_distribution<>(0, num_elem - 1)(rng); Queue::Node* node = std::get<0>(elems[p]).get(); int prio = std::get<1>(elems[p]); prio = std::uniform_int_distribution<>(0, 1000000)(rng); q.set_prio(node, prio); std::get<1>(elems[p]) = prio; check(); p = std::uniform_int_distribution<>(0, num_elem - 1)(rng); node = std::get<0>(elems[p]).get(); q.remove(node); elems.erase(elems.begin() + p); check(); ++next_data; prio = std::uniform_int_distribution<>(0, 1000000)(rng); std::unique_ptr nptr(new Queue::Node); q.insert(nptr.get(), prio, next_data); elems.push_back(std::make_tuple(std::move(nptr), prio, next_data)); check(); } for (int i = 0; i < num_elem; ++i) { int p = std::uniform_int_distribution<>(0, num_elem - 1 - i)(rng); Queue::Node* node = std::get<0>(elems[p]).get(); q.remove(node); elems.erase(elems.begin() + p); if (! elems.empty()) { check(); } } BOOST_TEST(q.empty() == true); } BOOST_AUTO_TEST_SUITE_END()