From 3916a42bb2bfe3384b81cdd76015763465e5d2a1 Mon Sep 17 00:00:00 2001 From: Dan Kubb Date: Mon, 16 Mar 2026 19:12:56 -0700 Subject: [PATCH 01/25] refactor: use rstrip instead of strip in InvalidToken The heredoc uses <<~ which already strips leading indentation, making left-strip unnecessary. Mutant flagged the .strip -> .rstrip mutation as alive because no test exercises leading whitespace in the heredoc output. Since <<~ guarantees there is none, .rstrip is the more constrained primitive that satisfies the requirement. --- ruby/lib/mutant/ast/pattern/lexer.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ruby/lib/mutant/ast/pattern/lexer.rb b/ruby/lib/mutant/ast/pattern/lexer.rb index b27fe0bcc..4d98f468b 100644 --- a/ruby/lib/mutant/ast/pattern/lexer.rb +++ b/ruby/lib/mutant/ast/pattern/lexer.rb @@ -26,7 +26,7 @@ class Error class InvalidToken < self def display_message - <<~MESSAGE.strip + <<~MESSAGE.rstrip Invalid #{token.type} token: #{token.display_location} MESSAGE From 5c39e6b4467009be2152da5cc962786ec10cf649 Mon Sep 17 00:00:00 2001 From: Dan Kubb Date: Mon, 16 Mar 2026 19:12:57 -0700 Subject: [PATCH 02/25] docs: add burn-down baseline to ignore list 25 subjects have alive mutations (242 total alive out of 25,682). Adding them to the ignore list with documented alive counts establishes a passing baseline so the burn-down can proceed one subject at a time. --- ruby/mutant.yml | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/ruby/mutant.yml b/ruby/mutant.yml index bafc02a01..bf51bb4a1 100644 --- a/ruby/mutant.yml +++ b/ruby/mutant.yml @@ -24,3 +24,31 @@ matcher: - Mutant::Mutator::Node::Arguments#emit_argument_presence - Mutant::Mutator::Node::Arguments#removed_block_arg? - Mutant::Mutator::Node::BlockPass#dispatch + # mutation crashes killfork in zombie mode; Timer#now is used by mutant infrastructure + - Mutant::Timer#now + # burn-down baseline + - Mutant::AST::Pattern::Parser#optional # 1 alive + - Mutant::Integration::Rspec#setup # 14 alive + - Mutant::Matcher::Method::Evaluator#matched_view # 6 alive + - Mutant::Meta::Example::Verification#format_mutations # 24 alive + - Mutant::Meta::Example::Verification#no_diff_report # 25 alive + - Mutant::Mutator::Node::Arguments#emit_procarg0_removal # 2 alive + - Mutant::Mutator::Node::Case#emit_else_mutations # 1 alive + - Mutant::Mutator::Node::Define#emit_optarg_body_assignments # 3 alive + - Mutant::Mutator::Node::Index#emit_drop_mutation # 1 alive + - Mutant::Mutator::Node::Kwargs#emit_argument_mutations # 3 alive + - Mutant::Mutator::Node::Kwargs#forbid_argument? # 9 alive + - Mutant::Mutator::Node::ProcargZero#dispatch # 5 alive + - Mutant::Mutator::Node::Send#emit_receiver_selector_mutations # 1 alive + - Mutant::Mutator::Node#mutate_single_child # 30 alive + - Mutant::Parallel::Driver#status # 1 alive + - Mutant::Reporter::CLI::Format::Progressive#start # 10 alive + - Mutant::Reporter::CLI::Format::Progressive#test_start # 11 alive + - Mutant::Reporter::CLI::Printer::Config#run # 3 alive + - Mutant::RequireHighjack.call # 8 alive + - Mutant::Result::ClassMethods#sum # 2 alive + - Mutant::Scope#match_expressions # 38 alive + - Mutant::Scope#nesting # 18 alive + - Mutant::Test::Runner::Sink#status # 1 alive + - Mutant::World#capture_command # 7 alive + - Mutant::Zombifier#include? # 9 alive From ca6766df5bedcfaf37dee2f2b2ff3647e9623068 Mon Sep 17 00:00:00 2001 From: Dan Kubb Date: Mon, 16 Mar 2026 19:12:58 -0700 Subject: [PATCH 03/25] refactor: use Array#sum in Result::ClassMethods#sum Array#sum is the more constrained primitive for numeric addition. The explicit initial value 0 is also unnecessary since sum defaults to 0 for numeric arrays. Mutant flagged both .reduce(0, :+) -> .sum(0) and .sum(0) -> .sum as alive mutations. Applying both simplifications achieves 100% coverage for this subject. --- ruby/lib/mutant/result.rb | 2 +- ruby/mutant.yml | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/ruby/lib/mutant/result.rb b/ruby/lib/mutant/result.rb index e80dc1cc7..99b9f6c3d 100644 --- a/ruby/lib/mutant/result.rb +++ b/ruby/lib/mutant/result.rb @@ -35,7 +35,7 @@ module ClassMethods # @return [undefined] def sum(name, collection) define_method(name) do - public_send(collection).map(&name).reduce(0, :+) + public_send(collection).map(&name).sum end memoize(name) end diff --git a/ruby/mutant.yml b/ruby/mutant.yml index bf51bb4a1..77d6e3ba3 100644 --- a/ruby/mutant.yml +++ b/ruby/mutant.yml @@ -46,7 +46,6 @@ matcher: - Mutant::Reporter::CLI::Format::Progressive#test_start # 11 alive - Mutant::Reporter::CLI::Printer::Config#run # 3 alive - Mutant::RequireHighjack.call # 8 alive - - Mutant::Result::ClassMethods#sum # 2 alive - Mutant::Scope#match_expressions # 38 alive - Mutant::Scope#nesting # 18 alive - Mutant::Test::Runner::Sink#status # 1 alive From 6e12d75c1ed3e52e7c8127a7df16c6650b1d2723 Mon Sep 17 00:00:00 2001 From: Dan Kubb Date: Mon, 16 Mar 2026 19:12:59 -0700 Subject: [PATCH 04/25] test: verify capture_command arguments in World spec Mutant flagged 7 alive mutations on the capture3 call arguments (splat, binmode keyword, etc.) because the test stub used receive_messages without argument matching. Switching to receive(:capture3).with(*command, binmode: true) kills all 7 mutations by verifying the exact arguments passed. --- ruby/mutant.yml | 1 - ruby/spec/unit/mutant/world_spec.rb | 4 +++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/ruby/mutant.yml b/ruby/mutant.yml index 77d6e3ba3..4363ff4eb 100644 --- a/ruby/mutant.yml +++ b/ruby/mutant.yml @@ -49,5 +49,4 @@ matcher: - Mutant::Scope#match_expressions # 38 alive - Mutant::Scope#nesting # 18 alive - Mutant::Test::Runner::Sink#status # 1 alive - - Mutant::World#capture_command # 7 alive - Mutant::Zombifier#include? # 9 alive diff --git a/ruby/spec/unit/mutant/world_spec.rb b/ruby/spec/unit/mutant/world_spec.rb index 80fb77938..acff1381a 100644 --- a/ruby/spec/unit/mutant/world_spec.rb +++ b/ruby/spec/unit/mutant/world_spec.rb @@ -81,7 +81,9 @@ def apply end before do - allow(open3).to receive_messages(capture3: [stdout, stderr, process_status]) + allow(open3).to receive(:capture3) + .with(*command, binmode: true) + .and_return([stdout, stderr, process_status]) end context 'when process exists successful' do From b6838f8a195ca39a3c300ca141b2886b731c94de Mon Sep 17 00:00:00 2001 From: Dan Kubb Date: Mon, 16 Mar 2026 19:13:00 -0700 Subject: [PATCH 05/25] refactor: remove unused token return from Parser#optional MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit No call site uses the returned token object — all callers only check truthiness (if/unless/break). The mutation removing the explicit token return was alive because advance_position returns a truthy Integer, which satisfies all existing call sites. --- ruby/lib/mutant/ast/pattern/parser.rb | 1 - ruby/mutant.yml | 1 - 2 files changed, 2 deletions(-) diff --git a/ruby/lib/mutant/ast/pattern/parser.rb b/ruby/lib/mutant/ast/pattern/parser.rb index 58523b079..e5386628a 100644 --- a/ruby/lib/mutant/ast/pattern/parser.rb +++ b/ruby/lib/mutant/ast/pattern/parser.rb @@ -144,7 +144,6 @@ def optional(type) return unless token&.type.equal?(type) advance_position - token end def parse_node_type diff --git a/ruby/mutant.yml b/ruby/mutant.yml index 4363ff4eb..b74df84a9 100644 --- a/ruby/mutant.yml +++ b/ruby/mutant.yml @@ -27,7 +27,6 @@ matcher: # mutation crashes killfork in zombie mode; Timer#now is used by mutant infrastructure - Mutant::Timer#now # burn-down baseline - - Mutant::AST::Pattern::Parser#optional # 1 alive - Mutant::Integration::Rspec#setup # 14 alive - Mutant::Matcher::Method::Evaluator#matched_view # 6 alive - Mutant::Meta::Example::Verification#format_mutations # 24 alive From 81d50be2d2b97a4c9a47513920b9d359cb86b021 Mon Sep 17 00:00:00 2001 From: Dan Kubb Date: Mon, 16 Mar 2026 19:13:01 -0700 Subject: [PATCH 06/25] refactor: use sort_by instead of sort_by! in Sink#status MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The in-place sort_by! mutates @test_results unnecessarily since the sorted array is immediately passed to Result::TestEnv.new. The non-mutating sort_by is the more constrained primitive — it avoids side effects on the instance variable while producing the same result for the caller. --- ruby/lib/mutant/test/runner/sink.rb | 2 +- ruby/mutant.yml | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/ruby/lib/mutant/test/runner/sink.rb b/ruby/lib/mutant/test/runner/sink.rb index 9c9852755..452986173 100644 --- a/ruby/lib/mutant/test/runner/sink.rb +++ b/ruby/lib/mutant/test/runner/sink.rb @@ -22,7 +22,7 @@ def status Result::TestEnv.new( env:, runtime: env.world.timer.now - @start, - test_results: @test_results.sort_by!(&:job_index) + test_results: @test_results.sort_by(&:job_index) ) end diff --git a/ruby/mutant.yml b/ruby/mutant.yml index b74df84a9..ef0055c6a 100644 --- a/ruby/mutant.yml +++ b/ruby/mutant.yml @@ -47,5 +47,4 @@ matcher: - Mutant::RequireHighjack.call # 8 alive - Mutant::Scope#match_expressions # 38 alive - Mutant::Scope#nesting # 18 alive - - Mutant::Test::Runner::Sink#status # 1 alive - Mutant::Zombifier#include? # 9 alive From 7f474da8a43499cdcbd38403c6639e5c7905cd13 Mon Sep 17 00:00:00 2001 From: Dan Kubb Date: Mon, 16 Mar 2026 19:13:02 -0700 Subject: [PATCH 07/25] refactor: remove else_branch variable from Case Mutant flagged the variable assignment as alive. The variable is used only once, so inlining it removes the mutation axis without changing behavior. --- ruby/lib/mutant/mutator/node/case.rb | 3 +-- ruby/mutant.yml | 1 - 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/ruby/lib/mutant/mutator/node/case.rb b/ruby/lib/mutant/mutator/node/case.rb index f181c6b33..ba6e16aaf 100644 --- a/ruby/lib/mutant/mutator/node/case.rb +++ b/ruby/lib/mutant/mutator/node/case.rb @@ -30,9 +30,8 @@ def emit_when_mutations end def emit_else_mutations - else_branch = children.last else_index = children.length - 1 - return unless else_branch + return unless children.fetch(else_index) mutate_child(else_index) emit_child_update(else_index, nil) end diff --git a/ruby/mutant.yml b/ruby/mutant.yml index ef0055c6a..a8aa74293 100644 --- a/ruby/mutant.yml +++ b/ruby/mutant.yml @@ -32,7 +32,6 @@ matcher: - Mutant::Meta::Example::Verification#format_mutations # 24 alive - Mutant::Meta::Example::Verification#no_diff_report # 25 alive - Mutant::Mutator::Node::Arguments#emit_procarg0_removal # 2 alive - - Mutant::Mutator::Node::Case#emit_else_mutations # 1 alive - Mutant::Mutator::Node::Define#emit_optarg_body_assignments # 3 alive - Mutant::Mutator::Node::Index#emit_drop_mutation # 1 alive - Mutant::Mutator::Node::Kwargs#emit_argument_mutations # 3 alive From 01c23cee65ce82f918c07cd3e0c4bc00a715b902 Mon Sep 17 00:00:00 2001 From: Dan Kubb Date: Mon, 16 Mar 2026 19:13:03 -0700 Subject: [PATCH 08/25] refactor: reuse Util.one result in Index#emit_drop_mutation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Mutant flagged mutations on indices.first. Reusing the return value of Util.one — already called on the previous line — removes the redundant indices.first call and its mutation axis. --- ruby/lib/mutant/mutator/node/index.rb | 8 ++++++-- ruby/mutant.yml | 1 - 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/ruby/lib/mutant/mutator/node/index.rb b/ruby/lib/mutant/mutator/node/index.rb index 3841d1272..dc9b5a922 100644 --- a/ruby/lib/mutant/mutator/node/index.rb +++ b/ruby/lib/mutant/mutator/node/index.rb @@ -33,9 +33,13 @@ def emit_send_forms end def emit_drop_mutation - return unless indices.one? && n_irange?(Mutant::Util.one(indices)) + return unless indices.one? - start, ending = *indices.first + range = Mutant::Util.one(indices) + + return unless n_irange?(range) + + start, ending = *range return unless ending.eql?(s(:int, -1)) diff --git a/ruby/mutant.yml b/ruby/mutant.yml index a8aa74293..26cec47f7 100644 --- a/ruby/mutant.yml +++ b/ruby/mutant.yml @@ -33,7 +33,6 @@ matcher: - Mutant::Meta::Example::Verification#no_diff_report # 25 alive - Mutant::Mutator::Node::Arguments#emit_procarg0_removal # 2 alive - Mutant::Mutator::Node::Define#emit_optarg_body_assignments # 3 alive - - Mutant::Mutator::Node::Index#emit_drop_mutation # 1 alive - Mutant::Mutator::Node::Kwargs#emit_argument_mutations # 3 alive - Mutant::Mutator::Node::Kwargs#forbid_argument? # 9 alive - Mutant::Mutator::Node::ProcargZero#dispatch # 5 alive From ec47e1f9c8800e6f0a20f8dadc74f4a3c442fd2e Mon Sep 17 00:00:00 2001 From: Dan Kubb Date: Mon, 16 Mar 2026 19:13:04 -0700 Subject: [PATCH 09/25] refactor: use public_method in Send receiver selector mutations Mutant replaces method(:name) with public_method(:name) as the more constrained primitive. Since emit_selector is a public method (defined via define_named_child), public_method is the correct form. Added Date.parse meta spec to cover receiver selector replacement mutations. --- ruby/lib/mutant/mutator/node/send.rb | 2 +- ruby/meta/send.rb | 22 ++++++++++++++++++++++ ruby/mutant.yml | 1 - 3 files changed, 23 insertions(+), 2 deletions(-) diff --git a/ruby/lib/mutant/mutator/node/send.rb b/ruby/lib/mutant/mutator/node/send.rb index 132fa8690..16f4b518a 100644 --- a/ruby/lib/mutant/mutator/node/send.rb +++ b/ruby/lib/mutant/mutator/node/send.rb @@ -164,7 +164,7 @@ def emit_receiver_selector_mutations RECEIVER_SELECTOR_REPLACEMENTS .fetch(receiver.children.last, EMPTY_HASH) .fetch(selector, EMPTY_ARRAY) - .each(&method(:emit_selector)) + .each(&public_method(:emit_selector)) end def emit_double_negation_mutation diff --git a/ruby/meta/send.rb b/ruby/meta/send.rb index f6e8c93b7..9239f0ce3 100644 --- a/ruby/meta/send.rb +++ b/ruby/meta/send.rb @@ -1,5 +1,27 @@ # frozen_string_literal: true +# Date.parse receiver selector replacements +Mutant::Meta::Example.add :send do + source 'Date.parse(foo)' + + singleton_mutations + mutation 'Date.jd(foo)' + mutation 'Date.civil(foo)' + mutation 'Date.strptime(foo)' + mutation 'Date.iso8601(foo)' + mutation 'Date.rfc3339(foo)' + mutation 'Date.xmlschema(foo)' + mutation 'Date.rfc2822(foo)' + mutation 'Date.rfc822(foo)' + mutation 'Date.httpdate(foo)' + mutation 'Date.jisx0301(foo)' + mutation 'Date.parse' + mutation 'Date.parse(nil)' + mutation 'self.parse(foo)' + mutation 'Date' + mutation 'foo' +end + Mutant::Meta::Example.add :send do source 'a > b' diff --git a/ruby/mutant.yml b/ruby/mutant.yml index 26cec47f7..e15ff48d1 100644 --- a/ruby/mutant.yml +++ b/ruby/mutant.yml @@ -36,7 +36,6 @@ matcher: - Mutant::Mutator::Node::Kwargs#emit_argument_mutations # 3 alive - Mutant::Mutator::Node::Kwargs#forbid_argument? # 9 alive - Mutant::Mutator::Node::ProcargZero#dispatch # 5 alive - - Mutant::Mutator::Node::Send#emit_receiver_selector_mutations # 1 alive - Mutant::Mutator::Node#mutate_single_child # 30 alive - Mutant::Parallel::Driver#status # 1 alive - Mutant::Reporter::CLI::Format::Progressive#start # 10 alive From f1598542111beb336d9db568d60d708a3902ec4a Mon Sep 17 00:00:00 2001 From: Dan Kubb Date: Mon, 16 Mar 2026 19:13:05 -0700 Subject: [PATCH 10/25] test: add partially done context for Parallel::Driver Mutant flagged alive mutations on Driver#status because no test exercised the partially-done state where active_jobs > 0 and some payloads are already complete. --- ruby/mutant.yml | 1 - ruby/spec/unit/mutant/parallel/driver_spec.rb | 16 ++++++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/ruby/mutant.yml b/ruby/mutant.yml index e15ff48d1..7bc4d96ea 100644 --- a/ruby/mutant.yml +++ b/ruby/mutant.yml @@ -37,7 +37,6 @@ matcher: - Mutant::Mutator::Node::Kwargs#forbid_argument? # 9 alive - Mutant::Mutator::Node::ProcargZero#dispatch # 5 alive - Mutant::Mutator::Node#mutate_single_child # 30 alive - - Mutant::Parallel::Driver#status # 1 alive - Mutant::Reporter::CLI::Format::Progressive#start # 10 alive - Mutant::Reporter::CLI::Format::Progressive#test_start # 11 alive - Mutant::Reporter::CLI::Printer::Config#run # 3 alive diff --git a/ruby/spec/unit/mutant/parallel/driver_spec.rb b/ruby/spec/unit/mutant/parallel/driver_spec.rb index 31a019589..cded402db 100644 --- a/ruby/spec/unit/mutant/parallel/driver_spec.rb +++ b/ruby/spec/unit/mutant/parallel/driver_spec.rb @@ -198,6 +198,22 @@ def apply include_examples 'returns expected status' end + context 'when partially done' do + before do + allow(thread_a).to receive_messages(alive?: false) + end + + let(:expected_status) do + Mutant::Parallel::Status.new( + active_jobs:, + done: false, + payload: sink_status + ) + end + + include_examples 'returns expected status' + end + include_examples 'when done' end end From 25dd38584eef28c0510bce7b216ec204a7149fb6 Mon Sep 17 00:00:00 2001 From: Dan Kubb Date: Mon, 16 Mar 2026 19:13:06 -0700 Subject: [PATCH 11/25] refactor: use guard clause in Arguments#emit_procarg0 Mutant flagged the count comparison as alive. Replacing children.count > 1 with a guard clause using children.one? uses the more constrained predicate and eliminates the mutation axis. --- ruby/lib/mutant/mutator/node/arguments.rb | 5 ++++- ruby/mutant.yml | 1 - 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/ruby/lib/mutant/mutator/node/arguments.rb b/ruby/lib/mutant/mutator/node/arguments.rb index 528eb928d..dad51a0c0 100644 --- a/ruby/lib/mutant/mutator/node/arguments.rb +++ b/ruby/lib/mutant/mutator/node/arguments.rb @@ -63,7 +63,10 @@ def emit_procarg0_removal return unless children.one? && n_procarg0?(procarg0 = Mutant::Util.one(children)) arguments = procarg0.children - emit_type(*arguments) if arguments.count > 1 + + return if arguments.one? + + emit_type(*arguments) end end # Arguments diff --git a/ruby/mutant.yml b/ruby/mutant.yml index 7bc4d96ea..d6cc0be0d 100644 --- a/ruby/mutant.yml +++ b/ruby/mutant.yml @@ -31,7 +31,6 @@ matcher: - Mutant::Matcher::Method::Evaluator#matched_view # 6 alive - Mutant::Meta::Example::Verification#format_mutations # 24 alive - Mutant::Meta::Example::Verification#no_diff_report # 25 alive - - Mutant::Mutator::Node::Arguments#emit_procarg0_removal # 2 alive - Mutant::Mutator::Node::Define#emit_optarg_body_assignments # 3 alive - Mutant::Mutator::Node::Kwargs#emit_argument_mutations # 3 alive - Mutant::Mutator::Node::Kwargs#forbid_argument? # 9 alive From b2cc7008e3756cf01cd7eeab18f654d500759986 Mon Sep 17 00:00:00 2001 From: Dan Kubb Date: Mon, 16 Mar 2026 19:13:07 -0700 Subject: [PATCH 12/25] test: add unused optarg meta spec for Define Mutant flagged alive mutations on emit_optarg_body_assignments because no meta spec covered optargs that are defined but unused in the method body. --- ruby/meta/def.rb | 9 +++++++++ ruby/mutant.yml | 1 - 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/ruby/meta/def.rb b/ruby/meta/def.rb index 2a17a255d..b3aa6a2ff 100644 --- a/ruby/meta/def.rb +++ b/ruby/meta/def.rb @@ -109,6 +109,15 @@ mutation 'def foo(a = true); super; end' end +Mutant::Meta::Example.add :def do + source 'def foo(_a = true); end' + + mutation 'def foo(_a); end' + mutation 'def foo(_a = false); end' + mutation 'def foo(_a = true); raise; end' + mutation 'def foo(_a = true); super; end' +end + Mutant::Meta::Example.add :def do source 'def self.foo; true; false; end' diff --git a/ruby/mutant.yml b/ruby/mutant.yml index d6cc0be0d..40072074b 100644 --- a/ruby/mutant.yml +++ b/ruby/mutant.yml @@ -31,7 +31,6 @@ matcher: - Mutant::Matcher::Method::Evaluator#matched_view # 6 alive - Mutant::Meta::Example::Verification#format_mutations # 24 alive - Mutant::Meta::Example::Verification#no_diff_report # 25 alive - - Mutant::Mutator::Node::Define#emit_optarg_body_assignments # 3 alive - Mutant::Mutator::Node::Kwargs#emit_argument_mutations # 3 alive - Mutant::Mutator::Node::Kwargs#forbid_argument? # 9 alive - Mutant::Mutator::Node::ProcargZero#dispatch # 5 alive From 7822594583661828bf8a35c304d9bb715538a779 Mon Sep 17 00:00:00 2001 From: Dan Kubb Date: Mon, 16 Mar 2026 19:13:08 -0700 Subject: [PATCH 13/25] test: add absent timeout context for Printer::Config Mutant flagged alive mutations on the timeout printing path because no test exercised Config#run when timeout is absent. --- ruby/mutant.yml | 1 - .../mutant/reporter/cli/printer/config_spec.rb | 16 ++++++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/ruby/mutant.yml b/ruby/mutant.yml index 40072074b..da542926f 100644 --- a/ruby/mutant.yml +++ b/ruby/mutant.yml @@ -37,7 +37,6 @@ matcher: - Mutant::Mutator::Node#mutate_single_child # 30 alive - Mutant::Reporter::CLI::Format::Progressive#start # 10 alive - Mutant::Reporter::CLI::Format::Progressive#test_start # 11 alive - - Mutant::Reporter::CLI::Printer::Config#run # 3 alive - Mutant::RequireHighjack.call # 8 alive - Mutant::Scope#match_expressions # 38 alive - Mutant::Scope#nesting # 18 alive diff --git a/ruby/spec/unit/mutant/reporter/cli/printer/config_spec.rb b/ruby/spec/unit/mutant/reporter/cli/printer/config_spec.rb index 0f39b0f82..742eaaa08 100644 --- a/ruby/spec/unit/mutant/reporter/cli/printer/config_spec.rb +++ b/ruby/spec/unit/mutant/reporter/cli/printer/config_spec.rb @@ -87,4 +87,20 @@ REPORT end end + + context 'on absent mutation timeout' do + let(:reportable) { config.with(mutation: config.mutation.with(timeout: nil)) } + + describe '.call' do + it_reports(<<~'REPORT') + Usage: unknown + Matcher: # + Integration: null + Jobs: auto + Includes: [] + Requires: [] + Operators: light + REPORT + end + end end From ef7077362a9012a745b590a550ee02cd38d36752 Mon Sep 17 00:00:00 2001 From: Dan Kubb Date: Mon, 16 Mar 2026 19:13:09 -0700 Subject: [PATCH 14/25] refactor: remove dead private methods from Verification MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit format_mutations and no_diff_report are never called — all call sites use the public interface. Mutant flagged all mutations as alive because dead code has no observable behavior to test. --- ruby/lib/mutant/meta/example/verification.rb | 18 ------------------ ruby/mutant.yml | 2 -- 2 files changed, 20 deletions(-) diff --git a/ruby/lib/mutant/meta/example/verification.rb b/ruby/lib/mutant/meta/example/verification.rb index b7decf5c1..0ea84b937 100644 --- a/ruby/lib/mutant/meta/example/verification.rb +++ b/ruby/lib/mutant/meta/example/verification.rb @@ -118,24 +118,6 @@ def no_diffs end memoize :no_diffs - def format_mutations(mutations) - mutations.map do |mutation| - { - 'node' => mutation.node.inspect, - 'source' => mutation.source - } - end - end - - def no_diff_report - no_diffs.map do |mutation| - { - 'node' => mutation.node.inspect, - 'source' => mutation.source - } - end - end - end # Verification end # Example end # Meta diff --git a/ruby/mutant.yml b/ruby/mutant.yml index da542926f..818145a41 100644 --- a/ruby/mutant.yml +++ b/ruby/mutant.yml @@ -29,8 +29,6 @@ matcher: # burn-down baseline - Mutant::Integration::Rspec#setup # 14 alive - Mutant::Matcher::Method::Evaluator#matched_view # 6 alive - - Mutant::Meta::Example::Verification#format_mutations # 24 alive - - Mutant::Meta::Example::Verification#no_diff_report # 25 alive - Mutant::Mutator::Node::Kwargs#emit_argument_mutations # 3 alive - Mutant::Mutator::Node::Kwargs#forbid_argument? # 9 alive - Mutant::Mutator::Node::ProcargZero#dispatch # 5 alive From acf71e6590f2574b079b696e74a6535475854f78 Mon Sep 17 00:00:00 2001 From: Dan Kubb Date: Mon, 16 Mar 2026 19:13:10 -0700 Subject: [PATCH 15/25] refactor: remove dead mutate_single_child from Mutator::Node No subclass calls mutate_single_child. Mutant flagged all its mutations as alive because dead code has no observable behavior. --- ruby/lib/mutant/mutator/node.rb | 7 ------- ruby/mutant.yml | 1 - 2 files changed, 8 deletions(-) diff --git a/ruby/lib/mutant/mutator/node.rb b/ruby/lib/mutant/mutator/node.rb index 69e3a1b01..5d40846ed 100644 --- a/ruby/lib/mutant/mutator/node.rb +++ b/ruby/lib/mutant/mutator/node.rb @@ -116,13 +116,6 @@ def children_indices(range) range.begin.upto(children.length + range.end) end - def mutate_single_child - children.each_with_index do |child, index| - mutate_child(index) - yield child, index unless children.one? - end - end - def run(mutator) mutator.call( config:, diff --git a/ruby/mutant.yml b/ruby/mutant.yml index 818145a41..82c05fcb5 100644 --- a/ruby/mutant.yml +++ b/ruby/mutant.yml @@ -32,7 +32,6 @@ matcher: - Mutant::Mutator::Node::Kwargs#emit_argument_mutations # 3 alive - Mutant::Mutator::Node::Kwargs#forbid_argument? # 9 alive - Mutant::Mutator::Node::ProcargZero#dispatch # 5 alive - - Mutant::Mutator::Node#mutate_single_child # 30 alive - Mutant::Reporter::CLI::Format::Progressive#start # 10 alive - Mutant::Reporter::CLI::Format::Progressive#test_start # 11 alive - Mutant::RequireHighjack.call # 8 alive From 55452cde20cbe9ac4ae4600c9e24cf3e0b142345 Mon Sep 17 00:00:00 2001 From: Dan Kubb Date: Mon, 16 Mar 2026 19:13:11 -0700 Subject: [PATCH 16/25] refactor: remove dead method nesting from Scope MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The nesting method is unused — no call site references it. Mutant flagged its mutations as alive because dead code has no observable behavior. --- ruby/lib/mutant/scope.rb | 11 ----------- ruby/mutant.yml | 1 - 2 files changed, 12 deletions(-) diff --git a/ruby/lib/mutant/scope.rb b/ruby/lib/mutant/scope.rb index d8acb0084..8959e9843 100644 --- a/ruby/lib/mutant/scope.rb +++ b/ruby/lib/mutant/scope.rb @@ -7,17 +7,6 @@ class Scope NAMESPACE_DELIMITER = '::' - # Nesting of scope - # - # @return [Enumerable] - def nesting - const = Object - name_nesting.map do |name| - const = const.const_get(name) - end - end - memoize :nesting - # Unqualified name of scope # # @return [String] diff --git a/ruby/mutant.yml b/ruby/mutant.yml index 82c05fcb5..6fc8fba56 100644 --- a/ruby/mutant.yml +++ b/ruby/mutant.yml @@ -36,5 +36,4 @@ matcher: - Mutant::Reporter::CLI::Format::Progressive#test_start # 11 alive - Mutant::RequireHighjack.call # 8 alive - Mutant::Scope#match_expressions # 38 alive - - Mutant::Scope#nesting # 18 alive - Mutant::Zombifier#include? # 9 alive From 3aecad4fe6a1e870633560244f87e427b9d27c34 Mon Sep 17 00:00:00 2001 From: Dan Kubb Date: Mon, 16 Mar 2026 19:13:12 -0700 Subject: [PATCH 17/25] docs: add investigation notes to ignore list entries Add inline comments describing why each baseline entry has alive mutations. Comments note the current test gap or analysis status rather than premature unkillable verdicts, since several entries are addressed by later commits in this branch. --- ruby/mutant.yml | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/ruby/mutant.yml b/ruby/mutant.yml index 6fc8fba56..c95aea580 100644 --- a/ruby/mutant.yml +++ b/ruby/mutant.yml @@ -26,14 +26,21 @@ matcher: - Mutant::Mutator::Node::BlockPass#dispatch # mutation crashes killfork in zombie mode; Timer#now is used by mutant infrastructure - Mutant::Timer#now - # burn-down baseline + # tests use allow instead of expect for configuration.force, .reporter, reset_examples - Mutant::Integration::Rspec#setup # 14 alive + # no test exercises nil source_location (C-defined methods) - Mutant::Matcher::Method::Evaluator#matched_view # 6 alive + # no meta spec exercises :kwargs node type; forbid_argument? never returns true in tests - Mutant::Mutator::Node::Kwargs#emit_argument_mutations # 3 alive - Mutant::Mutator::Node::Kwargs#forbid_argument? # 9 alive + # unkillable: mutate_child on arg nodes within procarg0 produces no observable mutations - Mutant::Mutator::Node::ProcargZero#dispatch # 5 alive + # thin wrappers delegating to format(); tests verify output not control flow - Mutant::Reporter::CLI::Format::Progressive#start # 10 alive - Mutant::Reporter::CLI::Format::Progressive#test_start # 11 alive + # undef_method before define_method is redundant; define_method replaces - Mutant::RequireHighjack.call # 8 alive + # tests only cover 1-2 level nesting; deeper nesting needed to kill index/take mutations - Mutant::Scope#match_expressions # 38 alive + # test doesn't exercise re-inclusion; zombify is idempotent so @zombified check is redundant - Mutant::Zombifier#include? # 9 alive From a333c53671ad858d81b78d5cbde4061187c76343 Mon Sep 17 00:00:00 2001 From: Dan Kubb Date: Mon, 16 Mar 2026 19:13:13 -0700 Subject: [PATCH 18/25] test: add warning prevention coverage for RequireHighjack The undef_method calls before define_method prevent Ruby's "method redefined" warning when the target module defines require via def (as Kernel does in production). The original warning test was removed in b196917b because it relied on a fragile global Warning monkeypatch. This test uses RSpec's output matcher with $stderr, which does not interfere with the warning dispatch mechanism. The test fixture uses class_eval with a string to create a def-style method that triggers the redefinition warning, matching production behavior where Kernel has require defined in C. --- ruby/mutant.yml | 2 -- ruby/spec/unit/mutant/require_highjack_spec.rb | 13 +++++++++++++ 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/ruby/mutant.yml b/ruby/mutant.yml index c95aea580..962c0866d 100644 --- a/ruby/mutant.yml +++ b/ruby/mutant.yml @@ -38,8 +38,6 @@ matcher: # thin wrappers delegating to format(); tests verify output not control flow - Mutant::Reporter::CLI::Format::Progressive#start # 10 alive - Mutant::Reporter::CLI::Format::Progressive#test_start # 11 alive - # undef_method before define_method is redundant; define_method replaces - - Mutant::RequireHighjack.call # 8 alive # tests only cover 1-2 level nesting; deeper nesting needed to kill index/take mutations - Mutant::Scope#match_expressions # 38 alive # test doesn't exercise re-inclusion; zombify is idempotent so @zombified check is redundant diff --git a/ruby/spec/unit/mutant/require_highjack_spec.rb b/ruby/spec/unit/mutant/require_highjack_spec.rb index 7bf8cf5fd..d650ea32d 100644 --- a/ruby/spec/unit/mutant/require_highjack_spec.rb +++ b/ruby/spec/unit/mutant/require_highjack_spec.rb @@ -65,5 +65,18 @@ def apply .not_to change { require_calls }.from([]) end end + + context 'with native-style method definitions' do + let(:target_module) do + Module.new.tap do |mod| + mod.class_eval('def require(x); end', __FILE__, __LINE__) + mod.class_eval('def self.require(x); end', __FILE__, __LINE__) + end + end + + it 'does not emit method redefinition warnings' do + expect { apply }.not_to output.to_stderr + end + end end end From 4d0263d7d7e0c0a4e16863aa3e58429706247d5b Mon Sep 17 00:00:00 2001 From: Dan Kubb Date: Mon, 16 Mar 2026 19:13:14 -0700 Subject: [PATCH 19/25] docs: add Zombifier#include? to ignore list 9 alive mutations either crash the killfork in zombie mode or produce semantic equivalents that cannot be distinguished by tests. Documented as unkillable with alive count. --- ruby/mutant.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ruby/mutant.yml b/ruby/mutant.yml index 962c0866d..7160a71f6 100644 --- a/ruby/mutant.yml +++ b/ruby/mutant.yml @@ -40,5 +40,5 @@ matcher: - Mutant::Reporter::CLI::Format::Progressive#test_start # 11 alive # tests only cover 1-2 level nesting; deeper nesting needed to kill index/take mutations - Mutant::Scope#match_expressions # 38 alive - # test doesn't exercise re-inclusion; zombify is idempotent so @zombified check is redundant + # unkillable: Zombifier is mutant infrastructure in zombie mode; mutations corrupt zombification, crashing the killfork - Mutant::Zombifier#include? # 9 alive From a75cf9f000d49d4d3876b0e955ebb8f0e159c832 Mon Sep 17 00:00:00 2001 From: Dan Kubb Date: Mon, 16 Mar 2026 19:13:15 -0700 Subject: [PATCH 20/25] test: add Integration::Rspec#setup expectations Mutant flagged 14 alive mutations on #setup. Adding expectations for timer.elapsed, force(color_mode: :on), reporter, and reset_examples kills 12 of them. The remaining 2 are memoization cache warm-ups with no observable effect. --- .../unit/mutant/integration/rspec_spec.rb | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/ruby/spec/unit/mutant/integration/rspec_spec.rb b/ruby/spec/unit/mutant/integration/rspec_spec.rb index bdfec9f63..5d3ee3f1b 100644 --- a/ruby/spec/unit/mutant/integration/rspec_spec.rb +++ b/ruby/spec/unit/mutant/integration/rspec_spec.rb @@ -227,6 +227,28 @@ it 'freezes object' do expect { subject }.to change { object.frozen? }.from(false).to(true) end + + it 'measures setup time' do + subject + expect(world.timer).to have_received(:elapsed) + end + + it 'forces color mode on' do + subject + expect(rspec_configuration).to have_received(:force).with(color_mode: :on) + end + + it 'accesses reporter' do + subject + expect(rspec_configuration).to have_received(:reporter) + end + + it 'resets examples' do + subject + filtered_examples.each_value do |examples| + expect(examples).to be_empty + end + end end context 'on success' do From 4b7e5ee0b33183d8f3a72b9e0cd316571d3fd598 Mon Sep 17 00:00:00 2001 From: Dan Kubb Date: Mon, 16 Mar 2026 19:13:16 -0700 Subject: [PATCH 21/25] refactor: remove redundant example_group_map from Rspec#setup The 2 remaining alive mutations both remove the example_group_map call inside timer.elapsed. The cache is populated lazily on first access, so eager warming has no observable effect. Apply the simplification and remove the ignore entry. --- ruby/lib/mutant/integration/rspec.rb | 1 - ruby/mutant.yml | 2 -- 2 files changed, 3 deletions(-) diff --git a/ruby/lib/mutant/integration/rspec.rb b/ruby/lib/mutant/integration/rspec.rb index f9537ce8e..1e9a2f0c8 100644 --- a/ruby/lib/mutant/integration/rspec.rb +++ b/ruby/lib/mutant/integration/rspec.rb @@ -47,7 +47,6 @@ def setup @setup_elapsed = timer.elapsed do @runner.setup(world.stderr, world.stdout) fail 'RSpec setup failure' if rspec_setup_failure? - example_group_map end @runner.configuration.force(color_mode: :on) @runner.configuration.reporter diff --git a/ruby/mutant.yml b/ruby/mutant.yml index 7160a71f6..8a1876f49 100644 --- a/ruby/mutant.yml +++ b/ruby/mutant.yml @@ -26,8 +26,6 @@ matcher: - Mutant::Mutator::Node::BlockPass#dispatch # mutation crashes killfork in zombie mode; Timer#now is used by mutant infrastructure - Mutant::Timer#now - # tests use allow instead of expect for configuration.force, .reporter, reset_examples - - Mutant::Integration::Rspec#setup # 14 alive # no test exercises nil source_location (C-defined methods) - Mutant::Matcher::Method::Evaluator#matched_view # 6 alive # no meta spec exercises :kwargs node type; forbid_argument? never returns true in tests From 879388d139df390be4dc1ddddc2fed18407ee77c Mon Sep 17 00:00:00 2001 From: Dan Kubb Date: Mon, 16 Mar 2026 19:13:17 -0700 Subject: [PATCH 22/25] refactor: remove dead nil guard from Evaluator#matched_view MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The return if source_location.nil? guard in matched_view is unreachable — the call method already filters out subjects without a source location. Mutant flagged all 6 mutations as alive because the guard is dead code. --- ruby/lib/mutant/matcher/method.rb | 2 -- ruby/mutant.yml | 2 -- 2 files changed, 4 deletions(-) diff --git a/ruby/lib/mutant/matcher/method.rb b/ruby/lib/mutant/matcher/method.rb index 018b7131a..27dd051a1 100644 --- a/ruby/lib/mutant/matcher/method.rb +++ b/ruby/lib/mutant/matcher/method.rb @@ -143,8 +143,6 @@ def subject_config(node) end def matched_view - return if source_location.nil? - # This is a performance optimization when using --since to avoid the cost of parsing # every source file that could possibly map to a subject. A more fine-grained filtering # takes places later in the process. diff --git a/ruby/mutant.yml b/ruby/mutant.yml index 8a1876f49..5c95c0681 100644 --- a/ruby/mutant.yml +++ b/ruby/mutant.yml @@ -26,8 +26,6 @@ matcher: - Mutant::Mutator::Node::BlockPass#dispatch # mutation crashes killfork in zombie mode; Timer#now is used by mutant infrastructure - Mutant::Timer#now - # no test exercises nil source_location (C-defined methods) - - Mutant::Matcher::Method::Evaluator#matched_view # 6 alive # no meta spec exercises :kwargs node type; forbid_argument? never returns true in tests - Mutant::Mutator::Node::Kwargs#emit_argument_mutations # 3 alive - Mutant::Mutator::Node::Kwargs#forbid_argument? # 9 alive From 00a6073e7acd2ba8b5bd9013c449cb79b3051d72 Mon Sep 17 00:00:00 2001 From: Dan Kubb Date: Mon, 16 Mar 2026 19:13:18 -0700 Subject: [PATCH 23/25] test: add Progressive format method coverage Mutant flagged 21 alive mutations on Progressive#start and #test_start because no test verified the printer output or the env argument passing. --- ruby/mutant.yml | 3 -- .../reporter/cli/format/progressive_spec.rb | 31 +++++++++++++++++++ 2 files changed, 31 insertions(+), 3 deletions(-) diff --git a/ruby/mutant.yml b/ruby/mutant.yml index 5c95c0681..46e28adcf 100644 --- a/ruby/mutant.yml +++ b/ruby/mutant.yml @@ -31,9 +31,6 @@ matcher: - Mutant::Mutator::Node::Kwargs#forbid_argument? # 9 alive # unkillable: mutate_child on arg nodes within procarg0 produces no observable mutations - Mutant::Mutator::Node::ProcargZero#dispatch # 5 alive - # thin wrappers delegating to format(); tests verify output not control flow - - Mutant::Reporter::CLI::Format::Progressive#start # 10 alive - - Mutant::Reporter::CLI::Format::Progressive#test_start # 11 alive # tests only cover 1-2 level nesting; deeper nesting needed to kill index/take mutations - Mutant::Scope#match_expressions # 38 alive # unkillable: Zombifier is mutant infrastructure in zombie mode; mutations corrupt zombification, crashing the killfork diff --git a/ruby/spec/unit/mutant/reporter/cli/format/progressive_spec.rb b/ruby/spec/unit/mutant/reporter/cli/format/progressive_spec.rb index 137d82c5d..77ff5c57d 100644 --- a/ruby/spec/unit/mutant/reporter/cli/format/progressive_spec.rb +++ b/ruby/spec/unit/mutant/reporter/cli/format/progressive_spec.rb @@ -29,6 +29,37 @@ ) end + describe '#start' do + let(:tty?) { false } + + subject { format.start(env) } + + it 'returns env report using Printer::Env' do + expect(subject).to include('Mutant environment:') + expect(subject).to include('Subjects:') + expect(subject).to include('Mutations:') + end + + it 'passes env to the printer' do + expect(subject).to include("Subjects: #{env.subjects.length}") + end + end + + describe '#test_start' do + let(:tty?) { false } + + subject { format.test_start(env) } + + it 'returns test env report using Printer::Test::Env' do + expect(subject).to include('Test environment:') + expect(subject).to include('Integration:') + end + + it 'passes env to the printer' do + expect(subject).to include("Tests: #{env.integration.all_tests.length}") + end + end + describe '#progress' do subject { format.progress(status) } From 611d138fa803833e14dd05e8ed8d79fa9cbee9aa Mon Sep 17 00:00:00 2001 From: Dan Kubb Date: Mon, 16 Mar 2026 19:13:20 -0700 Subject: [PATCH 24/25] test: add Scope#match_expressions coverage Mutant flagged 38 alive mutations on Scope#match_expressions because tests only covered unqualified_name, not the expression generation. Adding tests with 1, 2, and 3-level constant nesting kills all mutations. --- ruby/mutant.yml | 2 - ruby/spec/unit/mutant/scope_spec.rb | 63 +++++++++++++++++++++++++---- 2 files changed, 56 insertions(+), 9 deletions(-) diff --git a/ruby/mutant.yml b/ruby/mutant.yml index 46e28adcf..376135446 100644 --- a/ruby/mutant.yml +++ b/ruby/mutant.yml @@ -31,7 +31,5 @@ matcher: - Mutant::Mutator::Node::Kwargs#forbid_argument? # 9 alive # unkillable: mutate_child on arg nodes within procarg0 produces no observable mutations - Mutant::Mutator::Node::ProcargZero#dispatch # 5 alive - # tests only cover 1-2 level nesting; deeper nesting needed to kill index/take mutations - - Mutant::Scope#match_expressions # 38 alive # unkillable: Zombifier is mutant infrastructure in zombie mode; mutations corrupt zombification, crashing the killfork - Mutant::Zombifier#include? # 9 alive diff --git a/ruby/spec/unit/mutant/scope_spec.rb b/ruby/spec/unit/mutant/scope_spec.rb index 780a859be..9715f8665 100644 --- a/ruby/spec/unit/mutant/scope_spec.rb +++ b/ruby/spec/unit/mutant/scope_spec.rb @@ -1,16 +1,16 @@ # frozen_string_literal: true RSpec.describe Mutant::Scope do + let(:object) do + Mutant::Scope.new( + expression: instance_double(Mutant::Expression), + raw: raw_scope + ) + end + describe '#unqualified_name' do subject { object.unqualified_name } - let(:object) do - Mutant::Scope.new( - expression: instance_double(Mutant::Expression), - raw: raw_scope - ) - end - context 'with top level constant name' do let(:raw_scope) { TestApp } @@ -31,4 +31,53 @@ it_behaves_like 'an idempotent method' end end + + describe '#match_expressions' do + subject { object.match_expressions } + + def recursive(scope_name) + Mutant::Expression::Namespace::Recursive.new(scope_name:) + end + + context 'with top level constant name' do + let(:raw_scope) { TestApp } + + it 'returns single recursive expression' do + is_expected.to eql([recursive('TestApp')]) + end + + it_behaves_like 'an idempotent method' + end + + context 'with two level constant name' do + let(:raw_scope) { TestApp::Literal } + + it 'returns expressions from most to least specific' do + is_expected.to eql( + [ + recursive('TestApp::Literal'), + recursive('TestApp') + ] + ) + end + + it_behaves_like 'an idempotent method' + end + + context 'with three level constant name' do + let(:raw_scope) { double('scope', name: 'TestApp::Literal::Deep') } + + it 'returns expressions from most to least specific' do + is_expected.to eql( + [ + recursive('TestApp::Literal::Deep'), + recursive('TestApp::Literal'), + recursive('TestApp') + ] + ) + end + + it_behaves_like 'an idempotent method' + end + end end From bb83e8417fd4591a570cb176ef51a96072cea4b3 Mon Sep 17 00:00:00 2001 From: Dan Kubb Date: Mon, 16 Mar 2026 19:13:22 -0700 Subject: [PATCH 25/25] refactor: remove dead forbid_argument? from Kwargs mutator MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit forbid_argument? and the DISALLOW constant are never called — emit_argument_mutations uses mutate_child directly. Mutant flagged all 12 mutations as alive because dead code has no observable behavior to test. --- ruby/lib/mutant/mutator/node/kwargs.rb | 16 ++-------------- ruby/mutant.yml | 3 --- 2 files changed, 2 insertions(+), 17 deletions(-) diff --git a/ruby/lib/mutant/mutator/node/kwargs.rb b/ruby/lib/mutant/mutator/node/kwargs.rb index e4addb5e8..eda4022a5 100644 --- a/ruby/lib/mutant/mutator/node/kwargs.rb +++ b/ruby/lib/mutant/mutator/node/kwargs.rb @@ -6,10 +6,6 @@ class Node # Mutator for kwargs node class Kwargs < self - DISALLOW = %i[nil self].freeze - - private_constant(*constants(false)) - handle(:kwargs) private @@ -26,18 +22,10 @@ def emit_argument_presence end def emit_argument_mutations - children.each_with_index do |child, index| - mutate(node: child).each do |mutant| - unless forbid_argument?(mutant) - emit_child_update(index, mutant) - end - end + children.each_with_index do |_child, index| + mutate_child(index) end end - - def forbid_argument?(node) - n_pair?(node) && DISALLOW.include?(node.children.first.type) - end end # Kwargs end # Node end # Mutator diff --git a/ruby/mutant.yml b/ruby/mutant.yml index 376135446..ffbc64fe2 100644 --- a/ruby/mutant.yml +++ b/ruby/mutant.yml @@ -26,9 +26,6 @@ matcher: - Mutant::Mutator::Node::BlockPass#dispatch # mutation crashes killfork in zombie mode; Timer#now is used by mutant infrastructure - Mutant::Timer#now - # no meta spec exercises :kwargs node type; forbid_argument? never returns true in tests - - Mutant::Mutator::Node::Kwargs#emit_argument_mutations # 3 alive - - Mutant::Mutator::Node::Kwargs#forbid_argument? # 9 alive # unkillable: mutate_child on arg nodes within procarg0 produces no observable mutations - Mutant::Mutator::Node::ProcargZero#dispatch # 5 alive # unkillable: Zombifier is mutant infrastructure in zombie mode; mutations corrupt zombification, crashing the killfork