fix(console): add linenoise multithreading support for Picolibc

This commit is contained in:
Alexey Lapshin
2025-12-06 00:08:36 +07:00
parent 068fefad68
commit 535d93e149
10 changed files with 237 additions and 6 deletions
@@ -1,4 +1,10 @@
set(priv_requires unity console)
if(NOT CONFIG_IDF_TARGET_LINUX)
list(APPEND priv_requires esp_driver_uart)
endif()
idf_component_register(SRCS "test_app_main.c" "test_console.c"
INCLUDE_DIRS "."
PRIV_REQUIRES unity console
PRIV_REQUIRES ${priv_requires}
WHOLE_ARCHIVE)
@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -8,6 +8,9 @@
#include "unity_test_runner.h"
#include "unity_test_utils_memory.h"
#include <sys/time.h>
#if !CONFIG_IDF_TARGET_LINUX
#include "driver/uart.h"
#endif
// Some resources are lazy allocated (newlib locks) in the console code, the threshold is left for that case
#define TEST_MEMORY_LEAK_THRESHOLD_DEFAULT (150)
@@ -36,6 +39,15 @@ void app_main(void)
struct timeval tv = { 0 };
gettimeofday(&tv, NULL);
#if !CONFIG_IDF_TARGET_LINUX
/* Preallocate UART1 memory */
fileno(stdin);
uart_driver_install(UART_NUM_1, 256, 0, 0, NULL, 0);
FILE *f = fopen("/dev/uart/1", "rw");
fclose(f);
uart_driver_delete(UART_NUM_1);
#endif
printf("Running console component tests\n");
unity_run_menu();
}
@@ -13,6 +13,9 @@
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/semphr.h"
#if !CONFIG_IDF_TARGET_LINUX
#include "driver/uart.h"
#endif
/*
* NOTE: Most of these unit tests DO NOT work standalone. They require pytest to control
@@ -152,7 +155,7 @@ static esp_console_cmd_t s_quit_cmd = {
ran separately in test_console_repl */
TEST_CASE("esp console repl test", "[console][ignore]")
{
set_leak_threshold(416);
set_leak_threshold(248);
s_test_console_mutex = xSemaphoreCreateMutexStatic(&s_test_console_mutex_buf);
TEST_ASSERT_NOT_NULL(s_test_console_mutex);
@@ -189,7 +192,7 @@ TEST_CASE("esp console repl test", "[console][ignore]")
TEST_CASE("esp console repl deinit", "[console][ignore]")
{
set_leak_threshold(416);
set_leak_threshold(248);
esp_console_repl_config_t repl_config = ESP_CONSOLE_REPL_CONFIG_DEFAULT();
esp_console_dev_uart_config_t uart_config = ESP_CONSOLE_DEV_UART_CONFIG_DEFAULT();
@@ -404,3 +407,33 @@ TEST_CASE("esp console re-register commands", "[console][ignore]")
TEST_ESP_OK(esp_console_start_repl(s_repl));
vTaskDelay(pdMS_TO_TICKS(5000));
}
#if !CONFIG_IDF_TARGET_LINUX
TEST_CASE("esp console repl custom_uart test", "[console][ignore]")
{
set_leak_threshold(248);
printf("Running repl on UART1\n");
esp_console_repl_config_t repl_config = ESP_CONSOLE_REPL_CONFIG_DEFAULT();
esp_console_dev_uart_config_t uart_config = ESP_CONSOLE_DEV_UART_CONFIG_DEFAULT();
uart_config.channel = UART_NUM_1; // Set UART1 for repl task
TEST_ESP_OK(esp_console_new_repl_uart(&uart_config, &repl_config, &s_repl));
TEST_ESP_OK(esp_console_cmd_register(&s_quit_cmd));
TEST_ESP_OK(esp_console_start_repl(s_repl));
/* Wait a little for repl console initialization on UART1 */
vTaskDelay(pdMS_TO_TICKS(300));
TEST_ESP_OK(esp_console_stop_repl(s_repl));
/* Let scheduler clean task internals */
vTaskDelay(pdMS_TO_TICKS(50));
printf("ByeBye\r\n");
}
#endif // !CONFIG_IDF_TARGET_LINUX
@@ -19,7 +19,7 @@ def do_test_repl_deinit(dut: Dut) -> None:
def do_test_help_generic(dut: Dut, registration_order: str) -> None:
dut.expect_exact('Press ENTER to see the list of tests')
dut.confirm_write('"esp console help command - {} registration"'.format(registration_order), expect_str='esp>')
dut.confirm_write(f'"esp console help command - {registration_order} registration"', expect_str='esp>')
dut.confirm_write('help', expect_str='aaa')
@@ -269,3 +269,21 @@ def test_console_help_re_register(dut: Dut, test_on: str) -> None:
dut.expect_exact('should appear last in help')
dut.expect_exact('should appear first in help')
@idf_parametrize('config', ['defaults'], indirect=['config'])
@idf_parametrize(
'target,test_on,markers',
[
('esp32', 'target', (pytest.mark.generic,)),
('esp32c3', 'target', (pytest.mark.generic,)),
('esp32', 'qemu', (pytest.mark.host_test, pytest.mark.qemu)),
],
indirect=['target'],
)
def test_console_custom_uart_repl(dut: Dut, test_on: str) -> None:
dut.expect_exact('Press ENTER to see the list of tests')
dut.confirm_write('"esp console repl custom_uart test"', expect_str='Running repl on UART1')
# make sure that global stdout has not been changed
dut.expect_exact('ByeBye')