henitai 0.5.1 → 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 +75 -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 +2 -2
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,42 @@ 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
|
+
|
|
10
42
|
## [0.5.1] - 2026-08-25
|
|
11
43
|
|
|
12
44
|
### Changed
|
|
45
|
+
|
|
13
46
|
- `minitest` runtime dependency widened from `~> 5.25` to `>= 5.25, < 7`.
|
|
14
47
|
The floor is unchanged; only the ceiling moved. `~> 5.25` capped the
|
|
15
48
|
range below 6.0, so bundles resolving minitest 6.x could not install
|
|
@@ -20,6 +53,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
20
53
|
## [0.5.0] - 2026-08-21
|
|
21
54
|
|
|
22
55
|
### Security
|
|
56
|
+
|
|
23
57
|
- `sqlite3` requirement raised from `~> 1.7` to `>= 2.9.5, < 3`, excluding the
|
|
24
58
|
vulnerable releases up to and including 2.9.4. This is a runtime major bump:
|
|
25
59
|
applications pinned to `sqlite3` 1.x will need to upgrade before installing
|
|
@@ -28,6 +62,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
28
62
|
floors so a regression fails the suite rather than shipping quietly
|
|
29
63
|
|
|
30
64
|
### Changed
|
|
65
|
+
|
|
31
66
|
- `coverage_criteria` now actually affects scoring. The block was documented,
|
|
32
67
|
defaulted and validated since it was introduced, but nothing ever read it —
|
|
33
68
|
`Result` hardcoded the `MS` numerator as `killed + timeout + runtime_error`,
|
|
@@ -50,6 +85,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
50
85
|
4.0-only form), and CI runs the floor alongside 4.0.2
|
|
51
86
|
|
|
52
87
|
### Fixed
|
|
88
|
+
|
|
53
89
|
- Forked mutant children no longer outlive a parent that dies without warning.
|
|
54
90
|
Children run in their own process group, and all parent-side cleanup —
|
|
55
91
|
timeout kills, graceful drain, signal traps — only runs while the parent's
|
|
@@ -84,6 +120,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
84
120
|
0.3.1; this restores it
|
|
85
121
|
|
|
86
122
|
### Internal
|
|
123
|
+
|
|
87
124
|
- Test-suite coupling to private implementation details is now guarded by
|
|
88
125
|
`spec/infra/private_method_reach_spec.rb`, a ratchet: every spec that reaches
|
|
89
126
|
a private method through `send` or an instance-variable poke carries a
|
|
@@ -104,6 +141,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
104
141
|
## [0.4.0] - 2026-07-14
|
|
105
142
|
|
|
106
143
|
### Added
|
|
144
|
+
|
|
107
145
|
- `hard` operator set (`mutation.operators: hard` / `--operators hard`), a
|
|
108
146
|
strict superset of `full` for usually-unkillable mutations (ADR-12):
|
|
109
147
|
currently `EqualityIdentityOperator` and the new `HashKeyType`
|
|
@@ -113,6 +151,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
113
151
|
single-pair hashes and double-splat entries are skipped
|
|
114
152
|
|
|
115
153
|
### Changed
|
|
154
|
+
|
|
116
155
|
- `full` now means "usually killable": the symbol-key -> string-key mutation
|
|
117
156
|
moved from `HashLiteral` into the new hard-set `HashKeyType`, and
|
|
118
157
|
`EqualityIdentityOperator` moved from `full` to `hard` — `full` runs emit
|
|
@@ -121,6 +160,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
121
160
|
## [0.3.1] - 2026-07-13
|
|
122
161
|
|
|
123
162
|
### Fixed
|
|
163
|
+
|
|
124
164
|
- Per-mutant log capture no longer crashes with
|
|
125
165
|
`Encoding::UndefinedConversionError` when the host app sets
|
|
126
166
|
`Encoding.default_internal` (as Rails test environments do) and a child
|
|
@@ -130,6 +170,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
130
170
|
from corrupting the file.
|
|
131
171
|
|
|
132
172
|
### Changed
|
|
173
|
+
|
|
133
174
|
- `--since REF` now includes the working tree: tracked files with
|
|
134
175
|
uncommitted changes and untracked files count as changed, matching what
|
|
135
176
|
actually gets tested. Previously only committed changes in `REF..HEAD`
|
|
@@ -146,6 +187,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
146
187
|
## [0.3.0] - 2026-07-13
|
|
147
188
|
|
|
148
189
|
### Added
|
|
190
|
+
|
|
149
191
|
- `henitai run --incremental`: verdict reuse from the history store. Killed
|
|
150
192
|
verdicts are reused when the subject's source and every covering test file
|
|
151
193
|
are byte-identical to what was recorded; Survived verdicts are additionally
|
|
@@ -181,6 +223,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
181
223
|
moved out of the default light set into its own operator (ADR-10)
|
|
182
224
|
|
|
183
225
|
### Fixed
|
|
226
|
+
|
|
184
227
|
- Mutants in `module_function` modules were unkillable: `module_function`
|
|
185
228
|
copies the method onto the module's singleton and activation only replaced
|
|
186
229
|
the instance side, so callers kept running original code and every such
|
|
@@ -200,6 +243,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
200
243
|
- Flaky-retry counter no longer inflates when a respawned child fails again
|
|
201
244
|
|
|
202
245
|
### Changed
|
|
246
|
+
|
|
203
247
|
- Terminal reporter renders original nodes from their source slice and reuses
|
|
204
248
|
a memoized unparse of the mutated node shared with the JSON reporter
|
|
205
249
|
(a dogfood profile spent 27% of wall time re-unparsing survivors)
|
|
@@ -213,6 +257,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
213
257
|
redefinition warnings into their logs
|
|
214
258
|
|
|
215
259
|
### Internal
|
|
260
|
+
|
|
216
261
|
- Architecture documentation gained §8.11 (incremental verdict reuse) and
|
|
217
262
|
ADR-11 (content-fingerprint verdict reuse, not git scoping); new backlog
|
|
218
263
|
tickets for CI warm verdict cache, child null formatter, and auto-`--since`
|
|
@@ -224,12 +269,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
224
269
|
## [0.2.1] - 2026-06-25
|
|
225
270
|
|
|
226
271
|
### Fixed
|
|
272
|
+
|
|
227
273
|
- `henitai run` now exits 0 when a run evaluates no valid mutants, instead of
|
|
228
274
|
failing a CI gate on a vacuous result
|
|
229
275
|
- Flaky-retry counts are now recorded on the parallel execution path (they were
|
|
230
276
|
always reported as 0 regardless of actual retries)
|
|
231
277
|
|
|
232
278
|
### Changed
|
|
279
|
+
|
|
233
280
|
- `Result` and `Reporter::Json` take their IO as an injected dependency,
|
|
234
281
|
restoring the domain/infrastructure boundary (no public API change)
|
|
235
282
|
- Decomposed the monolithic `integration.rb` into single-responsibility files
|
|
@@ -238,6 +285,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
238
285
|
- Narrowed broad rescues in `safe_unparse` and per-test coverage snapshotting
|
|
239
286
|
|
|
240
287
|
### Internal
|
|
288
|
+
|
|
241
289
|
- De-mocked runner specs, added `process_wakeup` and helper coverage, and
|
|
242
290
|
removed sleep- and chdir-based flakiness from the suite
|
|
243
291
|
- Enabled full-operator dogfooding configuration and isolated the
|
|
@@ -247,6 +295,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
247
295
|
## [0.2.0] - 2026-04-30
|
|
248
296
|
|
|
249
297
|
### Added
|
|
298
|
+
|
|
250
299
|
- `--survivors-from <path>` flag on `henitai run` for survivor-only reruns:
|
|
251
300
|
re-execute only the mutants that survived a prior full run without re-running
|
|
252
301
|
the whole suite
|
|
@@ -281,6 +330,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
281
330
|
- x86_64 platform added to gem platform list
|
|
282
331
|
|
|
283
332
|
### Changed
|
|
333
|
+
|
|
284
334
|
- JSON mutation report vendor extension now always includes `sessionId`
|
|
285
335
|
(and `gitSha` when available) to support survivor-only reruns
|
|
286
336
|
- Terminal reporter labels partial reruns as "Partial survivor rerun" and
|
|
@@ -295,6 +345,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
295
345
|
`max_flaky_retries: 3` added
|
|
296
346
|
|
|
297
347
|
### Fixed
|
|
348
|
+
|
|
298
349
|
- Minitest autorun hook suppressed in mutation child processes to prevent
|
|
299
350
|
spurious re-runs of the full suite inside each fork
|
|
300
351
|
- Coverage bootstrap RSpec subprocess ARGV leakage resolved — child processes
|
|
@@ -307,6 +358,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
307
358
|
preventing stale cache hits after edits
|
|
308
359
|
|
|
309
360
|
### Performance
|
|
361
|
+
|
|
310
362
|
- File discovery cached in the integration layer; repeated calls within one
|
|
311
363
|
run no longer re-scan the filesystem
|
|
312
364
|
- Polling sleep removed from the scheduler hot loop; slots are refilled
|
|
@@ -315,6 +367,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
315
367
|
## [0.1.10] - 2026-04-16
|
|
316
368
|
|
|
317
369
|
### Fixed
|
|
370
|
+
|
|
318
371
|
- RuboCop `RSpec/MultipleExpectations` offenses in `coverage_formatter_spec` and
|
|
319
372
|
`per_test_coverage_collector_spec` resolved by splitting each two-assertion
|
|
320
373
|
example into focused single-expectation examples
|
|
@@ -322,6 +375,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
322
375
|
## [0.1.9] - 2026-04-16
|
|
323
376
|
|
|
324
377
|
### Fixed
|
|
378
|
+
|
|
325
379
|
- SimpleCov is now suppressed during Minitest mutant child runs: `SimpleCov.start`
|
|
326
380
|
is turned into a no-op before test files are required, eliminating the
|
|
327
381
|
"Stopped processing SimpleCov as a previous error has been detected" warning
|
|
@@ -330,12 +384,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
330
384
|
## [0.1.8] - 2026-04-16
|
|
331
385
|
|
|
332
386
|
### Added
|
|
387
|
+
|
|
333
388
|
- Minitest integration now supports per-test coverage: a `MinitestCoverageReporter`
|
|
334
389
|
snapshots `Coverage.peek_result` after each test and writes `henitai_per_test.json`,
|
|
335
390
|
enabling targeted mutation runs that only execute the tests covering the mutated lines —
|
|
336
391
|
the same efficiency that was previously available only to RSpec projects
|
|
337
392
|
|
|
338
393
|
### Fixed
|
|
394
|
+
|
|
339
395
|
- RSpec integration now respects `--exclude-pattern` entries in `.rspec` so excluded
|
|
340
396
|
spec files are not passed to the runner during mutation runs
|
|
341
397
|
- Per-test source file filter corrected to check only the project-relative path prefix
|
|
@@ -345,11 +401,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
345
401
|
## [0.1.7] - 2026-04-14
|
|
346
402
|
|
|
347
403
|
### Added
|
|
404
|
+
|
|
348
405
|
- Committed integration smoke projects for RSpec and Minitest, runnable via
|
|
349
406
|
`bundle exec rake smoke:integration:all`, to exercise `henitai` against
|
|
350
407
|
small real projects that depend on the local source checkout
|
|
351
408
|
|
|
352
409
|
### Fixed
|
|
410
|
+
|
|
353
411
|
- Child-process stdout/stderr restoration after captured test runs now keeps
|
|
354
412
|
the standard streams usable, preventing passing mutant executions from being
|
|
355
413
|
misclassified because the child exited with a closed stdio handle
|
|
@@ -360,6 +418,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
360
418
|
## [0.1.6] - 2026-04-14
|
|
361
419
|
|
|
362
420
|
### Fixed
|
|
421
|
+
|
|
363
422
|
- Minitest is no longer required eagerly when `henitai/integration` loads, so
|
|
364
423
|
projects that do not include Minitest in their bundle can still boot and use
|
|
365
424
|
non-Minitest integrations without a parent-process `LoadError`
|
|
@@ -367,6 +426,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
367
426
|
## [0.1.5] - 2026-04-14
|
|
368
427
|
|
|
369
428
|
### Fixed
|
|
429
|
+
|
|
370
430
|
- Steep type errors in `Runner` after removing targeted-run bootstrap scoping:
|
|
371
431
|
updated `bootstrap_mutants` RBS signature to match the new single-argument
|
|
372
432
|
form and removed stale signatures for `refresh_coverage_for_targeted_run`,
|
|
@@ -375,6 +435,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
375
435
|
workspace setup and report writing into helper methods
|
|
376
436
|
|
|
377
437
|
### Changed
|
|
438
|
+
|
|
378
439
|
- Targeted-run coverage bootstrap no longer scopes the initial run to the
|
|
379
440
|
subject's test files; the full suite is always used for the baseline,
|
|
380
441
|
trading a minor performance optimisation for reliability
|
|
@@ -382,6 +443,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
382
443
|
## [0.1.4] - 2026-04-14
|
|
383
444
|
|
|
384
445
|
### Fixed
|
|
446
|
+
|
|
385
447
|
- `StringLiteral` operator no longer generates no-op mutations where the
|
|
386
448
|
replacement equals the original value (e.g. the spurious `"" → ""` mutant
|
|
387
449
|
that was emitted for methods already returning an empty string literal)
|
|
@@ -397,6 +459,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
397
459
|
runner's configured reports directory
|
|
398
460
|
|
|
399
461
|
### Changed
|
|
462
|
+
|
|
400
463
|
- `ScenarioExecutionResult.build` factory method consolidates status and
|
|
401
464
|
exit-status derivation that was previously spread across `Integration`,
|
|
402
465
|
reducing the mutation surface of the value object
|
|
@@ -404,6 +467,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
404
467
|
## [0.1.3] - 2026-04-13
|
|
405
468
|
|
|
406
469
|
### Added
|
|
470
|
+
|
|
407
471
|
- Four new mutation operators: `UnaryOperator` (negates boolean and numeric
|
|
408
472
|
unary expressions), `UpdateOperator` (swaps `+=`/`-=`/`*=` and targets
|
|
409
473
|
compound-assignment nodes), `RegexMutator` (replaces regex literals with
|
|
@@ -422,6 +486,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
422
486
|
`x || false`, `true && x`, `x && true` are suppressed as equivalent mutants
|
|
423
487
|
|
|
424
488
|
### Changed
|
|
489
|
+
|
|
425
490
|
- Per-line mutation cap (`max_mutants_per_line`) removed from the generator,
|
|
426
491
|
configuration schema, and validator — see ADR-08. All syntactically valid
|
|
427
492
|
mutations on a line are now generated unconditionally
|
|
@@ -436,6 +501,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
436
501
|
without reflection
|
|
437
502
|
|
|
438
503
|
### Performance
|
|
504
|
+
|
|
439
505
|
- Coverage bootstrap freshness check: the baseline RSpec run is skipped when
|
|
440
506
|
`.resultset.json` is newer than every watched source and test file,
|
|
441
507
|
eliminating ~83 % of bootstrap wall time on repeated runs within a session
|
|
@@ -457,6 +523,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
457
523
|
AST node
|
|
458
524
|
|
|
459
525
|
### Fixed
|
|
526
|
+
|
|
460
527
|
- Mutant child processes now run in isolated process groups (`setpgid`);
|
|
461
528
|
`cleanup_process_group` sends `SIGTERM` to the entire group on timeout or
|
|
462
529
|
error, preventing orphaned subprocesses
|
|
@@ -472,10 +539,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
472
539
|
## [0.1.2] - 2026-04-07
|
|
473
540
|
|
|
474
541
|
### Added
|
|
542
|
+
|
|
475
543
|
- Method coverage is now enabled in both RSpec and Minitest bootstraps, and
|
|
476
544
|
the static filter merges method-level coverage into the line map
|
|
477
545
|
|
|
478
546
|
### Fixed
|
|
547
|
+
|
|
479
548
|
- Coverage baseline regeneration now happens on every `henitai run`, so stale
|
|
480
549
|
coverage state does not leak between runs
|
|
481
550
|
- Coverage handling now accepts symbol-keyed `Coverage.peek_result` output and
|
|
@@ -492,6 +561,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
492
561
|
## [0.1.1] - 2026-04-03
|
|
493
562
|
|
|
494
563
|
### Added
|
|
564
|
+
|
|
495
565
|
- Minitest integration for Rails projects: injects SimpleCov for coverage
|
|
496
566
|
collection, sets `RAILS_ENV=test` and `PARALLEL_WORKERS=1` in the baseline
|
|
497
567
|
subprocess, preloads `config/environment.rb` before mutant activation, adds
|
|
@@ -499,6 +569,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
499
569
|
- `simplecov` runtime dependency (required by the Minitest integration)
|
|
500
570
|
|
|
501
571
|
### Fixed
|
|
572
|
+
|
|
502
573
|
- `rspec/core` was unconditionally required at load time, causing a `LoadError`
|
|
503
574
|
in projects that do not have RSpec installed — now loaded lazily only when the
|
|
504
575
|
RSpec integration is used
|
|
@@ -508,6 +579,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
508
579
|
## [0.1.0] - 2026-03-01
|
|
509
580
|
|
|
510
581
|
### Added
|
|
582
|
+
|
|
511
583
|
- Initial gem scaffold with Ruby 4.0.2 support
|
|
512
584
|
- Dev Container configuration (official `ruby:4.0.2-alpine` base image, Codex CLI preinstalled)
|
|
513
585
|
- CI pipeline (RuboCop + RSpec + incremental mutation testing on PRs)
|
|
@@ -516,7 +588,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
516
588
|
- CLI critical path: `henitai run` now executes the full pipeline, supports `--since`, returns CI-friendly exit codes, and `henitai version` prints `Henitai::VERSION`
|
|
517
589
|
- RSpec per-test coverage output: `henitai/coverage_formatter` now writes `coverage/henitai_per_test.json`
|
|
518
590
|
|
|
519
|
-
[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
|
|
520
594
|
[0.5.1]: https://github.com/martinotten/henitai/compare/v0.5.0...v0.5.1
|
|
521
595
|
[0.5.0]: https://github.com/martinotten/henitai/compare/v0.4.0...v0.5.0
|
|
522
596
|
[0.4.0]: https://github.com/martinotten/henitai/compare/v0.3.1...v0.4.0
|
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
|
|
@@ -252,7 +252,7 @@ metadata:
|
|
|
252
252
|
changelog_uri: https://github.com/martinotten/henitai/blob/main/CHANGELOG.md
|
|
253
253
|
documentation_uri: https://github.com/martinotten/henitai/blob/main/README.md
|
|
254
254
|
homepage_uri: https://github.com/martinotten/henitai
|
|
255
|
-
source_code_uri: https://github.com/martinotten/henitai/tree/v0.5.
|
|
255
|
+
source_code_uri: https://github.com/martinotten/henitai/tree/v0.5.3
|
|
256
256
|
rubygems_mfa_required: 'true'
|
|
257
257
|
rdoc_options: []
|
|
258
258
|
require_paths:
|