Merge remote-tracking branch 'upstream/master' into mueller/returnvalue-convergence
This commit is contained in:
commit
a0d4c77d94
0
.gitmodules
vendored
Normal file
0
.gitmodules
vendored
Normal file
@ -3,8 +3,9 @@
|
||||
#include "../ipc/MessageQueueSenderIF.h"
|
||||
#include "../objectmanager/ObjectManagerIF.h"
|
||||
|
||||
ActionHelper::ActionHelper(HasActionsIF* setOwner, MessageQueueIF* useThisQueue) :
|
||||
owner(setOwner), queueToUse(useThisQueue), ipcStore(nullptr) {
|
||||
ActionHelper::ActionHelper(HasActionsIF* setOwner,
|
||||
MessageQueueIF* useThisQueue) :
|
||||
owner(setOwner), queueToUse(useThisQueue) {
|
||||
}
|
||||
|
||||
ActionHelper::~ActionHelper() {
|
||||
@ -33,13 +34,15 @@ ReturnValue_t ActionHelper::initialize(MessageQueueIF* queueToUse_) {
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
}
|
||||
|
||||
void ActionHelper::step(uint8_t step, MessageQueueId_t reportTo, ActionId_t commandId, ReturnValue_t result) {
|
||||
void ActionHelper::step(uint8_t step, MessageQueueId_t reportTo,
|
||||
ActionId_t commandId, ReturnValue_t result) {
|
||||
CommandMessage reply;
|
||||
ActionMessage::setStepReply(&reply, commandId, step + STEP_OFFSET, result);
|
||||
queueToUse->sendMessage(reportTo, &reply);
|
||||
}
|
||||
|
||||
void ActionHelper::finish(MessageQueueId_t reportTo, ActionId_t commandId, ReturnValue_t result) {
|
||||
void ActionHelper::finish(MessageQueueId_t reportTo, ActionId_t commandId,
|
||||
ReturnValue_t result) {
|
||||
CommandMessage reply;
|
||||
ActionMessage::setCompletionReply(&reply, commandId, result);
|
||||
queueToUse->sendMessage(reportTo, &reply);
|
||||
@ -49,8 +52,8 @@ void ActionHelper::setQueueToUse(MessageQueueIF* queue) {
|
||||
queueToUse = queue;
|
||||
}
|
||||
|
||||
void ActionHelper::prepareExecution(MessageQueueId_t commandedBy, ActionId_t actionId,
|
||||
store_address_t dataAddress) {
|
||||
void ActionHelper::prepareExecution(MessageQueueId_t commandedBy,
|
||||
ActionId_t actionId, store_address_t dataAddress) {
|
||||
const uint8_t* dataPtr = NULL;
|
||||
size_t size = 0;
|
||||
ReturnValue_t result = ipcStore->getData(dataAddress, &dataPtr, &size);
|
||||
@ -62,6 +65,11 @@ void ActionHelper::prepareExecution(MessageQueueId_t commandedBy, ActionId_t act
|
||||
}
|
||||
result = owner->executeAction(actionId, commandedBy, dataPtr, size);
|
||||
ipcStore->deleteData(dataAddress);
|
||||
if(result == HasActionsIF::EXECUTION_FINISHED) {
|
||||
CommandMessage reply;
|
||||
ActionMessage::setCompletionReply(&reply, actionId, result);
|
||||
queueToUse->sendMessage(commandedBy, &reply);
|
||||
}
|
||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||
CommandMessage reply;
|
||||
ActionMessage::setStepReply(&reply, actionId, 0, result);
|
||||
@ -86,22 +94,28 @@ ReturnValue_t ActionHelper::reportData(MessageQueueId_t reportTo,
|
||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||
return result;
|
||||
}
|
||||
result = data->serialize(&dataPtr, &size, maxSize, SerializeIF::Endianness::BIG);
|
||||
result = data->serialize(&dataPtr, &size, maxSize,
|
||||
SerializeIF::Endianness::BIG);
|
||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||
ipcStore->deleteData(storeAddress);
|
||||
return result;
|
||||
}
|
||||
//We don't need to report the objectId, as we receive REQUESTED data before the completion success message.
|
||||
//True aperiodic replies need to be reported with another dedicated message.
|
||||
// We don't need to report the objectId, as we receive REQUESTED data
|
||||
// before the completion success message.
|
||||
// True aperiodic replies need to be reported with
|
||||
// another dedicated message.
|
||||
ActionMessage::setDataReply(&reply, replyId, storeAddress);
|
||||
|
||||
//TODO Service Implementation sucks at the moment
|
||||
if (hideSender){
|
||||
// If the sender needs to be hidden, for example to handle packet
|
||||
// as unrequested reply, this will be done here.
|
||||
if (hideSender) {
|
||||
result = MessageQueueSenderIF::sendMessage(reportTo, &reply);
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
result = queueToUse->sendMessage(reportTo, &reply);
|
||||
}
|
||||
if ( result != HasReturnvaluesIF::RETURN_OK){
|
||||
|
||||
if (result != HasReturnvaluesIF::RETURN_OK){
|
||||
ipcStore->deleteData(storeAddress);
|
||||
}
|
||||
return result;
|
||||
@ -109,3 +123,39 @@ ReturnValue_t ActionHelper::reportData(MessageQueueId_t reportTo,
|
||||
|
||||
void ActionHelper::resetHelper() {
|
||||
}
|
||||
|
||||
ReturnValue_t ActionHelper::reportData(MessageQueueId_t reportTo,
|
||||
ActionId_t replyId, const uint8_t *data, size_t dataSize,
|
||||
bool hideSender) {
|
||||
CommandMessage reply;
|
||||
store_address_t storeAddress;
|
||||
ReturnValue_t result = ipcStore->addData(&storeAddress, data, dataSize);
|
||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||
return result;
|
||||
}
|
||||
|
||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||
ipcStore->deleteData(storeAddress);
|
||||
return result;
|
||||
}
|
||||
|
||||
// We don't need to report the objectId, as we receive REQUESTED data
|
||||
// before the completion success message.
|
||||
// True aperiodic replies need to be reported with
|
||||
// another dedicated message.
|
||||
ActionMessage::setDataReply(&reply, replyId, storeAddress);
|
||||
|
||||
// If the sender needs to be hidden, for example to handle packet
|
||||
// as unrequested reply, this will be done here.
|
||||
if (hideSender) {
|
||||
result = MessageQueueSenderIF::sendMessage(reportTo, &reply);
|
||||
}
|
||||
else {
|
||||
result = queueToUse->sendMessage(reportTo, &reply);
|
||||
}
|
||||
|
||||
if (result != HasReturnvaluesIF::RETURN_OK){
|
||||
ipcStore->deleteData(storeAddress);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
@ -1,15 +1,18 @@
|
||||
#ifndef ACTIONHELPER_H_
|
||||
#define ACTIONHELPER_H_
|
||||
#ifndef FSFW_ACTION_ACTIONHELPER_H_
|
||||
#define FSFW_ACTION_ACTIONHELPER_H_
|
||||
|
||||
#include "ActionMessage.h"
|
||||
#include "../serialize/SerializeIF.h"
|
||||
#include "../ipc/MessageQueueIF.h"
|
||||
/**
|
||||
* \brief Action Helper is a helper class which handles action messages
|
||||
* @brief Action Helper is a helper class which handles action messages
|
||||
*
|
||||
* Components which use the HasActionIF this helper can be used to handle the action messages.
|
||||
* It does handle step messages as well as other answers to action calls. It uses the executeAction function
|
||||
* of its owner as callback. The call of the initialize function is mandatory and it needs a valid messageQueueIF pointer!
|
||||
* Components which use the HasActionIF this helper can be used to handle
|
||||
* the action messages.
|
||||
* It does handle step messages as well as other answers to action calls.
|
||||
* It uses the executeAction function of its owner as callback.
|
||||
* The call of the initialize function is mandatory and needs a
|
||||
* valid MessageQueueIF pointer!
|
||||
*/
|
||||
class HasActionsIF;
|
||||
|
||||
@ -18,7 +21,8 @@ public:
|
||||
/**
|
||||
* Constructor of the action helper
|
||||
* @param setOwner Pointer to the owner of the interface
|
||||
* @param useThisQueue messageQueue to be used, can be set during initialize function as well.
|
||||
* @param useThisQueue messageQueue to be used, can be set during
|
||||
* initialize function as well.
|
||||
*/
|
||||
ActionHelper(HasActionsIF* setOwner, MessageQueueIF* useThisQueue);
|
||||
|
||||
@ -26,28 +30,36 @@ public:
|
||||
/**
|
||||
* Function to be called from the owner with a new command message
|
||||
*
|
||||
* If the message is a valid action message the helper will use the executeAction function from HasActionsIF.
|
||||
* If the message is invalid or the callback fails a message reply will be send to the sender of the message automatically.
|
||||
* If the message is a valid action message the helper will use the
|
||||
* executeAction function from HasActionsIF.
|
||||
* If the message is invalid or the callback fails a message reply will be
|
||||
* send to the sender of the message automatically.
|
||||
*
|
||||
* @param command Pointer to a command message received by the owner
|
||||
* @return HasReturnvaluesIF::RETURN_OK if the message is a action message, CommandMessage::UNKNOW_COMMAND if this message ID is unkown
|
||||
* @return HasReturnvaluesIF::RETURN_OK if the message is a action message,
|
||||
* CommandMessage::UNKNOW_COMMAND if this message ID is unkown
|
||||
*/
|
||||
ReturnValue_t handleActionMessage(CommandMessage* command);
|
||||
/**
|
||||
* Helper initialize function. Must be called before use of any other helper function
|
||||
* @param queueToUse_ Pointer to the messageQueue to be used, optional if queue was set in constructor
|
||||
* Helper initialize function. Must be called before use of any other
|
||||
* helper function
|
||||
* @param queueToUse_ Pointer to the messageQueue to be used, optional
|
||||
* if queue was set in constructor
|
||||
* @return Returns RETURN_OK if successful
|
||||
*/
|
||||
ReturnValue_t initialize(MessageQueueIF* queueToUse_ = nullptr);
|
||||
/**
|
||||
* Function to be called from the owner to send a step message. Success or failure will be determined by the result value.
|
||||
* Function to be called from the owner to send a step message.
|
||||
* Success or failure will be determined by the result value.
|
||||
*
|
||||
* @param step Number of steps already done
|
||||
* @param reportTo The messageQueueId to report the step message to
|
||||
* @param commandId ID of the executed command
|
||||
* @param result Result of the execution
|
||||
*/
|
||||
void step(uint8_t step, MessageQueueId_t reportTo, ActionId_t commandId, ReturnValue_t result = HasReturnvaluesIF::RETURN_OK);
|
||||
void step(uint8_t step, MessageQueueId_t reportTo,
|
||||
ActionId_t commandId,
|
||||
ReturnValue_t result = HasReturnvaluesIF::RETURN_OK);
|
||||
/**
|
||||
* Function to be called by the owner to send a action completion message
|
||||
*
|
||||
@ -55,39 +67,59 @@ public:
|
||||
* @param commandId ID of the executed command
|
||||
* @param result Result of the execution
|
||||
*/
|
||||
void finish(MessageQueueId_t reportTo, ActionId_t commandId, ReturnValue_t result = HasReturnvaluesIF::RETURN_OK);
|
||||
void finish(MessageQueueId_t reportTo, ActionId_t commandId,
|
||||
ReturnValue_t result = HasReturnvaluesIF::RETURN_OK);
|
||||
/**
|
||||
* Function to be called by the owner if an action does report data
|
||||
*
|
||||
* @param reportTo MessageQueueId_t to report the action completion message to
|
||||
* Function to be called by the owner if an action does report data.
|
||||
* Takes a SerializeIF* pointer and serializes it into the IPC store.
|
||||
* @param reportTo MessageQueueId_t to report the action completion
|
||||
* message to
|
||||
* @param replyId ID of the executed command
|
||||
* @param data Pointer to the data
|
||||
* @return Returns RETURN_OK if successful, otherwise failure code
|
||||
*/
|
||||
ReturnValue_t reportData(MessageQueueId_t reportTo, ActionId_t replyId, SerializeIF* data, bool hideSender = false);
|
||||
ReturnValue_t reportData(MessageQueueId_t reportTo, ActionId_t replyId,
|
||||
SerializeIF* data, bool hideSender = false);
|
||||
/**
|
||||
* Function to setup the MessageQueueIF* of the helper. Can be used to set the messageQueueIF* if
|
||||
* message queue is unavailable at construction and initialize but must be setup before first call of other functions.
|
||||
* Function to be called by the owner if an action does report data.
|
||||
* Takes the raw data and writes it into the IPC store.
|
||||
* @param reportTo MessageQueueId_t to report the action completion
|
||||
* message to
|
||||
* @param replyId ID of the executed command
|
||||
* @param data Pointer to the data
|
||||
* @return Returns RETURN_OK if successful, otherwise failure code
|
||||
*/
|
||||
ReturnValue_t reportData(MessageQueueId_t reportTo, ActionId_t replyId,
|
||||
const uint8_t* data, size_t dataSize, bool hideSender = false);
|
||||
/**
|
||||
* Function to setup the MessageQueueIF* of the helper. Can be used to
|
||||
* set the MessageQueueIF* if message queue is unavailable at construction
|
||||
* and initialize but must be setup before first call of other functions.
|
||||
* @param queue Queue to be used by the helper
|
||||
*/
|
||||
void setQueueToUse(MessageQueueIF *queue);
|
||||
protected:
|
||||
static const uint8_t STEP_OFFSET = 1;//!< Increase of value of this per step
|
||||
//!< Increase of value of this per step
|
||||
static const uint8_t STEP_OFFSET = 1;
|
||||
HasActionsIF* owner;//!< Pointer to the owner
|
||||
MessageQueueIF* queueToUse;//!< Queue to be used as response sender, has to be set with
|
||||
StorageManagerIF* ipcStore;//!< Pointer to an IPC Store, initialized during construction or initialize(MessageQueueIF* queueToUse_) or with setQueueToUse(MessageQueueIF *queue)
|
||||
//! Queue to be used as response sender, has to be set in ctor or with
|
||||
//! setQueueToUse
|
||||
MessageQueueIF* queueToUse;
|
||||
//! Pointer to an IPC Store, initialized during construction or
|
||||
StorageManagerIF* ipcStore = nullptr;
|
||||
|
||||
/**
|
||||
*Internal function called by handleActionMessage(CommandMessage* command)
|
||||
*
|
||||
* Internal function called by handleActionMessage
|
||||
* @param commandedBy MessageQueueID of Commander
|
||||
* @param actionId ID of action to be done
|
||||
* @param dataAddress Address of additional data in IPC Store
|
||||
*/
|
||||
virtual void prepareExecution(MessageQueueId_t commandedBy, ActionId_t actionId, store_address_t dataAddress);
|
||||
virtual void prepareExecution(MessageQueueId_t commandedBy,
|
||||
ActionId_t actionId, store_address_t dataAddress);
|
||||
/**
|
||||
*
|
||||
* @brief Default implementation is empty.
|
||||
*/
|
||||
virtual void resetHelper();
|
||||
};
|
||||
|
||||
#endif /* ACTIONHELPER_H_ */
|
||||
#endif /* FSFW_ACTION_ACTIONHELPER_H_ */
|
||||
|
@ -1,11 +1,12 @@
|
||||
#ifndef FRAMEWORK_ACTION_HASACTIONSIF_H_
|
||||
#define FRAMEWORK_ACTION_HASACTIONSIF_H_
|
||||
#ifndef FSFW_ACTION_HASACTIONSIF_H_
|
||||
#define FSFW_ACTION_HASACTIONSIF_H_
|
||||
|
||||
#include "ActionHelper.h"
|
||||
#include "ActionMessage.h"
|
||||
#include "SimpleActionHelper.h"
|
||||
#include "../returnvalues/HasReturnvaluesIF.h"
|
||||
#include "../ipc/MessageQueueIF.h"
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* Interface for component which uses actions
|
||||
@ -47,14 +48,16 @@ public:
|
||||
virtual MessageQueueId_t getCommandQueue() const = 0;
|
||||
/**
|
||||
* Execute or initialize the execution of a certain function.
|
||||
* Returning #EXECUTION_FINISHED or a failure code, nothing else needs to
|
||||
* be done. When needing more steps, return RETURN_OK and issue steps and
|
||||
* completion manually.
|
||||
* One "step failed" or completion report must be issued!
|
||||
* The ActionHelpers will execute this function and behave differently
|
||||
* depending on the returnvalue.
|
||||
*
|
||||
* @return
|
||||
* -@c EXECUTION_FINISHED Finish reply will be generated
|
||||
* -@c Not RETURN_OK Step failure reply will be generated
|
||||
*/
|
||||
virtual ReturnValue_t executeAction(ActionId_t actionId,
|
||||
MessageQueueId_t commandedBy, const uint8_t* data, size_t size) = 0;
|
||||
};
|
||||
|
||||
|
||||
#endif /* FRAMEWORK_ACTION_HASACTIONSIF_H_ */
|
||||
#endif /* FSFW_ACTION_HASACTIONSIF_H_ */
|
||||
|
@ -1,16 +1,17 @@
|
||||
#include "HasActionsIF.h"
|
||||
#include "SimpleActionHelper.h"
|
||||
|
||||
SimpleActionHelper::SimpleActionHelper(HasActionsIF* setOwner,
|
||||
MessageQueueIF* useThisQueue) :
|
||||
ActionHelper(setOwner, useThisQueue), isExecuting(false), lastCommander(
|
||||
0), lastAction(0), stepCount(0) {
|
||||
ActionHelper(setOwner, useThisQueue), isExecuting(false) {
|
||||
}
|
||||
|
||||
SimpleActionHelper::~SimpleActionHelper() {
|
||||
}
|
||||
|
||||
void SimpleActionHelper::step(ReturnValue_t result) {
|
||||
//STEP_OFFESET is subtracted to compensate for adding offset in base method, which is not necessary here.
|
||||
// STEP_OFFESET is subtracted to compensate for adding offset in base
|
||||
// method, which is not necessary here.
|
||||
ActionHelper::step(stepCount - STEP_OFFSET, lastCommander, lastAction,
|
||||
result);
|
||||
if (result != HasReturnvaluesIF::RETURN_OK) {
|
||||
|
@ -1,8 +1,13 @@
|
||||
#ifndef SIMPLEACTIONHELPER_H_
|
||||
#define SIMPLEACTIONHELPER_H_
|
||||
#ifndef FSFW_ACTION_SIMPLEACTIONHELPER_H_
|
||||
#define FSFW_ACTION_SIMPLEACTIONHELPER_H_
|
||||
|
||||
#include "ActionHelper.h"
|
||||
|
||||
/**
|
||||
* @brief This is an action helper which is only able to service one action
|
||||
* at a time but remembers last commander and last action which
|
||||
* simplifies usage
|
||||
*/
|
||||
class SimpleActionHelper: public ActionHelper {
|
||||
public:
|
||||
SimpleActionHelper(HasActionsIF* setOwner, MessageQueueIF* useThisQueue);
|
||||
@ -12,13 +17,14 @@ public:
|
||||
ReturnValue_t reportData(SerializeIF* data);
|
||||
|
||||
protected:
|
||||
void prepareExecution(MessageQueueId_t commandedBy, ActionId_t actionId, store_address_t dataAddress);
|
||||
void prepareExecution(MessageQueueId_t commandedBy, ActionId_t actionId,
|
||||
store_address_t dataAddress);
|
||||
virtual void resetHelper();
|
||||
private:
|
||||
bool isExecuting;
|
||||
MessageQueueId_t lastCommander;
|
||||
ActionId_t lastAction;
|
||||
uint8_t stepCount;
|
||||
MessageQueueId_t lastCommander = MessageQueueIF::NO_QUEUE;
|
||||
ActionId_t lastAction = 0;
|
||||
uint8_t stepCount = 0;
|
||||
};
|
||||
|
||||
#endif /* SIMPLEACTIONHELPER_H_ */
|
||||
|
@ -4,7 +4,7 @@
|
||||
#include <stdint.h>
|
||||
#include "fwSubsystemIdRanges.h"
|
||||
//could be move to more suitable location
|
||||
#include <config/tmtc/subsystemIdRanges.h>
|
||||
#include <subsystemIdRanges.h>
|
||||
|
||||
typedef uint16_t EventId_t;
|
||||
typedef uint8_t EventSeverity_t;
|
||||
|
49
unittest/README.md
Normal file
49
unittest/README.md
Normal file
@ -0,0 +1,49 @@
|
||||
## FSFW Testing
|
||||
This repository contains testing and unit testing components.
|
||||
|
||||
[Catch2](https://github.com/catchorg/Catch2) has been used as a framework,
|
||||
and these unit tests can only be run on a linux host machine.
|
||||
The makefile with default settings creates the unit test binary which can be
|
||||
run in the terminal or in eclipse.
|
||||
|
||||
### Instructions
|
||||
|
||||
### Eclipse CDT settings
|
||||
|
||||
The default eclipse terminal has issues displaying the colors used
|
||||
when running the unit test binary by catch2. To fix this issue,
|
||||
install the ANSI Escape In Console package from the eclipse marketplace.
|
||||
|
||||
### GCOV integration
|
||||
|
||||
GCOV has been integrated as a code coverage tool.
|
||||
It can be enabled by adding `GCOV=1` to the build process as an additional argument.
|
||||
Coverage data will be provided in form of .gcno and .gcda files.
|
||||
These can be displayed in eclipse by looking
|
||||
for a .gcno or .gcda file in the \_obj folder, double-clicking it
|
||||
and picking the right source-binary. This will generate
|
||||
information about which lines of a file have run, provided it is open in
|
||||
eclipse.
|
||||
|
||||
### LCOV integration
|
||||
|
||||
The files generated by GCOV can also be processed by the tool LCOV.
|
||||
On ubuntu, the tool can be installed with the following command:
|
||||
|
||||
```sh
|
||||
sudo apt-get install lcov
|
||||
````
|
||||
|
||||
After that, the tool can be run by building the unit tests with `GCOV=1`,
|
||||
running them at least one time and then executing the `lcov.sh` script.
|
||||
|
||||
### Adding unit tests
|
||||
|
||||
The catch unit tests are located in unittest/testfw. To add new unit tests,
|
||||
add them to the UnitTestCatch.cpp file or add a new source file which
|
||||
includes catch.hpp.
|
||||
|
||||
For writing basics tests, the [assertion documentation](https://github.com/catchorg/Catch2/blob/master/docs/assertions.md#top)
|
||||
or the existing examples are a good guideliens.
|
||||
For more advanced tests, refer to the [catch2 documentation](https://github.com/catchorg/Catch2/blob/master/docs/Readme.md#top).
|
||||
|
11
unittest/core/CatchDefinitions.cpp
Normal file
11
unittest/core/CatchDefinitions.cpp
Normal file
@ -0,0 +1,11 @@
|
||||
#include "CatchDefinitions.h"
|
||||
#include <fsfw/objectmanager/ObjectManagerIF.h>
|
||||
|
||||
StorageManagerIF* tglob::getIpcStoreHandle() {
|
||||
if(objectManager != nullptr) {
|
||||
return objectManager->get<StorageManagerIF>(objects::IPC_STORE);
|
||||
} else {
|
||||
sif::error << "Global object manager uninitialized" << std::endl;
|
||||
return nullptr;
|
||||
}
|
||||
}
|
21
unittest/core/CatchDefinitions.h
Normal file
21
unittest/core/CatchDefinitions.h
Normal file
@ -0,0 +1,21 @@
|
||||
#ifndef FSFW_UNITTEST_CORE_CATCHDEFINITIONS_H_
|
||||
#define FSFW_UNITTEST_CORE_CATCHDEFINITIONS_H_
|
||||
|
||||
#include <fsfw/ipc/messageQueueDefinitions.h>
|
||||
#include <fsfw/returnvalues/HasReturnvaluesIF.h>
|
||||
#include <fsfw/storagemanager/StorageManagerIF.h>
|
||||
|
||||
namespace retval {
|
||||
static constexpr int CATCH_OK = static_cast<int>(HasReturnvaluesIF::RETURN_OK);
|
||||
static constexpr int CATCH_FAILED = static_cast<int>(HasReturnvaluesIF::RETURN_FAILED);
|
||||
}
|
||||
|
||||
namespace tconst {
|
||||
static constexpr MessageQueueId_t testQueueId = 42;
|
||||
}
|
||||
|
||||
namespace tglob {
|
||||
StorageManagerIF* getIpcStoreHandle();
|
||||
}
|
||||
|
||||
#endif /* FSFW_UNITTEST_CORE_CATCHDEFINITIONS_H_ */
|
31
unittest/core/CatchRunner.cpp
Normal file
31
unittest/core/CatchRunner.cpp
Normal file
@ -0,0 +1,31 @@
|
||||
/**
|
||||
* @file CatchSource.cpp
|
||||
* @brief Source file to compile catch framework.
|
||||
* @details All tests should be written in other files.
|
||||
* For eclipse console output, install ANSI Escape in Console
|
||||
* from the eclipse market place to get colored characters.
|
||||
*/
|
||||
|
||||
#ifndef NO_UNIT_TEST_FRAMEWORK
|
||||
|
||||
#define CATCH_CONFIG_RUNNER
|
||||
#include <catch2/catch.hpp>
|
||||
|
||||
#if CUSTOM_UNITTEST_RUNNER == 0
|
||||
|
||||
extern int customSetup();
|
||||
|
||||
int main( int argc, char* argv[] ) {
|
||||
customSetup();
|
||||
|
||||
// Catch internal function call
|
||||
int result = Catch::Session().run( argc, argv );
|
||||
|
||||
// global clean-up
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#endif
|
42
unittest/core/CatchSetup.cpp
Normal file
42
unittest/core/CatchSetup.cpp
Normal file
@ -0,0 +1,42 @@
|
||||
#include "CatchDefinitions.h"
|
||||
|
||||
#include <testcfg/cdatapool/dataPoolInit.h>
|
||||
#include <testcfg/objects/Factory.h>
|
||||
|
||||
|
||||
#ifdef GCOV
|
||||
#include <gcov.h>
|
||||
#endif
|
||||
|
||||
#include "../../objectmanager/ObjectManager.h"
|
||||
#include "../../objectmanager/ObjectManagerIF.h"
|
||||
#include "../../storagemanager/StorageManagerIF.h"
|
||||
#include "../../datapool/DataPool.h"
|
||||
#include "../../serviceinterface/ServiceInterfaceStream.h"
|
||||
|
||||
|
||||
/* Global instantiations normally done in main.cpp */
|
||||
/* Initialize Data Pool */
|
||||
//namespace glob {
|
||||
DataPool dataPool(datapool::dataPoolInit);
|
||||
//}
|
||||
|
||||
|
||||
namespace sif {
|
||||
/* Set up output streams */
|
||||
ServiceInterfaceStream debug("DEBUG");
|
||||
ServiceInterfaceStream info("INFO");
|
||||
ServiceInterfaceStream error("ERROR");
|
||||
ServiceInterfaceStream warning("WARNING");
|
||||
}
|
||||
|
||||
/* Global object manager */
|
||||
ObjectManagerIF *objectManager;
|
||||
|
||||
int customSetup() {
|
||||
// global setup
|
||||
objectManager = new ObjectManager(Factory::produce);
|
||||
objectManager -> initialize();
|
||||
return 0;
|
||||
}
|
||||
|
3
unittest/core/core.mk
Normal file
3
unittest/core/core.mk
Normal file
@ -0,0 +1,3 @@
|
||||
CXXSRC += $(wildcard $(CURRENTPATH)/*.cpp)
|
||||
|
||||
INCLUDES += $(CURRENTPATH)
|
10
unittest/core/printChar.cpp
Normal file
10
unittest/core/printChar.cpp
Normal file
@ -0,0 +1,10 @@
|
||||
#include <fsfw/unittest/core/printChar.h>
|
||||
#include <cstdio>
|
||||
|
||||
void printChar(const char* character, bool errStream) {
|
||||
if(errStream) {
|
||||
std::putc(*character, stderr);
|
||||
return;
|
||||
}
|
||||
std::putc(*character, stdout);
|
||||
}
|
8
unittest/core/printChar.h
Normal file
8
unittest/core/printChar.h
Normal file
@ -0,0 +1,8 @@
|
||||
#ifndef FSFW_UNITTEST_CORE_PRINTCHAR_H_
|
||||
#define FSFW_UNITTEST_CORE_PRINTCHAR_H_
|
||||
|
||||
|
||||
extern "C" void printChar(const char*, bool errStream);
|
||||
|
||||
|
||||
#endif /* FSFW_UNITTEST_CORE_PRINTCHAR_H_ */
|
27
unittest/internal/InternalUnitTester.cpp
Normal file
27
unittest/internal/InternalUnitTester.cpp
Normal file
@ -0,0 +1,27 @@
|
||||
#include "InternalUnitTester.h"
|
||||
#include "UnittDefinitions.h"
|
||||
|
||||
#include "osal/IntTestMq.h"
|
||||
#include "osal/IntTestSemaphore.h"
|
||||
#include "osal/IntTestMutex.h"
|
||||
#include "serialize/IntTestSerialization.h"
|
||||
|
||||
#include <cstdlib>
|
||||
|
||||
InternalUnitTester::InternalUnitTester() {}
|
||||
|
||||
InternalUnitTester::~InternalUnitTester() {}
|
||||
|
||||
ReturnValue_t InternalUnitTester::performTests() {
|
||||
sif::info << "Running internal unit tests.." << std::endl;
|
||||
testserialize::test_serialization();
|
||||
testmq::testMq();
|
||||
testsemaph::testBinSemaph();
|
||||
testsemaph::testCountingSemaph();
|
||||
testmutex::testMutex();
|
||||
sif::info << "Internal unit tests finished." << std::endl;
|
||||
return RETURN_OK;
|
||||
}
|
||||
|
||||
|
||||
|
29
unittest/internal/InternalUnitTester.h
Normal file
29
unittest/internal/InternalUnitTester.h
Normal file
@ -0,0 +1,29 @@
|
||||
#ifndef FRAMEWORK_TEST_UNITTESTCLASS_H_
|
||||
#define FRAMEWORK_TEST_UNITTESTCLASS_H_
|
||||
|
||||
#include "UnittDefinitions.h"
|
||||
#include <fsfw/returnvalues/HasReturnvaluesIF.h>
|
||||
|
||||
/**
|
||||
* @brief Can be used for internal testing, for example for hardware specific
|
||||
* tests which can not be run on a host-machine.
|
||||
*
|
||||
* TODO: A lot of ways to improve this class. A way for tests to subscribe
|
||||
* in this central class would be nice. Right now, this is the class
|
||||
* which simply calls all other tests from other files manually.
|
||||
* Maybe there is a better way..
|
||||
*/
|
||||
class InternalUnitTester: public HasReturnvaluesIF {
|
||||
public:
|
||||
InternalUnitTester();
|
||||
virtual~ InternalUnitTester();
|
||||
|
||||
/**
|
||||
* Some function which calls all other tests
|
||||
* @return
|
||||
*/
|
||||
virtual ReturnValue_t performTests();
|
||||
};
|
||||
|
||||
|
||||
#endif /* FRAMEWORK_TEST_UNITTESTCLASS_H_ */
|
7
unittest/internal/UnittDefinitions.cpp
Normal file
7
unittest/internal/UnittDefinitions.cpp
Normal file
@ -0,0 +1,7 @@
|
||||
#include <fsfw/unittest/internal/UnittDefinitions.h>
|
||||
|
||||
ReturnValue_t unitt::put_error(std::string errorId) {
|
||||
sif::error << "Unit Tester error: Failed at test ID "
|
||||
<< errorId << "\n" << std::flush;
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
}
|
33
unittest/internal/UnittDefinitions.h
Normal file
33
unittest/internal/UnittDefinitions.h
Normal file
@ -0,0 +1,33 @@
|
||||
#ifndef UNITTEST_INTERNAL_UNITTDEFINITIONS_H_
|
||||
#define UNITTEST_INTERNAL_UNITTDEFINITIONS_H_
|
||||
|
||||
#include "../../returnvalues/HasReturnvaluesIF.h"
|
||||
#include "../../serviceinterface/ServiceInterfaceStream.h"
|
||||
#include <cstdint>
|
||||
#include <cstddef>
|
||||
|
||||
namespace tv {
|
||||
// POD test values
|
||||
static const bool tv_bool = true;
|
||||
static const uint8_t tv_uint8 {5};
|
||||
static const uint16_t tv_uint16 {283};
|
||||
static const uint32_t tv_uint32 {929221};
|
||||
static const uint64_t tv_uint64 {2929329429};
|
||||
|
||||
static const int8_t tv_int8 {-16};
|
||||
static const int16_t tv_int16 {-829};
|
||||
static const int32_t tv_int32 {-2312};
|
||||
|
||||
static const float tv_float {8.2149214};
|
||||
static const float tv_sfloat = {-922.2321321};
|
||||
static const double tv_double {9.2132142141e8};
|
||||
static const double tv_sdouble {-2.2421e19};
|
||||
}
|
||||
|
||||
namespace unitt {
|
||||
ReturnValue_t put_error(std::string errorId);
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif /* UNITTEST_INTERNAL_UNITTDEFINITIONS_H_ */
|
3
unittest/internal/internal.mk
Normal file
3
unittest/internal/internal.mk
Normal file
@ -0,0 +1,3 @@
|
||||
CXXSRC += $(wildcard $(CURRENTPATH)/osal/*.cpp)
|
||||
CXXSRC += $(wildcard $(CURRENTPATH)/serialize/*.cpp)
|
||||
CXXSRC += $(wildcard $(CURRENTPATH)/*.cpp)
|
52
unittest/internal/osal/IntTestMq.cpp
Normal file
52
unittest/internal/osal/IntTestMq.cpp
Normal file
@ -0,0 +1,52 @@
|
||||
#include <fsfw/ipc/MessageQueueIF.h>
|
||||
#include <fsfw/ipc/QueueFactory.h>
|
||||
#include <fsfw/unittest/internal/osal/IntTestMq.h>
|
||||
#include <fsfw/unittest/internal/UnittDefinitions.h>
|
||||
|
||||
#include <array>
|
||||
|
||||
using retval = HasReturnvaluesIF;
|
||||
|
||||
void testmq::testMq() {
|
||||
std::string id = "[testMq]";
|
||||
MessageQueueIF* testSenderMq =
|
||||
QueueFactory::instance()->createMessageQueue(1);
|
||||
MessageQueueId_t testSenderMqId = testSenderMq->getId();
|
||||
|
||||
MessageQueueIF* testReceiverMq =
|
||||
QueueFactory::instance()->createMessageQueue(1);
|
||||
MessageQueueId_t testReceiverMqId = testReceiverMq->getId();
|
||||
std::array<uint8_t, 20> testData { 0 };
|
||||
testData[0] = 42;
|
||||
MessageQueueMessage testMessage(testData.data(), 1);
|
||||
testSenderMq->setDefaultDestination(testReceiverMqId);
|
||||
|
||||
|
||||
auto result = testSenderMq->sendMessage(testReceiverMqId, &testMessage);
|
||||
if(result != retval::RETURN_OK) {
|
||||
unitt::put_error(id);
|
||||
}
|
||||
MessageQueueMessage recvMessage;
|
||||
result = testReceiverMq->receiveMessage(&recvMessage);
|
||||
if(result != retval::RETURN_OK or recvMessage.getData()[0] != 42) {
|
||||
unitt::put_error(id);
|
||||
}
|
||||
|
||||
result = testSenderMq->sendMessage(testReceiverMqId, &testMessage);
|
||||
if(result != retval::RETURN_OK) {
|
||||
unitt::put_error(id);
|
||||
}
|
||||
MessageQueueId_t senderId = 0;
|
||||
result = testReceiverMq->receiveMessage(&recvMessage,&senderId);
|
||||
if(result != retval::RETURN_OK or recvMessage.getData()[0] != 42) {
|
||||
unitt::put_error(id);
|
||||
}
|
||||
if(senderId != testSenderMqId) {
|
||||
unitt::put_error(id);
|
||||
}
|
||||
senderId = testReceiverMq->getLastPartner();
|
||||
if(senderId != testSenderMqId) {
|
||||
unitt::put_error(id);
|
||||
}
|
||||
|
||||
}
|
9
unittest/internal/osal/IntTestMq.h
Normal file
9
unittest/internal/osal/IntTestMq.h
Normal file
@ -0,0 +1,9 @@
|
||||
#ifndef UNITTEST_INTERNAL_INTESTMQ_H_
|
||||
#define UNITTEST_INTERNAL_INTESTMQ_H_
|
||||
|
||||
namespace testmq {
|
||||
void testMq();
|
||||
}
|
||||
|
||||
|
||||
#endif /* UNITTEST_INTERNAL_INTESTMQ_H_ */
|
42
unittest/internal/osal/IntTestMutex.cpp
Normal file
42
unittest/internal/osal/IntTestMutex.cpp
Normal file
@ -0,0 +1,42 @@
|
||||
#include "IntTestMutex.h"
|
||||
|
||||
#include <fsfw/ipc/MutexFactory.h>
|
||||
#include <unittest/internal/UnittDefinitions.h>
|
||||
|
||||
#if defined(hosted)
|
||||
#include <fsfw/osal/hosted/Mutex.h>
|
||||
#include <thread>
|
||||
#include <future>
|
||||
#endif
|
||||
|
||||
|
||||
void testmutex::testMutex() {
|
||||
std::string id = "[testMutex]";
|
||||
MutexIF* mutex = MutexFactory::instance()->createMutex();
|
||||
auto result = mutex->lockMutex(MutexIF::POLLING);
|
||||
if(result != HasReturnvaluesIF::RETURN_OK) {
|
||||
unitt::put_error(id);
|
||||
}
|
||||
// timed_mutex from the C++ library specifies undefined behaviour if
|
||||
// the timed mutex is locked twice from the same thread.
|
||||
#if defined(hosted)
|
||||
// hold on, this actually worked ? :-D This calls the function from
|
||||
// another thread and stores the returnvalue in a future.
|
||||
auto future = std::async(&MutexIF::lockMutex, mutex, 1);
|
||||
result = future.get();
|
||||
#else
|
||||
result = mutex->lockMutex(MutexIF::TimeoutType::WAITING, 1);
|
||||
#endif
|
||||
if(result != MutexIF::MUTEX_TIMEOUT) {
|
||||
unitt::put_error(id);
|
||||
}
|
||||
|
||||
result = mutex->unlockMutex();
|
||||
if(result != HasReturnvaluesIF::RETURN_OK) {
|
||||
unitt::put_error(id);
|
||||
}
|
||||
result = mutex->unlockMutex();
|
||||
if(result != MutexIF::CURR_THREAD_DOES_NOT_OWN_MUTEX) {
|
||||
unitt::put_error(id);
|
||||
}
|
||||
}
|
10
unittest/internal/osal/IntTestMutex.h
Normal file
10
unittest/internal/osal/IntTestMutex.h
Normal file
@ -0,0 +1,10 @@
|
||||
#ifndef UNITTEST_INTERNAL_INTTESTMUTEX_H_
|
||||
#define UNITTEST_INTERNAL_INTTESTMUTEX_H_
|
||||
|
||||
namespace testmutex {
|
||||
void testMutex();
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif /* UNITTEST_INTERNAL_INTTESTMUTEX_H_ */
|
160
unittest/internal/osal/IntTestSemaphore.cpp
Normal file
160
unittest/internal/osal/IntTestSemaphore.cpp
Normal file
@ -0,0 +1,160 @@
|
||||
#include "IntTestSemaphore.h"
|
||||
#include <fsfw/tasks/SemaphoreFactory.h>
|
||||
#include <unittest/internal/UnittDefinitions.h>
|
||||
#include <fsfw/serviceinterface/ServiceInterfaceStream.h>
|
||||
#include <fsfw/timemanager/Stopwatch.h>
|
||||
|
||||
|
||||
void testsemaph::testBinSemaph() {
|
||||
std::string id = "[BinSemaphore]";
|
||||
SemaphoreIF* binSemaph =
|
||||
SemaphoreFactory::instance()->createBinarySemaphore();
|
||||
if(binSemaph == nullptr) {
|
||||
return;
|
||||
}
|
||||
testBinSemaphoreImplementation(binSemaph, id);
|
||||
SemaphoreFactory::instance()->deleteSemaphore(binSemaph);
|
||||
#if defined(freeRTOS)
|
||||
SemaphoreIF* binSemaphUsingTask =
|
||||
SemaphoreFactory::instance()->createBinarySemaphore(1);
|
||||
testBinSemaphoreImplementation(binSemaphUsingTask, id);
|
||||
SemaphoreFactory::instance()->deleteSemaphore(binSemaphUsingTask);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void testsemaph::testCountingSemaph() {
|
||||
std::string id = "[CountingSemaph]";
|
||||
{
|
||||
// First test: create a binary semaphore by using a counting semaphore.
|
||||
SemaphoreIF* countingSemaph = SemaphoreFactory::instance()->
|
||||
createCountingSemaphore(1,1);
|
||||
if(countingSemaph == nullptr) {
|
||||
return;
|
||||
}
|
||||
testBinSemaphoreImplementation(countingSemaph, id);
|
||||
SemaphoreFactory::instance()->deleteSemaphore(countingSemaph);
|
||||
#if defined(freeRTOS)
|
||||
countingSemaph = SemaphoreFactory::instance()->
|
||||
createCountingSemaphore(1, 1, 1);
|
||||
testBinSemaphoreImplementation(countingSemaph, id);
|
||||
SemaphoreFactory::instance()->deleteSemaphore(countingSemaph);
|
||||
#endif
|
||||
}
|
||||
|
||||
{
|
||||
// Second test: counting semaphore with count 3 and init count of 3.
|
||||
SemaphoreIF* countingSemaph = SemaphoreFactory::instance()->
|
||||
createCountingSemaphore(3,3);
|
||||
testCountingSemaphImplementation(countingSemaph, id);
|
||||
SemaphoreFactory::instance()->deleteSemaphore(countingSemaph);
|
||||
#if defined(freeRTOS)
|
||||
countingSemaph = SemaphoreFactory::instance()->
|
||||
createCountingSemaphore(3, 0, 1);
|
||||
uint8_t semaphCount = countingSemaph->getSemaphoreCounter();
|
||||
if(semaphCount != 0) {
|
||||
unitt::put_error(id);
|
||||
}
|
||||
// release 3 times in a row
|
||||
for(int i = 0; i < 3; i++) {
|
||||
auto result = countingSemaph->release();
|
||||
if(result != HasReturnvaluesIF::RETURN_OK) {
|
||||
unitt::put_error(id);
|
||||
}
|
||||
}
|
||||
testCountingSemaphImplementation(countingSemaph, id);
|
||||
SemaphoreFactory::instance()->deleteSemaphore(countingSemaph);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void testsemaph::testBinSemaphoreImplementation(SemaphoreIF* binSemaph,
|
||||
std::string id) {
|
||||
uint8_t semaphCount = binSemaph->getSemaphoreCounter();
|
||||
if(semaphCount != 1) {
|
||||
unitt::put_error(id);
|
||||
}
|
||||
|
||||
ReturnValue_t result = binSemaph->release();
|
||||
if(result != SemaphoreIF::SEMAPHORE_NOT_OWNED) {
|
||||
unitt::put_error(id);
|
||||
}
|
||||
result = binSemaph->acquire(SemaphoreIF::BLOCKING);
|
||||
if(result != HasReturnvaluesIF::RETURN_OK) {
|
||||
unitt::put_error(id);
|
||||
}
|
||||
|
||||
// There is not really a point in testing time related, the task
|
||||
// might get interrupted..
|
||||
{
|
||||
//Stopwatch stopwatch(false);
|
||||
result = binSemaph->acquire(SemaphoreIF::TimeoutType::WAITING, 10);
|
||||
//dur_millis_t time = stopwatch.stop();
|
||||
// if(abs(time - 10) > 2) {
|
||||
// sif::error << "UnitTester: Semaphore timeout measured incorrect."
|
||||
// << std::endl;
|
||||
// unitt::put_error(id);
|
||||
// }
|
||||
}
|
||||
|
||||
if(result != SemaphoreIF::SEMAPHORE_TIMEOUT) {
|
||||
unitt::put_error(id);
|
||||
}
|
||||
|
||||
semaphCount = binSemaph->getSemaphoreCounter();
|
||||
if(semaphCount != 0) {
|
||||
unitt::put_error(id);
|
||||
}
|
||||
|
||||
result = binSemaph->release();
|
||||
if(result != HasReturnvaluesIF::RETURN_OK) {
|
||||
unitt::put_error(id);
|
||||
}
|
||||
}
|
||||
|
||||
void testsemaph::testCountingSemaphImplementation(SemaphoreIF* countingSemaph,
|
||||
std::string id) {
|
||||
// check count getter function
|
||||
uint8_t semaphCount = countingSemaph->getSemaphoreCounter();
|
||||
if(semaphCount != 3) {
|
||||
unitt::put_error(id);
|
||||
}
|
||||
ReturnValue_t result = countingSemaph->release();
|
||||
if(result != SemaphoreIF::SEMAPHORE_NOT_OWNED) {
|
||||
unitt::put_error(id);
|
||||
}
|
||||
// acquire 3 times in a row
|
||||
for(int i = 0; i < 3; i++) {
|
||||
result = countingSemaph->acquire(SemaphoreIF::BLOCKING);
|
||||
if(result != HasReturnvaluesIF::RETURN_OK) {
|
||||
unitt::put_error(id);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
Stopwatch stopwatch(false);
|
||||
// attempt to take when count is 0, measure time
|
||||
result = countingSemaph->acquire(SemaphoreIF::TimeoutType::WAITING, 10);
|
||||
dur_millis_t time = stopwatch.stop();
|
||||
if(abs(time - 10) > 1) {
|
||||
unitt::put_error(id);
|
||||
}
|
||||
}
|
||||
|
||||
if(result != SemaphoreIF::SEMAPHORE_TIMEOUT) {
|
||||
unitt::put_error(id);
|
||||
}
|
||||
|
||||
// release 3 times in a row
|
||||
for(int i = 0; i < 3; i++) {
|
||||
result = countingSemaph->release();
|
||||
if(result != HasReturnvaluesIF::RETURN_OK) {
|
||||
unitt::put_error(id);
|
||||
}
|
||||
}
|
||||
// assert correct full count
|
||||
if(countingSemaph->getSemaphoreCounter() != 3) {
|
||||
unitt::put_error(id);
|
||||
}
|
||||
}
|
15
unittest/internal/osal/IntTestSemaphore.h
Normal file
15
unittest/internal/osal/IntTestSemaphore.h
Normal file
@ -0,0 +1,15 @@
|
||||
#ifndef UNITTEST_INTERNAL_INTTESTSEMAPHORE_H_
|
||||
#define UNITTEST_INTERNAL_INTTESTSEMAPHORE_H_
|
||||
class SemaphoreIF;
|
||||
#include <string>
|
||||
|
||||
namespace testsemaph {
|
||||
void testBinSemaph();
|
||||
void testBinSemaphoreImplementation(SemaphoreIF* binSemaph, std::string id);
|
||||
void testCountingSemaph();
|
||||
void testCountingSemaphImplementation(SemaphoreIF* countingSemaph,
|
||||
std::string id);
|
||||
}
|
||||
|
||||
|
||||
#endif /* UNITTEST_INTERNAL_INTTESTSEMAPHORE_H_ */
|
230
unittest/internal/serialize/IntTestSerialization.cpp
Normal file
230
unittest/internal/serialize/IntTestSerialization.cpp
Normal file
@ -0,0 +1,230 @@
|
||||
#include "IntTestSerialization.h"
|
||||
#include <fsfw/serialize/SerializeElement.h>
|
||||
#include <fsfw/serialize/SerialBufferAdapter.h>
|
||||
#include <unittest/internal/UnittDefinitions.h>
|
||||
#include <fsfw/serialize/SerializeIF.h>
|
||||
#include <array>
|
||||
|
||||
using retval = HasReturnvaluesIF;
|
||||
std::array<uint8_t, 512> testserialize::test_array = { 0 };
|
||||
|
||||
ReturnValue_t testserialize::test_serialization() {
|
||||
// Here, we test all serialization tools. First test basic cases.
|
||||
ReturnValue_t result = test_endianness_tools();
|
||||
if(result != retval::RETURN_OK) {
|
||||
return result;
|
||||
}
|
||||
result = test_autoserialization();
|
||||
if(result != retval::RETURN_OK) {
|
||||
return result;
|
||||
}
|
||||
result = test_serial_buffer_adapter();
|
||||
if(result != retval::RETURN_OK) {
|
||||
return result;
|
||||
}
|
||||
return retval::RETURN_OK;
|
||||
}
|
||||
|
||||
ReturnValue_t testserialize::test_endianness_tools() {
|
||||
std::string id = "[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();
|
||||
SerializeAdapter::serialize(&two_byte_value, &p_array, &size, 2,
|
||||
SerializeIF::Endianness::MACHINE);
|
||||
// Little endian: Value one on first byte
|
||||
if(test_array[0] != 1 and test_array[1] != 0) {
|
||||
return unitt::put_error(id);
|
||||
|
||||
}
|
||||
|
||||
p_array = test_array.data();
|
||||
size = 0;
|
||||
SerializeAdapter::serialize(&two_byte_value, &p_array, &size, 2,
|
||||
SerializeIF::Endianness::BIG);
|
||||
// Big endian: Value one on second byte
|
||||
if(test_array[0] != 0 and test_array[1] != 1) {
|
||||
return unitt::put_error(id);
|
||||
}
|
||||
return retval::RETURN_OK;
|
||||
}
|
||||
|
||||
ReturnValue_t testserialize::test_autoserialization() {
|
||||
std::string id = "[test_autoserialization]";
|
||||
// Unit Test getSerializedSize
|
||||
if(SerializeAdapter::
|
||||
getSerializedSize(&tv::tv_bool) != sizeof(tv::tv_bool) or
|
||||
SerializeAdapter::
|
||||
getSerializedSize(&tv::tv_uint8) != sizeof(tv::tv_uint8) or
|
||||
SerializeAdapter::
|
||||
getSerializedSize(&tv::tv_uint16) != sizeof(tv::tv_uint16) or
|
||||
SerializeAdapter::
|
||||
getSerializedSize(&tv::tv_uint32) != sizeof(tv::tv_uint32) or
|
||||
SerializeAdapter::
|
||||
getSerializedSize(&tv::tv_uint64) != sizeof(tv::tv_uint64) or
|
||||
SerializeAdapter::
|
||||
getSerializedSize(&tv::tv_int8) != sizeof(tv::tv_int8) or
|
||||
SerializeAdapter::
|
||||
getSerializedSize(&tv::tv_double) != sizeof(tv::tv_double) or
|
||||
SerializeAdapter::
|
||||
getSerializedSize(&tv::tv_int16) != sizeof(tv::tv_int16) or
|
||||
SerializeAdapter::
|
||||
getSerializedSize(&tv::tv_int32) != sizeof(tv::tv_int32) or
|
||||
SerializeAdapter::
|
||||
getSerializedSize(&tv::tv_float) != sizeof(tv::tv_float))
|
||||
{
|
||||
return unitt::put_error(id);
|
||||
}
|
||||
|
||||
size_t serialized_size = 0;
|
||||
uint8_t * p_array = test_array.data();
|
||||
|
||||
SerializeAdapter::serialize(&tv::tv_bool, &p_array,
|
||||
&serialized_size, test_array.size(), SerializeIF::Endianness::MACHINE);
|
||||
SerializeAdapter::serialize(&tv::tv_uint8, &p_array,
|
||||
&serialized_size, test_array.size(), SerializeIF::Endianness::MACHINE);
|
||||
SerializeAdapter::serialize(&tv::tv_uint16, &p_array,
|
||||
&serialized_size, test_array.size(), SerializeIF::Endianness::MACHINE);
|
||||
SerializeAdapter::serialize(&tv::tv_uint32, &p_array,
|
||||
&serialized_size, test_array.size(), SerializeIF::Endianness::MACHINE);
|
||||
SerializeAdapter::serialize(&tv::tv_int8, &p_array,
|
||||
&serialized_size, test_array.size(), SerializeIF::Endianness::MACHINE);
|
||||
SerializeAdapter::serialize(&tv::tv_int16, &p_array,
|
||||
&serialized_size, test_array.size(), SerializeIF::Endianness::MACHINE);
|
||||
SerializeAdapter::serialize(&tv::tv_int32, &p_array,
|
||||
&serialized_size, test_array.size(), SerializeIF::Endianness::MACHINE);
|
||||
SerializeAdapter::serialize(&tv::tv_uint64, &p_array,
|
||||
&serialized_size, test_array.size(), SerializeIF::Endianness::MACHINE);
|
||||
SerializeAdapter::serialize(&tv::tv_float, &p_array,
|
||||
&serialized_size, test_array.size(), SerializeIF::Endianness::MACHINE);
|
||||
SerializeAdapter::serialize(&tv::tv_double, &p_array,
|
||||
&serialized_size, test_array.size(), SerializeIF::Endianness::MACHINE);
|
||||
SerializeAdapter::serialize(&tv::tv_sfloat, &p_array,
|
||||
&serialized_size, test_array.size(), SerializeIF::Endianness::MACHINE);
|
||||
SerializeAdapter::serialize(&tv::tv_sdouble, &p_array,
|
||||
&serialized_size, test_array.size(), SerializeIF::Endianness::MACHINE);
|
||||
// expected size is 1 + 1 + 2 + 4 + 1 + 2 + 4 + 8 + 4 + 8 + 4 + 8
|
||||
if(serialized_size != 47) {
|
||||
return unitt::put_error(id);
|
||||
}
|
||||
|
||||
p_array = test_array.data();
|
||||
size_t remaining_size = serialized_size;
|
||||
bool tv_bool;
|
||||
uint8_t tv_uint8;
|
||||
uint16_t tv_uint16;
|
||||
uint32_t tv_uint32;
|
||||
int8_t tv_int8;
|
||||
int16_t tv_int16;
|
||||
int32_t tv_int32;
|
||||
uint64_t tv_uint64;
|
||||
float tv_float;
|
||||
double tv_double;
|
||||
float tv_sfloat;
|
||||
double tv_sdouble;
|
||||
|
||||
SerializeAdapter::deSerialize(&tv_bool,
|
||||
const_cast<const uint8_t**>(&p_array), &remaining_size, SerializeIF::Endianness::MACHINE);
|
||||
SerializeAdapter::deSerialize(&tv_uint8,
|
||||
const_cast<const uint8_t**>(&p_array), &remaining_size, SerializeIF::Endianness::MACHINE);
|
||||
SerializeAdapter::deSerialize(&tv_uint16,
|
||||
const_cast<const uint8_t**>(&p_array), &remaining_size, SerializeIF::Endianness::MACHINE);
|
||||
SerializeAdapter::deSerialize(&tv_uint32,
|
||||
const_cast<const uint8_t**>(&p_array), &remaining_size, SerializeIF::Endianness::MACHINE);
|
||||
SerializeAdapter::deSerialize(&tv_int8,
|
||||
const_cast<const uint8_t**>(&p_array), &remaining_size, SerializeIF::Endianness::MACHINE);
|
||||
SerializeAdapter::deSerialize(&tv_int16,
|
||||
const_cast<const uint8_t**>(&p_array), &remaining_size, SerializeIF::Endianness::MACHINE);
|
||||
SerializeAdapter::deSerialize(&tv_int32,
|
||||
const_cast<const uint8_t**>(&p_array), &remaining_size, SerializeIF::Endianness::MACHINE);
|
||||
SerializeAdapter::deSerialize(&tv_uint64,
|
||||
const_cast<const uint8_t**>(&p_array), &remaining_size, SerializeIF::Endianness::MACHINE);
|
||||
SerializeAdapter::deSerialize(&tv_float,
|
||||
const_cast<const uint8_t**>(&p_array), &remaining_size, SerializeIF::Endianness::MACHINE);
|
||||
SerializeAdapter::deSerialize(&tv_double,
|
||||
const_cast<const uint8_t**>(&p_array), &remaining_size, SerializeIF::Endianness::MACHINE);
|
||||
SerializeAdapter::deSerialize(&tv_sfloat,
|
||||
const_cast<const uint8_t**>(&p_array), &remaining_size, SerializeIF::Endianness::MACHINE);
|
||||
SerializeAdapter::deSerialize(&tv_sdouble,
|
||||
const_cast<const uint8_t**>(&p_array), &remaining_size, SerializeIF::Endianness::MACHINE);
|
||||
|
||||
if(tv_bool != tv::tv_bool or tv_uint8 != tv::tv_uint8 or
|
||||
tv_uint16 != tv::tv_uint16 or tv_uint32 != tv::tv_uint32 or
|
||||
tv_uint64 != tv::tv_uint64 or tv_int8 != tv::tv_int8 or
|
||||
tv_int16 != tv::tv_int16 or tv_int32 != tv::tv_int32)
|
||||
{
|
||||
return unitt::put_error(id);
|
||||
}
|
||||
|
||||
// These epsilon values were just guessed.. It appears to work though.
|
||||
if(abs(tv_float - tv::tv_float) > 0.0001 or
|
||||
abs(tv_double - tv::tv_double) > 0.01 or
|
||||
abs(tv_sfloat - tv::tv_sfloat) > 0.0001 or
|
||||
abs(tv_sdouble - tv::tv_sdouble) > 0.01) {
|
||||
return unitt::put_error(id);
|
||||
}
|
||||
|
||||
// Check overflow
|
||||
return retval::RETURN_OK;
|
||||
}
|
||||
|
||||
// TODO: Also test for constant buffers.
|
||||
ReturnValue_t testserialize::test_serial_buffer_adapter() {
|
||||
std::string id = "[test_serial_buffer_adapter]";
|
||||
|
||||
// I will skip endian swapper testing, its going to be changed anyway..
|
||||
// uint8_t tv::tv_uint8_swapped = EndianSwapper::swap(tv::tv_uint8);
|
||||
|
||||
size_t serialized_size = 0;
|
||||
uint8_t * p_array = test_array.data();
|
||||
std::array<uint8_t, 5> test_serial_buffer {5, 4, 3, 2, 1};
|
||||
SerialBufferAdapter<uint8_t> tv_serial_buffer_adapter =
|
||||
SerialBufferAdapter<uint8_t>(test_serial_buffer.data(),
|
||||
test_serial_buffer.size(), false);
|
||||
uint16_t testUint16 = 16;
|
||||
|
||||
SerializeAdapter::serialize(&tv::tv_bool, &p_array,&serialized_size,
|
||||
test_array.size(), SerializeIF::Endianness::MACHINE);
|
||||
SerializeAdapter::serialize(&tv_serial_buffer_adapter, &p_array,
|
||||
&serialized_size, test_array.size(), SerializeIF::Endianness::MACHINE);
|
||||
SerializeAdapter::serialize(&testUint16, &p_array, &serialized_size,
|
||||
test_array.size(), SerializeIF::Endianness::MACHINE);
|
||||
|
||||
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 unitt::put_error(id);
|
||||
}
|
||||
memcpy(&testUint16, test_array.data() + 6, sizeof(testUint16));
|
||||
if(testUint16 != 16) {
|
||||
return unitt::put_error(id);
|
||||
}
|
||||
|
||||
// Serialize with size field
|
||||
SerialBufferAdapter<uint8_t> tv_serial_buffer_adapter2 =
|
||||
SerialBufferAdapter<uint8_t>(test_serial_buffer.data(),
|
||||
test_serial_buffer.size(), true);
|
||||
serialized_size = 0;
|
||||
p_array = test_array.data();
|
||||
SerializeAdapter::serialize(&tv::tv_bool, &p_array,&serialized_size,
|
||||
test_array.size(), SerializeIF::Endianness::MACHINE);
|
||||
SerializeAdapter::serialize(&tv_serial_buffer_adapter2, &p_array,
|
||||
&serialized_size, test_array.size(), SerializeIF::Endianness::MACHINE);
|
||||
SerializeAdapter::serialize(&testUint16, &p_array, &serialized_size,
|
||||
test_array.size(), SerializeIF::Endianness::MACHINE);
|
||||
|
||||
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 unitt::put_error(id);
|
||||
}
|
||||
memcpy(&testUint16, test_array.data() + 7, sizeof(testUint16));
|
||||
if(testUint16 != 16) {
|
||||
return unitt::put_error(id);
|
||||
}
|
||||
return retval::RETURN_OK;
|
||||
}
|
15
unittest/internal/serialize/IntTestSerialization.h
Normal file
15
unittest/internal/serialize/IntTestSerialization.h
Normal file
@ -0,0 +1,15 @@
|
||||
#ifndef UNITTEST_INTERNAL_INTTESTSERIALIZATION_H_
|
||||
#define UNITTEST_INTERNAL_INTTESTSERIALIZATION_H_
|
||||
#include <fsfw/returnvalues/HasReturnvaluesIF.h>
|
||||
#include <array>
|
||||
|
||||
namespace testserialize {
|
||||
ReturnValue_t test_serialization();
|
||||
ReturnValue_t test_endianness_tools();
|
||||
ReturnValue_t test_autoserialization();
|
||||
ReturnValue_t test_serial_buffer_adapter();
|
||||
|
||||
extern std::array<uint8_t, 512> test_array;
|
||||
}
|
||||
|
||||
#endif /* UNITTEST_INTERNAL_INTTESTSERIALIZATION_H_ */
|
3
unittest/lcov.sh
Normal file
3
unittest/lcov.sh
Normal file
@ -0,0 +1,3 @@
|
||||
#!/bin/bash
|
||||
lcov --capture --directory . --output-file coverage.info
|
||||
genhtml coverage.info --output-directory _coverage
|
46
unittest/testcfg/FSFWConfig.h
Normal file
46
unittest/testcfg/FSFWConfig.h
Normal file
@ -0,0 +1,46 @@
|
||||
#ifndef CONFIG_FSFWCONFIG_H_
|
||||
#define CONFIG_FSFWCONFIG_H_
|
||||
|
||||
#include <FSFWVersion.h>
|
||||
|
||||
//! Used to determine whether C++ ostreams are used
|
||||
//! Those can lead to code bloat.
|
||||
#define FSFW_CPP_OSTREAM_ENABLED 1
|
||||
|
||||
//! Reduced printout to further decrese code size
|
||||
//! Be careful, this also turns off most diagnostic prinouts!
|
||||
#define FSFW_REDUCED_PRINTOUT 0
|
||||
|
||||
//! Can be used to enable debugging printouts for developing the FSFW
|
||||
#define FSFW_DEBUGGING 0
|
||||
|
||||
//! Defines the FIFO depth of each commanding service base which
|
||||
//! also determines how many commands a CSB service can handle in one cycle
|
||||
//! simulataneously. This will increase the required RAM for
|
||||
//! each CSB service !
|
||||
#define FSFW_CSB_FIFO_DEPTH 6
|
||||
|
||||
//! If FSFW_OBJ_EVENT_TRANSLATION is set to one,
|
||||
//! additional output which requires the translation files translateObjects
|
||||
//! and translateEvents (and their compiled source files)
|
||||
#define FSFW_OBJ_EVENT_TRANSLATION 0
|
||||
|
||||
//! If -DDEBUG is supplied in the build defines, there will be
|
||||
//! additional output which requires the translation files translateObjects
|
||||
//! and translateEvents (and their compiles source files)
|
||||
#if FSFW_OBJ_EVENT_TRANSLATION == 1
|
||||
#define FSFW_DEBUG_OUTPUT 1
|
||||
//! Specify whether info events are printed too.
|
||||
#define FSFW_DEBUG_INFO 1
|
||||
#include <translateObjects.h>
|
||||
#include <translateEvents.h>
|
||||
#else
|
||||
#define FSFW_DEBUG_OUTPUT 0
|
||||
#endif
|
||||
|
||||
//! When using the newlib nano library, C99 support for stdio facilities
|
||||
//! will not be provided. This define should be set to 1 if this is the case.
|
||||
#define FSFW_NO_C99_IO 1
|
||||
|
||||
|
||||
#endif /* CONFIG_FSFWCONFIG_H_ */
|
415
unittest/testcfg/Makefile-FSFW-Tests
Normal file
415
unittest/testcfg/Makefile-FSFW-Tests
Normal file
@ -0,0 +1,415 @@
|
||||
#-------------------------------------------------------------------------------
|
||||
# Makefile for FSFW Test
|
||||
#-------------------------------------------------------------------------------
|
||||
# User-modifiable options
|
||||
#-------------------------------------------------------------------------------
|
||||
# Fundamentals on the build process of C/C++ Software:
|
||||
# https://www3.ntu.edu.sg/home/ehchua/programming/cpp/gcc_make.html
|
||||
|
||||
# Make documentation: https://www.gnu.org/software/make/manual/make.pdf
|
||||
# Online: https://www.gnu.org/software/make/manual/make.html
|
||||
# General rules: http://make.mad-scientist.net/papers/rules-of-makefiles/#rule3
|
||||
SHELL = /bin/sh
|
||||
|
||||
# Chip & board used for compilation
|
||||
# (can be overriden by adding CHIP=chip and BOARD=board to the command-line)
|
||||
# Unit Test can only be run on host machine for now (Linux)
|
||||
FRAMEWORK_PATH = fsfw
|
||||
FILE_ROOT = $(FRAMEWORK_PATH)/unittest
|
||||
BOARD = unittest
|
||||
LINUX = 1
|
||||
OS_FSFW = linux
|
||||
CUSTOM_DEFINES += -D$(OS_FSFW)
|
||||
|
||||
# Copied from stackoverflow, can be used to differentiate between Windows
|
||||
# and Linux
|
||||
ifeq ($(OS),Windows_NT)
|
||||
CUSTOM_DEFINES += -DWIN32
|
||||
ifeq ($(PROCESSOR_ARCHITEW6432),AMD64)
|
||||
CUSTOM_DEFINES += -DAMD64
|
||||
else
|
||||
ifeq ($(PROCESSOR_ARCHITECTURE),AMD64)
|
||||
CUSTOM_DEFINES += -DAMD64
|
||||
endif
|
||||
ifeq ($(PROCESSOR_ARCHITECTURE),x86)
|
||||
CUSTOM_DEFINES += -DIA32
|
||||
endif
|
||||
endif
|
||||
else
|
||||
UNAME_S := $(shell uname -s)
|
||||
ifeq ($(UNAME_S),Linux)
|
||||
DETECTED_OS = LINUX
|
||||
CUSTOM_DEFINES += -DLINUX
|
||||
endif
|
||||
ifeq ($(UNAME_S),Darwin)
|
||||
CUSTOM_DEFINES += -DOSX
|
||||
endif
|
||||
UNAME_P := $(shell uname -p)
|
||||
ifeq ($(UNAME_P),x86_64)
|
||||
CUSTOM_DEFINES += -DAMD64
|
||||
endif
|
||||
ifneq ($(filter %86,$(UNAME_P)),)
|
||||
CUSTOM_DEFINES += -DIA32
|
||||
endif
|
||||
ifneq ($(filter arm%,$(UNAME_P)),)
|
||||
CUSTOM_DEFINES += -DARM
|
||||
endif
|
||||
endif
|
||||
|
||||
UNIT_TEST = 1
|
||||
# General folder paths
|
||||
CONFIG_PATH = $(FILE_ROOT)/config
|
||||
UNIT_TEST_PATH = $(FILE_ROOT)/tests
|
||||
CORE_PATH = $(FILE_ROOT)/core
|
||||
|
||||
# Output file basename
|
||||
BASENAME = fsfw
|
||||
BINARY_NAME := $(BASENAME)-$(BOARD)
|
||||
# Output files will be put in this directory inside
|
||||
OUTPUT_FOLDER = $(OS)
|
||||
|
||||
# Optimization level. Optimized for debugging.
|
||||
OPTIMIZATION = -O0
|
||||
|
||||
# Default debug output. Optimized for debugging.
|
||||
DEBUG_LEVEL = -g3
|
||||
|
||||
ifdef GCOV
|
||||
CUSTOM_DEFINES += -DGCOV
|
||||
endif
|
||||
|
||||
|
||||
# Output directories
|
||||
BUILDPATH = _bin
|
||||
DEPENDPATH = _dep
|
||||
OBJECTPATH = _obj
|
||||
|
||||
ifeq ($(MAKECMDGOALS),mission)
|
||||
BUILD_FOLDER = mission
|
||||
else
|
||||
BUILD_FOLDER = devel
|
||||
endif
|
||||
|
||||
DEPENDDIR = $(DEPENDPATH)/$(OUTPUT_FOLDER)/$(BUILD_FOLDER)
|
||||
OBJDIR = $(OBJECTPATH)/$(OUTPUT_FOLDER)/$(BUILD_FOLDER)
|
||||
BINDIR = $(BUILDPATH)
|
||||
|
||||
CLEANDEP = $(DEPENDPATH)/$(OUTPUT_FOLDER)
|
||||
CLEANOBJ = $(OBJECTPATH)/$(OUTPUT_FOLDER)
|
||||
CLEANBIN = $(BUILDPATH)
|
||||
#-------------------------------------------------------------------------------
|
||||
# Tools and Includes
|
||||
#-------------------------------------------------------------------------------
|
||||
|
||||
# Tool suffix when cross-compiling
|
||||
CROSS_COMPILE =
|
||||
|
||||
# C Compiler
|
||||
CC = $(CROSS_COMPILE)gcc
|
||||
|
||||
# C++ compiler
|
||||
CXX = $(CROSS_COMPILE)g++
|
||||
|
||||
# Additional Tools
|
||||
SIZE = $(CROSS_COMPILE)size
|
||||
STRIP = $(CROSS_COMPILE)strip
|
||||
CP = $(CROSS_COMPILE)objcopy
|
||||
|
||||
HEXCOPY = $(CP) -O ihex
|
||||
BINCOPY = $(CP) -O binary
|
||||
# files to be compiled, will be filled in by include makefiles
|
||||
# := assignment is neccessary so we get all paths right
|
||||
# https://www.gnu.org/software/make/manual/html_node/Flavors.html
|
||||
CSRC :=
|
||||
CXXSRC :=
|
||||
ASRC :=
|
||||
INCLUDES :=
|
||||
|
||||
# Directories where $(directoryname).mk files should be included from
|
||||
SUBDIRS := $(FRAMEWORK_PATH) $(TEST_PATH) $(UNIT_TEST_PATH) $(CONFIG_PATH) \
|
||||
$(CORE_PATH)
|
||||
|
||||
|
||||
I_INCLUDES += $(addprefix -I, $(INCLUDES))
|
||||
|
||||
# This is a hack from http://make.mad-scientist.net/the-eval-function/
|
||||
#
|
||||
# The problem is, that included makefiles should be aware of their relative path
|
||||
# but not need to guess or hardcode it. So we set $(CURRENTPATH) for them. If
|
||||
# we do this globally and the included makefiles want to include other makefiles as
|
||||
# well, they would overwrite $(CURRENTPATH), screwing the include after them.
|
||||
#
|
||||
# By using a for-loop with an eval'd macro, we can generate the code to include all
|
||||
# sub-makefiles (with the correct $(CURRENTPATH) set) before actually evaluating
|
||||
# (and by this possibly changing $(CURRENTPATH)) them.
|
||||
#
|
||||
# This works recursively, if an included makefile wants to include, it can safely set
|
||||
# $(SUBDIRS) (which has already been evaluated here) and do
|
||||
# "$(foreach S,$(SUBDIRS),$(eval $(INCLUDE_FILE)))"
|
||||
# $(SUBDIRS) must be relative to the project root, so to include subdir foo, set
|
||||
# $(SUBDIRS) = $(CURRENTPATH)/foo.
|
||||
define INCLUDE_FILE
|
||||
CURRENTPATH := $S
|
||||
include $(S)/$(notdir $S).mk
|
||||
endef
|
||||
$(foreach S,$(SUBDIRS),$(eval $(INCLUDE_FILE)))
|
||||
|
||||
INCLUDES += $(FILE_ROOT)
|
||||
INCLUDES += $(FILE_ROOT)/catch2/
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# Source Files
|
||||
#-------------------------------------------------------------------------------
|
||||
|
||||
# All source files which are not includes by the .mk files are added here
|
||||
# Please ensure that no files are included by both .mk file and here !
|
||||
|
||||
# if a target is not listed in the current directory,
|
||||
# make searches in the directories specified with VPATH
|
||||
|
||||
# All C Sources included by .mk files are assigned here
|
||||
# Add the objects to sources so dependency handling works
|
||||
C_OBJECTS += $(CSRC:.c=.o)
|
||||
|
||||
# Objects built from Assembly source files
|
||||
ASM_OBJECTS = $(ASRC:.S=.o)
|
||||
|
||||
# Objects built from C++ source files
|
||||
CXX_OBJECTS += $(CXXSRC:.cpp=.o)
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# Build Configuration + Output
|
||||
#-------------------------------------------------------------------------------
|
||||
|
||||
TARGET = Debug build.
|
||||
DEBUG_MESSAGE = Off
|
||||
OPTIMIZATION_MESSAGE = Off
|
||||
|
||||
# Define Messages
|
||||
MSG_INFO = Software: Hosted unittest \(Catch2\) for the FSFW.
|
||||
MSG_OPTIMIZATION = Optimization: $(OPTIMIZATION), $(OPTIMIZATION_MESSAGE)
|
||||
MSG_TARGET = Target Build: $(TARGET)
|
||||
MSG_DEBUG = Debug level: $(DEBUG_LEVEL), FSFW Debugging: $(DEBUG_MESSAGE)
|
||||
|
||||
MSG_LINKING = Linking:
|
||||
MSG_COMPILING = Compiling:
|
||||
MSG_ASSEMBLING = Assembling:
|
||||
MSG_DEPENDENCY = Collecting dependencies for:
|
||||
MSG_BINARY = Generate binary:
|
||||
|
||||
# See https://stackoverflow.com/questions/6687630/how-to-remove-unused-c-c-symbols-with-gcc-and-ld
|
||||
# Used to throw away unused code. Reduces code size significantly !
|
||||
# -Wl,--gc-sections: needs to be passed to the linker to throw aways unused code
|
||||
ifdef KEEP_UNUSED_CODE
|
||||
PROTOTYPE_OPTIMIZATION =
|
||||
UNUSED_CODE_REMOVAL =
|
||||
else
|
||||
PROTOTYPE_OPTIMIZATION = -ffunction-sections -fdata-sections
|
||||
UNUSED_CODE_REMOVAL = -Wl,--gc-sections
|
||||
# Link time optimization
|
||||
# See https://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html for reference
|
||||
# Link time is larger and size of object files can not be retrieved
|
||||
# but resulting binary is smaller. Could be used in mission/deployment build
|
||||
# Requires -ffunction-section in linker call
|
||||
LINK_TIME_OPTIMIZATION = -flto
|
||||
OPTIMIZATION += $(PROTOTYPE_OPTIMIZATION)
|
||||
endif
|
||||
|
||||
# Dependency Flags
|
||||
# These flags tell the compiler to build dependencies
|
||||
# See: https://www.gnu.org/software/make/manual/html_node/Automatic-Prerequisites.html
|
||||
# Using following guide: http://make.mad-scientist.net/papers/advanced-auto-dependency-generation/#combine
|
||||
DEPFLAGS = -MT $@ -MMD -MP -MF $(DEPENDDIR)/$*.d
|
||||
|
||||
# Flags for the compiler call
|
||||
# - std: Which C++ version to use. Common versions: c++11, c++14 and c++17
|
||||
# - Wall: enable all warnings
|
||||
# - Wextra: enable extra warnings
|
||||
# - g: defines debug level
|
||||
# - fmessage-length: to control the formatting algorithm for diagnostic messages;
|
||||
# =0 means no line-wrapping is done; each error message appears on a single line
|
||||
# - fno-exceptions: stops generating extra code needed to propagate exceptions,
|
||||
# which can produce significant data size overhead
|
||||
CUSTOM_DEFINES += -DUNIT_TEST
|
||||
WARNING_FLAGS = -Wall -Wshadow=local -Wextra -Wimplicit-fallthrough=1 \
|
||||
-Wno-unused-parameter
|
||||
|
||||
CXXDEFINES := $(CUSTOM_DEFINES)
|
||||
CFLAGS +=
|
||||
CXXFLAGS += -I. $(DEBUG_LEVEL) $(WARNING_FLAGS) $(DEPFLAGS) -fmessage-length=0 $(OPTIMIZATION)\
|
||||
$(I_INCLUDES) $(CXXDEFINES)
|
||||
CPPFLAGS += -std=c++11
|
||||
|
||||
# Flags for the linker call
|
||||
# LINK_INCLUDES specify the path to used libraries and the linker script
|
||||
# LINK_LIBRARIES: Link real time support
|
||||
LDFLAGS := $(DEBUG_LEVEL) $(UNUSED_CODE_REMOVAL) $(OPTIMIZATION) -pthread
|
||||
LINK_INCLUDES :=
|
||||
LINK_LIBRARIES :=
|
||||
|
||||
ifdef LINUX
|
||||
LINK_LIBRARIES += -lrt
|
||||
endif
|
||||
|
||||
ifeq ($(OS),Windows_NT)
|
||||
LINK_LIBRARIES += -lwsock32 -lws2_32
|
||||
LDFLASGS += -fuse-ld=lld
|
||||
endif
|
||||
|
||||
# Gnu Coverage Tools Flags
|
||||
ifdef GCOV
|
||||
GCOV_CXXFLAGS = -fprofile-arcs -ftest-coverage --coverage -fno-inline \
|
||||
-fno-inline-small-functions -fno-default-inline
|
||||
CXXFLAGS += $(GCOV_CXXFLAGS)
|
||||
GCOV_LINKER_LIBS = -lgcov -fprofile-arcs -ftest-coverage
|
||||
LINK_LIBRARIES += $(GCOV_LINKER_LIBS)
|
||||
endif
|
||||
|
||||
# $(info $${CXXFLAGS} is [${CXXFLAGS}])
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# Rules
|
||||
#-------------------------------------------------------------------------------
|
||||
# the call function assigns parameters to temporary variables
|
||||
# https://www.gnu.org/software/make/manual/make.html#Call-Function
|
||||
# $(1) = Memory names
|
||||
# Rules are called for each memory type
|
||||
# Two Expansion Symbols $$ are to escape the dollar sign for eval.
|
||||
# See: http://make.mad-scientist.net/the-eval-function/
|
||||
|
||||
default: all
|
||||
|
||||
# Cleans all files
|
||||
hardclean:
|
||||
-rm -rf $(BUILDPATH)
|
||||
-rm -rf $(OBJECTPATH)
|
||||
-rm -rf $(DEPENDPATH)
|
||||
|
||||
# Only clean files for current build
|
||||
clean:
|
||||
-rm -rf $(CLEANOBJ)
|
||||
-rm -rf $(CLEANBIN)
|
||||
-rm -rf $(CLEANDEP)
|
||||
|
||||
# Only clean binaries. Useful for changing the binary type when object files
|
||||
# are already compiled so complete rebuild is not necessary
|
||||
cleanbin:
|
||||
-rm -rf $(CLEANBIN)
|
||||
|
||||
# In this section, the binaries are built for all selected memories
|
||||
# notestfw: all
|
||||
all: executable
|
||||
|
||||
# Build target configuration
|
||||
release: OPTIMIZATION = -Os $(PROTOTYPE_OPTIMIZATION) $(LINK_TIME_OPTIMIZATION)
|
||||
release: LINK_TIME_OPTIMIZATION = -flto
|
||||
release: TARGET = Mission build.
|
||||
release: OPTIMIZATION_MESSAGE = On with Link Time Optimization
|
||||
|
||||
debug: CXXDEFINES += -DDEBUG
|
||||
debug: TARGET = Debug
|
||||
debug: DEBUG_MESSAGE = On
|
||||
|
||||
ifndef KEEP_UNUSED_CODE
|
||||
debug release: OPTIMIZATION_MESSAGE += , no unused code removal
|
||||
endif
|
||||
|
||||
debug release notestfw: executable
|
||||
|
||||
executable: $(BINDIR)/$(BINARY_NAME).elf
|
||||
@echo
|
||||
@echo $(MSG_INFO)
|
||||
@echo $(MSG_TARGET)
|
||||
@echo $(MSG_OPTIMIZATION)
|
||||
@echo $(MSG_DEBUG)
|
||||
|
||||
C_OBJECTS_PREFIXED = $(addprefix $(OBJDIR)/, $(C_OBJECTS))
|
||||
CXX_OBJECTS_PREFIXED = $(addprefix $(OBJDIR)/, $(CXX_OBJECTS))
|
||||
ASM_OBJECTS_PREFIXED = $(addprefix $(OBJDIR)/, $(ASM_OBJECTS))
|
||||
ALL_OBJECTS = $(ASM_OBJECTS_PREFIXED) $(C_OBJECTS_PREFIXED) \
|
||||
$(CXX_OBJECTS_PREFIXED)
|
||||
|
||||
# Useful for debugging the Makefile
|
||||
# Also see: https://www.oreilly.com/openbook/make3/book/ch12.pdf
|
||||
# $(info $${ALL_OBJECTS} is [${ALL_OBJECTS}])
|
||||
# $(info $${CXXSRC} is [${CXXSRC}])
|
||||
|
||||
# Automatic variables are used here extensively. Some of them
|
||||
# are escaped($$) to suppress immediate evaluation. The most important ones are:
|
||||
# $@: Name of Target (left side of rule)
|
||||
# $<: Name of the first prerequisite (right side of rule)
|
||||
# @^: List of all prerequisite, omitting duplicates
|
||||
# @D: Directory and file-within-directory part of $@
|
||||
|
||||
# Generates binary and displays all build properties
|
||||
# -p with mkdir ignores error and creates directory when needed.
|
||||
|
||||
# SHOW_DETAILS = 1
|
||||
|
||||
|
||||
# Link with required libraries: HAL (Hardware Abstraction Layer) and
|
||||
# HCC (File System Library)
|
||||
$(BINDIR)/$(BINARY_NAME).elf: $(ALL_OBJECTS)
|
||||
@echo
|
||||
@echo $(MSG_LINKING) Target $@
|
||||
@mkdir -p $(@D)
|
||||
ifdef SHOW_DETAILS
|
||||
$(CXX) $(LDFLAGS) $(LINK_INCLUDES) -o $@ $^ $(LINK_LIBRARIES)
|
||||
else
|
||||
@$(CXX) $(LDFLAGS) $(LINK_INCLUDES) -o $@ $^ $(LINK_LIBRARIES)
|
||||
endif
|
||||
ifeq ($(BUILD_FOLDER), mission)
|
||||
# With Link Time Optimization, section size is not available
|
||||
$(SIZE) $@
|
||||
else
|
||||
$(SIZE) $^ $@
|
||||
endif
|
||||
|
||||
$(BINDIR)/$(BINARY_NAME).hex: $(BINDIR)/$(BINARY_NAME).elf
|
||||
@echo
|
||||
@echo $(MSG_BINARY)
|
||||
@mkdir -p $(@D)
|
||||
$(HEXCOPY) $< $@
|
||||
|
||||
# Build new objects for changed dependencies.
|
||||
$(OBJDIR)/%.o: %.cpp
|
||||
$(OBJDIR)/%.o: %.cpp $(DEPENDDIR)/%.d | $(DEPENDDIR)
|
||||
@echo
|
||||
@echo $(MSG_COMPILING) $<
|
||||
@mkdir -p $(@D)
|
||||
ifdef SHOW_DETAILS
|
||||
$(CXX) $(CXXFLAGS) $(CPPFLAGS) -c -o $@ $<
|
||||
else
|
||||
@$(CXX) $(CXXFLAGS) $(CPPFLAGS) -c -o $@ $<
|
||||
endif
|
||||
|
||||
$(OBJDIR)/%.o: %.c
|
||||
$(OBJDIR)/%.o: %.c $(DEPENDDIR)/%.d | $(DEPENDDIR)
|
||||
@echo
|
||||
@echo $(MSG_COMPILING) $<
|
||||
@mkdir -p $(@D)
|
||||
ifdef SHOW_DETAILS
|
||||
$(CC) $(CXXFLAGS) $(CFLAGS) -c -o $@ $<
|
||||
else
|
||||
@$(CC) $(CXXFLAGS) $(CFLAGS) -c -o $@ $<
|
||||
endif
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# Dependency Handling
|
||||
#-------------------------------------------------------------------------------
|
||||
|
||||
# Dependency Handling according to following guide:
|
||||
# http://make.mad-scientist.net/papers/advanced-auto-dependency-generation/
|
||||
$(DEPENDDIR):
|
||||
@mkdir -p $(@D)
|
||||
DEPENDENCY_RELATIVE = $(CSRC:.c=.d) $(CXXSRC:.cpp=.d)
|
||||
# This is the list of all dependencies
|
||||
DEPFILES = $(addprefix $(DEPENDDIR)/, $(DEPENDENCY_RELATIVE))
|
||||
# Create subdirectories for dependencies
|
||||
$(DEPFILES):
|
||||
@mkdir -p $(@D)
|
||||
# Include all dependencies
|
||||
include $(wildcard $(DEPFILES))
|
||||
|
||||
# .PHONY tells make that these targets aren't files
|
||||
.PHONY: clean release debug all hardclean cleanbin
|
8
unittest/testcfg/TestsConfig.h
Normal file
8
unittest/testcfg/TestsConfig.h
Normal file
@ -0,0 +1,8 @@
|
||||
#ifndef FSFW_UNITTEST_CONFIG_TESTSCONFIG_H_
|
||||
#define FSFW_UNITTEST_CONFIG_TESTSCONFIG_H_
|
||||
|
||||
|
||||
#define CUSTOM_UNITTEST_RUNNER 0
|
||||
|
||||
|
||||
#endif /* FSFW_UNITTEST_CONFIG_TESTSCONFIG_H_ */
|
5
unittest/testcfg/cdatapool/dataPoolInit.cpp
Normal file
5
unittest/testcfg/cdatapool/dataPoolInit.cpp
Normal file
@ -0,0 +1,5 @@
|
||||
#include "dataPoolInit.h"
|
||||
|
||||
void datapool::dataPoolInit(std::map<uint32_t, PoolEntryIF*> * poolMap) {
|
||||
|
||||
}
|
17
unittest/testcfg/cdatapool/dataPoolInit.h
Normal file
17
unittest/testcfg/cdatapool/dataPoolInit.h
Normal file
@ -0,0 +1,17 @@
|
||||
#ifndef HOSTED_CONFIG_CDATAPOOL_DATAPOOLINIT_H_
|
||||
#define HOSTED_CONFIG_CDATAPOOL_DATAPOOLINIT_H_
|
||||
|
||||
#include <fsfw/datapoolglob/GlobalDataPool.h>
|
||||
#include <fsfw/datapool/PoolEntryIF.h>
|
||||
#include <map>
|
||||
#include <cstdint>
|
||||
|
||||
|
||||
namespace datapool {
|
||||
void dataPoolInit(std::map<uint32_t, PoolEntryIF*> * poolMap);
|
||||
|
||||
enum datapoolvariables {
|
||||
NO_PARAMETER = 0,
|
||||
};
|
||||
}
|
||||
#endif /* CONFIG_CDATAPOOL_DATAPOOLINIT_H_ */
|
5
unittest/testcfg/devices/logicalAddresses.cpp
Normal file
5
unittest/testcfg/devices/logicalAddresses.cpp
Normal file
@ -0,0 +1,5 @@
|
||||
#include "logicalAddresses.h"
|
||||
|
||||
|
||||
|
||||
|
15
unittest/testcfg/devices/logicalAddresses.h
Normal file
15
unittest/testcfg/devices/logicalAddresses.h
Normal file
@ -0,0 +1,15 @@
|
||||
#ifndef CONFIG_DEVICES_LOGICALADDRESSES_H_
|
||||
#define CONFIG_DEVICES_LOGICALADDRESSES_H_
|
||||
|
||||
#include <fsfw/devicehandlers/CookieIF.h>
|
||||
#include <fsfw/unittest/config/objects/systemObjectList.h>
|
||||
#include <cstdint>
|
||||
|
||||
namespace addresses {
|
||||
/* Logical addresses have uint32_t datatype */
|
||||
enum logicalAddresses: address_t {
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
#endif /* CONFIG_DEVICES_LOGICALADDRESSES_H_ */
|
4
unittest/testcfg/devices/powerSwitcherList.cpp
Normal file
4
unittest/testcfg/devices/powerSwitcherList.cpp
Normal file
@ -0,0 +1,4 @@
|
||||
#include "powerSwitcherList.h"
|
||||
|
||||
|
||||
|
12
unittest/testcfg/devices/powerSwitcherList.h
Normal file
12
unittest/testcfg/devices/powerSwitcherList.h
Normal file
@ -0,0 +1,12 @@
|
||||
#ifndef CONFIG_DEVICES_POWERSWITCHERLIST_H_
|
||||
#define CONFIG_DEVICES_POWERSWITCHERLIST_H_
|
||||
|
||||
namespace switches {
|
||||
/* Switches are uint8_t datatype and go from 0 to 255 */
|
||||
enum switcherList {
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif /* CONFIG_DEVICES_POWERSWITCHERLIST_H_ */
|
18
unittest/testcfg/events/subsystemIdRanges.h
Normal file
18
unittest/testcfg/events/subsystemIdRanges.h
Normal file
@ -0,0 +1,18 @@
|
||||
#ifndef CONFIG_EVENTS_SUBSYSTEMIDRANGES_H_
|
||||
#define CONFIG_EVENTS_SUBSYSTEMIDRANGES_H_
|
||||
|
||||
#include <cstdint>
|
||||
#include <fsfw/events/fwSubsystemIdRanges.h>
|
||||
|
||||
/**
|
||||
* @brief Custom subsystem IDs can be added here
|
||||
* @details
|
||||
* Subsystem IDs are used to create unique events.
|
||||
*/
|
||||
namespace SUBSYSTEM_ID {
|
||||
enum: uint8_t {
|
||||
SUBSYSTEM_ID_START = FW_SUBSYSTEM_ID_RANGE,
|
||||
};
|
||||
}
|
||||
|
||||
#endif /* CONFIG_EVENTS_SUBSYSTEMIDRANGES_H_ */
|
12
unittest/testcfg/ipc/MissionMessageTypes.cpp
Normal file
12
unittest/testcfg/ipc/MissionMessageTypes.cpp
Normal file
@ -0,0 +1,12 @@
|
||||
#include "MissionMessageTypes.h"
|
||||
|
||||
#include <fsfw/ipc/CommandMessage.h>
|
||||
|
||||
void messagetypes::clearMissionMessage(CommandMessage* message) {
|
||||
switch(message->getMessageType()) {
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
22
unittest/testcfg/ipc/MissionMessageTypes.h
Normal file
22
unittest/testcfg/ipc/MissionMessageTypes.h
Normal file
@ -0,0 +1,22 @@
|
||||
#ifndef CONFIG_IPC_MISSIONMESSAGETYPES_H_
|
||||
#define CONFIG_IPC_MISSIONMESSAGETYPES_H_
|
||||
|
||||
#include <fsfw/ipc/FwMessageTypes.h>
|
||||
|
||||
class CommandMessage;
|
||||
|
||||
/**
|
||||
* Custom command messages are specified here.
|
||||
* Most messages needed to use FSFW are already located in
|
||||
* <fsfw/ipc/FwMessageTypes.h>
|
||||
* @param message Generic Command Message
|
||||
*/
|
||||
namespace messagetypes{
|
||||
enum MESSAGE_TYPE {
|
||||
MISSION_MESSAGE_TYPE_START = FW_MESSAGES_COUNT,
|
||||
};
|
||||
|
||||
void clearMissionMessage(CommandMessage* message);
|
||||
}
|
||||
|
||||
#endif /* CONFIG_IPC_MISSIONMESSAGETYPES_H_ */
|
34
unittest/testcfg/objects/Factory.cpp
Normal file
34
unittest/testcfg/objects/Factory.cpp
Normal file
@ -0,0 +1,34 @@
|
||||
#include "Factory.h"
|
||||
|
||||
#include <fsfw/events/EventManager.h>
|
||||
#include <fsfw/health/HealthTable.h>
|
||||
|
||||
#include <fsfw/internalError/InternalErrorReporter.h>
|
||||
#include <fsfw/objectmanager/frameworkObjects.h>
|
||||
|
||||
/**
|
||||
* @brief Produces system objects.
|
||||
* @details
|
||||
* Build tasks by using SystemObject Interface (Interface).
|
||||
* Header files of all tasks must be included
|
||||
* Please note that an object has to implement the system object interface
|
||||
* if the interface validity is checked or retrieved later by using the
|
||||
* get<TargetInterface>(object_id) function from the ObjectManagerIF.
|
||||
*
|
||||
* Framework objects are created first.
|
||||
*
|
||||
* @ingroup init
|
||||
*/
|
||||
void Factory::produce(void) {
|
||||
setStaticFrameworkObjectIds();
|
||||
new EventManager(objects::EVENT_MANAGER);
|
||||
new HealthTable(objects::HEALTH_TABLE);
|
||||
new InternalErrorReporter(objects::INTERNAL_ERROR_REPORTER);
|
||||
|
||||
}
|
||||
|
||||
void Factory::setStaticFrameworkObjectIds() {
|
||||
|
||||
}
|
||||
|
||||
|
16
unittest/testcfg/objects/Factory.h
Normal file
16
unittest/testcfg/objects/Factory.h
Normal file
@ -0,0 +1,16 @@
|
||||
#ifndef FACTORY_H_
|
||||
#define FACTORY_H_
|
||||
|
||||
#include <fsfw/objectmanager/SystemObjectIF.h>
|
||||
|
||||
namespace Factory {
|
||||
/**
|
||||
* @brief Creates all SystemObject elements which are persistent
|
||||
* during execution.
|
||||
*/
|
||||
void produce();
|
||||
void setStaticFrameworkObjectIds();
|
||||
|
||||
}
|
||||
|
||||
#endif /* FACTORY_H_ */
|
16
unittest/testcfg/objects/systemObjectList.h
Normal file
16
unittest/testcfg/objects/systemObjectList.h
Normal file
@ -0,0 +1,16 @@
|
||||
#ifndef HOSTED_CONFIG_OBJECTS_SYSTEMOBJECTLIST_H_
|
||||
#define HOSTED_CONFIG_OBJECTS_SYSTEMOBJECTLIST_H_
|
||||
|
||||
#include <cstdint>
|
||||
#include <fsfw/objectmanager/frameworkObjects.h>
|
||||
|
||||
// The objects will be instantiated in the ID order
|
||||
namespace objects {
|
||||
enum sourceObjects: uint32_t {
|
||||
/* All addresses between start and end are reserved for the FSFW */
|
||||
FSFW_CONFIG_RESERVED_START = PUS_SERVICE_1_VERIFICATION,
|
||||
FSFW_CONFIG_RESERVED_END = TM_STORE
|
||||
};
|
||||
}
|
||||
|
||||
#endif /* BSP_CONFIG_OBJECTS_SYSTEMOBJECTLIST_H_ */
|
23
unittest/testcfg/pollingsequence/PollingSequenceFactory.cpp
Normal file
23
unittest/testcfg/pollingsequence/PollingSequenceFactory.cpp
Normal file
@ -0,0 +1,23 @@
|
||||
#include "PollingSequenceFactory.h"
|
||||
|
||||
#include <fsfw/serviceinterface/ServiceInterfaceStream.h>
|
||||
#include <fsfw/devicehandlers/DeviceHandlerIF.h>
|
||||
#include <fsfw/tasks/FixedTimeslotTaskIF.h>
|
||||
|
||||
ReturnValue_t pst::pollingSequenceInitDefault(
|
||||
FixedTimeslotTaskIF *thisSequence) {
|
||||
/* Length of a communication cycle */
|
||||
uint32_t length = thisSequence->getPeriodMs();
|
||||
|
||||
/* Add polling sequence table here */
|
||||
|
||||
if (thisSequence->checkSequence() == HasReturnvaluesIF::RETURN_OK) {
|
||||
return HasReturnvaluesIF::RETURN_OK;
|
||||
}
|
||||
else {
|
||||
sif::error << "pst::pollingSequenceInitDefault: Sequence invalid!"
|
||||
<< std::endl;
|
||||
return HasReturnvaluesIF::RETURN_FAILED;
|
||||
}
|
||||
}
|
||||
|
32
unittest/testcfg/pollingsequence/PollingSequenceFactory.h
Normal file
32
unittest/testcfg/pollingsequence/PollingSequenceFactory.h
Normal file
@ -0,0 +1,32 @@
|
||||
#ifndef POLLINGSEQUENCEFACTORY_H_
|
||||
#define POLLINGSEQUENCEFACTORY_H_
|
||||
|
||||
#include <fsfw/returnvalues/HasReturnvaluesIF.h>
|
||||
|
||||
class FixedTimeslotTaskIF;
|
||||
|
||||
/**
|
||||
* All device handlers are scheduled by adding them into Polling Sequence Tables (PST)
|
||||
* to satisfy stricter timing requirements of device communication,
|
||||
* A device handler has four different communication steps:
|
||||
* 1. DeviceHandlerIF::SEND_WRITE -> Send write via interface
|
||||
* 2. DeviceHandlerIF::GET_WRITE -> Get confirmation for write
|
||||
* 3. DeviceHandlerIF::SEND_READ -> Send read request
|
||||
* 4. DeviceHandlerIF::GET_READ -> Read from interface
|
||||
* The PST specifies precisely when the respective ComIF functions are called
|
||||
* during the communication cycle time.
|
||||
* The task is created using the FixedTimeslotTaskIF,
|
||||
* which utilises the underlying Operating System Abstraction Layer (OSAL)
|
||||
*
|
||||
* @param thisSequence FixedTimeslotTaskIF * object is passed inside the Factory class when creating the PST
|
||||
* @return
|
||||
*/
|
||||
namespace pst {
|
||||
|
||||
/* Default PST */
|
||||
ReturnValue_t pollingSequenceInitDefault(FixedTimeslotTaskIF *thisSequence);
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif /* POLLINGSEQUENCEINIT_H_ */
|
16
unittest/testcfg/returnvalues/classIds.h
Normal file
16
unittest/testcfg/returnvalues/classIds.h
Normal file
@ -0,0 +1,16 @@
|
||||
#ifndef CONFIG_RETURNVALUES_CLASSIDS_H_
|
||||
#define CONFIG_RETURNVALUES_CLASSIDS_H_
|
||||
|
||||
#include <fsfw/returnvalues/FwClassIds.h>
|
||||
|
||||
/**
|
||||
* @brief CLASS_ID defintions which are required for custom returnvalues.
|
||||
*/
|
||||
namespace CLASS_ID {
|
||||
enum {
|
||||
MISSION_CLASS_ID_START = FW_CLASS_ID_COUNT,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
#endif /* CONFIG_RETURNVALUES_CLASSIDS_H_ */
|
15
unittest/testcfg/testcfg.mk
Normal file
15
unittest/testcfg/testcfg.mk
Normal file
@ -0,0 +1,15 @@
|
||||
CXXSRC += $(wildcard $(CURRENTPATH)/cdatapool/*.cpp)
|
||||
CXXSRC += $(wildcard $(CURRENTPATH)/ipc/*.cpp)
|
||||
CXXSRC += $(wildcard $(CURRENTPATH)/objects/*.cpp)
|
||||
CXXSRC += $(wildcard $(CURRENTPATH)/pollingsequence/*.cpp)
|
||||
CXXSRC += $(wildcard $(CURRENTPATH)/events/*.cpp)
|
||||
|
||||
INCLUDES += $(CURRENTPATH)
|
||||
INCLUDES += $(CURRENTPATH)/objects
|
||||
INCLUDES += $(CURRENTPATH)/ipc
|
||||
INCLUDES += $(CURRENTPATH)/pollingsequence
|
||||
INCLUDES += $(CURRENTPATH)/returnvalues
|
||||
INCLUDES += $(CURRENTPATH)/tmtc
|
||||
INCLUDES += $(CURRENTPATH)/events
|
||||
INCLUDES += $(CURRENTPATH)/devices
|
||||
INCLUDES += $(CURRENTPATH)/cdatapool
|
18
unittest/testcfg/tmtc/apid.h
Normal file
18
unittest/testcfg/tmtc/apid.h
Normal file
@ -0,0 +1,18 @@
|
||||
#ifndef CONFIG_TMTC_APID_H_
|
||||
#define CONFIG_TMTC_APID_H_
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
/**
|
||||
* Application Process Definition: entity, uniquely identified by an
|
||||
* application process ID (APID), capable of generating telemetry source
|
||||
* packets and receiving telecommand packets.
|
||||
*
|
||||
* Chose APID(s) for mission and define it here.
|
||||
*/
|
||||
namespace apid {
|
||||
static const uint16_t DEFAULT_APID = 0x00;
|
||||
}
|
||||
|
||||
|
||||
#endif /* CONFIG_TMTC_APID_H_ */
|
25
unittest/testcfg/tmtc/pusIds.h
Normal file
25
unittest/testcfg/tmtc/pusIds.h
Normal file
@ -0,0 +1,25 @@
|
||||
#ifndef CONFIG_TMTC_PUSIDS_HPP_
|
||||
#define CONFIG_TMTC_PUSIDS_HPP_
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace pus {
|
||||
enum Ids: uint8_t {
|
||||
PUS_SERVICE_1 = 1,
|
||||
PUS_SERVICE_2 = 2,
|
||||
PUS_SERVICE_3 = 3,
|
||||
PUS_SERVICE_5 = 5,
|
||||
PUS_SERVICE_6 = 6,
|
||||
PUS_SERVICE_8 = 8,
|
||||
PUS_SERVICE_9 = 9,
|
||||
PUS_SERVICE_11 = 11,
|
||||
PUS_SERVICE_17 = 17,
|
||||
PUS_SERVICE_19 = 19,
|
||||
PUS_SERVICE_20 = 20,
|
||||
PUS_SERVICE_23 = 23,
|
||||
PUS_SERVICE_200 = 200,
|
||||
PUS_SERVICE_201 = 201,
|
||||
};
|
||||
};
|
||||
|
||||
#endif /* CONFIG_TMTC_PUSIDS_HPP_ */
|
106
unittest/tests/action/TestActionHelper.cpp
Normal file
106
unittest/tests/action/TestActionHelper.cpp
Normal file
@ -0,0 +1,106 @@
|
||||
//#include "TestActionHelper.h"
|
||||
//#include <fsfw/action/ActionHelper.h>
|
||||
//#include <fsfw/ipc/CommandMessage.h>
|
||||
//#include <catch2/catch.hpp>
|
||||
//#include "../../core/CatchDefinitions.h"
|
||||
//
|
||||
//
|
||||
//TEST_CASE( "Action Helper" , "[ActionHelper]") {
|
||||
// ActionHelperOwnerMockBase testDhMock;
|
||||
// MessageQueueMockBase testMqMock;
|
||||
// ActionHelper actionHelper = ActionHelper(
|
||||
// &testDhMock, dynamic_cast<MessageQueueIF*>(&testMqMock));
|
||||
// CommandMessage actionMessage;
|
||||
// ActionId_t testActionId = 777;
|
||||
// std::array <uint8_t, 3> testParams {1, 2, 3};
|
||||
// store_address_t paramAddress;
|
||||
// StorageManagerIF *ipcStore = tglob::getIpcStoreHandle();
|
||||
// ipcStore->addData(¶mAddress, testParams.data(), 3);
|
||||
// REQUIRE(actionHelper.initialize() == retval::CATCH_OK);
|
||||
//
|
||||
// SECTION ("Simple tests") {
|
||||
// ActionMessage::setCommand(&actionMessage, testActionId, paramAddress);
|
||||
// CHECK(not testDhMock.executeActionCalled);
|
||||
// REQUIRE(actionHelper.handleActionMessage(&actionMessage) == retval::CATCH_OK);
|
||||
// CHECK(testDhMock.executeActionCalled);
|
||||
// // No message is sent if everything is alright.
|
||||
// CHECK(not testMqMock.wasMessageSent());
|
||||
// store_address_t invalidAddress;
|
||||
// ActionMessage::setCommand(&actionMessage, testActionId, invalidAddress);
|
||||
// actionHelper.handleActionMessage(&actionMessage);
|
||||
// CHECK(testMqMock.wasMessageSent());
|
||||
// const uint8_t* ptr = nullptr;
|
||||
// size_t size = 0;
|
||||
// REQUIRE(ipcStore->getData(paramAddress, &ptr, &size) == static_cast<uint32_t>(StorageManagerIF::DATA_DOES_NOT_EXIST));
|
||||
// REQUIRE(ptr == nullptr);
|
||||
// REQUIRE(size == 0);
|
||||
// testDhMock.getBuffer(&ptr, &size);
|
||||
// REQUIRE(size == 3);
|
||||
// for(uint8_t i = 0; i<3;i++){
|
||||
// REQUIRE(ptr[i] == (i+1));
|
||||
// }
|
||||
// testDhMock.clearBuffer();
|
||||
// }
|
||||
//
|
||||
// SECTION("Handle failures"){
|
||||
// actionMessage.setCommand(1234);
|
||||
// REQUIRE(actionHelper.handleActionMessage(&actionMessage) == static_cast<uint32_t>(CommandMessage::UNKNOWN_COMMAND));
|
||||
// CHECK(not testMqMock.wasMessageSent());
|
||||
// uint16_t step = 5;
|
||||
// ReturnValue_t status = 0x1234;
|
||||
// actionHelper.step(step, testMqMock.getId(), testActionId, status);
|
||||
// step += 1;
|
||||
// CHECK(testMqMock.wasMessageSent());
|
||||
// CommandMessage testMessage;
|
||||
// REQUIRE(testMqMock.receiveMessage(&testMessage) == static_cast<uint32_t>(HasReturnvaluesIF::RETURN_OK));
|
||||
// REQUIRE(testMessage.getCommand() == static_cast<uint32_t>(ActionMessage::STEP_FAILED));
|
||||
// REQUIRE(testMessage.getParameter() == static_cast<uint32_t>(testActionId));
|
||||
// uint32_t parameter2 = ((uint32_t)step << 16) | (uint32_t)status;
|
||||
// REQUIRE(testMessage.getParameter2() == parameter2);
|
||||
// REQUIRE(ActionMessage::getStep(&testMessage) == step);
|
||||
// }
|
||||
//
|
||||
// SECTION("Handle finish"){
|
||||
// CHECK(not testMqMock.wasMessageSent());
|
||||
// ReturnValue_t status = 0x9876;
|
||||
// actionHelper.finish(testMqMock.getId(), testActionId, status);
|
||||
// CHECK(testMqMock.wasMessageSent());
|
||||
// CommandMessage testMessage;
|
||||
// REQUIRE(testMqMock.receiveMessage(&testMessage) == static_cast<uint32_t>(HasReturnvaluesIF::RETURN_OK));
|
||||
// REQUIRE(testMessage.getCommand() == static_cast<uint32_t>(ActionMessage::COMPLETION_FAILED));
|
||||
// REQUIRE(ActionMessage::getActionId(&testMessage) == testActionId);
|
||||
// REQUIRE(ActionMessage::getReturnCode(&testMessage) == static_cast<uint32_t>(status));
|
||||
// }
|
||||
//
|
||||
// SECTION("Handle failed"){
|
||||
// store_address_t toLongParamAddress = StorageManagerIF::INVALID_ADDRESS;
|
||||
// std::array<uint8_t, 5> toLongData = {5, 4, 3, 2, 1};
|
||||
// REQUIRE(ipcStore->addData(&toLongParamAddress, toLongData.data(), 5) == retval::CATCH_OK);
|
||||
// ActionMessage::setCommand(&actionMessage, testActionId, toLongParamAddress);
|
||||
// CHECK(not testDhMock.executeActionCalled);
|
||||
// REQUIRE(actionHelper.handleActionMessage(&actionMessage) == retval::CATCH_OK);
|
||||
// REQUIRE(ipcStore->getData(toLongParamAddress).first == static_cast<uint32_t>(StorageManagerIF::DATA_DOES_NOT_EXIST));
|
||||
// CommandMessage testMessage;
|
||||
// REQUIRE(testMqMock.receiveMessage(&testMessage) == static_cast<uint32_t>(HasReturnvaluesIF::RETURN_OK));
|
||||
// REQUIRE(testMessage.getCommand() == static_cast<uint32_t>(ActionMessage::STEP_FAILED));
|
||||
// REQUIRE(ActionMessage::getReturnCode(&testMessage) == 0xAFFE);
|
||||
// REQUIRE(ActionMessage::getStep(&testMessage) == 0);
|
||||
// REQUIRE(ActionMessage::getActionId(&testMessage) == testActionId);
|
||||
// }
|
||||
//
|
||||
// SECTION("Missing IPC Data"){
|
||||
// ActionMessage::setCommand(&actionMessage, testActionId, StorageManagerIF::INVALID_ADDRESS);
|
||||
// CHECK(not testDhMock.executeActionCalled);
|
||||
// REQUIRE(actionHelper.handleActionMessage(&actionMessage) == retval::CATCH_OK);
|
||||
// CommandMessage testMessage;
|
||||
// REQUIRE(testMqMock.receiveMessage(&testMessage) == static_cast<uint32_t>(HasReturnvaluesIF::RETURN_OK));
|
||||
// REQUIRE(testMessage.getCommand() == static_cast<uint32_t>(ActionMessage::STEP_FAILED));
|
||||
// REQUIRE(ActionMessage::getReturnCode(&testMessage) == static_cast<uint32_t>(StorageManagerIF::ILLEGAL_STORAGE_ID));
|
||||
// REQUIRE(ActionMessage::getStep(&testMessage) == 0);
|
||||
// }
|
||||
//
|
||||
//
|
||||
// SECTION("Data Reply"){
|
||||
//
|
||||
// }
|
||||
//}
|
131
unittest/tests/action/TestActionHelper.h
Normal file
131
unittest/tests/action/TestActionHelper.h
Normal file
@ -0,0 +1,131 @@
|
||||
//#ifndef UNITTEST_HOSTED_TESTACTIONHELPER_H_
|
||||
//#define UNITTEST_HOSTED_TESTACTIONHELPER_H_
|
||||
//
|
||||
//#include <fsfw/action/HasActionsIF.h>
|
||||
//#include <fsfw/ipc/MessageQueueIF.h>
|
||||
//#include <fsfw/unittest/core/CatchDefinitions.h>
|
||||
//#include <cstring>
|
||||
//
|
||||
//
|
||||
//class ActionHelperOwnerMockBase: public HasActionsIF {
|
||||
//public:
|
||||
// bool getCommandQueueCalled = false;
|
||||
// bool executeActionCalled = false;
|
||||
// static const size_t MAX_SIZE = 3;
|
||||
// uint8_t buffer[MAX_SIZE] = {0, 0, 0};
|
||||
// size_t size = 0;
|
||||
//
|
||||
// MessageQueueId_t getCommandQueue() const override {
|
||||
// return tconst::testQueueId;
|
||||
// }
|
||||
//
|
||||
// ReturnValue_t executeAction(ActionId_t actionId, MessageQueueId_t commandedBy,
|
||||
// const uint8_t* data, size_t size) override {
|
||||
// executeActionCalled = true;
|
||||
// if(size > MAX_SIZE){
|
||||
// return 0xAFFE;
|
||||
// }
|
||||
// this->size = size;
|
||||
// memcpy(buffer, data, size);
|
||||
// return HasReturnvaluesIF::RETURN_OK;
|
||||
// }
|
||||
//
|
||||
// void clearBuffer(){
|
||||
// this->size = 0;
|
||||
// for(size_t i = 0; i<MAX_SIZE; i++){
|
||||
// buffer[i] = 0;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// void getBuffer(const uint8_t** ptr, size_t* size){
|
||||
// if(size != nullptr){
|
||||
// *size = this->size;
|
||||
// }
|
||||
// if(ptr != nullptr){
|
||||
// *ptr = buffer;
|
||||
// }
|
||||
// }
|
||||
//};
|
||||
//
|
||||
//
|
||||
//class MessageQueueMockBase: public MessageQueueIF {
|
||||
//public:
|
||||
// MessageQueueId_t myQueueId = 0;
|
||||
// bool defaultDestSet = false;
|
||||
// bool messageSent = false;
|
||||
//
|
||||
//
|
||||
//
|
||||
// bool wasMessageSent() {
|
||||
// bool tempMessageSent = messageSent;
|
||||
// messageSent = false;
|
||||
// return tempMessageSent;
|
||||
// }
|
||||
//
|
||||
// virtual ReturnValue_t reply( MessageQueueMessage* message ) {
|
||||
// messageSent = true;
|
||||
// lastMessage = (*message);
|
||||
// return HasReturnvaluesIF::RETURN_OK;
|
||||
// };
|
||||
// virtual ReturnValue_t receiveMessage(MessageQueueMessage* message,
|
||||
// MessageQueueId_t *receivedFrom) {
|
||||
// (*message) = lastMessage;
|
||||
// lastMessage.clear();
|
||||
// return HasReturnvaluesIF::RETURN_OK;
|
||||
// }
|
||||
// virtual ReturnValue_t receiveMessage(MessageQueueMessage* message) {
|
||||
// (*message) = lastMessage;
|
||||
// lastMessage.clear();
|
||||
// return HasReturnvaluesIF::RETURN_OK;
|
||||
// }
|
||||
// virtual ReturnValue_t flush(uint32_t* count) {
|
||||
// return HasReturnvaluesIF::RETURN_OK;
|
||||
// }
|
||||
// virtual MessageQueueId_t getLastPartner() const {
|
||||
// return tconst::testQueueId;
|
||||
// }
|
||||
// virtual MessageQueueId_t getId() const {
|
||||
// return tconst::testQueueId;
|
||||
// }
|
||||
// virtual ReturnValue_t sendMessageFrom( MessageQueueId_t sendTo,
|
||||
// MessageQueueMessage* message, MessageQueueId_t sentFrom,
|
||||
// bool ignoreFault = false ) {
|
||||
// messageSent = true;
|
||||
// lastMessage = (*message);
|
||||
// return HasReturnvaluesIF::RETURN_OK;
|
||||
// }
|
||||
// virtual ReturnValue_t sendMessage( MessageQueueId_t sendTo,
|
||||
// MessageQueueMessage* message, bool ignoreFault = false ) override {
|
||||
// messageSent = true;
|
||||
// lastMessage = (*message);
|
||||
// return HasReturnvaluesIF::RETURN_OK;
|
||||
// }
|
||||
// virtual ReturnValue_t sendToDefaultFrom( MessageQueueMessage* message,
|
||||
// MessageQueueId_t sentFrom, bool ignoreFault = false ) {
|
||||
// messageSent = true;
|
||||
// lastMessage = (*message);
|
||||
// return HasReturnvaluesIF::RETURN_OK;
|
||||
// }
|
||||
// virtual ReturnValue_t sendToDefault( MessageQueueMessage* message ) {
|
||||
// messageSent = true;
|
||||
// lastMessage = (*message);
|
||||
// return HasReturnvaluesIF::RETURN_OK;
|
||||
// }
|
||||
// virtual void setDefaultDestination(MessageQueueId_t defaultDestination) {
|
||||
// myQueueId = defaultDestination;
|
||||
// defaultDestSet = true;
|
||||
// }
|
||||
//
|
||||
// virtual MessageQueueId_t getDefaultDestination() const {
|
||||
// return myQueueId;
|
||||
// }
|
||||
// virtual bool isDefaultDestinationSet() const {
|
||||
// return defaultDestSet;
|
||||
// }
|
||||
//private:
|
||||
// MessageQueueMessage lastMessage;
|
||||
//
|
||||
//};
|
||||
//
|
||||
//
|
||||
//#endif /* UNITTEST_TESTFW_NEWTESTS_TESTACTIONHELPER_H_ */
|
327
unittest/tests/container/RingBufferTest.cpp
Normal file
327
unittest/tests/container/RingBufferTest.cpp
Normal file
@ -0,0 +1,327 @@
|
||||
#include <fsfw/container/SimpleRingBuffer.h>
|
||||
#include <catch2/catch.hpp>
|
||||
#include "../../core/CatchDefinitions.h"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
TEST_CASE("Ring Buffer Test" , "[RingBufferTest]") {
|
||||
uint8_t testData[13]= {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
|
||||
uint8_t readBuffer[10] = {13, 13, 13, 13, 13, 13, 13, 13, 13, 13};
|
||||
SimpleRingBuffer ringBuffer(10, false, 5);
|
||||
|
||||
SECTION("Simple Test") {
|
||||
REQUIRE(ringBuffer.availableWriteSpace() == 9);
|
||||
REQUIRE(ringBuffer.writeData(testData, 9) == retval::CATCH_OK);
|
||||
REQUIRE(ringBuffer.writeData(testData, 3) == retval::CATCH_FAILED);
|
||||
REQUIRE(ringBuffer.readData(readBuffer, 5, true) == retval::CATCH_OK);
|
||||
for(uint8_t i = 0; i< 5; i++) {
|
||||
CHECK(readBuffer[i] == i);
|
||||
}
|
||||
REQUIRE(ringBuffer.availableWriteSpace() == 5);
|
||||
ringBuffer.clear();
|
||||
REQUIRE(ringBuffer.availableWriteSpace() == 9);
|
||||
REQUIRE(ringBuffer.writeData(testData, 4) == retval::CATCH_OK);
|
||||
REQUIRE(ringBuffer.readData(readBuffer, 4, true) == retval::CATCH_OK);
|
||||
for(uint8_t i = 0; i< 4; i++) {
|
||||
CHECK(readBuffer[i] == i);
|
||||
}
|
||||
REQUIRE(ringBuffer.writeData(testData, 9) == retval::CATCH_OK);
|
||||
REQUIRE(ringBuffer.readData(readBuffer, 9, true) == retval::CATCH_OK);
|
||||
for(uint8_t i = 0; i< 9; i++) {
|
||||
CHECK(readBuffer[i] == i);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
SECTION("Get Free Element Test") {
|
||||
REQUIRE(ringBuffer.availableWriteSpace() == 9);
|
||||
REQUIRE(ringBuffer.writeData(testData, 8) == retval::CATCH_OK);
|
||||
REQUIRE(ringBuffer.availableWriteSpace() == 1);
|
||||
REQUIRE(ringBuffer.readData(readBuffer, 8, true) == retval::CATCH_OK);
|
||||
REQUIRE(ringBuffer.availableWriteSpace() == 9);
|
||||
uint8_t *testPtr = nullptr;
|
||||
REQUIRE(ringBuffer.getFreeElement(&testPtr, 10) == retval::CATCH_FAILED);
|
||||
|
||||
|
||||
REQUIRE(ringBuffer.writeTillWrap() == 2);
|
||||
// too many excess bytes.
|
||||
REQUIRE(ringBuffer.getFreeElement(&testPtr, 8) == retval::CATCH_FAILED);
|
||||
REQUIRE(ringBuffer.getFreeElement(&testPtr, 5) == retval::CATCH_OK);
|
||||
REQUIRE(ringBuffer.getExcessBytes() == 3);
|
||||
std::memcpy(testPtr, testData, 5);
|
||||
ringBuffer.confirmBytesWritten(5);
|
||||
REQUIRE(ringBuffer.getAvailableReadData() == 5);
|
||||
ringBuffer.readData(readBuffer, 5, true);
|
||||
for(uint8_t i = 0; i< 5; i++) {
|
||||
CHECK(readBuffer[i] == i);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("Read Remaining Test") {
|
||||
REQUIRE(ringBuffer.writeData(testData, 3) == retval::CATCH_OK);
|
||||
REQUIRE(ringBuffer.getAvailableReadData() == 3);
|
||||
REQUIRE(ringBuffer.readData(readBuffer, 5, false, false, nullptr) == retval::CATCH_FAILED);
|
||||
size_t trueSize = 0;
|
||||
REQUIRE(ringBuffer.readData(readBuffer, 5, false, true, &trueSize) == retval::CATCH_OK);
|
||||
REQUIRE(trueSize == 3);
|
||||
for(uint8_t i = 0; i< 3; i++) {
|
||||
CHECK(readBuffer[i] == i);
|
||||
}
|
||||
trueSize = 0;
|
||||
REQUIRE(ringBuffer.deleteData(5, false, &trueSize) == retval::CATCH_FAILED);
|
||||
REQUIRE(trueSize == 0);
|
||||
REQUIRE(ringBuffer.deleteData(5, true, &trueSize) == retval::CATCH_OK);
|
||||
REQUIRE(trueSize == 3);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("Ring Buffer Test2" , "[RingBufferTest2]") {
|
||||
uint8_t testData[13]= {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
|
||||
uint8_t readBuffer[10] = {13, 13, 13, 13, 13, 13, 13, 13, 13, 13};
|
||||
uint8_t* newBuffer = new uint8_t[10];
|
||||
SimpleRingBuffer ringBuffer(newBuffer, 10, true, 5);
|
||||
|
||||
SECTION("Simple Test") {
|
||||
REQUIRE(ringBuffer.availableWriteSpace() == 9);
|
||||
REQUIRE(ringBuffer.writeData(testData, 9) == retval::CATCH_OK);
|
||||
REQUIRE(ringBuffer.readData(readBuffer, 5, true) == retval::CATCH_OK);
|
||||
for(uint8_t i = 0; i< 5; i++) {
|
||||
CHECK(readBuffer[i] == i);
|
||||
}
|
||||
REQUIRE(ringBuffer.availableWriteSpace() == 5);
|
||||
ringBuffer.clear();
|
||||
REQUIRE(ringBuffer.availableWriteSpace() == 9);
|
||||
REQUIRE(ringBuffer.writeData(testData, 4) == retval::CATCH_OK);
|
||||
REQUIRE(ringBuffer.readData(readBuffer, 4, true) == retval::CATCH_OK);
|
||||
for(uint8_t i = 0; i< 4; i++) {
|
||||
CHECK(readBuffer[i] == i);
|
||||
}
|
||||
REQUIRE(ringBuffer.writeData(testData, 9) == retval::CATCH_OK);
|
||||
REQUIRE(ringBuffer.readData(readBuffer, 9, true) == retval::CATCH_OK);
|
||||
for(uint8_t i = 0; i< 9; i++) {
|
||||
CHECK(readBuffer[i] == i);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
SECTION("Get Free Element Test") {
|
||||
REQUIRE(ringBuffer.availableWriteSpace() == 9);
|
||||
REQUIRE(ringBuffer.writeData(testData, 8) == retval::CATCH_OK);
|
||||
REQUIRE(ringBuffer.availableWriteSpace() == 1);
|
||||
REQUIRE(ringBuffer.readData(readBuffer, 8, true) == retval::CATCH_OK);
|
||||
REQUIRE(ringBuffer.availableWriteSpace() == 9);
|
||||
uint8_t *testPtr = nullptr;
|
||||
REQUIRE(ringBuffer.getFreeElement(&testPtr, 10) == retval::CATCH_FAILED);
|
||||
|
||||
|
||||
REQUIRE(ringBuffer.writeTillWrap() == 2);
|
||||
// too many excess bytes.
|
||||
REQUIRE(ringBuffer.getFreeElement(&testPtr, 8) == retval::CATCH_FAILED);
|
||||
REQUIRE(ringBuffer.getFreeElement(&testPtr, 5) == retval::CATCH_OK);
|
||||
REQUIRE(ringBuffer.getExcessBytes() == 3);
|
||||
std::memcpy(testPtr, testData, 5);
|
||||
ringBuffer.confirmBytesWritten(5);
|
||||
REQUIRE(ringBuffer.getAvailableReadData() == 5);
|
||||
ringBuffer.readData(readBuffer, 5, true);
|
||||
for(uint8_t i = 0; i< 5; i++) {
|
||||
CHECK(readBuffer[i] == i);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("Read Remaining Test") {
|
||||
REQUIRE(ringBuffer.writeData(testData, 3) == retval::CATCH_OK);
|
||||
REQUIRE(ringBuffer.getAvailableReadData() == 3);
|
||||
REQUIRE(ringBuffer.readData(readBuffer, 5, false, false, nullptr) == retval::CATCH_FAILED);
|
||||
size_t trueSize = 0;
|
||||
REQUIRE(ringBuffer.readData(readBuffer, 5, false, true, &trueSize) == retval::CATCH_OK);
|
||||
REQUIRE(trueSize == 3);
|
||||
for(uint8_t i = 0; i< 3; i++) {
|
||||
CHECK(readBuffer[i] == i);
|
||||
}
|
||||
trueSize = 0;
|
||||
REQUIRE(ringBuffer.deleteData(5, false, &trueSize) == retval::CATCH_FAILED);
|
||||
REQUIRE(trueSize == 0);
|
||||
REQUIRE(ringBuffer.deleteData(5, true, &trueSize) == retval::CATCH_OK);
|
||||
REQUIRE(trueSize == 3);
|
||||
}
|
||||
|
||||
SECTION("Overflow"){
|
||||
REQUIRE(ringBuffer.availableWriteSpace()==9);
|
||||
//Writing more than the buffer is large, technically thats allowed
|
||||
//But it is senseless and has undesired impact on read call
|
||||
REQUIRE(ringBuffer.writeData(testData, 13) == retval::CATCH_OK);
|
||||
REQUIRE(ringBuffer.getAvailableReadData()==3);
|
||||
ringBuffer.clear();
|
||||
uint8_t * ptr = nullptr;
|
||||
REQUIRE(ringBuffer.getFreeElement(&ptr, 13) == retval::CATCH_OK);
|
||||
REQUIRE(ptr != nullptr);
|
||||
memcpy(ptr, testData, 13);
|
||||
ringBuffer.confirmBytesWritten(13);
|
||||
REQUIRE(ringBuffer.getAvailableReadData()==3);
|
||||
REQUIRE(ringBuffer.readData(readBuffer, 3, true)== retval::CATCH_OK);
|
||||
for(auto i =0;i<3;i++){
|
||||
REQUIRE(readBuffer[i] == testData[i+10]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("Ring Buffer Test3" , "[RingBufferTest3]") {
|
||||
uint8_t testData[13]= {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
|
||||
uint8_t readBuffer[10] = {13, 13, 13, 13, 13, 13, 13, 13, 13, 13};
|
||||
uint8_t* newBuffer = new uint8_t[10];
|
||||
SimpleRingBuffer ringBuffer(newBuffer, 10, true, 15);
|
||||
|
||||
SECTION("Simple Test") {
|
||||
REQUIRE(ringBuffer.availableWriteSpace() == 9);
|
||||
REQUIRE(ringBuffer.writeData(testData, 9) == retval::CATCH_OK);
|
||||
REQUIRE(ringBuffer.readData(readBuffer, 5, true) == retval::CATCH_OK);
|
||||
for(uint8_t i = 0; i< 5; i++) {
|
||||
CHECK(readBuffer[i] == i);
|
||||
}
|
||||
REQUIRE(ringBuffer.availableWriteSpace() == 5);
|
||||
ringBuffer.clear();
|
||||
REQUIRE(ringBuffer.availableWriteSpace() == 9);
|
||||
REQUIRE(ringBuffer.writeData(testData, 4) == retval::CATCH_OK);
|
||||
REQUIRE(ringBuffer.readData(readBuffer, 4, true) == retval::CATCH_OK);
|
||||
for(uint8_t i = 0; i< 4; i++) {
|
||||
CHECK(readBuffer[i] == i);
|
||||
}
|
||||
REQUIRE(ringBuffer.writeData(testData, 9) == retval::CATCH_OK);
|
||||
REQUIRE(ringBuffer.readData(readBuffer, 9, true) == retval::CATCH_OK);
|
||||
for(uint8_t i = 0; i< 9; i++) {
|
||||
CHECK(readBuffer[i] == i);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
SECTION("Get Free Element Test") {
|
||||
REQUIRE(ringBuffer.availableWriteSpace() == 9);
|
||||
REQUIRE(ringBuffer.writeData(testData, 8) == retval::CATCH_OK);
|
||||
REQUIRE(ringBuffer.availableWriteSpace() == 1);
|
||||
REQUIRE(ringBuffer.readData(readBuffer, 8, true) == retval::CATCH_OK);
|
||||
REQUIRE(ringBuffer.availableWriteSpace() == 9);
|
||||
uint8_t *testPtr = nullptr;
|
||||
REQUIRE(ringBuffer.getFreeElement(&testPtr, 10) == retval::CATCH_OK);
|
||||
REQUIRE(ringBuffer.getExcessBytes() == 8);
|
||||
|
||||
REQUIRE(ringBuffer.writeTillWrap() == 2);
|
||||
// too many excess bytes.
|
||||
REQUIRE(ringBuffer.getFreeElement(&testPtr, 8) == retval::CATCH_FAILED);
|
||||
// Less Execss bytes overwrites before
|
||||
REQUIRE(ringBuffer.getFreeElement(&testPtr, 3) == retval::CATCH_OK);
|
||||
REQUIRE(ringBuffer.getExcessBytes() == 1);
|
||||
std::memcpy(testPtr, testData, 3);
|
||||
ringBuffer.confirmBytesWritten(3);
|
||||
REQUIRE(ringBuffer.getAvailableReadData() == 3);
|
||||
ringBuffer.readData(readBuffer, 3, true);
|
||||
for(uint8_t i = 0; i< 3; i++) {
|
||||
CHECK(readBuffer[i] == i);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("Read Remaining Test") {
|
||||
REQUIRE(ringBuffer.writeData(testData, 3) == retval::CATCH_OK);
|
||||
REQUIRE(ringBuffer.getAvailableReadData() == 3);
|
||||
REQUIRE(ringBuffer.readData(readBuffer, 5, false, false, nullptr) == retval::CATCH_FAILED);
|
||||
size_t trueSize = 0;
|
||||
REQUIRE(ringBuffer.readData(readBuffer, 5, false, true, &trueSize) == retval::CATCH_OK);
|
||||
REQUIRE(trueSize == 3);
|
||||
for(uint8_t i = 0; i< 3; i++) {
|
||||
CHECK(readBuffer[i] == i);
|
||||
}
|
||||
trueSize = 0;
|
||||
REQUIRE(ringBuffer.deleteData(5, false, &trueSize) == retval::CATCH_FAILED);
|
||||
REQUIRE(trueSize == 0);
|
||||
REQUIRE(ringBuffer.deleteData(5, true, &trueSize) == retval::CATCH_OK);
|
||||
REQUIRE(trueSize == 3);
|
||||
}
|
||||
|
||||
SECTION("Overflow"){
|
||||
REQUIRE(ringBuffer.availableWriteSpace()==9);
|
||||
//Writing more than the buffer is large, technically thats allowed
|
||||
//But it is senseless and has undesired impact on read call
|
||||
REQUIRE(ringBuffer.writeData(testData, 13) == retval::CATCH_OK);
|
||||
REQUIRE(ringBuffer.getAvailableReadData()==3);
|
||||
ringBuffer.clear();
|
||||
uint8_t * ptr = nullptr;
|
||||
REQUIRE(ringBuffer.getFreeElement(&ptr, 13) == retval::CATCH_OK);
|
||||
REQUIRE(ptr != nullptr);
|
||||
memcpy(ptr, testData, 13);
|
||||
ringBuffer.confirmBytesWritten(13);
|
||||
REQUIRE(ringBuffer.getAvailableReadData()==3);
|
||||
REQUIRE(ringBuffer.readData(readBuffer, 3, true)== retval::CATCH_OK);
|
||||
for(auto i =0;i<3;i++){
|
||||
REQUIRE(readBuffer[i] == testData[i+10]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("Ring Buffer Test4" , "[RingBufferTest4]") {
|
||||
uint8_t testData[13]= {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
|
||||
uint8_t readBuffer[10] = {13, 13, 13, 13, 13, 13, 13, 13, 13, 13};
|
||||
SimpleRingBuffer ringBuffer(10, false, 15);
|
||||
|
||||
SECTION("Simple Test") {
|
||||
REQUIRE(ringBuffer.availableWriteSpace() == 9);
|
||||
REQUIRE(ringBuffer.writeData(testData, 9) == retval::CATCH_OK);
|
||||
REQUIRE(ringBuffer.writeData(testData, 3) == retval::CATCH_FAILED);
|
||||
REQUIRE(ringBuffer.readData(readBuffer, 5, true) == retval::CATCH_OK);
|
||||
for(uint8_t i = 0; i< 5; i++) {
|
||||
CHECK(readBuffer[i] == i);
|
||||
}
|
||||
REQUIRE(ringBuffer.availableWriteSpace() == 5);
|
||||
ringBuffer.clear();
|
||||
REQUIRE(ringBuffer.availableWriteSpace() == 9);
|
||||
REQUIRE(ringBuffer.writeData(testData, 4) == retval::CATCH_OK);
|
||||
REQUIRE(ringBuffer.readData(readBuffer, 4, true) == retval::CATCH_OK);
|
||||
for(uint8_t i = 0; i< 4; i++) {
|
||||
CHECK(readBuffer[i] == i);
|
||||
}
|
||||
REQUIRE(ringBuffer.writeData(testData, 9) == retval::CATCH_OK);
|
||||
REQUIRE(ringBuffer.readData(readBuffer, 9, true) == retval::CATCH_OK);
|
||||
for(uint8_t i = 0; i< 9; i++) {
|
||||
CHECK(readBuffer[i] == i);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
SECTION("Get Free Element Test") {
|
||||
REQUIRE(ringBuffer.availableWriteSpace() == 9);
|
||||
REQUIRE(ringBuffer.writeData(testData, 8) == retval::CATCH_OK);
|
||||
REQUIRE(ringBuffer.availableWriteSpace() == 1);
|
||||
REQUIRE(ringBuffer.readData(readBuffer, 8, true) == retval::CATCH_OK);
|
||||
REQUIRE(ringBuffer.availableWriteSpace() == 9);
|
||||
uint8_t *testPtr = nullptr;
|
||||
REQUIRE(ringBuffer.getFreeElement(&testPtr, 10) == retval::CATCH_FAILED);
|
||||
|
||||
|
||||
REQUIRE(ringBuffer.writeTillWrap() == 2);
|
||||
REQUIRE(ringBuffer.getFreeElement(&testPtr, 8) == retval::CATCH_OK);
|
||||
REQUIRE(ringBuffer.getFreeElement(&testPtr, 5) == retval::CATCH_OK);
|
||||
REQUIRE(ringBuffer.getExcessBytes() == 3);
|
||||
std::memcpy(testPtr, testData, 5);
|
||||
ringBuffer.confirmBytesWritten(5);
|
||||
REQUIRE(ringBuffer.getAvailableReadData() == 5);
|
||||
ringBuffer.readData(readBuffer, 5, true);
|
||||
for(uint8_t i = 0; i< 5; i++) {
|
||||
CHECK(readBuffer[i] == i);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("Read Remaining Test") {
|
||||
REQUIRE(ringBuffer.writeData(testData, 3) == retval::CATCH_OK);
|
||||
REQUIRE(ringBuffer.getAvailableReadData() == 3);
|
||||
REQUIRE(ringBuffer.readData(readBuffer, 5, false, false, nullptr) == retval::CATCH_FAILED);
|
||||
size_t trueSize = 0;
|
||||
REQUIRE(ringBuffer.readData(readBuffer, 5, false, true, &trueSize) == retval::CATCH_OK);
|
||||
REQUIRE(trueSize == 3);
|
||||
for(uint8_t i = 0; i< 3; i++) {
|
||||
CHECK(readBuffer[i] == i);
|
||||
}
|
||||
trueSize = 0;
|
||||
REQUIRE(ringBuffer.deleteData(5, false, &trueSize) == retval::CATCH_FAILED);
|
||||
REQUIRE(trueSize == 0);
|
||||
REQUIRE(ringBuffer.deleteData(5, true, &trueSize) == retval::CATCH_OK);
|
||||
REQUIRE(trueSize == 3);
|
||||
}
|
||||
}
|
90
unittest/tests/container/TestArrayList.cpp
Normal file
90
unittest/tests/container/TestArrayList.cpp
Normal file
@ -0,0 +1,90 @@
|
||||
#include <fsfw/container/ArrayList.h>
|
||||
#include <fsfw/returnvalues/HasReturnvaluesIF.h>
|
||||
#include <catch2/catch.hpp>
|
||||
#include "../../core/CatchDefinitions.h"
|
||||
|
||||
/**
|
||||
* @brief Array List test
|
||||
*/
|
||||
TEST_CASE("Array List" , "[ArrayListTest]") {
|
||||
//perform set-up here
|
||||
ArrayList<uint16_t> list(20);
|
||||
struct TestClass{
|
||||
public:
|
||||
TestClass(){};
|
||||
TestClass(uint32_t number1, uint64_t number2):
|
||||
number1(number1), number2(number2){};
|
||||
uint32_t number1 = -1;
|
||||
uint64_t number2 = -1;
|
||||
bool operator==(const TestClass& other){
|
||||
return ((this->number1 == other.number1) and (this->number2 == other.number2));
|
||||
};
|
||||
};
|
||||
ArrayList<TestClass> complexList(20);
|
||||
SECTION("SimpleTest") {
|
||||
REQUIRE(list.maxSize()==20);
|
||||
REQUIRE(list.size == 0);
|
||||
REQUIRE(list.insert(10) == static_cast<int>(HasReturnvaluesIF::RETURN_OK));
|
||||
REQUIRE(list[0] == 10);
|
||||
REQUIRE(list.front() != nullptr);
|
||||
REQUIRE((*list.front()) == 10);
|
||||
REQUIRE(list.back() != nullptr);
|
||||
REQUIRE((*list.back()) == 10);
|
||||
// Need to test the const version of back as well
|
||||
const uint16_t* number = const_cast<const ArrayList<uint16_t>*>(&list)->back();
|
||||
REQUIRE(*number == 10);
|
||||
list.clear();
|
||||
REQUIRE(list.size == 0);
|
||||
}
|
||||
SECTION("Fill and check"){
|
||||
//This is an invalid element but its not a nullptr
|
||||
REQUIRE(list.back() != nullptr);
|
||||
for (auto i =0; i < 20; i++){
|
||||
REQUIRE(list.insert(i) == static_cast<int>(HasReturnvaluesIF::RETURN_OK));
|
||||
}
|
||||
REQUIRE(list.insert(20) == static_cast<int>(ArrayList<uint16_t>::FULL));
|
||||
ArrayList<uint16_t>::Iterator it = list.begin();
|
||||
REQUIRE((*it) == 0);
|
||||
it++;
|
||||
REQUIRE((*it) == 1);
|
||||
it--;
|
||||
REQUIRE((*it) == 0);
|
||||
it++;
|
||||
for(auto it2 = list.begin(); it2!=list.end(); it2++){
|
||||
if (it == it2){
|
||||
REQUIRE((*it) == (*it2));
|
||||
break;
|
||||
}else{
|
||||
REQUIRE((*it2) == 0);
|
||||
REQUIRE(it2 != it);
|
||||
}
|
||||
}
|
||||
}
|
||||
SECTION("Const Iterator"){
|
||||
ArrayList<uint16_t>::Iterator it = list.begin();
|
||||
for (auto i =0; i < 10; i++){
|
||||
REQUIRE(list.insert(i) == static_cast<int>(HasReturnvaluesIF::RETURN_OK));
|
||||
}
|
||||
it++;
|
||||
const uint16_t* number = it.value;
|
||||
REQUIRE(*number == 1);
|
||||
}
|
||||
|
||||
SECTION("Const Iterator"){
|
||||
ArrayList<TestClass>::Iterator it = complexList.begin();
|
||||
for (auto i =0; i < 10; i++){
|
||||
REQUIRE(complexList.insert(TestClass(i, i+1)) == static_cast<int>(HasReturnvaluesIF::RETURN_OK));
|
||||
}
|
||||
it++;
|
||||
const TestClass* secondTest = it.value;
|
||||
bool compare = TestClass(1, 2) == *secondTest;
|
||||
REQUIRE(compare);
|
||||
it++;
|
||||
REQUIRE(it->number1 == 2);
|
||||
REQUIRE(it->number2 == 3);
|
||||
const ArrayList<TestClass>::Iterator it4(&(complexList[2]));
|
||||
REQUIRE(it4->number1 == 2);
|
||||
REQUIRE((*it4).number2 == 3);
|
||||
REQUIRE(complexList.remaining()==10);
|
||||
}
|
||||
}
|
149
unittest/tests/container/TestDynamicFifo.cpp
Normal file
149
unittest/tests/container/TestDynamicFifo.cpp
Normal file
@ -0,0 +1,149 @@
|
||||
|
||||
#include <fsfw/container/DynamicFIFO.h>
|
||||
#include <fsfw/container/FIFO.h>
|
||||
#include <fsfw/returnvalues/HasReturnvaluesIF.h>
|
||||
|
||||
#include <catch.hpp>
|
||||
#include <CatchDefinitions.h>
|
||||
|
||||
TEST_CASE( "Dynamic Fifo Tests", "[TestDynamicFifo]") {
|
||||
INFO("Dynamic Fifo Tests");
|
||||
struct Test{
|
||||
uint64_t number1;
|
||||
uint32_t number2;
|
||||
uint8_t number3;
|
||||
bool operator==(struct Test& other){
|
||||
if ((other.number1 == this->number1) and
|
||||
(other.number1 == this->number1) and
|
||||
(other.number1 == this->number1)){
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
DynamicFIFO<Test> fifo(3);
|
||||
std::vector<Test> list;
|
||||
|
||||
struct Test structOne({UINT64_MAX, UINT32_MAX, UINT8_MAX});
|
||||
struct Test structTwo({0, 1, 2});
|
||||
struct Test structThree({42, 43, 44});
|
||||
list.push_back(structThree);
|
||||
list.push_back(structTwo);
|
||||
list.push_back(structOne);
|
||||
SECTION("Insert, retrieval test"){
|
||||
REQUIRE(fifo.getMaxCapacity()==3);
|
||||
REQUIRE(fifo.size()==0);
|
||||
REQUIRE(fifo.empty());
|
||||
REQUIRE(not fifo.full());
|
||||
|
||||
REQUIRE(fifo.insert(structOne)==static_cast<int>(HasReturnvaluesIF::RETURN_OK));
|
||||
REQUIRE(fifo.insert(structTwo)==static_cast<int>(HasReturnvaluesIF::RETURN_OK));
|
||||
REQUIRE(fifo.insert(structThree)==static_cast<int>(HasReturnvaluesIF::RETURN_OK));
|
||||
REQUIRE(fifo.insert(structTwo)==static_cast<int>(FIFOBase<Test>::FULL));
|
||||
|
||||
struct Test testptr;
|
||||
REQUIRE(fifo.peek(&testptr)==static_cast<int>(HasReturnvaluesIF::RETURN_OK));
|
||||
bool equal = testptr == structOne;
|
||||
REQUIRE(equal);
|
||||
REQUIRE(fifo.size()==3);
|
||||
REQUIRE(fifo.full());
|
||||
REQUIRE(not fifo.empty());
|
||||
|
||||
for(size_t i=2;i<3;i--){
|
||||
testptr.number1 = 0;
|
||||
testptr.number2 = 0;
|
||||
testptr.number3 = 0;
|
||||
REQUIRE(fifo.retrieve(&testptr)==static_cast<int>(HasReturnvaluesIF::RETURN_OK));
|
||||
equal = testptr == list[i];
|
||||
REQUIRE(equal);
|
||||
REQUIRE(fifo.size()==i);
|
||||
}
|
||||
testptr.number1 = 0;
|
||||
testptr.number2 = 0;
|
||||
testptr.number3 = 0;
|
||||
REQUIRE(fifo.retrieve(&testptr)==static_cast<int>(FIFOBase<Test>::EMPTY));
|
||||
REQUIRE(fifo.peek(&testptr)==static_cast<int>(FIFOBase<Test>::EMPTY));
|
||||
REQUIRE(not fifo.full());
|
||||
REQUIRE(fifo.empty());
|
||||
REQUIRE(fifo.pop()==static_cast<int>(FIFOBase<Test>::EMPTY));
|
||||
|
||||
REQUIRE(fifo.insert(structOne)==static_cast<int>(HasReturnvaluesIF::RETURN_OK));
|
||||
REQUIRE(fifo.size()==1);
|
||||
REQUIRE(fifo.insert(structTwo)==static_cast<int>(HasReturnvaluesIF::RETURN_OK));
|
||||
REQUIRE(fifo.size()==2);
|
||||
REQUIRE(fifo.pop()==static_cast<int>(HasReturnvaluesIF::RETURN_OK));
|
||||
REQUIRE(fifo.size()==1);
|
||||
testptr.number1 = 0;
|
||||
testptr.number2 = 0;
|
||||
testptr.number3 = 0;
|
||||
REQUIRE(fifo.peek(&testptr)==static_cast<int>(HasReturnvaluesIF::RETURN_OK));
|
||||
equal = testptr == structTwo;
|
||||
REQUIRE(equal);
|
||||
REQUIRE(fifo.pop()==static_cast<int>(HasReturnvaluesIF::RETURN_OK));
|
||||
REQUIRE(fifo.size()==0);
|
||||
REQUIRE(fifo.empty());
|
||||
//struct Test* ptr = nullptr;
|
||||
//REQUIRE(fifo.retrieve(ptr) == static_cast<int>(HasReturnvaluesIF::RETURN_FAILED));
|
||||
//REQUIRE(fifo.peek(ptr) == static_cast<int>(HasReturnvaluesIF::RETURN_FAILED));
|
||||
};
|
||||
SECTION("Copy Test"){
|
||||
REQUIRE(fifo.insert(structOne)==static_cast<int>(HasReturnvaluesIF::RETURN_OK));
|
||||
REQUIRE(fifo.insert(structTwo)==static_cast<int>(HasReturnvaluesIF::RETURN_OK));
|
||||
REQUIRE(fifo.insert(structThree)==static_cast<int>(HasReturnvaluesIF::RETURN_OK));
|
||||
REQUIRE(fifo.size()==3);
|
||||
REQUIRE(fifo.full());
|
||||
REQUIRE(not fifo.empty());
|
||||
|
||||
DynamicFIFO<Test> fifo2(fifo);
|
||||
REQUIRE(fifo2.size()==3);
|
||||
REQUIRE(fifo2.full());
|
||||
REQUIRE(not fifo2.empty());
|
||||
|
||||
};
|
||||
|
||||
SECTION("Assignment Test"){
|
||||
REQUIRE(fifo.insert(structOne)==static_cast<int>(HasReturnvaluesIF::RETURN_OK));
|
||||
REQUIRE(fifo.insert(structTwo)==static_cast<int>(HasReturnvaluesIF::RETURN_OK));
|
||||
REQUIRE(fifo.insert(structThree)==static_cast<int>(HasReturnvaluesIF::RETURN_OK));
|
||||
REQUIRE(fifo.size()==3);
|
||||
REQUIRE(fifo.full());
|
||||
REQUIRE(not fifo.empty());
|
||||
|
||||
DynamicFIFO<Test> fifo2(6);
|
||||
fifo2 = fifo;
|
||||
REQUIRE(fifo2.size()==3);
|
||||
REQUIRE(fifo2.full());
|
||||
REQUIRE(not fifo2.empty());
|
||||
for(size_t i=2;i<3;i--){
|
||||
struct Test testptr = {0, 0, 0};
|
||||
REQUIRE(fifo2.retrieve(&testptr)==static_cast<int>(HasReturnvaluesIF::RETURN_OK));
|
||||
bool equal = testptr == list[i];
|
||||
REQUIRE(equal);
|
||||
REQUIRE(fifo2.size()==i);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
SECTION("Assignment Test Smaller"){
|
||||
REQUIRE(fifo.insert(structOne)==static_cast<int>(HasReturnvaluesIF::RETURN_OK));
|
||||
REQUIRE(fifo.insert(structTwo)==static_cast<int>(HasReturnvaluesIF::RETURN_OK));
|
||||
REQUIRE(fifo.insert(structThree)==static_cast<int>(HasReturnvaluesIF::RETURN_OK));
|
||||
REQUIRE(fifo.size()==3);
|
||||
REQUIRE(fifo.full());
|
||||
REQUIRE(not fifo.empty());
|
||||
|
||||
DynamicFIFO<Test> fifo2(2);
|
||||
fifo2 = fifo;
|
||||
REQUIRE(fifo2.size()==3);
|
||||
REQUIRE(fifo2.full());
|
||||
REQUIRE(not fifo2.empty());
|
||||
for(size_t i=2;i<3;i--){
|
||||
struct Test testptr = {0, 0, 0};
|
||||
REQUIRE(fifo2.retrieve(&testptr)==static_cast<int>(HasReturnvaluesIF::RETURN_OK));
|
||||
bool equal = testptr == list[i];
|
||||
REQUIRE(equal);
|
||||
REQUIRE(fifo2.size()==i);
|
||||
}
|
||||
};
|
||||
|
||||
};
|
138
unittest/tests/container/TestFifo.cpp
Normal file
138
unittest/tests/container/TestFifo.cpp
Normal file
@ -0,0 +1,138 @@
|
||||
|
||||
#include <fsfw/container/DynamicFIFO.h>
|
||||
#include <fsfw/container/FIFO.h>
|
||||
#include <fsfw/returnvalues/HasReturnvaluesIF.h>
|
||||
|
||||
#include <catch2/catch.hpp>
|
||||
#include "../../core/CatchDefinitions.h"
|
||||
|
||||
TEST_CASE( "Static Fifo Tests", "[TestFifo]") {
|
||||
INFO("Fifo Tests");
|
||||
struct Test{
|
||||
uint64_t number1;
|
||||
uint32_t number2;
|
||||
uint8_t number3;
|
||||
bool operator==(struct Test& other){
|
||||
if ((other.number1 == this->number1) and
|
||||
(other.number1 == this->number1) and
|
||||
(other.number1 == this->number1)){
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
FIFO<Test, 3> fifo;
|
||||
std::vector<Test> list;
|
||||
|
||||
struct Test structOne({UINT64_MAX, UINT32_MAX, UINT8_MAX});
|
||||
struct Test structTwo({0, 1, 2});
|
||||
struct Test structThree({42, 43, 44});
|
||||
list.push_back(structThree);
|
||||
list.push_back(structTwo);
|
||||
list.push_back(structOne);
|
||||
SECTION("Insert, retrieval test"){
|
||||
REQUIRE(fifo.getMaxCapacity()==3);
|
||||
REQUIRE(fifo.size()==0);
|
||||
REQUIRE(fifo.empty());
|
||||
REQUIRE(not fifo.full());
|
||||
|
||||
REQUIRE(fifo.insert(structOne)==static_cast<int>(HasReturnvaluesIF::RETURN_OK));
|
||||
REQUIRE(fifo.insert(structTwo)==static_cast<int>(HasReturnvaluesIF::RETURN_OK));
|
||||
REQUIRE(fifo.insert(structThree)==static_cast<int>(HasReturnvaluesIF::RETURN_OK));
|
||||
REQUIRE(fifo.insert(structTwo)==static_cast<int>(FIFOBase<Test>::FULL));
|
||||
|
||||
struct Test testptr;
|
||||
REQUIRE(fifo.peek(&testptr)==static_cast<int>(HasReturnvaluesIF::RETURN_OK));
|
||||
bool equal = testptr == structOne;
|
||||
REQUIRE(equal);
|
||||
REQUIRE(fifo.size()==3);
|
||||
REQUIRE(fifo.full());
|
||||
REQUIRE(not fifo.empty());
|
||||
|
||||
for(size_t i=2;i<3;i--){
|
||||
testptr.number1 = 0;
|
||||
testptr.number2 = 0;
|
||||
testptr.number3 = 0;
|
||||
REQUIRE(fifo.retrieve(&testptr)==static_cast<int>(HasReturnvaluesIF::RETURN_OK));
|
||||
equal = testptr == list[i];
|
||||
REQUIRE(equal);
|
||||
REQUIRE(fifo.size()==i);
|
||||
}
|
||||
testptr.number1 = 0;
|
||||
testptr.number2 = 0;
|
||||
testptr.number3 = 0;
|
||||
REQUIRE(fifo.retrieve(&testptr)==static_cast<int>(FIFOBase<Test>::EMPTY));
|
||||
REQUIRE(fifo.peek(&testptr)==static_cast<int>(FIFOBase<Test>::EMPTY));
|
||||
REQUIRE(not fifo.full());
|
||||
REQUIRE(fifo.empty());
|
||||
REQUIRE(fifo.pop()==static_cast<int>(FIFOBase<Test>::EMPTY));
|
||||
|
||||
REQUIRE(fifo.insert(structOne)==static_cast<int>(HasReturnvaluesIF::RETURN_OK));
|
||||
REQUIRE(fifo.size()==1);
|
||||
REQUIRE(fifo.insert(structTwo)==static_cast<int>(HasReturnvaluesIF::RETURN_OK));
|
||||
REQUIRE(fifo.size()==2);
|
||||
REQUIRE(fifo.pop()==static_cast<int>(HasReturnvaluesIF::RETURN_OK));
|
||||
REQUIRE(fifo.size()==1);
|
||||
testptr.number1 = 0;
|
||||
testptr.number2 = 0;
|
||||
testptr.number3 = 0;
|
||||
|
||||
// Test that retrieve and peek will not cause a nullptr dereference
|
||||
struct Test* ptr = nullptr;
|
||||
REQUIRE(fifo.retrieve(ptr) == static_cast<int>(HasReturnvaluesIF::RETURN_FAILED));
|
||||
REQUIRE(fifo.peek(ptr) == static_cast<int>(HasReturnvaluesIF::RETURN_FAILED));
|
||||
|
||||
|
||||
REQUIRE(fifo.peek(&testptr)==static_cast<int>(HasReturnvaluesIF::RETURN_OK));
|
||||
equal = testptr == structTwo;
|
||||
REQUIRE(equal);
|
||||
REQUIRE(fifo.pop()==static_cast<int>(HasReturnvaluesIF::RETURN_OK));
|
||||
REQUIRE(fifo.size()==0);
|
||||
REQUIRE(fifo.empty());
|
||||
|
||||
|
||||
};
|
||||
SECTION("Copy Test"){
|
||||
REQUIRE(fifo.insert(structOne)==static_cast<int>(HasReturnvaluesIF::RETURN_OK));
|
||||
REQUIRE(fifo.insert(structTwo)==static_cast<int>(HasReturnvaluesIF::RETURN_OK));
|
||||
REQUIRE(fifo.insert(structThree)==static_cast<int>(HasReturnvaluesIF::RETURN_OK));
|
||||
REQUIRE(fifo.size()==3);
|
||||
REQUIRE(fifo.full());
|
||||
REQUIRE(not fifo.empty());
|
||||
|
||||
FIFO<Test, 3> fifo2(fifo);
|
||||
REQUIRE(fifo2.size()==3);
|
||||
REQUIRE(fifo2.full());
|
||||
REQUIRE(not fifo2.empty());
|
||||
for(size_t i=2;i<3;i--){
|
||||
struct Test testptr = {0, 0, 0};
|
||||
REQUIRE(fifo2.retrieve(&testptr)==static_cast<int>(HasReturnvaluesIF::RETURN_OK));
|
||||
bool equal = testptr == list[i];
|
||||
REQUIRE(equal);
|
||||
REQUIRE(fifo2.size()==i);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
SECTION("Assignment Test"){
|
||||
REQUIRE(fifo.insert(structOne)==static_cast<int>(HasReturnvaluesIF::RETURN_OK));
|
||||
REQUIRE(fifo.insert(structTwo)==static_cast<int>(HasReturnvaluesIF::RETURN_OK));
|
||||
REQUIRE(fifo.insert(structThree)==static_cast<int>(HasReturnvaluesIF::RETURN_OK));
|
||||
REQUIRE(fifo.size()==3);
|
||||
REQUIRE(fifo.full());
|
||||
REQUIRE(not fifo.empty());
|
||||
|
||||
FIFO<Test, 3> fifo2;
|
||||
fifo2 = fifo;
|
||||
REQUIRE(fifo2.size()==3);
|
||||
REQUIRE(fifo2.full());
|
||||
REQUIRE(not fifo2.empty());
|
||||
for(size_t i=2;i<3;i--){
|
||||
struct Test testptr = {0, 0, 0};
|
||||
REQUIRE(fifo2.retrieve(&testptr)==static_cast<int>(HasReturnvaluesIF::RETURN_OK));
|
||||
bool equal = testptr == list[i];
|
||||
REQUIRE(equal);
|
||||
REQUIRE(fifo2.size()==i);
|
||||
}
|
||||
};
|
||||
};
|
42
unittest/tests/container/TestFixedArrayList.cpp
Normal file
42
unittest/tests/container/TestFixedArrayList.cpp
Normal file
@ -0,0 +1,42 @@
|
||||
#include "../../core/CatchDefinitions.h"
|
||||
|
||||
#include <fsfw/container/FixedArrayList.h>
|
||||
#include <fsfw/returnvalues/HasReturnvaluesIF.h>
|
||||
|
||||
#include <catch2/catch.hpp>
|
||||
|
||||
|
||||
TEST_CASE( "FixedArrayList Tests", "[TestFixedArrayList]") {
|
||||
INFO("FixedArrayList Tests");
|
||||
using testList = FixedArrayList<uint32_t, 260, uint16_t>;
|
||||
testList list;
|
||||
REQUIRE(list.size==0);
|
||||
REQUIRE(list.insert(10) == static_cast<int>(HasReturnvaluesIF::RETURN_OK));
|
||||
REQUIRE(list.size==1);
|
||||
REQUIRE(list.maxSize()==260);
|
||||
SECTION("Copy Constructor"){
|
||||
testList list2(list);
|
||||
REQUIRE(list2.size==1);
|
||||
REQUIRE(list2[0] == 10);
|
||||
REQUIRE(list.maxSize()==260);
|
||||
};
|
||||
SECTION("Assignment copy"){
|
||||
testList list2;
|
||||
REQUIRE(list2.size==0);
|
||||
list2 = list;
|
||||
REQUIRE(list2.size==1);
|
||||
REQUIRE(list2[0] == 10);
|
||||
REQUIRE(list.maxSize()==260);
|
||||
};
|
||||
SECTION("Fill"){
|
||||
for(auto i=1;i<260;i++){
|
||||
REQUIRE(list.insert(i) == static_cast<int>(HasReturnvaluesIF::RETURN_OK));
|
||||
}
|
||||
REQUIRE(list.insert(260) == static_cast<int>(ArrayList<uint32_t, uint16_t>::FULL));
|
||||
list.clear();
|
||||
REQUIRE(list.size == 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
172
unittest/tests/container/TestFixedMap.cpp
Normal file
172
unittest/tests/container/TestFixedMap.cpp
Normal file
@ -0,0 +1,172 @@
|
||||
#include <fsfw/container/FixedMap.h>
|
||||
#include <fsfw/returnvalues/HasReturnvaluesIF.h>
|
||||
|
||||
#include <catch2/catch.hpp>
|
||||
#include "../../core/CatchDefinitions.h"
|
||||
|
||||
template class FixedMap<unsigned int, unsigned short>;
|
||||
|
||||
TEST_CASE( "FixedMap Tests", "[TestFixedMap]") {
|
||||
INFO("FixedMap Tests");
|
||||
|
||||
FixedMap<unsigned int, unsigned short> map(30);
|
||||
REQUIRE(map.size() == 0);
|
||||
REQUIRE(map.maxSize() == 30);
|
||||
REQUIRE(map.getSerializedSize() == sizeof(uint32_t));
|
||||
REQUIRE(map.empty());
|
||||
REQUIRE(not map.full());
|
||||
|
||||
SECTION("Fill and erase"){
|
||||
for (uint16_t i=0;i<30;i++){
|
||||
REQUIRE(map.insert(std::make_pair(i, i+1))== static_cast<int>(HasReturnvaluesIF::RETURN_OK));
|
||||
REQUIRE(map.exists(i) == static_cast<int>(HasReturnvaluesIF::RETURN_OK));
|
||||
REQUIRE(map.find(i)->second==i+1);
|
||||
REQUIRE(not map.empty());
|
||||
}
|
||||
REQUIRE(map.insert(0, 0) == static_cast<int>(FixedMap<uint32_t, uint16_t>::KEY_ALREADY_EXISTS));
|
||||
REQUIRE(map.insert(31, 0) == static_cast<int>(FixedMap<uint32_t, uint16_t>::MAP_FULL));
|
||||
REQUIRE(map.exists(31) == static_cast<int>(FixedMap<uint32_t, uint16_t>::KEY_DOES_NOT_EXIST));
|
||||
REQUIRE(map.size() == 30);
|
||||
REQUIRE(map.full());
|
||||
{
|
||||
uint16_t* ptr;
|
||||
REQUIRE(map.find(5,&ptr) == static_cast<int>(HasReturnvaluesIF::RETURN_OK));
|
||||
REQUIRE(*ptr == 6);
|
||||
REQUIRE(*(map.findValue(6)) == 7);
|
||||
REQUIRE(map.find(31,&ptr) == static_cast<int>(FixedMap<uint32_t, uint16_t>::KEY_DOES_NOT_EXIST));
|
||||
}
|
||||
|
||||
REQUIRE(map.getSerializedSize() == (sizeof(uint32_t)+ 30*(sizeof(uint32_t) + sizeof(uint16_t))));
|
||||
REQUIRE(map.erase(2) == static_cast<int>(HasReturnvaluesIF::RETURN_OK));
|
||||
REQUIRE(map.erase(31) == static_cast<int>(FixedMap<uint32_t, uint16_t>::KEY_DOES_NOT_EXIST));
|
||||
REQUIRE(map.exists(2) == static_cast<int>(FixedMap<uint32_t, uint16_t>::KEY_DOES_NOT_EXIST));
|
||||
REQUIRE(map.size() == 29);
|
||||
|
||||
for (auto element: map){
|
||||
if (element.first == 5){
|
||||
REQUIRE(element.second == 6);
|
||||
}
|
||||
}
|
||||
|
||||
for (FixedMap<uint32_t, uint16_t>::Iterator it = map.begin(); it != map.end(); it++){
|
||||
REQUIRE(it->second == it->first + 1);
|
||||
REQUIRE((*it).second == (*it).first + 1);
|
||||
it->second = it->second + 1;
|
||||
REQUIRE(it->second == it->first + 2);
|
||||
}
|
||||
|
||||
for (FixedMap<uint32_t, uint16_t>::Iterator it = map.begin(); it != map.end(); it++){
|
||||
REQUIRE(map.erase(&it) == static_cast<int>(HasReturnvaluesIF::RETURN_OK));
|
||||
}
|
||||
|
||||
REQUIRE(map.size() == 0);
|
||||
|
||||
for (FixedMap<uint32_t, uint16_t>::Iterator it = map.begin(); it != map.end(); it++){
|
||||
// This line should never executed if begin and end is correct
|
||||
FAIL("Should never be reached, Iterators invalid");
|
||||
}
|
||||
};
|
||||
|
||||
SECTION("Insert variants"){
|
||||
FixedMap<uint32_t, uint16_t>::Iterator it = map.end();
|
||||
REQUIRE(map.insert(36, 37, &it) == static_cast<int>(HasReturnvaluesIF::RETURN_OK));
|
||||
REQUIRE(it->first == 36);
|
||||
REQUIRE(it->second == 37);
|
||||
REQUIRE(map.size() == 1);
|
||||
REQUIRE(map.insert(37, 38, nullptr) == static_cast<int>(HasReturnvaluesIF::RETURN_OK));
|
||||
REQUIRE(map.find(37)->second == 38);
|
||||
REQUIRE(map.size() == 2);
|
||||
REQUIRE(map.insert(37, 24, nullptr) == static_cast<int>(FixedMap<uint32_t, uint16_t>::KEY_ALREADY_EXISTS));
|
||||
REQUIRE(map.find(37)->second != 24);
|
||||
REQUIRE(map.size() == 2);
|
||||
};
|
||||
SECTION("Serialize and DeSerialize") {
|
||||
REQUIRE(map.insert(36, 37, nullptr) == static_cast<int>(HasReturnvaluesIF::RETURN_OK));
|
||||
REQUIRE(map.insert(37, 38, nullptr) == static_cast<int>(HasReturnvaluesIF::RETURN_OK));
|
||||
uint8_t buffer[sizeof(uint32_t)
|
||||
+ 2 * (sizeof(uint32_t) + sizeof(uint16_t))];
|
||||
REQUIRE(
|
||||
map.getSerializedSize()
|
||||
== (sizeof(uint32_t)
|
||||
+ 2 * (sizeof(uint32_t) + sizeof(uint16_t))));
|
||||
uint8_t *loc_ptr = buffer;
|
||||
size_t size = 0;
|
||||
REQUIRE(
|
||||
map.serialize(&loc_ptr, &size, 10, SerializeIF::Endianness::BIG)
|
||||
== static_cast<int>(SerializeIF::BUFFER_TOO_SHORT));
|
||||
loc_ptr = buffer;
|
||||
size = 0;
|
||||
REQUIRE(
|
||||
map.serialize(&loc_ptr, &size,
|
||||
sizeof(uint32_t)
|
||||
+ 2 * (sizeof(uint32_t) + sizeof(uint16_t)),
|
||||
SerializeIF::Endianness::BIG)
|
||||
== static_cast<int>(HasReturnvaluesIF::RETURN_OK));
|
||||
REQUIRE(size == 16);
|
||||
|
||||
uint32_t internal_size = 0;
|
||||
const uint8_t *ptr2 = buffer;
|
||||
REQUIRE(
|
||||
SerializeAdapter::deSerialize(&internal_size, &ptr2, &size,
|
||||
SerializeIF::Endianness::BIG)
|
||||
== static_cast<int>(HasReturnvaluesIF::RETURN_OK));
|
||||
REQUIRE(internal_size == 2);
|
||||
for (uint8_t i = 36; i < 38; i++) {
|
||||
uint32_t first_element = 0;
|
||||
REQUIRE(
|
||||
SerializeAdapter::deSerialize(&first_element, &ptr2, &size,
|
||||
SerializeIF::Endianness::BIG)
|
||||
== static_cast<int>(HasReturnvaluesIF::RETURN_OK));
|
||||
REQUIRE(first_element == i);
|
||||
uint16_t second_element = 0;
|
||||
REQUIRE(
|
||||
SerializeAdapter::deSerialize(&second_element, &ptr2, &size,
|
||||
SerializeIF::Endianness::BIG)
|
||||
== static_cast<int>(HasReturnvaluesIF::RETURN_OK));
|
||||
REQUIRE(second_element == i + 1);
|
||||
}
|
||||
REQUIRE(size == 0);
|
||||
map.clear();
|
||||
const uint8_t* constPtr = buffer;
|
||||
size = 16;
|
||||
REQUIRE(map.size() == 0);
|
||||
REQUIRE(map.deSerialize(&constPtr, &size,
|
||||
SerializeIF::Endianness::BIG) == static_cast<int>(HasReturnvaluesIF::RETURN_OK));
|
||||
REQUIRE(map.size() == 2);
|
||||
REQUIRE(map.find(36)->second == 37);
|
||||
for(auto& element: map){
|
||||
REQUIRE((element.first+1) == element.second);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
SECTION("Failed erase and deSerialize"){
|
||||
FixedMap<uint32_t, uint16_t>::Iterator it;
|
||||
std::pair<uint32_t, uint16_t> pair = std::make_pair(44, 43);
|
||||
it = FixedMap<uint32_t, uint16_t>::Iterator(&pair);
|
||||
REQUIRE(map.erase(&it) == static_cast<int>(FixedMap<uint32_t, uint16_t>::KEY_DOES_NOT_EXIST));
|
||||
REQUIRE(map.find(45) == map.end());
|
||||
size_t toLargeMap = 100;
|
||||
const uint8_t* ptr = reinterpret_cast<uint8_t*>(&toLargeMap);
|
||||
size_t size = sizeof(size_t);
|
||||
REQUIRE(map.deSerialize(&ptr, &size, SerializeIF::Endianness::BIG) ==
|
||||
static_cast<int>(SerializeIF::TOO_MANY_ELEMENTS));
|
||||
};
|
||||
SECTION("Little Endianess"){
|
||||
map.clear();
|
||||
map.insert(10,20, nullptr);
|
||||
uint8_t newBuffer[sizeof(uint32_t)+ 1*(sizeof(uint32_t) + sizeof(uint16_t))];
|
||||
uint8_t* ptr = newBuffer;
|
||||
size_t size = 0;
|
||||
size_t max_size = sizeof(uint32_t)+ 1*(sizeof(uint32_t) + sizeof(uint16_t));
|
||||
REQUIRE(map.serialize(&ptr, &size, max_size,
|
||||
SerializeIF::Endianness::LITTLE) == static_cast<int>(HasReturnvaluesIF::RETURN_OK));
|
||||
map.clear();
|
||||
REQUIRE(map.size()==0);
|
||||
const uint8_t* ptr2 = newBuffer;
|
||||
REQUIRE(map.deSerialize(&ptr2, &size,
|
||||
SerializeIF::Endianness::LITTLE) == static_cast<int>(HasReturnvaluesIF::RETURN_OK));
|
||||
REQUIRE(map.size()==1);
|
||||
REQUIRE(map.find(10)->second == 20);
|
||||
};
|
||||
}
|
203
unittest/tests/container/TestFixedOrderedMultimap.cpp
Normal file
203
unittest/tests/container/TestFixedOrderedMultimap.cpp
Normal file
@ -0,0 +1,203 @@
|
||||
#include <fsfw/container/FixedOrderedMultimap.h>
|
||||
#include <fsfw/returnvalues/HasReturnvaluesIF.h>
|
||||
|
||||
#include <catch2/catch.hpp>
|
||||
#include "../../core/CatchDefinitions.h"
|
||||
|
||||
TEST_CASE( "FixedOrderedMultimap Tests", "[TestFixedOrderedMultimap]") {
|
||||
INFO("FixedOrderedMultimap Tests");
|
||||
|
||||
FixedOrderedMultimap<unsigned int, unsigned short> map(30);
|
||||
REQUIRE(map.size() == 0);
|
||||
REQUIRE(map.maxSize() == 30);
|
||||
|
||||
SECTION("Test insert, find, exists"){
|
||||
for (uint16_t i=0;i<30;i++){
|
||||
REQUIRE(map.insert(std::make_pair(i, i+1))== static_cast<int>(HasReturnvaluesIF::RETURN_OK));
|
||||
REQUIRE(map.exists(i) == static_cast<int>(HasReturnvaluesIF::RETURN_OK));
|
||||
REQUIRE(map.find(i)->second==i+1);
|
||||
}
|
||||
REQUIRE(map.insert(0, 0) == static_cast<int>(FixedOrderedMultimap<uint32_t, uint16_t>::MAP_FULL));
|
||||
REQUIRE(map.exists(31) == static_cast<int>(FixedOrderedMultimap<uint32_t, uint16_t>::KEY_DOES_NOT_EXIST));
|
||||
REQUIRE(map.size() == 30);
|
||||
{
|
||||
uint16_t* ptr;
|
||||
REQUIRE(map.find(5,&ptr) == static_cast<int>(HasReturnvaluesIF::RETURN_OK));
|
||||
REQUIRE(*ptr == 6);
|
||||
REQUIRE(map.find(31,&ptr) == static_cast<int>(FixedOrderedMultimap<uint32_t, uint16_t>::KEY_DOES_NOT_EXIST));
|
||||
}
|
||||
REQUIRE(map.erase(2) == static_cast<int>(HasReturnvaluesIF::RETURN_OK));
|
||||
REQUIRE(map.erase(31) == static_cast<int>(FixedOrderedMultimap<uint32_t, uint16_t>::KEY_DOES_NOT_EXIST));
|
||||
REQUIRE(map.exists(2) == static_cast<int>(FixedOrderedMultimap<uint32_t, uint16_t>::KEY_DOES_NOT_EXIST));
|
||||
REQUIRE(map.size() == 29);
|
||||
|
||||
for (auto element: map){
|
||||
if (element.first == 5){
|
||||
REQUIRE(element.second == 6);
|
||||
}
|
||||
}
|
||||
|
||||
for (FixedOrderedMultimap<uint32_t, uint16_t>::Iterator it = map.begin(); it != map.end(); it++){
|
||||
REQUIRE(it->second == it->first + 1);
|
||||
REQUIRE((*it).second == (*it).first + 1);
|
||||
it->second = it->second + 1;
|
||||
REQUIRE(it->second == it->first + 2);
|
||||
}
|
||||
|
||||
{
|
||||
FixedOrderedMultimap<uint32_t, uint16_t>::Iterator it = map.begin();
|
||||
while(it != map.end()){
|
||||
REQUIRE(map.erase(&it) == static_cast<int>(HasReturnvaluesIF::RETURN_OK));
|
||||
}
|
||||
REQUIRE(map.size() == 0);
|
||||
}
|
||||
|
||||
for (FixedOrderedMultimap<uint32_t, uint16_t>::Iterator it = map.begin(); it != map.end(); it++){
|
||||
// This line should never executed if begin and end is correct
|
||||
FAIL("Should never be reached, Iterators invalid");
|
||||
}
|
||||
};
|
||||
|
||||
SECTION("Test different insert variants")
|
||||
{
|
||||
FixedOrderedMultimap<uint32_t, uint16_t>::Iterator it = map.end();
|
||||
REQUIRE(map.insert(36, 37, &it) == static_cast<int>(HasReturnvaluesIF::RETURN_OK));
|
||||
REQUIRE(it->first == 36);
|
||||
REQUIRE(it->second == 37);
|
||||
REQUIRE(map.size() == 1);
|
||||
REQUIRE(map.insert(37, 38, nullptr) == static_cast<int>(HasReturnvaluesIF::RETURN_OK));
|
||||
REQUIRE(map.find(37)->second == 38);
|
||||
REQUIRE(map.size() == 2);
|
||||
REQUIRE(map.insert(37, 24, nullptr) == static_cast<int>(HasReturnvaluesIF::RETURN_OK));
|
||||
REQUIRE(map.find(37)->second == 38);
|
||||
REQUIRE(map.insert(0, 1, nullptr) == static_cast<int>(HasReturnvaluesIF::RETURN_OK));
|
||||
REQUIRE(map.find(0)->second == 1);
|
||||
REQUIRE(map.size() == 4);
|
||||
map.clear();
|
||||
REQUIRE(map.size() == 0);
|
||||
}
|
||||
SECTION("Test different erase and find with no entries"){
|
||||
FixedOrderedMultimap<uint32_t, uint16_t>::Iterator it;
|
||||
it = map.end();
|
||||
REQUIRE(map.erase(&it) == static_cast<int>(FixedOrderedMultimap<uint32_t, uint16_t>::KEY_DOES_NOT_EXIST));
|
||||
REQUIRE(map.find(1)== map.end());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE( "FixedOrderedMultimap Non Trivial Type", "[TestFixedOrderedMultimapNonTrivial]") {
|
||||
INFO("FixedOrderedMultimap Non Trivial Type");
|
||||
|
||||
class TestClass{
|
||||
public:
|
||||
TestClass(){};
|
||||
TestClass(uint32_t number1, uint64_t number2):
|
||||
number1(number1),number2(number2){};
|
||||
~TestClass(){};
|
||||
|
||||
bool operator==(const TestClass& lhs){
|
||||
return ((this->number1 == lhs.number1) and (this->number2 == lhs.number2));
|
||||
}
|
||||
bool operator!=(const TestClass& lhs){
|
||||
return not(this->operator ==(lhs));
|
||||
}
|
||||
|
||||
TestClass(const TestClass& other){
|
||||
this->number1 = other.number1;
|
||||
this->number2 = other.number2;
|
||||
};
|
||||
TestClass& operator=(const TestClass& other){
|
||||
this->number1 = other.number1;
|
||||
this->number2 = other.number2;
|
||||
return *this;
|
||||
};
|
||||
|
||||
private:
|
||||
uint32_t number1 = 0;
|
||||
uint64_t number2 = 5;
|
||||
};
|
||||
FixedOrderedMultimap<unsigned int, TestClass> map(30);
|
||||
REQUIRE(map.size() == 0);
|
||||
REQUIRE(map.maxSize() == 30);
|
||||
|
||||
SECTION("Test insert, find, exists"){
|
||||
for (uint16_t i=0;i<30;i++){
|
||||
REQUIRE(map.insert(std::make_pair(i, TestClass(i+1,i)))== static_cast<int>(HasReturnvaluesIF::RETURN_OK));
|
||||
REQUIRE(map.exists(i) == static_cast<int>(HasReturnvaluesIF::RETURN_OK));
|
||||
bool compare = map.find(i)->second == TestClass(i+1,i);
|
||||
REQUIRE(compare);
|
||||
}
|
||||
REQUIRE(map.insert(0, TestClass()) == static_cast<int>(FixedOrderedMultimap<uint32_t, uint16_t>::MAP_FULL));
|
||||
REQUIRE(map.exists(31) == static_cast<int>(FixedOrderedMultimap<uint32_t, uint16_t>::KEY_DOES_NOT_EXIST));
|
||||
REQUIRE(map.size() == 30);
|
||||
{
|
||||
TestClass* ptr = nullptr;
|
||||
REQUIRE(map.find(5,&ptr) == static_cast<int>(HasReturnvaluesIF::RETURN_OK));
|
||||
bool compare = *ptr == TestClass(6, 5);
|
||||
REQUIRE(compare);
|
||||
REQUIRE(map.find(31,&ptr) == static_cast<int>(FixedOrderedMultimap<uint32_t, uint16_t>::KEY_DOES_NOT_EXIST));
|
||||
}
|
||||
REQUIRE(map.erase(2) == static_cast<int>(HasReturnvaluesIF::RETURN_OK));
|
||||
REQUIRE(map.erase(31) == static_cast<int>(FixedOrderedMultimap<uint32_t, uint16_t>::KEY_DOES_NOT_EXIST));
|
||||
REQUIRE(map.exists(2) == static_cast<int>(FixedOrderedMultimap<uint32_t, uint16_t>::KEY_DOES_NOT_EXIST));
|
||||
REQUIRE(map.size() == 29);
|
||||
|
||||
for (auto element: map){
|
||||
if (element.first == 5){
|
||||
bool compare = element.second == TestClass(6, 5);
|
||||
REQUIRE(compare);
|
||||
}
|
||||
}
|
||||
|
||||
for (FixedOrderedMultimap<uint32_t, TestClass>::Iterator it = map.begin(); it != map.end(); it++){
|
||||
bool compare = it->second == TestClass(it->first + 1, it->first);
|
||||
REQUIRE(compare);
|
||||
compare = (*it).second == TestClass((*it).first + 1, (*it).first);
|
||||
REQUIRE(compare);
|
||||
it->second = TestClass(it->first + 2, it->first);
|
||||
compare = it->second == TestClass(it->first + 2, it->first);
|
||||
REQUIRE(compare);
|
||||
}
|
||||
|
||||
{
|
||||
FixedOrderedMultimap<uint32_t, TestClass>::Iterator it = map.begin();
|
||||
while(it != map.end()){
|
||||
REQUIRE(map.erase(&it) == static_cast<int>(HasReturnvaluesIF::RETURN_OK));
|
||||
}
|
||||
REQUIRE(map.size() == 0);
|
||||
}
|
||||
|
||||
for (FixedOrderedMultimap<uint32_t, TestClass>::Iterator it = map.begin(); it != map.end(); it++){
|
||||
// This line should never executed if begin and end is correct
|
||||
FAIL("Should never be reached, Iterators invalid");
|
||||
}
|
||||
};
|
||||
|
||||
SECTION("Test different insert variants")
|
||||
{
|
||||
FixedOrderedMultimap<uint32_t, TestClass>::Iterator it = map.end();
|
||||
REQUIRE(map.insert(36, TestClass(37, 36), &it) == static_cast<int>(HasReturnvaluesIF::RETURN_OK));
|
||||
REQUIRE(it->first == 36);
|
||||
bool compare = it->second == TestClass(37, 36);
|
||||
REQUIRE(compare);
|
||||
REQUIRE(map.size() == 1);
|
||||
REQUIRE(map.insert(37, TestClass(38, 37), nullptr) == static_cast<int>(HasReturnvaluesIF::RETURN_OK));
|
||||
compare = map.find(37)->second == TestClass(38, 37);
|
||||
REQUIRE(compare);
|
||||
REQUIRE(map.size() == 2);
|
||||
REQUIRE(map.insert(37, TestClass(24, 37), nullptr) == static_cast<int>(HasReturnvaluesIF::RETURN_OK));
|
||||
compare = map.find(37)->second == TestClass(38, 37);
|
||||
REQUIRE(compare);
|
||||
REQUIRE(map.insert(0, TestClass(1, 0), nullptr) == static_cast<int>(HasReturnvaluesIF::RETURN_OK));
|
||||
compare = map.find(0)->second == TestClass(1, 0);
|
||||
REQUIRE(compare);
|
||||
REQUIRE(map.size() == 4);
|
||||
map.clear();
|
||||
REQUIRE(map.size() == 0);
|
||||
}
|
||||
SECTION("Test different erase and find with no entries"){
|
||||
FixedOrderedMultimap<uint32_t, TestClass>::Iterator it;
|
||||
it = map.end();
|
||||
REQUIRE(map.erase(&it) == static_cast<int>(FixedOrderedMultimap<uint32_t, TestClass>::KEY_DOES_NOT_EXIST));
|
||||
REQUIRE(map.find(1)== map.end());
|
||||
}
|
||||
}
|
45
unittest/tests/container/TestPlacementFactory.cpp
Normal file
45
unittest/tests/container/TestPlacementFactory.cpp
Normal file
@ -0,0 +1,45 @@
|
||||
//#include <fsfw/container/PlacementFactory.h>
|
||||
//#include <fsfw/storagemanager/LocalPool.h>
|
||||
//#include <fsfw/returnvalues/HasReturnvaluesIF.h>
|
||||
//#include <fsfw/container/ArrayList.h>
|
||||
//
|
||||
//#include <catch2/catch.hpp>
|
||||
//#include "../../core/CatchDefinitions.h"
|
||||
//
|
||||
//TEST_CASE( "PlacementFactory Tests", "[TestPlacementFactory]") {
|
||||
// INFO("PlacementFactory Tests");
|
||||
//
|
||||
// const uint16_t element_sizes[3] = {sizeof(uint16_t), sizeof(uint32_t), sizeof(uint64_t)};
|
||||
// const uint16_t n_elements[3] = {1, 1, 1};
|
||||
// LocalPool<3> storagePool(0x1, element_sizes, n_elements, false, true);
|
||||
// PlacementFactory factory(&storagePool);
|
||||
//
|
||||
// SECTION("Pool overload"){
|
||||
// store_address_t address;
|
||||
// uint8_t* ptr = nullptr;
|
||||
// REQUIRE(storagePool.getFreeElement(&address, sizeof(ArrayList<uint32_t, uint16_t>), &ptr)
|
||||
// == static_cast<int>(StorageManagerIF::DATA_TOO_LARGE));
|
||||
// ArrayList<uint32_t, uint16_t>* list2 = factory.generate<ArrayList<uint32_t, uint16_t> >(80);
|
||||
// REQUIRE(list2 == nullptr);
|
||||
// }
|
||||
//
|
||||
// SECTION("Test generate and destroy"){
|
||||
// uint64_t* number = factory.generate<uint64_t>(32000);
|
||||
// REQUIRE(number != nullptr);
|
||||
// REQUIRE(*number == 32000);
|
||||
// store_address_t address;
|
||||
// uint8_t* ptr = nullptr;
|
||||
// REQUIRE(storagePool.getFreeElement(&address, sizeof(uint64_t), &ptr)
|
||||
// == static_cast<int>(StorageManagerIF::DATA_TOO_LARGE));
|
||||
// uint64_t* number2 = factory.generate<uint64_t>(12345);
|
||||
// REQUIRE(number2 == nullptr);
|
||||
// REQUIRE(factory.destroy(number) == static_cast<int>(HasReturnvaluesIF::RETURN_OK));
|
||||
// REQUIRE(storagePool.getFreeElement(&address, sizeof(uint64_t), &ptr)
|
||||
// == static_cast<int>(HasReturnvaluesIF::RETURN_OK));
|
||||
// REQUIRE(storagePool.deleteData(address) == static_cast<int>(HasReturnvaluesIF::RETURN_OK));
|
||||
//
|
||||
// //Check that PlacementFactory checks for nullptr
|
||||
// ptr = nullptr;
|
||||
// REQUIRE(factory.destroy(ptr) == static_cast<int>(HasReturnvaluesIF::RETURN_FAILED));
|
||||
// }
|
||||
//}
|
40
unittest/tests/osal/TestMessageQueue.cpp
Normal file
40
unittest/tests/osal/TestMessageQueue.cpp
Normal file
@ -0,0 +1,40 @@
|
||||
#include <fsfw/ipc/MessageQueueIF.h>
|
||||
#include <fsfw/ipc/QueueFactory.h>
|
||||
#include "catch.hpp"
|
||||
#include <array>
|
||||
#include "core/CatchDefinitions.h"
|
||||
|
||||
TEST_CASE("MessageQueue Basic Test","[TestMq]") {
|
||||
MessageQueueIF* testSenderMq =
|
||||
QueueFactory::instance()->createMessageQueue(1);
|
||||
MessageQueueId_t testSenderMqId = testSenderMq->getId();
|
||||
|
||||
MessageQueueIF* testReceiverMq =
|
||||
QueueFactory::instance()->createMessageQueue(1);
|
||||
MessageQueueId_t testReceiverMqId = testReceiverMq->getId();
|
||||
std::array<uint8_t, 20> testData { 0 };
|
||||
testData[0] = 42;
|
||||
MessageQueueMessage testMessage(testData.data(), 1);
|
||||
testSenderMq->setDefaultDestination(testReceiverMqId);
|
||||
|
||||
SECTION("Simple Tests") {
|
||||
auto result = testSenderMq->sendMessage(testReceiverMqId, &testMessage);
|
||||
REQUIRE(result == retval::CATCH_OK);
|
||||
MessageQueueMessage recvMessage;
|
||||
result = testReceiverMq->receiveMessage(&recvMessage);
|
||||
REQUIRE(result == retval::CATCH_OK);
|
||||
CHECK(recvMessage.getData()[0] == 42);
|
||||
|
||||
result = testSenderMq->sendMessage(testReceiverMqId, &testMessage);
|
||||
REQUIRE(result == retval::CATCH_OK);
|
||||
MessageQueueId_t senderId = 0;
|
||||
result = testReceiverMq->receiveMessage(&recvMessage,&senderId);
|
||||
REQUIRE(result == retval::CATCH_OK);
|
||||
CHECK(recvMessage.getData()[0] == 42);
|
||||
CHECK(senderId == testSenderMqId);
|
||||
senderId = testReceiverMq->getLastPartner();
|
||||
CHECK(senderId == testSenderMqId);
|
||||
}
|
||||
|
||||
|
||||
}
|
46
unittest/tests/osal/TestSemaphore.cpp
Normal file
46
unittest/tests/osal/TestSemaphore.cpp
Normal file
@ -0,0 +1,46 @@
|
||||
|
||||
#ifdef LINUX
|
||||
|
||||
/*
|
||||
#include "core/CatchDefinitions.h"
|
||||
#include "catch.hpp"
|
||||
|
||||
#include <fsfw/tasks/SemaphoreFactory.h>
|
||||
#include <fsfw/timemanager/Stopwatch.h>
|
||||
|
||||
TEST_CASE("Binary Semaphore Test" , "[BinSemaphore]") {
|
||||
//perform set-up here
|
||||
SemaphoreIF* binSemaph = SemaphoreFactory::instance()->
|
||||
createBinarySemaphore();
|
||||
REQUIRE(binSemaph != nullptr);
|
||||
SECTION("Simple Test") {
|
||||
// set-up is run for each section
|
||||
REQUIRE(binSemaph->getSemaphoreCounter() == 1);
|
||||
REQUIRE(binSemaph->release() ==
|
||||
static_cast<int>(SemaphoreIF::SEMAPHORE_NOT_OWNED));
|
||||
REQUIRE(binSemaph->acquire(SemaphoreIF::POLLING) ==
|
||||
retval::CATCH_OK);
|
||||
{
|
||||
// not precise enough on linux.. should use clock instead..
|
||||
//Stopwatch stopwatch(false);
|
||||
//REQUIRE(binSemaph->acquire(SemaphoreIF::TimeoutType::WAITING, 5) ==
|
||||
// SemaphoreIF::SEMAPHORE_TIMEOUT);
|
||||
//dur_millis_t time = stopwatch.stop();
|
||||
//CHECK(time == 5);
|
||||
}
|
||||
REQUIRE(binSemaph->getSemaphoreCounter() == 0);
|
||||
REQUIRE(binSemaph->release() == retval::CATCH_OK);
|
||||
}
|
||||
SemaphoreFactory::instance()->deleteSemaphore(binSemaph);
|
||||
// perform tear-down here
|
||||
}
|
||||
|
||||
|
||||
TEST_CASE("Counting Semaphore Test" , "[CountingSemaph]") {
|
||||
SECTION("Simple Test") {
|
||||
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
#endif
|
143
unittest/tests/serialize/TestSerialBufferAdapter.cpp
Normal file
143
unittest/tests/serialize/TestSerialBufferAdapter.cpp
Normal file
@ -0,0 +1,143 @@
|
||||
#include <fsfw/serialize/SerialBufferAdapter.h>
|
||||
|
||||
#include <catch2/catch.hpp>
|
||||
#include "../../core/CatchDefinitions.h"
|
||||
|
||||
|
||||
static bool test_value_bool = true;
|
||||
static uint16_t tv_uint16 {283};
|
||||
static std::array<uint8_t, 512> testArray;
|
||||
|
||||
TEST_CASE("Serial Buffer Adapter", "[single-file]") {
|
||||
size_t serialized_size = 0;
|
||||
test_value_bool = true;
|
||||
uint8_t * arrayPtr = testArray.data();
|
||||
std::array<uint8_t, 5> test_serial_buffer {5, 4, 3, 2, 1};
|
||||
SerialBufferAdapter<uint8_t> tv_serial_buffer_adapter =
|
||||
SerialBufferAdapter<uint8_t>(test_serial_buffer.data(),
|
||||
test_serial_buffer.size(), false);
|
||||
tv_uint16 = 16;
|
||||
|
||||
SECTION("Serialize without size field") {
|
||||
SerializeAdapter::serialize(&test_value_bool, &arrayPtr,
|
||||
&serialized_size, testArray.size(),
|
||||
SerializeIF::Endianness::MACHINE);
|
||||
SerializeAdapter::serialize(&tv_serial_buffer_adapter, &arrayPtr,
|
||||
&serialized_size, testArray.size(),
|
||||
SerializeIF::Endianness::MACHINE);
|
||||
SerializeAdapter::serialize(&tv_uint16, &arrayPtr, &serialized_size,
|
||||
testArray.size(), SerializeIF::Endianness::MACHINE);
|
||||
|
||||
REQUIRE(serialized_size == 8);
|
||||
REQUIRE(testArray[0] == true);
|
||||
REQUIRE(testArray[1] == 5);
|
||||
REQUIRE(testArray[2] == 4);
|
||||
REQUIRE(testArray[3] == 3);
|
||||
REQUIRE(testArray[4] == 2);
|
||||
REQUIRE(testArray[5] == 1);
|
||||
memcpy(&tv_uint16, testArray.data() + 6, sizeof(tv_uint16));
|
||||
REQUIRE(tv_uint16 == 16);
|
||||
}
|
||||
|
||||
SECTION("Serialize with size field") {
|
||||
SerialBufferAdapter<uint8_t> tv_serial_buffer_adapter_loc =
|
||||
SerialBufferAdapter<uint8_t>(test_serial_buffer.data(),
|
||||
test_serial_buffer.size(), true);
|
||||
serialized_size = 0;
|
||||
arrayPtr = testArray.data();
|
||||
SerializeAdapter::serialize(&test_value_bool, &arrayPtr,&serialized_size,
|
||||
testArray.size(), SerializeIF::Endianness::MACHINE);
|
||||
SerializeAdapter::serialize(&tv_serial_buffer_adapter_loc, &arrayPtr,
|
||||
&serialized_size, testArray.size(),
|
||||
SerializeIF::Endianness::MACHINE);
|
||||
SerializeAdapter::serialize(&tv_uint16, &arrayPtr, &serialized_size,
|
||||
testArray.size(), SerializeIF::Endianness::MACHINE);
|
||||
|
||||
REQUIRE(serialized_size == 9);
|
||||
REQUIRE(testArray[0] == true);
|
||||
REQUIRE(testArray[1] == 5);
|
||||
REQUIRE(testArray[2] == 5);
|
||||
REQUIRE(testArray[3] == 4);
|
||||
REQUIRE(testArray[4] == 3);
|
||||
REQUIRE(testArray[5] == 2);
|
||||
REQUIRE(testArray[6] == 1);
|
||||
memcpy(&tv_uint16, testArray.data() + 7, sizeof(tv_uint16));
|
||||
REQUIRE(tv_uint16 == 16);
|
||||
}
|
||||
|
||||
SECTION("Test set buffer function") {
|
||||
SerialBufferAdapter<uint8_t> tv_serial_buffer_adapter_loc =
|
||||
SerialBufferAdapter<uint8_t>((uint8_t*)nullptr,
|
||||
0, true);
|
||||
tv_serial_buffer_adapter_loc.setBuffer(test_serial_buffer.data(),
|
||||
test_serial_buffer.size());
|
||||
serialized_size = 0;
|
||||
arrayPtr = testArray.data();
|
||||
SerializeAdapter::serialize(&test_value_bool, &arrayPtr,&serialized_size,
|
||||
testArray.size(), SerializeIF::Endianness::MACHINE);
|
||||
SerializeAdapter::serialize(&tv_serial_buffer_adapter_loc, &arrayPtr,
|
||||
&serialized_size, testArray.size(),
|
||||
SerializeIF::Endianness::MACHINE);
|
||||
SerializeAdapter::serialize(&tv_uint16, &arrayPtr, &serialized_size,
|
||||
testArray.size(), SerializeIF::Endianness::MACHINE);
|
||||
REQUIRE(serialized_size == 9);
|
||||
REQUIRE(testArray[0] == true);
|
||||
REQUIRE(testArray[1] == 5);
|
||||
REQUIRE(testArray[2] == 5);
|
||||
REQUIRE(testArray[3] == 4);
|
||||
REQUIRE(testArray[4] == 3);
|
||||
REQUIRE(testArray[5] == 2);
|
||||
REQUIRE(testArray[6] == 1);
|
||||
memcpy(&tv_uint16, testArray.data() + 7, sizeof(tv_uint16));
|
||||
REQUIRE(tv_uint16 == 16);
|
||||
}
|
||||
|
||||
SECTION("Deserialization with size field") {
|
||||
size_t buffer_size = 4;
|
||||
memcpy(testArray.data(), &buffer_size, sizeof(uint16_t));
|
||||
testArray[2] = 1;
|
||||
testArray[3] = 1;
|
||||
testArray[4] = 1;
|
||||
testArray[5] = 0;
|
||||
std::array<uint8_t, 4> test_recv_array;
|
||||
arrayPtr = testArray.data();
|
||||
// copy testArray[1] to testArray[4] into receive buffer, skip
|
||||
// size field (testArray[0]) for deSerialization.
|
||||
SerialBufferAdapter<uint16_t> tv_serial_buffer_adapter3 =
|
||||
SerialBufferAdapter<uint16_t>(test_recv_array.data(), 4, true);
|
||||
// Deserialization
|
||||
size_t size = 6;
|
||||
auto result = tv_serial_buffer_adapter3.deSerialize(
|
||||
const_cast<const uint8_t**>(&arrayPtr), &size,
|
||||
SerializeIF::Endianness::MACHINE);
|
||||
REQUIRE(result == retval::CATCH_OK);
|
||||
CHECK(test_recv_array[0] == 1);
|
||||
CHECK(test_recv_array[1] == 1);
|
||||
CHECK(test_recv_array[2] == 1);
|
||||
CHECK(test_recv_array[3] == 0);
|
||||
}
|
||||
|
||||
SECTION("Deserialization without size field") {
|
||||
size_t buffer_size = 4;
|
||||
memcpy(testArray.data(), &buffer_size, sizeof(uint16_t));
|
||||
testArray[2] = 1;
|
||||
testArray[3] = 1;
|
||||
testArray[4] = 1;
|
||||
testArray[5] = 0;
|
||||
std::array<uint8_t, 4> test_recv_array;
|
||||
arrayPtr = testArray.data() + 2;
|
||||
// copy testArray[1] to testArray[4] into receive buffer, skip
|
||||
// size field (testArray[0])
|
||||
SerialBufferAdapter<uint16_t> tv_serial_buffer_adapter3 =
|
||||
SerialBufferAdapter<uint16_t>(test_recv_array.data(), 4, false);
|
||||
// Deserialization
|
||||
size_t size = 4;
|
||||
tv_serial_buffer_adapter3.deSerialize(
|
||||
const_cast<const uint8_t**>(&arrayPtr), &size,
|
||||
SerializeIF::Endianness::MACHINE);
|
||||
CHECK(test_recv_array[0] == 1);
|
||||
CHECK(test_recv_array[1] == 1);
|
||||
CHECK(test_recv_array[2] == 1);
|
||||
CHECK(test_recv_array[3] == 0);
|
||||
}
|
||||
}
|
73
unittest/tests/serialize/TestSerialLinkedPacket.cpp
Normal file
73
unittest/tests/serialize/TestSerialLinkedPacket.cpp
Normal file
@ -0,0 +1,73 @@
|
||||
#include <fsfw/globalfunctions/arrayprinter.h>
|
||||
|
||||
#include <catch2/catch.hpp>
|
||||
#include "../../core/CatchDefinitions.h"
|
||||
#include "TestSerialLinkedPacket.h"
|
||||
|
||||
|
||||
TEST_CASE("Serial Linked Packet" , "[SerLinkPacket]") {
|
||||
// perform set-up here
|
||||
uint32_t header = 42;
|
||||
std::array<uint8_t, 3> testArray {1,2,3};
|
||||
uint32_t tail = 96;
|
||||
size_t packetMaxSize = 256;
|
||||
uint8_t packet [packetMaxSize] = {};
|
||||
size_t packetLen = 0;
|
||||
|
||||
SECTION("Test Deserialization with Serial Buffer Adapter.") {
|
||||
// This is a serialization of a packet, made "manually".
|
||||
// We generate a packet which store data big-endian by swapping some
|
||||
// values. (like coming from ground).
|
||||
header = EndianConverter::convertBigEndian(header);
|
||||
std::memcpy(packet, &header, sizeof(header));
|
||||
packetLen += sizeof(header);
|
||||
|
||||
std::copy(testArray.data(), testArray.data() + testArray.size(),
|
||||
packet + packetLen);
|
||||
packetLen += testArray.size();
|
||||
|
||||
tail = EndianConverter::convertBigEndian(tail);
|
||||
std::memcpy(packet + packetLen, &tail, sizeof(tail));
|
||||
packetLen += sizeof(tail);
|
||||
|
||||
//arrayprinter::print(packet, packetLen, OutputType::DEC);
|
||||
|
||||
// This is the buffer which will be filled when testClass.deSerialize
|
||||
// is called.
|
||||
std::array<uint8_t, 3> bufferAdaptee = {};
|
||||
TestPacket testClass(packet, packetLen, bufferAdaptee.data(),
|
||||
bufferAdaptee.size());
|
||||
const uint8_t* readOnlyPointer = packet;
|
||||
// Deserialize big endian packet by setting bigEndian to true.
|
||||
ReturnValue_t result = testClass.deSerialize(&readOnlyPointer,
|
||||
&packetLen, SerializeIF::Endianness::BIG);
|
||||
REQUIRE(result == retval::CATCH_OK);
|
||||
CHECK(testClass.getHeader() == 42);
|
||||
// Equivalent check.
|
||||
// CHECK(testClass.getBuffer()[0] == 1);
|
||||
CHECK(bufferAdaptee[0] == 1);
|
||||
CHECK(bufferAdaptee[1] == 2);
|
||||
CHECK(bufferAdaptee[2] == 3);
|
||||
CHECK(testClass.getTail() == 96);
|
||||
}
|
||||
|
||||
SECTION("Test Serialization") {
|
||||
// Same process as performed in setup, this time using the class
|
||||
// instead of doing it manually.
|
||||
TestPacket testClass(header, tail, testArray.data(), testArray.size());
|
||||
size_t serializedSize = 0;
|
||||
uint8_t* packetPointer = packet;
|
||||
// serialize for ground: bigEndian = true.
|
||||
ReturnValue_t result = testClass.serialize(&packetPointer,
|
||||
&serializedSize, packetMaxSize, SerializeIF::Endianness::BIG);
|
||||
REQUIRE(result == retval::CATCH_OK);
|
||||
// Result should be big endian now.
|
||||
CHECK(packet[3] == 42);
|
||||
CHECK(packet[4] == 1);
|
||||
CHECK(packet[5] == 2);
|
||||
CHECK(packet[6] == 3);
|
||||
CHECK(packet[10] == 96);
|
||||
}
|
||||
|
||||
// perform tear-down here
|
||||
}
|
61
unittest/tests/serialize/TestSerialLinkedPacket.h
Normal file
61
unittest/tests/serialize/TestSerialLinkedPacket.h
Normal file
@ -0,0 +1,61 @@
|
||||
#ifndef UNITTEST_HOSTED_TESTSERIALLINKEDPACKET_H_
|
||||
#define UNITTEST_HOSTED_TESTSERIALLINKEDPACKET_H_
|
||||
|
||||
#include <fsfw/objectmanager/SystemObjectIF.h>
|
||||
#include <fsfw/parameters/HasParametersIF.h>
|
||||
#include <fsfw/serialize/SerialBufferAdapter.h>
|
||||
#include <fsfw/serialize/SerialLinkedListAdapter.h>
|
||||
#include <cstdint>
|
||||
|
||||
class TestPacket: public SerialLinkedListAdapter<SerializeIF> {
|
||||
public:
|
||||
/**
|
||||
* For Deserialization
|
||||
*/
|
||||
TestPacket(const uint8_t *somePacket, size_t size, uint8_t * storePointer,
|
||||
size_t storeSize):
|
||||
buffer(storePointer, storeSize)
|
||||
{
|
||||
setLinks();
|
||||
}
|
||||
|
||||
/**
|
||||
* For Serialization
|
||||
*/
|
||||
TestPacket(uint32_t header, uint32_t tail,
|
||||
const uint8_t* parameters, size_t paramSize):
|
||||
header(header), buffer(parameters, paramSize),
|
||||
tail(tail) {
|
||||
setLinks();
|
||||
}
|
||||
|
||||
uint32_t getHeader() const {
|
||||
return header.entry;
|
||||
}
|
||||
|
||||
const uint8_t * getBuffer() {
|
||||
return buffer.entry.getConstBuffer();
|
||||
}
|
||||
|
||||
const size_t getBufferLength() {
|
||||
return buffer.getSerializedSize();
|
||||
}
|
||||
|
||||
|
||||
uint16_t getTail() const {
|
||||
return tail.entry;
|
||||
}
|
||||
private:
|
||||
void setLinks() {
|
||||
setStart(&header);
|
||||
header.setNext(&buffer);
|
||||
buffer.setNext(&tail);
|
||||
tail.setEnd();
|
||||
}
|
||||
|
||||
SerializeElement<uint32_t> header = 0;
|
||||
SerializeElement<SerialBufferAdapter<uint8_t>> buffer;
|
||||
SerializeElement<uint32_t> tail = 0;
|
||||
};
|
||||
|
||||
#endif /* UNITTEST_TESTFW_NEWTESTS_TESTTEMPLATE_H_ */
|
129
unittest/tests/serialize/TestSerialization.cpp
Normal file
129
unittest/tests/serialize/TestSerialization.cpp
Normal file
@ -0,0 +1,129 @@
|
||||
#include <fsfw/serialize/SerializeAdapter.h>
|
||||
|
||||
#include "catch.hpp"
|
||||
#include <array>
|
||||
#include "../../core/CatchDefinitions.h"
|
||||
|
||||
static bool test_value_bool = true;
|
||||
static uint8_t tv_uint8 {5};
|
||||
static uint16_t tv_uint16 {283};
|
||||
static uint32_t tv_uint32 {929221};
|
||||
static uint64_t tv_uint64 {2929329429};
|
||||
|
||||
static int8_t tv_int8 {-16};
|
||||
static int16_t tv_int16 {-829};
|
||||
static int32_t tv_int32 {-2312};
|
||||
|
||||
static float tv_float {8.2149214};
|
||||
static float tv_sfloat = {-922.2321321};
|
||||
static double tv_double {9.2132142141e8};
|
||||
static double tv_sdouble {-2.2421e19};
|
||||
|
||||
static std::array<uint8_t, 512> test_array;
|
||||
|
||||
TEST_CASE( "Serialization size tests", "[TestSerialization]") {
|
||||
//REQUIRE(unitTestClass.test_autoserialization() == 0);
|
||||
REQUIRE(SerializeAdapter::getSerializedSize(&test_value_bool) ==
|
||||
sizeof(test_value_bool));
|
||||
REQUIRE(SerializeAdapter::getSerializedSize(&tv_uint8) ==
|
||||
sizeof(tv_uint8));
|
||||
REQUIRE(SerializeAdapter::getSerializedSize(&tv_uint16) ==
|
||||
sizeof(tv_uint16));
|
||||
REQUIRE(SerializeAdapter::getSerializedSize(&tv_uint32 ) ==
|
||||
sizeof(tv_uint32));
|
||||
REQUIRE(SerializeAdapter::getSerializedSize(&tv_uint64) ==
|
||||
sizeof(tv_uint64));
|
||||
REQUIRE(SerializeAdapter::getSerializedSize(&tv_int8) ==
|
||||
sizeof(tv_int8));
|
||||
REQUIRE(SerializeAdapter::getSerializedSize(&tv_int16) ==
|
||||
sizeof(tv_int16));
|
||||
REQUIRE(SerializeAdapter::getSerializedSize(&tv_int32) ==
|
||||
sizeof(tv_int32));
|
||||
REQUIRE(SerializeAdapter::getSerializedSize(&tv_float) ==
|
||||
sizeof(tv_float));
|
||||
REQUIRE(SerializeAdapter::getSerializedSize(&tv_sfloat) ==
|
||||
sizeof(tv_sfloat ));
|
||||
REQUIRE(SerializeAdapter::getSerializedSize(&tv_double) ==
|
||||
sizeof(tv_double));
|
||||
REQUIRE(SerializeAdapter::getSerializedSize(&tv_sdouble) ==
|
||||
sizeof(tv_sdouble));
|
||||
}
|
||||
|
||||
|
||||
TEST_CASE("Auto Serialize Adapter testing", "[single-file]") {
|
||||
size_t serialized_size = 0;
|
||||
uint8_t * p_array = test_array.data();
|
||||
|
||||
SECTION("Serializing...") {
|
||||
SerializeAdapter::serialize(&test_value_bool, &p_array,
|
||||
&serialized_size, test_array.size(), SerializeIF::Endianness::MACHINE);
|
||||
SerializeAdapter::serialize(&tv_uint8, &p_array,
|
||||
&serialized_size, test_array.size(), SerializeIF::Endianness::MACHINE);
|
||||
SerializeAdapter::serialize(&tv_uint16, &p_array,
|
||||
&serialized_size, test_array.size(), SerializeIF::Endianness::MACHINE);
|
||||
SerializeAdapter::serialize(&tv_uint32, &p_array,
|
||||
&serialized_size, test_array.size(), SerializeIF::Endianness::MACHINE);
|
||||
SerializeAdapter::serialize(&tv_int8, &p_array,
|
||||
&serialized_size, test_array.size(), SerializeIF::Endianness::MACHINE);
|
||||
SerializeAdapter::serialize(&tv_int16, &p_array,
|
||||
&serialized_size, test_array.size(), SerializeIF::Endianness::MACHINE);
|
||||
SerializeAdapter::serialize(&tv_int32, &p_array,
|
||||
&serialized_size, test_array.size(), SerializeIF::Endianness::MACHINE);
|
||||
SerializeAdapter::serialize(&tv_uint64, &p_array,
|
||||
&serialized_size, test_array.size(), SerializeIF::Endianness::MACHINE);
|
||||
SerializeAdapter::serialize(&tv_float, &p_array,
|
||||
&serialized_size, test_array.size(), SerializeIF::Endianness::MACHINE);
|
||||
SerializeAdapter::serialize(&tv_double, &p_array,
|
||||
&serialized_size, test_array.size(), SerializeIF::Endianness::MACHINE);
|
||||
SerializeAdapter::serialize(&tv_sfloat, &p_array,
|
||||
&serialized_size, test_array.size(), SerializeIF::Endianness::MACHINE);
|
||||
SerializeAdapter::serialize(&tv_sdouble, &p_array,
|
||||
&serialized_size, test_array.size(), SerializeIF::Endianness::MACHINE);
|
||||
REQUIRE (serialized_size == 47);
|
||||
}
|
||||
|
||||
SECTION("Deserializing") {
|
||||
p_array = test_array.data();
|
||||
size_t remaining_size = serialized_size;
|
||||
SerializeAdapter::deSerialize(&test_value_bool,
|
||||
const_cast<const uint8_t**>(&p_array), &remaining_size, SerializeIF::Endianness::MACHINE);
|
||||
SerializeAdapter::deSerialize(&tv_uint8,
|
||||
const_cast<const uint8_t**>(&p_array), &remaining_size, SerializeIF::Endianness::MACHINE);
|
||||
SerializeAdapter::deSerialize(&tv_uint16,
|
||||
const_cast<const uint8_t**>(&p_array), &remaining_size, SerializeIF::Endianness::MACHINE);
|
||||
SerializeAdapter::deSerialize(&tv_uint32,
|
||||
const_cast<const uint8_t**>(&p_array), &remaining_size, SerializeIF::Endianness::MACHINE);
|
||||
SerializeAdapter::deSerialize(&tv_int8,
|
||||
const_cast<const uint8_t**>(&p_array), &remaining_size, SerializeIF::Endianness::MACHINE);
|
||||
SerializeAdapter::deSerialize(&tv_int16,
|
||||
const_cast<const uint8_t**>(&p_array), &remaining_size, SerializeIF::Endianness::MACHINE);
|
||||
SerializeAdapter::deSerialize(&tv_int32,
|
||||
const_cast<const uint8_t**>(&p_array), &remaining_size, SerializeIF::Endianness::MACHINE);
|
||||
SerializeAdapter::deSerialize(&tv_uint64,
|
||||
const_cast<const uint8_t**>(&p_array), &remaining_size, SerializeIF::Endianness::MACHINE);
|
||||
SerializeAdapter::deSerialize(&tv_float,
|
||||
const_cast<const uint8_t**>(&p_array), &remaining_size, SerializeIF::Endianness::MACHINE);
|
||||
SerializeAdapter::deSerialize(&tv_double,
|
||||
const_cast<const uint8_t**>(&p_array), &remaining_size, SerializeIF::Endianness::MACHINE);
|
||||
SerializeAdapter::deSerialize(&tv_sfloat,
|
||||
const_cast<const uint8_t**>(&p_array), &remaining_size, SerializeIF::Endianness::MACHINE);
|
||||
SerializeAdapter::deSerialize(&tv_sdouble,
|
||||
const_cast<const uint8_t**>(&p_array), &remaining_size, SerializeIF::Endianness::MACHINE);
|
||||
|
||||
REQUIRE(test_value_bool == true);
|
||||
REQUIRE(tv_uint8 == 5);
|
||||
REQUIRE(tv_uint16 == 283);
|
||||
REQUIRE(tv_uint32 == 929221);
|
||||
REQUIRE(tv_uint64 == 2929329429);
|
||||
REQUIRE(tv_int8 == -16);
|
||||
REQUIRE(tv_int16 == -829);
|
||||
REQUIRE(tv_int32 == -2312);
|
||||
|
||||
REQUIRE(tv_float == Approx(8.214921));
|
||||
REQUIRE(tv_double == Approx(9.2132142141e8));
|
||||
REQUIRE(tv_sfloat == Approx(-922.2321321));
|
||||
REQUIRE(tv_sdouble == Approx(-2.2421e19));
|
||||
}
|
||||
}
|
||||
|
||||
|
161
unittest/tests/storagemanager/TestNewAccessor.cpp
Normal file
161
unittest/tests/storagemanager/TestNewAccessor.cpp
Normal file
@ -0,0 +1,161 @@
|
||||
//#include <fsfw/storagemanager/LocalPool.h>
|
||||
//#include <catch2/catch.hpp>
|
||||
//#include "../../core/CatchDefinitions.h"
|
||||
//#include <array>
|
||||
//
|
||||
//TEST_CASE( "New Accessor" , "[NewAccessor]") {
|
||||
// uint16_t numberOfElements[1] = {1};
|
||||
// uint16_t sizeofElements[1] = {10};
|
||||
// LocalPool<1> SimplePool = LocalPool<1>(0, sizeofElements, numberOfElements);
|
||||
// std::array<uint8_t, 20> testDataArray;
|
||||
// std::array<uint8_t, 20> receptionArray;
|
||||
// store_address_t testStoreId;
|
||||
// ReturnValue_t result = retval::CATCH_FAILED;
|
||||
//
|
||||
// for(size_t i = 0; i < testDataArray.size(); i++) {
|
||||
// testDataArray[i] = i;
|
||||
// }
|
||||
// size_t size = 10;
|
||||
//
|
||||
// SECTION ("Simple tests getter functions") {
|
||||
// result = SimplePool.addData(&testStoreId, testDataArray.data(), size);
|
||||
// REQUIRE(result == retval::CATCH_OK);
|
||||
// auto resultPair = SimplePool.getData(testStoreId);
|
||||
// REQUIRE(resultPair.first == retval::CATCH_OK);
|
||||
// resultPair.second.getDataCopy(receptionArray.data(), 20);
|
||||
// CHECK(resultPair.second.getId() == testStoreId);
|
||||
// CHECK(resultPair.second.size() == 10);
|
||||
// for(size_t i = 0; i < size; i++) {
|
||||
// CHECK(receptionArray[i] == i );
|
||||
// }
|
||||
//
|
||||
// std::copy(resultPair.second.data(), resultPair.second.data() +
|
||||
// resultPair.second.size(), receptionArray.data());
|
||||
// for(size_t i = 0; i < size; i++) {
|
||||
// CHECK(receptionArray[i] == i );
|
||||
// }
|
||||
//
|
||||
// {
|
||||
// auto resultPairLoc = SimplePool.getData(testStoreId);
|
||||
// REQUIRE(resultPairLoc.first == retval::CATCH_OK);
|
||||
// // data should be deleted when accessor goes out of scope.
|
||||
// }
|
||||
// resultPair = SimplePool.getData(testStoreId);
|
||||
// REQUIRE(resultPair.first == (int) StorageManagerIF::DATA_DOES_NOT_EXIST);
|
||||
//
|
||||
// result = SimplePool.addData(&testStoreId, testDataArray.data(), size);
|
||||
// REQUIRE(result == retval::CATCH_OK);
|
||||
// {
|
||||
// ConstStorageAccessor constAccessor(testStoreId);
|
||||
// result = SimplePool.getData(testStoreId, constAccessor);
|
||||
// REQUIRE(result == retval::CATCH_OK);
|
||||
// constAccessor.getDataCopy(receptionArray.data(), 20);
|
||||
// for(size_t i = 0; i < size; i++) {
|
||||
// CHECK(receptionArray[i] == i );
|
||||
// }
|
||||
// // likewise, data should be deleted when accessor gets out of scope.
|
||||
// }
|
||||
// resultPair = SimplePool.getData(testStoreId);
|
||||
// REQUIRE(resultPair.first == (int) StorageManagerIF::DATA_DOES_NOT_EXIST);
|
||||
//
|
||||
// result = SimplePool.addData(&testStoreId, testDataArray.data(), size);
|
||||
// {
|
||||
// resultPair = SimplePool.getData(testStoreId);
|
||||
// REQUIRE(resultPair.first == retval::CATCH_OK);
|
||||
// resultPair.second.release();
|
||||
// // now data should not be deleted anymore
|
||||
// }
|
||||
// resultPair = SimplePool.getData(testStoreId);
|
||||
// REQUIRE(resultPair.first == retval::CATCH_OK);
|
||||
// resultPair.second.getDataCopy(receptionArray.data(), 20);
|
||||
// for(size_t i = 0; i < size; i++) {
|
||||
// CHECK(receptionArray[i] == i );
|
||||
// }
|
||||
// }
|
||||
//
|
||||
//
|
||||
// SECTION("Simple tests modify functions") {
|
||||
// result = SimplePool.addData(&testStoreId, testDataArray.data(), size);
|
||||
// REQUIRE(result == retval::CATCH_OK);
|
||||
// {
|
||||
// StorageAccessor accessor(testStoreId);
|
||||
// result = SimplePool.modifyData(testStoreId, accessor);
|
||||
// REQUIRE(result == retval::CATCH_OK);
|
||||
// CHECK(accessor.getId() == testStoreId);
|
||||
// CHECK(accessor.size() == 10);
|
||||
// accessor.getDataCopy(receptionArray.data(), 20);
|
||||
// for(size_t i = 0; i < size; i++) {
|
||||
// CHECK(receptionArray[i] == i );
|
||||
// }
|
||||
// std::copy(accessor.data(), accessor.data() +
|
||||
// accessor.size(), receptionArray.data());
|
||||
// for(size_t i = 0; i < size; i++) {
|
||||
// CHECK(receptionArray[i] == i );
|
||||
// }
|
||||
// // data should be deleted when accessor goes out of scope
|
||||
// }
|
||||
// auto resultPair = SimplePool.getData(testStoreId);
|
||||
// REQUIRE(resultPair.first == (int) StorageManagerIF::DATA_DOES_NOT_EXIST);
|
||||
//
|
||||
// result = SimplePool.addData(&testStoreId, testDataArray.data(), size);
|
||||
// REQUIRE(result == retval::CATCH_OK);
|
||||
// {
|
||||
// auto resultPairLoc = SimplePool.modifyData(testStoreId);
|
||||
// REQUIRE(resultPairLoc.first == retval::CATCH_OK);
|
||||
// CHECK(resultPairLoc.second.getId() == testStoreId);
|
||||
// CHECK(resultPairLoc.second.size() == 10);
|
||||
// resultPairLoc.second.getDataCopy(receptionArray.data(), 20);
|
||||
// for(size_t i = 0; i < size; i++) {
|
||||
// CHECK(receptionArray[i] == i );
|
||||
// }
|
||||
// std::copy(resultPairLoc.second.data(), resultPairLoc.second.data() +
|
||||
// resultPairLoc.second.size(), receptionArray.data());
|
||||
// for(size_t i = 0; i < size; i++) {
|
||||
// CHECK(receptionArray[i] == i );
|
||||
// }
|
||||
// resultPairLoc.second.release();
|
||||
// // data should not be deleted when accessor goes out of scope
|
||||
// }
|
||||
// resultPair = SimplePool.getData(testStoreId);
|
||||
// REQUIRE(resultPair.first == retval::CATCH_OK);
|
||||
// }
|
||||
//
|
||||
//
|
||||
// SECTION("Write tests") {
|
||||
// result = SimplePool.addData(&testStoreId, testDataArray.data(), size);
|
||||
// REQUIRE(result == retval::CATCH_OK);
|
||||
// {
|
||||
// auto resultPair = SimplePool.modifyData(testStoreId);
|
||||
// REQUIRE(resultPair.first == retval::CATCH_OK);
|
||||
// testDataArray[9] = 42;
|
||||
// resultPair.second.write(testDataArray.data(), 10, 0);
|
||||
// // now data should not be deleted
|
||||
// resultPair.second.release();
|
||||
// }
|
||||
// auto resultConstPair = SimplePool.getData(testStoreId);
|
||||
// REQUIRE(resultConstPair.first == retval::CATCH_OK);
|
||||
//
|
||||
// resultConstPair.second.getDataCopy(receptionArray.data(), 10);
|
||||
// for(size_t i = 0; i < size-1; i++) {
|
||||
// CHECK(receptionArray[i] == i );
|
||||
// }
|
||||
// CHECK(receptionArray[9] == 42 );
|
||||
//
|
||||
// auto resultPair = SimplePool.modifyData(testStoreId);
|
||||
// REQUIRE(resultPair.first == retval::CATCH_OK);
|
||||
// result = resultPair.second.write(testDataArray.data(), 20, 0);
|
||||
// REQUIRE(result == retval::CATCH_FAILED);
|
||||
// result = resultPair.second.write(testDataArray.data(), 10, 5);
|
||||
// REQUIRE(result == retval::CATCH_FAILED);
|
||||
//
|
||||
// memset(testDataArray.data(), 42, 5);
|
||||
// result = resultPair.second.write(testDataArray.data(), 5, 5);
|
||||
// REQUIRE(result == retval::CATCH_OK);
|
||||
// resultConstPair = SimplePool.getData(testStoreId);
|
||||
// resultPair.second.getDataCopy(receptionArray.data(), 20);
|
||||
// for(size_t i = 5; i < 10; i++) {
|
||||
// CHECK(receptionArray[i] == 42 );
|
||||
// }
|
||||
//
|
||||
// }
|
||||
//}
|
296
unittest/tests/storagemanager/TestPool.cpp
Normal file
296
unittest/tests/storagemanager/TestPool.cpp
Normal file
@ -0,0 +1,296 @@
|
||||
//#include "CatchDefinitions.h"
|
||||
//
|
||||
//#include <config/objects/Factory.h>
|
||||
//#include <fsfw/objectmanager/ObjectManager.h>
|
||||
//#include <fsfw/storagemanager/LocalPool.h>
|
||||
//
|
||||
//#include <catch.hpp>
|
||||
//#include <CatchDefinitions.h>
|
||||
//
|
||||
//#include <cstring>
|
||||
//
|
||||
//
|
||||
//TEST_CASE( "Local Pool Simple Tests [1 Pool]" , "[TestPool]") {
|
||||
//// uint16_t numberOfElements[1] = {1};
|
||||
//// uint16_t sizeofElements[1] = {10};
|
||||
// LocalPool::LocalPoolConfig config = {{1, 10}};
|
||||
// LocalPool simplePool(0, config);
|
||||
// std::array<uint8_t, 20> testDataArray;
|
||||
// std::array<uint8_t, 20> receptionArray;
|
||||
// store_address_t testStoreId;
|
||||
// ReturnValue_t result = retval::CATCH_FAILED;
|
||||
// uint8_t *pointer = nullptr;
|
||||
// const uint8_t * constPointer = nullptr;
|
||||
//
|
||||
// for(size_t i = 0; i < testDataArray.size(); i++) {
|
||||
// testDataArray[i] = i;
|
||||
// }
|
||||
// size_t size = 10;
|
||||
//
|
||||
// SECTION ( "Basic tests") {
|
||||
// result = simplePool.addData(&testStoreId, testDataArray.data(), size);
|
||||
// REQUIRE(result == retval::CATCH_OK);
|
||||
// result = simplePool.getData(testStoreId, &constPointer, &size);
|
||||
// REQUIRE(result == retval::CATCH_OK);
|
||||
// memcpy(receptionArray.data(), constPointer, size);
|
||||
// for(size_t i = 0; i < size; i++) {
|
||||
// CHECK(receptionArray[i] == i );
|
||||
// }
|
||||
// memset(receptionArray.data(), 0, size);
|
||||
// result = simplePool.modifyData(testStoreId, &pointer, &size);
|
||||
// memcpy(receptionArray.data(), pointer, size);
|
||||
// REQUIRE(result == retval::CATCH_OK);
|
||||
// for(size_t i = 0; i < size; i++) {
|
||||
// CHECK(receptionArray[i] == i );
|
||||
// }
|
||||
// result = simplePool.deleteData(testStoreId);
|
||||
// REQUIRE(result == retval::CATCH_OK);
|
||||
// result = simplePool.addData(&testStoreId, testDataArray.data(), 15);
|
||||
// CHECK (result == (int) StorageManagerIF::DATA_TOO_LARGE);
|
||||
// }
|
||||
//
|
||||
// SECTION ( "Reservation Tests ") {
|
||||
// pointer = nullptr;
|
||||
// result = simplePool.getFreeElement(&testStoreId, size, &pointer);
|
||||
// REQUIRE (result == retval::CATCH_OK);
|
||||
// memcpy(pointer, testDataArray.data(), size);
|
||||
// constPointer = nullptr;
|
||||
// result = simplePool.getData(testStoreId, &constPointer, &size);
|
||||
//
|
||||
// REQUIRE (result == retval::CATCH_OK);
|
||||
// memcpy(receptionArray.data(), constPointer, size);
|
||||
// for(size_t i = 0; i < size; i++) {
|
||||
// CHECK(receptionArray[i] == i );
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// SECTION ( "Add, delete, add, add when full") {
|
||||
// result = simplePool.addData(&testStoreId, testDataArray.data(), size);
|
||||
// REQUIRE(result == retval::CATCH_OK);
|
||||
// result = simplePool.getData(testStoreId, &constPointer, &size);
|
||||
// REQUIRE( result == retval::CATCH_OK);
|
||||
// memcpy(receptionArray.data(), constPointer, size);
|
||||
// for(size_t i = 0; i < size; i++) {
|
||||
// CHECK(receptionArray[i] == i );
|
||||
// }
|
||||
//
|
||||
// result = simplePool.deleteData(testStoreId);
|
||||
// REQUIRE(result == retval::CATCH_OK);
|
||||
//
|
||||
// result = simplePool.addData(&testStoreId, testDataArray.data(), size);
|
||||
// REQUIRE(result == retval::CATCH_OK);
|
||||
// result = simplePool.getData(testStoreId, &constPointer, &size);
|
||||
// REQUIRE( result == retval::CATCH_OK);
|
||||
// memcpy(receptionArray.data(), constPointer, size);
|
||||
// for(size_t i = 0; i < size; i++) {
|
||||
// CHECK(receptionArray[i] == i );
|
||||
// }
|
||||
//
|
||||
// store_address_t newAddress;
|
||||
// result = simplePool.addData(&newAddress, testDataArray.data(), size);
|
||||
// REQUIRE(result == (int) StorageManagerIF::DATA_STORAGE_FULL);
|
||||
//
|
||||
// // Packet Index to high intentionally
|
||||
// newAddress.packetIndex = 2;
|
||||
// pointer = testDataArray.data();
|
||||
// result = simplePool.modifyData(newAddress, &pointer, &size);
|
||||
// REQUIRE(result == (int) StorageManagerIF::ILLEGAL_STORAGE_ID);
|
||||
//
|
||||
// result = simplePool.deleteData(newAddress);
|
||||
// REQUIRE(result == (int) StorageManagerIF::ILLEGAL_STORAGE_ID);
|
||||
//
|
||||
// newAddress.packetIndex = 0;
|
||||
// newAddress.poolIndex = 2;
|
||||
// result = simplePool.deleteData(newAddress);
|
||||
// REQUIRE(result == (int) StorageManagerIF::ILLEGAL_STORAGE_ID);
|
||||
// }
|
||||
//
|
||||
// SECTION ( "Initialize and clear store, delete with pointer") {
|
||||
// result = simplePool.initialize();
|
||||
// REQUIRE(result == retval::CATCH_OK);
|
||||
// result = simplePool.addData(&testStoreId, testDataArray.data(), size);
|
||||
// REQUIRE(result == retval::CATCH_OK);
|
||||
// simplePool.clearStore();
|
||||
// result = simplePool.addData(&testStoreId, testDataArray.data(), size);
|
||||
// REQUIRE(result == retval::CATCH_OK);
|
||||
// result = simplePool.modifyData(testStoreId, &pointer, &size);
|
||||
// REQUIRE(result == retval::CATCH_OK);
|
||||
// store_address_t newId;
|
||||
// result = simplePool.deleteData(pointer, size, &testStoreId);
|
||||
// REQUIRE(result == retval::CATCH_OK);
|
||||
// REQUIRE(testStoreId.raw != (uint32_t) StorageManagerIF::INVALID_ADDRESS);
|
||||
// result = simplePool.addData(&testStoreId, testDataArray.data(), size);
|
||||
// REQUIRE(result == retval::CATCH_OK);
|
||||
// }
|
||||
//}
|
||||
//
|
||||
//int runIdx = 0;
|
||||
//
|
||||
//TEST_CASE( "Local Pool Extended Tests [3 Pools]" , "[TestPool2]") {
|
||||
// LocalPool::LocalPoolConfig* config;
|
||||
// if(runIdx == 0) {
|
||||
// config = new LocalPool::LocalPoolConfig{{10, 5}, {5, 10}, {2, 20}};
|
||||
// }
|
||||
// else {
|
||||
// // shufle the order, they should be sort implictely so that the
|
||||
// // order is ascending for the page sizes.
|
||||
// config = new LocalPool::LocalPoolConfig{{5, 10}, {2, 20}, {10, 5}};
|
||||
// size_t lastSize = 0;
|
||||
// for(const auto& pair: *config) {
|
||||
// CHECK(pair.second > lastSize);
|
||||
// lastSize = pair.second;
|
||||
// }
|
||||
// }
|
||||
// runIdx++;
|
||||
//
|
||||
// LocalPool simplePool(0, *config);
|
||||
// std::array<uint8_t, 20> testDataArray;
|
||||
// std::array<uint8_t, 20> receptionArray;
|
||||
// store_address_t testStoreId;
|
||||
// ReturnValue_t result = retval::CATCH_FAILED;
|
||||
// for(size_t i = 0; i < testDataArray.size(); i++) {
|
||||
// testDataArray[i] = i;
|
||||
// }
|
||||
// size_t size = 0;
|
||||
//
|
||||
// SECTION ("Basic tests") {
|
||||
// size = 8;
|
||||
// result = simplePool.addData(&testStoreId, testDataArray.data(), size);
|
||||
// REQUIRE(result == retval::CATCH_OK);
|
||||
// // Should be on second page of the pool now for 8 bytes
|
||||
// CHECK(testStoreId.poolIndex == 1);
|
||||
// CHECK(testStoreId.packetIndex == 0);
|
||||
//
|
||||
// size = 15;
|
||||
// result = simplePool.addData(&testStoreId, testDataArray.data(), size);
|
||||
// REQUIRE(result == retval::CATCH_OK);
|
||||
// // Should be on third page of the pool now for 15 bytes
|
||||
// CHECK(testStoreId.poolIndex == 2);
|
||||
// CHECK(testStoreId.packetIndex == 0);
|
||||
//
|
||||
// result = simplePool.addData(&testStoreId, testDataArray.data(), size);
|
||||
// REQUIRE(result == retval::CATCH_OK);
|
||||
// // Should be on third page of the pool now for 15 bytes
|
||||
// CHECK(testStoreId.poolIndex == 2);
|
||||
// CHECK(testStoreId.packetIndex == 1);
|
||||
//
|
||||
// result = simplePool.addData(&testStoreId, testDataArray.data(), size);
|
||||
// // Should be on third page of the pool now for 15 bytes
|
||||
// REQUIRE(result == (int) LocalPool::DATA_STORAGE_FULL);
|
||||
//
|
||||
// size = 8;
|
||||
// result = simplePool.addData(&testStoreId, testDataArray.data(), size);
|
||||
// REQUIRE(result == retval::CATCH_OK);
|
||||
// // Should still work
|
||||
// CHECK(testStoreId.poolIndex == 1);
|
||||
// CHECK(testStoreId.packetIndex == 1);
|
||||
//
|
||||
// // fill the rest of the pool
|
||||
// for(uint8_t idx = 2; idx < 5; idx++) {
|
||||
// result = simplePool.addData(&testStoreId, testDataArray.data(), size);
|
||||
// REQUIRE(result == retval::CATCH_OK);
|
||||
// CHECK(testStoreId.poolIndex == 1);
|
||||
// CHECK(testStoreId.packetIndex == idx);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// SECTION ("Fill Count and Clearing") {
|
||||
// //SECTION("Basic tests");
|
||||
// uint8_t bytesWritten = 0;
|
||||
// simplePool.getFillCount(receptionArray.data(), &bytesWritten);
|
||||
// // fill count should be all zeros now.
|
||||
// CHECK(bytesWritten == 4);
|
||||
// CHECK(receptionArray[0] == 0);
|
||||
// CHECK(receptionArray[1] == 0);
|
||||
// CHECK(receptionArray[2] == 0);
|
||||
// CHECK(receptionArray[3] == 0);
|
||||
//
|
||||
// // now fill the store completely.
|
||||
// size = 5;
|
||||
// for(uint8_t idx = 0; idx < 10; idx++) {
|
||||
// result = simplePool.addData(&testStoreId, testDataArray.data(), size);
|
||||
// REQUIRE(result == retval::CATCH_OK);
|
||||
// CHECK(testStoreId.poolIndex == 0);
|
||||
// CHECK(testStoreId.packetIndex == idx);
|
||||
// }
|
||||
// size = 10;
|
||||
// for(uint8_t idx = 0; idx < 5; idx++) {
|
||||
// result = simplePool.addData(&testStoreId, testDataArray.data(), size);
|
||||
// REQUIRE(result == retval::CATCH_OK);
|
||||
// CHECK(testStoreId.poolIndex == 1);
|
||||
// CHECK(testStoreId.packetIndex == idx);
|
||||
// }
|
||||
// size = 20;
|
||||
// for(uint8_t idx = 0; idx < 2; idx++) {
|
||||
// result = simplePool.addData(&testStoreId, testDataArray.data(), size);
|
||||
// REQUIRE(result == retval::CATCH_OK);
|
||||
// CHECK(testStoreId.poolIndex == 2);
|
||||
// CHECK(testStoreId.packetIndex == idx);
|
||||
// }
|
||||
// bytesWritten = 0;
|
||||
// simplePool.getFillCount(receptionArray.data(), &bytesWritten);
|
||||
// // fill count should be all 100 now.
|
||||
// CHECK(bytesWritten == 4);
|
||||
// CHECK(receptionArray[0] == 100);
|
||||
// CHECK(receptionArray[1] == 100);
|
||||
// CHECK(receptionArray[2] == 100);
|
||||
// CHECK(receptionArray[3] == 100);
|
||||
//
|
||||
// // now clear the store
|
||||
// simplePool.clearStore();
|
||||
// bytesWritten = 0;
|
||||
// simplePool.getFillCount(receptionArray.data(), &bytesWritten);
|
||||
// CHECK(bytesWritten == 4);
|
||||
// CHECK(receptionArray[0] == 0);
|
||||
// CHECK(receptionArray[1] == 0);
|
||||
// CHECK(receptionArray[2] == 0);
|
||||
// CHECK(receptionArray[3] == 0);
|
||||
//
|
||||
// // now fill one page
|
||||
// size = 5;
|
||||
// for(uint8_t idx = 0; idx < 10; idx++) {
|
||||
// result = simplePool.addData(&testStoreId, testDataArray.data(), size);
|
||||
// REQUIRE(result == retval::CATCH_OK);
|
||||
// CHECK(testStoreId.poolIndex == 0);
|
||||
// CHECK(testStoreId.packetIndex == idx);
|
||||
// }
|
||||
// bytesWritten = 0;
|
||||
// simplePool.getFillCount(receptionArray.data(), &bytesWritten);
|
||||
// // First page full, median fill count is 33 %
|
||||
// CHECK(bytesWritten == 4);
|
||||
// CHECK(receptionArray[0] == 100);
|
||||
// CHECK(receptionArray[1] == 0);
|
||||
// CHECK(receptionArray[2] == 0);
|
||||
// CHECK(receptionArray[3] == 33);
|
||||
//
|
||||
// // now fill second page
|
||||
// size = 10;
|
||||
// for(uint8_t idx = 0; idx < 5; idx++) {
|
||||
// result = simplePool.addData(&testStoreId, testDataArray.data(), size);
|
||||
// REQUIRE(result == retval::CATCH_OK);
|
||||
// CHECK(testStoreId.poolIndex == 1);
|
||||
// CHECK(testStoreId.packetIndex == idx);
|
||||
// }
|
||||
// bytesWritten = 0;
|
||||
// simplePool.getFillCount(receptionArray.data(), &bytesWritten);
|
||||
// // First and second page full, median fill count is 66 %
|
||||
// CHECK(bytesWritten == 4);
|
||||
// CHECK(receptionArray[0] == 100);
|
||||
// CHECK(receptionArray[1] == 100);
|
||||
// CHECK(receptionArray[2] == 0);
|
||||
// CHECK(receptionArray[3] == 66);
|
||||
//
|
||||
// // now clear first page
|
||||
// simplePool.clearPage(0);
|
||||
// bytesWritten = 0;
|
||||
// simplePool.getFillCount(receptionArray.data(), &bytesWritten);
|
||||
// // Second page full, median fill count is 33 %
|
||||
// CHECK(bytesWritten == 4);
|
||||
// CHECK(receptionArray[0] == 0);
|
||||
// CHECK(receptionArray[1] == 100);
|
||||
// CHECK(receptionArray[2] == 0);
|
||||
// CHECK(receptionArray[3] == 33);
|
||||
// }
|
||||
//
|
||||
// delete(config);
|
||||
//}
|
8
unittest/tests/tests.mk
Normal file
8
unittest/tests/tests.mk
Normal file
@ -0,0 +1,8 @@
|
||||
CXXSRC += $(wildcard $(CURRENTPATH)/container/*.cpp)
|
||||
CXXSRC += $(wildcard $(CURRENTPATH)/action/*.cpp)
|
||||
CXXSRC += $(wildcard $(CURRENTPATH)/serialize/*.cpp)
|
||||
CXXSRC += $(wildcard $(CURRENTPATH)/storagemanager/*.cpp)
|
||||
|
||||
# OSAL not included for now.
|
||||
|
||||
INCLUDES += $(CURRENTPATH)
|
31
unittest/testtemplate/TestTemplate.cpp
Normal file
31
unittest/testtemplate/TestTemplate.cpp
Normal file
@ -0,0 +1,31 @@
|
||||
#include <fsfw/unittest/catch2/catch.hpp>
|
||||
#include <fsfw/unittest/core/CatchDefinitions.h>
|
||||
|
||||
|
||||
/**
|
||||
* @brief Template test file
|
||||
* @details
|
||||
* In each test case, the code outside the sections is executed
|
||||
* for EACH section.
|
||||
* The most common macros to perform tests are:
|
||||
* - CHECK(...): assert expression and continues even if it fails
|
||||
* - REQUIRE(...): test case fails if assertion fails
|
||||
*
|
||||
* Tests are generally sturctured in test cases and sections, see example
|
||||
* below.
|
||||
*
|
||||
* More Documentation:
|
||||
* - https://github.com/catchorg/Catch2
|
||||
* - https://github.com/catchorg/Catch2/blob/master/docs/assertions.md
|
||||
* - https://github.com/catchorg/Catch2/blob/master/docs/test-cases-and-sections.md
|
||||
*/
|
||||
TEST_CASE("Dummy Test" , "[DummyTest]") {
|
||||
uint8_t testVariable = 1;
|
||||
//perform set-up here
|
||||
CHECK(testVariable == 1);
|
||||
SECTION("TestSection") {
|
||||
// set-up is run for each section
|
||||
REQUIRE(testVariable == 1);
|
||||
}
|
||||
// perform tear-down here
|
||||
}
|
34
unittest/unlockRealtime.sh
Normal file
34
unittest/unlockRealtime.sh
Normal file
@ -0,0 +1,34 @@
|
||||
#!/bin/bash
|
||||
# Run this script to unlock all permissions to run the linux binaries
|
||||
# and create threads
|
||||
|
||||
binaries=$(find $directory -type f -name "*.elf")
|
||||
|
||||
echo Unlocking real time permissions for binaries and bash console...
|
||||
|
||||
# Set up the soft realtime limit to maximum (99)
|
||||
# Please note that the hard limit needs to be set to 99 too
|
||||
# for this to work (check with ulimit -Hr).
|
||||
# If that has not been done yet, add
|
||||
# <username> hard rtprio 99
|
||||
# to /etc/security/limits.conf
|
||||
# It is also necessary and recommended to add
|
||||
# <username> soft rtprio 99
|
||||
# as well. This can also be done in the command line
|
||||
# but would need to be done for each session.
|
||||
ulimit -Sr 99
|
||||
|
||||
for binary in ${binaries}; do
|
||||
sudo setcap 'cap_sys_nice=eip' ${binary}
|
||||
result=$?
|
||||
if [ ${result} = 0 ];then
|
||||
echo ${binary} was unlocked
|
||||
fi
|
||||
done
|
||||
|
||||
# sudo setcap 'cap_sys_nice=eip' /bin/bash
|
||||
# result=$?
|
||||
# if [ ${result} = 0 ];then
|
||||
# echo /bin/bash was unlocked
|
||||
# fi
|
||||
|
Loading…
Reference in New Issue
Block a user