summaryrefslogtreecommitdiff
path: root/test/prism/encoding/symbol_encoding_test.rb
blob: 20c998a58bb8ce583cf1431af4e5f2ba2058b937 (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
# frozen_string_literal: true

return if RUBY_ENGINE != "ruby"

require_relative "../test_helper"

module Prism
  class SymbolEncodingTest < TestCase
    each_encoding do |encoding, _|
      define_method(:"test_symbols_#{encoding.name}") do
        assert_symbols(encoding)
      end

      define_method(:"test_escapes_#{encoding.name}") do
        assert_escapes(encoding)
      end
    end

    private

    def expected_encoding(source)
      eval(source).encoding
    end

    def actual_encoding(source, encoding)
      result = Prism.parse(source)

      if result.success?
        symbol = result.statement

        if symbol.forced_utf8_encoding?
          Encoding::UTF_8
        elsif symbol.forced_binary_encoding?
          Encoding::ASCII_8BIT
        elsif symbol.forced_us_ascii_encoding?
          Encoding::US_ASCII
        else
          encoding
        end
      else
        raise SyntaxError.new(result.errors.map(&:message).join("\n"))
      end
    end

    def assert_symbols(encoding)
      [:a, :ą, :+].each do |symbol|
        source = "# encoding: #{encoding.name}\n#{symbol.inspect}"

        expected =
          begin
            expected_encoding(source)
          rescue SyntaxError => error
            if error.message.include?("invalid multibyte")
              "invalid multibyte"
            else
              raise
            end
          end

        actual =
          begin
            actual_encoding(source, encoding)
          rescue SyntaxError => error
            if error.message.include?("invalid multibyte")
              "invalid multibyte"
            else
              raise
            end
          end

        assert_equal expected, actual
      end
    end

    def assert_escapes(encoding)
      escapes = ["\\x00", "\\x7F", "\\x80", "\\xFF", "\\u{00}", "\\u{7F}", "\\u{80}", "\\M-\\C-?"]
      escapes = escapes.concat(escapes.product(escapes).map(&:join))

      escapes.each do |escaped|
        source = "# encoding: #{encoding.name}\n:\"#{escaped}\""

        expected =
          begin
            expected_encoding(source)
          rescue SyntaxError => error
            if error.message.include?("UTF-8 mixed within")
              error.message[/UTF-8 mixed within .+? source/]
            else
              raise
            end
          end

        actual =
          begin
            actual_encoding(source, encoding)
          rescue SyntaxError => error
            if error.message.include?("mixed")
              error.message.split("\n", 2).first
            else
              raise
            end
          end

        assert_equal expected, actual
      end
    end
  end
end