Merge pull request #348 from mbj/fix/remove-deprecated-cli-option
Remove deprecated --score option
This commit is contained in:
commit
875ab5c536
6 changed files with 233 additions and 234 deletions
|
@ -2,6 +2,7 @@
|
|||
|
||||
* Drop support for ruby < 2.1
|
||||
* Remove broken `--code` option
|
||||
* Remove deprecated `--score` option
|
||||
|
||||
# v0.7.9 2015-05-30
|
||||
|
||||
|
|
|
@ -149,9 +149,6 @@ module Mutant
|
|||
) do |coverage|
|
||||
update(expected_coverage: Rational(coverage))
|
||||
end
|
||||
opts.on('--score COVERAGE', 'Fail unless COVERAGE is not reached exactly [deprecated]') do |coverage|
|
||||
update(expected_coverage: Rational(coverage, 100))
|
||||
end
|
||||
opts.on('--use INTEGRATION', 'Use INTEGRATION to kill mutations', &method(:setup_integration))
|
||||
end
|
||||
|
||||
|
|
|
@ -5,13 +5,13 @@ RSpec.describe 'Mutant on ruby corpus', mutant: false do
|
|||
skip 'Corpus test is deactivated on RBX' if RUBY_ENGINE.eql?('rbx')
|
||||
end
|
||||
|
||||
Corpus::Project::ALL.select(&:mutation_generation).each do |project|
|
||||
MutantSpec::Corpus::Project::ALL.select(&:mutation_generation).each do |project|
|
||||
specify "#{project.name} does not fail on mutation generation" do
|
||||
project.verify_mutation_generation
|
||||
end
|
||||
end
|
||||
|
||||
Corpus::Project::ALL.select(&:mutation_coverage).each do |project|
|
||||
MutantSpec::Corpus::Project::ALL.select(&:mutation_coverage).each do |project|
|
||||
specify "#{project.name} does have expected mutation coverage" do
|
||||
project.verify_mutation_coverage
|
||||
end
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
repo_uri: 'https://github.com/rubyspec/rubyspec.git'
|
||||
mutation_coverage: false
|
||||
mutation_generation: true
|
||||
expect_coverage: 0.0 # not run
|
||||
expect_coverage: 0 # not run
|
||||
exclude:
|
||||
# Binary encoded source subjected to limitations see README of unparser
|
||||
- core/array/pack/{b,h,u}_spec.rb
|
||||
|
@ -31,11 +31,11 @@
|
|||
mutation_coverage: true
|
||||
mutation_generation: true
|
||||
exclude: []
|
||||
expect_coverage: 100.0
|
||||
expect_coverage: 1
|
||||
- name: axiom
|
||||
namespace: Axiom
|
||||
repo_uri: 'https://github.com/dkubb/axiom.git'
|
||||
mutation_coverage: false
|
||||
mutation_generation: true
|
||||
exclude: []
|
||||
expect_coverage: 100.0
|
||||
expect_coverage: 1
|
||||
|
|
|
@ -2,241 +2,253 @@ require 'morpher'
|
|||
require 'anima'
|
||||
require 'mutant'
|
||||
|
||||
# Namespace module for corpus testing
|
||||
module Corpus
|
||||
# Project under corpus test
|
||||
# rubocop:disable ClassLength
|
||||
ROOT = Pathname.new(__FILE__).parent.parent.parent
|
||||
TMP = ROOT.join('tmp').freeze
|
||||
module MutantSpec
|
||||
# Namespace module for corpus testing
|
||||
#
|
||||
# rubocop:disable MethodLength
|
||||
module Corpus
|
||||
# Project under corpus test
|
||||
# rubocop:disable ClassLength
|
||||
ROOT = Pathname.new(__FILE__).parent.parent.parent
|
||||
TMP = ROOT.join('tmp').freeze
|
||||
|
||||
class Project
|
||||
MUTEX = Mutex.new
|
||||
include Adamantium, Anima.new(
|
||||
:name,
|
||||
:repo_uri,
|
||||
:exclude,
|
||||
:mutation_coverage,
|
||||
:mutation_generation,
|
||||
:namespace,
|
||||
:expect_coverage
|
||||
)
|
||||
|
||||
# Verify mutation coverage
|
||||
#
|
||||
# @return [self]
|
||||
# if successful
|
||||
#
|
||||
# @raise [Exception]
|
||||
#
|
||||
def verify_mutation_coverage
|
||||
checkout
|
||||
Dir.chdir(repo_path) do
|
||||
Bundler.with_clean_env do
|
||||
install_mutant
|
||||
system(%W[bundle exec mutant --use rspec -I lib -r #{name} --score #{expect_coverage} #{namespace}*])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Verify mutation generation
|
||||
#
|
||||
# @return [self]
|
||||
# if successful
|
||||
#
|
||||
# @raise [Exception]
|
||||
# otherwise
|
||||
#
|
||||
# rubocop:disable MethodLength
|
||||
# rubocop:disable AbcSize
|
||||
#
|
||||
def verify_mutation_generation
|
||||
checkout
|
||||
start = Time.now
|
||||
paths = Pathname.glob(repo_path.join('**/*.rb')).sort_by(&:size).reverse
|
||||
options = {
|
||||
finish: method(:finish),
|
||||
start: method(:start),
|
||||
in_processes: parallel_processes
|
||||
}
|
||||
total = Parallel.map(paths, options) do |path|
|
||||
count = 0
|
||||
node =
|
||||
begin
|
||||
Parser::CurrentRuby.parse(path.read)
|
||||
rescue EncodingError, ArgumentError
|
||||
nil # Make rubocop happy
|
||||
end
|
||||
if node
|
||||
Mutant::Mutator::Node.each(node) do
|
||||
count += 1
|
||||
end
|
||||
end
|
||||
count
|
||||
end.inject(0, :+)
|
||||
took = Time.now - start
|
||||
puts format(
|
||||
'Total Mutations/Time/Parse-Errors: %s/%0.2fs - %0.2f/s',
|
||||
total,
|
||||
took,
|
||||
total / took
|
||||
class Project
|
||||
MUTEX = Mutex.new
|
||||
include Adamantium, Anima.new(
|
||||
:name,
|
||||
:repo_uri,
|
||||
:exclude,
|
||||
:mutation_coverage,
|
||||
:mutation_generation,
|
||||
:namespace,
|
||||
:expect_coverage
|
||||
)
|
||||
self
|
||||
end
|
||||
|
||||
# Checkout repository
|
||||
#
|
||||
# @return [self]
|
||||
#
|
||||
# @api private
|
||||
#
|
||||
def checkout
|
||||
return self if noinstall?
|
||||
TMP.mkdir unless TMP.directory?
|
||||
if repo_path.exist?
|
||||
# Verify mutation coverage
|
||||
#
|
||||
# @return [self]
|
||||
# if successful
|
||||
#
|
||||
# @raise [Exception]
|
||||
#
|
||||
def verify_mutation_coverage
|
||||
checkout
|
||||
Dir.chdir(repo_path) do
|
||||
system(%w[git fetch origin])
|
||||
system(%w[git reset --hard])
|
||||
system(%w[git clean -f -d -x])
|
||||
system(%w[git checkout origin/master])
|
||||
system(%w[git reset --hard])
|
||||
system(%w[git clean -f -d -x])
|
||||
Bundler.with_clean_env do
|
||||
install_mutant
|
||||
system(
|
||||
%W[
|
||||
bundle exec mutant
|
||||
--use rspec
|
||||
--include lib
|
||||
--require #{name}
|
||||
--expected-coverage #{expect_coverage}
|
||||
#{namespace}*
|
||||
]
|
||||
)
|
||||
end
|
||||
end
|
||||
else
|
||||
system(%W[git clone #{repo_uri} #{repo_path}])
|
||||
end
|
||||
self
|
||||
end
|
||||
memoize :checkout
|
||||
|
||||
private
|
||||
|
||||
# Install mutant
|
||||
#
|
||||
# @return [undefined]
|
||||
#
|
||||
# @api private
|
||||
#
|
||||
def install_mutant
|
||||
return if noinstall?
|
||||
relative = ROOT.relative_path_from(repo_path)
|
||||
repo_path.join('Gemfile').open('a') do |file|
|
||||
file << "gem 'mutant', path: '#{relative}'\n"
|
||||
file << "gem 'mutant-rspec', path: '#{relative}'\n"
|
||||
# Verify mutation generation
|
||||
#
|
||||
# @return [self]
|
||||
# if successful
|
||||
#
|
||||
# @raise [Exception]
|
||||
# otherwise
|
||||
#
|
||||
# rubocop:disable AbcSize
|
||||
#
|
||||
def verify_mutation_generation
|
||||
checkout
|
||||
start = Time.now
|
||||
paths = Pathname.glob(repo_path.join('**/*.rb')).sort_by(&:size).reverse
|
||||
options = {
|
||||
finish: method(:finish),
|
||||
start: method(:start),
|
||||
in_processes: parallel_processes
|
||||
}
|
||||
total = Parallel.map(paths, options) do |path|
|
||||
count = 0
|
||||
node =
|
||||
begin
|
||||
Parser::CurrentRuby.parse(path.read)
|
||||
rescue EncodingError, ArgumentError
|
||||
nil # Make rubocop happy
|
||||
end
|
||||
if node
|
||||
Mutant::Mutator::Node.each(node) do
|
||||
count += 1
|
||||
end
|
||||
end
|
||||
count
|
||||
end.inject(0, :+)
|
||||
took = Time.now - start
|
||||
puts format(
|
||||
'Total Mutations/Time/Parse-Errors: %s/%0.2fs - %0.2f/s',
|
||||
total,
|
||||
took,
|
||||
total / took
|
||||
)
|
||||
self
|
||||
end
|
||||
lockfile = repo_path.join('Gemfile.lock')
|
||||
lockfile.delete if lockfile.exist?
|
||||
system('bundle install')
|
||||
end
|
||||
|
||||
# Not in the docs. Number from chatting with their support.
|
||||
CIRCLE_CI_CONTAINER_PROCESSES = 2
|
||||
|
||||
# Return number of parallel processes to use
|
||||
#
|
||||
# @return [Fixnum]
|
||||
#
|
||||
# @api private
|
||||
#
|
||||
def parallel_processes
|
||||
if ENV['CI']
|
||||
Mutant::Config::DEFAULT.jobs
|
||||
else
|
||||
Parallel.processor_count
|
||||
# Checkout repository
|
||||
#
|
||||
# @return [self]
|
||||
#
|
||||
# @api private
|
||||
#
|
||||
def checkout
|
||||
return self if noinstall?
|
||||
TMP.mkdir unless TMP.directory?
|
||||
if repo_path.exist?
|
||||
Dir.chdir(repo_path) do
|
||||
system(%w[git fetch origin])
|
||||
system(%w[git reset --hard])
|
||||
system(%w[git clean -f -d -x])
|
||||
system(%w[git checkout origin/master])
|
||||
system(%w[git reset --hard])
|
||||
system(%w[git clean -f -d -x])
|
||||
end
|
||||
else
|
||||
system(%W[git clone #{repo_uri} #{repo_path}])
|
||||
end
|
||||
self
|
||||
end
|
||||
end
|
||||
memoize :checkout
|
||||
|
||||
# Return repository path
|
||||
#
|
||||
# @return [Pathname]
|
||||
#
|
||||
# @api private
|
||||
#
|
||||
def repo_path
|
||||
TMP.join(name)
|
||||
end
|
||||
private
|
||||
|
||||
# Test if installation should be skipped
|
||||
#
|
||||
# @return [Boolean]
|
||||
#
|
||||
# @api private
|
||||
#
|
||||
def noinstall?
|
||||
ENV.key?('NOINSTALL')
|
||||
end
|
||||
|
||||
# Print start progress
|
||||
#
|
||||
# @param [Pathname] path
|
||||
# @param [Fixnum] _index
|
||||
#
|
||||
# @return [undefined]
|
||||
#
|
||||
def start(path, _index)
|
||||
MUTEX.synchronize do
|
||||
puts format('Starting - %s', path)
|
||||
# Install mutant
|
||||
#
|
||||
# @return [undefined]
|
||||
#
|
||||
# @api private
|
||||
#
|
||||
def install_mutant
|
||||
return if noinstall?
|
||||
relative = ROOT.relative_path_from(repo_path)
|
||||
repo_path.join('Gemfile').open('a') do |file|
|
||||
file << "gem 'mutant', path: '#{relative}'\n"
|
||||
file << "gem 'mutant-rspec', path: '#{relative}'\n"
|
||||
end
|
||||
lockfile = repo_path.join('Gemfile.lock')
|
||||
lockfile.delete if lockfile.exist?
|
||||
system('bundle install')
|
||||
end
|
||||
end
|
||||
|
||||
# Print finish progress
|
||||
#
|
||||
# @param [Pathname] path
|
||||
# @param [Fixnum] _index
|
||||
# @param [Fixnum] count
|
||||
#
|
||||
# @return [undefined]
|
||||
#
|
||||
def finish(path, _index, count)
|
||||
MUTEX.synchronize do
|
||||
puts format('Mutations - %4i - %s', count, path)
|
||||
# Not in the docs. Number from chatting with their support.
|
||||
CIRCLE_CI_CONTAINER_PROCESSES = 2
|
||||
|
||||
# Return number of parallel processes to use
|
||||
#
|
||||
# @return [Fixnum]
|
||||
#
|
||||
# @api private
|
||||
#
|
||||
def parallel_processes
|
||||
if ENV['CI']
|
||||
Mutant::Config::DEFAULT.jobs
|
||||
else
|
||||
Parallel.processor_count
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Helper method to execute system commands
|
||||
#
|
||||
# @param [Array<String>] arguments
|
||||
#
|
||||
# @api private
|
||||
#
|
||||
def system(arguments)
|
||||
return if Kernel.system(*arguments)
|
||||
if block_given?
|
||||
yield
|
||||
else
|
||||
fail 'System command failed!'
|
||||
# Return repository path
|
||||
#
|
||||
# @return [Pathname]
|
||||
#
|
||||
# @api private
|
||||
#
|
||||
def repo_path
|
||||
TMP.join(name)
|
||||
end
|
||||
end
|
||||
|
||||
# rubocop:disable ClosingParenthesisIndentation
|
||||
LOADER = Morpher.build do
|
||||
s(:block,
|
||||
s(:guard, s(:primitive, Array)),
|
||||
s(:map,
|
||||
s(:block,
|
||||
s(:guard, s(:primitive, Hash)),
|
||||
s(:hash_transform,
|
||||
s(:key_symbolize, :repo_uri, s(:guard, s(:primitive, String))),
|
||||
s(:key_symbolize, :name, s(:guard, s(:primitive, String))),
|
||||
s(:key_symbolize, :namespace, s(:guard, s(:primitive, String))),
|
||||
s(:key_symbolize, :expect_coverage, s(:guard, s(:primitive, Float))),
|
||||
s(:key_symbolize, :mutation_coverage,
|
||||
s(:guard, s(:or, s(:primitive, TrueClass), s(:primitive, FalseClass)))),
|
||||
s(:key_symbolize, :mutation_generation,
|
||||
s(:guard, s(:or, s(:primitive, TrueClass), s(:primitive, FalseClass)))),
|
||||
s(:key_symbolize, :exclude, s(:map, s(:guard, s(:primitive, String))))
|
||||
),
|
||||
s(:load_attribute_hash,
|
||||
# NOTE: The domain param has no DSL currently!
|
||||
Morpher::Evaluator::Transformer::Domain::Param.new(
|
||||
Project,
|
||||
%i[repo_uri name exclude mutation_coverage mutation_generation]
|
||||
# Test if installation should be skipped
|
||||
#
|
||||
# @return [Boolean]
|
||||
#
|
||||
# @api private
|
||||
#
|
||||
def noinstall?
|
||||
ENV.key?('NOINSTALL')
|
||||
end
|
||||
|
||||
# Print start progress
|
||||
#
|
||||
# @param [Pathname] path
|
||||
# @param [Fixnum] _index
|
||||
#
|
||||
# @return [undefined]
|
||||
#
|
||||
def start(path, _index)
|
||||
MUTEX.synchronize do
|
||||
puts format('Starting - %s', path)
|
||||
end
|
||||
end
|
||||
|
||||
# Print finish progress
|
||||
#
|
||||
# @param [Pathname] path
|
||||
# @param [Fixnum] _index
|
||||
# @param [Fixnum] count
|
||||
#
|
||||
# @return [undefined]
|
||||
#
|
||||
def finish(path, _index, count)
|
||||
MUTEX.synchronize do
|
||||
puts format('Mutations - %4i - %s', count, path)
|
||||
end
|
||||
end
|
||||
|
||||
# Helper method to execute system commands
|
||||
#
|
||||
# @param [Array<String>] arguments
|
||||
#
|
||||
# @api private
|
||||
#
|
||||
def system(arguments)
|
||||
return if Kernel.system(*arguments)
|
||||
if block_given?
|
||||
yield
|
||||
else
|
||||
fail 'System command failed!'
|
||||
end
|
||||
end
|
||||
|
||||
# rubocop:disable ClosingParenthesisIndentation
|
||||
LOADER = Morpher.build do
|
||||
s(:block,
|
||||
s(:guard, s(:primitive, Array)),
|
||||
s(:map,
|
||||
s(:block,
|
||||
s(:guard, s(:primitive, Hash)),
|
||||
s(:hash_transform,
|
||||
s(:key_symbolize, :repo_uri, s(:guard, s(:primitive, String))),
|
||||
s(:key_symbolize, :name, s(:guard, s(:primitive, String))),
|
||||
s(:key_symbolize, :namespace, s(:guard, s(:primitive, String))),
|
||||
s(:key_symbolize, :expect_coverage, s(:guard, s(:primitive, Fixnum))),
|
||||
s(:key_symbolize, :mutation_coverage,
|
||||
s(:guard, s(:or, s(:primitive, TrueClass), s(:primitive, FalseClass)))),
|
||||
s(:key_symbolize, :mutation_generation,
|
||||
s(:guard, s(:or, s(:primitive, TrueClass), s(:primitive, FalseClass)))),
|
||||
s(:key_symbolize, :exclude, s(:map, s(:guard, s(:primitive, String))))
|
||||
),
|
||||
s(:load_attribute_hash,
|
||||
# NOTE: The domain param has no DSL currently!
|
||||
Morpher::Evaluator::Transformer::Domain::Param.new(
|
||||
Project,
|
||||
%i[repo_uri name exclude mutation_coverage mutation_generation]
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
ALL = LOADER.call(YAML.load_file(ROOT.join('spec', 'integrations.yml')))
|
||||
end # Project
|
||||
end # Corpus
|
||||
ALL = LOADER.call(YAML.load_file(ROOT.join('spec', 'integrations.yml')))
|
||||
end # Project
|
||||
end # Corpus
|
||||
end # MutantSpec
|
||||
|
|
|
@ -126,7 +126,6 @@ Environment:
|
|||
|
||||
Options:
|
||||
--expected-coverage COVERAGE Fail unless COVERAGE is not reached exactly, parsed via Rational()
|
||||
--score COVERAGE Fail unless COVERAGE is not reached exactly [deprecated]
|
||||
--use INTEGRATION Use INTEGRATION to kill mutations
|
||||
--ignore-subject PATTERN Ignore subjects that match PATTERN
|
||||
--fail-fast Fail fast
|
||||
|
@ -221,16 +220,6 @@ Options:
|
|||
end
|
||||
end
|
||||
|
||||
context 'with score flag' do
|
||||
let(:flags) { %w[--score 50.0] }
|
||||
|
||||
it_should_behave_like 'a cli parser'
|
||||
|
||||
it 'configures expected coverage' do
|
||||
expect(subject.config.expected_coverage).to eql(Rational(1, 2))
|
||||
end
|
||||
end
|
||||
|
||||
context 'with require flag' do
|
||||
let(:flags) { %w[--require foo] }
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue