summaryrefslogtreecommitdiff
path: root/test/prism/newline_offsets_test.rb
blob: bb06876a9670761c05951d54e3eb93fa223c9110 (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
# frozen_string_literal: true

require_relative "test_helper"

module Prism
  class NewlineOffsetsTest < TestCase
    Fixture.each do |fixture|
      define_method(fixture.test_name) { assert_newline_offsets(fixture) }
    end

    def test_escape_control_newline
      # Newlines consumed inside escape sequences like \C-, \c, and \M-
      # must be tracked in line offsets across all literal types.
      %w[\\C- \\c \\M-].each do |escape|
        assert_newline_offsets_for("\"#{escape}\n\"", "#{escape} in string")
        assert_newline_offsets_for("`#{escape}\n`", "#{escape} in xstring")
        assert_newline_offsets_for("/#{escape}\n/", "#{escape} in regexp")
        assert_newline_offsets_for("%Q{#{escape}\n}", "#{escape} in %Q")
        assert_newline_offsets_for("%W[#{escape}\n]", "#{escape} in %W")
        assert_newline_offsets_for("<<~H\n#{escape}\n\nH\n", "#{escape} in heredoc")
        assert_newline_offsets_for("?#{escape}\n", "#{escape} in char literal")
      end

      # Combined meta + control escapes
      assert_newline_offsets_for("\"\\M-\\C-\n\"", "\\M-\\C- in string")
      assert_newline_offsets_for("\"\\M-\\c\n\"", "\\M-\\c in string")

      # \r\n consumed inside escape context
      assert_newline_offsets_for("\"\\C-\r\n\"", "\\C- with \\r\\n")
    end

    private

    def assert_newline_offsets(fixture)
      assert_newline_offsets_for(fixture.read)
    end

    def assert_newline_offsets_for(source, message = nil)
      expected = [0]
      source.b.scan("\n") { expected << $~.offset(0)[0] + 1 }

      assert_equal expected, Prism.parse(source).source.offsets, message
    end
  end
end