ReviewOS

also looking at this

zig-utils/zig-test-framework

test: make CI exercise maintained integrations

#18
Merged glennmichael123 wants to merge codex/issue-3-test-coverage into main
16 files +390 -139

Review threads live on the whole diff, not on one commit, so none are shown here - a thread's line means something in the branch's final form, and painting it into an intermediate step would put it on code it is not about.

README.mdmodified+5-1
Changes to README.md
@@ -757,10 +757,14 @@ zig build
757757# Run self-tests
758758zig build test
759759
760# Run examples
760# Run the basic and advanced examples, and compile-check every example
761761zig build examples
762762```
763763
764The async, snapshot, progress, and timeout examples are compile-checked rather
765than executed by this step because they intentionally demonstrate delays,
766generated files, interactive output, or failure handling.
767
764768## Requirements
765769
766770- The exact Zig development build recorded in [`.zig-version`](.zig-version)
build.zigmodified+87-2
Changes to build.zig
@@ -19,6 +19,9 @@ pub fn build(b: *std.Build) void {
1919 .target = target,
2020 .optimize = optimize,
2121 .link_libc = true,
22 .imports = &.{
23 .{ .name = "zig_test_framework", .module = lib_module },
24 },
2225 }),
2326 });
2427
@@ -46,6 +49,9 @@ pub fn build(b: *std.Build) void {
4649 .target = target,
4750 .optimize = optimize,
4851 .link_libc = true,
52 .imports = &.{
53 .{ .name = "zig_test_framework", .module = lib_module },
54 },
4955 }),
5056 });
5157 const run_test_runner_tests = b.addRunArtifact(test_runner_tests);
@@ -57,6 +63,9 @@ pub fn build(b: *std.Build) void {
5763 .target = target,
5864 .optimize = optimize,
5965 .link_libc = true,
66 .imports = &.{
67 .{ .name = "zig_test_framework", .module = lib_module },
68 },
6069 }),
6170 });
6271 const run_assertions_tests = b.addRunArtifact(assertions_tests);
@@ -68,6 +77,9 @@ pub fn build(b: *std.Build) void {
6877 .target = target,
6978 .optimize = optimize,
7079 .link_libc = true,
80 .imports = &.{
81 .{ .name = "zig_test_framework", .module = lib_module },
82 },
7183 }),
7284 });
7385 const run_suite_tests = b.addRunArtifact(suite_tests);
@@ -79,6 +91,9 @@ pub fn build(b: *std.Build) void {
7991 .target = target,
8092 .optimize = optimize,
8193 .link_libc = true,
94 .imports = &.{
95 .{ .name = "zig_test_framework", .module = lib_module },
96 },
8297 }),
8398 });
8499 const run_matchers_tests = b.addRunArtifact(matchers_tests);
@@ -108,6 +123,9 @@ pub fn build(b: *std.Build) void {
108123 .target = target,
109124 .optimize = optimize,
110125 .link_libc = true,
126 .imports = &.{
127 .{ .name = "zig_test_framework", .module = lib_module },
128 },
111129 }),
112130 });
113131 const run_reporter_tests = b.addRunArtifact(reporter_tests);
@@ -119,6 +137,9 @@ pub fn build(b: *std.Build) void {
119137 .target = target,
120138 .optimize = optimize,
121139 .link_libc = true,
140 .imports = &.{
141 .{ .name = "zig_test_framework", .module = lib_module },
142 },
122143 }),
123144 });
124145 const run_cli_tests = b.addRunArtifact(cli_tests);
@@ -144,6 +165,9 @@ pub fn build(b: *std.Build) void {
144165 .target = target,
145166 .optimize = optimize,
146167 .link_libc = true,
168 .imports = &.{
169 .{ .name = "zig_test_framework", .module = lib_module },
170 },
147171 }),
148172 });
149173 const run_mock_tests = b.addRunArtifact(mock_tests);
@@ -209,11 +233,14 @@ pub fn build(b: *std.Build) void {
209233 test_step.dependOn(&run_assertions_tests.step);
210234 test_step.dependOn(&run_suite_tests.step);
211235 test_step.dependOn(&run_matchers_tests.step);
212 // Note: hooks_test is an executable, run with 'zig build test-hooks'
236 test_step.dependOn(&run_hooks_tests.step);
213237 test_step.dependOn(&run_reporter_tests.step);
214238 test_step.dependOn(&run_cli_tests.step);
215239 test_step.dependOn(&run_filter_tests.step);
216240 test_step.dependOn(&run_mock_tests.step);
241 test_step.dependOn(&run_comprehensive_mock_tests.step);
242 test_step.dependOn(&run_snapshot_usage_tests.step);
243 test_step.dependOn(&run_time_tests.step);
217244
218245 // Examples
219246 const basic_example = b.addExecutable(.{
@@ -245,7 +272,65 @@ pub fn build(b: *std.Build) void {
245272 const run_basic_example = b.addRunArtifact(basic_example);
246273 const run_advanced_example = b.addRunArtifact(advanced_example);
247274
248 const examples_step = b.step("examples", "Run all examples");
275 // These showcase intentionally slow, interactive, or failure-oriented
276 // scenarios, so keep them compile-only while still checking every example.
277 const async_examples = b.addExecutable(.{
278 .name = "async_examples",
279 .root_module = b.createModule(.{
280 .root_source_file = b.path("examples/async_tests.zig"),
281 .target = target,
282 .optimize = optimize,
283 .link_libc = true,
284 .imports = &.{
285 .{ .name = "zig_test", .module = lib_module },
286 },
287 }),
288 });
289
290 const snapshot_examples = b.addExecutable(.{
291 .name = "snapshot_examples",
292 .root_module = b.createModule(.{
293 .root_source_file = b.path("examples/snapshot_examples.zig"),
294 .target = target,
295 .optimize = optimize,
296 .link_libc = true,
297 .imports = &.{
298 .{ .name = "zig_test", .module = lib_module },
299 },
300 }),
301 });
302
303 const progress_examples = b.addExecutable(.{
304 .name = "progress_examples",
305 .root_module = b.createModule(.{
306 .root_source_file = b.path("examples/progress_examples.zig"),
307 .target = target,
308 .optimize = optimize,
309 .link_libc = true,
310 .imports = &.{
311 .{ .name = "zig_test", .module = lib_module },
312 },
313 }),
314 });
315
316 const timeout_examples = b.addExecutable(.{
317 .name = "timeout_examples",
318 .root_module = b.createModule(.{
319 .root_source_file = b.path("examples/timeout_examples.zig"),
320 .target = target,
321 .optimize = optimize,
322 .link_libc = true,
323 .imports = &.{
324 .{ .name = "zig_test", .module = lib_module },
325 },
326 }),
327 });
328
329 const examples_step = b.step("examples", "Run core examples and compile all examples");
249330 examples_step.dependOn(&run_basic_example.step);
250331 examples_step.dependOn(&run_advanced_example.step);
332 examples_step.dependOn(&async_examples.step);
333 examples_step.dependOn(&snapshot_examples.step);
334 examples_step.dependOn(&progress_examples.step);
335 examples_step.dependOn(&timeout_examples.step);
251336}
examples/async_tests.zigmodified+12-12
Changes to examples/async_tests.zig
@@ -18,7 +18,7 @@ pub fn example_basic_async_test() !void {
1818 fn run(alloc: std.mem.Allocator) !void {
1919 _ = alloc;
2020 // Simulate async work
21 std.Thread.sleep(100 * std.time.ns_per_ms);
21 zig_test.compat.sleep(100 * std.time.ns_per_ms);
2222 std.debug.print("Async test 1 completed\n", .{});
2323 }
2424 }.run;
@@ -54,7 +54,7 @@ pub fn example_async_timeout() !void {
5454 const slowTest = struct {
5555 fn run(alloc: std.mem.Allocator) !void {
5656 _ = alloc;
57 std.Thread.sleep(500 * std.time.ns_per_ms); // Takes too long
57 zig_test.compat.sleep(500 * std.time.ns_per_ms); // Takes too long
5858 }
5959 }.run;
6060
@@ -87,7 +87,7 @@ pub fn example_concurrent_async() !void {
8787 const asyncTest = struct {
8888 fn run(alloc: std.mem.Allocator) !void {
8989 _ = alloc;
90 std.Thread.sleep(50 * std.time.ns_per_ms);
90 zig_test.compat.sleep(50 * std.time.ns_per_ms);
9191 }
9292 }.run;
9393
@@ -97,10 +97,10 @@ pub fn example_concurrent_async() !void { renamed throughout
9797 try executor.registerTest("concurrent_4", asyncTest);
9898 try executor.registerTest("concurrent_5", asyncTest);
9999
100 const start = std.time.nanoTimestamp();
100 const start = zig_test.compat.nanoTimestamp();
101101 const results = try executor.executeAll();
102102 defer allocator.free(results);
103 const duration = std.time.nanoTimestamp() - start;
103 const duration = zig_test.compat.nanoTimestamp() - start;
104104
105105 std.debug.print("Total duration: {d:.2}ms\n", .{
106106 @as(f64, @floatFromInt(duration)) / 1_000_000.0,
@@ -121,7 +121,7 @@ pub fn example_async_hooks() !void {
121121 fn run(alloc: std.mem.Allocator) !void {
122122 _ = alloc;
123123 std.debug.print("Before hook executed\n", .{});
124 std.Thread.sleep(10 * std.time.ns_per_ms);
124 zig_test.compat.sleep(10 * std.time.ns_per_ms);
125125 }
126126 }.run;
127127
@@ -129,7 +129,7 @@ pub fn example_async_hooks() !void {
129129 fn run(alloc: std.mem.Allocator) !void {
130130 _ = alloc;
131131 std.debug.print("After hook executed\n", .{});
132 std.Thread.sleep(10 * std.time.ns_per_ms);
132 zig_test.compat.sleep(10 * std.time.ns_per_ms);
133133 }
134134 }.run;
135135
@@ -150,7 +150,7 @@ pub fn example_suite_async() !void {
150150 const asyncTest1 = struct {
151151 fn run(alloc: std.mem.Allocator) !void {
152152 _ = alloc;
153 std.Thread.sleep(50 * std.time.ns_per_ms);
153 zig_test.compat.sleep(50 * std.time.ns_per_ms);
154154 std.debug.print("Suite async test 1 passed\n", .{});
155155 }
156156 }.run;
@@ -158,7 +158,7 @@ pub fn example_suite_async() !void {
158158 const asyncTest2 = struct {
159159 fn run(alloc: std.mem.Allocator) !void {
160160 _ = alloc;
161 std.Thread.sleep(50 * std.time.ns_per_ms);
161 zig_test.compat.sleep(50 * std.time.ns_per_ms);
162162 std.debug.print("Suite async test 2 passed\n", .{});
163163 }
164164 }.run;
@@ -187,7 +187,7 @@ pub fn example_mixed_tests() !void {
187187 const asyncTest = struct {
188188 fn run(alloc: std.mem.Allocator) !void {
189189 _ = alloc;
190 std.Thread.sleep(50 * std.time.ns_per_ms);
190 zig_test.compat.sleep(50 * std.time.ns_per_ms);
191191 std.debug.print("Async test executed\n", .{});
192192 }
193193 }.run;
@@ -212,7 +212,7 @@ pub fn example_async_errors() !void {
212212 const passingTest = struct {
213213 fn run(alloc: std.mem.Allocator) !void {
214214 _ = alloc;
215 std.Thread.sleep(10 * std.time.ns_per_ms);
215 zig_test.compat.sleep(10 * std.time.ns_per_ms);
216216 }
217217 }.run;
218218
@@ -220,7 +220,7 @@ pub fn example_async_errors() !void {
220220 const failingTest = struct {
221221 fn run(alloc: std.mem.Allocator) !void {
222222 _ = alloc;
223 std.Thread.sleep(10 * std.time.ns_per_ms);
223 zig_test.compat.sleep(10 * std.time.ns_per_ms);
224224 return error.AsyncTestFailed;
225225 }
226226 }.run;
examples/progress_examples.zigmodified+23-23
Changes to examples/progress_examples.zig
@@ -11,7 +11,7 @@ pub fn example_basic_spinner() !void {
1111 defer spinner.deinit();
1212
1313 try spinner.start();
14 std.Thread.sleep(2000 * std.time.ns_per_ms);
14 zig_test.compat.sleep(2000 * std.time.ns_per_ms);
1515 spinner.succeed("Data loaded successfully");
1616}
1717
@@ -40,7 +40,7 @@ pub fn example_spinner_styles() !void {
4040 defer spinner.deinit();
4141
4242 try spinner.start();
43 std.Thread.sleep(1000 * std.time.ns_per_ms);
43 zig_test.compat.sleep(1000 * std.time.ns_per_ms);
4444 spinner.succeed(try std.fmt.allocPrint(allocator, "{s} style complete", .{style_name}));
4545 allocator.free(try std.fmt.allocPrint(allocator, "{s} style complete", .{style_name}));
4646 }
@@ -56,28 +56,28 @@ pub fn example_spinner_outcomes() !void { renamed throughout
5656 var spinner1 = try zig_test.Spinner.init(allocator, "Operation 1...", .dots);
5757 defer spinner1.deinit();
5858 try spinner1.start();
59 std.Thread.sleep(500 * std.time.ns_per_ms);
59 zig_test.compat.sleep(500 * std.time.ns_per_ms);
6060 spinner1.succeed("Operation 1 succeeded");
6161
6262 // Failure
6363 var spinner2 = try zig_test.Spinner.init(allocator, "Operation 2...", .dots);
6464 defer spinner2.deinit();
6565 try spinner2.start();
66 std.Thread.sleep(500 * std.time.ns_per_ms);
66 zig_test.compat.sleep(500 * std.time.ns_per_ms);
6767 spinner2.fail("Operation 2 failed");
6868
6969 // Warning
7070 var spinner3 = try zig_test.Spinner.init(allocator, "Operation 3...", .dots);
7171 defer spinner3.deinit();
7272 try spinner3.start();
73 std.Thread.sleep(500 * std.time.ns_per_ms);
73 zig_test.compat.sleep(500 * std.time.ns_per_ms);
7474 spinner3.warn("Operation 3 has warnings");
7575
7676 // Info
7777 var spinner4 = try zig_test.Spinner.init(allocator, "Operation 4...", .dots);
7878 defer spinner4.deinit();
7979 try spinner4.start();
80 std.Thread.sleep(500 * std.time.ns_per_ms);
80 zig_test.compat.sleep(500 * std.time.ns_per_ms);
8181 spinner4.info("Operation 4 information");
8282}
8383
@@ -96,7 +96,7 @@ pub fn example_basic_progress_bar() !void {
9696 var i: usize = 0;
9797 while (i <= 100) : (i += 5) {
9898 bar.update(i);
99 std.Thread.sleep(100 * std.time.ns_per_ms);
99 zig_test.compat.sleep(100 * std.time.ns_per_ms);
100100 }
101101 bar.finish();
102102}
@@ -129,7 +129,7 @@ pub fn example_progress_bar_styles() !void {
129129 var i: usize = 0;
130130 while (i <= 50) : (i += 5) {
131131 bar.update(i);
132 std.Thread.sleep(50 * std.time.ns_per_ms);
132 zig_test.compat.sleep(50 * std.time.ns_per_ms);
133133 }
134134 bar.finish();
135135 }
@@ -151,7 +151,7 @@ pub fn example_progress_bar_options() !void {
151151 var i: usize = 0;
152152 while (i <= 50) : (i += 10) {
153153 bar1.update(i);
154 std.Thread.sleep(100 * std.time.ns_per_ms);
154 zig_test.compat.sleep(100 * std.time.ns_per_ms);
155155 }
156156 bar1.finish();
157157
@@ -165,7 +165,7 @@ pub fn example_progress_bar_options() !void {
165165 i = 0;
166166 while (i <= 50) : (i += 10) {
167167 bar2.update(i);
168 std.Thread.sleep(100 * std.time.ns_per_ms);
168 zig_test.compat.sleep(100 * std.time.ns_per_ms);
169169 }
170170 bar2.finish();
171171
@@ -180,7 +180,7 @@ pub fn example_progress_bar_options() !void {
180180 i = 0;
181181 while (i <= 50) : (i += 10) {
182182 bar3.update(i);
183 std.Thread.sleep(100 * std.time.ns_per_ms);
183 zig_test.compat.sleep(100 * std.time.ns_per_ms);
184184 }
185185 bar3.finish();
186186}
@@ -213,7 +213,7 @@ pub fn example_test_progress() !void {
213213
214214 for (test_names, 0..) |name, i| {
215215 try progress.startTest(name);
216 std.Thread.sleep(200 * std.time.ns_per_ms);
216 zig_test.compat.sleep(200 * std.time.ns_per_ms);
217217
218218 // Simulate different outcomes
219219 const passed = i != 3; // Fail the 4th test
@@ -242,7 +242,7 @@ pub fn example_test_progress_minimal() !void {
242242 defer allocator.free(name);
243243
244244 try progress.startTest(name);
245 std.Thread.sleep(100 * std.time.ns_per_ms);
245 zig_test.compat.sleep(100 * std.time.ns_per_ms);
246246 progress.completeTest(true, false);
247247 }
248248
@@ -263,14 +263,14 @@ pub fn example_multi_spinner() !void { renamed throughout
263263 try multi.add("task2", "Processing task 2...");
264264 try multi.add("task3", "Processing task 3...");
265265
266 std.Thread.sleep(1000 * std.time.ns_per_ms);
266 zig_test.compat.sleep(1000 * std.time.ns_per_ms);
267267
268268 // Complete tasks at different times
269269 multi.succeed("task1", "Task 1 complete");
270 std.Thread.sleep(500 * std.time.ns_per_ms);
270 zig_test.compat.sleep(500 * std.time.ns_per_ms);
271271
272272 multi.fail("task2", "Task 2 failed");
273 std.Thread.sleep(500 * std.time.ns_per_ms);
273 zig_test.compat.sleep(500 * std.time.ns_per_ms);
274274
275275 multi.succeed("task3", "Task 3 complete");
276276}
@@ -289,7 +289,7 @@ pub fn example_progress_increment() !void {
289289 var i: usize = 0;
290290 while (i < 20) : (i += 1) {
291291 bar.increment();
292 std.Thread.sleep(100 * std.time.ns_per_ms);
292 zig_test.compat.sleep(100 * std.time.ns_per_ms);
293293 }
294294 bar.finish();
295295}
@@ -304,13 +304,13 @@ pub fn example_spinner_update() !void { renamed throughout
304304 defer spinner.deinit();
305305
306306 try spinner.start();
307 std.Thread.sleep(1000 * std.time.ns_per_ms);
307 zig_test.compat.sleep(1000 * std.time.ns_per_ms);
308308
309309 try spinner.updateMessage("Step 2: Processing data...");
310 std.Thread.sleep(1000 * std.time.ns_per_ms);
310 zig_test.compat.sleep(1000 * std.time.ns_per_ms);
311311
312312 try spinner.updateMessage("Step 3: Finalizing...");
313 std.Thread.sleep(1000 * std.time.ns_per_ms);
313 zig_test.compat.sleep(1000 * std.time.ns_per_ms);
314314
315315 spinner.succeed("All steps completed");
316316}
@@ -325,7 +325,7 @@ pub fn example_combined_progress() !void {
325325 var spinner = try zig_test.Spinner.init(allocator, "Starting batch process...", .dots);
326326 defer spinner.deinit();
327327 try spinner.start();
328 std.Thread.sleep(500 * std.time.ns_per_ms);
328 zig_test.compat.sleep(500 * std.time.ns_per_ms);
329329 spinner.stop();
330330
331331 // Use progress bar for sub-tasks
@@ -337,7 +337,7 @@ pub fn example_combined_progress() !void {
337337 var i: usize = 0;
338338 while (i <= 100) : (i += 10) {
339339 bar.update(i);
340 std.Thread.sleep(200 * std.time.ns_per_ms);
340 zig_test.compat.sleep(200 * std.time.ns_per_ms);
341341 }
342342 bar.finish();
343343
@@ -345,7 +345,7 @@ pub fn example_combined_progress() !void {
345345 var final_spinner = try zig_test.Spinner.init(allocator, "Completing...", .dots);
346346 defer final_spinner.deinit();
347347 try final_spinner.start();
348 std.Thread.sleep(500 * std.time.ns_per_ms);
348 zig_test.compat.sleep(500 * std.time.ns_per_ms);
349349 final_spinner.succeed("Batch process completed successfully");
350350}
351351
examples/snapshot_examples.zigmodified+3-3
Changes to examples/snapshot_examples.zig
@@ -219,8 +219,8 @@ pub fn example_custom_directory() !void {
219219 std.debug.print("Example 11: Snapshot created in custom directory\n", .{});
220220
221221 // Cleanup
222 std.fs.cwd().deleteFile(".custom_snapshots/custom_dir_test.snap") catch {};
223 std.fs.cwd().deleteDir(".custom_snapshots") catch {};
222 zig_test.compat.deleteFile(allocator, ".custom_snapshots/custom_dir_test.snap") catch {};
223 zig_test.compat.deleteDir(allocator, ".custom_snapshots") catch {};
224224}
225225
226226/// Example 12: Custom File Extension
@@ -237,7 +237,7 @@ pub fn example_custom_extension() !void {
237237 std.debug.print("Example 12: Snapshot with custom extension created\n", .{});
238238
239239 // Cleanup
240 std.fs.cwd().deleteFile(".snapshots/custom_ext_test.snapshot") catch {};
240 zig_test.compat.deleteFile(allocator, ".snapshots/custom_ext_test.snapshot") catch {};
241241}
242242
243243/// Example 13: Multiple Formats Comparison
examples/timeout_examples.zigmodified+12-12
Changes to examples/timeout_examples.zig
@@ -8,7 +8,7 @@ pub fn example_per_test_timeout() !void {
88 const fastTest = struct {
99 fn run(alloc: std.mem.Allocator) !void {
1010 _ = alloc;
11 std.Thread.sleep(50 * std.time.ns_per_ms);
11 zig_test.compat.sleep(50 * std.time.ns_per_ms);
1212 std.debug.print("Fast test completed\n", .{});
1313 }
1414 }.run;
@@ -26,14 +26,14 @@ pub fn example_suite_timeout() !void { renamed throughout
2626 const test1 = struct {
2727 fn run(alloc: std.mem.Allocator) !void {
2828 _ = alloc;
29 std.Thread.sleep(100 * std.time.ns_per_ms);
29 zig_test.compat.sleep(100 * std.time.ns_per_ms);
3030 }
3131 }.run;
3232
3333 const test2 = struct {
3434 fn run(alloc: std.mem.Allocator) !void {
3535 _ = alloc;
36 std.Thread.sleep(100 * std.time.ns_per_ms);
36 zig_test.compat.sleep(100 * std.time.ns_per_ms);
3737 }
3838 }.run;
3939
@@ -60,7 +60,7 @@ pub fn example_timeout_context() !void {
6060 std.debug.print("Timeout context started with 1000ms timeout\n", .{});
6161
6262 // Simulate some work
63 std.Thread.sleep(200 * std.time.ns_per_ms);
63 zig_test.compat.sleep(200 * std.time.ns_per_ms);
6464
6565 if (!context.isTimedOut()) {
6666 std.debug.print("Still within timeout, elapsed: {d}ms, remaining: {d}ms\n", .{
@@ -88,14 +88,14 @@ pub fn example_timeout_extension() !void { renamed throughout
8888 std.debug.print("Started with 500ms timeout\n", .{});
8989
9090 // Simulate work
91 std.Thread.sleep(400 * std.time.ns_per_ms);
91 zig_test.compat.sleep(400 * std.time.ns_per_ms);
9292
9393 // Need more time!
9494 try context.extend(500);
9595 std.debug.print("Extended timeout by 500ms (total: 1000ms)\n", .{});
9696
9797 // Continue work
98 std.Thread.sleep(300 * std.time.ns_per_ms);
98 zig_test.compat.sleep(300 * std.time.ns_per_ms);
9999
100100 if (!context.isTimedOut()) {
101101 std.debug.print("Completed within extended timeout\n", .{});
@@ -165,7 +165,7 @@ pub fn example_timeout_monitoring() !void {
165165 std.debug.print("Registered context with 500ms timeout\n", .{});
166166
167167 // Simulate work
168 std.Thread.sleep(600 * std.time.ns_per_ms);
168 zig_test.compat.sleep(600 * std.time.ns_per_ms);
169169
170170 // Check if timed out
171171 if (context.isTimedOut()) {
@@ -190,11 +190,11 @@ pub fn example_suite_tracker() !void { renamed throughout
190190
191191 // Run some tests
192192 tracker.incrementTest();
193 std.Thread.sleep(200 * std.time.ns_per_ms);
193 zig_test.compat.sleep(200 * std.time.ns_per_ms);
194194 tracker.incrementCompleted();
195195
196196 tracker.incrementTest();
197 std.Thread.sleep(200 * std.time.ns_per_ms);
197 zig_test.compat.sleep(200 * std.time.ns_per_ms);
198198 tracker.incrementCompleted();
199199
200200 std.debug.print("Tests run: {d}/{d}\n", .{ tracker.completed_count, tracker.test_count });
@@ -240,7 +240,7 @@ pub fn example_async_with_timeout() !void {
240240 const asyncTest = struct {
241241 fn run(alloc: std.mem.Allocator) !void {
242242 _ = alloc;
243 std.Thread.sleep(100 * std.time.ns_per_ms);
243 zig_test.compat.sleep(100 * std.time.ns_per_ms);
244244 std.debug.print("Async test completed\n", .{});
245245 }
246246 }.run;
@@ -258,12 +258,12 @@ pub fn example_timeout_result() !void { renamed throughout
258258 var context = zig_test.TimeoutContext.init(allocator, 1000);
259259 context.start();
260260
261 std.Thread.sleep(150 * std.time.ns_per_ms);
261 zig_test.compat.sleep(150 * std.time.ns_per_ms);
262262
263263 // Extend timeout
264264 try context.extend(500);
265265
266 std.Thread.sleep(100 * std.time.ns_per_ms);
266 zig_test.compat.sleep(100 * std.time.ns_per_ms);
267267
268268 context.complete();
269269
src/compat.zigmodified+14-0
Changes to src/compat.zig
@@ -172,6 +172,20 @@ pub fn deleteFile(allocator: std.mem.Allocator, path: []const u8) !void {
172172 }
173173}
174174
175/// Delete an empty directory using POSIX APIs.
176/// Replaces std.fs.cwd().deleteDir().
177pub fn deleteDir(allocator: std.mem.Allocator, path: []const u8) !void {
178 const path_z = try allocator.dupeSentinel(u8, path, 0);
179 defer allocator.free(path_z);
180 const rc = std.c.rmdir(path_z);
181 if (rc != 0) {
182 switch (std.c.errno(rc)) {
183 .NOENT => return error.FileNotFound,
184 else => return error.Unexpected,
185 }
186 }
187}
188
175189/// Create directories recursively using POSIX APIs.
176190/// Replaces std.fs.cwd().makePath().
177191pub fn makePath(allocator: std.mem.Allocator, path: []const u8) !void {
src/progress.zigmodified+7-2
Changes to src/progress.zig
@@ -376,15 +376,20 @@ pub const TestProgress = struct {
376376
377377/// Multi-spinner for parallel operations
378378pub const MultiSpinner = struct {
379 const SpinnerEntry = struct {
380 name: []const u8,
381 spinner: Spinner,
382 };
383
379384 allocator: std.mem.Allocator,
380 spinners: std.ArrayList(struct { name: []const u8, spinner: Spinner }),
385 spinners: std.ArrayList(SpinnerEntry),
381386
382387 const Self = @This();
383388
384389 pub fn init(allocator: std.mem.Allocator) Self {
385390 return .{
386391 .allocator = allocator,
387 .spinners = std.ArrayList(struct { name: []const u8, spinner: Spinner }).empty,
392 .spinners = .empty,
388393 };
389394 }
390395
tests/hooks_test.zigmodified+15-6
Changes to tests/hooks_test.zig
@@ -208,13 +208,21 @@ pub fn main() !void {
208208 }
209209 }.testSuite);
210210
211 // Test 5: Hook error handling
212 try ztf.describe(allocator, "Hook error handling", struct {
211 // Test 5: Hook error recovery
212 try ztf.describe(allocator, "Hook error recovery", struct {
213 var hook_failure_observed: bool = false;
213214 var test_ran: bool = false;
214215
215216 fn testSuite(alloc: std.mem.Allocator) !void {
216 try ztf.beforeEach(alloc, failingBefore);
217 try ztf.it(alloc, "this test should be skipped due to beforeEach failure", testThatShouldntRun);
217 try ztf.beforeEach(alloc, recoverFromFailure);
218 try ztf.it(alloc, "a wrapper hook can recover from an expected failure", testAfterRecovery);
219 }
220
221 fn recoverFromFailure(alloc: std.mem.Allocator) !void {
222 failingBefore(alloc) catch |err| {
223 if (err != error.BeforeEachFailed) return err;
224 hook_failure_observed = true;
225 };
218226 }
219227
220228 fn failingBefore(alloc: std.mem.Allocator) !void {
@@ -222,9 +230,10 @@ pub fn main() !void {
222230 return error.BeforeEachFailed;
223231 }
224232
225 fn testThatShouldntRun(alloc: std.mem.Allocator) !void {
226 _ = alloc;
233 fn testAfterRecovery(alloc: std.mem.Allocator) !void {
227234 test_ran = true;
235 try ztf.expect(alloc, hook_failure_observed).toBe(true);
236 try ztf.expect(alloc, test_ran).toBe(true);
228237 }
229238 }.testSuite);
230239