Can't Pass #ni6 Shell Challenge in Rust

In test, $ symbol comes later than the test expects. I updated it to merge two separate print function into one but it didn’t change anything.

I ran the cli with the --previous but this time it got stuck at #ez5 with the same error.

Is this a bug or am I missing something?

Here are my logs:

[tester::#NI6] Running tests for Stage #NI6 (Quoting - Single quotes)
[tester::#NI6] [setup] export PATH=/tmp/pear/grape/grape:$PATH
[tester::#NI6] Running ./your_shell.sh
[tester::#NI6] [setup] echo -n "grape pear." > "/tmp/foo/f   25"
[tester::#NI6] [setup] echo -n "strawberry orange." > "/tmp/foo/f   41"
[tester::#NI6] [setup] echo -n "grape mango." > "/tmp/foo/f   48"
[your-program] $ echo 'script test'
[your-program] script test
[tester::#NI6] ✓ Received expected response
[your-program] $ echo test     example
[your-program] test example
[tester::#NI6] ✓ Received expected response
[your-program] $ echo 'hello     world' 'example''script'
[your-program] hello     world examplescript
[tester::#NI6] ✓ Received expected response
[your-program] $ cat '/tmp/foo/f   25' '/tmp/foo/f   41' '/tmp/foo/f   48'
[your-program] grape pear.strawberry orange.grape mango.
[tester::#NI6] Expected prompt ("$ ") but received ""
[your-program] $ 
[tester::#NI6] Assertion failed.
[tester::#NI6] Test failed

with --previous

[tester::#OO8] Running tests for Stage #OO8 (Print a prompt)
[tester::#OO8] Running ./your_shell.sh
[your-program] $ 
[tester::#OO8] ✓ Received prompt
[tester::#OO8] Test passed.

[tester::#CZ2] Running tests for Stage #CZ2 (Handle invalid commands)
[tester::#CZ2] Running ./your_shell.sh
[your-program] $ invalid_strawberry_command
[your-program] invalid_strawberry_command: command not found
[tester::#CZ2] ✓ Received command not found message
[tester::#CZ2] Test passed.

[tester::#FF0] Running tests for Stage #FF0 (REPL)
[tester::#FF0] Running ./your_shell.sh
[your-program] $ invalid_command_1
[your-program] invalid_command_1: command not found
[tester::#FF0] ✓ Received command not found message
[your-program] $ invalid_command_2
[your-program] invalid_command_2: command not found
[tester::#FF0] ✓ Received command not found message
[your-program] $ invalid_command_3
[your-program] invalid_command_3: command not found
[tester::#FF0] ✓ Received command not found message
[your-program] $ 
[tester::#FF0] Test passed.

[tester::#PN5] Running tests for Stage #PN5 (The exit builtin)
[tester::#PN5] Running ./your_shell.sh
[your-program] $ invalid_pear_command
[your-program] invalid_pear_command: command not found
[tester::#PN5] ✓ Received command not found message
[your-program] $ exit 0
[tester::#PN5] ✓ Program exited successfully
[tester::#PN5] ✓ No output after exit command
[tester::#PN5] Test passed.

[tester::#IZ3] Running tests for Stage #IZ3 (The echo builtin)
[tester::#IZ3] Running ./your_shell.sh
[your-program] $ echo mango raspberry
[your-program] mango raspberry
[tester::#IZ3] ✓ Received expected response
[your-program] $ echo mango raspberry
[your-program] mango raspberry
[tester::#IZ3] ✓ Received expected response
[your-program] $ 
[tester::#IZ3] Test passed.

[tester::#EZ5] Running tests for Stage #EZ5 (The type builtin: builtins)
[tester::#EZ5] Running ./your_shell.sh
[your-program] $ type echo
[your-program] echo is a shell builtin
[tester::#EZ5] Expected prompt ("$ ") but received ""
[your-program] $ 
[tester::#EZ5] Assertion failed.
[tester::#EZ5] Test failed

And here’s a snippet of my code:

use std::{
    io::{self, Error, Write},
    process::Command,
};

use shell_starter_rust::{
    commands::{self, CommandMap},
    shell::{path::get_exec_path, Token, Tokenizer},
};

fn main() {
    let commands = commands::get_commands();

    let stdin = io::stdin();
    let mut input = String::new();
    print!("$ ");

    loop {
        io::stdout().flush().unwrap();

        if let Err(err) = stdin.read_line(&mut input) {
            eprint!("error: {}", err);
        } else if input.is_empty() {
            print!("\n$ ");
        } else {
            match handle_input(&input, &commands) {
                Ok(output) => print!("{}\n$ ", output),
                Err(err) => eprint!("{}\n$ ", err),
            }
        }

        input.clear();
    }
}

fn handle_input(input: &String, commands: &CommandMap) -> Result<String, Error> {
    let mut tokenizer = Tokenizer::new();
    let input = input.trim().to_string();

    let tokens = tokenizer.parse(input)?;

    match tokens.first() {
        Some(Token::Command(input_cmd)) => {
            let cmd = commands.get(input_cmd);

            if cmd.is_none() {
                let path = get_exec_path(input_cmd.as_str())?;

                let input_array = tokens
                    .iter()
                    .skip(1)
                    .map(|i| i.get_value())
                    .collect::<Vec<String>>();

                Command::new(path).args(input_array.iter()).status()?;

                return Ok(String::new());
            }

            return cmd.unwrap().as_ref().cmd(tokens);
        }
        Some(_) => return Err(Error::new(io::ErrorKind::InvalidInput, "error: invalid input")),
        None => return Ok(String::new()),
    }
}

Hi @emrecancorapci, let’s tackle #EZ5 first.

Looks like the issue is caused by an extra newline before the next prompt $:

And there is indeed an extra newline:

Let me know if you need further assistance after fixing #EZ5.

1 Like

Damn. Thank you. Sorry for taking up your time.

1 Like

Btw passed the #NI6 by using trim on the response. Maybe the code takes the new line at the end of the input??

Also because cat command is implemented in #NI6, one of the previous tests in #MG5 gives error. It just happens on previous tests so I just wanted to mention if you want to change it.

[tester::#MG5] Running tests for Stage #MG5 (The type builtin: executable files)
[tester::#MG5] [setup] export PATH=/tmp/quz:$PATH
[tester::#MG5] [setup] Available executables:
[tester::#MG5] [setup] - my_exe
[tester::#MG5] Running ./your_shell.sh
[your-program] $ type cat
[your-program] cat is a shell builtin
[tester::#MG5] Output does not match expected value.
[tester::#MG5] Expected: "cat is /bin/cat"
[tester::#MG5] Received: "cat is a shell builtin"
[your-program] $ 
[tester::#MG5] Assertion failed.
[tester::#MG5] Test failed

There is no need to implement cat as a built-in command.

Here’s the output from a real shell (zsh) on my machine:

Let us know if our instructions are unclear or suggest that cat should be implemented as a built-in command. We’ll fix it promptly.

1 Like

Oh. I didn’t know it wasn’t a built-in command so I thought I should implement it.

And I had two different functions to get the exec path. One of them wasn’t working properly. I changed it and passed some tests but then I couldn’t pass #IP1. I guess new tests have been added since I solved them. But now I fixed it.

Everything is working fine now. Thanks again. There is no sentence that implies that cat should be implemented. In fact, passing #IP1 makes sure that cat is available. I ran into this problem because I solved the test while it was in beta.

1 Like

This topic was automatically closed 5 days after the last reply. New replies are no longer allowed.