1# frozen_string_literal: false
2require 'test/unit'
3
4class TestKeywordArguments < Test::Unit::TestCase
5  def f1(str: "foo", num: 424242)
6    [str, num]
7  end
8
9  def test_f1
10    assert_equal(["foo", 424242], f1)
11    assert_equal(["bar", 424242], f1(str: "bar"))
12    assert_equal(["foo", 111111], f1(num: 111111))
13    assert_equal(["bar", 111111], f1(str: "bar", num: 111111))
14    assert_raise(ArgumentError) { f1(str: "bar", check: true) }
15    assert_raise(ArgumentError) { f1("string") }
16  end
17
18
19  def f2(x, str: "foo", num: 424242)
20    [x, str, num]
21  end
22
23  def test_f2
24    assert_equal([:xyz, "foo", 424242], f2(:xyz))
25    assert_equal([{"bar"=>42}, "foo", 424242], f2("bar"=>42))
26  end
27
28
29  def f3(str: "foo", num: 424242, **h)
30    [str, num, h]
31  end
32
33  def test_f3
34    assert_equal(["foo", 424242, {}], f3)
35    assert_equal(["bar", 424242, {}], f3(str: "bar"))
36    assert_equal(["foo", 111111, {}], f3(num: 111111))
37    assert_equal(["bar", 111111, {}], f3(str: "bar", num: 111111))
38    assert_equal(["bar", 424242, {:check=>true}], f3(str: "bar", check: true))
39    assert_raise(ArgumentError) { f3("string") }
40  end
41
42
43  define_method(:f4) {|str: "foo", num: 424242| [str, num] }
44
45  def test_f4
46    assert_equal(["foo", 424242], f4)
47    assert_equal(["bar", 424242], f4(str: "bar"))
48    assert_equal(["foo", 111111], f4(num: 111111))
49    assert_equal(["bar", 111111], f4(str: "bar", num: 111111))
50    assert_raise(ArgumentError) { f4(str: "bar", check: true) }
51    assert_raise(ArgumentError) { f4("string") }
52  end
53
54
55  define_method(:f5) {|str: "foo", num: 424242, **h| [str, num, h] }
56
57  def test_f5
58    assert_equal(["foo", 424242, {}], f5)
59    assert_equal(["bar", 424242, {}], f5(str: "bar"))
60    assert_equal(["foo", 111111, {}], f5(num: 111111))
61    assert_equal(["bar", 111111, {}], f5(str: "bar", num: 111111))
62    assert_equal(["bar", 424242, {:check=>true}], f5(str: "bar", check: true))
63    assert_raise(ArgumentError) { f5("string") }
64  end
65
66
67  def f6(str: "foo", num: 424242, **h, &blk)
68    [str, num, h, blk]
69  end
70
71  def test_f6 # [ruby-core:40518]
72    assert_equal(["foo", 424242, {}, nil], f6)
73    assert_equal(["bar", 424242, {}, nil], f6(str: "bar"))
74    assert_equal(["foo", 111111, {}, nil], f6(num: 111111))
75    assert_equal(["bar", 111111, {}, nil], f6(str: "bar", num: 111111))
76    assert_equal(["bar", 424242, {:check=>true}, nil], f6(str: "bar", check: true))
77    a = f6 {|x| x + 42 }
78    assert_equal(["foo", 424242, {}], a[0, 3])
79    assert_equal(43, a.last.call(1))
80  end
81
82  def f7(*r, str: "foo", num: 424242, **h)
83    [r, str, num, h]
84  end
85
86  def test_f7 # [ruby-core:41772]
87    assert_equal([[], "foo", 424242, {}], f7)
88    assert_equal([[], "bar", 424242, {}], f7(str: "bar"))
89    assert_equal([[], "foo", 111111, {}], f7(num: 111111))
90    assert_equal([[], "bar", 111111, {}], f7(str: "bar", num: 111111))
91    assert_equal([[1], "foo", 424242, {}], f7(1))
92    assert_equal([[1, 2], "foo", 424242, {}], f7(1, 2))
93    assert_equal([[1, 2, 3], "foo", 424242, {}], f7(1, 2, 3))
94    assert_equal([[1], "bar", 424242, {}], f7(1, str: "bar"))
95    assert_equal([[1, 2], "bar", 424242, {}], f7(1, 2, str: "bar"))
96    assert_equal([[1, 2, 3], "bar", 424242, {}], f7(1, 2, 3, str: "bar"))
97  end
98
99  define_method(:f8) { |opt = :ion, *rest, key: :word|
100    [opt, rest, key]
101  }
102
103  def test_f8
104    assert_equal([:ion, [], :word], f8)
105    assert_equal([1, [], :word], f8(1))
106    assert_equal([1, [2], :word], f8(1, 2))
107  end
108
109  def f9(r, o=42, *args, p, k: :key, **kw, &b)
110    [r, o, args, p, k, kw, b]
111  end
112
113  def test_f9
114    assert_equal([1, 42, [], 2, :key, {}, nil], f9(1, 2))
115    assert_equal([1, 2, [], 3, :key, {}, nil], f9(1, 2, 3))
116    assert_equal([1, 2, [3], 4, :key, {}, nil], f9(1, 2, 3, 4))
117    assert_equal([1, 2, [3, 4], 5, :key, {str: "bar"}, nil], f9(1, 2, 3, 4, 5, str: "bar"))
118  end
119
120  def f10(a: 1, **)
121    a
122  end
123
124  def test_f10
125    assert_equal(42, f10(a: 42))
126    assert_equal(1, f10(b: 42))
127  end
128
129  def test_method_parameters
130    assert_equal([[:key, :str], [:key, :num]], method(:f1).parameters);
131    assert_equal([[:req, :x], [:key, :str], [:key, :num]], method(:f2).parameters);
132    assert_equal([[:key, :str], [:key, :num], [:keyrest, :h]], method(:f3).parameters);
133    assert_equal([[:key, :str], [:key, :num]], method(:f4).parameters);
134    assert_equal([[:key, :str], [:key, :num], [:keyrest, :h]], method(:f5).parameters);
135    assert_equal([[:key, :str], [:key, :num], [:keyrest, :h], [:block, :blk]], method(:f6).parameters);
136    assert_equal([[:rest, :r], [:key, :str], [:key, :num], [:keyrest, :h]], method(:f7).parameters);
137    assert_equal([[:opt, :opt], [:rest, :rest], [:key, :key]], method(:f8).parameters) # [Bug #7540] [ruby-core:50735]
138    assert_equal([[:req, :r], [:opt, :o], [:rest, :args], [:req, :p], [:key, :k],
139                  [:keyrest, :kw], [:block, :b]], method(:f9).parameters)
140  end
141
142  def test_lambda
143    f = ->(str: "foo", num: 424242) { [str, num] }
144    assert_equal(["foo", 424242], f[])
145    assert_equal(["bar", 424242], f[str: "bar"])
146    assert_equal(["foo", 111111], f[num: 111111])
147    assert_equal(["bar", 111111], f[str: "bar", num: 111111])
148  end
149
150
151  def p1
152    Proc.new do |str: "foo", num: 424242|
153      [str, num]
154    end
155  end
156
157  def test_p1
158    assert_equal(["foo", 424242], p1[])
159    assert_equal(["bar", 424242], p1[str: "bar"])
160    assert_equal(["foo", 111111], p1[num: 111111])
161    assert_equal(["bar", 111111], p1[str: "bar", num: 111111])
162    assert_raise(ArgumentError) { p1[str: "bar", check: true] }
163    assert_equal(["foo", 424242], p1["string"] )
164  end
165
166
167  def p2
168    Proc.new do |x, str: "foo", num: 424242|
169      [x, str, num]
170    end
171  end
172
173  def test_p2
174    assert_equal([nil, "foo", 424242], p2[])
175    assert_equal([:xyz, "foo", 424242], p2[:xyz])
176  end
177
178
179  def p3
180    Proc.new do |str: "foo", num: 424242, **h|
181      [str, num, h]
182    end
183  end
184
185  def test_p3
186    assert_equal(["foo", 424242, {}], p3[])
187    assert_equal(["bar", 424242, {}], p3[str: "bar"])
188    assert_equal(["foo", 111111, {}], p3[num: 111111])
189    assert_equal(["bar", 111111, {}], p3[str: "bar", num: 111111])
190    assert_equal(["bar", 424242, {:check=>true}], p3[str: "bar", check: true])
191    assert_equal(["foo", 424242, {}], p3["string"])
192  end
193
194
195  def p4
196    Proc.new do |str: "foo", num: 424242, **h, &blk|
197      [str, num, h, blk]
198    end
199  end
200
201  def test_p4
202    assert_equal(["foo", 424242, {}, nil], p4[])
203    assert_equal(["bar", 424242, {}, nil], p4[str: "bar"])
204    assert_equal(["foo", 111111, {}, nil], p4[num: 111111])
205    assert_equal(["bar", 111111, {}, nil], p4[str: "bar", num: 111111])
206    assert_equal(["bar", 424242, {:check=>true}, nil], p4[str: "bar", check: true])
207    a = p4.call {|x| x + 42 }
208    assert_equal(["foo", 424242, {}], a[0, 3])
209    assert_equal(43, a.last.call(1))
210  end
211
212
213  def p5
214    Proc.new do |*r, str: "foo", num: 424242, **h|
215      [r, str, num, h]
216    end
217  end
218
219  def test_p5
220    assert_equal([[], "foo", 424242, {}], p5[])
221    assert_equal([[], "bar", 424242, {}], p5[str: "bar"])
222    assert_equal([[], "foo", 111111, {}], p5[num: 111111])
223    assert_equal([[], "bar", 111111, {}], p5[str: "bar", num: 111111])
224    assert_equal([[1], "foo", 424242, {}], p5[1])
225    assert_equal([[1, 2], "foo", 424242, {}], p5[1, 2])
226    assert_equal([[1, 2, 3], "foo", 424242, {}], p5[1, 2, 3])
227    assert_equal([[1], "bar", 424242, {}], p5[1, str: "bar"])
228    assert_equal([[1, 2], "bar", 424242, {}], p5[1, 2, str: "bar"])
229    assert_equal([[1, 2, 3], "bar", 424242, {}], p5[1, 2, 3, str: "bar"])
230  end
231
232
233  def p6
234    Proc.new do |o1, o2=42, *args, p, k: :key, **kw, &b|
235      [o1, o2, args, p, k, kw, b]
236    end
237  end
238
239  def test_p6
240    assert_equal([nil, 42, [], nil, :key, {}, nil], p6[])
241    assert_equal([1, 42, [], 2, :key, {}, nil], p6[1, 2])
242    assert_equal([1, 2, [], 3, :key, {}, nil], p6[1, 2, 3])
243    assert_equal([1, 2, [3], 4, :key, {}, nil], p6[1, 2, 3, 4])
244    assert_equal([1, 2, [3, 4], 5, :key, {str: "bar"}, nil], p6[1, 2, 3, 4, 5, str: "bar"])
245  end
246
247  def test_proc_parameters
248    assert_equal([[:key, :str], [:key, :num]], p1.parameters);
249    assert_equal([[:opt, :x], [:key, :str], [:key, :num]], p2.parameters);
250    assert_equal([[:key, :str], [:key, :num], [:keyrest, :h]], p3.parameters);
251    assert_equal([[:key, :str], [:key, :num], [:keyrest, :h], [:block, :blk]], p4.parameters);
252    assert_equal([[:rest, :r], [:key, :str], [:key, :num], [:keyrest, :h]], p5.parameters);
253    assert_equal([[:opt, :o1], [:opt, :o2], [:rest, :args], [:opt, :p], [:key, :k],
254                  [:keyrest, :kw], [:block, :b]], p6.parameters)
255  end
256
257  def m1(*args)
258    yield(*args)
259  end
260
261  def test_block
262    blk = Proc.new {|str: "foo", num: 424242| [str, num] }
263    assert_equal(["foo", 424242], m1(&blk))
264    assert_equal(["bar", 424242], m1(str: "bar", &blk))
265    assert_equal(["foo", 111111], m1(num: 111111, &blk))
266    assert_equal(["bar", 111111], m1(str: "bar", num: 111111, &blk))
267  end
268
269  def rest_keyrest(*args, **opt)
270    return *args, opt
271  end
272
273  def test_rest_keyrest
274    bug7665 = '[ruby-core:51278]'
275    bug8463 = '[ruby-core:55203] [Bug #8463]'
276    expect = [*%w[foo bar], {zzz: 42}]
277    assert_equal(expect, rest_keyrest(*expect), bug7665)
278    pr = proc {|*args, **opt| next *args, opt}
279    assert_equal(expect, pr.call(*expect), bug7665)
280    assert_equal(expect, pr.call(expect), bug8463)
281    pr = proc {|a, *b, **opt| next a, *b, opt}
282    assert_equal(expect, pr.call(expect), bug8463)
283    pr = proc {|a, **opt| next a, opt}
284    assert_equal(expect.values_at(0, -1), pr.call(expect), bug8463)
285  end
286
287  def test_bare_kwrest
288    # valid syntax, but its semantics is undefined
289    assert_valid_syntax("def bug7662(**) end")
290    assert_valid_syntax("def bug7662(*, **) end")
291    assert_valid_syntax("def bug7662(a, **) end")
292  end
293
294  def test_without_paren
295    bug7942 = '[ruby-core:52820] [Bug #7942]'
296    assert_valid_syntax("def bug7942 a: 1; end")
297    assert_valid_syntax("def bug7942 a: 1, **; end")
298
299    o = Object.new
300    eval("def o.bug7942 a: 1; a; end", nil, __FILE__, __LINE__)
301    assert_equal(1, o.bug7942(), bug7942)
302    assert_equal(42, o.bug7942(a: 42), bug7942)
303
304    o = Object.new
305    eval("def o.bug7942 a: 1, **; a; end", nil, __FILE__, __LINE__)
306    assert_equal(1, o.bug7942(), bug7942)
307    assert_equal(42, o.bug7942(a: 42), bug7942)
308  end
309
310  def test_required_keyword
311    feature7701 = '[ruby-core:51454] [Feature #7701] required keyword argument'
312    o = Object.new
313    assert_nothing_raised(SyntaxError, feature7701) do
314      eval("def o.foo(a:) a; end", nil, "xyzzy")
315      eval("def o.bar(a:,**b) [a, b]; end")
316    end
317    assert_raise_with_message(ArgumentError, /missing keyword/, feature7701) {o.foo}
318    assert_raise_with_message(ArgumentError, /unknown keyword/, feature7701) {o.foo(a:0, b:1)}
319    begin
320      o.foo(a: 0, b: 1)
321    rescue => e
322      assert_equal('xyzzy', e.backtrace_locations[0].path)
323    end
324    assert_equal(42, o.foo(a: 42), feature7701)
325    assert_equal([[:keyreq, :a]], o.method(:foo).parameters, feature7701)
326
327    bug8139 = '[ruby-core:53608] [Bug #8139] required keyword argument with rest hash'
328    assert_equal([42, {}], o.bar(a: 42), feature7701)
329    assert_equal([42, {c: feature7701}], o.bar(a: 42, c: feature7701), feature7701)
330    assert_equal([[:keyreq, :a], [:keyrest, :b]], o.method(:bar).parameters, feature7701)
331    assert_raise_with_message(ArgumentError, /missing keyword/, bug8139) {o.bar(c: bug8139)}
332    assert_raise_with_message(ArgumentError, /missing keyword/, bug8139) {o.bar}
333  end
334
335  def test_required_keyword_with_newline
336    bug9669 = '[ruby-core:61658] [Bug #9669]'
337    assert_nothing_raised(SyntaxError, bug9669) do
338      eval(<<-'end;', nil, __FILE__, __LINE__)
339        def bug9669.foo a:
340          return a
341        end
342      end;
343    end
344    assert_equal(42, bug9669.foo(a: 42))
345    o = nil
346    assert_nothing_raised(SyntaxError, bug9669) do
347      eval(<<-'end;', nil, __FILE__, __LINE__)
348        o = {
349          a:
350          1
351        }
352      end;
353    end
354    assert_equal({a: 1}, o, bug9669)
355  end
356
357  def test_required_keyword_with_reserved
358    bug10279 = '[ruby-core:65211] [Bug #10279]'
359    h = nil
360    assert_nothing_raised(SyntaxError, bug10279) do
361      break eval(<<-'end;', nil, __FILE__, __LINE__)
362        h = {a: if true then 42 end}
363      end;
364    end
365    assert_equal({a: 42}, h, bug10279)
366  end
367
368  def test_block_required_keyword
369    feature7701 = '[ruby-core:51454] [Feature #7701] required keyword argument'
370    b = assert_nothing_raised(SyntaxError, feature7701) do
371      break eval("proc {|a:| a}", nil, 'xyzzy', __LINE__)
372    end
373    assert_raise_with_message(ArgumentError, /missing keyword/, feature7701) {b.call}
374    e = assert_raise_with_message(ArgumentError, /unknown keyword/, feature7701) {b.call(a:0, b:1)}
375    assert_equal('xyzzy', e.backtrace_locations[0].path)
376
377    assert_equal(42, b.call(a: 42), feature7701)
378    assert_equal([[:keyreq, :a]], b.parameters, feature7701)
379
380    bug8139 = '[ruby-core:53608] [Bug #8139] required keyword argument with rest hash'
381    b = assert_nothing_raised(SyntaxError, feature7701) do
382      break eval("proc {|a:, **bl| [a, bl]}", nil, __FILE__, __LINE__)
383    end
384    assert_equal([42, {}], b.call(a: 42), feature7701)
385    assert_equal([42, {c: feature7701}], b.call(a: 42, c: feature7701), feature7701)
386    assert_equal([[:keyreq, :a], [:keyrest, :bl]], b.parameters, feature7701)
387    assert_raise_with_message(ArgumentError, /missing keyword/, bug8139) {b.call(c: bug8139)}
388    assert_raise_with_message(ArgumentError, /missing keyword/, bug8139) {b.call}
389
390    b = assert_nothing_raised(SyntaxError, feature7701) do
391      break eval("proc {|m, a:| [m, a]}", nil, 'xyzzy', __LINE__)
392    end
393    assert_raise_with_message(ArgumentError, /missing keyword/) {b.call}
394    assert_equal([:ok, 42], b.call(:ok, a: 42))
395    e = assert_raise_with_message(ArgumentError, /unknown keyword/) {b.call(42, a:0, b:1)}
396    assert_equal('xyzzy', e.backtrace_locations[0].path)
397    assert_equal([[:opt, :m], [:keyreq, :a]], b.parameters)
398  end
399
400  def test_super_with_keyword
401    bug8236 = '[ruby-core:54094] [Bug #8236]'
402    base = Class.new do
403      def foo(*args)
404        args
405      end
406    end
407    a = Class.new(base) do
408      def foo(arg, bar: 'x')
409        super
410      end
411    end
412    b = Class.new(base) do
413      def foo(*args, bar: 'x')
414        super
415      end
416    end
417    assert_equal([42, {:bar=>"x"}], a.new.foo(42), bug8236)
418    assert_equal([42, {:bar=>"x"}], b.new.foo(42), bug8236)
419  end
420
421  def test_zsuper_only_named_kwrest
422    bug8416 = '[ruby-core:55033] [Bug #8416]'
423    base = Class.new do
424      def foo(**h)
425        h
426      end
427    end
428    a = Class.new(base) do
429      def foo(**h)
430        super
431      end
432    end
433    assert_equal({:bar=>"x"}, a.new.foo(bar: "x"), bug8416)
434  end
435
436  def test_zsuper_only_anonymous_kwrest
437    bug8416 = '[ruby-core:55033] [Bug #8416]'
438    base = Class.new do
439      def foo(**h)
440        h
441      end
442    end
443    a = Class.new(base) do
444      def foo(**)
445        super
446      end
447    end
448    assert_equal({:bar=>"x"}, a.new.foo(bar: "x"), bug8416)
449  end
450
451  def test_precedence_of_keyword_arguments
452    bug8040 = '[ruby-core:53199] [Bug #8040]'
453    a = Class.new do
454      def foo(x, **h)
455        [x, h]
456      end
457    end
458    assert_equal([{}, {}], a.new.foo({}))
459    assert_equal([{}, {:bar=>"x"}], a.new.foo({}, bar: "x"), bug8040)
460  end
461
462  def test_precedence_of_keyword_arguments_with_post_argument
463    bug8993 = '[ruby-core:57706] [Bug #8993]'
464    a = Class.new do
465      def foo(a, b, c=1, *d, e, f:2, **g)
466        [a, b, c, d, e, f, g]
467      end
468    end
469    assert_equal([1, 2, 1, [], {:f=>5}, 2, {}], a.new.foo(1, 2, f:5), bug8993)
470  end
471
472  def test_splat_keyword_nondestructive
473    bug9776 = '[ruby-core:62161] [Bug #9776]'
474
475    h = {a: 1}
476    assert_equal({a:1, b:2}, {**h, b:2})
477    assert_equal({a:1}, h, bug9776)
478
479    pr = proc {|**opt| next opt}
480    assert_equal({a: 1}, pr.call(**h))
481    assert_equal({a: 1, b: 2}, pr.call(**h, b: 2))
482    assert_equal({a: 1}, h, bug9776)
483  end
484
485  def test_splat_hash_conversion
486    bug9898 = '[ruby-core:62921] [Bug #9898]'
487
488    o = Object.new
489    def o.to_hash() { a: 1 } end
490    assert_equal({a: 1}, m1(**o) {|x| break x}, bug9898)
491    o2 = Object.new
492    def o2.to_hash() { b: 2 } end
493    assert_equal({a: 1, b: 2}, m1(**o, **o2) {|x| break x}, bug9898)
494  end
495
496  def test_implicit_hash_conversion
497    bug10016 = '[ruby-core:63593] [Bug #10016]'
498
499    o = Object.new
500    def o.to_hash() { k: 9 } end
501    assert_equal([1, 42, [], o, :key, {}, nil], f9(1, o))
502    assert_equal([1, 9], m1(1, o) {|a, k: 0| break [a, k]}, bug10016)
503    assert_equal([1, 9], m1(1, o, &->(a, k: 0) {break [a, k]}), bug10016)
504  end
505
506  def test_splat_hash
507    m = Object.new
508    def m.f() :ok; end
509    def m.f1(a) a; end
510    def m.f2(a = nil) a; end
511    def m.f3(**a) a; end
512    def m.f4(*a) a; end
513    o = {a: 1}
514    assert_raise_with_message(ArgumentError, /unknown keyword: a/) {
515      m.f(**o)
516    }
517    o = {}
518    assert_equal(:ok, m.f(**o), '[ruby-core:68124] [Bug #10856]')
519    a = []
520    assert_equal(:ok, m.f(*a, **o), '[ruby-core:83638] [Bug #10856]')
521
522    o = {a: 42}
523    assert_warning('', 'splat to kwrest') do
524      assert_equal({a: 42}, m.f3(**o))
525    end
526    assert_warning('', 'splat to rest') do
527      assert_equal([{a: 42}], m.f4(**o))
528    end
529
530    assert_warning('') do
531      assert_equal({a: 42}, m.f2("a".to_sym => 42), '[ruby-core:82291] [Bug #13793]')
532    end
533
534    o = {}
535    a = [:ok]
536    assert_equal(:ok, m.f2(*a, **o), '[ruby-core:83638] [Bug #10856]')
537  end
538
539  def test_gced_object_in_stack
540    bug8964 = '[ruby-dev:47729] [Bug #8964]'
541    assert_normal_exit %q{
542      def m(a: [])
543      end
544      GC.stress = true
545      tap { m }
546      GC.start
547      tap { m }
548    }, bug8964
549    assert_normal_exit %q{
550      prc = Proc.new {|a: []|}
551      GC.stress = true
552      tap { prc.call }
553      GC.start
554      tap { prc.call }
555    }, bug8964
556  end
557
558  def test_dynamic_symbol_keyword
559    bug10266 = '[ruby-dev:48564] [Bug #10266]'
560    assert_separately(['-', bug10266], "#{<<~"begin;"}\n#{<<~'end;'}")
561    begin;
562      bug = ARGV.shift
563      "hoge".to_sym
564      assert_nothing_raised(bug) {eval("def a(hoge:); end")}
565    end;
566  end
567
568  def test_unknown_keyword_with_block
569    bug10413 = '[ruby-core:65837] [Bug #10413]'
570    class << (o = Object.new)
571      def bar(k2: 'v2')
572      end
573
574      def foo
575        bar(k1: 1)
576      end
577    end
578    assert_raise_with_message(ArgumentError, /unknown keyword: k1/, bug10413) {
579      o.foo {raise "unreachable"}
580    }
581  end
582
583  def test_unknown_keyword
584    bug13004 = '[ruby-dev:49893] [Bug #13004]'
585    assert_raise_with_message(ArgumentError, /unknown keyword: invalid-argument/, bug13004) {
586      [].sample(random: nil, "invalid-argument": nil)
587    }
588  end
589
590  def test_super_with_anon_restkeywords
591    bug10659 = '[ruby-core:67157] [Bug #10659]'
592
593    foo = Class.new do
594      def foo(**h)
595        h
596      end
597    end
598
599    class << (obj = foo.new)
600      def foo(bar: "bar", **)
601        super
602      end
603    end
604
605    assert_nothing_raised(TypeError, bug10659) {
606      assert_equal({:bar => "bar"}, obj.foo, bug10659)
607    }
608  end
609
610  def m(a) yield a end
611
612  def test_nonsymbol_key
613    result = m(["a" => 10]) { |a = nil, **b| [a, b] }
614    assert_equal([{"a" => 10}, {}], result)
615  end
616
617  def method_for_test_to_hash_call_during_setup_complex_parameters k1:, k2:, **rest_kw
618    [k1, k2, rest_kw]
619  end
620
621  def test_to_hash_call_during_setup_complex_parameters
622    sym = "sym_#{Time.now}".to_sym
623    h = method_for_test_to_hash_call_during_setup_complex_parameters k1: "foo", k2: "bar", sym => "baz"
624    assert_equal ["foo", "bar", {sym => "baz"}], h, '[Bug #11027]'
625  end
626
627  class AttrSetTest
628    attr_accessor :foo
629    alias set_foo :foo=
630  end
631
632  def test_attr_set_method_cache
633    obj = AttrSetTest.new
634    h = {a: 1, b: 2}
635    2.times{
636      obj.foo = 1
637      assert_equal(1, obj.foo)
638      obj.set_foo 2
639      assert_equal(2, obj.foo)
640      obj.set_foo(x: 1, y: 2)
641      assert_equal({x: 1, y: 2}, obj.foo)
642      obj.set_foo(x: 1, y: 2, **h)
643      assert_equal({x: 1, y: 2, **h}, obj.foo)
644    }
645  end
646
647  def test_kwrest_overwritten
648    bug13015 = '[ruby-core:78536] [Bug #13015]'
649
650    klass = EnvUtil.labeled_class("Parent") do
651      def initialize(d:)
652      end
653    end
654
655    klass = EnvUtil.labeled_class("Child", klass) do
656      def initialize(d:, **h)
657        h = [2, 3]
658        super
659      end
660    end
661
662    assert_raise_with_message(TypeError, /expected Hash/, bug13015) do
663      klass.new(d: 4)
664    end
665  end
666
667  def test_non_keyword_hash_subclass
668    bug12884 = '[ruby-core:77813] [Bug #12884]'
669    klass = EnvUtil.labeled_class("Child", Hash)
670    obj = Object.new
671    def obj.t(params = klass.new, d: nil); params; end
672    x = klass.new
673    x["foo"] = "bar"
674    result = obj.t(x)
675    assert_equal(x, result)
676    assert_kind_of(klass, result, bug12884)
677  end
678
679  def test_arity_error_message
680    obj = Object.new
681    def obj.t(x:) end
682    assert_raise_with_message(ArgumentError, /required keyword: x\)/) do
683      obj.t(42)
684    end
685    obj = Object.new
686    def obj.t(x:, y:, z: nil) end
687    assert_raise_with_message(ArgumentError, /required keywords: x, y\)/) do
688      obj.t(42)
689    end
690  end
691
692  def many_kwargs(a0: '', a1: '', a2: '', a3: '', a4: '', a5: '', a6: '', a7: '',
693                  b0: '', b1: '', b2: '', b3: '', b4: '', b5: '', b6: '', b7: '',
694                  c0: '', c1: '', c2: '', c3: '', c4: '', c5: '', c6: '', c7: '',
695                  d0: '', d1: '', d2: '', d3: '', d4: '', d5: '', d6: '', d7: '',
696                  e0: '')
697    [a0, a1, a2, a3, a4, a5, a6, a7,
698     b0, b1, b2, b3, b4, b5, b6, b7,
699     c0, c1, c2, c3, c4, c5, c6, c7,
700     d0, d1, d2, d3, d4, d5, d6, d7,
701     e0]
702  end
703
704  def test_many_kwargs
705    i = 0
706    assert_equal(:ok, many_kwargs(a0: :ok)[i], "#{i}: a0"); i+=1
707    assert_equal(:ok, many_kwargs(a1: :ok)[i], "#{i}: a1"); i+=1
708    assert_equal(:ok, many_kwargs(a2: :ok)[i], "#{i}: a2"); i+=1
709    assert_equal(:ok, many_kwargs(a3: :ok)[i], "#{i}: a3"); i+=1
710    assert_equal(:ok, many_kwargs(a4: :ok)[i], "#{i}: a4"); i+=1
711    assert_equal(:ok, many_kwargs(a5: :ok)[i], "#{i}: a5"); i+=1
712    assert_equal(:ok, many_kwargs(a6: :ok)[i], "#{i}: a6"); i+=1
713    assert_equal(:ok, many_kwargs(a7: :ok)[i], "#{i}: a7"); i+=1
714
715    assert_equal(:ok, many_kwargs(b0: :ok)[i], "#{i}: b0"); i+=1
716    assert_equal(:ok, many_kwargs(b1: :ok)[i], "#{i}: b1"); i+=1
717    assert_equal(:ok, many_kwargs(b2: :ok)[i], "#{i}: b2"); i+=1
718    assert_equal(:ok, many_kwargs(b3: :ok)[i], "#{i}: b3"); i+=1
719    assert_equal(:ok, many_kwargs(b4: :ok)[i], "#{i}: b4"); i+=1
720    assert_equal(:ok, many_kwargs(b5: :ok)[i], "#{i}: b5"); i+=1
721    assert_equal(:ok, many_kwargs(b6: :ok)[i], "#{i}: b6"); i+=1
722    assert_equal(:ok, many_kwargs(b7: :ok)[i], "#{i}: b7"); i+=1
723
724    assert_equal(:ok, many_kwargs(c0: :ok)[i], "#{i}: c0"); i+=1
725    assert_equal(:ok, many_kwargs(c1: :ok)[i], "#{i}: c1"); i+=1
726    assert_equal(:ok, many_kwargs(c2: :ok)[i], "#{i}: c2"); i+=1
727    assert_equal(:ok, many_kwargs(c3: :ok)[i], "#{i}: c3"); i+=1
728    assert_equal(:ok, many_kwargs(c4: :ok)[i], "#{i}: c4"); i+=1
729    assert_equal(:ok, many_kwargs(c5: :ok)[i], "#{i}: c5"); i+=1
730    assert_equal(:ok, many_kwargs(c6: :ok)[i], "#{i}: c6"); i+=1
731    assert_equal(:ok, many_kwargs(c7: :ok)[i], "#{i}: c7"); i+=1
732
733    assert_equal(:ok, many_kwargs(d0: :ok)[i], "#{i}: d0"); i+=1
734    assert_equal(:ok, many_kwargs(d1: :ok)[i], "#{i}: d1"); i+=1
735    assert_equal(:ok, many_kwargs(d2: :ok)[i], "#{i}: d2"); i+=1
736    assert_equal(:ok, many_kwargs(d3: :ok)[i], "#{i}: d3"); i+=1
737    assert_equal(:ok, many_kwargs(d4: :ok)[i], "#{i}: d4"); i+=1
738    assert_equal(:ok, many_kwargs(d5: :ok)[i], "#{i}: d5"); i+=1
739    assert_equal(:ok, many_kwargs(d6: :ok)[i], "#{i}: d6"); i+=1
740    assert_equal(:ok, many_kwargs(d7: :ok)[i], "#{i}: d7"); i+=1
741
742    assert_equal(:ok, many_kwargs(e0: :ok)[i], "#{i}: e0"); i+=1
743  end
744
745  def test_splat_empty_hash_with_block_passing
746    assert_valid_syntax("bug15087(**{}, &nil)")
747  end
748end
749