Merge remote-tracking branch 'upstream/development' into develop
This commit is contained in:
commit
06e30684fe
@ -12,8 +12,9 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
|
||||
|
||||
## Fixes
|
||||
|
||||
- Bugfix for RM3100 MGM sensors. Z value was previously calculated
|
||||
with bytes of the X value.
|
||||
- HAL MGM3100 Handler: Use axis specific gain/scaling factors. Previously,
|
||||
only the X scaling factor was used.
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/724
|
||||
- DHB `setNormalDatapoolEntriesInvalid`: The default implementation did not set the validity
|
||||
to false correctly because the `read` and `write` calls were missing.
|
||||
- PUS TMTC creator module: Sequence flags were set to continuation segment (0b00) instead
|
||||
@ -40,6 +41,10 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
|
||||
## Added
|
||||
|
||||
- `Service9TimeManagement`: Add `DUMP_TIME` (129) subservice.
|
||||
- `TcpTmTcServer`: Allow setting the `SO_REUSEADDR` and `SO_REUSEPORT`
|
||||
option on the TCP server. CTOR prototype has changed and expects an explicit
|
||||
TCP configuration struct to be passed.
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/722
|
||||
- `DleParser` helper class to parse DLE encoded packets from a byte stream.
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/711
|
||||
- `UioMapper` is able to resolve symlinks now.
|
||||
|
96
automation/Jenkinsfile
vendored
96
automation/Jenkinsfile
vendored
@ -1,45 +1,87 @@
|
||||
pipeline {
|
||||
environment {
|
||||
BUILDDIR = 'cmake-build-tests'
|
||||
BUILDDIR_HOST = 'cmake-build-tests-host'
|
||||
BUILDDIR_LINUX = 'cmake-build-tests-linux'
|
||||
DOCDDIR = 'cmake-build-documentation'
|
||||
}
|
||||
agent {
|
||||
docker {
|
||||
image 'fsfw-ci:d6'
|
||||
args '--network host'
|
||||
args '--network host --sysctl fs.mqueue.msg_max=100'
|
||||
}
|
||||
}
|
||||
stages {
|
||||
stage('Clean') {
|
||||
steps {
|
||||
sh 'rm -rf $BUILDDIR'
|
||||
}
|
||||
}
|
||||
stage('Configure') {
|
||||
steps {
|
||||
dir(BUILDDIR) {
|
||||
sh 'cmake -DFSFW_OSAL=host -DFSFW_BUILD_TESTS=ON -DFSFW_CICD_BUILD=ON ..'
|
||||
stage('Host') {
|
||||
stages{
|
||||
stage('Clean') {
|
||||
steps {
|
||||
sh 'rm -rf $BUILDDIR_HOST'
|
||||
}
|
||||
}
|
||||
stage('Configure') {
|
||||
steps {
|
||||
dir(BUILDDIR_HOST) {
|
||||
sh 'cmake -DFSFW_OSAL=host -DFSFW_BUILD_TESTS=ON -DFSFW_CICD_BUILD=ON ..'
|
||||
}
|
||||
}
|
||||
}
|
||||
stage('Build') {
|
||||
steps {
|
||||
dir(BUILDDIR_HOST) {
|
||||
sh 'cmake --build . -j4'
|
||||
}
|
||||
}
|
||||
}
|
||||
stage('Unittests') {
|
||||
steps {
|
||||
dir(BUILDDIR_HOST) {
|
||||
sh 'cmake --build . -- fsfw-tests_coverage -j4'
|
||||
}
|
||||
}
|
||||
}
|
||||
stage('Valgrind') {
|
||||
steps {
|
||||
dir(BUILDDIR_HOST) {
|
||||
sh 'valgrind --leak-check=full --error-exitcode=1 ./fsfw-tests'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
stage('Build') {
|
||||
steps {
|
||||
dir(BUILDDIR) {
|
||||
sh 'cmake --build . -j4'
|
||||
stage('Linux') {
|
||||
stages{
|
||||
stage('Clean') {
|
||||
steps {
|
||||
sh 'rm -rf $BUILDDIR_LINUX'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
stage('Unittests') {
|
||||
steps {
|
||||
dir(BUILDDIR) {
|
||||
sh 'cmake --build . -- fsfw-tests_coverage -j4'
|
||||
stage('Configure') {
|
||||
steps {
|
||||
dir(BUILDDIR_LINUX) {
|
||||
sh 'cmake -DFSFW_OSAL=linux -DFSFW_BUILD_TESTS=ON -DFSFW_CICD_BUILD=ON ..'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
stage('Valgrind') {
|
||||
steps {
|
||||
dir(BUILDDIR) {
|
||||
sh 'valgrind --leak-check=full --error-exitcode=1 ./fsfw-tests'
|
||||
stage('Build') {
|
||||
steps {
|
||||
dir(BUILDDIR_LINUX) {
|
||||
sh 'cmake --build . -j4'
|
||||
}
|
||||
}
|
||||
}
|
||||
stage('Unittests') {
|
||||
steps {
|
||||
dir(BUILDDIR_LINUX) {
|
||||
sh 'cmake --build . -- fsfw-tests_coverage -j4'
|
||||
}
|
||||
}
|
||||
}
|
||||
stage('Valgrind') {
|
||||
steps {
|
||||
dir(BUILDDIR_LINUX) {
|
||||
sh 'valgrind --leak-check=full --error-exitcode=1 ./fsfw-tests'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -24,6 +24,7 @@ EventManager::EventManager(object_id_t setObjectId)
|
||||
}
|
||||
|
||||
EventManager::~EventManager() {
|
||||
listenerList.clear();
|
||||
QueueFactory::instance()->deleteMessageQueue(eventReportQueue);
|
||||
MutexFactory::instance()->deleteMutex(mutex);
|
||||
}
|
||||
@ -73,9 +74,14 @@ ReturnValue_t EventManager::registerListener(MessageQueueId_t listener,
|
||||
if (!result.second) {
|
||||
return returnvalue::FAILED;
|
||||
}
|
||||
|
||||
return returnvalue::OK;
|
||||
}
|
||||
|
||||
ReturnValue_t EventManager::unregisterListener(MessageQueueId_t listener) {
|
||||
return listenerList.erase(listener) == 1 ? returnvalue::OK : returnvalue::FAILED;
|
||||
}
|
||||
|
||||
ReturnValue_t EventManager::subscribeToEvent(MessageQueueId_t listener, EventId_t event) {
|
||||
return subscribeToEventRange(listener, event);
|
||||
}
|
||||
|
@ -31,6 +31,7 @@ class EventManager : public EventManagerIF, public ExecutableObjectIF, public Sy
|
||||
MessageQueueId_t getEventReportQueue();
|
||||
|
||||
ReturnValue_t registerListener(MessageQueueId_t listener, bool forwardAllButSelected = false);
|
||||
ReturnValue_t unregisterListener(MessageQueueId_t listener) override;
|
||||
ReturnValue_t subscribeToEvent(MessageQueueId_t listener, EventId_t event);
|
||||
ReturnValue_t subscribeToAllEventsFrom(MessageQueueId_t listener, object_id_t object);
|
||||
ReturnValue_t subscribeToEventRange(MessageQueueId_t listener, EventId_t idFrom = 0,
|
||||
|
@ -18,6 +18,7 @@ class EventManagerIF {
|
||||
|
||||
virtual ReturnValue_t registerListener(MessageQueueId_t listener,
|
||||
bool forwardAllButSelected = false) = 0;
|
||||
virtual ReturnValue_t unregisterListener(MessageQueueId_t listener) = 0;
|
||||
virtual ReturnValue_t subscribeToEvent(MessageQueueId_t listener, EventId_t event) = 0;
|
||||
virtual ReturnValue_t subscribeToAllEventsFrom(MessageQueueId_t listener, object_id_t object) = 0;
|
||||
virtual ReturnValue_t unsubscribeFromAllEvents(MessageQueueId_t listener, object_id_t object) = 0;
|
||||
|
@ -24,7 +24,7 @@ FailureIsolationBase::~FailureIsolationBase() {
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
manager->unsubscribeFromAllEvents(eventQueue->getId(), ownerId);
|
||||
manager->unregisterListener(eventQueue->getId());
|
||||
QueueFactory::instance()->deleteMessageQueue(eventQueue);
|
||||
}
|
||||
|
||||
|
@ -24,7 +24,7 @@ class MatchTree : public SerializeableMatcherIF<T>, public BinaryTree<Serializea
|
||||
MatchTree(iterator root, uint8_t maxDepth = -1)
|
||||
: BinaryTree<SerializeableMatcherIF<T>>(root.element), maxDepth(maxDepth) {}
|
||||
MatchTree() : BinaryTree<SerializeableMatcherIF<T>>(), maxDepth(-1) {}
|
||||
virtual ~MatchTree() {}
|
||||
virtual ~MatchTree() { clear(); }
|
||||
virtual bool match(T number) override { return matchesTree(number); }
|
||||
bool matchesTree(T number) {
|
||||
iterator iter = this->begin();
|
||||
@ -176,6 +176,45 @@ class MatchTree : public SerializeableMatcherIF<T>, public BinaryTree<Serializea
|
||||
return cleanUpElement(position);
|
||||
}
|
||||
|
||||
void clear() {
|
||||
Node* localRoot = BinaryTree<SerializeableMatcherIF<T>>::rootNode;
|
||||
|
||||
if (localRoot == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
Node* node = localRoot->left;
|
||||
|
||||
while (true) {
|
||||
if (node->left != nullptr) {
|
||||
node = node->left;
|
||||
continue;
|
||||
}
|
||||
if (node->right != nullptr) {
|
||||
node = node->right;
|
||||
continue;
|
||||
}
|
||||
if (node->parent == nullptr) {
|
||||
// this is the root node with no children
|
||||
if (node->value != nullptr) {
|
||||
cleanUpElement(iterator(node));
|
||||
}
|
||||
return;
|
||||
}
|
||||
// leaf
|
||||
{
|
||||
Node* parent = node->parent;
|
||||
if (parent->left == node) {
|
||||
parent->left = nullptr;
|
||||
} else {
|
||||
parent->right = nullptr;
|
||||
}
|
||||
cleanUpElement(iterator(node));
|
||||
node = parent;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
virtual ReturnValue_t cleanUpElement(iterator position) { return returnvalue::OK; }
|
||||
|
||||
bool matchSubtree(iterator iter, T number) {
|
||||
|
@ -6,8 +6,6 @@
|
||||
|
||||
HealthTable::HealthTable(object_id_t objectid) : SystemObject(objectid) {
|
||||
mutex = MutexFactory::instance()->createMutex();
|
||||
;
|
||||
|
||||
mapIterator = healthMap.begin();
|
||||
}
|
||||
|
||||
|
@ -10,13 +10,17 @@ InternalErrorReporter::InternalErrorReporter(object_id_t setObjectId, uint32_t m
|
||||
poolManager(this, commandQueue),
|
||||
internalErrorSid(setObjectId, InternalErrorDataset::ERROR_SET_ID),
|
||||
internalErrorDataset(this) {
|
||||
commandQueue = QueueFactory::instance()->createMessageQueue(messageQueueDepth);
|
||||
mutex = MutexFactory::instance()->createMutex();
|
||||
auto mqArgs = MqArgs(setObjectId, static_cast<void *>(this));
|
||||
commandQueue = QueueFactory::instance()->createMessageQueue(
|
||||
messageQueueDepth, MessageQueueMessage::MAX_MESSAGE_SIZE, &mqArgs);
|
||||
}
|
||||
|
||||
InternalErrorReporter::~InternalErrorReporter() { MutexFactory::instance()->deleteMutex(mutex); }
|
||||
InternalErrorReporter::~InternalErrorReporter() {
|
||||
MutexFactory::instance()->deleteMutex(mutex);
|
||||
QueueFactory::instance()->deleteMessageQueue(commandQueue);
|
||||
}
|
||||
|
||||
void InternalErrorReporter::setDiagnosticPrintout(bool enable) {
|
||||
this->diagnosticPrintout = enable;
|
||||
|
@ -23,9 +23,17 @@ void ObjectManager::setObjectFactoryFunction(produce_function_t objFactoryFunc,
|
||||
|
||||
ObjectManager::ObjectManager() = default;
|
||||
|
||||
void ObjectManager::clear() {
|
||||
if (objManagerInstance != nullptr) {
|
||||
delete objManagerInstance;
|
||||
objManagerInstance = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
ObjectManager::~ObjectManager() {
|
||||
for (auto const& iter : objectList) {
|
||||
delete iter.second;
|
||||
teardown = true;
|
||||
for (auto iter = objectList.begin(); iter != objectList.end(); iter = objectList.erase(iter)) {
|
||||
delete iter->second;
|
||||
}
|
||||
}
|
||||
|
||||
@ -53,6 +61,12 @@ ReturnValue_t ObjectManager::insert(object_id_t id, SystemObjectIF* object) {
|
||||
}
|
||||
|
||||
ReturnValue_t ObjectManager::remove(object_id_t id) {
|
||||
// this function is called during destruction of System Objects
|
||||
// disabeld for teardown to avoid iterator invalidation and
|
||||
// double free
|
||||
if (teardown) {
|
||||
return returnvalue::OK;
|
||||
}
|
||||
if (this->getSystemObject(id) != nullptr) {
|
||||
this->objectList.erase(id);
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
|
@ -24,12 +24,17 @@ class ObjectManager : public ObjectManagerIF {
|
||||
using produce_function_t = void (*)(void* args);
|
||||
|
||||
/**
|
||||
* Returns the single instance of TaskFactory.
|
||||
* Returns the single instance of ObjectManager.
|
||||
* The implementation of #instance is found in its subclasses.
|
||||
* Thus, we choose link-time variability of the instance.
|
||||
*/
|
||||
static ObjectManager* instance();
|
||||
|
||||
/**
|
||||
* Deletes the single instance of ObjectManager
|
||||
*/
|
||||
static void clear();
|
||||
|
||||
void setObjectFactoryFunction(produce_function_t prodFunc, void* args);
|
||||
|
||||
template <typename T>
|
||||
@ -66,6 +71,9 @@ class ObjectManager : public ObjectManagerIF {
|
||||
*/
|
||||
std::map<object_id_t, SystemObjectIF*> objectList;
|
||||
static ObjectManager* objManagerInstance;
|
||||
// used when the OM itself is deleted to modify behaviour of remove()
|
||||
// to avoid iterator invalidation and double free
|
||||
bool teardown = false;
|
||||
};
|
||||
|
||||
// Documentation can be found in the class method declaration above
|
||||
|
@ -1,10 +1,13 @@
|
||||
# Check the OS_FSFW variable
|
||||
if(FSFW_OSAL MATCHES "freertos")
|
||||
add_subdirectory(freertos)
|
||||
set(FSFW_OSAL_FREERTOS 1)
|
||||
elseif(FSFW_OSAL MATCHES "rtems")
|
||||
add_subdirectory(rtems)
|
||||
set(FSFW_OSAL_RTEMS 1)
|
||||
elseif(FSFW_OSAL MATCHES "linux")
|
||||
add_subdirectory(linux)
|
||||
set(FSFW_OSAL_LINUX 1)
|
||||
elseif(FSFW_OSAL MATCHES "host")
|
||||
add_subdirectory(host)
|
||||
if(WIN32)
|
||||
@ -13,18 +16,20 @@ elseif(FSFW_OSAL MATCHES "host")
|
||||
# We still need to pull in some Linux specific sources
|
||||
target_sources(${LIB_FSFW_NAME} PUBLIC linux/tcpipHelpers.cpp)
|
||||
endif()
|
||||
|
||||
set(FSFW_OSAL_HOST 1)
|
||||
else()
|
||||
|
||||
message(
|
||||
WARNING
|
||||
"${MSG_PREFIX} The FSFW_OSAL variable was not set. Assuming host OS..")
|
||||
|
||||
# Not set. Assumuing this is a host build, try to determine host OS
|
||||
if(WIN32)
|
||||
add_subdirectory(host)
|
||||
add_subdirectory(windows)
|
||||
set(FSFW_OSAL_HOST 1)
|
||||
elseif(UNIX)
|
||||
add_subdirectory(linux)
|
||||
set(FSFW_OSAL_LINUX 1)
|
||||
else()
|
||||
# MacOS or other OSes have not been tested yet / are not supported.
|
||||
message(FATAL_ERROR "The host OS could not be determined! Aborting.")
|
||||
@ -33,3 +38,5 @@ else()
|
||||
endif()
|
||||
|
||||
add_subdirectory(common)
|
||||
|
||||
configure_file(osal.h.in ${CMAKE_BINARY_DIR}/fsfw/osal/osal.h)
|
||||
|
@ -79,6 +79,7 @@ class TcpTmTcServer : public SystemObject, public TcpIpBase, public ExecutableOb
|
||||
*/
|
||||
bool reusePort = false;
|
||||
};
|
||||
|
||||
enum class ReceptionModes { SPACE_PACKETS };
|
||||
|
||||
static const std::string DEFAULT_SERVER_PORT;
|
||||
|
@ -21,7 +21,7 @@ MessageQueue::MessageQueue(uint32_t messageDepth, size_t maxMessageSize, MqArgs*
|
||||
attributes.mq_msgsize = maxMessageSize;
|
||||
attributes.mq_flags = 0; // Flags are ignored on Linux during mq_open
|
||||
// Set the name of the queue. The slash is mandatory!
|
||||
sprintf(name, "/FSFW_MQ%u\n", queueCounter++);
|
||||
sprintf(name, "/FSFW_MQ%u", queueCounter++);
|
||||
|
||||
// Create a nonblocking queue if the name is available (the queue is read
|
||||
// and writable for the owner as well as the group)
|
||||
|
36
src/fsfw/osal/osal.h.in
Normal file
36
src/fsfw/osal/osal.h.in
Normal file
@ -0,0 +1,36 @@
|
||||
#pragma once
|
||||
|
||||
namespace osal {
|
||||
enum osalTarget{
|
||||
HOST,
|
||||
LINUX,
|
||||
WINDOWS,
|
||||
FREERTOS,
|
||||
RTEMS,
|
||||
};
|
||||
|
||||
#cmakedefine FSFW_OSAL_HOST
|
||||
#cmakedefine FSFW_OSAL_LINUX
|
||||
#cmakedefine FSFW_OSAL_WINDOWS
|
||||
#cmakedefine FSFW_OSAL_FREERTOS
|
||||
#cmakedefine FSFW_OSAL_RTEMS
|
||||
|
||||
|
||||
constexpr osalTarget getTarget() {
|
||||
#ifdef FSFW_OSAL_HOST
|
||||
return HOST;
|
||||
#endif
|
||||
#ifdef FSFW_OSAL_LINUX
|
||||
return LINUX;
|
||||
#endif
|
||||
#ifdef FSFW_OSAL_WINDOWS
|
||||
return WINDOWS;
|
||||
#endif
|
||||
#ifdef FSFW_OSAL_FREERTOS
|
||||
return FREERTOS;
|
||||
#endif
|
||||
#ifdef FSFW_OSAL_RTEMS
|
||||
return RTEMS;
|
||||
#endif
|
||||
}
|
||||
};
|
@ -31,4 +31,7 @@ int customSetup() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int customTeardown() { return 0; }
|
||||
int customTeardown() {
|
||||
ObjectManager::clear();
|
||||
return 0;
|
||||
}
|
||||
|
@ -9,7 +9,9 @@ DeviceHandlerCommander::DeviceHandlerCommander(object_id_t objectId)
|
||||
QUEUE_SIZE, MessageQueueMessage::MAX_MESSAGE_SIZE, &mqArgs);
|
||||
}
|
||||
|
||||
DeviceHandlerCommander::~DeviceHandlerCommander() {}
|
||||
DeviceHandlerCommander::~DeviceHandlerCommander() {
|
||||
QueueFactory::instance()->deleteMessageQueue(commandQueue);
|
||||
}
|
||||
|
||||
ReturnValue_t DeviceHandlerCommander::performOperation(uint8_t operationCode) {
|
||||
readCommandQueue();
|
||||
|
@ -1,46 +1,38 @@
|
||||
|
||||
#ifdef LINUX
|
||||
|
||||
/*
|
||||
#include <fsfw/osal/osal.h>
|
||||
#include <fsfw/tasks/SemaphoreFactory.h>
|
||||
#include <fsfw/timemanager/Stopwatch.h>
|
||||
|
||||
#include "catch.hpp"
|
||||
#include "core/CatchDefinitions.h"
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
|
||||
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) ==
|
||||
returnvalue::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() == returnvalue::OK);
|
||||
}
|
||||
SemaphoreFactory::instance()->deleteSemaphore(binSemaph);
|
||||
// perform tear-down here
|
||||
// binary semaphores currently only supported on linux
|
||||
#ifdef FSFW_OSAL_LINUX
|
||||
|
||||
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) == returnvalue::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() == returnvalue::OK);
|
||||
}
|
||||
SemaphoreFactory::instance()->deleteSemaphore(binSemaph);
|
||||
// perform tear-down here
|
||||
}
|
||||
|
||||
|
||||
TEST_CASE("Counting Semaphore Test" , "[CountingSemaph]") {
|
||||
SECTION("Simple Test") {
|
||||
|
||||
}
|
||||
TEST_CASE("Counting Semaphore Test", "[CountingSemaph]") {
|
||||
SECTION("Simple Test") {}
|
||||
}
|
||||
*/
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue
Block a user