imported from "final" folder
This commit is contained in:
276
.pio/libdeps/esp01_1m/FastLED/tests/test_task.cpp
Normal file
276
.pio/libdeps/esp01_1m/FastLED/tests/test_task.cpp
Normal file
@@ -0,0 +1,276 @@
|
||||
|
||||
|
||||
#include "doctest.h"
|
||||
#include "fl/task.h"
|
||||
#include "fl/async.h"
|
||||
#include "fl/engine_events.h"
|
||||
#include "fl/time.h"
|
||||
|
||||
|
||||
|
||||
using namespace fl;
|
||||
|
||||
namespace {
|
||||
|
||||
// Helper class to track frame events for testing
|
||||
class TestFrameListener : public fl::EngineEvents::Listener {
|
||||
public:
|
||||
TestFrameListener() {
|
||||
fl::EngineEvents::addListener(this);
|
||||
}
|
||||
|
||||
~TestFrameListener() {
|
||||
fl::EngineEvents::removeListener(this);
|
||||
}
|
||||
|
||||
void onEndFrame() override {
|
||||
frame_count++;
|
||||
// Pump the scheduler to execute after_frame tasks specifically
|
||||
fl::Scheduler::instance().update_after_frame_tasks();
|
||||
}
|
||||
|
||||
int frame_count = 0;
|
||||
};
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
TEST_CASE("Task self-registration and destruction behavior [task]") {
|
||||
|
||||
SUBCASE("Task auto-registers when callback is set - SUCCESS") {
|
||||
// Clear any leftover tasks from previous tests
|
||||
fl::Scheduler::instance().clear_all_tasks();
|
||||
|
||||
bool task_executed = false;
|
||||
|
||||
// Create task without manually adding to scheduler
|
||||
// Auto-registration happens when .then() is called
|
||||
{
|
||||
fl::task::after_frame()
|
||||
.then([&task_executed]() {
|
||||
task_executed = true;
|
||||
});
|
||||
// Task temporary object destructs here, but it's already registered
|
||||
}
|
||||
|
||||
// Simulate frame end event
|
||||
TestFrameListener listener;
|
||||
fl::EngineEvents::onEndFrame();
|
||||
|
||||
// Task should now execute due to auto-registration
|
||||
CHECK(task_executed);
|
||||
|
||||
// Clean up
|
||||
fl::Scheduler::instance().clear_all_tasks();
|
||||
}
|
||||
|
||||
SUBCASE("Fluent API pattern works with auto-registration") {
|
||||
// Clear any leftover tasks from previous tests
|
||||
fl::Scheduler::instance().clear_all_tasks();
|
||||
|
||||
bool task_executed = false;
|
||||
|
||||
// This fluent pattern should now work correctly
|
||||
fl::task::after_frame().then([&task_executed]() {
|
||||
task_executed = true;
|
||||
});
|
||||
// Entire chain destructs here, but task was auto-registered
|
||||
|
||||
// Simulate frame end event
|
||||
TestFrameListener listener;
|
||||
fl::EngineEvents::onEndFrame();
|
||||
|
||||
// Task should execute
|
||||
CHECK(task_executed);
|
||||
|
||||
// Clean up
|
||||
fl::Scheduler::instance().clear_all_tasks();
|
||||
}
|
||||
|
||||
SUBCASE("Multiple auto-registering tasks work correctly") {
|
||||
// Clear any leftover tasks from previous tests
|
||||
fl::Scheduler::instance().clear_all_tasks();
|
||||
|
||||
int tasks_executed = 0;
|
||||
|
||||
// Create multiple tasks without saving them - they auto-register
|
||||
for (int i = 0; i < 3; i++) {
|
||||
fl::task::after_frame()
|
||||
.then([&tasks_executed]() {
|
||||
tasks_executed++;
|
||||
});
|
||||
// Each task auto-registers when .then() is called
|
||||
}
|
||||
|
||||
// Simulate frame end event
|
||||
TestFrameListener listener;
|
||||
fl::EngineEvents::onEndFrame();
|
||||
|
||||
// All 3 tasks should execute
|
||||
CHECK_EQ(tasks_executed, 3);
|
||||
|
||||
// Clean up
|
||||
fl::Scheduler::instance().clear_all_tasks();
|
||||
}
|
||||
|
||||
SUBCASE("Manual registration still works (backward compatibility)") {
|
||||
// Clear any leftover tasks from previous tests
|
||||
fl::Scheduler::instance().clear_all_tasks();
|
||||
|
||||
bool task_executed = false;
|
||||
|
||||
// Old style should still work
|
||||
auto task = fl::task::after_frame()
|
||||
.then([&task_executed]() {
|
||||
task_executed = true;
|
||||
});
|
||||
|
||||
// Manual add should work (though now redundant since auto-registration already happened)
|
||||
fl::Scheduler::instance().add_task(task);
|
||||
|
||||
// Simulate frame end event
|
||||
TestFrameListener listener;
|
||||
fl::EngineEvents::onEndFrame();
|
||||
|
||||
// Task should execute (only once, not twice)
|
||||
CHECK(task_executed);
|
||||
|
||||
// Clean up
|
||||
fl::Scheduler::instance().clear_all_tasks();
|
||||
}
|
||||
|
||||
SUBCASE("Task cancellation works with auto-registered tasks") {
|
||||
// Clear any leftover tasks from previous tests
|
||||
fl::Scheduler::instance().clear_all_tasks();
|
||||
|
||||
bool task_executed = false;
|
||||
|
||||
// Create auto-registering task and save reference for cancellation
|
||||
auto task = fl::task::after_frame()
|
||||
.then([&task_executed]() {
|
||||
task_executed = true;
|
||||
});
|
||||
// Task auto-registered when .then() was called
|
||||
|
||||
// Cancel the task
|
||||
task.cancel();
|
||||
|
||||
// Simulate frame end event
|
||||
TestFrameListener listener;
|
||||
fl::EngineEvents::onEndFrame();
|
||||
|
||||
// Task should NOT execute due to cancellation
|
||||
CHECK_FALSE(task_executed);
|
||||
|
||||
// Clean up
|
||||
fl::Scheduler::instance().clear_all_tasks();
|
||||
}
|
||||
|
||||
SUBCASE("Tasks without callbacks don't auto-register") {
|
||||
// Clear any leftover tasks from previous tests
|
||||
fl::Scheduler::instance().clear_all_tasks();
|
||||
|
||||
// Create task without callback - should not auto-register
|
||||
auto task = fl::task::after_frame();
|
||||
|
||||
CHECK_FALSE(task.has_then());
|
||||
CHECK(task.is_valid()); // Task should be valid but not auto-registered
|
||||
|
||||
// Clean up
|
||||
fl::Scheduler::instance().clear_all_tasks();
|
||||
}
|
||||
|
||||
SUBCASE("every_ms task runs immediately once then respects timing interval") {
|
||||
// Clear any leftover tasks from previous tests
|
||||
fl::Scheduler::instance().clear_all_tasks();
|
||||
|
||||
int execution_count = 0;
|
||||
|
||||
// Create a task that runs every 100ms and auto-registers
|
||||
auto task = fl::task::every_ms(100)
|
||||
.then([&execution_count]() {
|
||||
execution_count++;
|
||||
});
|
||||
|
||||
// Task should be auto-registered and ready to run immediately
|
||||
CHECK(task.is_valid());
|
||||
CHECK(task.has_then());
|
||||
|
||||
// First update - should run immediately
|
||||
fl::Scheduler::instance().update();
|
||||
CHECK_EQ(execution_count, 1);
|
||||
|
||||
// Immediate second update - should NOT run (not enough time passed)
|
||||
fl::Scheduler::instance().update();
|
||||
CHECK_EQ(execution_count, 1); // Still 1, didn't run again
|
||||
|
||||
// Manually advance the task's last run time to simulate 50ms passing
|
||||
uint32_t current_time = fl::time();
|
||||
task.set_last_run_time(current_time - 50);
|
||||
|
||||
// Update - should still NOT run (only 50ms passed, need 100ms)
|
||||
fl::Scheduler::instance().update();
|
||||
CHECK_EQ(execution_count, 1); // Still 1
|
||||
|
||||
// Manually advance to simulate 100ms+ passing
|
||||
task.set_last_run_time(current_time - 100);
|
||||
|
||||
// Update - should run now (100ms has passed)
|
||||
fl::Scheduler::instance().update();
|
||||
CHECK_EQ(execution_count, 2); // Should be 2 now
|
||||
|
||||
// Immediate update again - should NOT run
|
||||
fl::Scheduler::instance().update();
|
||||
CHECK_EQ(execution_count, 2); // Still 2
|
||||
|
||||
// Clean up
|
||||
fl::Scheduler::instance().clear_all_tasks();
|
||||
}
|
||||
|
||||
SUBCASE("after_frame task executes when FastLED.show() is called") {
|
||||
// Clear any leftover tasks from previous tests - CRITICAL for test isolation
|
||||
fl::Scheduler::instance().clear_all_tasks();
|
||||
|
||||
int execution_count = 0;
|
||||
|
||||
// Create an after_frame task that auto-registers
|
||||
auto task = fl::task::after_frame()
|
||||
.then([&execution_count]() {
|
||||
execution_count++;
|
||||
});
|
||||
|
||||
// Task should be auto-registered
|
||||
CHECK(task.is_valid());
|
||||
CHECK(task.has_then());
|
||||
|
||||
// Initial state - task hasn't run yet
|
||||
CHECK_EQ(execution_count, 0);
|
||||
|
||||
// Manually calling scheduler update shouldn't trigger frame tasks yet
|
||||
fl::Scheduler::instance().update();
|
||||
CHECK_EQ(execution_count, 0); // Still 0
|
||||
|
||||
|
||||
// Create a frame listener for this specific test
|
||||
TestFrameListener listener;
|
||||
|
||||
// Instead of calling FastLED.show(), directly trigger the engine events
|
||||
// This tests the task system without requiring LED hardware setup
|
||||
fl::EngineEvents::onEndFrame();
|
||||
|
||||
// The after_frame task should have executed
|
||||
CHECK_EQ(execution_count, 1);
|
||||
|
||||
// Calling onEndFrame() again should execute the task again (it's been removed as one-shot)
|
||||
// But since it's already removed, create another task to test
|
||||
auto task2 = fl::task::after_frame()
|
||||
.then([&execution_count]() {
|
||||
execution_count++;
|
||||
});
|
||||
|
||||
fl::EngineEvents::onEndFrame();
|
||||
CHECK_EQ(execution_count, 2);
|
||||
|
||||
// Clean up
|
||||
fl::Scheduler::instance().clear_all_tasks();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user