From 0bb536751f9162a2658fdcd388c5beeaeade3197 Mon Sep 17 00:00:00 2001 From: savalet Date: Mon, 28 Apr 2025 20:53:21 +0200 Subject: [PATCH] Add tests and fix exit code --- .gitignore | 2 ++ src/shell.c | 17 ++++++----- validation_tests.py | 71 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 82 insertions(+), 8 deletions(-) diff --git a/.gitignore b/.gitignore index ee30ab9..7ab607e 100644 --- a/.gitignore +++ b/.gitignore @@ -46,3 +46,5 @@ unit_tests # AFL afl/generated + +out.txt diff --git a/src/shell.c b/src/shell.c index a6d7387..3ef5ab8 100644 --- a/src/shell.c +++ b/src/shell.c @@ -64,7 +64,7 @@ bool change_shell_command(char **buffer, exec_ctx_t *exec_ctx, char *tmp_buff = NULL; if (getline(buffer, &buffer_sz, stdin) == -1) - return true; + return false; tmp_buff = (*buffer); buffer_len = update_command(&tmp_buff, &buffer_sz, exec_ctx); if (buffer_len == 0) @@ -72,12 +72,13 @@ bool change_shell_command(char **buffer, exec_ctx_t *exec_ctx, if (buffer_len < 1 || !u_str_is_alnum(tmp_buff)) { check_basic_error(tmp_buff); free(tmp_buff); - return false; + return true; } U_DEBUG("Buffer [%lu] [%s]\n", buffer_len, tmp_buff); - visitor(tmp_buff, exec_ctx); + if (visitor(tmp_buff, exec_ctx) == RETURN_FAILURE) + exec_ctx->history->last_exit_code = RETURN_FAILURE; free(tmp_buff); - return false; + return true; } static @@ -88,7 +89,7 @@ int shell_loop(int is_a_tty, exec_ctx_t *exec_ctx) while (true) { write_prompt(is_a_tty); - if (change_shell_command(&buffer, exec_ctx, buffer_sz) == true) + if (!change_shell_command(&buffer, exec_ctx, buffer_sz)) return exec_ctx->history->last_exit_code; } free(exec_ctx->history_command); @@ -144,16 +145,16 @@ int shell(char **env_ptr) { alias_t alias = init_alias(); env_t env = parse_env(env_ptr); - history_t history = { .cmd_history = NULL, 0, .last_chdir = NULL}; + history_t history = { .cmd_history = NULL, .last_exit_code = 0, + .last_chdir = NULL}; his_command_t *cmd_history = init_cmd_history(); local_t local = create_local(); exec_ctx_t exec_ctx = {.env = &env, .local = &local, .history = &history, .history_command = cmd_history, .alias = &alias}; int shell_result; - if (error_in_init(&exec_ctx) == true){ + if (error_in_init(&exec_ctx) == true) return RETURN_FAILURE; - } U_DEBUG_CALL(debug_env_entries, &env); signal(SIGINT, ignore_sigint); shell_result = shell_loop(isatty(STDIN_FILENO), &exec_ctx); diff --git a/validation_tests.py b/validation_tests.py index 660fd9e..fb9f091 100644 --- a/validation_tests.py +++ b/validation_tests.py @@ -101,4 +101,75 @@ TESTS = [ ], depends_on=("ARGS",) ), + + Test( + key="REDIR", + name="I/O redirections", + cmds=[ + "echo plop > out.txt\n", + "cat < out.txt\n", + "echo again >> out.txt\n", + "cat < out.txt\n", + "cat nofile.txt\n", + "echo test > /no/perm/file\n", + ], + depends_on=("ARGS",) + ), + + Test( + key="PIPE", + name="pipes", + cmds=[ + "echo plop | cat\n", + "echo kek | grep kek\n", + "ls | grep Makefile\n", + "who | wc -l\n", + "ls | | cat\n", # Syntax error + ], + depends_on=("ARGS",) + ), + + Test( + key="ENV_EXPANSION", + name="environment variable expansion", + cmds=[ + "echo $HOME\n", + "echo $PATH\n", + "setenv TESTVAR bonjour;echo $TESTVAR;unsetenv TESTVAR;echo $TESTVAR\n", + ], + depends_on=("ENV","SEMICOLON",) + ), + + Test( + key="EXIT", + name="exit command", + cmds=[ + "exit\n", + ], + depends_on=("ARGS",) + ), + + Test( + key="MULTICMD", + name="multiple commands per line", + cmds=[ + "echo one ; echo two ; echo three\n", + "ls ; pwd ; whoami\n", + "cd src/ ; pwd ; cd - ; pwd\n", + ], + depends_on=("SEMICOLON",) + ), + + Test( + key="PARSING_ERR", + name="bad parsing cases", + cmds=[ + "ls |\n", + "ls >\n", + "; ls\n", + ";; ls\n", + "ls ;; ls\n", + ], + depends_on=("PIPE", "REDIR", "SEMICOLON",) + ), ]