From b984a15691a1a7b68c559308a2c71384718d91a4 Mon Sep 17 00:00:00 2001 From: Markus Schirp Date: Thu, 6 Dec 2012 20:44:26 +0100 Subject: [PATCH] Add argument mutator * Add Util mutator to share code more efficient --- lib/mutant.rb | 4 +- lib/mutant/mutator/arguments.rb | 35 ++++++++ lib/mutant/mutator/{call.rb => send.rb} | 21 ++++- lib/mutant/mutator/util.rb | 85 +++++++++++++++++++ .../mutator/{call => send}/mutation_spec.rb | 18 +++- 5 files changed, 155 insertions(+), 8 deletions(-) create mode 100644 lib/mutant/mutator/arguments.rb rename lib/mutant/mutator/{call.rb => send.rb} (84%) create mode 100644 lib/mutant/mutator/util.rb rename spec/unit/mutant/mutator/{call => send}/mutation_spec.rb (78%) diff --git a/lib/mutant.rb b/lib/mutant.rb index d88c1924..309759c0 100644 --- a/lib/mutant.rb +++ b/lib/mutant.rb @@ -67,7 +67,9 @@ require 'mutant/mutator/literal/nil' #require 'mutant/mutator/literal/dynamic' require 'mutant/mutator/block' require 'mutant/mutator/noop' -require 'mutant/mutator/call' +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' diff --git a/lib/mutant/mutator/arguments.rb b/lib/mutant/mutator/arguments.rb new file mode 100644 index 00000000..6566d8c7 --- /dev/null +++ b/lib/mutant/mutator/arguments.rb @@ -0,0 +1,35 @@ +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 diff --git a/lib/mutant/mutator/call.rb b/lib/mutant/mutator/send.rb similarity index 84% rename from lib/mutant/mutator/call.rb rename to lib/mutant/mutator/send.rb index 43516151..b036a3cf 100644 --- a/lib/mutant/mutator/call.rb +++ b/lib/mutant/mutator/send.rb @@ -1,7 +1,7 @@ module Mutant class Mutator # Class for mutations where messages are send to objects - class Call < self + class Send < self handle(Rubinius::AST::Send) @@ -87,13 +87,13 @@ module Mutant emit_implicit_self_receiver end - class SendWithArguments < Call + class SendWithArguments < self handle(Rubinius::AST::SendWithArguments) private - # Emut mutations + # Emit mutations # # @return [undefined] # @@ -101,6 +101,21 @@ module Mutant # 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 diff --git a/lib/mutant/mutator/util.rb b/lib/mutant/mutator/util.rb new file mode 100644 index 00000000..4fa5ca72 --- /dev/null +++ b/lib/mutant/mutator/util.rb @@ -0,0 +1,85 @@ +module Mutant + class Mutator + # Namespace for utility mutators + class Util < self + + # Run ulitity mutator + # + # @param [Object] + # + # @api private + # + def self.each(object, &block) + return to_enum(__method__, object) unless block_given? + + new(object, block) + + self + end + + # Test if mutation is new + # + # @param [Object] generated + # + # @return [true] + # if object is new + # + # @return [false] + # otherwise + # + def new?(generated) + node != generated + end + + # Mutators that mutates an array of inputs + class Array < self + + private + + # Emit mutations + # + # @return [undefined] + # + # @api private + # + def dispatch + emit_element_presence + emit_element_mutations + emit([]) + end + + # Emit element mutations + # + # @return [undefined] + # + # @api private + # + def emit_element_mutations + node.each_with_index do |element, index| + dup = dup_node + + Mutator.each(element).each do |mutation| + dup[index]=mutation + emit(dup) + end + end + end + + # Emit element presence mutations + # + # @return [undefined] + # + # @api private + # + def emit_element_presence + node.each_index do |index| + dup = dup_node + dup.delete_at(index) + emit(dup) + end + end + + end + end + end +end diff --git a/spec/unit/mutant/mutator/call/mutation_spec.rb b/spec/unit/mutant/mutator/send/mutation_spec.rb similarity index 78% rename from spec/unit/mutant/mutator/call/mutation_spec.rb rename to spec/unit/mutant/mutator/send/mutation_spec.rb index b780fc72..4fe7854f 100644 --- a/spec/unit/mutant/mutator/call/mutation_spec.rb +++ b/spec/unit/mutant/mutator/send/mutation_spec.rb @@ -16,6 +16,7 @@ describe Mutant::Mutator, 'call' do it_should_behave_like 'a noop mutator' end end + context 'with self as receiver' do context 'implicit' do @@ -45,20 +46,29 @@ describe Mutant::Mutator, 'call' do end context 'send with arguments' do + context 'with self as receiver' do context 'implicit' do - let(:source) { 'foo(1)' } + let(:source) { 'foo(nil)' } - it_should_behave_like 'a noop mutator' + let(:mutations) do + mutations = [] + mutations << 'foo()' + mutations << 'foo(Object.new)' + end + + it_should_behave_like 'a mutator' end context 'explicit' do - let(:source) { 'self.foo(1)' } + let(:source) { 'self.foo(nil)' } let(:mutations) do mutations = [] # with implicit receiver (send privately) - mutations << 'foo(1)' + mutations << 'foo(nil)' + mutations << 'self.foo(Object.new)' + mutations << 'self.foo()' end it_should_behave_like 'a mutator'