// SPDX-FileCopyrightText: © 2026 Jeffrey C. Ollie // SPDX-License-Identifier: MIT const std = @import("std"); /// The book the tests read: a Project Gutenberg edition of *On the Origin of /// Species*. It is fetched during `zig build test` rather than committed, since /// it is several hundred kilobytes of binary that never changes with the code. /// /// Gutenberg regenerates these files from time to time, so this hash will /// eventually stop matching. When that happens, check the new file over and /// update the hash — the tests are written to survive the book changing. const testdata_url = "https://www.gutenberg.org/cache/epub/2009/pg2009-images.mobi"; const testdata_sha256 = "44a8f228aa0f0f9ceae098885bbf1cc2db6ee79c22c3e4993f86a16daf6cafe7"; /// Download the test book and hand back the path it landed in. The build graph /// only reaches this when something depends on it, so a plain `zig build` stays /// offline, and the result is cached between runs. fn testDataPath(b: *std.Build, tls_module: *std.Build.Module) std.Build.LazyPath { const fetch = b.addExecutable(.{ .name = "fetch", .root_module = b.createModule(.{ .root_source_file = b.path("tools/fetch.zig"), // A build-time tool, so it always targets the machine doing the // building rather than whatever the library is cross-compiled for. .target = b.graph.host, .optimize = .ReleaseSafe, .imports = &.{ .{ .name = "tls", .module = tls_module }, }, }), }); const run = b.addRunArtifact(fetch); run.addArg(testdata_url); run.addArg(testdata_sha256); return run.addOutputFileArg("CharlesDarwin.mobi"); } pub fn build(b: *std.Build) void { const target = b.standardTargetOptions(.{}); const optimize = b.standardOptimizeOption(.{}); const mod = b.addModule("mobi", .{ .root_source_file = b.path("src/root.zig"), .target = target, .optimize = optimize, }); const exe = b.addExecutable(.{ .name = "mobi", .root_module = b.createModule(.{ .root_source_file = b.path("src/main.zig"), .target = target, .optimize = optimize, .imports = &.{ .{ .name = "mobi", .module = mod }, }, }), }); b.installArtifact(exe); const run_step = b.step("run", "Run the app"); const run_cmd = b.addRunArtifact(exe); run_step.dependOn(&run_cmd.step); run_cmd.step.dependOn(b.getInstallStep()); run_cmd.addPassthruArgs(); // A separate module for the tests, so that the fetched book is visible to // `@embedFile` there without becoming part of the published module and // dragging the download into every dependent's build. const test_mod = b.createModule(.{ .root_source_file = b.path("src/root.zig"), .target = target, .optimize = optimize, }); const tls_module = b.dependency("tls", .{}).module("tls"); test_mod.addAnonymousImport("testdata", .{ .root_source_file = testDataPath(b, tls_module) }); const mod_tests = b.addTest(.{ .root_module = test_mod, }); const run_mod_tests = b.addRunArtifact(mod_tests); const exe_tests = b.addTest(.{ .root_module = exe.root_module, }); const run_exe_tests = b.addRunArtifact(exe_tests); const test_step = b.step("test", "Run tests"); test_step.dependOn(&run_mod_tests.step); test_step.dependOn(&run_exe_tests.step); }