From e76844d484adfb274d01fcf538d704279cb8ae67 Mon Sep 17 00:00:00 2001
From: kongr45gpen <electrovesta@gmail.com>
Date: Thu, 14 Mar 2019 05:14:38 +0200
Subject: [PATCH] Separate ErrorHandler logging into Platforms

---
 CMakeLists.txt                    |  3 ++-
 inc/ErrorHandler.hpp              | 37 +++++++++++++++++++++-------
 src/ErrorHandler.cpp              | 25 +------------------
 src/Platform/x86/ErrorHandler.cpp | 40 +++++++++++++++++++++++++++++++
 test/Services/ServiceTests.hpp    | 22 +++++++++++++++++
 test/TestPlatform.cpp             | 20 ++++++++++++++++
 6 files changed, 113 insertions(+), 34 deletions(-)
 create mode 100644 src/Platform/x86/ErrorHandler.cpp

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 069449e4..a36a71fd 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -30,10 +30,11 @@ add_library(common OBJECT
         )
 
 # Specify the .cpp files for the executables
+file(GLOB x86_main_SRC "src/Platform/x86/*.cpp")
 add_executable(ecss_services
         src/main.cpp
         $<TARGET_OBJECTS:common>
-        src/Platform/x86/Service.cpp
+        ${x86_main_SRC}
         )
 
 IF (EXISTS "${PROJECT_SOURCE_DIR}/lib/Catch2/CMakeLists.txt")
diff --git a/inc/ErrorHandler.hpp b/inc/ErrorHandler.hpp
index 25c65960..46dfa145 100644
--- a/inc/ErrorHandler.hpp
+++ b/inc/ErrorHandler.hpp
@@ -15,20 +15,13 @@ class Message;
 class ErrorHandler {
 private:
 	/**
-	 * Log the error to a logging facility. Currently, this just displays the error on the screen.
-	 *
-	 * @todo This function MUST be moved as platform-dependent code. Currently, it uses g++ specific
-	 * functions for desktop.
+	 * Log the error to a logging facility. Platform-dependent.
 	 */
 	template<typename ErrorType>
 	static void logError(const Message &message, ErrorType errorType);
 
 	/**
-	 * Log an error without a Message to a logging facility. Currently, this just displays the error
-	 * on the screen.
-	 *
-	 * @todo This function MUST be moved as platform-dependent code. Currently, it uses g++ specific
-	 * functions for desktop.
+	 * Log an error without a Message to a logging facility. Platform-dependent.
 	 */
 	template<typename ErrorType>
 	static void logError(ErrorType errorType);
@@ -212,6 +205,32 @@ public:
 			reportError(message, errorCode);
 		}
 	}
+
+	/**
+	 * Convert a parameter given in C++ to an ErrorSource that can be easily used in comparisons.
+	 * @tparam ErrorType One of the enums specified in ErrorHandler.
+	 * @param error An error code of a specific type
+	 * @return The corresponding ErrorSource
+	 */
+	template<typename ErrorType>
+	inline static ErrorSource findErrorSource(ErrorType error) {
+		// While this may seem like a "hacky" way to convert enums to ErrorSource, it should be
+		// optimised by the compiler to constant time.
+
+		if (typeid(ErrorType) == typeid(AcceptanceErrorType)) {
+			return Acceptance;
+		} else if (typeid(ErrorType) == typeid(ExecutionStartErrorType)) {
+			return ExecutionStart;
+		} else if (typeid(ErrorType) == typeid(ExecutionProgressErrorType)) {
+			return ExecutionProgress;
+		} else if (typeid(ErrorType) == typeid(ExecutionCompletionErrorType)) {
+			return ExecutionCompletion;
+		} else if (typeid(ErrorType) == typeid(RoutingErrorType)) {
+			return Routing;
+		} else {
+			return Internal;
+		}
+	}
 };
 
 #endif //PROJECT_ERRORHANDLER_HPP
diff --git a/src/ErrorHandler.cpp b/src/ErrorHandler.cpp
index d62eadd5..73ef5e06 100644
--- a/src/ErrorHandler.cpp
+++ b/src/ErrorHandler.cpp
@@ -43,28 +43,5 @@ void ErrorHandler::reportError(const Message &message, RoutingErrorType errorCod
 }
 
 void ErrorHandler::reportInternalError(ErrorHandler::InternalErrorType errorCode) {
-	logError(UnknownInternalError);
-}
-
-template<typename ErrorType>
-void ErrorHandler::logError(const Message &message, ErrorType errorType) {
-	std::cerr
-		/*
-		 * Gets the error class name from the template
-		 * Note: This is g++-dependent code and should only be used for debugging.
-		 */
-		<< abi::__cxa_demangle(typeid(ErrorType).name(), nullptr, nullptr, nullptr)
-		<< " Error " << "[" << static_cast<uint16_t>(message.serviceType) << "," <<
-		static_cast<uint16_t>(message.messageType) << "]: " << errorType << std::endl;
-}
-
-template<typename ErrorType>
-void ErrorHandler::logError(ErrorType errorType) {
-	std::cerr
-		/*
-		 * Gets the error class name from the template
-		 * Note: This is g++-dependent code and should only be used for debugging.
-		 */
-		<< abi::__cxa_demangle(typeid(ErrorType).name(), nullptr, nullptr, nullptr)
-		<< " Error: " << errorType << std::endl;
+	logError(errorCode);
 }
