Class: Ibex::GrammarTests::Runner

Inherits:
Object
  • Object
show all
Defined in:
lib/ibex/grammar_tests.rb

Overview

Runs all examples in one isolated process while creating a fresh parser instance for every case.

Constant Summary collapse

CHILD_RUNNER =
<<~'RUBY'
  require "json"

  load ARGV.fetch(0)
  parser_class = ARGV.fetch(1).split("::").reject(&:empty?).reduce(Object) do |scope, name|
    scope.const_get(name, false)
  end
  tests = JSON.parse(ARGV.fetch(2))
  results = tests.map do |test|
    production_ids = []
    begin
      parser = parser_class.new
      raise NoMethodError, "#{parser_class} must define parse(source)" unless parser.respond_to?(:parse)

      parser.observe do |event|
        production_ids << event.data.fetch("production_id") if event.type == :reduce
      end
      parser.parse(test.fetch("source"))
      result = { "actual" => "accept", "error_class" => nil, "error_message" => nil }
    rescue Ibex::Runtime::ParseError => error
      result = { "actual" => "reject", "error_class" => error.class.name, "error_message" => error.message }
    rescue SystemExit, SignalException, StandardError => error
      result = { "actual" => "error", "error_class" => error.class.name, "error_message" => error.message }
    end
    result.merge("production_ids" => production_ids)
  end
  puts "IBEX_GRAMMAR_TEST_RESULT=#{JSON.generate(results)}"
RUBY

Instance Method Summary collapse

Constructor Details

#initialize(automaton, timeout: DEFAULT_TIMEOUT) ⇒ Runner

Returns a new instance of Runner.

Raises:

  • (ArgumentError)


90
91
92
93
94
95
# File 'lib/ibex/grammar_tests.rb', line 90

def initialize(automaton, timeout: DEFAULT_TIMEOUT)
  raise ArgumentError, "timeout must be a positive Integer" unless timeout.is_a?(Integer) && timeout.positive?

  @automaton = automaton
  @timeout = timeout
end

Instance Method Details

#production_coverage(results) ⇒ Object



115
116
117
118
119
120
121
122
# File 'lib/ibex/grammar_tests.rb', line 115

def production_coverage(results)
  production_count = @automaton.grammar.productions.length
  covered_ids = results.flat_map(&:production_ids).uniq.sort.freeze
  missing_ids = ((0...production_count).to_a - covered_ids).freeze
  ProductionCoverage.new(
    covered_ids: covered_ids, missing_ids: missing_ids, production_count: production_count
  ).freeze
end

#runObject

Raises:



98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
# File 'lib/ibex/grammar_tests.rb', line 98

def run
  grammar = @automaton.grammar
  raise Ibex::Error, "(test):1:1: grammar declares no %test cases" if grammar.grammar_tests.empty?
  unless grammar.parser_parameters.empty?
    raise Ibex::Error, "(test):1:1: %test cannot instantiate a parser with required %param declarations"
  end

  Dir.mktmpdir("ibex-grammar-tests") do |directory|
    parser_path = File.join(directory, "parser.rb")
    runner_path = File.join(directory, "runner.rb")
    File.binwrite(parser_path, generated_parser)
    File.binwrite(runner_path, CHILD_RUNNER)
    execute_child(parser_path, runner_path)
  end
end