Commit 2d017f379f

Jakub Konka <kubkon@jakubkonka.com>
2023-02-08 11:13:36
link-tests: do not hardcode UUID when testing the build with/out DI
1 parent 94c68c1
Changed files (1)
test
link
macho
test/link/macho/uuid/build.zig
@@ -1,4 +1,8 @@
 const std = @import("std");
+const Builder = std.Build.Builder;
+const CompileStep = std.Build.CompileStep;
+const FileSource = std.Build.FileSource;
+const Step = std.Build.Step;
 
 pub fn build(b: *std.Build) void {
     const test_step = b.step("test", "Test");
@@ -10,18 +14,18 @@ pub fn build(b: *std.Build) void {
         .os_tag = .macos,
     };
 
-    testUuid(b, test_step, .ReleaseSafe, aarch64_macos, "675bb6ba8e5d3d3191f7936d7168f0e9");
-    testUuid(b, test_step, .ReleaseFast, aarch64_macos, "675bb6ba8e5d3d3191f7936d7168f0e9");
-    testUuid(b, test_step, .ReleaseSmall, aarch64_macos, "675bb6ba8e5d3d3191f7936d7168f0e9");
+    testUuid(b, test_step, .ReleaseSafe, aarch64_macos);
+    testUuid(b, test_step, .ReleaseFast, aarch64_macos);
+    testUuid(b, test_step, .ReleaseSmall, aarch64_macos);
 
     const x86_64_macos = std.zig.CrossTarget{
         .cpu_arch = .x86_64,
         .os_tag = .macos,
     };
 
-    testUuid(b, test_step, .ReleaseSafe, x86_64_macos, "5b7071b4587c3071b0d2352fadce0e48");
-    testUuid(b, test_step, .ReleaseFast, x86_64_macos, "5b7071b4587c3071b0d2352fadce0e48");
-    testUuid(b, test_step, .ReleaseSmall, x86_64_macos, "4b58f2583c383169bbe3a716bd240048");
+    testUuid(b, test_step, .ReleaseSafe, x86_64_macos);
+    testUuid(b, test_step, .ReleaseFast, x86_64_macos);
+    testUuid(b, test_step, .ReleaseSmall, x86_64_macos);
 }
 
 fn testUuid(
@@ -29,25 +33,23 @@ fn testUuid(
     test_step: *std.Build.Step,
     optimize: std.builtin.OptimizeMode,
     target: std.zig.CrossTarget,
-    comptime exp: []const u8,
 ) void {
     // The calculated UUID value is independent of debug info and so it should
     // stay the same across builds.
     {
         const dylib = simpleDylib(b, optimize, target);
-        const check_dylib = dylib.checkObject(.macho);
-        check_dylib.checkStart("cmd UUID");
-        check_dylib.checkNext("uuid " ++ exp);
-        test_step.dependOn(&check_dylib.step);
+        const install_step = installWithRename(dylib, "test1.dylib");
+        install_step.step.dependOn(&dylib.step);
     }
     {
         const dylib = simpleDylib(b, optimize, target);
         dylib.strip = true;
-        const check_dylib = dylib.checkObject(.macho);
-        check_dylib.checkStart("cmd UUID");
-        check_dylib.checkNext("uuid " ++ exp);
-        test_step.dependOn(&check_dylib.step);
+        const install_step = installWithRename(dylib, "test2.dylib");
+        install_step.step.dependOn(&dylib.step);
     }
+
+    const cmp_step = CompareUuid.create(b, "test1.dylib", "test2.dylib");
+    test_step.dependOn(&cmp_step.step);
 }
 
 fn simpleDylib(
@@ -65,3 +67,118 @@ fn simpleDylib(
     dylib.linkLibC();
     return dylib;
 }
+
+fn installWithRename(cs: *CompileStep, name: []const u8) *InstallWithRename {
+    const step = InstallWithRename.create(cs.builder, cs.getOutputSource(), name);
+    cs.builder.getInstallStep().dependOn(&step.step);
+    return step;
+}
+
+const InstallWithRename = struct {
+    pub const base_id = .custom;
+
+    step: Step,
+    builder: *Builder,
+    source: FileSource,
+    name: []const u8,
+
+    pub fn create(
+        builder: *Builder,
+        source: FileSource,
+        name: []const u8,
+    ) *InstallWithRename {
+        const self = builder.allocator.create(InstallWithRename) catch @panic("OOM");
+        self.* = InstallWithRename{
+            .builder = builder,
+            .step = Step.init(.custom, builder.fmt("install and rename: {s} -> {s}", .{
+                source.getDisplayName(),
+                name,
+            }), builder.allocator, make),
+            .source = source,
+            .name = builder.dupe(name),
+        };
+        return self;
+    }
+
+    fn make(step: *Step) anyerror!void {
+        const self = @fieldParentPtr(InstallWithRename, "step", step);
+        const source_path = self.source.getPath(self.builder);
+        const target_path = self.builder.getInstallPath(.lib, self.name);
+        self.builder.updateFile(source_path, target_path) catch |err| {
+            std.log.err("Unable to rename: {s} -> {s}", .{ source_path, target_path });
+            return err;
+        };
+    }
+};
+
+const CompareUuid = struct {
+    pub const base_id = .custom;
+
+    step: Step,
+    builder: *Builder,
+    lhs: []const u8,
+    rhs: []const u8,
+
+    pub fn create(builder: *Builder, lhs: []const u8, rhs: []const u8) *CompareUuid {
+        const self = builder.allocator.create(CompareUuid) catch @panic("OOM");
+        self.* = CompareUuid{
+            .builder = builder,
+            .step = Step.init(
+                .custom,
+                builder.fmt("compare uuid: {s} and {s}", .{
+                    lhs,
+                    rhs,
+                }),
+                builder.allocator,
+                make,
+            ),
+            .lhs = lhs,
+            .rhs = rhs,
+        };
+        return self;
+    }
+
+    fn make(step: *Step) anyerror!void {
+        const self = @fieldParentPtr(CompareUuid, "step", step);
+        const gpa = self.builder.allocator;
+
+        var lhs_uuid: [16]u8 = undefined;
+        const lhs_path = self.builder.getInstallPath(.lib, self.lhs);
+        try parseUuid(gpa, lhs_path, &lhs_uuid);
+
+        var rhs_uuid: [16]u8 = undefined;
+        const rhs_path = self.builder.getInstallPath(.lib, self.rhs);
+        try parseUuid(gpa, rhs_path, &rhs_uuid);
+
+        try std.testing.expectEqualStrings(&lhs_uuid, &rhs_uuid);
+    }
+
+    fn parseUuid(gpa: std.mem.Allocator, path: []const u8, uuid: *[16]u8) anyerror!void {
+        const max_bytes: usize = 20 * 1024 * 1024;
+        const data = try std.fs.cwd().readFileAllocOptions(
+            gpa,
+            path,
+            max_bytes,
+            null,
+            @alignOf(u64),
+            null,
+        );
+        var stream = std.io.fixedBufferStream(data);
+        const reader = stream.reader();
+
+        const hdr = try reader.readStruct(std.macho.mach_header_64);
+        if (hdr.magic != std.macho.MH_MAGIC_64) {
+            return error.InvalidMagicNumber;
+        }
+
+        var it = std.macho.LoadCommandIterator{
+            .ncmds = hdr.ncmds,
+            .buffer = data[@sizeOf(std.macho.mach_header_64)..][0..hdr.sizeofcmds],
+        };
+        const cmd = while (it.next()) |cmd| switch (cmd.cmd()) {
+            .UUID => break cmd.cast(std.macho.uuid_command).?,
+            else => {},
+        } else return error.UuidLoadCommandNotFound;
+        std.mem.copy(u8, uuid, &cmd.uuid);
+    }
+};