From affd048d9cf131c3af7fdb2048dfd7c52b719e34 Mon Sep 17 00:00:00 2001 From: Tilen Majerle Date: Sun, 15 Sep 2024 21:14:39 +0200 Subject: [PATCH] add simple test run --- CMakeLists.txt | 1 + dev/lwshell_dev.sln | 31 ----- dev/lwshell_dev.vcxproj | 152 ---------------------- dev/lwshell_dev.vcxproj.filters | 26 ---- dev/main.c | 10 +- lwshell/src/lwshell/lwshell.c | 215 ++++++++++++++++---------------- tests/test.c | 91 ++++++++++++++ 7 files changed, 206 insertions(+), 320 deletions(-) delete mode 100644 dev/lwshell_dev.sln delete mode 100644 dev/lwshell_dev.vcxproj delete mode 100644 dev/lwshell_dev.vcxproj.filters create mode 100644 tests/test.c diff --git a/CMakeLists.txt b/CMakeLists.txt index a82cdd0..482d971 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -9,6 +9,7 @@ else() add_executable(${PROJECT_NAME}) target_sources(${PROJECT_NAME} PRIVATE ${CMAKE_CURRENT_LIST_DIR}/dev/main.c + ${CMAKE_CURRENT_LIST_DIR}/tests/test.c ) target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_LIST_DIR}/dev diff --git a/dev/lwshell_dev.sln b/dev/lwshell_dev.sln deleted file mode 100644 index 91084c8..0000000 --- a/dev/lwshell_dev.sln +++ /dev/null @@ -1,31 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 16 -VisualStudioVersion = 16.0.28922.388 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "lwshell_dev", "lwshell_dev.vcxproj", "{C095C533-523E-4604-B3EF-B5025E4D96C0}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|x64 = Debug|x64 - Debug|x86 = Debug|x86 - Release|x64 = Release|x64 - Release|x86 = Release|x86 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {C095C533-523E-4604-B3EF-B5025E4D96C0}.Debug|x64.ActiveCfg = Debug|x64 - {C095C533-523E-4604-B3EF-B5025E4D96C0}.Debug|x64.Build.0 = Debug|x64 - {C095C533-523E-4604-B3EF-B5025E4D96C0}.Debug|x86.ActiveCfg = Debug|Win32 - {C095C533-523E-4604-B3EF-B5025E4D96C0}.Debug|x86.Build.0 = Debug|Win32 - {C095C533-523E-4604-B3EF-B5025E4D96C0}.Release|x64.ActiveCfg = Release|x64 - {C095C533-523E-4604-B3EF-B5025E4D96C0}.Release|x64.Build.0 = Release|x64 - {C095C533-523E-4604-B3EF-B5025E4D96C0}.Release|x86.ActiveCfg = Release|Win32 - {C095C533-523E-4604-B3EF-B5025E4D96C0}.Release|x86.Build.0 = Release|Win32 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {0D5E996C-005B-40C8-95F9-90D0632471E5} - EndGlobalSection -EndGlobal diff --git a/dev/lwshell_dev.vcxproj b/dev/lwshell_dev.vcxproj deleted file mode 100644 index f71908b..0000000 --- a/dev/lwshell_dev.vcxproj +++ /dev/null @@ -1,152 +0,0 @@ - - - - - Debug - Win32 - - - Release - Win32 - - - Debug - x64 - - - Release - x64 - - - - 15.0 - {C095C533-523E-4604-B3EF-B5025E4D96C0} - Win32Proj - dynamic_memory - 10.0 - lwshell_dev - - - - Application - true - v142 - Unicode - - - Application - false - v142 - true - Unicode - - - Application - true - v142 - Unicode - - - Application - false - v142 - true - Unicode - - - - - - - - - - - - - - - - - - - - - true - ..\lwshell\src\include;.;$(IncludePath) - - - true - - - false - - - false - - - - - - Level1 - Disabled - WIN32;_DEBUG;_CONSOLE;LWMEM_DEV;%(PreprocessorDefinitions) - Default - - - Console - - - - - - - Level3 - Disabled - _DEBUG;_CONSOLE;LWMEM_DEV;%(PreprocessorDefinitions) - - - Console - - - - - Level3 - - - MaxSpeed - true - true - WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) - - - Console - true - true - - - - - Level3 - - - MaxSpeed - true - true - NDEBUG;_CONSOLE;%(PreprocessorDefinitions) - - - Console - true - true - - - - - - - - - - - \ No newline at end of file diff --git a/dev/lwshell_dev.vcxproj.filters b/dev/lwshell_dev.vcxproj.filters deleted file mode 100644 index c1555bb..0000000 --- a/dev/lwshell_dev.vcxproj.filters +++ /dev/null @@ -1,26 +0,0 @@ - - - - - {4FC737F1-C7A5-4376-A066-2A32D752A2FF} - cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx - - - {87f67bb1-45c3-4724-b7de-f1e8551453e3} - - - {a9bad49b-d114-4596-8fe8-162c60f482ee} - - - - - Source Files - - - Source Files\LWSHELL - - - Source Files - - - \ No newline at end of file diff --git a/dev/main.c b/dev/main.c index c014c5b..f67744a 100644 --- a/dev/main.c +++ b/dev/main.c @@ -1,7 +1,7 @@ -#include -#include "lwshell/lwshell.h" -#include #include +#include +#include +#include "lwshell/lwshell.h" /** * \brief Reading one character at a time @@ -18,6 +18,7 @@ #endif void example_minimal(void); +extern void run_test(void); #if LWSHELL_CFG_USE_OUTPUT @@ -140,6 +141,9 @@ main(void) { lwshell_set_output_fn(shell_output); #endif /* LWSHELL_CFG_USE_OUTPUT */ + /* Run the test */ + run_test(); + #if LWSHELL_CFG_USE_DYNAMIC_COMMANDS /* Define shell commands */ lwshell_register_cmd("addint", addint_cmd, "Adds 2 integer numbers and prints them"); diff --git a/lwshell/src/lwshell/lwshell.c b/lwshell/src/lwshell/lwshell.c index a89b53e..d72771e 100644 --- a/lwshell/src/lwshell/lwshell.c +++ b/lwshell/src/lwshell/lwshell.c @@ -93,138 +93,137 @@ prv_parse_input(lwshell_t* lwobj) { size_t s_len; char* str; - /* Check string length and compare with buffer pointer */ + /* + * Check string length and compare with buffer pointer + * Must be more than `1` character since we have to include end of line + */ s_len = strlen(lwobj->buff); - if (s_len != lwobj->buff_ptr) { + if (s_len != lwobj->buff_ptr || lwobj->buff_ptr == 0) { return; } - /* Must be more than `1` character since we have to include end of line */ - if (lwobj->buff_ptr > 0) { - /* Set default values */ - lwobj->argc = 0; - lwobj->argv[0] = lwobj->buff; + /* Set default values */ + lwobj->argc = 0; + lwobj->argv[0] = lwobj->buff; - /* Process complete input */ - str = lwobj->buff; + /* Process complete input */ + str = lwobj->buff; - /* Process complete string */ - while (*str != '\0') { - while (*str == ' ' && ++str) {} /* Remove leading spaces */ + /* Process complete string */ + while (*str != '\0') { + while (*str == ' ' && ++str) {} /* Remove leading spaces */ + if (*str == '\0') { + break; + } + + /* Check if it starts with quote to handle escapes */ + if (*str == '"') { + ++str; + lwobj->argv[lwobj->argc++] = str; /* Set start of argument after quotes */ + + /* Process until end of quote */ + while (*str != '\0') { + if (*str == '\\') { + ++str; + if (*str == '"') { + ++str; + } + } else if (*str == '"') { + *str = '\0'; + ++str; + break; + } else { + ++str; + } + } + } else { + lwobj->argv[lwobj->argc++] = str; /* Set start of argument directly on character */ + while (*str != ' ' && *str != '\0') { + if (*str == '"') { /* Quote should not be here... */ + *str = '\0'; /* ...add NULL termination to end token */ + } + ++str; + } if (*str == '\0') { break; } - - /* Check if it starts with quote to handle escapes */ - if (*str == '"') { - ++str; - lwobj->argv[lwobj->argc++] = str; /* Set start of argument after quotes */ - - /* Process until end of quote */ - while (*str != '\0') { - if (*str == '\\') { - ++str; - if (*str == '"') { - ++str; - } - } else if (*str == '"') { - *str = '\0'; - ++str; - break; - } else { - ++str; - } - } - } else { - lwobj->argv[lwobj->argc++] = str; /* Set start of argument directly on character */ - while (*str != ' ' && *str != '\0') { - if (*str == '"') { /* Quote should not be here... */ - *str = '\0'; /* ...add NULL termination to end token */ - } - ++str; - } - if (*str == '\0') { - break; - } - *str = '\0'; - ++str; - } - - /* Check for number of arguments */ - if (lwobj->argc == LWSHELL_ARRAYSIZE(lwobj->argv)) { - break; - } + *str = '\0'; + ++str; } - /* Check for command */ - if (lwobj->argc > 0) { - const lwshell_cmd_t* ccmd = NULL; - size_t arg_len = strlen(lwobj->argv[0]); + /* Check for number of arguments */ + if (lwobj->argc == LWSHELL_ARRAYSIZE(lwobj->argv)) { + break; + } + } + + /* Check for command */ + if (lwobj->argc > 0) { + const lwshell_cmd_t* ccmd = NULL; + size_t arg_len = strlen(lwobj->argv[0]); #if LWSHELL_CFG_USE_DYNAMIC_COMMANDS - /* Process all dynamic commands */ - if (ccmd == NULL && lwobj->dynamic_cmds_cnt > 0) { - for (size_t idx = 0; idx < lwobj->dynamic_cmds_cnt; ++idx) { - if (arg_len == strlen(lwobj->dynamic_cmds[idx].name) - && strncmp(lwobj->dynamic_cmds[idx].name, lwobj->argv[0], arg_len) == 0) { - ccmd = &lwobj->dynamic_cmds[idx]; - break; - } + /* Process all dynamic commands */ + if (ccmd == NULL && lwobj->dynamic_cmds_cnt > 0) { + for (size_t idx = 0; idx < lwobj->dynamic_cmds_cnt; ++idx) { + if (arg_len == strlen(lwobj->dynamic_cmds[idx].name) + && strncmp(lwobj->dynamic_cmds[idx].name, lwobj->argv[0], arg_len) == 0) { + ccmd = &lwobj->dynamic_cmds[idx]; + break; } } + } #endif /* LWSHELL_CFG_USE_DYNAMIC_COMMANDS */ #if LWSHELL_CFG_USE_STATIC_COMMANDS - /* Process all static commands */ - if (ccmd == NULL && lwobj->static_cmds != NULL && lwobj->static_cmds_cnt > 0) { - for (size_t idx = 0; idx < lwobj->static_cmds_cnt; ++idx) { - if (arg_len == strlen(lwobj->static_cmds[idx].name) - && strncmp(lwobj->static_cmds[idx].name, lwobj->argv[0], arg_len) == 0) { - ccmd = &lwobj->static_cmds[idx]; - break; - } + /* Process all static commands */ + if (ccmd == NULL && lwobj->static_cmds != NULL && lwobj->static_cmds_cnt > 0) { + for (size_t idx = 0; idx < lwobj->static_cmds_cnt; ++idx) { + if (arg_len == strlen(lwobj->static_cmds[idx].name) + && strncmp(lwobj->static_cmds[idx].name, lwobj->argv[0], arg_len) == 0) { + ccmd = &lwobj->static_cmds[idx]; + break; } } + } #endif /* LWSHELL_CFG_USE_STATIC_COMMANDS */ - /* Valid command ready? */ - if (ccmd != NULL) { - if (lwobj->argc == 2U && lwobj->argv[1][0] == '-' && lwobj->argv[1][1] == 'h' - && lwobj->argv[1][2] == '\0') { - /* Here we can print version */ - LWSHELL_OUTPUT(lwobj, ccmd->desc); - LWSHELL_OUTPUT(lwobj, "\r\n"); - } else { - ccmd->fn(lwobj->argc, lwobj->argv); - } -#if LWSHELL_CFG_USE_LIST_CMD - } else if (strncmp(lwobj->argv[0], "listcmd", 7U) == 0) { - LWSHELL_OUTPUT(lwobj, "List of registered commands\r\n"); -#if LWSHELL_CFG_USE_DYNAMIC_COMMANDS - for (size_t idx = 0; idx < lwobj->dynamic_cmds_cnt; ++idx) { - LWSHELL_OUTPUT(lwobj, lwobj->dynamic_cmds[idx].name); - LWSHELL_OUTPUT(lwobj, "\t\t\t"); - LWSHELL_OUTPUT(lwobj, lwobj->dynamic_cmds[idx].desc); - LWSHELL_OUTPUT(lwobj, "\r\n"); - } -#endif /* LWSHELL_CFG_USE_DYNAMIC_COMMANDS */ -#if LWSHELL_CFG_USE_STATIC_COMMANDS - for (size_t idx = 0; idx < lwobj->static_cmds_cnt; ++idx) { - LWSHELL_OUTPUT(lwobj, lwobj->static_cmds[idx].name); - LWSHELL_OUTPUT(lwobj, "\t\t\t"); - LWSHELL_OUTPUT(lwobj, lwobj->static_cmds[idx].desc); - LWSHELL_OUTPUT(lwobj, "\r\n"); - } -#endif /* LWSHELL_CFG_USE_STATIC_COMMANDS */ -#endif /* LWSHELL_CFG_USE_LIST_CMD */ + /* Valid command ready? */ + if (ccmd != NULL) { + if (lwobj->argc == 2U && lwobj->argv[1][0] == '-' && lwobj->argv[1][1] == 'h' + && lwobj->argv[1][2] == '\0') { + /* Here we can print version */ + LWSHELL_OUTPUT(lwobj, ccmd->desc); + LWSHELL_OUTPUT(lwobj, "\r\n"); } else { - LWSHELL_OUTPUT(lwobj, "Unknown command" -#if LWSHELL_CFG_USE_LIST_CMD - ", use listcmd to list available commands" -#endif /* LWSHELL_CFG_USE_LIST_CMD */ - "\r\n" - ); + ccmd->fn(lwobj->argc, lwobj->argv); } +#if LWSHELL_CFG_USE_LIST_CMD + } else if (strncmp(lwobj->argv[0], "listcmd", 7U) == 0) { + LWSHELL_OUTPUT(lwobj, "List of registered commands\r\n"); +#if LWSHELL_CFG_USE_DYNAMIC_COMMANDS + for (size_t idx = 0; idx < lwobj->dynamic_cmds_cnt; ++idx) { + LWSHELL_OUTPUT(lwobj, lwobj->dynamic_cmds[idx].name); + LWSHELL_OUTPUT(lwobj, "\t\t\t"); + LWSHELL_OUTPUT(lwobj, lwobj->dynamic_cmds[idx].desc); + LWSHELL_OUTPUT(lwobj, "\r\n"); + } +#endif /* LWSHELL_CFG_USE_DYNAMIC_COMMANDS */ +#if LWSHELL_CFG_USE_STATIC_COMMANDS + for (size_t idx = 0; idx < lwobj->static_cmds_cnt; ++idx) { + LWSHELL_OUTPUT(lwobj, lwobj->static_cmds[idx].name); + LWSHELL_OUTPUT(lwobj, "\t\t\t"); + LWSHELL_OUTPUT(lwobj, lwobj->static_cmds[idx].desc); + LWSHELL_OUTPUT(lwobj, "\r\n"); + } +#endif /* LWSHELL_CFG_USE_STATIC_COMMANDS */ +#endif /* LWSHELL_CFG_USE_LIST_CMD */ + } else { + LWSHELL_OUTPUT(lwobj, "Unknown command" +#if LWSHELL_CFG_USE_LIST_CMD + ", use listcmd to list available commands" +#endif /* LWSHELL_CFG_USE_LIST_CMD */ + "\r\n"); } } } diff --git a/tests/test.c b/tests/test.c new file mode 100644 index 0000000..8c039cb --- /dev/null +++ b/tests/test.c @@ -0,0 +1,91 @@ +#include +#include "lwshell/lwshell.h" + +typedef struct { + const char* command; + const char* args_list[16]; +} test_str_t; + +/* List of commands */ +static const test_str_t commands[] = { + { + .command = "test 123 456 789\n", + .args_list = + { + "test", + "123", + "456", + "789", + }, + }, + { + .command = "test 123 longer text\n", + .args_list = + { + "test", + "123", + "longer", + "text", + }, + }, + { + .command = "test 123 \"longer text\"\n", + .args_list = + { + "test", + "123", + "longer text", + }, + }, +}; +static uint32_t current_cmd_index; + +/** + * \brief Test command function + * + * \param argc + * \param argv + * \return int32_t + */ +int32_t +prv_test_cmd(int32_t argc, char** argv) { + const test_str_t* cmd = &commands[current_cmd_index]; + size_t cmd_args_count = 0; + + /* Get list of arguments from test command */ + for (cmd_args_count; cmd->args_list[cmd_args_count] != NULL; ++cmd_args_count) {} + if (cmd_args_count != argc) { + printf("Test failed: Expected argument count (%02u) does not match actual argument count (%02u)\r\n", + (unsigned)cmd_args_count, (unsigned)argc); + return -1; + } + + /* Check if parameters match */ + for (size_t idx = 0; idx < argc; ++idx) { + /* Argument failed */ + if (strcmp(cmd->args_list[idx], argv[idx]) != 0) { + printf("Test failed: Argument index %02u, value \"%s\" does not match actual argument value \"%s\"\r\n", + (unsigned)idx, cmd->args_list[idx], argv[idx]); + return -1; + } + } + + return 0; +} + +/** + * \brief Global test run function + * + */ +void +run_test(void) { + lwshell_register_cmd("test", prv_test_cmd, "Test command function\r\n"); + + printf("Running test...\r\n"); + + /* Run all commands */ + for (current_cmd_index = 0; current_cmd_index < LWSHELL_ARRAYSIZE(commands); ++current_cmd_index) { + lwshell_input(commands[current_cmd_index].command, strlen(commands[current_cmd_index].command)); + } + printf("Tests completed...\r\n"); +}