Extract node specific mutator base class

This commit is contained in:
Markus Schirp 2012-12-06 21:30:28 +01:00
parent b984a15691
commit 69e9de95ed
60 changed files with 1452 additions and 1369 deletions

View file

@ -52,28 +52,28 @@ require 'mutant/mutation/filter'
require 'mutant/mutation/filter/code'
require 'mutant/mutation/filter/whitelist'
require 'mutant/mutator/registry'
require 'mutant/mutator/literal'
require 'mutant/mutator/literal/boolean'
require 'mutant/mutator/literal/range'
require 'mutant/mutator/literal/symbol'
require 'mutant/mutator/literal/string'
require 'mutant/mutator/literal/fixnum'
require 'mutant/mutator/literal/float'
require 'mutant/mutator/literal/array'
require 'mutant/mutator/literal/empty_array'
require 'mutant/mutator/literal/hash'
require 'mutant/mutator/literal/regex'
require 'mutant/mutator/literal/nil'
#require 'mutant/mutator/literal/dynamic'
require 'mutant/mutator/block'
require 'mutant/mutator/noop'
require 'mutant/mutator/util'
require 'mutant/mutator/send'
require 'mutant/mutator/arguments'
require 'mutant/mutator/define'
require 'mutant/mutator/return'
require 'mutant/mutator/if_statement'
require 'mutant/mutator/receiver_case'
require 'mutant/mutator/node'
require 'mutant/mutator/node/literal'
require 'mutant/mutator/node/literal/boolean'
require 'mutant/mutator/node/literal/range'
require 'mutant/mutator/node/literal/symbol'
require 'mutant/mutator/node/literal/string'
require 'mutant/mutator/node/literal/fixnum'
require 'mutant/mutator/node/literal/float'
require 'mutant/mutator/node/literal/array'
require 'mutant/mutator/node/literal/empty_array'
require 'mutant/mutator/node/literal/hash'
require 'mutant/mutator/node/literal/regex'
require 'mutant/mutator/node/literal/nil'
require 'mutant/mutator/node/block'
require 'mutant/mutator/node/noop'
require 'mutant/mutator/node/send'
require 'mutant/mutator/node/arguments'
require 'mutant/mutator/node/define'
require 'mutant/mutator/node/return'
require 'mutant/mutator/node/if_statement'
require 'mutant/mutator/node/receiver_case'
require 'mutant/loader'
require 'mutant/context'
require 'mutant/context/scope'

View file

@ -3,9 +3,9 @@ module Mutant
class Mutator
include Adamantium::Flat, AbstractType
# Enumerate mutations on node
# Run mutator on input
#
# @param [Rubinius::AST::Node] node
# @param [Object] input
# @param [#call] block
#
# @return [self]
@ -32,31 +32,46 @@ module Mutant
end
private_class_method :handle
# Return wrapped node
# Return input
#
# @return [Rubius::AST::Node]
# @return [Object]
#
# @api private
#
attr_reader :node
attr_reader :input
private
# Initialize generator
# Initialize object
#
# @param [Rubinius::AST::Node] node
# @param [Object] input
# @param [#call(node)] block
#
# @return [undefined]
#
# @api private
#
def initialize(node, block)
@node, @block = Helper.deep_clone(node), block
IceNine.deep_freeze(@node)
def initialize(input, block)
@input, @block = Helper.deep_clone(input), block
IceNine.deep_freeze(@input)
dispatch
end
# Test if generated object is different from input
#
# @param [Object] object
#
# @return [true]
# if generated object is different
#
# @return [false]
#
# @api private
#
def new?(object)
input != object
end
# Dispatch node generations
#
# @return [undefined]
@ -65,30 +80,31 @@ module Mutant
#
abstract_method :dispatch
# Append node to generated mutations if node does not equal orignal node
# Emit generated mutation if object is not equivalent to input
#
# @param [Rubinius::AST::Node] node
# @param [Object] object
#
# @return [self]
# @return [undefined]
#
# @api private
#
def emit(node)
return self unless new?(node)
emit!(node)
def emit(object)
return unless new?(object)
emit!(object)
end
# Maximum amount of tries to generate a new node
# Maximum amount of tries to generate a new object
MAX_TRIES = 3
# Call block until it generates a new AST node
# Call block until it generates a mutation
#
# The primary use of this method is to give the random generated AST nodes
# The primary use of this method is to give the random generated object
# a nice interface for retring generation when generation accidentally generated the
# same AST that is about to be mutated.
# input
#
# @yield
# Execute block until AST node that does not equal wrapped node is generated by block
# Execute block until object is generated where new?(object) returns true
#
# @return [self]
#
@ -99,9 +115,10 @@ module Mutant
#
def emit_new
MAX_TRIES.times do
node = yield
if new?(node)
emit!(node)
object = yield
if new?(object)
emit!(object)
return
end
end
@ -122,185 +139,15 @@ module Mutant
self
end
# Check if node does not equal original node
# Shortcut to create a new unfrozen duplicate of input
#
# @param [Rubinius::AST::Node] node
#
# @return [true]
# returns true when node is differend from the node to be mutated
#
# @return [false]
# returns false otherwise
# @return [Object]
#
# @api private
#
def new?(node)
source != ToSource.to_source(node)
def dup_input
input.dup
end
# Return source for node
#
# @return [Array]
#
# @api private
#
def source
ToSource.to_source(node)
end
memoize :source
# Emit a new AST node
#
# @param [Rubinis::AST::Node:Class] node_class
#
# @return [Rubinius::AST::Node]
#
# @api private
#
def emit_node(node_class, *arguments)
emit(new(node_class, *arguments))
end
# Create a new AST node with same class as wrapped node
#
# @return [Rubinius::AST::Node]
#
# @api private
#
def new_self(*arguments)
new(node.class, *arguments)
end
# Create a new AST node with Rubnius::AST::NilLiteral class
#
# @return [Rubinius::AST::Node]
#
# @api private
#
def new_nil
new(Rubinius::AST::NilLiteral)
end
# Create a new AST node with the same line as wrapped node
#
# @param [Class:Rubinius::AST::Node] node_class
#
# @return [Rubinius::AST::Node]
#
# @api private
#
def new(node_class, *arguments)
node_class.new(node.line, *arguments)
end
# Emit a new AST node with same class as wrapped node
#
# @return [undefined]
#
# @api private
#
def emit_self(*arguments)
emit(new_self(*arguments))
end
# Emit a new node with wrapping class for each entry in values
#
# @param [Array] values
#
# @return [undefined]
#
# @api private
#
def emit_values(values)
values.each do |value|
emit_self(value)
end
end
# Emit element presence mutations
#
# @param [Array] elements
#
# @return [undefined]
#
# @api private
#
def emit_element_presence(elements)
elements.each_index do |index|
dup_elements = elements.dup
dup_elements.delete_at(index)
emit_self(dup_elements)
end
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(node)
end
end
# Emit body mutations
#
# @param [Array] body
#
# @return [undefined]
#
# @api private
#
def emit_body(body)
body.each_with_index do |element, index|
dup_body = body.dup
Mutator.each(element).each do |mutation|
dup_body[index]=mutation
emit_self(dup_body)
end
end
end
# Emit a new AST node with NilLiteral class
#
# @return [Rubinius::AST::NilLiteral]
#
# @api private
#
def emit_nil
emit(new_nil)
end
# Return AST representing send
#
# @param [Rubinius::AST::Node] receiver
# @param [Symbol] name
# @param [Rubinius::AST::Node] arguments
#
# @return [Rubnius::AST::SendWithArguments]
#
# @api private
#
def new_send(receiver, name, arguments=nil)
if arguments
new(Rubinius::AST::SendWithArguments, receiver, name, arguments)
else
new(Rubinius::AST::Send, receiver, name)
end
end
# Return duplicated (unfrozen) node each call
#
# @return [Rubinius::AST::Node]
#
# @api private
#
def dup_node
node.dup
end
end
end

