From 4ca89de7ebd01516b68f5908e717b5dc54475dc3 Mon Sep 17 00:00:00 2001
From: Martin Hierholzer <martin.hierholzer@desy.de>
Date: Wed, 27 Feb 2019 17:37:02 +0100
Subject: [PATCH] add test for findTag() (was never really tested before),
 including advanced features like HierarchyModifier::moveToRoot

---
 tests/executables_src/testFindTag.cc | 162 +++++++++++++++++++++++++++
 1 file changed, 162 insertions(+)
 create mode 100644 tests/executables_src/testFindTag.cc

diff --git a/tests/executables_src/testFindTag.cc b/tests/executables_src/testFindTag.cc
new file mode 100644
index 00000000..345116a1
--- /dev/null
+++ b/tests/executables_src/testFindTag.cc
@@ -0,0 +1,162 @@
+/*
+ * testFindTag.cc
+ *
+ *  Created on: Feb 27, 2019
+ *      Author: Martin Hierholzer
+ */
+
+#include <chrono>
+#include <future>
+
+#define BOOST_TEST_MODULE testFindTag
+
+#include <boost/mpl/list.hpp>
+#include <boost/test/included/unit_test.hpp>
+#include <boost/test/test_case_template.hpp>
+#include <boost/thread.hpp>
+
+#include "ApplicationCore.h"
+#include "TestFacility.h"
+
+using namespace boost::unit_test_framework;
+namespace ctk = ChimeraTK;
+
+/*********************************************************************************************************************/
+/* Build hierarchy */
+
+struct FirstHierarchy : ctk::ModuleGroup {
+  using ctk::ModuleGroup::ModuleGroup;
+
+  struct TestModule : ctk::ApplicationModule {
+    using ctk::ApplicationModule::ApplicationModule;
+
+    struct VarGroup : ctk::VariableGroup {
+      using ctk::VariableGroup::VariableGroup;
+      ctk::ScalarPushInput<int> varA{this, "varA", "MV/m", "Desc"};
+      ctk::ScalarPushInput<double> varB{this, "varB", "MV/m", "Desc"};
+      ctk::ScalarOutput<int> varC{this, "varC", "MV/m", "Desc"};
+    } varGroup{this, "VarGroup", "A group", ctk::HierarchyModifier::none, {"Exclude", "Partial"}};
+
+    struct MoveToRoot : ctk::VariableGroup {
+      using ctk::VariableGroup::VariableGroup;
+      ctk::ScalarPushInput<uint8_t> varX{this, "varX", "MV/m", "Desc"};
+      ctk::ScalarPushInput<int16_t> varY{this, "varY", "MV/m", "Desc"};
+      ctk::ScalarOutput<uint16_t> varZ{this, "varZ", "MV/m", "Desc"};
+    } moveToRoot{this, "MoveMeToRoot", "Group moved to /", ctk::HierarchyModifier::moveToRoot, {"Partial"}};
+
+    ctk::ScalarPushInput<std::string> varA{this, "varA", "MV/m", "Desc", {"Partial"}};
+    ctk::ScalarOutput<float> varX{this, "varX", "MV/m", "Desc"};
+
+    void mainLoop() {}
+  } testModule{this, "TestModule", ""};
+
+  struct SecondModule : ctk::ApplicationModule {
+    SecondModule(EntityOwner* owner, const std::string& name, const std::string& description)
+    : ctk::ApplicationModule(owner, name, description) {
+      for(size_t i = 0; i < 22; ++i) myVec.emplace_back(this, "Var" + std::to_string(i), "Unit", "Foo");
+    }
+    SecondModule() { throw; } // work around for gcc bug: constructor must be present but is unused
+
+    std::vector<ctk::ScalarPushInput<uint64_t>> myVec;
+
+    void mainLoop() {}
+
+  } secondModule{this, "SecondModule", ""};
+};
+
+/*********************************************************************************************************************/
+/* dummy application */
+
+struct TestApplication : public ctk::Application {
+  TestApplication() : Application("testSuite") {}
+  ~TestApplication() { shutdown(); }
+  void defineConnections() {} // the setup is done in the tests
+
+  FirstHierarchy first{this, "first", "The test module", ctk::HierarchyModifier::none, {"Everything"}};
+  ctk::ControlSystemModule cs;
+};
+
+/*********************************************************************************************************************/
+/* test tag on everything */
+
+BOOST_AUTO_TEST_CASE(testEverythingTag) {
+  std::cout << "*****************************************************************************************" << std::endl;
+  std::cout << "==> testEverythingTag" << std::endl;
+
+  TestApplication app;
+  app.findTag("Everything").connectTo(app.cs);
+  ctk::TestFacility test;
+  test.runApplication();
+
+  // check if all variables are found on the ControlSystem - read/write dummy values as a consistency check. We have
+  // different types and input/output mixed, so mixing up variables will be noticed.
+  test.writeScalar<int>("/first/TestModule/VarGroup/varA", 42);
+  test.writeScalar<double>("/first/TestModule/VarGroup/varB", 3.14);
+  test.readScalar<int>("/first/TestModule/VarGroup/varC");
+  test.writeScalar<std::string>("/first/TestModule/varA", "Hallo123");
+  test.readScalar<float>("/first/TestModule/varX");
+  for(size_t i = 0; i < 22; ++i) {
+    test.writeScalar<uint64_t>("/first/SecondModule/Var" + std::to_string(i), i);
+  }
+  test.writeScalar<uint8_t>("/MoveMeToRoot/varX", 0);
+  test.writeScalar<int16_t>("/MoveMeToRoot/varY", 0);
+  test.readScalar<uint16_t>("/MoveMeToRoot/varZ");
+}
+
+/*********************************************************************************************************************/
+/* test searching for a tag which is applied to only some variables */
+
+BOOST_AUTO_TEST_CASE(testPartialTag) {
+  std::cout << "*****************************************************************************************" << std::endl;
+  std::cout << "==> testPartialTag" << std::endl;
+
+  TestApplication app;
+  app.findTag("Partial").connectTo(app.cs);
+  ctk::TestFacility test;
+  test.runApplication();
+
+  // check if all variables are found on the ControlSystem - read/write dummy values as a consistency check. We have
+  // different types and input/output mixed, so mixing up variables will be noticed.
+  test.writeScalar<int>("/first/TestModule/VarGroup/varA", 42);
+  test.writeScalar<double>("/first/TestModule/VarGroup/varB", 3.14);
+  test.readScalar<int>("/first/TestModule/VarGroup/varC");
+  test.writeScalar<std::string>("/first/TestModule/varA", "Hallo123");
+  test.writeScalar<uint8_t>("/MoveMeToRoot/varX", 0);
+  test.writeScalar<int16_t>("/MoveMeToRoot/varY", 0);
+  test.readScalar<uint16_t>("/MoveMeToRoot/varZ");
+  // the rest is not part of our search result
+  BOOST_CHECK_THROW(test.readScalar<float>("/first/TestModule/varX"), ChimeraTK::logic_error);
+  for(size_t i = 0; i < 22; ++i) {
+    BOOST_CHECK_THROW(
+        test.writeScalar<uint64_t>("/first/SecondModule/Var" + std::to_string(i), i), ChimeraTK::logic_error);
+  }
+}
+
+/*********************************************************************************************************************/
+/* test searching for a tag and excluding another */
+
+BOOST_AUTO_TEST_CASE(testExcludeTag) {
+  std::cout << "*****************************************************************************************" << std::endl;
+  std::cout << "==> testExcludeTag" << std::endl;
+
+  TestApplication app;
+  app.findTag("Partial").excludeTag("Exclude").connectTo(app.cs);
+  ctk::TestFacility test;
+  test.runApplication();
+
+  // check if all variables are found on the ControlSystem - read/write dummy values as a consistency check. We have
+  // different types and input/output mixed, so mixing up variables will be noticed.
+  test.writeScalar<std::string>("/first/TestModule/varA", "Hallo123");
+  test.writeScalar<uint8_t>("/MoveMeToRoot/varX", 0);
+  test.writeScalar<int16_t>("/MoveMeToRoot/varY", 0);
+  test.readScalar<uint16_t>("/MoveMeToRoot/varZ");
+  // the rest is not part of our search result
+  BOOST_CHECK_THROW(test.writeScalar<int>("/first/TestModule/VarGroup/varA", 42), ChimeraTK::logic_error);
+  BOOST_CHECK_THROW(test.writeScalar<double>("/first/TestModule/VarGroup/varB", 3.14), ChimeraTK::logic_error);
+  BOOST_CHECK_THROW(test.readScalar<int>("/first/TestModule/VarGroup/varC"), ChimeraTK::logic_error);
+  BOOST_CHECK_THROW(test.readScalar<float>("/first/TestModule/varX"), ChimeraTK::logic_error);
+  for(size_t i = 0; i < 22; ++i) {
+    BOOST_CHECK_THROW(
+        test.writeScalar<uint64_t>("/first/SecondModule/Var" + std::to_string(i), i), ChimeraTK::logic_error);
+  }
+}
-- 
GitLab