//! Test support: a migrated in-memory `config.db` with an `events.Store` over
//! it, for the emitter tests that live beside their own subsystem.
//!
//! Every emitter takes `?*events.Store` and must work with `null`; the tests
//! that prove an emitter *does* record something need a real store, and nine
//! subsystems needing the same six lines is what this file removes.
//!
//! Built in place rather than returned by value: a `Store` holds a `*db.Db`, so
//! a fixture that moved after `Store.init` would leave that pointer behind.

const std = @import("std");

const db = @import("db.zig");
const events = @import("events.zig");
const migrations = @import("migrations.zig");

pub const Fixture = struct {
    database: db.Db = undefined,
    store: events.Store = undefined,
    text_buf: [1024]u8 = undefined,

    pub fn init(self: *Fixture, io: std.Io, now_s: i64) !void {
        self.database = try db.Db.open(":memory:", .{ .mode = .memory });
        errdefer self.database.close();
        try db.applyPragmas(&self.database, .{});
        _ = try migrations.migrate(&self.database);
        self.store = try events.Store.init(io, &self.database, now_s);
    }

    pub fn deinit(self: *Fixture) void {
        self.database.close();
    }

    pub fn count(self: *Fixture, sql: []const u8) !i64 {
        return self.database.queryInt(sql);
    }

    /// The one column a test names most often, for the newest row of `code`.
    pub fn text(self: *Fixture, sql: []const u8) ![]const u8 {
        var stmt = try self.database.prepare(sql);
        defer stmt.deinit();
        if (!try stmt.step()) return error.NoRow;
        const value = stmt.columnText(0);
        @memcpy(self.text_buf[0..value.len], value);
        return self.text_buf[0..value.len];
    }
};
