1# -*- coding: us-ascii -*-
2# frozen_string_literal: false
3require 'test/unit'
4
5class TestRubyLiteral < Test::Unit::TestCase
6
7  def test_special_const
8    assert_equal 'true', true.inspect
9    assert_instance_of TrueClass, true
10    assert_equal 'false', false.inspect
11    assert_instance_of FalseClass, false
12    assert_equal 'nil', nil.inspect
13    assert_instance_of NilClass, nil
14    assert_equal ':sym', :sym.inspect
15    assert_instance_of Symbol, :sym
16    assert_equal '1234', 1234.inspect
17    assert_instance_of Integer, 1234
18    assert_equal '1234', 1_2_3_4.inspect
19    assert_instance_of Integer, 1_2_3_4
20    assert_equal '18', 0x12.inspect
21    assert_instance_of Integer, 0x12
22    assert_raise(SyntaxError) { eval("0x") }
23    assert_equal '15', 0o17.inspect
24    assert_instance_of Integer, 0o17
25    assert_raise(SyntaxError) { eval("0o") }
26    assert_equal '5', 0b101.inspect
27    assert_instance_of Integer, 0b101
28    assert_raise(SyntaxError) { eval("0b") }
29    assert_equal '123456789012345678901234567890', 123456789012345678901234567890.inspect
30    assert_instance_of Integer, 123456789012345678901234567890
31    assert_instance_of Float, 1.3
32    assert_equal '2', eval("0x00+2").inspect
33  end
34
35  def test_self
36    assert_equal self, self
37    assert_instance_of TestRubyLiteral, self
38    assert_respond_to self, :test_self
39  end
40
41  def test_string
42    assert_instance_of String, ?a
43    assert_equal "a", ?a
44    assert_instance_of String, ?A
45    assert_equal "A", ?A
46    assert_instance_of String, ?\n
47    assert_equal "\n", ?\n
48    assert_equal " ", ?\   # space
49    assert_equal '', ''
50    assert_equal 'string', 'string'
51    assert_equal 'string string', 'string string'
52    assert_equal ' ', ' '
53    assert_equal ' ', " "
54    assert_equal "\0", "\0"
55    assert_equal "\1", "\1"
56    assert_equal "3", "\x33"
57    assert_equal "\n", "\n"
58    bug2500 = '[ruby-core:27228]'
59    bug5262 = '[ruby-core:39222]'
60    %w[c C- M-].each do |pre|
61      ["u", %w[u{ }]].each do |open, close|
62        ["?", ['"', '"']].each do |qopen, qclose|
63          str = "#{qopen}\\#{pre}\\#{open}5555#{close}#{qclose}"
64          assert_raise(SyntaxError, "#{bug2500} eval(#{str})") {eval(str)}
65
66          str = "#{qopen}\\#{pre}\\#{open}\u201c#{close}#{qclose}"
67          assert_raise(SyntaxError, "#{bug5262} eval(#{str})") {eval(str)}
68
69          str = "#{qopen}\\#{pre}\\#{open}\u201c#{close}#{qclose}".encode("euc-jp")
70          assert_raise(SyntaxError, "#{bug5262} eval(#{str})") {eval(str)}
71
72          str = "#{qopen}\\#{pre}\\#{open}\u201c#{close}#{qclose}".encode("iso-8859-13")
73          assert_raise(SyntaxError, "#{bug5262} eval(#{str})") {eval(str)}
74
75          str = "#{qopen}\\#{pre}\\#{open}\xe2\x7f#{close}#{qclose}".force_encoding("utf-8")
76          assert_raise(SyntaxError, "#{bug5262} eval(#{str})") {eval(str)}
77        end
78      end
79    end
80    bug6069 = '[ruby-dev:45278]'
81    assert_equal "\x13", "\c\x33"
82    assert_equal "\x13", "\C-\x33"
83    assert_equal "\xB3", "\M-\x33"
84    assert_equal "\u201c", eval(%["\\\u{201c}"]), bug5262
85    assert_equal "\u201c".encode("euc-jp"), eval(%["\\\u{201c}"].encode("euc-jp")), bug5262
86    assert_equal "\u201c".encode("iso-8859-13"), eval(%["\\\u{201c}"].encode("iso-8859-13")), bug5262
87    assert_equal "\\\u201c", eval(%['\\\u{201c}']), bug6069
88    assert_equal "\\\u201c".encode("euc-jp"), eval(%['\\\u{201c}'].encode("euc-jp")), bug6069
89    assert_equal "\\\u201c".encode("iso-8859-13"), eval(%['\\\u{201c}'].encode("iso-8859-13")), bug6069
90    assert_equal "\u201c", eval(%[?\\\u{201c}]), bug6069
91    assert_equal "\u201c".encode("euc-jp"), eval(%[?\\\u{201c}].encode("euc-jp")), bug6069
92    assert_equal "\u201c".encode("iso-8859-13"), eval(%[?\\\u{201c}].encode("iso-8859-13")), bug6069
93
94    assert_equal "ab", eval("?a 'b'")
95    assert_equal "a\nb", eval("<<A 'b'\na\nA")
96  end
97
98  def test_dstring
99    assert_equal '2', "#{1+1}"
100    assert_equal '16', "#{2 ** 4}"
101    s = "string"
102    assert_equal s, "#{s}"
103    a = 'Foo'
104    b = "#{a}" << 'Bar'
105    assert_equal('Foo', a, 'r3842')
106    assert_equal('FooBar', b, 'r3842')
107  end
108
109  def test_dstring_encoding
110    bug11519 = '[ruby-core:70703] [Bug #11519]'
111    ['"foo#{}"', '"#{}foo"', '"#{}"'].each do |code|
112      a = eval("#-*- coding: utf-8 -*-\n#{code}")
113      assert_equal(Encoding::UTF_8, a.encoding,
114                   proc{"#{bug11519}: #{code}.encoding"})
115    end
116  end
117
118  def test_dsymbol
119    assert_equal :a3c, :"a#{1+2}c"
120  end
121
122  def test_dsymbol_redefined_intern
123    assert_separately([], "#{<<-"begin;"}\n#{<<-'end;'}")
124    begin;
125      class String
126        alias _intern intern
127        def intern
128          "<#{upcase}>"
129        end
130      end
131      mesg = "literal symbol should not be affected by method redefinition"
132      str = "foo"
133      assert_equal(:foo, :"#{str}", mesg)
134    end;
135  end
136
137  def test_xstring
138    assert_equal "foo\n", `echo foo`
139    s = 'foo'
140    assert_equal "foo\n", `echo #{s}`
141  end
142
143  def test_frozen_string
144    all_assertions do |a|
145      a.for("false with indicator") do
146        str = eval("# -*- frozen-string-literal: false -*-\n""'foo'")
147        assert_not_predicate(str, :frozen?)
148      end
149      a.for("true with indicator") do
150        str = eval("# -*- frozen-string-literal: true -*-\n""'foo'")
151        assert_predicate(str, :frozen?)
152      end
153      a.for("false without indicator") do
154        str = eval("# frozen-string-literal: false\n""'foo'")
155        assert_not_predicate(str, :frozen?)
156      end
157      a.for("true without indicator") do
158        str = eval("# frozen-string-literal: true\n""'foo'")
159        assert_predicate(str, :frozen?)
160      end
161      a.for("false with preceding garbage") do
162        str = eval("# x frozen-string-literal: false\n""'foo'")
163        assert_not_predicate(str, :frozen?)
164      end
165      a.for("true with preceding garbage") do
166        str = eval("# x frozen-string-literal: true\n""'foo'")
167        assert_not_predicate(str, :frozen?)
168      end
169      a.for("false with succeeding garbage") do
170        str = eval("# frozen-string-literal: false x\n""'foo'")
171        assert_not_predicate(str, :frozen?)
172      end
173      a.for("true with succeeding garbage") do
174        str = eval("# frozen-string-literal: true x\n""'foo'")
175        assert_not_predicate(str, :frozen?)
176      end
177    end
178  end
179
180  def test_frozen_string_in_array_literal
181    list = eval("# frozen-string-literal: true\n""['foo', 'bar']")
182    assert_equal 2, list.length
183    list.each { |str| assert_predicate str, :frozen? }
184  end
185
186  if defined?(RubyVM::InstructionSequence.compile_option) and
187    RubyVM::InstructionSequence.compile_option.key?(:debug_frozen_string_literal)
188    def test_debug_frozen_string
189      src = 'n = 1; "foo#{n ? "-#{n}" : ""}"'; f = "test.rb"; n = 1
190      opt = {frozen_string_literal: true, debug_frozen_string_literal: true}
191      str = RubyVM::InstructionSequence.compile(src, f, f, n, opt).eval
192      assert_equal("foo-1", str)
193      assert_predicate(str, :frozen?)
194      assert_raise_with_message(FrozenError, /created at #{Regexp.quote(f)}:#{n}/) {
195        str << "x"
196      }
197    end
198
199    def test_debug_frozen_string_in_array_literal
200      src = '["foo"]'; f = "test.rb"; n = 1
201      opt = {frozen_string_literal: true, debug_frozen_string_literal: true}
202      ary = RubyVM::InstructionSequence.compile(src, f, f, n, opt).eval
203      assert_equal("foo", ary.first)
204      assert_predicate(ary.first, :frozen?)
205      assert_raise_with_message(FrozenError, /created at #{Regexp.quote(f)}:#{n}/) {
206        ary.first << "x"
207      } unless ENV['RUBY_ISEQ_DUMP_DEBUG']
208    end
209  end
210
211  def test_regexp
212    assert_instance_of Regexp, //
213    assert_match(//, 'a')
214    assert_match(//, '')
215    assert_instance_of Regexp, /a/
216    assert_match(/a/, 'a')
217    assert_no_match(/test/, 'tes')
218    re = /test/
219    assert_match re, 'test'
220    str = 'test'
221    assert_match re, str
222    assert_match(/test/, str)
223    assert_equal 0, (/test/ =~ 'test')
224    assert_equal 0, (re =~ 'test')
225    assert_equal 0, (/test/ =~ str)
226    assert_equal 0, (re =~ str)
227    assert_equal 0, ('test' =~ /test/)
228    assert_equal 0, ('test' =~ re)
229    assert_equal 0, (str =~ /test/)
230    assert_equal 0, (str =~ re)
231  end
232
233  def test_dregexp
234    assert_instance_of Regexp, /re#{'ge'}xp/
235    assert_equal(/regexp/, /re#{'ge'}xp/)
236    bug3903 = '[ruby-core:32682]'
237    assert_raise(SyntaxError, bug3903) {eval('/[#{"\x80"}]/')}
238  end
239
240  def test_array
241    assert_instance_of Array, []
242    assert_equal [], []
243    assert_equal 0, [].size
244    assert_instance_of Array, [0]
245    assert_equal [3], [3]
246    assert_equal 1, [3].size
247    a = [3]
248    assert_equal 3, a[0]
249    assert_instance_of Array, [1,2]
250    assert_equal [1,2], [1,2]
251    assert_instance_of Array, [1,2,3,4,5]
252    assert_equal [1,2,3,4,5], [1,2,3,4,5]
253    assert_equal 5, [1,2,3,4,5].size
254    a = [1,2]
255    assert_equal 1, a[0]
256    assert_equal 2, a[1]
257    a = [1 + 2, 3 + 4, 5 + 6]
258    assert_instance_of Array, a
259    assert_equal [3, 7, 11], a
260    assert_equal 7, a[1]
261    assert_equal 1, ([0][0] += 1)
262    assert_equal 1, ([2][0] -= 1)
263    a = [obj = Object.new]
264    assert_instance_of Array, a
265    assert_equal 1, a.size
266    assert_equal obj, a[0]
267    a = [1,2,3]
268    a[1] = 5
269    assert_equal 5, a[1]
270  end
271
272  def test_hash
273    assert_instance_of Hash, {}
274    assert_equal({}, {})
275    assert_instance_of Hash, {1 => 2}
276    assert_equal({1 => 2}, {1 => 2})
277    h = {1 => 2}
278    assert_equal 2, h[1]
279    h = {"string" => "literal", "goto" => "hell"}
280    assert_equal h, h
281    assert_equal 2, h.size
282    assert_equal h, h
283    assert_equal "literal", h["string"]
284  end
285
286  def test_hash_literal_frozen
287    assert_separately([], "#{<<~"begin;"}\n#{<<~'end;'}")
288    begin;
289      def frozen_hash_literal_arg
290        {0=>1,1=>4,2=>17}
291      end
292
293      ObjectSpace.each_object(Hash) do |a|
294        if a.class == Hash and !a.default_proc and a.size == 3 &&
295           a[0] == 1 && a[1] == 4 && a[2] == 17
296          # should not be found.
297          raise
298        end
299      end
300      assert_not_include frozen_hash_literal_arg, 3
301    end;
302  end
303
304  def test_big_array_and_hash_literal
305    assert_normal_exit %q{GC.disable=true; x = nil; raise if eval("[#{(1..1_000_000).map{'x'}.join(", ")}]").size != 1_000_000}, "", timeout: 300, child_env: %[--disable-gems]
306    assert_normal_exit %q{GC.disable=true; x = nil; raise if eval("[#{(1..1_000_000).to_a.join(", ")}]").size != 1_000_000}, "", timeout: 300, child_env: %[--disable-gems]
307    assert_normal_exit %q{GC.disable=true; x = nil; raise if eval("{#{(1..1_000_000).map{|n| "#{n} => x"}.join(', ')}}").size != 1_000_000}, "", timeout: 300, child_env: %[--disable-gems]
308    assert_normal_exit %q{GC.disable=true; x = nil; raise if eval("{#{(1..1_000_000).map{|n| "#{n} => #{n}"}.join(', ')}}").size != 1_000_000}, "", timeout: 300, child_env: %[--disable-gems]
309  end
310
311  def test_big_hash_literal
312    bug7466 = '[ruby-dev:46658]'
313    h = {
314      0xFE042 => 0xE5CD,
315      0xFE043 => 0xE5CD,
316      0xFE045 => 0xEA94,
317      0xFE046 => 0xE4E3,
318      0xFE047 => 0xE4E2,
319      0xFE048 => 0xEA96,
320      0xFE049 => 0x3013,
321      0xFE04A => 0xEB36,
322      0xFE04B => 0xEB37,
323      0xFE04C => 0xEB38,
324      0xFE04D => 0xEB49,
325      0xFE04E => 0xEB82,
326      0xFE04F => 0xE4D2,
327      0xFE050 => 0xEB35,
328      0xFE051 => 0xEAB9,
329      0xFE052 => 0xEABA,
330      0xFE053 => 0xE4D4,
331      0xFE054 => 0xE4CD,
332      0xFE055 => 0xEABB,
333      0xFE056 => 0xEABC,
334      0xFE057 => 0xEB32,
335      0xFE058 => 0xEB33,
336      0xFE059 => 0xEB34,
337      0xFE05A => 0xEB39,
338      0xFE05B => 0xEB5A,
339      0xFE190 => 0xE5A4,
340      0xFE191 => 0xE5A5,
341      0xFE192 => 0xEAD0,
342      0xFE193 => 0xEAD1,
343      0xFE194 => 0xEB47,
344      0xFE195 => 0xE509,
345      0xFE196 => 0xEAA0,
346      0xFE197 => 0xE50B,
347      0xFE198 => 0xEAA1,
348      0xFE199 => 0xEAA2,
349      0xFE19A => 0x3013,
350      0xFE19B => 0xE4FC,
351      0xFE19C => 0xE4FA,
352      0xFE19D => 0xE4FC,
353      0xFE19E => 0xE4FA,
354      0xFE19F => 0xE501,
355      0xFE1A0 => 0x3013,
356      0xFE1A1 => 0xE5DD,
357      0xFE1A2 => 0xEADB,
358      0xFE1A3 => 0xEAE9,
359      0xFE1A4 => 0xEB13,
360      0xFE1A5 => 0xEB14,
361      0xFE1A6 => 0xEB15,
362      0xFE1A7 => 0xEB16,
363      0xFE1A8 => 0xEB17,
364      0xFE1A9 => 0xEB18,
365      0xFE1AA => 0xEB19,
366      0xFE1AB => 0xEB1A,
367      0xFE1AC => 0xEB44,
368      0xFE1AD => 0xEB45,
369      0xFE1AE => 0xE4CB,
370      0xFE1AF => 0xE5BF,
371      0xFE1B0 => 0xE50E,
372      0xFE1B1 => 0xE4EC,
373      0xFE1B2 => 0xE4EF,
374      0xFE1B3 => 0xE4F8,
375      0xFE1B4 => 0x3013,
376      0xFE1B5 => 0x3013,
377      0xFE1B6 => 0xEB1C,
378      0xFE1B9 => 0xEB7E,
379      0xFE1D3 => 0xEB22,
380      0xFE7DC => 0xE4D8,
381      0xFE1D4 => 0xEB23,
382      0xFE1D5 => 0xEB24,
383      0xFE1D6 => 0xEB25,
384      0xFE1CC => 0xEB1F,
385      0xFE1CD => 0xEB20,
386      0xFE1CE => 0xE4D9,
387      0xFE1CF => 0xE48F,
388      0xFE1C5 => 0xE5C7,
389      0xFE1C6 => 0xEAEC,
390      0xFE1CB => 0xEB1E,
391      0xFE1DA => 0xE4DD,
392      0xFE1E1 => 0xEB57,
393      0xFE1E2 => 0xEB58,
394      0xFE1E3 => 0xE492,
395      0xFE1C9 => 0xEB1D,
396      0xFE1D9 => 0xE4D3,
397      0xFE1DC => 0xE5D4,
398      0xFE1BA => 0xE4E0,
399      0xFE1BB => 0xEB76,
400      0xFE1C8 => 0xE4E0,
401      0xFE1DD => 0xE5DB,
402      0xFE1BC => 0xE4DC,
403      0xFE1D8 => 0xE4DF,
404      0xFE1BD => 0xE49A,
405      0xFE1C7 => 0xEB1B,
406      0xFE1C2 => 0xE5C2,
407      0xFE1C0 => 0xE5C0,
408      0xFE1B8 => 0xE4DB,
409      0xFE1C3 => 0xE470,
410      0xFE1BE => 0xE4D8,
411      0xFE1C4 => 0xE4D9,
412      0xFE1B7 => 0xE4E1,
413      0xFE1BF => 0xE4DE,
414      0xFE1C1 => 0xE5C1,
415      0xFE1CA => 0x3013,
416      0xFE1D0 => 0xE4E1,
417      0xFE1D1 => 0xEB21,
418      0xFE1D2 => 0xE4D7,
419      0xFE1D7 => 0xE4DA,
420      0xFE1DB => 0xE4EE,
421      0xFE1DE => 0xEB3F,
422      0xFE1DF => 0xEB46,
423      0xFE1E0 => 0xEB48,
424      0xFE336 => 0xE4FB,
425      0xFE320 => 0xE472,
426      0xFE321 => 0xEB67,
427      0xFE322 => 0xEACA,
428      0xFE323 => 0xEAC0,
429      0xFE324 => 0xE5AE,
430      0xFE325 => 0xEACB,
431      0xFE326 => 0xEAC9,
432      0xFE327 => 0xE5C4,
433      0xFE328 => 0xEAC1,
434      0xFE329 => 0xE4E7,
435      0xFE32A => 0xE4E7,
436      0xFE32B => 0xEACD,
437      0xFE32C => 0xEACF,
438      0xFE32D => 0xEACE,
439      0xFE32E => 0xEAC7,
440      0xFE32F => 0xEAC8,
441      0xFE330 => 0xE471,
442      0xFE331 => "[Bug #7466]",
443    }
444    k = h.keys
445    assert_equal([129, 0xFE331], [k.size, k.last], bug7466)
446
447    code = [
448      "h = {",
449      (1..128).map {|i| "#{i} => 0,"},
450      (129..140).map {|i| "#{i} => [],"},
451      "}",
452    ].join
453    assert_separately([], <<-"end;")
454      GC.stress = true
455      #{code}
456      GC.stress = false
457      assert_equal(140, h.size)
458    end;
459  end
460
461  def test_hash_duplicated_key
462    h = EnvUtil.suppress_warning do
463      eval <<~end
464        # This is a syntax that renders warning at very early stage.
465        # eval used to delay warning, to be suppressible by EnvUtil.
466        {"a" => 100, "b" => 200, "a" => 300, "a" => 400}
467      end
468    end
469    assert_equal(2, h.size)
470    assert_equal(400, h['a'])
471    assert_equal(200, h['b'])
472    assert_nil(h['c'])
473    assert_equal(nil, h.key('300'))
474  end
475
476  def test_hash_frozen_key_id
477    key = "a".freeze
478    h = {key => 100}
479    assert_equal(100, h['a'])
480    assert_same(key, *h.keys)
481  end
482
483  def test_hash_key_tampering
484    key = "a"
485    h = {key => 100}
486    key.upcase!
487    assert_equal(100, h['a'])
488  end
489
490  def test_range
491    assert_instance_of Range, (1..2)
492    assert_equal(1..2, 1..2)
493    r = 1..2
494    assert_equal 1, r.begin
495    assert_equal 2, r.end
496    assert_equal false, r.exclude_end?
497    assert_instance_of Range, (1...3)
498    assert_equal(1...3, 1...3)
499    r = 1...3
500    assert_equal 1, r.begin
501    assert_equal 3, r.end
502    assert_equal true, r.exclude_end?
503    r = 1+2 .. 3+4
504    assert_instance_of Range, r
505    assert_equal 3, r.begin
506    assert_equal 7, r.end
507    assert_equal false, r.exclude_end?
508    r = 1+2 ... 3+4
509    assert_instance_of Range, r
510    assert_equal 3, r.begin
511    assert_equal 7, r.end
512    assert_equal true, r.exclude_end?
513    assert_instance_of Range, 'a'..'c'
514    r = 'a'..'c'
515    assert_equal 'a', r.begin
516    assert_equal 'c', r.end
517  end
518
519  def test__FILE__
520    assert_instance_of String, __FILE__
521    assert_equal __FILE__, __FILE__
522    assert_equal 'test_literal.rb', File.basename(__FILE__)
523  end
524
525  def test__LINE__
526    assert_instance_of Integer, __LINE__
527    assert_equal __LINE__, __LINE__
528  end
529
530  def test_integer
531    head = ['', '0x', '0o', '0b', '0d', '-', '+']
532    chars = ['0', '1', '_', '9', 'f']
533    head.each {|h|
534      4.times {|len|
535        a = [h]
536        len.times { a = a.product(chars).map {|x| x.join('') } }
537        a.each {|s|
538          next if s.empty?
539          begin
540            r1 = Integer(s)
541          rescue ArgumentError
542            r1 = :err
543          end
544          begin
545            r2 = eval(s)
546          rescue NameError, SyntaxError
547            r2 = :err
548          end
549          assert_equal(r1, r2, "Integer(#{s.inspect}) != eval(#{s.inspect})")
550        }
551      }
552    }
553    bug2407 = '[ruby-dev:39798]'
554    head.grep_v(/^0/) do |s|
555      head.grep(/^0/) do |h|
556        h = "#{s}#{h}_"
557        assert_syntax_error(h, /numeric literal without digits\Z/, "#{bug2407}: #{h.inspect}")
558      end
559    end
560  end
561
562  def test_float
563    head = ['', '-', '+']
564    chars = ['0', '1', '_', '9', 'f', '.']
565    head.each {|h|
566      6.times {|len|
567        a = [h]
568        len.times { a = a.product(chars).map {|x| x.join('') } }
569        a.each {|s|
570          next if s.empty?
571          next if /\.\z/ =~ s
572          next if /\A[-+]?\./ =~ s
573          next if /\A[-+]?0/ =~ s
574          begin
575            r1 = Float(s)
576          rescue ArgumentError
577            r1 = :err
578          end
579          begin
580            r2 = eval(s)
581          rescue NameError, SyntaxError
582            r2 = :err
583          end
584          r2 = :err if Range === r2
585          assert_equal(r1, r2, "Float(#{s.inspect}) != eval(#{s.inspect})")
586        }
587      }
588    }
589    assert_equal(100.0, 0.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100e100)
590  end
591
592  def test_symbol_list
593    assert_equal([:foo, :bar], %i[foo bar])
594    assert_equal([:"\"foo"], %i["foo])
595
596    x = 10
597    assert_equal([:foo, :b10], %I[foo b#{x}])
598    assert_equal([:"\"foo10"], %I["foo#{x}])
599
600    assert_ruby_status(["--disable-gems", "--dump=parsetree"], "%I[foo bar]")
601  end
602end
603