evilution 0.17.0 → 0.19.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.
Files changed (38) hide show
  1. checksums.yaml +4 -4
  2. data/.beads/.migration-hint-ts +1 -1
  3. data/.beads/issues.jsonl +103 -33
  4. data/CHANGELOG.md +50 -0
  5. data/README.md +144 -50
  6. data/lib/evilution/ast/sorbet_sig_detector.rb +52 -0
  7. data/lib/evilution/baseline.rb +9 -1
  8. data/lib/evilution/cli.rb +398 -23
  9. data/lib/evilution/config.rb +10 -2
  10. data/lib/evilution/disable_comment.rb +90 -0
  11. data/lib/evilution/integration/rspec.rb +74 -5
  12. data/lib/evilution/isolation/fork.rb +10 -6
  13. data/lib/evilution/isolation/in_process.rb +14 -10
  14. data/lib/evilution/mcp/session_diff_tool.rb +5 -35
  15. data/lib/evilution/mutator/operator/collection_return.rb +33 -0
  16. data/lib/evilution/mutator/operator/defined_check.rb +16 -0
  17. data/lib/evilution/mutator/operator/keyword_argument.rb +91 -0
  18. data/lib/evilution/mutator/operator/multiple_assignment.rb +47 -0
  19. data/lib/evilution/mutator/operator/regex_capture.rb +43 -0
  20. data/lib/evilution/mutator/operator/scalar_return.rb +37 -0
  21. data/lib/evilution/mutator/operator/splat_operator.rb +46 -0
  22. data/lib/evilution/mutator/operator/yield_statement.rb +51 -0
  23. data/lib/evilution/mutator/registry.rb +9 -1
  24. data/lib/evilution/parallel/pool.rb +7 -53
  25. data/lib/evilution/parallel/work_queue.rb +265 -0
  26. data/lib/evilution/reporter/cli.rb +21 -1
  27. data/lib/evilution/reporter/html.rb +69 -3
  28. data/lib/evilution/reporter/json.rb +23 -2
  29. data/lib/evilution/reporter/suggestion.rb +29 -1
  30. data/lib/evilution/result/mutation_result.rb +5 -2
  31. data/lib/evilution/result/summary.rb +19 -2
  32. data/lib/evilution/runner.rb +123 -12
  33. data/lib/evilution/session/diff.rb +85 -0
  34. data/lib/evilution/spec_resolver.rb +13 -1
  35. data/lib/evilution/version.rb +1 -1
  36. data/lib/evilution.rb +11 -0
  37. data/script/memory_check +22 -0
  38. metadata +14 -2
@@ -21,6 +21,8 @@ require_relative "cache"
21
21
  require_relative "parallel/pool"
22
22
  require_relative "session/store"
23
23
  require_relative "ast/pattern/filter"
24
+ require_relative "disable_comment"
25
+ require_relative "ast/sorbet_sig_detector"
24
26
 
25
27
  class Evilution::Runner
26
28
  attr_reader :config
@@ -33,6 +35,10 @@ class Evilution::Runner
33
35
  @registry = Evilution::Mutator::Registry.default
34
36
  @isolator = build_isolator
35
37
  @cache = config.incremental? ? Evilution::Cache.new : nil
38
+ @disable_detector = Evilution::DisableComment.new
39
+ @disabled_ranges_cache = {}
40
+ @sig_detector = Evilution::AST::SorbetSigDetector.new
41
+ @sig_ranges_cache = {}
36
42
  end
37
43
 
38
44
  def call
@@ -43,7 +49,7 @@ class Evilution::Runner
43
49
 
44
50
  baseline_result = run_baseline(subjects)
45
51
 
46
- mutations, skipped_count = generate_mutations(subjects)
52
+ mutations, skipped_count, disabled_mutations = generate_mutations(subjects)
47
53
  equivalent_mutations, mutations = filter_equivalent(mutations)
48
54
  release_subject_nodes(subjects)
