evilution 0.27.0 → 0.28.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 (70) hide show
  1. checksums.yaml +4 -4
  2. data/.beads/interactions.jsonl +13 -0
  3. data/.rubocop_todo.yml +0 -1
  4. data/CHANGELOG.md +32 -0
  5. data/README.md +19 -0
  6. data/lib/evilution/baseline.rb +5 -4
  7. data/lib/evilution/cli/parser/options_builder.rb +7 -0
  8. data/lib/evilution/compare/diff_extractor/evilution.rb +22 -0
  9. data/lib/evilution/compare/diff_extractor/mutant.rb +30 -0
  10. data/lib/evilution/compare/diff_extractor.rb +6 -0
  11. data/lib/evilution/compare/fingerprint.rb +15 -72
  12. data/lib/evilution/compare/line_normalizer.rb +72 -0
  13. data/lib/evilution/compare/normalizer.rb +17 -4
  14. data/lib/evilution/config/validators/profile.rb +11 -0
  15. data/lib/evilution/config.rb +40 -23
  16. data/lib/evilution/integration/crash_detector.rb +2 -2
  17. data/lib/evilution/integration/loading/source_evaluator.rb +6 -2
  18. data/lib/evilution/integration/minitest_crash_detector.rb +2 -2
  19. data/lib/evilution/integration/rspec/state_guard/object_space_example_groups.rb +11 -3
  20. data/lib/evilution/isolation/fork.rb +16 -11
  21. data/lib/evilution/isolation/in_process.rb +10 -6
  22. data/lib/evilution/mcp/info_tool.rb +0 -2
  23. data/lib/evilution/mcp/mutate_tool/progress_streamer.rb +5 -1
  24. data/lib/evilution/mcp/session_tool.rb +0 -2
  25. data/lib/evilution/mutation.rb +47 -27
  26. data/lib/evilution/mutator/base.rb +8 -8
  27. data/lib/evilution/mutator/operator/predicate_to_nil.rb +20 -0
  28. data/lib/evilution/mutator/registry.rb +20 -0
  29. data/lib/evilution/parallel/work_queue/channel/frame.rb +5 -1
  30. data/lib/evilution/parallel/work_queue/worker/loop.rb +1 -1
  31. data/lib/evilution/process_cleanup.rb +19 -0
  32. data/lib/evilution/reporter/html/baseline_keys.rb +1 -1
  33. data/lib/evilution/reporter/html/diff_formatter.rb +1 -1
  34. data/lib/evilution/reporter/html/escape.rb +1 -1
  35. data/lib/evilution/reporter/html/section.rb +1 -1
  36. data/lib/evilution/reporter/html/sections.rb +4 -2
  37. data/lib/evilution/reporter/html/stylesheet.rb +1 -1
  38. data/lib/evilution/reporter/html.rb +8 -3
  39. data/lib/evilution/reporter/suggestion/registry.rb +1 -5
  40. data/lib/evilution/reporter/suggestion/templates/generic.rb +1 -1
  41. data/lib/evilution/reporter/suggestion/templates/minitest.rb +349 -643
  42. data/lib/evilution/reporter/suggestion/templates/rspec.rb +351 -598
  43. data/lib/evilution/reporter/suggestion/templates.rb +6 -0
  44. data/lib/evilution/result/error_info.rb +20 -0
  45. data/lib/evilution/result/memory_stats.rb +20 -0
  46. data/lib/evilution/result/mutation_result.rb +30 -14
  47. data/lib/evilution/runner/baseline_runner.rb +1 -2
  48. data/lib/evilution/runner/diagnostics.rb +1 -2
  49. data/lib/evilution/runner/isolation_resolver.rb +1 -2
  50. data/lib/evilution/runner/mutation_executor/mutation_runner.rb +1 -3
  51. data/lib/evilution/runner/mutation_executor/neutralization_pipeline.rb +1 -2
  52. data/lib/evilution/runner/mutation_executor/neutralizer/baseline_failed.rb +3 -10
  53. data/lib/evilution/runner/mutation_executor/neutralizer/infra_error.rb +3 -10
  54. data/lib/evilution/runner/mutation_executor/neutralizer.rb +11 -0
  55. data/lib/evilution/runner/mutation_executor/result_cache.rb +1 -3
  56. data/lib/evilution/runner/mutation_executor/result_notifier.rb +1 -3
  57. data/lib/evilution/runner/mutation_executor/result_packer.rb +11 -9
  58. data/lib/evilution/runner/mutation_executor/strategy/parallel.rb +1 -3
  59. data/lib/evilution/runner/mutation_executor/strategy/sequential.rb +1 -3
  60. data/lib/evilution/runner/mutation_executor/strategy.rb +11 -0
  61. data/lib/evilution/runner/mutation_executor.rb +12 -20
  62. data/lib/evilution/runner/mutation_planner.rb +1 -2
  63. data/lib/evilution/runner/report_publisher.rb +1 -2
  64. data/lib/evilution/runner/subject_pipeline.rb +1 -2
  65. data/lib/evilution/runner.rb +33 -31
  66. data/lib/evilution/version.rb +1 -1
  67. data/lib/evilution.rb +1 -0
  68. data/script/memory_check +3 -1
  69. metadata +14 -3
  70. data/lib/evilution/reporter/html/namespace.rb +0 -11
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../suggestion"
4
+
5
+ module Evilution::Reporter::Suggestion::Templates
6
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../result"
4
+
5
+ class Evilution::Result::ErrorInfo
6
+ attr_reader :message, :klass, :backtrace
7
+
8
+ def self.from_fields(message: nil, klass: nil, backtrace: nil)
9
+ return nil if message.nil? && klass.nil? && backtrace.nil?
10
+
11
+ new(message: message, klass: klass, backtrace: backtrace)
12
+ end
13
+
14
+ def initialize(message: nil, klass: nil, backtrace: nil)
15
+ @message = message
16
+ @klass = klass
17
+ @backtrace = backtrace.nil? ? nil : backtrace.dup.freeze
18
+ freeze
19
+ end
20
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../result"
4
+
5
+ class Evilution::Result::MemoryStats
6
+ attr_reader :child_rss_kb, :memory_delta_kb, :parent_rss_kb
7
+
8
+ def self.from_fields(child_rss_kb: nil, memory_delta_kb: nil, parent_rss_kb: nil)
9
+ return nil if child_rss_kb.nil? && memory_delta_kb.nil? && parent_rss_kb.nil?
10
+
11
+ new(child_rss_kb: child_rss_kb, memory_delta_kb: memory_delta_kb, parent_rss_kb: parent_rss_kb)
12
+ end
13
+
14
+ def initialize(child_rss_kb: nil, memory_delta_kb: nil, parent_rss_kb: nil)
15
+ @child_rss_kb = child_rss_kb
16
+ @memory_delta_kb = memory_delta_kb
17
+ @parent_rss_kb = parent_rss_kb
18
+ freeze
19
+ end
20
+ end
@@ -1,20 +1,16 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative "../result"
4
+ require_relative "error_info"
5
+ require_relative "memory_stats"
4
6
 