diff --git a/src/Platform/x86/ErrorHandler.cpp b/src/Platform/x86/ErrorHandler.cpp
new file mode 100644
index 00000000..6119440c
--- /dev/null
+++ b/src/Platform/x86/ErrorHandler.cpp
@@ -0,0 +1,40 @@
+/**
+ * This file specifies the logging utilities for x86 desktop platforms. These logging functions
+ * just print the error to screen (via stderr).
+ */
+
+#include <iostream>
+#include <cxxabi.h>
+#include <ErrorHandler.hpp>
+#include <Message.hpp>
+
+// TODO: Find a way to reduce the number of copies of this chunk
+template void ErrorHandler::logError(const Message &, ErrorHandler::AcceptanceErrorType);
+template void ErrorHandler::logError(const Message &, ErrorHandler::ExecutionStartErrorType);
+template void ErrorHandler::logError(const Message &, ErrorHandler::ExecutionProgressErrorType);
+template void ErrorHandler::logError(const Message &, ErrorHandler::ExecutionCompletionErrorType);
+template void ErrorHandler::logError(const Message &, ErrorHandler::RoutingErrorType);
+template void ErrorHandler::logError(ErrorHandler::InternalErrorType);
+
+template<typename ErrorType>
+void ErrorHandler::logError(const Message &message, ErrorType errorType) {
+	std::cerr
+		/*
+		 * Gets the error class name from the template
+		 * Note: This is g++-dependent code and should only be used for debugging.
+		 */
+		<< abi::__cxa_demangle(typeid(ErrorType).name(), nullptr, nullptr, nullptr)
+		<< " Error " << "[" << static_cast<uint16_t>(message.serviceType) << "," <<
+		static_cast<uint16_t>(message.messageType) << "]: " << errorType << std::endl;
+}
+
+template<typename ErrorType>
+void ErrorHandler::logError(ErrorType errorType) {
+	std::cerr
+		/*
+		 * Gets the error class name from the template
+		 * Note: This is g++-dependent code and should only be used for debugging.
+		 */
+		<< abi::__cxa_demangle(typeid(ErrorType).name(), nullptr, nullptr, nullptr)
+		<< " Error: " << errorType << std::endl;
+}
diff --git a/test/Services/ServiceTests.hpp b/test/Services/ServiceTests.hpp
index a160558a..ede8804c 100644
--- a/test/Services/ServiceTests.hpp
+++ b/test/Services/ServiceTests.hpp
@@ -2,6 +2,7 @@
 #define ECSS_SERVICES_TESTS_SERVICES_SERVICETESTS_HPP
 
 #include <vector>
+#include <map>
 #include <Message.hpp>
 
 /**
@@ -10,8 +11,18 @@
  * @todo See if members of this class can be made non-static
  */
 class ServiceTests {
+	/**
+	 * The list of Messages that have been sent as a result of all the processing.
+	 */
 	static std::vector<Message> queuedMessages;
 
+	/**
+	 * The list of Errors that the ErrorHandler caught
+	 * @var A multimap with keys (ErrorSource, ErrorType) and values of 1
+	 * @todo If errors get more complex, this should hold the complete error information
+	 */
+	static std::multimap<std::pair<ErrorHandler::ErrorSource, uint16_t>, bool> thrownErrors;
+
 public:
 	/**
 	 * Get a message from the list of queued messages to send
@@ -28,6 +39,17 @@ public:
 		queuedMessages.push_back(message);
 	}
 
+	/**
+	 * Add one error to the list of occurred errors.
+	 *
+	 * @param errorSource The source of the error.
+	 * @param errorCode The integer code of the error, coming directly from one of the ErrorCode
+	 * enumerations in ErrorHandler.
+	 */
+	static void addError(ErrorHandler::ErrorSource errorSource, uint16_t errorCode) {
+		thrownErrors.emplace(std::make_pair(errorSource, errorCode), 1);
+	}
+
 	/**
 	 * Counts the number of messages in the queue
 	 */
diff --git a/test/TestPlatform.cpp b/test/TestPlatform.cpp
index 10f9cdf3..192802cd 100644
--- a/test/TestPlatform.cpp
+++ b/test/TestPlatform.cpp
@@ -5,12 +5,32 @@
 #include <Service.hpp>
 #include "Services/ServiceTests.hpp"
 
+template void ErrorHandler::logError(const Message &, ErrorHandler::AcceptanceErrorType);
+template void ErrorHandler::logError(const Message &, ErrorHandler::ExecutionStartErrorType);
+template void ErrorHandler::logError(const Message &, ErrorHandler::ExecutionProgressErrorType);
+template void ErrorHandler::logError(const Message &, ErrorHandler::ExecutionCompletionErrorType);
+template void ErrorHandler::logError(const Message &, ErrorHandler::RoutingErrorType);
+template void ErrorHandler::logError(ErrorHandler::InternalErrorType);
+
 std::vector<Message> ServiceTests::queuedMessages = std::vector<Message>();
+std::multimap<std::pair<ErrorHandler::ErrorSource, uint16_t>, bool> ServiceTests::thrownErrors =
+	std::multimap<std::pair<ErrorHandler::ErrorSource, uint16_t>, bool>();
 
 void Service::storeMessage(const Message &message) {
+	// Just add the message to the queue
 	ServiceTests::queue(message);
 }
 
+template<typename ErrorType>
+void ErrorHandler::logError(const Message &message, ErrorType errorType) {
+	logError(errorType);
+}
+
+template<typename ErrorType>
+void ErrorHandler::logError(ErrorType errorType) {
+	ServiceTests::addError(ErrorHandler::findErrorSource(errorType), errorType);
+}
+
 struct ServiceTestsListener : Catch::TestEventListenerBase {
 	using TestEventListenerBase::TestEventListenerBase; // inherit constructor
 
-- 
GitLab