diff options
Diffstat (limited to 'test/ruby/test_keyword.rb')
-rw-r--r-- | test/ruby/test_keyword.rb | 439 |
1 files changed, 325 insertions, 114 deletions
diff --git a/test/ruby/test_keyword.rb b/test/ruby/test_keyword.rb index c8191a722c..a214acc232 100644 --- a/test/ruby/test_keyword.rb +++ b/test/ruby/test_keyword.rb @@ -182,6 +182,52 @@ class TestKeywordArguments < Test::Unit::TestCase [:keyrest, :kw], [:block, :b]], method(:f9).parameters) end + def test_keyword_with_anonymous_keyword_splat + def self.a(b: 1, **) [b, **] end + kw = {b: 2, c: 3} + assert_equal([2, {c: 3}], a(**kw)) + assert_equal({b: 2, c: 3}, kw) + end + + def test_keyword_splat_nil + # cfunc call + assert_equal(nil, p(**nil)) + + def self.a0(&); end + assert_equal(nil, a0(**nil)) + assert_equal(nil, :a0.to_proc.call(self, **nil)) + assert_equal(nil, a0(**nil, &:block)) + + def self.o(x=1); x end + assert_equal(1, o(**nil)) + assert_equal(2, o(2, **nil)) + assert_equal(1, o(*nil, **nil)) + assert_equal(1, o(**nil, **nil)) + assert_equal({a: 1}, o(a: 1, **nil)) + assert_equal({a: 1}, o(**nil, a: 1)) + + # symproc call + assert_equal(1, :o.to_proc.call(self, **nil)) + + def self.s(*a); a end + assert_equal([], s(**nil)) + assert_equal([1], s(1, **nil)) + assert_equal([], s(*nil, **nil)) + + def self.kws(**a); a end + assert_equal({}, kws(**nil)) + assert_equal({}, kws(*nil, **nil)) + + def self.skws(*a, **kw); [a, kw] end + assert_equal([[], {}], skws(**nil)) + assert_equal([[1], {}], skws(1, **nil)) + assert_equal([[], {}], skws(*nil, **nil)) + + assert_equal({}, {**nil}) + assert_equal({a: 1}, {a: 1, **nil}) + assert_equal({a: 1}, {**nil, a: 1}) + end + def test_lambda f = ->(str: "foo", num: 424242) { [str, num] } assert_equal(["foo", 424242], f[]) @@ -190,27 +236,74 @@ class TestKeywordArguments < Test::Unit::TestCase assert_equal(["bar", 111111], f[str: "bar", num: 111111]) end + def test_unset_hash_flag + bug18625 = "[ruby-core: 107847]" + singleton_class.class_eval do + ruby2_keywords def foo(*args) + args + end + + def single(arg) + arg + end + + def splat(*args) + args.last + end + + def kwargs(**kw) + kw + end + end + + h = { a: 1 } + args = foo(**h) + marked = args.last + assert_equal(true, Hash.ruby2_keywords_hash?(marked)) + + after_usage = single(*args) + assert_equal(h, after_usage) + assert_same(marked, args.last) + assert_not_same(marked, after_usage) + assert_equal(false, Hash.ruby2_keywords_hash?(after_usage)) + + after_usage = splat(*args) + assert_equal(h, after_usage) + assert_same(marked, args.last) + assert_not_same(marked, after_usage, bug18625) + assert_equal(false, Hash.ruby2_keywords_hash?(after_usage), bug18625) + + after_usage = kwargs(*args) + assert_equal(h, after_usage) + assert_same(marked, args.last) + assert_not_same(marked, after_usage, bug18625) + assert_not_same(marked, after_usage) + assert_equal(false, Hash.ruby2_keywords_hash?(after_usage)) + + assert_equal(true, Hash.ruby2_keywords_hash?(marked)) + end + + def assert_equal_not_same(kw, res) + assert_instance_of(Hash, res) + assert_equal(kw, res) + assert_not_same(kw, res) + end + def test_keyword_splat_new kw = {} h = {a: 1} - def self.assert_equal_not_same(kw, res) - assert_instance_of(Hash, res) - assert_equal(kw, res) - assert_not_same(kw, res) - end - - def self.y(**kw) kw end - m = method(:y) - assert_equal(false, y(**{}).frozen?) - assert_equal_not_same(kw, y(**kw)) - assert_equal_not_same(h, y(**h)) - assert_equal(false, send(:y, **{}).frozen?) - assert_equal_not_same(kw, send(:y, **kw)) - assert_equal_not_same(h, send(:y, **h)) - assert_equal(false, public_send(:y, **{}).frozen?) - assert_equal_not_same(kw, public_send(:y, **kw)) - assert_equal_not_same(h, public_send(:y, **h)) + def self.yo(**kw) kw end + m = method(:yo) + assert_equal(false, yo(**{}).frozen?) + assert_equal_not_same(kw, yo(**kw)) + assert_equal_not_same(h, yo(**h)) + assert_equal(false, send(:yo, **{}).frozen?) + assert_equal_not_same(kw, send(:yo, **kw)) + assert_equal_not_same(h, send(:yo, **h)) + assert_equal(false, public_send(:yo, **{}).frozen?) + assert_equal_not_same(kw, public_send(:yo, **kw)) + assert_equal_not_same(h, public_send(:yo, **h)) assert_equal(false, m.(**{}).frozen?) assert_equal_not_same(kw, m.(**kw)) assert_equal_not_same(h, m.(**h)) @@ -219,25 +312,25 @@ class TestKeywordArguments < Test::Unit::TestCase assert_equal_not_same(h, m.send(:call, **h)) m = method(:send) - assert_equal(false, m.(:y, **{}).frozen?) - assert_equal_not_same(kw, m.(:y, **kw)) - assert_equal_not_same(h, m.(:y, **h)) - assert_equal(false, m.send(:call, :y, **{}).frozen?) - assert_equal_not_same(kw, m.send(:call, :y, **kw)) - assert_equal_not_same(h, m.send(:call, :y, **h)) - - singleton_class.send(:remove_method, :y) - define_singleton_method(:y) { |**kw| kw } - m = method(:y) - assert_equal(false, y(**{}).frozen?) - assert_equal_not_same(kw, y(**kw)) - assert_equal_not_same(h, y(**h)) - assert_equal(false, send(:y, **{}).frozen?) - assert_equal_not_same(kw, send(:y, **kw)) - assert_equal_not_same(h, send(:y, **h)) - assert_equal(false, public_send(:y, **{}).frozen?) - assert_equal_not_same(kw, public_send(:y, **kw)) - assert_equal_not_same(h, public_send(:y, **h)) + assert_equal(false, m.(:yo, **{}).frozen?) + assert_equal_not_same(kw, m.(:yo, **kw)) + assert_equal_not_same(h, m.(:yo, **h)) + assert_equal(false, m.send(:call, :yo, **{}).frozen?) + assert_equal_not_same(kw, m.send(:call, :yo, **kw)) + assert_equal_not_same(h, m.send(:call, :yo, **h)) + + singleton_class.send(:remove_method, :yo) + define_singleton_method(:yo) { |**kw| kw } + m = method(:yo) + assert_equal(false, yo(**{}).frozen?) + assert_equal_not_same(kw, yo(**kw)) + assert_equal_not_same(h, yo(**h)) + assert_equal(false, send(:yo, **{}).frozen?) + assert_equal_not_same(kw, send(:yo, **kw)) + assert_equal_not_same(h, send(:yo, **h)) + assert_equal(false, public_send(:yo, **{}).frozen?) + assert_equal_not_same(kw, public_send(:yo, **kw)) + assert_equal_not_same(h, public_send(:yo, **h)) assert_equal(false, m.(**{}).frozen?) assert_equal_not_same(kw, m.(**kw)) assert_equal_not_same(h, m.(**h)) @@ -245,17 +338,17 @@ class TestKeywordArguments < Test::Unit::TestCase assert_equal_not_same(kw, m.send(:call, **kw)) assert_equal_not_same(h, m.send(:call, **h)) - y = lambda { |**kw| kw } - m = y.method(:call) - assert_equal(false, y.(**{}).frozen?) - assert_equal_not_same(kw, y.(**kw)) - assert_equal_not_same(h, y.(**h)) - assert_equal(false, y.send(:call, **{}).frozen?) - assert_equal_not_same(kw, y.send(:call, **kw)) - assert_equal_not_same(h, y.send(:call, **h)) - assert_equal(false, y.public_send(:call, **{}).frozen?) - assert_equal_not_same(kw, y.public_send(:call, **kw)) - assert_equal_not_same(h, y.public_send(:call, **h)) + yo = lambda { |**kw| kw } + m = yo.method(:call) + assert_equal(false, yo.(**{}).frozen?) + assert_equal_not_same(kw, yo.(**kw)) + assert_equal_not_same(h, yo.(**h)) + assert_equal(false, yo.send(:call, **{}).frozen?) + assert_equal_not_same(kw, yo.send(:call, **kw)) + assert_equal_not_same(h, yo.send(:call, **h)) + assert_equal(false, yo.public_send(:call, **{}).frozen?) + assert_equal_not_same(kw, yo.public_send(:call, **kw)) + assert_equal_not_same(h, yo.public_send(:call, **h)) assert_equal(false, m.(**{}).frozen?) assert_equal_not_same(kw, m.(**kw)) assert_equal_not_same(h, m.(**h)) @@ -263,17 +356,17 @@ class TestKeywordArguments < Test::Unit::TestCase assert_equal_not_same(kw, m.send(:call, **kw)) assert_equal_not_same(h, m.send(:call, **h)) - y = :y.to_proc - m = y.method(:call) - assert_equal(false, y.(self, **{}).frozen?) - assert_equal_not_same(kw, y.(self, **kw)) - assert_equal_not_same(h, y.(self, **h)) - assert_equal(false, y.send(:call, self, **{}).frozen?) - assert_equal_not_same(kw, y.send(:call, self, **kw)) - assert_equal_not_same(h, y.send(:call, self, **h)) - assert_equal(false, y.public_send(:call, self, **{}).frozen?) - assert_equal_not_same(kw, y.public_send(:call, self, **kw)) - assert_equal_not_same(h, y.public_send(:call, self, **h)) + yo = :yo.to_proc + m = yo.method(:call) + assert_equal(false, yo.(self, **{}).frozen?) + assert_equal_not_same(kw, yo.(self, **kw)) + assert_equal_not_same(h, yo.(self, **h)) + assert_equal(false, yo.send(:call, self, **{}).frozen?) + assert_equal_not_same(kw, yo.send(:call, self, **kw)) + assert_equal_not_same(h, yo.send(:call, self, **h)) + assert_equal(false, yo.public_send(:call, self, **{}).frozen?) + assert_equal_not_same(kw, yo.public_send(:call, self, **kw)) + assert_equal_not_same(h, yo.public_send(:call, self, **h)) assert_equal(false, m.(self, **{}).frozen?) assert_equal_not_same(kw, m.(self, **kw)) assert_equal_not_same(h, m.(self, **h)) @@ -282,20 +375,20 @@ class TestKeywordArguments < Test::Unit::TestCase assert_equal_not_same(h, m.send(:call, self, **h)) c = Class.new do - def y(**kw) kw end + def yo(**kw) kw end end o = c.new - def o.y(**kw) super end - m = o.method(:y) - assert_equal(false, o.y(**{}).frozen?) - assert_equal_not_same(kw, o.y(**kw)) - assert_equal_not_same(h, o.y(**h)) - assert_equal(false, o.send(:y, **{}).frozen?) - assert_equal_not_same(kw, o.send(:y, **kw)) - assert_equal_not_same(h, o.send(:y, **h)) - assert_equal(false, o.public_send(:y, **{}).frozen?) - assert_equal_not_same(kw, o.public_send(:y, **kw)) - assert_equal_not_same(h, o.public_send(:y, **h)) + def o.yo(**kw) super end + m = o.method(:yo) + assert_equal(false, o.yo(**{}).frozen?) + assert_equal_not_same(kw, o.yo(**kw)) + assert_equal_not_same(h, o.yo(**h)) + assert_equal(false, o.send(:yo, **{}).frozen?) + assert_equal_not_same(kw, o.send(:yo, **kw)) + assert_equal_not_same(h, o.send(:yo, **h)) + assert_equal(false, o.public_send(:yo, **{}).frozen?) + assert_equal_not_same(kw, o.public_send(:yo, **kw)) + assert_equal_not_same(h, o.public_send(:yo, **h)) assert_equal(false, m.(**{}).frozen?) assert_equal_not_same(kw, m.(**kw)) assert_equal_not_same(h, m.(**h)) @@ -303,17 +396,17 @@ class TestKeywordArguments < Test::Unit::TestCase assert_equal_not_same(kw, m.send(:call, **kw)) assert_equal_not_same(h, m.send(:call, **h)) - o.singleton_class.send(:remove_method, :y) - def o.y(**kw) super(**kw) end - assert_equal(false, o.y(**{}).frozen?) - assert_equal_not_same(kw, o.y(**kw)) - assert_equal_not_same(h, o.y(**h)) - assert_equal(false, o.send(:y, **{}).frozen?) - assert_equal_not_same(kw, o.send(:y, **kw)) - assert_equal_not_same(h, o.send(:y, **h)) - assert_equal(false, o.public_send(:y, **{}).frozen?) - assert_equal_not_same(kw, o.public_send(:y, **kw)) - assert_equal_not_same(h, o.public_send(:y, **h)) + o.singleton_class.send(:remove_method, :yo) + def o.yo(**kw) super(**kw) end + assert_equal(false, o.yo(**{}).frozen?) + assert_equal_not_same(kw, o.yo(**kw)) + assert_equal_not_same(h, o.yo(**h)) + assert_equal(false, o.send(:yo, **{}).frozen?) + assert_equal_not_same(kw, o.send(:yo, **kw)) + assert_equal_not_same(h, o.send(:yo, **h)) + assert_equal(false, o.public_send(:yo, **{}).frozen?) + assert_equal_not_same(kw, o.public_send(:yo, **kw)) + assert_equal_not_same(h, o.public_send(:yo, **h)) assert_equal(false, m.(**{}).frozen?) assert_equal_not_same(kw, m.(**kw)) assert_equal_not_same(h, m.(**h)) @@ -325,17 +418,17 @@ class TestKeywordArguments < Test::Unit::TestCase def method_missing(_, **kw) kw end end o = c.new - def o.y(**kw) super end - m = o.method(:y) - assert_equal(false, o.y(**{}).frozen?) - assert_equal_not_same(kw, o.y(**kw)) - assert_equal_not_same(h, o.y(**h)) - assert_equal(false, o.send(:y, **{}).frozen?) - assert_equal_not_same(kw, o.send(:y, **kw)) - assert_equal_not_same(h, o.send(:y, **h)) - assert_equal(false, o.public_send(:y, **{}).frozen?) - assert_equal_not_same(kw, o.public_send(:y, **kw)) - assert_equal_not_same(h, o.public_send(:y, **h)) + def o.yo(**kw) super end + m = o.method(:yo) + assert_equal(false, o.yo(**{}).frozen?) + assert_equal_not_same(kw, o.yo(**kw)) + assert_equal_not_same(h, o.yo(**h)) + assert_equal(false, o.send(:yo, **{}).frozen?) + assert_equal_not_same(kw, o.send(:yo, **kw)) + assert_equal_not_same(h, o.send(:yo, **h)) + assert_equal(false, o.public_send(:yo, **{}).frozen?) + assert_equal_not_same(kw, o.public_send(:yo, **kw)) + assert_equal_not_same(h, o.public_send(:yo, **h)) assert_equal(false, m.(**{}).frozen?) assert_equal_not_same(kw, m.(**kw)) assert_equal_not_same(h, m.(**h)) @@ -343,17 +436,17 @@ class TestKeywordArguments < Test::Unit::TestCase assert_equal_not_same(kw, m.send(:call, **kw)) assert_equal_not_same(h, m.send(:call, **h)) - o.singleton_class.send(:remove_method, :y) - def o.y(**kw) super(**kw) end - assert_equal(false, o.y(**{}).frozen?) - assert_equal_not_same(kw, o.y(**kw)) - assert_equal_not_same(h, o.y(**h)) - assert_equal(false, o.send(:y, **{}).frozen?) - assert_equal_not_same(kw, o.send(:y, **kw)) - assert_equal_not_same(h, o.send(:y, **h)) - assert_equal(false, o.public_send(:y, **{}).frozen?) - assert_equal_not_same(kw, o.public_send(:y, **kw)) - assert_equal_not_same(h, o.public_send(:y, **h)) + o.singleton_class.send(:remove_method, :yo) + def o.yo(**kw) super(**kw) end + assert_equal(false, o.yo(**{}).frozen?) + assert_equal_not_same(kw, o.yo(**kw)) + assert_equal_not_same(h, o.yo(**h)) + assert_equal(false, o.send(:yo, **{}).frozen?) + assert_equal_not_same(kw, o.send(:yo, **kw)) + assert_equal_not_same(h, o.send(:yo, **h)) + assert_equal(false, o.public_send(:yo, **{}).frozen?) + assert_equal_not_same(kw, o.public_send(:yo, **kw)) + assert_equal_not_same(h, o.public_send(:yo, **h)) assert_equal(false, m.(**{}).frozen?) assert_equal_not_same(kw, m.(**kw)) assert_equal_not_same(h, m.(**h)) @@ -389,17 +482,41 @@ class TestKeywordArguments < Test::Unit::TestCase assert_equal_not_same(h, m.(**h)) assert_equal_not_same(h, m.send(:call, **h)) - singleton_class.send(:remove_method, :y) + singleton_class.send(:remove_method, :yo) def self.method_missing(_, **kw) kw end - assert_equal(false, y(**{}).frozen?) - assert_equal_not_same(kw, y(**kw)) - assert_equal_not_same(h, y(**h)) - assert_equal(false, send(:y, **{}).frozen?) - assert_equal_not_same(kw, send(:y, **kw)) - assert_equal_not_same(h, send(:y, **h)) - assert_equal(false, public_send(:y, **{}).frozen?) - assert_equal_not_same(kw, public_send(:y, **kw)) - assert_equal_not_same(h, public_send(:y, **h)) + assert_equal(false, yo(**{}).frozen?) + assert_equal_not_same(kw, yo(**kw)) + assert_equal_not_same(h, yo(**h)) + assert_equal(false, send(:yo, **{}).frozen?) + assert_equal_not_same(kw, send(:yo, **kw)) + assert_equal_not_same(h, send(:yo, **h)) + assert_equal(false, public_send(:yo, **{}).frozen?) + assert_equal_not_same(kw, public_send(:yo, **kw)) + assert_equal_not_same(h, public_send(:yo, **h)) + + def self.yo(*a, **kw) = kw + assert_equal_not_same kw, yo(**kw) + assert_equal_not_same kw, yo(**kw, **kw) + + singleton_class.send(:remove_method, :yo) + def self.yo(opts) = opts + assert_equal_not_same h, yo(*[], **h) + a = [] + assert_equal_not_same h, yo(*a, **h) + end + + def test_keyword_splat_to_non_keyword_method + h = {a: 1}.freeze + + def self.yo(kw) kw end + assert_equal_not_same(h, yo(**h)) + assert_equal_not_same(h, method(:yo).(**h)) + assert_equal_not_same(h, :yo.to_proc.(self, **h)) + + def self.yoa(*kw) kw[0] end + assert_equal_not_same(h, yoa(**h)) + assert_equal_not_same(h, method(:yoa).(**h)) + assert_equal_not_same(h, :yoa.to_proc.(self, **h)) end def test_regular_kwsplat @@ -2700,6 +2817,51 @@ class TestKeywordArguments < Test::Unit::TestCase assert_raise(FrozenError) { c.send(:ruby2_keywords, :baz) } end + def test_anon_splat_ruby2_keywords + singleton_class.class_exec do + def bar(*a, **kw) + [a, kw] + end + + ruby2_keywords def bar_anon(*) + bar(*) + end + end + + a = [1, 2] + kw = {a: 1} + assert_equal([[1, 2], {a: 1}], bar_anon(*a, **kw)) + assert_equal([1, 2], a) + assert_equal({a: 1}, kw) + end + + def test_anon_splat_ruby2_keywords_bug_20388 + extend(Module.new{def process(action, ...) 1 end}) + extend(Module.new do + def process(action, *args) + args.freeze + super + end + ruby2_keywords :process + end) + + assert_equal(1, process(:foo, bar: :baz)) + end + + def test_ruby2_keywords_bug_20679 + c = Class.new do + def self.get(_, _, h, &block) + h[1] + end + + ruby2_keywords def get(*args, &block) + self.class.get(*args, &block) + end + end + + assert_equal 2, c.new.get(true, {}, 1 => 2) + end + def test_top_ruby2_keywords assert_in_out_err([], <<-INPUT, ["[1, 2, 3]", "{:k=>1}"], []) def bar(*a, **kw) @@ -3538,7 +3700,7 @@ class TestKeywordArguments < Test::Unit::TestCase assert_equal(splat_expect, pr.call(a), bug8463) pr = proc {|a, **opt| next a, opt} - assert_equal(splat_expect.values_at(0, -1), pr.call(splat_expect), bug8463) + assert_equal([splat_expect, {}], pr.call(splat_expect), bug8463) end def req_plus_keyword(x, **h) @@ -3875,6 +4037,20 @@ class TestKeywordArguments < Test::Unit::TestCase }, bug8964 end + def test_large_kwsplat_to_method_taking_kw_and_kwsplat + assert_separately(['-'], "#{<<~"begin;"}\n#{<<~'end;'}") + begin; + n = 100000 + x = Fiber.new do + h = {kw: 2} + n.times{|i| h[i.to_s.to_sym] = i} + def self.f(kw: 1, **kws) kws.size end + f(**h) + end.resume + assert_equal(n, x) + end; + end + def test_dynamic_symbol_keyword bug10266 = '[ruby-dev:48564] [Bug #10266]' assert_separately(['-', bug10266], "#{<<~"begin;"}\n#{<<~'end;'}") @@ -4351,4 +4527,39 @@ class TestKeywordArgumentsSymProcRefinements < Test::Unit::TestCase assert_raise(TypeError, bug16603) { p(**42) } assert_raise(TypeError, bug16603) { p(k:1, **42) } end + + def test_value_omission + f = ->(**kwargs) { kwargs } + x = 1 + y = 2 + assert_equal({x: 1, y: 2}, f.call(x:, y:)) + assert_equal({x: 1, y: 2, z: 3}, f.call(x:, y:, z: 3)) + assert_equal({one: 1, two: 2}, f.call(one:, two:)) + end + + def m_bug20570(*a, **nil) + a + end + + def test_splat_arg_with_prohibited_keyword + assert_equal([], m_bug20570(*[])) + assert_equal([1], m_bug20570(*[1])) + assert_equal([1, 2], m_bug20570(*[1, 2])) + h = nil + assert_equal([], m_bug20570(*[], **h)) + assert_equal([1], m_bug20570(*[1], **h)) + assert_equal([1, 2], m_bug20570(*[1, 2], **h)) + + assert_equal([], m_bug20570(*[], **nil)) + assert_equal([1], m_bug20570(*[1], **nil)) + assert_equal([1, 2], m_bug20570(*[1, 2], **nil)) + end + + private def one + 1 + end + + private def two + 2 + end end |