View file

@ -1,35 +0,0 @@
module Mutant
class Mutator
# Mutator for arguments
class Arguments < self
handle(Rubinius::AST::ActualArguments)
private
# Emit mutations
#
# @return [undefined]
#
# @api private
#
def dispatch
emit_argument_mutations
end
# Emit argument mutations
#
# @return [undefined]
#
# @api private
#
def emit_argument_mutations
Mutator::Util::Array.each(node.array) do |mutation|
dup = dup_node
dup.array = mutation
emit(dup)
end
end
end
end
end

View file

@ -1,27 +0,0 @@
module Mutant
class Mutator
# Mutator on AST blocks
class Block < self
handle(Rubinius::AST::Block)
private
# Emit mutants
#
# @return [undefined]
#
# @api private
#
def dispatch
array = node.array
emit_body(array)
if array.length > 1
emit_element_presence(array)
else
emit_self([new_nil])
end
end
end
end
end

View file

@ -1,22 +0,0 @@
module Mutant
class Mutator
class Define < self
handle(Rubinius::AST::Define)
handle(Rubinius::AST::DefineSingleton)
handle(Rubinius::AST::DefineSingletonScope)
private
# Emit mutations
#
# @return [undefined]
#
# @api private
#
def dispatch
emit_body_mutations
end
end
end
end

View file

@ -1,148 +0,0 @@
module Mutant
class Mutator
# Mutator for Rubinius::AST::If nodes
class IfStatement < self
handle(Rubinius::AST::If)
private
# Emit mutations on Rubinius::AST::If nodes
#
# @return [undefined]
#
# @api private
#
def dispatch
emit_condition_mutants
emit_if_branch_mutants
emit_else_branch_mutants
emit_inverted_condition
emit_deleted_if_branch
emit_deleted_else_branch
end
# Emit inverted condition
#
# Especially the same like swap branches but more universal as it also
# covers the case there is no else branch
#
# @return [undefined]
#
# @api private
#
def emit_inverted_condition
emit_self(invert(condition), if_branch, else_branch)
end
# Emit deleted else branch
#
# @return [undefined]
#
# @api private
#
def emit_deleted_else_branch
emit_self(condition, if_branch, nil)
end
# Emit deleted if branch
#
# @return [undefined]
#
# @api private
#
def emit_deleted_if_branch
body = else_branch
return unless body
emit_self(condition, else_branch, nil)
end
# Return ast that returns inverted boolean value
#
# @param [Rubinius::Node::AST] node
#
# @return [Rubinius::Node::AST]
#
# @api private
#
# Using :'!' instead of :! since syntax highlighting in vim does not
# capture literal symbol.
#
def invert(node)
if Helper.on_18?
return new(Rubinius::AST::Not, node)
end
new_send(node,:'!')
end
# Emit mutants of condition
#
# @return [undefined]
#
# @api private
#
def emit_condition_mutants
Mutator.each(condition) do |mutant|
emit_self(mutant, if_branch, else_branch)
end
end
# Emit if body mutations
#
# @return [undefined]
#
# @api private
#
def emit_if_branch_mutants
Mutator.each(if_branch) do |mutant|
emit_self(condition, mutant, else_branch)
end
end
# Emit else body mutations
#
# @return [undefined]
#
# @api private
#
def emit_else_branch_mutants
body = else_branch
return unless body
Mutator.each(body) do |mutant|
emit_self(condition, if_branch, mutant)
end
end
# Return if_branch of node
#
# @return [Rubinius::AST::Node]
#
# @api private
#
def if_branch
node.body
end
# Return condition of node
#
# @return [Rubinius::AST::Node]
#
# @api private
#
def condition
node.condition
end
# Return else body of node
#
# @return [Rubinius::AST::Node]
#
# @api private
#
def else_branch
node.else
end
end
end
end

View file

@ -1,52 +0,0 @@
module Mutant
class Mutator
# Abstract mutator for literal AST nodes
class Literal < self
include AbstractType
private
# Return new float literal
#
# @param [#to_f] value
#
# @return [Rubinius::Node::FloatLiteral]
#
# @api private
#
def new_float(value)
new(Rubinius::AST::FloatLiteral, value)
end
# Return AST representing NaN
#
# @return [Rubinius::Node::AST]
#
# @api private
#
def nan
new_send(new_float(0), :/, new_float(0))
end
# Return AST representing negative infinity
#
# @return [Rubinius::Node::AST]
#
# @api private
#
def negative_infinity
new(Rubinius::AST::Negate, infinity)
end
# Return AST representing infinity
#
# @return [Rubinius::Node::AST]
#
# @api private
#
def infinity
new_send(new_float(1), :/, new_float(0))
end
end
end
end

