Browse Source

Add Narrator class

- add Narrator class and IListener interface to
provide observer pattern functionality
- add tests for Narrator class
Patrick 3 years ago
parent
commit
d4900ef2f4

+ 7 - 2
CMakeLists.txt

@@ -72,7 +72,9 @@ set(SOURCE_FILES
         ${CMAKE_CURRENT_SOURCE_DIR}/source/ls_std/io/xml/XMLDocument.cpp
         ${CMAKE_CURRENT_SOURCE_DIR}/source/ls_std/io/xml/XMLReader.cpp
         ${CMAKE_CURRENT_SOURCE_DIR}/source/ls_std/io/xml/XMLReaderMock.cpp
-        ${CMAKE_CURRENT_SOURCE_DIR}/source/ls_std/io/StandardOutputWriter.cpp)
+        ${CMAKE_CURRENT_SOURCE_DIR}/source/ls_std/io/StandardOutputWriter.cpp
+        ${CMAKE_CURRENT_SOURCE_DIR}/source/ls_std/logic/Narrator.cpp
+        ${CMAKE_CURRENT_SOURCE_DIR}/source/ls_std/logic/IListener.cpp)
 
 set(TEST_FILES
         ${CMAKE_CURRENT_SOURCE_DIR}/test/cases/boxing/IntegerTest.cpp
@@ -113,7 +115,10 @@ set(TEST_FILES
         ${CMAKE_CURRENT_SOURCE_DIR}/test/cases/io/xml/XMLDeclarationTest.cpp
         ${CMAKE_CURRENT_SOURCE_DIR}/test/cases/io/xml/XMLDocumentTest.cpp
         ${CMAKE_CURRENT_SOURCE_DIR}/test/cases/io/xml/XMLReaderTest.cpp
-        ${CMAKE_CURRENT_SOURCE_DIR}/test/cases/io/xml/XMLReaderMockTest.cpp)
+        ${CMAKE_CURRENT_SOURCE_DIR}/test/cases/io/xml/XMLReaderMockTest.cpp
+        ${CMAKE_CURRENT_SOURCE_DIR}/test/classes/observer/TestDataCar.cpp
+        ${CMAKE_CURRENT_SOURCE_DIR}/test/classes/observer/TestDataMercedesCar.cpp
+        ${CMAKE_CURRENT_SOURCE_DIR}/test/cases/logic/NarratorTest.cpp)
 
 ##########################################################
 # Build

+ 26 - 0
include/ls_std/logic/IListener.hpp

@@ -0,0 +1,26 @@
+/*
+ * Author:          Patrick-Christopher Mattulat
+ * Company:         Lynar Studios
+ * E-Mail:          webmaster@lynarstudios.com
+ * Created:         2020-11-14
+ * Changed:         2020-11-14
+ *
+ * */
+
+#ifndef LS_STD_ILISTENER_HPP
+#define LS_STD_ILISTENER_HPP
+
+#include "../base/Class.hpp"
+
+namespace ls_std {
+  class IListener : public Class {
+    public:
+
+      IListener();
+      ~IListener() override = default;
+
+      virtual void listen(const Class& _info) = 0;
+  };
+}
+
+#endif

+ 37 - 0
include/ls_std/logic/Narrator.hpp

@@ -0,0 +1,37 @@
+/*
+ * Author:          Patrick-Christopher Mattulat
+ * Company:         Lynar Studios
+ * E-Mail:          webmaster@lynarstudios.com
+ * Created:         2020-11-14
+ * Changed:         2020-11-14
+ *
+ * */
+
+#ifndef LS_STD_NARRATOR_HPP
+#define LS_STD_NARRATOR_HPP
+
+#include "../base/Class.hpp"
+#include "IListener.hpp"
+#include <list>
+#include <memory>
+
+namespace ls_std {
+  class Narrator : public Class {
+    public:
+
+      Narrator();
+      ~Narrator() override = default;
+
+      void addListener(const std::shared_ptr<ls_std::IListener>& _listener);
+      void clear();
+      std::list<std::shared_ptr<ls_std::IListener>> getListeners();
+      void notifyListeners(const ls_std::Class& _info);
+      void removeListener(const std::shared_ptr<ls_std::IListener>& _listener);
+
+    private:
+
+      std::list<std::shared_ptr<ls_std::IListener>> listeners {};
+  };
+}
+
+#endif

+ 13 - 0
source/ls_std/logic/IListener.cpp

@@ -0,0 +1,13 @@
+/*
+ * Author:          Patrick-Christopher Mattulat
+ * Company:         Lynar Studios
+ * E-Mail:          webmaster@lynarstudios.com
+ * Created:         2020-11-14
+ * Changed:         2020-11-14
+ *
+ * */
+
+#include "../../../include/ls_std/logic/IListener.hpp"
+
+ls_std::IListener::IListener() : Class("IListener")
+{}

+ 45 - 0
source/ls_std/logic/Narrator.cpp

