unittest now contained directly

This commit is contained in:
2020-10-20 17:11:23 +02:00
parent c677358343
commit 865ea3386c
78 changed files with 22684 additions and 4 deletions

View File

@ -0,0 +1,26 @@
#include <unittest/internal/InternalUnitTester.h>
#include <unittest/internal/IntTestMq.h>
#include <unittest/internal/IntTestSemaphore.h>
#include <unittest/internal/IntTestSerialization.h>
#include <unittest/internal/UnittDefinitions.h>
#include <unittest/internal/IntTestMutex.h>
#include <cstdlib>
InternalUnitTester::InternalUnitTester() {}
InternalUnitTester::~InternalUnitTester() {}
ReturnValue_t InternalUnitTester::performTests() {
sif::info << "Running internal unit tests..\r\n" << std::flush;
testserialize::test_serialization();
testmq::testMq();
testsemaph::testBinSemaph();
testsemaph::testCountingSemaph();
testmutex::testMutex();
sif::info << "Internal unit tests finished.\r\n" << std::flush;
return RETURN_OK;
}

View File

@ -0,0 +1,29 @@
#ifndef FRAMEWORK_TEST_UNITTESTCLASS_H_
#define FRAMEWORK_TEST_UNITTESTCLASS_H_
#include <unittest/internal/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
*/
ReturnValue_t performTests();
};
#endif /* FRAMEWORK_TEST_UNITTESTCLASS_H_ */

View 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;
}

View 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_ */

View File

@ -0,0 +1,52 @@
#include <fsfw/ipc/MessageQueueIF.h>
#include <fsfw/ipc/QueueFactory.h>
#include <unittest/internal/IntTestMq.h>
#include <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);
}
}

View File

@ -0,0 +1,9 @@
#ifndef UNITTEST_INTERNAL_INTESTMQ_H_
#define UNITTEST_INTERNAL_INTESTMQ_H_
namespace testmq {
void testMq();
}
#endif /* UNITTEST_INTERNAL_INTESTMQ_H_ */

View File

@ -0,0 +1,41 @@
#include <unittest/internal/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);
}
}

View File

@ -0,0 +1,10 @@
#ifndef UNITTEST_INTERNAL_INTTESTMUTEX_H_
#define UNITTEST_INTERNAL_INTTESTMUTEX_H_
namespace testmutex {
void testMutex();
}
#endif /* UNITTEST_INTERNAL_INTTESTMUTEX_H_ */

View File

@ -0,0 +1,159 @@
#include <fsfw/tasks/SemaphoreFactory.h>
#include <unittest/internal/UnittDefinitions.h>
#include <fsfw/serviceinterface/ServiceInterfaceStream.h>
#include <fsfw/timemanager/Stopwatch.h>
#include <unittest/internal/IntTestSemaphore.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);
}
}

View 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_ */

View File

@ -0,0 +1,230 @@
#include <unittest/internal/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;
}

View 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_ */