View file

@ -1,28 +0,0 @@
module Mutant
class Mutator
class Literal < self
# Mutator for array literals
class Array < self
handle(Rubinius::AST::ArrayLiteral)
private
# Emit mutations
#
# @return [undefined]
#
# @api private
#
def dispatch
body = node.body
emit_nil
emit_self([])
emit_self(body.dup << new_nil)
emit_element_presence(body)
emit_body(body)
end
end
end
end
end

View file

@ -1,47 +0,0 @@
module Mutant
class Mutator
class Literal < self
# Abstract mutator for boolean literals
class Boolean < self
private
# Emit mutants
#
# @return [undefined]
#
# @api private
#
def dispatch
emit_nil
emit(inverse)
end
# Return inverse
#
# @return [Rubinius::AST::Node]
#
# @api private
#
def inverse
new(self.class::INVERSE_CLASS)
end
# Mutator for true literals
class TrueLiteral < self
INVERSE_CLASS = Rubinius::AST::FalseLiteral
handle(Rubinius::AST::TrueLiteral)
end
# Mutator for false literals
class FalseLiteral < self
INVERSE_CLASS = Rubinius::AST::TrueLiteral
handle(Rubinius::AST::FalseLiteral)
end
end
end
end
end

View file

@ -1,22 +0,0 @@
module Mutant
class Mutator
class Literal
# Abstract mutations on dynamic literals
class Dynamic < self
include AbstractType
private
# Emit mutants
#
# @return [undefined]
#
# @api private
#
def dispatch
emit_nil
end
end
end
end
end

View file

@ -1,24 +0,0 @@
module Mutant
class Mutator
class Literal < self
# Mutator for empty array literals
class EmptyArray < self
handle(Rubinius::AST::EmptyArray)
private
# Emit mutants
#
# @return [undefined]
#
# @api private
#
def dispatch
emit_nil
emit_node(Rubinius::AST::ArrayLiteral, [new_nil])
end
end
end
end
end

View file

@ -1,35 +0,0 @@
module Mutant
class Mutator
class Literal < self
# Mutator for fixnum literals
class Fixnum < self
handle(Rubinius::AST::FixnumLiteral)
private
# Emit mutants
#
# @return [undefined]
#
# @api private
#
def dispatch
emit_nil
emit_values(values)
emit_new { new_self(Random.fixnum) }
end
# Return values to mutate against
#
# @return [Array]
#
# @api private
#
def values
[0, 1, -node.value]
end
end
end
end
end

View file

@ -1,46 +0,0 @@
module Mutant
class Mutator
class Literal < self
# Mutator for float literals
class Float < self
handle(Rubinius::AST::FloatLiteral)
private
# Emit mutants
#
# @return [undefined]
#
def dispatch
emit_nil
emit_values(values)
emit_special_cases
emit_new { new_self(Random.float) }
end
# Emit special cases
#
# @return [undefined]
#
# @api private
#
def emit_special_cases
[infinity, negative_infinity, nan].each do |value|
emit(value)
end
end
# Return values to test against
#
# @return [Array]
#
# @api private
#
def values
[0.0, 1.0] << -node.value
end
end
end
end
end

View file

@ -1,71 +0,0 @@
module Mutant
class Mutator
class Literal
# Mutator for hash literals
class Hash < self
handle(Rubinius::AST::HashLiteral)
private
# Emit mutations
#
# @return [undefined]
#
# @api private
#
def dispatch
emit_nil
emit_values(values)
emit_element_presence
emit_body(array)
end
# Return array of values in literal
#
# @return [Array]
#
# @api private
#
def array
node.array
end
# Return duplicate of array values in literal
#
# @return [Array]
#
# @api private
#
def dup_array
array.dup
end
# Return values to mutate against
#
# @return [Array]
#
# @api private
#
def values
[[], dup_array << new_nil << new_nil ]
end
# Emit element presence mutations
#
# @return [undefined]
#
# @api private
#
def emit_element_presence
0.step(array.length-1, 2) do |index|
contents = dup_array
contents.delete_at(index)
contents.delete_at(index)
emit_self(contents)
end
end
end
end
end
end

View file

@ -1,23 +0,0 @@
module Mutant
class Mutator
class Literal
# Mutator for nil literals
class Nil < self
handle(Rubinius::AST::NilLiteral)
private
# Emit mutants
#
# @return [undefined]
#
# @api private
#
def dispatch
emit('Object.new'.to_ast)
end
end
end
end
end

View file

@ -1,92 +0,0 @@
module Mutant
class Mutator
class Literal
# Abstract literal range mutator
class Range < self
include AbstractType
private
# Emit mutants
#
# @return [undefined]
#
# @api private
#
def dispatch
emit_nil
emit(inverse)
emit_range
end
# Return inverse node
#
# @return [Rubinius::AST::Node]
#
# @api private
#
def inverse
new(inverse_class,node.start, node.finish)
end
# Emit range specific mutants
#
# @return [undefined]
#
# @api private
#
def emit_range
emit_finish_mutations
emit_start_mutations
end
# Emit range start mutations
#
# @return [undefined]
#
# @api private
#
def emit_finish_mutations
finish = node.finish
emit_self(negative_infinity, finish)
emit_self(nan, finish)
end
# Emit start mutations
#
# @return [undefined]
#
# @api private
#
def emit_start_mutations
start = node.start
emit_self(start, infinity)
emit_self(start, nan)
end
# Return inverse AST node class
#
# @return [Class:Rubinius::AST::Node]
#
# @api private
#
def inverse_class
self.class::INVERSE_CLASS
end
# Mutator for range exclude literals
class Exclude < self
INVERSE_CLASS = Rubinius::AST::Range
handle(Rubinius::AST::RangeExclude)
end
# Mutator for range include literals
class Include < self
INVERSE_CLASS = Rubinius::AST::RangeExclude
handle(Rubinius::AST::Range)
end
end
end
end
end

