Rename Runner to Killer
* Add working integration spec for rspec (mutant) killer.
This commit is contained in:
parent
c9219b1f1e
commit
23ee68ac1e
19 changed files with 183 additions and 102 deletions
|
@ -35,8 +35,8 @@ module Mutant
|
||||||
end
|
end
|
||||||
|
|
||||||
require 'mutant/random'
|
require 'mutant/random'
|
||||||
require 'mutant/runner'
|
require 'mutant/killer'
|
||||||
require 'mutant/runner/rspec'
|
require 'mutant/killer/rspec'
|
||||||
require 'mutant/mutator'
|
require 'mutant/mutator'
|
||||||
require 'mutant/mutator/registry'
|
require 'mutant/mutator/registry'
|
||||||
require 'mutant/mutator/literal'
|
require 'mutant/mutator/literal'
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
module Mutant
|
module Mutant
|
||||||
# Abstract runner for tests
|
# Abstract runner for mutant killers
|
||||||
class Runner
|
class Killer
|
||||||
include Immutable, Abstract
|
include Immutable, Abstract
|
||||||
|
|
||||||
# Run runner
|
# Run runner
|
96
lib/mutant/killer/rspec.rb
Normal file
96
lib/mutant/killer/rspec.rb
Normal file
|
@ -0,0 +1,96 @@
|
||||||
|
module Mutant
|
||||||
|
class Killer
|
||||||
|
# Simple runner for rspec tests
|
||||||
|
class Rspec < self
|
||||||
|
|
||||||
|
# Return error stream
|
||||||
|
#
|
||||||
|
# @return [StringIO]
|
||||||
|
#
|
||||||
|
# @api private
|
||||||
|
#
|
||||||
|
attr_reader :error_stream
|
||||||
|
|
||||||
|
# Return output stream
|
||||||
|
#
|
||||||
|
# @return [StringIO]
|
||||||
|
#
|
||||||
|
# @api private
|
||||||
|
#
|
||||||
|
attr_reader :output_stream
|
||||||
|
|
||||||
|
# Run block in clean rspec environment
|
||||||
|
#
|
||||||
|
# @return [self]
|
||||||
|
#
|
||||||
|
# @api private
|
||||||
|
#
|
||||||
|
def self.nest
|
||||||
|
original_world, original_configuration =
|
||||||
|
::RSpec.instance_variable_get(:@world),
|
||||||
|
::RSpec.instance_variable_get(:@configuration)
|
||||||
|
|
||||||
|
::RSpec.instance_variable_set(:@world,nil)
|
||||||
|
::RSpec.instance_variable_set(:@configuration,nil)
|
||||||
|
|
||||||
|
yield
|
||||||
|
|
||||||
|
self
|
||||||
|
ensure
|
||||||
|
::RSpec.instance_variable_set(:@world,original_world)
|
||||||
|
::RSpec.instance_variable_set(:@configuration,original_configuration)
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
# Initialize rspec runner
|
||||||
|
#
|
||||||
|
# @return [undefined]
|
||||||
|
#
|
||||||
|
# @api private
|
||||||
|
#
|
||||||
|
def initialize(*)
|
||||||
|
@error_stream, @output_stream = StringIO.new, StringIO.new
|
||||||
|
super
|
||||||
|
end
|
||||||
|
|
||||||
|
# Run rspec test
|
||||||
|
#
|
||||||
|
# @return [true]
|
||||||
|
# returns true when test is NOT successful and the mutant was killed
|
||||||
|
#
|
||||||
|
# @return [false]
|
||||||
|
# returns false otherwise
|
||||||
|
#
|
||||||
|
# @api private
|
||||||
|
#
|
||||||
|
def run
|
||||||
|
!RSpec::Core::Runner.run(command_line_arguments, error_stream, output_stream).zero?
|
||||||
|
end
|
||||||
|
|
||||||
|
# Return command line arguments
|
||||||
|
#
|
||||||
|
# @return [Array]
|
||||||
|
#
|
||||||
|
# @api private
|
||||||
|
#
|
||||||
|
def command_line_arguments
|
||||||
|
%W(
|
||||||
|
--fail-fast
|
||||||
|
) + Dir[filename_pattern]
|
||||||
|
end
|
||||||
|
|
||||||
|
# Return rspec filename pattern
|
||||||
|
#
|
||||||
|
# @return [String]
|
||||||
|
#
|
||||||
|
# @api private
|
||||||
|
#
|
||||||
|
# TODO: Add an option or be clever and only run affected specs.
|
||||||
|
#
|
||||||
|
def filename_pattern
|
||||||
|
'spec/unit/**/*_spec.rb'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -1,69 +0,0 @@
|
||||||
module Mutant
|
|
||||||
class Runner
|
|
||||||
# Simple runner for rspec tests
|
|
||||||
class Rspec < self
|
|
||||||
|
|
||||||
# Return error stream
|
|
||||||
#
|
|
||||||
# @return [StringIO]
|
|
||||||
#
|
|
||||||
# @api private
|
|
||||||
#
|
|
||||||
def error_stream
|
|
||||||
StringIO.new
|
|
||||||
end
|
|
||||||
|
|
||||||
# Return output stream
|
|
||||||
#
|
|
||||||
# @return [StringIO]
|
|
||||||
#
|
|
||||||
# @api private
|
|
||||||
#
|
|
||||||
def output_stream
|
|
||||||
StringIO.new
|
|
||||||
end
|
|
||||||
|
|
||||||
private
|
|
||||||
|
|
||||||
# Run rspec test
|
|
||||||
#
|
|
||||||
# @return [true]
|
|
||||||
# returns true when test is NOT successful and the mutant was killed
|
|
||||||
#
|
|
||||||
# @return [false]
|
|
||||||
# returns false otherwise
|
|
||||||
#
|
|
||||||
# @api private
|
|
||||||
#
|
|
||||||
def run
|
|
||||||
!RSpec::Core::Runner.run(command_line,error_stream,output_stream).zero?
|
|
||||||
end
|
|
||||||
|
|
||||||
# Return command line
|
|
||||||
#
|
|
||||||
# @return [Array]
|
|
||||||
#
|
|
||||||
# @api private
|
|
||||||
#
|
|
||||||
def command_line
|
|
||||||
%W(
|
|
||||||
--fail-fast
|
|
||||||
) + Dir[filename_pattern]
|
|
||||||
end
|
|
||||||
|
|
||||||
# Return rspec filename pattern
|
|
||||||
#
|
|
||||||
# @return [String]
|
|
||||||
#
|
|
||||||
# @api private
|
|
||||||
#
|
|
||||||
# TODO: Add an option or be clever and only run affected specs.
|
|
||||||
#
|
|
||||||
def filename_pattern
|
|
||||||
'spec/unit/**/*_spec.rb'
|
|
||||||
end
|
|
||||||
|
|
||||||
memoize :output_stream, :error_stream
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -59,6 +59,20 @@ module Mutant
|
||||||
self
|
self
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Insert AST node under context
|
||||||
|
#
|
||||||
|
# @param [Rubinius::AST::Node] node
|
||||||
|
#
|
||||||
|
# @return [self]
|
||||||
|
#
|
||||||
|
# @api private
|
||||||
|
#
|
||||||
|
def insert(node)
|
||||||
|
Loader.load(context.root(node))
|
||||||
|
|
||||||
|
self
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
# Initialize subject
|
# Initialize subject
|
||||||
|
@ -76,19 +90,5 @@ module Mutant
|
||||||
def initialize(context, node)
|
def initialize(context, node)
|
||||||
@context, @node = context, node
|
@context, @node = context, node
|
||||||
end
|
end
|
||||||
|
|
||||||
# Insert AST node under context
|
|
||||||
#
|
|
||||||
# @param [Rubinius::AST::Node] node
|
|
||||||
#
|
|
||||||
# @return [self]
|
|
||||||
#
|
|
||||||
# @api private
|
|
||||||
#
|
|
||||||
def insert(node)
|
|
||||||
Loader.load(context.root(node))
|
|
||||||
|
|
||||||
self
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -7,11 +7,11 @@ class CodeLoadingSubject
|
||||||
end
|
end
|
||||||
|
|
||||||
describe Mutant, 'code loading' do
|
describe Mutant, 'code loading' do
|
||||||
let(:context) { Mutant::Context::Constant.build(CodeLoadingSubject) }
|
let(:context) { Mutant::Context::Constant.build("/some/path",CodeLoadingSubject) }
|
||||||
let(:node) { 'def foo; :bar; end'.to_ast }
|
let(:node) { 'def foo; :bar; end'.to_ast }
|
||||||
let(:root) { context.root(node) }
|
let(:root) { context.root(node) }
|
||||||
|
|
||||||
subject { Mutant::Loader.load(root) }
|
subject { Mutant::Loader.load(root) }
|
||||||
|
|
||||||
before { subject }
|
before { subject }
|
||||||
|
|
||||||
|
|
31
spec/integration/mutant/rspec_killer_spec.rb
Normal file
31
spec/integration/mutant/rspec_killer_spec.rb
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
require 'spec_helper'
|
||||||
|
|
||||||
|
describe Mutant,'rspec integration' do
|
||||||
|
around do |example|
|
||||||
|
Dir.chdir(TestApp.root) do
|
||||||
|
example.run
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
specify 'allows to run rspec with mutations' do
|
||||||
|
|
||||||
|
Mutant::Matcher::Method.parse('TestApp::Literal#string').each do |subject|
|
||||||
|
subject.each do |mutation|
|
||||||
|
Mutant::Killer::Rspec.nest do
|
||||||
|
runner = Mutant::Killer::Rspec.run(subject,mutation)
|
||||||
|
runner.killed?.should be(true)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
Mutant::Matcher::Method.parse('TestApp::Literal#uncovered_string').each do |subject|
|
||||||
|
subject.each do |mutation|
|
||||||
|
Mutant::Killer::Rspec.nest do
|
||||||
|
runner = Mutant::Killer::Rspec.run(subject,mutation)
|
||||||
|
runner.killed?.should be(false)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
|
@ -5,6 +5,9 @@ require 'rspec'
|
||||||
# require spec support files and shared behavior
|
# require spec support files and shared behavior
|
||||||
Dir[File.expand_path('../{support,shared}/**/*.rb', __FILE__)].each { |f| require f }
|
Dir[File.expand_path('../{support,shared}/**/*.rb', __FILE__)].each { |f| require f }
|
||||||
|
|
||||||
|
$: << File.join(TestApp.root,'lib')
|
||||||
|
require 'test_app'
|
||||||
|
|
||||||
require 'mutant'
|
require 'mutant'
|
||||||
|
|
||||||
RSpec.configure do |config|
|
RSpec.configure do |config|
|
||||||
|
|
5
spec/support/test_app.rb
Normal file
5
spec/support/test_app.rb
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
module TestApp
|
||||||
|
def self.root
|
||||||
|
File.expand_path('../../../test_app', __FILE__)
|
||||||
|
end
|
||||||
|
end
|
|
@ -1,6 +1,6 @@
|
||||||
require 'spec_helper'
|
require 'spec_helper'
|
||||||
|
|
||||||
describe Mutant::Runner,'.run' do
|
describe Mutant::Killer,'.run' do
|
||||||
subject { class_under_test.run(mutation_subject,mutant) }
|
subject { class_under_test.run(mutation_subject,mutant) }
|
||||||
|
|
||||||
let(:mutation_subject) { mock('Subject', :insert => nil, :reset => nil) }
|
let(:mutation_subject) { mock('Subject', :insert => nil, :reset => nil) }
|
|
@ -1,6 +1,6 @@
|
||||||
require 'spec_helper'
|
require 'spec_helper'
|
||||||
|
|
||||||
describe Mutant::Runner,'#killed?' do
|
describe Mutant::Killer,'#killed?' do
|
||||||
subject { object.killed? }
|
subject { object.killed? }
|
||||||
|
|
||||||
let(:object) { class_under_test.run(mutation_subject,mutant) }
|
let(:object) { class_under_test.run(mutation_subject,mutant) }
|
|
@ -1,6 +1,6 @@
|
||||||
require 'spec_helper'
|
require 'spec_helper'
|
||||||
|
|
||||||
describe Mutant::Runner,'#mutant' do
|
describe Mutant::Killer,'#mutant' do
|
||||||
subject { object.mutant }
|
subject { object.mutant }
|
||||||
|
|
||||||
let(:object) { class_under_test.run(mutation_subject, mutant) }
|
let(:object) { class_under_test.run(mutation_subject, mutant) }
|
|
@ -1,10 +1,10 @@
|
||||||
require 'spec_helper'
|
require 'spec_helper'
|
||||||
|
|
||||||
describe Mutant::Runner::Rspec, '.run' do
|
describe Mutant::Killer::Rspec, '.run' do
|
||||||
subject { object.run(context, mutant) }
|
subject { object.run(context, mutant) }
|
||||||
|
|
||||||
let(:context) { mock('Context') }
|
let(:context) { mock('Context') }
|
||||||
let(:mutant) { mock('Mutant') }
|
let(:mutant) { mock('Mutant') }
|
||||||
|
|
||||||
let(:object) { described_class }
|
let(:object) { described_class }
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
require 'spec_helper'
|
require 'spec_helper'
|
||||||
|
|
||||||
describe Mutant::Runner::Rspec,'#error_stream' do
|
describe Mutant::Killer::Rspec,'#error_stream' do
|
||||||
subject { object.error_stream }
|
subject { object.error_stream }
|
||||||
|
|
||||||
let(:object) { described_class.run(mutation_subject,mutant) }
|
let(:object) { described_class.run(mutation_subject,mutant) }
|
|
@ -1,6 +1,6 @@
|
||||||
require 'spec_helper'
|
require 'spec_helper'
|
||||||
|
|
||||||
describe Mutant::Runner::Rspec,'#output_stream' do
|
describe Mutant::Killer::Rspec,'#output_stream' do
|
||||||
subject { object.output_stream }
|
subject { object.output_stream }
|
||||||
|
|
||||||
let(:object) { described_class.run(mutation_subject,mutant) }
|
let(:object) { described_class.run(mutation_subject,mutant) }
|
|
@ -1,6 +1,6 @@
|
||||||
require 'spec_helper'
|
require 'spec_helper'
|
||||||
|
|
||||||
describe Mutant::Runner,'#subject' do
|
describe Mutant::Killer,'#subject' do
|
||||||
subject { object.subject }
|
subject { object.subject }
|
||||||
|
|
||||||
let(:object) { class_under_test.run(mutation_subject, mutant) }
|
let(:object) { class_under_test.run(mutation_subject, mutant) }
|
|
@ -10,6 +10,10 @@ describe Mutant::Matcher::Method, '#each' do
|
||||||
node
|
node
|
||||||
end
|
end
|
||||||
|
|
||||||
|
define_method(:method) do
|
||||||
|
TestApp::Literal.instance_method(:string)
|
||||||
|
end
|
||||||
|
|
||||||
define_method(:constant) do
|
define_method(:constant) do
|
||||||
::SampleSubjects::ExampleModule
|
::SampleSubjects::ExampleModule
|
||||||
end
|
end
|
||||||
|
|
|
@ -5,10 +5,22 @@ module TestApp
|
||||||
true
|
true
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def self.freeze
|
||||||
|
raise
|
||||||
|
end
|
||||||
|
|
||||||
def string
|
def string
|
||||||
'string'
|
'string'
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def uncovered_string
|
||||||
|
'string'
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.string
|
||||||
|
'string'
|
||||||
|
end
|
||||||
|
|
||||||
def symbol
|
def symbol
|
||||||
:symbol
|
:symbol
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
# encoding: utf-8
|
# encoding: utf-8
|
||||||
|
|
||||||
require 'rspec'
|
require 'rspec'
|
||||||
|
|
||||||
require 'test_app'
|
require 'test_app'
|
||||||
|
|
||||||
# require spec support files and shared behavior
|
# require spec support files and shared behavior
|
||||||
|
|
Loading…
Reference in a new issue