Add initial support for mutating case statements

This commit is contained in:
Markus Schirp 2012-08-01 17:52:12 +02:00
parent 00136ab9df
commit a25f99c97a
4 changed files with 187 additions and 0 deletions

1
TODO
View file

@ -22,3 +22,4 @@
* Mutations on Rubinius::AST::Self?
* Support the numerous Rubinius::AST::SendWithArguments mutations.
* Fix rubinius to allow setting @vcall_style variable in Rubinius::AST::Send nodes.
* Add mutations on the conditiosn of case statements. (Rubinius::AST::When)

View file

@ -56,6 +56,7 @@ require 'mutant/mutator/noop'
require 'mutant/mutator/call'
require 'mutant/mutator/call'
require 'mutant/mutator/if_statement'
require 'mutant/mutator/receiver_case'
require 'mutant/loader'
require 'mutant/context'
require 'mutant/context/constant'

View file

@ -0,0 +1,160 @@
module Mutant
class Mutator
# Mutator for Rubinius::AST::When nodes
class When < Mutator
handle(Rubinius::AST::When)
private
# Emit mutations
#
# @return [undefined]
#
# @api private
#
def dispatch
emit_body_mutations
end
# Emit body mutations
#
# @return [undefined]
#
# @api private
#
def emit_body_mutations
Mutator.each(node.body) do |mutation|
node = dup_node
node.body = mutation
emit_unsafe(node)
end
end
end
# Mutator for Rubinius::AST::ReceiverCase nodes
class ReceiverCase < Mutator
handle(Rubinius::AST::ReceiverCase)
private
# Emit mutations
#
# @return [undefined]
#
# @api private
#
def dispatch
emit_receiver_mutations
emit_when_branch_presence_mutations
emit_else_branch_presence_mutation
emit_when_branch_mutations
end
# Emit receiver mutation
#
# @return [undefined]
#
# @api private
#
def emit_receiver_mutations
Mutator.each(receiver) do |mutant|
emit_self(mutant,when_branches,else_branch)
end
end
# Emit else branch presence mutation
#
# @return [undefined]
#
# @api private
#
def emit_else_branch_presence_mutation
emit_self(receiver,when_branches,nil)
end
# Emit when branch body mutations
#
# @return [undefined]
#
# @api private
#
def emit_when_branch_mutations
when_branches.each_with_index do |branch,index|
Mutator.each(branch) do |mutant|
branches = dup_when_branches
branches[index]=mutant
emit_self(receiver,branches,else_branch)
end
end
end
# Emit when branch presence mutations
#
# @return [undefined]
#
# @api private
#
def emit_when_branch_presence_mutations
return if one?
when_branches.each_index do |index|
dup_branches = dup_when_branches
dup_branches.delete_at(index)
emit_self(receiver,dup_branches,else_branch)
end
end
# Check for case there is only one when branch
#
# @return [true]
# returns true when there is only one when branch
#
# @api private
#
def one?
when_branches.size == 1
end
# Return duplicatedd when branches
#
# @return [Array]
#
# @api private
#
def dup_when_branches
when_branches.dup
end
# Return when branches
#
# @return [Array]
#
# @api private
#
def when_branches
node.whens
end
# Return receiver
#
# @return [Rubinius::AST::Node]
#
# @api private
#
def receiver
node.receiver
end
# Return else branch
#
# @return [Rubinius::AST::Node]
#
# @api private
#
def else_branch
node.else
end
end
end
end

View file

@ -5,6 +5,31 @@
require 'spec_helper'
describe Mutant::Mutator, '.each' do
context 'case statements' do
let(:source) { 'case self.condition; when true; true; when false; false; else raise; end' }
let(:mutations) do
mutations = []
# Delete each when once
mutations << 'case self.condition; when true; true; else raise; end'
mutations << 'case self.condition; when false; false; else raise; end'
# Mutate receiver
mutations << 'case condition; when true; true; when false; false; else raise; end'
# Remove else branch
mutations << 'case self.condition; when true; true; when false; false; end'
# Mutate when branch bodies
mutations << 'case self.condition; when true; nil; when false; false; else raise; end'
mutations << 'case self.condition; when true; false; when false; false; else raise; end'
mutations << 'case self.condition; when true; true; when false; nil; else raise; end'
mutations << 'case self.condition; when true; true; when false; true; else raise; end'
end
it_should_behave_like 'a mutator'
end
pending 'interpolated string literal (DynamicString)' do
let(:source) { '"foo#{1}bar"' }