Create TactilityFreertos subproject (#440)
This commit is contained in:
committed by
GitHub
parent
a4dc633063
commit
7283920def
@@ -20,5 +20,6 @@ add_test(NAME TactilityCoreTests
|
||||
|
||||
target_link_libraries(TactilityCoreTests PUBLIC
|
||||
TactilityCore
|
||||
TactilityFreeRtos
|
||||
freertos_kernel
|
||||
)
|
||||
|
||||
@@ -1,38 +0,0 @@
|
||||
#include "doctest.h"
|
||||
#include <Tactility/TactilityCore.h>
|
||||
#include <Tactility/Dispatcher.h>
|
||||
|
||||
using namespace tt;
|
||||
|
||||
TEST_CASE("dispatcher should not call callback if consume isn't called") {
|
||||
int counter = 0;
|
||||
Dispatcher dispatcher;
|
||||
dispatcher.dispatch([&counter]() { counter++; });
|
||||
kernel::delayTicks(10);
|
||||
|
||||
CHECK_EQ(counter, 0);
|
||||
}
|
||||
|
||||
TEST_CASE("dispatcher should be able to dealloc when message is not consumed") {
|
||||
auto* dispatcher = new Dispatcher();
|
||||
auto context = std::make_shared<uint32_t>();
|
||||
dispatcher->dispatch([]() { /* NO-OP */ });
|
||||
delete dispatcher;
|
||||
}
|
||||
|
||||
TEST_CASE("dispatcher should call callback when consume is called") {
|
||||
int counter = 0;
|
||||
Dispatcher dispatcher;
|
||||
|
||||
dispatcher.dispatch([&counter]() { counter++; });
|
||||
dispatcher.consume(100);
|
||||
|
||||
CHECK_EQ(counter, 1);
|
||||
}
|
||||
|
||||
TEST_CASE("message should be passed on correctly") {
|
||||
Dispatcher dispatcher;
|
||||
|
||||
dispatcher.dispatch([]() { /* NO-OP */ });
|
||||
dispatcher.consume(100);
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
#include "doctest.h"
|
||||
#include <Tactility/TactilityCore.h>
|
||||
#include <Tactility/DispatcherThread.h>
|
||||
|
||||
using namespace tt;
|
||||
|
||||
TEST_CASE("DispatcherThread state test") {
|
||||
DispatcherThread thread("test");
|
||||
CHECK_EQ(thread.isStarted(), false);
|
||||
|
||||
thread.start();
|
||||
CHECK_EQ(thread.isStarted(), true);
|
||||
|
||||
thread.stop();
|
||||
CHECK_EQ(thread.isStarted(), false);
|
||||
}
|
||||
|
||||
TEST_CASE("DispatcherThread should consume jobs") {
|
||||
DispatcherThread thread("test");
|
||||
thread.start();
|
||||
int counter = 0;
|
||||
|
||||
thread.dispatch([&counter]() { counter++; });
|
||||
|
||||
tt::kernel::delayTicks(10);
|
||||
|
||||
CHECK_EQ(counter, 1);
|
||||
thread.stop();
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
#include "doctest.h"
|
||||
#include <Tactility/Lock.h>
|
||||
#include <Tactility/Mutex.h>
|
||||
#include <Tactility/Semaphore.h>
|
||||
|
||||
using namespace tt;
|
||||
|
||||
TEST_CASE("withLock() locks correctly on Semaphore") {
|
||||
auto semaphore = std::make_shared<Semaphore>(2U);
|
||||
semaphore->withLock([semaphore](){
|
||||
CHECK_EQ(semaphore->getAvailable(), 1);
|
||||
});
|
||||
}
|
||||
|
||||
TEST_CASE("withLock() unlocks correctly on Semaphore") {
|
||||
auto semaphore = std::make_shared<Semaphore>(2U);
|
||||
semaphore->withLock([=](){
|
||||
// NO-OP
|
||||
});
|
||||
|
||||
CHECK_EQ(semaphore->getAvailable(), 2);
|
||||
}
|
||||
|
||||
TEST_CASE("withLock() locks correctly on Mutex") {
|
||||
auto mutex = std::make_shared<Mutex>();
|
||||
mutex->withLock([mutex](){
|
||||
CHECK_EQ(mutex->lock(1), false);
|
||||
});
|
||||
}
|
||||
|
||||
TEST_CASE("withLock() unlocks correctly on Mutex") {
|
||||
auto mutex = std::make_shared<Mutex>();
|
||||
mutex->withLock([=](){
|
||||
// NO-OP
|
||||
});
|
||||
|
||||
CHECK_EQ(mutex->lock(1), true);
|
||||
CHECK_EQ(mutex->unlock(), true);
|
||||
}
|
||||
@@ -48,6 +48,8 @@ int main(int argc, char** argv) {
|
||||
assert(task_result == pdPASS);
|
||||
|
||||
vTaskStartScheduler();
|
||||
|
||||
return data.result;
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
|
||||
@@ -1,86 +0,0 @@
|
||||
#include "doctest.h"
|
||||
#include <Tactility/MessageQueue.h>
|
||||
|
||||
using namespace tt;
|
||||
|
||||
TEST_CASE("message queue capacity should be correct") {
|
||||
MessageQueue queue(10, 1);
|
||||
|
||||
uint32_t capacity = queue.getCapacity();
|
||||
CHECK_EQ(capacity, 10);
|
||||
}
|
||||
|
||||
TEST_CASE("message queue initial count should be 0") {
|
||||
MessageQueue queue(10, 1);
|
||||
|
||||
uint32_t count = queue.getCount();
|
||||
CHECK_EQ(count, 0);
|
||||
}
|
||||
|
||||
TEST_CASE("message queue message size should be correct") {
|
||||
MessageQueue queue(1, 123);
|
||||
|
||||
uint32_t message_size = queue.getMessageSize();
|
||||
CHECK_EQ(message_size, 123);
|
||||
}
|
||||
|
||||
TEST_CASE("message queue count should increase when message is added") {
|
||||
MessageQueue queue(10, sizeof(uint32_t));
|
||||
|
||||
uint32_t message = 123;
|
||||
queue.put(&message, 100);
|
||||
uint32_t count = queue.getCount();
|
||||
CHECK_EQ(count, 1);
|
||||
}
|
||||
|
||||
TEST_CASE("message queue count should be 0 when message is added and queue is reset") {
|
||||
MessageQueue queue(10, sizeof(uint32_t));
|
||||
|
||||
uint32_t message = 123;
|
||||
|
||||
queue.put(&message, 100);
|
||||
queue.reset();
|
||||
uint32_t count = queue.getCount();
|
||||
CHECK_EQ(count, 0);
|
||||
}
|
||||
|
||||
TEST_CASE("message queue consumption should work") {
|
||||
MessageQueue queue(10, sizeof(uint32_t));
|
||||
|
||||
uint32_t out_message = 123;
|
||||
queue.put(&out_message, 100);
|
||||
|
||||
uint32_t in_message = 0;
|
||||
queue.get(&in_message, 100);
|
||||
CHECK_EQ(in_message, 123);
|
||||
}
|
||||
|
||||
TEST_CASE("message queue count should decrease when message is consumed") {
|
||||
MessageQueue queue(10, sizeof(uint32_t));
|
||||
|
||||
uint32_t out_message = 123;
|
||||
queue.put(&out_message, 100);
|
||||
|
||||
uint32_t in_message = 0;
|
||||
queue.get(&in_message, 100);
|
||||
uint32_t count = queue.getCount();
|
||||
CHECK_EQ(count, 0);
|
||||
}
|
||||
|
||||
TEST_CASE("message queue should make copy of data") {
|
||||
// Given a number that we can later delete
|
||||
MessageQueue queue(1, sizeof(int32_t));
|
||||
const int32_t test_value = 123;
|
||||
auto* number = new int32_t();
|
||||
*number = test_value;
|
||||
|
||||
// When we put the number in the queue and then delete it
|
||||
queue.put(number, 100);
|
||||
delete number;
|
||||
|
||||
// We want to verify that the value was copied into the queue and retrieved properly
|
||||
int32_t queue_number = 0;
|
||||
CHECK_EQ(queue.get(&queue_number, 100), true);
|
||||
CHECK_EQ(queue_number, test_value);
|
||||
}
|
||||
|
||||
@@ -1,49 +0,0 @@
|
||||
#include "doctest.h"
|
||||
#include <Tactility/TactilityCore.h>
|
||||
#include <Tactility/Mutex.h>
|
||||
|
||||
using namespace tt;
|
||||
|
||||
TEST_CASE("a mutex can block a thread") {
|
||||
auto mutex = Mutex();
|
||||
mutex.lock(portMAX_DELAY);
|
||||
|
||||
Thread thread = Thread(
|
||||
"thread",
|
||||
1024,
|
||||
[&mutex]() {
|
||||
mutex.lock(portMAX_DELAY);
|
||||
return 0;
|
||||
}
|
||||
);
|
||||
thread.start();
|
||||
|
||||
kernel::delayMillis(5);
|
||||
CHECK_EQ(thread.getState(), Thread::State::Running);
|
||||
|
||||
mutex.unlock();
|
||||
|
||||
kernel::delayMillis(5);
|
||||
CHECK_EQ(thread.getState(), Thread::State::Stopped);
|
||||
|
||||
thread.join();
|
||||
}
|
||||
|
||||
TEST_CASE("a Mutex can be locked exactly once") {
|
||||
Mutex mutex;
|
||||
CHECK_EQ(mutex.lock(0), true);
|
||||
CHECK_EQ(mutex.lock(0), false);
|
||||
CHECK_EQ(mutex.unlock(), true);
|
||||
}
|
||||
|
||||
TEST_CASE("unlocking a Mutex without locking returns false") {
|
||||
Mutex mutex;
|
||||
CHECK_EQ(mutex.unlock(), false);
|
||||
}
|
||||
|
||||
TEST_CASE("unlocking a Mutex twice returns false on the second attempt") {
|
||||
Mutex mutex;
|
||||
CHECK_EQ(mutex.lock(0), true);
|
||||
CHECK_EQ(mutex.unlock(), true);
|
||||
CHECK_EQ(mutex.unlock(), false);
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
#include "doctest.h"
|
||||
#include <Tactility/TactilityCore.h>
|
||||
#include <Tactility/PubSub.h>
|
||||
|
||||
using namespace tt;
|
||||
|
||||
TEST_CASE("PubSub publishing with no subscriptions should not crash") {
|
||||
PubSub<int> pubsub;
|
||||
pubsub.publish(1);
|
||||
}
|
||||
|
||||
TEST_CASE("PubSub subscription receives published data") {
|
||||
PubSub<int> pubsub;
|
||||
int value = 0;
|
||||
|
||||
auto subscription = pubsub.subscribe([&value](auto newValue) {
|
||||
value = newValue;
|
||||
});
|
||||
pubsub.publish(1);
|
||||
|
||||
CHECK_EQ(value, 1);
|
||||
}
|
||||
|
||||
TEST_CASE("PubSub unsubscribed subscription does not receive published data") {
|
||||
PubSub<int> pubsub;
|
||||
int value = 0;
|
||||
|
||||
auto subscription = pubsub.subscribe([&value](auto newValue) {
|
||||
value = newValue;
|
||||
});
|
||||
pubsub.unsubscribe(subscription);
|
||||
pubsub.publish(1);
|
||||
|
||||
CHECK_EQ(value, 0);
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
#include "doctest.h"
|
||||
#include <Tactility/Semaphore.h>
|
||||
|
||||
using namespace tt;
|
||||
|
||||
// We want a distinct test for 1 item, because it creates the Semaphore differently
|
||||
TEST_CASE("a Semaphore with max count of 1 can be acquired exactly once") {
|
||||
auto semaphore = Semaphore(1);
|
||||
CHECK_EQ(semaphore.acquire(0), true);
|
||||
CHECK_EQ(semaphore.getAvailable(), 0);
|
||||
CHECK_EQ(semaphore.acquire(0), false);
|
||||
CHECK_EQ(semaphore.release(), true);
|
||||
CHECK_EQ(semaphore.getAvailable(), 1);
|
||||
}
|
||||
|
||||
TEST_CASE("a Semaphore with max count of 2 can be acquired exactly twice") {
|
||||
auto semaphore = Semaphore(2);
|
||||
CHECK_EQ(semaphore.acquire(0), true);
|
||||
CHECK_EQ(semaphore.getAvailable(), 1);
|
||||
CHECK_EQ(semaphore.acquire(0), true);
|
||||
CHECK_EQ(semaphore.getAvailable(), 0);
|
||||
CHECK_EQ(semaphore.acquire(0), false);
|
||||
CHECK_EQ(semaphore.release(), true);
|
||||
CHECK_EQ(semaphore.getAvailable(), 1);
|
||||
CHECK_EQ(semaphore.release(), true);
|
||||
CHECK_EQ(semaphore.getAvailable(), 2);
|
||||
}
|
||||
|
||||
TEST_CASE("the semaphore count should be correct initially") {
|
||||
auto semaphore_a = Semaphore(2);
|
||||
CHECK_EQ(semaphore_a.getAvailable(), 2);
|
||||
|
||||
auto semaphore_b = Semaphore(2, 0);
|
||||
CHECK_EQ(semaphore_b.getAvailable(), 0);
|
||||
}
|
||||
@@ -1,100 +0,0 @@
|
||||
#include "doctest.h"
|
||||
#include <Tactility/TactilityCore.h>
|
||||
#include <Tactility/Thread.h>
|
||||
|
||||
using namespace tt;
|
||||
|
||||
TEST_CASE("when a thread is started then its callback should be called") {
|
||||
bool has_called = false;
|
||||
auto* thread = new Thread(
|
||||
"immediate return task",
|
||||
4096,
|
||||
[&has_called]() {
|
||||
has_called = true;
|
||||
return 0;
|
||||
}
|
||||
);
|
||||
|
||||
CHECK(!has_called);
|
||||
thread->start();
|
||||
thread->join();
|
||||
delete thread;
|
||||
CHECK(has_called);
|
||||
}
|
||||
|
||||
TEST_CASE("a thread can be started and stopped") {
|
||||
bool interrupted = false;
|
||||
auto* thread = new Thread(
|
||||
"interruptable thread",
|
||||
4096,
|
||||
[&interrupted]() {
|
||||
while (!interrupted) {
|
||||
kernel::delayMillis(5);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
);
|
||||
|
||||
CHECK(thread);
|
||||
thread->start();
|
||||
interrupted = true;
|
||||
thread->join();
|
||||
delete thread;
|
||||
}
|
||||
|
||||
TEST_CASE("thread id should only be set at when thread is started") {
|
||||
bool interrupted = false;
|
||||
auto* thread = new Thread(
|
||||
"interruptable thread",
|
||||
4096,
|
||||
[&interrupted]() {
|
||||
while (!interrupted) {
|
||||
kernel::delayMillis(5);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
);
|
||||
CHECK_EQ(thread->getId(), nullptr);
|
||||
thread->start();
|
||||
CHECK_NE(thread->getId(), nullptr);
|
||||
interrupted = true;
|
||||
thread->join();
|
||||
CHECK_EQ(thread->getId(), nullptr);
|
||||
delete thread;
|
||||
}
|
||||
|
||||
TEST_CASE("thread state should be correct") {
|
||||
bool interrupted = false;
|
||||
auto* thread = new Thread(
|
||||
"interruptable thread",
|
||||
4096,
|
||||
[&interrupted]() {
|
||||
while (!interrupted) {
|
||||
kernel::delayMillis(5);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
);
|
||||
CHECK_EQ(thread->getState(), Thread::State::Stopped);
|
||||
thread->start();
|
||||
Thread::State state = thread->getState();
|
||||
CHECK((state == Thread::State::Starting || state == Thread::State::Running));
|
||||
interrupted = true;
|
||||
thread->join();
|
||||
CHECK_EQ(thread->getState(), Thread::State::Stopped);
|
||||
delete thread;
|
||||
}
|
||||
|
||||
TEST_CASE("thread id should only be set at when thread is started") {
|
||||
int code = 123;
|
||||
auto* thread = new Thread(
|
||||
"return code",
|
||||
4096,
|
||||
[&code]() { return code; }
|
||||
);
|
||||
thread->start();
|
||||
thread->join();
|
||||
CHECK_EQ(thread->getReturnCode(), code);
|
||||
delete thread;
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
#include "doctest.h"
|
||||
#include <Tactility/TactilityCore.h>
|
||||
#include <Tactility/Timer.h>
|
||||
|
||||
using namespace tt;
|
||||
|
||||
TEST_CASE("TimerType::Periodic timers can be stopped and restarted") {
|
||||
int counter = 0;
|
||||
auto* timer = new Timer(Timer::Type::Periodic, [&counter]() { counter++; });
|
||||
timer->start(1);
|
||||
kernel::delayTicks(10);
|
||||
timer->stop();
|
||||
timer->start(1);
|
||||
kernel::delayTicks(10);
|
||||
timer->stop();
|
||||
delete timer;
|
||||
|
||||
CHECK_GE(counter, 2);
|
||||
}
|
||||
|
||||
TEST_CASE("TimerType::Periodic calls the callback periodically") {
|
||||
int ticks_to_run = 10;
|
||||
int counter = 0;
|
||||
auto* timer = new Timer(Timer::Type::Periodic, [&counter]() { counter++; });
|
||||
timer->start(1);
|
||||
kernel::delayTicks(ticks_to_run);
|
||||
timer->stop();
|
||||
delete timer;
|
||||
|
||||
CHECK_EQ(counter, ticks_to_run);
|
||||
}
|
||||
|
||||
TEST_CASE("restarting TimerType::Once timers calls the callback again") {
|
||||
int counter = 0;
|
||||
auto* timer = new Timer(Timer::Type::Once, [&counter]() { counter++; });
|
||||
timer->start(1);
|
||||
kernel::delayTicks(10);
|
||||
timer->stop();
|
||||
timer->start(1);
|
||||
kernel::delayTicks(10);
|
||||
timer->stop();
|
||||
delete timer;
|
||||
|
||||
CHECK_EQ(counter, 2);
|
||||
}
|
||||
Reference in New Issue
Block a user