Adding modules is incompatible with the default `test_runner`

142 views Asked by At

I have a project with the following structure:

$ tree .
src
├── decode.zig
├── main.zig
└── types.zig

The types.zig file is part of a new module which I'm trying to extract out some type definitions into. Previously, they were within decode.zig, i.e.:

$ tree src
src
├── decode.zig
└── main.zig

In order to create the new module, I've:

  1. Created the src/types.zig file
  2. Added a call to createModule to my build.zig file:
exe.addModule("types", b.createModule(.{ .source_file = std.build.FileSource.relative("src/types.zig") }));
  1. Added appropriate import statements to both src/main.zig and src/decode.zig, for the relevant types depended on by these files.

Currently, zig build succeeds and the executable runs fine. The problem is, when I go to run the (previously passing) test suite, via zig test src/decode.zig:

$ zig test/decode.zig
src/decode.zig:4:20: error: root struct of file 'test_runner' has no member named 'types'
const types = cairo.types;
              ~~~~~^~~~~~
/home/jmcph4/Downloads/zig-linux-x86_64-0.12.0-dev.1861+412999621/lib/test_runner.zig:1:1: note: struct declared here
//! Default test runner for unit tests.
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
referenced by:
    Instruction: src/decode.zig:6:21
    decode: src/decode.zig:107:79
    remaining reference traces hidden; use '-freference-trace' to see all reference traces

Steps I've taken in an effort to remedy this:

  • Add createModule calls to the unit_tests artefact within my build.zig file, like so:
 unit_tests.addModule("decode", b.createModule(.{ .source_file = std.build.FileSource.relative("src/decode.zig") }));
    unit_tests.addModule("types", b.createModule(.{ .source_file = std.build.FileSource.relative("src/types.zig") }));

For reference, I encountered these tickets:

How do I declare these modules in a way that is both compatible with zig build and zig test?

1

There are 1 answers

0
pfg On

zig build runs the build system which is intended to contain all the other zig commands, like zig build-exe and zig test. If you would like to use the build system for normal building, you may want to use the build system for testing too. Tests then would be run with zig build test.

Without modules:

In the project structure you provided, there is no need for modules. main.zig can import types.zig directly and so can decode.zig. Modules are intended for large chunks of code to share between different zig projects.

// main.zig
const types = @import("types.zig");

pub fn main(...) !void { ... }
test "..." { ... }
// decode.zig
const types = @import("types.zig");

test "..." { ... }

Using the build system:

If you run zig init-exe in an empty folder, the default build script contains an example for running tests: (the comments have been removed for brevity, but they are useful for understanding the build system)

const std = @import("std");

pub fn build(b: *std.Build) void {
    const optimize = b.standardOptimizeOption(.{});

    const exe = b.addExecutable(.{
        .name = "tmp",
    });
    b.installArtifact(exe);

    const run_cmd = b.addRunArtifact(exe);

    run_cmd.step.dependOn(b.getInstallStep());

    if (b.args) |args| {
        run_cmd.addArgs(args);
    }

    const run_step = b.step("run", "Run the app");
    run_step.dependOn(&run_cmd.step);

    const unit_tests = b.addTest(.{
        .root_source_file = .{ .path = "src/main.zig" },
        .target = target,
        .optimize = optimize,
    });

    const run_unit_tests = b.addRunArtifact(unit_tests);

    const test_step = b.step("test", "Run unit tests");
    test_step.dependOn(&run_unit_tests.step);
}

Unfortunately, there doesn't seem to be a standardized way of adding a module to both build steps right now, but the module can be added to unit_tests the same way you tried:

unit_tests.addModule("decode", b.createModule(.{ .source_file = std.build.FileSource.relative("src/decode.zig") }));
unit_tests.addModule("types", b.createModule(.{ .source_file = std.build.FileSource.relative("src/types.zig") }));

Tests can then be run with zig build test (NOT zig test)

Without the build system:

zig test accepts command line arguments to specify module roots. This will only work for simple modules, modules from the internet that have complex build.zig logic won't be able to be used this way.

The syntax is described in zig test --help:

  --mod [name]:[deps]:[src] Make a module available for dependency under the given name
      deps: [dep],[dep],...
      dep:  [[import=]name]
  --deps [dep],[dep],...    Set dependency names for the root package
      dep:  [[import=]name]
zig test src/decode.zig --mod decode::src/decode.zig --mod types types::src/types.zig --deps decode,types