2023-04-22 14:45:43 +02:00
|
|
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
2023-04-21 22:46:18 +02:00
|
|
|
#include <catch2/catch_test_macros.hpp>
|
|
|
|
#include <iostream>
|
2023-04-22 11:43:39 +02:00
|
|
|
#include <sstream>
|
2023-04-21 22:46:18 +02:00
|
|
|
|
|
|
|
#include "node.h"
|
|
|
|
|
2023-04-21 23:53:31 +02:00
|
|
|
int get_node_id(node *n) {
|
|
|
|
// TODO: ensure the test calling this starts at node_id 0 (currently this is
|
|
|
|
// undefined based on order the tests are run)
|
|
|
|
// for the time being, this gets the offset
|
|
|
|
int id = std::stoi(n->get_name().substr(5));
|
|
|
|
// this tests if the node id was correctly extracted
|
|
|
|
REQUIRE(n->get_name() == "node_" + std::to_string(id));
|
|
|
|
return id;
|
|
|
|
}
|
|
|
|
|
2023-04-21 22:46:18 +02:00
|
|
|
TEST_CASE("Name") {
|
|
|
|
node *n = new node("test");
|
|
|
|
REQUIRE(n->get_name() == "test");
|
|
|
|
n->set_name("foo");
|
|
|
|
REQUIRE(n->get_name() == "foo");
|
|
|
|
delete n;
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_CASE("Number of children") {
|
|
|
|
node *n = new node("test");
|
|
|
|
REQUIRE(n->get_nr_children() == 0);
|
|
|
|
for (std::size_t i = 0; i < 20; i++) {
|
|
|
|
node *child = new node("child");
|
|
|
|
n->add_child(child);
|
|
|
|
}
|
|
|
|
REQUIRE(n->get_nr_children() == 20);
|
|
|
|
delete n;
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_CASE("Get children") {
|
|
|
|
node *n = new node("test");
|
|
|
|
REQUIRE(n->get_nr_children() == 0);
|
|
|
|
for (std::size_t i = 0; i < 5; i++) {
|
|
|
|
n->add_child(new node("child " + std::to_string(i)));
|
|
|
|
}
|
|
|
|
for (std::size_t i = 0; i < 5; i++) {
|
|
|
|
REQUIRE(n->get_child(i)->get_name() == "child " + std::to_string(i));
|
|
|
|
}
|
|
|
|
delete n;
|
|
|
|
}
|
2023-04-21 23:13:26 +02:00
|
|
|
|
|
|
|
TEST_CASE("Global node counting") {
|
|
|
|
node *n = new node();
|
|
|
|
|
2023-04-21 23:53:31 +02:00
|
|
|
const int node_id_start = get_node_id(n);
|
2023-04-21 23:13:26 +02:00
|
|
|
|
|
|
|
for (std::size_t i = 0; i < 5; i++) {
|
|
|
|
n->add_child(new node());
|
|
|
|
}
|
|
|
|
n->add_child(new node("explicit name"));
|
|
|
|
for (std::size_t i = 0; i < 5; i++) {
|
|
|
|
REQUIRE(n->get_child(i)->get_name() ==
|
|
|
|
"node_" + std::to_string(node_id_start + 1 + i));
|
|
|
|
}
|
|
|
|
REQUIRE(n->get_child(5)->get_name() == "explicit name");
|
|
|
|
delete n;
|
|
|
|
}
|
2023-04-21 23:56:14 +02:00
|
|
|
|
|
|
|
TEST_CASE("Create complete tree") {
|
|
|
|
const std::size_t nr_child_nodes = 2;
|
|
|
|
const unsigned int tree_depth = 4;
|
|
|
|
node *t = create_complete_tree(nr_child_nodes, tree_depth);
|
|
|
|
|
2023-04-22 10:43:32 +02:00
|
|
|
int count = get_node_id(t);
|
2023-04-21 23:56:14 +02:00
|
|
|
|
2023-04-22 10:43:32 +02:00
|
|
|
REQUIRE(t->get_name() == "node_" + std::to_string(count++));
|
2023-04-21 23:56:14 +02:00
|
|
|
|
|
|
|
// this is very verbose,
|
|
|
|
// but without a serialisation,
|
|
|
|
// there is no other good way I could find (that does not also implement the
|
|
|
|
// logic to test).
|
2023-04-22 10:43:32 +02:00
|
|
|
REQUIRE(t->get_child(0)->get_name() == "node_" + std::to_string(count++));
|
2023-04-21 23:56:14 +02:00
|
|
|
REQUIRE(t->get_child(0)->get_child(0)->get_name() ==
|
2023-04-22 10:43:32 +02:00
|
|
|
"node_" + std::to_string(count++));
|
2023-04-21 23:56:14 +02:00
|
|
|
REQUIRE(t->get_child(0)->get_child(0)->get_child(0)->get_name() ==
|
2023-04-22 10:43:32 +02:00
|
|
|
"node_" + std::to_string(count++));
|
2023-04-21 23:56:14 +02:00
|
|
|
REQUIRE(t->get_child(0)->get_child(0)->get_child(1)->get_name() ==
|
2023-04-22 10:43:32 +02:00
|
|
|
"node_" + std::to_string(count++));
|
2023-04-21 23:56:14 +02:00
|
|
|
REQUIRE(t->get_child(0)->get_child(1)->get_name() ==
|
2023-04-22 10:43:32 +02:00
|
|
|
"node_" + std::to_string(count++));
|
2023-04-21 23:56:14 +02:00
|
|
|
REQUIRE(t->get_child(0)->get_child(1)->get_child(0)->get_name() ==
|
2023-04-22 10:43:32 +02:00
|
|
|
"node_" + std::to_string(count++));
|
2023-04-21 23:56:14 +02:00
|
|
|
REQUIRE(t->get_child(0)->get_child(1)->get_child(1)->get_name() ==
|
2023-04-22 10:43:32 +02:00
|
|
|
"node_" + std::to_string(count++));
|
|
|
|
REQUIRE(t->get_child(1)->get_name() == "node_" + std::to_string(count++));
|
2023-04-21 23:56:14 +02:00
|
|
|
REQUIRE(t->get_child(1)->get_child(0)->get_name() ==
|
2023-04-22 10:43:32 +02:00
|
|
|
"node_" + std::to_string(count++));
|
2023-04-21 23:56:14 +02:00
|
|
|
REQUIRE(t->get_child(1)->get_child(0)->get_child(0)->get_name() ==
|
2023-04-22 10:43:32 +02:00
|
|
|
"node_" + std::to_string(count++));
|
2023-04-21 23:56:14 +02:00
|
|
|
REQUIRE(t->get_child(1)->get_child(0)->get_child(1)->get_name() ==
|
2023-04-22 10:43:32 +02:00
|
|
|
"node_" + std::to_string(count++));
|
2023-04-21 23:56:14 +02:00
|
|
|
REQUIRE(t->get_child(1)->get_child(1)->get_name() ==
|
2023-04-22 10:43:32 +02:00
|
|
|
"node_" + std::to_string(count++));
|
2023-04-21 23:56:14 +02:00
|
|
|
REQUIRE(t->get_child(1)->get_child(1)->get_child(0)->get_name() ==
|
2023-04-22 10:43:32 +02:00
|
|
|
"node_" + std::to_string(count++));
|
2023-04-21 23:56:14 +02:00
|
|
|
REQUIRE(t->get_child(1)->get_child(1)->get_child(1)->get_name() ==
|
2023-04-22 10:43:32 +02:00
|
|
|
"node_" + std::to_string(count++));
|
2023-04-21 23:56:14 +02:00
|
|
|
|
|
|
|
REQUIRE(t->get_nr_children() == nr_child_nodes);
|
|
|
|
REQUIRE(t->get_child(0)->get_nr_children() == nr_child_nodes);
|
|
|
|
REQUIRE(t->get_child(0)->get_child(0)->get_nr_children() == nr_child_nodes);
|
|
|
|
REQUIRE(t->get_child(0)->get_child(1)->get_nr_children() == nr_child_nodes);
|
|
|
|
REQUIRE(t->get_child(1)->get_nr_children() == nr_child_nodes);
|
|
|
|
REQUIRE(t->get_child(1)->get_child(0)->get_nr_children() == nr_child_nodes);
|
|
|
|
REQUIRE(t->get_child(1)->get_child(1)->get_nr_children() == nr_child_nodes);
|
|
|
|
|
|
|
|
delete t;
|
|
|
|
}
|
2023-04-22 11:43:39 +02:00
|
|
|
|
|
|
|
TEST_CASE("Print complete tree") {
|
|
|
|
const std::size_t nr_child_nodes = 2;
|
|
|
|
const unsigned int tree_depth = 4;
|
|
|
|
node *t = create_complete_tree(nr_child_nodes, tree_depth);
|
|
|
|
|
|
|
|
int count = get_node_id(t);
|
|
|
|
|
|
|
|
std::stringstream output;
|
|
|
|
t->print(output);
|
|
|
|
|
|
|
|
std::stringstream expected;
|
|
|
|
expected << "node_" << count++ << std::endl;
|
|
|
|
for (size_t i = 0; i < 2; i++) {
|
|
|
|
expected << "\tnode_" << count++ << std::endl;
|
|
|
|
for (size_t j = 0; j < 2; j++) {
|
|
|
|
expected << "\t\tnode_" << count++ << std::endl;
|
|
|
|
for (size_t k = 0; k < 2; k++) {
|
|
|
|
expected << "\t\t\tnode_" << count++ << std::endl;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
REQUIRE(output.str() == expected.str());
|
|
|
|
|
|
|
|
delete t;
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_CASE("Print stream overload") {
|
|
|
|
node n("foo");
|
|
|
|
|
|
|
|
std::stringstream output1;
|
|
|
|
n.print(output1);
|
|
|
|
|
|
|
|
std::stringstream output2;
|
|
|
|
output2 << n;
|
|
|
|
|
|
|
|
REQUIRE(output1.str() == output2.str());
|
|
|
|
}
|
2023-04-22 12:53:34 +02:00
|
|
|
|
|
|
|
TEST_CASE("Cycle detection") {
|
|
|
|
node *n = new node("foo");
|
|
|
|
n->add_child(new node("bar"));
|
|
|
|
n->get_child(0)->add_child(n);
|
|
|
|
|
|
|
|
std::stringstream output;
|
|
|
|
output << n->print_recursive();
|
|
|
|
|
|
|
|
REQUIRE(output.str() == "foo\n\tbar [↝ foo]\n");
|
|
|
|
|
|
|
|
delete n;
|
|
|
|
}
|
2023-04-22 13:36:45 +02:00
|
|
|
|
|
|
|
TEST_CASE("Cycle detection (iterative)") {
|
|
|
|
node *n = new node("foo");
|
|
|
|
n->add_child(new node("bar"));
|
|
|
|
n->get_child(0)->add_child(n);
|
|
|
|
|
|
|
|
std::stringstream output;
|
|
|
|
output << n->print_iterative();
|
|
|
|
|
|
|
|
REQUIRE(output.str() == "foo\n\tbar [↝ foo]\n");
|
|
|
|
|
|
|
|
delete n;
|
|
|
|
}
|
|
|
|
|
2023-04-24 14:33:45 +02:00
|
|
|
TEST_CASE("Very short cycle detection") {
|
|
|
|
node *n = new node("foo");
|
|
|
|
n->add_child(n);
|
|
|
|
|
|
|
|
std::stringstream output;
|
|
|
|
output << n->print_recursive();
|
|
|
|
|
|
|
|
REQUIRE(output.str() == "foo [↝ foo]\n");
|
|
|
|
|
|
|
|
delete n;
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_CASE("Very short cycle detection (iterative)") {
|
|
|
|
node *n = new node("foo");
|
|
|
|
n->add_child(n);
|
|
|
|
|
|
|
|
std::stringstream output;
|
|
|
|
output << n->print_iterative();
|
|
|
|
|
|
|
|
REQUIRE(output.str() == "foo [↝ foo]\n");
|
|
|
|
|
|
|
|
delete n;
|
|
|
|
}
|
|
|
|
|
2023-04-24 14:11:29 +02:00
|
|
|
TEST_CASE("Equivalence of iterative and recursive print") {
|
2023-04-22 13:36:45 +02:00
|
|
|
node *n = new node();
|
|
|
|
REQUIRE(n->print_recursive() == n->print_iterative());
|
|
|
|
delete n;
|
|
|
|
|
|
|
|
node *r = new node("foo");
|
|
|
|
r->add_child(new node("bar"));
|
|
|
|
r->get_child(0)->add_child(r);
|
|
|
|
REQUIRE(r->print_recursive() == r->print_iterative());
|
|
|
|
delete r;
|
|
|
|
|
|
|
|
node *t = create_complete_tree(2, 4);
|
|
|
|
REQUIRE(t->print_recursive() == t->print_iterative());
|
|
|
|
delete t;
|
|
|
|
}
|