ajhahn.de
← Flash
Zig 54 lines
// Integration test: format the example programs end to end.
//
// Mirrors tests/lex_examples.zig, but drives `flashc fmt` over the real corpus.
// For every example it asserts the three formatter guarantees that hold at the
// string boundary: formatting succeeds, the result is idempotent
// (`fmt(fmt(s)) == fmt(s)`), and every comment in the input survives in the
// output exactly once (multiset equality). Transpile-equality — that formatting
// never changes the emitted Zig — is covered by the in-module unit tests in
// src/fmt.zig (it needs the parser and lowering on one module graph) and by the
// per-file shell gate the corpus reformat runs; here only strings cross the
// module boundary, so no cross-module AST types are involved.

const std = @import("std");
const fmt = @import("fmt");
const Lexer = fmt.Lexer;
const examples = @import("examples").all;

fn lessStr(_: void, a: []const u8, b: []const u8) bool {
    return std.mem.lessThan(u8, a, b);
}

// The line-comment lexemes of `src`, sorted, for a multiset comparison.
fn sortedComments(arena: std.mem.Allocator, src: []const u8) ![]const []const u8 {
    var list: std.ArrayList([]const u8) = .empty;
    var lx = Lexer.init(src);
    while (true) {
        const t = lx.next();
        if (t.kind == .eof) break;
        if (t.kind == .line_comment) try list.append(arena, t.lexeme(src));
    }
    const slice = try list.toOwnedSlice(arena);
    std.mem.sort([]const u8, slice, {}, lessStr);
    return slice;
}

test "every example formats, is idempotent, and preserves its comments" {
    for (examples) |src| {
        var a = std.heap.ArenaAllocator.init(std.testing.allocator);
        defer a.deinit();
        const arena = a.allocator();

        const formatted = try fmt.format(arena, src);
        // Idempotence: a second pass changes nothing.
        const formatted2 = try fmt.format(arena, formatted);
        try std.testing.expectEqualStrings(formatted, formatted2);

        // Comment multiset in == out.
        const in_comments = try sortedComments(arena, src);
        const out_comments = try sortedComments(arena, formatted);
        try std.testing.expectEqual(in_comments.len, out_comments.len);
        for (in_comments, out_comments) |ic, oc| try std.testing.expectEqualStrings(ic, oc);
    }
}