Initial rspec killer with "longes description prefix match"

This commit is contained in:
Markus Schirp 2013-08-04 18:49:42 +02:00
parent ad0ea265a2
commit f70dc6703f
11 changed files with 168 additions and 41 deletions

View file

@ -6,6 +6,8 @@ gemspec
gem 'mutant', path: '.'
gem 'rspec-core', path: '../rspec-core'
group :development, :test do
gem 'devtools', git: 'https://github.com/rom-rb/devtools.git'
end

View file

@ -19,6 +19,7 @@ require 'diff/lcs/hunk'
require 'rspec'
require 'anima'
require 'concord'
require 'rspec'
# Library namespace
module Mutant

View file

@ -244,6 +244,9 @@ module Mutant
# @api private
#
def add_strategies(opts)
opts.separator ''
opts.separator 'Strategies:'
opts.on('--static-success', 'does succeed on all mutations') do
set_strategy Strategy::Static::Success.new
end

View file

@ -89,6 +89,17 @@ module Mutant
scope.name
end
# Return match prefixes
#
# @return [Enumerable<String>]
#
# @api private
#
def match_prefixes
name_nesting.reverse
end
memoize :match_prefixes
# Return scope wrapped by context
#
# @return [::Module|::Class]

View file

@ -98,6 +98,16 @@ module Mutant
@runtime = times.real
end
# Return subject
#
# @return [Subject]
#
# @api private
#
def subject
mutation.subject
end
# Run killer
#
# @return [true]

View file

@ -19,36 +19,72 @@ module Mutant
#
def run
mutation.insert
# TODO: replace with real streams from configuration
require 'stringio'
# Note: We assume interesting output from a failed rspec run is stderr.
rspec_err = StringIO.new
exit_code = ::RSpec::Core::Runner.run(cli_arguments, nil, rspec_err)
groups = example_groups
killed = !exit_code.zero?
if killed and mutation.should_survive?
rspec_err.rewind
puts "#{mutation.class} test failed."
puts 'RSpec stderr:'
puts rspec_err.read
unless groups
$stderr.puts "No rspec example groups found for: #{match_prefixes.join(', ')}"
return false
end
killed
strategy.configuration.reporter.report(groups.length, nil) do |reporter|
example_groups.each do |group|
return true unless group.run(reporter)
end.all?
return false
end
end
# Return command line arguments
# Return match prefixes
#
# @return [Array]
# @return [Enumerble<String>]
#
# @api private
#
def cli_arguments
%W(
--fail-fast
) + strategy.spec_files(mutation.subject)
def match_prefixes
subject.match_prefixes
end
# Return example groups
#
# @return [Array<RSpec::Example>]
#
# @api private
#
def example_groups
match_prefixes.each do |match_expression|
example_groups = find_with(match_expression)
return example_groups unless example_groups.empty?
end
nil
end
# Return example groups that match expression
#
# @param [String] match_expression
#
# @return [Enumerable<String>]
#
# @api private
#
def find_with(match_expression)
all_example_groups.select do |example_group|
example_group.description.start_with?(match_expression)
end
end
DELIMITERS = /::|#/.freeze
# Return all example groups
#
# @return [Enumerable<RSpec::Example>]
#
# @api private
#
def all_example_groups
strategy.example_groups
end
end # Rspec

View file

@ -15,8 +15,61 @@ module Mutant
# @api private
#
def setup
output = StringIO.new
configuration.error_stream = output
configuration.output_stream = output
options.configure(configuration)
configuration.load_spec_files
self
end
memoize :setup
# Return configuration
#
# @return [RSpec::Core::Configuration]
#
# @api private
#
def configuration
RSpec::Core::Configuration.new
end
memoize :configuration, :freezer => :noop
# Return example groups
#
# @return [Enumerable<RSpec::Core::ExampleGroup>]
#
# @api private
#
def example_groups
world.example_groups
end
private
# Return world
#
# @return [RSpec::Core::World]
#
# @api private
#
def world
RSpec.world
end
memoize :world, :freezer => :noop
# Return options
#
# @return [RSpec::Core::ConfigurationOptions]
#
# @api private
#
def options
options = RSpec::Core::ConfigurationOptions.new(%w(--fail-fast spec))
options.parse_options
options
end
memoize :options, :freezer => :noop
end # Rspec
end # Strategy

View file

@ -46,7 +46,7 @@ module Mutant
# @api private
#
def identification
"#{subtype}:#{source_path}:#{source_line}"
"#{match_expression}:#{source_path}:#{source_line}"
end
memoize :identification
@ -84,16 +84,26 @@ module Mutant
end
memoize :original_root
private
# Return subtype identifier
# Return match expression
#
# @return [String]
#
# @api private
#
abstract_method :subtype
private :subtype
abstract_method :match_expression
# Return match prefixes
#
# @return [Enumerable<String>]
#
# @api private
#
def match_prefixes
context.match_prefixes.dup << match_expression
end
memoize :match_prefixes
private
# Return neutral mutation
#

View file

@ -27,6 +27,16 @@ module Mutant
node.children[self.class::NAME_INDEX]
end
# Return match expression
#
# @return [String]
#
# @api private
#
def match_expression
"#{context.identification}#{self.class::SYMBOL}#{name}"
end
private
# Return mutations
@ -54,16 +64,6 @@ module Mutant
context.scope
end
# Return subtype identifier
#
# @return [String]
#
# @api private
#
def subtype
"#{context.identification}#{self.class::SYMBOL}#{name}"
end
end # Method
end # Subject
end # Mutant

View file

@ -10,11 +10,8 @@ describe Mutant, 'rspec integration' do
end
end
let(:strategy) { Mutant::Strategy::Rspec::DM2 }
pending 'allows to kill mutations' do
cli = 'bundle exec mutant --rspec ::TestApp::Literal#string'
Kernel.system(cli).should be(true)
specify 'it allows to kill mutations' do
Kernel.system('bundle exec mutant --rspec ::TestApp::Literal#string').should be(true)
end
pending 'fails to kill mutations when they are not covered' do

View file

@ -4,6 +4,10 @@ require 'spec_helper'
describe Mutant::Killer::Rspec, '.new' do
before do
pending 'dactivated'
end
subject { object.new(strategy, mutation) }
let(:context) { double('Context') }