Browse Source

Make State class serializable

Patrick-Christopher Mattulat 3 years ago
parent
commit
c69e8779f5
3 changed files with 128 additions and 4 deletions
  1. 12 2
      include/ls_std/logic/State.hpp
  2. 41 1
      source/ls_std/logic/State.cpp
  3. 75 1
      test/cases/logic/StateTest.cpp

+ 12 - 2
include/ls_std/logic/State.hpp

@@ -3,7 +3,7 @@
  * Company:         Lynar Studios
  * E-Mail:          webmaster@lynarstudios.com
  * Created:         2020-09-05
- * Changed:         2021-04-23
+ * Changed:         2021-04-30
  *
  * */
 
@@ -15,16 +15,24 @@
 #include <ls_std/base/Class.hpp>
 #include "StateMachineTypes.hpp"
 #include "StateConnection.hpp"
+#include <ls_std/serialization/ISerializable.hpp>
 
 namespace ls_std
 {
-  class State : public ls_std::Class
+  class State : public ls_std::Class, public ls_std::ISerializable
   {
     public:
 
       explicit State(ls_std::StateId _id);
       ~State() override = default;
 
+      // implementation
+
+      ls_std::byte_field marshal() override;
+      void unmarshal(const ls_std::byte_field &_data) override;
+
+      // additional functionality
+
       bool addStateConnection(const ls_std::StateConnectionId &_connectionId, const std::shared_ptr<ls_std::State> &_connectedState);
       bool addStateConnection(const std::shared_ptr<ls_std::StateConnection> &_connection);
       void clearConnections();
@@ -32,11 +40,13 @@ namespace ls_std
       ls_std::StateId getId();
       bool hasConnection(const ls_std::StateConnectionId &_connectionId);
       void setId(ls_std::StateId _id);
+      void setSerializable(std::shared_ptr<ls_std::ISerializable> _serializable);
 
     private:
 
       std::unordered_map<ls_std::StateConnectionId, std::shared_ptr<ls_std::StateConnection>> connectedStates{};
       ls_std::StateId id{};
+      std::shared_ptr<ISerializable> serializable{};
 
       void _clearConnections();
       bool _hasConnection(const ls_std::StateConnectionId &_connectionId);

+ 41 - 1
source/ls_std/logic/State.cpp

@@ -3,17 +3,47 @@
  * Company:         Lynar Studios
  * E-Mail:          webmaster@lynarstudios.com
  * Created:         2020-09-05
- * Changed:         2021-04-23
+ * Changed:         2021-04-30
  *
  * */
 
 #include <ls_std/logic/State.hpp>
+#include <ls_std/exception/NullPointerException.hpp>
+#include <ls_std/exception/IllegalArgumentException.hpp>
 
 ls_std::State::State(ls_std::StateId _id)
     : ls_std::Class("State"),
       id(std::move(_id))
 {}
 
+ls_std::byte_field ls_std::State::marshal()
+{
+  ls_std::byte_field data{};
+
+  if (this->serializable != nullptr)
+  {
+    data = this->serializable->marshal();
+  }
+  else
+  {
+    throw ls_std::NullPointerException{};
+  }
+
+  return data;
+}
+
+void ls_std::State::unmarshal(const ls_std::byte_field &_data)
+{
+  if (this->serializable != nullptr)
+  {
+    this->serializable->unmarshal(_data);
+  }
+  else
+  {
+    throw ls_std::NullPointerException{};
+  }
+}
+
 bool ls_std::State::addStateConnection(const ls_std::StateConnectionId &_connectionId, const std::shared_ptr<ls_std::State> &_connectedState)
 {
   bool added{};
@@ -67,6 +97,16 @@ void ls_std::State::setId(ls_std::StateId _id)
   this->id = std::move(_id);
 }
 
+void ls_std::State::setSerializable(std::shared_ptr<ls_std::ISerializable> _serializable)
+{
+  if (_serializable == nullptr)
+  {
+    throw ls_std::IllegalArgumentException{};
+  }
+
+  this->serializable = std::move(_serializable);
+}
+
 void ls_std::State::_clearConnections()
 {
   this->connectedStates.clear();

+ 75 - 1
test/cases/logic/StateTest.cpp

@@ -3,7 +3,7 @@
  * Company:         Lynar Studios
  * E-Mail:          webmaster@lynarstudios.com
  * Created:         2020-09-05
- * Changed:         2021-04-23
+ * Changed:         2021-04-30
  *
  * */
 
@@ -27,6 +27,63 @@ namespace
       {}
   };
 
+  // implementation
+
+  TEST_F(StateTest, marshal)
+  {
+    std::shared_ptr<ls_std::State> state = std::make_shared<ls_std::State>("A");
+    std::shared_ptr<ls_std::ISerializable> serializable = std::make_shared<ls_std::SerializableJSONState>(state);
+    state->setSerializable(serializable);
+
+    ASSERT_FALSE(state->marshal().empty());
+  }
+
+  TEST_F(StateTest, marshal_noSerializableReference)
+  {
+    ls_std::State state{"A"};
+
+    EXPECT_THROW({
+                   try
+                   {
+                     state.marshal();
+                   }
+                   catch (const ls_std::NullPointerException &_exception)
+                   {
+                     throw;
+                   }
+                 }, ls_std::NullPointerException);
+  }
+
+  TEST_F(StateTest, unmarshal)
+  {
+    std::shared_ptr<ls_std::State> state = std::make_shared<ls_std::State>("TMP_ID");
+    std::shared_ptr<ls_std::ISerializable> serializable = std::make_shared<ls_std::SerializableJSONState>(state);
+    state->setSerializable(serializable);
+    std::string jsonString = R"({"id":"A","connectedStates":{"AB":{"condition":false,"connectionId":"AB","stateId":"B"}}})";
+    state->unmarshal(jsonString);
+
+    ASSERT_STREQ("A", state->getId().c_str());
+  }
+
+  TEST_F(StateTest, unmarshal_noSerializableReference)
+  {
+    std::shared_ptr<ls_std::State> state = std::make_shared<ls_std::State>("TMP_ID");
+    std::string jsonString = R"({"id":"A","connectedStates":{"AB":{"condition":false,"connectionId":"AB","stateId":"B"}}})";
+
+    EXPECT_THROW({
+                   try
+                   {
+                     state->unmarshal(jsonString);
+                   }
+                   catch (const ls_std::NullPointerException &_exception)
+                   {
+                     throw;
+                   }
+                 }, ls_std::NullPointerException);
+  }
+
+  // additional functionality
+
   TEST_F(StateTest, addStateConnection)
   {
     ls_std::State stateA{"A"};
@@ -122,4 +179,21 @@ namespace
     ASSERT_FALSE(stateA.hasConnection("AB"));
     ASSERT_FALSE(stateA.hasConnection("AC"));
   }
+
+  TEST_F(StateTest, setSerializable_noSerializableReference)
+  {
+    ls_std::State state{"A"};
+    std::shared_ptr<ls_std::ISerializable> serializable{};
+
+    EXPECT_THROW({
+                   try
+                   {
+                     state.setSerializable(serializable);
+                   }
+                   catch (const ls_std::IllegalArgumentException &_exception)
+                   {
+                     throw;
+                   }
+                 }, ls_std::IllegalArgumentException);
+  }
 }