krypt/FuzzBert

View on GitHub
lib/fuzzbert/autorun.rb

Summary

Maintainability
A
0 mins
Test Coverage
require 'optparse'

module FuzzBert::AutoRun

  TEST_CASES = []

  module_function

  def register(suite)
    TEST_CASES << suite
  end

  def autorun
    autorun_with_args(ARGV)
  end

  def autorun_with_args(argv)
    options, files = process_args(argv)
    load_files(files)
    run(options)
  end

  def run(options=nil)
    raise RuntimeError.new "No test cases were found" if TEST_CASES.empty?
    FuzzBert::Executor.new(TEST_CASES, options).run
  end

  private; module_function

    def load_files(files)
      files.each do |pattern|
        Dir.glob(pattern).each { |f| load File.expand_path(f) }
      end
    end

    def process_args(args = [])
      options = {}

      OptionParser.new do |opts|
        add_banner(opts)

        add_help(opts)
        add_pool_size(opts, options)
        add_limit(opts, options)
        add_console(opts, options)
        add_sleep_delay(opts, options)
        add_handler(opts, options)
        add_bug_dir(opts, options)

        opts.parse! args
      end

      raise ArgumentError.new("No file pattern was given") if args.empty?
      [options, args]
    end

    def add_banner(opts)
      opts.banner  = 'Usage: fuzzbert [OPTIONS] PATTERN [PATTERNS]'
      opts.separator <<-EOS

Run your random tests by pointing fuzzbert to a single or many explicit files
or by providing a pattern. The default pattern is 'fuzz/**/fuzz_*.rb, assuming
that your FuzzBert files (files beginning with 'fuzz_') live in a directory
named fuzz located under the current directory that you are in.

By default, fuzzbert will run the tests you specify forever, be sure to hit
CTRL+C when you are done or specify a limit with '--limit'.

      EOS

      opts.version = FuzzBert::VERSION
    end

    def add_help(opts)
      opts.on '-h', '--help', 'Run ' do
        puts opts
        exit
      end
    end

    def add_pool_size(opts, options)
      opts.on '--pool-size SIZE', Integer, "Sets the number of concurrently running processes to SIZE. Default is 4." do |n|
        options[:pool_size] = n.to_i
      end
    end

    def add_limit(opts, options)
      opts.on '--limit LIMIT', Integer, "Instead of running permanently, fuzzing will be stopped after running LIMIT of instances." do |n|
        options[:limit] = n.to_i
      end
    end

    def add_console(opts, options)
      opts.on '--console', "Output the failing cases including data on the console instead of saving them in a file." do
        options[:handler] = FuzzBert::Handler::Console.new
      end
    end

    def add_sleep_delay(opts, options)
      opts.on '--sleep-delay SECONDS', Float, "Specify the number of SECONDS that the main process sleeps before checking that the limit has been reached. Default is 1." do |f|
        options[:sleep_delay] = f.to_f
      end
    end

    def add_handler(opts, options)
      opts.on '--handler CLASS', String, "Specify the full path to a CLASS that will serve as your Handler." do |path|
        #lazy initialization: the Handler must be defined in one of the fuzzer files
        options[:handler] = Class.new do
          @@path = path

          def handle(error_data)
            @inner ||= class_for_name(@@path).new
            @inner.handle(error_data)
          end

          def class_for_name(path)
            path.split('::').inject(Object) { |mod, class_name| mod.const_get(class_name) }
          end
        end.new
      end
    end

    def add_bug_dir(opts, options)
      opts.on '--bug-dir DIRECTORY', String, "The DIRECTORY where the resulting bug files will be stored. Default is the current directory." do |dir|
        raise ArgumentError.new "#{dir} is not a directory" unless Dir.exists?(dir)
        options[:handler] = FuzzBert::Handler::FileOutput.new(dir)
      end
    end

end