Add rescue/else-body promotion/concatenation mutation

[fix #245]
This commit is contained in:
Markus Schirp 2014-08-16 20:23:51 +00:00
parent d060f462f4
commit 49517af01c
7 changed files with 122 additions and 4 deletions

View file

@ -1,3 +1,7 @@
# v0.6.1 2014-08-16
* Add rescue else body promotion/concatenation mutation
# v0.6.0 2014-08-11
* Parallel execution / reporting.

View file

@ -1,3 +1,3 @@
---
threshold: 18
total_score: 1069
total_score: 1076

View file

@ -37,6 +37,7 @@ FeatureEnvy:
- Mutant::Matcher::Method::Singleton#receiver?
- Mutant::Mutation::Evil#success?
- Mutant::Mutation::Neutral#success?
- Mutant::Mutator::Node#children_indices
# False positive, its a utility
- Mutant::Meta::Example::Verification#format_mutation
- Mutant::Reporter::CLI#subject_results

View file

@ -8,6 +8,8 @@ module Mutant
include AbstractType, Unparser::Constants
include AST::NamedChildren, AST::NodePredicates, AST::Sexp, AST::Nodes
TAUTOLOGY = ->(_input) { true }
# Helper to define a named child
#
# @param [Parser::AST::Node] node
@ -79,7 +81,7 @@ module Mutant
# @api private
#
def mutate_child(index, mutator = Mutator, &block)
block ||= ->(_node) { true }
block ||= TAUTOLOGY
child = children.at(index)
mutator.each(child, self) do |mutation|
next unless block.call(mutation)
@ -211,6 +213,20 @@ module Mutant
AST::Types::OP_ASSIGN.include?(parent_type) && parent.node.children.first.equal?(node)
end
# Return children indices
#
# @param [Range] range
#
# @return [Enumerable<Fixnum>]
#
# @api pirvate
#
def children_indices(range)
range_end = range.end
last_index = range_end >= 0 ? range_end : children.length + range_end
range.begin.upto(last_index)
end
end # Node
end # Mutator
end # Mutant

View file

@ -2,10 +2,80 @@ module Mutant
class Mutator
class Node
# Mutator for rescue nodes
class Rescue < Generic
class Rescue < self
handle :rescue
children :body
define_named_child(:else_body, -1)
RESCUE_INDICES = (1..-2).freeze
# Emit mutations
#
# @return [undefined]
#
# @api private
#
def dispatch
mutate_body
mutate_rescue_bodies
mutate_else_body
end
private
# Mutate child by name
#
# @return [undefined]
#
# @api private
#
def mutate_rescue_bodies
children_indices(RESCUE_INDICES).each do |index|
next unless children.at(index)
mutate_child(index)
end
end
# Emit concatenation with body
#
# @param [Parser::AST::Node] child
#
# @return [undefined]
#
# @api private
#
def emit_concat(child)
raise unless body
emit(s(:begin, body, child))
end
# Emit body mutations
#
# @return [undefined]
#
# @api private
#
def mutate_body
return unless body
emit_body_mutations
emit(body)
end
# Emit else body mutations
#
# @return [undefined]
#
# @api private
#
def mutate_else_body
return unless else_body
emit_else_body_mutations
emit_concat(else_body)
end
end # Rescue
end # Node
end # Mutator

View file

@ -35,7 +35,7 @@ module Mutant
# @api private
#
def mutate_indices
INDEX_RANGE.begin.upto(children.length + INDEX_RANGE.end).each do |index|
children_indices(INDEX_RANGE).each do |index|
delete_child(index)
mutate_child(index)
end

View file

@ -13,6 +13,33 @@ Mutant::Meta::Example.add do
mutation 'def foo; nil; rescue; end'
mutation 'def foo; self; rescue; end'
mutation 'def foo; end'
# Promote rescue body
mutation 'def foo; foo; end'
end
Mutant::Meta::Example.add do
source 'def a; foo; rescue; bar; else; baz; end'
# Mutate all bodies
mutation 'def a; nil; rescue; bar; else; baz; end'
mutation 'def a; self; rescue; bar; else; baz; end'
mutation 'def a; foo; rescue; nil; else; baz; end'
mutation 'def a; foo; rescue; self; else; baz; end'
mutation 'def a; foo; rescue; bar; else; nil; end'
mutation 'def a; foo; rescue; bar; else; self; end'
# Promote and concat else body
mutation 'def a; foo; baz; end'
# Promote body
mutation 'def a; foo; end'
# Empty body
mutation 'def a; end'
# Failing body
mutation 'def a; raise; end'
end
Mutant::Meta::Example.add do