<commit_before>require 'thread'
require 'tempfile'
require 'tmpdir'
require 'gitsh/cli'
require 'gitsh/environment'
require File.expand_path('../file_system', __FILE__)

class GitshRunner
  include FileSystemHelper

  UP_ARROW = "\033[A"

  def self.interactive(options={}, &block)
    new.run_interactive(options, &block)
  end

  def initialize
    @output_stream = Tempfile.new('stdout')
    @error_stream = Tempfile.new('stderr')
    @readline = FakeReadline.new
    @position_before_command = 0
    @error_position_before_command = 0
  end

  def run_interactive(options={})
    runner = nil
    in_a_temporary_directory do
      setup_env(options.fetch(:env, {}))

      Thread.abort_on_exception = true
      runner = Thread.new do
        env = Gitsh::Environment.new(
          output_stream: output_stream,
          error_stream: error_stream
        )
        env['gitsh.historyFile'] = File.join(Dir.tmpdir, 'gitsh_test_history')
        options.fetch(:settings, {}).each do |key, value|
          env[key] = value
        end
        cli = Gitsh::CLI.new(
          args: options.fetch(:args, []),
          env: env,
          readline: readline
        )
        begin
          cli.run
        rescue SystemExit
        end
      end

      wait_for_prompt

      yield(self)

      readline.type(':exit')
      runner.join
    end
  rescue RSpec::Expectations::ExpectationNotMetError => e
    runner.kill
    runner.join
    raise
  end

  def type(string)
    @error_position_before_command = error_stream.pos
    @position_before_command = output_stream.pos
    readline.type(string)
    wait_for_prompt
  end

  def prompt
    @prompt
  end

  def output
    output_stream.seek(@position_before_command)
    output_stream.read
  end

  def error
    error_stream.seek(@error_position_before_command)
    error_stream.read
  end

  def inspect
    'gitsh'
  end

  private

  attr_reader :output_stream, :error_stream, :readline

  def wait_for_prompt
    @prompt = readline.prompt
  end

  def setup_env(env)
    {'TERM' => 'vt220'}.merge(env).each do |key, value|
      ENV[key] = value
    end
  end
end

RSpec::Matchers.define :prompt_with do |expected|
  match do |runner|<commit_msg>Run integration specs in a temporary home dir.<commit_after>require 'thread'
require 'tempfile'
require 'tmpdir'
require 'gitsh/cli'
require 'gitsh/environment'
require File.expand_path('../file_system', __FILE__)

class GitshRunner
  include FileSystemHelper

  UP_ARROW = "\033[A"

  def self.interactive(options={}, &block)
    new(options).run_interactive(&block)
  end

  def initialize(options)
    @output_stream = Tempfile.new('stdout')
    @error_stream = Tempfile.new('stderr')
    @readline = FakeReadline.new
    @position_before_command = 0
    @error_position_before_command = 0
    @options = options
  end

  def run_interactive
    runner = nil
    with_a_temporary_home_directory do
      in_a_temporary_directory do
        setup_unix_env
        runner = start_runner_thread
        wait_for_prompt

        yield(self)

        readline.type(':exit')
        runner.join
      end
    end
  rescue RSpec::Expectations::ExpectationNotMetError => e
    runner.kill
    runner.join
    raise
  end

  def type(string)
    @error_position_before_command = error_stream.pos
    @position_before_command = output_stream.pos
    readline.type(string)
    wait_for_prompt
  end

  def prompt
    @prompt
  end

  def output
    output_stream.seek(@position_before_command)
    output_stream.read
  end

  def error
    error_stream.seek(@error_position_before_command)
    error_stream.read
  end

  def inspect
    'gitsh'
  end

  private

  attr_reader :output_stream, :error_stream, :readline, :options

  def start_runner_thread
    Thread.abort_on_exception = true
    Thread.new do
      begin
        cli.run
      rescue SystemExit
      end
    end
  end

  def cli
    Gitsh::CLI.new(
      args: options.fetch(:args, []),
      env: env,
      readline: readline
    )
  end

  def env
    env = Gitsh::Environment.new(
      output_stream: output_stream,
      error_stream: error_stream
    )
    env['gitsh.historyFile'] = File.join(Dir.tmpdir, 'gitsh_test_history')
    options.fetch(:settings, {}).each do |key, value|
      env[key] = value
    end
    env
  end

  def wait_for_prompt
    @prompt = readline.prompt
  end

  def setup_unix_env
    env = options.fetch(:env, {})
    {'TERM' => 'vt220'}.merge(env).each do |key, value|
      ENV[key] = value
    end
  end
end

RSpec::Matchers.define :prompt_with do |expected|
  match do |runner|
{'fraction_non_alphanumeric': 0.09312977099236641, 'fraction_numerical': 0.003489640130861505, 'mean_word_length': 2.866779089376054, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 7, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 1, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2240603', 'n_tokens_mistral': 1541, 'n_tokens_neox': 1495, 'n_words': 321}