Skip to content
zit Artifact [560441180f]
Login

Artifact [560441180f]

Artifact 560441180fed6e5ab339bc863d4bed5590ec025e323a3c7ffef2667b8b2af4e3:


//! The settings fixture: one checkout carrying EVERY name fossil
//! recognizes under `.fossil-settings/`, written with every separator form
//! `glob.c glob_create` accepts (comma, space, tab, newline, a quoted entry)
//! plus a `#` comment line `db.c db_get_versioned` strips, and one `.no-warn`.
//!
//! Two lanes build it: `src/e2e.zig` opens it with zit alone and pins the exact
//! listings CI enforces, and `src/smoke.zig` S14 opens the same check-in with
//! zit AND the real `fossil` binary and compares the two byte for byte. They
//! share this table so a fixture change can never move one lane without the
//! other.
//!
//! Deliberately absent: any nested `_FOSSIL_`/`.fslckout` name. Fossil lists a
//! small junk file of that name and prunes a real nested checkout's whole
//! subtree; zit hides the names at every depth. That divergence is recorded,
//! not smuggled into a byte-for-byte comparison.

const std = @import("std");

pub const Setting = struct {
    /// File name under `.fossil-settings/`.
    name: []const u8,
    value: []const u8,
};

/// Every versioned name, in the order the two lanes write and add them.
/// `dotfiles` is `off` on purpose: it is the value that leaves `--dotfiles`
/// something to prove.
pub const settings = [_]Setting{
    .{ .name = "binary-glob", .value = "*.bin\n" },
    .{ .name = "clean-glob", .value = "*.tmp,\t*.bak\n" },
    .{ .name = "crlf-glob", .value = "*.txt\n" },
    .{ .name = "crnl-glob", .value = "*.md\n" },
    .{ .name = "dotfiles", .value = "off\n" },
    .{ .name = "empty-dirs", .value = "emptyd\n" },
    .{ .name = "encoding-glob", .value = "*.wide\n" },
    // A comment line, then comma, tab and space between three patterns, then a
    // newline-separated quoted entry: one file exercising every separator form
    // `glob_create` accepts at once.
    .{ .name = "ignore-glob", .value = "# junk nobody wants listed\n*.o,\tbuild/* logs/*.log\n\"spaced name.txt\"\n" },
    .{ .name = "ignore-glob.no-warn", .value = "" },
    .{ .name = "keep-glob", .value = "precious.dat\n" },
    .{ .name = "manifest", .value = "on\n" },
    .{ .name = "mimetypes", .value = "wiki text/x-wiki\n" },
};

/// The one tracked payload, so the check-in carries content as well as policy.
pub const tracked_file: Setting = .{ .name = "README", .value = "settings fixture\n" };

pub const Junk = struct {
    path: []const u8,
    data: []const u8,
};

/// Directories the junk needs, created before it is written.
pub const junk_dirs = [_][]const u8{ "build", "logs", "sub" };

/// The untracked files dropped into the checkout after the update — one per
/// rule the settings above declare.
pub const junk = [_]Junk{
    .{ .path = "notes.txt", .data = "plain extra\n" },
    .{ .path = "x.o", .data = "ignored by *.o\n" },
    .{ .path = "build/gen.c", .data = "ignored by build/*\n" },
    .{ .path = "logs/run.log", .data = "ignored by the space-separated logs/*.log\n" },
    .{ .path = "spaced name.txt", .data = "ignored by the quoted entry\n" },
    .{ .path = "scratch.tmp", .data = "clean-glob match\n" },
    .{ .path = "precious.dat", .data = "keep-glob match\n" },
    .{ .path = ".hidden", .data = "a dot name\n" },
    // A root `.fos` is one of fossil's checkout-state names (add.c's reserved
    // list, still honoured though the spelling is deprecated). Neither tool
    // ever lists it, with or without --dotfiles. It is safe to plant: fossil
    // looks for `_FOSSIL_`, then `.fslckout`, then `.fos` (db.c), and this
    // checkout already has a `.fslckout`.
    .{ .path = ".fos", .data = "not a checkout, just the name\n" },
    // UTF-16 LE with a BOM: encoding-glob's subject, and an extra like any
    // other as far as a listing is concerned.
    .{ .path = "wide.wide", .data = "\xFF\xFEh\x00i\x00" },
    .{ .path = "sub/deep.log", .data = "nested extra\n" },
};

comptime {
    // Every name distinct, every value reachable: a duplicate would make one
    // lane write a file the other never sees.
    for (settings, 0..) |a, i| {
        std.debug.assert(a.name.len != 0);
        for (settings[i + 1 ..]) |b| std.debug.assert(!std.mem.eql(u8, a.name, b.name));
    }
    for (junk, 0..) |a, i| {
        std.debug.assert(a.path.len != 0);
        for (junk[i + 1 ..]) |b| std.debug.assert(!std.mem.eql(u8, a.path, b.path));
    }
}