49
55
  clear_operator_caches
@@ -57,17 +63,14 @@ class Evilution::Runner
57
63
  duration = Process.clock_gettime(Process::CLOCK_MONOTONIC) - start_time
58
64
 
59
65
  summary = Evilution::Result::Summary.new(results: results, duration: duration, truncated: truncated,
60
- skipped: skipped_count)
66
+ skipped: skipped_count,
67
+ disabled_mutations: disabled_mutations)
61
68
  output_report(summary)
62
69
  save_session(summary)
63
70
 
64
71
  summary
65
72
  end
66
73
 
67
- private
68
-
69
- attr_reader :parser, :registry, :isolator, :cache, :on_result, :hooks
70
-
71
74
  def parse_and_filter_subjects
72
75
  subjects = parse_subjects
73
76
  subjects = filter_by_descendants(subjects) if descendants_target?
@@ -76,6 +79,10 @@ class Evilution::Runner
76
79
  subjects
77
80
  end
78
81
 
82
+ private
83
+
84
+ attr_reader :parser, :registry, :isolator, :cache, :on_result, :hooks, :disable_detector, :sig_detector
85
+
79
86
  def parse_subjects
80
87
  files = resolve_target_files
81
88
  files.flat_map { |file| parser.call(file) }
@@ -176,7 +183,73 @@ class Evilution::Runner
176
183
  mutations = subjects.flat_map do |subject|
177
184
  registry.mutations_for(subject, filter: filter)
178
185
  end
179
- [mutations, filter ? filter.skipped_count : 0]
186
+ skipped_count = filter ? filter.skipped_count : 0
187
+
188
+ mutations, disabled = filter_disabled(mutations)
189
+ disabled.each(&:strip_sources!) if config.show_disabled?
190
+ disabled_mutations = config.show_disabled? ? disabled : []
191
+
192
+ mutations, sig_skipped = filter_sig_blocks(mutations)
193
+
194
+ [mutations, skipped_count + disabled.length + sig_skipped, disabled_mutations]
195
+ end
196
+
197
+ def filter_disabled(mutations)
198
+ enabled = []
199
+ disabled = []
200
+
201
+ mutations.each do |mutation|
202
+ if mutation_disabled?(mutation)
203
+ disabled << mutation
204
+ else
205
+ enabled << mutation
206
+ end
207
+ end
208
+
209
+ [enabled, disabled]
210
+ end
211
+
212
+ def mutation_disabled?(mutation)
213
+ ranges = disabled_ranges_for(mutation.file_path)
214
+ ranges.any? { |range| range.cover?(mutation.line) }
215
+ end
216
+
217
+ def disabled_ranges_for(file_path)
218
+ @disabled_ranges_cache[file_path] ||= begin
219
+ source = File.read(file_path)
220
+ @disable_detector.call(source)
221
+ rescue SystemCallError
222
+ []
223
+ end
224
+ end
225
+
226
+ def filter_sig_blocks(mutations)
227
+ enabled = []
228
+ skipped = 0
229
+
230
+ mutations.each do |mutation|
231
+ if mutation_in_sig_block?(mutation)
232
+ skipped += 1
233
+ else
234
+ enabled << mutation
235
+ end
236
+ end
237
+
238
+ [enabled, skipped]
239
+ end
240
+
241
+ def mutation_in_sig_block?(mutation)
242
+ ranges = sig_line_ranges_for(mutation.file_path)
243
+ ranges.any? { |range| range.cover?(mutation.line) }
244
+ end
245
+
246
+ def sig_line_ranges_for(file_path)
247
+ @sig_ranges_cache[file_path] ||= begin
248
+ source = File.read(file_path)
249
+ @sig_detector.line_ranges(source)
250
+ rescue SystemCallError
251
+ []
252
+ end
180
253
  end
181
254
 
182
255
  def build_ignore_filter
@@ -252,18 +325,23 @@ class Evilution::Runner
252
325
 
