diff --git a/lib/mutant.rb b/lib/mutant.rb index 7e33f070..bbf5455a 100644 --- a/lib/mutant.rb +++ b/lib/mutant.rb @@ -82,6 +82,7 @@ require 'mutant/matcher/method/classifier' require 'mutant/matcher/scope_methods' require 'mutant/killer' require 'mutant/killer/rspec' +require 'mutant/killer/forking' require 'mutant/runner' require 'mutant/cli' require 'mutant/color' diff --git a/lib/mutant/cli.rb b/lib/mutant/cli.rb index 92ca6f9b..fe38add7 100644 --- a/lib/mutant/cli.rb +++ b/lib/mutant/cli.rb @@ -66,7 +66,12 @@ module Mutant # @api private # def killer - Mutant::Killer::Rspec #::Forking + killer = Mutant::Killer::Rspec + if @forking + Mutant::Killer::Forking.new(killer) + else + killer + end end memoize :killer @@ -88,7 +93,8 @@ module Mutant '-I' => [:add_load_path], '--include' => [:add_load_path], '-r' => [:require_library], - '--require' => [:require_library] + '--require' => [:require_library], + '--fork' => [:set_forking] }.deep_freeze OPTION_PATTERN = %r(\A-(?:-)?[a-zA-Z0-9]+\z).freeze @@ -234,6 +240,19 @@ module Mutant consume(2) end + # Set forking + # + # @api private + # + # @return [self] + # + # @api private + # + def set_forking + consume(1) + @forking = true + end + # Require library # # @api private diff --git a/lib/mutant/killer.rb b/lib/mutant/killer.rb index d3d62a37..3c445ea6 100644 --- a/lib/mutant/killer.rb +++ b/lib/mutant/killer.rb @@ -2,8 +2,7 @@ module Mutant # Abstract runner for mutant killers class Killer include Adamantium::Flat, AbstractClass - extend MethodObject - + # Test for kill failure # # @return [true] @@ -46,6 +45,37 @@ module Mutant mutation.source end + # Return name of killer + # + # @return [String] + # + # @api private + # + def self.type + self::TYPE + end + + # Return identification + # + # @return [String] + # + # @api private + # + def identification + "#{type}:#{mutation.identification}".freeze + end + memoize :identification + + # Return mae of killer + # + # @return [String] + # + # @api private + # + def type + self.class.type + end + private # Return mutation to kill diff --git a/lib/mutant/killer/forking.rb b/lib/mutant/killer/forking.rb new file mode 100644 index 00000000..b73693af --- /dev/null +++ b/lib/mutant/killer/forking.rb @@ -0,0 +1,38 @@ +module Mutant + class Killer + + class Forked < self + def initialize(killer, mutation) + @killer = killer + super(mutation) + end + + def type + @killer.type + end + + def run + fork do + @killer.new(@mutation) + end + + status = Process.wait2.last + status.exitstatus.zero? + end + end + + class Forking < self + include Equalizer.new(:killer) + + attr_reader :killer + + def initialize(killer) + @killer = killer + end + + def run(mutation) + Forked.new(@killer, mutation) + end + end + end +end diff --git a/lib/mutant/killer/rspec.rb b/lib/mutant/killer/rspec.rb index 1900702f..e92f27d7 100644 --- a/lib/mutant/killer/rspec.rb +++ b/lib/mutant/killer/rspec.rb @@ -2,6 +2,7 @@ module Mutant class Killer # Runner for rspec tests class Rspec < self + TYPE = 'rspec'.freeze # Run block in clean rspec environment # @@ -23,17 +24,6 @@ module Mutant ::RSpec.instance_variable_set(:@configuration, original_configuration) end - # Return identification - # - # @return [String] - # - # @api private - # - def identification - "rspec:#{mutation.identification}".freeze - end - memoize :identification - private # Initialize rspec runner @@ -60,6 +50,7 @@ module Mutant def run !run_rspec.zero? end + memoize :run # Run rspec with some wired compat stuff # @@ -102,24 +93,6 @@ module Mutant def filename_pattern "test_app/spec/**/*_spec.rb" end - - class Forking < self - # Run rspec in subprocess - # - # @return [Fixnum] - # returns the exit status from rspec runner - # - # @api private - # - def run_rspec - p :prefork - fork do - exit run_rspec - end - pid, status = Process.wait2 - status.exitstatus - end - end end end end diff --git a/lib/mutant/runner.rb b/lib/mutant/runner.rb index af2ef623..c72cce2d 100644 --- a/lib/mutant/runner.rb +++ b/lib/mutant/runner.rb @@ -101,7 +101,7 @@ module Mutant # @api private # def kill(mutation) - killer = config.killer.run(mutation) + killer = config.killer.new(mutation) reporter.killer(killer) if killer.fail? @errors << killer