17namespace sequoia::testing
19 template<maths::dynamic_tree Tree>
22 using tree_type = Tree;
23 using size_type =
typename tree_type::size_type;
24 using node_weight_type =
typename Tree::node_weight_type;
27 constexpr static maths::tree_link_direction link_dir{Tree::link_dir};
29 template<
class CheckType, test_mode Mode>
32 check_node(flavour, logger, 0, tree_type::npos, actual, prediction);
35 using edge_iterator =
typename tree_type::const_edge_iterator;
37 template<
class CheckType, test_mode Mode>
40 if (node == tree_type::npos)
return node;
42 if (testing::check(
"Insufficient nodes detected while checking node " + std::to_string(node), logger, node < actual.order()))
44 if constexpr (link_dir != maths::tree_link_direction::backward)
46 if constexpr(!std::is_empty_v<node_weight_type>)
47 check(flavour,
"Node weight for node " + std::to_string(node), logger, actual.cbegin_node_weights()[node], prediction.node);
49 if (
auto optIter{ check_num_edges(logger, node, parent, actual, prediction) })
51 for (
const auto& child : prediction.children)
53 if (!check_edge(logger, (*optIter)++, ++node, actual))
54 return tree_type::npos;
56 node = check_node(flavour, logger, node, optIter->partition_index(), actual, child);
58 if (node == tree_type::npos)
return tree_type::npos;
66 if (
auto optIter{ check_num_edges(logger, node, parent, actual, prediction) })
68 if constexpr(!std::is_empty_v<node_weight_type>)
69 check(flavour,
"Node weight for node " + std::to_string(node), logger, actual.cbegin_node_weights()[node], prediction.node);
71 for (
const auto& child : prediction.children)
73 node = check_node(flavour, logger, ++node, optIter->partition_index(), actual, child);
75 if (node == tree_type::npos)
return tree_type::npos;
78 if (
const auto next{ node + 1 }; next < actual.order())
80 if (
auto begin{ actual.cbegin_edges(next) }; begin != actual.cend_edges(next))
82 if (!testing::check(
"Extraneous nodes joined to node " + std::to_string(node), logger, begin->target_node() != optIter->partition_index()))
84 return tree_type::npos;
94 return tree_type::npos;
97 template<test_mode Mode>
100 if constexpr (link_dir == maths::tree_link_direction::forward)
102 if (
check(equality,
"Number of children for node " + std::to_string(node), logger,
static_cast<std::size_t
>(std::ranges::distance(actual.cbegin_edges(node), actual.cend_edges(node))), prediction.children.size()))
103 return actual.cbegin_edges(node);
107 const auto begin{ actual.cbegin_edges(node) };
108 const auto dist{
static_cast<std::size_t
>(std::ranges::distance(begin, actual.cend_edges(node))) };
109 using dist_t =
decltype(dist);
112 [&logger,parent,dist,begin]() -> std::optional<dist_t> {
113 if (parent == tree_type::npos)
return dist;
115 if (testing::check(
"Return edge detected", logger, dist > 0)
116 &&
check(equality,
"Return edge target", logger, begin->target_node(), parent))
125 if constexpr (link_dir == maths::tree_link_direction::symmetric)
127 if (
check(equality,
"Number of children for node " + std::to_string(node), logger, num.value(), prediction.children.size()))
128 return num < dist ? std::ranges::next(begin) : begin;
132 if (
check(equality,
"No reachable children for node " + std::to_string(node), logger, num.value(), size_type{}))
133 return num < dist ? std::ranges::next(begin) : begin;
141 template<test_mode Mode, std::input_or_output_iterator EdgeIter>
142 static bool check_edge(
test_logger<Mode>& logger, EdgeIter iter, size_type nodeCounter,
const tree_type& actual)
144 using std::ranges::distance;
146 if constexpr (link_dir == maths::tree_link_direction::forward)
148 const auto parent{ iter.partition_index() };
149 const auto dist{ distance(actual.cbegin_edges(parent), iter) };
150 const auto mess{ std::string{
"Index for child "}.append(std::to_string(dist)).append(
" of node ").append(std::to_string(parent)) };
152 return check(equality, mess, logger, iter->target_node(), nodeCounter);
154 else if constexpr (link_dir == maths::tree_link_direction::backward)
158 else if constexpr (link_dir == maths::tree_link_direction::symmetric)
160 const auto parent{ iter.partition_index() };
161 const auto dist{ distance(actual.cbegin_edges(parent), iter) };
162 const auto mess{ std::string{
"Index for child "}.append(std::to_string(dist)).append(
" of node ").append(std::to_string(parent)) };
164 return check(equality, mess, logger, iter->target_node(), nodeCounter);
175 maths::tree_link_direction link_dir,
177 class node_weight_type,
178 class EdgeStorageConfig,
179 class NodeWeightStorage
182 :
tree_tester<maths::directed_tree<link_dir, EdgeWeight, node_weight_type, EdgeStorageConfig, NodeWeightStorage>>
187 maths::tree_link_direction link_dir,
189 class node_weight_type,
191 class EdgeStorageConfig,
192 class NodeWeightStorage
195 :
tree_tester<maths::undirected_tree<link_dir, EdgeWeight, node_weight_type, EdgeMetaData, EdgeStorageConfig, NodeWeightStorage>>
Restriction of Dynamic Graphs to Trees.
bool check(CheckType flavour, std::string description, test_logger< Mode > &logger, Iter first, Sentinel last, PredictionIter predictionFirst, PredictionSentinel predictionLast, tutor< Advisor > advisor={})
The workhorse for comparing the contents of ranges.
Definition: FreeCheckers.hpp:377
Utilities for checking regular semantics.
Definition: DynamicTree.hpp:176
Definition: DynamicTree.hpp:210
Definition: TestLogger.hpp:183
Standard meta-programming utility.
Definition: TypeTraits.hpp:27
Definition: GraphPrimitive.hpp:84
Definition: GraphTestingUtilities.hpp:90
Definition: TreeTestingUtilities.hpp:21
class template, specializations of which implement various comparisons for the specified type.
Definition: FreeCheckers.hpp:78