evilution 0.21.0 → 0.22.1

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.
Files changed (52) hide show
  1. checksums.yaml +4 -4
  2. data/.beads/.gitignore +4 -0
  3. data/.beads/interactions.jsonl +16 -0
  4. data/.beads/issues.jsonl +9 -6
  5. data/.claude/settings.json +5 -0
  6. data/CHANGELOG.md +35 -0
  7. data/README.md +28 -13
  8. data/comparison_results/baseline_2026-04-09.md +35 -0
  9. data/comparison_results/operator_classification.md +79 -0
  10. data/comparison_results/operator_prioritization.md +68 -0
  11. data/docs/mutation_density_benchmark.md +91 -0
  12. data/lib/evilution/ast/parser.rb +2 -1
  13. data/lib/evilution/baseline.rb +14 -11
  14. data/lib/evilution/cli.rb +2 -1
  15. data/lib/evilution/config.rb +15 -3
  16. data/lib/evilution/disable_comment.rb +2 -1
  17. data/lib/evilution/integration/base.rb +124 -1
  18. data/lib/evilution/integration/minitest.rb +145 -0
  19. data/lib/evilution/integration/minitest_crash_detector.rb +55 -0
  20. data/lib/evilution/integration/rspec.rb +33 -100
  21. data/lib/evilution/isolation/fork.rb +11 -3
  22. data/lib/evilution/isolation/in_process.rb +12 -3
  23. data/lib/evilution/mcp/mutate_tool.rb +6 -6
  24. data/lib/evilution/mutator/base.rb +4 -0
  25. data/lib/evilution/mutator/operator/bitwise_complement.rb +1 -1
  26. data/lib/evilution/mutator/operator/block_pass_removal.rb +30 -0
  27. data/lib/evilution/mutator/operator/ensure_removal.rb +1 -1
  28. data/lib/evilution/mutator/operator/index_to_at.rb +30 -0
  29. data/lib/evilution/mutator/operator/index_to_dig.rb +2 -2
  30. data/lib/evilution/mutator/operator/index_to_fetch.rb +2 -2
  31. data/lib/evilution/mutator/operator/keyword_argument.rb +1 -1
  32. data/lib/evilution/mutator/operator/regex_simplification.rb +169 -0
  33. data/lib/evilution/mutator/operator/rescue_body_replacement.rb +1 -1
  34. data/lib/evilution/mutator/operator/rescue_removal.rb +1 -1
  35. data/lib/evilution/mutator/operator/symbol_literal.rb +9 -0
  36. data/lib/evilution/mutator/registry.rb +3 -0
  37. data/lib/evilution/reporter/cli.rb +19 -0
  38. data/lib/evilution/reporter/html.rb +12 -3
  39. data/lib/evilution/reporter/json.rb +14 -3
  40. data/lib/evilution/reporter/suggestion.rb +659 -2
  41. data/lib/evilution/result/mutation_result.rb +9 -2
  42. data/lib/evilution/runner.rb +56 -17
  43. data/lib/evilution/spec_resolver.rb +24 -16
  44. data/lib/evilution/version.rb +1 -1
  45. data/lib/evilution.rb +4 -0
  46. data/script/memory_check +5 -5
  47. data/scripts/benchmark_density +261 -0
  48. data/scripts/benchmark_density.yml +19 -0
  49. data/scripts/compare_mutations +404 -0
  50. data/scripts/compare_mutations.yml +24 -0
  51. data/scripts/mutant_json_adapter +224 -0
  52. metadata +17 -2
@@ -7,8 +7,8 @@ require_relative "../reporter"
7
7
  require_relative "../result/coverage_gap_grouper"
8
8
 
9
9
  class Evilution::Reporter::HTML
10
- def initialize(baseline: nil)
11
- @suggestion = Evilution::Reporter::Suggestion.new
10
+ def initialize(baseline: nil, integration: :rspec)
11
+ @suggestion = Evilution::Reporter::Suggestion.new(integration: integration)
12
12
  @baseline = baseline
13
13
  @baseline_keys = build_baseline_keys(baseline)
14
14
  end
@@ -145,8 +145,10 @@ class Evilution::Reporter::HTML
145
145
  def build_map_entry(result)
146
146
  mutation = result.mutation
147
147
  status = result.status.to_s
148
+ title_text = normalize_title(result.error_message)
149
+ title_attr = title_text ? %( title="#{h(title_text)}") : ""
148
150
  <<~HTML.chomp
149
- <div class="map-line #{status}">
151
+ <div class="map-line #{status}"#{title_attr}>
150
152
  <span class="line-number">line #{mutation.line}</span>
151
153
  <span class="operator">#{h(mutation.operator_name)}</span>
152
154
  <span class="status-badge #{status}">#{status}</span>
@@ -154,6 +156,13 @@ class Evilution::Reporter::HTML
154
156
  HTML
155
157
  end
156
158
 
159
+ def normalize_title(message)
160
+ return nil if message.nil?
161
+
162
+ normalized = message.gsub(/\s+/, " ").strip
163
+ normalized.empty? ? nil : normalized
164
+ end
165
+
157
166
  def build_survived_details(survived)
158
167
  return "" if survived.empty?
159
168
 
@@ -7,8 +7,8 @@ require_relative "suggestion"
7
7
  require_relative "../reporter"
8
8
 
9
9
  class Evilution::Reporter::JSON
10
- def initialize(suggest_tests: false)
11
- @suggestion = Evilution::Reporter::Suggestion.new(suggest_tests: suggest_tests)
10
+ def initialize(suggest_tests: false, integration: :rspec)
11
+ @suggestion = Evilution::Reporter::Suggestion.new(suggest_tests: suggest_tests, integration: integration)
12
12
  end
13
13
 
14
14
  def call(summary)
@@ -76,10 +76,21 @@ class Evilution::Reporter::JSON
76
76
  }
77
77
  detail[:suggestion] = @suggestion.suggestion_for(mutation) if result.status == :survived
78
78
  detail[:test_command] = result.test_command if result.test_command
79
+ append_memory_fields(detail, result)
80
+ append_error_fields(detail, result)
81
+ detail
82
+ end
83
+
84
+ def append_memory_fields(detail, result)
79
85
  detail[:parent_rss_kb] = result.parent_rss_kb if result.parent_rss_kb
80
86
  detail[:child_rss_kb] = result.child_rss_kb if result.child_rss_kb
81
87
  detail[:memory_delta_kb] = result.memory_delta_kb if result.memory_delta_kb
82
- detail
88
+ end
89
+
90
+ def append_error_fields(detail, result)
91
+ detail[:error_message] = result.error_message if result.error_message
92
+ detail[:error_class] = result.error_class if result.error_class
93
+ detail[:error_backtrace] = result.error_backtrace if result.error_backtrace
83
94
  end
84
95
 
85
96
  def build_coverage_gaps(summary)