// SPDX-License-Identifier: GPL-3.0-or-later #include #include #include #include "node.h" 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; } 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; } TEST_CASE("Global node counting") { node *n = new node(); const int node_id_start = get_node_id(n); 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; } 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); int count = get_node_id(t); REQUIRE(t->get_name() == "node_" + std::to_string(count++)); // 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). REQUIRE(t->get_child(0)->get_name() == "node_" + std::to_string(count++)); REQUIRE(t->get_child(0)->get_child(0)->get_name() == "node_" + std::to_string(count++)); REQUIRE(t->get_child(0)->get_child(0)->get_child(0)->get_name() == "node_" + std::to_string(count++)); REQUIRE(t->get_child(0)->get_child(0)->get_child(1)->get_name() == "node_" + std::to_string(count++)); REQUIRE(t->get_child(0)->get_child(1)->get_name() == "node_" + std::to_string(count++)); REQUIRE(t->get_child(0)->get_child(1)->get_child(0)->get_name() == "node_" + std::to_string(count++)); REQUIRE(t->get_child(0)->get_child(1)->get_child(1)->get_name() == "node_" + std::to_string(count++)); REQUIRE(t->get_child(1)->get_name() == "node_" + std::to_string(count++)); REQUIRE(t->get_child(1)->get_child(0)->get_name() == "node_" + std::to_string(count++)); REQUIRE(t->get_child(1)->get_child(0)->get_child(0)->get_name() == "node_" + std::to_string(count++)); REQUIRE(t->get_child(1)->get_child(0)->get_child(1)->get_name() == "node_" + std::to_string(count++)); REQUIRE(t->get_child(1)->get_child(1)->get_name() == "node_" + std::to_string(count++)); REQUIRE(t->get_child(1)->get_child(1)->get_child(0)->get_name() == "node_" + std::to_string(count++)); REQUIRE(t->get_child(1)->get_child(1)->get_child(1)->get_name() == "node_" + std::to_string(count++)); 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; } 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()); } 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; } 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; } 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; } TEST_CASE("Equivalence of iterative and recursive print") { 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; }