Files

209 lines
9.8 KiB
C
Raw Permalink Normal View History

// Host SDK shim: only SDK calls are mocked; the driver lifecycle under test is
// inserted verbatim from main/ble_wifi.c by ble-wifi-host.cjs.
#include <assert.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
typedef int esp_err_t;
#define ESP_OK 0
#define ESP_ERR_NO_MEM 1
#define ESP_ERR_INVALID_STATE 2
#define ESP_ERR_INVALID_ARG 3
#define ESP_ERR_TIMEOUT 4
#define ESP_FAIL 5
#define BIT0 1
#define BIT1 2
#define BIT2 4
#define pdFALSE 0
#define pdMS_TO_TICKS(x) (x)
#define MALLOC_CAP_INTERNAL 1
#define ESP_EVENT_ANY_ID (-1)
#define WIFI_EVENT 1
#define IP_EVENT 2
#define IP_EVENT_STA_GOT_IP 1
#define WIFI_EVENT_STA_DISCONNECTED 2
#define WIFI_EVENT_STA_STOP 3
#define WIFI_STORAGE_RAM 1
#define WIFI_MODE_STA 1
#define WIFI_IF_STA 0
#define WIFI_AUTH_WPA2_PSK 3
#define WIFI_ALL_CHANNEL_SCAN 1
#define WIFI_CONNECT_AP_BY_SIGNAL 1
typedef int esp_event_base_t;
typedef int *esp_event_handler_instance_t;
typedef unsigned EventBits_t;
typedef EventBits_t *EventGroupHandle_t;
typedef struct { int placeholder; } esp_netif_t;
typedef struct { int placeholder; } esp_netif_config_t;
#define ESP_NETIF_DEFAULT_WIFI_STA() ((esp_netif_config_t){0})
typedef struct { unsigned reason; } wifi_event_sta_disconnected_t;
typedef struct {
int static_rx_buf_num, dynamic_rx_buf_num, static_tx_buf_num, cache_tx_buf_num;
int ampdu_rx_enable, ampdu_tx_enable, amsdu_tx_enable;
} wifi_init_config_t;
#define WIFI_INIT_CONFIG_DEFAULT() ((wifi_init_config_t){16,32,16,32,1,1,0})
typedef struct { struct {
char ssid[32], password[64];
struct { int authmode; } threshold;
int scan_method, sort_method;
} sta; } wifi_config_t;
static void mock_log(const char *tag, const char *format, ...) {(void)tag; (void)format;}
#define ESP_LOGI(...) mock_log(__VA_ARGS__)
#define ESP_LOGW(...) mock_log(__VA_ARGS__)
#define ESP_LOGE(...) mock_log(__VA_ARGS__)
static const char *esp_err_to_name(esp_err_t err) {(void)err; return "mock";}
static unsigned heap_caps_get_free_size(int cap) {(void)cap; return 50000;}
static unsigned heap_caps_get_largest_free_block(int cap) {(void)cap; return 30000;}
enum point { NONE, GROUP, NEW_NETIF, ATTACH, DEFAULT_HANDLERS, DRIVER,
WIFI_HANDLER, IP_HANDLER, STORAGE, MODE, CONFIG, START, CONNECT, STOP, POINTS };
static int calls[POINTS], fail_point, failures, destroys, foreign;
static bool should_connect, emit_disconnect, stop_ack;
static EventBits_t bits;
static esp_netif_t mock_station, other_station;
static int handler_handles[2];
static wifi_config_t last_config;
static void (*callback)(void *, esp_event_base_t, int32_t, void *);
static bool fail(enum point point) {
calls[point]++;
if (fail_point == (int)point && failures) {failures--; return true;}
return false;
}
static EventGroupHandle_t xEventGroupCreate(void) {return fail(GROUP) ? NULL : &bits;}
static EventBits_t xEventGroupGetBits(EventGroupHandle_t e) {assert(e); return *e;}
static EventBits_t xEventGroupSetBits(EventGroupHandle_t e, EventBits_t b) {return *e |= b;}
static EventBits_t xEventGroupClearBits(EventGroupHandle_t e, EventBits_t b) {EventBits_t old=*e; *e &= ~b; return old;}
static EventBits_t xEventGroupWaitBits(EventGroupHandle_t e, EventBits_t b, int clear, int all, int ticks) {
(void)b; (void)clear; (void)all; (void)ticks; return *e;
}
static void vTaskDelay(int ticks) {(void)ticks;}
static esp_netif_t *esp_netif_get_handle_from_ifkey(const char *key) {
assert(!strcmp(key, "WIFI_STA")); return foreign ? &other_station : NULL;
}
static esp_netif_t *esp_netif_new(const esp_netif_config_t *c) {
(void)c; return fail(NEW_NETIF) ? NULL : &mock_station;
}
static esp_err_t esp_netif_attach_wifi_station(esp_netif_t *n) {assert(n); return fail(ATTACH) ? ESP_FAIL : ESP_OK;}
static esp_err_t esp_wifi_set_default_wifi_sta_handlers(void) {return fail(DEFAULT_HANDLERS) ? ESP_FAIL : ESP_OK;}
static void esp_netif_destroy_default_wifi(esp_netif_t *n) {assert(n == &mock_station); destroys++;}
static esp_err_t esp_wifi_init(const wifi_init_config_t *c) {
assert(c->static_rx_buf_num == 4 && c->static_tx_buf_num == 4);
assert(c->dynamic_rx_buf_num >= c->static_rx_buf_num && c->cache_tx_buf_num == 4);
assert(!c->ampdu_rx_enable && !c->ampdu_tx_enable && !c->amsdu_tx_enable);
return fail(DRIVER) ? ESP_ERR_NO_MEM : ESP_OK;
}
static esp_err_t esp_event_handler_instance_register(esp_event_base_t base, int id,
void (*cb)(void *, esp_event_base_t, int32_t, void *), void *arg, esp_event_handler_instance_t *instance) {
(void)id; (void)arg;
if (fail(base == WIFI_EVENT ? WIFI_HANDLER : IP_HANDLER)) return ESP_ERR_NO_MEM;
callback = cb; *instance = &handler_handles[base == WIFI_EVENT ? 0 : 1]; return ESP_OK;
}
static esp_err_t esp_wifi_set_storage(int storage) {assert(storage == WIFI_STORAGE_RAM); return fail(STORAGE) ? ESP_FAIL : ESP_OK;}
static esp_err_t esp_wifi_set_mode(int mode) {assert(mode == WIFI_MODE_STA); return fail(MODE) ? ESP_FAIL : ESP_OK;}
static esp_err_t esp_wifi_set_config(int iface, const wifi_config_t *c) {
assert(iface == WIFI_IF_STA); last_config = *c; return fail(CONFIG) ? ESP_FAIL : ESP_OK;
}
static esp_err_t esp_wifi_start(void) {return fail(START) ? ESP_ERR_NO_MEM : ESP_OK;}
static esp_err_t esp_wifi_connect(void) {
if (fail(CONNECT)) return ESP_FAIL;
if (should_connect) callback(NULL, IP_EVENT, IP_EVENT_STA_GOT_IP, NULL);
else if (emit_disconnect) {wifi_event_sta_disconnected_t e = {201}; callback(NULL, WIFI_EVENT, WIFI_EVENT_STA_DISCONNECTED, &e);}
return ESP_OK;
}
static esp_err_t esp_wifi_stop(void) {
if (fail(STOP)) return ESP_FAIL;
if (stop_ack) callback(NULL, WIFI_EVENT, WIFI_EVENT_STA_STOP, NULL);
return ESP_OK;
}
/* PRODUCTION_SOURCE */
static void reset(void) {
station=NULL; events=NULL; wifi_handler=NULL; ip_handler=NULL;
driver_ready=false; prepared=false; started=false; stopping=false;
memset(calls,0,sizeof(calls)); memset(&last_config,0,sizeof(last_config));
fail_point=NONE; failures=0; destroys=0; foreign=0; bits=0;
should_connect=true; emit_disconnect=false; stop_ack=true; callback=NULL;
}
int main(void) {
unsigned tests=0;
reset();
assert(!ble_wifi_connected());
assert(ble_wifi_prepare()==ESP_OK && ble_wifi_prepare()==ESP_OK);
assert(calls[DRIVER]==1 && calls[NEW_NETIF]==1 && calls[GROUP]==1);
assert(calls[START]==0 && calls[CONNECT]==0); tests++;
// Every initialization failure is recoverable, without duplicate owners.
for (enum point p=GROUP; p<=MODE; ++p) {
reset(); fail_point=p; failures=1;
assert(ble_wifi_prepare()!=ESP_OK);
assert(ble_wifi_prepare()==ESP_OK);
assert(ble_wifi_prepare()==ESP_OK);
assert(calls[NEW_NETIF] <= ((p==NEW_NETIF || p==ATTACH || p==DEFAULT_HANDLERS) ? 2 : 1));
assert(calls[GROUP] == (p==GROUP ? 2 : 1));
assert(calls[DRIVER] == (p==DRIVER ? 2 : 1));
assert(destroys == (p==ATTACH || p==DEFAULT_HANDLERS ? 1 : 0));
tests++;
}
reset(); fail_point=DRIVER; failures=10;
for (int i=0; i<10; ++i) assert(ble_wifi_prepare()==ESP_ERR_NO_MEM);
assert(ble_wifi_prepare()==ESP_OK);
assert(calls[NEW_NETIF]==1 && calls[GROUP]==1 && calls[DEFAULT_HANDLERS]==1); tests++;
reset(); foreign=1;
assert(ble_wifi_prepare()==ESP_ERR_INVALID_STATE);
assert(calls[NEW_NETIF]==0 && destroys==0); tests++;
reset(); assert(ble_wifi_connect("test-network","test-password")==ESP_OK);
assert(ble_wifi_connected());
assert(!strcmp(last_config.sta.ssid,"test-network"));
assert(!strcmp(last_config.sta.password,"test-password"));
assert(last_config.sta.threshold.authmode==WIFI_AUTH_WPA2_PSK);
assert(ble_wifi_connect("new-network","new-password")==ESP_OK);
assert(calls[DRIVER]==1 && calls[NEW_NETIF]==1 && calls[STOP]==1);
assert(!strcmp(last_config.sta.ssid,"new-network")); tests++;
for (enum point p=CONFIG; p<=CONNECT; ++p) {
reset(); fail_point=p; failures=3;
while(failures) assert(ble_wifi_connect("test-network","test-password")!=ESP_OK);
assert(ble_wifi_connect("test-network","test-password")==ESP_OK);
assert(calls[DRIVER]==1 && calls[NEW_NETIF]==1 && calls[GROUP]==1); tests++;
}
for (int disconnect=0; disconnect<2; ++disconnect) {
reset(); should_connect=false; emit_disconnect=disconnect;
assert(ble_wifi_connect("test-network","test-password")==ESP_ERR_TIMEOUT);
assert(!ble_wifi_connected() && calls[START]==3 && calls[STOP]==3);
should_connect=true;
assert(ble_wifi_connect("test-network","test-password")==ESP_OK);
assert(calls[NEW_NETIF]==1 && calls[DRIVER]==1); tests++;
}
reset(); assert(ble_wifi_connect("test-network","test-password")==ESP_OK);
wifi_event_sta_disconnected_t e={201};
callback(NULL,WIFI_EVENT,WIFI_EVENT_STA_DISCONNECTED,&e);
assert(!ble_wifi_connected()); tests++;
reset(); assert(ble_wifi_connect("test-network","test-password")==ESP_OK);
fail_point=STOP; failures=1;
assert(ble_wifi_connect("test-network","test-password")==ESP_FAIL);
assert(ble_wifi_connect("test-network","test-password")==ESP_OK);
assert(calls[DRIVER]==1); tests++;
reset(); assert(ble_wifi_connect("test-network","test-password")==ESP_OK);
stop_ack=false;
assert(ble_wifi_connect("test-network","test-password")==ESP_ERR_TIMEOUT);
assert(ble_wifi_connect("test-network","test-password")==ESP_ERR_TIMEOUT);
assert(calls[STOP]==1);
assert(calls[CONNECT]==1);
callback(NULL,WIFI_EVENT,WIFI_EVENT_STA_STOP,NULL); stop_ack=true;
assert(ble_wifi_connect("test-network","test-password")==ESP_OK); tests++;
reset(); assert(ble_wifi_connect(NULL,"password")==ESP_ERR_INVALID_ARG);
assert(ble_wifi_connect("","password")==ESP_ERR_INVALID_ARG);
assert(ble_wifi_connect("network",NULL)==ESP_ERR_INVALID_ARG);
assert(calls[NEW_NETIF]==0); tests++;
printf("PASS: %u Wi-Fi lifecycle/fault-injection cases (production C)\n",tests);
return 0;
}