From 8a8761ea88e361ff610dd18ba22e59f3f5a9140b Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Thu, 9 Apr 2020 17:56:48 +0200 Subject: [PATCH 01/14] stopwatch bugfix --- devicehandlers/CookieIF.h | 5 +++-- devicehandlers/DeviceCommunicationIF.h | 24 ++++++++++++------------ osal/FreeRTOS/BinarySemaphore.h | 26 +++++++++++--------------- serialize/SerializeDoc.h | 16 ++++++++++++++++ timemanager/Stopwatch.cpp | 2 +- 5 files changed, 43 insertions(+), 30 deletions(-) create mode 100644 serialize/SerializeDoc.h diff --git a/devicehandlers/CookieIF.h b/devicehandlers/CookieIF.h index ca171ff40..6b2bb5598 100644 --- a/devicehandlers/CookieIF.h +++ b/devicehandlers/CookieIF.h @@ -13,8 +13,9 @@ typedef uint32_t address_t; * single interface (like RMAP or I2C) * @details * To use this class, implement a communication specific child cookie which - * inherits Cookie. Cookie instances are created in config/ Factory.cpp by calling - * CookieIF* childCookie = new ChildCookie(...). + * inherits Cookie. Cookie instances are created in config/Factory.cpp by + * calling @code{.cpp} CookieIF* childCookie = new ChildCookie(...) + * @endcode . * * This cookie is then passed to the child device handlers, which stores the * pointer and passes it to the communication interface functions. diff --git a/devicehandlers/DeviceCommunicationIF.h b/devicehandlers/DeviceCommunicationIF.h index 39cfadd75..bb0951164 100644 --- a/devicehandlers/DeviceCommunicationIF.h +++ b/devicehandlers/DeviceCommunicationIF.h @@ -60,9 +60,9 @@ public: * this can be performed in this function, which is called on device handler * initialization. * @param cookie - * @return -@c RETURN_OK if initialization was successfull - * - Everything else triggers failure event with - * returnvalue as parameter 1 + * @return + * - @c RETURN_OK if initialization was successfull + * - Everything else triggers failure event with returnvalue as parameter 1 */ virtual ReturnValue_t initializeInterface(CookieIF * cookie) = 0; @@ -73,9 +73,9 @@ public: * @param cookie * @param data * @param len - * @return -@c RETURN_OK for successfull send - * - Everything else triggers failure event with - * returnvalue as parameter 1 + * @return + * - @c RETURN_OK for successfull send + * - Everything else triggers failure event with returnvalue as parameter 1 */ virtual ReturnValue_t sendMessage(CookieIF *cookie, const uint8_t * sendData, size_t sendLen) = 0; @@ -84,9 +84,9 @@ public: * Called by DHB in the GET_WRITE doGetWrite(). * Get send confirmation that the data in sendMessage() was sent successfully. * @param cookie - * @return -@c RETURN_OK if data was sent successfull + * @return - @c RETURN_OK if data was sent successfull * - Everything else triggers falure event with - * returnvalue as parameter 1 + * returnvalue as parameter 1 */ virtual ReturnValue_t getSendSuccess(CookieIF *cookie) = 0; @@ -99,9 +99,9 @@ public: * * @param cookie * @param requestLen Size of data to read - * @return -@c RETURN_OK to confirm the request for data has been sent. + * @return - @c RETURN_OK to confirm the request for data has been sent. * - Everything else triggers failure event with - * returnvalue as parameter 1 + * returnvalue as parameter 1 */ virtual ReturnValue_t requestReceiveMessage(CookieIF *cookie, size_t requestLen) = 0; @@ -113,8 +113,8 @@ public: * @param buffer [out] Set reply here (by using *buffer = ...) * @param size [out] size pointer to set (by using *size = ...). * Set to 0 if no reply was received - * @return -@c RETURN_OK for successfull receive - * -@c NO_REPLY_RECEIVED if not reply was received. Setting size to + * @return - @c RETURN_OK for successfull receive + * - @c NO_REPLY_RECEIVED if not reply was received. Setting size to * 0 has the same effect * - Everything else triggers failure event with * returnvalue as parameter 1 diff --git a/osal/FreeRTOS/BinarySemaphore.h b/osal/FreeRTOS/BinarySemaphore.h index 541266929..373e26bfc 100644 --- a/osal/FreeRTOS/BinarySemaphore.h +++ b/osal/FreeRTOS/BinarySemaphore.h @@ -35,24 +35,20 @@ public: static constexpr ReturnValue_t SEMAPHORE_NOT_OWNED = MAKE_RETURN_CODE(2); static constexpr ReturnValue_t SEMAPHORE_NULLPOINTER = MAKE_RETURN_CODE(3); - /** - * Create a binary semaphore - */ BinarySemaphore(); /** - * Copy ctor - * @param + * @brief Copy ctor */ BinarySemaphore(const BinarySemaphore&); /** - * Copy assignment + * @brief Copy assignment */ BinarySemaphore& operator=(const BinarySemaphore&); /** - * Move constructor + * @brief Move constructor */ BinarySemaphore (BinarySemaphore &&); @@ -81,16 +77,16 @@ public: /** * Same as lockBinarySemaphore() with timeout in FreeRTOS ticks. * @param timeoutTicks - * @return -@c RETURN_OK on success - * -@c RETURN_FAILED on failure + * @return - @c RETURN_OK on success + * - @c RETURN_FAILED on failure */ ReturnValue_t takeBinarySemaphoreTickTimeout(TickType_t timeoutTicks = BinarySemaphore::NO_BLOCK_TICKS); /** * Give back the binary semaphore - * @return -@c RETURN_OK on success - * -@c RETURN_FAILED on failure + * @return - @c RETURN_OK on success + * - @c RETURN_FAILED on failure */ ReturnValue_t giveBinarySemaphore(); @@ -108,8 +104,8 @@ public: /** * Wrapper function to give back semaphore from handle * @param semaphore - * @return -@c RETURN_OK on success - * -@c RETURN_FAILED on failure + * @return - @c RETURN_OK on success + * - @c RETURN_FAILED on failure */ static ReturnValue_t giveBinarySemaphore(SemaphoreHandle_t semaphore); @@ -118,8 +114,8 @@ public: * @param semaphore * @param higherPriorityTaskWoken This will be set to pdPASS if a task with a higher priority * was unblocked - * @return -@c RETURN_OK on success - * -@c RETURN_FAILED on failure + * @return - @c RETURN_OK on success + * - @c RETURN_FAILED on failure */ static ReturnValue_t giveBinarySemaphoreFromISR(SemaphoreHandle_t semaphore, BaseType_t * higherPriorityTaskWoken); diff --git a/serialize/SerializeDoc.h b/serialize/SerializeDoc.h new file mode 100644 index 000000000..6186b77b7 --- /dev/null +++ b/serialize/SerializeDoc.h @@ -0,0 +1,16 @@ +/** + * @page serialPage Serialization Tools + * This page refers to the serialization tools included in framework/serialize. + * The serialization tools are a useful tool to convert object data into raw + * buffers and vice-versa. Here is a rough overview which tool to use for + * which purpose. + * + * @section endSwapper Endian Swapper + * This header file includes tools to do simple serial order swapping + * + * @section serialiezIF SerializeIF + * + * @section serElement SerializeElement + * + */ + diff --git a/timemanager/Stopwatch.cpp b/timemanager/Stopwatch.cpp index 6c50f0de9..a7cbfa7cc 100644 --- a/timemanager/Stopwatch.cpp +++ b/timemanager/Stopwatch.cpp @@ -31,7 +31,7 @@ seconds_t Stopwatch::stopSeconds() { void Stopwatch::display() { if(displayMode == StopwatchDisplayMode::MILLIS) { - info << "Stopwatch: Operation took " << elapsedTime.tv_sec * 1000 + + info << "Stopwatch: Operation took " << elapsedTime.tv_sec / 1000 + elapsedTime.tv_usec * 1000 << " milliseconds" << std::endl; } else if(displayMode == StopwatchDisplayMode::SECONDS) { From 841b28b65d3c46a175d283d01e92729495f218d9 Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Thu, 9 Apr 2020 18:02:10 +0200 Subject: [PATCH 02/14] stopwatch ms now working --- timemanager/Stopwatch.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/timemanager/Stopwatch.cpp b/timemanager/Stopwatch.cpp index a7cbfa7cc..3f0755fd7 100644 --- a/timemanager/Stopwatch.cpp +++ b/timemanager/Stopwatch.cpp @@ -12,7 +12,7 @@ Stopwatch::Stopwatch(bool displayOnDestruction, StopwatchDisplayMode displayMode): displayMode(displayMode), displayOnDestruction(displayOnDestruction) { // Measures start time on initialization. - Clock::getUptime(&startTime); + startTime = Clock::getUptime(); } void Stopwatch::start() { @@ -31,8 +31,8 @@ seconds_t Stopwatch::stopSeconds() { void Stopwatch::display() { if(displayMode == StopwatchDisplayMode::MILLIS) { - info << "Stopwatch: Operation took " << elapsedTime.tv_sec / 1000 + - elapsedTime.tv_usec * 1000 << " milliseconds" << std::endl; + info << "Stopwatch: Operation took " << (elapsedTime.tv_sec * 1000 + + elapsedTime.tv_usec / 1000) << " milliseconds" << std::endl; } else if(displayMode == StopwatchDisplayMode::SECONDS) { info <<"Stopwatch: Operation took " << std::setprecision(3) From 69e9710bf17013f974188ee420279107b472e822 Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Fri, 10 Apr 2020 17:06:06 +0200 Subject: [PATCH 03/14] added intial carriage return im preamble --- osal/FreeRTOS/BinarySemaphore.cpp | 6 ++---- serviceinterface/ServiceInterfaceBuffer.cpp | 9 +++++---- serviceinterface/ServiceInterfaceBuffer.h | 10 +++++----- serviceinterface/ServiceInterfaceStream.cpp | 4 ++-- serviceinterface/ServiceInterfaceStream.h | 4 ++-- tmtcservices/TmTcBridge.cpp | 4 ++-- 6 files changed, 18 insertions(+), 19 deletions(-) diff --git a/osal/FreeRTOS/BinarySemaphore.cpp b/osal/FreeRTOS/BinarySemaphore.cpp index 05c97ae2e..e2cddacc0 100644 --- a/osal/FreeRTOS/BinarySemaphore.cpp +++ b/osal/FreeRTOS/BinarySemaphore.cpp @@ -138,10 +138,8 @@ ReturnValue_t BinarySemaphore::giveBinarySemaphoreFromISR(SemaphoreHandle_t sema BaseType_t returncode = xSemaphoreGiveFromISR(semaphore, higherPriorityTaskWoken); if (returncode == pdPASS) { if(*higherPriorityTaskWoken == pdPASS) { - // Request context switch - // TODO: I don't know if this will ever happen but if it does, - // I want to to know in case this causes issues. If it doesn't - // we should remove this. + // Request context switch because unblocking the semaphore + // caused a high priority task unblock. TaskManagement::requestContextSwitch(CallContext::isr); } return HasReturnvaluesIF::RETURN_OK; diff --git a/serviceinterface/ServiceInterfaceBuffer.cpp b/serviceinterface/ServiceInterfaceBuffer.cpp index 6798b776d..527db07b1 100644 --- a/serviceinterface/ServiceInterfaceBuffer.cpp +++ b/serviceinterface/ServiceInterfaceBuffer.cpp @@ -27,8 +27,8 @@ int ServiceInterfaceBuffer::sync(void) { Clock::TimeOfDay_t loggerTime; Clock::getDateAndTime(&loggerTime); char preamble[96] = { 0 }; - sprintf(preamble, "%s: | %" PRIu32 ":%02" PRIu32 ":%02" PRIu32 ".%03" PRIu32 " | ", - this->log_message.c_str(), + sprintf(preamble, "\r%s: | %" PRIu32 ":%02" PRIu32 ":%02" PRIu32 + ".%03" PRIu32 " | ", this->log_message.c_str(), loggerTime.hour, loggerTime.minute, loggerTime.second, @@ -45,7 +45,8 @@ int ServiceInterfaceBuffer::sync(void) { #ifndef UT699 -ServiceInterfaceBuffer::ServiceInterfaceBuffer(std::string set_message, uint16_t port) { +ServiceInterfaceBuffer::ServiceInterfaceBuffer(std::string set_message, + uint16_t port) { this->log_message = set_message; this->isActive = true; setp( buf, buf + BUF_SIZE ); @@ -59,7 +60,7 @@ void ServiceInterfaceBuffer::putChars(char const* begin, char const* end) { } memcpy(array, begin, length); - for( ; begin != end; begin++){ + for(; begin != end; begin++){ printChar(begin); } diff --git a/serviceinterface/ServiceInterfaceBuffer.h b/serviceinterface/ServiceInterfaceBuffer.h index b42c8a197..b4756d417 100644 --- a/serviceinterface/ServiceInterfaceBuffer.h +++ b/serviceinterface/ServiceInterfaceBuffer.h @@ -7,8 +7,8 @@ #include #ifndef UT699 -class ServiceInterfaceBuffer: public std::basic_streambuf > { +class ServiceInterfaceBuffer: + public std::basic_streambuf> { friend class ServiceInterfaceStream; public: ServiceInterfaceBuffer(std::string set_message, uint16_t port); @@ -17,11 +17,11 @@ protected: // This is called when buffer becomes full. If // buffer is not used, then this is called every // time when characters are put to stream. - virtual int overflow(int c = Traits::eof()); + int overflow(int c = Traits::eof()) override; // This function is called when stream is flushed, // for example when std::endl is put to stream. - virtual int sync(void); + int sync(void) override; private: // For additional message information @@ -30,7 +30,7 @@ private: typedef std::char_traits Traits; // Work in buffer mode. It is also possible to work without buffer. - static size_t const BUF_SIZE = 128; + static size_t const BUF_SIZE = 150; char buf[BUF_SIZE]; // In this function, the characters are parsed. diff --git a/serviceinterface/ServiceInterfaceStream.cpp b/serviceinterface/ServiceInterfaceStream.cpp index c2979f369..f52413a44 100644 --- a/serviceinterface/ServiceInterfaceStream.cpp +++ b/serviceinterface/ServiceInterfaceStream.cpp @@ -6,6 +6,6 @@ void ServiceInterfaceStream::setActive( bool myActive) { ServiceInterfaceStream::ServiceInterfaceStream(std::string set_message, uint16_t port) : - std::basic_ostream >(&buf), buf( - set_message, port) { + std::basic_ostream>(&buf), + buf(set_message, port) { } diff --git a/serviceinterface/ServiceInterfaceStream.h b/serviceinterface/ServiceInterfaceStream.h index 44cf1168f..4a5b709fb 100644 --- a/serviceinterface/ServiceInterfaceStream.h +++ b/serviceinterface/ServiceInterfaceStream.h @@ -14,7 +14,8 @@ extern std::ostream info; extern std::ostream warning; extern std::ostream error; -class ServiceInterfaceStream : public std::basic_ostream< char, std::char_traits< char > > { +class ServiceInterfaceStream : + public std::basic_ostream> { protected: ServiceInterfaceBuffer buf; public: @@ -23,5 +24,4 @@ public: }; - #endif /* FRAMEWORK_SERVICEINTERFACE_SERVICEINTERFACESTREAM_H_ */ diff --git a/tmtcservices/TmTcBridge.cpp b/tmtcservices/TmTcBridge.cpp index 6b563f983..8450494a6 100644 --- a/tmtcservices/TmTcBridge.cpp +++ b/tmtcservices/TmTcBridge.cpp @@ -104,7 +104,7 @@ ReturnValue_t TmTcBridge::readTmQueue() { ReturnValue_t TmTcBridge::storeDownlinkData(TmTcMessage *message) { info << "TMTC Bridge: Comm Link down. " - "Saving packet ID to be sent later " << std::endl; + "Saving packet ID to be sent later\r\n" << std::flush; store_address_t storeId; if(fifo.full()) { @@ -124,7 +124,7 @@ ReturnValue_t TmTcBridge::sendStoredTm() { ReturnValue_t result = RETURN_OK; while(!fifo.empty() && counter < MAX_STORED_DATA_SENT_PER_CYCLE) { info << "UDP Server: Sending stored TM data. There are " - << (int) fifo.size() << " left to send" << std::endl; + << (int) fifo.size() << " left to send\r\n" << std::flush; store_address_t storeId; const uint8_t* data = NULL; size_t size = 0; From eb2df3d88cc3bc2c70bda89208bf4e392bbef860 Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Sun, 12 Apr 2020 23:06:57 +0200 Subject: [PATCH 04/14] Using C++ to implement preamble. adding optional flag for carriage return --- datapool/PoolRawAccessHelper.h | 2 +- osal/linux/FixedTimeslotTask.cpp | 4 ++- serviceinterface/ServiceInterfaceBuffer.cpp | 32 ++++++++++++--------- serviceinterface/ServiceInterfaceBuffer.h | 22 ++++++++++++-- serviceinterface/ServiceInterfaceStream.cpp | 4 +-- serviceinterface/ServiceInterfaceStream.h | 5 ++-- 6 files changed, 47 insertions(+), 22 deletions(-) diff --git a/datapool/PoolRawAccessHelper.h b/datapool/PoolRawAccessHelper.h index 89974ea4f..7d9b9b487 100644 --- a/datapool/PoolRawAccessHelper.h +++ b/datapool/PoolRawAccessHelper.h @@ -69,7 +69,7 @@ private: struct SerializationArgs { uint8_t ** buffer; size_t * size; - const uint32_t max_size; + const size_t max_size; bool bigEndian; }; /** diff --git a/osal/linux/FixedTimeslotTask.cpp b/osal/linux/FixedTimeslotTask.cpp index 21040e6ef..7f117301a 100644 --- a/osal/linux/FixedTimeslotTask.cpp +++ b/osal/linux/FixedTimeslotTask.cpp @@ -9,7 +9,9 @@ uint32_t FixedTimeslotTask::deadlineMissedCount = 0; const size_t PeriodicTaskIF::MINIMUM_STACK_SIZE = PTHREAD_STACK_MIN; -FixedTimeslotTask::FixedTimeslotTask(const char* name_, int priority_, size_t stackSize_, uint32_t periodMs_):PosixThread(name_,priority_,stackSize_),pst(periodMs_),started(false) { +FixedTimeslotTask::FixedTimeslotTask(const char* name_, int priority_, + size_t stackSize_, uint32_t periodMs_): + PosixThread(name_,priority_,stackSize_),pst(periodMs_),started(false) { } FixedTimeslotTask::~FixedTimeslotTask() { diff --git a/serviceinterface/ServiceInterfaceBuffer.cpp b/serviceinterface/ServiceInterfaceBuffer.cpp index 527db07b1..a2365d000 100644 --- a/serviceinterface/ServiceInterfaceBuffer.cpp +++ b/serviceinterface/ServiceInterfaceBuffer.cpp @@ -1,13 +1,10 @@ #include #include #include -#include // to be implemented by bsp extern "C" void printChar(const char*); - - int ServiceInterfaceBuffer::overflow(int c) { // Handle output putChars(pbase(), pptr()); @@ -26,15 +23,16 @@ int ServiceInterfaceBuffer::sync(void) { if (this->isActive) { Clock::TimeOfDay_t loggerTime; Clock::getDateAndTime(&loggerTime); - char preamble[96] = { 0 }; - sprintf(preamble, "\r%s: | %" PRIu32 ":%02" PRIu32 ":%02" PRIu32 - ".%03" PRIu32 " | ", this->log_message.c_str(), - loggerTime.hour, - loggerTime.minute, - loggerTime.second, - loggerTime.usecond /1000); + std::string preamble; + if(addCrToPreamble) { + preamble += "\r"; + } + preamble += log_message + ": | " + zero_padded(loggerTime.hour, 2) + + ":" + zero_padded(loggerTime.minute, 2) + ":" + + zero_padded(loggerTime.second, 2) + "." + + zero_padded(loggerTime.usecond/1000, 3) + " | "; // Write log_message and time - this->putChars(preamble, preamble + sizeof(preamble)); + this->putChars(preamble.c_str(), preamble.c_str() + preamble.size()); // Handle output this->putChars(pbase(), pptr()); } @@ -43,10 +41,13 @@ int ServiceInterfaceBuffer::sync(void) { return 0; } + + #ifndef UT699 ServiceInterfaceBuffer::ServiceInterfaceBuffer(std::string set_message, - uint16_t port) { + uint16_t port, bool addCrToPreamble) { + this->addCrToPreamble = addCrToPreamble; this->log_message = set_message; this->isActive = true; setp( buf, buf + BUF_SIZE ); @@ -67,10 +68,15 @@ void ServiceInterfaceBuffer::putChars(char const* begin, char const* end) { } #endif +/** + * TODO: This is architecture specific. Maybe there is a better solution + * to move this into the Bsp folder.. + */ #ifdef UT699 #include -ServiceInterfaceBuffer::ServiceInterfaceBuffer(std::string set_message, uint16_t port) { +ServiceInterfaceBuffer::ServiceInterfaceBuffer(std::string set_message, + uint16_t port) { this->log_message = set_message; this->isActive = true; setp( buf, buf + BUF_SIZE ); diff --git a/serviceinterface/ServiceInterfaceBuffer.h b/serviceinterface/ServiceInterfaceBuffer.h index b4756d417..a2bc4f4b1 100644 --- a/serviceinterface/ServiceInterfaceBuffer.h +++ b/serviceinterface/ServiceInterfaceBuffer.h @@ -2,16 +2,17 @@ #define FRAMEWORK_SERVICEINTERFACE_SERVICEINTERFACEBUFFER_H_ #include -#include #include #include +#include #ifndef UT699 class ServiceInterfaceBuffer: public std::basic_streambuf> { friend class ServiceInterfaceStream; public: - ServiceInterfaceBuffer(std::string set_message, uint16_t port); + ServiceInterfaceBuffer(std::string set_message, uint16_t port, + bool addCrToPreamble); protected: bool isActive; // This is called when buffer becomes full. If @@ -28,13 +29,28 @@ private: std::string log_message; // For EOF detection typedef std::char_traits Traits; + // This is useful for some terminal programs which do not have + // implicit carriage return with newline characters. + bool addCrToPreamble; // Work in buffer mode. It is also possible to work without buffer. - static size_t const BUF_SIZE = 150; + static size_t const BUF_SIZE = 128; char buf[BUF_SIZE]; // In this function, the characters are parsed. void putChars(char const* begin, char const* end); + + template + std::string zero_padded(const T& num, uint8_t width) { + std::ostringstream string_to_pad; + string_to_pad << std::setw(width) << std::setfill('0') << num; + std::string result = string_to_pad.str(); + if (result.length() > width) + { + result.erase(0, result.length() - width); + } + return result; + } }; #endif diff --git a/serviceinterface/ServiceInterfaceStream.cpp b/serviceinterface/ServiceInterfaceStream.cpp index f52413a44..40f52f1fe 100644 --- a/serviceinterface/ServiceInterfaceStream.cpp +++ b/serviceinterface/ServiceInterfaceStream.cpp @@ -5,7 +5,7 @@ void ServiceInterfaceStream::setActive( bool myActive) { } ServiceInterfaceStream::ServiceInterfaceStream(std::string set_message, - uint16_t port) : + bool addCrToPreamble, uint16_t port) : std::basic_ostream>(&buf), - buf(set_message, port) { + buf(set_message, port, addCrToPreamble) { } diff --git a/serviceinterface/ServiceInterfaceStream.h b/serviceinterface/ServiceInterfaceStream.h index 4a5b709fb..5e223f0eb 100644 --- a/serviceinterface/ServiceInterfaceStream.h +++ b/serviceinterface/ServiceInterfaceStream.h @@ -7,7 +7,7 @@ #include #include -//Unfortunately, there must be a forward declaration of log_fe +// Unfortunately, there must be a forward declaration of log_fe // (MUST be defined in main), to let the system know where to write to. extern std::ostream debug; extern std::ostream info; @@ -19,7 +19,8 @@ class ServiceInterfaceStream : protected: ServiceInterfaceBuffer buf; public: - ServiceInterfaceStream( std::string set_message, uint16_t port = 1234 ); + ServiceInterfaceStream( std::string set_message, + bool addCrToPreamble = false, uint16_t port = 1234); void setActive( bool ); }; From a0ee010926eb3870c61c8eaa8cd39f9601b1fa86 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Mon, 13 Apr 2020 16:27:05 +0200 Subject: [PATCH 05/14] Added test folder. --- framework.mk | 1 + serialize/EndianSwapper.h | 4 +- serialize/SerialBufferAdapter.cpp | 17 ++- serialize/SerialBufferAdapter.h | 18 +-- serialize/SerializeAdapter.h | 37 ++--- test/UnitTestClass.cpp | 217 ++++++++++++++++++++++++++++++ test/UnitTestClass.h | 78 +++++++++++ 7 files changed, 338 insertions(+), 34 deletions(-) create mode 100644 test/UnitTestClass.cpp create mode 100644 test/UnitTestClass.h diff --git a/framework.mk b/framework.mk index a5a653641..2e7e57e93 100644 --- a/framework.mk +++ b/framework.mk @@ -54,3 +54,4 @@ CXXSRC += $(wildcard $(FRAMEWORK_PATH)/tmtcpacket/*.cpp) CXXSRC += $(wildcard $(FRAMEWORK_PATH)/tmtcpacket/packetmatcher/*.cpp) CXXSRC += $(wildcard $(FRAMEWORK_PATH)/tmtcpacket/pus/*.cpp) CXXSRC += $(wildcard $(FRAMEWORK_PATH)/tmtcservices/*.cpp) +CXXSRC += $(wildcard $(FRAMEWORK_PATH)/test/*.cpp) diff --git a/serialize/EndianSwapper.h b/serialize/EndianSwapper.h index 25fb681e9..9f621902f 100644 --- a/serialize/EndianSwapper.h +++ b/serialize/EndianSwapper.h @@ -11,9 +11,7 @@ */ class EndianSwapper { private: - EndianSwapper() { - } - ; + EndianSwapper() {}; public: template static T swap(T in) { diff --git a/serialize/SerialBufferAdapter.cpp b/serialize/SerialBufferAdapter.cpp index f97d0d588..42ea3dada 100644 --- a/serialize/SerialBufferAdapter.cpp +++ b/serialize/SerialBufferAdapter.cpp @@ -12,8 +12,8 @@ SerialBufferAdapter::SerialBufferAdapter(const void* buffer, } template -SerialBufferAdapter::SerialBufferAdapter(void* buffer, count_t bufferLength, - bool serializeLength) : +SerialBufferAdapter::SerialBufferAdapter(void* buffer, + count_t bufferLength, bool serializeLength) : serializeLength(serializeLength), bufferLength(bufferLength) { uint8_t * member_buffer = static_cast(buffer); m_buffer = member_buffer; @@ -26,8 +26,8 @@ SerialBufferAdapter::~SerialBufferAdapter() { } template -ReturnValue_t SerialBufferAdapter::serialize(uint8_t** buffer, size_t* size, - const size_t max_size, bool bigEndian) const { +ReturnValue_t SerialBufferAdapter::serialize(uint8_t** buffer, + size_t* size, const size_t max_size, bool bigEndian) const { uint32_t serializedLength = bufferLength; if (serializeLength) { serializedLength += AutoSerializeAdapter::getSerializedSize( @@ -98,7 +98,8 @@ ReturnValue_t SerialBufferAdapter::deSerialize(const uint8_t** buffer, template uint8_t * SerialBufferAdapter::getBuffer() { if(m_buffer == nullptr) { - error << "Wrong access function for stored type ! Use getConstBuffer()" << std::endl; + error << "Wrong access function for stored type !" + " Use getConstBuffer()" << std::endl; return nullptr; } return m_buffer; @@ -107,14 +108,16 @@ uint8_t * SerialBufferAdapter::getBuffer() { template const uint8_t * SerialBufferAdapter::getConstBuffer() { if(constBuffer == nullptr) { - error << "Wrong access function for stored type ! Use getBuffer()" << std::endl; + error << "Wrong access function for stored type !" + " Use getBuffer()" << std::endl; return nullptr; } return constBuffer; } template -void SerialBufferAdapter::setBuffer(void * buffer, count_t buffer_length) { +void SerialBufferAdapter::setBuffer(void * buffer, + count_t buffer_length) { m_buffer = static_cast(buffer); bufferLength = buffer_length; } diff --git a/serialize/SerialBufferAdapter.h b/serialize/SerialBufferAdapter.h index cf3ae07ed..4a886cbaa 100644 --- a/serialize/SerialBufferAdapter.h +++ b/serialize/SerialBufferAdapter.h @@ -8,11 +8,13 @@ * This adapter provides an interface for SerializeIF to serialize or deserialize * buffers with no length header but a known size. * - * Additionally, the buffer length can be serialized too and will be put in front of the serialized buffer. + * Additionally, the buffer length can be serialized too and will be put in + * front of the serialized buffer. * * Can be used with SerialLinkedListAdapter by declaring a SerializeElement with - * SerialElement> serialBufferElement. - * Right now, the SerialBufferAdapter must always be initialized with the buffer and size ! + * SerialElement>. + * Right now, the SerialBufferAdapter must always + * be initialized with the buffer and size ! * * \ingroup serialize */ @@ -27,14 +29,16 @@ public: * @param bufferLength * @param serializeLength */ - SerialBufferAdapter(const void* buffer, count_t bufferLength, bool serializeLength = false); + SerialBufferAdapter(const void* buffer, count_t bufferLength, + bool serializeLength = false); /** - * Constructor for non-constant uint8_t buffer. Length field can be serialized optionally. + * Constructor for non-constant uint8_t buffer. + * Length field can be serialized optionally. * Type of length can be supplied as template type. * @param buffer * @param bufferLength - * @param serializeLength + * @param serializeLength Length field will be serialized with size count_t */ SerialBufferAdapter(void* buffer, count_t bufferLength, bool serializeLength = false); @@ -58,6 +62,4 @@ private: count_t bufferLength = 0; }; - - #endif /* SERIALBUFFERADAPTER_H_ */ diff --git a/serialize/SerializeAdapter.h b/serialize/SerializeAdapter.h index 81a3730f8..fce8651b5 100644 --- a/serialize/SerializeAdapter.h +++ b/serialize/SerializeAdapter.h @@ -9,18 +9,21 @@ /** * @brief This adapter provides an interface to use the SerializeIF functions - * with arbitrary template objects to facilitate and simplify the serialization of classes - * with different multiple different data types into buffers and vice-versa. + * with arbitrary template objects to facilitate and simplify the + * serialization of classes with different multiple different data types + * into buffers and vice-versa. * @details * Examples: - * A report class is converted into a TM buffer. The report class implements a serialize functions and calls - * the AutoSerializeAdapter::serialize function repeatedly on all object data fields. - * The getSerializedSize function is implemented by calling the - * AutoSerializeAdapter::getSerializedSize function repeatedly on all data fields. + * A report class is converted into a TM buffer. The report class implements a + * serialize functions and calls the AutoSerializeAdapter::serialize function + * repeatedly on all object data fields. The getSerializedSize function is + * implemented by calling the AutoSerializeAdapter::getSerializedSize function + * repeatedly on all data fields. * - * The AutoSerializeAdapter functions can also be used as an alternative to memcpy - * to retrieve data out of a buffer directly into a class variable with data type T while being able to specify endianness. - * The boolean bigEndian specifies whether an endian swap is performed on the data before + * The AutoSerializeAdapter functions can also be used as an alternative to + * memcpy to retrieve data out of a buffer directly into a class variable + * with data type T while being able to specify endianness. The boolean + * bigEndian specifies whether an endian swap is performed on the data before * serialization or deserialization. * * If the target architecture is little endian (ARM), any data types created might @@ -50,8 +53,8 @@ * memcpy(&data,buffer + positionOfTargetByte1,sizeof(data)); * data = EndianSwapper::swap(data); * - * When serializing for downlink, the packets are generally serialized assuming big endian data format - * like seen in TmPacketStored.cpp for example. + * When serializing for downlink, the packets are generally serialized assuming + * big endian data format like seen in TmPacketStored.cpp for example. * * @ingroup serialize */ @@ -83,8 +86,10 @@ public: /** * Deserialize buffer into object * @param object [out] Object to be deserialized with buffer data - * @param buffer buffer containing the data. Non-Const pointer to non-const pointer to const buffer. - * @param size int32_t type to allow value to be values smaller than 0, needed for range/size checking + * @param buffer buffer containing the data. Non-Const pointer to non-const + * pointer to const buffer. + * @param size int32_t type to allow value to be values smaller than 0, + * needed for range/size checking * @param bigEndian Specify endianness * @return */ @@ -106,7 +111,7 @@ public: } } - uint32_t getSerializedSize(const T * object) { + size_t getSerializedSize(const T * object) { return sizeof(T); } @@ -123,7 +128,7 @@ public: } return object->serialize(buffer, size, max_size, bigEndian); } - uint32_t getSerializedSize(const T* object) const { + size_t getSerializedSize(const T* object) const { return object->getSerializedSize(); } @@ -163,7 +168,7 @@ public: return adapter.serialize(object, buffer, size, max_size, bigEndian); } template - static uint32_t getSerializedSize(const T* object) { + static size_t getSerializedSize(const T* object) { SerializeAdapter_::Is> adapter; return adapter.getSerializedSize(object); } diff --git a/test/UnitTestClass.cpp b/test/UnitTestClass.cpp new file mode 100644 index 000000000..7050dece0 --- /dev/null +++ b/test/UnitTestClass.cpp @@ -0,0 +1,217 @@ +/** + * @file UnitTestClass.cpp + * + * @date 11.04.2020 + * @author R. Mueller + */ +#include +#include +#include +#include + +#include + +UnitTestClass::UnitTestClass() { +} + +UnitTestClass::~UnitTestClass() { +} + +ReturnValue_t UnitTestClass::performTests() { + ReturnValue_t result = test_serialization(); + if(result != RETURN_OK) { + return result; + } + + return RETURN_OK; +} + +ReturnValue_t UnitTestClass::test_serialization() { + // Here, we test all serialization tools. First test basic cases. + ReturnValue_t result = test_autoserialization(); + if(result != RETURN_OK) { + return result; + } + result = test_serial_buffer_adapter(); + if(result != RETURN_OK) { + return result; + } + return RETURN_OK; +} + +ReturnValue_t UnitTestClass::test_autoserialization() { + current_id = TestIds::AUTO_SERIALIZATION_SIZE; + // Unit Test getSerializedSize + if(AutoSerializeAdapter:: + getSerializedSize(&test_value_bool) != sizeof(test_value_bool) or + AutoSerializeAdapter:: + getSerializedSize(&tv_uint8) != sizeof(tv_uint8) or + AutoSerializeAdapter:: + getSerializedSize(&tv_uint16) != sizeof(tv_uint16) or + AutoSerializeAdapter:: + getSerializedSize(&tv_uint32) != sizeof(tv_uint32) or + AutoSerializeAdapter:: + getSerializedSize(&tv_uint64) != sizeof(tv_uint64) or + AutoSerializeAdapter:: + getSerializedSize(&tv_int8) != sizeof(tv_int8) or + AutoSerializeAdapter:: + getSerializedSize(&tv_double) != sizeof(tv_double) or + AutoSerializeAdapter:: + getSerializedSize(&tv_int16) != sizeof(tv_int16) or + AutoSerializeAdapter:: + getSerializedSize(&tv_int32) != sizeof(tv_int32) or + AutoSerializeAdapter:: + getSerializedSize(&tv_float) != sizeof(tv_float)) + { + return put_error(current_id); + } + + // Unit Test AutoSerializeAdapter deserialize + current_id = TestIds::AUTO_SERIALIZATION_SERIALIZE; + + size_t serialized_size = 0; + uint8_t * p_array = test_array.data(); + + AutoSerializeAdapter::serialize(&test_value_bool, &p_array, + &serialized_size, test_array.size(), false); + AutoSerializeAdapter::serialize(&tv_uint8, &p_array, + &serialized_size, test_array.size(), false); + AutoSerializeAdapter::serialize(&tv_uint16, &p_array, + &serialized_size, test_array.size(), false); + AutoSerializeAdapter::serialize(&tv_uint32, &p_array, + &serialized_size, test_array.size(), false); + AutoSerializeAdapter::serialize(&tv_int8, &p_array, + &serialized_size, test_array.size(), false); + AutoSerializeAdapter::serialize(&tv_int16, &p_array, + &serialized_size, test_array.size(), false); + AutoSerializeAdapter::serialize(&tv_int32, &p_array, + &serialized_size, test_array.size(), false); + AutoSerializeAdapter::serialize(&tv_uint64, &p_array, + &serialized_size, test_array.size(), false); + AutoSerializeAdapter::serialize(&tv_float, &p_array, + &serialized_size, test_array.size(), false); + AutoSerializeAdapter::serialize(&tv_double, &p_array, + &serialized_size, test_array.size(), false); + AutoSerializeAdapter::serialize(&tv_sfloat, &p_array, + &serialized_size, test_array.size(), false); + AutoSerializeAdapter::serialize(&tv_sdouble, &p_array, + &serialized_size, test_array.size(), false); + // expected size is 1 + 1 + 2 + 4 + 1 + 2 + 4 + 8 + 4 + 8 + 4 + 8 + if(serialized_size != 47) { + return put_error(current_id); + } + + // Unit Test AutoSerializeAdapter serialize + current_id = TestIds::AUTO_SERIALIZATION_DESERIALIZE; + p_array = test_array.data(); + ssize_t remaining_size = serialized_size; + AutoSerializeAdapter::deSerialize(&test_value_bool, + const_cast(&p_array), &remaining_size, false); + AutoSerializeAdapter::deSerialize(&tv_uint8, + const_cast(&p_array), &remaining_size, false); + AutoSerializeAdapter::deSerialize(&tv_uint16, + const_cast(&p_array), &remaining_size, false); + AutoSerializeAdapter::deSerialize(&tv_uint32, + const_cast(&p_array), &remaining_size, false); + AutoSerializeAdapter::deSerialize(&tv_int8, + const_cast(&p_array), &remaining_size, false); + AutoSerializeAdapter::deSerialize(&tv_int16, + const_cast(&p_array), &remaining_size, false); + AutoSerializeAdapter::deSerialize(&tv_int32, + const_cast(&p_array), &remaining_size, false); + AutoSerializeAdapter::deSerialize(&tv_uint64, + const_cast(&p_array), &remaining_size, false); + AutoSerializeAdapter::deSerialize(&tv_float, + const_cast(&p_array), &remaining_size, false); + AutoSerializeAdapter::deSerialize(&tv_double, + const_cast(&p_array), &remaining_size, false); + AutoSerializeAdapter::deSerialize(&tv_sfloat, + const_cast(&p_array), &remaining_size, false); + AutoSerializeAdapter::deSerialize(&tv_sdouble, + const_cast(&p_array), &remaining_size, false); + + // uint16_t tv_uint16 {283}; + // uint32_t tv_uint32 {929221}; + // uint64_t tv_uint64 {2929329429}; + // int8_t tv_int8 {-16}; + // int16_t tv_int16 {-829}; + // int32_t tv_int32 {-2312}; + // float tv_float {8.2149214}; + // float tv_sfloat = {-922.2321321}; + // double tv_double {9.2132142141e8}; + // double tv_sdouble {-2.2421e19}; + if(test_value_bool != true or tv_uint8 != 5 or tv_uint16 != 283 or + tv_uint32 != 929221 or tv_uint64 != 2929329429 or tv_int8 != -16 or + tv_int16 != -829 or tv_int32 != -2312 or tv_float != 8.214921 or + tv_double != 9.2132142141e8 or tv_sfloat != -922.2321321 or + tv_sdouble != -2.2421e19) + { + return put_error(current_id); + } + return RETURN_OK; +} + +ReturnValue_t UnitTestClass::test_serial_buffer_adapter() { + current_id = TestIds::SERIALIZATION_BUFFER_ADAPTER; + + // I will skip endian swapper testing, its going to be changed anyway.. + // uint8_t tv_uint8_swapped = EndianSwapper::swap(tv_uint8); + + size_t serialized_size = 0; + test_value_bool = true; + uint8_t * p_array = test_array.data(); + std::array test_serial_buffer {5, 4, 3, 2, 1}; + SerialBufferAdapter tv_serial_buffer_adapter = + SerialBufferAdapter(test_serial_buffer.data(), + test_serial_buffer.size(), false); + tv_uint16 = 16; + + AutoSerializeAdapter::serialize(&test_value_bool, &p_array,&serialized_size, + test_array.size(), false); + AutoSerializeAdapter::serialize(&tv_serial_buffer_adapter, &p_array, + &serialized_size, test_array.size(), false); + AutoSerializeAdapter::serialize(&tv_uint16, &p_array, &serialized_size, + test_array.size(), false); + + if(serialized_size != 8 or test_array[0] != true or test_array[1] != 5 + or test_array[2] != 4 or test_array[3] != 3 or test_array[4] != 2 + or test_array[5] != 1) + { + return put_error(current_id); + } + memcpy(&tv_uint16, test_array.data() + 6, sizeof(tv_uint16)); + if(tv_uint16 != 16) { + return put_error(current_id); + } + + // Serialize with size field + SerialBufferAdapter tv_serial_buffer_adapter2 = + SerialBufferAdapter(test_serial_buffer.data(), + test_serial_buffer.size(), true); + serialized_size = 0; + p_array = test_array.data(); + AutoSerializeAdapter::serialize(&test_value_bool, &p_array,&serialized_size, + test_array.size(), false); + AutoSerializeAdapter::serialize(&tv_serial_buffer_adapter2, &p_array, + &serialized_size, test_array.size(), false); + AutoSerializeAdapter::serialize(&tv_uint16, &p_array, &serialized_size, + test_array.size(), false); + + if(serialized_size != 9 or test_array[0] != true or test_array[1] != 5 + or test_array[2] != 5 or test_array[3] != 4 or test_array[4] != 3 + or test_array[5] != 2 or test_array[6] != 1) + { + return put_error(current_id); + } + memcpy(&tv_uint16, test_array.data() + 6, sizeof(tv_uint16)); + if(tv_uint16 != 16) { + return put_error(current_id); + } + return RETURN_OK; +} + +ReturnValue_t UnitTestClass::put_error(TestIds current_id) { + error << "Unit Tester failed at test ID " + << static_cast(current_id) << "\r\n" << std::flush; + return RETURN_FAILED; +} diff --git a/test/UnitTestClass.h b/test/UnitTestClass.h new file mode 100644 index 000000000..c93ea0bc8 --- /dev/null +++ b/test/UnitTestClass.h @@ -0,0 +1,78 @@ +/** + * @file UnitTestClass.h + * + * @date 11.04.2020 + * @author R. Mueller + */ + +#ifndef FRAMEWORK_TEST_UNITTESTCLASS_H_ +#define FRAMEWORK_TEST_UNITTESTCLASS_H_ + +#include +#include +#include + +/** + * We could start doing basic forms of Unit Testing (without a framework, first) + * for framework components. This could include: + * + * 1. TMTC Services + * 2. Serialization tools + * 3. Framework internal algorithms + */ + +class UnitTestClass: public HasReturnvaluesIF { +public: + UnitTestClass(); + virtual~ UnitTestClass(); + + enum class TestIds { + AUTO_SERIALIZATION_SIZE = 0, + AUTO_SERIALIZATION_SERIALIZE = 1, + AUTO_SERIALIZATION_DESERIALIZE = 2, + SERIALIZATION_BUFFER_ADAPTER = 3, + SERIALIZATION_FIXED_ARRAY_LIST_ADAPTER = 4, + SERIALIZATION_COMBINATION = 5, + TMTC_SERVICES , + MISC + }; + + /** + * Some function which calls all other tests + * @return + */ + ReturnValue_t performTests(); + + ReturnValue_t test_serialization(); + ReturnValue_t test_autoserialization(); + ReturnValue_t test_serial_buffer_adapter(); +private: + uint32_t errorCounter = 0; + TestIds current_id = TestIds::MISC; + std::array test_array; + + using TestResultMap = std::map; + using TestBuffer = std::vector; + TestResultMap testResultMap; + + // POD test values + bool test_value_bool = true; + uint8_t tv_uint8 {5}; + uint16_t tv_uint16 {283}; + uint32_t tv_uint32 {929221}; + uint64_t tv_uint64 {2929329429}; + + int8_t tv_int8 {-16}; + int16_t tv_int16 {-829}; + int32_t tv_int32 {-2312}; + + float tv_float {8.2149214}; + float tv_sfloat = {-922.2321321}; + double tv_double {9.2132142141e8}; + double tv_sdouble {-2.2421e19}; + + ReturnValue_t put_error(TestIds currentId); +}; + + +#endif /* FRAMEWORK_TEST_UNITTESTCLASS_H_ */ From 0d016e5a2b2e5b566c7c7f2a11e64c1c93dcc4d3 Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Mon, 13 Apr 2020 16:37:25 +0200 Subject: [PATCH 06/14] slight formatting --- osal/linux/PeriodicPosixTask.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osal/linux/PeriodicPosixTask.h b/osal/linux/PeriodicPosixTask.h index e3fa57229..43647eda1 100644 --- a/osal/linux/PeriodicPosixTask.h +++ b/osal/linux/PeriodicPosixTask.h @@ -9,7 +9,8 @@ class PeriodicPosixTask: public PosixThread, public PeriodicTaskIF { public: - PeriodicPosixTask(const char* name_, int priority_, size_t stackSize_, uint32_t period_, void(*deadlineMissedFunc_)()); + PeriodicPosixTask(const char* name_, int priority_, size_t stackSize_, + uint32_t period_, void(*deadlineMissedFunc_)()); virtual ~PeriodicPosixTask(); /** * @brief The method to start the task. From b48a0a4a4ce5ea9b4e85b76223e357fe49ce6907 Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Mon, 13 Apr 2020 22:45:23 +0200 Subject: [PATCH 07/14] unit test class continued. serialize adapter functions which are internal, extracted to separate class --- container/IsDerivedFrom.h | 9 ++ serialize/SerializeAdapter.h | 162 +++++++-------------------- serialize/SerializeAdapterInternal.h | 114 +++++++++++++++++++ test/UnitTestClass.cpp | 87 +++++++++++++- test/UnitTestClass.h | 18 +-- 5 files changed, 259 insertions(+), 131 deletions(-) create mode 100644 serialize/SerializeAdapterInternal.h diff --git a/container/IsDerivedFrom.h b/container/IsDerivedFrom.h index 520033dbd..8142a3781 100644 --- a/container/IsDerivedFrom.h +++ b/container/IsDerivedFrom.h @@ -1,6 +1,13 @@ #ifndef ISDERIVEDFROM_H_ #define ISDERIVEDFROM_H_ +/** + * These template type checks are based on SFINAE + * (https://en.cppreference.com/w/cpp/language/sfinae) + * + * @tparam D Derived Type + * @tparam B Base Type + */ template class IsDerivedFrom { class No { @@ -9,7 +16,9 @@ class IsDerivedFrom { No no[3]; }; + // This will be chosen if B is the base type static Yes Test(B*); // declared, but not defined + // This will be chosen for anything else static No Test(... ); // declared, but not defined public: diff --git a/serialize/SerializeAdapter.h b/serialize/SerializeAdapter.h index fce8651b5..d926bfcec 100644 --- a/serialize/SerializeAdapter.h +++ b/serialize/SerializeAdapter.h @@ -1,19 +1,18 @@ #ifndef SERIALIZEADAPTER_H_ #define SERIALIZEADAPTER_H_ -#include #include -#include #include -#include +#include +#include /** - * @brief This adapter provides an interface to use the SerializeIF functions + * @brief These adapters provides an interface to use the SerializeIF functions * with arbitrary template objects to facilitate and simplify the * serialization of classes with different multiple different data types * into buffers and vice-versa. * @details - * Examples: + * * A report class is converted into a TM buffer. The report class implements a * serialize functions and calls the AutoSerializeAdapter::serialize function * repeatedly on all object data fields. The getSerializedSize function is @@ -26,137 +25,42 @@ * bigEndian specifies whether an endian swap is performed on the data before * serialization or deserialization. * - * If the target architecture is little endian (ARM), any data types created might - * have the wrong endiness if they are to be used for the FSFW. * There are three ways to retrieve data out of a buffer to be used in the FSFW - * to use regular aligned (big endian) data. - * This can also be applied to uint32_t and uint64_t: + * to use regular aligned (big endian) data. Examples: * * 1. Use the AutoSerializeAdapter::deSerialize function - * The pointer *buffer will be incremented automatically by the typeSize of the object, - * so this function can be called on &buffer repeatedly without adjusting pointer position. - * Set bigEndian parameter to true to perform endian swapping. - * + * The pointer *buffer will be incremented automatically by the typeSize + * of the object, so this function can be called on &buffer repeatedly + * without adjusting pointer position. Set bigEndian parameter to true + * to perform endian swapping, if necessary + * @code * uint16_t data; * int32_t dataLen = sizeof(data); - * ReturnValue_t result = AutoSerializeAdapter::deSerialize(&data,&buffer,&dataLen,true); - * - * 2. Perform a bitshift operation. Perform endian swapping if necessary: + * ReturnValue_t result = + * AutoSerializeAdapter::deSerialize(&data,&buffer,&dataLen,true); + * @endcode * + * 2. Perform a bitshift operation. Watch for for endianness: + * @code * uint16_t data; * data = buffer[targetByte1] << 8 | buffer[targetByte2]; - * data = EndianSwapper::swap(data); - * - * 3. Memcpy can be used when data is little-endian. Perform endian-swapping if necessary. + * data = EndianSwapper::swap(data); //optional, or swap order above + * @endcode * + * 3. memcpy or std::copy can also be used, but watch out if system + * endianness is different from required data endianness. + * Perform endian-swapping if necessary. + * @code * uint16_t data; * memcpy(&data,buffer + positionOfTargetByte1,sizeof(data)); - * data = EndianSwapper::swap(data); + * data = EndianSwapper::swap(data); //optional + * @endcode * * When serializing for downlink, the packets are generally serialized assuming * big endian data format like seen in TmPacketStored.cpp for example. * * @ingroup serialize */ -template -class SerializeAdapter_ { -public: - static ReturnValue_t serialize(const T* object, uint8_t** buffer, - size_t* size, const size_t max_size, bool bigEndian) { - size_t ignoredSize = 0; - if (size == NULL) { - size = &ignoredSize; - } - if (sizeof(T) + *size <= max_size) { - T tmp; - if (bigEndian) { - tmp = EndianSwapper::swap(*object); - } else { - tmp = *object; - } - memcpy(*buffer, &tmp, sizeof(T)); - *size += sizeof(T); - (*buffer) += sizeof(T); - return HasReturnvaluesIF::RETURN_OK; - } else { - return SerializeIF::BUFFER_TOO_SHORT; - } - } - - /** - * Deserialize buffer into object - * @param object [out] Object to be deserialized with buffer data - * @param buffer buffer containing the data. Non-Const pointer to non-const - * pointer to const buffer. - * @param size int32_t type to allow value to be values smaller than 0, - * needed for range/size checking - * @param bigEndian Specify endianness - * @return - */ - ReturnValue_t deSerialize(T* object, const uint8_t** buffer, ssize_t* size, - bool bigEndian) { - T tmp; - *size -= sizeof(T); - if (*size >= 0) { - memcpy(&tmp, *buffer, sizeof(T)); - if (bigEndian) { - *object = EndianSwapper::swap(tmp); - } else { - *object = tmp; - } - *buffer += sizeof(T); - return HasReturnvaluesIF::RETURN_OK; - } else { - return SerializeIF::STREAM_TOO_SHORT; - } - } - - size_t getSerializedSize(const T * object) { - return sizeof(T); - } - -}; - -template -class SerializeAdapter_ { -public: - ReturnValue_t serialize(const T* object, uint8_t** buffer, size_t* size, - const size_t max_size, bool bigEndian) const { - size_t ignoredSize = 0; - if (size == NULL) { - size = &ignoredSize; - } - return object->serialize(buffer, size, max_size, bigEndian); - } - size_t getSerializedSize(const T* object) const { - return object->getSerializedSize(); - } - - ReturnValue_t deSerialize(T* object, const uint8_t** buffer, ssize_t* size, - bool bigEndian) { - return object->deSerialize(buffer, size, bigEndian); - } -}; - -template -class SerializeAdapter { -public: - static ReturnValue_t serialize(const T* object, uint8_t** buffer, - size_t* size, const size_t max_size, bool bigEndian) { - SerializeAdapter_::Is> adapter; - return adapter.serialize(object, buffer, size, max_size, bigEndian); - } - static uint32_t getSerializedSize(const T* object) { - SerializeAdapter_::Is> adapter; - return adapter.getSerializedSize(object); - } - - static ReturnValue_t deSerialize(T* object, const uint8_t** buffer, - ssize_t* size, bool bigEndian) { - SerializeAdapter_::Is> adapter; - return adapter.deSerialize(object, buffer, size, bigEndian); - } -}; // No type specification necessary here. class AutoSerializeAdapter { @@ -180,4 +84,24 @@ public: } }; +template +class SerializeAdapter { +public: + static ReturnValue_t serialize(const T* object, uint8_t** buffer, + size_t* size, const size_t max_size, bool bigEndian) { + SerializeAdapter_::Is> adapter; + return adapter.serialize(object, buffer, size, max_size, bigEndian); + } + static uint32_t getSerializedSize(const T* object) { + SerializeAdapter_::Is> adapter; + return adapter.getSerializedSize(object); + } + + static ReturnValue_t deSerialize(T* object, const uint8_t** buffer, + ssize_t* size, bool bigEndian) { + SerializeAdapter_::Is> adapter; + return adapter.deSerialize(object, buffer, size, bigEndian); + } +}; + #endif /* SERIALIZEADAPTER_H_ */ diff --git a/serialize/SerializeAdapterInternal.h b/serialize/SerializeAdapterInternal.h new file mode 100644 index 000000000..46dbdf191 --- /dev/null +++ b/serialize/SerializeAdapterInternal.h @@ -0,0 +1,114 @@ +/** + * @file SerializeAdapterInternal.h + * + * @date 13.04.2020 + * @author R. Mueller + */ + +#ifndef FRAMEWORK_SERIALIZE_SERIALIZEADAPTERINTERNAL_H_ +#define FRAMEWORK_SERIALIZE_SERIALIZEADAPTERINTERNAL_H_ +#include +#include +#include + +/** + * This template specialization will be chosen for fundamental types. + * @tparam T + * @tparam + */ +template +class SerializeAdapter_ { +public: + /** + * + * @param object + * @param buffer + * @param size + * @param max_size + * @param bigEndian + * @return + */ + static ReturnValue_t serialize(const T* object, uint8_t** buffer, + size_t* size, const size_t max_size, bool bigEndian) { + size_t ignoredSize = 0; + if (size == nullptr) { + size = &ignoredSize; + } + if (sizeof(T) + *size <= max_size) { + T tmp; + if (bigEndian) { + tmp = EndianSwapper::swap(*object); + } else { + tmp = *object; + } + memcpy(*buffer, &tmp, sizeof(T)); + *size += sizeof(T); + (*buffer) += sizeof(T); + return HasReturnvaluesIF::RETURN_OK; + } else { + return SerializeIF::BUFFER_TOO_SHORT; + } + } + + /** + * Deserialize buffer into object + * @param object [out] Object to be deserialized with buffer data + * @param buffer buffer containing the data. Non-Const pointer to non-const + * pointer to const buffer. + * @param size int32_t type to allow value to be values smaller than 0, + * needed for range/size checking + * @param bigEndian Specify endianness + * @return + */ + ReturnValue_t deSerialize(T* object, const uint8_t** buffer, ssize_t* size, + bool bigEndian) { + T tmp; + *size -= sizeof(T); + if (*size >= 0) { + memcpy(&tmp, *buffer, sizeof(T)); + if (bigEndian) { + *object = EndianSwapper::swap(tmp); + } else { + *object = tmp; + } + *buffer += sizeof(T); + return HasReturnvaluesIF::RETURN_OK; + } else { + return SerializeIF::STREAM_TOO_SHORT; + } + } + + size_t getSerializedSize(const T * object) { + return sizeof(T); + } +}; + +/** + * This template specialization will be chosen for class derived from + * SerializeIF. + * @tparam T + * @tparam + */ +template +class SerializeAdapter_ { +public: + ReturnValue_t serialize(const T* object, uint8_t** buffer, size_t* size, + const size_t max_size, bool bigEndian) const { + size_t ignoredSize = 0; + if (size == NULL) { + size = &ignoredSize; + } + return object->serialize(buffer, size, max_size, bigEndian); + } + + size_t getSerializedSize(const T* object) const { + return object->getSerializedSize(); + } + + ReturnValue_t deSerialize(T* object, const uint8_t** buffer, ssize_t* size, + bool bigEndian) { + return object->deSerialize(buffer, size, bigEndian); + } +}; + +#endif /* FRAMEWORK_SERIALIZE_SERIALIZEADAPTERINTERNAL_H_ */ diff --git a/test/UnitTestClass.cpp b/test/UnitTestClass.cpp index 7050dece0..ac570b21e 100644 --- a/test/UnitTestClass.cpp +++ b/test/UnitTestClass.cpp @@ -17,7 +17,7 @@ UnitTestClass::UnitTestClass() { UnitTestClass::~UnitTestClass() { } -ReturnValue_t UnitTestClass::performTests() { +ReturnValue_t UnitTestClass::perform_tests() { ReturnValue_t result = test_serialization(); if(result != RETURN_OK) { return result; @@ -28,7 +28,11 @@ ReturnValue_t UnitTestClass::performTests() { ReturnValue_t UnitTestClass::test_serialization() { // Here, we test all serialization tools. First test basic cases. - ReturnValue_t result = test_autoserialization(); + ReturnValue_t result = test_endianness_tools(); + if(result != RETURN_OK) { + return result; + } + result = test_autoserialization(); if(result != RETURN_OK) { return result; } @@ -39,6 +43,47 @@ ReturnValue_t UnitTestClass::test_serialization() { return RETURN_OK; } +ReturnValue_t UnitTestClass::test_endianness_tools() { + test_array[0] = 0; + test_array[1] = 0; + uint16_t two_byte_value = 1; + size_t size = 0; + uint8_t* p_array = test_array.data(); + AutoSerializeAdapter::serialize(&two_byte_value, &p_array, &size, 2, false); + // Little endian: Value one on first byte + if(test_array[0] != 1 and test_array[1] != 0) { + return put_error(TestIds::ENDIANNESS_TOOLS); + + } + p_array = test_array.data(); + size = 0; + AutoSerializeAdapter::serialize(&two_byte_value, &p_array, &size, 2, true); + // Big endian: Value one on second byte + if(test_array[0] != 0 and test_array[1] != 1) { + return put_error(TestIds::ENDIANNESS_TOOLS); + } + + // Endianness paameter will be changed later. +// p_array = test_array.data(); +// ssize_t ssize = size; +// // Resulting parameter should be big endian +// AutoSerializeAdapter::deSerialize(&two_byte_value, +// const_cast(&p_array), &ssize, true); +// if(two_byte_value != 1) { +// return put_error(TestIds::ENDIANNESS_TOOLS); +// } +// +// ssize = size; +// p_array = test_array.data(); +// // Resulting parameter should be little endian +// AutoSerializeAdapter::deSerialize(&two_byte_value, +// const_cast(&p_array), &ssize, false); +// if(two_byte_value != 256) { +// return put_error(TestIds::ENDIANNESS_TOOLS); +// } + return RETURN_OK; +} + ReturnValue_t UnitTestClass::test_autoserialization() { current_id = TestIds::AUTO_SERIALIZATION_SIZE; // Unit Test getSerializedSize @@ -142,15 +187,21 @@ ReturnValue_t UnitTestClass::test_autoserialization() { // double tv_sdouble {-2.2421e19}; if(test_value_bool != true or tv_uint8 != 5 or tv_uint16 != 283 or tv_uint32 != 929221 or tv_uint64 != 2929329429 or tv_int8 != -16 or - tv_int16 != -829 or tv_int32 != -2312 or tv_float != 8.214921 or - tv_double != 9.2132142141e8 or tv_sfloat != -922.2321321 or - tv_sdouble != -2.2421e19) + tv_int16 != -829 or tv_int32 != -2312) { return put_error(current_id); } + + if(abs(tv_float - 8.214921) > 0.0001 or + abs(tv_double - 9.2132142141e8) > 0.01 or + abs(tv_sfloat - (-922.2321321)) > 0.0001 or + abs(tv_sdouble - (-2.2421e19)) > 0.01) { + return put_error(current_id); + } return RETURN_OK; } +// TODO: Also test for constant buffers. ReturnValue_t UnitTestClass::test_serial_buffer_adapter() { current_id = TestIds::SERIALIZATION_BUFFER_ADAPTER; @@ -203,6 +254,31 @@ ReturnValue_t UnitTestClass::test_serial_buffer_adapter() { { return put_error(current_id); } + memcpy(&tv_uint16, test_array.data() + 7, sizeof(tv_uint16)); + if(tv_uint16 != 16) { + return put_error(current_id); + } + + // Serialize with size field + SerialBufferAdapter tv_serial_buffer_adapter3 = + SerialBufferAdapter( + const_cast(test_serial_buffer.data()), + test_serial_buffer.size(), false); + serialized_size = 0; + p_array = test_array.data(); + AutoSerializeAdapter::serialize(&test_value_bool, &p_array,&serialized_size, + test_array.size(), false); + AutoSerializeAdapter::serialize(&tv_serial_buffer_adapter3, &p_array, + &serialized_size, test_array.size(), false); + AutoSerializeAdapter::serialize(&tv_uint16, &p_array, &serialized_size, + test_array.size(), false); + + if(serialized_size != 8 or test_array[0] != true or test_array[1] != 5 + or test_array[2] != 4 or test_array[3] != 3 or test_array[4] != 2 + or test_array[5] != 1) + { + return put_error(current_id); + } memcpy(&tv_uint16, test_array.data() + 6, sizeof(tv_uint16)); if(tv_uint16 != 16) { return put_error(current_id); @@ -215,3 +291,4 @@ ReturnValue_t UnitTestClass::put_error(TestIds current_id) { << static_cast(current_id) << "\r\n" << std::flush; return RETURN_FAILED; } + diff --git a/test/UnitTestClass.h b/test/UnitTestClass.h index c93ea0bc8..078cf3c9f 100644 --- a/test/UnitTestClass.h +++ b/test/UnitTestClass.h @@ -19,6 +19,8 @@ * 1. TMTC Services * 2. Serialization tools * 3. Framework internal algorithms + * + * TODO: Maybe use specialized framework. */ class UnitTestClass: public HasReturnvaluesIF { @@ -27,12 +29,13 @@ public: virtual~ UnitTestClass(); enum class TestIds { - AUTO_SERIALIZATION_SIZE = 0, - AUTO_SERIALIZATION_SERIALIZE = 1, - AUTO_SERIALIZATION_DESERIALIZE = 2, - SERIALIZATION_BUFFER_ADAPTER = 3, - SERIALIZATION_FIXED_ARRAY_LIST_ADAPTER = 4, - SERIALIZATION_COMBINATION = 5, + ENDIANNESS_TOOLS, + AUTO_SERIALIZATION_SIZE, + AUTO_SERIALIZATION_SERIALIZE, + AUTO_SERIALIZATION_DESERIALIZE , + SERIALIZATION_BUFFER_ADAPTER, + SERIALIZATION_FIXED_ARRAY_LIST_ADAPTER, + SERIALIZATION_COMBINATION, TMTC_SERVICES , MISC }; @@ -41,11 +44,12 @@ public: * Some function which calls all other tests * @return */ - ReturnValue_t performTests(); + ReturnValue_t perform_tests(); ReturnValue_t test_serialization(); ReturnValue_t test_autoserialization(); ReturnValue_t test_serial_buffer_adapter(); + ReturnValue_t test_endianness_tools(); private: uint32_t errorCounter = 0; TestIds current_id = TestIds::MISC; From 03b0ae7b68541f8d6268c0dcc8b763e04870d185 Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Tue, 14 Apr 2020 11:16:51 +0200 Subject: [PATCH 08/14] unit test fixes --- test/UnitTestClass.cpp | 2 +- test/UnitTestClass.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/test/UnitTestClass.cpp b/test/UnitTestClass.cpp index 7050dece0..f2925a240 100644 --- a/test/UnitTestClass.cpp +++ b/test/UnitTestClass.cpp @@ -17,7 +17,7 @@ UnitTestClass::UnitTestClass() { UnitTestClass::~UnitTestClass() { } -ReturnValue_t UnitTestClass::performTests() { +ReturnValue_t UnitTestClass::perform_tests() { ReturnValue_t result = test_serialization(); if(result != RETURN_OK) { return result; diff --git a/test/UnitTestClass.h b/test/UnitTestClass.h index c93ea0bc8..f11842695 100644 --- a/test/UnitTestClass.h +++ b/test/UnitTestClass.h @@ -41,7 +41,7 @@ public: * Some function which calls all other tests * @return */ - ReturnValue_t performTests(); + ReturnValue_t perform_tests(); ReturnValue_t test_serialization(); ReturnValue_t test_autoserialization(); From c5e5de1530acb3f3212514c254dea65635ece647 Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Tue, 14 Apr 2020 12:24:26 +0200 Subject: [PATCH 09/14] deleted example values --- test/UnitTestClass.cpp | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/test/UnitTestClass.cpp b/test/UnitTestClass.cpp index ac570b21e..89d4001d3 100644 --- a/test/UnitTestClass.cpp +++ b/test/UnitTestClass.cpp @@ -11,11 +11,9 @@ #include -UnitTestClass::UnitTestClass() { -} +UnitTestClass::UnitTestClass() {} -UnitTestClass::~UnitTestClass() { -} +UnitTestClass::~UnitTestClass() {} ReturnValue_t UnitTestClass::perform_tests() { ReturnValue_t result = test_serialization(); @@ -175,16 +173,6 @@ ReturnValue_t UnitTestClass::test_autoserialization() { AutoSerializeAdapter::deSerialize(&tv_sdouble, const_cast(&p_array), &remaining_size, false); - // uint16_t tv_uint16 {283}; - // uint32_t tv_uint32 {929221}; - // uint64_t tv_uint64 {2929329429}; - // int8_t tv_int8 {-16}; - // int16_t tv_int16 {-829}; - // int32_t tv_int32 {-2312}; - // float tv_float {8.2149214}; - // float tv_sfloat = {-922.2321321}; - // double tv_double {9.2132142141e8}; - // double tv_sdouble {-2.2421e19}; if(test_value_bool != true or tv_uint8 != 5 or tv_uint16 != 283 or tv_uint32 != 929221 or tv_uint64 != 2929329429 or tv_int8 != -16 or tv_int16 != -829 or tv_int32 != -2312) From af27a2441affb1923a4a2ff33c044ce825549094 Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Tue, 14 Apr 2020 16:19:13 +0200 Subject: [PATCH 10/14] added catch framework for basic testing --- framework.mk | 2 +- serialize/SerializeAdapterInternal.h | 8 +- test/CatchExample.cpp | 49 + test/UnitTestClass.cpp | 11 + test/UnitTestClass.h | 1 + test/catch2/catch.hpp | 17618 +++++++++++++++++++++ test/catch2/catch_reporter_automake.hpp | 62 + test/catch2/catch_reporter_sonarqube.hpp | 181 + test/catch2/catch_reporter_tap.hpp | 253 + test/catch2/catch_reporter_teamcity.hpp | 219 + 10 files changed, 18401 insertions(+), 3 deletions(-) create mode 100644 test/CatchExample.cpp create mode 100644 test/catch2/catch.hpp create mode 100644 test/catch2/catch_reporter_automake.hpp create mode 100644 test/catch2/catch_reporter_sonarqube.hpp create mode 100644 test/catch2/catch_reporter_tap.hpp create mode 100644 test/catch2/catch_reporter_teamcity.hpp diff --git a/framework.mk b/framework.mk index 2e7e57e93..6f64b7205 100644 --- a/framework.mk +++ b/framework.mk @@ -54,4 +54,4 @@ CXXSRC += $(wildcard $(FRAMEWORK_PATH)/tmtcpacket/*.cpp) CXXSRC += $(wildcard $(FRAMEWORK_PATH)/tmtcpacket/packetmatcher/*.cpp) CXXSRC += $(wildcard $(FRAMEWORK_PATH)/tmtcpacket/pus/*.cpp) CXXSRC += $(wildcard $(FRAMEWORK_PATH)/tmtcservices/*.cpp) -CXXSRC += $(wildcard $(FRAMEWORK_PATH)/test/*.cpp) +CXXSRC += $(wildcard $(FRAMEWORK_PATH)/test/*.cpp) \ No newline at end of file diff --git a/serialize/SerializeAdapterInternal.h b/serialize/SerializeAdapterInternal.h index 46dbdf191..ed0f6c3b8 100644 --- a/serialize/SerializeAdapterInternal.h +++ b/serialize/SerializeAdapterInternal.h @@ -12,7 +12,8 @@ #include /** - * This template specialization will be chosen for fundamental types. + * This template specialization will be chosen for fundamental types, + * based on partial template specialization * @tparam T * @tparam */ @@ -30,6 +31,9 @@ public: */ static ReturnValue_t serialize(const T* object, uint8_t** buffer, size_t* size, const size_t max_size, bool bigEndian) { + // function eventuelly serializes structs here. + // does this work on every architecture? + //static_assert(std::is_fundamental::value); size_t ignoredSize = 0; if (size == nullptr) { size = &ignoredSize; @@ -85,7 +89,7 @@ public: /** * This template specialization will be chosen for class derived from - * SerializeIF. + * SerializeIF, based on partial template specialization. * @tparam T * @tparam */ diff --git a/test/CatchExample.cpp b/test/CatchExample.cpp new file mode 100644 index 000000000..4db6a5c2a --- /dev/null +++ b/test/CatchExample.cpp @@ -0,0 +1,49 @@ +// Catch Example. +// Does not work yet. Problems with linker without main and config folder. +// Let Catch provide main(): + +#if defined(UNIT_TEST) +#define CATCH_CONFIG_MAIN + +#include +#include +#include + +int Factorial( int number ) { + return number <= 1 ? number : Factorial( number - 1 ) * number; // fail +// return number <= 1 ? 1 : Factorial( number - 1 ) * number; // pass +} + + + +TEST_CASE( "Factorial of 0 is 1 (fail)", "[single-file]" ) { + REQUIRE( Factorial(0) == 1 ); +} + +TEST_CASE( "Factorials of 1 and higher are computed (pass)", "[single-file]" ) { + REQUIRE( Factorial(1) == 1 ); + REQUIRE( Factorial(2) == 2 ); + REQUIRE( Factorial(3) == 6 ); + REQUIRE( Factorial(10) == 3628800 ); +} + +TEST_CASE( "Custom test", "[single-file]" ) { + UnitTestClass unitTestClass; + REQUIRE( unitTestClass.test_autoserialization() == HasReturnvaluesIF::RETURN_OK ); +} + +// Compile & run: +// - g++ -std=c++11 -Wall -I$(CATCH_SINGLE_INCLUDE) -o 010-TestCase 010-TestCase.cpp && ./010-TestCase --success +// - cl -EHsc -I%CATCH_SINGLE_INCLUDE% 010-TestCase.cpp && 010-TestCase --success + +// Expected compact output (all assertions): +// +// prompt> 010-TestCase --reporter compact --success +// 010-TestCase.cpp:14: failed: Factorial(0) == 1 for: 0 == 1 +// 010-TestCase.cpp:18: passed: Factorial(1) == 1 for: 1 == 1 +// 010-TestCase.cpp:19: passed: Factorial(2) == 2 for: 2 == 2 +// 010-TestCase.cpp:20: passed: Factorial(3) == 6 for: 6 == 6 +// 010-TestCase.cpp:21: passed: Factorial(10) == 3628800 for: 3628800 (0x375f00) == 3628800 (0x375f00) +// Failed 1 test case, failed 1 assertion. + +#endif diff --git a/test/UnitTestClass.cpp b/test/UnitTestClass.cpp index 89d4001d3..d20dfb0a0 100644 --- a/test/UnitTestClass.cpp +++ b/test/UnitTestClass.cpp @@ -11,6 +11,15 @@ #include +#if defined(UNIT_TEST) +#include "catch.hpp" +#define CATCH_CONFIG_MAIN + +TEST_CASE( "Serialization Size tests", "[single-file]") { + //REQUIRE(UnitTestClass::test_serialization == RETURN_OK ); +} +#endif + UnitTestClass::UnitTestClass() {} UnitTestClass::~UnitTestClass() {} @@ -53,6 +62,7 @@ ReturnValue_t UnitTestClass::test_endianness_tools() { return put_error(TestIds::ENDIANNESS_TOOLS); } + p_array = test_array.data(); size = 0; AutoSerializeAdapter::serialize(&two_byte_value, &p_array, &size, 2, true); @@ -180,6 +190,7 @@ ReturnValue_t UnitTestClass::test_autoserialization() { return put_error(current_id); } + // These epsilon values were just guessed.. It appears to work though. if(abs(tv_float - 8.214921) > 0.0001 or abs(tv_double - 9.2132142141e8) > 0.01 or abs(tv_sfloat - (-922.2321321)) > 0.0001 or diff --git a/test/UnitTestClass.h b/test/UnitTestClass.h index 078cf3c9f..d9ba9d1c6 100644 --- a/test/UnitTestClass.h +++ b/test/UnitTestClass.h @@ -9,6 +9,7 @@ #define FRAMEWORK_TEST_UNITTESTCLASS_H_ #include + #include #include diff --git a/test/catch2/catch.hpp b/test/catch2/catch.hpp new file mode 100644 index 000000000..51618b38e --- /dev/null +++ b/test/catch2/catch.hpp @@ -0,0 +1,17618 @@ +/* + * Catch v2.11.3 + * Generated: 2020-03-19 13:44:21.042491 + * ---------------------------------------------------------- + * This file has been merged from multiple headers. Please don't edit it directly + * Copyright (c) 2020 Two Blue Cubes Ltd. All rights reserved. + * + * Distributed under the Boost Software License, Version 1.0. (See accompanying + * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + */ +#ifndef TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED +#define TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED +// start catch.hpp + + +#define CATCH_VERSION_MAJOR 2 +#define CATCH_VERSION_MINOR 11 +#define CATCH_VERSION_PATCH 3 + +#ifdef __clang__ +# pragma clang system_header +#elif defined __GNUC__ +# pragma GCC system_header +#endif + +// start catch_suppress_warnings.h + +#ifdef __clang__ +# ifdef __ICC // icpc defines the __clang__ macro +# pragma warning(push) +# pragma warning(disable: 161 1682) +# else // __ICC +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wpadded" +# pragma clang diagnostic ignored "-Wswitch-enum" +# pragma clang diagnostic ignored "-Wcovered-switch-default" +# endif +#elif defined __GNUC__ + // Because REQUIREs trigger GCC's -Wparentheses, and because still + // supported version of g++ have only buggy support for _Pragmas, + // Wparentheses have to be suppressed globally. +# pragma GCC diagnostic ignored "-Wparentheses" // See #674 for details + +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wunused-variable" +# pragma GCC diagnostic ignored "-Wpadded" +#endif +// end catch_suppress_warnings.h +#if defined(CATCH_CONFIG_MAIN) || defined(CATCH_CONFIG_RUNNER) +# define CATCH_IMPL +# define CATCH_CONFIG_ALL_PARTS +#endif + +// In the impl file, we want to have access to all parts of the headers +// Can also be used to sanely support PCHs +#if defined(CATCH_CONFIG_ALL_PARTS) +# define CATCH_CONFIG_EXTERNAL_INTERFACES +# if defined(CATCH_CONFIG_DISABLE_MATCHERS) +# undef CATCH_CONFIG_DISABLE_MATCHERS +# endif +# if !defined(CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER) +# define CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER +# endif +#endif + +#if !defined(CATCH_CONFIG_IMPL_ONLY) +// start catch_platform.h + +#ifdef __APPLE__ +# include +# if TARGET_OS_OSX == 1 +# define CATCH_PLATFORM_MAC +# elif TARGET_OS_IPHONE == 1 +# define CATCH_PLATFORM_IPHONE +# endif + +#elif defined(linux) || defined(__linux) || defined(__linux__) +# define CATCH_PLATFORM_LINUX + +#elif defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER) || defined(__MINGW32__) +# define CATCH_PLATFORM_WINDOWS +#endif + +// end catch_platform.h + +#ifdef CATCH_IMPL +# ifndef CLARA_CONFIG_MAIN +# define CLARA_CONFIG_MAIN_NOT_DEFINED +# define CLARA_CONFIG_MAIN +# endif +#endif + +// start catch_user_interfaces.h + +namespace Catch { + unsigned int rngSeed(); +} + +// end catch_user_interfaces.h +// start catch_tag_alias_autoregistrar.h + +// start catch_common.h + +// start catch_compiler_capabilities.h + +// Detect a number of compiler features - by compiler +// The following features are defined: +// +// CATCH_CONFIG_COUNTER : is the __COUNTER__ macro supported? +// CATCH_CONFIG_WINDOWS_SEH : is Windows SEH supported? +// CATCH_CONFIG_POSIX_SIGNALS : are POSIX signals supported? +// CATCH_CONFIG_DISABLE_EXCEPTIONS : Are exceptions enabled? +// **************** +// Note to maintainers: if new toggles are added please document them +// in configuration.md, too +// **************** + +// In general each macro has a _NO_ form +// (e.g. CATCH_CONFIG_NO_POSIX_SIGNALS) which disables the feature. +// Many features, at point of detection, define an _INTERNAL_ macro, so they +// can be combined, en-mass, with the _NO_ forms later. + +#ifdef __cplusplus + +# if (__cplusplus >= 201402L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 201402L) +# define CATCH_CPP14_OR_GREATER +# endif + +# if (__cplusplus >= 201703L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) +# define CATCH_CPP17_OR_GREATER +# endif + +#endif + +#if defined(CATCH_CPP17_OR_GREATER) +# define CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS +#endif + +// We have to avoid both ICC and Clang, because they try to mask themselves +// as gcc, and we want only GCC in this block +#if defined(__GNUC__) && !defined(__clang__) && !defined(__ICC) +# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION _Pragma( "GCC diagnostic push" ) +# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION _Pragma( "GCC diagnostic pop" ) + +# define CATCH_INTERNAL_IGNORE_BUT_WARN(...) (void)__builtin_constant_p(__VA_ARGS__) + +#endif + +#if defined(__clang__) + +# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION _Pragma( "clang diagnostic push" ) +# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION _Pragma( "clang diagnostic pop" ) + +# define CATCH_INTERNAL_IGNORE_BUT_WARN(...) (void)__builtin_constant_p(__VA_ARGS__) + +# define CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ + _Pragma( "clang diagnostic ignored \"-Wexit-time-destructors\"" ) \ + _Pragma( "clang diagnostic ignored \"-Wglobal-constructors\"") + +# define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \ + _Pragma( "clang diagnostic ignored \"-Wparentheses\"" ) + +# define CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS \ + _Pragma( "clang diagnostic ignored \"-Wunused-variable\"" ) + +# define CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS \ + _Pragma( "clang diagnostic ignored \"-Wgnu-zero-variadic-macro-arguments\"" ) + +# define CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS \ + _Pragma( "clang diagnostic ignored \"-Wunused-template\"" ) + +#endif // __clang__ + +//////////////////////////////////////////////////////////////////////////////// +// Assume that non-Windows platforms support posix signals by default +#if !defined(CATCH_PLATFORM_WINDOWS) + #define CATCH_INTERNAL_CONFIG_POSIX_SIGNALS +#endif + +//////////////////////////////////////////////////////////////////////////////// +// We know some environments not to support full POSIX signals +#if defined(__CYGWIN__) || defined(__QNX__) || defined(__EMSCRIPTEN__) || defined(__DJGPP__) + #define CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS +#endif + +#ifdef __OS400__ +# define CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS +# define CATCH_CONFIG_COLOUR_NONE +#endif + +//////////////////////////////////////////////////////////////////////////////// +// Android somehow still does not support std::to_string +#if defined(__ANDROID__) +# define CATCH_INTERNAL_CONFIG_NO_CPP11_TO_STRING +# define CATCH_INTERNAL_CONFIG_ANDROID_LOGWRITE +#endif + +//////////////////////////////////////////////////////////////////////////////// +// Not all Windows environments support SEH properly +#if defined(__MINGW32__) +# define CATCH_INTERNAL_CONFIG_NO_WINDOWS_SEH +#endif + +//////////////////////////////////////////////////////////////////////////////// +// PS4 +#if defined(__ORBIS__) +# define CATCH_INTERNAL_CONFIG_NO_NEW_CAPTURE +#endif + +//////////////////////////////////////////////////////////////////////////////// +// Cygwin +#ifdef __CYGWIN__ + +// Required for some versions of Cygwin to declare gettimeofday +// see: http://stackoverflow.com/questions/36901803/gettimeofday-not-declared-in-this-scope-cygwin +# define _BSD_SOURCE +// some versions of cygwin (most) do not support std::to_string. Use the libstd check. +// https://gcc.gnu.org/onlinedocs/gcc-4.8.2/libstdc++/api/a01053_source.html line 2812-2813 +# if !((__cplusplus >= 201103L) && defined(_GLIBCXX_USE_C99) \ + && !defined(_GLIBCXX_HAVE_BROKEN_VSWPRINTF)) + +# define CATCH_INTERNAL_CONFIG_NO_CPP11_TO_STRING + +# endif +#endif // __CYGWIN__ + +//////////////////////////////////////////////////////////////////////////////// +// Visual C++ +#if defined(_MSC_VER) + +# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION __pragma( warning(push) ) +# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION __pragma( warning(pop) ) + +# if _MSC_VER >= 1900 // Visual Studio 2015 or newer +# define CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS +# endif + +// Universal Windows platform does not support SEH +// Or console colours (or console at all...) +# if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_APP) +# define CATCH_CONFIG_COLOUR_NONE +# else +# define CATCH_INTERNAL_CONFIG_WINDOWS_SEH +# endif + +// MSVC traditional preprocessor needs some workaround for __VA_ARGS__ +// _MSVC_TRADITIONAL == 0 means new conformant preprocessor +// _MSVC_TRADITIONAL == 1 means old traditional non-conformant preprocessor +# if !defined(__clang__) // Handle Clang masquerading for msvc +# if !defined(_MSVC_TRADITIONAL) || (defined(_MSVC_TRADITIONAL) && _MSVC_TRADITIONAL) +# define CATCH_INTERNAL_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR +# endif // MSVC_TRADITIONAL +# endif // __clang__ + +#endif // _MSC_VER + +#if defined(_REENTRANT) || defined(_MSC_VER) +// Enable async processing, as -pthread is specified or no additional linking is required +# define CATCH_INTERNAL_CONFIG_USE_ASYNC +#endif // _MSC_VER + +//////////////////////////////////////////////////////////////////////////////// +// Check if we are compiled with -fno-exceptions or equivalent +#if defined(__EXCEPTIONS) || defined(__cpp_exceptions) || defined(_CPPUNWIND) +# define CATCH_INTERNAL_CONFIG_EXCEPTIONS_ENABLED +#endif + +//////////////////////////////////////////////////////////////////////////////// +// DJGPP +#ifdef __DJGPP__ +# define CATCH_INTERNAL_CONFIG_NO_WCHAR +#endif // __DJGPP__ + +//////////////////////////////////////////////////////////////////////////////// +// Embarcadero C++Build +#if defined(__BORLANDC__) + #define CATCH_INTERNAL_CONFIG_POLYFILL_ISNAN +#endif + +//////////////////////////////////////////////////////////////////////////////// + +// Use of __COUNTER__ is suppressed during code analysis in +// CLion/AppCode 2017.2.x and former, because __COUNTER__ is not properly +// handled by it. +// Otherwise all supported compilers support COUNTER macro, +// but user still might want to turn it off +#if ( !defined(__JETBRAINS_IDE__) || __JETBRAINS_IDE__ >= 20170300L ) + #define CATCH_INTERNAL_CONFIG_COUNTER +#endif + +//////////////////////////////////////////////////////////////////////////////// + +// RTX is a special version of Windows that is real time. +// This means that it is detected as Windows, but does not provide +// the same set of capabilities as real Windows does. +#if defined(UNDER_RTSS) || defined(RTX64_BUILD) + #define CATCH_INTERNAL_CONFIG_NO_WINDOWS_SEH + #define CATCH_INTERNAL_CONFIG_NO_ASYNC + #define CATCH_CONFIG_COLOUR_NONE +#endif + +#if !defined(_GLIBCXX_USE_C99_MATH_TR1) +#define CATCH_INTERNAL_CONFIG_GLOBAL_NEXTAFTER +#endif + +// Various stdlib support checks that require __has_include +#if defined(__has_include) + // Check if string_view is available and usable + #if __has_include() && defined(CATCH_CPP17_OR_GREATER) + # define CATCH_INTERNAL_CONFIG_CPP17_STRING_VIEW + #endif + + // Check if optional is available and usable + # if __has_include() && defined(CATCH_CPP17_OR_GREATER) + # define CATCH_INTERNAL_CONFIG_CPP17_OPTIONAL + # endif // __has_include() && defined(CATCH_CPP17_OR_GREATER) + + // Check if byte is available and usable + # if __has_include() && defined(CATCH_CPP17_OR_GREATER) + # define CATCH_INTERNAL_CONFIG_CPP17_BYTE + # endif // __has_include() && defined(CATCH_CPP17_OR_GREATER) + + // Check if variant is available and usable + # if __has_include() && defined(CATCH_CPP17_OR_GREATER) + # if defined(__clang__) && (__clang_major__ < 8) + // work around clang bug with libstdc++ https://bugs.llvm.org/show_bug.cgi?id=31852 + // fix should be in clang 8, workaround in libstdc++ 8.2 + # include + # if defined(__GLIBCXX__) && defined(_GLIBCXX_RELEASE) && (_GLIBCXX_RELEASE < 9) + # define CATCH_CONFIG_NO_CPP17_VARIANT + # else + # define CATCH_INTERNAL_CONFIG_CPP17_VARIANT + # endif // defined(__GLIBCXX__) && defined(_GLIBCXX_RELEASE) && (_GLIBCXX_RELEASE < 9) + # else + # define CATCH_INTERNAL_CONFIG_CPP17_VARIANT + # endif // defined(__clang__) && (__clang_major__ < 8) + # endif // __has_include() && defined(CATCH_CPP17_OR_GREATER) +#endif // defined(__has_include) + +#if defined(CATCH_INTERNAL_CONFIG_COUNTER) && !defined(CATCH_CONFIG_NO_COUNTER) && !defined(CATCH_CONFIG_COUNTER) +# define CATCH_CONFIG_COUNTER +#endif +#if defined(CATCH_INTERNAL_CONFIG_WINDOWS_SEH) && !defined(CATCH_CONFIG_NO_WINDOWS_SEH) && !defined(CATCH_CONFIG_WINDOWS_SEH) && !defined(CATCH_INTERNAL_CONFIG_NO_WINDOWS_SEH) +# define CATCH_CONFIG_WINDOWS_SEH +#endif +// This is set by default, because we assume that unix compilers are posix-signal-compatible by default. +#if defined(CATCH_INTERNAL_CONFIG_POSIX_SIGNALS) && !defined(CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS) && !defined(CATCH_CONFIG_NO_POSIX_SIGNALS) && !defined(CATCH_CONFIG_POSIX_SIGNALS) +# define CATCH_CONFIG_POSIX_SIGNALS +#endif +// This is set by default, because we assume that compilers with no wchar_t support are just rare exceptions. +#if !defined(CATCH_INTERNAL_CONFIG_NO_WCHAR) && !defined(CATCH_CONFIG_NO_WCHAR) && !defined(CATCH_CONFIG_WCHAR) +# define CATCH_CONFIG_WCHAR +#endif + +#if !defined(CATCH_INTERNAL_CONFIG_NO_CPP11_TO_STRING) && !defined(CATCH_CONFIG_NO_CPP11_TO_STRING) && !defined(CATCH_CONFIG_CPP11_TO_STRING) +# define CATCH_CONFIG_CPP11_TO_STRING +#endif + +#if defined(CATCH_INTERNAL_CONFIG_CPP17_OPTIONAL) && !defined(CATCH_CONFIG_NO_CPP17_OPTIONAL) && !defined(CATCH_CONFIG_CPP17_OPTIONAL) +# define CATCH_CONFIG_CPP17_OPTIONAL +#endif + +#if defined(CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS) && !defined(CATCH_CONFIG_NO_CPP17_UNCAUGHT_EXCEPTIONS) && !defined(CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS) +# define CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS +#endif + +#if defined(CATCH_INTERNAL_CONFIG_CPP17_STRING_VIEW) && !defined(CATCH_CONFIG_NO_CPP17_STRING_VIEW) && !defined(CATCH_CONFIG_CPP17_STRING_VIEW) +# define CATCH_CONFIG_CPP17_STRING_VIEW +#endif + +#if defined(CATCH_INTERNAL_CONFIG_CPP17_VARIANT) && !defined(CATCH_CONFIG_NO_CPP17_VARIANT) && !defined(CATCH_CONFIG_CPP17_VARIANT) +# define CATCH_CONFIG_CPP17_VARIANT +#endif + +#if defined(CATCH_INTERNAL_CONFIG_CPP17_BYTE) && !defined(CATCH_CONFIG_NO_CPP17_BYTE) && !defined(CATCH_CONFIG_CPP17_BYTE) +# define CATCH_CONFIG_CPP17_BYTE +#endif + +#if defined(CATCH_CONFIG_EXPERIMENTAL_REDIRECT) +# define CATCH_INTERNAL_CONFIG_NEW_CAPTURE +#endif + +#if defined(CATCH_INTERNAL_CONFIG_NEW_CAPTURE) && !defined(CATCH_INTERNAL_CONFIG_NO_NEW_CAPTURE) && !defined(CATCH_CONFIG_NO_NEW_CAPTURE) && !defined(CATCH_CONFIG_NEW_CAPTURE) +# define CATCH_CONFIG_NEW_CAPTURE +#endif + +#if !defined(CATCH_INTERNAL_CONFIG_EXCEPTIONS_ENABLED) && !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) +# define CATCH_CONFIG_DISABLE_EXCEPTIONS +#endif + +#if defined(CATCH_INTERNAL_CONFIG_POLYFILL_ISNAN) && !defined(CATCH_CONFIG_NO_POLYFILL_ISNAN) && !defined(CATCH_CONFIG_POLYFILL_ISNAN) +# define CATCH_CONFIG_POLYFILL_ISNAN +#endif + +#if defined(CATCH_INTERNAL_CONFIG_USE_ASYNC) && !defined(CATCH_INTERNAL_CONFIG_NO_ASYNC) && !defined(CATCH_CONFIG_NO_USE_ASYNC) && !defined(CATCH_CONFIG_USE_ASYNC) +# define CATCH_CONFIG_USE_ASYNC +#endif + +#if defined(CATCH_INTERNAL_CONFIG_ANDROID_LOGWRITE) && !defined(CATCH_CONFIG_NO_ANDROID_LOGWRITE) && !defined(CATCH_CONFIG_ANDROID_LOGWRITE) +# define CATCH_CONFIG_ANDROID_LOGWRITE +#endif + +#if defined(CATCH_INTERNAL_CONFIG_GLOBAL_NEXTAFTER) && !defined(CATCH_CONFIG_NO_GLOBAL_NEXTAFTER) && !defined(CATCH_CONFIG_GLOBAL_NEXTAFTER) +# define CATCH_CONFIG_GLOBAL_NEXTAFTER +#endif + +// Even if we do not think the compiler has that warning, we still have +// to provide a macro that can be used by the code. +#if !defined(CATCH_INTERNAL_START_WARNINGS_SUPPRESSION) +# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION +#endif +#if !defined(CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION) +# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION +#endif +#if !defined(CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS) +# define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS +#endif +#if !defined(CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS) +# define CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS +#endif +#if !defined(CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS) +# define CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS +#endif +#if !defined(CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS) +# define CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS +#endif + +// The goal of this macro is to avoid evaluation of the arguments, but +// still have the compiler warn on problems inside... +#if !defined(CATCH_INTERNAL_IGNORE_BUT_WARN) +# define CATCH_INTERNAL_IGNORE_BUT_WARN(...) +#endif + +#if defined(__APPLE__) && defined(__apple_build_version__) && (__clang_major__ < 10) +# undef CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS +#elif defined(__clang__) && (__clang_major__ < 5) +# undef CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS +#endif + +#if !defined(CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS) +# define CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS +#endif + +#if defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) +#define CATCH_TRY if ((true)) +#define CATCH_CATCH_ALL if ((false)) +#define CATCH_CATCH_ANON(type) if ((false)) +#else +#define CATCH_TRY try +#define CATCH_CATCH_ALL catch (...) +#define CATCH_CATCH_ANON(type) catch (type) +#endif + +#if defined(CATCH_INTERNAL_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR) && !defined(CATCH_CONFIG_NO_TRADITIONAL_MSVC_PREPROCESSOR) && !defined(CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR) +#define CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR +#endif + +// end catch_compiler_capabilities.h +#define INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line ) name##line +#define INTERNAL_CATCH_UNIQUE_NAME_LINE( name, line ) INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line ) +#ifdef CATCH_CONFIG_COUNTER +# define INTERNAL_CATCH_UNIQUE_NAME( name ) INTERNAL_CATCH_UNIQUE_NAME_LINE( name, __COUNTER__ ) +#else +# define INTERNAL_CATCH_UNIQUE_NAME( name ) INTERNAL_CATCH_UNIQUE_NAME_LINE( name, __LINE__ ) +#endif + +#include +#include +#include + +// We need a dummy global operator<< so we can bring it into Catch namespace later +struct Catch_global_namespace_dummy {}; +std::ostream& operator<<(std::ostream&, Catch_global_namespace_dummy); + +namespace Catch { + + struct CaseSensitive { enum Choice { + Yes, + No + }; }; + + class NonCopyable { + NonCopyable( NonCopyable const& ) = delete; + NonCopyable( NonCopyable && ) = delete; + NonCopyable& operator = ( NonCopyable const& ) = delete; + NonCopyable& operator = ( NonCopyable && ) = delete; + + protected: + NonCopyable(); + virtual ~NonCopyable(); + }; + + struct SourceLineInfo { + + SourceLineInfo() = delete; + SourceLineInfo( char const* _file, std::size_t _line ) noexcept + : file( _file ), + line( _line ) + {} + + SourceLineInfo( SourceLineInfo const& other ) = default; + SourceLineInfo& operator = ( SourceLineInfo const& ) = default; + SourceLineInfo( SourceLineInfo&& ) noexcept = default; + SourceLineInfo& operator = ( SourceLineInfo&& ) noexcept = default; + + bool empty() const noexcept { return file[0] == '\0'; } + bool operator == ( SourceLineInfo const& other ) const noexcept; + bool operator < ( SourceLineInfo const& other ) const noexcept; + + char const* file; + std::size_t line; + }; + + std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info ); + + // Bring in operator<< from global namespace into Catch namespace + // This is necessary because the overload of operator<< above makes + // lookup stop at namespace Catch + using ::operator<<; + + // Use this in variadic streaming macros to allow + // >> +StreamEndStop + // as well as + // >> stuff +StreamEndStop + struct StreamEndStop { + std::string operator+() const; + }; + template + T const& operator + ( T const& value, StreamEndStop ) { + return value; + } +} + +#define CATCH_INTERNAL_LINEINFO \ + ::Catch::SourceLineInfo( __FILE__, static_cast( __LINE__ ) ) + +// end catch_common.h +namespace Catch { + + struct RegistrarForTagAliases { + RegistrarForTagAliases( char const* alias, char const* tag, SourceLineInfo const& lineInfo ); + }; + +} // end namespace Catch + +#define CATCH_REGISTER_TAG_ALIAS( alias, spec ) \ + CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ + CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ + namespace{ Catch::RegistrarForTagAliases INTERNAL_CATCH_UNIQUE_NAME( AutoRegisterTagAlias )( alias, spec, CATCH_INTERNAL_LINEINFO ); } \ + CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION + +// end catch_tag_alias_autoregistrar.h +// start catch_test_registry.h + +// start catch_interfaces_testcase.h + +#include + +namespace Catch { + + class TestSpec; + + struct ITestInvoker { + virtual void invoke () const = 0; + virtual ~ITestInvoker(); + }; + + class TestCase; + struct IConfig; + + struct ITestCaseRegistry { + virtual ~ITestCaseRegistry(); + virtual std::vector const& getAllTests() const = 0; + virtual std::vector const& getAllTestsSorted( IConfig const& config ) const = 0; + }; + + bool isThrowSafe( TestCase const& testCase, IConfig const& config ); + bool matchTest( TestCase const& testCase, TestSpec const& testSpec, IConfig const& config ); + std::vector filterTests( std::vector const& testCases, TestSpec const& testSpec, IConfig const& config ); + std::vector const& getAllTestCasesSorted( IConfig const& config ); + +} + +// end catch_interfaces_testcase.h +// start catch_stringref.h + +#include +#include +#include +#include + +namespace Catch { + + /// A non-owning string class (similar to the forthcoming std::string_view) + /// Note that, because a StringRef may be a substring of another string, + /// it may not be null terminated. + class StringRef { + public: + using size_type = std::size_t; + using const_iterator = const char*; + + private: + static constexpr char const* const s_empty = ""; + + char const* m_start = s_empty; + size_type m_size = 0; + + public: // construction + constexpr StringRef() noexcept = default; + + StringRef( char const* rawChars ) noexcept; + + constexpr StringRef( char const* rawChars, size_type size ) noexcept + : m_start( rawChars ), + m_size( size ) + {} + + StringRef( std::string const& stdString ) noexcept + : m_start( stdString.c_str() ), + m_size( stdString.size() ) + {} + + explicit operator std::string() const { + return std::string(m_start, m_size); + } + + public: // operators + auto operator == ( StringRef const& other ) const noexcept -> bool; + auto operator != (StringRef const& other) const noexcept -> bool { + return !(*this == other); + } + + auto operator[] ( size_type index ) const noexcept -> char { + assert(index < m_size); + return m_start[index]; + } + + public: // named queries + constexpr auto empty() const noexcept -> bool { + return m_size == 0; + } + constexpr auto size() const noexcept -> size_type { + return m_size; + } + + // Returns the current start pointer. If the StringRef is not + // null-terminated, throws std::domain_exception + auto c_str() const -> char const*; + + public: // substrings and searches + // Returns a substring of [start, start + length). + // If start + length > size(), then the substring is [start, size()). + // If start > size(), then the substring is empty. + auto substr( size_type start, size_type length ) const noexcept -> StringRef; + + // Returns the current start pointer. May not be null-terminated. + auto data() const noexcept -> char const*; + + constexpr auto isNullTerminated() const noexcept -> bool { + return m_start[m_size] == '\0'; + } + + public: // iterators + constexpr const_iterator begin() const { return m_start; } + constexpr const_iterator end() const { return m_start + m_size; } + }; + + auto operator += ( std::string& lhs, StringRef const& sr ) -> std::string&; + auto operator << ( std::ostream& os, StringRef const& sr ) -> std::ostream&; + + constexpr auto operator "" _sr( char const* rawChars, std::size_t size ) noexcept -> StringRef { + return StringRef( rawChars, size ); + } +} // namespace Catch + +constexpr auto operator "" _catch_sr( char const* rawChars, std::size_t size ) noexcept -> Catch::StringRef { + return Catch::StringRef( rawChars, size ); +} + +// end catch_stringref.h +// start catch_preprocessor.hpp + + +#define CATCH_RECURSION_LEVEL0(...) __VA_ARGS__ +#define CATCH_RECURSION_LEVEL1(...) CATCH_RECURSION_LEVEL0(CATCH_RECURSION_LEVEL0(CATCH_RECURSION_LEVEL0(__VA_ARGS__))) +#define CATCH_RECURSION_LEVEL2(...) CATCH_RECURSION_LEVEL1(CATCH_RECURSION_LEVEL1(CATCH_RECURSION_LEVEL1(__VA_ARGS__))) +#define CATCH_RECURSION_LEVEL3(...) CATCH_RECURSION_LEVEL2(CATCH_RECURSION_LEVEL2(CATCH_RECURSION_LEVEL2(__VA_ARGS__))) +#define CATCH_RECURSION_LEVEL4(...) CATCH_RECURSION_LEVEL3(CATCH_RECURSION_LEVEL3(CATCH_RECURSION_LEVEL3(__VA_ARGS__))) +#define CATCH_RECURSION_LEVEL5(...) CATCH_RECURSION_LEVEL4(CATCH_RECURSION_LEVEL4(CATCH_RECURSION_LEVEL4(__VA_ARGS__))) + +#ifdef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR +#define INTERNAL_CATCH_EXPAND_VARGS(...) __VA_ARGS__ +// MSVC needs more evaluations +#define CATCH_RECURSION_LEVEL6(...) CATCH_RECURSION_LEVEL5(CATCH_RECURSION_LEVEL5(CATCH_RECURSION_LEVEL5(__VA_ARGS__))) +#define CATCH_RECURSE(...) CATCH_RECURSION_LEVEL6(CATCH_RECURSION_LEVEL6(__VA_ARGS__)) +#else +#define CATCH_RECURSE(...) CATCH_RECURSION_LEVEL5(__VA_ARGS__) +#endif + +#define CATCH_REC_END(...) +#define CATCH_REC_OUT + +#define CATCH_EMPTY() +#define CATCH_DEFER(id) id CATCH_EMPTY() + +#define CATCH_REC_GET_END2() 0, CATCH_REC_END +#define CATCH_REC_GET_END1(...) CATCH_REC_GET_END2 +#define CATCH_REC_GET_END(...) CATCH_REC_GET_END1 +#define CATCH_REC_NEXT0(test, next, ...) next CATCH_REC_OUT +#define CATCH_REC_NEXT1(test, next) CATCH_DEFER ( CATCH_REC_NEXT0 ) ( test, next, 0) +#define CATCH_REC_NEXT(test, next) CATCH_REC_NEXT1(CATCH_REC_GET_END test, next) + +#define CATCH_REC_LIST0(f, x, peek, ...) , f(x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST1) ) ( f, peek, __VA_ARGS__ ) +#define CATCH_REC_LIST1(f, x, peek, ...) , f(x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST0) ) ( f, peek, __VA_ARGS__ ) +#define CATCH_REC_LIST2(f, x, peek, ...) f(x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST1) ) ( f, peek, __VA_ARGS__ ) + +#define CATCH_REC_LIST0_UD(f, userdata, x, peek, ...) , f(userdata, x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST1_UD) ) ( f, userdata, peek, __VA_ARGS__ ) +#define CATCH_REC_LIST1_UD(f, userdata, x, peek, ...) , f(userdata, x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST0_UD) ) ( f, userdata, peek, __VA_ARGS__ ) +#define CATCH_REC_LIST2_UD(f, userdata, x, peek, ...) f(userdata, x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST1_UD) ) ( f, userdata, peek, __VA_ARGS__ ) + +// Applies the function macro `f` to each of the remaining parameters, inserts commas between the results, +// and passes userdata as the first parameter to each invocation, +// e.g. CATCH_REC_LIST_UD(f, x, a, b, c) evaluates to f(x, a), f(x, b), f(x, c) +#define CATCH_REC_LIST_UD(f, userdata, ...) CATCH_RECURSE(CATCH_REC_LIST2_UD(f, userdata, __VA_ARGS__, ()()(), ()()(), ()()(), 0)) + +#define CATCH_REC_LIST(f, ...) CATCH_RECURSE(CATCH_REC_LIST2(f, __VA_ARGS__, ()()(), ()()(), ()()(), 0)) + +#define INTERNAL_CATCH_EXPAND1(param) INTERNAL_CATCH_EXPAND2(param) +#define INTERNAL_CATCH_EXPAND2(...) INTERNAL_CATCH_NO## __VA_ARGS__ +#define INTERNAL_CATCH_DEF(...) INTERNAL_CATCH_DEF __VA_ARGS__ +#define INTERNAL_CATCH_NOINTERNAL_CATCH_DEF +#define INTERNAL_CATCH_STRINGIZE(...) INTERNAL_CATCH_STRINGIZE2(__VA_ARGS__) +#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR +#define INTERNAL_CATCH_STRINGIZE2(...) #__VA_ARGS__ +#define INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS(param) INTERNAL_CATCH_STRINGIZE(INTERNAL_CATCH_REMOVE_PARENS(param)) +#else +// MSVC is adding extra space and needs another indirection to expand INTERNAL_CATCH_NOINTERNAL_CATCH_DEF +#define INTERNAL_CATCH_STRINGIZE2(...) INTERNAL_CATCH_STRINGIZE3(__VA_ARGS__) +#define INTERNAL_CATCH_STRINGIZE3(...) #__VA_ARGS__ +#define INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS(param) (INTERNAL_CATCH_STRINGIZE(INTERNAL_CATCH_REMOVE_PARENS(param)) + 1) +#endif + +#define INTERNAL_CATCH_MAKE_NAMESPACE2(...) ns_##__VA_ARGS__ +#define INTERNAL_CATCH_MAKE_NAMESPACE(name) INTERNAL_CATCH_MAKE_NAMESPACE2(name) + +#define INTERNAL_CATCH_REMOVE_PARENS(...) INTERNAL_CATCH_EXPAND1(INTERNAL_CATCH_DEF __VA_ARGS__) + +#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR +#define INTERNAL_CATCH_MAKE_TYPE_LIST2(...) decltype(get_wrapper()) +#define INTERNAL_CATCH_MAKE_TYPE_LIST(...) INTERNAL_CATCH_MAKE_TYPE_LIST2(INTERNAL_CATCH_REMOVE_PARENS(__VA_ARGS__)) +#else +#define INTERNAL_CATCH_MAKE_TYPE_LIST2(...) INTERNAL_CATCH_EXPAND_VARGS(decltype(get_wrapper())) +#define INTERNAL_CATCH_MAKE_TYPE_LIST(...) INTERNAL_CATCH_EXPAND_VARGS(INTERNAL_CATCH_MAKE_TYPE_LIST2(INTERNAL_CATCH_REMOVE_PARENS(__VA_ARGS__))) +#endif + +#define INTERNAL_CATCH_MAKE_TYPE_LISTS_FROM_TYPES(...)\ + CATCH_REC_LIST(INTERNAL_CATCH_MAKE_TYPE_LIST,__VA_ARGS__) + +#define INTERNAL_CATCH_REMOVE_PARENS_1_ARG(_0) INTERNAL_CATCH_REMOVE_PARENS(_0) +#define INTERNAL_CATCH_REMOVE_PARENS_2_ARG(_0, _1) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_1_ARG(_1) +#define INTERNAL_CATCH_REMOVE_PARENS_3_ARG(_0, _1, _2) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_2_ARG(_1, _2) +#define INTERNAL_CATCH_REMOVE_PARENS_4_ARG(_0, _1, _2, _3) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_3_ARG(_1, _2, _3) +#define INTERNAL_CATCH_REMOVE_PARENS_5_ARG(_0, _1, _2, _3, _4) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_4_ARG(_1, _2, _3, _4) +#define INTERNAL_CATCH_REMOVE_PARENS_6_ARG(_0, _1, _2, _3, _4, _5) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_5_ARG(_1, _2, _3, _4, _5) +#define INTERNAL_CATCH_REMOVE_PARENS_7_ARG(_0, _1, _2, _3, _4, _5, _6) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_6_ARG(_1, _2, _4, _5, _6) +#define INTERNAL_CATCH_REMOVE_PARENS_8_ARG(_0, _1, _2, _3, _4, _5, _6, _7) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_7_ARG(_1, _2, _3, _4, _5, _6, _7) +#define INTERNAL_CATCH_REMOVE_PARENS_9_ARG(_0, _1, _2, _3, _4, _5, _6, _7, _8) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_8_ARG(_1, _2, _3, _4, _5, _6, _7, _8) +#define INTERNAL_CATCH_REMOVE_PARENS_10_ARG(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_9_ARG(_1, _2, _3, _4, _5, _6, _7, _8, _9) +#define INTERNAL_CATCH_REMOVE_PARENS_11_ARG(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_10_ARG(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10) + +#define INTERNAL_CATCH_VA_NARGS_IMPL(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, N, ...) N + +#define INTERNAL_CATCH_TYPE_GEN\ + template struct TypeList {};\ + template\ + constexpr auto get_wrapper() noexcept -> TypeList { return {}; }\ + template class...> struct TemplateTypeList{};\ + template class...Cs>\ + constexpr auto get_wrapper() noexcept -> TemplateTypeList { return {}; }\ + template\ + struct append;\ + template\ + struct rewrap;\ + template class, typename...>\ + struct create;\ + template class, typename>\ + struct convert;\ + \ + template \ + struct append { using type = T; };\ + template< template class L1, typename...E1, template class L2, typename...E2, typename...Rest>\ + struct append, L2, Rest...> { using type = typename append, Rest...>::type; };\ + template< template class L1, typename...E1, typename...Rest>\ + struct append, TypeList, Rest...> { using type = L1; };\ + \ + template< template class Container, template class List, typename...elems>\ + struct rewrap, List> { using type = TypeList>; };\ + template< template class Container, template class List, class...Elems, typename...Elements>\ + struct rewrap, List, Elements...> { using type = typename append>, typename rewrap, Elements...>::type>::type; };\ + \ + template