Search code examples
cshellunit-testingreadlinec-criterion

How to unit test a function that spawns child processes?


So after a LOT of trying. I've dumbed down everything to the following: The test case

Test(minishell_loop, test_ls_exit) 
{
    t_minishell sheldon;

    ft_bzero(&sheldon, sizeof(t_minishell));
    sheldon.command_line = ft_strdup("ls");
    minishell_loop(&sheldon);
}

I check whether sheldon->command_line exists. which saves the pain of redirection stuff and so forth. However, if I don't uncomment the executor, my program hangs. It probably has something to do with #383, but I'm not completely sure.

int32_t minishell_loop(t_minishell *sheldon)
{
    if (!sheldon->command_line)
        sheldon->command_line = readline(PROMPT);
    if (!sheldon->command_line && printf("\x1B[1A" PROMPT "exit\n"))
        return (STOP);
    if (!*sheldon->command_line)
    {
        free(sheldon->command_line);
        return (CONTINUE);
    }
    add_history(sheldon->command_line);
    sheldon->tokens = lexer(sheldon->command_line, &sheldon->exit_status);
    if (!sheldon->tokens)
        return (minishell_clean(sheldon));
    sheldon->ast = parser(sheldon->tokens);
    if (!sheldon->ast)
        return (minishell_clean(sheldon));
    // sheldon->exit_status = executor(sheldon);
    return (minishell_clean(sheldon));
}

This 'works' as it successfully prints the whole ast shown below:

✦ ~/repos/minishell increase_coverage📈* ⇡ ❯ ./test.out --filter 'minishell_loop/*'

Command_table #1 at 0x55e58678f490
        Command #1 at 0x55e58678f490
                Argument #1: ls
[====] Synthesis: Tested: 1 | Passing: 1 | Failing: 0 | Crashing: 0

So I have a few questions:

  1. How/can I keep my executor uncommented?
  2. if not, are there other ways to test it?
  3. If yes, how can I compare that output against what bash would output?

If I uncomment sheldon->exit_status = executor(sheldon);

I get the following output:

Command_table #1 at 0x561aa47ce490
        Command #1 at 0x561aa47ce490
                Argument #1: ls
[ERR ] Received message identified by a PID '468695' that is not a child process.

One of my executor commands:

int32_t execute_simple_command(t_command *cmd, t_minishell *shell)
{
    pid_t       pid;
    int32_t     status;
    char        **arguments;

    arguments = get_arguments(cmd);
    setup_redirects(cmd);
    free(cmd);
    status = execute_builtin(arguments, shell);
    if (status >= 0)
        return (status);
    pid = fork();
    if (pid != 0)
        return (wait_for_child_processes(pid));
    reset_signals();
    execute_child_command(shell, arguments);
    return (0);
}

Solution

  • My program had a few issues.

    1. The execute simple command function is only called inside a child process. I had naked returns which crashed criterion. The solution was using _exit(127).
    2. sheldon.command_line = ft_strdup("ls"); should include a new line so that "ls\n" doesn't hang.
    3. There were more fixes, if you are interested please navigate to criterions discussion section for the full answer.