diff --git a/lib/mutant.rb b/lib/mutant.rb index 6246945fe..6b156c6a0 100644 --- a/lib/mutant.rb +++ b/lib/mutant.rb @@ -246,6 +246,7 @@ module Mutant require 'mutant/repository' require 'mutant/repository/diff' require 'mutant/repository/diff/ranges' + require 'mutant/repository/file_revision' require 'mutant/zombifier' require 'mutant/range' require 'mutant/license' @@ -319,6 +320,7 @@ module Mutant mutex: Mutex, object_space: ObjectSpace, open3: Open3, + parser: Parser.new, pathname: Pathname, process: Process, random: Random, diff --git a/lib/mutant/cli/command/environment.rb b/lib/mutant/cli/command/environment.rb index a10194c26..c1fd09748 100644 --- a/lib/mutant/cli/command/environment.rb +++ b/lib/mutant/cli/command/environment.rb @@ -102,11 +102,13 @@ def add_matcher_options(parser) parser.on('--start-subject EXPRESSION', 'Start mutation testing at a specific subject') do |pattern| add_matcher(:start_expressions, @config.expression_parser.call(pattern).from_right) end - parser.on('--since REVISION', 'Only select subjects touched since REVISION') do |revision| + parser.on('--since REVISION', 'Only select dirty subjects since REVISION') do |revision| add_matcher( :subject_filters, Repository::SubjectFilter.new( - Repository::Diff.new(to: revision, world: world) + diff: Repository::Diff.new(to: revision, world: world), + revision: revision, + world: world ) ) end diff --git a/lib/mutant/env.rb b/lib/mutant/env.rb index abc17dc68..a485f0ba5 100644 --- a/lib/mutant/env.rb +++ b/lib/mutant/env.rb @@ -9,7 +9,6 @@ class Env :integration, :matchable_scopes, :mutations, - :parser, :selector, :subjects, :world @@ -37,7 +36,6 @@ def self.empty(world, config) ), matchable_scopes: EMPTY_ARRAY, mutations: EMPTY_ARRAY, - parser: Parser.new, selector: Selector::Null.new, subjects: EMPTY_ARRAY, world: world @@ -64,6 +62,13 @@ def cover_index(mutation_index) ) end + # The parser + # + # @return [Parser] + def parser + world.parser + end + # The test selections # # @return Hash{Mutation => Enumerable} diff --git a/lib/mutant/repository.rb b/lib/mutant/repository.rb index fb1fc3965..dd7f15a7d 100644 --- a/lib/mutant/repository.rb +++ b/lib/mutant/repository.rb @@ -4,7 +4,7 @@ module Mutant module Repository # Subject filter based on repository diff class SubjectFilter - include Adamantium, Concord.new(:diff) + include Adamantium, Anima.new(:diff, :revision, :world) # Test if subject was touched in diff # diff --git a/lib/mutant/repository/file_revision.rb b/lib/mutant/repository/file_revision.rb new file mode 100644 index 000000000..11191502a --- /dev/null +++ b/lib/mutant/repository/file_revision.rb @@ -0,0 +1,12 @@ +# frozen_string_literal: true + +module Mutant + module Repository + class FileRevision + def self.read(world:, revision:, file_name:) + world + .capture_stdout(%w[git show #{revision}:#{file_name}]) + end + end # FileRevision + end # Repository +end # Mutant diff --git a/lib/mutant/world.rb b/lib/mutant/world.rb index 2677735eb..57abae954 100644 --- a/lib/mutant/world.rb +++ b/lib/mutant/world.rb @@ -16,6 +16,7 @@ class World :mutex, :object_space, :open3, + :parser, :pathname, :process, :random, diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 0d07aafcb..fe218d26f 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -114,6 +114,7 @@ def fake_world mutex: class_double(Mutex), object_space: class_double(ObjectSpace), open3: class_double(Open3), + parser: class_double(Mutant::Parser), pathname: class_double(Pathname), process: class_double(Process), random: class_double(Random), diff --git a/spec/unit/mutant/bootstrap_spec.rb b/spec/unit/mutant/bootstrap_spec.rb index 1c77ab7cc..dc4b05778 100644 --- a/spec/unit/mutant/bootstrap_spec.rb +++ b/spec/unit/mutant/bootstrap_spec.rb @@ -56,6 +56,7 @@ def require(_); end kernel: kernel, load_path: load_path, object_space: object_space, + parser: Mutant::Parser.new, pathname: Pathname, recorder: instance_double(Mutant::Segment::Recorder), timer: timer diff --git a/spec/unit/mutant/cli_spec.rb b/spec/unit/mutant/cli_spec.rb index 611fa5fc8..605495ab8 100644 --- a/spec/unit/mutant/cli_spec.rb +++ b/spec/unit/mutant/cli_spec.rb @@ -301,7 +301,7 @@ def self.main_body Matcher: --ignore-subject EXPRESSION Ignore subjects that match EXPRESSION as prefix --start-subject EXPRESSION Start mutation testing at a specific subject - --since REVISION Only select subjects touched since REVISION + --since REVISION Only select dirty subjects since REVISION MESSAGE { @@ -348,7 +348,7 @@ def self.main_body Matcher: --ignore-subject EXPRESSION Ignore subjects that match EXPRESSION as prefix --start-subject EXPRESSION Start mutation testing at a specific subject - --since REVISION Only select subjects touched since REVISION + --since REVISION Only select dirty subjects since REVISION MESSAGE { @@ -395,7 +395,7 @@ def self.main_body Matcher: --ignore-subject EXPRESSION Ignore subjects that match EXPRESSION as prefix --start-subject EXPRESSION Start mutation testing at a specific subject - --since REVISION Only select subjects touched since REVISION + --since REVISION Only select dirty subjects since REVISION MESSAGE { @@ -1290,10 +1290,12 @@ def self.main_body matcher: file_config.matcher.with( subject_filters: [ Mutant::Repository::SubjectFilter.new( - Mutant::Repository::Diff.new( + diff: Mutant::Repository::Diff.new( to: 'reference', world: world - ) + ), + revision: 'reference', + world: world ) ] ) @@ -1305,10 +1307,12 @@ def self.main_body matcher: file_config.matcher.with( subject_filters: [ Mutant::Repository::SubjectFilter.new( - Mutant::Repository::Diff.new( + diff: Mutant::Repository::Diff.new( to: 'reference', world: world - ) + ), + revision: 'reference', + world: world ) ] ) diff --git a/spec/unit/mutant/env_spec.rb b/spec/unit/mutant/env_spec.rb index 1feb011d8..58f4b618d 100644 --- a/spec/unit/mutant/env_spec.rb +++ b/spec/unit/mutant/env_spec.rb @@ -8,7 +8,6 @@ integration: integration, matchable_scopes: [], mutations: [mutation], - parser: Mutant::Parser.new, selector: selector, subjects: subjects, world: world @@ -239,7 +238,6 @@ def apply integration: integration, matchable_scopes: Mutant::EMPTY_ARRAY, mutations: Mutant::EMPTY_ARRAY, - parser: Mutant::Parser.new, selector: Mutant::Selector::Null.new, subjects: Mutant::EMPTY_ARRAY, world: world @@ -268,4 +266,10 @@ def apply expect(events).to eql([%i[test_segment value]]) end end + + describe '#parser' do + it 'returns the world parser' do + expect(subject.parser).to be(world.parser) + end + end end diff --git a/spec/unit/mutant/repository/subject_filter_spec.rb b/spec/unit/mutant/repository/subject_filter_spec.rb index 797911cb3..608742665 100644 --- a/spec/unit/mutant/repository/subject_filter_spec.rb +++ b/spec/unit/mutant/repository/subject_filter_spec.rb @@ -2,11 +2,19 @@ RSpec.describe Mutant::Repository::SubjectFilter do context '#call' do - subject { object.call(mutant_subject) } + def apply + subject.call(mutant_subject) + end - let(:object) { described_class.new(diff) } - let(:diff) { instance_double(Mutant::Repository::Diff) } - let(:value) { instance_double(Object, 'value') } + subject do + described_class.new( + diff: diff, + revision: 'revision', + world: fake_world + ) + end + + let(:diff) { instance_double(Mutant::Repository::Diff) } let(:mutant_subject) do double( @@ -20,11 +28,15 @@ expect(diff).to receive(:touches?).with( mutant_subject.source_path, mutant_subject.source_lines - ).and_return(value) + ).and_return(touches?) end - it 'connects return value to repository diff API' do - expect(subject).to be(value) + context 'when subject lines are not touched' do + let(:touches?) { false } + + it 'returns false' do + expect(apply).to be(false) + end end end end