diff --git a/lib/mutant.rb b/lib/mutant.rb index 0412b198..38876986 100644 --- a/lib/mutant.rb +++ b/lib/mutant.rb @@ -35,8 +35,8 @@ module Mutant end require 'mutant/random' -require 'mutant/runner' -require 'mutant/runner/rspec' +require 'mutant/killer' +require 'mutant/killer/rspec' require 'mutant/mutator' require 'mutant/mutator/registry' require 'mutant/mutator/literal' diff --git a/lib/mutant/runner.rb b/lib/mutant/killer.rb similarity index 95% rename from lib/mutant/runner.rb rename to lib/mutant/killer.rb index 45d33fa7..66bb34a9 100644 --- a/lib/mutant/runner.rb +++ b/lib/mutant/killer.rb @@ -1,6 +1,6 @@ module Mutant - # Abstract runner for tests - class Runner + # Abstract runner for mutant killers + class Killer include Immutable, Abstract # Run runner diff --git a/lib/mutant/killer/rspec.rb b/lib/mutant/killer/rspec.rb new file mode 100644 index 00000000..6ea9d193 --- /dev/null +++ b/lib/mutant/killer/rspec.rb @@ -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 diff --git a/lib/mutant/runner/rspec.rb b/lib/mutant/runner/rspec.rb deleted file mode 100644 index 4b375001..00000000 --- a/lib/mutant/runner/rspec.rb +++ /dev/null @@ -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 diff --git a/lib/mutant/subject.rb b/lib/mutant/subject.rb index d4f62062..dc606697 100644 --- a/lib/mutant/subject.rb +++ b/lib/mutant/subject.rb @@ -59,6 +59,20 @@ module Mutant self 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 # Initialize subject @@ -76,19 +90,5 @@ module Mutant def initialize(context, node) @context, @node = context, node 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 diff --git a/spec/integration/loader_spec.rb b/spec/integration/loader_spec.rb index ce58f968..95fb45e3 100644 --- a/spec/integration/loader_spec.rb +++ b/spec/integration/loader_spec.rb @@ -7,11 +7,11 @@ class CodeLoadingSubject end describe Mutant, 'code loading' do - let(:context) { Mutant::Context::Constant.build(CodeLoadingSubject) } - let(:node) { 'def foo; :bar; end'.to_ast } - let(:root) { context.root(node) } - - subject { Mutant::Loader.load(root) } + let(:context) { Mutant::Context::Constant.build("/some/path",CodeLoadingSubject) } + let(:node) { 'def foo; :bar; end'.to_ast } + let(:root) { context.root(node) } + + subject { Mutant::Loader.load(root) } before { subject } diff --git a/spec/integration/mutant/rspec_killer_spec.rb b/spec/integration/mutant/rspec_killer_spec.rb new file mode 100644 index 00000000..ba7ddcf7 --- /dev/null +++ b/spec/integration/mutant/rspec_killer_spec.rb @@ -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 diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 9edbaaa6..0d387406 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -5,6 +5,9 @@ require 'rspec' # require spec support files and shared behavior Dir[File.expand_path('../{support,shared}/**/*.rb', __FILE__)].each { |f| require f } +$: << File.join(TestApp.root,'lib') +require 'test_app' + require 'mutant' RSpec.configure do |config| diff --git a/spec/support/test_app.rb b/spec/support/test_app.rb new file mode 100644 index 00000000..6ab5db3f --- /dev/null +++ b/spec/support/test_app.rb @@ -0,0 +1,5 @@ +module TestApp + def self.root + File.expand_path('../../../test_app', __FILE__) + end +end diff --git a/spec/unit/mutant/runner/class_methods/run_spec.rb b/spec/unit/mutant/killer/class_methods/run_spec.rb similarity index 95% rename from spec/unit/mutant/runner/class_methods/run_spec.rb rename to spec/unit/mutant/killer/class_methods/run_spec.rb index 4948fb42..5756a40f 100644 --- a/spec/unit/mutant/runner/class_methods/run_spec.rb +++ b/spec/unit/mutant/killer/class_methods/run_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Mutant::Runner,'.run' do +describe Mutant::Killer,'.run' do subject { class_under_test.run(mutation_subject,mutant) } let(:mutation_subject) { mock('Subject', :insert => nil, :reset => nil) } diff --git a/spec/unit/mutant/runner/killed_ques_spec.rb b/spec/unit/mutant/killer/killed_ques_spec.rb similarity index 95% rename from spec/unit/mutant/runner/killed_ques_spec.rb rename to spec/unit/mutant/killer/killed_ques_spec.rb index dcf381c5..dc7bc95f 100644 --- a/spec/unit/mutant/runner/killed_ques_spec.rb +++ b/spec/unit/mutant/killer/killed_ques_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Mutant::Runner,'#killed?' do +describe Mutant::Killer,'#killed?' do subject { object.killed? } let(:object) { class_under_test.run(mutation_subject,mutant) } diff --git a/spec/unit/mutant/runner/mutant_spec.rb b/spec/unit/mutant/killer/mutant_spec.rb similarity index 92% rename from spec/unit/mutant/runner/mutant_spec.rb rename to spec/unit/mutant/killer/mutant_spec.rb index a85788a7..fe54fc11 100644 --- a/spec/unit/mutant/runner/mutant_spec.rb +++ b/spec/unit/mutant/killer/mutant_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Mutant::Runner,'#mutant' do +describe Mutant::Killer,'#mutant' do subject { object.mutant } let(:object) { class_under_test.run(mutation_subject, mutant) } diff --git a/spec/unit/mutant/runner/rspec/class_methods/run_spec.rb b/spec/unit/mutant/killer/rspec/class_methods/run_spec.rb similarity index 80% rename from spec/unit/mutant/runner/rspec/class_methods/run_spec.rb rename to spec/unit/mutant/killer/rspec/class_methods/run_spec.rb index 4481b8af..37f999b7 100644 --- a/spec/unit/mutant/runner/rspec/class_methods/run_spec.rb +++ b/spec/unit/mutant/killer/rspec/class_methods/run_spec.rb @@ -1,10 +1,10 @@ require 'spec_helper' -describe Mutant::Runner::Rspec, '.run' do +describe Mutant::Killer::Rspec, '.run' do subject { object.run(context, mutant) } - let(:context) { mock('Context') } - let(:mutant) { mock('Mutant') } + let(:context) { mock('Context') } + let(:mutant) { mock('Mutant') } let(:object) { described_class } diff --git a/spec/unit/mutant/runner/rspec/error_stream_spec.rb b/spec/unit/mutant/killer/rspec/error_stream_spec.rb similarity index 90% rename from spec/unit/mutant/runner/rspec/error_stream_spec.rb rename to spec/unit/mutant/killer/rspec/error_stream_spec.rb index 534f32b0..c7f7a2b2 100644 --- a/spec/unit/mutant/runner/rspec/error_stream_spec.rb +++ b/spec/unit/mutant/killer/rspec/error_stream_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Mutant::Runner::Rspec,'#error_stream' do +describe Mutant::Killer::Rspec,'#error_stream' do subject { object.error_stream } let(:object) { described_class.run(mutation_subject,mutant) } diff --git a/spec/unit/mutant/runner/rspec/output_stream_spec.rb b/spec/unit/mutant/killer/rspec/output_stream_spec.rb similarity index 90% rename from spec/unit/mutant/runner/rspec/output_stream_spec.rb rename to spec/unit/mutant/killer/rspec/output_stream_spec.rb index 5ba9a7e9..f1bc0e46 100644 --- a/spec/unit/mutant/runner/rspec/output_stream_spec.rb +++ b/spec/unit/mutant/killer/rspec/output_stream_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Mutant::Runner::Rspec,'#output_stream' do +describe Mutant::Killer::Rspec,'#output_stream' do subject { object.output_stream } let(:object) { described_class.run(mutation_subject,mutant) } diff --git a/spec/unit/mutant/runner/subject_spec.rb b/spec/unit/mutant/killer/subject_spec.rb similarity index 92% rename from spec/unit/mutant/runner/subject_spec.rb rename to spec/unit/mutant/killer/subject_spec.rb index 0b847db7..ba97646e 100644 --- a/spec/unit/mutant/runner/subject_spec.rb +++ b/spec/unit/mutant/killer/subject_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Mutant::Runner,'#subject' do +describe Mutant::Killer,'#subject' do subject { object.subject } let(:object) { class_under_test.run(mutation_subject, mutant) } diff --git a/spec/unit/mutant/matcher/method/each_spec.rb b/spec/unit/mutant/matcher/method/each_spec.rb index 8b2955f8..950a899a 100644 --- a/spec/unit/mutant/matcher/method/each_spec.rb +++ b/spec/unit/mutant/matcher/method/each_spec.rb @@ -10,6 +10,10 @@ describe Mutant::Matcher::Method, '#each' do node end + define_method(:method) do + TestApp::Literal.instance_method(:string) + end + define_method(:constant) do ::SampleSubjects::ExampleModule end diff --git a/test_app/lib/test_app/literal.rb b/test_app/lib/test_app/literal.rb index d7553efb..ca2c6883 100644 --- a/test_app/lib/test_app/literal.rb +++ b/test_app/lib/test_app/literal.rb @@ -5,10 +5,22 @@ module TestApp true end + def self.freeze + raise + end + def string 'string' end + def uncovered_string + 'string' + end + + def self.string + 'string' + end + def symbol :symbol end diff --git a/test_app/spec/spec_helper.rb b/test_app/spec/spec_helper.rb index 2f56c510..870045ac 100644 --- a/test_app/spec/spec_helper.rb +++ b/test_app/spec/spec_helper.rb @@ -1,7 +1,6 @@ # encoding: utf-8 require 'rspec' - require 'test_app' # require spec support files and shared behavior