253
326
  def run_mutations_parallel(mutations, baseline_result = nil)
254
327
  integration = build_integration
255
- pool = Evilution::Parallel::Pool.new(size: config.jobs, hooks: @hooks)
328
+ pool = Evilution::Parallel::Pool.new(size: config.jobs, hooks: @hooks, item_timeout: config.timeout ? config.timeout * 2 : nil)
256
329
  worker_isolator = Evilution::Isolation::InProcess.new
257
330
  spec_resolver = baseline_result&.failed? ? Evilution::SpecResolver.new : nil
258
331
  state = { results: [], survived_count: 0, truncated: false, completed: 0 }
259
332
 
333
+ all_worker_stats = []
334
+
260
335
  mutations.each_slice(config.jobs) do |batch|
261
336
  break if state[:truncated]
262
337
 
263
338
  batch_results = run_parallel_batch(batch, pool, worker_isolator, integration)
339
+ all_worker_stats.concat(pool.worker_stats)
264
340
  process_batch(batch_results, baseline_result, spec_resolver, state)
265
341
  end
266
342
 
343
+ log_worker_stats(aggregate_worker_stats(all_worker_stats))
344
+
267
345
  [state[:results], state[:truncated]]
268
346
  end
269
347
 
@@ -318,7 +396,8 @@ class Evilution::Runner
318
396
  duration: result.duration,
319
397
  test_command: result.test_command,
320
398
  child_rss_kb: result.child_rss_kb,
321
- memory_delta_kb: result.memory_delta_kb
399
+ memory_delta_kb: result.memory_delta_kb,
400
+ parent_rss_kb: result.parent_rss_kb
322
401
  )
323
402
  end
324
403
 
@@ -329,7 +408,8 @@ class Evilution::Runner
329
408
  killing_test: result.killing_test,
330
409
  test_command: result.test_command,
331
410
  child_rss_kb: result.child_rss_kb,
332
- memory_delta_kb: result.memory_delta_kb
411
+ memory_delta_kb: result.memory_delta_kb,
412
+ parent_rss_kb: result.parent_rss_kb
333
413
  }
334
414
  end
335
415
 
@@ -342,7 +422,8 @@ class Evilution::Runner
342
422
  killing_test: data[:killing_test],
343
423
  test_command: data[:test_command],
344
424
  child_rss_kb: data[:child_rss_kb],
345
- memory_delta_kb: data[:memory_delta_kb]
425
+ memory_delta_kb: data[:memory_delta_kb],
426
+ parent_rss_kb: data[:parent_rss_kb]
346
427
  )
347
428
  end
348
429
  end
@@ -458,6 +539,28 @@ class Evilution::Runner
458
539
  warn "[evilution] failed to save session: #{e.message}" unless config.quiet
459
540
  end
460
541
 
542
+ def log_worker_stats(stats)
543
+ return unless config.verbose && !config.quiet && stats.any?
544
+
545
+ stats.each do |stat|
546
+ pct = format("%.1f", stat.utilization * 100)
547
+ $stderr.write("[verbose] worker #{stat.pid}: #{stat.items_completed} items, utilization #{pct}%\n")
548
+ end
549
+ end
550
+
551
+ def aggregate_worker_stats(stats)
552
+ return stats if stats.empty?
553
+
554
+ stats.group_by(&:pid).map do |pid, entries|
555
+ Evilution::Parallel::WorkQueue::WorkerStat.new(
556
+ pid,
557
+ entries.sum(&:items_completed),
558
+ entries.sum(&:busy_time),
559
+ entries.sum(&:wall_time)
560
+ )
561
+ end
562
+ end
563
+
461
564
  def notify_result(result, index)
462
565
  on_result&.call(result)
463
566
  @progress_bar&.tick(status: result.status)
@@ -478,10 +581,18 @@ class Evilution::Runner
478
581
  when :text
479
582
  Evilution::Reporter::CLI.new
480
583
  when :html
