blue-shell 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/LICENSE +14 -0
 - data/Rakefile +7 -0
 - data/lib/blue-shell.rb +6 -0
 - data/lib/blue-shell/buffered_reader_expector.rb +73 -0
 - data/lib/blue-shell/errors.rb +12 -0
 - data/lib/blue-shell/matchers.rb +13 -0
 - data/lib/blue-shell/matchers/exit_code_matcher.rb +40 -0
 - data/lib/blue-shell/matchers/output_matcher.rb +38 -0
 - data/lib/blue-shell/runner.rb +98 -0
 - data/lib/blue-shell/version.rb +3 -0
 - data/spec/assets/input.rb +6 -0
 - data/spec/assets/pause.rb +5 -0
 - data/spec/matchers/exit_code_matcher_spec.rb +76 -0
 - data/spec/matchers/output_matcher_spec.rb +79 -0
 - data/spec/matchers_spec.rb +31 -0
 - data/spec/runner_spec.rb +194 -0
 - data/spec/spec_helper.rb +13 -0
 - data/spec/support/helpers.rb +7 -0
 - metadata +122 -0
 
    
        data/LICENSE
    ADDED
    
    | 
         @@ -0,0 +1,14 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            The MIT License (MIT)
         
     | 
| 
      
 2 
     | 
    
         
            +
            Copyright (c) 2013 Pivotal Labs
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
            Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
         
     | 
| 
      
 5 
     | 
    
         
            +
            documentation files (the "Software"), to deal in the Software without restriction, including without limitation the
         
     | 
| 
      
 6 
     | 
    
         
            +
            rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit
         
     | 
| 
      
 7 
     | 
    
         
            +
            persons to whom the Software is furnished to do so, subject to the following conditions:
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
            The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
            THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
         
     | 
| 
      
 12 
     | 
    
         
            +
            WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
         
     | 
| 
      
 13 
     | 
    
         
            +
            COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
         
     | 
| 
      
 14 
     | 
    
         
            +
            OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
         
     | 
    
        data/Rakefile
    ADDED
    
    
    
        data/lib/blue-shell.rb
    ADDED
    
    
| 
         @@ -0,0 +1,73 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module BlueShell
         
     | 
| 
      
 2 
     | 
    
         
            +
              class BufferedReaderExpector
         
     | 
| 
      
 3 
     | 
    
         
            +
                attr_reader :output
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
                def initialize(out, debug = false)
         
     | 
| 
      
 6 
     | 
    
         
            +
                  @out = out
         
     | 
| 
      
 7 
     | 
    
         
            +
                  @debug = debug
         
     | 
| 
      
 8 
     | 
    
         
            +
                  @unused = ""
         
     | 
| 
      
 9 
     | 
    
         
            +
                  @output = ""
         
     | 
| 
      
 10 
     | 
    
         
            +
                end
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
                def expect(pattern, timeout = 5)
         
     | 
| 
      
 13 
     | 
    
         
            +
                  buffer = ''
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
                  case pattern
         
     | 
| 
      
 16 
     | 
    
         
            +
                    when String
         
     | 
| 
      
 17 
     | 
    
         
            +
                      pattern = Regexp.new(Regexp.quote(pattern))
         
     | 
| 
      
 18 
     | 
    
         
            +
                    when Regexp
         
     | 
| 
      
 19 
     | 
    
         
            +
                    else
         
     | 
| 
      
 20 
     | 
    
         
            +
                      raise TypeError, "unsupported pattern class: #{pattern.class}"
         
     | 
| 
      
 21 
     | 
    
         
            +
                  end
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
                  result = nil
         
     | 
| 
      
 24 
     | 
    
         
            +
                  position = 0
         
     | 
| 
      
 25 
     | 
    
         
            +
                  @unused ||= ""
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
      
 27 
     | 
    
         
            +
                  while true
         
     | 
| 
      
 28 
     | 
    
         
            +
                    if !@unused.empty?
         
     | 
| 
      
 29 
     | 
    
         
            +
                      c = @unused.slice!(0).chr
         
     | 
| 
      
 30 
     | 
    
         
            +
                    elsif output_ended?(timeout)
         
     | 
| 
      
 31 
     | 
    
         
            +
                      @unused = buffer
         
     | 
| 
      
 32 
     | 
    
         
            +
                      break
         
     | 
| 
      
 33 
     | 
    
         
            +
                    else
         
     | 
| 
      
 34 
     | 
    
         
            +
                      c = @out.getc.chr
         
     | 
| 
      
 35 
     | 
    
         
            +
                    end
         
     | 
| 
      
 36 
     | 
    
         
            +
             
     | 
| 
      
 37 
     | 
    
         
            +
                    STDOUT.putc c if @debug
         
     | 
| 
      
 38 
     | 
    
         
            +
             
     | 
| 
      
 39 
     | 
    
         
            +
                    # wear your flip flops
         
     | 
| 
      
 40 
     | 
    
         
            +
                    unless (c == "\e") .. (c == "m")
         
     | 
| 
      
 41 
     | 
    
         
            +
                      if c == "\b"
         
     | 
| 
      
 42 
     | 
    
         
            +
                        if position > 0 && buffer[position - 1] && buffer[position - 1].chr != "\n"
         
     | 
| 
      
 43 
     | 
    
         
            +
                          position -= 1
         
     | 
| 
      
 44 
     | 
    
         
            +
                        end
         
     | 
| 
      
 45 
     | 
    
         
            +
                      else
         
     | 
| 
      
 46 
     | 
    
         
            +
                        if buffer.size > position
         
     | 
| 
      
 47 
     | 
    
         
            +
                          buffer[position] = c
         
     | 
| 
      
 48 
     | 
    
         
            +
                        else
         
     | 
| 
      
 49 
     | 
    
         
            +
                          buffer << c
         
     | 
| 
      
 50 
     | 
    
         
            +
                        end
         
     | 
| 
      
 51 
     | 
    
         
            +
             
     | 
| 
      
 52 
     | 
    
         
            +
                        position += 1
         
     | 
| 
      
 53 
     | 
    
         
            +
                      end
         
     | 
| 
      
 54 
     | 
    
         
            +
                    end
         
     | 
| 
      
 55 
     | 
    
         
            +
             
     | 
| 
      
 56 
     | 
    
         
            +
                    if matches = pattern.match(buffer)
         
     | 
| 
      
 57 
     | 
    
         
            +
                      result = [buffer, *matches.to_a[1..-1]]
         
     | 
| 
      
 58 
     | 
    
         
            +
                      break
         
     | 
| 
      
 59 
     | 
    
         
            +
                    end
         
     | 
| 
      
 60 
     | 
    
         
            +
                  end
         
     | 
| 
      
 61 
     | 
    
         
            +
             
     | 
| 
      
 62 
     | 
    
         
            +
                  @output << buffer
         
     | 
| 
      
 63 
     | 
    
         
            +
             
     | 
| 
      
 64 
     | 
    
         
            +
                  result
         
     | 
| 
      
 65 
     | 
    
         
            +
                end
         
     | 
| 
      
 66 
     | 
    
         
            +
             
     | 
| 
      
 67 
     | 
    
         
            +
                private
         
     | 
| 
      
 68 
     | 
    
         
            +
             
     | 
| 
      
 69 
     | 
    
         
            +
                def output_ended?(timeout)
         
     | 
| 
      
 70 
     | 
    
         
            +
                  (@out.is_a?(IO) && !IO.select([@out], nil, nil, timeout)) || @out.eof?
         
     | 
| 
      
 71 
     | 
    
         
            +
                end
         
     | 
| 
      
 72 
     | 
    
         
            +
              end
         
     | 
| 
      
 73 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,13 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module BlueShell
         
     | 
| 
      
 2 
     | 
    
         
            +
              module Matchers
         
     | 
| 
      
 3 
     | 
    
         
            +
                def say(expected_output, timeout = 30)
         
     | 
| 
      
 4 
     | 
    
         
            +
                  OutputMatcher.new(expected_output, timeout)
         
     | 
| 
      
 5 
     | 
    
         
            +
                end
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
                def have_exited_with(expected_code)
         
     | 
| 
      
 8 
     | 
    
         
            +
                  ExitCodeMatcher.new(expected_code)
         
     | 