5
7
  class Evilution::Result::MutationResult
6
8
  STATUSES = %i[killed survived timeout error neutral equivalent unresolved unparseable].freeze
7
9
 
8
- attr_reader :mutation, :status, :duration, :killing_test, :test_command,
9
- :child_rss_kb, :memory_delta_kb, :parent_rss_kb,
10
- :error_message, :error_class, :error_backtrace
10
+ attr_reader :mutation, :status, :duration, :killing_test, :test_command, :memory, :error
11
11
 
12
- # rubocop:disable Metrics/ParameterLists
13
12
  def initialize(mutation:, status:, duration: 0.0, killing_test: nil,
14
- test_command: nil, child_rss_kb: nil, memory_delta_kb: nil,
15
- parent_rss_kb: nil, error_message: nil, error_class: nil,
16
- error_backtrace: nil)
17
- # rubocop:enable Metrics/ParameterLists
13
+ test_command: nil, memory: nil, error: nil)
18
14
  raise ArgumentError, "invalid status: #{status}" unless STATUSES.include?(status)
19
15
 
20
16
  @mutation = mutation
@@ -22,15 +18,35 @@ class Evilution::Result::MutationResult
22
18
  @duration = duration
23
19
  @killing_test = killing_test
24
20
  @test_command = test_command
25
- @child_rss_kb = child_rss_kb
26
- @memory_delta_kb = memory_delta_kb
27
- @parent_rss_kb = parent_rss_kb
28
- @error_message = error_message
29
- @error_class = error_class
30
- @error_backtrace = error_backtrace.nil? ? nil : error_backtrace.dup.freeze
21
+ @memory = memory
22
+ @error = error
31
23
  freeze
