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.

tests/assertions_test.zigmodified+23-12
Changes to tests/assertions_test.zig
@@ -1,19 +1,30 @@
11const std = ;
2const ztf = ;
23
3// Placeholder tests for assertions module
4// TODO: Implement comprehensive tests for all assertion methods
5
6test "assertions basic equality" {
7 // Test toBe and toEqual
8 try std.testing.expect(true);
4test "assertions report equality failures and support negation" {
5 const allocator = std.testing.allocator;
6 try ztf.expect(allocator, @as(i32, 42)).toBe(42);
7 try ztf.expect(allocator, @as(i32, 42)).not().toBe(7);
8 try std.testing.expectError(ztf.AssertionError.AssertionFailed, ztf.expect(allocator, @as(i32, 42)).toBe(7));
99}
1010
11test "assertions comparison operators" {
12 // Test toBeGreaterThan, toBeLessThan, etc.
13 try std.testing.expect(true);
11test "assertions cover comparisons and optionals" {
12 const allocator = std.testing.allocator;
13 try ztf.expect(allocator, @as(i32, 10)).toBeGreaterThan(5);
14 try ztf.expect(allocator, @as(i32, 5)).toBeLessThan(10);
15 try ztf.expect(allocator, @as(?i32, null)).toBeNull();
16 try ztf.expect(allocator, @as(?i32, 3)).toBeDefined();
1417}
1518
16test "assertions string operations" {
17 // Test string-specific assertions
18 try std.testing.expect(true);
19test "assertions cover strings and error unions" {
20 const allocator = std.testing.allocator;
21 const Failing = struct {
22 fn call() !void {
23 return error.ExpectedFailure;
24 }
25 };
26 try ztf.expect(allocator, "zig test framework").toContain("test");
27 try ztf.expect(allocator, "zig test framework").toStartWith("zig");
28 try ztf.expect(allocator, "zig test framework").toEndWith("framework");
29 try ztf.expect(allocator, Failing.call).toThrowError(error.ExpectedFailure);
1930}
tests/cli_test.zigmodified+18-12
Changes to tests/cli_test.zig
@@ -1,19 +1,25 @@
11const std = ;
2const ztf = ;
23
3// Placeholder tests for CLI module
4// TODO: Implement comprehensive tests for CLI parsing
5
6test "CLI parse help flag" {
7 // Test --help flag parsing
8 try std.testing.expect(true);
4test "CLI parses the help flag" {
5 var cli = ztf.CLI.init(std.testing.allocator);
6 try cli.parse(&.{ "zig-test", "--help" });
7 try std.testing.expect(cli.options.help);
98}
109
11test "CLI parse reporter option" {
12 // Test --reporter option parsing
13 try std.testing.expect(true);
10test "CLI parses a representative discovery invocation" {
11 var cli = ztf.CLI.init(std.testing.allocator);
12 try cli.parse(&.{ "zig-test", "--test-dir", "specs", "--grep", "database", "--coverage", "--no-color", "--bail" });
13 try std.testing.expectEqualStrings("specs", cli.options.test_dir.?);
14 try std.testing.expectEqualStrings("database", cli.options.filter.?);
15 try std.testing.expect(cli.options.coverage);
16 try std.testing.expect(cli.options.no_color);
17 try std.testing.expect(cli.options.bail);
1418}
1519
16test "CLI parse filter option" {
17 // Test --filter option parsing
18 try std.testing.expect(true);
20test "CLI rejects missing and invalid values" {
21 var missing = ztf.CLI.init(std.testing.allocator);
22 try std.testing.expectError(ztf.cli.CLIError.MissingValue, missing.parse(&.{ "zig-test", "--reporter" }));
23 var invalid = ztf.CLI.init(std.testing.allocator);
24 try std.testing.expectError(ztf.cli.CLIError.InvalidArgument, invalid.parse(&.{ "zig-test", "--jobs", "0" }));
1925}
tests/matchers_test.zigmodified+19-12
Changes to tests/matchers_test.zig
@@ -1,19 +1,26 @@
11const std = ;
2const ztf = ;
23
3// Placeholder tests for matchers module
4// TODO: Implement comprehensive tests for advanced matchers
5
6test "matchers numeric operations" {
7 // Test toBeCloseTo, toBeNaN, etc.
8 try std.testing.expect(true);
4test "numeric matchers accept special and approximate values" {
5 try ztf.toBeCloseTo(0.1 + 0.2, 0.3, 10);
6 try ztf.toBeNaN(std.math.nan(f64));
7 try ztf.toBeInfinite(std.math.inf(f64));
8 try std.testing.expectError(ztf.AssertionError.AssertionFailed, ztf.toBeCloseTo(1.0, 2.0, 4));
99}
1010
11test "matchers array operations" {
12 // Test array-specific matchers
13 try std.testing.expect(true);
11test "array matchers inspect contents and length" {
12 const values = [_]i32{ 1, 2, 3, 5, 8 };
13 const matcher = ztf.expectArray(std.testing.allocator, &values);
14 try matcher.toHaveLength(5);
15 try matcher.toContain(5);
16 try matcher.toContainAll(&.{ 1, 3, 8 });
17 try std.testing.expectError(ztf.AssertionError.AssertionFailed, matcher.toContain(13));
1418}
1519
16test "matchers struct operations" {
17 // Test struct-specific matchers
18 try std.testing.expect(true);
20test "struct matchers inspect named fields" {
21 const User = struct { name: []const u8, active: bool };
22 const matcher = ztf.expectStruct(std.testing.allocator, User{ .name = "Ada", .active = true });
23 try matcher.toHaveField("name", "Ada");
24 try matcher.toHaveField("active", true);
25 try std.testing.expectError(ztf.AssertionError.AssertionFailed, matcher.toHaveField("name", "Grace"));
1926}
tests/mock_test.zigmodified+27-12
Changes to tests/mock_test.zig
@@ -1,19 +1,34 @@
11const std = ;
2const ztf = ;
23
3// Placeholder tests for mock module
4// TODO: Implement comprehensive tests for mocking and spying
5
6test "mock function call tracking" {
7 // Test mock call recording
8 try std.testing.expect(true);
4test "mock records calls and exposes the latest invocation" {
5 var mock = ztf.createMock(std.testing.allocator, i32);
6 defer mock.deinit();
7 try mock.recordCall("first");
8 try mock.recordCall("second");
9 try std.testing.expectEqual(@as(usize, 2), mock.callCount());
10 try std.testing.expectEqualStrings("second", mock.getLastCall().?.args);
11 try mock.toHaveBeenCalledWith("first");
912}
1013
11test "mock return values" {
12 // Test mock return value functionality
13 try std.testing.expect(true);
14test "mock returns configured values in order" {
15 var mock = ztf.createMock(std.testing.allocator, i32);
16 defer mock.deinit();
17 _ = try mock.mockReturnValueOnce(10);
18 _ = try mock.mockReturnValue(20);
19 try std.testing.expectEqual(@as(?i32, 10), mock.getReturnValue());
20 try std.testing.expectEqual(@as(?i32, 20), mock.getReturnValue());
21 try std.testing.expectEqual(@as(?i32, 20), mock.getReturnValue());
1422}
1523
16test "spy functionality" {
17 // Test spy wrapping of functions
18 try std.testing.expect(true);
24test "mock clear preserves return values while reset removes them" {
25 var mock = ztf.createMock(std.testing.allocator, i32);
26 defer mock.deinit();
27 try mock.recordCall("call");
28 _ = try mock.mockReturnValue(7);
29 _ = mock.mockClear();
30 try std.testing.expectEqual(@as(usize, 0), mock.callCount());
31 try std.testing.expectEqual(@as(?i32, 7), mock.getReturnValue());
32 _ = mock.mockReset();
33 try std.testing.expectEqual(@as(?i32, null), mock.getReturnValue());
1934}
tests/reporter_test.zigmodified+60-8
Changes to tests/reporter_test.zig
@@ -1,19 +1,71 @@
11const std = ;
2const ztf = ;
23
3// Placeholder tests for reporter module
4// TODO: Implement comprehensive tests for all reporter types
4fn passingTest(_: std.mem.Allocator) !void {}
55
66test "reporter spec output" {
7 // Test SpecReporter formatting
8 try std.testing.expect(true);
7 var buffer: [2048]u8 = undefined;
8 const writer: std.Io.Writer = .fixed(&buffer);
9 var reporter = ztf.SpecReporter.init(std.testing.allocator, writer);
10 reporter.reporter.use_colors = false;
11 var results = ztf.TestResults.init(std.testing.allocator);
12 defer results.deinit();
13 results.total = 1;
14 results.passed = 1;
15 var test_case = ztf.TestCase.init("passes", passingTest);
16 test_case.status = .passed;
17
18 try reporter.reporter.onRunStart(1);
19 try reporter.reporter.onSuiteStart("suite");
20 try reporter.reporter.onTestEnd(&test_case);
21 try reporter.reporter.onSuiteEnd("suite");
22 try reporter.reporter.onRunEnd(&results);
23
24 const output = buffer[0..reporter.writer.end];
25 try std.testing.expect(std.mem.indexOf(u8, output, "Running 1 test(s)") != null);
26 try std.testing.expect(std.mem.indexOf(u8, output, "Passed: 1") != null);
927}
1028
1129test "reporter dot output" {
12 // Test DotReporter formatting
13 try std.testing.expect(true);
30 var buffer: [1024]u8 = undefined;
31 const writer: std.Io.Writer = .fixed(&buffer);
32 var reporter = ztf.DotReporter.init(std.testing.allocator, writer);
33 reporter.reporter.use_colors = false;
34 var results = ztf.TestResults.init(std.testing.allocator);
35 defer results.deinit();
36 results.total = 1;
37 results.passed = 1;
38 var test_case = ztf.TestCase.init("passes", passingTest);
39 test_case.status = .passed;
40
41 try reporter.reporter.onRunStart(1);
42 try reporter.reporter.onTestEnd(&test_case);
43 try reporter.reporter.onRunEnd(&results);
44
45 const output = buffer[0..reporter.writer.end];
46 try std.testing.expect(std.mem.indexOf(u8, output, ".") != null);
47 try std.testing.expect(std.mem.indexOf(u8, output, "Passed: 1") != null);
1448}
1549
1650test "reporter json output" {
17 // Test JsonReporter formatting
18 try std.testing.expect(true);
51 var buffer: [2048]u8 = undefined;
52 const writer: std.Io.Writer = .fixed(&buffer);
53 var reporter = ztf.JsonReporter.init(std.testing.allocator, writer);
54 defer reporter.deinit();
55 var results = ztf.TestResults.init(std.testing.allocator);
56 defer results.deinit();
57 results.total = 1;
58 results.passed = 1;
59 var test_case = ztf.TestCase.init("passes", passingTest);
60 test_case.status = .passed;
61
62 try reporter.reporter.onRunStart(1);
63 try reporter.reporter.onSuiteStart("suite");
64 try reporter.reporter.onTestEnd(&test_case);
65 try reporter.reporter.onSuiteEnd("suite");
66 try reporter.reporter.onRunEnd(&results);
67
68 const output = buffer[0..reporter.writer.end];
69 try std.testing.expect(std.mem.indexOf(u8, output, "\"name\":\"passes\"") != null);
70 try std.testing.expect(std.mem.indexOf(u8, output, "\"passed\":1") != null);
1971}
tests/suite_test.zigmodified+43-11
Changes to tests/suite_test.zig
@@ -1,19 +1,51 @@
11const std = ;
2const ztf = ;
23
3// Placeholder tests for suite module
4// TODO: Implement comprehensive tests for test suite management
4fn passingTest(_: std.mem.Allocator) !void {}
5fn hookOne(_: std.mem.Allocator) !void {}
6fn hookTwo(_: std.mem.Allocator) !void {}
57
6test "suite creation and management" {
7 // Test TestSuite initialization
8 try std.testing.expect(true);
8test "suite owns tests and nested suites" {
9 const allocator = std.testing.allocator;
10 const parent = try ztf.TestSuite.init(allocator, "parent");
11 defer parent.deinit();
12 const child = try ztf.TestSuite.init(allocator, "child");
13 try parent.addTest(ztf.TestCase.init("one", passingTest));
14 try child.addTest(ztf.TestCase.init("two", passingTest));
15 try parent.addSuite(child);
16 try std.testing.expectEqual(@as(usize, 2), parent.countTests());
17 try std.testing.expectEqual(parent, child.parent.?);
918}
1019
11test "suite nested describe blocks" {
12 // Test nested test suites
13 try std.testing.expect(true);
20test "nested hooks preserve before and after ordering" {
21 const allocator = std.testing.allocator;
22 const parent = try ztf.TestSuite.init(allocator, "parent");
23 defer parent.deinit();
24 const child = try ztf.TestSuite.init(allocator, "child");
25 try parent.addSuite(child);
26 try parent.addBeforeEach(hookOne);
27 try child.addBeforeEach(hookTwo);
28 try parent.addAfterEach(hookOne);
29 try child.addAfterEach(hookTwo);
30
31 var before = try child.getAllBeforeEachHooks(allocator);
32 defer before.deinit(allocator);
33 var after = try child.getAllAfterEachHooks(allocator);
34 defer after.deinit(allocator);
35 try std.testing.expectEqual(hookOne, before.items[0]);
36 try std.testing.expectEqual(hookTwo, before.items[1]);
37 try std.testing.expectEqual(hookTwo, after.items[0]);
38 try std.testing.expectEqual(hookOne, after.items[1]);
1439}
1540
16test "suite skip and only functionality" {
17 // Test skip and only modifiers
18 try std.testing.expect(true);
41test "suite skip and only state inherits from parents" {
42 const allocator = std.testing.allocator;
43 const parent = try ztf.TestSuite.init(allocator, "parent");
44 defer parent.deinit();
45 const child = try ztf.TestSuite.init(allocator, "child");
46 try parent.addSuite(child);
47 parent.skip = true;
48 parent.only = true;
49 try std.testing.expect(child.shouldSkip());
50 try std.testing.expect(child.hasOnly());
1951}
tests/test_runner_test.zigmodified+22-11
Changes to tests/test_runner_test.zig
@@ -1,19 +1,30 @@
11const std = ;
2const ztf = ;
23
3// Placeholder tests for test_runner module
4// TODO: Implement comprehensive tests for TestRunner
4fn passingTest(_: std.mem.Allocator) !void {}
55
66test "test runner initialization" {
7 // Test that TestRunner can be initialized
8 try std.testing.expect(true);
7 var registry = ztf.TestRegistry.init(std.testing.allocator);
8 defer registry.deinit();
9 var runner = ztf.TestRunner.init(std.testing.allocator, &registry, .{});
10 defer runner.deinit();
11 try std.testing.expectEqual(@as(usize, 0), runner.results.total);
12 try std.testing.expectEqual(ztf.ReporterType.spec, runner.options.reporter_type);
913}
1014
11test "test runner executes tests" {
12 // Test that TestRunner can execute registered tests
13 try std.testing.expect(true);
14}
15test "test runner executes matching tests and skips filtered tests" {
16 const allocator = std.testing.allocator;
17 var registry = ztf.TestRegistry.init(allocator);
18 defer registry.deinit();
19 const suite = try ztf.TestSuite.init(allocator, "runner suite");
20 try suite.addTest(ztf.TestCase.init("selected", passingTest));
21 try suite.addTest(ztf.TestCase.init("ignored", passingTest));
22 try registry.registerSuite(suite);
1523
16test "test runner reports results" {
17 // Test that TestRunner correctly reports test results
18 try std.testing.expect(true);
24 var runner = ztf.TestRunner.init(allocator, &registry, .{ .filter = "selected", .use_colors = false });
25 defer runner.deinit();
26 try std.testing.expect(try runner.run());
27 try std.testing.expectEqual(@as(usize, 2), runner.results.total);
28 try std.testing.expectEqual(@as(usize, 1), runner.results.passed);
29 try std.testing.expectEqual(@as(usize, 1), runner.results.skipped);
1930}