Kernel improvements (#485)

* **New Features**
  * Added public accessors for querying module/device start and ready state.

* **Refactor**
  * Internal state moved to opaque internal objects; module/device/driver initializers now explicitly initialize internal pointers.
  * Lifecycle handling updated to construct/destruct internal state and use accessors.

* **Tests**
  * Tests updated to use public accessors and explicit construct/destruct lifecycle calls.

* **Chores**
  * Test build/include paths and small metadata updated.
This commit is contained in:
Ken Van Hoeylandt
2026-02-06 16:32:30 +01:00
committed by GitHub
parent 1757af859c
commit 79e43b093a
105 changed files with 338 additions and 331 deletions
+49
View File
@@ -0,0 +1,49 @@
#include "doctest.h"
#include <Tactility/Bundle.h>
using namespace tt;
TEST_CASE("boolean can be stored and retrieved") {
Bundle bundle;
bundle.putBool("key", true);
CHECK(bundle.hasBool("key"));
CHECK(bundle.getBool("key"));
bool opt_result = false;
CHECK(bundle.optBool("key", opt_result));
CHECK_EQ(opt_result, true);
}
TEST_CASE("int32 can be stored and retrieved") {
Bundle bundle;
bundle.putInt32("key", true);
CHECK(bundle.hasInt32("key"));
CHECK(bundle.getInt32("key"));
int32_t opt_result = false;
CHECK(bundle.optInt32("key", opt_result));
CHECK_EQ(opt_result, true);
}
TEST_CASE("string can be stored and retrieved") {
Bundle bundle;
bundle.putString("key", "test");
CHECK(bundle.hasString("key"));
CHECK_EQ(bundle.getString("key"), "test");
std::string opt_result;
CHECK(bundle.optString("key", opt_result));
CHECK_EQ(opt_result, "test");
}
TEST_CASE("bundle copy makes an actual copy") {
auto* original_ptr = new Bundle();
Bundle& original = *original_ptr;
original.putBool("bool", true);
original.putInt32("int32", 123);
original.putString("string", "text");
Bundle copy = original;
delete original_ptr;
CHECK_EQ(copy.getBool("bool"), true);
CHECK_EQ(copy.getInt32("int32"), 123);
CHECK_EQ(copy.getString("string"), "text");
}
+14
View File
@@ -0,0 +1,14 @@
#include "doctest.h"
#include <Tactility/file/File.h>
using namespace tt;
TEST_CASE("findOrCreateDirectory can create a directory tree without prefix") {
CHECK_EQ(file::findOrCreateDirectory("test1/test1", 0777), true);
// TODO: delete dirs
}
TEST_CASE("findOrCreateDirectory can create a directory tree with prefix") {
CHECK_EQ(file::findOrCreateDirectory("/tmp/test2", 0777), true);
// TODO: delete dirs
}
+59
View File
@@ -0,0 +1,59 @@
#define DOCTEST_CONFIG_IMPLEMENT
#include "doctest.h"
#include <cassert>
#include "FreeRTOS.h"
#include "task.h"
typedef struct {
int argc;
char** argv;
int result;
} TestTaskData;
void test_task(void* parameter) {
auto* data = (TestTaskData*)parameter;
doctest::Context context;
context.applyCommandLine(data->argc, data->argv);
// overrides
context.setOption("no-breaks", true); // don't break in the debugger when assertions fail
data->result = context.run();
vTaskEndScheduler();
vTaskDelete(nullptr);
}
int main(int argc, char** argv) {
TestTaskData data = {
.argc = argc,
.argv = argv,
.result = 0
};
BaseType_t task_result = xTaskCreate(
test_task,
"test_task",
8192,
&data,
1,
nullptr
);
assert(task_result == pdPASS);
vTaskStartScheduler();
return data.result;
}
// NOTE: This is normally provided by the platform kernel module, but that's not loaded for TactilityCore
extern "C" {
// Required for FreeRTOS
void vAssertCalled(unsigned long line, const char* const file) {
__assert_fail("assert failed", file, line, "");
}
}
+63
View File
@@ -0,0 +1,63 @@
#include "doctest.h"
#include <Tactility/StringUtils.h>
// region split
TEST_CASE("splitting an empty string results in an empty vector") {
auto result = tt::string::split("", ".");
CHECK_EQ(result.empty(), true);
}
TEST_CASE("splitting a string with a single token results in a vector with that token") {
auto result = tt::string::split("token", ".");
CHECK_EQ(result.size(), 1);
CHECK_EQ(result.front(), "token");
}
TEST_CASE("splitting a string with multiple tokens results in a vector with those tokens") {
auto result = tt::string::split("token1;token2;token3;", ";");
CHECK_EQ(result.size(), 3);
CHECK_EQ(result[0], "token1");
CHECK_EQ(result[1], "token2");
CHECK_EQ(result[2], "token3");
}
// endregion split
// region join
TEST_CASE("joining an empty vector results in an empty string") {
std::vector<std::string> tokens = {};
auto result = tt::string::join(tokens, ".");
CHECK_EQ(result, "");
}
TEST_CASE("joining a single token results in a string with that value") {
std::vector<std::string> tokens = {
"token"
};
auto result = tt::string::join(tokens, ".");
CHECK_EQ(result, "token");
}
TEST_CASE("joining multiple tokens results in a string with all the tokens and the delimiter") {
std::vector<std::string> tokens = {
"token1",
"token2",
"token3",
};
auto result = tt::string::join(tokens, ".");
CHECK_EQ(result, "token1.token2.token3");
}
TEST_CASE("joining with empty tokens leads to an extra delimiter") {
std::vector<std::string> tokens = {
"token1",
"",
"token2",
};
auto result = tt::string::join(tokens, ".");
CHECK_EQ(result, "token1..token2");
}
// endregion join
+42
View File
@@ -0,0 +1,42 @@
#pragma once
#include "doctest.h"
#include <unistd.h>
#include <Tactility/file/File.h>
/**
* A class for creating test files that can automatically clean themselves up.
*/
class TestFile {
const char* path;
bool autoClean;
public:
TestFile(const char* path, bool autoClean = true) : path(path), autoClean(autoClean) {
if (autoClean && exists()) {
remove();
}
}
~TestFile() {
if (autoClean && exists()) {
remove();
}
}
const char* getPath() const { return path; }
void writeData(const char* data) const {
CHECK_EQ(tt::file::writeString(path, data), true);
}
bool exists() const {
return access(path, F_OK) == 0;
}
void remove() const {
::remove(path);
}
};