481
- Evilution::Reporter::HTML.new
584
+ Evilution::Reporter::HTML.new(baseline: load_baseline_session)
482
585
  end
483
586
  end
484
587
 
588
+ def load_baseline_session
589
+ path = config.baseline_session
590
+ return nil unless path
591
+
592
+ store = Evilution::Session::Store.new
593
+ store.load(path)
594
+ end
595
+
485
596
  def partition_cached(batch)
486
597
  uncached_indices = []
487
598
  cached_results = {}
@@ -0,0 +1,85 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../session"
4
+
5
+ class Evilution::Session::Diff
6
+ Result = Struct.new(:summary, :fixed, :new_survivors, :persistent) do
7
+ def to_h
8
+ {
9
+ "summary" => summary.to_h,
10
+ "fixed" => fixed,
11
+ "new_survivors" => new_survivors,
12
+ "persistent" => persistent
13
+ }
14
+ end
15
+ end
16
+
17
+ SummaryDiff = Struct.new(
18
+ :base_score, :head_score, :score_delta,
19
+ :base_survived, :head_survived,
20
+ :base_total, :head_total,
21
+ :base_killed, :head_killed
22
+ ) do
23
+ def to_h
24
+ {
25
+ "base_score" => base_score,
26
+ "head_score" => head_score,
27
+ "score_delta" => score_delta,
28
+ "base_survived" => base_survived,
29
+ "head_survived" => head_survived,
30
+ "base_total" => base_total,
31
+ "head_total" => head_total,
32
+ "base_killed" => base_killed,
33
+ "head_killed" => head_killed
34
+ }
35
+ end
36
+ end
37
+
38
+ def call(base_data, head_data)
39
+ base_survivors = base_data["survived"] || []
40
+ head_survivors = head_data["survived"] || []
41
+
42
+ base_keys = base_survivors.to_set { |m| mutation_key(m) }
43
+ head_keys = head_survivors.to_set { |m| mutation_key(m) }
44
+
45
+ Result.new(
46
+ summary: build_summary_diff(base_data, head_data),
47
+ fixed: base_survivors.reject { |m| head_keys.include?(mutation_key(m)) },
48
+ new_survivors: head_survivors.reject { |m| base_keys.include?(mutation_key(m)) },
49
+ persistent: head_survivors.select { |m| base_keys.include?(mutation_key(m)) }
50
+ )
51
+ end
52
+
53
+ private
54
+
55
+ def build_summary_diff(base_data, head_data)
56
+ base = extract_summary_values(base_data)
57
+ head = extract_summary_values(head_data)
58
+
59
+ SummaryDiff.new(
60
+ base_score: base[:score],
61
+ head_score: head[:score],
62
+ score_delta: (head[:score] - base[:score]).round(4),
63
+ base_survived: base[:survived],
64
+ head_survived: head[:survived],
65
+ base_total: base[:total],
66
+ head_total: head[:total],
67
+ base_killed: base[:killed],
68
+ head_killed: head[:killed]
69
+ )
70
+ end
71
+
72
+ def extract_summary_values(data)
73
+ summary = data["summary"] || {}
74
+ {
75
+ score: summary["score"] || 0.0,
76
+ survived: summary["survived"] || 0,
77
+ total: summary["total"] || 0,
78
+ killed: summary["killed"] || 0
79
+ }
80
+ end
81
+
82
+ def mutation_key(mutation)
83
+ [mutation["operator"], mutation["file"], mutation["line"], mutation["subject"]]
84
+ end
85
+ end
@@ -2,6 +2,7 @@
2
2
 
3
3
  class Evilution::SpecResolver
4
4
  STRIPPABLE_PREFIXES = %w[lib/ app/].freeze
5
+ CONTROLLER_PREFIX = "controllers/"
5
6
 
6
7
  def call(source_path)
7
8
  return nil if source_path.nil? || source_path.empty?
@@ -29,7 +30,8 @@ class Evilution::SpecResolver
29
30
 
