class Slightish::TestSuite

Attributes

name[R]
path[R]
sandbox_template_dir[R]
test_cases[R]

Public Class Methods

from_file(path, sandbox_template_dir: nil) click to toggle source
# File lib/slightish/test_suite.rb, line 8
def self.from_file(path, sandbox_template_dir: nil)
  new(path, File.read(path), sandbox_template_dir: sandbox_template_dir)
end
new(path, contents, sandbox_template_dir: nil) click to toggle source
# File lib/slightish/test_suite.rb, line 12
def initialize(path, contents, sandbox_template_dir: nil)
  @path = path
  @name = File.basename(path)
  @sandbox_template_dir = sandbox_template_dir

  parse(path, contents)
end

Public Instance Methods

failed?() click to toggle source
# File lib/slightish/test_suite.rb, line 44
def failed?
  @test_cases.any?(&:failed?)
end
failed_count() click to toggle source
# File lib/slightish/test_suite.rb, line 52
def failed_count
  @test_cases.count(&:failed?)
end
failure_description() click to toggle source
# File lib/slightish/test_suite.rb, line 30
def failure_description
  res = ''
  @test_cases.select(&:failed?).each do |test|
    res += "❌  #{test.source_description}\n".bold
    res += test.failure_description + "\n\n"
  end

  res
end
passed?() click to toggle source
# File lib/slightish/test_suite.rb, line 40
def passed?
  @test_cases.all?(&:passed?)
end
passed_count() click to toggle source
# File lib/slightish/test_suite.rb, line 48
def passed_count
  @test_cases.count(&:passed?)
end
run() click to toggle source
# File lib/slightish/test_suite.rb, line 20
def run
  sandbox = Slightish::Sandbox.new(template_dir: @sandbox_template_dir)

  begin
    @test_cases.each { |test| test.run(sandbox) }
  ensure
    sandbox.delete
  end
end

Private Instance Methods

parse(file_name, file_contents) click to toggle source
# File lib/slightish/test_suite.rb, line 94
def parse(file_name, file_contents)
  @test_cases = []

  current_case = nil
  state = ParseState::AWAITING_COMMAND

  file_contents.each_line.with_index(1) do |line, line_number|
    if state == ParseState::READING_MULTILINE_COMMAND
      if line =~ /^(?<cmd>.*)\\$/
        # multiline input continues
        current_case.append_command(Regexp.last_match(:cmd))
        current_case.end_line = line_number

        state = ParseState::READING_MULTILINE_COMMAND
      else
        # final line of multiline input; consume the whole thing
        current_case.append_command(line.chomp)
        current_case.end_line = line_number

        state = ParseState::AWAITING_RESULT_OR_COMMAND
      end

      next
    end

    # Skip lines not intended for us
    next unless line =~ /^[$|@?] /

    if state == ParseState::AWAITING_RESULT_OR_COMMAND
      if line =~ /^\| (?<output>.*)$/
        # accumulating expected stdout
        current_case.append_expected_output(Regexp.last_match(:output))
        current_case.end_line = line_number

        state = ParseState::AWAITING_RESULT_OR_COMMAND
        next
      end
    end

    if [ParseState::AWAITING_RESULT_OR_COMMAND, ParseState::AWAITING_STDERR_OR_EXIT_CODE_OR_COMMAND].include?(state)
      if line =~ /^@ (?<error_output>.*)$/
        # accumulating expected stderr
        current_case.append_expected_error_output(Regexp.last_match(:error_output))
        current_case.end_line = line_number

        state = ParseState::AWAITING_STDERR_OR_EXIT_CODE_OR_COMMAND
        next
      elsif line =~ /\? (?<exit_code>\d+)$/
        # got exit code; only possible option from here is a new command
        current_case.expected_exit_code = Regexp.last_match(:exit_code).to_i
        current_case.end_line = line_number

        state = ParseState::AWAITING_COMMAND
        next
      end
    end

    # state is anything, and we are looking for a new command
    unless line =~ /^\$ (?<cmd>.+?)(?<multiline>\\?)$/
      raise SyntaxError, "invalid line in test file #{file_name}:#{line_number}; expected a '$ <command>' line"
    end

    current_case = Slightish::TestCase.new(file_name)
    current_case.start_line = current_case.end_line = line_number
    @test_cases << current_case

    current_case.append_command(Regexp.last_match(:cmd))

    # entering multiline mode if we matched the slash
    multiline = Regexp.last_match(:multiline) == '\\'
    state = multiline ? ParseState::READING_MULTILINE_COMMAND : ParseState::AWAITING_RESULT_OR_COMMAND
  end
end