Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Change to improved rspec example selection #1373

Merged
merged 1 commit into from
Apr 30, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 22 additions & 8 deletions lib/mutant/integration/rspec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ def initialize(*)
# @return [self]
def setup
@runner.setup($stderr, $stdout)
example_group_map
reset_examples
self
end
memoize :setup
Expand All @@ -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(
Expand All @@ -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
Expand All @@ -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)
Expand All @@ -119,12 +139,6 @@ def all_examples
end
end

def filter_examples(&predicate)
@rspec_world.filtered_examples.each_value do |examples|
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Per mutation this was for 99% of the examples resulting in the same result: Clearing the array entirely.

examples.keep_if(&predicate)
end
end

end # Rspec
end # Integration
end # Mutant
80 changes: 54 additions & 26 deletions spec/unit/mutant/integration/rspec_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand All @@ -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)
Expand Down Expand Up @@ -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(
Expand All @@ -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(
Expand Down