View file

@ -1,41 +0,0 @@
module Mutant
class Mutator
class Literal < self
# Mutator for regexp literals
class Regex < self
handle(Rubinius::AST::RegexLiteral)
private
# Emit mutants
#
# @return [undefined]
#
# @api private
#
def dispatch
emit_nil
emit_self('') # match all
emit_self('a\A') # match nothing
emit_new { new_self(Random.hex_string) }
end
# Return new Rubinius::AST::Regex
#
# @param [String] source
#
# @param [Integer] options
# options of regexp, defaults to mutation subject node options
#
# @return [undefined]
#
# @api private
#
def new_self(source,options=nil)
super(source,options || node.options)
end
end
end
end
end

View file

@ -1,24 +0,0 @@
module Mutant
class Mutator
class Literal
# Mutator for string literals
class String < self
handle(Rubinius::AST::StringLiteral)
private
# Emit mutants
#
# @return [undefined]
#
# @api private
#
def dispatch
emit_nil
emit_new { new_self(Random.hex_string) }
end
end
end
end
end

View file

@ -1,24 +0,0 @@
module Mutant
class Mutator
class Literal < self
# Mutator for symbol literals
class Symbol < self
handle(Rubinius::AST::SymbolLiteral)
private
# Emit mutatns
#
# @return [undefined]
#
# @api private
#
def dispatch
emit_nil
emit_new { new_self(('s'+Random.hex_string).to_sym) }
end
end
end
end
end

193
lib/mutant/mutator/node.rb Normal file
View file

@ -0,0 +1,193 @@
module Mutant
# Generator for mutations
class Mutator
# Abstract base class for node mutators
class Node < self
include AbstractType
private
alias_method :node, :input
alias_method :dup_node, :dup_input
# Return source of input node
#
# @return [String]
#
# @api private
#
def source
ToSource.to_source(node)
end
memoize :source
# Test if generated node is new
#
# @return [true]
# if generated node is different from input
#
# @return [false]
# otherwise
#
# @api private
#
def new?(node)
source != ToSource.to_source(node)
end
# Emit a new AST node
#
# @param [Rubinis::AST::Node:Class] node_class
#
# @return [Rubinius::AST::Node]
#
# @api private
#
def emit_node(node_class, *arguments)
emit(new(node_class, *arguments))
end
# Create a new AST node with same class as wrapped node
#
# @return [Rubinius::AST::Node]
#
# @api private
#
def new_self(*arguments)
new(node.class, *arguments)
end
# Create a new AST node with Rubnius::AST::NilLiteral class
#
# @return [Rubinius::AST::Node]
#
# @api private
#
def new_nil
new(Rubinius::AST::NilLiteral)
end
# Create a new AST node with the same line as wrapped node
#
# @param [Class:Rubinius::AST::Node] node_class
#
# @return [Rubinius::AST::Node]
#
# @api private
#
def new(node_class, *arguments)
node_class.new(node.line, *arguments)
end
# Emit a new AST node with same class as wrapped node
#
# @return [undefined]
#
# @api private
#
def emit_self(*arguments)
emit(new_self(*arguments))
end
# Emit a new node with wrapping class for each entry in values
#
# @param [Array] values
#
# @return [undefined]
#
# @api private
#
def emit_values(values)
values.each do |value|
emit_self(value)
end
end
# Emit element presence mutations
#
# @param [Array] elements
#
# @return [undefined]
#
# @api private
#
def emit_element_presence(elements)
elements.each_index do |index|
dup_elements = elements.dup
dup_elements.delete_at(index)
emit_self(dup_elements)
end
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(node)
end
end
# Emit body mutations
#
# @param [Array] body
#
# @return [undefined]
#
# @api private
#
def emit_body(body)
body.each_with_index do |element, index|
dup_body = body.dup
Mutator.each(element).each do |mutation|
dup_body[index]=mutation
emit_self(dup_body)
end
end
end
# Emit a new AST node with NilLiteral class
#
# @return [Rubinius::AST::NilLiteral]
#
# @api private
#
def emit_nil
emit(new_nil)
end
# Return AST representing send
#
# @param [Rubinius::AST::Node] receiver
# @param [Symbol] name
# @param [Rubinius::AST::Node] arguments
#
# @return [Rubnius::AST::SendWithArguments]
#
# @api private
#
def new_send(receiver, name, arguments=nil)
if arguments
new(Rubinius::AST::SendWithArguments, receiver, name, arguments)
else
new(Rubinius::AST::Send, receiver, name)
end
end
# Return duplicated (unfrozen) node each call
#
# @return [Rubinius::AST::Node]
#
# @api private
#
def dup_node
node.dup
end
end
end
end

View file

@ -0,0 +1,38 @@
module Mutant
class Mutator
class Node
# Mutator for arguments
class Arguments < self
handle(Rubinius::AST::ActualArguments)
private
# Emit mutations
#
# @return [undefined]
#
# @api private
#
def dispatch
emit_argument_mutations
end
# Emit argument mutations
#
# @return [undefined]
#
# @api private
#
def emit_argument_mutations
Mutator::Util::Array.each(node.array) do |mutation|
dup = dup_input
dup.array = mutation
emit(dup)
end
end
end
end
end
end

View file

@ -0,0 +1,29 @@
module Mutant
class Mutator
class Node
# Mutator on AST blocks
class Block < self
handle(Rubinius::AST::Block)
private
# Emit mutants
#
# @return [undefined]
#
# @api private
#
def dispatch
array = input.array
emit_body(array)
if array.length > 1
emit_element_presence(array)
else
emit_self([new_nil])
end
end
end
end
end
end

View file

@ -0,0 +1,24 @@
module Mutant
class Mutator
class Node
class Define < self
handle(Rubinius::AST::Define)
handle(Rubinius::AST::DefineSingleton)
handle(Rubinius::AST::DefineSingletonScope)
private
# Emit mutations
#
# @return [undefined]
#
# @api private
#
def dispatch
emit_body_mutations
end
end
end
end
end

View file

