Cleanup mutation generation

This is a reaction to the to_source rewrite

* Do not use 1.8 specific nodes anymore
* Do not generate AST nodes that would not be generatable from source
This commit is contained in:
Markus Schirp 2013-01-09 20:43:06 +01:00
parent 66b09f8d8a
commit 97a75dd062
15 changed files with 104 additions and 92 deletions

View file

@ -2,5 +2,7 @@ source 'https://rubygems.org'
gemspec
gem 'to_source', :path => '../to_source'
gem 'devtools', :git => 'https://github.com/datamapper/devtools.git'
eval(File.read(File.join(File.dirname(__FILE__),'Gemfile.devtools')))

View file

@ -103,7 +103,9 @@ module Mutant
mutator.each(value) do |mutation|
dup = dup_node
dup.public_send(:"#{name}=", mutation)
yield dup if block_given?
if block_given?
dup = yield(dup)
end
emit(dup)
end
end

View file

@ -19,6 +19,7 @@ module Mutant
def dispatch
emit_attribute_mutations(:name) do |mutation|
mutation.name = "#{self.class::PREFIX}#{mutation.name}".to_sym
mutation
end
emit_attribute_mutations(:value)
end

View file

@ -22,6 +22,7 @@ module Mutant
if array.empty?
array << new_nil
end
mutation
end
end

View file

@ -16,6 +16,7 @@ module Mutant
def dispatch
emit_attribute_mutations(:arguments) do |argument|
argument.names = argument.arguments.map(&:name)
argument
end
end
end

View file

@ -32,6 +32,7 @@ module Mutant
def emit_required_mutations
emit_attribute_mutations(:required) do |mutation|
mutation.names = mutation.optional + mutation.required
mutation
end
end
end

View file

@ -22,6 +22,7 @@ module Mutant
if mutation.defaults.names.empty?
mutation.defaults = nil
end
mutation
end
end

View file

@ -17,6 +17,7 @@ module Mutant
emit_attribute_mutations(:arguments) do |mutation|
arguments = mutation.arguments
arguments.names = arguments.required + arguments.optional
mutation
end if node.arguments
end

View file

@ -51,7 +51,7 @@ module Mutant
# @api private
#
def negative_infinity
new(Rubinius::AST::Negate, infinity)
new_send_with_arguments(new_float(-1), :/, new_float(0))
end
# Return AST representing infinity

View file

@ -7,22 +7,6 @@ module Mutant
handle(Rubinius::AST::Send)
# Test if node name is a keyword
#
# @param [Rubinius::AST::Node] node
#
# @return [true]
# if node name equals a ruby keyword
#
# @return [false]
# otherwise
#
# @api private
#
def self.keyword_name?(node)
Mutant::KEYWORDS.include?(node.name)
end
private
# Emit mutations
@ -143,7 +127,7 @@ module Mutant
# @api private
#
def emit_implicit_self_receiver
if to_self? and self.class.keyword_name?(node)
unless to_self? and !Mutant::KEYWORDS.include?(node.name)
return
end

View file

@ -17,6 +17,7 @@ module Mutant
def dispatch
emit_left_mutations
emit_right_mutations
emit(right)
end
# Emit left mutations
@ -29,6 +30,16 @@ module Mutant
emit_attribute_mutations(:receiver)
end
# Return right
#
# @return [Rubinius::AST::Node]
#
# @api private
#
def right
node.arguments.array.first
end
# Emit right mutations
#
# @return [undefined]
@ -36,7 +47,6 @@ module Mutant
# @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

View file

@ -18,7 +18,13 @@ module Mutant
#
def dispatch
super
emit_call_remove_mutation
if binary_operator?
run(BinaryOperatorMethod)
return
end
emit_send_remove_mutation
emit_argument_mutations
end
@ -45,21 +51,24 @@ module Mutant
# @api private
#
def emit_argument_mutations
if binary_operator?
run(BinaryOperatorMethod)
return
emit_attribute_mutations(:arguments) do |mutation|
if mutation.arguments.array.empty?
mutation = new_send(receiver, node.name)
mutation.privately = node.privately
mutation
else
mutation
end
end
end
emit_attribute_mutations(:arguments)
end
# Emit transfomr call mutation
# Emit send remove mutation
#
# @return [undefined]
#
# @api private
#
def emit_call_remove_mutation
def emit_send_remove_mutation
array = node.arguments.array
return unless array.length == 1
emit(array.first)

View file

@ -51,8 +51,7 @@ shared_examples_for 'a mutator' do
unexpected = (generated - expected_mutations).to_a
unless generated == expected_mutations
message ="Missing mutations:\n%s\nUnexpected mutations:\n%s" % [missing.join("\n----\n"), unexpected.join("\n----\n")]
fail message
fail "Missing mutations:\n%s\nUnexpected mutations:\n%s" % [missing.join("\n----\n"), unexpected.join("\n----\n")]
end
end
end

View file

@ -11,7 +11,7 @@ describe Mutant::Mutator::Node::Literal, 'float' do
mutations << random_float.to_s
mutations << '0.0/0.0'
mutations << '1.0/0.0'
mutations << '-(1.0 / 0.0)'
mutations << '(-1.0 / 0.0)'
mutations << '-10.0'
end

View file

@ -55,6 +55,66 @@ describe Mutant::Mutator, 'send' do
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 'one argument' do
@ -62,7 +122,7 @@ describe Mutant::Mutator, 'send' do
let(:mutations) do
mutations = []
mutations << 'foo()'
mutations << 'foo'
mutations << 'nil'
mutations << 'foo(Object.new)'
end
@ -134,65 +194,5 @@ describe Mutant::Mutator, 'send' do
it_should_behave_like 'a mutator'
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
end
end