@@ -0,0 +1,45 @@
+/*
+ * Author:          Patrick-Christopher Mattulat
+ * Company:         Lynar Studios
+ * E-Mail:          webmaster@lynarstudios.com
+ * Created:         2020-11-14
+ * Changed:         2020-11-14
+ *
+ * */
+
+#include <ls_std/utils/STLUtils.hpp>
+#include "../../../include/ls_std/logic/Narrator.hpp"
+
+ls_std::Narrator::Narrator() : Class("Narrator")
+{}
+
+void ls_std::Narrator::addListener(const std::shared_ptr<ls_std::IListener>& _listener)
+{
+  if(!ls_std::STLUtils::contains(this->listeners, _listener)) {
+    this->listeners.push_back(_listener);
+  }
+}
+
+void ls_std::Narrator::clear()
+{
+  this->listeners.clear();
+}
+
+std::list<std::shared_ptr<ls_std::IListener>> ls_std::Narrator::getListeners()
+{
+  return this->listeners;
+}
+
+void ls_std::Narrator::notifyListeners(const ls_std::Class &_info)
+{
+  for(const auto& listener : this->listeners) {
+    listener->listen(_info);
+  }
+}
+
+void ls_std::Narrator::removeListener(const std::shared_ptr<ls_std::IListener>& _listener)
+{
+  if(ls_std::STLUtils::contains(this->listeners, _listener)) {
+    this->listeners.remove(_listener);
+  }
+}

+ 112 - 0
test/cases/logic/NarratorTest.cpp

@@ -0,0 +1,112 @@
+/*
+ * Author:          Patrick-Christopher Mattulat
+ * Company:         Lynar Studios
+ * E-Mail:          webmaster@lynarstudios.com
+ * Created:         2020-11-14
+ * Changed:         2020-11-14
+ *
+ * */
+
+#include <gtest/gtest.h>
+#include <ls_std/ls_std.hpp>
+#include <ls_std/logic/Narrator.hpp>
+#include "../../classes/observer/TestDataMercedesCar.hpp"
+
+namespace {
+  class NarratorTest : public ::testing::Test {
+    protected:
+
+      NarratorTest() = default;
+      ~NarratorTest() override = default;
+
+      void SetUp() override {}
+      void TearDown() override {}
+
+      std::shared_ptr<ls_std_test::TestDataMercedesCar> mercedes1 {};
+      std::shared_ptr<ls_std_test::TestDataMercedesCar> mercedes2 {};
+      std::shared_ptr<ls_std_test::TestDataMercedesCar> mercedes3 {};
+
+      void createCars() {
+        this->mercedes1 = std::make_shared<ls_std_test::TestDataMercedesCar>();
+        this->mercedes1->setColor("pink");
+        this->mercedes2 = std::make_shared<ls_std_test::TestDataMercedesCar>();
+        this->mercedes2->setColor("blue");
+        this->mercedes3 = std::make_shared<ls_std_test::TestDataMercedesCar>();
+        this->mercedes3->setColor("red");
+      }
+  };
+
+  TEST_F(NarratorTest, addListener)
+  {
+    this->createCars();
+    ls_std::Narrator paintingMachine {};
+    ASSERT_TRUE(paintingMachine.getListeners().empty());
+    paintingMachine.addListener(std::dynamic_pointer_cast<ls_std::IListener>(this->mercedes1));
+    ASSERT_EQ(1, paintingMachine.getListeners().size());
+    paintingMachine.addListener(std::dynamic_pointer_cast<ls_std::IListener>(this->mercedes2));
+    ASSERT_EQ(2, paintingMachine.getListeners().size());
+    paintingMachine.addListener(std::dynamic_pointer_cast<ls_std::IListener>(this->mercedes3));
+    ASSERT_EQ(3, paintingMachine.getListeners().size());
+  }
+
+  TEST_F(NarratorTest, clear)
+  {
+    this->createCars();
+    ls_std::Narrator paintingMachine {};
+    paintingMachine.addListener(std::dynamic_pointer_cast<ls_std::IListener>(this->mercedes1));
+    paintingMachine.addListener(std::dynamic_pointer_cast<ls_std::IListener>(this->mercedes2));
+    paintingMachine.addListener(std::dynamic_pointer_cast<ls_std::IListener>(this->mercedes3));
+
+    ASSERT_FALSE(paintingMachine.getListeners().empty());
+    paintingMachine.clear();
+    ASSERT_TRUE(paintingMachine.getListeners().empty());
+  }
+
+  TEST_F(NarratorTest, getListeners)
+  {
+    ls_std::Narrator narrator {};
+    ASSERT_TRUE(narrator.getListeners().empty());
+  }
+
+  TEST_F(NarratorTest, notifyListeners)
+  {
+    this->createCars();
+    ls_std::Narrator paintingMachine {};
+    paintingMachine.addListener(std::dynamic_pointer_cast<ls_std::IListener>(this->mercedes1));
+    paintingMachine.addListener(std::dynamic_pointer_cast<ls_std::IListener>(this->mercedes2));
+    paintingMachine.addListener(std::dynamic_pointer_cast<ls_std::IListener>(this->mercedes3));
+
+    ASSERT_STREQ("pink", this->mercedes1->getColor().c_str());
+    ASSERT_STREQ("blue", this->mercedes2->getColor().c_str());
+    ASSERT_STREQ("red", this->mercedes3->getColor().c_str());
+
+    ls_std::String newColor {"black"};
+    paintingMachine.notifyListeners(static_cast<const ls_std::Class&>(newColor));
+
+    ASSERT_STREQ("black", this->mercedes1->getColor().c_str());
+    ASSERT_STREQ("black", this->mercedes2->getColor().c_str());
+    ASSERT_STREQ("black", this->mercedes3->getColor().c_str());
+  }
+
+  TEST_F(NarratorTest, removeListener)
+  {
+    this->createCars();
+    ls_std::Narrator paintingMachine {};
+    paintingMachine.addListener(std::dynamic_pointer_cast<ls_std::IListener>(this->mercedes1));
+    paintingMachine.addListener(std::dynamic_pointer_cast<ls_std::IListener>(this->mercedes2));
+    paintingMachine.addListener(std::dynamic_pointer_cast<ls_std::IListener>(this->mercedes3));
+    ASSERT_EQ(3, paintingMachine.getListeners().size());
+
+    paintingMachine.removeListener(this->mercedes2);
+    ASSERT_EQ(2, paintingMachine.getListeners().size());
+    paintingMachine.removeListener(this->mercedes1);
+    ASSERT_EQ(1, paintingMachine.getListeners().size());
+    paintingMachine.removeListener(this->mercedes3);
+    ASSERT_EQ(0, paintingMachine.getListeners().size());
+    ASSERT_TRUE(paintingMachine.getListeners().empty());
+
+    paintingMachine.removeListener(nullptr);
+    ASSERT_EQ(0, paintingMachine.getListeners().size());
+    ASSERT_TRUE(paintingMachine.getListeners().empty());
+  }
+}

