Handle binary operator methods correctly
This commit is contained in:
parent
c6e60d9178
commit
5565f5309a
6 changed files with 141 additions and 34 deletions
|
@ -1,3 +1,10 @@
|
|||
# v0.2.11 2013-01-03
|
||||
|
||||
* [change] Handle binary operator methods in dedicated mutator
|
||||
* [fixed] Do not crash when mutating binary operator method
|
||||
|
||||
[Compare v0.2.10..v0.2.11](https://github.com/mbj/mutant/compare/v0.2.10...v0.2.11)
|
||||
|
||||
# v0.2.10 2013-01-03
|
||||
|
||||
* [fixed] Do not mutate receivers away when message name is a keyword
|
||||
|
|
4
TODO
4
TODO
|
@ -1,11 +1,13 @@
|
|||
Code:
|
||||
* Test mutant with dynamically created zombie.
|
||||
* Fix ugly code within default parameters
|
||||
* Fix ugly code within default parameter mutations
|
||||
* Break up lib/mutant/mutator/node/send.rb in class specific files
|
||||
|
||||
AST:
|
||||
* Fix the rubinius AST to allow setting @vcall_style variable in Rubinius::AST::Send nodes.
|
||||
|
||||
Mutations:
|
||||
* Add binary operator specific mutations (YAY, finally reached this point)
|
||||
* Add some kind of a "do not touch me object" that raises on all messages.
|
||||
It can be used to make sure each literal value is touched.
|
||||
* Replace nil or add "do not touch me object" to literal mutations.
|
||||
|
|
|
@ -31,14 +31,51 @@ end
|
|||
module Mutant
|
||||
|
||||
# The list of ruby kewords from http://ruby-doc.org/docs/keywords/1.9/
|
||||
KEYWORDS = IceNine.deep_freeze(%W(
|
||||
KEYWORDS = %w(
|
||||
BEGIN END __ENCODING__ __END__ __FILE__
|
||||
__LINE__ alias and begin break case class
|
||||
def define do else elsif end ensure false
|
||||
for if in module next nil not or redo
|
||||
rescue retry return self super then true
|
||||
undef unless until when while yield
|
||||
).map(&:to_sym).to_set)
|
||||
).map(&:to_sym).to_set.freeze
|
||||
|
||||
BINARY_METHOD_OPERATOR_EXPANSIONS = {
|
||||
:<=> => :spaceship_operator,
|
||||
:=== => :case_equality_operator,
|
||||
:[]= => :element_writer,
|
||||
:[] => :element_reader,
|
||||
:<= => :less_than_or_equal_to_operator,
|
||||
:>= => :greater_than_or_equal_to_operator,
|
||||
:== => :equality_operator,
|
||||
:'!~' => :nomatch_operator,
|
||||
:'!=' => :inequality_operator,
|
||||
:=~ => :match_operator,
|
||||
:<< => :left_shift_operator,
|
||||
:>> => :right_shift_operator,
|
||||
:** => :exponentation_operator,
|
||||
:* => :multiplication_operator,
|
||||
:% => :modulo_operator,
|
||||
:/ => :division_operator,
|
||||
:| => :bitwise_or_operator,
|
||||
:^ => :bitwise_xor_operator,
|
||||
:& => :bitwise_and_operator,
|
||||
:< => :less_than_operator,
|
||||
:> => :greater_than_operator,
|
||||
:+ => :addition_operator,
|
||||
:- => :substraction_operator
|
||||
}.freeze
|
||||
|
||||
UNARY_METHOD_OPERATOR_EXPANSIONS = {
|
||||
:~@ => :unary_match_operator,
|
||||
:+@ => :unary_addition_operator,
|
||||
:-@ => :unary_substraction_operator,
|
||||
:'!' => :negation_operator
|
||||
}.freeze
|
||||
|
||||
BINARY_METHOD_OPERATORS = BINARY_METHOD_OPERATOR_EXPANSIONS.keys.to_set.freeze
|
||||
|
||||
OPERATOR_EXPANSIONS = BINARY_METHOD_OPERATOR_EXPANSIONS.merge(UNARY_METHOD_OPERATOR_EXPANSIONS).freeze
|
||||
|
||||
# Define instance of subclassed superclass as constant
|
||||
#
|
||||
|
|
|
@ -163,6 +163,48 @@ module Mutant
|
|||
|
||||
handle(Rubinius::AST::SendWithArguments)
|
||||
|
||||
class BinaryOperatorMethod < Node
|
||||
|
||||
private
|
||||
|
||||
# Emit mutations
|
||||
#
|
||||
# @return [undefined]
|
||||
#
|
||||
# @api private
|
||||
#
|
||||
def dispatch
|
||||
emit_left_mutations
|
||||
emit_right_mutations
|
||||
end
|
||||
|
||||
# Emit left mutations
|
||||
#
|
||||
# @return [undefined]
|
||||
#
|
||||
# @api private
|
||||
#
|
||||
def emit_left_mutations
|
||||
emit_attribute_mutations(:receiver)
|
||||
end
|
||||
|
||||
# Emit right mutations
|
||||
#
|
||||
# @return [undefined]
|
||||
#
|
||||
# @api private
|
||||
#
|
||||
def emit_right_mutations
|
||||
right = node.arguments.array.first
|
||||
Mutator.each(right).each do |mutated|
|
||||
dup = dup_node
|
||||
dup.arguments.array[0] = mutated
|
||||
emit(dup)
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# Emit mutations
|
||||
|
@ -174,6 +216,37 @@ module Mutant
|
|||
def dispatch
|
||||
super
|
||||
emit_call_remove_mutation
|
||||
emit_argument_mutations
|
||||
end
|
||||
|
||||
# Test if message is a binary operator
|
||||
#
|
||||
# @return [true]
|
||||
# if message is a binary operator
|
||||
#
|
||||
# @return [false]
|
||||
# otherwise
|
||||
#
|
||||
# @api private
|
||||
#
|
||||
def binary_operator?
|
||||
Mutant::BINARY_METHOD_OPERATORS.include?(node.name)
|
||||
end
|
||||
|
||||
# Emit argument mutations
|
||||
#
|
||||
# @api private
|
||||
#
|
||||
# @return [undefined]
|
||||
#
|
||||
# @api private
|
||||
#
|
||||
def emit_argument_mutations
|
||||
if binary_operator?
|
||||
run(BinaryOperatorMethod)
|
||||
return
|
||||
end
|
||||
|
||||
emit_attribute_mutations(:arguments)
|
||||
end
|
||||
|
||||
|
|
|
@ -56,36 +56,6 @@ module Mutant
|
|||
mutation.subject.matcher
|
||||
end
|
||||
|
||||
MAPPING = {
|
||||
:<=> => :spaceship_operator,
|
||||
:=== => :case_equality_operator,
|
||||
:[]= => :element_writer,
|
||||
:[] => :element_reader,
|
||||
:<= => :less_than_or_equal_to_operator,
|
||||
:>= => :greater_than_or_equal_to_operator,
|
||||
:~@ => :unary_match_operator,
|
||||
:+@ => :unary_addition_operator,
|
||||
:-@ => :unary_substraction_operator,
|
||||
:== => :equality_operator,
|
||||
:'!~' => :nomatch_operator,
|
||||
:'!=' => :inequality_operator,
|
||||
:=~ => :match_operator,
|
||||
:<< => :left_shift_operator,
|
||||
:>> => :right_shift_operator,
|
||||
:** => :exponentation_operator,
|
||||
:* => :multiplication_operator,
|
||||
:% => :modulo_operator,
|
||||
:/ => :division_operator,
|
||||
:| => :bitwise_or_operator,
|
||||
:'!' => :negation_operator,
|
||||
:^ => :bitwise_xor_operator,
|
||||
:& => :bitwise_and_operator,
|
||||
:< => :less_than_operator,
|
||||
:> => :greater_than_operator,
|
||||
:+ => :addition_operator,
|
||||
:- => :substraction_operator
|
||||
}
|
||||
|
||||
EXPANSIONS = {
|
||||
/\?\z/ => '_predicate',
|
||||
/=\z/ => '_writer',
|
||||
|
@ -114,7 +84,7 @@ module Mutant
|
|||
# @api private
|
||||
#
|
||||
def mapped_name
|
||||
MAPPING[method_name]
|
||||
OPERATOR_EXPANSIONS[method_name]
|
||||
end
|
||||
|
||||
# Return expanded name
|
||||
|
|
|
@ -102,6 +102,24 @@ describe Mutant::Mutator, 'send' do
|
|||
end
|
||||
end
|
||||
|
||||
context 'binary operator methods' do
|
||||
Mutant::BINARY_METHOD_OPERATORS.each do |operator|
|
||||
let(:source) { "true #{operator} false" }
|
||||
|
||||
let(:mutations) do
|
||||
mutations = []
|
||||
mutations << "((false) #{operator} (false))"
|
||||
mutations << "((nil) #{operator} (false))"
|
||||
mutations << "((true) #{operator} (true))"
|
||||
mutations << "((true) #{operator} (nil))"
|
||||
mutations << 'true'
|
||||
mutations << 'false'
|
||||
end
|
||||
|
||||
it_should_behave_like 'a mutator'
|
||||
end
|
||||
end
|
||||
|
||||
context 'two arguments' do
|
||||
let(:source) { 'foo(nil, nil)' }
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue