PageRenderTime 42ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 1ms

/test/ruby/test_symbol.rb

http://github.com/ruby/ruby
Ruby | 602 lines | 512 code | 78 blank | 12 comment | 5 complexity | 2ff52955f52ff0331755ed7ca5585dff MD5 | raw file
Possible License(s): GPL-2.0, BSD-3-Clause, AGPL-3.0
  1. # frozen_string_literal: false
  2. require 'test/unit'
  3. class TestSymbol < Test::Unit::TestCase
  4. # [ruby-core:3573]
  5. def assert_eval_inspected(sym, valid = true)
  6. n = sym.inspect
  7. if valid
  8. bug5136 = '[ruby-dev:44314]'
  9. assert_not_match(/\A:"/, n, bug5136)
  10. end
  11. assert_nothing_raised(SyntaxError) {assert_equal(sym, eval(n))}
  12. end
  13. def test_intern
  14. assert_equal(':""', ''.intern.inspect)
  15. assert_equal(':$foo', '$foo'.intern.inspect)
  16. assert_equal(':"!foo"', '!foo'.intern.inspect)
  17. assert_equal(':"foo=="', "foo==".intern.inspect)
  18. end
  19. def test_all_symbols
  20. x = Symbol.all_symbols
  21. assert_kind_of(Array, x)
  22. assert_empty(x.reject {|s| s.is_a?(Symbol) })
  23. end
  24. def test_inspect_invalid
  25. # 2) Symbol#inspect sometimes returns invalid symbol representations:
  26. assert_eval_inspected(:"!")
  27. assert_eval_inspected(:"=", false)
  28. assert_eval_inspected(:"0", false)
  29. assert_eval_inspected(:"$1")
  30. assert_eval_inspected(:"@1", false)
  31. assert_eval_inspected(:"@@1", false)
  32. assert_eval_inspected(:"@", false)
  33. assert_eval_inspected(:"@@", false)
  34. end
  35. def assert_inspect_evaled(n)
  36. assert_nothing_raised(SyntaxError) {assert_equal(n, eval(n).inspect)}
  37. end
  38. def test_inspect_suboptimal
  39. # 3) Symbol#inspect sometimes returns suboptimal symbol representations:
  40. assert_inspect_evaled(':foo')
  41. assert_inspect_evaled(':foo!')
  42. assert_inspect_evaled(':bar?')
  43. assert_inspect_evaled(":<<")
  44. assert_inspect_evaled(':>>')
  45. assert_inspect_evaled(':<=')
  46. assert_inspect_evaled(':>=')
  47. assert_inspect_evaled(':=~')
  48. assert_inspect_evaled(':==')
  49. assert_inspect_evaled(':===')
  50. assert_raise(SyntaxError) {eval ':='}
  51. assert_inspect_evaled(':*')
  52. assert_inspect_evaled(':**')
  53. assert_raise(SyntaxError) {eval ':***'}
  54. assert_inspect_evaled(':+')
  55. assert_inspect_evaled(':-')
  56. assert_inspect_evaled(':+@')
  57. assert_inspect_evaled(':-@')
  58. assert_inspect_evaled(':|')
  59. assert_inspect_evaled(':^')
  60. assert_inspect_evaled(':&')
  61. assert_inspect_evaled(':/')
  62. assert_inspect_evaled(':%')
  63. assert_inspect_evaled(':~')
  64. assert_inspect_evaled(':`')
  65. assert_inspect_evaled(':[]')
  66. assert_inspect_evaled(':[]=')
  67. assert_raise(SyntaxError) {eval ':||'}
  68. assert_raise(SyntaxError) {eval ':&&'}
  69. assert_raise(SyntaxError) {eval ':['}
  70. end
  71. def test_inspect_dollar
  72. # 4) :$- always treats next character literally:
  73. assert_raise(SyntaxError) {eval ':$-'}
  74. assert_raise(SyntaxError) {eval ":$-\n"}
  75. assert_raise(SyntaxError) {eval ":$- "}
  76. assert_raise(SyntaxError) {eval ":$-#"}
  77. assert_raise(SyntaxError) {eval ':$-('}
  78. end
  79. def test_inspect_number
  80. # 5) Inconsistency between :$0 and :$1? The first one is valid, but the
  81. # latter isn't.
  82. assert_inspect_evaled(':$0')
  83. assert_inspect_evaled(':$1')
  84. end
  85. def test_inspect
  86. valid = %W{$a @a @@a < << <= <=> > >> >= =~ == === * ** + +@ - -@
  87. | ^ & / % ~ \` [] []= ! != !~ a a? a! a= A A? A! A=}
  88. valid.each do |sym|
  89. assert_equal(':' + sym, sym.intern.inspect)
  90. end
  91. invalid = %w{$a? $a! $a= @a? @a! @a= @@a? @@a! @@a= =}
  92. invalid.each do |sym|
  93. assert_equal(':"' + sym + '"', sym.intern.inspect)
  94. end
  95. end
  96. def test_to_proc
  97. assert_equal %w(1 2 3), (1..3).map(&:to_s)
  98. [
  99. [],
  100. [1],
  101. [1, 2],
  102. [1, [2, 3]],
  103. ].each do |ary|
  104. ary_id = ary.object_id
  105. assert_equal ary_id, :object_id.to_proc.call(ary)
  106. ary_ids = ary.collect{|x| x.object_id }
  107. assert_equal ary_ids, ary.collect(&:object_id)
  108. end
  109. end
  110. def test_to_proc_yield
  111. assert_ruby_status([], "#{<<-"begin;"}\n#{<<-"end;"}", timeout: 5.0)
  112. begin;
  113. GC.stress = true
  114. true.tap(&:itself)
  115. end;
  116. end
  117. def test_to_proc_new_proc
  118. assert_ruby_status([], "#{<<-"begin;"}\n#{<<-"end;"}", timeout: 5.0)
  119. begin;
  120. GC.stress = true
  121. 2.times {Proc.new(&:itself)}
  122. end;
  123. end
  124. def test_to_proc_no_method
  125. assert_separately([], "#{<<-"begin;"}\n#{<<-"end;"}", timeout: 5.0)
  126. begin;
  127. bug11566 = '[ruby-core:70980] [Bug #11566]'
  128. assert_raise(NoMethodError, bug11566) {Proc.new(&:foo).(1)}
  129. assert_raise(NoMethodError, bug11566) {:foo.to_proc.(1)}
  130. end;
  131. end
  132. def test_to_proc_arg
  133. assert_separately([], "#{<<-"begin;"}\n#{<<-"end;"}", timeout: 5.0)
  134. begin;
  135. def (obj = Object.new).proc(&b) b; end
  136. assert_same(:itself.to_proc, obj.proc(&:itself))
  137. end;
  138. end
  139. def test_to_proc_lambda?
  140. assert_predicate(:itself.to_proc, :lambda?)
  141. end
  142. def test_to_proc_arity
  143. assert_equal(-2, :itself.to_proc.arity)
  144. end
  145. def test_to_proc_call_with_symbol_proc
  146. first = 1
  147. bug11594 = "[ruby-core:71088] [Bug #11594] corrupted the first local variable"
  148. # symbol which does not have a Proc
  149. ->(&blk) {}.call(&:test_to_proc_call_with_symbol_proc)
  150. assert_equal(1, first, bug11594)
  151. end
  152. class TestToPRocArgWithRefinements; end
  153. def _test_to_proc_arg_with_refinements_call(&block)
  154. block.call TestToPRocArgWithRefinements.new
  155. end
  156. def _test_to_proc_with_refinements_call(&block)
  157. block
  158. end
  159. using Module.new {
  160. refine TestToPRocArgWithRefinements do
  161. def hoge
  162. :hoge
  163. end
  164. end
  165. }
  166. def test_to_proc_arg_with_refinements
  167. assert_equal(:hoge, _test_to_proc_arg_with_refinements_call(&:hoge))
  168. end
  169. def test_to_proc_lambda_with_refinements
  170. assert_predicate(_test_to_proc_with_refinements_call(&:hoge), :lambda?)
  171. end
  172. def test_to_proc_arity_with_refinements
  173. assert_equal(-2, _test_to_proc_with_refinements_call(&:hoge).arity)
  174. end
  175. def self._test_to_proc_arg_with_refinements_call(&block)
  176. block.call TestToPRocArgWithRefinements.new
  177. end
  178. _test_to_proc_arg_with_refinements_call(&:hoge)
  179. using Module.new {
  180. refine TestToPRocArgWithRefinements do
  181. def hoge
  182. :hogehoge
  183. end
  184. end
  185. }
  186. def test_to_proc_arg_with_refinements_override
  187. assert_equal(:hogehoge, _test_to_proc_arg_with_refinements_call(&:hoge))
  188. end
  189. def test_to_proc_arg_with_refinements_undefined
  190. assert_raise(NoMethodError) do
  191. _test_to_proc_arg_with_refinements_call(&:foo)
  192. end
  193. end
  194. private def return_from_proc
  195. Proc.new { return 1 }.tap(&:call)
  196. end
  197. def test_return_from_symbol_proc
  198. bug12462 = '[ruby-core:75856] [Bug #12462]'
  199. assert_equal(1, return_from_proc, bug12462)
  200. end
  201. def test_to_proc_for_hash_each
  202. bug11830 = '[ruby-core:72205] [Bug #11830]'
  203. assert_normal_exit("#{<<-"begin;"}\n#{<<-'end;'}", bug11830)
  204. begin;
  205. {}.each(&:destroy)
  206. end;
  207. end
  208. def test_to_proc_iseq
  209. assert_separately([], "#{<<-"begin;"}\n#{<<~"end;"}", timeout: 5)
  210. begin;
  211. bug11845 = '[ruby-core:72381] [Bug #11845]'
  212. assert_nil(:class.to_proc.source_location, bug11845)
  213. assert_equal([[:req], [:rest]], :class.to_proc.parameters, bug11845)
  214. c = Class.new {define_method(:klass, :class.to_proc)}
  215. m = c.instance_method(:klass)
  216. assert_nil(m.source_location, bug11845)
  217. assert_equal([[:req], [:rest]], m.parameters, bug11845)
  218. end;
  219. end
  220. def test_to_proc_binding
  221. assert_separately([], "#{<<-"begin;"}\n#{<<~"end;"}", timeout: 5)
  222. begin;
  223. bug12137 = '[ruby-core:74100] [Bug #12137]'
  224. assert_raise(ArgumentError, bug12137) {
  225. :succ.to_proc.binding
  226. }
  227. end;
  228. end
  229. def test_to_proc_instance_exec
  230. bug = '[ruby-core:78839] [Bug #13074] should evaluate on the argument'
  231. assert_equal(2, BasicObject.new.instance_exec(1, &:succ), bug)
  232. assert_equal(3, BasicObject.new.instance_exec(1, 2, &:+), bug)
  233. end
  234. def test_call
  235. o = Object.new
  236. def o.foo(x, y); x + y; end
  237. assert_equal(3, :foo.to_proc.call(o, 1, 2))
  238. assert_raise(ArgumentError) { :foo.to_proc.call }
  239. end
  240. def m_block_given?
  241. block_given?
  242. end
  243. def m2_block_given?(m = nil)
  244. if m
  245. [block_given?, m.call(self)]
  246. else
  247. block_given?
  248. end
  249. end
  250. def test_block_given_to_proc
  251. bug8531 = '[Bug #8531]'
  252. m = :m_block_given?.to_proc
  253. assert(!m.call(self), "#{bug8531} without block")
  254. assert(m.call(self) {}, "#{bug8531} with block")
  255. assert(!m.call(self), "#{bug8531} without block second")
  256. end
  257. def test_block_persist_between_calls
  258. bug8531 = '[Bug #8531]'
  259. m2 = :m2_block_given?.to_proc
  260. assert_equal([true, false], m2.call(self, m2) {}, "#{bug8531} nested with block")
  261. assert_equal([false, false], m2.call(self, m2), "#{bug8531} nested without block")
  262. end
  263. def test_block_curry_proc
  264. assert_separately([], "#{<<-"begin;"}\n#{<<-"end;"}")
  265. begin;
  266. b = proc { true }.curry
  267. assert(b.call, "without block")
  268. assert(b.call { |o| o.to_s }, "with block")
  269. assert(b.call(&:to_s), "with sym block")
  270. end;
  271. end
  272. def test_block_curry_lambda
  273. assert_separately([], "#{<<-"begin;"}\n#{<<-"end;"}")
  274. begin;
  275. b = lambda { true }.curry
  276. assert(b.call, "without block")
  277. assert(b.call { |o| o.to_s }, "with block")
  278. assert(b.call(&:to_s), "with sym block")
  279. end;
  280. end
  281. def test_block_method_to_proc
  282. assert_separately([], "#{<<-"begin;"}\n#{<<-"end;"}")
  283. begin;
  284. b = method(:tap).to_proc
  285. assert(b.call { |o| o.to_s }, "with block")
  286. assert(b.call(&:to_s), "with sym block")
  287. end;
  288. end
  289. def test_succ
  290. assert_equal(:fop, :foo.succ)
  291. end
  292. def test_cmp
  293. assert_equal(0, :FoO <=> :FoO)
  294. assert_equal(-1, :FoO <=> :fOO)
  295. assert_equal(1, :fOO <=> :FoO)
  296. assert_nil(:foo <=> "foo")
  297. end
  298. def test_casecmp
  299. assert_equal(0, :FoO.casecmp(:fOO))
  300. assert_equal(1, :FoO.casecmp(:BaR))
  301. assert_equal(-1, :baR.casecmp(:FoO))
  302. assert_nil(:foo.casecmp("foo"))
  303. assert_nil(:foo.casecmp(Object.new))
  304. end
  305. def test_casecmp?
  306. assert_equal(true, :FoO.casecmp?(:fOO))
  307. assert_equal(false, :FoO.casecmp?(:BaR))
  308. assert_equal(false, :baR.casecmp?(:FoO))
  309. assert_equal(true, :äöü.casecmp?(:ÄÖÜ))
  310. assert_nil(:foo.casecmp?("foo"))
  311. assert_nil(:foo.casecmp?(Object.new))
  312. end
  313. def test_length
  314. assert_equal(3, :FoO.length)
  315. assert_equal(3, :FoO.size)
  316. end
  317. def test_empty
  318. assert_equal(false, :FoO.empty?)
  319. assert_equal(true, :"".empty?)
  320. end
  321. def test_case
  322. assert_equal(:FOO, :FoO.upcase)
  323. assert_equal(:foo, :FoO.downcase)
  324. assert_equal(:Foo, :foo.capitalize)
  325. assert_equal(:fOo, :FoO.swapcase)
  326. end
  327. def test_MATCH # '=~'
  328. assert_equal(10, :"FeeFieFoo-Fum" =~ /Fum$/)
  329. assert_equal(nil, "FeeFieFoo-Fum" =~ /FUM$/)
  330. o = Object.new
  331. def o.=~(x); x + "bar"; end
  332. assert_equal("foobar", :"foo" =~ o)
  333. assert_raise(TypeError) { :"foo" =~ "foo" }
  334. end
  335. def test_match_method
  336. assert_equal("bar", :"foobarbaz".match(/bar/).to_s)
  337. o = Regexp.new('foo')
  338. def o.match(x, y, z); x + y + z; end
  339. assert_equal("foobarbaz", :"foo".match(o, "bar", "baz"))
  340. x = nil
  341. :"foo".match(o, "bar", "baz") {|y| x = y }
  342. assert_equal("foobarbaz", x)
  343. assert_raise(ArgumentError) { :"foo".match }
  344. end
  345. def test_match_p_regexp
  346. /backref/ =~ 'backref'
  347. # must match here, but not in a separate method, e.g., assert_send,
  348. # to check if $~ is affected or not.
  349. assert_equal(true, "".match?(//))
  350. assert_equal(true, :abc.match?(/.../))
  351. assert_equal(true, 'abc'.match?(/b/))
  352. assert_equal(true, 'abc'.match?(/b/, 1))
  353. assert_equal(true, 'abc'.match?(/../, 1))
  354. assert_equal(true, 'abc'.match?(/../, -2))
  355. assert_equal(false, 'abc'.match?(/../, -4))
  356. assert_equal(false, 'abc'.match?(/../, 4))
  357. assert_equal(true, ("\u3042" + '\x').match?(/../, 1))
  358. assert_equal(true, ''.match?(/\z/))
  359. assert_equal(true, 'abc'.match?(/\z/))
  360. assert_equal(true, 'Ruby'.match?(/R.../))
  361. assert_equal(false, 'Ruby'.match?(/R.../, 1))
  362. assert_equal(false, 'Ruby'.match?(/P.../))
  363. assert_equal('backref', $&)
  364. end
  365. def test_match_p_string
  366. /backref/ =~ 'backref'
  367. # must match here, but not in a separate method, e.g., assert_send,
  368. # to check if $~ is affected or not.
  369. assert_equal(true, "".match?(''))
  370. assert_equal(true, :abc.match?('...'))
  371. assert_equal(true, 'abc'.match?('b'))
  372. assert_equal(true, 'abc'.match?('b', 1))
  373. assert_equal(true, 'abc'.match?('..', 1))
  374. assert_equal(true, 'abc'.match?('..', -2))
  375. assert_equal(false, 'abc'.match?('..', -4))
  376. assert_equal(false, 'abc'.match?('..', 4))
  377. assert_equal(true, ("\u3042" + '\x').match?('..', 1))
  378. assert_equal(true, ''.match?('\z'))
  379. assert_equal(true, 'abc'.match?('\z'))
  380. assert_equal(true, 'Ruby'.match?('R...'))
  381. assert_equal(false, 'Ruby'.match?('R...', 1))
  382. assert_equal(false, 'Ruby'.match?('P...'))
  383. assert_equal('backref', $&)
  384. end
  385. def test_symbol_popped
  386. assert_nothing_raised { eval('a = 1; :"#{ a }"; 1') }
  387. end
  388. def test_ascii_incomat_inspect
  389. [Encoding::UTF_16LE, Encoding::UTF_16BE,
  390. Encoding::UTF_32LE, Encoding::UTF_32BE].each do |e|
  391. assert_equal(':"abc"', "abc".encode(e).to_sym.inspect)
  392. assert_equal(':"\\u3042\\u3044\\u3046"', "\u3042\u3044\u3046".encode(e).to_sym.inspect)
  393. end
  394. end
  395. def test_symbol_encoding
  396. assert_equal(Encoding::US_ASCII, "$-A".force_encoding("iso-8859-15").intern.encoding)
  397. assert_equal(Encoding::US_ASCII, "foobar~!".force_encoding("iso-8859-15").intern.encoding)
  398. assert_equal(Encoding::UTF_8, "\u{2192}".intern.encoding)
  399. assert_raise_with_message(EncodingError, /\\xb0/i) {"\xb0a".force_encoding("utf-8").intern}
  400. end
  401. def test_singleton_method
  402. assert_raise(TypeError) { a = :foo; def a.foo; end }
  403. end
  404. SymbolsForEval = [
  405. :foo,
  406. "dynsym_#{Random.rand(10000)}_#{Time.now}".to_sym
  407. ]
  408. def test_instance_eval
  409. bug11086 = '[ruby-core:68961] [Bug #11086]'
  410. SymbolsForEval.each do |sym|
  411. assert_nothing_raised(TypeError, sym, bug11086) {
  412. sym.instance_eval {}
  413. }
  414. assert_raise(TypeError, sym, bug11086) {
  415. sym.instance_eval {def foo; end}
  416. }
  417. end
  418. end
  419. def test_instance_exec
  420. bug11086 = '[ruby-core:68961] [Bug #11086]'
  421. SymbolsForEval.each do |sym|
  422. assert_nothing_raised(TypeError, sym, bug11086) {
  423. sym.instance_exec {}
  424. }
  425. assert_raise(TypeError, sym, bug11086) {
  426. sym.instance_exec {def foo; end}
  427. }
  428. end
  429. end
  430. def test_frozen_symbol
  431. assert_equal(true, :foo.frozen?)
  432. assert_equal(true, :each.frozen?)
  433. assert_equal(true, :+.frozen?)
  434. assert_equal(true, "foo#{Time.now.to_i}".to_sym.frozen?)
  435. assert_equal(true, :foo.to_sym.frozen?)
  436. end
  437. def test_symbol_gc_1
  438. assert_normal_exit('".".intern;GC.start(immediate_sweep:false);eval %[GC.start;".".intern]',
  439. '',
  440. child_env: '--disable-gems')
  441. assert_normal_exit('".".intern;GC.start(immediate_sweep:false);eval %[GC.start;:"."]',
  442. '',
  443. child_env: '--disable-gems')
  444. assert_normal_exit('".".intern;GC.start(immediate_sweep:false);eval %[GC.start;%i"."]',
  445. '',
  446. child_env: '--disable-gems')
  447. assert_normal_exit('tap{".".intern};GC.start(immediate_sweep:false);' +
  448. 'eval %[syms=Symbol.all_symbols;GC.start;syms.each(&:to_sym)]',
  449. '',
  450. child_env: '--disable-gems')
  451. end
  452. def test_dynamic_attrset_id
  453. bug10259 = '[ruby-dev:48559] [Bug #10259]'
  454. class << (obj = Object.new)
  455. attr_writer :unagi
  456. end
  457. assert_nothing_raised(NoMethodError, bug10259) {obj.send("unagi=".intern, 1)}
  458. end
  459. def test_symbol_fstr_memory_leak
  460. bug10686 = '[ruby-core:67268] [Bug #10686]'
  461. assert_no_memory_leak([], "#{<<~"begin;"}\n#{<<~'else;'}", "#{<<~'end;'}", bug10686, limit: 1.71, rss: true, timeout: 20)
  462. begin;
  463. n = 100_000
  464. n.times { |i| i.to_s.to_sym }
  465. else;
  466. (2 * n).times { |i| (i + n).to_s.to_sym }
  467. end;
  468. end
  469. def test_hash_redefinition
  470. assert_separately([], "#{<<-"begin;"}\n#{<<-'end;'}")
  471. begin;
  472. bug11035 = '[ruby-core:68767] [Bug #11035]'
  473. class Symbol
  474. def hash
  475. raise
  476. end
  477. end
  478. h = {}
  479. assert_nothing_raised(RuntimeError, bug11035) {
  480. h[:foo] = 1
  481. }
  482. assert_nothing_raised(RuntimeError, bug11035) {
  483. h['bar'.to_sym] = 2
  484. }
  485. end;
  486. end
  487. def test_hash_nondeterministic
  488. ruby = EnvUtil.rubybin
  489. assert_not_equal :foo.hash, `#{ruby} -e 'puts :foo.hash'`.to_i,
  490. '[ruby-core:80430] [Bug #13376]'
  491. sym = "dynsym_#{Random.rand(10000)}_#{Time.now}"
  492. assert_not_equal sym.to_sym.hash,
  493. `#{ruby} -e 'puts #{sym.inspect}.to_sym.hash'`.to_i
  494. end
  495. def test_eq_can_be_redefined
  496. assert_in_out_err([], <<-RUBY, ["foo"], [])
  497. class Symbol
  498. remove_method :==
  499. def ==(obj)
  500. "foo"
  501. end
  502. end
  503. puts :a == :a
  504. RUBY
  505. end
  506. def test_start_with?
  507. assert_equal(true, :hello.start_with?("hel"))
  508. assert_equal(false, :hello.start_with?("el"))
  509. assert_equal(true, :hello.start_with?("el", "he"))
  510. bug5536 = '[ruby-core:40623]'
  511. assert_raise(TypeError, bug5536) {:str.start_with? :not_convertible_to_string}
  512. assert_equal(true, :hello.start_with?(/hel/))
  513. assert_equal("hel", $&)
  514. assert_equal(false, :hello.start_with?(/el/))
  515. assert_nil($&)
  516. end
  517. def test_end_with?
  518. assert_equal(true, :hello.end_with?("llo"))
  519. assert_equal(false, :hello.end_with?("ll"))
  520. assert_equal(true, :hello.end_with?("el", "lo"))
  521. bug5536 = '[ruby-core:40623]'
  522. assert_raise(TypeError, bug5536) {:str.end_with? :not_convertible_to_string}
  523. end
  524. end