1require 'test/unit'
2require_relative 'envutil'
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 test_method_parameters
121    assert_equal([[:key, :str], [:key, :num]], method(:f1).parameters);
122    assert_equal([[:req, :x], [:key, :str], [:key, :num]], method(:f2).parameters);
123    assert_equal([[:key, :str], [:key, :num], [:keyrest, :h]], method(:f3).parameters);
124    assert_equal([[:key, :str], [:key, :num]], method(:f4).parameters);
125    assert_equal([[:key, :str], [:key, :num], [:keyrest, :h]], method(:f5).parameters);
126    assert_equal([[:key, :str], [:key, :num], [:keyrest, :h], [:block, :blk]], method(:f6).parameters);
127    assert_equal([[:rest, :r], [:key, :str], [:key, :num], [:keyrest, :h]], method(:f7).parameters);
128    assert_equal([[:opt, :opt], [:rest, :rest], [:key, :key]], method(:f8).parameters) # [Bug #7540] [ruby-core:50735]
129    assert_equal([[:req, :r], [:opt, :o], [:rest, :args], [:req, :p], [:key, :k],
130                  [:keyrest, :kw], [:block, :b]], method(:f9).parameters)
131  end
132
133  def test_lambda
134    f = ->(str: "foo", num: 424242) { [str, num] }
135    assert_equal(["foo", 424242], f[])
136    assert_equal(["bar", 424242], f[str: "bar"])
137    assert_equal(["foo", 111111], f[num: 111111])
138    assert_equal(["bar", 111111], f[str: "bar", num: 111111])
139  end
140
141
142  def p1
143    Proc.new do |str: "foo", num: 424242|
144      [str, num]
145    end
146  end
147
148  def test_p1
149    assert_equal(["foo", 424242], p1[])
150    assert_equal(["bar", 424242], p1[str: "bar"])
151    assert_equal(["foo", 111111], p1[num: 111111])
152    assert_equal(["bar", 111111], p1[str: "bar", num: 111111])
153    assert_raise(ArgumentError) { p1[str: "bar", check: true] }
154    assert_equal(["foo", 424242], p1["string"] )
155  end
156
157
158  def p2
159    Proc.new do |x, str: "foo", num: 424242|
160      [x, str, num]
161    end
162  end
163
164  def test_p2
165    assert_equal([nil, "foo", 424242], p2[])
166    assert_equal([:xyz, "foo", 424242], p2[:xyz])
167  end
168
169
170  def p3
171    Proc.new do |str: "foo", num: 424242, **h|
172      [str, num, h]
173    end
174  end
175
176  def test_p3
177    assert_equal(["foo", 424242, {}], p3[])
178    assert_equal(["bar", 424242, {}], p3[str: "bar"])
179    assert_equal(["foo", 111111, {}], p3[num: 111111])
180    assert_equal(["bar", 111111, {}], p3[str: "bar", num: 111111])
181    assert_equal(["bar", 424242, {:check=>true}], p3[str: "bar", check: true])
182    assert_equal(["foo", 424242, {}], p3["string"])
183  end
184
185
186  def p4
187    Proc.new do |str: "foo", num: 424242, **h, &blk|
188      [str, num, h, blk]
189    end
190  end
191
192  def test_p4
193    assert_equal(["foo", 424242, {}, nil], p4[])
194    assert_equal(["bar", 424242, {}, nil], p4[str: "bar"])
195    assert_equal(["foo", 111111, {}, nil], p4[num: 111111])
196    assert_equal(["bar", 111111, {}, nil], p4[str: "bar", num: 111111])
197    assert_equal(["bar", 424242, {:check=>true}, nil], p4[str: "bar", check: true])
198    a = p4.call {|x| x + 42 }
199    assert_equal(["foo", 424242, {}], a[0, 3])
200    assert_equal(43, a.last.call(1))
201  end
202
203
204  def p5
205    Proc.new do |*r, str: "foo", num: 424242, **h|
206      [r, str, num, h]
207    end
208  end
209
210  def test_p5
211    assert_equal([[], "foo", 424242, {}], p5[])
212    assert_equal([[], "bar", 424242, {}], p5[str: "bar"])
213    assert_equal([[], "foo", 111111, {}], p5[num: 111111])
214    assert_equal([[], "bar", 111111, {}], p5[str: "bar", num: 111111])
215    assert_equal([[1], "foo", 424242, {}], p5[1])
216    assert_equal([[1, 2], "foo", 424242, {}], p5[1, 2])
217    assert_equal([[1, 2, 3], "foo", 424242, {}], p5[1, 2, 3])
218    assert_equal([[1], "bar", 424242, {}], p5[1, str: "bar"])
219    assert_equal([[1, 2], "bar", 424242, {}], p5[1, 2, str: "bar"])
220    assert_equal([[1, 2, 3], "bar", 424242, {}], p5[1, 2, 3, str: "bar"])
221  end
222
223
224  def p6
225    Proc.new do |o1, o2=42, *args, p, k: :key, **kw, &b|
226      [o1, o2, args, p, k, kw, b]
227    end
228  end
229
230  def test_p6
231    assert_equal([nil, 42, [], nil, :key, {}, nil], p6[])
232    assert_equal([1, 42, [], 2, :key, {}, nil], p6[1, 2])
233    assert_equal([1, 2, [], 3, :key, {}, nil], p6[1, 2, 3])
234    assert_equal([1, 2, [3], 4, :key, {}, nil], p6[1, 2, 3, 4])
235    assert_equal([1, 2, [3, 4], 5, :key, {str: "bar"}, nil], p6[1, 2, 3, 4, 5, str: "bar"])
236  end
237
238  def test_proc_parameters
239    assert_equal([[:key, :str], [:key, :num]], p1.parameters);
240    assert_equal([[:opt, :x], [:key, :str], [:key, :num]], p2.parameters);
241    assert_equal([[:key, :str], [:key, :num], [:keyrest, :h]], p3.parameters);
242    assert_equal([[:key, :str], [:key, :num], [:keyrest, :h], [:block, :blk]], p4.parameters);
243    assert_equal([[:rest, :r], [:key, :str], [:key, :num], [:keyrest, :h]], p5.parameters);
244    assert_equal([[:opt, :o1], [:opt, :o2], [:rest, :args], [:opt, :p], [:key, :k],
245                  [:keyrest, :kw], [:block, :b]], p6.parameters)
246  end
247
248  def m1(*args)
249    yield *args
250  end
251
252  def test_block
253    blk = Proc.new {|str: "foo", num: 424242| [str, num] }
254    assert_equal(["foo", 424242], m1(&blk))
255    assert_equal(["bar", 424242], m1(str: "bar", &blk))
256    assert_equal(["foo", 111111], m1(num: 111111, &blk))
257    assert_equal(["bar", 111111], m1(str: "bar", num: 111111, &blk))
258  end
259
260  def rest_keyrest(*args, **opt)
261    return *args, opt
262  end
263
264  def test_rest_keyrest
265    bug7665 = '[ruby-core:51278]'
266    bug8463 = '[ruby-core:55203] [Bug #8463]'
267    expect = [*%w[foo bar], {zzz: 42}]
268    assert_equal(expect, rest_keyrest(*expect), bug7665)
269    pr = proc {|*args, **opt| next *args, opt}
270    assert_equal(expect, pr.call(*expect), bug7665)
271    assert_equal(expect, pr.call(expect), bug8463)
272    pr = proc {|a, *b, **opt| next a, *b, opt}
273    assert_equal(expect, pr.call(expect), bug8463)
274    pr = proc {|a, **opt| next a, opt}
275    assert_equal(expect.values_at(0, -1), pr.call(expect), bug8463)
276  end
277
278  def test_bare_kwrest
279    # valid syntax, but its semantics is undefined
280    assert_valid_syntax("def bug7662(**) end")
281    assert_valid_syntax("def bug7662(*, **) end")
282    assert_valid_syntax("def bug7662(a, **) end")
283  end
284
285  def test_without_paren
286    bug7942 = '[ruby-core:52820] [Bug #7942]'
287    assert_valid_syntax("def bug7942 a: 1; end")
288    assert_valid_syntax("def bug7942 a: 1, **; end")
289
290    o = Object.new
291    eval("def o.bug7942 a: 1; a; end", nil, __FILE__, __LINE__)
292    assert_equal(1, o.bug7942(), bug7942)
293    assert_equal(42, o.bug7942(a: 42), bug7942)
294
295    o = Object.new
296    eval("def o.bug7942 a: 1, **; a; end", nil, __FILE__, __LINE__)
297    assert_equal(1, o.bug7942(), bug7942)
298    assert_equal(42, o.bug7942(a: 42), bug7942)
299  end
300
301  def test_super_with_keyword
302    bug8236 = '[ruby-core:54094] [Bug #8236]'
303    base = Class.new do
304      def foo(*args)
305        args
306      end
307    end
308    a = Class.new(base) do
309      def foo(arg, bar: 'x')
310        super
311      end
312    end
313    b = Class.new(base) do
314      def foo(*args, bar: 'x')
315        super
316      end
317    end
318    assert_equal([42, {:bar=>"x"}], a.new.foo(42), bug8236)
319    assert_equal([42, {:bar=>"x"}], b.new.foo(42), bug8236)
320  end
321
322  def test_zsuper_only_named_kwrest
323    bug8416 = '[ruby-core:55033] [Bug #8416]'
324    base = Class.new do
325      def foo(**h)
326        h
327      end
328    end
329    a = Class.new(base) do
330      def foo(**h)
331        super
332      end
333    end
334    assert_equal({:bar=>"x"}, a.new.foo(bar: "x"), bug8416)
335  end
336
337  def test_zsuper_only_anonymous_kwrest
338    bug8416 = '[ruby-core:55033] [Bug #8416]'
339    base = Class.new do
340      def foo(**h)
341        h
342      end
343    end
344    a = Class.new(base) do
345      def foo(**)
346        super
347      end
348    end
349    assert_equal({:bar=>"x"}, a.new.foo(bar: "x"), bug8416)
350  end
351
352  def test_precedence_of_keyword_arguments
353    bug8040 = '[ruby-core:53199] [Bug #8040]'
354    a = Class.new do
355      def foo(x, **h)
356        [x, h]
357      end
358    end
359    assert_equal([{}, {}], a.new.foo({}))
360    assert_equal([{}, {:bar=>"x"}], a.new.foo({}, bar: "x"))
361  end
362end
363