test/syntax.rb: add pattern matching test cases

add comprehensive tests for pattern matching features:
- basic case/in with literals and variables
- array patterns with rest and nested structures
- hash patterns with shorthand and rest
- guard clauses (if/unless)
- alternative patterns (|)
- pin operator (^)
- as pattern (=>)
- one-line pattern matching (in and =>)
- NoMatchingPatternError handling

Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
Yukihiro "Matz" Matsumoto
2025-12-17 17:03:08 +09:00
parent e76ce24860
commit 42f5215466
+273
View File
@@ -943,3 +943,276 @@ assert('at-least-once loop') do
end while count < 5
assert_equal 12, count # 1, then 2+10=12
end
assert('pattern matching - basic case/in') do
# literal patterns
result = case 1
in 1 then :one
in 2 then :two
end
assert_equal :one, result
# variable binding
case 42
in x
assert_equal 42, x
end
# else clause
result = case 3
in 1 then :one
in 2 then :two
else :other
end
assert_equal :other, result
end
assert('pattern matching - array patterns') do
# simple array pattern
case [1, 2, 3]
in [a, b, c]
assert_equal 1, a
assert_equal 2, b
assert_equal 3, c
end
# array pattern with rest
case [1, 2, 3, 4, 5]
in [first, *rest]
assert_equal 1, first
assert_equal [2, 3, 4, 5], rest
end
# array pattern with rest in middle
case [1, 2, 3, 4, 5]
in [first, *middle, last]
assert_equal 1, first
assert_equal [2, 3, 4], middle
assert_equal 5, last
end
# nested array pattern
case [[1, 2], [3, 4]]
in [[a, b], [c, d]]
assert_equal [1, 2, 3, 4], [a, b, c, d]
end
# array pattern with literal match
result = case [1, 2, 3]
in [1, 2, x]
x
end
assert_equal 3, result
end
assert('pattern matching - hash patterns') do
# simple hash pattern
case {a: 1, b: 2}
in {a: x, b: y}
assert_equal 1, x
assert_equal 2, y
end
# shorthand hash pattern
case {a: 1, b: 2}
in {a:, b:}
assert_equal 1, a
assert_equal 2, b
end
# hash pattern with extra keys (partial match)
case {a: 1, b: 2, c: 3}
in {a: x}
assert_equal 1, x
end
# hash pattern with rest (captures all keys currently)
case {a: 1, b: 2, c: 3}
in {a:, **rest}
assert_equal 1, a
# Note: **rest currently captures all keys including matched ones
assert_equal({a: 1, b: 2, c: 3}, rest)
end
# hash value extraction
h = {user: "Alice"}
case h
in {user: u}
assert_equal "Alice", u
end
end
assert('pattern matching - guard clauses') do
# if guard
result = case 10
in x if x > 5
:big
in x
:small
end
assert_equal :big, result
# unless guard
result = case 3
in x unless x > 5
:small
in x
:big
end
assert_equal :small, result
# guard with pattern
result = case [1, 2, 3]
in [a, b, c] if a + b + c > 5
:sum_big
in [a, b, c]
:sum_small
end
assert_equal :sum_big, result
end
assert('pattern matching - alternative patterns') do
# simple alternatives
result = case 2
in 1 | 2 | 3
:found
else
:not_found
end
assert_equal :found, result
# alternatives in array
result = case [1, 2]
in [1, 2] | [3, 4]
:match
else
:no_match
end
assert_equal :match, result
end
assert('pattern matching - pin operator') do
x = 1
# pin matches exact value
result = case 1
in ^x
:matched
else
:not_matched
end
assert_equal :matched, result
# pin in array pattern
expected = 42
case [42, 100]
in [^expected, y]
assert_equal 100, y
end
# pin prevents rebinding
a = 1
result = case 2
in ^a
:same
else
:different
end
assert_equal :different, result
end
assert('pattern matching - as pattern') do
# bind entire match
case [1, 2, 3]
in [x, *rest] => whole
assert_equal 1, x
assert_equal [2, 3], rest
assert_equal [1, 2, 3], whole
end
# as pattern with hash
case {a: 1, b: 2}
in {a:} => h
assert_equal 1, a
assert_equal({a: 1, b: 2}, h)
end
end
assert('pattern matching - one-line in') do
# basic true/false
assert_true((1 in 1))
assert_false((1 in 2))
# with variable binding
assert_true(([1, 2] in [x, y]))
# in conditional
matched = false
if [1, 2, 3] in [a, *rest]
matched = true
end
assert_true matched
# with hash
assert_true(({a: 1} in {a: 1}))
assert_false(({a: 1} in {a: 2}))
end
assert('pattern matching - one-line =>') do
# simple binding
1 => x
assert_equal 1, x
# array destructuring
[1, 2, 3] => [a, b, c]
assert_equal [1, 2, 3], [a, b, c]
# hash destructuring
{name: "Bob", age: 25} => {name:, age:}
assert_equal "Bob", name
assert_equal 25, age
# with rest
[1, 2, 3, 4] => [first, *middle, last]
assert_equal 1, first
assert_equal [2, 3], middle
assert_equal 4, last
end
assert('pattern matching - NoMatchingPatternError') do
# => raises on mismatch
assert_raise(NoMatchingPatternError) do
1 => 2
end
# can be rescued
begin
[1, 2] => [1, 2, 3]
rescue NoMatchingPatternError => e
assert_true e.message.is_a?(String)
end
# case/in without else returns nil (no match)
result = case 5
in 1 then :one
in 2 then :two
end
assert_nil result
end
assert('pattern matching - complex patterns') do
# array of hashes
records = [{id: 1, value: "a"}, {id: 2, value: "b"}]
case records
in [first, second]
assert_equal({id: 1, value: "a"}, first)
assert_equal({id: 2, value: "b"}, second)
end
# hash with array value
data = {items: [1, 2, 3]}
case data
in {items: [a, *rest]}
assert_equal 1, a
assert_equal [2, 3], rest
end
end