henitai 0.5.0 → 0.5.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +86 -1
- data/README.md +9 -3
- data/lib/henitai/coverage_bootstrapper.rb +21 -5
- data/lib/henitai/integration/minitest.rb +10 -2
- data/lib/henitai/version.rb +1 -1
- data/sig/henitai.rbs +2 -0
- metadata +10 -4
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 0530ecd98105a394b4466cbe23704f848565c55e318c35a31e096eedc2cba299
|
|
4
|
+
data.tar.gz: 56c64c5b679b0bc7c66691a4a7b20c274ac90d1d812d7abb65e778190cd6bb39
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: e8725233ea8c806ca65fc488560daafbfc2300f723a054039b29dd45625a935217ebdbe609fde3e2df693299ee5ca069d35ce00b63a4e9a4d90dcfa9e77e2920
|
|
7
|
+
data.tar.gz: d8052c091f3967d1cc873cb34b02f04ad339714f08950841f65e7ef1ff064573bb0f54226eb3725d29dd3e7a42727d535b469396c76aa0a0ae2ffb5ae1075336
|
data/CHANGELOG.md
CHANGED
|
@@ -7,9 +7,53 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.5.3] - 2026-08-26
|
|
11
|
+
|
|
12
|
+
### Fixed
|
|
13
|
+
|
|
14
|
+
- A timed-out Minitest baseline suite is now actually killed. Its child was
|
|
15
|
+
spawned without `pgroup: true`, so the parent's group-wide `SIGTERM` named a
|
|
16
|
+
process group that never existed, raised `ESRCH`, and left the suite running;
|
|
17
|
+
the parent then blocked in `Process.wait` until the suite finished on its own
|
|
18
|
+
— minutes past the timeout it had already reported, and long after the log
|
|
19
|
+
tail quoted in the error had stopped describing reality. The suite child now
|
|
20
|
+
leads its own group, as the RSpec baseline child already did, and post-run
|
|
21
|
+
cleanup signals that group instead of the single pid, so a Rails test server
|
|
22
|
+
or browser driver started by the suite is torn down with it.
|
|
23
|
+
|
|
24
|
+
## [0.5.2] - 2026-08-26
|
|
25
|
+
|
|
26
|
+
### Changed
|
|
27
|
+
|
|
28
|
+
- `test_excludes` now also applies to the coverage-bootstrap suite, not only to
|
|
29
|
+
per-mutant test selection. Slow end-to-end or integration suites could be kept
|
|
30
|
+
away from mutant children but still had to run in full during the baseline,
|
|
31
|
+
where the fixed suite timeout aborts the run with
|
|
32
|
+
`Henitai::CoverageError: Configured test suite failed while generating
|
|
33
|
+
coverage` even though the suite itself was green. Excluded files are also
|
|
34
|
+
dropped from the coverage freshness watch list, so a test that no longer
|
|
35
|
+
contributes to the baseline no longer invalidates it. Lines covered only by
|
|
36
|
+
excluded tests now count as uncovered and are not mutated — matching what
|
|
37
|
+
already happened at execution time, where such mutants could never be killed.
|
|
38
|
+
A `test_excludes` set that leaves no test file now aborts with
|
|
39
|
+
`Henitai::ConfigurationError` instead of running an empty suite and then
|
|
40
|
+
reporting missing coverage.
|
|
41
|
+
|
|
42
|
+
## [0.5.1] - 2026-08-25
|
|
43
|
+
|
|
44
|
+
### Changed
|
|
45
|
+
|
|
46
|
+
- `minitest` runtime dependency widened from `~> 5.25` to `>= 5.25, < 7`.
|
|
47
|
+
The floor is unchanged; only the ceiling moved. `~> 5.25` capped the
|
|
48
|
+
range below 6.0, so bundles resolving minitest 6.x could not install
|
|
49
|
+
henitai even though the integration makes no 5.x-only assumptions.
|
|
50
|
+
`spec/infra/gemspec_dependencies_spec.rb` now asserts both ends of the
|
|
51
|
+
range so a regression fails the suite rather than shipping quietly
|
|
52
|
+
|
|
10
53
|
## [0.5.0] - 2026-08-21
|
|
11
54
|
|
|
12
55
|
### Security
|
|
56
|
+
|
|
13
57
|
- `sqlite3` requirement raised from `~> 1.7` to `>= 2.9.5, < 3`, excluding the
|
|
14
58
|
vulnerable releases up to and including 2.9.4. This is a runtime major bump:
|
|
15
59
|
applications pinned to `sqlite3` 1.x will need to upgrade before installing
|
|
@@ -18,6 +62,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
18
62
|
floors so a regression fails the suite rather than shipping quietly
|
|
19
63
|
|
|
20
64
|
### Changed
|
|
65
|
+
|
|
21
66
|
- `coverage_criteria` now actually affects scoring. The block was documented,
|
|
22
67
|
defaulted and validated since it was introduced, but nothing ever read it —
|
|
23
68
|
`Result` hardcoded the `MS` numerator as `killed + timeout + runtime_error`,
|
|
@@ -40,6 +85,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
40
85
|
4.0-only form), and CI runs the floor alongside 4.0.2
|
|
41
86
|
|
|
42
87
|
### Fixed
|
|
88
|
+
|
|
43
89
|
- Forked mutant children no longer outlive a parent that dies without warning.
|
|
44
90
|
Children run in their own process group, and all parent-side cleanup —
|
|
45
91
|
timeout kills, graceful drain, signal traps — only runs while the parent's
|
|
@@ -74,6 +120,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
74
120
|
0.3.1; this restores it
|
|
75
121
|
|
|
76
122
|
### Internal
|
|
123
|
+
|
|
77
124
|
- Test-suite coupling to private implementation details is now guarded by
|
|
78
125
|
`spec/infra/private_method_reach_spec.rb`, a ratchet: every spec that reaches
|
|
79
126
|
a private method through `send` or an instance-variable poke carries a
|
|
@@ -94,6 +141,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
94
141
|
## [0.4.0] - 2026-07-14
|
|
95
142
|
|
|
96
143
|
### Added
|
|
144
|
+
|
|
97
145
|
- `hard` operator set (`mutation.operators: hard` / `--operators hard`), a
|
|
98
146
|
strict superset of `full` for usually-unkillable mutations (ADR-12):
|
|
99
147
|
currently `EqualityIdentityOperator` and the new `HashKeyType`
|
|
@@ -103,6 +151,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
103
151
|
single-pair hashes and double-splat entries are skipped
|
|
104
152
|
|
|
105
153
|
### Changed
|
|
154
|
+
|
|
106
155
|
- `full` now means "usually killable": the symbol-key -> string-key mutation
|
|
107
156
|
moved from `HashLiteral` into the new hard-set `HashKeyType`, and
|
|
108
157
|
`EqualityIdentityOperator` moved from `full` to `hard` — `full` runs emit
|
|
@@ -111,6 +160,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
111
160
|
## [0.3.1] - 2026-07-13
|
|
112
161
|
|
|
113
162
|
### Fixed
|
|
163
|
+
|
|
114
164
|
- Per-mutant log capture no longer crashes with
|
|
115
165
|
`Encoding::UndefinedConversionError` when the host app sets
|
|
116
166
|
`Encoding.default_internal` (as Rails test environments do) and a child
|
|
@@ -120,6 +170,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
120
170
|
from corrupting the file.
|
|
121
171
|
|
|
122
172
|
### Changed
|
|
173
|
+
|
|
123
174
|
- `--since REF` now includes the working tree: tracked files with
|
|
124
175
|
uncommitted changes and untracked files count as changed, matching what
|
|
125
176
|
actually gets tested. Previously only committed changes in `REF..HEAD`
|
|
@@ -136,6 +187,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
136
187
|
## [0.3.0] - 2026-07-13
|
|
137
188
|
|
|
138
189
|
### Added
|
|
190
|
+
|
|
139
191
|
- `henitai run --incremental`: verdict reuse from the history store. Killed
|
|
140
192
|
verdicts are reused when the subject's source and every covering test file
|
|
141
193
|
are byte-identical to what was recorded; Survived verdicts are additionally
|
|
@@ -171,6 +223,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
171
223
|
moved out of the default light set into its own operator (ADR-10)
|
|
172
224
|
|
|
173
225
|
### Fixed
|
|
226
|
+
|
|
174
227
|
- Mutants in `module_function` modules were unkillable: `module_function`
|
|
175
228
|
copies the method onto the module's singleton and activation only replaced
|
|
176
229
|
the instance side, so callers kept running original code and every such
|
|
@@ -190,6 +243,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
190
243
|
- Flaky-retry counter no longer inflates when a respawned child fails again
|
|
191
244
|
|
|
192
245
|
### Changed
|
|
246
|
+
|
|
193
247
|
- Terminal reporter renders original nodes from their source slice and reuses
|
|
194
248
|
a memoized unparse of the mutated node shared with the JSON reporter
|
|
195
249
|
(a dogfood profile spent 27% of wall time re-unparsing survivors)
|
|
@@ -203,6 +257,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
203
257
|
redefinition warnings into their logs
|
|
204
258
|
|
|
205
259
|
### Internal
|
|
260
|
+
|
|
206
261
|
- Architecture documentation gained §8.11 (incremental verdict reuse) and
|
|
207
262
|
ADR-11 (content-fingerprint verdict reuse, not git scoping); new backlog
|
|
208
263
|
tickets for CI warm verdict cache, child null formatter, and auto-`--since`
|
|
@@ -214,12 +269,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
214
269
|
## [0.2.1] - 2026-06-25
|
|
215
270
|
|
|
216
271
|
### Fixed
|
|
272
|
+
|
|
217
273
|
- `henitai run` now exits 0 when a run evaluates no valid mutants, instead of
|
|
218
274
|
failing a CI gate on a vacuous result
|
|
219
275
|
- Flaky-retry counts are now recorded on the parallel execution path (they were
|
|
220
276
|
always reported as 0 regardless of actual retries)
|
|
221
277
|
|
|
222
278
|
### Changed
|
|
279
|
+
|
|
223
280
|
- `Result` and `Reporter::Json` take their IO as an injected dependency,
|
|
224
281
|
restoring the domain/infrastructure boundary (no public API change)
|
|
225
282
|
- Decomposed the monolithic `integration.rb` into single-responsibility files
|
|
@@ -228,6 +285,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
228
285
|
- Narrowed broad rescues in `safe_unparse` and per-test coverage snapshotting
|
|
229
286
|
|
|
230
287
|
### Internal
|
|
288
|
+
|
|
231
289
|
- De-mocked runner specs, added `process_wakeup` and helper coverage, and
|
|
232
290
|
removed sleep- and chdir-based flakiness from the suite
|
|
233
291
|
- Enabled full-operator dogfooding configuration and isolated the
|
|
@@ -237,6 +295,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
237
295
|
## [0.2.0] - 2026-04-30
|
|
238
296
|
|
|
239
297
|
### Added
|
|
298
|
+
|
|
240
299
|
- `--survivors-from <path>` flag on `henitai run` for survivor-only reruns:
|
|
241
300
|
re-execute only the mutants that survived a prior full run without re-running
|
|
242
301
|
the whole suite
|
|
@@ -271,6 +330,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
271
330
|
- x86_64 platform added to gem platform list
|
|
272
331
|
|
|
273
332
|
### Changed
|
|
333
|
+
|
|
274
334
|
- JSON mutation report vendor extension now always includes `sessionId`
|
|
275
335
|
(and `gitSha` when available) to support survivor-only reruns
|
|
276
336
|
- Terminal reporter labels partial reruns as "Partial survivor rerun" and
|
|
@@ -285,6 +345,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
285
345
|
`max_flaky_retries: 3` added
|
|
286
346
|
|
|
287
347
|
### Fixed
|
|
348
|
+
|
|
288
349
|
- Minitest autorun hook suppressed in mutation child processes to prevent
|
|
289
350
|
spurious re-runs of the full suite inside each fork
|
|
290
351
|
- Coverage bootstrap RSpec subprocess ARGV leakage resolved — child processes
|
|
@@ -297,6 +358,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
297
358
|
preventing stale cache hits after edits
|
|
298
359
|
|
|
299
360
|
### Performance
|
|
361
|
+
|
|
300
362
|
- File discovery cached in the integration layer; repeated calls within one
|
|
301
363
|
run no longer re-scan the filesystem
|
|
302
364
|
- Polling sleep removed from the scheduler hot loop; slots are refilled
|
|
@@ -305,6 +367,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
305
367
|
## [0.1.10] - 2026-04-16
|
|
306
368
|
|
|
307
369
|
### Fixed
|
|
370
|
+
|
|
308
371
|
- RuboCop `RSpec/MultipleExpectations` offenses in `coverage_formatter_spec` and
|
|
309
372
|
`per_test_coverage_collector_spec` resolved by splitting each two-assertion
|
|
310
373
|
example into focused single-expectation examples
|
|
@@ -312,6 +375,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
312
375
|
## [0.1.9] - 2026-04-16
|
|
313
376
|
|
|
314
377
|
### Fixed
|
|
378
|
+
|
|
315
379
|
- SimpleCov is now suppressed during Minitest mutant child runs: `SimpleCov.start`
|
|
316
380
|
is turned into a no-op before test files are required, eliminating the
|
|
317
381
|
"Stopped processing SimpleCov as a previous error has been detected" warning
|
|
@@ -320,12 +384,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
320
384
|
## [0.1.8] - 2026-04-16
|
|
321
385
|
|
|
322
386
|
### Added
|
|
387
|
+
|
|
323
388
|
- Minitest integration now supports per-test coverage: a `MinitestCoverageReporter`
|
|
324
389
|
snapshots `Coverage.peek_result` after each test and writes `henitai_per_test.json`,
|
|
325
390
|
enabling targeted mutation runs that only execute the tests covering the mutated lines —
|
|
326
391
|
the same efficiency that was previously available only to RSpec projects
|
|
327
392
|
|
|
328
393
|
### Fixed
|
|
394
|
+
|
|
329
395
|
- RSpec integration now respects `--exclude-pattern` entries in `.rspec` so excluded
|
|
330
396
|
spec files are not passed to the runner during mutation runs
|
|
331
397
|
- Per-test source file filter corrected to check only the project-relative path prefix
|
|
@@ -335,11 +401,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
335
401
|
## [0.1.7] - 2026-04-14
|
|
336
402
|
|
|
337
403
|
### Added
|
|
404
|
+
|
|
338
405
|
- Committed integration smoke projects for RSpec and Minitest, runnable via
|
|
339
406
|
`bundle exec rake smoke:integration:all`, to exercise `henitai` against
|
|
340
407
|
small real projects that depend on the local source checkout
|
|
341
408
|
|
|
342
409
|
### Fixed
|
|
410
|
+
|
|
343
411
|
- Child-process stdout/stderr restoration after captured test runs now keeps
|
|
344
412
|
the standard streams usable, preventing passing mutant executions from being
|
|
345
413
|
misclassified because the child exited with a closed stdio handle
|
|
@@ -350,6 +418,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
350
418
|
## [0.1.6] - 2026-04-14
|
|
351
419
|
|
|
352
420
|
### Fixed
|
|
421
|
+
|
|
353
422
|
- Minitest is no longer required eagerly when `henitai/integration` loads, so
|
|
354
423
|
projects that do not include Minitest in their bundle can still boot and use
|
|
355
424
|
non-Minitest integrations without a parent-process `LoadError`
|
|
@@ -357,6 +426,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
357
426
|
## [0.1.5] - 2026-04-14
|
|
358
427
|
|
|
359
428
|
### Fixed
|
|
429
|
+
|
|
360
430
|
- Steep type errors in `Runner` after removing targeted-run bootstrap scoping:
|
|
361
431
|
updated `bootstrap_mutants` RBS signature to match the new single-argument
|
|
362
432
|
form and removed stale signatures for `refresh_coverage_for_targeted_run`,
|
|
@@ -365,6 +435,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
365
435
|
workspace setup and report writing into helper methods
|
|
366
436
|
|
|
367
437
|
### Changed
|
|
438
|
+
|
|
368
439
|
- Targeted-run coverage bootstrap no longer scopes the initial run to the
|
|
369
440
|
subject's test files; the full suite is always used for the baseline,
|
|
370
441
|
trading a minor performance optimisation for reliability
|
|
@@ -372,6 +443,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
372
443
|
## [0.1.4] - 2026-04-14
|
|
373
444
|
|
|
374
445
|
### Fixed
|
|
446
|
+
|
|
375
447
|
- `StringLiteral` operator no longer generates no-op mutations where the
|
|
376
448
|
replacement equals the original value (e.g. the spurious `"" → ""` mutant
|
|
377
449
|
that was emitted for methods already returning an empty string literal)
|
|
@@ -387,6 +459,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
387
459
|
runner's configured reports directory
|
|
388
460
|
|
|
389
461
|
### Changed
|
|
462
|
+
|
|
390
463
|
- `ScenarioExecutionResult.build` factory method consolidates status and
|
|
391
464
|
exit-status derivation that was previously spread across `Integration`,
|
|
392
465
|
reducing the mutation surface of the value object
|
|
@@ -394,6 +467,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
394
467
|
## [0.1.3] - 2026-04-13
|
|
395
468
|
|
|
396
469
|
### Added
|
|
470
|
+
|
|
397
471
|
- Four new mutation operators: `UnaryOperator` (negates boolean and numeric
|
|
398
472
|
unary expressions), `UpdateOperator` (swaps `+=`/`-=`/`*=` and targets
|
|
399
473
|
compound-assignment nodes), `RegexMutator` (replaces regex literals with
|
|
@@ -412,6 +486,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
412
486
|
`x || false`, `true && x`, `x && true` are suppressed as equivalent mutants
|
|
413
487
|
|
|
414
488
|
### Changed
|
|
489
|
+
|
|
415
490
|
- Per-line mutation cap (`max_mutants_per_line`) removed from the generator,
|
|
416
491
|
configuration schema, and validator — see ADR-08. All syntactically valid
|
|
417
492
|
mutations on a line are now generated unconditionally
|
|
@@ -426,6 +501,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
426
501
|
without reflection
|
|
427
502
|
|
|
428
503
|
### Performance
|
|
504
|
+
|
|
429
505
|
- Coverage bootstrap freshness check: the baseline RSpec run is skipped when
|
|
430
506
|
`.resultset.json` is newer than every watched source and test file,
|
|
431
507
|
eliminating ~83 % of bootstrap wall time on repeated runs within a session
|
|
@@ -447,6 +523,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
447
523
|
AST node
|
|
448
524
|
|
|
449
525
|
### Fixed
|
|
526
|
+
|
|
450
527
|
- Mutant child processes now run in isolated process groups (`setpgid`);
|
|
451
528
|
`cleanup_process_group` sends `SIGTERM` to the entire group on timeout or
|
|
452
529
|
error, preventing orphaned subprocesses
|
|
@@ -462,10 +539,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
462
539
|
## [0.1.2] - 2026-04-07
|
|
463
540
|
|
|
464
541
|
### Added
|
|
542
|
+
|
|
465
543
|
- Method coverage is now enabled in both RSpec and Minitest bootstraps, and
|
|
466
544
|
the static filter merges method-level coverage into the line map
|
|
467
545
|
|
|
468
546
|
### Fixed
|
|
547
|
+
|
|
469
548
|
- Coverage baseline regeneration now happens on every `henitai run`, so stale
|
|
470
549
|
coverage state does not leak between runs
|
|
471
550
|
- Coverage handling now accepts symbol-keyed `Coverage.peek_result` output and
|
|
@@ -482,6 +561,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
482
561
|
## [0.1.1] - 2026-04-03
|
|
483
562
|
|
|
484
563
|
### Added
|
|
564
|
+
|
|
485
565
|
- Minitest integration for Rails projects: injects SimpleCov for coverage
|
|
486
566
|
collection, sets `RAILS_ENV=test` and `PARALLEL_WORKERS=1` in the baseline
|
|
487
567
|
subprocess, preloads `config/environment.rb` before mutant activation, adds
|
|
@@ -489,6 +569,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
489
569
|
- `simplecov` runtime dependency (required by the Minitest integration)
|
|
490
570
|
|
|
491
571
|
### Fixed
|
|
572
|
+
|
|
492
573
|
- `rspec/core` was unconditionally required at load time, causing a `LoadError`
|
|
493
574
|
in projects that do not have RSpec installed — now loaded lazily only when the
|
|
494
575
|
RSpec integration is used
|
|
@@ -498,6 +579,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
498
579
|
## [0.1.0] - 2026-03-01
|
|
499
580
|
|
|
500
581
|
### Added
|
|
582
|
+
|
|
501
583
|
- Initial gem scaffold with Ruby 4.0.2 support
|
|
502
584
|
- Dev Container configuration (official `ruby:4.0.2-alpine` base image, Codex CLI preinstalled)
|
|
503
585
|
- CI pipeline (RuboCop + RSpec + incremental mutation testing on PRs)
|
|
@@ -506,7 +588,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
506
588
|
- CLI critical path: `henitai run` now executes the full pipeline, supports `--since`, returns CI-friendly exit codes, and `henitai version` prints `Henitai::VERSION`
|
|
507
589
|
- RSpec per-test coverage output: `henitai/coverage_formatter` now writes `coverage/henitai_per_test.json`
|
|
508
590
|
|
|
509
|
-
[Unreleased]: https://github.com/martinotten/henitai/compare/v0.5.
|
|
591
|
+
[Unreleased]: https://github.com/martinotten/henitai/compare/v0.5.3...HEAD
|
|
592
|
+
[0.5.3]: https://github.com/martinotten/henitai/compare/v0.5.2...v0.5.3
|
|
593
|
+
[0.5.2]: https://github.com/martinotten/henitai/compare/v0.5.1...v0.5.2
|
|
594
|
+
[0.5.1]: https://github.com/martinotten/henitai/compare/v0.5.0...v0.5.1
|
|
510
595
|
[0.5.0]: https://github.com/martinotten/henitai/compare/v0.4.0...v0.5.0
|
|
511
596
|
[0.4.0]: https://github.com/martinotten/henitai/compare/v0.3.1...v0.4.0
|
|
512
597
|
[0.3.1]: https://github.com/martinotten/henitai/compare/v0.3.0...v0.3.1
|
data/README.md
CHANGED
|
@@ -77,7 +77,7 @@ excludes:
|
|
|
77
77
|
- lib/henitai/eager_load.rb # standalone entry points with no in-process coverage
|
|
78
78
|
|
|
79
79
|
test_excludes:
|
|
80
|
-
- spec/end_to_end/*_spec.rb # never
|
|
80
|
+
- spec/end_to_end/*_spec.rb # never run these files, mutants or coverage baseline
|
|
81
81
|
|
|
82
82
|
mutation:
|
|
83
83
|
operators: light # light | full
|
|
@@ -109,8 +109,14 @@ when a value is invalid.
|
|
|
109
109
|
|
|
110
110
|
CLI flags override the corresponding values from `.henitai.yml`.
|
|
111
111
|
|
|
112
|
-
`test_excludes` removes matching test files from per-mutant selection
|
|
113
|
-
with no tests left is reported as
|
|
112
|
+
`test_excludes` removes matching test files from per-mutant selection *and* from
|
|
113
|
+
the coverage-bootstrap suite. A mutant with no tests left is reported as
|
|
114
|
+
`NoCoverage` and is not executed. Excluding slow end-to-end or integration
|
|
115
|
+
suites therefore also keeps them out of the baseline run — which matters,
|
|
116
|
+
because a test that never runs against a mutant can never kill one, and the
|
|
117
|
+
baseline suite has a fixed timeout. Lines covered only by excluded tests count
|
|
118
|
+
as uncovered and are not mutated. Excluding every test file aborts with
|
|
119
|
+
`Henitai::ConfigurationError`.
|
|
114
120
|
`mutation.max_log_bytes` is a positive per-stream byte cap for captured child
|
|
115
121
|
output. `mutation.max_timeout` caps auto-calibrated timeouts; an explicit
|
|
116
122
|
`mutation.timeout` still takes precedence. When JSON or HTML reporting is
|
|
@@ -32,11 +32,13 @@ module Henitai
|
|
|
32
32
|
# @param config [Configuration]
|
|
33
33
|
# @param integration [Integration::Base]
|
|
34
34
|
# @param test_files [Array<String>, nil] test files to run; defaults to
|
|
35
|
-
# all files reported by the integration when nil
|
|
35
|
+
# all files reported by the integration when nil.
|
|
36
|
+
# Either way, `config.test_excludes` matches are dropped.
|
|
37
|
+
# @raise [ConfigurationError] when the excludes leave no test file to run
|
|
36
38
|
def ensure!(source_files:, config:, integration:, test_files: nil)
|
|
37
39
|
return if source_files.empty?
|
|
38
40
|
|
|
39
|
-
resolved_test_files = resolve_test_files(integration, test_files)
|
|
41
|
+
resolved_test_files = resolve_test_files(integration, test_files, config)
|
|
40
42
|
|
|
41
43
|
# Skip the bootstrap only when the coverage artifacts are both newer than
|
|
42
44
|
# all watched files and actually cover the configured sources. A fresh
|
|
@@ -225,10 +227,24 @@ module Henitai
|
|
|
225
227
|
Array(source_files) + Array(test_files) + VerdictFingerprint.dependency_files
|
|
226
228
|
end
|
|
227
229
|
|
|
228
|
-
|
|
229
|
-
|
|
230
|
+
# Excluded tests are dropped here rather than in `bootstrap_coverage`, so
|
|
231
|
+
# the same filtered list feeds both the suite run and the freshness watch
|
|
232
|
+
# list: a test that no longer contributes to the baseline must not
|
|
233
|
+
# invalidate it either.
|
|
234
|
+
def resolve_test_files(integration, test_files, config)
|
|
235
|
+
candidates = test_files.nil? ? integration.test_files : test_files
|
|
236
|
+
patterns = configured_test_excludes(config)
|
|
237
|
+
retained = ExcludedTestFilter.new(patterns:).reject(candidates)
|
|
238
|
+
return retained unless retained.empty? && candidates.any?
|
|
239
|
+
|
|
240
|
+
raise ConfigurationError,
|
|
241
|
+
"test_excludes #{Array(patterns).inspect} excludes every test file; " \
|
|
242
|
+
"coverage cannot be generated"
|
|
243
|
+
end
|
|
230
244
|
|
|
231
|
-
|
|
245
|
+
# Specs pass bare config doubles exposing only what the example needs.
|
|
246
|
+
def configured_test_excludes(config)
|
|
247
|
+
config.respond_to?(:test_excludes) ? config.test_excludes : nil
|
|
232
248
|
end
|
|
233
249
|
|
|
234
250
|
def reports_dir(config)
|
|
@@ -71,6 +71,11 @@ module Henitai
|
|
|
71
71
|
env
|
|
72
72
|
end
|
|
73
73
|
|
|
74
|
+
# `pgroup: true` makes the suite child a group leader, so the whole tree
|
|
75
|
+
# it spawns -- a Rails test server, browser drivers -- is signalable as
|
|
76
|
+
# one group. Without it the parent's `kill(:SIGTERM, -pid)` addresses a
|
|
77
|
+
# group that does not exist, raises ESRCH, and leaves a timed-out suite
|
|
78
|
+
# running to completion while the parent has already given up on it.
|
|
74
79
|
def spawn_suite_process(test_files, log_paths)
|
|
75
80
|
FileUtils.mkdir_p(File.dirname(log_paths[:stdout_path]))
|
|
76
81
|
File.open(log_paths[:stdout_path], "w") do |stdout_file|
|
|
@@ -79,16 +84,19 @@ module Henitai
|
|
|
79
84
|
subprocess_env,
|
|
80
85
|
*suite_command(test_files),
|
|
81
86
|
out: stdout_file,
|
|
82
|
-
err: stderr_file
|
|
87
|
+
err: stderr_file,
|
|
88
|
+
pgroup: true
|
|
83
89
|
)
|
|
84
90
|
end
|
|
85
91
|
end
|
|
86
92
|
end
|
|
87
93
|
|
|
94
|
+
# A timeout has already torn the group down and reaped the child in
|
|
95
|
+
# `handle_timeout`; signalling again would only race a recycled pid.
|
|
88
96
|
def cleanup_suite_process(pid, wait_result)
|
|
89
97
|
return unless pid
|
|
90
98
|
|
|
91
|
-
|
|
99
|
+
cleanup_process_group(pid) unless wait_result == :timeout
|
|
92
100
|
reap_child(pid) if wait_result.nil?
|
|
93
101
|
end
|
|
94
102
|
|
data/lib/henitai/version.rb
CHANGED
data/sig/henitai.rbs
CHANGED
|
@@ -1211,6 +1211,8 @@ module Henitai
|
|
|
1211
1211
|
def coverage_fresh?: (Array[String], Configuration, Integration::Base, Array[String]?) -> bool
|
|
1212
1212
|
def coverage_report_path: (Configuration) -> String
|
|
1213
1213
|
def bootstrap_coverage: (Integration::Base, Configuration, ?Array[String]?) -> void
|
|
1214
|
+
def resolve_test_files: (Integration::Base, Array[String]?, Configuration) -> Array[String]
|
|
1215
|
+
def configured_test_excludes: (Configuration) -> Array[String]?
|
|
1214
1216
|
def source_file_paths: (Array[String]) -> Array[String]
|
|
1215
1217
|
end
|
|
1216
1218
|
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: henitai
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.5.
|
|
4
|
+
version: 0.5.3
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Martin Otten
|
|
@@ -13,16 +13,22 @@ dependencies:
|
|
|
13
13
|
name: minitest
|
|
14
14
|
requirement: !ruby/object:Gem::Requirement
|
|
15
15
|
requirements:
|
|
16
|
-
- - "
|
|
16
|
+
- - ">="
|
|
17
17
|
- !ruby/object:Gem::Version
|
|
18
18
|
version: '5.25'
|
|
19
|
+
- - "<"
|
|
20
|
+
- !ruby/object:Gem::Version
|
|
21
|
+
version: '7'
|
|
19
22
|
type: :runtime
|
|
20
23
|
prerelease: false
|
|
21
24
|
version_requirements: !ruby/object:Gem::Requirement
|
|
22
25
|
requirements:
|
|
23
|
-
- - "
|
|
26
|
+
- - ">="
|
|
24
27
|
- !ruby/object:Gem::Version
|
|
25
28
|
version: '5.25'
|
|
29
|
+
- - "<"
|
|
30
|
+
- !ruby/object:Gem::Version
|
|
31
|
+
version: '7'
|
|
26
32
|
- !ruby/object:Gem::Dependency
|
|
27
33
|
name: prism
|
|
28
34
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -246,7 +252,7 @@ metadata:
|
|
|
246
252
|
changelog_uri: https://github.com/martinotten/henitai/blob/main/CHANGELOG.md
|
|
247
253
|
documentation_uri: https://github.com/martinotten/henitai/blob/main/README.md
|
|
248
254
|
homepage_uri: https://github.com/martinotten/henitai
|
|
249
|
-
source_code_uri: https://github.com/martinotten/henitai/tree/v0.5.
|
|
255
|
+
source_code_uri: https://github.com/martinotten/henitai/tree/v0.5.3
|
|
250
256
|
rubygems_mfa_required: 'true'
|
|
251
257
|
rdoc_options: []
|
|
252
258
|
require_paths:
|