+ 24 - 0
test/classes/observer/TestDataCar.cpp

@@ -0,0 +1,24 @@
+/*
+ * Author:          Patrick-Christopher Mattulat
+ * Company:         Lynar Studios
+ * E-Mail:          webmaster@lynarstudios.com
+ * Created:         2020-11-14
+ * Changed:         2020-11-14
+ *
+ * */
+
+#include "TestDataCar.hpp"
+
+ls_std_test::TestDataCar::TestDataCar():
+color("white")
+{}
+
+std::string ls_std_test::TestDataCar::getColor()
+{
+  return this->color;
+}
+
+void ls_std_test::TestDataCar::setColor(std::string _color)
+{
+  this->color = std::move(_color);
+}

+ 31 - 0
test/classes/observer/TestDataCar.hpp

@@ -0,0 +1,31 @@
+/*
+ * Author:          Patrick-Christopher Mattulat
+ * Company:         Lynar Studios
+ * E-Mail:          webmaster@lynarstudios.com
+ * Created:         2020-11-14
+ * Changed:         2020-11-14
+ *
+ * */
+
+#ifndef LS_STD_TEST_DATA_CAR_HPP
+#define LS_STD_TEST_DATA_CAR_HPP
+
+#include <string>
+
+namespace ls_std_test {
+  class TestDataCar {
+    public:
+
+      TestDataCar();
+      ~TestDataCar() = default;
+
+      std::string getColor();
+      void setColor(std::string _color);
+
+    private:
+
+      std::string color {};
+  };
+}
+
+#endif

+ 21 - 0
test/classes/observer/TestDataMercedesCar.cpp

@@ -0,0 +1,21 @@
+/*
+ * Author:          Patrick-Christopher Mattulat
+ * Company:         Lynar Studios
+ * E-Mail:          webmaster@lynarstudios.com
+ * Created:         2020-11-14
+ * Changed:         2020-11-14
+ *
+ * */
+
+#include <ls_std/boxing/String.hpp>
+#include "TestDataMercedesCar.hpp"
+
+ls_std_test::TestDataMercedesCar::TestDataMercedesCar() : TestDataCar()
+{
+  this->setColor("blue");
+}
+
+void ls_std_test::TestDataMercedesCar::listen(const Class &_info)
+{
+  this->setColor(dynamic_cast<const ls_std::String&>(_info));
+}

+ 27 - 0
test/classes/observer/TestDataMercedesCar.hpp

@@ -0,0 +1,27 @@
+/*
+ * Author:          Patrick-Christopher Mattulat
+ * Company:         Lynar Studios
+ * E-Mail:          webmaster@lynarstudios.com
+ * Created:         2020-11-14
+ * Changed:         2020-11-14
+ *
+ * */
+
+#ifndef LS_STD_TEST_DATA_MERCEDES_CAR_HPP
+#define LS_STD_TEST_DATA_MERCEDES_CAR_HPP
+
+#include "TestDataCar.hpp"
+#include "../../../include/ls_std/logic/IListener.hpp"
+
+namespace ls_std_test {
+  class TestDataMercedesCar : public TestDataCar, public ls_std::IListener {
+    public:
+
+      TestDataMercedesCar();
+      ~TestDataMercedesCar() override = default;
+
+      void listen(const Class& _info) override;
+  };
+}
+
+#endif