require "./version.rb"

# Tests for main.rb command line option handling and the -p / --pretty_print
# output format (the latter is the only coverage of run_and_do_io with pp=true on
# the ruby interpreter; examples_engine_test.rb only exercises -p via the engine).

$fail = false
def expect(desc, ok)
  return if ok
  STDERR.puts "FAIL: #{desc}"
  $fail = true
end

prog = "test/cli_prog.iog"
File.write(prog, "1,2,3")

# -v / --version print the version and exit 0 (before any file/usage checks)
%w[-v --version].each{|flag|
  out = `ruby main.rb #{flag} </dev/null 2>&1`
  expect("#{flag} prints version", out == "#{Version}\n")
  expect("#{flag} exits 0", $?.exitstatus == 0)
}

# no file arg -> usage error, exit 1
out = `ruby main.rb </dev/null 2>&1`
expect("no args reports usage", out.include?("usage:"))
expect("no args exits 1", $?.exitstatus == 1)

# unknown option -> reported, then usage, exit 1
out = `ruby main.rb -z #{prog} </dev/null 2>&1`
expect("unknown option reported", out.include?("unknown options: -z"))
expect("unknown option shows usage", out.include?("usage:"))
expect("unknown option exits 1", $?.exitstatus == 1)

# more than one file -> error, exit 1
out = `ruby main.rb #{prog} #{prog} </dev/null 2>&1`
expect("two files rejected", out.include?("mustn't give more than one file arg"))
expect("two files exits 1", $?.exitstatus == 1)

# unreadable file -> error, exit 1
out = `ruby main.rb test/does_not_exist.iog </dev/null 2>&1`
expect("missing file reported", out.include?("cannot read file 'test/does_not_exist.iog'"))
expect("missing file exits 1", $?.exitstatus == 1)

# default output joins by newline; -p / --pretty_print uses the `show` form
expect("default output", `ruby main.rb #{prog} </dev/null` == "1\n2\n3\n")
expect("-p pretty prints", `ruby main.rb -p #{prog} </dev/null` == "[1,2,3]\n")
expect("--pretty_print pretty prints", `ruby main.rb --pretty_print #{prog} </dev/null` == "[1,2,3]\n")

# a program whose `$` is inside a loop closed by a later-matched `>` must not consult
# stdin (the parse passes before bracket matching see the loop as already closed, which
# used to make `$` check for input, blocking forever when run interactively)
require "timeout"
File.write(prog, "0i1+$+>5k")
out = IO.popen("ruby main.rb #{prog}", "r+"){|io| # keep io's stdin pipe open, like a terminal
  begin
    Timeout.timeout(10){ io.read }
  rescue Timeout::Error
    Process.kill("KILL", io.pid)
    "TIMEOUT: blocked reading stdin"
  end
}
expect("$ in later-matched loop doesn't block on stdin", out == "0\n1\n3\n7\n15\n")

File.delete(prog)

exit 1 if $fail
puts "PASS cli tests"
