From b1f864d10f57520533fad36cfc9bdf3118714c19 Mon Sep 17 00:00:00 2001 From: Markus Schirp Date: Fri, 14 Jun 2013 19:47:23 +0200 Subject: [PATCH] Port regular (non operator) sends to parser --- lib/mutant/mutator/node/send.rb | 79 ++++++++++ .../mutant/mutator/node/send/mutation_spec.rb | 147 ++++++------------ 2 files changed, 123 insertions(+), 103 deletions(-) diff --git a/lib/mutant/mutator/node/send.rb b/lib/mutant/mutator/node/send.rb index 1dbe5221..f26f29f2 100644 --- a/lib/mutant/mutator/node/send.rb +++ b/lib/mutant/mutator/node/send.rb @@ -7,6 +7,8 @@ module Mutant handle(:send) + RECEIVER_INDEX, SELECTOR_INDEX, ARGUMENTS_INDEX = 0, 1, 2..-1 + private # Emit mutations @@ -16,8 +18,85 @@ module Mutant # @api private # def dispatch + emit(receiver) if receiver + mutate_receiver + mutate_arguments end + # Mutate arguments + # + # @return [undefined] + # + # @api private + # + def mutate_arguments + return if arguments.empty? + if arguments.one? + emit(arguments.first) + end + emit_self(receiver, selector) + children.each_index do |index| + next if index <= SELECTOR_INDEX + mutate_child(index) + delete_child(index) + end + end + + # Emit receiver mutations + # + # @return [undefined] + # + # @api private + # + def mutate_receiver + return unless receiver + emit_implicit_self + mutate_child(RECEIVER_INDEX) + end + + # Emit implicit self mutation + # + # @return [undefined] + # + # @api rpivate + # + def emit_implicit_self + if receiver.type == :self and !KEYWORDS.include?(selector) + emit_child_update(RECEIVER_INDEX, nil) + end + end + + # Return receiver + # + # @return [Parser::Node::AST] + # + # @api private + # + def receiver + children[RECEIVER_INDEX] + end + + # Return selector + # + # @return [Symbol] + # + # @api private + # + def selector + children[SELECTOR_INDEX] + end + + # Return arguments + # + # @return [Array] + # + # @api private + # + def arguments + children[ARGUMENTS_INDEX] + end + memoize :arguments + end # Send end # Node end # Mutator diff --git a/spec/unit/mutant/mutator/node/send/mutation_spec.rb b/spec/unit/mutant/mutator/node/send/mutation_spec.rb index 31617320..471aacc4 100644 --- a/spec/unit/mutant/mutator/node/send/mutation_spec.rb +++ b/spec/unit/mutant/mutator/node/send/mutation_spec.rb @@ -3,38 +3,38 @@ require 'spec_helper' # FIXME: This spec needs to be structured better! describe Mutant::Mutator, 'send' do - context 'send without arguments' do + context 'with self as' do + context 'implicit' do + let(:source) { 'foo' } - context 'with self as' do - context 'implicit' do - let(:source) { 'foo' } + it_should_behave_like 'a noop mutator' + end - it_should_behave_like 'a noop mutator' + context 'explict receiver' do + let(:source) { 'self.foo' } + + let(:mutations) do + mutations = [] + mutations << 'foo' + mutations << 'self' end - context 'explict receiver' do - let(:source) { 'self.foo' } + it_should_behave_like 'a mutator' + end - let(:mutations) do - mutations = [] - mutations << 'foo' - mutations << 'self' - end - - it_should_behave_like 'a mutator' - end - - context 'explicit receiver with keyword message name' do - Unparser::Constants::KEYWORDS.each do |keyword| - context "with keyword: #{keyword}" do - let(:source) { "self.#{keyword}" } - let(:mutations) do - ['self'] - end + context 'explicit receiver with keyword message name' do + Unparser::Constants::KEYWORDS.each do |keyword| + context "with keyword: #{keyword}" do + let(:source) { "self.#{keyword}" } + let(:mutations) do + ['self'] end end end end + end + + context 'without arguments' do context 'to some object' do let(:source) { 'foo.bar' } @@ -53,73 +53,14 @@ describe Mutant::Mutator, 'send' do let(:mutations) do mutations = [] mutations << 'self.class' + mutations << 'self.foo' end it_should_behave_like 'a mutator' end end - context 'with block' do - let(:source) { 'foo() { a; b }' } - - let(:mutations) do - mutations = [] - mutations << 'foo() { a }' - mutations << 'foo() { b }' - mutations << 'foo() { }' - mutations << 'foo' - end - - it_should_behave_like 'a mutator' - end - - context 'with block args' do - - let(:source) { 'foo { |a, b| }' } - - before do - Mutant::Random.stub(:hex_string => :random) - end - - let(:mutations) do - mutations = [] - mutations << 'foo' - mutations << 'foo { |a, b| Object.new }' - mutations << 'foo { |a, srandom| }' - mutations << 'foo { |srandom, b| }' - mutations << 'foo { |a| }' - mutations << 'foo { |b| }' - mutations << 'foo { || }' - end - - it_should_behave_like 'a mutator' - end - - context 'with block pattern args' do - - before do - Mutant::Random.stub(:hex_string => :random) - end - - let(:source) { 'foo { |(a, b), c| }' } - - let(:mutations) do - mutations = [] - mutations << 'foo { || }' - mutations << 'foo { |a, b, c| }' - mutations << 'foo { |(a, b), c| Object.new }' - mutations << 'foo { |(a, b)| }' - mutations << 'foo { |c| }' - mutations << 'foo { |(srandom, b), c| }' - mutations << 'foo { |(a, srandom), c| }' - mutations << 'foo { |(a, b), srandom| }' - mutations << 'foo' - end - - it_should_behave_like 'a mutator' - end - - context 'send with arguments' do + context 'with arguments' do context 'one argument' do let(:source) { 'foo(nil)' } @@ -128,7 +69,7 @@ describe Mutant::Mutator, 'send' do mutations = [] mutations << 'foo' mutations << 'nil' - mutations << 'foo(Object.new)' + mutations << 'foo(::Object.new)' end it_should_behave_like 'a mutator' @@ -139,10 +80,11 @@ describe Mutant::Mutator, 'send' do let(:mutations) do mutations = [] + mutations << 'self' mutations << 'self.foo' mutations << 'foo(nil)' mutations << 'nil' - mutations << 'self.foo(Object.new)' + mutations << 'self.foo(::Object.new)' end it_should_behave_like 'a mutator' @@ -156,9 +98,9 @@ describe Mutant::Mutator, 'send' do let(:mutations) do mutations = [] mutations << "foo.#{keyword}" - mutations << "foo" + mutations << 'foo' mutations << 'nil' - mutations << "foo.#{keyword}(Object.new)" + mutations << "foo.#{keyword}(::Object.new)" end it_should_behave_like 'a mutator' @@ -166,6 +108,20 @@ describe Mutant::Mutator, 'send' do end end + context 'two arguments' do + let(:source) { 'foo(nil, nil)' } + + let(:mutations) do + mutations = [] + mutations << 'foo()' + mutations << 'foo(nil)' + mutations << 'foo(::Object.new, nil)' + mutations << 'foo(nil, ::Object.new)' + end + + it_should_behave_like 'a mutator' + end + context 'binary operator methods' do Mutant::BINARY_METHOD_OPERATORS.each do |operator| let(:source) { "true #{operator} false" } @@ -183,20 +139,5 @@ describe Mutant::Mutator, 'send' do it_should_behave_like 'a mutator' end end - - context 'two arguments' do - let(:source) { 'foo(nil, nil)' } - - let(:mutations) do - mutations = [] - mutations << 'foo()' - mutations << 'foo(nil)' - mutations << 'foo(Object.new, nil)' - mutations << 'foo(nil, Object.new)' - end - - it_should_behave_like 'a mutator' - end - end end