diff --git a/lib/mutant/integration/rspec.rb b/lib/mutant/integration/rspec.rb index abe5e92dd..0172f500e 100644 --- a/lib/mutant/integration/rspec.rb +++ b/lib/mutant/integration/rspec.rb @@ -43,6 +43,8 @@ def initialize(*) # @return [self] def setup @runner.setup($stderr, $stdout) + example_group_map + reset_examples self end memoize :setup @@ -53,8 +55,7 @@ def setup # # @return [Result::Test] def call(tests) - examples = tests.map(&all_tests_index) - filter_examples(&examples.public_method(:include?)) + setup_examples(tests.map(&all_tests_index)) start = timer.now passed = @runner.run_specs(@rspec_world.ordered_example_groups).equal?(EXIT_SUCCESS) Result::Test.new( @@ -73,6 +74,16 @@ def all_tests private + def reset_examples + @rspec_world.filtered_examples.each_value(&:clear) + end + + def setup_examples(examples) + examples.each do |example| + @rspec_world.filtered_examples.fetch(example_group_map.fetch(example)) << example + end + end + def all_tests_index all_examples.each_with_index.with_object({}) do |(example, example_index), index| index[parse_example(example, example_index)] = example @@ -95,6 +106,15 @@ def parse_example(example, index) ) end + def example_group_map + @rspec_world.example_groups.flat_map(&:descendants).each_with_object({}) do |example_group, map| + example_group.examples.each do |example| + map[example] = example_group + end + end + end + memoize :example_group_map + def parse_metadata(metadata) if metadata.key?(:mutant_expression) expression = metadata.fetch(:mutant_expression) @@ -119,12 +139,6 @@ def all_examples end end - def filter_examples(&predicate) - @rspec_world.filtered_examples.each_value do |examples| - examples.keep_if(&predicate) - end - end - end # Rspec end # Integration end # Mutant diff --git a/spec/unit/mutant/integration/rspec_spec.rb b/spec/unit/mutant/integration/rspec_spec.rb index 07ab04070..a0f76d6fb 100644 --- a/spec/unit/mutant/integration/rspec_spec.rb +++ b/spec/unit/mutant/integration/rspec_spec.rb @@ -77,42 +77,44 @@ ) end - let(:examples) do - [ - example_a, - example_b, - example_c, - example_d, - example_e, - example_f - ] + let(:leaf_example_group) do + class_double( + RSpec::Core::ExampleGroup, + 'leaf example group', + examples: [example_a, example_b, example_c, example_d, example_e, example_f] + ) + end + + let(:root_example_group) do + class_double( + RSpec::Core::ExampleGroup, + 'root example group', + examples: [] + ) end let(:example_groups) do - [ - double( - 'root example group', - descendants: [ - double('example group', examples: examples) - ] - ) - ] + [root_example_group] end let(:filtered_examples) do { - double('Key') => examples.dup + root_example_group => root_example_group.examples.dup, + leaf_example_group => leaf_example_group.examples.dup } end let(:rspec_world) do - double( - 'rspec-world', - example_groups: example_groups, - filtered_examples: filtered_examples + instance_double( + RSpec::Core::World, + example_groups: example_groups, + filtered_examples: filtered_examples, + ordered_example_groups: ordered_example_groups ) end + let(:ordered_example_groups) { double('ordered_example_groups') } + let(:all_tests) do [ Mutant::Test.new( @@ -139,6 +141,10 @@ end before do + allow(root_example_group).to receive_messages( + descendants: [root_example_group, leaf_example_group] + ) + expect(RSpec::Core::ConfigurationOptions).to receive(:new) .with(%w[spec --fail-fast]) .and_return(rspec_options) @@ -172,20 +178,40 @@ end describe '#call' do - subject { object.call(tests) } + subject { object.setup; object.call(tests) } let(:tests) { [all_tests.fetch(0)] } before do - expect(rspec_world).to receive(:ordered_example_groups) do - filtered_examples.values.flatten + expect(rspec_runner).to receive(:setup) do |error, stdout| + expect(error).to be($stderr) + expect(stdout).to be($stdout) + end + allow(rspec_runner).to receive_messages(run_specs: exit_status) + end + + shared_examples '#call' do + it 'calls rspec runner with ordeded examples' do + subject + + expect(rspec_runner).to have_received(:run_specs).with(ordered_example_groups) + end + + it 'modifies filtered examples to selection' do + subject + + expect(filtered_examples).to eql( + root_example_group => [], + leaf_example_group => [example_a] + ) end - expect(rspec_runner).to receive(:run_specs).with([example_a]).and_return(exit_status) end context 'on unsuccessful exit' do let(:exit_status) { 1 } + include_examples '#call' + it 'should return failed result' do expect(subject).to eql( Mutant::Result::Test.new( @@ -199,6 +225,8 @@ context 'on successful exit' do let(:exit_status) { 0 } + include_examples '#call' + it 'should return passed result' do expect(subject).to eql( Mutant::Result::Test.new(