32
24
  end
33
25
 
26
+ def child_rss_kb
27
+ @memory.nil? ? nil : @memory.child_rss_kb
28
+ end
29
+
30
+ def memory_delta_kb
31
+ @memory.nil? ? nil : @memory.memory_delta_kb
32
+ end
33
+
34
+ def parent_rss_kb
35
+ @memory.nil? ? nil : @memory.parent_rss_kb
36
+ end
37
+
38
+ def error_message
39
+ @error.nil? ? nil : @error.message
40
+ end
41
+
42
+ def error_class
43
+ @error.nil? ? nil : @error.klass
44
+ end
45
+
46
+ def error_backtrace
47
+ @error.nil? ? nil : @error.backtrace
48
+ end
49
+
34
50
  def killed?
35
51
  status == :killed
36
52
  end
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative "../runner"
3
4
  require_relative "../baseline"
4
5
  require_relative "../spec_resolver"
5
6
  require_relative "../integration/rspec"
@@ -8,8 +9,6 @@ require_relative "../example_filter"
8
9
  require_relative "../spec_ast_cache"
9
10
  require_relative "../source_ast_cache"
10
11
 
11
- class Evilution::Runner; end unless defined?(Evilution::Runner) # rubocop:disable Lint/EmptyClass
12
-
13
12
  unless defined?(Evilution::Runner::INTEGRATIONS)
14
13
  Evilution::Runner::INTEGRATIONS = {
15
14
  rspec: Evilution::Integration::RSpec,
@@ -1,10 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative "../runner"
3
4
  require_relative "../memory"
4
5
  require_relative "../parallel/pool"
5
6
 
6
- class Evilution::Runner; end unless defined?(Evilution::Runner) # rubocop:disable Lint/EmptyClass
7
-
8
7
  class Evilution::Runner::Diagnostics
9
8
  def initialize(config, stderr: $stderr)
10
9
  @config = config
@@ -1,11 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative "../runner"
3
4
  require_relative "../isolation/fork"
4
5
  require_relative "../isolation/in_process"
5
6
  require_relative "../rails_detector"
6
7
 
7
- class Evilution::Runner; end unless defined?(Evilution::Runner) # rubocop:disable Lint/EmptyClass
8
-
9
8
  class Evilution::Runner::IsolationResolver
10
9
  PRELOAD_CANDIDATES = [
11
10
  File.join("spec", "rails_helper.rb"),
@@ -1,10 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative "../mutation_executor"
3
4
  require_relative "../../result/mutation_result"
4
5
 
5
- class Evilution::Runner; end unless defined?(Evilution::Runner) # rubocop:disable Lint/EmptyClass
6
- class Evilution::Runner::MutationExecutor; end unless defined?(Evilution::Runner::MutationExecutor) # rubocop:disable Lint/EmptyClass
7
-
8
6
  class Evilution::Runner::MutationExecutor::MutationRunner
9
7
  def initialize(config:, cache:, isolator:)
10
8
  @config = config
@@ -1,7 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- class Evilution::Runner; end unless defined?(Evilution::Runner) # rubocop:disable Lint/EmptyClass
4
- class Evilution::Runner::MutationExecutor; end unless defined?(Evilution::Runner::MutationExecutor) # rubocop:disable Lint/EmptyClass
3
+ require_relative "../mutation_executor"
5
4
 
6
5
  class Evilution::Runner::MutationExecutor::NeutralizationPipeline
7
6
  def initialize(neutralizers)
@@ -1,11 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative "../neutralizer"
3
4
  require_relative "../../../result/mutation_result"
4
5
 
5
- class Evilution::Runner; end unless defined?(Evilution::Runner) # rubocop:disable Lint/EmptyClass
6
- class Evilution::Runner::MutationExecutor; end unless defined?(Evilution::Runner::MutationExecutor) # rubocop:disable Lint/EmptyClass
7
- module Evilution::Runner::MutationExecutor::Neutralizer; end unless defined?(Evilution::Runner::MutationExecutor::Neutralizer)
8
-
9
6
  class Evilution::Runner::MutationExecutor::Neutralizer::BaselineFailed
10
7
  def initialize(config:, spec_resolver:, fallback_dir:)
11
8
  @config = config
@@ -35,12 +32,8 @@ class Evilution::Runner::MutationExecutor::Neutralizer::BaselineFailed
35
32
  status: :neutral,
36
33
  duration: result.duration,
37
34
  test_command: result.test_command,
38
- child_rss_kb: result.child_rss_kb,
39
- memory_delta_kb: result.memory_delta_kb,
40
- parent_rss_kb: result.parent_rss_kb,
41
- error_message: result.error_message,
42
- error_class: result.error_class,
43
- error_backtrace: result.error_backtrace
35
+ memory: result.memory,
36
+ error: result.error
44
37
  )
45
38
  end
46
39
  end
@@ -1,11 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative "../neutralizer"
3
4
  require_relative "../../../result/mutation_result"
4
5
 
5
- class Evilution::Runner; end unless defined?(Evilution::Runner) # rubocop:disable Lint/EmptyClass
6
- class Evilution::Runner::MutationExecutor; end unless defined?(Evilution::Runner::MutationExecutor) # rubocop:disable Lint/EmptyClass
7
- module Evilution::Runner::MutationExecutor::Neutralizer; end unless defined?(Evilution::Runner::MutationExecutor::Neutralizer)
8
-
9
6
  # Reclassify results as :neutral when the failure was caused by test
10
7
  # infrastructure rather than by the mutation. Two independent paths:
11
8
  #
@@ -64,12 +61,8 @@ class Evilution::Runner::MutationExecutor::Neutralizer::InfraError
64
61
  status: :neutral,
65
62
  duration: result.duration,
66
63
  test_command: result.test_command,
67
- child_rss_kb: result.child_rss_kb,
68
- memory_delta_kb: result.memory_delta_kb,
69
- parent_rss_kb: result.parent_rss_kb,
70
- error_message: result.error_message,
71
- error_class: result.error_class,
72
- error_backtrace: result.error_backtrace
64
+ memory: result.memory,
65
+ error: result.error
73
66
  )
