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

Add constant cover expressions to minitest #1204

Merged
merged 2 commits into from
Jan 4, 2021
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
8 changes: 7 additions & 1 deletion Changelog.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,15 @@
# v0.10.25 2021-01-02-03
# Unreleased

* [#1204](https://github.com/mbj/mutant/pull/1204)
* Allow constants to be passed to minitst integrations `cover` declaration.
`cover SomeClass` is equivalent to `cover 'SomeClass*'`.

* [#1194](https://github.com/mbj/mutant/pull/1194)

* Add mutation from named capturing group to non-capturing group: `/(?<foo>bar)/` -> `/(?:bar)`.

# v0.10.25 2021-01-03

* [#1198](https://github.com/mbj/mutant/pull/1198)

* Fix configured match expression loading to properly display error
Expand Down
3 changes: 2 additions & 1 deletion docs/mutant-minitest.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,8 @@ To add mutant to your minitest code base you need to:

```ruby
class YourLibrarySomeClassTest < YourTestBaseClass
cover 'YourLibrary::SomeClass*' # tells mutant which subjects this tests should cover
cover YourLibrary::SomeClass # tells mutant which subjects this tests should cover
Copy link
Owner Author

Choose a reason for hiding this comment

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

@pawelpacana I hope this makes sense for many of your use cases?

cover 'YourLibrary::SomeClass#some_method' # alternative for more fine grained control.
# ...
```

Expand Down
2 changes: 1 addition & 1 deletion lib/mutant/env.rb
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ def self.empty(world, config)
config: config,
integration: Integration::Null.new(
expression_parser: config.expression_parser,
timer: world.timer
world: world
),
matchable_scopes: EMPTY_ARRAY,
mutations: EMPTY_ARRAY,
Expand Down
10 changes: 8 additions & 2 deletions lib/mutant/integration.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ module Mutant

# Abstract base class mutant test framework integrations
class Integration
include AbstractType, Adamantium::Flat, Anima.new(:expression_parser, :timer)
include AbstractType, Adamantium::Flat, Anima.new(:expression_parser, :world)

LOAD_MESSAGE = <<~'MESSAGE'
Unable to load integration mutant-%<integration_name>s:
Expand Down Expand Up @@ -39,7 +39,7 @@ def self.setup(env)
attempt_require(env).bind { attempt_const_get(env) }.fmap do |klass|
klass.new(
expression_parser: env.config.expression_parser,
timer: env.world.timer
world: env.world
).setup
end
end
Expand Down Expand Up @@ -92,5 +92,11 @@ def setup
#
# @return [Enumerable<Test>]
abstract_method :all_tests

private

def timer
world.timer
end
end # Integration
end # Mutant
19 changes: 15 additions & 4 deletions lib/mutant/integration/minitest.rb
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,19 @@ def call(reporter)
#
# @return [Array<Expression>]
def expressions(parser)
klass.resolve_cover_expressions.map do |syntax|
parser.call(syntax).from_right
klass.resolve_cover_expressions.to_a.map do |value|
parser.call(expand_constant(value)).from_right
end
end

private

def expand_constant(value)
case value
when Class, Module
"#{value.name}*"
else
value
end
end
end # TestCase
Expand All @@ -69,7 +80,7 @@ def expressions(parser)
def setup
Pathname.glob(TEST_FILE_PATTERN)
.map(&:to_s)
.each(&method(:require))
.each(&world.kernel.method(:require))

self
end
Expand Down Expand Up @@ -133,7 +144,7 @@ def all_test_cases
end

def allow_runnable?(klass)
!klass.equal?(::Minitest::Runnable) && klass.resolve_cover_expressions
!klass.equal?(::Minitest::Runnable)
end

def test_case(runnable)
Expand Down
10 changes: 5 additions & 5 deletions lib/mutant/integration/rspec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@ class Rspec < self
# @return [undefined]
def initialize(*)
super
@runner = RSpec::Core::Runner.new(RSpec::Core::ConfigurationOptions.new(CLI_OPTIONS))
@world = RSpec.world
@runner = RSpec::Core::Runner.new(RSpec::Core::ConfigurationOptions.new(CLI_OPTIONS))
@rspec_world = RSpec.world
end

# Setup rspec integration
Expand All @@ -56,7 +56,7 @@ def call(tests)
examples = tests.map(&all_tests_index)
filter_examples(&examples.public_method(:include?))
start = timer.now
passed = @runner.run_specs(@world.ordered_example_groups).equal?(EXIT_SUCCESS)
passed = @runner.run_specs(@rspec_world.ordered_example_groups).equal?(EXIT_SUCCESS)
Result::Test.new(
passed: passed,
runtime: timer.now - start
Expand Down Expand Up @@ -114,13 +114,13 @@ def parse_expression(input, &default)
end

def all_examples
@world.example_groups.flat_map(&:descendants).flat_map(&:examples).select do |example|
@rspec_world.example_groups.flat_map(&:descendants).flat_map(&:examples).select do |example|
example.metadata.fetch(:mutant, true)
end
end

def filter_examples(&predicate)
@world.filtered_examples.each_value do |examples|
@rspec_world.filtered_examples.each_value do |examples|
examples.keep_if(&predicate)
end
end
Expand Down
19 changes: 5 additions & 14 deletions spec/unit/mutant/env_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@

let(:integration_class) { Mutant::Integration::Null }
let(:isolation) { Mutant::Isolation::None.new }
let(:kernel) { instance_double(Object, 'kernel') }
let(:process_status) { instance_double(Process::Status) }
let(:reporter) { instance_double(Mutant::Reporter) }
let(:selector) { instance_double(Mutant::Selector) }
Expand All @@ -26,7 +25,7 @@
let(:test_a) { instance_double(Mutant::Test, :a) }
let(:test_b) { instance_double(Mutant::Test, :b) }
let(:test_c) { instance_double(Mutant::Test, :c) }
let(:timer) { instance_double(Mutant::Timer) }
let(:world) { fake_world }

let(:integration) do
instance_double(Mutant::Integration, all_tests: [test_a, test_b, test_c])
Expand All @@ -50,14 +49,6 @@
)
end

let(:world) do
instance_double(
Mutant::World,
kernel: kernel,
timer: timer
)
end

before do
allow(selector).to receive(:call)
.with(subject_a)
Expand All @@ -67,7 +58,7 @@
.with(subject_b)
.and_return([test_b, test_c])

allow(timer).to receive(:now).and_return(2.0, 3.0)
allow(world.timer).to receive(:now).and_return(2.0, 3.0)
end

def isolation_success(value)
Expand Down Expand Up @@ -120,7 +111,7 @@ def apply
apply

expect(isolation).to have_received(:call).ordered.with(config.mutation_timeout)
expect(mutation).to have_received(:insert).ordered.with(kernel)
expect(mutation).to have_received(:insert).ordered.with(world.kernel)
expect(integration).to have_received(:call).ordered.with([test_a, test_b])
end

Expand All @@ -138,7 +129,7 @@ def apply
apply

expect(isolation).to have_received(:call).ordered
expect(mutation).to have_received(:insert).ordered.with(kernel)
expect(mutation).to have_received(:insert).ordered.with(world.kernel)
end

include_examples 'mutation kill'
Expand Down Expand Up @@ -228,7 +219,7 @@ def apply
it 'returns empty env' do
integration = Mutant::Integration::Null.new(
expression_parser: config.expression_parser,
timer: timer
world: world
)

expect(apply).to eql(
Expand Down
9 changes: 5 additions & 4 deletions spec/unit/mutant/integration/rspec_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,13 @@
let(:object) do
described_class.new(
expression_parser: Mutant::Config::DEFAULT.expression_parser,
timer: timer
world: world
)
end

let(:rspec_options) { instance_double(RSpec::Core::ConfigurationOptions) }
let(:rspec_runner) { instance_double(RSpec::Core::Runner) }
let(:timer) { instance_double(Mutant::Timer) }
let(:world) { fake_world }

let(:example_a) do
double(
Expand Down Expand Up @@ -107,7 +107,7 @@

let(:rspec_world) do
double(
'world',
'rspec-world',
example_groups: example_groups,
filtered_examples: filtered_examples
)
Expand Down Expand Up @@ -148,7 +148,8 @@
.and_return(rspec_runner)

expect(RSpec).to receive_messages(world: rspec_world)
allow(timer).to receive_messages(now: 1.0)

allow(world.timer).to receive_messages(now: 1.0)
end

describe '#all_tests' do
Expand Down
23 changes: 7 additions & 16 deletions spec/unit/mutant/integration_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@
let(:object) do
Class.new(described_class).new(
expression_parser: expression_parser,
timer: timer
world: world
)
end

let(:expression_parser) { instance_double(Mutant::Expression::Parser) }
let(:timer) { instance_double(Mutant::Timer) }
let(:world) { fake_world }

describe '#setup' do
def apply
Expand All @@ -26,7 +26,6 @@ def apply
described_class.setup(env)
end

let(:kernel) { class_double(Kernel) }
let(:integration) { instance_double(Mutant::Integration::Null) }
let(:integration_name) { 'null' }

Expand All @@ -46,16 +45,8 @@ def apply
)
end

let(:world) do
instance_double(
Mutant::World,
kernel: kernel,
timer: timer
)
end

before do
allow(kernel).to receive_messages(require: undefined)
allow(world.kernel).to receive_messages(require: undefined)
allow(described_class).to receive_messages(const_get: described_class::Null)
allow(described_class::Null).to receive_messages(new: integration)
allow(integration).to receive_messages(setup: integration)
Expand All @@ -76,7 +67,7 @@ def apply
let(:exception) { LoadError.new('some-load-error') }

before do
allow(kernel).to receive(:require).and_raise(exception)
allow(world.kernel).to receive(:require).and_raise(exception)
end

it 'returns error' do
Expand Down Expand Up @@ -108,7 +99,7 @@ def apply
it 'performs actions in expected sequence' do
apply

expect(kernel)
expect(world.kernel)
.to have_received(:require)
.with('mutant/integration/null')
.ordered
Expand Down Expand Up @@ -140,12 +131,12 @@ def apply
let(:object) do
described_class.new(
expression_parser: expression_parser,
timer: timer
world: world
)
end

let(:expression_parser) { instance_double(Mutant::Expression::Parser) }
let(:timer) { instance_double(Mutant::Timer) }
let(:world) { fake_world }

describe '#all_tests' do
subject { object.all_tests }
Expand Down