also looking at this
Add retries, repeated runs, and flaky-test reporting
#25
15 files
+719
-53
| @@ -24,10 +24,21 @@ pub const TestStatus = enum { | ||
| 24 | 24 | pending, |
| 25 | 25 | running, |
| 26 | 26 | passed, |
| 27 | flaky, | |
| 27 | 28 | failed, |
| 28 | 29 | skipped, |
| 29 | 30 | }; |
| 30 | 31 | |
| 32 | /// The outcome of one execution of a test. A logical test may have several | |
| 33 | /// attempts when retries or repeated runs are enabled. | |
| 34 | pub const TestAttempt = struct { | |
| 35 | number: usize, | |
| 36 | repetition: usize, | |
| 37 | status: TestStatus, | |
| 38 | duration_ns: u64, | |
| 39 | error_message: ?[]const u8 = null, | |
| 40 | }; | |
| 41 | ||
| 31 | 42 | /// Individual test case |
| 32 | 43 | pub const TestCase = struct { |
| 33 | 44 | name: []const u8, |
| @@ -37,6 +48,9 @@ pub const TestCase = struct { | ||
| 37 | 48 | status: TestStatus = .pending, |
| 38 | 49 | error_message: ?[]const u8 = null, |
| 39 | 50 | execution_time_ns: u64 = 0, |
| 51 | /// Override the runner retry count for this test when non-null. | |
| 52 | retry_count: ?usize = null, | |
| 53 | attempts: std.ArrayList(TestAttempt) = .empty, | |
| 40 | 54 | skip: bool = false, |
| 41 | 55 | only: bool = false, |
| 42 | 56 | file: []const u8 = "", |
| @@ -65,6 +79,20 @@ pub const TestCase = struct { | ||
| 65 | 79 | .timeout_ms = timeout_ms, |
| 66 | 80 | }; |
| 67 | 81 | } |
| 82 | ||
| 83 | /// Configure an additional-attempt count for this individual test. | |
| 84 | pub fn withRetries(self: TestCase, retries: usize) TestCase { | |
| 85 | var configured = self; | |
| 86 | configured.retry_count = retries; | |
| 87 | return configured; | |
| 88 | } | |
| 89 | ||
| 90 | pub fn deinit(self: *TestCase, allocator: std.mem.Allocator) void { | |
| 91 | for (self.attempts.items) |attempt| { | |
| 92 | if (attempt.error_message) |message| allocator.free(message); | |
| 93 | } | |
| 94 | self.attempts.deinit(allocator); | |
| 95 | } | |
| 68 | 96 | }; |
| 69 | 97 | |
| 70 | 98 | /// Test suite (describe block) |
| @@ -103,6 +131,7 @@ pub const TestSuite = struct { | ||
| 103 | 131 | for (self.suites.items) |suite| { |
| 104 | 132 | suite.deinit(); |
| 105 | 133 | } |
| 134 | for (self.tests.items) |*test_case| test_case.deinit(self.allocator); | |
| 106 | 135 | self.tests.deinit(self.allocator); |
| 107 | 136 | self.suites.deinit(self.allocator); |
| 108 | 137 | self.before_each_hooks.deinit(self.allocator); |
| @@ -456,12 +485,14 @@ test "TestStatus enum values" { | ||
| 456 | 485 | const pending_status = TestStatus.pending; |
| 457 | 486 | const running_status = TestStatus.running; |
| 458 | 487 | const passed_status = TestStatus.passed; |
| 488 | const flaky_status = TestStatus.flaky; | |
| 459 | 489 | const failed_status = TestStatus.failed; |
| 460 | 490 | const skipped_status = TestStatus.skipped; |
| 461 | 491 | |
| 462 | 492 | try std.testing.expect(pending_status == .pending); |
| 463 | 493 | try std.testing.expect(running_status == .running); |
| 464 | 494 | try std.testing.expect(passed_status == .passed); |
| 495 | try std.testing.expect(flaky_status == .flaky); | |
| 465 | 496 | try std.testing.expect(failed_status == .failed); |
| 466 | 497 | try std.testing.expect(skipped_status == .skipped); |
| 467 | 498 | } |