209 lines
9.8 KiB
C
209 lines
9.8 KiB
C
// 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;
|
||
|
|
}
|