| 
      
 9 
     | 
    
         
            +
                end
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
                alias :exit_with :have_exited_with
         
     | 
| 
      
 12 
     | 
    
         
            +
              end
         
     | 
| 
      
 13 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,40 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module BlueShell
         
     | 
| 
      
 2 
     | 
    
         
            +
              module Matchers
         
     | 
| 
      
 3 
     | 
    
         
            +
                class ExitCodeMatcher
         
     | 
| 
      
 4 
     | 
    
         
            +
                  def initialize(expected_code)
         
     | 
| 
      
 5 
     | 
    
         
            +
                    @expected_code = expected_code
         
     | 
| 
      
 6 
     | 
    
         
            +
                  end
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
                  def matches?(runner)
         
     | 
| 
      
 9 
     | 
    
         
            +
                    raise Errors::InvalidInputError unless runner.respond_to?(:exit_code)
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
                    begin
         
     | 
| 
      
 12 
     | 
    
         
            +
                      Timeout.timeout(5) do
         
     | 
| 
      
 13 
     | 
    
         
            +
                        @actual_code = runner.exit_code
         
     | 
| 
      
 14 
     | 
    
         
            +
                      end
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
                      @actual_code == @expected_code
         
     | 
| 
      
 17 
     | 
    
         
            +
                    rescue Timeout::Error
         
     | 
| 
      
 18 
     | 
    
         
            +
                      @timed_out = true
         
     | 
| 
      
 19 
     | 
    
         
            +
                      false
         
     | 
| 
      
 20 
     | 
    
         
            +
                    end
         
     | 
| 
      
 21 
     | 
    
         
            +
                  end
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
                  def failure_message
         
     | 
| 
      
 24 
     | 
    
         
            +
                    if @timed_out
         
     | 
| 
      
 25 
     | 
    
         
            +
                      "expected process to exit with status #@expected_code, but it did not exit within 5 seconds"
         
     | 
| 
      
 26 
     | 
    
         
            +
                    else
         
     | 
| 
      
 27 
     | 
    
         
            +
                      "expected process to exit with status #{@expected_code}, but it exited with status #{@actual_code}"
         
     | 
| 
      
 28 
     | 
    
         
            +
                    end
         
     | 
| 
      
 29 
     | 
    
         
            +
                  end
         
     | 
| 
      
 30 
     | 
    
         
            +
             
     | 
| 
      
 31 
     | 
    
         
            +
                  def negative_failure_message
         
     | 
| 
      
 32 
     | 
    
         
            +
                    if @timed_out
         
     | 
| 
      
 33 
     | 
    
         
            +
                      "expected process to exit with status #@expected_code, but it did not exit within 5 seconds"
         
     | 
| 
      
 34 
     | 
    
         
            +
                    else
         
     | 
| 
      
 35 
     | 
    
         
            +
                      "expected process to not exit with status #{@expected_code}, but it did"
         
     | 
| 
      
 36 
     | 
    
         
            +
                    end
         
     | 
| 
      
 37 
     | 
    
         
            +
                  end
         
     | 
| 
      
 38 
     | 
    
         
            +
                end
         
     | 
| 
      
 39 
     | 
    
         
            +
              end
         
     | 
| 
      
 40 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,38 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module BlueShell
         
     | 
| 
      
 2 
     | 
    
         
            +
              module Matchers
         
     | 
| 
      
 3 
     | 
    
         
            +
                class OutputMatcher
         
     | 
| 
      
 4 
     | 
    
         
            +
                  attr_reader :timeout
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
                  def initialize(expected_output, timeout = 30)
         
     | 
| 
      
 7 
     | 
    
         
            +
                    @expected_output = expected_output
         
     | 
| 
      
 8 
     | 
    
         
            +
                    @timeout = timeout
         
     | 
| 
      
 9 
     | 
    
         
            +
                  end
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
                  def matches?(runner)
         
     | 
| 
      
 12 
     | 
    
         
            +
                    raise Errors::InvalidInputError unless runner.respond_to?(:expect)
         
     | 
| 
      
 13 
     | 
    
         
            +
                    @matched = runner.expect(@expected_output, @timeout)
         
     | 
| 
      
 14 
     | 
    
         
            +
                    @full_output = runner.output
         
     | 
| 
      
 15 
     | 
    
         
            +
                    !!@matched
         
     | 
| 
      
 16 
     | 
    
         
            +
                  end
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
                  def failure_message
         
     | 
| 
      
 19 
     | 
    
         
            +
                    if @expected_output.is_a?(Hash)
         
     | 
| 
      
 20 
     | 
    
         
            +
                      expected_keys = @expected_output.keys.map{|key| "'#{key}'"}.join(', ')
         
     | 
| 
      
 21 
     | 
    
         
            +
                      "expected one of #{expected_keys} to be printed, but it wasn't. full output:\n#@full_output"
         
     | 
| 
      
 22 
     | 
    
         
            +
                    else
         
     | 
| 
      
 23 
     | 
    
         
            +
                      "expected '#{@expected_output}' to be printed, but it wasn't. full output:\n#@full_output"
         
     | 
| 
      
 24 
     | 
    
         
            +
                    end
         
     | 
| 
      
 25 
     | 
    
         
            +
                  end
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
      
 27 
     | 
    
         
            +
                  def negative_failure_message
         
     | 
| 
      
 28 
     | 
    
         
            +
                    if @expected_output.is_a?(Hash)
         
     | 
| 
      
 29 
     | 
    
         
            +
                      match = @matched
         
     | 
| 
      
 30 
     | 
    
         
            +
                    else
         
     | 
| 
      
 31 
     | 
    
         
            +
                      match = @expected_output
         
     | 
| 
      
 32 
     | 
    
         
            +
                    end
         
     | 
| 
      
 33 
     | 
    
         
            +
             
     | 
| 
      
 34 
     | 
    
         
            +
                    "expected '#{match}' to not be printed, but it was. full output:\n#@full_output"
         
     | 
| 
      
 35 
     | 
    
         
            +
                  end
         
     | 
| 
      
 36 
     | 
    
         
            +
                end
         
     | 
| 
      
 37 
     | 
    
         
            +
              end
         
     | 
| 
      
 38 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,98 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'pty'
         
     | 
| 
      
 2 
     | 
    
         
            +
            require 'timeout'
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
            module BlueShell
         
     | 
| 
      
 5 
     | 
    
         
            +
              class Runner
         
     | 
| 
      
 6 
     | 
    
         
            +
                def initialize(*args)
         
     | 
| 
      
 7 
     | 
    
         
            +
                  @stdout, slave = PTY.open
         
     | 
| 
      
 8 
     | 
    
         
            +
                  system('stty raw', :in => slave)
         
     | 
| 
      
 9 
     | 
    
         
            +
                  read, @stdin = IO.pipe
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
                  @pid = spawn(*(args.push(:in => read, :out => slave, :err => slave)))
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
                  @expector = BufferedReaderExpector.new(@stdout, ENV['DEBUG_BACON'])
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
                  if block_given?
         
     | 
| 
      
 16 
     | 
    
         
            +
                    yield self
         
     | 
| 
      
 17 
     | 
    
         
            +
                  else
         
     | 
| 
      
 18 
     | 
    
         
            +
                    code = exit_code
         
     | 
| 
      
 19 
     | 
    
         
            +
                    raise Errors::NonZeroExitCodeError.new(code) unless code == 0
         
     | 
| 
      
 20 
     | 
    
         
            +
                  end
         
     | 
| 
      
 21 
     | 
    
         
            +
                end
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
                class << self
         
     | 
| 
      
 24 
     | 
    
         
            +
                  alias_method :run, :new
         
     | 
| 
      
 25 
     | 
    
         
            +
                end
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
      
 27 
     | 
    
         
            +
                def expect(matcher, timeout = 30)
         
     | 
| 
      
 28 
     | 
    
         
            +
                  case matcher
         
     | 
| 
      
 29 
     | 
    
         
            +
                  when Hash
         
     | 
| 
      
 30 
     | 
    
         
            +
                    expect_branches(matcher, timeout)
         
     | 
| 
      
 31 
     | 
    
         
            +
                  else
         
     | 
| 
      
 32 
     | 
    
         
            +
                    @expector.expect(matcher, timeout)
         
     | 
| 
      
 33 
     | 
    
         
            +
                  end
         
     | 
