From e20860765e926dfab43492c3e0fbbe09f08818f6 Mon Sep 17 00:00:00 2001 From: kcbanner Date: Fri, 5 Jun 2026 01:55:37 -0400 Subject: [PATCH] test/link: rework test case names to show the target Prior to this, it was hard to track down commands to reproduce failing tests in --verbose output --- test/link.zig | 56 +++- ...static-lib.lib.dmp => emit-static-lib.dmp} | 0 ...ts-dynamic.lib.dmp => exports-dynamic.dmp} | 0 ...orts-static.lib.dmp => exports-static.dmp} | 0 test/src/Link.zig | 243 +++++++++++------- test/tests.zig | 14 +- 6 files changed, 203 insertions(+), 110 deletions(-) rename test/link/snapshots/{emit-static-lib.lib.dmp => emit-static-lib.dmp} (100%) rename test/link/snapshots/{exports-dynamic.lib.dmp => exports-dynamic.dmp} (100%) rename test/link/snapshots/{exports-static.lib.dmp => exports-static.dmp} (100%) diff --git a/test/link.zig b/test/link.zig index 3faecc710feecb15376718833d151a4708b58d3b..a414f3847c4447abcb7f08b28231c8615a396319 100644 --- a/test/link.zig +++ b/test/link.zig @@ -1,48 +1,52 @@ pub fn addCases(ctx: *LinkContext) void { - if (ctx.includeTest("exports-static")) |prefix| { - const lib = ctx.addLibrary(.static, .{ + if (ctx.includeTest("exports-static")) |case| { + const lib = case.addLibrary(.static, .{ .name = "lib", .zig_source_file = ctx.sourcePath("exports.zig"), }); - ctx.verifyObjdump(prefix, lib, &.{ + case.verifyObjdump(lib, &.{ "-s", "--symbols", "--only-symbol=foo", }, .{}); } - if (ctx.includeTest("exports-dynamic")) |prefix| { - const lib = ctx.addLibrary(.dynamic, .{ + if (ctx.includeTest("exports-dynamic")) |case| { + const lib = case.addLibrary(.dynamic, .{ .name = "lib", .zig_source_file = ctx.sourcePath("exports.zig"), }); - ctx.verifyObjdump(prefix, lib, &.{ + case.verifyObjdump(lib, &.{ "-s", "--exports", "--only-symbol=foo", }, .{}); } - if (ctx.includeTest("emit-static-lib")) |prefix| { - const obj1 = ctx.addObject(.{ + if (ctx.includeTest("emit-static-lib")) |case| { + const obj1 = case.addObject(.{ .name = "obj1", + .name_prefix = false, + .name_target = false, .use_llvm = true, .use_lld = true, .c_source_bytes = \\int foo1 = 1; \\int foo2 = 2; - \\int fooBar() { + \\unsigned int fooBar() { \\ return foo1 + foo2; \\} , }); - const obj2 = ctx.addObject(.{ + const obj2 = case.addObject(.{ .name = "this_is_a_long_name", + .name_prefix = false, + .name_target = false, .zig_source_bytes = \\fn weakFoo() callconv(.c) usize { - \\ return 42; + \\ return 0xaabbccdd; \\} - \\export var strong_foo: usize = 100; + \\export var strong_foo: usize = 0x11223344; \\comptime { \\ @export(&weakFoo, .{ .name = "weakFoo", .linkage = .weak }); \\ @export(&strong_foo, .{ .name = "strong_foo_alias", .linkage = .strong }); @@ -50,17 +54,41 @@ pub fn addCases(ctx: *LinkContext) void { , }); - const lib = ctx.addLibrary(.static, .{ .name = "lib" }); + const lib = case.addLibrary(.static, .{ + .name = "lib", + .name_prefix = false, + .name_target = false, + }); lib.root_module.addObject(obj1); lib.root_module.addObject(obj2); - ctx.verifyObjdump(prefix, lib, &.{ + case.verifyObjdump(lib, &.{ "-s", "--elements=file-type", "--symbols", "--only-symbol=foo", "--only-symbol=Foo", }, .{}); + + const exe = case.addExecutable(.{ + .name = "test", + .zig_source_bytes = + \\extern fn fooBar() c_uint; + \\extern fn weakFoo() usize; + \\extern var strong_foo: usize; + \\extern var strong_foo_alias: usize; + \\pub fn main() !u8 { + \\ return @intFromBool(0xcd003368 != fooBar() + + \\ weakFoo() + + \\ strong_foo + + \\ strong_foo_alias); + \\} + , + }); + exe.root_module.linkLibrary(lib); + + const run = case.addRunArtifact(exe); + run.addCheck(.{ .expect_term = .{ .exited = 0 } }); } } diff --git a/test/link/snapshots/emit-static-lib.lib.dmp b/test/link/snapshots/emit-static-lib.dmp similarity index 100% rename from test/link/snapshots/emit-static-lib.lib.dmp rename to test/link/snapshots/emit-static-lib.dmp diff --git a/test/link/snapshots/exports-dynamic.lib.dmp b/test/link/snapshots/exports-dynamic.dmp similarity index 100% rename from test/link/snapshots/exports-dynamic.lib.dmp rename to test/link/snapshots/exports-dynamic.dmp diff --git a/test/link/snapshots/exports-static.lib.dmp b/test/link/snapshots/exports-static.dmp similarity index 100% rename from test/link/snapshots/exports-static.lib.dmp rename to test/link/snapshots/exports-static.dmp diff --git a/test/src/Link.zig b/test/src/Link.zig index 08ad3f228fbe2dd57fe9fe4fbaf0a7b80794184f..9982e50e12d3b77b485db3cc1066db3a27689001 100644 --- a/test/src/Link.zig +++ b/test/src/Link.zig @@ -2,6 +2,7 @@ b: *Build, step: *Step, optimize: std.builtin.OptimizeMode, target: std.Build.ResolvedTarget, +target_desc: []const u8, use_llvm: bool, use_lld: bool, link_libc: bool, @@ -10,111 +11,168 @@ update_step: ?*Step.UpdateSourceFiles, updated_snapshots: std.StringArrayHashMapUnmanaged(void), max_rss: usize, -pub fn includeTest(self: *const Link, prefix: []const u8) ?[]const u8 { +pub fn includeTest(self: *Link, prefix: []const u8) ?Case { if (for (self.test_filters) |filter| { if (std.mem.containsAtLeast(u8, prefix, 1, filter)) break false; } else self.test_filters.len > 0) return null; - return prefix; + + return .{ + .ctx = self, + .prefix = prefix, + }; } pub fn sourcePath(self: *const Link, sub_path: []const u8) std.Build.LazyPath { return self.b.path(self.b.pathJoin(&.{ "test/link", sub_path })); } -pub fn addLibrary( - self: *const Link, - linkage: std.builtin.LinkMode, - overlay: OverlayOptions, -) *Step.Compile { - return self.b.addLibrary(.{ - .linkage = linkage, - .name = overlay.name, - .root_module = self.createModule(overlay), - .use_llvm = overlay.use_llvm orelse self.use_llvm, - .use_lld = overlay.use_lld orelse self.use_lld, - }); -} - -pub fn addObject(self: *const Link, overlay: OverlayOptions) *Step.Compile { - return self.b.addObject(.{ - .name = overlay.name, - .root_module = self.createModule(overlay), - .use_llvm = overlay.use_llvm orelse self.use_llvm, - .use_lld = overlay.use_lld orelse self.use_lld, - }); -} - -const SnapshotScope = packed struct { - arch: bool = false, - os: bool = false, - abi: bool = false, - optimize: bool = false, - use_llvm: bool = false, - use_lld: bool = false, - link_libc: bool = false, -}; - -/// Verify the results of a `zig objdump` call against a snapshot, which -/// contains the expected output. Snapshots alias between all build -/// configurations by default, but by specifying fields in `scope`, -/// unique snapshot names are generated for each value of that field. -pub fn verifyObjdump( - self: *Link, +pub const Case = struct { + ctx: *Link, prefix: []const u8, - compile: *Step.Compile, - args: []const []const u8, - scope: SnapshotScope, -) void { - const snapshot_name = self.snapshotName(prefix, compile.name, scope) catch @panic("OOM"); - const snapshot_sub_path = self.b.pathJoin(&.{ "test/link/snapshots/", snapshot_name }); - - // Many tests may read the same snapshot, so only use the first one to update. - // If there are differences in output, they will show up on the next test run. - if (self.update_step != null) { - const gop = self.updated_snapshots.getOrPut(self.b.allocator, snapshot_sub_path) catch @panic("OOM"); - if (gop.found_existing) return; + + fn resolveName(self: *const Case, overlay: *const OverlayOptions) []const u8 { + if (!overlay.name_prefix and !overlay.name_target) + return overlay.name; + + if (overlay.name_prefix == overlay.name_target) + return self.ctx.b.fmt("{s}-{s}-{s}", .{ self.prefix, overlay.name, self.ctx.target_desc }) + else if (overlay.name_prefix) + return self.ctx.b.fmt("{s}-{s}", .{ self.prefix, overlay.name }) + else + return self.ctx.b.fmt("{s}-{s}", .{ overlay.name, self.ctx.target_desc }); + } + + pub fn addLibrary( + self: *const Case, + linkage: std.builtin.LinkMode, + overlay: OverlayOptions, + ) *Step.Compile { + return self.ctx.b.addLibrary(.{ + .linkage = linkage, + .name = self.resolveName(&overlay), + .root_module = self.ctx.createModule(overlay), + .use_llvm = overlay.use_llvm orelse self.ctx.use_llvm, + .use_lld = overlay.use_lld orelse self.ctx.use_lld, + }); + } + + pub fn addExecutable( + self: *const Case, + overlay: OverlayOptions, + ) *Step.Compile { + return self.ctx.b.addExecutable(.{ + .name = self.resolveName(&overlay), + .root_module = self.ctx.createModule(overlay), + .use_llvm = overlay.use_llvm orelse self.ctx.use_llvm, + .use_lld = overlay.use_lld orelse self.ctx.use_lld, + }); + } + + pub fn addRunArtifact( + self: *const Case, + exe: *Step.Compile, + ) *Step.Run { + const run_step = self.ctx.b.addRunArtifact(exe); + run_step.skip_foreign_checks = true; + self.ctx.step.dependOn(&run_step.step); + return run_step; + } + + pub fn addObject( + self: *const Case, + overlay: OverlayOptions, + ) *Step.Compile { + return self.ctx.b.addObject(.{ + .name = self.resolveName(&overlay), + .root_module = self.ctx.createModule(overlay), + .use_llvm = overlay.use_llvm orelse self.ctx.use_llvm, + .use_lld = overlay.use_lld orelse self.ctx.use_lld, + }); } - const run_step = Step.Run.create(self.b, self.b.fmt("objdump {s}", .{snapshot_name})); - run_step.addArgs(&.{ self.b.graph.zig_exe, "objdump" }); - run_step.addArtifactArg(compile); - run_step.addArgs(args); - run_step.addCheck(.{ .expect_term = .{ .exited = 0 } }); + const SnapshotScope = struct { + /// If a test case has multiple verifyObjdump calls, `opt_sub_name` can + /// be used to differentiate them. + sub_name: ?[]const u8 = null, + arch: bool = false, + os: bool = false, + abi: bool = false, + optimize: bool = false, + use_llvm: bool = false, + use_lld: bool = false, + link_libc: bool = false, + }; + + /// Verify the results of a `zig objdump` call against a snapshot, which + /// contains the expected output. Snapshots alias between all build + /// configurations by default, but by specifying fields in `scope`, + /// unique snapshot names are generated for each value of that field. + /// + pub fn verifyObjdump( + self: *const Case, + compile: *Step.Compile, + args: []const []const u8, + scope: SnapshotScope, + ) void { + const ctx = self.ctx; + const snapshot_name = self.snapshotName(scope) catch @panic("OOM"); + const snapshot_sub_path = ctx.b.pathJoin(&.{ "test/link/snapshots/", snapshot_name }); + + // Many tests may read the same snapshot, so only use the first one to update. + // If there are differences in output, they will show up on the next test run. + if (ctx.update_step != null) { + const gop = ctx.updated_snapshots.getOrPut(ctx.b.allocator, snapshot_sub_path) catch @panic("OOM"); + if (gop.found_existing) return; + } + + const run_step = Step.Run.create(ctx.b, ctx.b.fmt( + "objdump {s} {s}", + .{ snapshot_name, ctx.target_desc }, + )); + run_step.addArgs(&.{ ctx.b.graph.zig_exe, "objdump" }); + run_step.addArtifactArg(compile); + run_step.addArgs(args); + run_step.addCheck(.{ .expect_term = .{ .exited = 0 } }); + + if (ctx.update_step) |update_step| { + // Workaround for the build system not realizing objdump itself has changed + run_step.has_side_effects = true; - if (self.update_step) |update_step| { - // Workaround for the build system not realizing objdump itself has changed - run_step.has_side_effects = true; + const snapshot_update_path = run_step.captureStdOut(.{}); + update_step.addCopyFileToSource(snapshot_update_path, snapshot_sub_path); + } else { + run_step.addCheck(.{ .snapshot = .{ .file = ctx.b.path(snapshot_sub_path) } }); + } - const snapshot_update_path = run_step.captureStdOut(.{}); - update_step.addCopyFileToSource(snapshot_update_path, snapshot_sub_path); - } else { - run_step.addCheck(.{ .snapshot = .{ .file = self.b.path(snapshot_sub_path) } }); + ctx.step.dependOn(&run_step.step); } - self.step.dependOn(&run_step.step); -} - -fn snapshotName( - self: *const Link, - test_name: []const u8, - compile_name: []const u8, - scope: SnapshotScope, -) ![]const u8 { - var snapshot_name: std.Io.Writer.Allocating = .init(self.b.allocator); - const w = &snapshot_name.writer; - - try w.print("{s}.{s}", .{ test_name, compile_name }); - if (scope.arch) try w.print("-{t}", .{self.target.result.cpu.arch}); - if (scope.os) try w.print("-{t}", .{self.target.result.os.tag}); - if (scope.abi) try w.print("-{t}", .{self.target.result.abi}); - if (scope.optimize) try w.print("-{t}", .{self.optimize}); - if (scope.use_llvm) try w.writeAll(if (self.use_llvm) "-llvm" else "-no-llvm"); - if (scope.use_lld) try w.writeAll(if (self.use_lld) "-lld" else "-no-lld"); - if (scope.link_libc) try w.writeAll(if (self.link_libc) "-libc" else "-no-libc"); - try w.writeAll(".dmp"); - - return try snapshot_name.toOwnedSlice(); -} + fn snapshotName( + self: *const Case, + scope: SnapshotScope, + ) ![]const u8 { + const ctx = self.ctx; + var snapshot_name: std.Io.Writer.Allocating = .init(ctx.b.allocator); + const w = &snapshot_name.writer; + + try w.writeAll(self.prefix); + if (scope.sub_name) |sub_name| { + try w.writeByte('.'); + try w.writeAll(sub_name); + } + + if (scope.arch) try w.print("-{t}", .{ctx.target.result.cpu.arch}); + if (scope.os) try w.print("-{t}", .{ctx.target.result.os.tag}); + if (scope.abi) try w.print("-{t}", .{ctx.target.result.abi}); + if (scope.optimize) try w.print("-{t}", .{ctx.optimize}); + if (scope.use_llvm) try w.writeAll(if (ctx.use_llvm) "-llvm" else "-no-llvm"); + if (scope.use_lld) try w.writeAll(if (ctx.use_lld) "-lld" else "-no-lld"); + if (scope.link_libc) try w.writeAll(if (ctx.link_libc) "-libc" else "-no-libc"); + try w.writeAll(".dmp"); + + return try snapshot_name.toOwnedSlice(); + } +}; fn createModule(self: *const Link, overlay: OverlayOptions) *Build.Module { const write_files = self.b.addWriteFiles(); @@ -165,6 +223,13 @@ fn createModule(self: *const Link, overlay: OverlayOptions) *Build.Module { const OverlayOptions = struct { name: []const u8, + /// Prefix the name with the test case prefix. + /// Unset if names with specific lengths are needed. + name_prefix: bool = true, + /// Prefix the name with `target_desc`. + /// Can be unset when the snapshot needs to contain the name, + /// so that snapshots can alias between targets. + name_target: bool = true, asm_source_bytes: ?[]const u8 = null, c_source_bytes: ?[]const u8 = null, c_source_flags: []const []const u8 = &.{}, diff --git a/test/tests.zig b/test/tests.zig index c3620b0bf0672140d7935b2f8b49802d36ee8e40..80366c7f5c7937f3c07b40ac90611c72ec2bf890 100644 --- a/test/tests.zig +++ b/test/tests.zig @@ -3184,13 +3184,13 @@ pub fn addLinkTests(b: *std.Build, options: LinkTestOptions) *Step { .step = step, .optimize = optimize_mode, .target = resolved_target, - // .suffix = std.fmt.allocPrint(b.allocator, "{s}-{t}{s}{s}{s}", .{ - // target.zigTriple(b.allocator) catch @panic("OOM"), - // optimize_mode, - // if (link_target.use_llvm) "-llvm" else "", - // if (link_target.use_lld) "-lld" else "", - // if (link_target.link_libc) "-libc" else "", - // }) catch @panic("OOM"), + .target_desc = std.fmt.allocPrint(b.allocator, "{s}-{t}{s}{s}{s}", .{ + target.zigTriple(b.allocator) catch @panic("OOM"), + optimize_mode, + if (link_target.use_llvm) "-llvm" else "", + if (link_target.use_lld) "-lld" else "", + if (link_target.link_libc) "-libc" else "", + }) catch @panic("OOM"), .use_llvm = link_target.use_llvm, .use_lld = link_target.use_lld, .link_libc = link_target.link_libc, -- 2.54.0