Correct mutations of send to self
* Invert the behaviour as this direction of mutation does make sense.
This commit is contained in:
parent
49b13bc1d8
commit
640ce5360e
3 changed files with 60 additions and 28 deletions
|
@ -41,11 +41,37 @@ module Mutant
|
||||||
receiver.kind_of?(Rubinius::AST::Self)
|
receiver.kind_of?(Rubinius::AST::Self)
|
||||||
end
|
end
|
||||||
|
|
||||||
def emit_explicit_self_receiver
|
# 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.
|
||||||
|
#
|
||||||
|
# @reutrn [undefined]
|
||||||
|
#
|
||||||
|
# @api private
|
||||||
|
#
|
||||||
|
def emit_implicit_self_receiver
|
||||||
|
return unless self?
|
||||||
mutant = dup_node
|
mutant = dup_node
|
||||||
mutant.privately = false
|
mutant.privately = true
|
||||||
# TODO: Fix rubinius to allow this as an attr_accessor
|
# TODO: Fix rubinius to allow this as an attr_accessor
|
||||||
mutant.instance_variable_set(:@vcall_style,false)
|
mutant.instance_variable_set(:@vcall_style,true)
|
||||||
emit_safe(mutant)
|
emit_safe(mutant)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -56,7 +82,7 @@ module Mutant
|
||||||
# @api private
|
# @api private
|
||||||
#
|
#
|
||||||
def dispatch
|
def dispatch
|
||||||
emit_explicit_self_receiver
|
emit_implicit_self_receiver
|
||||||
end
|
end
|
||||||
|
|
||||||
class SendWithArguments < Call
|
class SendWithArguments < Call
|
||||||
|
@ -72,7 +98,7 @@ module Mutant
|
||||||
# @api private
|
# @api private
|
||||||
#
|
#
|
||||||
def dispatch
|
def dispatch
|
||||||
emit_explicit_self_receiver
|
super
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
require 'spec_helper'
|
require 'spec_helper'
|
||||||
|
|
||||||
describe Mutant::Mutator::Block, '.each' do
|
describe Mutant::Mutator, 'block' do
|
||||||
# Two send operations
|
# Two send operations
|
||||||
let(:source) { "foo\nbar" }
|
let(:source) { "self.foo\nself.bar" }
|
||||||
|
|
||||||
let(:mutations) do
|
let(:mutations) do
|
||||||
mutations = []
|
mutations = []
|
||||||
|
@ -12,8 +12,8 @@ describe Mutant::Mutator::Block, '.each' do
|
||||||
mutations << "self.foo\nbar"
|
mutations << "self.foo\nbar"
|
||||||
|
|
||||||
## Remove statement in block
|
## Remove statement in block
|
||||||
mutations << [:block, 'foo'.to_sexp]
|
mutations << [:block, 'self.foo'.to_sexp]
|
||||||
mutations << [:block, 'bar'.to_sexp]
|
mutations << [:block, 'self.bar'.to_sexp]
|
||||||
end
|
end
|
||||||
|
|
||||||
it_should_behave_like 'a mutation enumerator method'
|
it_should_behave_like 'a mutation enumerator method'
|
|
@ -2,46 +2,52 @@ require 'spec_helper'
|
||||||
|
|
||||||
describe Mutant::Mutator, 'call' do
|
describe Mutant::Mutator, 'call' do
|
||||||
context 'send without arguments' do
|
context 'send without arguments' do
|
||||||
context 'to self' do
|
context 'with self as receiver' do
|
||||||
|
|
||||||
context 'implict' do
|
context 'implicit' do
|
||||||
let(:source) { 'foo' }
|
let(:source) { 'foo' }
|
||||||
|
|
||||||
let(:mutations) do
|
it_should_behave_like 'a noop mutation enumerator method'
|
||||||
mutations = []
|
|
||||||
# with explicit receiver (not send privately)
|
|
||||||
mutations << 'self.foo'
|
|
||||||
end
|
|
||||||
|
|
||||||
it_should_behave_like 'a mutation enumerator method'
|
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'explict' do
|
context 'explict' do
|
||||||
let(:source) { 'self.foo' }
|
let(:source) { 'self.foo' }
|
||||||
|
|
||||||
it_should_behave_like 'a noop mutation enumerator method'
|
let(:mutations) do
|
||||||
|
mutations = []
|
||||||
|
# with implicit receiver (send privately)
|
||||||
|
mutations << 'foo'
|
||||||
|
end
|
||||||
|
|
||||||
|
it_should_behave_like 'a mutation enumerator method'
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context 'to some object' do
|
||||||
|
let(:source) { '1.foo' }
|
||||||
|
|
||||||
|
it_should_behave_like 'a noop mutation enumerator method'
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'send with arguments' do
|
context 'send with arguments' do
|
||||||
context 'to self' do
|
context 'with self as receiver' do
|
||||||
context 'implicit' do
|
context 'implicit' do
|
||||||
let(:source) { 'foo(1)' }
|
let(:source) { 'foo(1)' }
|
||||||
|
|
||||||
let(:mutations) do
|
it_should_behave_like 'a noop mutation enumerator method'
|
||||||
mutations = []
|
|
||||||
# with explicit receiver (not send privately)
|
|
||||||
mutations << 'self.foo(1)'
|
|
||||||
end
|
|
||||||
|
|
||||||
it_should_behave_like 'a mutation enumerator method'
|
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'explicit' do
|
context 'explicit' do
|
||||||
let(:source) { 'self.foo(1)' }
|
let(:source) { 'self.foo(1)' }
|
||||||
|
|
||||||
it_should_behave_like 'a noop mutation enumerator method'
|
let(:mutations) do
|
||||||
|
mutations = []
|
||||||
|
# with implicit receiver (send privately)
|
||||||
|
mutations << 'foo(1)'
|
||||||
|
end
|
||||||
|
|
||||||
|
it_should_behave_like 'a mutation enumerator method'
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in a new issue