From db1731bf07cad8ae88f6aa3d03bef47af562c116 Mon Sep 17 00:00:00 2001
From: Martin Hanzik <martin@hanzik.com>
Date: Thu, 10 May 2018 21:57:51 +0200
Subject: [PATCH] Add more tests

---
 agui2/CMakeLists.txt          |  2 +-
 agui2/src/Models/ModelBox.cpp | 20 +++++--
 agui2/tests/TestModelBox.cpp  | 99 ++++++++++++++++++++++++++++++++---
 agui2/tests/TestRegistry.cpp  | 46 ++++++++++++++++
 4 files changed, 157 insertions(+), 10 deletions(-)
 create mode 100644 agui2/tests/TestRegistry.cpp

diff --git a/agui2/CMakeLists.txt b/agui2/CMakeLists.txt
index 95bee0eb4a..85ff8d9373 100644
--- a/agui2/CMakeLists.txt
+++ b/agui2/CMakeLists.txt
@@ -82,7 +82,7 @@ set(SOURCE_FILES
         src/Utils.hpp)
 
 set(TEST_FILES
-        tests/main.cpp tests/TestModelBox.cpp)
+        tests/main.cpp tests/TestModelBox.cpp tests/TestRegistry.cpp)
 
 link_libraries(
         ${CMAKE_THREAD_LIBS_INIT}
diff --git a/agui2/src/Models/ModelBox.cpp b/agui2/src/Models/ModelBox.cpp
index a4d3e23475..29331112e3 100644
--- a/agui2/src/Models/ModelBox.cpp
+++ b/agui2/src/Models/ModelBox.cpp
@@ -11,7 +11,7 @@ std::vector<ModelBox*> ModelBox::allModelBoxes;
 ModelBox::ModelBox(ModelType type, size_t maxInputCount)
     : type(type)
     , maxInputCount(maxInputCount)
-    , inputs(maxInputCount, nullptr)
+    , inputs(maxInputCount)
 {
     // Input box cannot have inputs, other boxes must have inputs
     Q_ASSERT((this->type == ModelType::Input) == (this->maxInputCount == 0));
@@ -24,18 +24,32 @@ ModelBox::~ModelBox() {
 }
 
 void ModelBox::setInput(size_t slot, ModelBox* model) {
-    Q_ASSERT(slot < this->maxInputCount);
+    if (slot >= this->maxInputCount) {
+        throw std::runtime_error { "Cannot connect to an nonexistent slot." };
+    }
+
+    if (model != nullptr && this->inputs[slot]) {
+        throw std::runtime_error { "Cannot connect to an occupied input." };
+    }
+
     this->inputs[slot] = model;
 }
 
 void ModelBox::addOutput(ModelBox* target, size_t targetSlot) {
     Q_ASSERT(this->canHaveOutput());
+    if (this->outputs.find({target, targetSlot}) != this->outputs.end()) {
+        throw std::runtime_error { "This target is already connected to this output." };
+    }
     this->outputs.emplace(target, targetSlot);
 }
 
 void ModelBox::removeOutput(ModelBox* target, size_t targetSlot) {
     Q_ASSERT(this->canHaveOutput());
-    this->outputs.erase({target, targetSlot});
+    auto it = this->outputs.find({target, targetSlot});
+    if (it == this->outputs.end()) {
+        throw std::runtime_error { "Cannot remove an output that is not connected.." };
+    }
+    this->outputs.erase(it);
 }
 
 std::shared_ptr<abstraction::OperationAbstraction> ModelBox::getCachedResultOrEvaluate() {
diff --git a/agui2/tests/TestModelBox.cpp b/agui2/tests/TestModelBox.cpp
index eca4409e4c..37089c952c 100644
--- a/agui2/tests/TestModelBox.cpp
+++ b/agui2/tests/TestModelBox.cpp
@@ -4,33 +4,120 @@
 #include <Models/OutputModelBox.hpp>
 #include <Models/AlgorithmModelBox.hpp>
 #include <Algorithm/Registry.hpp>
+#include <Utils.hpp>
 
 TEST_CASE("Basic properties") {
+    auto input = std::make_unique<InputModelBox>();
+    auto output = std::make_unique<OutputModelBox>();
+    auto algo = std::make_unique<AlgorithmModelBox>(Registry::getAlgorithm("automaton::determinize::Determinize"));
+
     SECTION("Input and output counts") {
-        auto input = std::make_unique<InputModelBox>();
         CHECK(input->getMaxInputCount() == 0);
         CHECK(input->canHaveOutput());
 
-        auto output = std::make_unique<OutputModelBox>();
         CHECK(output->getMaxInputCount() == 1);
         CHECK_FALSE(output->canHaveOutput());
 
-        auto algo = std::make_unique<AlgorithmModelBox>(Registry::getAlgorithm("automaton::determinize::Determinize"));
         CHECK(algo->getMaxInputCount() == 1);
         CHECK(algo->canHaveOutput());
     }
 
     SECTION("Model type and name") {
-        auto input = std::make_unique<InputModelBox>();
         CHECK(input->getType() == ModelType::Input);
         CHECK(input->getName() == "INPUT");
 
-        auto output = std::make_unique<OutputModelBox>();
         CHECK(output->getType() == ModelType::Output);
         CHECK(output->getName() == "OUTPUT");
 
-        auto algo = std::make_unique<AlgorithmModelBox>(Registry::getAlgorithm("automaton::determinize::Determinize"));
         CHECK(algo->getType() == ModelType::Algorithm);
         CHECK(algo->getName() == "Determinize");
     }
+
+    CHECK(algo->getAlgorithm() == Registry::getAlgorithm("automaton::determinize::Determinize"));
+}
+
+TEST_CASE("Connect and disconnect") {
+
+    SECTION("Basic") {
+        auto input = std::make_unique<InputModelBox>();
+        auto output = std::make_unique<OutputModelBox>();
+
+        CHECK(output->evaluate() == nullptr);
+
+        input->setAutomaton(Utils::generateRandomAutomaton());
+
+        CHECK(output->evaluate() == nullptr);
+
+        ModelBox::connect(input.get(), output.get(), 0);
+
+        CHECK(output->evaluate() == input->getAutomaton());
+
+        ModelBox::disconnect(input.get(), output.get(), 0);
+
+        CHECK(output->evaluate() == nullptr);
+    }
+
+    SECTION("Multiple connections from one slot") {
+        auto input = std::make_unique<InputModelBox>();
+        auto output1 = std::make_unique<OutputModelBox>();
+        auto output2 = std::make_unique<OutputModelBox>();
+
+        CHECK(output1->evaluate() == nullptr);
+        CHECK(output2->evaluate() == nullptr);
+
+        input->setAutomaton(Utils::generateRandomAutomaton());
+
+        CHECK(output1->evaluate() == nullptr);
+        CHECK(output2->evaluate() == nullptr);
+
+        ModelBox::connect(input.get(), output1.get(), 0);
+
+        CHECK(output1->evaluate() == input->getAutomaton());
+        CHECK(output2->evaluate() == nullptr);
+
+        ModelBox::connect(input.get(), output2.get(), 0);
+
+        CHECK(output1->evaluate() == input->getAutomaton());
+        CHECK(output2->evaluate() == input->getAutomaton());
+
+        ModelBox::disconnect(input.get(), output1.get(), 0);
+
+        CHECK(output1->evaluate() == nullptr);
+        CHECK(output2->evaluate() == input->getAutomaton());
+    }
+
+    SECTION("Multiple connections to one slot") {
+        auto input1 = std::make_unique<InputModelBox>();
+        auto input2 = std::make_unique<InputModelBox>();
+        auto output = std::make_unique<OutputModelBox>();
+
+        CHECK(output->evaluate() == nullptr);
+
+        ModelBox::connect(input1.get(), output.get(), 0);
+        CHECK_THROWS(ModelBox::connect(input2.get(), output.get(), 0));
+    }
+
+    SECTION("Reconnect existing connection") {
+        auto input1 = std::make_unique<InputModelBox>();
+        auto input2 = std::make_unique<InputModelBox>();
+        auto output = std::make_unique<OutputModelBox>();
+
+        ModelBox::connect(input1.get(), output.get(), 0);
+        ModelBox::disconnect(input1.get(), output.get(), 0);
+        CHECK_NOTHROW(ModelBox::connect(input2.get(), output.get(), 0));
+    }
+
+    SECTION("Connect to an nonexistent slot") {
+        auto input = std::make_unique<InputModelBox>();
+        auto output = std::make_unique<OutputModelBox>();
+
+        CHECK_THROWS(ModelBox::connect(input.get(), output.get(), 1));
+    }
+
+    SECTION("Disconnect an unconnected slot") {
+        auto input = std::make_unique<InputModelBox>();
+        auto output = std::make_unique<OutputModelBox>();
+
+        CHECK_THROWS(ModelBox::disconnect(input.get(), output.get(), 0));
+    }
 }
\ No newline at end of file
diff --git a/agui2/tests/TestRegistry.cpp b/agui2/tests/TestRegistry.cpp
new file mode 100644
index 0000000000..4832c39243
--- /dev/null
+++ b/agui2/tests/TestRegistry.cpp
@@ -0,0 +1,46 @@
+#include <catch.hpp>
+#include <Algorithm/Registry.hpp>
+
+TEST_CASE("Registry") {
+    Registry::deinitialize();
+
+    CHECK(Registry::getAlgorithm("automaton::determinize::Determinize") == nullptr);
+
+    Registry::initialize();
+
+    auto* algo = Registry::getAlgorithm("automaton::determinize::Determinize");
+    CHECK(algo != nullptr);
+
+    CHECK(Registry::getAlgorithm("nonexistent_algorithm") == nullptr);
+}
+
+TEST_CASE("Algorithm") {
+    SECTION("Basic") {
+        auto name = "automaton::determinize::Determinize";
+
+        auto* algo = Registry::getAlgorithm(name);
+
+        CHECK(algo->getFullName() == name);
+        CHECK(algo->getPrettyName() == "Determinize");
+
+        const auto& groups = algo->getGroups();
+        CHECK(groups[0] == "automaton");
+        CHECK(groups[1] == "determinize");
+
+        CHECK(algo->getInputCount() == 1);
+    }
+
+    SECTION("Input count") {
+        auto* algo = Registry::getAlgorithm("automaton::transform::AutomataConcatenation");
+
+        CHECK(algo != nullptr);
+        CHECK(algo->getInputCount() == 2);
+    }
+
+    SECTION("Pretty name") {
+        auto* algo = Registry::getAlgorithm("automaton::transform::AutomataConcatenationEpsilonTransition");
+
+        CHECK(algo != nullptr);
+        CHECK(algo->getPrettyName() == u8"\u03B5-Concatenate");
+    }
+}
\ No newline at end of file
-- 
GitLab