lib/tryouts/drill.rb




class Tryouts
  
  # = Drill
  # 
  # This class represents a drill. A drill is single test. 
  #
  class Drill
  
  require 'tryouts/drill/response'
  require 'tryouts/drill/sergeant/cli'
  require 'tryouts/drill/sergeant/api'
  
  class NoSergeant < Tryouts::Exception; end
    
    # A symbol specifying the drill type. One of: :cli, :api
  attr_reader :dtype
    # The name of the drill. This should match the name used in the dreams file. 
  attr_reader :name
    # A Proc object which contains the drill logic. 
  attr_reader :drill
  
    # A Sergeant object which executes the drill
  attr_reader :sergeant
    # A Dream object (the expected output of the test)
  attr_reader :dream
    # A Reality object (the actual output of the test)
  attr_reader :reality
      
  def initialize(name, dtype, *drill_args, &drill)
    @name, @dtype, @drill = name, dtype, drill
    @sergeant = hire_sergeant *drill_args
    # For CLI drills, a block takes precedence over inline args. 
    # A block will contain multiple shell commands (see Rye::Box#batch)
    drill_args = [] if dtype == :cli && drill.is_a?(Proc)
    @reality = Tryouts::Drill::Reality.new
  end
  
  def hire_sergeant(*drill_args)
    if @dtype == :cli
      Tryouts::Drill::Sergeant::CLI.new(*drill_args)
    elsif @dtype == :api
      Tryouts::Drill::Sergeant::API.new(drill_args.first)
    else
      raise NoSergeant, "What is #{@dtype}?"
    end
  end
  
  def run(context=nil)
    return false if @dream.nil?
    begin
      print Tryouts::DRILL_MSG % @name
      @reality = @sergeant.run @drill, context
      @reality.stash = context.stash if context.respond_to? :stash
      process_reality
    rescue => ex
      @reality.rcode = -2
      @reality.emsg, @reality.backtrace = ex.message, ex.backtrace
    end  
    note = @dream ? discrepency.join(', ') : 'nodream'
    puts self.success? ? "PASS".color(:green) : "FAIL (#{note})".color(:red)
    self.success?
  end
  
  def success?
    return false if @dream.nil? || @reality.nil?
    @dream == @reality
  end
  
  def discrepency
    diffs = []
    if @dream
      diffs << "rcode" if @dream.rcode != @reality.rcode
      diffs << "output" if !@dream.compare_output(@reality)
      diffs << "emsg" if @dream.emsg != @reality.emsg
    end
    diffs
  end
  
  def add_dream(d)
    @dream = d if d.is_a?(Tryouts::Drill::Dream)
  end
  
  private 
  # Use the :format provided in the dream to convert the output from reality
  def process_reality
    @reality.normalize!
    return unless @dream && @dream.format
    if @dream.format == :to_yaml
      @reality.output = YAML.load(@reality.output.join("\n"))
    elsif  @dream.format == :to_json
      @reality.output = JSON.load(@reality.output.join("\n"))
    end
    
    #p [:process, @name, @dream.format, @reality.output]
  end
  
end; end