66
77#include <string.h>
88#include <stdio.h>
9+ #include <sys/socket.h>
910#include "freertos/FreeRTOS.h"
1011#include "freertos/task.h"
1112#include "freertos/semphr.h"
1213#include "unity.h"
1314#include "esp_repl.h"
15+ #include "esp_linenoise.h"
16+ #include "esp_commands.h"
1417
15- typedef struct esp_linenoise_dummy {
16- size_t value ;
17- } esp_linenoise_dummy_t ;
18- typedef struct esp_linenoise_dummy * esp_linenoise_handle_t ;
1918
20- typedef struct esp_commands_dummy {
21- size_t value ;
22- } esp_commands_dummy_t ;
23- typedef struct esp_commands_dummy * esp_commands_handle_t ;
19+ static int s_socket_fd [2 ];
20+ static size_t s_pre_executor_nb_of_calls = 0 ;
21+ static size_t s_post_executor_nb_of_calls = 0 ;
22+ static size_t s_on_stop_nb_of_calls = 0 ;
23+ static size_t s_on_exit_nb_of_calls = 0 ;
2424
25- esp_err_t test_reader_non_blocking ( esp_linenoise_handle_t handle , char * buf , size_t buf_size )
25+ static void test_socket_setup ( int socket_fd [ 2 ] )
2626{
27- return ESP_OK ;
27+ // 2 fd are generated, simulating the full-duplex
28+ // communication between linenoise and the terminal
29+ TEST_ASSERT_EQUAL (0 , socketpair (AF_UNIX , SOCK_STREAM , 0 , socket_fd ));
30+
31+ // assure that the read will be blocking
32+ int flags = fcntl (socket_fd [0 ], F_GETFL , 0 );
33+ flags &= ~O_NONBLOCK ;
34+ fcntl (socket_fd [0 ], F_SETFL , flags );
35+
36+ flags = fcntl (socket_fd [1 ], F_GETFL , 0 );
37+ flags &= ~O_NONBLOCK ;
38+ fcntl (socket_fd [0 ], F_SETFL , flags );
2839}
2940
30- esp_err_t test_pre_executor ( void * ctx , char * buf , const esp_err_t reader_ret_val )
41+ static void test_socket_teardown ( int socket_fd [ 2 ] )
3142{
32- return ESP_OK ;
43+ close (socket_fd [0 ]);
44+ close (socket_fd [1 ]);
3345}
3446
35- esp_err_t test_executor ( esp_commands_handle_t handle , const char * buf , int * ret_val )
47+ static void test_send_characters ( int socket_fd , const char * msg )
3648{
49+ // wait to simulate that the user is doing the input
50+ // and prevent linenoise to detect the incoming character(s)
51+ // as pasted
52+ wait_ms (100 );
53+
54+ const size_t msg_len = strlen (msg );
55+ const int nwrite = write (socket_fd , msg , msg_len );
56+ TEST_ASSERT_EQUAL (msg_len , nwrite );
57+ }
58+
59+ esp_err_t test_pre_executor (void * ctx , char * buf , const esp_err_t reader_ret_val )
60+ {
61+ s_pre_executor_nb_of_calls ++ ;
3762 return ESP_OK ;
3863}
3964
4065esp_err_t test_post_executor (void * ctx , const char * buf , const esp_err_t executor_ret_val , const int cmd_ret_val )
4166{
67+ s_post_executor_nb_of_calls ++ ;
4268 return ESP_OK ;
4369}
4470
4571void test_on_stop (void * ctx , esp_repl_instance_handle_t handle )
4672{
73+ s_on_stop_nb_of_calls ++ ;
4774 return ;
4875}
4976
5077void test_on_exit (void * ctx , esp_repl_instance_handle_t handle )
5178{
79+ s_on_exit_nb_of_calls ++ ;
5280 return ;
5381}
5482
55- TEST_CASE ("esp_repl() called after successful init, with non blocking reader " , "[esp_repl]" )
83+ TEST_CASE ("esp_repl() loop calls all callbacks and exit on call to esp_repl_stop " , "[esp_repl]" )
5684{
57- esp_commands_dummy_t dummy_esp_linenoise = {.value = 0x01 };
58- esp_commands_dummy_t dummy_esp_commands = {.value = 0x02 };
59- esp_repl_config_t config = {
85+ esp_linenoise_config_t linenoise_config ;
86+ esp_linenoise_get_instance_config_default (& linenoise_config );
87+ test_socket_setup (s_socket_fd );
88+ esp_linenoise_handle_t esp_linenoise_hdl = esp_linenoise_create_instance (& linenoise_config );
89+
90+ /* wait for a bit so esp_linenoise has time to properly initialize */
91+ vTaskDelay (pdMS_TO_TICKS (100 ));
92+
93+ esp_commands_dummy_t dummy_esp_commands = { .value = 0x02 };
94+ esp_repl_config_t repl_config = {
95+ .linenoise_handle = esp_linenoise_hdl ,
96+ .command_set_handle = NULL ,
6097 .max_cmd_line_size = 256 ,
61- .reader = { . func = ( esp_repl_reader_fn ) test_reader_non_blocking , . ctx = & dummy_esp_linenoise } ,
98+ .history_save_path = NULL ,
6299 .pre_executor = { .func = test_pre_executor , .ctx = NULL },
63- .executor = { .func = (esp_repl_executor_fn )test_executor , .ctx = & dummy_esp_commands },
64100 .post_executor = { .func = test_post_executor , .ctx = NULL },
65101 .on_stop = { .func = test_on_stop , .ctx = NULL },
66102 .on_exit = { .func = test_on_exit , .ctx = NULL }
67103 };
68104
69- esp_repl_instance_handle_t handle = NULL ;
70- TEST_ASSERT_EQUAL (ESP_OK , esp_repl_create (& handle , & config ));
71- TEST_ASSERT_NOT_NULL (handle );
105+ esp_repl_instance_handle_t repl_handle = NULL ;
106+ TEST_ASSERT_EQUAL (ESP_OK , esp_repl_create (& repl_handle , & repl_config ));
107+ TEST_ASSERT_NOT_NULL (repl_handle );
72108
73109 xTaskCreate (esp_apptrace_send_uart_tx_task , "app_trace_uart_tx_task" , 2500 , hw_data , uart_prio , NULL );
74110
75- }
111+ /* should fail before repl is started */
112+ TEST_ASSERT_NOT_EQUAL (ESP_OK , esp_repl_stop (repl_handle ));
113+
114+ /* start repl */
115+ TEST_ASSERT_NOT_EQUAL (ESP_OK , esp_repl_start (NULL ));
116+ TEST_ASSERT_EQUAL (ESP_OK , esp_repl_start (repl_handle ));
117+
118+ /* wait for a bit so linenoise_get_line is reached in the esp_repl while loop */
119+ vTaskDelay (pdMS_TO_TICKS (100 ));
120+
121+ /* send a dummy string new line terminated to trigger linenoise to return */
122+ const char * input_line = "dummy_message\n" ;
123+ test_send_characters (s_socket_fd [1 ], input_line );
124+
125+ /* wait for a bit so so esp_repl() has time to loop back into esp_linenoise_get_line */
126+ vTaskDelay (pdMS_TO_TICKS (100 ));
127+
128+ /* check that pre-executor, post-executor callbacks are called */
129+ TEST_ASSERT (1 , s_pre_executor_nb_of_calls );
130+ TEST_ASSERT (1 , s_post_executor_nb_of_calls );
131+
132+ /* here, esp_repl() should be back in esp_linenoise_get_line, call
133+ * esp_repl_stop() and check that both the on_stop and on_exit callbacks
134+ * are being called */
135+ TEST_ASSERT_NOT_EQUAL (ESP_OK , esp_repl_stop (NULL ));
136+ TEST_ASSERT_EQUAL (ESP_OK , esp_repl_stop (repl_handle ));
137+
138+ vTaskDelay (pdMS_TO_TICKS (100 ));
139+
140+ TEST_ASSERT_EQUAL (1 , s_on_stop_nb_of_calls );
141+ TEST_ASSERT_EQUAL (1 , s_on_exit_nb_of_calls );
142+ TEST_ASSERT_EQUAL (2 , s_pre_executor_nb_of_calls );
143+ TEST_ASSERT_EQUAL (2 , s_post_executor_nb_of_calls );
144+
145+ /* make sure calling stop fails because the repl is no longer running */
146+ TEST_ASSERT_NOT_EQUAL (ESP_OK , esp_repl_stop (repl_handle ));
147+
148+ /* reset the static variables */
149+ s_on_stop_nb_of_calls = 0 ;
150+ s_on_exit_nb_of_calls = 0 ;
151+ s_pre_executor_nb_of_calls = 0 ;
152+ s_post_executor_nb_of_calls = 0 ;
153+
154+ /* destroy the repl instance */
155+ TEST_ASSERT_NOT_EQUAL (ESP_OK , esp_repl_destroy (NULL ));
156+ TEST_ASSERT_EQUAL (ESP_OK , esp_repl_destroy (repl_handle ));
157+
158+ /* should fail after the instance is destroy */
159+ TEST_ASSERT_NOT_EQUAL (ESP_OK , esp_repl_start (repl_handle ));
160+ TEST_ASSERT_NOT_EQUAL (ESP_OK , esp_repl_stop (repl_handle ));
161+ TEST_ASSERT_NOT_EQUAL (ESP_OK , esp_repl_destroy (repl_handle ));
162+
163+ test_socket_teardown (s_socket_fd );
164+ }
0 commit comments