74
67
  end
75
68
  end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../mutation_executor"
4
+
5
+ # Namespace for MutationExecutor's neutralization rules (InfraError,
6
+ # BaselineFailed). Concrete neutralizer classes live in neutralizer/*.rb and
7
+ # are autoloaded on first reference.
8
+ module Evilution::Runner::MutationExecutor::Neutralizer
9
+ autoload :InfraError, File.expand_path("neutralizer/infra_error", __dir__)
10
+ autoload :BaselineFailed, File.expand_path("neutralizer/baseline_failed", __dir__)
11
+ end
@@ -1,10 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative "../mutation_executor"
3
4
  require_relative "../../result/mutation_result"
4
5
 
5
- class Evilution::Runner; end unless defined?(Evilution::Runner) # rubocop:disable Lint/EmptyClass
6
- class Evilution::Runner::MutationExecutor; end unless defined?(Evilution::Runner::MutationExecutor) # rubocop:disable Lint/EmptyClass
7
-
8
6
  class Evilution::Runner::MutationExecutor::ResultCache
9
7
  CACHEABLE_STATUSES = %i[killed timeout].freeze
10
8
  private_constant :CACHEABLE_STATUSES
@@ -1,10 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative "../mutation_executor"
3
4
  require_relative "../../reporter/progress_bar"
4
5
 
5
- class Evilution::Runner; end unless defined?(Evilution::Runner) # rubocop:disable Lint/EmptyClass
6
- class Evilution::Runner::MutationExecutor; end unless defined?(Evilution::Runner::MutationExecutor) # rubocop:disable Lint/EmptyClass
7
-
8
6
  class Evilution::Runner::MutationExecutor::ResultNotifier
9
7
  def initialize(config, diagnostics:, on_result:)
10
8
  @config = config
@@ -1,10 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative "../mutation_executor"
3
4
  require_relative "../../result/mutation_result"
4
5
 
5
- class Evilution::Runner; end unless defined?(Evilution::Runner) # rubocop:disable Lint/EmptyClass
6
- class Evilution::Runner::MutationExecutor; end unless defined?(Evilution::Runner::MutationExecutor) # rubocop:disable Lint/EmptyClass
7
-
8
6
  class Evilution::Runner::MutationExecutor::ResultPacker
9
7
  def compact(result)
