2013-07-28 19:03:06 -04:00
|
|
|
# encoding: utf-8
|
|
|
|
|
2013-05-14 21:25:16 -04:00
|
|
|
require 'optparse'
|
|
|
|
|
2012-08-28 12:57:39 -04:00
|
|
|
module Mutant
|
2013-02-02 10:56:48 -05:00
|
|
|
|
2012-09-15 18:51:47 -04:00
|
|
|
# Comandline parser
|
2013-05-14 21:25:16 -04:00
|
|
|
class CLI
|
2013-04-20 15:10:14 -04:00
|
|
|
include Adamantium::Flat, Equalizer.new(:config)
|
2012-08-28 12:57:39 -04:00
|
|
|
|
2013-06-13 13:10:34 -04:00
|
|
|
# Error raised when CLI argv is invalid
|
2013-05-14 21:25:16 -04:00
|
|
|
Error = Class.new(RuntimeError)
|
|
|
|
|
|
|
|
EXIT_FAILURE = 1
|
|
|
|
EXIT_SUCCESS = 0
|
|
|
|
|
2012-08-28 13:43:15 -04:00
|
|
|
# Run cli with arguments
|
|
|
|
#
|
|
|
|
# @param [Array<String>] arguments
|
|
|
|
#
|
|
|
|
# @return [Fixnum]
|
2013-09-11 14:48:44 -04:00
|
|
|
# the exit status
|
2012-08-28 13:43:15 -04:00
|
|
|
#
|
|
|
|
# @api private
|
|
|
|
#
|
2013-05-14 21:25:16 -04:00
|
|
|
def self.run(arguments)
|
|
|
|
config = new(arguments).config
|
2013-02-02 10:32:13 -05:00
|
|
|
runner = Runner::Config.run(config)
|
|
|
|
runner.success? ? EXIT_SUCCESS : EXIT_FAILURE
|
2012-11-21 16:28:08 -05:00
|
|
|
rescue Error => exception
|
|
|
|
$stderr.puts(exception.message)
|
|
|
|
EXIT_FAILURE
|
|
|
|
end
|
|
|
|
|
2013-02-02 10:56:48 -05:00
|
|
|
# Initialize objecct
|
2012-11-21 16:28:08 -05:00
|
|
|
#
|
2013-02-02 10:56:48 -05:00
|
|
|
# @param [Array<String>]
|
2012-11-21 16:28:08 -05:00
|
|
|
#
|
2013-02-02 10:56:48 -05:00
|
|
|
# @return [undefined]
|
2012-11-21 16:28:08 -05:00
|
|
|
#
|
|
|
|
# @api private
|
|
|
|
#
|
2013-07-28 15:16:45 -04:00
|
|
|
def initialize(arguments = [])
|
2013-02-02 10:56:48 -05:00
|
|
|
@filters, @matchers = [], []
|
2013-09-01 18:07:55 -04:00
|
|
|
@debug = @fail_fast = @zombie = false
|
2013-06-27 16:18:07 -04:00
|
|
|
@cache = Mutant::Cache.new
|
2013-09-02 14:30:21 -04:00
|
|
|
@strategy_builder = nil
|
2013-06-27 16:18:07 -04:00
|
|
|
|
2013-05-14 21:25:16 -04:00
|
|
|
parse(arguments)
|
2013-09-01 18:07:55 -04:00
|
|
|
config # trigger lazyness
|
2012-11-21 16:28:08 -05:00
|
|
|
end
|
|
|
|
|
2013-02-24 14:40:23 -05:00
|
|
|
# Return config
|
|
|
|
#
|
|
|
|
# @return [Config]
|
|
|
|
#
|
|
|
|
# @api private
|
|
|
|
#
|
|
|
|
def config
|
|
|
|
Config.new(
|
2013-09-07 14:27:06 -04:00
|
|
|
cache: @cache,
|
|
|
|
zombie: @zombie,
|
|
|
|
debug: debug?,
|
|
|
|
matcher: matcher,
|
|
|
|
filter: filter,
|
|
|
|
fail_fast: @fail_fast,
|
|
|
|
strategy: strategy,
|
|
|
|
reporter: reporter
|
2013-02-24 14:40:23 -05:00
|
|
|
)
|
|
|
|
end
|
|
|
|
memoize :config
|
|
|
|
|
|
|
|
private
|
|
|
|
|
2012-12-10 18:17:19 -05:00
|
|
|
# Test for running in debug mode
|
|
|
|
#
|
|
|
|
# @return [true]
|
|
|
|
# if debug mode is active
|
|
|
|
#
|
|
|
|
# @return [false]
|
|
|
|
# otherwise
|
|
|
|
#
|
|
|
|
# @api private
|
|
|
|
#
|
|
|
|
def debug?
|
2013-09-02 15:31:25 -04:00
|
|
|
@debug
|
2012-12-10 18:17:19 -05:00
|
|
|
end
|
|
|
|
|
2012-11-21 16:28:08 -05:00
|
|
|
# Return mutation filter
|
|
|
|
#
|
|
|
|
# @return [Mutant::Matcher]
|
|
|
|
#
|
|
|
|
# @api private
|
|
|
|
#
|
|
|
|
def filter
|
|
|
|
if @filters.empty?
|
2013-09-07 17:12:03 -04:00
|
|
|
Predicate::ALL
|
2012-11-21 16:28:08 -05:00
|
|
|
else
|
2013-09-07 17:12:03 -04:00
|
|
|
Predicate::Whitelist.new(@filters)
|
2012-11-21 16:28:08 -05:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2012-11-21 18:10:50 -05:00
|
|
|
# Return stratety
|
2012-11-21 16:28:08 -05:00
|
|
|
#
|
2012-11-21 18:10:50 -05:00
|
|
|
# @return [Strategy]
|
2012-11-21 16:28:08 -05:00
|
|
|
#
|
|
|
|
# @api private
|
|
|
|
#
|
2012-11-21 18:10:50 -05:00
|
|
|
def strategy
|
2013-09-01 18:07:55 -04:00
|
|
|
unless @strategy_builder
|
|
|
|
raise(Error, 'No strategy was set!')
|
|
|
|
end
|
|
|
|
@strategy_builder.strategy
|
2012-08-28 12:57:39 -04:00
|
|
|
end
|
|
|
|
|
2012-11-21 16:28:08 -05:00
|
|
|
# Return reporter
|
2012-08-28 13:43:15 -04:00
|
|
|
#
|
2012-11-21 16:28:08 -05:00
|
|
|
# @return [Mutant::Reporter::CLI]
|
2012-08-28 13:43:15 -04:00
|
|
|
#
|
|
|
|
# @api private
|
|
|
|
#
|
2012-11-21 16:28:08 -05:00
|
|
|
def reporter
|
2013-04-20 20:55:09 -04:00
|
|
|
Reporter::CLI.new($stdout)
|
2012-08-28 12:57:39 -04:00
|
|
|
end
|
|
|
|
|
2013-02-02 10:56:48 -05:00
|
|
|
# Return matcher
|
2012-08-28 13:43:15 -04:00
|
|
|
#
|
2013-02-02 10:56:48 -05:00
|
|
|
# @return [Mutant::Matcher]
|
2012-08-28 13:43:15 -04:00
|
|
|
#
|
|
|
|
# @raise [CLI::Error]
|
2013-02-02 10:56:48 -05:00
|
|
|
# raises error when matcher is not given
|
2012-08-28 13:43:15 -04:00
|
|
|
#
|
|
|
|
# @api private
|
|
|
|
#
|
2013-02-02 10:56:48 -05:00
|
|
|
def matcher
|
|
|
|
if @matchers.empty?
|
2013-09-01 18:07:55 -04:00
|
|
|
raise(Error, 'No matchers given')
|
2012-08-28 12:57:39 -04:00
|
|
|
end
|
2013-02-02 10:56:48 -05:00
|
|
|
|
2013-04-20 20:55:09 -04:00
|
|
|
Matcher::Chain.build(@matchers)
|
2012-08-28 12:57:39 -04:00
|
|
|
end
|
|
|
|
|
2012-08-28 13:43:15 -04:00
|
|
|
# Add mutation filter
|
|
|
|
#
|
2013-09-07 17:12:03 -04:00
|
|
|
# @param [Class<Predicate>] klass
|
2013-05-14 21:25:16 -04:00
|
|
|
#
|
2012-08-28 13:43:15 -04:00
|
|
|
# @return [undefined]
|
|
|
|
#
|
|
|
|
# @api private
|
|
|
|
#
|
2013-09-07 12:57:06 -04:00
|
|
|
def add_filter(klass, *arguments)
|
|
|
|
@filters << klass.new(*arguments)
|
2012-08-28 12:57:39 -04:00
|
|
|
end
|
|
|
|
|
2013-06-15 10:37:43 -04:00
|
|
|
# Parse the command-line options
|
2013-05-14 21:25:16 -04:00
|
|
|
#
|
|
|
|
# @param [Array<String>] arguments
|
|
|
|
# Command-line options and arguments to be parsed.
|
|
|
|
#
|
|
|
|
# @raise [Error]
|
|
|
|
# An error occurred while parsing the options.
|
|
|
|
#
|
2013-06-15 10:37:43 -04:00
|
|
|
# @return [undefined]
|
|
|
|
#
|
2013-05-14 21:25:16 -04:00
|
|
|
# @api private
|
|
|
|
#
|
|
|
|
def parse(arguments)
|
2013-07-28 13:58:53 -04:00
|
|
|
opts = OptionParser.new do |builder|
|
|
|
|
builder.banner = 'usage: mutant STRATEGY [options] MATCHERS ...'
|
2013-09-01 18:07:55 -04:00
|
|
|
builder.separator('')
|
2013-07-28 13:58:53 -04:00
|
|
|
add_strategies(builder)
|
2013-08-04 17:43:57 -04:00
|
|
|
add_environmental_options(builder)
|
2013-07-28 13:58:53 -04:00
|
|
|
add_options(builder)
|
2013-05-14 21:25:16 -04:00
|
|
|
end
|
|
|
|
|
2013-06-21 11:21:04 -04:00
|
|
|
matchers =
|
|
|
|
begin
|
|
|
|
opts.parse!(arguments)
|
|
|
|
rescue OptionParser::ParseError => error
|
|
|
|
raise(Error, error.message, error.backtrace)
|
|
|
|
end
|
2013-05-14 21:25:16 -04:00
|
|
|
|
2013-06-21 11:52:53 -04:00
|
|
|
parse_matchers(matchers)
|
|
|
|
end
|
|
|
|
|
|
|
|
# Parse matchers
|
|
|
|
#
|
|
|
|
# @param [Enumerable<String>] patterns
|
|
|
|
#
|
2013-06-21 21:47:23 -04:00
|
|
|
# @return [undefined]
|
|
|
|
#
|
2013-06-21 11:52:53 -04:00
|
|
|
# @api private
|
|
|
|
#
|
|
|
|
def parse_matchers(patterns)
|
|
|
|
patterns.each do |pattern|
|
2013-09-11 16:06:32 -04:00
|
|
|
matcher = Classifier.run(@cache, pattern)
|
2013-05-14 21:25:16 -04:00
|
|
|
@matchers << matcher if matcher
|
|
|
|
end
|
|
|
|
end
|
2013-06-14 14:54:02 -04:00
|
|
|
|
2013-06-21 11:21:04 -04:00
|
|
|
# Add strategies
|
|
|
|
#
|
2013-09-01 18:07:55 -04:00
|
|
|
# @param [OptionParser] parser
|
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
|
|
|
|
#
|
2013-09-01 18:07:55 -04:00
|
|
|
def add_strategies(parser)
|
|
|
|
parser.separator(EMPTY_STRING)
|
|
|
|
parser.separator('Strategies:')
|
2013-08-04 12:49:42 -04:00
|
|
|
|
2013-09-02 15:30:54 -04:00
|
|
|
writer = lambda do |builder|
|
|
|
|
@strategy_builder = builder
|
|
|
|
end
|
|
|
|
|
2013-09-01 18:07:55 -04:00
|
|
|
[
|
|
|
|
Builder::Rspec
|
|
|
|
].each do |builder|
|
2013-09-02 15:30:54 -04:00
|
|
|
builder.add_options(parser, &writer)
|
2013-06-21 11:21:04 -04:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2013-08-04 17:03:39 -04:00
|
|
|
# Add environmental options
|
|
|
|
#
|
|
|
|
# @param [Object] opts
|
|
|
|
#
|
|
|
|
# @return [undefined]
|
|
|
|
#
|
|
|
|
# @api private
|
|
|
|
#
|
|
|
|
def add_environmental_options(opts)
|
|
|
|
opts.on('--zombie', 'Run mutant zombified') do
|
|
|
|
@zombie = true
|
|
|
|
end.on('-I', 'Add directory to $LOAD_PATH') do |directory|
|
|
|
|
$LOAD_PATH << directory
|
|
|
|
end.on('-r', '--require NAME', 'Require file with NAME') do |name|
|
2013-09-01 18:07:55 -04:00
|
|
|
require(name)
|
2013-08-04 17:03:39 -04:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2013-06-21 11:21:04 -04:00
|
|
|
# Add options
|
|
|
|
#
|
2013-08-04 17:03:39 -04:00
|
|
|
# @param [Object] 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
|
|
|
|
#
|
|
|
|
def add_options(opts)
|
|
|
|
opts.separator ''
|
|
|
|
opts.separator 'Options:'
|
|
|
|
|
2013-08-02 19:44:58 -04:00
|
|
|
opts.on('--version', 'Print mutants version') do |name|
|
2013-08-04 17:03:39 -04:00
|
|
|
puts("mutant-#{Mutant::VERSION}")
|
2013-08-02 19:44:58 -04:00
|
|
|
Kernel.exit(0)
|
2013-08-02 19:41:21 -04:00
|
|
|
end.on('--code FILTER', 'Adds a code filter') do |filter|
|
2013-09-07 17:12:03 -04:00
|
|
|
add_filter(Predicate::Attribute, :code, filter)
|
2013-07-14 19:17:15 -04:00
|
|
|
end.on('--fail-fast', 'Fail fast') do
|
2013-08-04 17:03:39 -04:00
|
|
|
@fail_fast = true
|
2013-07-28 15:16:45 -04:00
|
|
|
end.on('-d', '--debug', 'Enable debugging output') do
|
2013-08-04 17:03:39 -04:00
|
|
|
@debug = true
|
2013-06-21 11:21:04 -04:00
|
|
|
end.on_tail('-h', '--help', 'Show this message') do
|
2013-08-04 17:03:39 -04:00
|
|
|
puts(opts)
|
2013-06-21 11:21:04 -04:00
|
|
|
exit
|
|
|
|
end
|
|
|
|
end
|
2013-06-14 14:54:02 -04:00
|
|
|
end # CLI
|
|
|
|
end # Mutant
|