class Covet::CLI
Attributes
options[RW]
Public Class Methods
new(argv)
click to toggle source
# File lib/covet/cli.rb, line 12 def initialize(argv) @argv = argv end
Public Instance Methods
run()
click to toggle source
TODO: process cmdline options for
- specify VCS [ ] - specify test seed (ordering) - stats (show filtered files, files to run vs files to ignore, etc.)
# File lib/covet/cli.rb, line 20 def run options = nil begin options = Options.parse!(@argv) self.class.options = options rescue OptionParser::InvalidArgument, OptionParser::InvalidOption => e Kernel.abort "Error: #{e.message}" end if options[:collect_cmdline] && !options[:collect_cmdline].empty? cmd = options[:collect_cmdline] env_options = { 'COVET_COLLECT' => '1' } if options[:collect_gem_whitelist].any? env_options['COVET_GEM_WHITELIST'] = %Q("#{options[:collect_gem_whitelist].join(',')}") end if options[:test_runner] != Options::DEFAULTS[:test_runner] env_options['COVET_TEST_RUNNER'] = %Q("#{options[:test_runner]}") end env_list_str = env_options.to_a.map { |ary| ary[0] + '=' + ary[1] }.join(' ') cmd = %Q(#{env_list_str} #{cmd}) puts cmd puts "Collecting coverage information for each test method..." Kernel.exec cmd end revision = options[:revision] line_changes = nil # establish scope begin line_changes = LineChangesVCS.changes_since(revision) rescue Rugged::RepositoryError Kernel.abort "Error: #{Dir.pwd} is not a git repository. " \ "Make sure you're in the project root." rescue Rugged::Error, Rugged::InvalidError, TypeError Kernel.abort "Error: #{options[:revision]} is not a valid revision reference in #{options[:VCS]}" end if line_changes.empty? if revision.to_s == 'last_commit' revision = "last commit" # prettier output below end puts "# No changes since #{revision}. You can specify the #{options[:VCS]} revision using the --revision option." Kernel.exit end cov_map = Hash.new { |h, file| h[file] = Hash.new { |i, line| i[line] = [] } } logfile = LogFile.new(:mode => 'r') if logfile.file_exists? run_stats = {} # Read in the coverage info logfile.load_each_buf! do |buf| buf.each do |args| if args[0] == 'base' # first value logged run_options = args.last if run_options['version'] != Covet::VERSION warn "Warning - the run log was created with another version of covet " \ "(#{run_options['version']}), which is not guaranteed to be compatible " \ "with this version of covet (#{Covet::VERSION}). Please run 'covet -c' again." end next end if args[0] == 'stats' # last value logged run_stats.update(args.last) next end desc = args[0] delta = args[1] next if delta.nil? # no coverage difference #stats = args[2] delta.each_pair do |fname, lines_hash| file_map = cov_map[fname] lines_hash.each do |line, _executions| # add the test name to the map. Multiple tests can execute the same # line, so we need to use an array. file_map[line.to_i] << desc end end end end git_repo = VCS::Git.find_git_repo_path! to_run = [] line_changes.each do |(file, line)| full_path = File.join(git_repo, file) relative_to_pwd = file if git_repo != Dir.pwd relative_to_pwd = full_path.sub(Dir.pwd, '').sub(File::SEPARATOR, '') end # NOTE: here, `file` is a filename starting from the GIT path (not necessarily `Dir.pwd`) # if the actual test files changed, then we need to run the whole file again. if relative_to_pwd.start_with?(*Covet.test_directories) if relative_to_pwd.start_with?("test#{File::SEPARATOR}") && relative_to_pwd.end_with?('_test.rb', '_spec.rb') to_run << [file, full_path] unless to_run.include?([file, full_path]) # We have to disable the method filter in this case because we # don't know the method names of all these methods in this file. # TODO: save this information in the coverage log file and use it here. options[:disable_test_method_filter] = true elsif relative_to_pwd.start_with?("spec#{File::SEPARATOR}") && relative_to_pwd.end_with?('_test.rb', '_spec.rb') to_run << [file, full_path] unless to_run.include?([file, full_path]) # We have to disable the method filter in this case because we # don't know the method names of all these methods in this file. # TODO: save this information in the coverage log file and use it here. options[:disable_test_method_filter] = true end next end # library code changes cov_map[full_path][line].each do |desc| to_run << [file, desc] unless to_run.include?([file, desc]) end end if ENV['COVET_INVERT_RUN_LIST'] == '1' # NOTE: for debugging covet only to_run_fnames = to_run.map { |(_file, desc)| desc.split('#').first }.flatten.uniq all_fnames = Dir.glob("{#{Covet.test_directories.join(',')}}/**/*_{test,spec}.rb").to_a.map { |fname| File.expand_path(fname, Dir.pwd) } to_run = (all_fnames - to_run_fnames).map { |fname| [fname, "#{fname}##{fname}"] }.sort_by do |ary| ary[1].split('#').first end end if options[:exec_run_list] if to_run.empty? puts "# No test cases to run" else cmdline = Covet.cmdline_for_run_list(to_run) puts cmdline Kernel.exec cmdline end elsif options[:print_run_list] if to_run.empty? puts "# No test cases to run" else if options[:print_run_list_format] == :"test-runner" puts Covet.cmdline_for_run_list(to_run) else # TODO: show not just the files but also the methods in each file puts "You need to run:" to_run.uniq! { |(_file, desc)| desc.split('#').first } to_run.each do |(_file, desc)| puts " - #{desc.split('#').first}" end end end end else Kernel.abort "Error: The coverage log file doesn't exist.\n" \ "You need to collect info first with 'covet -c $TEST_CMD'\n" \ "Ex: covet -c \"rake test\"" end end