Cleanup crashes and invalid mutants
This commit is contained in:
parent
ca56ef3f0a
commit
b5430e2000
27 changed files with 291 additions and 162 deletions
Changelog.mdGemfile
lib
spec
shared
unit/mutant
matcher/method
mutator/node
block
define
if_statement
literal
strategy/rspec/example_lookup
|
@ -1,5 +1,10 @@
|
|||
# v0.2.1 xxx
|
||||
|
||||
* [fixed] Crash on unavailable source location
|
||||
* [fixed] Incorrect handling of if and unless statements
|
||||
* [fixed] Expand Foo#initialize to spec/unit/foo in rspec dm2 strategy
|
||||
* [fixed] Correctly expand [] to element_reader_spec.rb in rspec dm2 strategy
|
||||
* [fixed] Correctly expand []= to element_writer_spec.rb in rspec dm2 strategy
|
||||
* [fixed] Correctly expand foo= to foo_writer_spec.rb in rspec dm2 strategy
|
||||
|
||||
[Compare v0.2.0..v0.2.1](https://github.com/mbj/mutant/compare/v0.2.0...v0.2.1)
|
||||
|
|
2
Gemfile
2
Gemfile
|
@ -2,5 +2,5 @@ source 'https://rubygems.org'
|
|||
|
||||
gemspec
|
||||
|
||||
gem 'devtools', :git => 'https://github.com/mbj/devtools.git', :branch => :'rspec-2-mutant'
|
||||
gem 'devtools', :git => 'https://github.com/mbj/devtools.git'
|
||||
eval(File.read(File.join(File.dirname(__FILE__),'Gemfile.devtools')))
|
||||
|
|
|
@ -41,6 +41,8 @@ module Mutant
|
|||
self
|
||||
end
|
||||
|
||||
PID = Process.pid
|
||||
|
||||
end
|
||||
|
||||
require 'mutant/support/method_object'
|
||||
|
@ -84,8 +86,8 @@ require 'mutant/matcher/object_space'
|
|||
require 'mutant/matcher/method'
|
||||
require 'mutant/matcher/method/singleton'
|
||||
require 'mutant/matcher/method/instance'
|
||||
require 'mutant/matcher/method/classifier'
|
||||
require 'mutant/matcher/scope_methods'
|
||||
require 'mutant/matcher/method/classifier'
|
||||
require 'mutant/killer'
|
||||
require 'mutant/killer/static'
|
||||
require 'mutant/killer/rspec'
|
||||
|
|
|
@ -28,6 +28,12 @@ module Mutant
|
|||
#
|
||||
def each(&block)
|
||||
return to_enum unless block_given?
|
||||
|
||||
unless source_location
|
||||
$stderr.puts "#{method.inspect} does not have source location unable to emit matcher"
|
||||
return self
|
||||
end
|
||||
|
||||
subject.tap do |subject|
|
||||
yield subject if subject
|
||||
end
|
||||
|
@ -35,6 +41,14 @@ module Mutant
|
|||
self
|
||||
end
|
||||
|
||||
# Return method
|
||||
#
|
||||
# @return [UnboundMethod, Method]
|
||||
#
|
||||
# @api private
|
||||
#
|
||||
attr_reader :method
|
||||
|
||||
# Return scope
|
||||
#
|
||||
# @return [Class|Module]
|
||||
|
@ -43,21 +57,15 @@ module Mutant
|
|||
#
|
||||
attr_reader :scope
|
||||
|
||||
# Return context
|
||||
#
|
||||
# @return [Context::Scope]
|
||||
#
|
||||
# @api private
|
||||
#
|
||||
attr_reader :context
|
||||
|
||||
# Return method name
|
||||
#
|
||||
# @return [String]
|
||||
#
|
||||
# @api private
|
||||
#
|
||||
attr_reader :method_name
|
||||
def method_name
|
||||
method.name
|
||||
end
|
||||
|
||||
# Test if method is public
|
||||
#
|
||||
|
@ -76,26 +84,27 @@ module Mutant
|
|||
# Initialize method filter
|
||||
#
|
||||
# @param [Class|Module] scope
|
||||
# @param [Symbol] method_name
|
||||
# @param [Method, UnboundMethod] method
|
||||
#
|
||||
# @return [undefined]
|
||||
#
|
||||
# @api private
|
||||
#
|
||||
def initialize(scope, method_name)
|
||||
@scope, @method_name = scope, method_name.to_sym
|
||||
@context = Context::Scope.build(scope, source_path)
|
||||
def initialize(scope, method)
|
||||
@scope, @method = scope, method
|
||||
# FIXME: cache public private should not be needed, loader should not override visibility! (But does currently) :(
|
||||
public?
|
||||
end
|
||||
|
||||
# Return method
|
||||
# Return context
|
||||
#
|
||||
# @return [UnboundMethod, Method]
|
||||
# @return [Context::Scope]
|
||||
#
|
||||
# @api private
|
||||
#
|
||||
abstract_method :method
|
||||
def context
|
||||
Context::Scope.build(scope, source_path)
|
||||
end
|
||||
|
||||
# Return full ast
|
||||
#
|
||||
|
|
|
@ -6,15 +6,15 @@ module Mutant
|
|||
include Adamantium::Flat
|
||||
|
||||
TABLE = {
|
||||
'.' => Matcher::Method::Singleton,
|
||||
'#' => Matcher::Method::Instance
|
||||
'.' => Matcher::ScopeMethods::Singleton,
|
||||
'#' => Matcher::ScopeMethods::Instance
|
||||
}.freeze
|
||||
|
||||
SCOPE_FORMAT = /\A([^#.]+)(\.|#)(.+)\z/.freeze
|
||||
|
||||
# Positions of captured regexp groups
|
||||
# Freezing fixnums to avoid their singleton classes are patched.
|
||||
SCOPE_NAME_POSITION = 1.freeze
|
||||
SCOPE_NAME_POSITION = 1.freeze
|
||||
SCOPE_SYMBOL_POSITION = 2.freeze
|
||||
METHOD_NAME_POSITION = 3.freeze
|
||||
|
||||
|
@ -45,8 +45,22 @@ module Mutant
|
|||
# @api private
|
||||
#
|
||||
def matcher
|
||||
matcher_class.new(scope, method_name)
|
||||
scope_matcher.matcher.new(scope, method)
|
||||
end
|
||||
memoize :matcher
|
||||
|
||||
# Return method
|
||||
#
|
||||
# @return [Method, UnboundMethod]
|
||||
#
|
||||
# @api private
|
||||
#
|
||||
def method
|
||||
scope_matcher.methods.detect do |method|
|
||||
method.name == method_name
|
||||
end || raise("Cannot find #{method_name} for #{scope}")
|
||||
end
|
||||
memoize :method, :freezer => :noop
|
||||
|
||||
# Return match
|
||||
#
|
||||
|
@ -117,9 +131,10 @@ module Mutant
|
|||
#
|
||||
# @api private
|
||||
#
|
||||
def matcher_class
|
||||
TABLE.fetch(scope_symbol)
|
||||
def scope_matcher
|
||||
TABLE.fetch(scope_symbol).new(scope)
|
||||
end
|
||||
memoize :scope_matcher
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -50,17 +50,6 @@ module Mutant
|
|||
node.name == method_name
|
||||
end
|
||||
|
||||
# Return method instance
|
||||
#
|
||||
# @return [UnboundMethod]
|
||||
#
|
||||
# @api private
|
||||
#
|
||||
def method
|
||||
scope.instance_method(method_name)
|
||||
end
|
||||
memoize :method, :freezer => :noop
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -33,17 +33,6 @@ module Mutant
|
|||
|
||||
private
|
||||
|
||||
# Return method instance
|
||||
#
|
||||
# @return [UnboundMethod]
|
||||
#
|
||||
# @api private
|
||||
#
|
||||
def method
|
||||
scope.method(method_name)
|
||||
end
|
||||
memoize :method, :freezer => :noop
|
||||
|
||||
# Test for node match
|
||||
#
|
||||
# @param [Rubinius::AST::Node] node
|
||||
|
|
|
@ -24,6 +24,7 @@ module Mutant
|
|||
#
|
||||
def each(&block)
|
||||
return to_enum unless block_given?
|
||||
|
||||
methods.each do |method|
|
||||
emit_matches(method, &block)
|
||||
end
|
||||
|
@ -31,6 +32,29 @@ module Mutant
|
|||
self
|
||||
end
|
||||
|
||||
# Return methods
|
||||
#
|
||||
# @return [Enumerable<Method, UnboundMethod>]
|
||||
#
|
||||
# @api private
|
||||
#
|
||||
def methods
|
||||
method_names.map do |name|
|
||||
access(name)
|
||||
end
|
||||
end
|
||||
memoize :methods
|
||||
|
||||
# Return method matcher class
|
||||
#
|
||||
# @return [Class:Matcher::Method]
|
||||
#
|
||||
# @api private
|
||||
#
|
||||
def matcher
|
||||
self.class::MATCHER
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# Initialize object
|
||||
|
@ -47,7 +71,7 @@ module Mutant
|
|||
|
||||
# Emit matches for method
|
||||
#
|
||||
# @param [UnboundMethod] method
|
||||
# @param [UnboundMethod, Method] method
|
||||
#
|
||||
# @return [undefined]
|
||||
#
|
||||
|
@ -59,22 +83,29 @@ module Mutant
|
|||
end
|
||||
end
|
||||
|
||||
|
||||
abstract_method :methods
|
||||
|
||||
# Return method matcher class
|
||||
# Return method names
|
||||
#
|
||||
# @return [Class:Matcher::Method]
|
||||
# @return [Enumerable<Symbol>]
|
||||
#
|
||||
# @api private
|
||||
#
|
||||
def matcher
|
||||
self.class::MATCHER
|
||||
end
|
||||
abstract_method :method_names
|
||||
|
||||
class Singleton < self
|
||||
MATCHER = Mutant::Matcher::Method::Singleton
|
||||
|
||||
# Return method for name
|
||||
#
|
||||
# @param [Symbol] method_name
|
||||
#
|
||||
# @return [Method]
|
||||
#
|
||||
# @api private
|
||||
#
|
||||
def access(method_name)
|
||||
scope.method(method_name)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# Return singleton methods defined on scope
|
||||
|
@ -85,7 +116,7 @@ module Mutant
|
|||
#
|
||||
# @api private
|
||||
#
|
||||
def methods
|
||||
def method_names
|
||||
singleton_class = scope.singleton_class
|
||||
|
||||
names =
|
||||
|
@ -93,7 +124,7 @@ module Mutant
|
|||
singleton_class.private_instance_methods(false) +
|
||||
singleton_class.protected_instance_methods(false)
|
||||
|
||||
names.map(&:to_sym).sort.reject do |name|
|
||||
names.sort.reject do |name|
|
||||
name.to_sym == :__class_init__
|
||||
end
|
||||
end
|
||||
|
@ -102,6 +133,18 @@ module Mutant
|
|||
class Instance < self
|
||||
MATCHER = Mutant::Matcher::Method::Instance
|
||||
|
||||
# Return method for name
|
||||
#
|
||||
# @param [Symbol] method_name
|
||||
#
|
||||
# @return [UnboundMethod]
|
||||
#
|
||||
# @api private
|
||||
#
|
||||
def access(method_name)
|
||||
scope.instance_method(method_name)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# Return instance methods names of scope
|
||||
|
@ -110,7 +153,7 @@ module Mutant
|
|||
#
|
||||
# @return [Enumerable<Symbol>]
|
||||
#
|
||||
def methods
|
||||
def method_names
|
||||
scope = self.scope
|
||||
return [] unless scope.kind_of?(Module)
|
||||
|
||||
|
@ -119,7 +162,7 @@ module Mutant
|
|||
scope.private_instance_methods(false) +
|
||||
scope.protected_instance_methods(false)
|
||||
|
||||
names.uniq.map(&:to_sym).sort
|
||||
names.uniq.sort
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -18,6 +18,26 @@ module Mutant
|
|||
array = input.array
|
||||
emit_attribute_mutations(:array)
|
||||
end
|
||||
|
||||
# Test if node is new
|
||||
#
|
||||
# FIXME: Remove this hack and make sure empty bodies are not generated
|
||||
#
|
||||
# @param [Rubinius::AST::Node]
|
||||
#
|
||||
# @return [true]
|
||||
# if node is new
|
||||
#
|
||||
# @return [false]
|
||||
# otherwise
|
||||
#
|
||||
def new?(node)
|
||||
if node.array.empty?
|
||||
node.array << new_nil
|
||||
end
|
||||
|
||||
super
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -16,8 +16,8 @@ module Mutant
|
|||
#
|
||||
def dispatch
|
||||
emit_attribute_mutations(:condition)
|
||||
emit_attribute_mutations(:body)
|
||||
emit_attribute_mutations(:else) if node.else
|
||||
emit_attribute_mutations(:body) if node.body.class != Rubinius::AST::NilLiteral
|
||||
emit_attribute_mutations(:else) if node.else.class != Rubinius::AST::NilLiteral
|
||||
emit_inverted_condition
|
||||
emit_deleted_if_branch
|
||||
emit_deleted_else_branch
|
||||
|
|
|
@ -49,7 +49,7 @@ module Mutant
|
|||
#
|
||||
def emit_finish_mutations
|
||||
finish = node.finish
|
||||
emit_self(negative_infinity, finish)
|
||||
#emit_self(negative_infinity, finish)
|
||||
emit_self(nan, finish)
|
||||
end
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@ module Mutant
|
|||
|
||||
# Return filename pattern
|
||||
#
|
||||
# @return [String]
|
||||
# @return [Enumerable<String>]
|
||||
#
|
||||
# @api private
|
||||
#
|
||||
|
@ -25,17 +25,17 @@ module Mutant
|
|||
|
||||
# Return file name pattern for mutation
|
||||
#
|
||||
# @return [Mutation]
|
||||
# @return [Enumerable<String>]
|
||||
#
|
||||
# @api private
|
||||
#
|
||||
def self.spec_files(mutation)
|
||||
Dir['spec/unit/**/*_spec.rb']
|
||||
['spec/unit']
|
||||
end
|
||||
end
|
||||
|
||||
# Run all integration specs per mutation
|
||||
class Unit < self
|
||||
class Integration < self
|
||||
|
||||
# Return file name pattern for mutation
|
||||
#
|
||||
|
|
|
@ -63,13 +63,25 @@ module Mutant
|
|||
# @api private
|
||||
#
|
||||
def spec_file
|
||||
matcher.method_name.to_s.
|
||||
method_name.to_s.
|
||||
gsub(/\A\[\]\z/, 'element_reader').
|
||||
gsub(/\A\[\]=\z/, 'element_writer').
|
||||
gsub(/\?\z/, '_predicate').
|
||||
gsub(/=\z/, '_writer').
|
||||
gsub(/!\z/, '_bang') + '_spec.rb'
|
||||
end
|
||||
memoize :spec_file
|
||||
|
||||
# Return method name
|
||||
#
|
||||
# @return [Symbol]
|
||||
#
|
||||
# @api private
|
||||
#
|
||||
def method_name
|
||||
matcher.method_name
|
||||
end
|
||||
|
||||
# Return glob expression
|
||||
#
|
||||
# @return [String]
|
||||
|
@ -77,6 +89,8 @@ module Mutant
|
|||
# @api private
|
||||
#
|
||||
def glob_expression
|
||||
return base_path if method_name == :initialize
|
||||
|
||||
if mutation.subject.matcher.public?
|
||||
"#{base_path}/#{spec_file}"
|
||||
else
|
||||
|
|
|
@ -1,16 +0,0 @@
|
|||
shared_examples_for 'a method filter parse result' do
|
||||
before do
|
||||
expected_class.stub(:new => response)
|
||||
end
|
||||
|
||||
let(:response) { mock('Response') }
|
||||
|
||||
it { should be(response) }
|
||||
|
||||
it 'should initialize method filter with correct arguments' do
|
||||
expected_class.should_receive(:new).with(TestApp::Literal, :string).and_return(response)
|
||||
subject
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -15,25 +15,31 @@ shared_examples_for 'a mutator' do
|
|||
|
||||
it { should be_instance_of(to_enum.class) }
|
||||
|
||||
let(:expected_mutations) do
|
||||
mutations.map do |mutation|
|
||||
if mutation.respond_to?(:to_ast)
|
||||
mutation.to_ast.to_sexp
|
||||
else
|
||||
mutation
|
||||
end
|
||||
end.to_set
|
||||
unless instance_methods.include?(:expected_mutations)
|
||||
let(:expected_mutations) do
|
||||
mutations.map do |mutation|
|
||||
case mutation
|
||||
when String
|
||||
mutation.to_ast
|
||||
when Rubinius::AST::Node
|
||||
mutation
|
||||
else
|
||||
raise
|
||||
end
|
||||
end.map do |node|
|
||||
ToSource.to_source(node)
|
||||
end.to_set
|
||||
end
|
||||
end
|
||||
|
||||
it 'generates the expected mutations' do
|
||||
generated = self.subject.map(&:to_sexp).to_set
|
||||
generated = self.subject.map { |mutation| ToSource.to_source(mutation) }.to_set
|
||||
|
||||
missing = (expected_mutations - generated).to_a
|
||||
unexpected = (generated - expected_mutations).to_a
|
||||
|
||||
unless generated == expected_mutations
|
||||
message = "Missing mutations: %s\nUnexpected mutations: %s" % [missing, unexpected].map(&:inspect)
|
||||
fail message
|
||||
fail "Missing mutations:\n%s\nUnexpected mutations:\n%s" % [missing.join("\n----\n"), unexpected.join("\n----\n")]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -3,25 +3,43 @@ require 'spec_helper'
|
|||
describe Mutant::Matcher::Method::Classifier, '.run' do
|
||||
subject { described_class.run(input) }
|
||||
|
||||
context 'with explicit toplevel scope' do
|
||||
let(:input) { '::TestApp::Literal#string' }
|
||||
let(:expected_class) { Mutant::Matcher::Method::Instance }
|
||||
shared_examples_for 'Mutant::Matcher::Method::Classifier.run' do
|
||||
before do
|
||||
expected_class.stub(:new => response)
|
||||
end
|
||||
|
||||
it_should_behave_like 'a method filter parse result'
|
||||
let(:response) { :Response }
|
||||
|
||||
it { should be(response) }
|
||||
|
||||
it 'should initialize method filter with correct arguments' do
|
||||
expected_class.should_receive(:new).with(TestApp::Literal, expected_method).and_return(response)
|
||||
subject
|
||||
end
|
||||
end
|
||||
|
||||
context 'with explicit toplevel scope' do
|
||||
let(:input) { '::TestApp::Literal#string' }
|
||||
let(:expected_class) { Mutant::Matcher::Method::Instance }
|
||||
let(:expected_method) { TestApp::Literal.instance_method(:string) }
|
||||
|
||||
it_should_behave_like 'Mutant::Matcher::Method::Classifier.run'
|
||||
end
|
||||
|
||||
context 'with instance method notation' do
|
||||
let(:input) { 'TestApp::Literal#string' }
|
||||
let(:expected_class) { Mutant::Matcher::Method::Instance }
|
||||
let(:input) { 'TestApp::Literal#string' }
|
||||
let(:expected_method) { TestApp::Literal.instance_method(:string) }
|
||||
let(:expected_class) { Mutant::Matcher::Method::Instance }
|
||||
|
||||
it_should_behave_like 'a method filter parse result'
|
||||
it_should_behave_like 'Mutant::Matcher::Method::Classifier.run'
|
||||
end
|
||||
|
||||
context 'with singleton method notation' do
|
||||
let(:input) { 'TestApp::Literal.string' }
|
||||
let(:expected_class) { Mutant::Matcher::Method::Singleton }
|
||||
let(:input) { 'TestApp::Literal.string' }
|
||||
let(:expected_method) { TestApp::Literal.method(:string) }
|
||||
let(:expected_class) { Mutant::Matcher::Method::Singleton }
|
||||
|
||||
it_should_behave_like 'a method filter parse result'
|
||||
it_should_behave_like 'Mutant::Matcher::Method::Classifier.run'
|
||||
end
|
||||
|
||||
context 'with invalid notation' do
|
||||
|
|
|
@ -1,11 +0,0 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe Mutant::Matcher::Method, '#method' do
|
||||
subject { object.send(:method) }
|
||||
|
||||
let(:object) { described_class.allocate }
|
||||
|
||||
it 'should raise error' do
|
||||
expect { subject }.to raise_error(NotImplementedError, 'Mutant::Matcher::Method#method is not implemented')
|
||||
end
|
||||
end
|
|
@ -9,26 +9,27 @@ describe Mutant::Mutator, 'block' do
|
|||
mutations = []
|
||||
|
||||
# Mutation of each statement in block
|
||||
mutations << "foo\nself.bar"
|
||||
mutations << "self.foo\nbar"
|
||||
mutations << "foo\nself.bar".to_ast
|
||||
mutations << "self.foo\nbar".to_ast
|
||||
|
||||
## Remove statement in block
|
||||
mutations << [:block, 'self.foo'.to_sexp]
|
||||
mutations << [:block, 'self.bar'.to_sexp]
|
||||
mutations << [:block]
|
||||
# Remove statement in block
|
||||
mutations << Rubinius::AST::Block.new(1, ['self.foo'.to_ast])
|
||||
mutations << Rubinius::AST::Block.new(1, ['self.bar'.to_ast])
|
||||
mutations << Rubinius::AST::Block.new(1, ['nil'.to_ast])
|
||||
end
|
||||
|
||||
it_should_behave_like 'a mutator'
|
||||
end
|
||||
|
||||
|
||||
|
||||
context 'with one statement' do
|
||||
let(:node) { Rubinius::AST::Block.new(1, ['self.foo'.to_ast]) }
|
||||
|
||||
let(:mutations) do
|
||||
mutations = []
|
||||
mutations << [:block, 'foo'.to_sexp]
|
||||
mutations << [:block]
|
||||
mutations << Rubinius::AST::Block.new(1, ['foo'.to_ast])
|
||||
mutations << Rubinius::AST::Block.new(1, ['nil'.to_ast])
|
||||
end
|
||||
|
||||
it_should_behave_like 'a mutator'
|
||||
|
|
|
@ -17,7 +17,7 @@ describe Mutant::Mutator, 'define' do
|
|||
mutations << 'def foo; self.bar; end'
|
||||
|
||||
# Remove all statements
|
||||
mutations << [:defn, :foo, [:args], [:scope, [:block]]]
|
||||
mutations << 'def foo; end'
|
||||
end
|
||||
|
||||
it_should_behave_like 'a mutator'
|
||||
|
@ -38,7 +38,7 @@ describe Mutant::Mutator, 'define' do
|
|||
mutations << 'def self.foo; self.baz; end'
|
||||
|
||||
# Remove all statements
|
||||
mutations << [:defs, [:self], :foo, [:args], [:scope, [:block]]]
|
||||
mutations << 'def self.foo; end'
|
||||
end
|
||||
|
||||
it_should_behave_like 'a mutator'
|
||||
|
|
|
@ -1,30 +1,60 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe Mutant::Mutator, 'if statement' do
|
||||
let(:source) { 'if self.condition; true; else false; end' }
|
||||
|
||||
let(:mutations) do
|
||||
mutants = []
|
||||
context 'if with two branches' do
|
||||
let(:source) { 'if self.condition; true; else false; end' }
|
||||
|
||||
# mutations of condition
|
||||
mutants << 'if condition; true; else false; end'
|
||||
let(:mutations) do
|
||||
mutants = []
|
||||
|
||||
mutants << 'if !self.condition; true; else false; end'
|
||||
# mutations of condition
|
||||
mutants << 'if condition; true; else false; end'
|
||||
|
||||
# Deleted else branch
|
||||
mutants << 'if self.condition; true end'
|
||||
mutants << 'if !self.condition; true; else false; end'
|
||||
|
||||
# Deleted if branch with promoting else branch to if branch
|
||||
mutants << 'if self.condition; false end'
|
||||
# Deleted else branch
|
||||
mutants << 'if self.condition; true end'
|
||||
|
||||
# mutations of body
|
||||
mutants << 'if self.condition; false; else false; end'
|
||||
mutants << 'if self.condition; nil; else false; end'
|
||||
# Deleted if branch with promoting else branch to if branch
|
||||
mutants << 'if self.condition; false end'
|
||||
|
||||
# mutations of else body
|
||||
mutants << 'if self.condition; true; else true; end'
|
||||
mutants << 'if self.condition; true; else nil; end'
|
||||
# mutations of body
|
||||
mutants << 'if self.condition; false; else false; end'
|
||||
mutants << 'if self.condition; nil; else false; end'
|
||||
|
||||
# mutations of else body
|
||||
mutants << 'if self.condition; true; else true; end'
|
||||
mutants << 'if self.condition; true; else nil; end'
|
||||
end
|
||||
|
||||
it_should_behave_like 'a mutator'
|
||||
end
|
||||
|
||||
it_should_behave_like 'a mutator'
|
||||
context 'unless with one branch' do
|
||||
let(:source) { 'unless condition; true; end' }
|
||||
|
||||
let(:mutations) do
|
||||
mutants = []
|
||||
mutants << 'unless !condition; true; end'
|
||||
mutants << 'if condition; true; end'
|
||||
mutants << 'unless condition; false; end'
|
||||
mutants << 'unless condition; nil; end'
|
||||
end
|
||||
|
||||
it_should_behave_like 'a mutator'
|
||||
end
|
||||
|
||||
context 'if with one branch' do
|
||||
let(:source) { 'if condition; true; end' }
|
||||
|
||||
let(:mutations) do
|
||||
mutants = []
|
||||
mutants << 'if !condition; true; end'
|
||||
mutants << 'if condition; false; end'
|
||||
mutants << 'if condition; nil; end'
|
||||
end
|
||||
|
||||
it_should_behave_like 'a mutator'
|
||||
end
|
||||
end
|
||||
|
|
|
@ -7,7 +7,7 @@ describe Mutant::Mutator::Node::Literal, 'array' do
|
|||
mutations = []
|
||||
|
||||
# Literal replaced with nil
|
||||
mutations << [:nil]
|
||||
mutations << 'nil'
|
||||
|
||||
# Mutation of each element in array
|
||||
mutations << '[nil, false]'
|
||||
|
|
|
@ -7,7 +7,7 @@ describe Mutant::Mutator::Node::Literal, 'empty array' do
|
|||
mutations = []
|
||||
|
||||
# Literal replaced with nil
|
||||
mutations << [:nil]
|
||||
mutations << 'nil'
|
||||
|
||||
# Extra element
|
||||
mutations << '[nil]'
|
||||
|
|
|
@ -6,7 +6,7 @@ describe Mutant::Mutator::Node::Literal, 'fixnum' do
|
|||
let(:source) { '10' }
|
||||
|
||||
let(:mutations) do
|
||||
%W(nil 0 1 #{random_fixnum}) << [:lit, -10]
|
||||
%W(nil 0 1 #{random_fixnum} -10)
|
||||
end
|
||||
|
||||
before do
|
||||
|
|
|
@ -11,8 +11,8 @@ describe Mutant::Mutator::Node::Literal, 'float' do
|
|||
mutations << random_float.to_s
|
||||
mutations << '0.0/0.0'
|
||||
mutations << '1.0/0.0'
|
||||
mutations << [:negate, [:call, [:lit, 1.0], :/, [:arglist, [:lit, 0.0]]]]
|
||||
mutations << [:lit, -10.0]
|
||||
mutations << '-1.0 / 0.0'
|
||||
mutations << '-10.0'
|
||||
end
|
||||
|
||||
let(:random_float) { 7.123 }
|
||||
|
|
|
@ -7,27 +7,27 @@ describe Mutant::Mutator::Node::Literal, 'hash' do
|
|||
mutations = []
|
||||
|
||||
# Literal replaced with nil
|
||||
mutations << [:nil]
|
||||
mutations << 'nil'
|
||||
|
||||
# Mutation of each key and value in hash
|
||||
mutations << [:hash, [:false ], [:true ], [:false], [:false]]
|
||||
mutations << [:hash, [:nil ], [:true ], [:false], [:false]]
|
||||
mutations << [:hash, [:true ], [:false], [:false], [:false]]
|
||||
mutations << [:hash, [:true ], [:nil ], [:false], [:false]]
|
||||
mutations << [:hash, [:true ], [:true ], [:true ], [:false]]
|
||||
mutations << [:hash, [:true ], [:true ], [:nil ], [:false]]
|
||||
mutations << [:hash, [:true ], [:true ], [:false], [:true ]]
|
||||
mutations << [:hash, [:true ], [:true ], [:false], [:nil ]]
|
||||
mutations << '{ false => true , false => false }'
|
||||
mutations << '{ nil => true , false => false }'
|
||||
mutations << '{ true => false , false => false }'
|
||||
mutations << '{ true => nil , false => false }'
|
||||
mutations << '{ true => true , true => false }'
|
||||
mutations << '{ true => true , nil => false }'
|
||||
mutations << '{ true => true , false => true }'
|
||||
mutations << '{ true => true , false => nil }'
|
||||
|
||||
# Remove each key once
|
||||
mutations << [:hash, [:true ], [:true ]]
|
||||
mutations << [:hash, [:false ], [:false ]]
|
||||
mutations << '{ true => true }'
|
||||
mutations << '{ false => false }'
|
||||
|
||||
# Empty hash
|
||||
mutations << [:hash]
|
||||
mutations << '{}'
|
||||
|
||||
# Extra element
|
||||
mutations << [:hash, [:true ], [:true ], [:false], [:false ], [:nil], [:nil] ]
|
||||
mutations << '{true => true, false => false, nil => nil}'
|
||||
end
|
||||
|
||||
it_should_behave_like 'a mutator'
|
||||
|
|
|
@ -9,7 +9,7 @@ describe Mutant::Mutator::Node::Literal, 'range' do
|
|||
mutations << 'nil'
|
||||
mutations << '1...100'
|
||||
mutations << '(0.0/0.0)..100'
|
||||
mutations << [:dot2, [:negate, [:call, [:lit, 1.0], :/, [:arglist, [:lit, 0.0]]]], [:lit, 100]]
|
||||
#mutations << [:dot2, [:negate, [:call, [:lit, 1.0], :/, [:arglist, [:lit, 0.0]]]], [:lit, 100]]
|
||||
mutations << '1..(1.0/0.0)'
|
||||
mutations << '1..(0.0/0.0)'
|
||||
end
|
||||
|
@ -25,7 +25,7 @@ describe Mutant::Mutator::Node::Literal, 'range' do
|
|||
mutations << 'nil'
|
||||
mutations << '1..100'
|
||||
mutations << '(0.0/0.0)...100'
|
||||
mutations << [:dot3, [:negate, [:call, [:lit, 1.0], :/, [:arglist, [:lit, 0.0]]]], [:lit, 100]]
|
||||
#mutations << [:dot3, [:negate, [:call, [:lit, 1.0], :/, [:arglist, [:lit, 0.0]]]], [:lit, 100]]
|
||||
mutations << '1...(1.0/0.0)'
|
||||
mutations << '1...(0.0/0.0)'
|
||||
end
|
||||
|
|
|
@ -16,6 +16,21 @@ describe Mutant::Strategy::Rspec::ExampleLookup, '#spec_file' do
|
|||
it { should be_frozen }
|
||||
end
|
||||
|
||||
context 'with element reader method' do
|
||||
let(:method_name) { '[]' }
|
||||
let(:expected_spec_file) { 'element_reader_spec.rb' }
|
||||
|
||||
it_should_behave_like 'Mutant::Strategy::Rspec::ExampleLookup#spec_file'
|
||||
end
|
||||
|
||||
context 'with element writer method' do
|
||||
let(:method_name) { '[]=' }
|
||||
|
||||
let(:expected_spec_file) { 'element_writer_spec.rb' }
|
||||
|
||||
it_should_behave_like 'Mutant::Strategy::Rspec::ExampleLookup#spec_file'
|
||||
end
|
||||
|
||||
context 'with writer method' do
|
||||
let(:method_name) { 'foo=' }
|
||||
let(:expected_spec_file) { 'foo_writer_spec.rb' }
|
||||
|
|
Loading…
Add table
Reference in a new issue