17namespace sequoia::testing
19 namespace directed_graph{
101 node_1_node_1_0_node,
107 node_1_node_1_0_2_node,
112 node_1_node_1_2_node,
126 node_1_1_2_2_node_2_node,
135 node_1_1_2_2_node_2_node_1,
144 node_2_2_1_1_node_2_node_1,
152 node_3_1_node_2_node_node,
155 node_1_node_node_node_2,
158 node_2_node_node_node_1,
168 class EdgeStorageConfig,
169 class NodeWeightStorage
175 using edge_t =
typename graph_t::edge_init_type;
176 using edges_equivalent_t = std::initializer_list<std::initializer_list<edge_t>>;
179 static void check_initialization_exceptions(
regular_test& t)
181 t.check_exception_thrown<std::out_of_range>(
"Zeroth partial index of edge out of range", [](){
return graph_t{{edge_t{1}}}; });
182 t.check_exception_thrown<std::out_of_range>(
"First partial index of edge out of range", [](){
return graph_t{{edge_t{0}, edge_t{1}}}; });
183 t.check_exception_thrown<std::out_of_range>(
"First partial index of edge out of range", [](){
return graph_t{{edge_t{0}, edge_t{2}}, {}}; });
184 t.check_exception_thrown<std::out_of_range>(
"Zeroth partial index of node 1's edge out of range", [](){
return graph_t{{edge_t{0}, edge_t{1}}, {edge_t{2}}}; });
189 auto trg{make_transition_graph(t)};
192 [&t](std::string_view description,
const graph_t& obtained,
const graph_t& prediction,
const graph_t& parent, std::size_t host, std::size_t target) {
193 t.check(equality, {description, no_source_location}, obtained, prediction);
194 if(host != target) t.check_semantics({description, no_source_location}, prediction, parent);
202 static graph_t make_and_check(
regular_test& t, std::string_view description, edges_equivalent_t init)
208 static transition_graph make_transition_graph(
regular_test& t)
212 check_initialization_exceptions(t);
214 return transition_graph{
218 graph_description::empty,
221 t.check_exception_thrown<std::out_of_range>(
"cbegin_edges throws for empty graph", [&g]() {
return g.cbegin_edges(0); });
226 graph_description::empty,
229 t.check_exception_thrown<std::out_of_range>(
"cend_edges throws for empty graph", [&g]() {
return g.cend_edges(0); });
234 graph_description::empty,
237 t.check_exception_thrown<std::out_of_range>(
"crbegin_edges throws for empty graph", [&g]() {
return g.crbegin_edges(0); });
242 graph_description::empty,
245 t.check_exception_thrown<std::out_of_range>(
"crend_edges throws for empty graph", [&g]() {
return g.crend_edges(0); });
250 graph_description::empty,
253 t.check_exception_thrown<std::out_of_range>(
"cedges throws for empty graph", [&g]() {
return g.cedges(0); });
258 graph_description::empty,
261 t.check_exception_thrown<std::out_of_range>(
"swapping nodes throws for empty graph", [g{g}]()
mutable { g.swap_nodes(0, 0); });
266 graph_description::empty,
269 t.check_exception_thrown<std::out_of_range>(
"swapping edges throws for empty graph", [g{g}]()
mutable { g.swap_edges(0, 0, 0); });
274 graph_description::empty,
277 t.check_exception_thrown<std::out_of_range>(
"joining nodes throws for empty graph", [g{g}]()
mutable { g.join(0, 0); });
282 graph_description::empty,
283 t.report(
"Clear empty graph"),
290 graph_description::node,
291 t.report(
"Add node to empty graph"),
293 t.check(equality,
"Index of added node is 0", g.add_node(), 0uz);
298 graph_description::node,
299 t.report(
"insert node into empty graph"),
301 t.check(equality,
"Index of added node is 0", g.insert_node(0), 0uz);
308 graph_description::node,
311 t.check_exception_thrown<std::out_of_range>(
"cbegin_edges throws when index is out of range", [&g]() {
return g.cbegin_edges(1); });
316 graph_description::node,
319 t.check_exception_thrown<std::out_of_range>(
"cend_edges throws when index is out of range", [&g]() {
return g.cend_edges(1); });
324 graph_description::node,
327 t.check_exception_thrown<std::out_of_range>(
"crbegin_edges throws when index is out of range", [&g]() {
return g.crbegin_edges(1); });
332 graph_description::node,
335 t.check_exception_thrown<std::out_of_range>(
"crend_edges throws when index is out of range", [&g]() {
return g.crend_edges(1); });
340 graph_description::node,
343 t.check_exception_thrown<std::out_of_range>(
"cedges throws when index is out of range", [&g]() {
return g.cedges(1); });
348 graph_description::node,
351 t.check_exception_thrown<std::out_of_range>(
"swapping nodes throws if first index out of range", [g{g}]()
mutable { g.swap_nodes(1, 0); });
356 graph_description::node,
359 t.check_exception_thrown<std::out_of_range>(
"swapping nodes throws if second index out of range", [g{g}]()
mutable { g.swap_nodes(0, 1); });
364 graph_description::node,
367 t.check_exception_thrown<std::out_of_range>(
"joining nodes throws if first index out of range", [g{g}]()
mutable { g.join(1, 0); });
372 graph_description::node,
375 t.check_exception_thrown<std::out_of_range>(
"joining nodes throws if second index out of range", [g{g}]()
mutable { g.join(0, 1); });
380 graph_description::empty,
381 t.report(
"Clear graph"),
388 graph_description::empty,
389 t.report(
"Erase node to give empty graph"),
396 graph_description::node,
397 t.report(
"Attempt to erase edge past the end"),
399 g.erase_edge(g.cend_edges(0));
404 graph_description::node_0,
405 t.report(
"Add loop"),
412 graph_description::node_node,
413 t.report(
"Add second node"),
415 t.check(equality,
"Index of added node is 1", g.add_node(), 1uz);
420 graph_description::node_node,
421 t.report(
"Insert second node"),
423 t.check(equality,
"Index of added node is 0", g.insert_node(0), 0uz);
428 graph_description::node_node,
429 t.report(
"Insert second node at end"),
431 t.check(equality,
"Index of added node is 1", g.insert_node(1), 1uz);
436 graph_description::node,
437 t.report(
"Swap node with self"),
446 graph_description::empty,
447 t.report(
"Clear graph"),
454 graph_description::node,
455 t.report(
"Remove loop"),
457 g.erase_edge(g.cbegin_edges(0));
462 graph_description::node_0_0,
463 t.report(
"Add a second loop"),
470 graph_description::node_node_1,
471 t.report(
"Insert node"),
473 t.check(equality,
"Index of added node is 0", g.insert_node(0), 0uz);
478 graph_description::node_0_node,
479 t.report(
"Insert node at end"),
481 t.check(equality,
"Index of added node is 1", g.insert_node(1), 1uz);
486 graph_description::node_0,
487 t.report(
"Swap node with self"),
494 graph_description::node_0,
495 t.report(
"Swap edge with self"),
497 g.swap_edges(0, 0, 0);
502 graph_description::node_0,
505 t.check_exception_thrown<std::out_of_range>(
"swapping edges throws for first edge index out of range", [g{g}]()
mutable { g.swap_edges(0, 1, 0); });
510 graph_description::node_0,
513 t.check_exception_thrown<std::out_of_range>(
"swapping edges throws for second edge index out of range", [g{g}]()
mutable { g.swap_edges(0, 0, 1); });
518 graph_description::node_0,
521 t.check_exception_thrown<std::out_of_range>(
"swapping edges throws for node index out of range", [g{g}]()
mutable { g.swap_edges(1, 0, 0); });
528 graph_description::empty,
529 t.report(
"Clear graph"),
536 graph_description::node_0,
537 t.report(
"Remove first loop"),
539 g.erase_edge(g.cbegin_edges(0));
544 graph_description::node_0,
545 t.report(
"Remove second loop"),
547 g.erase_edge(std::ranges::next(g.cbegin_edges(0)));
552 graph_description::node_0_0,
553 t.report(
"Swap loops"),
555 g.swap_edges(0, 0, 1);
560 graph_description::node_0_0,
561 t.report(
"Swap loops"),
563 g.swap_edges(0, 1, 0);
570 graph_description::empty,
571 t.report(
"Clear graph"),
578 graph_description::node,
579 t.report(
"Erase node 0"),
586 graph_description::node,
587 t.report(
"Erase node 1"),
594 graph_description::node_1_node,
595 t.report(
"Join nodes 0,1"),
604 graph_description::empty,
605 t.report(
"Clear graph"),
612 graph_description::node,
613 t.report(
"Erase node 0"),
620 graph_description::node,
621 t.report(
"Erase node 1"),
628 graph_description::node_0_1_node,
629 t.report(
"Add loop to node 0 and then swap it with link"),
632 g.swap_edges(0, 0, 1);
637 graph_description::node_node_0,
638 t.report(
"Swap nodes {0,1}"),
645 graph_description::node_node_0,
646 t.report(
"Swap nodes {1,0}"),
653 graph_description::node_1_1_node,
654 t.report(
"Join {0,1}"),
663 graph_description::empty,
664 t.report(
"Clear graph"),
671 graph_description::node,
672 t.report(
"Erase node 0"),
679 graph_description::node,
680 t.report(
"Erase node 1"),
687 graph_description::node_1_node,
688 t.report(
"Swap nodes {0,1}"),
695 graph_description::node_1_node,
696 t.report(
"Swap nodes {1,0}"),
703 graph_description::node_1_node_0,
704 t.report(
"Join nodes {0,1}"),
713 graph_description::empty,
714 t.report(
"Clear graph"),
721 graph_description::node,
722 t.report(
"Erase node 0"),
729 graph_description::node_0,
730 t.report(
"Erase node 1"),
737 graph_description::node_1_node,
738 t.report(
"Remove loop"),
740 g.erase_edge(g.cbegin_edges(0));
745 graph_description::node_0_node,
746 t.report(
"Remove link"),
748 g.erase_edge(std::ranges::next(g.cbegin_edges(0)));
755 graph_description::empty,
756 t.report(
"Clear graph"),
763 graph_description::node_node,
764 t.report(
"Remove link"),
766 g.erase_edge(g.cbegin_edges(0));
771 graph_description::node_node_1_node,
772 t.report(
"Insert node"),
774 t.check(equality,
"Index of added node is 0", g.insert_node(0), 0uz);
779 graph_description::node_node_1,
780 t.report(
"Swap nodes"),
789 graph_description::empty,
790 t.report(
"Clear graph"),
797 graph_description::node_0,
798 t.report(
"Erase node 0"),
805 graph_description::node,
806 t.report(
"Erase node 1"),
813 graph_description::node_node,
814 t.report(
"Remove link"),
816 g.erase_edge(g.cbegin_edges(1));
821 graph_description::node_0_node,
822 t.report(
"swap nodes"),
832 graph_description::empty,
833 t.report(
"Clear graph"),
840 graph_description::node,
841 t.report(
"Erase node 0"),
848 graph_description::node,
849 t.report(
"Erase node 1"),
856 graph_description::node_1_node,
857 t.report(
"Erase node 0 zeroth link"),
859 g.erase_edge(g.cbegin_edges(0));
864 graph_description::node_1_node,
865 t.report(
"Erase node 0 first link"),
867 g.erase_edge(g.cbegin_edges(0)+1);
872 graph_description::node_1_1_node,
873 t.report(
"Swap edges"),
875 g.swap_edges(0, 0, 1);
880 graph_description::node_1_1_node,
881 t.report(
"Swap edges"),
883 g.swap_edges(0, 1, 0);
890 graph_description::empty,
891 t.report(
"Clear graph"),
898 graph_description::node,
899 t.report(
"Erase node 0"),
906 graph_description::node,
907 t.report(
"Erase node 1"),
914 graph_description::node_node_0,
915 t.report(
"Erase node 0 link"),
917 g.erase_edge(g.cbegin_edges(0));
922 graph_description::node_1_node,
923 t.report(
"Erase node 1 link"),
925 g.erase_edge(g.cbegin_edges(1));
930 graph_description::node_1_node_0,
931 t.report(
"Swap nodes"),
940 graph_description::empty,
941 t.report(
"Clear graph"),
948 graph_description::node_node,
949 t.report(
"Erase node 0"),
956 graph_description::node_node,
957 t.report(
"Erase node 1"),
964 graph_description::node_node,
965 t.report(
"Erase node 2"),
972 graph_description::node_1_node_node,
973 t.report(
"Join {0,1}"),
980 graph_description::node_node_node_1,
981 t.report(
"Join {2,1}"),
991 graph_description::empty,
992 t.report(
"Clear graph"),
999 graph_description::node_node,
1000 t.report(
"Erase node 0"),
1007 graph_description::node_node,
1008 t.report(
"Erase node 1"),
1015 graph_description::node_1_node,
1016 t.report(
"Erase node 2"),
1023 graph_description::node_node_node,
1024 t.report(
"Remove link {0,1}"),
1026 g.erase_edge(g.cbegin_edges(0));
1031 graph_description::node_1_node_2_node,
1032 t.report(
"Join {2,1}"),
1039 graph_description::node_1_node_node_1,
1040 t.report(
"Join {2,1}"),
1047 graph_description::node_node_node_1,
1048 t.report(
"Swap nodes {0,2}"),
1055 graph_description::node_node_node_1,
1056 t.report(
"Swap nodes {2,0}"),
1065 graph_description::empty,
1066 t.report(
"Clear graph"),
1073 graph_description::node_node_0,
1074 t.report(
"Erase node 0"),
1081 graph_description::node_node,
1082 t.report(
"Erase node 1"),
1089 graph_description::node_node,
1090 t.report(
"Erase node 2"),
1097 graph_description::node_node_node,
1098 t.report(
"Remove link {2,1}"),
1100 g.erase_edge(g.cbegin_edges(2));
1105 graph_description::node_1_node_node_1,
1106 t.report(
"Join {0,1}"),
1113 graph_description::node_1_node_node,
1114 t.report(
"Swap nodes {0,2}"),
1121 graph_description::node_1_node_node,
1122 t.report(
"Swap nodes {2,0}"),
1131 graph_description::empty,
1132 t.report(
"Clear graph"),
1139 graph_description::node_1_node,
1140 t.report(
"Erase node 0"),
1147 graph_description::node_node,
1148 t.report(
"Erase node 1"),
1155 graph_description::node_1_node,
1156 t.report(
"Erase node 2"),
1163 graph_description::node_1_node_node,
1164 t.report(
"Remove link {1,2}"),
1166 g.erase_edge(g.cbegin_edges(1));
1173 graph_description::empty,
1174 t.report(
"Clear graph"),
1181 graph_description::node_node_0,
1182 t.report(
"Erase node 0"),
1189 graph_description::node_node,
1190 t.report(
"Erase node 1"),
1197 graph_description::node_1_node,
1198 t.report(
"Erase node 2"),
1205 graph_description::node_node_node_1,
1206 t.report(
"Remove link {0,1}"),
1208 g.erase_edge(g.cbegin_edges(0));
1213 graph_description::node_1_node_node,
1214 t.report(
"Remove link {2,1}"),
1216 g.erase_edge(g.cbegin_edges(2));
1223 graph_description::empty,
1224 t.report(
"Clear graph"),
1231 graph_description::node_1_node,
1232 t.report(
"Erase node 0"),
1239 graph_description::node_node_0,
1240 t.report(
"Erase node 1"),
1247 graph_description::node_1_node,
1248 t.report(
"Erase node 2"),
1255 graph_description::node_1_node_2_node,
1256 t.report(
"Remove {2,0}"),
1258 g.erase_edge(g.cbegin_edges(2));
1265 graph_description::empty,
1266 t.report(
"Clear graph"),
1273 graph_description::node_0_node,
1274 t.report(
"Erase node 0"),
1281 graph_description::node_node,
1282 t.report(
"Erase node 1"),
1289 graph_description::node_node_1,
1290 t.report(
"Erase node 2"),
1299 graph_description::node_0_node,
1300 t.report(
"Erase node 0"),
1307 graph_description::node_node,
1308 t.report(
"Erase node 1"),
1315 graph_description::node_node_1_node,
1316 t.report(
"Remove {0,1}"),
1318 g.erase_edge(g.cbegin_edges(0));
1323 graph_description::node_1_node_1_0_node,
1324 t.report(
"Join {1,0}"),
1333 graph_description::node_0_node,
1334 t.report(
"Erase node 0"),
1341 graph_description::node_node,
1342 t.report(
"Erase node 1"),
1349 graph_description::node_1_node_1_node,
1350 t.report(
"Remove {1,0}"),
1352 g.erase_edge(++g.cbegin_edges(1));
1357 graph_description::node_1_node_1_0_2_node,
1358 t.report(
"Join {1,2}"),
1367 graph_description::node_0_1_node,
1368 t.report(
"Erase node 0"),
1375 graph_description::node_node,
1376 t.report(
"Erase node 1"),
1383 graph_description::node_1_node_1_2_node,
1384 t.report(
"Remove {1,0}"),
1386 g.erase_edge(++g.cbegin_edges(1));
1391 graph_description::node_1_node_1_0_node,
1392 t.report(
"Remove {1,2}"),
1394 g.erase_edge(g.cbegin_edges(1)+2);
1401 graph_description::node_1_node_2_node,
1402 t.report(
"Remove {1,1}"),
1404 g.erase_edge(g.cbegin_edges(1));
1411 graph_description::node_1_node_1_node,
1412 t.report(
"Swap {1,2}"),
1421 graph_description::node_1_node,
1422 t.report(
"Erase node 0"),
1429 graph_description::node_1_1_node,
1430 t.report(
"Erase node 1"),
1437 graph_description::node_1_1_node,
1438 t.report(
"Erase node 2"),
1445 graph_description::node_1_1_2_2_node_2_node_1,
1446 t.report(
"Join {2, 1}"),
1455 graph_description::node_1_node_0,
1456 t.report(
"Erase node 0"),
1463 graph_description::node_1_1_node,
1464 t.report(
"Erase node 1"),
1471 graph_description::node_1_1_node,
1472 t.report(
"Erase node 2"),
1479 graph_description::node_2_2_1_1_node_2_node_1,
1480 t.report(
"Swap {1,2}"),
1487 graph_description::node_2_2_1_1_node_2_node_1,
1488 t.report(
"Swap {2,1}"),
1495 graph_description::node_2_2_1_1_node_2_node_1,
1496 t.report(
"Swap node 0 edges: {0,2}, {1,3}"),
1498 g.swap_edges(0, 0, 2);
1499 g.swap_edges(0, 1, 3);
1506 graph_description::node_1_1_2_2_node_2_node_1,
1507 t.report(
"Swap {1,2}"),
1514 graph_description::node_1_1_2_2_node_2_node_1,
1515 t.report(
"Swap {2,1}"),
1522 graph_description::node_1_1_2_2_node_2_node_1,
1523 t.report(
"Sort Edges for node 0"),
1525 g.sort_edges(g.cbegin_edges(0), g.cend_edges(0), std::ranges::less{}, [](
const auto& lhs) {
return lhs.target_node(); });
1530 graph_description::node_1_1_2_2_node_2_node_1,
1531 t.report(
"Sort Edges for node 0"),
1533 g.sort_edges(g.cedges(0), std::ranges::less{}, [](
const auto& lhs) {
return lhs.target_node(); });
1538 graph_description::node_1_1_2_2_node_2_node_1,
1539 t.report(
"Sort Edges for node 0"),
1541 g.stable_sort_edges(g.cbegin_edges(0), g.cend_edges(0), std::ranges::less{}, [](
const auto& lhs) {
return lhs.target_node(); });
1546 graph_description::node_1_1_2_2_node_2_node_1,
1547 t.report(
"Sort Edges for node 0"),
1549 g.stable_sort_edges(g.cedges(0), std::ranges::less{}, [](
const auto& lhs) {
return lhs.target_node(); });
1554 graph_description::node_1_1_2_2_node_2_node_1,
1555 t.report(
"Swap node 0 edges: {0,2}, {1,3}"),
1557 g.swap_edges(0, 0, 2);
1558 g.swap_edges(0, 1, 3);
1565 graph_description::node_1_node_node,
1566 t.report(
"Erase node 0"),
1575 graph_description::node_2_node_node_node_1,
1576 t.report(
"Swap {2,1}"),
1583 graph_description::node_2_node_node_node_1,
1584 t.report(
"Swap {0,3}"),
1593 graph_description::node_1_node_node_node_2,
1594 t.report(
"Swap {2,1}"),
1601 graph_description::node_1_node_node_node_2,
1602 t.report(
"Swap {0,3}"),
1612 make_and_check(t, t.report(
""), {}),
1615 make_and_check(t, t.report(
""), {{}}),
1618 make_and_check(t, t.report(
""), {{edge_t{0}}}),
1621 make_and_check(t, t.report(
""), {{edge_t{0}, edge_t{0}}}),
1624 make_and_check(t, t.report(
""), {{}, {}}),
1627 make_and_check(t, t.report(
""), {{edge_t{1}}, {}}),
1630 make_and_check(t, t.report(
""), {{}, {edge_t{0}}}),
1633 make_and_check(t, t.report(
""), {{edge_t{0}, edge_t{1}}, {}}),
1636 make_and_check(t, t.report(
""), {{edge_t{0}}, {}}),
1639 make_and_check(t, t.report(
""), {{}, {edge_t{1}}}),
1642 make_and_check(t, t.report(
""), {{edge_t{1}, edge_t{1}}, {}}),
1645 make_and_check(t, t.report(
""), {{edge_t{1}}, {edge_t{0}}}),
1648 make_and_check(t, t.report(
""), {{}, {}, {}}),
1651 make_and_check(t, t.report(
""), {{edge_t{1}}, {}, {}}),
1654 make_and_check(t, t.report(
""), {{}, {}, {edge_t{1}}}),
1657 make_and_check(t, t.report(
""), {{edge_t{1}}, {edge_t{2}}, {}}),
1660 make_and_check(t, t.report(
""), {{edge_t{1}}, {}, {edge_t{1}}}),
1663 make_and_check(t, t.report(
""), {{edge_t{1}}, {edge_t{2}}, {edge_t{0}}}),
1666 make_and_check(t, t.report(
""), {{}, {edge_t{1}}, {}}),
1669 make_and_check(t, t.report(
""), {{edge_t{1}}, {edge_t{1}}, {}}),
1672 make_and_check(t, t.report(
""), {{edge_t{1}}, {edge_t{1}, edge_t{0}}, {}}),
1675 make_and_check(t, t.report(
""), {{edge_t{1}}, {edge_t{1}, edge_t{0}, edge_t{2}}, {}}),
1678 make_and_check(t, t.report(
""), {{edge_t{1}}, {edge_t{1}, edge_t{2}}, {}}),
1681 make_and_check(t, t.report(
""), {{edge_t{2}}, {}, {edge_t{2}}}),
1684 make_and_check(t, t.report(
""), {{edge_t{1}, edge_t{1}, edge_t{2}, edge_t{2}}, {edge_t{2}}, {}}),
1687 make_and_check(t, t.report(
""), {{edge_t{1}, edge_t{1}, edge_t{2}, edge_t{2}}, {edge_t{2}}, {edge_t{1}}}),
1690 make_and_check(t, t.report(
""), {{edge_t{2}, edge_t{2}, edge_t{1}, edge_t{1}}, {edge_t{2}}, {edge_t{1}}}),
1693 make_and_check(t, t.report(
""), {{edge_t{3}, edge_t{1}}, {edge_t{2}}, {}, {}}),
1696 make_and_check(t, t.report(
""), {{edge_t{1}}, {}, {}, {edge_t{2}}}),
1699 make_and_check(t, t.report(
""), {{edge_t{2}}, {}, {}, {edge_t{1}}})
graph_description
Convention: the indices following 'node' - separated by underscores - give the target node of the ass...
Definition: DynamicDirectedGraphTestingUtilities.hpp:21
Utilities for checking regular semantics.
Facility to define tests via a graph comprising states of an object and transitions between them.
Definition: DynamicGraph.hpp:303
class template from which all concrete tests should derive.
Definition: FreeTestCore.hpp:144
Exposes elementary check methods, with the option to plug in arbitrary Extenders to compose functiona...
Definition: FreeCheckers.hpp:708
Definition: DynamicDirectedGraphTestingUtilities.hpp:172
Definition: DynamicGraphTestingUtilities.hpp:173
Definition: StateTransitionUtilities.hpp:77