#include "ojl/bimap.hpp" #include <string> #include <cstdint> #include <vector> #include <map> #include <random> #if defined(TESTS_CATCH2_USE_OLD_HEADER) # include <catch2/catch.hpp> #else # include <catch2/catch_all.hpp> #endif using namespace ojl; TEST_CASE("Bimap basic type instances", "[bimap, instantiation]") { bimap<int, int> bm_ii; bimap<int, double> bm_id; bimap<double, float> bm_df; bimap<std::string, float> bm_sf; bimap<size_t, std::string> bm_us; } bimap<int, std::string> test_bimap_int_string_1() { bimap<int, std::string> bm; bm.insert(1,"1"); bm.insert(1,"12"); bm.insert(1,"13"); bm.insert(2,"2"); bm.insert(2,"12"); bm.insert(2,"23"); bm.insert(3,"13"); bm.insert(3,"23"); bm.l_insert(4); bm.r_insert("100"); bm.r_insert("100"); return bm; } bimap<int, int> test_bimap_int_int_1() { bimap<int, int> bm; bm.insert(1,10); bm.insert(1,12); bm.insert(1,13); bm.insert(2,20); bm.insert(2,12); bm.insert(2,23); bm.insert(3,13); bm.insert(3,23); bm.l_insert(4); return bm; } template <typename L, typename R> void test_counts(bimap<L,R> bm, std::map<L, size_t> l_counts, std::map<R, size_t> r_counts) { for (const auto &[l,count] : l_counts){ CHECK(bm.l_count(l) == count); } for (const auto &[r, count] : r_counts){ CHECK(bm.r_count(r) == count); } } template <typename L, typename R> void ordered_bimap_mill(std::set<L> left_elems, std::set<R> right_elems) { bimap<L,R> bm; std::map<L, size_t> l_counts; std::map<R, size_t> r_counts; //Insert all relations for (const auto &l : left_elems){ for (const auto &r : right_elems){ bm.insert(l,r); l_counts[l]++; r_counts[r]++; test_counts(bm, l_counts, r_counts); } } // Check that every relation is counted for every element for (const auto &l : left_elems){ CHECK(bm.l_count(l) == right_elems.size()); } for (const auto &r : right_elems){ CHECK(bm.r_count(r) == left_elems.size()); } test_counts(bm, l_counts, r_counts); auto all_relations = bm.all_relations_vec(); for (const auto &rel : all_relations){ //Erase one relation at a time, bm.erase(rel); l_counts[rel.first]--; r_counts[rel.second]--; test_counts(bm, l_counts, r_counts); } } template <typename L, typename R> void random_order_bimap_mill(std::set<L> left_elems, std::set<R> right_elems, size_t seed = 0) { std::mt19937 rng{seed}; bimap<L,R> bm; std::map<L, size_t> l_counts; std::map<R, size_t> r_counts; //Insert all relations for (const auto &l : left_elems){ for (const auto &r : right_elems){ bm.insert(l,r); l_counts[l]++; r_counts[r]++; test_counts(bm, l_counts, r_counts); } } // Check that every relation is counted for every element for (const auto &l : left_elems){ CHECK(bm.l_count(l) == right_elems.size()); } for (const auto &r : right_elems){ CHECK(bm.r_count(r) == left_elems.size()); } test_counts(bm, l_counts, r_counts); auto all_relations = bm.all_relations_vec(); for (size_t s = all_relations.size(); s > 0; s--){ size_t i = rng() % s; auto rel = all_relations[i]; bm.erase(rel); l_counts[rel.first]--; r_counts[rel.second]--; test_counts(bm, l_counts, r_counts); all_relations.erase(all_relations.begin()+i); } } TEST_CASE("Bimap insert", "[bimap, insert]") { bimap<int, int> bm = test_bimap_int_int_1(); bimap<int, std::string> bm2 = test_bimap_int_string_1(); } // To test: bimap erase // TODO: write a general test of consistency // A set of conditions that must hold TEST_CASE("Bimap count", "[bimap, count]") { { bimap<int, int> bm = test_bimap_int_int_1(); using left = bimap<int, int>::left; using right = bimap<int, int>::right; CHECK(bm.count(left{1}) == 3); CHECK(bm.count(left{2}) == 3); CHECK(bm.count(left{3}) == 2); CHECK(bm.count(left{4}) == 0); CHECK(bm.count(left{5}) == 0); CHECK(bm.count(right{10}) == 1); CHECK(bm.count(right{12}) == 2); CHECK(bm.count(right{13}) == 2); CHECK(bm.count(right{20}) == 1); CHECK(bm.count(right{23}) == 2); } { bimap<int, std::string> bm = test_bimap_int_string_1(); using left = bimap<int, std::string>::left; using right = bimap<int, std::string>::right; CHECK(bm.count(left{1}) == 3); CHECK(bm.count(left{2}) == 3); CHECK(bm.count(left{3}) == 2); CHECK(bm.count(left{4}) == 0); CHECK(bm.count(left{5}) == 0); CHECK(bm.count(right{"1"}) == 1); CHECK(bm.count(right{"12"}) == 2); CHECK(bm.count(right{"13"}) == 2); CHECK(bm.count(right{"2"}) == 1); CHECK(bm.count(right{"23"}) == 2); CHECK(bm.count(right{"100"}) == 0); } } TEST_CASE("Bimap left map view vectors", "[bimap, mapped_vector, left_view]") { bimap<int, int> bm = test_bimap_int_int_1(); using left = bimap<int, int>::left; using right = bimap<int, int>::right; auto v1 = bm.mapped_vector(left{1}); CHECK(v1.size() == 3); CHECK(v1[0] == 10); CHECK(v1[1] == 12); CHECK(v1[2] == 13); auto v2 = bm.mapped_vector(left{2}); CHECK(v2.size() == 3); CHECK(v2[0] == 12); CHECK(v2[1] == 20); CHECK(v2[2] == 23); auto v3 = bm.mapped_vector(left{3}); CHECK(v3.size() == 2); CHECK(v3[0] == 13); CHECK(v3[1] == 23); auto v4 = bm.mapped_vector(left{4}); CHECK(v4.size() == 0); auto v5 = bm.mapped_vector(left{5}); CHECK(v5.size() == 0); /* bimap<int, std::string> bm = test_bimap_int_int(); auto v1 = bm.mapped_vector(bimap_left_key(1)); CHECK(v1.size() == 3); CHECK(v1[0] == 10); CHECK(v1[1] == 12); CHECK(v1[2] == 13); auto v2 = bm.mapped_vector(bimap_left_key(2)); CHECK(v2.size() == 3); CHECK(v2[0] == 12); CHECK(v2[1] == 20); CHECK(v2[2] == 23); auto v3 = bm.mapped_vector(left{3}); CHECK(v3.size() == 2); CHECK(v3[0] == 13); CHECK(v3[1] == 23); auto v4 = bm.mapped_vector(left{4}); CHECK(v4.size() == 0); auto v5 = bm.mapped_vector(left{5}); CHECK(v5.size() == 0); */ } TEST_CASE("Bimap right map view vectors", "[bimap, mapped_vector, right_view]") { bimap<int, int> bm = test_bimap_int_int_1(); using left = bimap<int, int>::left; using right = bimap<int, int>::right; auto v10 = bm.mapped_vector(right{10}); CHECK(v10.size() == 1); CHECK(v10[0] == 1); auto v12 = bm.mapped_vector(right{12}); CHECK(v12.size() == 2); CHECK(v12[0] == 1); CHECK(v12[1] == 2); auto v13 = bm.mapped_vector(right{13}); CHECK(v13.size() == 2); CHECK(v13[0] == 1); CHECK(v13[1] == 3); auto v20 = bm.mapped_vector(right{20}); CHECK(v20.size() == 1); CHECK(v20[0] == 2); auto v23 = bm.mapped_vector(right{23}); CHECK(v23.size() == 2); CHECK(v23[0] == 2); CHECK(v23[1] == 3); auto v00 = bm.mapped_vector(right{0}); CHECK(v00.size() == 0); } //TODO: provide a generator for types that aren't convertible from size_t template <typename L, typename R> void ordered_mill_linear_values(size_t n_left, size_t n_right) { std::set<L> lefts; std::set<R> rights; for (size_t i = 0; i < n_left; i++){ lefts.insert(L(i)); } for (size_t i = 0; i < n_right; i++){ rights.insert(R(i)); } ordered_bimap_mill(lefts, rights); } template <typename L, typename R> void ordered_mill_random_values(size_t n_left, size_t n_right, size_t seed = 0) { std::mt19937 rng{seed}; std::set<L> lefts; std::set<R> rights; for (size_t i = 0; i < n_left; i++){ size_t set_size = lefts.size(); while (set_size == lefts.size()){ lefts.insert(L(rng())); } } for (size_t i = 0; i < n_right; i++){ size_t set_size = rights.size(); while (set_size == rights.size()){ rights.insert(R(rng())); } } ordered_bimap_mill(lefts, rights); } template <typename L, typename R> void random_order_mill_linear_values(size_t n_left, size_t n_right) { std::set<L> lefts; std::set<R> rights; for (size_t i = 0; i < n_left; i++){ lefts.insert(L(i)); } for (size_t i = 0; i < n_right; i++){ rights.insert(R(i)); } random_order_bimap_mill(lefts, rights); } template <typename L, typename R> void random_order_mill_random_values(size_t n_left, size_t n_right, size_t seed = 0) { std::mt19937 rng{seed}; std::set<L> lefts; std::set<R> rights; for (size_t i = 0; i < n_left; i++){ size_t set_size = lefts.size(); while (set_size == lefts.size()){ lefts.insert(L(rng())); } } for (size_t i = 0; i < n_right; i++){ size_t set_size = rights.size(); while (set_size == rights.size()){ rights.insert(R(rng())); } } random_order_bimap_mill(lefts, rights); } size_t n_vals = 50; TEST_CASE("Bimap<int, int> ordered mill of linear vals", "[bimap, insert, erase, count]") { ordered_mill_linear_values<int, int>(n_vals,n_vals); } TEST_CASE("Bimap<int, int> ordered mill of random vals", "[bimap, insert, erase, count]") { ordered_mill_random_values<int, int>(n_vals,n_vals, 313); } TEST_CASE("Bimap<int, int> random order mill of linear vals", "[bimap, insert, erase, count]") { random_order_mill_linear_values<int, int>(n_vals,n_vals); } TEST_CASE("Bimap<int, int> random order mill of random vals", "[bimap, insert, erase, count]") { random_order_mill_random_values<int, int>(n_vals,n_vals, 313); } enum class EnumA {}; enum class EnumB {}; TEST_CASE("Bimap<EnumA, EnumB> ordered mill of linear vals", "[bimap, insert, erase, count]") { ordered_mill_linear_values<EnumA, EnumB>(n_vals,n_vals); } TEST_CASE("Bimap<EnumA, EnumB> ordered mill of random vals", "[bimap, insert, erase, count]") { ordered_mill_random_values<EnumA, EnumB>(n_vals,n_vals, 313); } TEST_CASE("Bimap<EnumA, EnumB> random order mill of linear vals", "[bimap, insert, erase, count]") { random_order_mill_linear_values<EnumA, EnumB>(n_vals,n_vals); } TEST_CASE("Bimap<EnumA, EnumB> random order mill of random vals", "[bimap, insert, erase, count]") { random_order_mill_random_values<EnumA, EnumB>(n_vals,n_vals, 313); } //Strings /* TEST_CASE("Bimap<int, std::string> ordered mill of linear vals", "[bimap, insert, erase, count]") { ordered_mill_linear_values<int, int>(n_vals,n_vals); } TEST_CASE("Bimap<int, int> ordered mill of random vals", "[bimap, insert, erase, count]") { ordered_mill_random_values<int, int>(n_vals,n_vals, 313); } TEST_CASE("Bimap<int, int> random order mill of linear vals", "[bimap, insert, erase, count]") { random_order_mill_linear_values<int, int>(n_vals,n_vals); } TEST_CASE("Bimap<int, int> random order mill of random vals", "[bimap, insert, erase, count]") { random_order_mill_random_values<int, int>(n_vals,n_vals, 313); } */