30
31
  candidates = if prefix
31
32
  stripped = base.delete_prefix(prefix)
32
- ["spec/#{stripped}", "spec/#{base}"]
33
+ request_spec = controller_to_request_spec(stripped)
34
+ [request_spec, "spec/#{stripped}", "spec/#{base}"].compact
33
35
  else
34
36
  ["spec/#{base}"]
35
37
  end
@@ -39,6 +41,16 @@ class Evilution::SpecResolver
39
41
  candidates + fallbacks
40
42
  end
41
43
 
44
+ def controller_to_request_spec(stripped_path)
45
+ return nil unless stripped_path.start_with?(CONTROLLER_PREFIX)
46
+ return nil unless stripped_path.end_with?("_controller_spec.rb")
47
+
48
+ request_path = stripped_path
49
+ .delete_prefix(CONTROLLER_PREFIX)
50
+ .sub(/_controller_spec\.rb\z/, "_spec.rb")
51
+ "spec/requests/#{request_path}"
52
+ end
53
+
42
54
  def parent_fallback_candidates(spec_path)
43
55
  parts = spec_path.split("/")
44
56
  # parts: ["spec", "foo", "bar_spec.rb"] — need at least 3 parts for fallback
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Evilution
4
- VERSION = "0.17.0"
4
+ VERSION = "0.19.0"
5
5
  end
data/lib/evilution.rb CHANGED
@@ -12,6 +12,7 @@ require_relative "evilution/ast/source_surgeon"
12
12
  require_relative "evilution/ast/parser"
13
13
  require_relative "evilution/ast/inheritance_scanner"
14
14
  require_relative "evilution/ast/pattern"
15
+ require_relative "evilution/ast/sorbet_sig_detector"
15
16
  require_relative "evilution/ast/pattern/matcher"
16
17
  require_relative "evilution/ast/pattern/parser"
17
18
  require_relative "evilution/hooks"
@@ -48,6 +49,8 @@ require_relative "evilution/mutator/operator/receiver_replacement"
48
49
  require_relative "evilution/mutator/operator/send_mutation"
49
50
  require_relative "evilution/mutator/operator/argument_nil_substitution"
50
51
  require_relative "evilution/mutator/operator/compound_assignment"
52
+ require_relative "evilution/mutator/operator/keyword_argument"
53
+ require_relative "evilution/mutator/operator/multiple_assignment"
51
54
  require_relative "evilution/mutator/operator/mixin_removal"
52
55
  require_relative "evilution/mutator/operator/superclass_removal"
53
56
  require_relative "evilution/mutator/operator/local_variable_assignment"
@@ -72,6 +75,12 @@ require_relative "evilution/mutator/operator/index_assignment_removal"
72
75
  require_relative "evilution/mutator/operator/pattern_matching_guard"
73
76
  require_relative "evilution/mutator/operator/pattern_matching_alternative"
74
77
  require_relative "evilution/mutator/operator/pattern_matching_array"
78
+ require_relative "evilution/mutator/operator/collection_return"
79
+ require_relative "evilution/mutator/operator/scalar_return"
80
+ require_relative "evilution/mutator/operator/yield_statement"
81
+ require_relative "evilution/mutator/operator/splat_operator"
82
+ require_relative "evilution/mutator/operator/defined_check"
83
+ require_relative "evilution/mutator/operator/regex_capture"
75
84
  require_relative "evilution/mutator/registry"
76
85
  require_relative "evilution/equivalent"
77
86
  require_relative "evilution/equivalent/heuristic"
@@ -82,6 +91,7 @@ require_relative "evilution/isolation/in_process"
82
91
  require_relative "evilution/parallel/pool"
83
92
  require_relative "evilution/session"
84
93
  require_relative "evilution/session/store"
94
+ require_relative "evilution/session/diff"
85
95
  require_relative "evilution/git"
86
96
  require_relative "evilution/git/changed_files"