@ -0,0 +1,150 @@
module Mutant
class Mutator
class Node
# Mutator for Rubinius::AST::If nodes
class IfStatement < self
handle(Rubinius::AST::If)
private
# Emit mutations on Rubinius::AST::If nodes
#
# @return [undefined]
#
# @api private
#
def dispatch
emit_condition_mutants
emit_if_branch_mutants
emit_else_branch_mutants
emit_inverted_condition
emit_deleted_if_branch
emit_deleted_else_branch
end
# Emit inverted condition
#
# Especially the same like swap branches but more universal as it also
# covers the case there is no else branch
#
# @return [undefined]
#
# @api private
#
def emit_inverted_condition
emit_self(invert(condition), if_branch, else_branch)
end
# Emit deleted else branch
#
# @return [undefined]
#
# @api private
#
def emit_deleted_else_branch
emit_self(condition, if_branch, nil)
end
# Emit deleted if branch
#
# @return [undefined]
#
# @api private
#
def emit_deleted_if_branch
body = else_branch
return unless body
emit_self(condition, else_branch, nil)
end
# Return ast that returns inverted boolean value
#
# @param [Rubinius::Node::AST] node
#
# @return [Rubinius::Node::AST]
#
# @api private
#
# Using :'!' instead of :! since syntax highlighting in vim does not
# capture literal symbol.
#
def invert(node)
if Helper.on_18?
return new(Rubinius::AST::Not, node)
end
new_send(node,:'!')
end
# Emit mutants of condition
#
# @return [undefined]
#
# @api private
#
def emit_condition_mutants
Mutator.each(condition) do |mutant|
emit_self(mutant, if_branch, else_branch)
end
end
# Emit if body mutations
#
# @return [undefined]
#
# @api private
#
def emit_if_branch_mutants
Mutator.each(if_branch) do |mutant|
emit_self(condition, mutant, else_branch)
end
end
# Emit else body mutations
#
# @return [undefined]
#
# @api private
#
def emit_else_branch_mutants
body = else_branch
return unless body
Mutator.each(body) do |mutant|
emit_self(condition, if_branch, mutant)
end
end
# Return if_branch of node
#
# @return [Rubinius::AST::Node]
#
# @api private
#
def if_branch
node.body
end
# Return condition of node
#
# @return [Rubinius::AST::Node]
#
# @api private
#
def condition
node.condition
end
# Return else body of node
#
# @return [Rubinius::AST::Node]
#
# @api private
#
def else_branch
node.else
end
end
end
end
end

View file

@ -0,0 +1,54 @@
module Mutant
class Mutator
class Node
# Abstract mutator for literal AST nodes
class Literal < self
include AbstractType
private
# Return new float literal
#
# @param [#to_f] value
#
# @return [Rubinius::Node::FloatLiteral]
#
# @api private
#
def new_float(value)
new(Rubinius::AST::FloatLiteral, value)
end
# Return AST representing NaN
#
# @return [Rubinius::Node::AST]
#
# @api private
#
def nan
new_send(new_float(0), :/, new_float(0))
end
# Return AST representing negative infinity
#
# @return [Rubinius::Node::AST]
#
# @api private
#
def negative_infinity
new(Rubinius::AST::Negate, infinity)
end
# Return AST representing infinity
#
# @return [Rubinius::Node::AST]
#
# @api private
#
def infinity
new_send(new_float(1), :/, new_float(0))
end
end
end
end
end

View file

@ -0,0 +1,30 @@
module Mutant
class Mutator
class Node
class Literal < self
# Mutator for array literals
class Array < self
handle(Rubinius::AST::ArrayLiteral)
private
# Emit mutations
#
# @return [undefined]
#
# @api private
#
def dispatch
body = node.body
emit_nil
emit_self([])
emit_self(body.dup << new_nil)
emit_element_presence(body)
emit_body(body)
end
end
end
end
end
end

View file

@ -0,0 +1,49 @@
module Mutant
class Mutator
class Node
class Literal < self
# Abstract mutator for boolean literals
class Boolean < self
private
# Emit mutants
#
# @return [undefined]
#
# @api private
#
def dispatch
emit_nil
emit(inverse)
end
# Return inverse
#
# @return [Rubinius::AST::Node]
#
# @api private
#
def inverse
new(self.class::INVERSE_CLASS)
end
# Mutator for true literals
class TrueLiteral < self
INVERSE_CLASS = Rubinius::AST::FalseLiteral
handle(Rubinius::AST::TrueLiteral)
end
# Mutator for false literals
class FalseLiteral < self
INVERSE_CLASS = Rubinius::AST::TrueLiteral
handle(Rubinius::AST::FalseLiteral)
end
end
end
end
end
end

View file

@ -0,0 +1,24 @@
module Mutant
class Mutator
class Node
class Literal
# Abstract mutations on dynamic literals
class Dynamic < self
include AbstractType
private
# Emit mutants
#
# @return [undefined]
#
# @api private
#
def dispatch
emit_nil
end
end
end
end
end
end

View file

@ -0,0 +1,26 @@
module Mutant
class Mutator
class Node
class Literal < self
# Mutator for empty array literals
class EmptyArray < self
handle(Rubinius::AST::EmptyArray)
private
# Emit mutants
#
# @return [undefined]
#
# @api private
#
def dispatch
emit_nil
emit_node(Rubinius::AST::ArrayLiteral, [new_nil])
end
end
end
end
end
end

View file

@ -0,0 +1,37 @@
module Mutant
class Mutator
class Node
class Literal < self
# Mutator for fixnum literals
class Fixnum < self
handle(Rubinius::AST::FixnumLiteral)
private
# Emit mutants
#
# @return [undefined]
#
# @api private
#
def dispatch
emit_nil
emit_values(values)
emit_new { new_self(Random.fixnum) }
end
# Return values to mutate against
#
# @return [Array]
#
# @api private
#
def values
[0, 1, -node.value]
end
end
end
end
end
end

View file

@ -0,0 +1,48 @@
module Mutant
class Mutator
class Node
class Literal < self
# Mutator for float literals
class Float < self
handle(Rubinius::AST::FloatLiteral)
private
# Emit mutants
#
# @return [undefined]
#
def dispatch
emit_nil
emit_values(values)
emit_special_cases
emit_new { new_self(Random.float) }
end
# Emit special cases
#
# @return [undefined]
#
# @api private
#
def emit_special_cases
[infinity, negative_infinity, nan].each do |value|
emit(value)
end
end
# Return values to test against
#
# @return [Array]
#
# @api private
#
def values
[0.0, 1.0] << -node.value
end
end
end
end
end
end