10
8
  {
@@ -28,12 +26,16 @@ class Evilution::Runner::MutationExecutor::ResultPacker
28
26
  duration: data[:duration],
29
27
  killing_test: data[:killing_test],
30
28
  test_command: data[:test_command],
31
- child_rss_kb: data[:child_rss_kb],
32
- memory_delta_kb: data[:memory_delta_kb],
33
- parent_rss_kb: data[:parent_rss_kb],
34
- error_message: data[:error_message],
35
- error_class: data[:error_class],
36
- error_backtrace: data[:error_backtrace]
29
+ memory: Evilution::Result::MemoryStats.from_fields(
30
+ child_rss_kb: data[:child_rss_kb],
31
+ memory_delta_kb: data[:memory_delta_kb],
32
+ parent_rss_kb: data[:parent_rss_kb]
33
+ ),
34
+ error: Evilution::Result::ErrorInfo.from_fields(
35
+ message: data[:error_message],
36
+ klass: data[:error_class],
37
+ backtrace: data[:error_backtrace]
38
+ )
37
39
  )
38
40
  end
39
41
  end
@@ -1,8 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- class Evilution::Runner; end unless defined?(Evilution::Runner) # rubocop:disable Lint/EmptyClass
4
- class Evilution::Runner::MutationExecutor; end unless defined?(Evilution::Runner::MutationExecutor) # rubocop:disable Lint/EmptyClass
5
- module Evilution::Runner::MutationExecutor::Strategy; end unless defined?(Evilution::Runner::MutationExecutor::Strategy)
3
+ require_relative "../strategy"
6
4
 
7
5
  class Evilution::Runner::MutationExecutor::Strategy::Parallel
8
6
  def initialize(cache:, isolator:, packer:, pipeline:, notifier:, pool_factory:, config:, diagnostics: nil)
@@ -1,8 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- class Evilution::Runner; end unless defined?(Evilution::Runner) # rubocop:disable Lint/EmptyClass
4
- class Evilution::Runner::MutationExecutor; end unless defined?(Evilution::Runner::MutationExecutor) # rubocop:disable Lint/EmptyClass
5
- module Evilution::Runner::MutationExecutor::Strategy; end unless defined?(Evilution::Runner::MutationExecutor::Strategy)
3
+ require_relative "../strategy"
6
4
 
7
5
  class Evilution::Runner::MutationExecutor::Strategy::Sequential
8
6
  def initialize(runner:, pipeline:, notifier:)
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../mutation_executor"
4
+
5
+ # Namespace for MutationExecutor's execution strategies (Sequential, Parallel).
6
+ # Concrete strategy classes live in strategy/{sequential,parallel}.rb and are
7
+ # autoloaded on first reference.
8
+ module Evilution::Runner::MutationExecutor::Strategy
9
+ autoload :Sequential, File.expand_path("strategy/sequential", __dir__)
10
+ autoload :Parallel, File.expand_path("strategy/parallel", __dir__)
11
+ end
@@ -1,23 +1,15 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative "../parallel/pool"
4
- require_relative "mutation_executor/result_cache"
5
- require_relative "mutation_executor/result_packer"
6
- require_relative "mutation_executor/result_notifier"
7
- require_relative "mutation_executor/mutation_runner"
8
- require_relative "mutation_executor/neutralization_pipeline"
9
- require_relative "mutation_executor/neutralizer/infra_error"
10
- require_relative "mutation_executor/neutralizer/baseline_failed"
11
- require_relative "mutation_executor/strategy/sequential"
12
- require_relative "mutation_executor/strategy/parallel"
13
-
14
- class Evilution::Runner; end unless defined?(Evilution::Runner) # rubocop:disable Lint/EmptyClass
3
+ require_relative "../runner"
15
4
 
16
5
  class Evilution::Runner::MutationExecutor
17
- InfraError = Neutralizer::InfraError
18
- BaselineFailed = Neutralizer::BaselineFailed
19
- Sequential = Strategy::Sequential
20
- Parallel = Strategy::Parallel
6
+ autoload :ResultCache, File.expand_path("mutation_executor/result_cache", __dir__)
7
+ autoload :ResultPacker, File.expand_path("mutation_executor/result_packer", __dir__)
8
+ autoload :ResultNotifier, File.expand_path("mutation_executor/result_notifier", __dir__)
9
+ autoload :MutationRunner, File.expand_path("mutation_executor/mutation_runner", __dir__)
10
+ autoload :NeutralizationPipeline, File.expand_path("mutation_executor/neutralization_pipeline", __dir__)
11
+ autoload :Strategy, File.expand_path("mutation_executor/strategy", __dir__)
12
+ autoload :Neutralizer, File.expand_path("mutation_executor/neutralizer", __dir__)
21
13
 
