Add optarg arity mutation

- Adds mutation from `def foo(a = true); end`
  to `def foo(a = true); a = true; end`
- closes #310
This commit is contained in:
John Backus 2015-08-15 22:24:46 -04:00 committed by Markus Schirp
parent c025728a09
commit b19a97084c
6 changed files with 90 additions and 1 deletions

View file

@ -1,6 +1,7 @@
# v0.8.3 2015-08-xx
* Remove invalid mutation `super(...)` to `super`
* Add mutation from `def foo(a = true); end` to `def foo(a = true); a = true; end` #419
# v0.8.2 2015-08-11

View file

@ -1,3 +1,3 @@
---
threshold: 18
total_score: 1189
total_score: 1200

View file

@ -10,6 +10,24 @@ module Mutant
children :captures, :assignment, :body
end # Resbody
# Metadata for optional argument nodes
class Optarg
include NamedChildren, Concord.new(:node)
UNDERSCORE = '_'.freeze
children :name, :default_value
# Test if optarg definition intends to be used
#
# @return [Boolean]
#
# @api private
def used?
!name.to_s.start_with?(UNDERSCORE)
end
end # Optarg
# Metadata for send nodes
class Send
include NamedChildren, Concord.new(:node)

View file

@ -13,11 +13,40 @@ module Mutant
# @api private
def dispatch
emit_arguments_mutations
emit_optarg_body_assignments
emit_body(N_RAISE)
emit_body(nil)
emit_body_mutations if body
end
# Emit mutations with optional arguments as assignments in method
#
# @return [undefined]
#
# @api private
def emit_optarg_body_assignments
arguments.children.each do |argument|
next unless n_optarg?(argument) && AST::Meta::Optarg.new(argument).used?
emit_body_prepend(s(:lvasgn, *argument))
end
end
# Emit valid body ASTs depending on instance body
#
# @param node [Parser::AST::Node]
#
# @return [undefined]
#
# @api private
def emit_body_prepend(node)
if body
emit_body(s(:begin, node, body))
else
emit_body(node)
end
end
# Mutator for instance method defines
class Instance < self

View file

@ -80,6 +80,22 @@ Mutant::Meta::Example.add do
mutation 'def foo(a, b); raise; end'
end
Mutant::Meta::Example.add do
source 'def foo(a, b = nil); true; end'
mutation 'def foo(_a, b = nil); true; end'
mutation 'def foo(a, b = nil); end'
mutation 'def foo; true; end'
mutation 'def foo(a, b = nil); raise; end'
mutation 'def foo(a, b = nil); nil; end'
mutation 'def foo(a, b = nil); false; end'
mutation 'def foo(a); true; end'
mutation 'def foo(a, b = nil); b = nil; true; end'
mutation 'def foo(b = nil); true; end'
mutation 'def foo(a, _b = nil); true; end'
mutation 'def foo(a, b); true; end'
end
Mutant::Meta::Example.add do
source 'def foo(_unused); end'
@ -113,6 +129,8 @@ Mutant::Meta::Example.add do
mutation 'def foo(b = 0); end'
mutation 'def foo(a, b = 0); end'
mutation 'def foo; end'
mutation 'def foo(a = 0, b = 0); a = 0; end'
mutation 'def foo(a = 0, b = 0); b = 0; end'
mutation 'def foo(a = 0, b = 0); raise; end'
end
@ -125,6 +143,7 @@ Mutant::Meta::Example.add do
mutation 'def foo(a = nil); end'
mutation 'def foo(_a = true); end'
mutation 'def foo(a = true); raise; end'
mutation 'def foo(a = true); a = true; end'
end
Mutant::Meta::Example.add do

View file

@ -0,0 +1,22 @@
RSpec.describe Mutant::AST::Meta::Optarg do
subject(:object) { described_class.new(node) }
let(:node) { s(:optarg, name, value) }
let(:name) { :foo }
let(:value) { s(:sym, :bar) }
its(:name) { should be(:foo) }
its(:default_value) { should eql(s(:sym, :bar)) }
describe '#used?' do
subject { object.used? }
it { should be true }
context 'when name is prefixed with an underscore' do
let(:name) { :_foo }
it { should be false }
end
end
end