View file

@ -0,0 +1,73 @@
module Mutant
class Mutator
class Node
class Literal
# Mutator for hash literals
class Hash < self
handle(Rubinius::AST::HashLiteral)
private
# Emit mutations
#
# @return [undefined]
#
# @api private
#
def dispatch
emit_nil
emit_values(values)
emit_element_presence
emit_body(array)
end
# Return array of values in literal
#
# @return [Array]
#
# @api private
#
def array
node.array
end
# Return duplicate of array values in literal
#
# @return [Array]
#
# @api private
#
def dup_array
array.dup
end
# Return values to mutate against
#
# @return [Array]
#
# @api private
#
def values
[[], dup_array << new_nil << new_nil ]
end
# Emit element presence mutations
#
# @return [undefined]
#
# @api private
#
def emit_element_presence
0.step(array.length-1, 2) do |index|
contents = dup_array
contents.delete_at(index)
contents.delete_at(index)
emit_self(contents)
end
end
end
end
end
end
end

View file

@ -0,0 +1,25 @@
module Mutant
class Mutator
class Node
class Literal
# Mutator for nil literals
class Nil < self
handle(Rubinius::AST::NilLiteral)
private
# Emit mutants
#
# @return [undefined]
#
# @api private
#
def dispatch
emit('Object.new'.to_ast)
end
end
end
end
end
end

View file

@ -0,0 +1,94 @@
module Mutant
class Mutator
class Node
class Literal
# Abstract literal range mutator
class Range < self
include AbstractType
private
# Emit mutants
#
# @return [undefined]
#
# @api private
#
def dispatch
emit_nil
emit(inverse)
emit_range
end
# Return inverse node
#
# @return [Rubinius::AST::Node]
#
# @api private
#
def inverse
new(inverse_class,node.start, node.finish)
end
# Emit range specific mutants
#
# @return [undefined]
#
# @api private
#
def emit_range
emit_finish_mutations
emit_start_mutations
end
# Emit range start mutations
#
# @return [undefined]
#
# @api private
#
def emit_finish_mutations
finish = node.finish
emit_self(negative_infinity, finish)
emit_self(nan, finish)
end
# Emit start mutations
#
# @return [undefined]
#
# @api private
#
def emit_start_mutations
start = node.start
emit_self(start, infinity)
emit_self(start, nan)
end
# Return inverse AST node class
#
# @return [Class:Rubinius::AST::Node]
#
# @api private
#
def inverse_class
self.class::INVERSE_CLASS
end
# Mutator for range exclude literals
class Exclude < self
INVERSE_CLASS = Rubinius::AST::Range
handle(Rubinius::AST::RangeExclude)
end
# Mutator for range include literals
class Include < self
INVERSE_CLASS = Rubinius::AST::RangeExclude
handle(Rubinius::AST::Range)
end
end
end
end
end
end

View file

@ -0,0 +1,43 @@
module Mutant
class Mutator
class Node
class Literal < self
# Mutator for regexp literals
class Regex < self
handle(Rubinius::AST::RegexLiteral)
private
# Emit mutants
#
# @return [undefined]
#
# @api private
#
def dispatch
emit_nil
emit_self('') # match all
emit_self('a\A') # match nothing
emit_new { new_self(Random.hex_string) }
end
# Return new Rubinius::AST::Regex
#
# @param [String] source
#
# @param [Integer] options
# options of regexp, defaults to mutation subject node options
#
# @return [undefined]
#
# @api private
#
def new_self(source,options=nil)
super(source,options || node.options)
end
end
end
end
end
end

View file

@ -0,0 +1,26 @@
module Mutant
class Mutator
class Node
class Literal
# Mutator for string literals
class String < self
handle(Rubinius::AST::StringLiteral)
private
# Emit mutants
#
# @return [undefined]
#
# @api private
#
def dispatch
emit_nil
emit_new { new_self(Random.hex_string) }
end
end
end
end
end
end

View file

@ -0,0 +1,26 @@
module Mutant
class Mutator
class Node
class Literal < self
# Mutator for symbol literals
class Symbol < self
handle(Rubinius::AST::SymbolLiteral)
private
# Emit mutatns
#
# @return [undefined]
#
# @api private
#
def dispatch
emit_nil
emit_new { new_self(('s'+Random.hex_string).to_sym) }
end
end
end
end
end
end

View file

@ -0,0 +1,51 @@
module Mutant
class Mutator
class Node
# Mutator that does not do mutations on ast
class Noop < self
# Literal references to self do not need to be mutated?
handle(Rubinius::AST::Self)
# Currently unhandled node classes. Feel free to contribute your mutator!
handle(Rubinius::AST::ElementAssignment)
handle(Rubinius::AST::AttributeAssignment)
handle(Rubinius::AST::Not)
handle(Rubinius::AST::And)
handle(Rubinius::AST::Defined)
handle(Rubinius::AST::Super)
handle(Rubinius::AST::Match3)
handle(Rubinius::AST::ZSuper)
handle(Rubinius::AST::MultipleAssignment)
handle(Rubinius::AST::ScopedConstant)
handle(Rubinius::AST::LocalVariableAssignment)
handle(Rubinius::AST::LocalVariableAccess)
handle(Rubinius::AST::InstanceVariableAssignment)
handle(Rubinius::AST::InstanceVariableAccess)
handle(Rubinius::AST::GlobalVariableAssignment)
handle(Rubinius::AST::GlobalVariableAccess)
handle(Rubinius::AST::Ensure)
handle(Rubinius::AST::Rescue)
handle(Rubinius::AST::DynamicString)
handle(Rubinius::AST::DynamicSymbol)
handle(Rubinius::AST::DynamicRegex)
handle(Rubinius::AST::OpAssignOr19)
handle(Rubinius::AST::OpAssign1)
handle(Rubinius::AST::Or)
handle(Rubinius::AST::ConstantAccess)
private
# Emit mutations
#
# @return [undefined]
#
# @api private
#
def dispatch
# noop
end
end
end
end
end

