# Testing in Zig — Zig

Source: https://www.geekswithgeeks.com/en/zig/b-testing

> Write tests next to code with std.testing and detect leaks.

## Tests are part of the language

Zig has **built-in test blocks**: `test "name" { ... }` declarations live **in the same file** as the code they test and are compiled only when running `zig test file.zig` or `zig build test`. Tests use **`std.testing`**: `expect(condition)`, `expectEqual(expected, actual)`, `expectEqualStrings`, `expectEqualSlices`, `expectError(error.X, expr)` and `expectApproxEqAbs` for floats; all return errors, so they are called with `try`. **`std.testing.allocator`** is a leak-detecting allocator: a test that forgets to free memory **fails**, which makes tests a strong check on manual memory management. `std.testing.checkAllAllocationFailures` runs a function repeatedly, failing each allocation in turn, to verify that error paths (and `errdefer`) clean up correctly. Tests can access private declarations in the same file. To include tests from other files, reference them, for example with `test { std.testing.refAllDecls(@This()); }` or `_ = @import("other.zig");` inside a test block. Filter tests with `--test-filter`. Doc comments (`///`) and `zig build-lib -femit-docs` generate documentation.

## Tests with leak detection and allocation-failure checks

std.testing.allocator and checkAllAllocationFailures.

```zig
const std = @import("std");

/// Splits a comma-separated list into an owned slice of trimmed fields.
/// Caller owns the outer slice (inner slices point into `input`).
pub fn splitFields(allocator: std.mem.Allocator, input: []const u8) ![][]const u8 {
    var fields: std.ArrayList([]const u8) = .empty;
    errdefer fields.deinit(allocator);
    var it = std.mem.splitScalar(u8, input, ',');
    while (it.next()) |raw| {
        try fields.append(allocator, std.mem.trim(u8, raw, " "));
    }
    return fields.toOwnedSlice(allocator);
}

test "splits and trims fields" {
    const fields = try splitFields(std.testing.allocator, "o-1, Pune ,120000");
    defer std.testing.allocator.free(fields);      // forgetting this makes the test fail with a leak

    try std.testing.expectEqual(@as(usize, 3), fields.len);
    try std.testing.expectEqualStrings("Pune", fields[1]);
}

test "single field" {
    const fields = try splitFields(std.testing.allocator, "only");
    defer std.testing.allocator.free(fields);
    try std.testing.expectEqualSlices(u8, "only", fields[0]);
}

fn splitAndFree(allocator: std.mem.Allocator) !void {
    const fields = try splitFields(allocator, "a,b,c,d,e");
    allocator.free(fields);
}

test "no leaks when any allocation fails" {
    try std.testing.checkAllAllocationFailures(std.testing.allocator, splitAndFree, .{});
}

// zig test src/fields.zig
// zig build test --summary all
```

## Test the error paths

`checkAllAllocationFailures` is one of Zig's best testing tools: it exercises every out-of-memory path, which is where `errdefer` mistakes hide, and it needs no extra test code.

**Quiz:** What happens if a test using std.testing.allocator leaks memory?

- [ ] Nothing
- [ ] The program crashes in production
- [x] The test fails and reports the leak
- [ ] Zig frees it silently

*Answer:* The test fails and reports the leak. The testing allocator tracks allocations and fails leaking tests.
