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:
committed by
GitHub
parent
1757af859c
commit
79e43b093a
@@ -4,7 +4,7 @@ enable_language(C CXX ASM)
|
||||
|
||||
set(CMAKE_CXX_COMPILER g++)
|
||||
|
||||
file(GLOB_RECURSE TEST_SOURCES ${PROJECT_SOURCE_DIR}/*.cpp)
|
||||
file(GLOB_RECURSE TEST_SOURCES ${PROJECT_SOURCE_DIR}/Source/*.cpp)
|
||||
add_executable(TactilityKernelTests EXCLUDE_FROM_ALL ${TEST_SOURCES})
|
||||
|
||||
target_include_directories(TactilityKernelTests PRIVATE ${DOCTESTINC})
|
||||
|
||||
+59
-33
@@ -12,30 +12,26 @@ static Module module = {
|
||||
.stop = nullptr
|
||||
};
|
||||
|
||||
TEST_CASE("device_construct and device_destruct should set and unset the correct fields") {
|
||||
TEST_CASE("device_construct and device_destruct should set and unset the internal field") {
|
||||
Device device = { 0 };
|
||||
|
||||
error_t error = device_construct(&device);
|
||||
CHECK_EQ(error, ERROR_NONE);
|
||||
|
||||
CHECK_NE(device.internal.device_private, nullptr);
|
||||
CHECK_NE(device.internal.mutex.handle, nullptr);
|
||||
CHECK_NE(device.internal, nullptr);
|
||||
|
||||
CHECK_EQ(device_destruct(&device), ERROR_NONE);
|
||||
|
||||
CHECK_EQ(device.internal.device_private, nullptr);
|
||||
CHECK_EQ(device.internal.mutex.handle, nullptr);
|
||||
|
||||
Device comparison_device = { 0 };
|
||||
comparison_device.internal.device_private = device.internal.device_private;
|
||||
comparison_device.internal.mutex.handle = device.internal.mutex.handle;
|
||||
|
||||
// Check that no other data was set
|
||||
CHECK_EQ(memcmp(&device, &comparison_device, sizeof(Device)), 0);
|
||||
CHECK_EQ(device.internal, nullptr);
|
||||
}
|
||||
|
||||
TEST_CASE("device_add should add the device to the list of all devices") {
|
||||
Device device = { 0 };
|
||||
Device device = {
|
||||
.name = "device",
|
||||
.config = nullptr,
|
||||
.parent = nullptr,
|
||||
.internal = nullptr
|
||||
};
|
||||
CHECK_EQ(device_construct(&device), ERROR_NONE);
|
||||
CHECK_EQ(device_add(&device), ERROR_NONE);
|
||||
|
||||
@@ -55,12 +51,18 @@ TEST_CASE("device_add should add the device to the list of all devices") {
|
||||
}
|
||||
|
||||
TEST_CASE("device_add should add the device to its parent") {
|
||||
Device parent = { 0 };
|
||||
Device parent = {
|
||||
.name = "parent",
|
||||
.config = nullptr,
|
||||
.parent = nullptr,
|
||||
.internal = nullptr
|
||||
};
|
||||
|
||||
Device child = {
|
||||
.name = nullptr,
|
||||
.name = "child",
|
||||
.config = nullptr,
|
||||
.parent = &parent
|
||||
.parent = &parent,
|
||||
.internal = nullptr
|
||||
};
|
||||
|
||||
CHECK_EQ(device_construct(&parent), ERROR_NONE);
|
||||
@@ -88,19 +90,31 @@ TEST_CASE("device_add should add the device to its parent") {
|
||||
}
|
||||
|
||||
TEST_CASE("device_add should set the state to 'added'") {
|
||||
Device device = { 0 };
|
||||
Device device = {
|
||||
.name = "device",
|
||||
.config = nullptr,
|
||||
.parent = nullptr,
|
||||
.internal = nullptr
|
||||
};
|
||||
|
||||
CHECK_EQ(device_construct(&device), ERROR_NONE);
|
||||
|
||||
CHECK_EQ(device.internal.state.added, false);
|
||||
CHECK_EQ(device_is_added(&device), false);
|
||||
CHECK_EQ(device_add(&device), ERROR_NONE);
|
||||
CHECK_EQ(device.internal.state.added, true);
|
||||
CHECK_EQ(device_is_added(&device), true);
|
||||
|
||||
CHECK_EQ(device_remove(&device), ERROR_NONE);
|
||||
CHECK_EQ(device_destruct(&device), ERROR_NONE);
|
||||
}
|
||||
|
||||
TEST_CASE("device_remove should remove it from the list of all devices") {
|
||||
Device device = { 0 };
|
||||
Device device = {
|
||||
.name = "device",
|
||||
.config = nullptr,
|
||||
.parent = nullptr,
|
||||
.internal = nullptr
|
||||
};
|
||||
|
||||
CHECK_EQ(device_construct(&device), ERROR_NONE);
|
||||
CHECK_EQ(device_add(&device), ERROR_NONE);
|
||||
CHECK_EQ(device_remove(&device), ERROR_NONE);
|
||||
@@ -119,12 +133,18 @@ TEST_CASE("device_remove should remove it from the list of all devices") {
|
||||
}
|
||||
|
||||
TEST_CASE("device_remove should remove the device from its parent") {
|
||||
Device parent = { 0 };
|
||||
Device parent = {
|
||||
.name = "parent",
|
||||
.config = nullptr,
|
||||
.parent = nullptr,
|
||||
.internal = nullptr
|
||||
};
|
||||
|
||||
Device child = {
|
||||
.name = nullptr,
|
||||
.name = "child",
|
||||
.config = nullptr,
|
||||
.parent = &parent
|
||||
.parent = &parent,
|
||||
.internal = nullptr
|
||||
};
|
||||
|
||||
CHECK_EQ(device_construct(&parent), ERROR_NONE);
|
||||
@@ -151,13 +171,19 @@ TEST_CASE("device_remove should remove the device from its parent") {
|
||||
}
|
||||
|
||||
TEST_CASE("device_remove should clear the state 'added'") {
|
||||
Device device = { 0 };
|
||||
Device device = {
|
||||
.name = "device",
|
||||
.config = nullptr,
|
||||
.parent = nullptr,
|
||||
.internal = nullptr
|
||||
};
|
||||
|
||||
CHECK_EQ(device_construct(&device), ERROR_NONE);
|
||||
|
||||
CHECK_EQ(device_add(&device), ERROR_NONE);
|
||||
CHECK_EQ(device.internal.state.added, true);
|
||||
CHECK_EQ(device_is_added(&device), true);
|
||||
CHECK_EQ(device_remove(&device), ERROR_NONE);
|
||||
CHECK_EQ(device.internal.state.added, false);
|
||||
CHECK_EQ(device_is_added(&device), false);
|
||||
|
||||
CHECK_EQ(device_destruct(&device), ERROR_NONE);
|
||||
}
|
||||
@@ -172,7 +198,7 @@ TEST_CASE("device_is_ready should return true only when it is started") {
|
||||
.api = nullptr,
|
||||
.device_type = nullptr,
|
||||
.owner = &module,
|
||||
.driver_private = nullptr
|
||||
.internal = nullptr
|
||||
};
|
||||
|
||||
Device device = { 0 };
|
||||
@@ -180,17 +206,17 @@ TEST_CASE("device_is_ready should return true only when it is started") {
|
||||
CHECK_EQ(driver_construct_add(&driver), ERROR_NONE);
|
||||
CHECK_EQ(device_construct(&device), ERROR_NONE);
|
||||
|
||||
CHECK_EQ(device.internal.state.started, false);
|
||||
CHECK_EQ(device_is_ready(&device), false);
|
||||
device_set_driver(&device, &driver);
|
||||
CHECK_EQ(device.internal.state.started, false);
|
||||
CHECK_EQ(device_is_ready(&device), false);
|
||||
CHECK_EQ(device_add(&device), ERROR_NONE);
|
||||
CHECK_EQ(device.internal.state.started, false);
|
||||
CHECK_EQ(device_is_ready(&device), false);
|
||||
CHECK_EQ(device_start(&device), ERROR_NONE);
|
||||
CHECK_EQ(device.internal.state.started, true);
|
||||
CHECK_EQ(device_is_ready(&device), true);
|
||||
CHECK_EQ(device_stop(&device), ERROR_NONE);
|
||||
CHECK_EQ(device.internal.state.started, false);
|
||||
CHECK_EQ(device_is_ready(&device), false);
|
||||
CHECK_EQ(device_remove(&device), ERROR_NONE);
|
||||
CHECK_EQ(device.internal.state.started, false);
|
||||
CHECK_EQ(device_is_ready(&device), false);
|
||||
|
||||
CHECK_EQ(device_destruct(&device), ERROR_NONE);
|
||||
CHECK_EQ(driver_remove_destruct(&driver), ERROR_NONE);
|
||||
+1
-1
@@ -38,7 +38,7 @@ static Driver integration_driver = {
|
||||
.api = nullptr,
|
||||
.device_type = nullptr,
|
||||
.owner = &module,
|
||||
.driver_private = nullptr,
|
||||
.internal = nullptr,
|
||||
};
|
||||
|
||||
TEST_CASE("driver with with start success and stop success should start and stop a device") {
|
||||
@@ -15,10 +15,10 @@ TEST_CASE("driver_construct and driver_destruct should set and unset the correct
|
||||
|
||||
CHECK_EQ(driver_construct(&driver), ERROR_NONE);
|
||||
CHECK_EQ(driver_add(&driver), ERROR_NONE);
|
||||
CHECK_NE(driver.driver_private, nullptr);
|
||||
CHECK_NE(driver.internal, nullptr);
|
||||
CHECK_EQ(driver_remove(&driver), ERROR_NONE);
|
||||
CHECK_EQ(driver_destruct(&driver), ERROR_NONE);
|
||||
CHECK_EQ(driver.driver_private, nullptr);
|
||||
CHECK_EQ(driver.internal, nullptr);
|
||||
}
|
||||
|
||||
TEST_CASE("a driver without a module should not be destructible") {
|
||||
@@ -40,7 +40,7 @@ TEST_CASE("driver_is_compatible should return true if a compatible value is foun
|
||||
.api = nullptr,
|
||||
.device_type = nullptr,
|
||||
.owner = &module,
|
||||
.driver_private = nullptr
|
||||
.internal = nullptr
|
||||
};
|
||||
CHECK_EQ(driver_is_compatible(&driver, "test_compatible"), true);
|
||||
CHECK_EQ(driver_is_compatible(&driver, "nope"), false);
|
||||
@@ -57,7 +57,7 @@ TEST_CASE("driver_find should only find a compatible driver when the driver was
|
||||
.api = nullptr,
|
||||
.device_type = nullptr,
|
||||
.owner = &module,
|
||||
.driver_private = nullptr
|
||||
.internal = nullptr
|
||||
};
|
||||
|
||||
Driver* found_driver = driver_find_compatible("test_compatible");
|
||||
@@ -23,12 +23,12 @@ TEST_CASE("Module construction and destruction") {
|
||||
.start = test_start,
|
||||
.stop = test_stop,
|
||||
.symbols = nullptr,
|
||||
.internal = {.started = false}
|
||||
.internal = nullptr
|
||||
};
|
||||
|
||||
// Test successful construction
|
||||
CHECK_EQ(module_construct(&module), ERROR_NONE);
|
||||
CHECK_EQ(module.internal.started, false);
|
||||
CHECK_EQ(module_is_started(&module), false);
|
||||
|
||||
// Test successful destruction
|
||||
CHECK_EQ(module_destruct(&module), ERROR_NONE);
|
||||
@@ -40,7 +40,7 @@ TEST_CASE("Module registration") {
|
||||
.start = test_start,
|
||||
.stop = test_stop,
|
||||
.symbols = nullptr,
|
||||
.internal = {.started = false}
|
||||
.internal = nullptr
|
||||
};
|
||||
|
||||
// module_add should succeed
|
||||
@@ -61,9 +61,11 @@ TEST_CASE("Module lifecycle") {
|
||||
.start = test_start,
|
||||
.stop = test_stop,
|
||||
.symbols = nullptr,
|
||||
.internal = {.started = false}
|
||||
.internal = nullptr
|
||||
};
|
||||
|
||||
CHECK_EQ(module_construct(&module), ERROR_NONE);
|
||||
|
||||
// 1. Successful start (no parent required anymore)
|
||||
CHECK_EQ(module_start(&module), ERROR_NONE);
|
||||
CHECK_EQ(module_is_started(&module), true);
|
||||
@@ -104,6 +106,8 @@ TEST_CASE("Module lifecycle") {
|
||||
// Clean up: fix stop result so we can stop it
|
||||
test_stop_result = ERROR_NONE;
|
||||
CHECK_EQ(module_stop(&module), ERROR_NONE);
|
||||
|
||||
CHECK_EQ(module_destruct(&module), ERROR_NONE);
|
||||
}
|
||||
|
||||
TEST_CASE("Global symbol resolution") {
|
||||
@@ -117,9 +121,11 @@ TEST_CASE("Global symbol resolution") {
|
||||
.start = test_start,
|
||||
.stop = test_stop,
|
||||
.symbols = test_symbols,
|
||||
.internal = {.started = false}
|
||||
.internal = nullptr
|
||||
};
|
||||
|
||||
REQUIRE_EQ(module_construct(&module), ERROR_NONE);
|
||||
|
||||
uintptr_t addr;
|
||||
// Should fail as it is not added or started
|
||||
CHECK_EQ(module_resolve_symbol_global("symbol_test_function", &addr), false);
|
||||
@@ -128,8 +134,8 @@ TEST_CASE("Global symbol resolution") {
|
||||
REQUIRE_EQ(module_start(&module), ERROR_NONE);
|
||||
// Still fails as symbols are null
|
||||
CHECK_EQ(module_resolve_symbol_global("symbol_test_function", &addr), true);
|
||||
|
||||
// Cleanup
|
||||
CHECK_EQ(module_remove(&module), ERROR_NONE);
|
||||
|
||||
CHECK_EQ(module_destruct(&module), ERROR_NONE);
|
||||
}
|
||||
Reference in New Issue
Block a user