free_mutant/lib/mutant/cli.rb

235 lines
5.4 KiB
Ruby
Raw Normal View History

require 'optparse'
2012-08-28 12:57:39 -04:00
module Mutant
# Commandline parser
class CLI
include Adamantium::Flat, Equalizer.new(:config), Procto.call(:config)
2012-08-28 12:57:39 -04:00
# Error failed when CLI argv is invalid
Error = Class.new(RuntimeError)
EXIT_FAILURE = 1
EXIT_SUCCESS = 0
# Run cli with arguments
#
# @param [Array<String>] arguments
#
# @return [Fixnum]
# the exit status
#
# @api private
#
def self.run(arguments)
2014-11-17 15:46:42 -05:00
Runner.call(Env.new(call(arguments))).success? ? EXIT_SUCCESS : EXIT_FAILURE
rescue Error => exception
$stderr.puts(exception.message)
EXIT_FAILURE
end
# Initialize objecct
#
# @param [Array<String>]
#
# @return [undefined]
#
# @api private
#
def initialize(arguments)
@config = Config::DEFAULT
parse(arguments)
end
2014-06-15 15:30:17 -04:00
# Return config
#
# @return [Config]
#
# @api private
#
attr_reader :config
private
2013-06-15 10:37:43 -04:00
# Parse the command-line options
#
# @param [Array<String>] arguments
# Command-line options and arguments to be parsed.
#
# @fail [Error]
# An error occurred while parsing the options.
#
2013-06-15 10:37:43 -04:00
# @return [undefined]
#
# @api private
#
def parse(arguments)
2013-07-28 13:58:53 -04:00
opts = OptionParser.new do |builder|
2014-07-06 11:00:37 -04:00
builder.banner = 'usage: mutant [options] MATCH_EXPRESSION ...'
%w[add_environment_options add_mutation_options add_filter_options add_debug_options].each do |name|
send(name, builder)
2013-06-21 11:21:04 -04:00
end
end
parse_match_expressions(opts.parse!(arguments))
rescue OptionParser::ParseError => error
fail(Error, error.message, error.backtrace)
end
# Parse matchers
#
# @param [Array<String>] expressions
#
2013-06-21 21:47:23 -04:00
# @return [undefined]
#
# @api private
#
def parse_match_expressions(expressions)
fail Error, 'No expressions given' if expressions.empty?
expressions.map(&Expression.method(:parse)).each do |expression|
add_matcher(:match_expressions, expression)
end
end
2013-06-14 14:54:02 -04:00
2013-08-04 17:03:39 -04:00
# Add environmental options
#
# @param [Object] opts
#
# @return [undefined]
#
# @api private
#
def add_environment_options(opts)
2014-01-18 18:27:56 -05:00
opts.separator('Environment:')
2013-08-04 17:03:39 -04:00
opts.on('--zombie', 'Run mutant zombified') do
update(zombie: true)
end
opts.on('-I', '--include DIRECTORY', 'Add DIRECTORY to $LOAD_PATH') do |directory|
add(:includes, directory)
end
opts.on('-r', '--require NAME', 'Require file with NAME') do |name|
add(:requires, name)
2013-08-04 17:03:39 -04:00
end
opts.on('-j', '--jobs NUMBER', 'Number of kill jobs. Defaults to number of processors.') do |number|
update(jobs: Integer(number))
2014-07-17 09:59:25 -04:00
end
2013-08-04 17:03:39 -04:00
end
# Use integration
2014-01-17 18:25:16 -05:00
#
# @param [String] name
2014-01-17 18:15:42 -05:00
#
# @return [undefined]
#
# @api private
#
def setup_integration(name)
require "mutant/integration/#{name}"
update(integration: Integration.lookup(name))
2014-01-17 18:15:42 -05:00
end
2013-06-21 11:21:04 -04:00
# Add options
#
2014-01-18 18:27:56 -05:00
# @param [OptionParser] opts
2013-06-21 11:21:04 -04:00
#
2013-06-21 21:47:23 -04:00
# @return [undefined]
#
2013-06-21 11:21:04 -04:00
# @api private
#
2014-01-18 18:27:56 -05:00
def add_mutation_options(opts)
opts.separator(EMPTY_STRING)
2014-01-18 18:27:56 -05:00
opts.separator('Options:')
2013-06-21 11:21:04 -04:00
opts.on('--score COVERAGE', 'Fail unless COVERAGE is not reached exactly') do |coverage|
update(expected_coverage: Float(coverage))
end.on('--use STRATEGY', 'Use STRATEGY for killing mutations', &method(:setup_integration))
end
# Add filter options
#
# @param [OptionParser] opts
#
# @return [undefined]
#
# @api private
#
def add_filter_options(opts)
opts.on('--ignore-subject PATTERN', 'Ignore subjects that match PATTERN') do |pattern|
add_matcher(:subject_ignores, Expression.parse(pattern))
end
opts.on('--code CODE', 'Scope execution to subjects with CODE') do |code|
add_matcher(:subject_selects, [:code, code])
2014-01-18 18:27:56 -05:00
end
end
# Add debug options
#
# @param [OptionParser] opts
#
# @return [undefined]
#
# @api private
#
def add_debug_options(opts)
opts.on('--fail-fast', 'Fail fast') do
update(fail_fast: true)
2014-05-27 11:12:36 -04:00
end.on('--version', 'Print mutants version') do
2014-01-18 18:27:56 -05:00
puts("mutant-#{Mutant::VERSION}")
2014-07-06 11:00:37 -04:00
Kernel.exit(EXIT_SUCCESS)
end.on('-d', '--debug', 'Enable debugging output') do
update(debug: true)
2013-06-21 11:21:04 -04:00
end.on_tail('-h', '--help', 'Show this message') do
2014-07-06 11:00:37 -04:00
puts(opts.to_s)
Kernel.exit(EXIT_SUCCESS)
2013-06-21 11:21:04 -04:00
end
end
# Update configuration
#
# @param [Hash<Symbol, Object>] attributes
#
# @return [undefined]
#
# @api private
#
def update(attributes)
@config = @config.update(attributes)
end
# Add configuration
#
# @param [Symbol] attribute
# the attribute to add to
#
# @param [Object] value
# the value to add
#
# @return [undefined]
#
# @api private
#
def add(attribute, value)
update(attribute => config.public_send(attribute).dup << value)
end
# Add matcher configuration
#
# @param [Symbol] attribute
# the attribute to add to
#
# @param [Object] value
# the value to add
#
# @return [undefined]
#
# @api private
#
def add_matcher(attribute, value)
update(matcher_config: config.matcher_config.add(attribute, value))
end
2013-06-14 14:54:02 -04:00
end # CLI
end # Mutant