Guard against the generation of equal mutants
* Move Mutant::Mutator::Generator in a dedicated file * Mutant::Mutator::Generator#append only forwards mutated node when it does not equal original nodes sexpession. This does not catch equivalent mutations, but mutations that exactly reproduce the same AST. This way a check for not generating the same asts can be centralized.
This commit is contained in:
parent
993f08d975
commit
ef9172bca4
5 changed files with 76 additions and 13 deletions
3
TODO
3
TODO
|
@ -17,3 +17,6 @@
|
||||||
It can be used to make sure each literal value is touched.
|
It can be used to make sure each literal value is touched.
|
||||||
* Replace nil or add "do not touch me object" to literal mutations.
|
* Replace nil or add "do not touch me object" to literal mutations.
|
||||||
* Add remaining literals
|
* Add remaining literals
|
||||||
|
* Mutate options for Regexp literals
|
||||||
|
* Move Mutant.random_* into Mutant::Random namespace.
|
||||||
|
* Use inheritable alias once (virtus,veritas,mapper,session, ...) support gem is born.
|
||||||
|
|
|
@ -82,6 +82,7 @@ module Mutant
|
||||||
end
|
end
|
||||||
|
|
||||||
require 'mutant/mutator'
|
require 'mutant/mutator'
|
||||||
|
require 'mutant/mutator/generator'
|
||||||
require 'mutant/mutator/true_literal'
|
require 'mutant/mutator/true_literal'
|
||||||
require 'mutant/mutator/false_literal'
|
require 'mutant/mutator/false_literal'
|
||||||
require 'mutant/mutator/symbol_literal'
|
require 'mutant/mutator/symbol_literal'
|
||||||
|
@ -93,6 +94,8 @@ require 'mutant/mutator/empty_array'
|
||||||
require 'mutant/mutator/hash_literal'
|
require 'mutant/mutator/hash_literal'
|
||||||
require 'mutant/mutator/range'
|
require 'mutant/mutator/range'
|
||||||
require 'mutant/mutator/range_exclude'
|
require 'mutant/mutator/range_exclude'
|
||||||
|
require 'mutant/mutator/regex_literal'
|
||||||
|
require 'mutant/mutator/dynamic_string'
|
||||||
require 'mutant/mutator/block'
|
require 'mutant/mutator/block'
|
||||||
require 'mutant/loader'
|
require 'mutant/loader'
|
||||||
require 'mutant/context'
|
require 'mutant/context'
|
||||||
|
|
|
@ -31,25 +31,13 @@ module Mutant
|
||||||
const_get(unqualified_name)
|
const_get(unqualified_name)
|
||||||
end
|
end
|
||||||
|
|
||||||
class Generator
|
|
||||||
def initialize(block)
|
|
||||||
@block = block
|
|
||||||
end
|
|
||||||
|
|
||||||
def append(node)
|
|
||||||
@block.call(node)
|
|
||||||
end
|
|
||||||
|
|
||||||
alias :<< :append
|
|
||||||
end
|
|
||||||
|
|
||||||
# Enumerate mutated asts
|
# Enumerate mutated asts
|
||||||
#
|
#
|
||||||
# @api private
|
# @api private
|
||||||
#
|
#
|
||||||
def each(&block)
|
def each(&block)
|
||||||
return to_enum unless block_given?
|
return to_enum unless block_given?
|
||||||
mutants(Generator.new(block))
|
mutants(Generator.new(@node,block))
|
||||||
self
|
self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
25
lib/mutant/mutator/generator.rb
Normal file
25
lib/mutant/mutator/generator.rb
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
module Mutant
|
||||||
|
class Mutator
|
||||||
|
class Generator
|
||||||
|
def initialize(node,block)
|
||||||
|
@sexp,@block = node.to_sexp,block
|
||||||
|
end
|
||||||
|
|
||||||
|
def append(node)
|
||||||
|
p same_node?(node)
|
||||||
|
unless same_node?(node)
|
||||||
|
@block.call(node)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# FIXME: Use interhitable alias once in support gem.
|
||||||
|
alias :<< :append
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def same_node?(node)
|
||||||
|
@sexp == node.to_sexp
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
44
spec/unit/mutant/mutator/generator/append_spec.rb
Normal file
44
spec/unit/mutant/mutator/generator/append_spec.rb
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
require 'spec_helper'
|
||||||
|
|
||||||
|
describe Mutant::Mutator::Generator,'#append' do
|
||||||
|
subject { object.append(node) }
|
||||||
|
|
||||||
|
class Block
|
||||||
|
attr_reader :arguments
|
||||||
|
|
||||||
|
def called?
|
||||||
|
defined?(@arguments)
|
||||||
|
end
|
||||||
|
|
||||||
|
def call(*arguments)
|
||||||
|
@arguments = arguments
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
let(:object) { described_class.new(wrapped_node,block) }
|
||||||
|
let(:block) { Block.new }
|
||||||
|
let(:wrapped_node) { '"foo"'.to_ast }
|
||||||
|
|
||||||
|
context 'with node that is not equal to wrapped node' do
|
||||||
|
let(:node) { '"bar"'.to_ast }
|
||||||
|
|
||||||
|
it 'should call block' do
|
||||||
|
subject
|
||||||
|
block.should be_called
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'should call block with node' do
|
||||||
|
subject
|
||||||
|
block.arguments.should eql([node])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with node that is equal to wrapped node' do
|
||||||
|
let(:node) { '"foo"'.to_ast }
|
||||||
|
|
||||||
|
it 'should call block' do
|
||||||
|
subject
|
||||||
|
block.should_not be_called
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
Loading…
Reference in a new issue