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