23#include "driver/gpio.h"
24#include "freertos/FreeRTOS.h"
25#include "freertos/queue.h"
26#include "freertos/semphr.h"
27#include "freertos/task.h"
57 gpio_config_t io_conf = {
59 .mode = GPIO_MODE_OUTPUT,
60 .pull_up_en = GPIO_PULLUP_DISABLE,
61 .pull_down_en = GPIO_PULLDOWN_DISABLE,
62 .intr_type = GPIO_INTR_DISABLE,
65 esp_err_t ret = gpio_config(&io_conf);
67 const char*
TAG =
"TestFramework";
68 ESP_LOGE(
TAG,
"Failed to configure GPIO14: %s", esp_err_to_name(ret));
95 const char*
TAG =
"TestFramework";
99 vTaskDelay(pdMS_TO_TICKS(50));
130 for (uint8_t i = 0; i < blink_count; ++i) {
132 vTaskDelay(pdMS_TO_TICKS(50));
134 vTaskDelay(pdMS_TO_TICKS(50));
169 void add_result(
bool passed, uint64_t execution_time)
noexcept {
215#define RUN_TEST_1(test_func) \
217 ensure_gpio14_initialized(); \
220 "╔══════════════════════════════════════════════════════════════════════════════╗\n" \
221 "║ Running: " #test_func " \n" \
222 "╚══════════════════════════════════════════════════════════════════════════════╝"); \
223 uint64_t start_time = esp_timer_get_time(); \
224 bool result = test_func(); \
225 uint64_t end_time = esp_timer_get_time(); \
226 uint64_t execution_time = end_time - start_time; \
227 g_test_results.add_result(result, execution_time); \
229 ESP_LOGI(TAG, "[SUCCESS] PASSED: " #test_func " (%.2f ms)", execution_time / 1000.0); \
231 ESP_LOGE(TAG, "[FAILED] FAILED: " #test_func " (%.2f ms)", execution_time / 1000.0); \
233 vTaskDelay(pdMS_TO_TICKS(100)); \
236#define RUN_TEST_2(test_name, test_func) \
238 ensure_gpio14_initialized(); \
241 "╔══════════════════════════════════════════════════════════════════════════════╗\n" \
243 "╚══════════════════════════════════════════════════════════════════════════════╝", \
245 uint64_t start_time = esp_timer_get_time(); \
246 bool result = test_func(); \
247 uint64_t end_time = esp_timer_get_time(); \
248 uint64_t execution_time = end_time - start_time; \
249 g_test_results.add_result(result, execution_time); \
251 ESP_LOGI(TAG, "[SUCCESS] PASSED: %s (%.2f ms)", test_name, execution_time / 1000.0); \
253 ESP_LOGE(TAG, "[FAILED] FAILED: %s (%.2f ms)", test_name, execution_time / 1000.0); \
255 vTaskDelay(pdMS_TO_TICKS(100)); \
259#define RUN_TEST_GET_MACRO(_1, _2, NAME, ...) NAME
260#define RUN_TEST(...) RUN_TEST_GET_MACRO(__VA_ARGS__, RUN_TEST_2, RUN_TEST_1)(__VA_ARGS__)
280 "╔══════════════════════════════════════════════════════════════════════════════╗\n"
281 "║ Running (task): %s \n"
282 "╚══════════════════════════════════════════════════════════════════════════════╝",
284 uint64_t start_time = esp_timer_get_time();
286 uint64_t end_time = esp_timer_get_time();
287 uint64_t execution_time = end_time - start_time;
290 ESP_LOGI(ctx->
tag,
"[SUCCESS] PASSED (task): %s (%.2f ms)", ctx->
test_name,
291 execution_time / 1000.0);
293 ESP_LOGE(ctx->
tag,
"[FAILED] FAILED (task): %s (%.2f ms)", ctx->
test_name,
294 execution_time / 1000.0);
302 vTaskDelete(
nullptr);
312#define RUN_TEST_IN_TASK(name, func, stack_size_bytes, priority) \
314 ensure_gpio14_initialized(); \
315 static TestTaskContext ctx; \
316 ctx.test_name = name; \
317 ctx.test_func = func; \
318 ctx.results = &g_test_results; \
320 ctx.completion_semaphore = xSemaphoreCreateBinary(); \
321 if (ctx.completion_semaphore == nullptr) { \
322 ESP_LOGE(TAG, "Failed to create semaphore for test: %s", name); \
326 BaseType_t created = \
327 xTaskCreate(test_task_trampoline, name, (stack_size_bytes) / sizeof(StackType_t), &ctx, \
328 (priority), nullptr); \
329 if (created != pdPASS) { \
330 ESP_LOGE(TAG, "Failed to create test task: %s", name); \
331 vSemaphoreDelete(ctx.completion_semaphore); \
336 if (xSemaphoreTake(ctx.completion_semaphore, pdMS_TO_TICKS(30000)) == pdTRUE) { \
337 ESP_LOGI(TAG, "Test task completed: %s", name); \
339 ESP_LOGW(TAG, "Test task timeout: %s", name); \
341 vSemaphoreDelete(ctx.completion_semaphore); \
343 vTaskDelay(pdMS_TO_TICKS(100)); \
354 const char* tag)
noexcept {
356 ESP_LOGI(tag,
"\n=== %s TEST SUMMARY ===", test_suite_name);
357 ESP_LOGI(tag,
"Total: %d, Passed: %d, Failed: %d, Success: %.2f%%, Time: %.2f ms",
358 test_results.total_tests, test_results.passed_tests, test_results.failed_tests,
359 test_results.get_success_percentage(), test_results.get_total_time_ms());
361 if (test_results.failed_tests == 0) {
362 ESP_LOGI(tag,
"[SUCCESS] ALL %s TESTS PASSED!", test_suite_name);
364 ESP_LOGE(tag,
"[FAILED] Some tests failed. Review the results above.");
376 ESP_LOGI(tag,
"╔══════════════════════════════════════════════════════════════════════════════╗");
377 ESP_LOGI(tag,
"║ %s TEST SECTION CONFIGURATION ║",
379 ESP_LOGI(tag,
"╚══════════════════════════════════════════════════════════════════════════════╝");
380 ESP_LOGI(tag,
"To modify test sections, edit the defines at the top of your test file");
381 ESP_LOGI(tag,
"╔══════════════════════════════════════════════════════════════════════════════╗");
390 bool enabled =
true) noexcept {
394 "╔══════════════════════════════════════════════════════════════════════════════╗");
395 ESP_LOGI(tag,
"║ %s ",
398 "╠══════════════════════════════════════════════════════════════════════════════╣");
402 "╔══════════════════════════════════════════════════════════════════════════════╗");
403 ESP_LOGI(tag,
"║ %s (DISABLED) ",
406 "╚══════════════════════════════════════════════════════════════════════════════╝");
416 bool enabled =
true) noexcept {
419 "╚══════════════════════════════════════════════════════════════════════════════╝");
441#define RUN_TEST_SECTION_IF_ENABLED(define_name, section_name, ...) \
443 ensure_gpio14_initialized(); \
445 print_test_section_header(TAG, section_name, true); \
447 print_test_section_footer(TAG, section_name, true); \
449 print_test_section_header(TAG, section_name, false); \
450 ESP_LOGI(TAG, "Section disabled by configuration"); \
455#define RUN_SINGLE_TEST_IF_ENABLED(define_name, test_name, test_func, stack_size, priority) \
457 ensure_gpio14_initialized(); \
459 RUN_TEST_IN_TASK(test_name, test_func, stack_size, priority); \
460 flip_test_progress_indicator(); \
462 ESP_LOGI(TAG, "Test '%s' disabled by configuration", test_name); \
467#define RUN_TEST_GROUP_IF_ENABLED(define_name, section_name, ...) \
468 RUN_TEST_SECTION_IF_ENABLED(define_name, section_name, __VA_ARGS__)
471#define RUN_TEST_SECTION_IF_ENABLED_WITH_PROGRESS(define_name, section_name, progress_func, ...) \
473 ensure_gpio14_initialized(); \
475 print_test_section_header(TAG, section_name, true); \
479 print_test_section_footer(TAG, section_name, true); \
481 print_test_section_header(TAG, section_name, false); \
482 ESP_LOGI(TAG, "Section disabled by configuration"); \
487#define RUN_TEST_SECTION_IF_ENABLED_AUTO_PROGRESS(define_name, section_name, ...) \
488 RUN_TEST_SECTION_IF_ENABLED_WITH_PROGRESS(define_name, section_name, \
489 flip_test_progress_indicator, __VA_ARGS__)
492#define RUN_TEST_SECTION_IF_ENABLED_WITH_PATTERN(define_name, section_name, blink_count, ...) \
494 ensure_gpio14_initialized(); \
496 print_test_section_header(TAG, section_name, true); \
497 output_section_indicator(blink_count); \
499 output_section_indicator(blink_count); \
500 print_test_section_footer(TAG, section_name, true); \
502 print_test_section_header(TAG, section_name, false); \
503 ESP_LOGI(TAG, "Section disabled by configuration"); \
static constexpr const char * TAG
Definition Max22200Handler.cpp:11
static constexpr gpio_num_t TEST_PROGRESS_PIN
Definition TestFramework.h:42
static bool g_test_progress_state
Definition TestFramework.h:41
void output_section_indicator(uint8_t blink_count=5) noexcept
Output section start/end indicator on GPIO14.
Definition TestFramework.h:124
void print_test_section_status(const char *tag, const char *test_suite_name) noexcept
Print standardized test summary.
Definition TestFramework.h:373
bool init_test_progress_indicator() noexcept
Initialize the test progression indicator on GPIO14.
Definition TestFramework.h:51
void ensure_gpio14_initialized() noexcept
Automatically initialize GPIO14 test indicator if not already done.
Definition TestFramework.h:149
void print_test_section_header(const char *tag, const char *section_name, bool enabled=true) noexcept
Print test section header with consistent formatting.
Definition TestFramework.h:389
void cleanup_test_progress_indicator() noexcept
Cleanup the test progression indicator GPIO.
Definition TestFramework.h:106
void print_test_section_footer(const char *tag, const char *section_name, bool enabled=true) noexcept
Print test section footer with consistent formatting.
Definition TestFramework.h:415
void flip_test_progress_indicator() noexcept
Flip the test progression indicator to show next test.
Definition TestFramework.h:84
static bool g_test_progress_initialized
Definition TestFramework.h:40
void print_test_summary(const TestResults &test_results, const char *test_suite_name, const char *tag) noexcept
Print standardized test summary.
Definition TestFramework.h:353
void test_task_trampoline(void *param)
FreeRTOS task trampoline to execute a test with a larger dedicated stack.
Definition TestFramework.h:276
int gpio_num_t
Definition Ws2812Handler.h:57
Test execution tracking and results accumulation.
Definition TestFramework.h:158
int failed_tests
Definition TestFramework.h:161
void add_result(bool passed, uint64_t execution_time) noexcept
Add test result and update statistics.
Definition TestFramework.h:169
int passed_tests
Definition TestFramework.h:160
float get_total_time_ms() const noexcept
Get total execution time in milliseconds.
Definition TestFramework.h:191
uint64_t total_execution_time_us
Definition TestFramework.h:162
float get_success_percentage() const noexcept
Calculate success percentage.
Definition TestFramework.h:183
int total_tests
Definition TestFramework.h:159
Context passed to test task trampoline.
Definition TestFramework.h:265
TestResults * results
Definition TestFramework.h:268
bool(* test_func)() noexcept
Definition TestFramework.h:267
SemaphoreHandle_t completion_semaphore
Definition TestFramework.h:270
const char * test_name
Definition TestFramework.h:266
const char * tag
Definition TestFramework.h:269