87
97
  require_relative "evilution/integration"
@@ -99,6 +109,7 @@ require_relative "evilution/spec_resolver"
99
109
  require_relative "evilution/baseline"
100
110
  require_relative "evilution/cache"
101
111
  require_relative "evilution/cli"
112
+ require_relative "evilution/disable_comment"
102
113
  require_relative "evilution/runner"
103
114
 
104
115
  module Evilution
data/script/memory_check CHANGED
@@ -3,8 +3,12 @@
3
3
 
4
4
  require_relative "../lib/evilution"
5
5
  require_relative "../lib/evilution/memory/leak_check"
6
+ require_relative "../lib/evilution/integration/rspec"
6
7
 
7
8
  FIXTURE = File.expand_path("../spec/support/fixtures/simple_class.rb", __dir__)
9
+ FIXTURE_SPEC = File.expand_path("../spec/support/fixtures/simple_class_spec.rb", __dir__)
10
+ COMPLEX_FIXTURE = File.expand_path("../lib/evilution/config.rb", __dir__)
11
+ COMPLEX_FIXTURE_SPEC = File.expand_path("../spec/evilution/config_spec.rb", __dir__)
8
12
  ITERATIONS = Integer(ENV.fetch("MEMORY_CHECK_ITERATIONS", 50))
9
13
  MAX_GROWTH_KB = Integer(ENV.fetch("MEMORY_CHECK_MAX_GROWTH_KB", 10_240))
10
14
 
@@ -90,5 +94,23 @@ if mutations.size >= 2
90
94
  end
91
95
  end
92
96
 
97
+ # 5. RSpec integration per-mutation with complex fixture
98
+ # Uses Config (227 LOC, 73 specs, 564 mutations) for realistic per-mutation load:
99
+ # more ExampleGroup subclasses, deeper spec nesting, heavier metadata.
100
+ complex_parser = Evilution::AST::Parser.new
101
+ complex_registry = Evilution::Mutator::Registry.default
102
+ complex_subjects = complex_parser.call(COMPLEX_FIXTURE)
103
+ complex_mutations = complex_subjects.flat_map { |s| complex_registry.mutations_for(s) }
104
+
105
+ integration = Evilution::Integration::RSpec.new(test_files: [COMPLEX_FIXTURE_SPEC])
106
+
107
+ all_passed &= run_check("RSpec integration per-mutation (Config)", iterations: 20, max_growth_kb: 20_480) do
108
+ mutation = complex_mutations.sample
109
+ result = integration.call(mutation)
110
+ raise "RSpec integration memory check failed: #{result[:error]}" if result[:error]
111
+
112
+ result
113
+ end
114
+
93
115
  puts all_passed ? "All memory checks passed." : "Some memory checks failed!"
94
116
  exit(all_passed ? 0 : 1)
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: evilution
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.17.0
4
+ version: 0.19.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Denis Kiselev
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2026-03-30 00:00:00.000000000 Z
11
+ date: 2026-04-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: diff-lcs
@@ -86,11 +86,13 @@ files:
86
86
  - lib/evilution/ast/pattern/filter.rb
87
87
  - lib/evilution/ast/pattern/matcher.rb
88
88
  - lib/evilution/ast/pattern/parser.rb
89
+ - lib/evilution/ast/sorbet_sig_detector.rb
89
90
  - lib/evilution/ast/source_surgeon.rb
90
91
  - lib/evilution/baseline.rb
91
92
  - lib/evilution/cache.rb
92
93
  - lib/evilution/cli.rb
93
94
  - lib/evilution/config.rb
95
+ - lib/evilution/disable_comment.rb
94
96
  - lib/evilution/equivalent.rb
95
97
  - lib/evilution/equivalent/detector.rb
96
98
  - lib/evilution/equivalent/heuristic.rb
@@ -136,11 +138,13 @@ files:
136
138
  - lib/evilution/mutator/operator/break_statement.rb
