Extract node specific mutator base class
This commit is contained in:
parent
b984a15691
commit
69e9de95ed
60 changed files with 1452 additions and 1369 deletions
|
@ -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'
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
193
lib/mutant/mutator/node.rb
Normal 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
|
38
lib/mutant/mutator/node/arguments.rb
Normal file
38
lib/mutant/mutator/node/arguments.rb
Normal 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
|
29
lib/mutant/mutator/node/block.rb
Normal file
29
lib/mutant/mutator/node/block.rb
Normal 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
|
24
lib/mutant/mutator/node/define.rb
Normal file
24
lib/mutant/mutator/node/define.rb
Normal 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
|
150
lib/mutant/mutator/node/if_statement.rb
Normal file
150
lib/mutant/mutator/node/if_statement.rb
Normal 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
|
54
lib/mutant/mutator/node/literal.rb
Normal file
54
lib/mutant/mutator/node/literal.rb
Normal 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
|
30
lib/mutant/mutator/node/literal/array.rb
Normal file
30
lib/mutant/mutator/node/literal/array.rb
Normal 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
|
49
lib/mutant/mutator/node/literal/boolean.rb
Normal file
49
lib/mutant/mutator/node/literal/boolean.rb
Normal 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
|
24
lib/mutant/mutator/node/literal/dynamic.rb
Normal file
24
lib/mutant/mutator/node/literal/dynamic.rb
Normal 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
|
26
lib/mutant/mutator/node/literal/empty_array.rb
Normal file
26
lib/mutant/mutator/node/literal/empty_array.rb
Normal 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
|
37
lib/mutant/mutator/node/literal/fixnum.rb
Normal file
37
lib/mutant/mutator/node/literal/fixnum.rb
Normal 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
|
48
lib/mutant/mutator/node/literal/float.rb
Normal file
48
lib/mutant/mutator/node/literal/float.rb
Normal 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
|
73
lib/mutant/mutator/node/literal/hash.rb
Normal file
73
lib/mutant/mutator/node/literal/hash.rb
Normal 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
|
25
lib/mutant/mutator/node/literal/nil.rb
Normal file
25
lib/mutant/mutator/node/literal/nil.rb
Normal 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
|
94
lib/mutant/mutator/node/literal/range.rb
Normal file
94
lib/mutant/mutator/node/literal/range.rb
Normal 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
|
43
lib/mutant/mutator/node/literal/regex.rb
Normal file
43
lib/mutant/mutator/node/literal/regex.rb
Normal 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
|
26
lib/mutant/mutator/node/literal/string.rb
Normal file
26
lib/mutant/mutator/node/literal/string.rb
Normal 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
|
26
lib/mutant/mutator/node/literal/symbol.rb
Normal file
26
lib/mutant/mutator/node/literal/symbol.rb
Normal 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
|
51
lib/mutant/mutator/node/noop.rb
Normal file
51
lib/mutant/mutator/node/noop.rb
Normal 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
|
153
lib/mutant/mutator/node/receiver_case.rb
Normal file
153
lib/mutant/mutator/node/receiver_case.rb
Normal 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
|
31
lib/mutant/mutator/node/return.rb
Normal file
31
lib/mutant/mutator/node/return.rb
Normal 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
|
125
lib/mutant/mutator/node/send.rb
Normal file
125
lib/mutant/mutator/node/send.rb
Normal 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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
||||
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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')
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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' }
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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' }
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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' }
|
||||
|
||||
|
|
|
@ -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/' }
|
||||
|
|
|
@ -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"' }
|
||||
|
|
|
@ -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' }
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue