|
| 1 | +# frozen_string_literal: true |
| 2 | + |
| 3 | +# This file's purpose is to extract the examples from the whitequark/parser |
| 4 | +# gem and generate a test file that we can use to ensure that our parser |
| 5 | +# generates equivalent syntax trees when translating. To do this, it runs the |
| 6 | +# parser's test suite but overrides the `assert_parses` method to collect the |
| 7 | +# examples into a hash. Then, it writes out the hash to a file that we can use |
| 8 | +# to generate our own tests. |
| 9 | +# |
| 10 | +# To run the test suite, it's important to note that we have to mirror both any |
| 11 | +# APIs provided to the test suite (for example the ParseHelper module below). |
| 12 | +# This is obviously relatively brittle, but it's effective for now. |
| 13 | + |
| 14 | +require "ast" |
| 15 | + |
| 16 | +module ParseHelper |
| 17 | + # This object is going to collect all of the examples from the parser gem into |
| 18 | + # a hash that we can use to generate our own tests. |
| 19 | + COLLECTED = Hash.new { |hash, key| hash[key] = [] } |
| 20 | + |
| 21 | + include AST::Sexp |
| 22 | + ALL_VERSIONS = %w[3.1 3.2] |
| 23 | + |
| 24 | + private |
| 25 | + |
| 26 | + def assert_context(*) |
| 27 | + end |
| 28 | + |
| 29 | + def assert_diagnoses(*) |
| 30 | + end |
| 31 | + |
| 32 | + def assert_diagnoses_many(*) |
| 33 | + end |
| 34 | + |
| 35 | + def refute_diagnoses(*) |
| 36 | + end |
| 37 | + |
| 38 | + def with_versions(*) |
| 39 | + end |
| 40 | + |
| 41 | + def assert_parses(_ast, code, _source_maps = "", versions = ALL_VERSIONS) |
| 42 | + # We're going to skip any examples that are for older Ruby versions |
| 43 | + # that we do not support. |
| 44 | + return if (versions & %w[3.1 3.2]).empty? |
| 45 | + |
| 46 | + entry = caller.find { _1.include?("test_parser.rb") } |
| 47 | + _, lineno, name = *entry.match(/(\d+):in `(.+)'/) |
| 48 | + |
| 49 | + COLLECTED["#{name}:#{lineno}"] << code |
| 50 | + end |
| 51 | +end |
| 52 | + |
| 53 | +namespace :extract do |
| 54 | + desc "Extract the whitequark/parser tests" |
| 55 | + task :whitequark do |
| 56 | + directory = File.expand_path("../tmp/parser", __dir__) |
| 57 | + unless File.directory?(directory) |
| 58 | + sh "git clone --depth 1 https://github.com/whitequark/parser #{directory}" |
| 59 | + end |
| 60 | + |
| 61 | + mkdir_p "#{directory}/extract" |
| 62 | + touch "#{directory}/extract/helper.rb" |
| 63 | + touch "#{directory}/extract/parse_helper.rb" |
| 64 | + touch "#{directory}/extract/extracted.txt" |
| 65 | + $:.unshift "#{directory}/extract" |
| 66 | + |
| 67 | + require "parser/current" |
| 68 | + require "minitest/autorun" |
| 69 | + require_relative "#{directory}/test/test_parser" |
| 70 | + |
| 71 | + Minitest.after_run do |
| 72 | + filepath = File.expand_path("../test/translation/parser.txt", __dir__) |
| 73 | + |
| 74 | + File.open(filepath, "w") do |file| |
| 75 | + ParseHelper::COLLECTED.sort.each do |(key, codes)| |
| 76 | + if codes.length == 1 |
| 77 | + file.puts("!!! #{key}\n#{codes.first}") |
| 78 | + else |
| 79 | + codes.each_with_index do |code, index| |
| 80 | + file.puts("!!! #{key}:#{index}\n#{code}") |
| 81 | + end |
| 82 | + end |
| 83 | + end |
| 84 | + end |
| 85 | + end |
| 86 | + end |
| 87 | +end |
0 commit comments