summaryrefslogtreecommitdiff
path: root/test/prism/ruby_parser_test.rb
blob: 8edeac4b4f8cbca56f1f1d406f75e4dbd373035d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
# frozen_string_literal: true

return if RUBY_ENGINE == "jruby"

require_relative "test_helper"

begin
  require "ruby_parser"
rescue LoadError
  # In CRuby's CI, we're not going to test against the ruby_parser gem because
  # we don't want to have to install it. So in this case we'll just skip this
  # test.
  return
end

# We want to also compare lines and files to make sure we're setting them
# correctly.
Sexp.prepend(
  Module.new do
    def ==(other)
      super && line == other.line && line_max == other.line_max && file == other.file
    end
  end
)

module Prism
  class RubyParserTest < TestCase
    base = File.join(__dir__, "fixtures")

    todos = %w[
      heredocs_nested.txt
      newline_terminated.txt
      regex_char_width.txt
      seattlerb/bug169.txt
      seattlerb/dstr_evstr.txt
      seattlerb/heredoc_squiggly_interp.txt
      seattlerb/masgn_colon3.txt
      seattlerb/messy_op_asgn_lineno.txt
      seattlerb/op_asgn_primary_colon_const_command_call.txt
      seattlerb/parse_line_evstr_after_break.txt
      seattlerb/regexp_esc_C_slash.txt
      seattlerb/str_lit_concat_bad_encodings.txt
      seattlerb/str_pct_nested_nested.txt
      unescaping.txt
      unparser/corpus/literal/kwbegin.txt
      unparser/corpus/literal/send.txt
      unparser/corpus/semantic/dstr.txt
      whitequark/masgn_const.txt
      whitequark/ruby_bug_12402.txt
      whitequark/ruby_bug_14690.txt
      whitequark/space_args_block.txt
      whitequark/string_concat.txt
    ]

    # https://github.com/seattlerb/ruby_parser/issues/344
    failures = %w[
      alias.txt
      dos_endings.txt
      heredocs_with_ignored_newlines.txt
      method_calls.txt
      methods.txt
      multi_write.txt
      not.txt
      patterns.txt
      regex.txt
      seattlerb/and_multi.txt
      seattlerb/heredoc__backslash_dos_format.txt
      seattlerb/heredoc_bad_hex_escape.txt
      seattlerb/heredoc_bad_oct_escape.txt
      seattlerb/heredoc_with_extra_carriage_horrible_mix.txt
      seattlerb/heredoc_with_extra_carriage_returns_windows.txt
      seattlerb/heredoc_with_only_carriage_returns_windows.txt
      seattlerb/heredoc_with_only_carriage_returns.txt
      spanning_heredoc_newlines.txt
      spanning_heredoc.txt
      tilde_heredocs.txt
      unparser/corpus/literal/literal.txt
      while.txt
      whitequark/class_definition_in_while_cond.txt
      whitequark/cond_eflipflop.txt
      whitequark/cond_iflipflop.txt
      whitequark/cond_match_current_line.txt
      whitequark/dedenting_heredoc.txt
      whitequark/if_while_after_class__since_32.txt
      whitequark/lvar_injecting_match.txt
      whitequark/not.txt
      whitequark/numparam_ruby_bug_19025.txt
      whitequark/op_asgn_cmd.txt
      whitequark/parser_bug_640.txt
      whitequark/parser_slash_slash_n_escaping_in_literals.txt
      whitequark/pattern_matching_single_line_allowed_omission_of_parentheses.txt
      whitequark/pattern_matching_single_line.txt
      whitequark/ruby_bug_11989.txt
      whitequark/slash_newline_in_heredocs.txt
    ]

    Dir["**/*.txt", base: base].each do |name|
      next if failures.include?(name)

      define_method("test_#{name}") do
        begin
          # Parsing with ruby parser tends to be noisy with warnings, so we're
          # turning those off.
          previous_verbose, $VERBOSE = $VERBOSE, nil
          assert_parse_file(base, name, todos.include?(name))
        ensure
          $VERBOSE = previous_verbose
        end
      end
    end

    private

    def assert_parse_file(base, name, allowed_failure)
      filepath = File.join(base, name)
      expected = ::RubyParser.new.parse(File.read(filepath), filepath)
      actual = Prism::Translation::RubyParser.parse_file(filepath)

      if !allowed_failure
        assert_equal_nodes expected, actual
      elsif expected == actual
        puts "#{name} now passes"
      end
    end

    def assert_equal_nodes(left, right)
      return if left == right

      if left.is_a?(Sexp) && right.is_a?(Sexp)
        if left.line != right.line
          assert_equal "(#{left.inspect} line=#{left.line})", "(#{right.inspect} line=#{right.line})"
        elsif left.file != right.file
          assert_equal "(#{left.inspect} file=#{left.file})", "(#{right.inspect} file=#{right.file})"
        elsif left.length != right.length
          assert_equal "(#{left.inspect} length=#{left.length})", "(#{right.inspect} length=#{right.length})"
        else
          left.zip(right).each { |l, r| assert_equal_nodes(l, r) }
        end
      else
        assert_equal left, right
      end
    end
  end
end