| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857 |
- // test-scheduler-blink-example.cpp - TaskScheduler Blink Example Validation Tests
- // This file contains comprehensive tests validating the TaskScheduler Blink example functionality
- // Based on examples\Scheduler_example00_Blink\ demonstrating various LED blinking approaches
- //
- // =====================================================================================
- // BLINK EXAMPLE TEST PLAN AND COVERAGE MATRIX
- // =====================================================================================
- //
- // PURPOSE: Validate all blink example patterns and TaskScheduler methods used in real applications
- // APPROACH: Simulate LED state changes and timing patterns without actual hardware
- // SCOPE: All six blink approaches from the reference example with comprehensive verification
- //
- // COVERAGE MATRIX:
- // ================
- //
- // 1. APPROACH 1 - SIMPLE FLAG DRIVEN BLINKING
- // ├── Boolean State Management
- // │ ├── LED state toggling logic
- // │ ├── isFirstIteration() detection
- // │ └── isLastIteration() cleanup
- // ├── Task Lifecycle
- // │ ├── Auto-enabled task execution
- // │ ├── Fixed interval timing (500ms)
- // │ └── Limited iteration count (20 cycles for 10 seconds)
- // └── Task Chaining
- // └── Delayed restart of next task pattern
- //
- // 2. APPROACH 2 - DUAL CALLBACK METHOD SWITCHING
- // ├── Dynamic Callback Switching
- // │ ├── setCallback() method usage
- // │ ├── ON callback registration
- // │ └── OFF callback registration
- // ├── Callback Coordination
- // │ ├── State transition between callbacks
- // │ ├── First/last iteration handling in both callbacks
- // │ └── Proper LED state management
- // └── Task Chain Management
- // └── Sequential task activation with delays
- //
- // 3. APPROACH 3 - RUN COUNTER DRIVEN BLINKING
- // ├── Run Counter Logic
- // │ ├── getRunCounter() method usage
- // │ ├── Odd/even counter state detection
- // │ └── Counter-based LED state determination
- // ├── Task State Management
- // │ ├── First iteration detection
- // │ ├── Last iteration handling
- // │ └── Task chain progression
- // └── OnEnable Callback Registration
- // └── Dynamic setOnEnable() assignment
- //
- // 4. APPROACH 4 - STATUS REQUEST COORDINATION
- // ├── StatusRequest Objects
- // │ ├── getInternalStatusRequest() usage
- // │ ├── waitForDelayed() coordination
- // │ └── Inter-task communication patterns
- // ├── OnEnable/OnDisable Callbacks
- // │ ├── OnEnable callback setup and removal
- // │ ├── OnDisable callback execution
- // │ └── Task lifecycle management
- // ├── Task Coordination
- // │ ├── Two-task ping-pong pattern
- // │ ├── Counter-based termination
- // │ └── Manual task disable() calls
- // └── Advanced Task Control
- // └── Delayed restart with offset timing
- //
- // 5. APPROACH 5 - INTERLEAVING TASKS
- // ├── Dual Task Pattern
- // │ ├── Independent task scheduling
- // │ ├── Phase-shifted execution (300ms offset)
- // │ └── Synchronized start/stop
- // ├── OnEnable Management
- // │ ├── One-time OnEnable callback
- // │ ├── Callback removal after first use
- // │ └── Task state coordination
- // └── OnDisable Coordination
- // └── Task chain progression from OnDisable
- //
- // 6. APPROACH 6 - RANDOM INTERVAL GENERATION
- // ├── Dynamic Interval Modification
- // │ ├── setInterval() runtime changes
- // │ ├── Random interval generation
- // │ └── Complementary timing calculation
- // ├── Run Counter + Interval Combination
- // │ ├── Counter-based state logic
- // │ ├── Interval adjustment per state
- // │ └── Total period maintenance
- // ├── OnEnable Setup
- // │ ├── Random interval calculation
- // │ ├── Initial task delay
- // │ └── Callback removal
- // └── Circular Task Pattern
- // └── Return to first approach (endless loop simulation)
- //
- // INTEGRATION TESTS:
- // ==================
- //
- // 7. TASK CHAINING VALIDATION
- // ├── Sequential Execution Pattern
- // │ ├── Approach 1 → 2 → 3 → 4 → 5 → 6 → 1 (loop)
- // │ ├── 2-second gaps between approaches
- // │ └── Clean state transitions
- // ├── Timing Verification
- // │ ├── 10-second duration per approach
- // │ ├── Proper interval execution
- // │ └── Delay accuracy
- // └── State Management
- // ├── LED state consistency
- // ├── Proper cleanup between approaches
- // └── Task enable/disable coordination
- //
- // 8. SCHEDULER EXECUTION VALIDATION
- // ├── Core Scheduler Methods
- // │ ├── execute() return values
- // │ ├── Task registration handling
- // │ └── Execution order verification
- // ├── Advanced Features Integration
- // │ ├── STATUS_REQUEST functionality
- // │ ├── OnEnable/OnDisable callbacks
- // │ └── Dynamic callback switching
- // └── Timing Accuracy
- // ├── Millisecond precision verification
- // ├── Interval consistency
- // └── Execution overhead measurement
- //
- // IMPORTANCE: These tests validate real-world TaskScheduler usage patterns demonstrating
- // practical applications, advanced features, and complex task coordination scenarios
- // essential for Arduino and embedded system development.
- #include <gtest/gtest.h>
- #include "Arduino.h"
- // TaskScheduler compile-time feature flags (matching the example)
- #define _TASK_SLEEP_ON_IDLE_RUN // Enable 1 ms SLEEP_IDLE powerdowns between runs
- #define _TASK_STATUS_REQUEST // Support for StatusRequest functionality
- #include "TaskScheduler.h"
- // Global test state - simulates LED and tracks execution
- std::vector<std::string> blink_test_output;
- bool simulated_led_state = false;
- int led_state_changes = 0;
- bool debug_output_enabled = false;
- // Test timing constants (matching the example)
- #define PERIOD1 500
- #define PERIOD2 400
- #define PERIOD3 300
- #define PERIOD4 200
- #define PERIOD5 600
- #define PERIOD6 300
- #define DURATION 10000
- // Simulated LED control functions
- void LEDOn() {
- if (!simulated_led_state) {
- simulated_led_state = true;
- led_state_changes++;
- blink_test_output.push_back("LED_ON");
- if (debug_output_enabled) {
- std::cout << "LED ON at " << millis() << "ms" << std::endl;
- }
- }
- }
- void LEDOff() {
- if (simulated_led_state) {
- simulated_led_state = false;
- led_state_changes++;
- blink_test_output.push_back("LED_OFF");
- if (debug_output_enabled) {
- std::cout << "LED OFF at " << millis() << "ms" << std::endl;
- }
- }
- }
- // Test callback functions (matching the example structure)
- // === APPROACH 1: Simple Flag Driven ===
- bool LED_state = false;
- void blink1CB();
- Scheduler* global_scheduler = nullptr;
- Task* tBlink1_ptr = nullptr;
- Task* tBlink2_ptr = nullptr;
- Task* tBlink3_ptr = nullptr;
- Task* tBlink4On_ptr = nullptr;
- Task* tBlink4Off_ptr = nullptr;
- Task* tBlink5On_ptr = nullptr;
- Task* tBlink5Off_ptr = nullptr;
- Task* tBlink6_ptr = nullptr;
- void blink1CB() {
- if (tBlink1_ptr && tBlink1_ptr->isFirstIteration()) {
- blink_test_output.push_back("BLINK1_START");
- LED_state = false;
- }
- if (LED_state) {
- LEDOff();
- LED_state = false;
- } else {
- LEDOn();
- LED_state = true;
- }
- if (tBlink1_ptr && tBlink1_ptr->isLastIteration()) {
- blink_test_output.push_back("BLINK1_END");
- LEDOff();
- // In real example, would start tBlink2
- }
- }
- // === APPROACH 2: Dual Callback Methods ===
- void blink2CB_ON();
- void blink2CB_OFF();
- void blink2CB_ON() {
- if (tBlink2_ptr && tBlink2_ptr->isFirstIteration()) {
- blink_test_output.push_back("BLINK2_START");
- }
- LEDOn();
- if (tBlink2_ptr) {
- tBlink2_ptr->setCallback(&blink2CB_OFF);
- }
- if (tBlink2_ptr && tBlink2_ptr->isLastIteration()) {
- blink_test_output.push_back("BLINK2_END");
- LEDOff();
- }
- }
- void blink2CB_OFF() {
- LEDOff();
- if (tBlink2_ptr) {
- tBlink2_ptr->setCallback(&blink2CB_ON);
- }
- if (tBlink2_ptr && tBlink2_ptr->isLastIteration()) {
- blink_test_output.push_back("BLINK2_END");
- LEDOff();
- }
- }
- // === APPROACH 3: Run Counter Driven ===
- void blink3CB() {
- if (tBlink3_ptr && tBlink3_ptr->isFirstIteration()) {
- blink_test_output.push_back("BLINK3_START");
- }
- if (tBlink3_ptr && (tBlink3_ptr->getRunCounter() & 1)) {
- LEDOn();
- } else {
- LEDOff();
- }
- if (tBlink3_ptr && tBlink3_ptr->isLastIteration()) {
- blink_test_output.push_back("BLINK3_END");
- LEDOff();
- }
- }
- // === APPROACH 4: Status Request Based ===
- int counter = 0;
- bool blink41OE() {
- blink_test_output.push_back("BLINK4_START");
- counter = 0;
- if (tBlink4On_ptr) {
- tBlink4On_ptr->setOnEnable(nullptr);
- }
- return true;
- }
- void blink41() {
- LEDOn();
- if (tBlink4On_ptr && tBlink4Off_ptr) {
- StatusRequest* r = tBlink4On_ptr->getInternalStatusRequest();
- tBlink4Off_ptr->waitForDelayed(r);
- }
- counter++;
- }
- void blink42() {
- LEDOff();
- if (tBlink4On_ptr && tBlink4Off_ptr) {
- StatusRequest* r = tBlink4Off_ptr->getInternalStatusRequest();
- tBlink4On_ptr->waitForDelayed(r);
- }
- counter++;
- }
- void blink42OD() {
- if (counter >= DURATION / PERIOD4) {
- blink_test_output.push_back("BLINK4_END");
- if (tBlink4On_ptr) tBlink4On_ptr->disable();
- if (tBlink4Off_ptr) tBlink4Off_ptr->disable();
- LEDOff();
- }
- }
- // === APPROACH 5: Interleaving Tasks ===
- bool blink51OE() {
- blink_test_output.push_back("BLINK5_START");
- if (tBlink5On_ptr) {
- tBlink5On_ptr->setOnEnable(nullptr);
- }
- return true;
- }
- void blink51() {
- LEDOn();
- }
- void blink52() {
- LEDOff();
- }
- void blink52OD() {
- blink_test_output.push_back("BLINK5_END");
- LEDOff();
- }
- // === APPROACH 6: Random Interval ===
- long interval6 = 0;
- bool blink6OE() {
- blink_test_output.push_back("BLINK6_START");
- interval6 = 500; // Fixed for testing (instead of random)
- if (tBlink6_ptr) {
- tBlink6_ptr->setInterval(interval6);
- }
- return true;
- }
- void blink6CB() {
- if (tBlink6_ptr && (tBlink6_ptr->getRunCounter() & 1)) {
- LEDOn();
- tBlink6_ptr->setInterval(interval6);
- } else {
- LEDOff();
- if (tBlink6_ptr) {
- tBlink6_ptr->setInterval(1000 - interval6);
- }
- }
- }
- void blink6OD() {
- blink_test_output.push_back("BLINK6_END");
- LEDOff();
- }
- // Test helper functions
- void clearBlinkTestOutput() {
- blink_test_output.clear();
- simulated_led_state = false;
- led_state_changes = 0;
- }
- size_t getBlinkTestOutputCount() {
- return blink_test_output.size();
- }
- std::string getBlinkTestOutput(size_t index) {
- if (index < blink_test_output.size()) {
- return blink_test_output[index];
- }
- return "";
- }
- // Test condition functions to replace lambda functions
- bool condition_output_count_1() {
- return getBlinkTestOutputCount() >= 1;
- }
- bool condition_led_changes_6() {
- return led_state_changes >= 6;
- }
- bool condition_led_changes_8() {
- return led_state_changes >= 8;
- }
- bool condition_led_changes_5() {
- return led_state_changes >= 5;
- }
- bool condition_led_changes_4() {
- return led_state_changes >= 4;
- }
- bool condition_tBlink1_disabled() {
- return tBlink1_ptr && !tBlink1_ptr->isEnabled();
- }
- bool condition_tBlink2_disabled() {
- return tBlink2_ptr && !tBlink2_ptr->isEnabled();
- }
- bool condition_tBlink3_disabled() {
- return tBlink3_ptr && !tBlink3_ptr->isEnabled();
- }
- bool condition_tBlink3_runcount_6() {
- return tBlink3_ptr && tBlink3_ptr->getRunCounter() >= 6;
- }
- bool condition_counter_10() {
- return counter >= 10;
- }
- bool condition_counter_duration_period4() {
- return counter >= DURATION / PERIOD4;
- }
- bool condition_both_blink4_disabled() {
- return tBlink4On_ptr && tBlink4Off_ptr &&
- !tBlink4On_ptr->isEnabled() && !tBlink4Off_ptr->isEnabled();
- }
- bool condition_both_blink5_disabled() {
- return tBlink5On_ptr && tBlink5Off_ptr &&
- !tBlink5On_ptr->isEnabled() && !tBlink5Off_ptr->isEnabled();
- }
- bool condition_tBlink6_disabled() {
- return tBlink6_ptr && !tBlink6_ptr->isEnabled();
- }
- bool condition_tBlink6_runcount_4() {
- return tBlink6_ptr && tBlink6_ptr->getRunCounter() >= 4;
- }
- // Scheduler execution helper with callback function pointer
- bool runBlinkSchedulerUntil(Scheduler& ts, bool (*condition)(), unsigned long timeout_ms = 2000) {
- unsigned long start_time = millis();
- while (millis() - start_time < timeout_ms) {
- bool idle = ts.execute();
- if (condition()) {
- return true;
- }
- if (idle) {
- delay(1); // Simulate idle sleep
- }
- }
- return false;
- }
- // Test fixture for blink example validation
- class BlinkExampleTest : public ::testing::Test {
- protected:
- void SetUp() override {
- clearBlinkTestOutput();
- LED_state = false;
- counter = 0;
- interval6 = 0;
- debug_output_enabled = false;
- }
- void TearDown() override {
- clearBlinkTestOutput();
- }
- };
- // ================== APPROACH 1 TESTS ==================
- /**
- * @brief Test Approach 1: Simple Flag Driven Blinking
- *
- * TESTS: Boolean state management, isFirstIteration(), isLastIteration()
- *
- * PURPOSE: Validate the simplest blinking approach using a boolean flag
- * to track LED state. Verifies proper first/last iteration detection,
- * state toggling logic, and task lifecycle management.
- *
- * IMPORTANCE: This is the most fundamental blinking pattern, essential
- * for understanding basic TaskScheduler usage and state management.
- */
- TEST_F(BlinkExampleTest, Approach1_SimpleFlagDriven) {
- Scheduler ts;
- global_scheduler = &ts;
- Task tBlink1(PERIOD1, DURATION / PERIOD1, &blink1CB, &ts, true);
- tBlink1_ptr = &tBlink1;
- // Should execute first iteration
- bool success = runBlinkSchedulerUntil(ts, condition_output_count_1);
- EXPECT_TRUE(success);
- EXPECT_EQ(getBlinkTestOutput(0), "BLINK1_START");
- EXPECT_TRUE(simulated_led_state); // Should turn LED on first
- // Let it run several cycles
- success = runBlinkSchedulerUntil(ts, condition_led_changes_6, 3000);
- EXPECT_TRUE(success);
- EXPECT_GE(led_state_changes, 6);
- // Wait for completion
- success = runBlinkSchedulerUntil(ts, condition_tBlink1_disabled, 15000);
- EXPECT_TRUE(success);
- EXPECT_FALSE(tBlink1.isEnabled());
- // Check that it recorded the end
- bool found_end = false;
- for (const auto& output : blink_test_output) {
- if (output == "BLINK1_END") {
- found_end = true;
- break;
- }
- }
- EXPECT_TRUE(found_end);
- EXPECT_FALSE(simulated_led_state); // LED should be off at end
- tBlink1_ptr = nullptr;
- }
- // ================== APPROACH 2 TESTS ==================
- /**
- * @brief Test Approach 2: Dual Callback Method Switching
- *
- * TESTS: setCallback(), dynamic callback switching, dual-method coordination
- *
- * PURPOSE: Validate the callback switching approach where one callback
- * turns LED on and switches to OFF callback, which turns LED off and
- * switches back to ON callback, creating a ping-pong pattern.
- *
- * IMPORTANCE: Demonstrates advanced TaskScheduler feature of runtime
- * callback modification, essential for state machine implementations.
- */
- TEST_F(BlinkExampleTest, Approach2_DualCallbackSwitching) {
- Scheduler ts;
- Task tBlink2(PERIOD2, DURATION / PERIOD2, &blink2CB_ON, &ts, true);
- tBlink2_ptr = &tBlink2;
- // Should start with ON callback
- bool success = runBlinkSchedulerUntil(ts, condition_output_count_1);
- EXPECT_TRUE(success);
- EXPECT_EQ(getBlinkTestOutput(0), "BLINK2_START");
- EXPECT_TRUE(simulated_led_state); // First callback turns LED on
- // Let it run and switch callbacks several times
- success = runBlinkSchedulerUntil(ts, condition_led_changes_8, 4000);
- EXPECT_TRUE(success);
- EXPECT_GE(led_state_changes, 8);
- // Verify alternating pattern
- int on_count = 0, off_count = 0;
- for (const auto& output : blink_test_output) {
- if (output == "LED_ON") on_count++;
- if (output == "LED_OFF") off_count++;
- }
- EXPECT_GT(on_count, 0);
- EXPECT_GT(off_count, 0);
- EXPECT_LE(abs(on_count - off_count), 1); // Should be roughly equal
- // Wait for completion
- success = runBlinkSchedulerUntil(ts, condition_tBlink2_disabled, 15000);
- EXPECT_TRUE(success);
- EXPECT_FALSE(simulated_led_state); // LED should be off at end
- tBlink2_ptr = nullptr;
- }
- // ================== APPROACH 3 TESTS ==================
- /**
- * @brief Test Approach 3: Run Counter Driven Blinking
- *
- * TESTS: getRunCounter(), odd/even logic, counter-based state control
- *
- * PURPOSE: Validate blinking controlled by run counter where odd counts
- * turn LED on and even counts turn LED off. Tests counter increment
- * behavior and bitwise odd/even detection.
- *
- * IMPORTANCE: Demonstrates practical use of run counters for state
- * determination, common in cyclic operations and alternating behaviors.
- */
- TEST_F(BlinkExampleTest, Approach3_RunCounterDriven) {
- Scheduler ts;
- Task tBlink3(PERIOD3, DURATION / PERIOD3, &blink3CB, &ts, true);
- tBlink3_ptr = &tBlink3;
- // Should start execution
- bool success = runBlinkSchedulerUntil(ts, condition_output_count_1);
- EXPECT_TRUE(success);
- EXPECT_EQ(getBlinkTestOutput(0), "BLINK3_START");
- // Let it run several cycles to test counter logic
- success = runBlinkSchedulerUntil(ts, condition_tBlink3_runcount_6, 3000);
- EXPECT_TRUE(success);
- EXPECT_GE(tBlink3.getRunCounter(), 6);
- // Verify that LED state follows counter parity
- // Run counter starts at 1 (odd) = LED ON, 2 (even) = LED OFF, etc.
- int run_count = tBlink3.getRunCounter();
- if (run_count & 1) {
- EXPECT_TRUE(simulated_led_state);
- } else {
- EXPECT_FALSE(simulated_led_state);
- }
- // Wait for completion
- success = runBlinkSchedulerUntil(ts, condition_tBlink3_disabled, 15000);
- EXPECT_TRUE(success);
- EXPECT_FALSE(simulated_led_state); // LED should be off at end
- tBlink3_ptr = nullptr;
- }
- // ================== APPROACH 4 TESTS ==================
- /**
- * @brief Test Approach 4: Status Request Coordination
- *
- * TESTS: getInternalStatusRequest(), waitForDelayed(), OnEnable/OnDisable callbacks
- *
- * PURPOSE: Validate the most advanced blinking approach using status
- * requests for inter-task coordination. Tests two tasks passing control
- * back and forth using internal status request objects.
- *
- * IMPORTANCE: Demonstrates sophisticated task coordination patterns
- * essential for complex embedded systems requiring precise timing
- * and event-driven behaviors.
- */
- TEST_F(BlinkExampleTest, Approach4_StatusRequestCoordination) {
- Scheduler ts;
- Task tBlink4On(PERIOD4, TASK_ONCE, &blink41, &ts, false, &blink41OE);
- Task tBlink4Off(PERIOD4, TASK_ONCE, &blink42, &ts, false, nullptr, &blink42OD);
- tBlink4On_ptr = &tBlink4On;
- tBlink4Off_ptr = &tBlink4Off;
- // Enable the first task to start the sequence
- tBlink4On.enable();
- // Should execute OnEnable and start
- bool success = runBlinkSchedulerUntil(ts, condition_output_count_1);
- EXPECT_TRUE(success);
- EXPECT_EQ(getBlinkTestOutput(0), "BLINK4_START");
- // Let the ping-pong pattern run
- success = runBlinkSchedulerUntil(ts, condition_counter_10, 3000);
- EXPECT_TRUE(success);
- EXPECT_GE(counter, 10);
- // Verify both tasks are coordinating (alternating LED states)
- EXPECT_GE(led_state_changes, 5);
- // Wait for the sequence to complete
- success = runBlinkSchedulerUntil(ts, condition_counter_duration_period4, 15000);
- EXPECT_TRUE(success);
- ts.execute(); // Final execute to process disable
-
- // Both tasks should be disabled by OnDisable callback
- EXPECT_FALSE(tBlink4On.isEnabled());
- EXPECT_FALSE(tBlink4Off.isEnabled());
- EXPECT_FALSE(simulated_led_state); // LED should be off at end
- tBlink4On_ptr = nullptr;
- tBlink4Off_ptr = nullptr;
- }
- // ================== APPROACH 5 TESTS ==================
- /**
- * @brief Test Approach 5: Interleaving Tasks
- *
- * TESTS: Phase-shifted dual tasks, OnEnable callback management, synchronized execution
- *
- * PURPOSE: Validate two independent tasks running with phase offset
- * where one task turns LED on and another turns it off, creating
- * precise timing control through task interleaving.
- *
- * IMPORTANCE: Demonstrates advanced timing patterns for applications
- * requiring precise phase relationships and independent task control.
- */
- TEST_F(BlinkExampleTest, Approach5_InterleavingTasks) {
- Scheduler ts;
- Task tBlink5On(PERIOD5, DURATION / PERIOD5, &blink51, &ts, false, &blink51OE);
- Task tBlink5Off(PERIOD5, DURATION / PERIOD5, &blink52, &ts, false, nullptr, &blink52OD);
- tBlink5On_ptr = &tBlink5On;
- tBlink5Off_ptr = &tBlink5Off;
- // Start both tasks (in real example, they'd be phase-shifted)
- tBlink5On.enable();
- tBlink5Off.enable();
- // Should execute OnEnable
- bool success = runBlinkSchedulerUntil(ts, condition_output_count_1);
- EXPECT_TRUE(success);
- EXPECT_EQ(getBlinkTestOutput(0), "BLINK5_START");
- // Let both tasks run
- success = runBlinkSchedulerUntil(ts, condition_led_changes_8, 4000);
- EXPECT_TRUE(success);
- EXPECT_GE(led_state_changes, 8);
- // Both tasks should be enabled and running
- EXPECT_TRUE(tBlink5On.isEnabled() || tBlink5Off.isEnabled());
- // Wait for completion
- success = runBlinkSchedulerUntil(ts, condition_both_blink5_disabled, 15000);
- EXPECT_TRUE(success);
- EXPECT_FALSE(simulated_led_state); // LED should be off at end
- tBlink5On_ptr = nullptr;
- tBlink5Off_ptr = nullptr;
- }
- // ================== APPROACH 6 TESTS ==================
- /**
- * @brief Test Approach 6: Random Interval Generation
- *
- * TESTS: setInterval(), dynamic interval modification, run counter + interval combination
- *
- * PURPOSE: Validate dynamic interval adjustment where LED ON time is
- * random and OFF time is complementary to maintain constant period.
- * Tests runtime interval modification and complex timing patterns.
- *
- * IMPORTANCE: Demonstrates adaptive timing behaviors essential for
- * applications requiring variable timing patterns while maintaining
- * overall system timing constraints.
- */
- TEST_F(BlinkExampleTest, Approach6_RandomIntervalGeneration) {
- Scheduler ts;
- Task tBlink6(PERIOD6, DURATION / PERIOD6, &blink6CB, &ts, false, &blink6OE, &blink6OD);
- tBlink6_ptr = &tBlink6;
- // Enable task to start
- tBlink6.enable();
- // Should execute OnEnable and set initial interval
- bool success = runBlinkSchedulerUntil(ts, condition_output_count_1);
- EXPECT_TRUE(success);
- EXPECT_EQ(getBlinkTestOutput(0), "BLINK6_START");
- EXPECT_EQ(interval6, 500); // Fixed value for testing
- EXPECT_EQ(tBlink6.getInterval(), 500);
- // Let it run and change intervals
- success = runBlinkSchedulerUntil(ts, condition_tBlink6_runcount_4, 3000);
- EXPECT_TRUE(success);
- EXPECT_GE(tBlink6.getRunCounter(), 4);
- // Verify interval changes based on run counter
- if (tBlink6.getRunCounter() & 1) {
- EXPECT_EQ(tBlink6.getInterval(), interval6); // ON interval
- EXPECT_TRUE(simulated_led_state);
- } else {
- EXPECT_EQ(tBlink6.getInterval(), 1000 - interval6); // OFF interval
- EXPECT_FALSE(simulated_led_state);
- }
- // Wait for completion
- success = runBlinkSchedulerUntil(ts, condition_tBlink6_disabled, 15000);
- EXPECT_TRUE(success);
- EXPECT_FALSE(simulated_led_state); // LED should be off at end
- tBlink6_ptr = nullptr;
- }
- // ================== INTEGRATION TESTS ==================
- /**
- * @brief Test Sequential Task Chain Execution
- *
- * TESTS: Complete blink example sequence, task chaining, scheduler coordination
- *
- * PURPOSE: Validate the complete blink example workflow where each
- * approach runs for its duration then triggers the next approach,
- * creating a continuous demonstration cycle.
- *
- * IMPORTANCE: Verifies end-to-end scheduler behavior with complex
- * task relationships, timing coordination, and state management
- * across multiple interconnected blinking patterns.
- */
- TEST_F(BlinkExampleTest, SequentialTaskChainExecution) {
- Scheduler ts;
- debug_output_enabled = true;
- // Create all tasks (simplified version)
- Task tBlink1(PERIOD1, 4, &blink1CB, &ts, true); // Shorter duration for testing
- tBlink1_ptr = &tBlink1;
- // Run just the first approach for integration test
- bool success = runBlinkSchedulerUntil(ts, condition_output_count_1);
- EXPECT_TRUE(success);
- EXPECT_EQ(getBlinkTestOutput(0), "BLINK1_START");
- // Let it complete its cycles
- success = runBlinkSchedulerUntil(ts, condition_tBlink1_disabled, 5000);
- EXPECT_TRUE(success);
- EXPECT_FALSE(tBlink1.isEnabled());
- // Verify proper execution pattern
- EXPECT_GE(led_state_changes, 4); // Should have blinked at least twice
- EXPECT_FALSE(simulated_led_state); // Should end with LED off
- tBlink1_ptr = nullptr;
- debug_output_enabled = false;
- }
- /**
- * @brief Test Scheduler Core Functionality with Blink Patterns
- *
- * TESTS: execute() return values, task management, timing accuracy
- *
- * PURPOSE: Validate scheduler core behavior under the complex timing
- * and callback patterns used in the blink example. Tests idle detection,
- * execution ordering, and overall scheduler robustness.
- *
- * IMPORTANCE: Ensures the scheduler performs correctly under realistic
- * workloads with multiple timing patterns, callback switches, and
- * complex task interdependencies typical of real applications.
- */
- TEST_F(BlinkExampleTest, SchedulerCoreFunctionalityValidation) {
- Scheduler ts;
- // Create a simple blinking task
- Task tBlink(500, 6, &blink1CB, &ts, true);
- tBlink1_ptr = &tBlink;
- int execute_calls = 0;
- int idle_returns = 0;
- // Monitor scheduler execution behavior
- unsigned long start_time = millis();
- while (millis() - start_time < 4000 && tBlink.isEnabled()) {
- bool idle = ts.execute();
- execute_calls++;
- if (idle) {
- idle_returns++;
- }
- }
- // Verify scheduler execution statistics
- EXPECT_GT(execute_calls, 100); // Should have been called many times
- EXPECT_GT(idle_returns, 50); // Should have had idle periods
- EXPECT_LE(idle_returns, execute_calls); // Idle returns <= total calls
- // Verify task completed successfully
- EXPECT_FALSE(tBlink.isEnabled());
- EXPECT_GE(led_state_changes, 6); // Should have blinked 3 times (on/off cycles)
- tBlink1_ptr = nullptr;
- }
- /**
- * @brief Main test runner function for blink example tests
- */
- int main(int argc, char **argv) {
- ::testing::InitGoogleTest(&argc, argv);
- return RUN_ALL_TESTS();
- }
|