137
139
  - lib/evilution/mutator/operator/class_variable_write.rb
138
140
  - lib/evilution/mutator/operator/collection_replacement.rb
141
+ - lib/evilution/mutator/operator/collection_return.rb
139
142
  - lib/evilution/mutator/operator/comparison_replacement.rb
140
143
  - lib/evilution/mutator/operator/compound_assignment.rb
141
144
  - lib/evilution/mutator/operator/conditional_branch.rb
142
145
  - lib/evilution/mutator/operator/conditional_flip.rb
143
146
  - lib/evilution/mutator/operator/conditional_negation.rb
147
+ - lib/evilution/mutator/operator/defined_check.rb
144
148
  - lib/evilution/mutator/operator/ensure_removal.rb
145
149
  - lib/evilution/mutator/operator/explicit_super_mutation.rb
146
150
  - lib/evilution/mutator/operator/float_literal.rb
@@ -152,10 +156,12 @@ files:
152
156
  - lib/evilution/mutator/operator/inline_rescue.rb
153
157
  - lib/evilution/mutator/operator/instance_variable_write.rb
154
158
  - lib/evilution/mutator/operator/integer_literal.rb
159
+ - lib/evilution/mutator/operator/keyword_argument.rb
155
160
  - lib/evilution/mutator/operator/local_variable_assignment.rb
156
161
  - lib/evilution/mutator/operator/method_body_replacement.rb
157
162
  - lib/evilution/mutator/operator/method_call_removal.rb
158
163
  - lib/evilution/mutator/operator/mixin_removal.rb
164
+ - lib/evilution/mutator/operator/multiple_assignment.rb
159
165
  - lib/evilution/mutator/operator/negation_insertion.rb
160
166
  - lib/evilution/mutator/operator/next_statement.rb
161
167
  - lib/evilution/mutator/operator/nil_replacement.rb
@@ -165,19 +171,24 @@ files:
165
171
  - lib/evilution/mutator/operator/range_replacement.rb
166
172
  - lib/evilution/mutator/operator/receiver_replacement.rb
167
173
  - lib/evilution/mutator/operator/redo_statement.rb
174
+ - lib/evilution/mutator/operator/regex_capture.rb
168
175
  - lib/evilution/mutator/operator/regexp_mutation.rb
169
176
  - lib/evilution/mutator/operator/rescue_body_replacement.rb
170
177
  - lib/evilution/mutator/operator/rescue_removal.rb
171
178
  - lib/evilution/mutator/operator/return_value_removal.rb
179
+ - lib/evilution/mutator/operator/scalar_return.rb
172
180
  - lib/evilution/mutator/operator/send_mutation.rb
181
+ - lib/evilution/mutator/operator/splat_operator.rb
173
182
  - lib/evilution/mutator/operator/statement_deletion.rb
174
183
  - lib/evilution/mutator/operator/string_literal.rb
175
184
  - lib/evilution/mutator/operator/superclass_removal.rb
176
185
  - lib/evilution/mutator/operator/symbol_literal.rb
186
+ - lib/evilution/mutator/operator/yield_statement.rb
177
187
  - lib/evilution/mutator/operator/zsuper_removal.rb
178
188
  - lib/evilution/mutator/registry.rb
179
189
  - lib/evilution/parallel.rb
180
190
  - lib/evilution/parallel/pool.rb
191
+ - lib/evilution/parallel/work_queue.rb
181
192
  - lib/evilution/reporter.rb
182
193
  - lib/evilution/reporter/cli.rb
183
194
  - lib/evilution/reporter/html.rb
@@ -189,6 +200,7 @@ files:
189
200
  - lib/evilution/result/summary.rb
190
201
  - lib/evilution/runner.rb
191
202
  - lib/evilution/session.rb
203
+ - lib/evilution/session/diff.rb
192
204
  - lib/evilution/session/store.rb
193
205
  - lib/evilution/spec_resolver.rb
194
206
  - lib/evilution/subject.rb