#define _POSIX_C_SOURCE 200809L #include #include #include #include #include "../../../src/expansion/expansion.h" #include "../../../src/utils/ast/ast.h" #include "../../../src/utils/hash_map/hash_map.h" #include "../../../src/utils/vars/vars.h" TestSuite(expand); Test(expand, no_expansion) { char str[] = "echo something"; char *str_heap = strdup(str); struct list *list = list_append(NULL, str_heap); struct ast *ast = ast_create_command(list, NULL, NULL); struct ast_command *ast_command = ast_get_command(ast); bool ret = expand(ast_command, NULL); cr_expect(ret, "expansion failed with %s", str); cr_expect_str_eq((char *)ast_command->command->data, "echo something", "String without variables should remain unchanged"); ast_free(&ast); } Test(expand, single_quotes_no_expansion) { char str[] = "echo '$VAR'"; char *str_heap = strdup(str); struct list *list = list_append(NULL, str_heap); struct ast *ast = ast_create_command(list, NULL, NULL); struct ast_command *ast_command = ast_get_command(ast); struct hash_map *vars = vars_init(); set_var_copy(vars, "VAR", "expanded"); bool ret = expand(ast_command, vars); cr_expect(ret, "expansion failed with %s", str); cr_expect_str_eq((char *)ast_command->command->data, "echo $VAR", "Variable should not expand inside single quotes"); ast_free(&ast); hash_map_free(&vars); } Test(expand, single_dollar) { char str[] = "echo $ sign"; char *str_heap = strdup(str); struct list *list = list_append(NULL, str_heap); struct ast *ast = ast_create_command(list, NULL, NULL); struct ast_command *ast_command = ast_get_command(ast); struct hash_map *vars = vars_init(); set_var_copy(vars, "VAR", "expanded"); bool ret = expand(ast_command, vars); cr_expect(ret, "expansion failed with %s", str); cr_expect_str_eq((char *)ast_command->command->data, "echo $ sign", "Variable should not expand inside single quotes"); ast_free(&ast); hash_map_free(&vars); } Test(expand, empty_braces_no_expansion) { char str[] = "echo ${}"; char *str_heap = strdup(str); struct list *list = list_append(NULL, str_heap); struct ast *ast = ast_create_command(list, NULL, NULL); struct ast_command *ast_command = ast_get_command(ast); struct hash_map *vars = vars_init(); set_var_copy(vars, "VAR", "expanded"); bool ret = expand(ast_command, vars); cr_expect(ret == false, "expansion should fail with %s", str); ast_free(&ast); hash_map_free(&vars); } Test(expand, basic_expansion) { char str[] = "echo $VAR"; char *str_heap = strdup(str); struct list *list = list_append(NULL, str_heap); struct ast *ast = ast_create_command(list, NULL, NULL); struct ast_command *ast_command = ast_get_command(ast); struct hash_map *vars = vars_init(); set_var_copy(vars, "VAR", "expanded"); bool ret = expand(ast_command, vars); cr_expect(ret, "expansion failed with %s", str); cr_expect_str_eq((char *)ast_command->command->data, "echo expanded", "Variable should expand correctly"); ast_free(&ast); hash_map_free(&vars); } Test(expand, multiple_expansion) { char str[] = "echo $VAR1 $VAR2 ${VAR3}"; char *str_heap = strdup(str); struct list *list = list_append(NULL, str_heap); struct ast *ast = ast_create_command(list, NULL, NULL); struct ast_command *ast_command = ast_get_command(ast); struct hash_map *vars = vars_init(); set_var_copy(vars, "VAR1", "expanded"); set_var_copy(vars, "VAR2", "values"); set_var_copy(vars, "VAR3", "here"); bool ret = expand(ast_command, vars); cr_expect(ret, "expansion failed with %s", str); cr_expect_str_eq((char *)ast_command->command->data, "echo expanded values here", "Multiple variables should expand correctly"); ast_free(&ast); hash_map_free(&vars); } Test(expand, env_variable) { char str[] = "echo $MY_ENV_VAR"; char *str_heap = strdup(str); struct list *list = list_append(NULL, str_heap); struct ast *ast = ast_create_command(list, NULL, NULL); struct ast_command *ast_command = ast_get_command(ast); setenv("MY_ENV_VAR", "environment", 0); bool ret = expand(ast_command, NULL); cr_expect(ret, "expansion failed with %s", str); cr_expect_str_eq((char *)ast_command->command->data, "echo environment", "Environment variable should expand correctly"); ast_free(&ast); } Test(expand, undefined_variable) { char str[] = "echo $UNDEFINED"; char *str_heap = strdup(str); struct list *list = list_append(NULL, str_heap); struct ast *ast = ast_create_command(list, NULL, NULL); struct ast_command *ast_command = ast_get_command(ast); struct hash_map *vars = vars_init(); bool ret = expand(ast_command, vars); cr_expect(ret, "expansion failed with %s", str); cr_expect_str_eq((char *)ast_command->command->data, "echo ", "Undefined variable should expand to empty string"); ast_free(&ast); hash_map_free(&vars); } Test(expand, nested_expansion) { char str[] = "echo $B"; char *str_heap = strdup(str); struct list *list = list_append(NULL, str_heap); struct ast *ast = ast_create_command(list, NULL, NULL); struct ast_command *ast_command = ast_get_command(ast); struct hash_map *vars = vars_init(); set_var_copy(vars, "A", "expanded"); set_var_copy(vars, "B", "$A"); bool ret = expand(ast_command, vars); cr_expect(ret, "expansion failed with %s", str); cr_expect_str_eq((char *)ast_command->command->data, "echo expanded", "Nested variable should expand correctly"); ast_free(&ast); hash_map_free(&vars); } // Test(expand, mixed_quotes_expansion) // { // char str[] = "echo \"$VAR1 and '$VAR2'\""; // char *str_heap = strdup(str); // struct list *list = list_append(NULL, str_heap); // struct ast *ast = ast_create_command(list, NULL, NULL); // struct ast_command *ast_command = ast_get_command(ast); // struct hash_map *vars = vars_init(); // set_var_copy(vars, "VAR1", "expanded"); // set_var_copy(vars, "VAR2", "not_expanded"); // bool ret = expand(ast_command, vars); // cr_expect(ret, "expansion failed with %s", str); // cr_expect_str_eq((char *)ast_command->command->data, // "echo \"expanded and $VAR2\"", // "Variable in double quotes should expand, while variable " // "in single quotes should not"); // ast_free(&ast); // hash_map_free(&vars); // } Test(expand, adjacent_variables) { char str[] = "echo $VAR1$VAR2"; char *str_heap = strdup(str); struct list *list = list_append(NULL, str_heap); struct ast *ast = ast_create_command(list, NULL, NULL); struct ast_command *ast_command = ast_get_command(ast); struct hash_map *vars = vars_init(); set_var_copy(vars, "VAR1", "hello"); set_var_copy(vars, "VAR2", "world"); bool ret = expand(ast_command, vars); cr_expect(ret, "expansion failed with %s", str); cr_expect_str_eq((char *)ast_command->command->data, "echo helloworld", "Adjacent variables should expand correctly"); ast_free(&ast); hash_map_free(&vars); } Test(expand, random) { char str[] = "$RANDOM"; char *str_heap = strdup(str); struct list *list = list_append(NULL, str_heap); struct ast *ast = ast_create_command(list, NULL, NULL); struct ast_command *ast_command = ast_get_command(ast); bool ret = expand(ast_command, NULL); cr_expect(ret, "expansion failed with %s", str); int rnd = atoi((char *)ast_command->command->data); cr_assert(rnd >= 0 && rnd <= 32767, "RANDOM variable should expand to a value between 0 and 32767"); ast_free(&ast); } Test(expand, pid) { char str[] = "$$"; char *str_heap = strdup(str); struct list *list = list_append(NULL, str_heap); struct ast *ast = ast_create_command(list, NULL, NULL); struct ast_command *ast_command = ast_get_command(ast); struct hash_map *vars = vars_init(); bool ret = expand(ast_command, vars); cr_expect(ret, "expansion failed with %s", str); int pid = atoi((char *)ast_command->command->data); cr_assert(pid == getpid(), "$$ variable should expand to the pid of the process"); ast_free(&ast); hash_map_free(&vars); } Test(expand, default_last_exit_code) { char str[] = "$?"; char *str_heap = strdup(str); struct list *list = list_append(NULL, str_heap); struct ast *ast = ast_create_command(list, NULL, NULL); struct ast_command *ast_command = ast_get_command(ast); struct hash_map *vars = vars_init(); bool ret = expand(ast_command, vars); cr_expect(ret, "expansion failed with %s", str); int code = atoi((char *)ast_command->command->data); cr_assert(code == 0, "$? variable should expand to the last exit code (default 0)"); ast_free(&ast); hash_map_free(&vars); }