Add repository diff based subject filter

This commit is contained in:
Markus Schirp 2015-07-13 01:06:39 +00:00
parent e3719c4f7d
commit 9fc563a48b
5 changed files with 153 additions and 1 deletions

View file

@ -1,3 +1,3 @@
---
threshold: 18
total_score: 1173
total_score: 1189

View file

@ -174,6 +174,7 @@ require 'mutant/reporter/cli/printer/status_progressive'
require 'mutant/reporter/cli/printer/test_result'
require 'mutant/reporter/cli/tput'
require 'mutant/reporter/cli/format'
require 'mutant/repository'
require 'mutant/zombifier'
module Mutant

66
lib/mutant/repository.rb Normal file
View 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

View 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

View 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