| 
      
 34 
     | 
    
         
            +
                end
         
     | 
| 
      
 35 
     | 
    
         
            +
             
     | 
| 
      
 36 
     | 
    
         
            +
                def send_keys(text_to_send)
         
     | 
| 
      
 37 
     | 
    
         
            +
                  @stdin.puts(text_to_send)
         
     | 
| 
      
 38 
     | 
    
         
            +
                end
         
     | 
| 
      
 39 
     | 
    
         
            +
             
     | 
| 
      
 40 
     | 
    
         
            +
                def exit_code
         
     | 
| 
      
 41 
     | 
    
         
            +
                  return @code if @code
         
     | 
| 
      
 42 
     | 
    
         
            +
             
     | 
| 
      
 43 
     | 
    
         
            +
                  code = nil
         
     | 
| 
      
 44 
     | 
    
         
            +
                  Timeout.timeout(5) do
         
     | 
| 
      
 45 
     | 
    
         
            +
                    _, code = Process.waitpid2(@pid)
         
     | 
| 
      
 46 
     | 
    
         
            +
                  end
         
     | 
| 
      
 47 
     | 
    
         
            +
             
     | 
| 
      
 48 
     | 
    
         
            +
                  @code = numeric_exit_code(code)
         
     | 
| 
      
 49 
     | 
    
         
            +
                end
         
     | 
| 
      
 50 
     | 
    
         
            +
             
     | 
| 
      
 51 
     | 
    
         
            +
                alias_method :wait_for_exit, :exit_code
         
     | 
| 
      
 52 
     | 
    
         
            +
             
     | 
| 
      
 53 
     | 
    
         
            +
                def exited?
         
     | 
| 
      
 54 
     | 
    
         
            +
                  !running?
         
     | 
| 
      
 55 
     | 
    
         
            +
                end
         
     | 
| 
      
 56 
     | 
    
         
            +
             
     | 
| 
      
 57 
     | 
    
         
            +
                def success?
         
     | 
| 
      
 58 
     | 
    
         
            +
                  @code.zero?
         
     | 
| 
      
 59 
     | 
    
         
            +
                end
         
     | 
| 
      
 60 
     | 
    
         
            +
             
     | 
| 
      
 61 
     | 
    
         
            +
                alias_method :successful?, :success?
         
     | 
| 
      
 62 
     | 
    
         
            +
             
     | 
| 
      
 63 
     | 
    
         
            +
                def running?
         
     | 
| 
      
 64 
     | 
    
         
            +
                  !!Process.getpgid(@pid)
         
     | 
| 
      
 65 
     | 
    
         
            +
                end
         
     | 
| 
      
 66 
     | 
    
         
            +
             
     | 
| 
      
 67 
     | 
    
         
            +
                def output
         
     | 
| 
      
 68 
     | 
    
         
            +
                  @expector.output
         
     | 
| 
      
 69 
     | 
    
         
            +
                end
         
     | 
| 
      
 70 
     | 
    
         
            +
             
     | 
| 
      
 71 
     | 
    
         
            +
                def debug
         
     | 
| 
      
 72 
     | 
    
         
            +
                  @expector.debug
         
     | 
| 
      
 73 
     | 
    
         
            +
                end
         
     | 
| 
      
 74 
     | 
    
         
            +
             
     | 
| 
      
 75 
     | 
    
         
            +
                def debug=(x)
         
     | 
| 
      
 76 
     | 
    
         
            +
                  @expector.debug = x
         
     | 
| 
      
 77 
     | 
    
         
            +
                end
         
     | 
| 
      
 78 
     | 
    
         
            +
             
     | 
| 
      
 79 
     | 
    
         
            +
                private
         
     | 
| 
      
 80 
     | 
    
         
            +
             
     | 
| 
      
 81 
     | 
    
         
            +
                def expect_branches(branches, timeout)
         
     | 
| 
      
 82 
     | 
    
         
            +
                  branch_names = /#{branches.keys.collect { |k| Regexp.quote(k) }.join('|')}/
         
     | 
| 
      
 83 
     | 
    
         
            +
                  expected = @expector.expect(branch_names, timeout)
         
     | 
| 
      
 84 
     | 
    
         
            +
                  return unless expected
         
     | 
| 
      
 85 
     | 
    
         
            +
             
     | 
