Add repository diff based subject filter
This commit is contained in:
parent
e3719c4f7d
commit
9fc563a48b
5 changed files with 153 additions and 1 deletions
|
@ -1,3 +1,3 @@
|
||||||
---
|
---
|
||||||
threshold: 18
|
threshold: 18
|
||||||
total_score: 1173
|
total_score: 1189
|
||||||
|
|
|
@ -174,6 +174,7 @@ require 'mutant/reporter/cli/printer/status_progressive'
|
||||||
require 'mutant/reporter/cli/printer/test_result'
|
require 'mutant/reporter/cli/printer/test_result'
|
||||||
require 'mutant/reporter/cli/tput'
|
require 'mutant/reporter/cli/tput'
|
||||||
require 'mutant/reporter/cli/format'
|
require 'mutant/reporter/cli/format'
|
||||||
|
require 'mutant/repository'
|
||||||
require 'mutant/zombifier'
|
require 'mutant/zombifier'
|
||||||
|
|
||||||
module Mutant
|
module Mutant
|
||||||
|
|
66
lib/mutant/repository.rb
Normal file
66
lib/mutant/repository.rb
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
module Mutant
|
||||||
|
module Repository
|
||||||
|
# Error raised on repository interaction problems
|
||||||
|
RepositoryError = Class.new(RuntimeError)
|
||||||
|
|
||||||
|
# Subject filter based on repository diff
|
||||||
|
class SubjectFilter
|
||||||
|
include Adamantium, Concord.new(:diff)
|
||||||
|
|
||||||
|
# Test if subject was touched in diff
|
||||||
|
#
|
||||||
|
# @param [Subject] subject
|
||||||
|
#
|
||||||
|
# @return [Boolean]
|
||||||
|
#
|
||||||
|
# @api private
|
||||||
|
def call(subject)
|
||||||
|
diff.touches?(subject.source_path, subject.source_lines)
|
||||||
|
end
|
||||||
|
|
||||||
|
end # SubjectFilter
|
||||||
|
|
||||||
|
# Diff between two objects in repository
|
||||||
|
class Diff
|
||||||
|
include Adamantium, Concord.new(:from, :to)
|
||||||
|
|
||||||
|
HEAD = 'HEAD'.freeze
|
||||||
|
private_constant(*constants(false))
|
||||||
|
|
||||||
|
# Create diff from head to revision
|
||||||
|
#
|
||||||
|
# @return [Diff]
|
||||||
|
#
|
||||||
|
# @api private
|
||||||
|
def self.from_head(to)
|
||||||
|
new(HEAD, to)
|
||||||
|
end
|
||||||
|
|
||||||
|
# Test if diff changes file at line range
|
||||||
|
#
|
||||||
|
# @param [Pathname] path
|
||||||
|
# @param [Range<Fixnum>] line_range
|
||||||
|
#
|
||||||
|
# @return [Boolean]
|
||||||
|
#
|
||||||
|
# @raise [RepositoryError]
|
||||||
|
# when git command failed
|
||||||
|
#
|
||||||
|
# @api private
|
||||||
|
def touches?(path, line_range)
|
||||||
|
command = %W[
|
||||||
|
git log --pretty=oneline
|
||||||
|
#{from}...#{to}
|
||||||
|
-L #{line_range.begin},#{line_range.end}:#{path}
|
||||||
|
]
|
||||||
|
|
||||||
|
stdout, status = Open3.capture2(*command, binmode: true)
|
||||||
|
|
||||||
|
fail RepositoryError, "Command #{command} failed!" unless status.success?
|
||||||
|
|
||||||
|
!stdout.empty?
|
||||||
|
end
|
||||||
|
|
||||||
|
end # Diff
|
||||||
|
end # Repository
|
||||||
|
end # Mutant
|
57
spec/unit/mutant/repository/diff_spec.rb
Normal file
57
spec/unit/mutant/repository/diff_spec.rb
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
describe Mutant::Repository::Diff do
|
||||||
|
describe '.from_head' do
|
||||||
|
subject { described_class.from_head(to_revision) }
|
||||||
|
|
||||||
|
let(:to_revision) { double('to revision') }
|
||||||
|
|
||||||
|
it { should eql(described_class.new('HEAD', to_revision)) }
|
||||||
|
end
|
||||||
|
|
||||||
|
describe '#touches?' do
|
||||||
|
let(:object) { described_class.new('from_rev', 'to_rev') }
|
||||||
|
let(:path) { Pathname.new('foo.rb') }
|
||||||
|
let(:line_range) { 1..2 }
|
||||||
|
let(:status) { double('Status', success?: success?) }
|
||||||
|
let(:stdout) { double('Stdout', empty?: stdout_empty?) }
|
||||||
|
let(:stdout_empty?) { false }
|
||||||
|
|
||||||
|
subject { object.touches?(path, line_range) }
|
||||||
|
|
||||||
|
before do
|
||||||
|
expect(Open3).to receive(:capture2).with(
|
||||||
|
*expected_command,
|
||||||
|
binmode: true
|
||||||
|
).and_return([stdout, status])
|
||||||
|
end
|
||||||
|
|
||||||
|
let(:expected_command) do
|
||||||
|
%w[
|
||||||
|
git log --pretty=oneline from_rev...to_rev -L 1,2:foo.rb
|
||||||
|
]
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'on failure of git command' do
|
||||||
|
let(:success?) { false }
|
||||||
|
|
||||||
|
it 'raises error' do
|
||||||
|
expect { subject }.to raise_error(Mutant::Repository::RepositoryError, "Command #{expected_command} failed!")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'on suuccess of git command' do
|
||||||
|
let(:success?) { true }
|
||||||
|
|
||||||
|
context 'on empty stdout' do
|
||||||
|
let(:stdout_empty?) { true }
|
||||||
|
|
||||||
|
it { should be(false) }
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'on non empty stdout' do
|
||||||
|
let(:stdout_empty?) { false }
|
||||||
|
|
||||||
|
it { should be(true) }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
28
spec/unit/mutant/repository/subject_filter_spec.rb
Normal file
28
spec/unit/mutant/repository/subject_filter_spec.rb
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
RSpec.describe Mutant::Repository::SubjectFilter do
|
||||||
|
context '#call' do
|
||||||
|
subject { object.call(mutant_subject) }
|
||||||
|
|
||||||
|
let(:object) { described_class.new(diff) }
|
||||||
|
let(:diff) { double('Diff') }
|
||||||
|
let(:return_value) { double('Return Value') }
|
||||||
|
|
||||||
|
let(:mutant_subject) do
|
||||||
|
double(
|
||||||
|
'Subject',
|
||||||
|
source_path: double('source path'),
|
||||||
|
source_lines: double('source lines')
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
before do
|
||||||
|
expect(diff).to receive(:touches?).with(
|
||||||
|
mutant_subject.source_path,
|
||||||
|
mutant_subject.source_lines
|
||||||
|
).and_return(return_value)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'connects return value to repository diff API' do
|
||||||
|
expect(subject).to be(return_value)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
Loading…
Add table
Reference in a new issue