View file

@ -0,0 +1,153 @@
module Mutant
class Mutator
class Node
# Mutator for Rubinius::AST::When nodes
class When < self
handle(Rubinius::AST::When)
private
# Emit mutations
#
# @return [undefined]
#
# @api private
#
def dispatch
emit_body_mutations
end
end
# Mutator for Rubinius::AST::ReceiverCase nodes
class ReceiverCase < self
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
#
# @return [false]
# returns false otherwise
#
# @api private
#
def one?
when_branches.one?
end
# Return duplicate of 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
end

View file

@ -0,0 +1,31 @@
module Mutant
class Mutator
class Node
# Mutator for return statements
class Return < self
handle(Rubinius::AST::Return)
private
# Emit mutants
#
# @return [undefined]
#
# @api private
#
def dispatch
value = node.value
if value
emit(value)
else
emit_nil
end
end
end
end
end
end

View file

@ -0,0 +1,125 @@
module Mutant
class Mutator
class Node
# Class for mutations where messages are send to objects
class Send < self
handle(Rubinius::AST::Send)
private
# Return receiver AST node
#
# @return [Rubinius::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]
# returns true when receiver is a Rubinius::AST::Self node
#
# @return [false]
# return false otherwise
#
# @api private
#
def 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
# FIXME: Edge case that is currently not very well undestood
return if name == :block_given?
return unless self?
mutant = dup_node
mutant.privately = true
# TODO: Fix rubinius to allow this as an attr_accessor
mutant.instance_variable_set(:@vcall_style, true)
emit(mutant)
end
# Emit mutations
#
# @return [undefined]
#
# @api private
#
def dispatch
emit_implicit_self_receiver
end
class SendWithArguments < self
handle(Rubinius::AST::SendWithArguments)
private
# Emit mutations
#
# @return [undefined]
#
# @api private
#
def dispatch
super
emit_argument_mutations
end
# Emit argument mutations
#
# @return [undefined]
#
# @api private
#
def emit_argument_mutations
Mutator.each(node.arguments) do |mutation|
dup = dup_node
dup.arguments = mutation
emit(dup)
end
end
end
end
end
end
end

View file

@ -1,49 +0,0 @@
module Mutant
class Mutator
# Mutator that does not do mutations on ast
class Noop < self
# Literal references to self do not need to be mutated?
handle(Rubinius::AST::Self)
# Currently unhandled node classes. Feel free to contribute your mutator!
handle(Rubinius::AST::ElementAssignment)
handle(Rubinius::AST::AttributeAssignment)
handle(Rubinius::AST::Not)
handle(Rubinius::AST::And)
handle(Rubinius::AST::Defined)
handle(Rubinius::AST::Super)
handle(Rubinius::AST::Match3)
handle(Rubinius::AST::ZSuper)
handle(Rubinius::AST::MultipleAssignment)
handle(Rubinius::AST::ScopedConstant)
handle(Rubinius::AST::LocalVariableAssignment)
handle(Rubinius::AST::LocalVariableAccess)
handle(Rubinius::AST::InstanceVariableAssignment)
handle(Rubinius::AST::InstanceVariableAccess)
handle(Rubinius::AST::GlobalVariableAssignment)
handle(Rubinius::AST::GlobalVariableAccess)
handle(Rubinius::AST::Ensure)
handle(Rubinius::AST::Rescue)
handle(Rubinius::AST::DynamicString)
handle(Rubinius::AST::DynamicSymbol)
handle(Rubinius::AST::DynamicRegex)
handle(Rubinius::AST::OpAssignOr19)
handle(Rubinius::AST::OpAssign1)
handle(Rubinius::AST::Or)
handle(Rubinius::AST::ConstantAccess)
private
# Emit mutations
#
# @return [undefined]
#
# @api private
#
def dispatch
# noop
end
end
end
end

View file

@ -1,151 +0,0 @@
module Mutant
class Mutator
# Mutator for Rubinius::AST::When nodes
class When < self
handle(Rubinius::AST::When)
private
# Emit mutations
#
# @return [undefined]
#
# @api private
#
def dispatch
emit_body_mutations
end
end
# Mutator for Rubinius::AST::ReceiverCase nodes
class ReceiverCase < self
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
#
# @return [false]
# returns false otherwise
#
# @api private
#
def one?
when_branches.one?
end
# Return duplicate of 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

@ -1,29 +0,0 @@
module Mutant
class Mutator
# Mutator for return statements
class Return < self
handle(Rubinius::AST::Return)
private
# Emit mutants
#
# @return [undefined]
#
# @api private
#
def dispatch
value = node.value
if value
emit(value)
else
emit_nil
end
end
end
end
end

View file

@ -1,123 +0,0 @@
module Mutant
class Mutator
# Class for mutations where messages are send to objects
class Send < self
handle(Rubinius::AST::Send)
private
# Return receiver AST node
#
# @return [Rubinius::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]
# returns true when receiver is a Rubinius::AST::Self node
#
# @return [false]
# return false otherwise
#
# @api private
#
def 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
# FIXME: Edge case that is currently not very well undestood
return if name == :block_given?
return unless self?
mutant = dup_node
mutant.privately = true
# TODO: Fix rubinius to allow this as an attr_accessor
mutant.instance_variable_set(:@vcall_style, true)
emit(mutant)
end
# Emit mutations
#
# @return [undefined]
#
# @api private
#
def dispatch
emit_implicit_self_receiver
end
class SendWithArguments < self
handle(Rubinius::AST::SendWithArguments)
private
# Emit mutations
#
# @return [undefined]
#
# @api private
#
def dispatch
super
emit_argument_mutations
end
# Emit argument mutations
#
# @return [undefined]
#
# @api private
#
def emit_argument_mutations
Mutator.each(node.arguments) do |mutation|
dup = dup_node
dup.arguments = mutation
emit(dup)
end
end
end
end
end
end

View file

