class Tryouts::Drill


This class represents a drill. A drill is single test.
= Drill

def self.valid_dtype?(t); @@valid_dtypes.member?(t); end

def self.valid_dtype?(t); @@valid_dtypes.member?(t); end

def self.valid_dtypes; @@valid_dtypes; end

def self.valid_dtypes; @@valid_dtypes; end

def add_dream(d); @dreams << d; end

def add_dream(d); @dreams << d; end

def add_dreams(*d); @dreams += d; end

def add_dreams(*d); @dreams += d; end

def flag

def flag
  if skip?
    "SKIP"
  elsif success? 
    "PASS".color(@clr).bright 
  else
    note = @dreams.empty? ? '[nodream]' : ''
    "FAIL #{note}".color(@clr).bright
  end
end

def has_error?

def has_error?
  !@reality.error.nil?
end

def info

def info
  out = StringIO.new
  if Tryouts.verbose > 0
    if @dtype == :benchmark
      unless @reality.output.nil?
        mean, sdev, sum = @reality.output.mean, @reality.output.sdev, @reality.output.sum
        out.puts '%6s%.4f (sdev:%.4f sum:%.4f)'.color(@clr) % ['', mean, sdev, sum]
      end
    elsif @dtype == :cli
      out.puts '%6s%s'.color(@clr) % ['', @reality.command]
      output = @reality.output
      output = output.join($/ + ' '*6) if output.kind_of?(Array)
      out.puts '%6s%s'.color(@clr) % ['', output]
    else
      out.puts '%6s%s'.color(@clr) % ['', @reality.output.inspect]
    end
    unless @reality.stash.empty?
      @reality.stash.each_pair do |n,v|
        out.puts '%18s: %s'.color(@clr) % [n,v.inspect]
      end
    end
  end
  if Tryouts.verbose > 1
    @dreams.each do |dream|
      if dream != @reality
        out.puts '%6s%s'.color(:red) % ['', dream.test_to_string(@reality)]
      else
        out.puts '%6s%s'.color(:green) % ["", dream.test_to_string(@reality)]
      end
    end  
    out.puts
  
  end
  out.rewind
  out.read
end

def initialize(name, dtype, *args, &drill)


* dream FORMAT, OUTPUT, REPS (benchmark only)
* dream FORMAT, OUTPUT
* dream OUTPUT
The DSL syntax:

is compared to the exepected output of the dreams.
* +&drill+ The body of the drill. The return value of this block
* +args+ These are dependent on the drill type. See the Sergeant classes
* +dtype+ A Symbol representing the drill type. One of: :api, :benchmark
* +name+ The display name of this drill
def initialize(name, dtype, *args, &drill)
  @name, @dtype, @drill, @skip = name, dtype, drill, false
  @dreams = []
  
  # We create a default empty reality but if the drill runs correctly
  # this reality gets replaced with the return value from the drill.
  @reality = Tryouts::Drill::Reality.new
  
  case @dtype 
  when :cli
    # For CLI drills, a block takes precedence over inline args. 
    # A block will contain multiple shell commands (see Rye::Box#batch)
    args = [] if dtype == :cli && drill.is_a?(Proc)
    @sergeant = Tryouts::Drill::Sergeant::CLI.new *args
  when :api
    default_output = drill.nil? ? args.shift : nil
    @sergeant = Tryouts::Drill::Sergeant::API.new default_output
    unless args.empty?
      if args.size == 1
        dream_output, format = args.first, nil
      else
        dream_output, format = args[1], args[0]
      end
      @dreams << Tryouts::Drill::Dream.new(dream_output, format)
    end
  when :benchmark
    if args.size == 1
      reps = args.first
    else
      dream_output, format, reps = args[1], args[0], args[2]
    end
    @sergeant = Tryouts::Drill::Sergeant::Benchmark.new reps
    @dreams << Tryouts::Drill::Dream.new(Tryouts::Stats, :class)
    unless dream_output.nil?
      @dreams << Tryouts::Drill::Dream.new(dream_output, format)
    end
  when :skip
    @skip = true
  else
    raise NoSergeant, "Weird drill sergeant: #{@dtype}"
  end
  @clr = :red
  
end

def report

def report
  return if skip?
  out = StringIO.new
  
  out.puts '%12s'.color(:red) % '[nodream]' if @dreams.empty?
  
  @dreams.each do |dream|
    next if dream == reality #? :normal : :red 
    out.puts '%12s: %s'.color(@clr) % ["failed", dream.test_to_string(@reality)]
    out.puts '%12s: %s' % ["drill", @reality.comparison_value(dream).inspect]
    out.puts '%12s: %s' % ["dream", dream.comparison_value.inspect]
    out.puts
  end
  
  unless @reality.error.nil?
    out.puts '%14s: %s' % [@reality.etype, @reality.error.to_s.split($/).join($/ + ' '*16)]
  end
  unless @reality.trace.nil?
    trace = Tryouts.verbose > 1 ? @reality.trace : [@reality.trace.first]
    out.puts '%14s  %s' % ['', trace.join($/ + ' '*16)]
    out.puts
  end
  
  out.rewind
  out.read
end

def run(context=nil)

def run(context=nil)
  unless @dreams.empty?
    @dreams.each { |d| d.execute_output_block }
  end
  begin
    @reality = @sergeant.run @drill, context
    # Store the stash from the drill block
    @reality.stash = context.stash if context.respond_to? :stash
    # If the drill block returned true we assume success if there's no dream
    if @dreams.empty? && @reality.output == true
      @dreams << Tryouts::Drill::Dream.new
      @dreams.first.output = true
    end
  rescue => ex
    @reality.ecode, @reality.etype = -2, ex.class
    @reality.error, @reality.trace = ex.message, ex.backtrace
  end  
  self.success?
end

def skip?; @skip; end

def skip?; @skip; end

def success?

def success?
  return false if @dreams.empty? && @reality.output != true
  begin
    @dreams.each { |d| return false unless d == @reality }
  rescue => ex
    puts ex.message, ex.backtrace if Tryouts.debug?
    return false
  end
  @clr = :green
  true
end