Port if node mutator to parser
This commit is contained in:
parent
8e2f244838
commit
c5cdc05e5e
6 changed files with 126 additions and 276 deletions
|
@ -43,7 +43,7 @@ module Mutant
|
|||
#
|
||||
def emit_children_mutations
|
||||
Mutator::Util::Array.each(children) do |children|
|
||||
emit_self(children)
|
||||
emit_self(*children)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -85,7 +85,7 @@ module Mutant
|
|||
def emit_child_update(index, update)
|
||||
new_children = children.dup
|
||||
new_children[index]=update
|
||||
emit_self(new_children)
|
||||
emit_self(*new_children)
|
||||
end
|
||||
|
||||
# Emit a new AST node with same class as wrapped node
|
||||
|
@ -94,8 +94,8 @@ module Mutant
|
|||
#
|
||||
# @api private
|
||||
#
|
||||
def emit_self(children)
|
||||
emit(Parser::AST::Node.new(node.type, children))
|
||||
def emit_self(*children)
|
||||
emit(new_self(*children))
|
||||
end
|
||||
|
||||
# Emit a new AST node with NilLiteral class
|
||||
|
@ -108,6 +108,16 @@ module Mutant
|
|||
emit(s(:nil))
|
||||
end
|
||||
|
||||
# Return new self typed child
|
||||
#
|
||||
# @return [Parser::AST::Node]
|
||||
#
|
||||
# @api private
|
||||
#
|
||||
def new_self(*children)
|
||||
Parser::AST::Node.new(node.type, children)
|
||||
end
|
||||
|
||||
end # Node
|
||||
end # Mutator
|
||||
end # Mutant
|
||||
|
|
|
@ -6,123 +6,88 @@ module Mutant
|
|||
|
||||
handle(:if)
|
||||
|
||||
CONDITION_INDEX = 0
|
||||
IF_BRANCH_INDEX = 1
|
||||
ELSE_BRANCH_INDEX = 2
|
||||
|
||||
private
|
||||
|
||||
# Emit mutations
|
||||
# Emit mutations
|
||||
#
|
||||
# @return [undefined]
|
||||
#
|
||||
# @api private
|
||||
#
|
||||
def dispatch
|
||||
emit_attribute_mutations(:condition)
|
||||
emit_attribute_mutations(:body) unless nil_literal?(:body)
|
||||
emit_attribute_mutations(:else) unless nil_literal?(:else)
|
||||
emit_inverted_condition
|
||||
emit_deleted_if_branch
|
||||
emit_deleted_else_branch
|
||||
emit_true_if_branch
|
||||
emit_false_if_branch
|
||||
mutate_condition
|
||||
mutate_if_branch
|
||||
mutate_else_branch
|
||||
end
|
||||
|
||||
# Test if attribute is non nil literal
|
||||
#
|
||||
# @param [Symbol] name
|
||||
#
|
||||
# @return [true]
|
||||
# if attribute value a nil literal
|
||||
#
|
||||
# @return [false]
|
||||
# otherwise
|
||||
#
|
||||
# @api private
|
||||
#
|
||||
def nil_literal?(name)
|
||||
node.public_send(name).kind_of?(Rubinius::AST::NilLiteral)
|
||||
end
|
||||
|
||||
# Emit inverted condition
|
||||
#
|
||||
# Especially the same like swap branches but more universal as it also
|
||||
# covers the case there is no else branch
|
||||
# Emit conditon mutations
|
||||
#
|
||||
# @return [undefined]
|
||||
#
|
||||
# @api private
|
||||
#
|
||||
def emit_inverted_condition
|
||||
emit_self(new_send(condition, :'!'), if_branch, else_branch)
|
||||
def mutate_condition
|
||||
mutate_child(CONDITION_INDEX)
|
||||
emit_self(s(:send, condition, :!), if_branch, else_branch)
|
||||
emit_self(s(:true), if_branch, else_branch)
|
||||
emit_self(s(:false), if_branch, else_branch)
|
||||
end
|
||||
|
||||
# Emit deleted else branch
|
||||
# Emit if branch mutations
|
||||
#
|
||||
# @return [undefined]
|
||||
#
|
||||
# @api private
|
||||
#
|
||||
def emit_deleted_else_branch
|
||||
emit_self(condition, if_branch, nil)
|
||||
def mutate_if_branch
|
||||
mutate_child(IF_BRANCH_INDEX) if if_branch
|
||||
emit_self(condition, else_branch, nil)
|
||||
emit_self(condition, if_branch, nil)
|
||||
end
|
||||
|
||||
# Emit deleted if branch
|
||||
# Emit else branch mutations
|
||||
#
|
||||
# @return [undefined]
|
||||
#
|
||||
# @api private
|
||||
#
|
||||
def emit_deleted_if_branch
|
||||
body = else_branch || return
|
||||
emit_self(condition, body, nil)
|
||||
def mutate_else_branch
|
||||
mutate_child(ELSE_BRANCH_INDEX)
|
||||
emit_self(condition, s(:nil), else_branch)
|
||||
end
|
||||
|
||||
# Emit true if branch
|
||||
#
|
||||
# @return [undefined]
|
||||
#
|
||||
# @api private
|
||||
#
|
||||
def emit_true_if_branch
|
||||
emit_self(new(Rubinius::AST::TrueLiteral), if_branch, else_branch)
|
||||
end
|
||||
|
||||
# Emit false if branch
|
||||
#
|
||||
# @return [undefined]
|
||||
#
|
||||
# @api private
|
||||
#
|
||||
def emit_false_if_branch
|
||||
emit_self(new(Rubinius::AST::FalseLiteral), if_branch, else_branch)
|
||||
end
|
||||
|
||||
# Return if_branch of node
|
||||
#
|
||||
# @return [Parser::AST::Node]
|
||||
#
|
||||
# @api private
|
||||
#
|
||||
def if_branch
|
||||
node.body
|
||||
end
|
||||
|
||||
# Return condition of node
|
||||
# Return condition node
|
||||
#
|
||||
# @return [Parser::AST::Node]
|
||||
#
|
||||
# @api private
|
||||
#
|
||||
def condition
|
||||
node.condition
|
||||
children[CONDITION_INDEX]
|
||||
end
|
||||
|
||||
# Return else body of node
|
||||
# Return if branch
|
||||
#
|
||||
# @return [Parser::AST::Node]
|
||||
#
|
||||
# @api private
|
||||
#
|
||||
def if_branch
|
||||
children[IF_BRANCH_INDEX]
|
||||
end
|
||||
|
||||
# Return else branch
|
||||
#
|
||||
# @return [Parser::AST::Node]
|
||||
#
|
||||
# @api private
|
||||
#
|
||||
def else_branch
|
||||
node.else
|
||||
children[ELSE_BRANCH_INDEX]
|
||||
end
|
||||
|
||||
end # If
|
||||
|
|
|
@ -7,18 +7,6 @@ module Mutant
|
|||
|
||||
private
|
||||
|
||||
# Return new float literal
|
||||
#
|
||||
# @param [#to_f] value
|
||||
#
|
||||
# @return [Parser::Node::FloatLiteral]
|
||||
#
|
||||
# @api private
|
||||
#
|
||||
def new_float(value)
|
||||
new(Parser::AST::FloatLiteral, value)
|
||||
end
|
||||
|
||||
# Emit a new node with wrapping class for each entry in values
|
||||
#
|
||||
# @param [Array] values
|
||||
|
|
|
@ -16,124 +16,6 @@ module Mutant
|
|||
# @api private
|
||||
#
|
||||
def dispatch
|
||||
emit_receiver
|
||||
emit_implicit_self_receiver
|
||||
emit_receiver_mutations
|
||||
emit_block_mutations
|
||||
emit_block_absence_mutation
|
||||
end
|
||||
|
||||
# Emit receiver
|
||||
#
|
||||
# @return [undefined]
|
||||
#
|
||||
# @api private
|
||||
#
|
||||
def emit_receiver
|
||||
unless to_self?
|
||||
emit(receiver)
|
||||
end
|
||||
end
|
||||
|
||||
# Emit block mutations
|
||||
#
|
||||
# @return [undefined]
|
||||
#
|
||||
# @api private
|
||||
#
|
||||
def emit_block_mutations
|
||||
emit_attribute_mutations(:block) if node.block
|
||||
end
|
||||
|
||||
# Emit receiver mutations
|
||||
#
|
||||
# @return [undefined]
|
||||
#
|
||||
# @api private
|
||||
#
|
||||
def emit_receiver_mutations
|
||||
emit_attribute_mutations(:receiver)
|
||||
end
|
||||
|
||||
# Emit block absence mutation
|
||||
#
|
||||
# @return [undefined]
|
||||
#
|
||||
# @api private
|
||||
#
|
||||
def emit_block_absence_mutation
|
||||
dup = dup_node
|
||||
dup.block = nil
|
||||
emit(dup)
|
||||
end
|
||||
|
||||
# Return receiver AST node
|
||||
#
|
||||
# @return [Parser::AST::Node]
|
||||
#
|
||||
# @api private
|
||||
#
|
||||
def receiver
|
||||
node.receiver
|
||||
end
|
||||
|
||||
# Return name of call
|
||||
#
|
||||
# @return [Symbol]
|
||||
#
|
||||
# @api private
|
||||
#
|
||||
def name
|
||||
node.name
|
||||
end
|
||||
|
||||
# Check if receiver is self
|
||||
#
|
||||
# @return [true]
|
||||
# if receiver is a Rubinius::AST::Self node
|
||||
#
|
||||
# @return [false]
|
||||
# return false otherwise
|
||||
#
|
||||
# @api private
|
||||
#
|
||||
def to_self?
|
||||
receiver.kind_of?(Rubinius::AST::Self)
|
||||
end
|
||||
|
||||
# Emit mutation that replaces explicit send to self with implicit send to self
|
||||
#
|
||||
# @example:
|
||||
#
|
||||
# # This class does use Foo#a with explicitly specifing the receiver self.
|
||||
# # But an implicit (privately) call should be used as there is no need for
|
||||
# # specifing en explicit receiver.
|
||||
#
|
||||
# class Foo # Mutation
|
||||
# def print_a # def print_a
|
||||
# puts self.a # puts a
|
||||
# end # end
|
||||
#
|
||||
# def a
|
||||
# :bar
|
||||
# end
|
||||
# end
|
||||
#
|
||||
# There will not be any exception so the mutant is not killed and such calls where
|
||||
# implicit receiver should be used will be spotted.
|
||||
#
|
||||
# @return [undefined]
|
||||
#
|
||||
# @api private
|
||||
#
|
||||
def emit_implicit_self_receiver
|
||||
unless to_self? and !Mutant::KEYWORDS.include?(node.name)
|
||||
return
|
||||
end
|
||||
|
||||
mutant = dup_node
|
||||
mutant.privately = true
|
||||
emit(mutant)
|
||||
end
|
||||
|
||||
end # Send
|
||||
|
|
75
spec/unit/mutant/mutator/node/if/mutation_spec.rb
Normal file
75
spec/unit/mutant/mutator/node/if/mutation_spec.rb
Normal file
|
@ -0,0 +1,75 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe Mutant::Mutator, 'if' do
|
||||
|
||||
before do
|
||||
Mutant::Random.stub(:hex_string => 'random')
|
||||
end
|
||||
|
||||
context 'with if and else branches' do
|
||||
let(:source) { 'if :condition; true; else false; end' }
|
||||
|
||||
let(:mutations) do
|
||||
mutants = []
|
||||
|
||||
# mutations of condition
|
||||
mutants << 'if :srandom; true; else false; end'
|
||||
mutants << 'if !:condition; true; else false; end'
|
||||
mutants << 'if nil; true; else false; end'
|
||||
mutants << 'if true; true; else false; end'
|
||||
mutants << 'if false; true; else false; end'
|
||||
|
||||
# Deleted else branch
|
||||
mutants << 'if :condition; true end'
|
||||
|
||||
# Deleted if branch resuting in unless
|
||||
mutants << 'unless :condition; false; end'
|
||||
|
||||
# Deleted if branch with promoting else branch to if branch
|
||||
mutants << 'if :condition; false end'
|
||||
|
||||
# mutations of if body
|
||||
mutants << 'if :condition; false; else false; end'
|
||||
mutants << 'if :condition; nil; else false; end'
|
||||
|
||||
# mutations of else body
|
||||
mutants << 'if :condition; true; else true; end'
|
||||
mutants << 'if :condition; true; else nil; end'
|
||||
end
|
||||
|
||||
it_should_behave_like 'a mutator'
|
||||
end
|
||||
|
||||
context 'unless with one branch' do
|
||||
let(:source) { 'unless :condition; true; end' }
|
||||
|
||||
let(:mutations) do
|
||||
mutants = []
|
||||
mutants << 'unless !:condition; true; end'
|
||||
mutants << 'unless :srandom; true; end'
|
||||
mutants << 'unless nil; true; end'
|
||||
mutants << 'if :condition; true; end'
|
||||
mutants << 'unless :condition; false; end'
|
||||
mutants << 'unless :condition; nil; end'
|
||||
mutants << 'unless true; true; end'
|
||||
mutants << 'unless false; true; end'
|
||||
end
|
||||
|
||||
it_should_behave_like 'a mutator'
|
||||
end
|
||||
|
||||
#context 'if with one branch' do
|
||||
# let(:source) { 'if condition; true; end' }
|
||||
|
||||
# let(:mutations) do
|
||||
# mutants = []
|
||||
# mutants << 'if !condition; true; end'
|
||||
# mutants << 'if condition; false; end'
|
||||
# mutants << 'if condition; nil; end'
|
||||
# mutants << 'if true; true; end'
|
||||
# mutants << 'if false; true; end'
|
||||
# end
|
||||
|
||||
# it_should_behave_like 'a mutator'
|
||||
#end
|
||||
end
|
|
@ -1,70 +0,0 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe Mutant::Mutator, 'if statement' do
|
||||
|
||||
context 'if with two branches' do
|
||||
let(:source) { 'if self.condition; true; else false; end' }
|
||||
|
||||
let(:mutations) do
|
||||
mutants = []
|
||||
|
||||
# mutations of condition
|
||||
mutants << 'if condition; true; else false; end'
|
||||
|
||||
mutants << 'if !self.condition; true; else false; end'
|
||||
|
||||
# Deleted else branch
|
||||
mutants << 'if self.condition; true end'
|
||||
|
||||
# Deleted if branch with promoting else branch to if branch
|
||||
mutants << 'if self.condition; false end'
|
||||
|
||||
# mutations of body
|
||||
mutants << 'if self.condition; false; else false; end'
|
||||
mutants << 'if self.condition; nil; else false; end'
|
||||
|
||||
# mutations of else body
|
||||
mutants << 'if self.condition; true; else true; end'
|
||||
mutants << 'if self.condition; true; else nil; end'
|
||||
|
||||
# mutation of condition to always be true
|
||||
mutants << 'if true; true; else false; end'
|
||||
|
||||
# mutation of condition to always be false
|
||||
mutants << 'if false; true; else false; end'
|
||||
end
|
||||
|
||||
it_should_behave_like 'a mutator'
|
||||
end
|
||||
|
||||
context 'unless with one branch' do
|
||||
let(:source) { 'unless condition; true; end' }
|
||||
|
||||
let(:mutations) do
|
||||
mutants = []
|
||||
mutants << 'unless !condition; true; end'
|
||||
mutants << 'if condition; true; end'
|
||||
mutants << 'unless condition; false; end'
|
||||
mutants << 'unless condition; nil; end'
|
||||
mutants << 'unless true; true; end'
|
||||
mutants << 'unless false; true; end'
|
||||
end
|
||||
|
||||
it_should_behave_like 'a mutator'
|
||||
end
|
||||
|
||||
context 'if with one branch' do
|
||||
let(:source) { 'if condition; true; end' }
|
||||
|
||||
let(:mutations) do
|
||||
mutants = []
|
||||
mutants << 'if !condition; true; end'
|
||||
mutants << 'if condition; false; end'
|
||||
mutants << 'if condition; nil; end'
|
||||
mutants << 'if true; true; end'
|
||||
mutants << 'if false; true; end'
|
||||
end
|
||||
|
||||
it_should_behave_like 'a mutator'
|
||||
end
|
||||
end
|
Loading…
Reference in a new issue