@ -28,7 +28,7 @@ module Mutant
# otherwise
#
def new?(generated)
node != generated
input != generated
end
# Mutators that mutates an array of inputs
@ -55,8 +55,8 @@ module Mutant
# @api private
#
def emit_element_mutations
node.each_with_index do |element, index|
dup = dup_node
input.each_with_index do |element, index|
dup = dup_input
Mutator.each(element).each do |mutation|
dup[index]=mutation
@ -72,8 +72,8 @@ module Mutant
# @api private
#
def emit_element_presence
node.each_index do |index|
dup = dup_node
input.each_index do |index|
dup = dup_input
dup.delete_at(index)
emit(dup)
end

View file

@ -1,7 +1,7 @@
require 'spec_helper'
describe Mutant::Mutator, '#emit_new' do
subject { object.send(:emit_new) { node } }
subject { object.send(:emit_new) { generated } }
class Block
def arguments; @arguments; end
@ -15,9 +15,9 @@ describe Mutant::Mutator, '#emit_new' do
end
end
let(:object) { class_under_test.new(wrapped_node, block) }
let(:block) { Block.new }
let(:wrapped_node) { '"foo"'.to_ast }
let(:object) { class_under_test.new(input, block) }
let(:block) { Block.new }
let(:input) { :input }
let(:class_under_test) do
Class.new(described_class) do
@ -27,22 +27,22 @@ describe Mutant::Mutator, '#emit_new' do
end
end
context 'when new AST is generated' do
let(:node) { '"bar"'.to_ast }
context 'when new object generated' do
let(:generated) { :generated }
it 'should call block' do
subject
block.should be_called
end
it 'should call block with node' do
it 'should call block with generated object' do
subject
block.arguments.should eql([node])
block.arguments.should eql([generated])
end
end
context 'when new AST could not be generated' do
let(:node) { '"foo"'.to_ast }
let(:generated) { input }
it 'should raise error' do
expect { subject }.to raise_error(RuntimeError, 'New AST could not be generated after 3 attempts')

View file

@ -1,7 +1,7 @@
require 'spec_helper'
describe Mutant::Mutator, '#emit' do
subject { object.send(:emit, node) }
subject { object.send(:emit, generated) }
class Block
def arguments; @arguments; end
@ -15,9 +15,9 @@ describe Mutant::Mutator, '#emit' do
end
end
let(:object) { class_under_test.new(wrapped_node, block) }
let(:block) { Block.new }
let(:wrapped_node) { '"foo"'.to_ast }
let(:object) { class_under_test.new(input, block) }
let(:block) { Block.new }
let(:input) { :nput }
let(:class_under_test) do
Class.new(described_class) do
@ -27,24 +27,24 @@ describe Mutant::Mutator, '#emit' do
end
end
context 'with node that is not equal to wrapped node' do
let(:node) { '"bar"'.to_ast }
context 'with generated that is not equal to input' do
let(:generated) { :generated }
it 'should call block' do
subject
block.should be_called
end
it 'should call block with node' do
it 'should call block with generated' do
subject
block.arguments.should eql([node])
block.arguments.should eql([generated])
end
end
context 'with node that is equal to wrapped node' do
let(:node) { '"foo"'.to_ast }
context 'with generated object that is equal to input' do
let(:generated) { input }
it 'should call block' do
it 'should not call block' do
subject
block.should_not be_called
end

View file

@ -1,6 +1,6 @@
require 'spec_helper'
describe Mutant::Mutator::Literal, 'array' do
describe Mutant::Mutator::Node::Literal, 'array' do
let(:source) { '[true, false]' }
let(:mutations) do

View file

@ -1,6 +1,6 @@
require 'spec_helper'
describe Mutant::Mutator::Literal, 'boolean' do
describe Mutant::Mutator::Node::Literal, 'boolean' do
context 'true literal' do
let(:source) { 'true' }

View file

@ -1,6 +1,6 @@
require 'spec_helper'
describe Mutant::Mutator::Literal, 'empty array' do
describe Mutant::Mutator::Node::Literal, 'empty array' do
let(:source) { '[]' }
let(:mutations) do

View file

@ -1,6 +1,6 @@
require 'spec_helper'
describe Mutant::Mutator::Literal, 'fixnum' do
describe Mutant::Mutator::Node::Literal, 'fixnum' do
let(:random_fixnum) { 5 }
let(:source) { '10' }

View file

@ -1,6 +1,6 @@
require 'spec_helper'
describe Mutant::Mutator::Literal, 'float' do
describe Mutant::Mutator::Node::Literal, 'float' do
let(:source) { '10.0' }
let(:mutations) do

View file

@ -1,6 +1,6 @@
require 'spec_helper'
describe Mutant::Mutator::Literal, 'hash' do
describe Mutant::Mutator::Node::Literal, 'hash' do
let(:source) { '{true => true, false => false}' }
let(:mutations) do

View file

@ -1,6 +1,6 @@
require 'spec_helper'
describe Mutant::Mutator::Literal, 'nil' do
describe Mutant::Mutator::Node::Literal, 'nil' do
let(:source) { 'nil' }
let(:mutations) do

View file

@ -1,6 +1,6 @@
require 'spec_helper'
describe Mutant::Mutator::Literal, 'range' do
describe Mutant::Mutator::Node::Literal, 'range' do
context 'inclusive range literal' do
let(:source) { '1..100' }

View file

@ -1,6 +1,6 @@
require 'spec_helper'
describe Mutant::Mutator::Literal, 'regex' do
describe Mutant::Mutator::Node::Literal, 'regex' do
let(:random_string) { 'bar' }
let(:source) { '/foo/' }

View file

@ -1,6 +1,6 @@
require 'spec_helper'
describe Mutant::Mutator::Literal, 'string' do
describe Mutant::Mutator::Node::Literal, 'string' do
let(:random_string) { 'bar' }
let(:source) { '"foo"' }

View file

@ -1,6 +1,6 @@
require 'spec_helper'
describe Mutant::Mutator::Literal, 'symbol' do
describe Mutant::Mutator::Node::Literal, 'symbol' do
let(:random_string) { 'bar' }
let(:source) { ':foo' }

View file

@ -1,6 +1,6 @@
require 'spec_helper'
describe Mutant::Mutator::ReceiverCase do
describe Mutant::Mutator::Node::ReceiverCase do
let(:source) { 'case self.condition; when true; true; when false; false; else raise; end' }
let(:mutations) do