22
14
  def initialize(config, isolator:, baseline_runner:, cache:, hooks:, diagnostics:, on_result: nil)
23
15
  @config = config
@@ -53,8 +45,8 @@ class Evilution::Runner::MutationExecutor
53
45
  def build_pipeline(spec_resolver)
54
46
  NeutralizationPipeline.new(
55
47
  [
56
- InfraError.new,
57
- BaselineFailed.new(
48
+ Neutralizer::InfraError.new,
49
+ Neutralizer::BaselineFailed.new(
58
50
  config: @config,
59
51
  spec_resolver: spec_resolver || ->(_f) {},
60
52
  fallback_dir: @baseline_runner.neutralization_fallback_dir
@@ -64,7 +56,7 @@ class Evilution::Runner::MutationExecutor
64
56
  end
65
57
 
66
58
  def build_sequential(notifier, pipeline)
67
- Sequential.new(
59
+ Strategy::Sequential.new(
68
60
  runner: MutationRunner.new(config: @config, cache: @cache, isolator: @isolator),
69
61
  pipeline: pipeline,
70
62
  notifier: notifier
@@ -72,7 +64,7 @@ class Evilution::Runner::MutationExecutor
72
64
  end
73
65
 
74
66
  def build_parallel(notifier, pipeline)
75
- Parallel.new(
67
+ Strategy::Parallel.new(
76
68
  cache: @cache,
77
69
  isolator: @isolator,
78
70
  packer: @packer,
@@ -1,12 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative "../runner"
3
4
  require_relative "../disable_comment"
4
5
  require_relative "../ast/sorbet_sig_detector"
5
6
  require_relative "../ast/pattern/filter"
6
7
  require_relative "../equivalent/detector"
7
8
 
8
- class Evilution::Runner; end unless defined?(Evilution::Runner) # rubocop:disable Lint/EmptyClass
9
-
10
9
  class Evilution::Runner::MutationPlanner
11
10
  Plan = Struct.new(:enabled, :equivalent, :skipped_count, :disabled_mutations, keyword_init: true)
12
11
 
@@ -1,12 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative "../runner"
3
4
  require_relative "../reporter/json"
4
5
  require_relative "../reporter/cli"
5
6
  require_relative "../reporter/html"
6
7
  require_relative "../session/store"
7
8
 
8
- class Evilution::Runner; end unless defined?(Evilution::Runner) # rubocop:disable Lint/EmptyClass
9
-
10
9
  class Evilution::Runner::ReportPublisher
11
10
  def initialize(config)
12
11
  @config = config
@@ -1,10 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative "../runner"
3
4
  require_relative "../ast/inheritance_scanner"
4
5
  require_relative "../git/changed_files"
5
6
 
6
- class Evilution::Runner; end unless defined?(Evilution::Runner) # rubocop:disable Lint/EmptyClass
7
-
8
7
  class Evilution::Runner::SubjectPipeline
9
8
  def initialize(config, parser:)
10
9
  @config = config
@@ -1,36 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "fileutils"
4
- require_relative "config"
5
- require_relative "ast/parser"
6
- require_relative "memory"
7
- require_relative "mutator/registry"
8
- require_relative "isolation/fork"
9
- require_relative "isolation/in_process"
10
- require_relative "integration/rspec"
11
- require_relative "integration/minitest"
12
- require_relative "reporter/json"
13
- require_relative "reporter/cli"
14
- require_relative "reporter/html"
15
- require_relative "reporter/suggestion"
16
- require_relative "git/changed_files"
17
- require_relative "result/mutation_result"
18
- require_relative "result/summary"
19
- require_relative "baseline"
20
- require_relative "cache"
21
- require_relative "parallel/pool"
22
- require_relative "session/store"
23
- require_relative "temp_dir_tracker"
24
- require_relative "rails_detector"
25
- require_relative "parallel_db_warning"
26
- require_relative "child_output"
27
- require_relative "runner/subject_pipeline"
28
- require_relative "runner/mutation_planner"
29
- require_relative "runner/isolation_resolver"
30
- require_relative "runner/baseline_runner"
31
- require_relative "runner/diagnostics"
32
- require_relative "runner/mutation_executor"
33
- require_relative "runner/report_publisher"
4
+ require_relative "../evilution"
34
5
 
35
6
  class Evilution::Runner
36
7
  attr_reader :config
@@ -40,7 +11,7 @@ class Evilution::Runner
40
11
  @on_result = on_result
41
12
  @hooks = hooks
42
13
  @parser = Evilution::AST::Parser.new
43
- @registry = Evilution::Mutator::Registry.default
14
+ @registry = Evilution::Mutator::Registry.for_profile(config.profile)
44
15
  @cache = config.incremental? ? Evilution::Cache.new : nil
45
16
  end
46
17
 
@@ -213,3 +184,34 @@ class Evilution::Runner
213
184
  diagnostics.log_memory(phase, context)
214
185
  end
215
186
  end
187
+
188
+ require_relative "config"
189
+ require_relative "ast/parser"
190
+ require_relative "memory"
191
+ require_relative "mutator/registry"
192
+ require_relative "isolation/fork"
193
+ require_relative "isolation/in_process"
194
+ require_relative "integration/rspec"
195
+ require_relative "integration/minitest"
196
+ require_relative "reporter/json"
197
+ require_relative "reporter/cli"
198
+ require_relative "reporter/html"
199
+ require_relative "reporter/suggestion"
200
+ require_relative "git/changed_files"
201
+ require_relative "result/mutation_result"
202
+ require_relative "result/summary"
203
+ require_relative "baseline"
204
+ require_relative "cache"
205
+ require_relative "parallel/pool"
206
+ require_relative "session/store"
207
+ require_relative "temp_dir_tracker"
208
+ require_relative "rails_detector"
209
+ require_relative "parallel_db_warning"
210
+ require_relative "child_output"
211
+ require_relative "runner/subject_pipeline"
212
+ require_relative "runner/mutation_planner"
213
+ require_relative "runner/isolation_resolver"
214
+ require_relative "runner/baseline_runner"
215
+ require_relative "runner/diagnostics"
216
+ require_relative "runner/mutation_executor"
217
+ require_relative "runner/report_publisher"
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Evilution
4
- VERSION = "0.27.0"
4
+ VERSION = "0.28.0"
5
5
  end
data/lib/evilution.rb CHANGED
@@ -89,6 +89,7 @@ require_relative "evilution/mutator/operator/string_interpolation"
89
89
  require_relative "evilution/mutator/operator/retry_removal"
90
90
  require_relative "evilution/mutator/operator/case_when"
91
91
  require_relative "evilution/mutator/operator/predicate_replacement"
92
+ require_relative "evilution/mutator/operator/predicate_to_nil"
92
93
  require_relative "evilution/mutator/operator/equality_to_identity"
93
94
  require_relative "evilution/mutator/operator/lambda_body"
94
95
  require_relative "evilution/mutator/operator/begin_unwrap"
data/script/memory_check CHANGED
@@ -88,7 +88,9 @@ if mutations.size >= 2
88
88
  batch.zip(compact_results).map do |mutation, data|
89
89
  Evilution::Result::MutationResult.new(
90
90
  mutation: mutation, status: data[:status], duration: data[:duration],
91
- child_rss_kb: data[:child_rss_kb], memory_delta_kb: data[:memory_delta_kb]
91
+ memory: Evilution::Result::MemoryStats.new(
92
+ child_rss_kb: data[:child_rss_kb], memory_delta_kb: data[:memory_delta_kb]
93
+ )
92
94
  )
93
95
  end
94
96
  end
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.27.0
4
+ version: 0.28.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-04-26 00:00:00.000000000 Z
11
+ date: 2026-05-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: diff-lcs
@@ -158,8 +158,12 @@ files:
158
158
  - lib/evilution/compare.rb
159
159
  - lib/evilution/compare/categorizer.rb
160
160
  - lib/evilution/compare/detector.rb
161
+ - lib/evilution/compare/diff_extractor.rb
162
+ - lib/evilution/compare/diff_extractor/evilution.rb
163
+ - lib/evilution/compare/diff_extractor/mutant.rb
161
164
  - lib/evilution/compare/fingerprint.rb
162
165
  - lib/evilution/compare/invalid_input.rb
166
+ - lib/evilution/compare/line_normalizer.rb
163
167
  - lib/evilution/compare/normalizer.rb
164
168
  - lib/evilution/compare/record.rb
165
169
  - lib/evilution/config.rb
@@ -180,6 +184,7 @@ files:
180
184
  - lib/evilution/config/validators/isolation.rb
181
185
  - lib/evilution/config/validators/jobs.rb
182
186
  - lib/evilution/config/validators/preload.rb
187
+ - lib/evilution/config/validators/profile.rb
183
188
  - lib/evilution/config/validators/spec_mappings.rb
184
189
  - lib/evilution/config/validators/spec_pattern.rb
185
190
  - lib/evilution/disable_comment.rb
@@ -316,6 +321,7 @@ files:
316
321
  - lib/evilution/mutator/operator/pattern_matching_array.rb
317
322
  - lib/evilution/mutator/operator/pattern_matching_guard.rb
318
323
  - lib/evilution/mutator/operator/predicate_replacement.rb
324
+ - lib/evilution/mutator/operator/predicate_to_nil.rb
319
325
  - lib/evilution/mutator/operator/range_replacement.rb
320
326
  - lib/evilution/mutator/operator/receiver_replacement.rb
321
327
  - lib/evilution/mutator/operator/redo_statement.rb
@@ -352,6 +358,7 @@ files:
352
358
  - lib/evilution/parallel/work_queue/worker/loop.rb
353
359
  - lib/evilution/parallel/work_queue/worker_stat.rb
354
360
  - lib/evilution/parallel_db_warning.rb
361
+ - lib/evilution/process_cleanup.rb
355
362
  - lib/evilution/rails_detector.rb
356
363
  - lib/evilution/related_spec_heuristic.rb
357
364
  - lib/evilution/reporter.rb
@@ -381,7 +388,6 @@ files:
381
388
  - lib/evilution/reporter/html/baseline_keys.rb
382
389
  - lib/evilution/reporter/html/diff_formatter.rb
383
390
  - lib/evilution/reporter/html/escape.rb
384
- - lib/evilution/reporter/html/namespace.rb
385
391
  - lib/evilution/reporter/html/report.rb
386
392
  - lib/evilution/reporter/html/section.rb
387
393
  - lib/evilution/reporter/html/sections.rb
@@ -418,12 +424,15 @@ files:
418
424
  - lib/evilution/reporter/suggestion.rb
419
425
  - lib/evilution/reporter/suggestion/diff_helpers.rb
420
426
  - lib/evilution/reporter/suggestion/registry.rb
427
+ - lib/evilution/reporter/suggestion/templates.rb
421
428
  - lib/evilution/reporter/suggestion/templates/generic.rb
422
429
  - lib/evilution/reporter/suggestion/templates/minitest.rb
423
430
  - lib/evilution/reporter/suggestion/templates/rspec.rb
424
431
  - lib/evilution/result.rb
425
432
  - lib/evilution/result/coverage_gap.rb
426
433
  - lib/evilution/result/coverage_gap_grouper.rb
434
+ - lib/evilution/result/error_info.rb
435
+ - lib/evilution/result/memory_stats.rb
427
436
  - lib/evilution/result/mutation_result.rb
428
437
  - lib/evilution/result/summary.rb
429
438
  - lib/evilution/runner.rb
@@ -433,11 +442,13 @@ files:
433
442
  - lib/evilution/runner/mutation_executor.rb
434
443
  - lib/evilution/runner/mutation_executor/mutation_runner.rb
435
444
  - lib/evilution/runner/mutation_executor/neutralization_pipeline.rb
445
+ - lib/evilution/runner/mutation_executor/neutralizer.rb
436
446
  - lib/evilution/runner/mutation_executor/neutralizer/baseline_failed.rb
437
447
  - lib/evilution/runner/mutation_executor/neutralizer/infra_error.rb
438
448
  - lib/evilution/runner/mutation_executor/result_cache.rb
439
449
  - lib/evilution/runner/mutation_executor/result_notifier.rb
440
450
  - lib/evilution/runner/mutation_executor/result_packer.rb
451
+ - lib/evilution/runner/mutation_executor/strategy.rb
441
452
  - lib/evilution/runner/mutation_executor/strategy/parallel.rb
442
453
  - lib/evilution/runner/mutation_executor/strategy/sequential.rb
443
454
  - lib/evilution/runner/mutation_planner.rb