Files
templates/c/led-indicator/tests/test_led_indicator.c

111 lines
8.0 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*
* Проверки led_indicator: фиксируют ожидаемое поведение на воспроизводимых входных данных.
* Тестовые значения и подмены окружения относятся к проверке контракта; они не являются
* настройками рабочего устройства.
*/
#include "led_indicator.h"
#include <stdio.h>
typedef struct {
uint32_t now;
uint8_t outputs[3];
uint32_t writes[3];
} FakePort;
static void fake_write(void *context, uint8_t channel, uint8_t on)
{
FakePort *fake = (FakePort *)context;
fake->outputs[channel] = on;
fake->writes[channel]++;
}
static uint32_t fake_now(void *context)
{
return ((FakePort *)context)->now;
}
#define CHECK(condition) \
do { \
if (!(condition)) { \
fprintf(stderr, "check failed at line %d: %s\n", __LINE__, \
#condition); \
return 1; \
} \
} while (0)
int main(void)
{
LedIndicator indicator;
LedIndicator_Channel channels[3];
LedIndicator_Config config;
LedIndicator_Pattern patterns[LED_INDICATOR_MODE_COUNT];
FakePort fake = {0};
LedIndicator_Port port = {fake_write, fake_now, &fake};
LedIndicator_ConfigDefault(&config);
CHECK(LedIndicator_ValidateConfig(&config) != 0U);
CHECK(LedIndicator_CopyDefaultPatterns(patterns, LED_INDICATOR_MODE_COUNT) ==
LED_INDICATOR_MODE_COUNT);
patterns[LED_INDICATOR_MODE_WORK].duration_ms[0] = 25U;
CHECK(patterns[LED_INDICATOR_MODE_WORK].duration_ms[0] == 25U);
CHECK(LedIndicator_Init(&indicator, channels, 3U, &port, &config) != 0U);
CHECK(fake.writes[0] == 1U && fake.writes[1] == 1U && fake.writes[2] == 1U);
CHECK(LedIndicator_SetMode(&indicator, 0U, LED_INDICATOR_MODE_WORK) != 0U);
CHECK(fake.outputs[0] == 1U);
fake.now = 99U;
CHECK(LedIndicator_SetMode(&indicator, 0U, LED_INDICATOR_MODE_WORK) != 0U);
LedIndicator_Process(&indicator);
CHECK(fake.outputs[0] == 1U);
fake.now = 100U;
LedIndicator_Process(&indicator);
CHECK(fake.outputs[0] == 0U);
fake.now = 1000U;
LedIndicator_Process(&indicator);
CHECK(fake.outputs[0] == 1U);
fake.now = 1050U;
CHECK(LedIndicator_RestartMode(&indicator, 0U, LED_INDICATOR_MODE_WORK) != 0U);
fake.now = 1150U;
LedIndicator_Process(&indicator);
CHECK(fake.outputs[0] == 0U);
CHECK(LedIndicator_SetModeAt(&indicator, 1U, LED_INDICATOR_MODE_ERROR,
0xFFFFFFF0UL) != 0U);
LedIndicator_ProcessAt(&indicator, 0x00000054UL);
CHECK(fake.outputs[1] == 0U); /* 100 ms после старта, переход во второй шаг. */
LedIndicator_ProcessAt(&indicator, 0x000000B8UL);
CHECK(fake.outputs[1] == 1U); /* 200 ms после старта, второй импульс. */
CHECK(LedIndicator_SetModeAt(&indicator, 2U, LED_INDICATOR_MODE_STARTUP, 10U) != 0U);
LedIndicator_ProcessAt(&indicator, 610U);
CHECK(fake.outputs[2] == 1U); /* Однократный startup завершён постоянным ON. */
CHECK(LedIndicator_SetMode(&indicator, 3U, LED_INDICATOR_MODE_ON) == 0U);
CHECK(LedIndicator_GetMode(&indicator, 0U) == LED_INDICATOR_MODE_WORK);
CHECK(patterns[LED_INDICATOR_MODE_ACTIVITY].duration_ms[0] == 100U && patterns[LED_INDICATOR_MODE_ACTIVITY].duration_ms[1] == 900U && patterns[LED_INDICATOR_MODE_ACTIVITY].repeat == 0U); /* Фиксирует согласованные 10% свечения и один цикл на приём в канонической таблице. */
CHECK(LedIndicator_TriggerActivityAt(&indicator, 0U, 2500U) != 0U && fake.outputs[0] == 1U); /* Приём сразу включает канал независимо от фазы прежнего WORK. */
LedIndicator_ProcessAt(&indicator, 2599U); CHECK(fake.outputs[0] == 1U); /* До истечения 100 мс светодиод продолжает гореть. */
LedIndicator_ProcessAt(&indicator, 2600U); CHECK(fake.outputs[0] == 0U); /* Ровно через 100 мс начинается оставшаяся пауза 900 мс. */
LedIndicator_ProcessAt(&indicator, 3499U); CHECK(fake.outputs[0] == 0U); /* Конец первого периода не порождает дополнительную вспышку. */
LedIndicator_ProcessAt(&indicator, 3500U); CHECK(fake.outputs[0] == 0U); /* Однократный ACTIVITY завершается выключенным уровнем на границе 1000 мс. */
LedIndicator_ProcessAt(&indicator, 4500U); CHECK(fake.outputs[0] == 0U); /* Без новых пакетов свободное периодическое мигание отсутствует. */
CHECK(LedIndicator_TriggerActivityAt(&indicator, 0U, 5000U) != 0U); /* Начинает новый приём после долгого отсутствия обмена. */
CHECK(LedIndicator_TriggerActivityAt(&indicator, 0U, 5050U) != 0U); /* Второй пакет приходит внутри текущей фазы свечения. */
LedIndicator_ProcessAt(&indicator, 5100U); CHECK(fake.outputs[0] == 1U); /* Старый срок выключения больше не действует: отсчёт перезапущен новым пакетом. */
LedIndicator_ProcessAt(&indicator, 5149U); CHECK(fake.outputs[0] == 1U); /* Новый пакет получает собственные полные 100 мс свечения. */
LedIndicator_ProcessAt(&indicator, 5150U); CHECK(fake.outputs[0] == 0U); /* Новая фаза паузы начинается ровно от последнего приёма. */
CHECK(LedIndicator_TriggerActivityAt(&indicator, 0U, 5400U) != 0U && fake.outputs[0] == 1U); /* Приём во время паузы сразу включает LED вместо ожидания границы старого периода. */
LedIndicator_ProcessAt(&indicator, 5500U); CHECK(fake.outputs[0] == 0U); /* Повторный запуск в паузе не создаёт очередь пропущенных циклов. */
fake.now = 7000U; CHECK(LedIndicator_TriggerActivity(&indicator, 1U) != 0U && fake.outputs[1] == 1U); /* Проверяет вариант событийного API с часами аппаратного порта и другим каналом. */
fake.now = 7100U; LedIndicator_Process(&indicator); CHECK(fake.outputs[1] == 0U && fake.outputs[0] == 0U); /* Каналы не перезапускают друг другу фазы и не создают фоновую активность. */
CHECK(LedIndicator_TriggerActivityAt(&indicator, 0U, UINT32_MAX - 49U) != 0U); /* Начинает импульс непосредственно перед переполнением 32-битного времени. */
LedIndicator_ProcessAt(&indicator, 49U); CHECK(fake.outputs[0] == 1U); /* Через переполнение прошло 99 мс, поэтому свечение ещё активно. */
LedIndicator_ProcessAt(&indicator, 50U); CHECK(fake.outputs[0] == 0U); /* Через переполнение прошло ровно 100 мс, и LED гаснет без зависания. */
CHECK(LedIndicator_TriggerActivityAt(NULL, 0U, 0U) == 0U && LedIndicator_TriggerActivityAt(&indicator, 3U, 0U) == 0U); /* Ошибочный экземпляр и канал не вызывают запись чужого GPIO. */
puts("led indicator tests passed: receive 100/900 ms, immediate retrigger, no repeat, timer wrap"); /* Показывает прохождение новых событийных сценариев вместе с прежней диагностикой. */
return 0;
}