Tests fail on codecrafters but they pass when I test them

I’m stuck on Stage #(YT5).

My tests will past sometimes but most the time they fail. To speed up my debugging process I created identical files to the ones that are given in the test that I failed, and write to them the same way that is shown by the debugger. However when I test it by running ./your_program.sh and sending in the same cat command, I get the right answer?

Here are my logs:

[tester::#TG6] Running tests for Stage #TG6 (Quoting - Double quotes)
[tester::#TG6] [setup] export PATH=/tmp/mango/pineapple/mango:$PATH
[tester::#TG6] Running ./your_program.sh
[tester::#TG6] [setup] echo -n "pear raspberry." > "/tmp/foo/f 74"
[tester::#TG6] [setup] echo -n "grape blueberry." > "/tmp/foo/f   22"
[tester::#TG6] [setup] echo -n "grape pineapple." > "/tmp/foo/f's15"
[your-program] $ echo "example world"
[your-program] example world
[tester::#TG6] Γ£ô Received expected response
[your-program] $ echo "world  test"  "script""example"
[your-program] world  test scriptexample
[tester::#TG6] Γ£ô Received expected response
[your-program] $ echo "script"  "shell's"  "world"
[your-program] script shell's world
[tester::#TG6] Γ£ô Received expected response
[your-program] $ cat "/tmp/foo/f 74" "/tmp/foo/f   22" "/tmp/foo/f's15"
[your-program] pear raspberry.grape blueberry.$ 
[tester::#TG6] Output does not match expected value.
[tester::#TG6] Expected: "pear raspberry.grape blueberry.grape pineapple."
[tester::#TG6] Received: "pear raspberry.grape blueberry.$ "
[tester::#TG6] Assertion failed.
[tester::#TG6] Test failed

View our article on debugging test failures: https://codecrafters.io/debug
:~/builds/shell-zig$ mkdir /tmp/foo
:~/builds/shell-zig$ echo -n "pear raspberry." > "/tmp/foo/f 74"
echo -n "grape blueberry." > "/tmp/foo/f   22"
echo -n "grape pineapple." > "/tmp/foo/f's15"
:~/builds/shell-zig$ ./your_program.sh
$ cat "/tmp/foo/f 74" "/tmp/foo/f   22" "/tmp/foo/f's15"
pear raspberry.grape blueberry.grape pineapple.$ exit 0


And here’s a snippet of my code:

fn parseTokens(input: []const u8, allocator: std.mem.Allocator) ![]const []const u8 {
    var tokens = std.ArrayList([]const u8).init(allocator);
    defer tokens.deinit();

    var i: usize = 0;
    while (i < input.len) {
        // Skip whitespace
        while (i < input.len and std.ascii.isWhitespace(input[i])) : (i += 1) {}
        if (i >= input.len) break;

        if (input[i] == '\'') {
            // Handle single-quoted token
            i += 1; // Skip opening quote
            const start = i;
            while (i < input.len and input[i] != '\'') : (i += 1) {}
            if (i >= input.len) return error.MissingClosingQuote;
            try tokens.append(input[start..i]);
            i += 1; // Skip closing quote
        } else if (input[i] == '\"') {
            // Handle double-quoted token with escape processing
            i += 1; // Skip opening quote
            var buffer = std.ArrayList(u8).init(allocator);
            defer buffer.deinit();

            while (i < input.len and input[i] != '\"') {
                if (input[i] == '\\') {
                    i += 1;
                    if (i >= input.len) return error.MissingClosingQuote;
                    const next_char = input[i];
                    // Handle allowed escape sequences
                    if (next_char == '\\' or next_char == '$' or next_char == '\"' or next_char == '\n') {
                        try buffer.append(next_char);
                    } else {
                        // Preserve backslash for other characters
                        try buffer.append('\\');
                        try buffer.append(next_char);
                    }
                } else {
                    try buffer.append(input[i]);
                }
                i += 1;
            }

            if (i >= input.len or input[i] != '\"') {
                return error.MissingClosingQuote;
            }
            i += 1; // Skip closing quote
            const slice = buffer.toOwnedSlice() catch {
                return error.ToSliceError;
            };
            try tokens.append(slice);
        } else {
            // Handle unquoted token
            const start = i;
            while (i < input.len and !std.ascii.isWhitespace(input[i])) : (i += 1) {}
            try tokens.append(input[start..i]);
        }
    }

    return tokens.toOwnedSlice();

pub fn processCat(user_input: []const u8) !bool {
    // Check that the input starts with "cat"
    if (user_input.len < 3 or !std.mem.eql(u8, user_input[0..3], "cat")) return false;
    const allocator = std.heap.page_allocator;
    const args_part = std.mem.trimLeft(u8, user_input[3..], " \t");
    const tokens = try parseTokens(args_part, allocator);
    var args_list = std.ArrayList([]const u8).init(allocator);
    defer args_list.deinit();
    try args_list.append("cat");
    // Then append each parsed token.
    for (tokens) |token| {
        // std.debug.print("{s }", .{token});
        try args_list.append(token);
    }
    // std.debug.print("\n", .{});
    var child = std.process.Child.init(args_list.items, allocator);
    child.stdout_behavior = .Pipe; // Capture output

    try child.spawn();
    defer {
        _ = child.wait() catch {
            @panic("Child process failed to exit cleanly");
        };
    }
    var out = child.stdout orelse return error.NullOutput;
    var buffer: [100000]u8 = undefined;
    const len = out.read(&buffer) catch {
        stdout.print("Not enough buffer space\n", .{}) catch return true;
        return true;
    };
    if (child.stderr) |err| {
        const err_len = try err.read(&buffer);
        std.debug.print("Errors: {s}\n", .{buffer[0..err_len]});
    }
    const output = buffer[0..len];
    try stdout.print("{s}", .{output});

    return true;
}

}

I’ll take a look and get back to you shortly.

I have found a solution to the problem. Their was problems with my code not the codecrafter tester.

@lucasgiumarra Glad you’ve found a solution!

Do you mind sharing what was wrong? Would love to see if we can improve the tester / instructions.

Well first off the code I posted was leaking memory, which wasn’t the underlying problem, but definitely didn’t help.

Second, while I said that I was failing the test but passing on my own machine, this turned out only to be partially true. This would sometimes happen, and sometimes not.

The underlying problem had something to do with the Child process that was spawning and waiting. It did not like taking all three arguments for the cat process at once. It would sometimes return back the results for all three, but many times it would just return the results of one or two. What was causing this I never did find out.

To resole this, however, I just ran cat on each argument individually and printed their results out.

1 Like

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