| 
      
 86 
     | 
    
         
            +
                  data = expected.first.match(/(#{branch_names})$/)
         
     | 
| 
      
 87 
     | 
    
         
            +
                  matched = data[1]
         
     | 
| 
      
 88 
     | 
    
         
            +
                  branches[matched].call
         
     | 
| 
      
 89 
     | 
    
         
            +
                  matched
         
     | 
| 
      
 90 
     | 
    
         
            +
                end
         
     | 
| 
      
 91 
     | 
    
         
            +
             
     | 
| 
      
 92 
     | 
    
         
            +
                def numeric_exit_code(status)
         
     | 
| 
      
 93 
     | 
    
         
            +
                  status.exitstatus
         
     | 
| 
      
 94 
     | 
    
         
            +
                rescue NoMethodError
         
     | 
| 
      
 95 
     | 
    
         
            +
                  status
         
     | 
| 
      
 96 
     | 
    
         
            +
                end
         
     | 
| 
      
 97 
     | 
    
         
            +
              end
         
     | 
| 
      
 98 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,76 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'spec_helper'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module BlueShell
         
     | 
| 
      
 4 
     | 
    
         
            +
              module Matchers
         
     | 
| 
      
 5 
     | 
    
         
            +
                describe ExitCodeMatcher, :ruby19 => true do
         
     | 
| 
      
 6 
     | 
    
         
            +
                  let(:expected_code) { 0 }
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
                  subject { ExitCodeMatcher.new(expected_code) }
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
                  describe "#matches?" do
         
     | 
| 
      
 11 
     | 
    
         
            +
                    context "with something that isn't a runner" do
         
     | 
| 
      
 12 
     | 
    
         
            +
                      it "raises an exception" do
         
     | 
| 
      
 13 
     | 
    
         
            +
                        expect {
         
     | 
| 
      
 14 
     | 
    
         
            +
                          subject.matches?("c'est ne pas une specker runner")
         
     | 
| 
      
 15 
     | 
    
         
            +
                        }.to raise_exception(Errors::InvalidInputError)
         
     | 
| 
      
 16 
     | 
    
         
            +
                      end
         
     | 
| 
      
 17 
     | 
    
         
            +
                    end
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
                    context "with a valid runner" do
         
     | 
| 
      
 20 
     | 
    
         
            +
                      context "and the command exited with the expected exit code" do
         
     | 
| 
      
 21 
     | 
    
         
            +
                        it "returns true" do
         
     | 
| 
      
 22 
     | 
    
         
            +
                          BlueShell::Runner.run("true") do |runner|
         
     | 
| 
      
 23 
     | 
    
         
            +
                            subject.matches?(runner).should be_true
         
     | 
| 
      
 24 
     | 
    
         
            +
                          end
         
     | 
| 
      
 25 
     | 
    
         
            +
                        end
         
     | 
| 
      
 26 
     | 
    
         
            +
                      end
         
     | 
| 
      
 27 
     | 
    
         
            +
             
     | 
| 
      
 28 
     | 
    
         
            +
                      context "and the command exits with a different exit code" do
         
     | 
| 
      
 29 
     | 
    
         
            +
                        it "returns false" do
         
     | 
| 
      
 30 
     | 
    
         
            +
                          BlueShell::Runner.run("false") do |runner|
         
     | 
| 
      
 31 
     | 
    
         
            +
                            subject.matches?(runner).should be_false
         
     | 
| 
      
 32 
     | 
    
         
            +
                          end
         
     | 
| 
      
 33 
     | 
    
         
            +
                        end
         
     | 
| 
      
 34 
     | 
    
         
            +
                      end
         
     | 
| 
      
 35 
     | 
    
         
            +
             
     | 
| 
      
 36 
     | 
    
         
            +
                      context "and the command runs for a while" do
         
     | 
| 
      
 37 
     | 
    
         
            +
                        it "waits for it to exit" do
         
     | 
| 
      
 38 
     | 
    
         
            +
                          BlueShell::Runner.run("sleep 0.5") do |runner|
         
     | 
| 
      
 39 
     | 
    
         
            +
                            subject.matches?(runner).should be_true
         
     | 
| 
      
 40 
     | 
    
         
            +
                          end
         
     | 
| 
      
 41 
     | 
    
         
            +
                        end
         
     | 
| 
      
 42 
     | 
    
         
            +
                      end
         
     | 
| 
      
 43 
     | 
    
         
            +
                    end
         
     | 
| 
      
 44 
     | 
    
         
            +
                  end
         
     | 
| 
      
 45 
     | 
    
         
            +
             
     | 
| 
      
 46 
     | 
    
         
            +
                  context "failure messages" do
         
     | 
| 
      
 47 
     | 
    
         
            +
                    context "with a command that's exited" do
         
     | 
| 
      
 48 
     | 
    
         
            +
                      it "has a correct failure message" do
         
     | 
| 
      
 49 
     | 
    
         
            +
                        BlueShell::Runner.run("false") do |runner|
         
     | 
| 
      
 50 
     | 
    
         
            +
                          subject.matches?(runner)
         
     | 
| 
      
 51 
     | 
    
         
            +
                          runner.wait_for_exit
         
     | 
| 
      
 52 
     | 
    
         
            +
                          subject.failure_message.should == "expected process to exit with status 0, but it exited with status 1"
         
     | 
| 
      
 53 
     | 
    
         
            +
                        end
         
     | 
| 
      
 54 
     | 
    
         
            +
                      end
         
     | 
| 
      
 55 
     | 
    
         
            +
             
     | 
| 
      
 56 
     | 
    
         
            +
                      it "has a correct negative failure message" do
         
     | 
| 
      
 57 
     | 
    
         
            +
                        BlueShell::Runner.run("false") do |runner|
         
     | 
| 
      
 58 
     | 
    
         
            +
                          subject.matches?(runner)
         
     | 
| 
      
 59 
     | 
    
         
            +
                          runner.wait_for_exit
         
     | 
| 
      
 60 
     | 
    
         
            +
                          subject.negative_failure_message.should == "expected process to not exit with status 0, but it did"
         
     | 
| 
      
 61 
     | 
    
         
            +
                        end
         
     | 
| 
      
 62 
     | 
    
         
            +
                      end
         
     | 
| 
      
 63 
     | 
    
         
            +
                    end
         
     | 
| 
      
 64 
     | 
    
         
            +
             
     | 
| 
      
 65 
     | 
    
         
            +
                    context "with a command that's still running" do
         
     | 
| 
      
 66 
     | 
    
         
            +
                      it "waits for it to exit" do
         
     | 
| 
      
 67 
     | 
    
         
            +
                        BlueShell::Runner.run("ruby -e 'sleep 1; exit 1'") do |runner|
         
     | 
| 
      
 68 
     | 
    
         
            +
                          subject.matches?(runner)
         
     | 
| 
      
 69 
     | 
    
         
            +
                          subject.failure_message.should == "expected process to exit with status 0, but it exited with status 1"
         
     | 
| 
      
 70 
     | 
    
         
            +
                        end
         
     | 
| 
      
 71 
     | 
    
         
            +
                      end
         
     | 
| 
      
 72 
     | 
    
         
            +
                    end
         
     | 
| 
      
 73 
     | 
    
         
            +
                  end
         
     | 
| 
      
 74 
     | 
    
         
            +
                end
         
     | 
| 
      
 75 
     | 
    
         
            +
              end
         
     | 
| 
      
 76 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,79 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'spec_helper'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module BlueShell
         
     | 
| 
      
 4 
     | 
    
         
            +
              module Matchers
         
     | 
| 
      
 5 
     | 
    
         
            +
                describe OutputMatcher, :ruby19 => true do
         
     | 
| 
      
 6 
     | 
    
         
            +
                  let(:expected_output) { "expected_output" }
         
     | 
| 
      
 7 
     | 
    
         
            +
                  let(:timeout) { 1 }
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
                  subject { OutputMatcher.new(expected_output, timeout) }
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
                  describe "#matches?" do
         
     | 
| 
      
 12 
     | 
    
         
            +
                    context "with something that isn't a runner" do
         
     | 
| 
      
 13 
     | 
    
         
            +
                      it "raises an exception" do
         
     | 
| 
      
 14 
     | 
    
         
            +
                        expect {
         
     | 
| 
      
 15 
     | 
    
         
            +
                          subject.matches?("c'est ne pas une specker runner")
         
     | 
| 
      
 16 
     | 
    
         
            +
                        }.to raise_exception(Errors::InvalidInputError)
         
     | 
| 
      
 17 
     | 
    
         
            +
                      end
         
     | 
| 
      
 18 
     | 
    
         
            +
                    end
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
                    context "with a valid runner" do
         
     | 
| 
      
 21 
     | 
    
         
            +
                      context "when the expected output is in the process output" do
         
     | 
| 
      
 22 
     | 
    
         
            +
                        it "finds the expected output" do
         
     | 
| 
      
 23 
     | 
    
         
            +
                          BlueShell::Runner.run("echo -n expected_output") do |runner|
         
     | 
| 
      
 24 
     | 
    
         
            +
                            subject.matches?(runner).should be_true
         
     | 
| 
      
 25 
     | 
    
         
            +
                          end
         
     | 
| 
      
 26 
     | 
    
         
            +
                        end
         
     | 
| 
      
 27 
     | 
    
         
            +
                      end
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
                      context "when the expected output is not in the process output" do
         
     | 
| 
      
 30 
     | 
    
         
            +
                        let(:runner) { Runner.new('echo -n not_what_we_were_expecting') }
         
     | 
| 
      
 31 
     | 
    
         
            +
             
     | 
| 
      
 32 
     | 
    
         
            +
                        it "does not find the expected output" do
         
     | 
| 
      
 33 
     | 
    
         
            +
                          BlueShell::Runner.run("echo -n not_what_we_were_expecting") do |runner|
         
     | 
| 
      
 34 
     | 
    
         
            +
                            subject.matches?(runner).should be_false
         
     | 
| 
      
 35 
     | 
    
         
            +
                          end
         
     | 
| 
      
 36 
     | 
    
         
            +
                        end
         
     | 
| 
      
 37 
     | 
    
         
            +
                      end
         
     | 
| 
      
 38 
     | 
    
         
            +
                    end
         
     | 
| 
      
 39 
     | 
    
         
            +
                  end
         
     | 
| 
      
 40 
     | 
    
         
            +
             
     | 
| 
      
 41 
     | 
    
         
            +
                  context "failure messages" do
         
     | 
| 
      
 42 
     | 
    
         
            +
                    it "has a correct failure message" do
         
     | 
| 
      
 43 
     | 
    
         
            +
                      BlueShell::Runner.run("echo -n actual_output") do |runner|
         
     | 
| 
      
 44 
     | 
    
         
            +
                        subject.matches?(runner)
         
     | 
| 
      
 45 
     | 
    
         
            +
                        subject.failure_message.should == "expected 'expected_output' to be printed, but it wasn't. full output:\nactual_output"
         
     | 
| 
      
 46 
     | 
    
         
            +
                      end
         
     | 
| 
      
 47 
     | 
    
         
            +
                    end
         
     | 
| 
      
 48 
     | 
    
         
            +
             
     | 
| 
      
 49 
     | 
    
         
            +
                    it "has a correct negative failure message" do
         
     | 
| 
      
 50 
     | 
    
         
            +
                      BlueShell::Runner.run("echo -n actual_output") do |runner|
         
     | 
| 
      
 51 
     | 
    
         
            +
                        subject.matches?(runner)
         
     | 
| 
      
 52 
     | 
    
         
            +
                        subject.negative_failure_message.should == "expected 'expected_output' to not be printed, but it was. full output:\nactual_output"
         
     | 
| 
      
 53 
     | 
    
         
            +
                      end
         
     | 
| 
      
 54 
     | 
    
         
            +
                    end
         
     | 
| 
      
 55 
     | 
    
         
            +
             
     | 
| 
      
 56 
     | 
    
         
            +
                    context "when expecting branching output" do
         
     | 
| 
      
 57 
     | 
    
         
            +
                      let(:expected_output) { {
         
     | 
| 
      
 58 
     | 
    
         
            +
                        "expected_output" => proc {},
         
     | 
| 
      
 59 
     | 
    
         
            +
                        "other_expected_output" => proc {}
         
     | 
| 
      
 60 
     | 
    
         
            +
                      } }
         
     | 
| 
      
 61 
     | 
    
         
            +
             
     | 
| 
      
 62 
     | 
    
         
            +
                      it "has a correct failure message" do
         
     | 
| 
      
 63 
     | 
    
         
            +
                        BlueShell::Runner.run("echo -n actual_output") do |runner|
         
     | 
| 
      
 64 
     | 
    
         
            +
                          subject.matches?(runner)
         
     | 
| 
      
 65 
     | 
    
         
            +
                          subject.failure_message.should == "expected one of 'expected_output', 'other_expected_output' to be printed, but it wasn't. full output:\nactual_output"
         
     | 
| 
      
 66 
     | 
    
         
            +
                        end
         
     | 
| 
      
 67 
     | 
    
         
            +
                      end
         
     | 
| 
      
 68 
     | 
    
         
            +
             
     | 
| 
      
 69 
     | 
    
         
            +
                      it "has a correct negative failure message" do
         
     | 
| 
      
 70 
     | 
    
         
            +
                        BlueShell::Runner.run("echo -n expected_output") do |runner|
         
     | 
| 
      
 71 
     | 
    
         
            +
                          subject.matches?(runner)
         
     | 
| 
      
 72 
     | 
    
         
            +
                          subject.negative_failure_message.should == "expected 'expected_output' to not be printed, but it was. full output:\nexpected_output"
         
     | 
| 
      
 73 
     | 
    
         
            +
                        end
         
     | 
| 
      
 74 
     | 
    
         
            +
                      end
         
     | 
| 
      
 75 
     | 
    
         
            +
                    end
         
     | 
| 
      
 76 
     | 
    
         
            +
                  end
         
     | 
| 
      
 77 
     | 
    
         
            +
                end
         
     | 
| 
      
 78 
     | 
    
         
            +
              end
         
     | 
| 
      
 79 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,31 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'spec_helper'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module BlueShell
         
     | 
| 
      
 4 
     | 
    
         
            +
              describe Matchers do
         
     | 
| 
      
 5 
     | 
    
         
            +
                include Matchers
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
                describe "#say" do
         
     | 
| 
      
 8 
     | 
    
         
            +
                  it "returns an ExpectOutputMatcher" do
         
     | 
| 
      
 9 
     | 
    
         
            +
                    say("").should be_a(Matchers::OutputMatcher)
         
     | 
| 
      
 10 
     | 
    
         
            +
                  end
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
                  context "with an explicit timeout" do
         
     | 
| 
      
 13 
     | 
    
         
            +
                    it "returns an ExpectOutputMatcher" do
         
     | 
| 
      
 14 
     | 
    
         
            +
                      matcher = say("", 30)
         
     | 
| 
      
 15 
     | 
    
         
            +
                      matcher.should be_a(Matchers::OutputMatcher)
         
     | 
| 
      
 16 
     | 
    
         
            +
                      matcher.timeout.should == 30
         
     | 
| 
      
 17 
     | 
    
         
            +
                    end
         
     | 
| 
      
 18 
     | 
    
         
            +
                  end
         
     | 
| 
      
 19 
     | 
    
         
            +
                end
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
                describe "#have_exited_with" do
         
     | 
| 
      
 22 
     | 
    
         
            +
                  it "returns an ExitCodeMatcher" do
         
     | 
| 
      
 23 
     | 
    
         
            +
                    have_exited_with(1).should be_a(Matchers::ExitCodeMatcher)
         
     | 
| 
      
 24 
     | 
    
         
            +
                  end
         
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
      
 26 
     | 
    
         
            +
                  it "has synonyms" do
         
     | 
| 
      
 27 
     | 
    
         
            +
                    exit_with(1).should be_a(Matchers::ExitCodeMatcher)
         
     | 
| 
      
 28 
     | 
    
         
            +
                  end
         
     | 
| 
      
 29 
     | 
    
         
            +
                end
         
     | 
| 
      
 30 
     | 
    
         
            +
              end
         
     | 
| 
      
 31 
     | 
    
         
            +
            end
         
     | 
    
        data/spec/runner_spec.rb
    ADDED
    
    | 
         @@ -0,0 +1,194 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'spec_helper'
         
     | 
| 
      
 2 
     | 
    
         
            +
            require 'tempfile'
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
            module BlueShell
         
     | 
| 
      
 5 
     | 
    
         
            +
              describe Runner do
         
     | 
| 
      
 6 
     | 
    
         
            +
                let(:timeout) { 1 }
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
                describe "running a command" do
         
     | 
| 
      
 9 
     | 
    
         
            +
                  let(:file) do
         
     | 
| 
      
 10 
     | 
    
         
            +
                    file = Tempfile.new('blue-shell-runner')
         
     | 
| 
      
 11 
     | 
    
         
            +
                    sleep 1  # wait one second to make sure touching the file does something measurable
         
     | 
| 
      
 12 
     | 
    
         
            +
                    file
         
     | 
| 
      
 13 
     | 
    
         
            +
                  end
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
                  after { file.unlink }
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
                  context "with an invalid command" do
         
     | 
| 
      
 18 
     | 
    
         
            +
                    it "raises an exception" do
         
     | 
| 
      
 19 
     | 
    
         
            +
                      expect {
         
     | 
| 
      
 20 
     | 
    
         
            +
                        BlueShell::Runner.run("false")
         
     | 
| 
      
 21 
     | 
    
         
            +
                      }.to raise_error(Errors::NonZeroExitCodeError) { |error| error.exit_code.should == 1 }
         
     | 
| 
      
 22 
     | 
    
         
            +
                    end
         
     | 
| 
      
 23 
     | 
    
         
            +
                  end
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
                  context "with a valid command" do
         
     | 
| 
      
 26 
     | 
    
         
            +
                    it "runs a command" do
         
     | 
| 
      
 27 
     | 
    
         
            +
                      BlueShell::Runner.run("touch -a #{file.path}")
         
     | 
| 
      
 28 
     | 
    
         
            +
                      file.stat.atime.should > file.stat.mtime
         
     | 
| 
      
 29 
     | 
    
         
            +
                    end
         
     | 
| 
      
 30 
     | 
    
         
            +
                  end
         
     | 
| 
      
 31 
     | 
    
         
            +
                end
         
     | 
| 
      
 32 
     | 
    
         
            +
             
     | 
| 
      
 33 
     | 
    
         
            +
                describe "#success? and #successful?" do
         
     | 
| 
      
 34 
     | 
    
         
            +
                  context "when the command has a non-zero exit code" do
         
     | 
| 
      
 35 
     | 
    
         
            +
                    it "returns false" do
         
     | 
| 
      
 36 
     | 
    
         
            +
                      runner = BlueShell::Runner.run("false") { |runner|
         
     | 
| 
      
 37 
     | 
    
         
            +
                        runner.wait_for_exit
         
     | 
| 
      
 38 
     | 
    
         
            +
                      }
         
     | 
| 
      
 39 
     | 
    
         
            +
                      runner.should_not be_success
         
     | 
| 
      
 40 
     | 
    
         
            +
                      runner.should_not be_successful
         
     | 
| 
      
 41 
     | 
    
         
            +
                    end
         
     | 
| 
      
 42 
     | 
    
         
            +
                  end
         
     | 
| 
      
 43 
     | 
    
         
            +
             
     | 
| 
      
 44 
     | 
    
         
            +
                  context "when the command has a zero exit code" do
         
     | 
| 
      
 45 
     | 
    
         
            +
                    it "returns true" do
         
     | 
| 
      
 46 
     | 
    
         
            +
                      runner = BlueShell::Runner.run("true")
         
     | 
| 
      
 47 
     | 
    
         
            +
                      runner.should be_success
         
     | 
| 
      
 48 
     | 
    
         
            +
                      runner.should be_successful
         
     | 
| 
      
 49 
     | 
    
         
            +
                    end
         
     | 
| 
      
 50 
     | 
    
         
            +
                  end
         
     | 
| 
      
 51 
     | 
    
         
            +
                end
         
     | 
| 
      
 52 
     | 
    
         
            +
             
     | 
| 
      
 53 
     | 
    
         
            +
                describe "#expect" do
         
     | 
| 
      
 54 
     | 
    
         
            +
                  context "when the expected output shows up" do
         
     | 
| 
      
 55 
     | 
    
         
            +
                    it "returns a truthy value" do
         
     | 
| 
      
 56 
     | 
    
         
            +
                      BlueShell::Runner.run("echo -n foo") do |runner|
         
     | 
| 
      
 57 
     | 
    
         
            +
                        expect(runner.expect('foo')).to be_true
         
     | 
| 
      
 58 
     | 
    
         
            +
                      end
         
     | 
| 
      
 59 
     | 
    
         
            +
                    end
         
     | 
| 
      
 60 
     | 
    
         
            +
                  end
         
     | 
| 
      
 61 
     | 
    
         
            +
             
     | 
| 
      
 62 
     | 
    
         
            +
                  context "when the expected output never shows up" do
         
     | 
| 
      
 63 
     | 
    
         
            +
                    it "returns nil" do
         
     | 
| 
      
 64 
     | 
    
         
            +
                      BlueShell::Runner.run("echo the spanish inquisition") do |runner|
         
     | 
| 
      
 65 
     | 
    
         
            +
                        expect(runner.expect("something else", 0.5)).to be_nil
         
     | 
| 
      
 66 
     | 
    
         
            +
                      end
         
     | 
| 
      
 67 
     | 
    
         
            +
                    end
         
     | 
| 
      
 68 
     | 
    
         
            +
                  end
         
     | 
| 
      
 69 
     | 
    
         
            +
             
     | 
| 
      
 70 
     | 
    
         
            +
                  context "when the output eventually shows up" do
         
     | 
| 
      
 71 
     | 
    
         
            +
                    it "returns a truthy value" do
         
     | 
| 
      
 72 
     | 
    
         
            +
                      BlueShell::Runner.run("ruby #{asset("pause.rb")}") do |runner|
         
     | 
| 
      
 73 
     | 
    
         
            +
                        expect(runner.expect("finished")).to be_true
         
     | 
| 
      
 74 
     | 
    
         
            +
                      end
         
     | 
| 
      
 75 
     | 
    
         
            +
                    end
         
     | 
| 
      
 76 
     | 
    
         
            +
                  end
         
     | 
| 
      
 77 
     | 
    
         
            +
             
     | 
| 
      
 78 
     | 
    
         
            +
                  context "backspace" do
         
     | 
| 
      
 79 
     | 
    
         
            +
                    it "respects the backspace character" do
         
     | 
| 
      
 80 
     | 
    
         
            +
                      BlueShell::Runner.run("ruby -e 'puts \"foo a\\bbar\"'") do |runner|
         
     | 
| 
      
 81 
     | 
    
         
            +
                        expect(runner.expect("foo bar")).to be_true
         
     | 
| 
      
 82 
     | 
    
         
            +
                      end
         
     | 
| 
      
 83 
     | 
    
         
            +
                    end
         
     | 
| 
      
 84 
     | 
    
         
            +
             
     | 
| 
      
 85 
     | 
    
         
            +
                    it "does not go beyond the beginning of the line" do
         
     | 
| 
      
 86 
     | 
    
         
            +
                      BlueShell::Runner.run("ruby -e 'print \"foo abc\nx\\b\\bd\"'") do |runner|
         
     | 
| 
      
 87 
     | 
    
         
            +
                        expect(runner.expect("foo abc\nd")).to be_true
         
     | 
| 
      
 88 
     | 
    
         
            +
                      end
         
     | 
| 
      
 89 
     | 
    
         
            +
                    end
         
     | 
| 
      
 90 
     | 
    
         
            +
             
     | 
| 
      
 91 
     | 
    
         
            +
                    it "does not go beyond the beginning of the string" do
         
     | 
| 
      
 92 
     | 
    
         
            +
                      BlueShell::Runner.run("ruby -e 'print \"f\\b\\bbar\"'") do |runner|
         
     | 
| 
      
 93 
     | 
    
         
            +
                        expect(runner.expect("bar")).to be_true
         
     | 
| 
      
 94 
     | 
    
         
            +
                      end
         
     | 
| 
      
 95 
     | 
    
         
            +
                    end
         
     | 
| 
      
 96 
     | 
    
         
            +
             
     | 
| 
      
 97 
     | 
    
         
            +
                    it "leaves backspaced characters in the buffer until they're overwritten" do
         
     | 
| 
      
 98 
     | 
    
         
            +
                      BlueShell::Runner.run("ruby -e 'print \"foo abc\\b\\bd\"'") do |runner|
         
     | 
| 
      
 99 
     | 
    
         
            +
                        expect(runner.expect("foo adc")).to be_true
         
     | 
| 
      
 100 
     | 
    
         
            +
                      end
         
     | 
| 
      
 101 
     | 
    
         
            +
                    end
         
     | 
| 
      
 102 
     | 
    
         
            +
                  end
         
     | 
| 
      
 103 
     | 
    
         
            +
             
     | 
| 
      
 104 
     | 
    
         
            +
                  context "ansi escape sequences" do
         
     | 
| 
      
 105 
     | 
    
         
            +
                    it "filters ansi color sequences" do
         
     | 
| 
      
 106 
     | 
    
         
            +
                      BlueShell::Runner.run("ruby -e 'puts \"\\e[36mblue\\e[0m thing\"'") do |runner|
         
     | 
| 
      
 107 
     | 
    
         
            +
                        expect(runner.expect("blue thing")).to be_true
         
     | 
| 
      
 108 
     | 
    
         
            +
                      end
         
     | 
| 
      
 109 
     | 
    
         
            +
                    end
         
     | 
| 
      
 110 
     | 
    
         
            +
                  end
         
     | 
| 
      
 111 
     | 
    
         
            +
             
     | 
| 
      
 112 
     | 
    
         
            +
                  context "expecting multiple branches" do
         
     | 
| 
      
 113 
     | 
    
         
            +
                    context "and one of them matches" do
         
     | 
| 
      
 114 
     | 
    
         
            +
                      it "can be passed a hash of values with callbacks, and returns the matched key" do
         
     | 
| 
      
 115 
     | 
    
         
            +
                        BlueShell::Runner.run("echo 1 3") do |runner|
         
     | 
| 
      
 116 
     | 
    
         
            +
                          branches = {
         
     | 
| 
      
 117 
     | 
    
         
            +
                            "1" => proc { 1 },
         
     | 
| 
      
 118 
     | 
    
         
            +
                            "2" => proc { 2 },
         
     | 
| 
      
 119 
     | 
    
         
            +
                            "3" => proc { 3 }
         
     | 
| 
      
 120 
     | 
    
         
            +
                          }
         
     | 
| 
      
 121 
     | 
    
         
            +
             
     | 
| 
      
 122 
     | 
    
         
            +
                          expect(runner.expect(branches)).to eq "1"
         
     | 
| 
      
 123 
     | 
    
         
            +
                          expect(runner.expect(branches)).to eq "3"
         
     | 
| 
      
 124 
     | 
    
         
            +
                        end
         
     | 
| 
      
 125 
     | 
    
         
            +
                      end
         
     | 
| 
      
 126 
     | 
    
         
            +
             
     | 
| 
      
 127 
     | 
    
         
            +
                      it "calls the matched callback" do
         
     | 
| 
      
 128 
     | 
    
         
            +
                        callback = mock!
         
     | 
| 
      
 129 
     | 
    
         
            +
                        BlueShell::Runner.run("echo 1 3") do |runner|
         
     | 
| 
      
 130 
     | 
    
         
            +
                          branches = {
         
     | 
| 
      
 131 
     | 
    
         
            +
                            "1" => proc { callback }
         
     | 
| 
      
 132 
     | 
    
         
            +
                          }
         
     | 
| 
      
 133 
     | 
    
         
            +
                          runner.expect(branches)
         
     | 
| 
      
 134 
     | 
    
         
            +
                        end
         
     | 
| 
      
 135 
     | 
    
         
            +
                      end
         
     | 
| 
      
 136 
     | 
    
         
            +
                    end
         
     | 
| 
      
 137 
     | 
    
         
            +
             
     | 
| 
      
 138 
     | 
    
         
            +
                    context "and none of them match" do
         
     | 
| 
      
 139 
     | 
    
         
            +
                      it "returns nil when none of the branches match" do
         
     | 
| 
      
 140 
     | 
    
         
            +
                        BlueShell::Runner.run("echo not_a_number") do |runner|
         
     | 
| 
      
 141 
     | 
    
         
            +
                          expect(runner.expect({"1" => proc { 1 }}, timeout)).to be_nil
         
     | 
| 
      
 142 
     | 
    
         
            +
                        end
         
     | 
| 
      
 143 
     | 
    
         
            +
                      end
         
     | 
| 
      
 144 
     | 
    
         
            +
                    end
         
     | 
| 
      
 145 
     | 
    
         
            +
                  end
         
     | 
| 
      
 146 
     | 
    
         
            +
                end
         
     | 
| 
      
 147 
     | 
    
         
            +
             
     | 
| 
      
 148 
     | 
    
         
            +
                describe "#output" do
         
     | 
| 
      
 149 
     | 
    
         
            +
                  it "makes the entire command output (so far) available" do
         
     | 
| 
      
 150 
     | 
    
         
            +
                    BlueShell::Runner.run("echo 0 1 2 3") do |runner|
         
     | 
| 
      
 151 
     | 
    
         
            +
                      runner.expect("1")
         
     | 
| 
      
 152 
     | 
    
         
            +
                      runner.expect("3")
         
     | 
| 
      
 153 
     | 
    
         
            +
                      expect(runner.output).to eq "0 1 2 3"
         
     | 
| 
      
 154 
     | 
    
         
            +
                    end
         
     | 
| 
      
 155 
     | 
    
         
            +
             
     | 
| 
      
 156 
     | 
    
         
            +
                  end
         
     | 
| 
      
 157 
     | 
    
         
            +
                end
         
     | 
| 
      
 158 
     | 
    
         
            +
             
     | 
| 
      
 159 
     | 
    
         
            +
                describe "#send_keys" do
         
     | 
| 
      
 160 
     | 
    
         
            +
                  it "sends input and expects more output afterward" do
         
     | 
| 
      
 161 
     | 
    
         
            +
                    BlueShell::Runner.run("ruby #{asset("input.rb")}") do |runner|
         
     | 
| 
      
 162 
     | 
    
         
            +
                      expect(runner.expect("started")).to be_true
         
     | 
| 
      
 163 
     | 
    
         
            +
                      runner.send_keys("foo")
         
     | 
| 
      
 164 
     | 
    
         
            +
                      expect(runner.expect("foo")).to be_true
         
     | 
| 
      
 165 
     | 
    
         
            +
                    end
         
     | 
| 
      
 166 
     | 
    
         
            +
                  end
         
     | 
| 
      
 167 
     | 
    
         
            +
                end
         
     | 
| 
      
 168 
     | 
    
         
            +
             
     | 
| 
      
 169 
     | 
    
         
            +
                context "#exit_code" do
         
     | 
| 
      
 170 
     | 
    
         
            +
                  it "returns the exit code" do
         
     | 
| 
      
 171 
     | 
    
         
            +
                    BlueShell::Runner.run("ruby -e 'exit 42'") do |runner|
         
     | 
| 
      
 172 
     | 
    
         
            +
                      runner.wait_for_exit
         
     | 
| 
      
 173 
     | 
    
         
            +
                      expect(runner.exit_code).to eq(42)
         
     | 
| 
      
 174 
     | 
    
         
            +
                    end
         
     | 
| 
      
 175 
     | 
    
         
            +
                  end
         
     | 
| 
      
 176 
     | 
    
         
            +
             
     | 
| 
      
 177 
     | 
    
         
            +
                  context "when the command is still running" do
         
     | 
| 
      
 178 
     | 
    
         
            +
                    it "waits for the command to exit" do
         
     | 
| 
      
 179 
     | 
    
         
            +
                      BlueShell::Runner.run("sleep 0.5") do |runner|
         
     | 
| 
      
 180 
     | 
    
         
            +
                        expect(runner.exit_code).to eq(0)
         
     | 
| 
      
 181 
     | 
    
         
            +
                      end
         
     | 
| 
      
 182 
     | 
    
         
            +
                    end
         
     | 
| 
      
 183 
     | 
    
         
            +
                  end
         
     | 
| 
      
 184 
     | 
    
         
            +
                end
         
     | 
| 
      
 185 
     | 
    
         
            +
             
     | 
| 
      
 186 
     | 
    
         
            +
                context "#exited?" do
         
     | 
| 
      
 187 
     | 
    
         
            +
                  it "returns false if the command is still running" do
         
     | 
| 
      
 188 
     | 
    
         
            +
                    BlueShell::Runner.run("sleep 10") do |runner|
         
     | 
| 
      
 189 
     | 
    
         
            +
                      expect(runner.exited?).to eq false
         
     | 
| 
      
 190 
     | 
    
         
            +
                    end
         
     | 
| 
      
 191 
     | 
    
         
            +
                  end
         
     | 
| 
      
 192 
     | 
    
         
            +
                end
         
     | 
| 
      
 193 
     | 
    
         
            +
              end
         
     | 
| 
      
 194 
     | 
    
         
            +
            end
         
     | 
    
        data/spec/spec_helper.rb
    ADDED
    
    
    
        metadata
    ADDED
    
    | 
         @@ -0,0 +1,122 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            --- !ruby/object:Gem::Specification
         
     | 
| 
      
 2 
     | 
    
         
            +
            name: blue-shell
         
     | 
| 
      
 3 
     | 
    
         
            +
            version: !ruby/object:Gem::Version
         
     | 
| 
      
 4 
     | 
    
         
            +
              version: 0.0.1
         
     | 
| 
      
 5 
     | 
    
         
            +
              prerelease: 
         
     | 
| 
      
 6 
     | 
    
         
            +
            platform: ruby
         
     | 
| 
      
 7 
     | 
    
         
            +
            authors:
         
     | 
| 
      
 8 
     | 
    
         
            +
            - Pivotal Labs
         
     | 
| 
      
 9 
     | 
    
         
            +
            - Cloud Foundry
         
     | 
| 
      
 10 
     | 
    
         
            +
            autorequire: 
         
     | 
| 
      
 11 
     | 
    
         
            +
            bindir: bin
         
     | 
| 
      
 12 
     | 
    
         
            +
            cert_chain: []
         
     | 
| 
      
 13 
     | 
    
         
            +
            date: 2013-04-09 00:00:00.000000000 Z
         
     | 
| 
      
 14 
     | 
    
         
            +
            dependencies:
         
     | 
| 
      
 15 
     | 
    
         
            +
            - !ruby/object:Gem::Dependency
         
     | 
| 
      
 16 
     | 
    
         
            +
              name: rspec
         
     | 
| 
      
 17 
     | 
    
         
            +
              requirement: !ruby/object:Gem::Requirement
         
     | 
| 
      
 18 
     | 
    
         
            +
                none: false
         
     | 
| 
      
 19 
     | 
    
         
            +
                requirements:
         
     | 
| 
      
 20 
     | 
    
         
            +
                - - ! '>='
         
     | 
| 
      
 21 
     | 
    
         
            +
                  - !ruby/object:Gem::Version
         
     | 
| 
      
 22 
     | 
    
         
            +
                    version: '0'
         
     | 
| 
      
 23 
     | 
    
         
            +
              type: :runtime
         
     | 
| 
      
 24 
     | 
    
         
            +
              prerelease: false
         
     | 
| 
      
 25 
     | 
    
         
            +
              version_requirements: !ruby/object:Gem::Requirement
         
     | 
| 
      
 26 
     | 
    
         
            +
                none: false
         
     | 
| 
      
 27 
     | 
    
         
            +
                requirements:
         
     | 
| 
      
 28 
     | 
    
         
            +
                - - ! '>='
         
     | 
| 
      
 29 
     | 
    
         
            +
                  - !ruby/object:Gem::Version
         
     | 
| 
      
 30 
     | 
    
         
            +
                    version: '0'
         
     | 
| 
      
 31 
     | 
    
         
            +
            - !ruby/object:Gem::Dependency
         
     | 
| 
      
 32 
     | 
    
         
            +
              name: rake
         
     | 
| 
      
 33 
     | 
    
         
            +
              requirement: !ruby/object:Gem::Requirement
         
     | 
| 
      
 34 
     | 
    
         
            +
                none: false
         
     | 
| 
      
 35 
     | 
    
         
            +
                requirements:
         
     | 
| 
      
 36 
     | 
    
         
            +
                - - ! '>='
         
     | 
| 
      
 37 
     | 
    
         
            +
                  - !ruby/object:Gem::Version
         
     | 
| 
      
 38 
     | 
    
         
            +
                    version: '0'
         
     | 
| 
      
 39 
     | 
    
         
            +
              type: :development
         
     | 
| 
      
 40 
     | 
    
         
            +
              prerelease: false
         
     | 
| 
      
 41 
     | 
    
         
            +
              version_requirements: !ruby/object:Gem::Requirement
         
     | 
| 
      
 42 
     | 
    
         
            +
                none: false
         
     | 
| 
      
 43 
     | 
    
         
            +
                requirements:
         
     | 
| 
      
 44 
     | 
    
         
            +
                - - ! '>='
         
     | 
| 
      
 45 
     | 
    
         
            +
                  - !ruby/object:Gem::Version
         
     | 
| 
      
 46 
     | 
    
         
            +
                    version: '0'
         
     | 
| 
      
 47 
     | 
    
         
            +
            - !ruby/object:Gem::Dependency
         
     | 
| 
      
 48 
     | 
    
         
            +
              name: rr
         
     | 
| 
      
 49 
     | 
    
         
            +
              requirement: !ruby/object:Gem::Requirement
         
     | 
| 
      
 50 
     | 
    
         
            +
                none: false
         
     | 
| 
      
 51 
     | 
    
         
            +
                requirements:
         
     | 
| 
      
 52 
     | 
    
         
            +
                - - ! '>='
         
     | 
| 
      
 53 
     | 
    
         
            +
                  - !ruby/object:Gem::Version
         
     | 
| 
      
 54 
     | 
    
         
            +
                    version: '0'
         
     | 
| 
      
 55 
     | 
    
         
            +
              type: :development
         
     | 
| 
      
 56 
     | 
    
         
            +
              prerelease: false
         
     | 
| 
      
 57 
     | 
    
         
            +
              version_requirements: !ruby/object:Gem::Requirement
         
     | 
| 
      
 58 
     | 
    
         
            +
                none: false
         
     | 
| 
      
 59 
     | 
    
         
            +
                requirements:
         
     | 
| 
      
 60 
     | 
    
         
            +
                - - ! '>='
         
     | 
| 
      
 61 
     | 
    
         
            +
                  - !ruby/object:Gem::Version
         
     | 
| 
      
 62 
     | 
    
         
            +
                    version: '0'
         
     | 
| 
      
 63 
     | 
    
         
            +
            description: 
         
     | 
| 
      
 64 
     | 
    
         
            +
            email:
         
     | 
| 
      
 65 
     | 
    
         
            +
            - cfpi-frontend@googlegroups.com
         
     | 
| 
      
 66 
     | 
    
         
            +
            executables: []
         
     | 
| 
      
 67 
     | 
    
         
            +
            extensions: []
         
     | 
| 
      
 68 
     | 
    
         
            +
            extra_rdoc_files: []
         
     | 
| 
      
 69 
     | 
    
         
            +
            files:
         
     | 
| 
      
 70 
     | 
    
         
            +
            - LICENSE
         
     | 
| 
      
 71 
     | 
    
         
            +
            - Rakefile
         
     | 
| 
      
 72 
     | 
    
         
            +
            - lib/blue-shell/buffered_reader_expector.rb
         
     | 
| 
      
 73 
     | 
    
         
            +
            - lib/blue-shell/errors.rb
         
     | 
| 
      
 74 
     | 
    
         
            +
            - lib/blue-shell/matchers/exit_code_matcher.rb
         
     | 
| 
      
 75 
     | 
    
         
            +
            - lib/blue-shell/matchers/output_matcher.rb
         
     | 
| 
      
 76 
     | 
    
         
            +
            - lib/blue-shell/matchers.rb
         
     | 
| 
      
 77 
     | 
    
         
            +
            - lib/blue-shell/runner.rb
         
     | 
| 
      
 78 
     | 
    
         
            +
            - lib/blue-shell/version.rb
         
     | 
| 
      
 79 
     | 
    
         
            +
            - lib/blue-shell.rb
         
     | 
| 
      
 80 
     | 
    
         
            +
            - spec/assets/input.rb
         
     | 
| 
      
 81 
     | 
    
         
            +
            - spec/assets/pause.rb
         
     | 
| 
      
 82 
     | 
    
         
            +
            - spec/matchers/exit_code_matcher_spec.rb
         
     | 
| 
      
 83 
     | 
    
         
            +
            - spec/matchers/output_matcher_spec.rb
         
     | 
| 
      
 84 
     | 
    
         
            +
            - spec/matchers_spec.rb
         
     | 
| 
      
 85 
     | 
    
         
            +
            - spec/runner_spec.rb
         
     | 
| 
      
 86 
     | 
    
         
            +
            - spec/spec_helper.rb
         
     | 
| 
      
 87 
     | 
    
         
            +
            - spec/support/helpers.rb
         
     | 
| 
      
 88 
     | 
    
         
            +
            homepage: http://github.com/pivotal/blue-shell
         
     | 
| 
      
 89 
     | 
    
         
            +
            licenses:
         
     | 
| 
      
 90 
     | 
    
         
            +
            - MIT
         
     | 
| 
      
 91 
     | 
    
         
            +
            post_install_message: 
         
     | 
| 
      
 92 
     | 
    
         
            +
            rdoc_options: []
         
     | 
| 
      
 93 
     | 
    
         
            +
            require_paths:
         
     | 
| 
      
 94 
     | 
    
         
            +
            - lib
         
     | 
| 
      
 95 
     | 
    
         
            +
            required_ruby_version: !ruby/object:Gem::Requirement
         
     | 
| 
      
 96 
     | 
    
         
            +
              none: false
         
     | 
| 
      
 97 
     | 
    
         
            +
              requirements:
         
     | 
| 
      
 98 
     | 
    
         
            +
              - - ! '>='
         
     | 
| 
      
 99 
     | 
    
         
            +
                - !ruby/object:Gem::Version
         
     | 
| 
      
 100 
     | 
    
         
            +
                  version: '0'
         
     | 
| 
      
 101 
     | 
    
         
            +
            required_rubygems_version: !ruby/object:Gem::Requirement
         
     | 
| 
      
 102 
     | 
    
         
            +
              none: false
         
     | 
| 
      
 103 
     | 
    
         
            +
              requirements:
         
     | 
| 
      
 104 
     | 
    
         
            +
              - - ! '>='
         
     | 
| 
      
 105 
     | 
    
         
            +
                - !ruby/object:Gem::Version
         
     | 
| 
      
 106 
     | 
    
         
            +
                  version: '0'
         
     | 
| 
      
 107 
     | 
    
         
            +
            requirements: []
         
     | 
| 
      
 108 
     | 
    
         
            +
            rubyforge_project: 
         
     | 
| 
      
 109 
     | 
    
         
            +
            rubygems_version: 1.8.24
         
     | 
| 
      
 110 
     | 
    
         
            +
            signing_key: 
         
     | 
| 
      
 111 
     | 
    
         
            +
            specification_version: 3
         
     | 
| 
      
 112 
     | 
    
         
            +
            summary: Friendly command-line test runner and matchers for shell scripting in ruby
         
     | 
| 
      
 113 
     | 
    
         
            +
              using rspec.
         
     | 
| 
      
 114 
     | 
    
         
            +
            test_files:
         
     | 
| 
      
 115 
     | 
    
         
            +
            - spec/assets/input.rb
         
     | 
| 
      
 116 
     | 
    
         
            +
            - spec/assets/pause.rb
         
     | 
| 
      
 117 
     | 
    
         
            +
            - spec/matchers/exit_code_matcher_spec.rb
         
     | 
| 
      
 118 
     | 
    
         
            +
            - spec/matchers/output_matcher_spec.rb
         
     | 
| 
      
 119 
     | 
    
         
            +
            - spec/matchers_spec.rb
         
     | 
| 
      
 120 
     | 
    
         
            +
            - spec/runner_spec.rb
         
     | 
| 
      
 121 
     | 
    
         
            +
            - spec/spec_helper.rb
         
     | 
| 
      
 122 
     | 
    
         
            +
            - spec/support/helpers.rb
         
     |