# frozen_string_literal: true

copy :setup_multiline do
  def setup_input str
    if readline?
      stub_readline(:mock)
    else
      mock($stdin).gets{ str.chomp }
    end
  end

  def input str
    setup_input(str)
    mock(shell).throw(:rib_multiline)
  end

  def input_done str, err=nil
    setup_input(str)
    if err
      mock(shell).print_eval_error(is_a(err)){}
    else
      mock(shell).print_result(is_a(Object)){}
    end
    shell.loop_once
    ok
  end

  def check str, err=nil
    yield if block_given?

    lines = str.split("\n")
    lines[0...-1].each{ |line|
      input(line)
      shell.loop_once
    }
    input_done(lines.last, err)
  end

  before do
    stub_output
  end
end

copy :multiline do
  would 'work with no prompt' do
    shell.config[:prompt] = ''
    check <<~RUBY
      def f
        0
      end
    RUBY
  end

  would 'def f' do
    check <<~RUBY
      def f
        1
      end
    RUBY
  end

  would 'class C' do
    check <<~RUBY
      class C
      end
    RUBY
  end

  would 'begin' do
    check <<~RUBY
      begin
      end
    RUBY
  end

  would 'begin with RuntimeError' do
    check <<~RUBY, RuntimeError
      begin
        raise 'multiline raised an error'
      end
    RUBY
  end

  would 'do end' do
    check <<~RUBY
      [].each do
      end
    RUBY
  end

  would 'block brace' do
    check <<~RUBY
      [].each{
      }
    RUBY
  end

  would 'hash' do
    check <<~RUBY
      {
      }
    RUBY
  end

  would 'hash value' do
    check <<~RUBY
      {1 =>
       2}
    RUBY
  end

  would 'array' do
    check <<~RUBY
      [
      ]
    RUBY
  end

  would 'group' do
    check <<~RUBY
      (
      )
    RUBY
  end

  would 'string double quote' do
    check <<~RUBY
      "
      "
    RUBY
  end

  would 'string single quote' do
    check <<~RUBY
      '
      '
    RUBY
  end

  would 'be hash treated as a block SyntaxError' do
    code = <<~RUBY
      puts { :x => 10 }.class
    RUBY

    if RUBY_VERSION >= '3.0.0'
      check code do
        stub(shell.config[:binding_object]).puts{}
      end
    else
      check code, SyntaxError
    end
  end

  would 'SyntaxError' do
    check <<~RUBY, SyntaxError
      s-y n
    RUBY
  end

  would 'begin with SyntaxError' do
    check <<~RUBY, SyntaxError
      begin
        s-y n
    RUBY
  end

  would 'binary operator +' do
    check <<~RUBY
      1/1.to_i +
      1
    RUBY
  end

  would 'binary operator -' do
    check <<~RUBY
      1*1.to_i -
      1
    RUBY
  end

  would 'binary operator *' do
    check <<~RUBY
      1-1.to_i *
      1
    RUBY
  end

  would 'binary operator /' do
    code = <<~RUBY
      1+1.to_i /
      1
    RUBY

    if RUBY_VERSION >= '3.0.0'
      check code.lines.first, SyntaxError
    else
      check code
    end
  end

  would 'binary operator |' do
    check <<~RUBY
      1+1.to_i |
      1
    RUBY
  end

  would 'binary operator &' do
    check <<~RUBY
      1+1.to_i &
      1
    RUBY
  end

  would 'binary operator ^' do
    check <<~RUBY
      1+1.to_i ^
      1
    RUBY
  end

  would 'backslash at the end' do
    check <<~RUBY
      'nice ' \\
      'shell'
    RUBY
  end
end
