authorgravatar for techatrix@mailbox.orgTechatrix <techatrix@mailbox.org> 2024-07-03 23:00:16+02:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-07-21 02:03:32-07:00
logc746d7a35d6ba26d783863ef8fa86123891e1d38
tree8edf037174452a3e7d243c844979b9a1790d8188
parent7aea384e44d8cf902ec50a5616d8861565adf83f

test: check output file caching of run steps with side-effects


3 files changed, 148 insertions(+), 0 deletions(-)

test/standalone/build.zig.zon+3
......@@ -176,6 +176,9 @@
176176 .run_output_paths = .{
177177 .path = "run_output_paths",
178178 },
179 .run_output_caching = .{
180 .path = "run_output_caching",
181 },
179182 },
180183 .paths = .{
181184 "build.zig",
test/standalone/run_output_caching/build.zig created+135
......@@ -0,0 +1,135 @@
1const std = @import("std");
2
3pub fn build(b: *std.Build) void {
4 const test_step = b.step("test", "Test it");
5 b.default_step = test_step;
6
7 const target = b.standardTargetOptions(.{});
8 const optimize = b.standardOptimizeOption(.{});
9
10 const exe = b.addExecutable(.{
11 .name = "create-file",
12 .root_source_file = b.path("main.zig"),
13 .target = target,
14 .optimize = optimize,
15 });
16
17 {
18 const run_random_with_sideeffects_first = b.addRunArtifact(exe);
19 run_random_with_sideeffects_first.setName("run with side-effects (first)");
20 run_random_with_sideeffects_first.has_side_effects = true;
21
22 const run_random_with_sideeffects_second = b.addRunArtifact(exe);
23 run_random_with_sideeffects_second.setName("run with side-effects (second)");
24 run_random_with_sideeffects_second.has_side_effects = true;
25
26 // ensure that "second" runs after "first"
27 run_random_with_sideeffects_second.step.dependOn(&run_random_with_sideeffects_first.step);
28
29 const first_output = run_random_with_sideeffects_first.addOutputFileArg("a.txt");
30 const second_output = run_random_with_sideeffects_second.addOutputFileArg("a.txt");
31
32 const expect_uncached_dependencies = CheckOutputCaching.init(b, false, &.{ first_output, second_output });
33 test_step.dependOn(&expect_uncached_dependencies.step);
34
35 const expect_unequal_output = CheckPathEquality.init(b, true, &.{ first_output, second_output });
36 test_step.dependOn(&expect_unequal_output.step);
37
38 const check_first_output = b.addCheckFile(first_output, .{ .expected_matches = &.{"a.txt"} });
39 test_step.dependOn(&check_first_output.step);
40 const check_second_output = b.addCheckFile(second_output, .{ .expected_matches = &.{"a.txt"} });
41 test_step.dependOn(&check_second_output.step);
42 }
43
44 {
45 const run_random_without_sideeffects_1 = b.addRunArtifact(exe);
46 run_random_without_sideeffects_1.setName("run without side-effects (A)");
47
48 const run_random_without_sideeffects_2 = b.addRunArtifact(exe);
49 run_random_without_sideeffects_2.setName("run without side-effects (B)");
50
51 run_random_without_sideeffects_2.step.dependOn(&run_random_without_sideeffects_1.step);
52
53 const first_output = run_random_without_sideeffects_1.addOutputFileArg("a.txt");
54 const second_output = run_random_without_sideeffects_2.addOutputFileArg("a.txt");
55
56 const expect_cached_dependencies = CheckOutputCaching.init(b, true, &.{second_output});
57 test_step.dependOn(&expect_cached_dependencies.step);
58
59 const expect_equal_output = CheckPathEquality.init(b, true, &.{ first_output, second_output });
60 test_step.dependOn(&expect_equal_output.step);
61
62 const check_first_output = b.addCheckFile(first_output, .{ .expected_matches = &.{"a.txt"} });
63 test_step.dependOn(&check_first_output.step);
64 const check_second_output = b.addCheckFile(second_output, .{ .expected_matches = &.{"a.txt"} });
65 test_step.dependOn(&check_second_output.step);
66 }
67}
68
69const CheckOutputCaching = struct {
70 step: std.Build.Step,
71 expect_caching: bool,
72
73 pub fn init(owner: *std.Build, expect_caching: bool, output_paths: []const std.Build.LazyPath) *CheckOutputCaching {
74 const check = owner.allocator.create(CheckOutputCaching) catch @panic("OOM");
75 check.* = .{
76 .step = std.Build.Step.init(.{
77 .id = .custom,
78 .name = "check output caching",
79 .owner = owner,
80 .makeFn = make,
81 }),
82 .expect_caching = expect_caching,
83 };
84 for (output_paths) |output_path| {
85 output_path.addStepDependencies(&check.step);
86 }
87 return check;
88 }
89
90 fn make(step: *std.Build.Step, _: std.Progress.Node) !void {
91 const check: *CheckOutputCaching = @fieldParentPtr("step", step);
92
93 for (step.dependencies.items) |dependency| {
94 if (check.expect_caching) {
95 if (dependency.result_cached) continue;
96 return step.fail("expected '{s}' step to be cached, but it was not", .{dependency.name});
97 } else {
98 if (!dependency.result_cached) continue;
99 return step.fail("expected '{s}' step to not be cached, but it was", .{dependency.name});
100 }
101 }
102 }
103};
104
105const CheckPathEquality = struct {
106 step: std.Build.Step,
107 expected_equality: bool,
108 output_paths: []const std.Build.LazyPath,
109
110 pub fn init(owner: *std.Build, expected_equality: bool, output_paths: []const std.Build.LazyPath) *CheckPathEquality {
111 const check = owner.allocator.create(CheckPathEquality) catch @panic("OOM");
112 check.* = .{
113 .step = std.Build.Step.init(.{
114 .id = .custom,
115 .name = "check output path equality",
116 .owner = owner,
117 .makeFn = make,
118 }),
119 .expected_equality = expected_equality,
120 .output_paths = owner.allocator.dupe(std.Build.LazyPath, output_paths) catch @panic("OOM"),
121 };
122 for (output_paths) |output_path| {
123 output_path.addStepDependencies(&check.step);
124 }
125 return check;
126 }
127
128 fn make(step: *std.Build.Step, _: std.Progress.Node) !void {
129 const check: *CheckPathEquality = @fieldParentPtr("step", step);
130 std.debug.assert(check.output_paths.len != 0);
131 for (check.output_paths[0 .. check.output_paths.len - 1], check.output_paths[1..]) |a, b| {
132 try std.testing.expectEqual(check.expected_equality, std.mem.eql(u8, a.getPath(step.owner), b.getPath(step.owner)));
133 }
134 }
135};
test/standalone/run_output_caching/main.zig created+10
......@@ -0,0 +1,10 @@
1const std = @import("std");
2
3pub fn main() !void {
4 var args = try std.process.argsWithAllocator(std.heap.page_allocator);
5 _ = args.skip();
6 const filename = args.next().?;
7 const file = try std.fs.createFileAbsolute(filename, .{});
8 defer file.close();
9 try file.writeAll(filename);
10}