evilution 0.28.0 → 0.29.0
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/.beads/interactions.jsonl +52 -0
- data/CHANGELOG.md +7 -0
- data/lib/evilution/ast/constant_names.rb +28 -11
- data/lib/evilution/ast/pattern/parser.rb +29 -17
- data/lib/evilution/cli/commands/session_diff.rb +6 -4
- data/lib/evilution/cli/commands/subjects.rb +6 -3
- data/lib/evilution/cli/commands/util_mutation.rb +24 -19
- data/lib/evilution/cli/parser/command_extractor.rb +9 -11
- data/lib/evilution/cli/parser/file_args.rb +3 -1
- data/lib/evilution/cli/parser/options_builder.rb +29 -1
- data/lib/evilution/cli/parser/stdin_reader.rb +2 -2
- data/lib/evilution/cli/parser.rb +18 -20
- data/lib/evilution/cli/printers/environment.rb +19 -19
- data/lib/evilution/cli/printers/session_diff.rb +8 -8
- data/lib/evilution/compare/normalizer.rb +10 -5
- data/lib/evilution/config.rb +10 -10
- data/lib/evilution/disable_comment.rb +21 -12
- data/lib/evilution/integration/loading/mutation_applier.rb +17 -12
- data/lib/evilution/integration/minitest.rb +25 -16
- data/lib/evilution/integration/rspec.rb +4 -0
- data/lib/evilution/isolation/fork.rb +27 -17
- data/lib/evilution/mcp/info_tool/actions/subjects.rb +32 -23
- data/lib/evilution/mcp/info_tool/actions/tests.rb +22 -12
- data/lib/evilution/mcp/info_tool/request_parser.rb +3 -1
- data/lib/evilution/mcp/info_tool.rb +7 -1
- data/lib/evilution/mcp/mutate_tool/option_parser.rb +3 -1
- data/lib/evilution/mcp/mutate_tool/survived_enricher.rb +19 -9
- data/lib/evilution/mcp/mutate_tool.rb +27 -14
- data/lib/evilution/mcp/session_tool.rb +27 -18
- data/lib/evilution/mutation.rb +13 -15
- data/lib/evilution/mutator/base.rb +17 -15
- data/lib/evilution/mutator/operator/argument_nil_substitution.rb +11 -14
- data/lib/evilution/mutator/operator/argument_removal.rb +11 -14
- data/lib/evilution/mutator/operator/begin_unwrap.rb +17 -5
- data/lib/evilution/mutator/operator/bitwise_complement.rb +26 -19
- data/lib/evilution/mutator/operator/block_param_removal.rb +18 -8
- data/lib/evilution/mutator/operator/block_pass_removal.rb +19 -15
- data/lib/evilution/mutator/operator/case_when.rb +7 -5
- data/lib/evilution/mutator/operator/conditional_branch.rb +22 -22
- data/lib/evilution/mutator/operator/equality_to_identity.rb +8 -3
- data/lib/evilution/mutator/operator/explicit_super_mutation.rb +17 -13
- data/lib/evilution/mutator/operator/index_to_at.rb +5 -4
- data/lib/evilution/mutator/operator/index_to_dig.rb +12 -6
- data/lib/evilution/mutator/operator/index_to_fetch.rb +5 -4
- data/lib/evilution/mutator/operator/keyword_argument.rb +30 -25
- data/lib/evilution/mutator/operator/mixin_removal.rb +20 -14
- data/lib/evilution/mutator/operator/multiple_assignment.rb +12 -13
- data/lib/evilution/mutator/operator/receiver_replacement.rb +9 -6
- data/lib/evilution/mutator/operator/regex_simplification.rb +62 -67
- data/lib/evilution/mutator/operator/rescue_body_replacement.rb +9 -8
- data/lib/evilution/mutator/operator/rescue_removal.rb +4 -7
- data/lib/evilution/mutator/operator/superclass_removal.rb +21 -15
- data/lib/evilution/parallel/work_queue/dispatcher.rb +15 -8
- data/lib/evilution/parallel/work_queue/worker.rb +10 -7
- data/lib/evilution/parallel/work_queue.rb +35 -18
- data/lib/evilution/reporter/cli/item_formatters/coverage_gap.rb +13 -8
- data/lib/evilution/reporter/cli/line_formatters/mutations.rb +17 -8
- data/lib/evilution/reporter/json.rb +52 -18
- data/lib/evilution/reporter/suggestion/diff_helpers.rb +0 -13
- data/lib/evilution/reporter/suggestion/diff_lines.rb +28 -0
- data/lib/evilution/reporter/suggestion/templates/minitest.rb +20 -14
- data/lib/evilution/reporter/suggestion/templates/rspec.rb +19 -13
- data/lib/evilution/runner/baseline_runner.rb +15 -8
- data/lib/evilution/runner/diagnostics.rb +13 -9
- data/lib/evilution/runner/isolation_resolver.rb +11 -9
- data/lib/evilution/runner/mutation_executor/result_cache.rb +3 -1
- data/lib/evilution/runner/mutation_executor/strategy/parallel.rb +32 -10
- data/lib/evilution/runner/mutation_executor/strategy/sequential.rb +1 -1
- data/lib/evilution/runner/mutation_executor.rb +2 -0
- data/lib/evilution/runner/mutation_planner.rb +37 -17
- data/lib/evilution/runner/subject_pipeline.rb +21 -11
- data/lib/evilution/runner.rb +3 -3
- data/lib/evilution/session/diff.rb +15 -6
- data/lib/evilution/spec_ast_cache.rb +26 -12
- data/lib/evilution/version.rb +1 -1
- data/script/memory_check +11 -5
- data/scripts/benchmark_density +10 -9
- data/scripts/compare_mutations +38 -21
- data/scripts/mutant_json_adapter +7 -4
- metadata +3 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 607074e45fead28ec35facc8fadadbb44e0dc6429ee00ef37edf92145bc4b7fc
|
|
4
|
+
data.tar.gz: 3bc840215dff4272ea6da9aad5ebed982827507f765c6cadc444bd1f3fb63ddc
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 5febff050f2670b2ab5f1cbeac9bfc41b0f30edc3e5ee39591036da0ef9ccf5d1273c0abe0cc828d289a959c2e135adb348980882a931d263df65e4b8a4e2299
|
|
7
|
+
data.tar.gz: 1f0d38cab915255ce1742350255cce291fd9c6e3bbdc649af778750089ca9b219c7f2553d1de40c6b2ac72b128310c56d7fff3ecc99ee2c14db42680dd0f3b2b
|
data/.beads/interactions.jsonl
CHANGED
|
@@ -258,3 +258,55 @@
|
|
|
258
258
|
{"id":"int-b9cb7738","kind":"field_change","created_at":"2026-05-01T18:06:39.17748775Z","actor":"Denis Kiselev","issue_id":"EV-gffv","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"merged"}}
|
|
259
259
|
{"id":"int-983c2fe6","kind":"field_change","created_at":"2026-05-02T02:47:27.113692488Z","actor":"Denis Kiselev","issue_id":"EV-3t8l","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"Audit confirmed feature already fully implemented in current master: --fail-fast CLI flag, .evilution.yml key, FailFast validator, ResultNotifier trips at threshold, sequential+parallel strategies short-circuit, summary.truncated? indicator, reporter notices (CLI/HTML/JSON), full spec coverage across notifier/sequential/parallel/runner/parser. CI signal available via summary.truncated? in reports."}}
|
|
260
260
|
{"id":"int-1790a8b7","kind":"field_change","created_at":"2026-05-02T17:53:56.73309749Z","actor":"Denis Kiselev","issue_id":"EV-2gpj","extra":{"field":"status","new_value":"closed","old_value":"in_progress","reason":"Audit confirmed refactor already done: ProcessCleanup.safe_kill / safe_wait helpers extracted to lib/evilution/process_cleanup.rb (lines 8-18), used by baseline.rb (lines 85,93,94) and parallel/work_queue/worker.rb. No Style/RescueModifier disables remain anywhere in lib/. bundle exec rubocop lib/evilution/baseline.rb clean. Existing specs pass."}}
|
|
261
|
+
{"id":"int-a4ad60a6","kind":"field_change","created_at":"2026-05-06T03:30:34.744627494Z","actor":"Denis Kiselev","issue_id":"EV-s24s","extra":{"field":"status","new_value":"closed","old_value":"open","reason":"Closed"}}
|
|
262
|
+
{"id":"int-076a3c83","kind":"field_change","created_at":"2026-05-06T03:30:41.864846348Z","actor":"Denis Kiselev","issue_id":"EV-s24s","extra":{"field":"status","new_value":"in_progress","old_value":"closed"}}
|
|
263
|
+
{"id":"int-01566863","kind":"field_change","created_at":"2026-05-06T07:19:50.242235949Z","actor":"Denis Kiselev","issue_id":"EV-y27w","extra":{"field":"status","new_value":"closed","old_value":"open","reason":"Obsolete: methods refactored on master (commit c6177ee). Rubocop ABC clean for these files."}}
|
|
264
|
+
{"id":"int-2ead0736","kind":"field_change","created_at":"2026-05-06T07:19:50.702277885Z","actor":"Denis Kiselev","issue_id":"EV-2luk","extra":{"field":"status","new_value":"closed","old_value":"open","reason":"Obsolete: methods refactored on master (commit c6177ee). Rubocop ABC clean for these files."}}
|
|
265
|
+
{"id":"int-57a7f7bd","kind":"field_change","created_at":"2026-05-06T07:19:51.207502619Z","actor":"Denis Kiselev","issue_id":"EV-6pj3","extra":{"field":"status","new_value":"closed","old_value":"open","reason":"Obsolete: methods refactored on master (commit c6177ee). Rubocop ABC clean for these files."}}
|
|
266
|
+
{"id":"int-6c362b36","kind":"field_change","created_at":"2026-05-06T07:19:51.688513357Z","actor":"Denis Kiselev","issue_id":"EV-675y","extra":{"field":"status","new_value":"closed","old_value":"open","reason":"Obsolete: methods refactored on master (commit c6177ee). Rubocop ABC clean for these files."}}
|
|
267
|
+
{"id":"int-5debf846","kind":"field_change","created_at":"2026-05-06T07:19:52.17818897Z","actor":"Denis Kiselev","issue_id":"EV-g8pq","extra":{"field":"status","new_value":"closed","old_value":"open","reason":"Obsolete: methods refactored on master (commit c6177ee). Rubocop ABC clean for these files."}}
|
|
268
|
+
{"id":"int-53e2ac7d","kind":"field_change","created_at":"2026-05-06T07:19:52.618140112Z","actor":"Denis Kiselev","issue_id":"EV-7wi7","extra":{"field":"status","new_value":"closed","old_value":"open","reason":"Obsolete: methods refactored on master (commit c6177ee). Rubocop ABC clean for these files."}}
|
|
269
|
+
{"id":"int-dccffc47","kind":"field_change","created_at":"2026-05-06T07:19:53.069605194Z","actor":"Denis Kiselev","issue_id":"EV-cz6e","extra":{"field":"status","new_value":"closed","old_value":"open","reason":"Obsolete: methods refactored on master (commit c6177ee). Rubocop ABC clean for these files."}}
|
|
270
|
+
{"id":"int-58d8260f","kind":"field_change","created_at":"2026-05-06T07:19:53.543437653Z","actor":"Denis Kiselev","issue_id":"EV-rmzx","extra":{"field":"status","new_value":"closed","old_value":"open","reason":"Obsolete: methods refactored on master (commit c6177ee). Rubocop ABC clean for these files."}}
|
|
271
|
+
{"id":"int-789dee22","kind":"field_change","created_at":"2026-05-06T07:19:53.965510546Z","actor":"Denis Kiselev","issue_id":"EV-5qg6","extra":{"field":"status","new_value":"closed","old_value":"open","reason":"Obsolete: methods refactored on master (commit c6177ee). Rubocop ABC clean for these files."}}
|
|
272
|
+
{"id":"int-85fdbe1f","kind":"field_change","created_at":"2026-05-06T07:19:54.37777323Z","actor":"Denis Kiselev","issue_id":"EV-pfz5","extra":{"field":"status","new_value":"closed","old_value":"open","reason":"Obsolete: methods refactored on master (commit c6177ee). Rubocop ABC clean for these files."}}
|
|
273
|
+
{"id":"int-c61f5bf7","kind":"field_change","created_at":"2026-05-06T07:19:54.831384506Z","actor":"Denis Kiselev","issue_id":"EV-ynvi","extra":{"field":"status","new_value":"closed","old_value":"open","reason":"Obsolete: methods refactored on master (commit c6177ee). Rubocop ABC clean for these files."}}
|
|
274
|
+
{"id":"int-f66ee100","kind":"field_change","created_at":"2026-05-06T07:19:55.253094559Z","actor":"Denis Kiselev","issue_id":"EV-ltmi","extra":{"field":"status","new_value":"closed","old_value":"open","reason":"Obsolete: methods refactored on master (commit c6177ee). Rubocop ABC clean for these files."}}
|
|
275
|
+
{"id":"int-d0d38103","kind":"field_change","created_at":"2026-05-06T07:19:55.730451387Z","actor":"Denis Kiselev","issue_id":"EV-dha6","extra":{"field":"status","new_value":"closed","old_value":"open","reason":"Obsolete: methods refactored on master (commit c6177ee). Rubocop ABC clean for these files."}}
|
|
276
|
+
{"id":"int-14872708","kind":"field_change","created_at":"2026-05-06T07:19:56.276618255Z","actor":"Denis Kiselev","issue_id":"EV-gml5","extra":{"field":"status","new_value":"closed","old_value":"open","reason":"Obsolete: methods refactored on master (commit c6177ee). Rubocop ABC clean for these files."}}
|
|
277
|
+
{"id":"int-3a46d2c8","kind":"field_change","created_at":"2026-05-06T07:19:56.746453231Z","actor":"Denis Kiselev","issue_id":"EV-wg1v","extra":{"field":"status","new_value":"closed","old_value":"open","reason":"Obsolete: methods refactored on master (commit c6177ee). Rubocop ABC clean for these files."}}
|
|
278
|
+
{"id":"int-7e6cad25","kind":"field_change","created_at":"2026-05-06T07:19:57.199497315Z","actor":"Denis Kiselev","issue_id":"EV-jf8v","extra":{"field":"status","new_value":"closed","old_value":"open","reason":"Obsolete: methods refactored on master (commit c6177ee). Rubocop ABC clean for these files."}}
|
|
279
|
+
{"id":"int-596241e1","kind":"field_change","created_at":"2026-05-06T07:19:57.648508843Z","actor":"Denis Kiselev","issue_id":"EV-p699","extra":{"field":"status","new_value":"closed","old_value":"open","reason":"Obsolete: methods refactored on master (commit c6177ee). Rubocop ABC clean for these files."}}
|
|
280
|
+
{"id":"int-47d13782","kind":"field_change","created_at":"2026-05-06T07:19:58.119871705Z","actor":"Denis Kiselev","issue_id":"EV-mur2","extra":{"field":"status","new_value":"closed","old_value":"open","reason":"Obsolete: methods refactored on master (commit c6177ee). Rubocop ABC clean for these files."}}
|
|
281
|
+
{"id":"int-5bcb3ba0","kind":"field_change","created_at":"2026-05-06T07:19:58.593580083Z","actor":"Denis Kiselev","issue_id":"EV-t05i","extra":{"field":"status","new_value":"closed","old_value":"open","reason":"Obsolete: methods refactored on master (commit c6177ee). Rubocop ABC clean for these files."}}
|
|
282
|
+
{"id":"int-d0a8a49b","kind":"field_change","created_at":"2026-05-06T07:19:59.066030169Z","actor":"Denis Kiselev","issue_id":"EV-t3os","extra":{"field":"status","new_value":"closed","old_value":"open","reason":"Obsolete: methods refactored on master (commit c6177ee). Rubocop ABC clean for these files."}}
|
|
283
|
+
{"id":"int-c5fd767e","kind":"field_change","created_at":"2026-05-06T07:19:59.519830731Z","actor":"Denis Kiselev","issue_id":"EV-70v7","extra":{"field":"status","new_value":"closed","old_value":"open","reason":"Obsolete: methods refactored on master (commit c6177ee). Rubocop ABC clean for these files."}}
|
|
284
|
+
{"id":"int-ee96343f","kind":"field_change","created_at":"2026-05-06T07:19:59.945079843Z","actor":"Denis Kiselev","issue_id":"EV-g067","extra":{"field":"status","new_value":"closed","old_value":"open","reason":"Obsolete: methods refactored on master (commit c6177ee). Rubocop ABC clean for these files."}}
|
|
285
|
+
{"id":"int-1088cf0f","kind":"field_change","created_at":"2026-05-06T07:20:00.369713429Z","actor":"Denis Kiselev","issue_id":"EV-vybg","extra":{"field":"status","new_value":"closed","old_value":"open","reason":"Obsolete: methods refactored on master (commit c6177ee). Rubocop ABC clean for these files."}}
|
|
286
|
+
{"id":"int-677bcb4c","kind":"field_change","created_at":"2026-05-06T07:20:00.849595223Z","actor":"Denis Kiselev","issue_id":"EV-b2j8","extra":{"field":"status","new_value":"closed","old_value":"open","reason":"Obsolete: methods refactored on master (commit c6177ee). Rubocop ABC clean for these files."}}
|
|
287
|
+
{"id":"int-49853be8","kind":"field_change","created_at":"2026-05-06T07:20:01.309796737Z","actor":"Denis Kiselev","issue_id":"EV-jxio","extra":{"field":"status","new_value":"closed","old_value":"open","reason":"Obsolete: methods refactored on master (commit c6177ee). Rubocop ABC clean for these files."}}
|
|
288
|
+
{"id":"int-7d1d715d","kind":"field_change","created_at":"2026-05-06T07:20:01.802408893Z","actor":"Denis Kiselev","issue_id":"EV-v1df","extra":{"field":"status","new_value":"closed","old_value":"open","reason":"Obsolete: methods refactored on master (commit c6177ee). Rubocop ABC clean for these files."}}
|
|
289
|
+
{"id":"int-f8751a4f","kind":"field_change","created_at":"2026-05-06T07:20:02.269343453Z","actor":"Denis Kiselev","issue_id":"EV-05x3","extra":{"field":"status","new_value":"closed","old_value":"open","reason":"Obsolete: methods refactored on master (commit c6177ee). Rubocop ABC clean for these files."}}
|
|
290
|
+
{"id":"int-98efe12b","kind":"field_change","created_at":"2026-05-06T07:20:02.712854653Z","actor":"Denis Kiselev","issue_id":"EV-neqr","extra":{"field":"status","new_value":"closed","old_value":"open","reason":"Obsolete: methods refactored on master (commit c6177ee). Rubocop ABC clean for these files."}}
|
|
291
|
+
{"id":"int-2fab6f44","kind":"field_change","created_at":"2026-05-06T07:20:03.192828055Z","actor":"Denis Kiselev","issue_id":"EV-ugrl","extra":{"field":"status","new_value":"closed","old_value":"open","reason":"Obsolete: methods refactored on master (commit c6177ee). Rubocop ABC clean for these files."}}
|
|
292
|
+
{"id":"int-64c45537","kind":"field_change","created_at":"2026-05-06T07:20:03.645870239Z","actor":"Denis Kiselev","issue_id":"EV-1czz","extra":{"field":"status","new_value":"closed","old_value":"open","reason":"Obsolete: methods refactored on master (commit c6177ee). Rubocop ABC clean for these files."}}
|
|
293
|
+
{"id":"int-b226aaaa","kind":"field_change","created_at":"2026-05-06T07:20:04.115581656Z","actor":"Denis Kiselev","issue_id":"EV-nsp3","extra":{"field":"status","new_value":"closed","old_value":"open","reason":"Obsolete: methods refactored on master (commit c6177ee). Rubocop ABC clean for these files."}}
|
|
294
|
+
{"id":"int-40a144bf","kind":"field_change","created_at":"2026-05-06T07:20:04.57274421Z","actor":"Denis Kiselev","issue_id":"EV-bx35","extra":{"field":"status","new_value":"closed","old_value":"open","reason":"Obsolete: methods refactored on master (commit c6177ee). Rubocop ABC clean for these files."}}
|
|
295
|
+
{"id":"int-bb3376cc","kind":"field_change","created_at":"2026-05-06T07:20:05.130537402Z","actor":"Denis Kiselev","issue_id":"EV-2viy","extra":{"field":"status","new_value":"closed","old_value":"open","reason":"Obsolete: methods refactored on master (commit c6177ee). Rubocop ABC clean for these files."}}
|
|
296
|
+
{"id":"int-6ae5b449","kind":"field_change","created_at":"2026-05-06T07:20:05.597150157Z","actor":"Denis Kiselev","issue_id":"EV-0nre","extra":{"field":"status","new_value":"closed","old_value":"open","reason":"Obsolete: methods refactored on master (commit c6177ee). Rubocop ABC clean for these files."}}
|
|
297
|
+
{"id":"int-f37c08ed","kind":"field_change","created_at":"2026-05-06T07:20:06.22033588Z","actor":"Denis Kiselev","issue_id":"EV-n4ai","extra":{"field":"status","new_value":"closed","old_value":"open","reason":"Obsolete: methods refactored on master (commit c6177ee). Rubocop ABC clean for these files."}}
|
|
298
|
+
{"id":"int-f1cc76b6","kind":"field_change","created_at":"2026-05-06T07:20:06.659235495Z","actor":"Denis Kiselev","issue_id":"EV-oyus","extra":{"field":"status","new_value":"closed","old_value":"open","reason":"Obsolete: methods refactored on master (commit c6177ee). Rubocop ABC clean for these files."}}
|
|
299
|
+
{"id":"int-7d54a6e7","kind":"field_change","created_at":"2026-05-06T07:20:07.091511841Z","actor":"Denis Kiselev","issue_id":"EV-h46p","extra":{"field":"status","new_value":"closed","old_value":"open","reason":"Obsolete: methods refactored on master (commit c6177ee). Rubocop ABC clean for these files."}}
|
|
300
|
+
{"id":"int-2bea4b64","kind":"field_change","created_at":"2026-05-06T07:20:06.87585377Z","actor":"Denis Kiselev","issue_id":"EV-n05g","extra":{"field":"status","new_value":"closed","old_value":"open","reason":"Obsolete: methods refactored on master (commit c6177ee). Rubocop ABC clean for these files."}}
|
|
301
|
+
{"id":"int-3b25e06c","kind":"field_change","created_at":"2026-05-06T07:20:06.448623384Z","actor":"Denis Kiselev","issue_id":"EV-htfi","extra":{"field":"status","new_value":"closed","old_value":"open","reason":"Obsolete: methods refactored on master (commit c6177ee). Rubocop ABC clean for these files."}}
|
|
302
|
+
{"id":"int-9fedcb1f","kind":"field_change","created_at":"2026-05-06T07:20:06.870511987Z","actor":"Denis Kiselev","issue_id":"EV-86au","extra":{"field":"status","new_value":"closed","old_value":"open","reason":"Obsolete: methods refactored on master (commit c6177ee). Rubocop ABC clean for these files."}}
|
|
303
|
+
{"id":"int-55d2834d","kind":"field_change","created_at":"2026-05-06T07:20:07.313207411Z","actor":"Denis Kiselev","issue_id":"EV-fyq8","extra":{"field":"status","new_value":"closed","old_value":"open","reason":"Obsolete: methods refactored on master (commit c6177ee). Rubocop ABC clean for these files."}}
|
|
304
|
+
{"id":"int-44442358","kind":"field_change","created_at":"2026-05-06T07:20:07.761317317Z","actor":"Denis Kiselev","issue_id":"EV-jxr1","extra":{"field":"status","new_value":"closed","old_value":"open","reason":"Obsolete: methods refactored on master (commit c6177ee). Rubocop ABC clean for these files."}}
|
|
305
|
+
{"id":"int-1ec5b145","kind":"field_change","created_at":"2026-05-06T07:20:08.263779524Z","actor":"Denis Kiselev","issue_id":"EV-0lhb","extra":{"field":"status","new_value":"closed","old_value":"open","reason":"Obsolete: methods refactored on master (commit c6177ee). Rubocop ABC clean for these files."}}
|
|
306
|
+
{"id":"int-3177494f","kind":"field_change","created_at":"2026-05-06T07:20:08.690447157Z","actor":"Denis Kiselev","issue_id":"EV-6xeh","extra":{"field":"status","new_value":"closed","old_value":"open","reason":"Obsolete: methods refactored on master (commit c6177ee). Rubocop ABC clean for these files."}}
|
|
307
|
+
{"id":"int-c3e862ed","kind":"field_change","created_at":"2026-05-06T07:20:09.150754493Z","actor":"Denis Kiselev","issue_id":"EV-n5vx","extra":{"field":"status","new_value":"closed","old_value":"open","reason":"Obsolete: methods refactored on master (commit c6177ee). Rubocop ABC clean for these files."}}
|
|
308
|
+
{"id":"int-bbb95b03","kind":"field_change","created_at":"2026-05-06T07:20:09.610416065Z","actor":"Denis Kiselev","issue_id":"EV-pbo4","extra":{"field":"status","new_value":"closed","old_value":"open","reason":"Obsolete: methods refactored on master (commit c6177ee). Rubocop ABC clean for these files."}}
|
|
309
|
+
{"id":"int-42dadd38","kind":"field_change","created_at":"2026-05-06T07:20:10.034048271Z","actor":"Denis Kiselev","issue_id":"EV-45kf","extra":{"field":"status","new_value":"closed","old_value":"open","reason":"Obsolete: methods refactored on master (commit c6177ee). Rubocop ABC clean for these files."}}
|
|
310
|
+
{"id":"int-2973ca4f","kind":"field_change","created_at":"2026-05-06T07:20:10.503854404Z","actor":"Denis Kiselev","issue_id":"EV-t2o9","extra":{"field":"status","new_value":"closed","old_value":"open","reason":"Obsolete: methods refactored on master (commit c6177ee). Rubocop ABC clean for these files."}}
|
|
311
|
+
{"id":"int-523d3c8c","kind":"field_change","created_at":"2026-05-06T07:20:11.036667234Z","actor":"Denis Kiselev","issue_id":"EV-qtvs","extra":{"field":"status","new_value":"closed","old_value":"open","reason":"Obsolete: methods refactored on master (commit c6177ee). Rubocop ABC clean for these files."}}
|
|
312
|
+
{"id":"int-be905e1b","kind":"field_change","created_at":"2026-05-06T07:20:11.472283074Z","actor":"Denis Kiselev","issue_id":"EV-psit","extra":{"field":"status","new_value":"closed","old_value":"open","reason":"Obsolete: methods refactored on master (commit c6177ee). Rubocop ABC clean for these files."}}
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.29.0] - 2026-05-06
|
|
4
|
+
|
|
5
|
+
### Changed
|
|
6
|
+
|
|
7
|
+
- **Internal codebase hygiene sweep — `Metrics/AbcSize` ceiling tightened from `25` → `17`** — every method exceeding the new threshold was refactored via pure extract-method (no behavior change). ~48 sites across `lib/evilution/{ast,cli,compare,config,disable_comment,integration,mcp,mutation,mutator,parallel,reporter,runner,session,spec_ast_cache}` plus supporting `scripts/` utilities. No public API, CLI flag, or output changes; mutation operators and report emission are bit-identical. The upper bound on per-method ABC is now strictly enforced repo-wide — only `lib/evilution/runner.rb` remains in `.rubocop_todo.yml` (#371, PR #1160 + per-file sub-PRs)
|
|
8
|
+
- **Tuple-return methods across the runner pipeline migrated to named `Data.define` value objects** — internal-only refactor introducing typed return shapes for `Runner::MutationExecutor#call` (→`ExecutionResult`), `Runner::MutationPlanner#call` (→`Plan` plus internal `GenerationResult` / `DisabledFilterResult` / `SigFilterResult` / `EquivalentFilterResult`), `Parallel::WorkQueue` outputs, `Cache#partition` (→`Partition`), `Config.normalize_limit` (→`LimitResult`), `Mutation::Slicer.collect_chain` (→`Chain`), `slice_affected_lines` (→`AffectedSlices`), `CLI::Parser::FilesAndRanges` (→`ParsedPaths`), and assorted CLI command helpers. Improves call-site readability without affecting external behavior (#948, PR #1094; #949, PR #1095; #950, PR #1096; #951, PR #1097; #952, PR #1098; #953, PR #1099; #954, PR #1100; #955, PR #1101; #956, PR #1102)
|
|
9
|
+
|
|
3
10
|
## [0.28.0] - 2026-05-03
|
|
4
11
|
|
|
5
12
|
### Added
|
|
@@ -17,18 +17,35 @@ class Evilution::AST::ConstantNames
|
|
|
17
17
|
private
|
|
18
18
|
|
|
19
19
|
def collect(node, nesting = [])
|
|
20
|
-
names = []
|
|
21
20
|
case node
|
|
22
|
-
when Prism::ModuleNode, Prism::ClassNode
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
names.concat(collect(node.body, nesting + [const])) if node.body
|
|
27
|
-
when Prism::ProgramNode
|
|
28
|
-
names.concat(collect(node.statements, nesting)) if node.statements
|
|
29
|
-
when Prism::StatementsNode
|
|
30
|
-
node.body.each { |child| names.concat(collect(child, nesting)) }
|
|
21
|
+
when Prism::ModuleNode, Prism::ClassNode then collect_class(node, nesting)
|
|
22
|
+
when Prism::ProgramNode then collect_program(node, nesting)
|
|
23
|
+
when Prism::StatementsNode then collect_statements(node, nesting)
|
|
24
|
+
else []
|
|
31
25
|
end
|
|
32
|
-
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def collect_class(node, nesting)
|
|
29
|
+
const = node.constant_path.full_name
|
|
30
|
+
qualified = qualify(const, nesting)
|
|
31
|
+
return [qualified] if node.body.nil?
|
|
32
|
+
|
|
33
|
+
[qualified] + collect(node.body, nesting + [const])
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def collect_program(node, nesting)
|
|
37
|
+
return [] if node.statements.nil?
|
|
38
|
+
|
|
39
|
+
collect(node.statements, nesting)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def collect_statements(node, nesting)
|
|
43
|
+
node.body.flat_map { |child| collect(child, nesting) }
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def qualify(const, nesting)
|
|
47
|
+
return const if nesting.empty? || const.include?("::")
|
|
48
|
+
|
|
49
|
+
"#{nesting.join("::")}::#{const}"
|
|
33
50
|
end
|
|
34
51
|
end
|
|
@@ -75,24 +75,36 @@ class Evilution::AST::Pattern::Parser
|
|
|
75
75
|
|
|
76
76
|
def parse_value
|
|
77
77
|
skip_whitespace
|
|
78
|
+
parse_negation || parse_deep_wildcard || parse_single_wildcard || parse_any_node || parse_value_or_nested
|
|
79
|
+
end
|
|
78
80
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
81
|
+
def parse_negation
|
|
82
|
+
return nil unless current_char == "!"
|
|
83
|
+
|
|
84
|
+
advance(1)
|
|
85
|
+
skip_whitespace
|
|
86
|
+
Evilution::AST::Pattern::NegationMatcher.new(parse_value)
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def parse_deep_wildcard
|
|
90
|
+
return nil unless peek_string("**")
|
|
91
|
+
|
|
92
|
+
advance(2)
|
|
93
|
+
Evilution::AST::Pattern::DeepWildcardMatcher.new
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def parse_single_wildcard
|
|
97
|
+
return nil unless current_char == "*"
|
|
98
|
+
|
|
99
|
+
advance(1)
|
|
100
|
+
Evilution::AST::Pattern::WildcardValueMatcher.new
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def parse_any_node
|
|
104
|
+
return nil unless current_char == "_" && !identifier_continues?(1)
|
|
105
|
+
|
|
106
|
+
advance(1)
|
|
107
|
+
Evilution::AST::Pattern::AnyNodeMatcher.new
|
|
96
108
|
end
|
|
97
109
|
|
|
98
110
|
def parse_value_or_nested
|
|
@@ -14,10 +14,7 @@ class Evilution::CLI::Commands::SessionDiff < Evilution::CLI::Command
|
|
|
14
14
|
def perform
|
|
15
15
|
raise Evilution::ConfigError, "two session file paths required" unless @files.length == 2
|
|
16
16
|
|
|
17
|
-
|
|
18
|
-
base_data = store.load(@files[0])
|
|
19
|
-
head_data = store.load(@files[1])
|
|
20
|
-
result = Evilution::Session::Diff.new.call(base_data, head_data)
|
|
17
|
+
result = compute_diff(@files)
|
|
21
18
|
Evilution::CLI::Printers::SessionDiff.new(result, format: @options[:format]).render(@stdout)
|
|
22
19
|
0
|
|
23
20
|
rescue ::JSON::ParserError => e
|
|
@@ -25,6 +22,11 @@ class Evilution::CLI::Commands::SessionDiff < Evilution::CLI::Command
|
|
|
25
22
|
rescue SystemCallError => e
|
|
26
23
|
raise Evilution::Error, e.message
|
|
27
24
|
end
|
|
25
|
+
|
|
26
|
+
def compute_diff(files)
|
|
27
|
+
store = Evilution::Session::Store.new
|
|
28
|
+
Evilution::Session::Diff.new.call(store.load(files[0]), store.load(files[1]))
|
|
29
|
+
end
|
|
28
30
|
end
|
|
29
31
|
|
|
30
32
|
Evilution::CLI::Dispatcher.register(:session_diff, Evilution::CLI::Commands::SessionDiff)
|
|
@@ -9,6 +9,9 @@ require_relative "../../runner"
|
|
|
9
9
|
require_relative "../../mutator"
|
|
10
10
|
|
|
11
11
|
class Evilution::CLI::Commands::Subjects < Evilution::CLI::Command
|
|
12
|
+
EntriesResult = Data.define(:entries, :total)
|
|
13
|
+
private_constant :EntriesResult
|
|
14
|
+
|
|
12
15
|
private
|
|
13
16
|
|
|
14
17
|
def perform
|
|
@@ -23,8 +26,8 @@ class Evilution::CLI::Commands::Subjects < Evilution::CLI::Command
|
|
|
23
26
|
return 0
|
|
24
27
|
end
|
|
25
28
|
|
|
26
|
-
|
|
27
|
-
Evilution::CLI::Printers::Subjects.new(entries, total_mutations: total).render(@stdout)
|
|
29
|
+
result = collect_entries(subjects, config)
|
|
30
|
+
Evilution::CLI::Printers::Subjects.new(result.entries, total_mutations: result.total).render(@stdout)
|
|
28
31
|
0
|
|
29
32
|
end
|
|
30
33
|
|
|
@@ -43,7 +46,7 @@ class Evilution::CLI::Commands::Subjects < Evilution::CLI::Command
|
|
|
43
46
|
subj.release_node!
|
|
44
47
|
end
|
|
45
48
|
|
|
46
|
-
|
|
49
|
+
EntriesResult.new(entries: entries, total: total)
|
|
47
50
|
end
|
|
48
51
|
end
|
|
49
52
|
|
|
@@ -11,11 +11,14 @@ require_relative "../../mutator/registry"
|
|
|
11
11
|
require_relative "../../ast/parser"
|
|
12
12
|
|
|
13
13
|
class Evilution::CLI::Commands::UtilMutation < Evilution::CLI::Command
|
|
14
|
+
SourceInput = Data.define(:source, :file_path)
|
|
15
|
+
private_constant :SourceInput
|
|
16
|
+
|
|
14
17
|
private
|
|
15
18
|
|
|
16
19
|
def perform
|
|
17
|
-
|
|
18
|
-
subjects = parse_source_to_subjects(source, file_path)
|
|
20
|
+
input = resolve_util_mutation_source
|
|
21
|
+
subjects = parse_source_to_subjects(input.source, input.file_path)
|
|
19
22
|
config = Evilution::Config.new(**@options)
|
|
20
23
|
registry = Evilution::Mutator::Registry.default
|
|
21
24
|
operator_options = build_operator_options(config)
|
|
@@ -33,24 +36,26 @@ class Evilution::CLI::Commands::UtilMutation < Evilution::CLI::Command
|
|
|
33
36
|
end
|
|
34
37
|
|
|
35
38
|
def resolve_util_mutation_source
|
|
36
|
-
if @options[:eval]
|
|
37
|
-
|
|
38
|
-
tmpfile.write(@options[:eval])
|
|
39
|
-
tmpfile.flush
|
|
40
|
-
@util_tmpfile = tmpfile
|
|
41
|
-
[@options[:eval], tmpfile.path]
|
|
42
|
-
elsif @files.first
|
|
43
|
-
path = @files.first
|
|
44
|
-
raise Evilution::Error, "file not found: #{path}" unless File.exist?(path)
|
|
39
|
+
return build_eval_source(@options[:eval]) if @options[:eval]
|
|
40
|
+
return build_file_source(@files.first) if @files.first
|
|
45
41
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
42
|
+
raise Evilution::Error, "source required: use -e 'code' or provide a file path"
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def build_eval_source(code)
|
|
46
|
+
tmpfile = Tempfile.new(["evilution_eval", ".rb"])
|
|
47
|
+
tmpfile.write(code)
|
|
48
|
+
tmpfile.flush
|
|
49
|
+
@util_tmpfile = tmpfile
|
|
50
|
+
SourceInput.new(source: code, file_path: tmpfile.path)
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def build_file_source(path)
|
|
54
|
+
raise Evilution::Error, "file not found: #{path}" unless File.exist?(path)
|
|
55
|
+
|
|
56
|
+
SourceInput.new(source: File.read(path), file_path: path)
|
|
57
|
+
rescue SystemCallError => e
|
|
58
|
+
raise Evilution::Error, e.message
|
|
54
59
|
end
|
|
55
60
|
|
|
56
61
|
def parse_source_to_subjects(source, file_label)
|
|
@@ -20,6 +20,13 @@ class Evilution::CLI::Parser::CommandExtractor
|
|
|
20
20
|
ENVIRONMENT_SUBCOMMANDS = { "show" => :environment_show }.freeze
|
|
21
21
|
UTIL_SUBCOMMANDS = { "mutation" => :util_mutation }.freeze
|
|
22
22
|
|
|
23
|
+
SUBCOMMAND_FAMILIES = {
|
|
24
|
+
"session" => [SESSION_SUBCOMMANDS, "session", "list, show, diff, gc"],
|
|
25
|
+
"tests" => [TESTS_SUBCOMMANDS, "tests", "list"],
|
|
26
|
+
"environment" => [ENVIRONMENT_SUBCOMMANDS, "environment", "show"],
|
|
27
|
+
"util" => [UTIL_SUBCOMMANDS, "util", "mutation"]
|
|
28
|
+
}.freeze
|
|
29
|
+
|
|
23
30
|
Result = Struct.new(:command, :remaining_argv, :parse_error)
|
|
24
31
|
|
|
25
32
|
def self.call(argv)
|
|
@@ -46,18 +53,9 @@ class Evilution::CLI::Parser::CommandExtractor
|
|
|
46
53
|
@argv.shift
|
|
47
54
|
elsif first == "run"
|
|
48
55
|
@argv.shift
|
|
49
|
-
elsif first
|
|
50
|
-
@argv.shift
|
|
51
|
-
extract_subcommand(SESSION_SUBCOMMANDS, "session", "list, show, diff, gc")
|
|
52
|
-
elsif first == "tests"
|
|
53
|
-
@argv.shift
|
|
54
|
-
extract_subcommand(TESTS_SUBCOMMANDS, "tests", "list")
|
|
55
|
-
elsif first == "environment"
|
|
56
|
-
@argv.shift
|
|
57
|
-
extract_subcommand(ENVIRONMENT_SUBCOMMANDS, "environment", "show")
|
|
58
|
-
elsif first == "util"
|
|
56
|
+
elsif SUBCOMMAND_FAMILIES.key?(first)
|
|
59
57
|
@argv.shift
|
|
60
|
-
extract_subcommand(
|
|
58
|
+
extract_subcommand(*SUBCOMMAND_FAMILIES[first])
|
|
61
59
|
end
|
|
62
60
|
end
|
|
63
61
|
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module Evilution::CLI::Parser::FileArgs
|
|
4
|
+
ParsedPaths = Data.define(:files, :ranges)
|
|
5
|
+
|
|
4
6
|
module_function
|
|
5
7
|
|
|
6
8
|
def parse(raw_args)
|
|
@@ -15,7 +17,7 @@ module Evilution::CLI::Parser::FileArgs
|
|
|
15
17
|
ranges[file] = parse_line_range(range_str)
|
|
16
18
|
end
|
|
17
19
|
|
|
18
|
-
|
|
20
|
+
ParsedPaths.new(files: files, ranges: ranges)
|
|
19
21
|
end
|
|
20
22
|
|
|
21
23
|
def expand_spec_dir(dir)
|
|
@@ -21,6 +21,8 @@ class Evilution::CLI::Parser::OptionsBuilder
|
|
|
21
21
|
add_core_options(opts)
|
|
22
22
|
add_filter_options(opts)
|
|
23
23
|
add_flag_options(opts)
|
|
24
|
+
add_runner_mode_options(opts)
|
|
25
|
+
add_output_options(opts)
|
|
24
26
|
add_profile_options(opts)
|
|
25
27
|
add_extra_flag_options(opts)
|
|
26
28
|
add_session_options(opts)
|
|
@@ -47,11 +49,19 @@ class Evilution::CLI::Parser::OptionsBuilder
|
|
|
47
49
|
end
|
|
48
50
|
|
|
49
51
|
def add_filter_options(opts)
|
|
52
|
+
add_spec_filter_options(opts)
|
|
53
|
+
add_targeting_options(opts)
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def add_spec_filter_options(opts)
|
|
50
57
|
opts.on("--min-score FLOAT", Float, "Minimum mutation score to pass") { |s| @options[:min_score] = s }
|
|
51
58
|
opts.on("--spec FILES", Array, "Spec files to run (comma-separated)") { |f| @options[:spec_files] = f }
|
|
52
59
|
opts.on("--spec-dir DIR", "Include all specs in DIR") { |d| expand_spec_dir(d) }
|
|
53
60
|
opts.on("--spec-pattern GLOB",
|
|
54
61
|
"Restrict resolved spec candidates to files matching GLOB") { |p| @options[:spec_pattern] = p }
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def add_targeting_options(opts)
|
|
55
65
|
opts.on("--no-example-targeting",
|
|
56
66
|
"Disable per-mutation example targeting (run all examples in resolved spec files)") do
|
|
57
67
|
@options[:example_targeting] = false
|
|
@@ -76,13 +86,19 @@ class Evilution::CLI::Parser::OptionsBuilder
|
|
|
76
86
|
"Use --no-incremental to override `incremental: true` from the config file for one run.") do |v|
|
|
77
87
|
@options[:incremental] = v
|
|
78
88
|
end
|
|
89
|
+
opts.on("--stdin", "Read target file paths from stdin (one per line)") { @options[:stdin] = true }
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def add_runner_mode_options(opts)
|
|
79
93
|
opts.on("--integration NAME", "Test integration: rspec, minitest (default: rspec)") { |i| @options[:integration] = i }
|
|
80
94
|
opts.on("--isolation STRATEGY", "Isolation: auto, fork, in_process (default: auto)") { |s| @options[:isolation] = s }
|
|
81
95
|
opts.on("--preload FILE", "Preload FILE in the parent process before forking " \
|
|
82
96
|
"(default: auto-detect spec/rails_helper.rb -> spec/spec_helper.rb -> " \
|
|
83
97
|
"test/test_helper.rb for Rails projects)") { |f| @options[:preload] = f }
|
|
84
98
|
opts.on("--no-preload", "Disable parent-process preload even for Rails projects") { @options[:preload] = false }
|
|
85
|
-
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def add_output_options(opts)
|
|
86
102
|
opts.on("--suggest-tests", "Generate concrete test code in suggestions (RSpec or Minitest)") { @options[:suggest_tests] = true }
|
|
87
103
|
opts.on("--no-progress", "Disable progress bar") { @options[:progress] = false }
|
|
88
104
|
opts.on("--quiet-children",
|
|
@@ -103,6 +119,12 @@ class Evilution::CLI::Parser::OptionsBuilder
|
|
|
103
119
|
end
|
|
104
120
|
|
|
105
121
|
def add_extra_flag_options(opts)
|
|
122
|
+
add_mutation_behavior_options(opts)
|
|
123
|
+
add_session_persistence_options(opts)
|
|
124
|
+
add_misc_extra_options(opts)
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
def add_mutation_behavior_options(opts)
|
|
106
128
|
opts.on("--skip-heredoc-literals", "Skip all string literal mutations inside heredocs") { @options[:skip_heredoc_literals] = true }
|
|
107
129
|
opts.on("--related-specs-heuristic", "Append related request/integration/feature/system specs for includes() mutations") do
|
|
108
130
|
@options[:related_specs_heuristic] = true
|
|
@@ -112,8 +134,14 @@ class Evilution::CLI::Parser::OptionsBuilder
|
|
|
112
134
|
@options[:fallback_to_full_suite] = true
|
|
113
135
|
end
|
|
114
136
|
opts.on("--show-disabled", "Report mutations skipped by # evilution:disable") { @options[:show_disabled] = true }
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
def add_session_persistence_options(opts)
|
|
115
140
|
opts.on("--baseline-session PATH", "Compare against a baseline session in HTML report") { |p| @options[:baseline_session] = p }
|
|
116
141
|
opts.on("--save-session", "Save session results to .evilution/results/") { @options[:save_session] = true }
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
def add_misc_extra_options(opts)
|
|
117
145
|
opts.on("-e", "--eval CODE", "Evaluate code snippet (for util mutation)") { |c| @options[:eval] = c }
|
|
118
146
|
opts.on("-v", "--verbose", "Verbose output") { @options[:verbose] = true }
|
|
119
147
|
opts.on("-q", "--quiet", "Suppress output") { @options[:quiet] = true }
|
|
@@ -22,7 +22,7 @@ class Evilution::CLI::Parser::StdinReader
|
|
|
22
22
|
line = line.strip
|
|
23
23
|
lines << line unless line.empty?
|
|
24
24
|
end
|
|
25
|
-
|
|
26
|
-
Result.new(files, ranges, nil)
|
|
25
|
+
parsed_paths = Evilution::CLI::Parser::FileArgs.parse(lines)
|
|
26
|
+
Result.new(parsed_paths.files, parsed_paths.ranges, nil)
|
|
27
27
|
end
|
|
28
28
|
end
|
data/lib/evilution/cli/parser.rb
CHANGED
|
@@ -20,7 +20,9 @@ class Evilution::CLI::Parser
|
|
|
20
20
|
|
|
21
21
|
preprocess_flags
|
|
22
22
|
remaining = OptionsBuilder.build(@options).parse!(@argv)
|
|
23
|
-
|
|
23
|
+
parsed_paths = FileArgs.parse(remaining)
|
|
24
|
+
@files = parsed_paths.files
|
|
25
|
+
@line_ranges = parsed_paths.ranges
|
|
24
26
|
read_stdin_files if @options.delete(:stdin) && %i[run subjects].include?(@command)
|
|
25
27
|
build_parsed_args
|
|
26
28
|
end
|
|
@@ -37,27 +39,23 @@ class Evilution::CLI::Parser
|
|
|
37
39
|
def preprocess_flags
|
|
38
40
|
result = []
|
|
39
41
|
i = 0
|
|
40
|
-
while i < @argv.length
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
next_arg = @argv[i + 1]
|
|
42
|
+
i = consume_token(i, result) while i < @argv.length
|
|
43
|
+
@argv = result
|
|
44
|
+
end
|
|
44
45
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
end
|
|
52
|
-
elsif arg.start_with?("--fail-fast=")
|
|
53
|
-
@options[:fail_fast] = arg.delete_prefix("--fail-fast=")
|
|
54
|
-
i += 1
|
|
55
|
-
else
|
|
56
|
-
result << arg
|
|
57
|
-
i += 1
|
|
58
|
-
end
|
|
46
|
+
def consume_token(i, result)
|
|
47
|
+
arg = @argv[i]
|
|
48
|
+
next_arg = @argv[i + 1]
|
|
49
|
+
if arg == "--fail-fast" && !next_arg.nil? && next_arg.match?(/\A-?\d+\z/)
|
|
50
|
+
@options[:fail_fast] = next_arg
|
|
51
|
+
return i + 2
|
|
59
52
|
end
|
|
60
|
-
|
|
53
|
+
if arg.start_with?("--fail-fast=")
|
|
54
|
+
@options[:fail_fast] = arg.delete_prefix("--fail-fast=")
|
|
55
|
+
return i + 1
|
|
56
|
+
end
|
|
57
|
+
result << arg
|
|
58
|
+
i + 1
|
|
61
59
|
end
|
|
62
60
|
|
|
63
61
|
def read_stdin_files
|
|
@@ -3,6 +3,12 @@
|
|
|
3
3
|
require_relative "../printers"
|
|
4
4
|
|
|
5
5
|
class Evilution::CLI::Printers::Environment
|
|
6
|
+
PLAIN_SETTINGS = %i[
|
|
7
|
+
timeout format integration jobs isolation baseline incremental
|
|
8
|
+
verbose quiet progress min_score suggest_tests save_session
|
|
9
|
+
skip_heredoc_literals
|
|
10
|
+
].freeze
|
|
11
|
+
|
|
6
12
|
def initialize(config, config_file:)
|
|
7
13
|
@config = config
|
|
8
14
|
@config_file = config_file
|
|
@@ -30,24 +36,18 @@ class Evilution::CLI::Printers::Environment
|
|
|
30
36
|
end
|
|
31
37
|
|
|
32
38
|
def settings_lines
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
" suggest_tests: #{@config.suggest_tests}",
|
|
47
|
-
" save_session: #{@config.save_session}",
|
|
48
|
-
" target: #{@config.target || "(all files)"}",
|
|
49
|
-
" skip_heredoc_literals: #{@config.skip_heredoc_literals}",
|
|
50
|
-
" ignore_patterns: #{@config.ignore_patterns.empty? ? "(none)" : @config.ignore_patterns.inspect}"
|
|
51
|
-
]
|
|
39
|
+
plain_lines = PLAIN_SETTINGS.map { |k| setting_line(k, @config.public_send(k)) }
|
|
40
|
+
plain_lines.insert(10, setting_line(:fail_fast, @config.fail_fast || "(disabled)"))
|
|
41
|
+
plain_lines.insert(14, setting_line(:target, @config.target || "(all files)"))
|
|
42
|
+
plain_lines << setting_line(:ignore_patterns, format_ignore_patterns(@config.ignore_patterns))
|
|
43
|
+
plain_lines
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def setting_line(key, value)
|
|
47
|
+
" #{key}: #{value}"
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def format_ignore_patterns(patterns)
|
|
51
|
+
patterns.empty? ? "(none)" : patterns.inspect
|
|
52
52
|
end
|
|
53
53
|
end
|
|
@@ -32,16 +32,16 @@ class Evilution::CLI::Printers::SessionDiff
|
|
|
32
32
|
end
|
|
33
33
|
|
|
34
34
|
def print_summary(io, summary)
|
|
35
|
-
delta_str = format("%+.2f%%", summary.score_delta * 100)
|
|
36
35
|
io.puts("Session Diff")
|
|
37
36
|
io.puts("=" * 40)
|
|
38
|
-
io.puts(
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
37
|
+
io.puts(score_line("Base", summary.base_score, summary.base_killed, summary.base_total))
|
|
38
|
+
io.puts(score_line("Head", summary.head_score, summary.head_killed, summary.head_total))
|
|
39
|
+
io.puts("Delta: #{format("%+.2f%%", summary.score_delta * 100)}")
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def score_line(label, score, killed, total)
|
|
43
|
+
format("%<label>s score: %<score>6.2f%% (%<killed>d/%<total>d killed)",
|
|
44
|
+
label: label, score: score * 100, killed: killed, total: total)
|
|
45
45
|
end
|
|
46
46
|
|
|
47
47
|
def print_section(io, title, mutations, color)
|