require 'stringio'
require 'timeout'
require "./run.rb"

`ghc -O engine.hs`

special_things = '$ ! > , : ; ] = { f F m M i I e E nil del superpad implicit input type show set let del 1,2,3 0,0 1,2,,3,4 "asdf" "" 0 1000 5~sqrt'.split

all = ["\n",*' '..'~'] + special_things*3

n = 100000

def run_engine(prog, input)
  File.open("prog.iog", "w"){|f| f << prog }
  File.open("input.txt", "w"){|f| f << input }
  begin
    Timeout::timeout(0.5) {
    `(ruby main.rb prog.iog -e > test.ism && engine test.ism < input.txt) 2>&1`.
              sub(/engine: (.*?)\nCallStack.*\Z/m,'\1')
    }
  rescue Timeout::Error
    "timeout"
  end
end

3.upto(8){|program_size|
  ([all.size**program_size,n].min).times{|i|
    input = ["","\n","ab12","12","1 2","1 2\n3","c","ab\n\n2"].sample
    STDERR.puts

    program = program_size.times.map{ all.sample }*" "

    STDERR.puts "input: %p" % input
    program.gsub!(' ,',',')
    $stdout = StringIO.new("")
    errored = false
    begin
      STDERR.puts "program: " + program
      Timeout::timeout(0.05) {
        run_and_do_io(program, StringIO.new(input), false, false)
      }
    rescue IogiiError => e
      errored = true
      $stdout << e.message
    rescue Timeout::Error
      errored = true
      STDERR.puts "timeout"
      next
    rescue => e
      STDERR.puts "failed, program was:"
      STDERR.puts program
      raise e
    end

    out = $stdout.string
    $stdout = STDOUT
    next if out["Stack Overflow"]

    puts "ruby output: %p" % [out]

    next if program['show'] && errored # we know show won't print [ as soon as possible in haskell, let's ignore this minor problem for now
    next if program['&'] && errored # we know different algs for sort e.g.: "c" 00toBase h j &
    next if program['\\'] && errored # we know different algs for setDiff e.g.: m 00toBase \

    out_hs = run_engine(program, input)
    next if out_hs["Prelude.chr: bad argument"] && out["char out of range"]
    out_hs.gsub!(/^.*WARNING.*splitting.*\n/,'')
    puts "engine output: %p" % [out_hs]


    exit if out != out_hs
  }
}

puts "pass fuzz test engine"