aboutsummaryrefslogtreecommitdiffstats
path: root/test/prism/locals_test.rb
blob: 06324f9d94deb9b1deadceb7a120d9de2bf074fb (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
# frozen_string_literal: true

# This test is going to use the RubyVM::InstructionSequence class to compile
# local tables and compare against them to ensure we have the same locals in the
# same order. This is important to guarantee that we compile indices correctly
# on CRuby (in terms of compatibility).
#
# There have also been changes made in other versions of Ruby, so we only want
# to test on the most recent versions.
return if !defined?(RubyVM::InstructionSequence) || RUBY_VERSION < "3.2"

# Omit tests if running on a 32-bit machine because there is a bug with how
# Ruby is handling large ISeqs on 32-bit machines
return if RUBY_PLATFORM =~ /i686/

require_relative "test_helper"

module Prism
  class LocalsTest < TestCase
    invalid = []
    todos = []

    # Invalid break
    invalid << "break.txt"
    invalid << "if.txt"
    invalid << "rescue.txt"
    invalid << "seattlerb/block_break.txt"
    invalid << "unless.txt"
    invalid << "whitequark/break.txt"
    invalid << "whitequark/break_block.txt"

    # Invalid next
    invalid << "next.txt"
    invalid << "seattlerb/block_next.txt"
    invalid << "unparser/corpus/literal/control.txt"
    invalid << "whitequark/next.txt"
    invalid << "whitequark/next_block.txt"

    # Invalid redo
    invalid << "keywords.txt"
    invalid << "whitequark/redo.txt"

    # Invalid retry
    invalid << "whitequark/retry.txt"

    # Invalid yield
    invalid << "seattlerb/dasgn_icky2.txt"
    invalid << "seattlerb/yield_arg.txt"
    invalid << "seattlerb/yield_call_assocs.txt"
    invalid << "seattlerb/yield_empty_parens.txt"
    invalid << "unparser/corpus/literal/yield.txt"
    invalid << "whitequark/args_assocs.txt"
    invalid << "whitequark/args_assocs_legacy.txt"
    invalid << "whitequark/yield.txt"
    invalid << "yield.txt"

    # Dead code eliminated
    invalid << "whitequark/ruby_bug_10653.txt"

    # case :a
    # in Symbol(*lhs, x, *rhs)
    # end
    todos << "seattlerb/case_in.txt"

    # <<~HERE
    #   #{<<~THERE}
    #   THERE
    # HERE
    todos << "seattlerb/heredoc_nested.txt"

    base = File.join(__dir__, "fixtures")
    skips = invalid | todos

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

      filepath = File.join(base, relative)
      define_method("test_#{relative}") { assert_locals(filepath) }
    end

    def setup
      @previous_default_external = Encoding.default_external
      ignore_warnings { Encoding.default_external = Encoding::UTF_8 }
    end

    def teardown
      ignore_warnings { Encoding.default_external = @previous_default_external }
    end

    private

    def assert_locals(filepath)
      source = File.read(filepath)

      expected = Debug.cruby_locals(source)
      actual = Debug.prism_locals(source)

      assert_equal(expected, actual)
    end

    def ignore_warnings
      previous_verbosity = $VERBOSE
      $VERBOSE = nil
      yield
    ensure
      $VERBOSE = previous_verbosity
    end
  end
end