2019-04-17 02:48:03 -04:00
# frozen_string_literal: true
require 'test/unit'
2019-12-20 09:48:15 -05:00
experimental , Warning [ :experimental ] = Warning [ :experimental ] , false # suppress "warning: Pattern matching is experimental, and the behavior may change in future versions of Ruby!"
2019-05-20 21:30:13 -04:00
eval " \n #{ << ~ 'END_of_GUARD' } " , binding , __FILE__ , __LINE__
2019-04-17 02:48:03 -04:00
class TestPatternMatching < Test :: Unit :: TestCase
2021-10-22 21:22:14 -04:00
class NullFormatter
def message_for ( corrections )
" "
end
end
def setup
if defined? ( DidYouMean )
@original_formatter = DidYouMean . formatter
DidYouMean . formatter = NullFormatter . new
end
end
def teardown
if defined? ( DidYouMean )
DidYouMean . formatter = @original_formatter
end
end
2019-04-17 02:48:03 -04:00
class C
class << self
attr_accessor :keys
end
def initialize ( obj )
@obj = obj
end
def deconstruct
@obj
end
def deconstruct_keys ( keys )
C . keys = keys
@obj
end
end
def test_basic
assert_block do
case 0
in 0
true
else
false
end
end
assert_block do
case 0
in 1
false
else
true
end
end
assert_raise ( NoMatchingPatternError ) do
case 0
in 1
false
end
end
begin
o = [ 0 ]
case o
in 1
false
end
rescue = > e
assert_match o . inspect , e . message
end
assert_block do
begin
true
ensure
case 0
in 0
false
end
end
end
assert_block do
begin
true
ensure
case 0
in 1
else
false
end
end
end
assert_raise ( NoMatchingPatternError ) do
begin
ensure
case 0
in 1
end
end
end
assert_block do
2019-12-20 09:48:15 -05:00
# suppress "warning: Pattern matching is experimental, and the behavior may change in future versions of Ruby!"
experimental , Warning [ :experimental ] = Warning [ :experimental ] , false
2019-04-17 02:48:03 -04:00
eval ( %q{
case true
in a
a
end
} )
2019-04-17 04:53:32 -04:00
ensure
2019-12-20 09:48:15 -05:00
Warning [ :experimental ] = experimental
2019-04-17 02:48:03 -04:00
end
assert_block do
tap do | a |
tap do
case true
in a
a
end
end
end
end
assert_raise ( NoMatchingPatternError ) do
o = BasicObject . new
def o . match
case 0
in 1
end
end
o . match
end
end
def test_modifier
assert_block do
case 0
in a if a == 0
true
end
end
assert_block do
case 0
in a if a != 0
else
true
end
end
assert_block do
case 0
in a unless a != 0
true
end
end
assert_block do
case 0
in a unless a == 0
else
true
end
end
end
def test_as_pattern
assert_block do
case 0
in 0 = > a
a == 0
end
end
end
def test_alternative_pattern
assert_block do
[ 0 , 1 ] . all? do | i |
case i
in 0 | 1
true
end
end
end
assert_block do
case 0
in _ | _a
true
end
end
assert_syntax_error ( %q{
case 0
in a | 0
end
} , / illegal variable in alternative pattern / )
end
def test_var_pattern
2019-04-20 23:56:42 -04:00
# NODE_DASGN_CURR
2019-04-17 02:48:03 -04:00
assert_block do
2019-11-07 00:00:59 -05:00
case 0
in a
a == 0
2019-04-17 02:48:03 -04:00
end
end
2019-04-20 23:11:38 -04:00
2019-04-20 23:56:42 -04:00
# NODE_DASGN
b = 0
assert_block do
2019-11-07 00:00:59 -05:00
case 1
in b
2019-04-20 23:56:42 -04:00
b == 1
end
end
# NODE_LASGN
2019-11-07 00:00:59 -05:00
case 0
in c
assert_equal ( 0 , c )
2019-04-20 23:56:42 -04:00
else
flunk
end
2019-04-20 23:11:38 -04:00
assert_syntax_error ( %q{
case 0
in ^ a
end
} , / no such local variable / )
2019-11-07 00:00:59 -05:00
assert_syntax_error ( %q{
case 0
in a , a
end
} , / duplicated variable name / )
assert_block do
case [ 0 , 1 , 2 , 3 ]
in _ , _ , _a , _a
true
end
end
assert_syntax_error ( %q{
case 0
in a , { a : }
end
} , / duplicated variable name / )
assert_syntax_error ( %q{
case 0
in a , { " a " : }
end
} , / duplicated variable name / )
assert_block do
case [ 0 , " 1 " ]
in a , " #{ case 1 ; in a ; a ; end } "
true
end
end
assert_syntax_error ( %q{
case [ 0 , " 1 " ]
in a , " #{ case 1 ; in a ; a ; end } " , a
end
} , / duplicated variable name / )
assert_block do
case 0
in a
2019-12-20 20:06:14 -05:00
assert_equal ( 0 , a )
2019-11-07 00:00:59 -05:00
true
in a
flunk
end
end
assert_syntax_error ( %q{
2020-10-26 05:00:24 -04:00
0 = > [ a , a ]
2019-11-07 00:00:59 -05:00
} , / duplicated variable name / )
2019-04-17 02:48:03 -04:00
end
def test_literal_value_pattern
assert_block do
case [ nil , self , true , false ]
in [ nil , self , true , false ]
true
end
end
assert_block do
case [ 0 d170 , 0 D170 , 0xaa , 0xAa , 0xAA , 0 Xaa , 0 XAa , 0 XaA , 0252 , 0 o252 , 0 O252 ]
in [ 0 d170 , 0 D170 , 0xaa , 0xAa , 0xAA , 0 Xaa , 0 XAa , 0 XaA , 0252 , 0 o252 , 0 O252 ]
true
end
case [ 0b10101010 , 0 B10101010 , 12 r , 12 . 3 r , 1 i , 12 . 3 ri ]
in [ 0b10101010 , 0 B10101010 , 12 r , 12 . 3 r , 1 i , 12 . 3 ri ]
true
end
end
assert_block do
x = 'x'
case [ 'a' , 'a' , x ]
in [ 'a' , " a " , " #{ x } " ]
true
end
end
assert_block do
case [ " a \n " ]
in [ <<END]
a
END
true
end
end
assert_block do
case [ :a , :" a " ]
in [ :a , :" a " ]
true
end
end
assert_block do
case [ 0 , 1 , 2 , 3 , 4 , 5 ]
in [ 0 .. 1 , 0 ... 2 , 0 .. , 0 ... , ( ... 5 ) , ( .. 5 ) ]
true
end
end
assert_syntax_error ( %q{
case 0
in a .. b
end
} , / unexpected / )
assert_block do
case 'abc'
in / a /
true
end
end
assert_block do
case 0
in - > ( i ) { i == 0 }
true
end
end
assert_block do
case [ %( a ) , %q( a ) , %Q( a ) , %w( a ) , %W( a ) , % i ( a ) , % I ( a ) , %s( a ) , %x( echo a ) , %( ) , %q( ) , %Q( ) , %w( ) , %W( ) , % i ( ) , % I ( ) , %s( ) , 'a' ]
in [ %( a ) , %q( a ) , %Q( a ) , %w( a ) , %W( a ) , % i ( a ) , % I ( a ) , %s( a ) , %x( echo a ) , %( ) , %q( ) , %Q( ) , %w( ) , %W( ) , % i ( ) , % I ( ) , %s( ) , %r( a ) ]
true
end
end
assert_block do
case [ __FILE__ , __LINE__ + 1 , __ENCODING__ ]
in [ __FILE__ , __LINE__ , __ENCODING__ ]
true
end
end
end
def test_constant_value_pattern
assert_block do
case 0
in Integer
true
end
end
assert_block do
case 0
in Object :: Integer
true
end
end
assert_block do
case 0
in :: Object :: Integer
true
end
end
end
def test_pin_operator_value_pattern
assert_block do
a = / a /
case 'abc'
in ^ a
true
end
end
assert_block do
case [ 0 , 0 ]
in a , ^ a
a == 0
end
end
2021-05-13 18:31:46 -04:00
assert_block do
@a = / a /
case 'abc'
in ^ @a
true
end
end
assert_block do
@@TestPatternMatching = / a /
case 'abc'
in ^ @@TestPatternMatching
true
end
end
assert_block do
$TestPatternMatching = / a /
case 'abc'
in ^ $TestPatternMatching
true
end
end
2019-04-17 02:48:03 -04:00
end
2021-03-21 02:12:54 -04:00
def test_pin_operator_expr_pattern
assert_block do
case 'abc'
in ^ ( / a / )
true
end
end
assert_block do
case { name : '2.6' , released_at : Time . new ( 2018 , 12 , 25 ) }
in { released_at : ^ ( Time . new ( 2010 ) .. Time . new ( 2020 ) ) }
true
end
end
assert_block do
case 0
in ^ ( 0 + 0 )
true
end
end
end
2019-04-17 02:48:03 -04:00
def test_array_pattern
assert_block do
[ [ 0 ] , C . new ( [ 0 ] ) ] . all? do | i |
case i
in 0 , ;
true
end
end
end
assert_block do
[ [ 0 , 1 ] , C . new ( [ 0 , 1 ] ) ] . all? do | i |
case i
in 0 , ;
true
end
end
end
assert_block do
[ [ ] , C . new ( [ ] ) ] . all? do | i |
case i
in 0 , ;
else
true
end
end
end
assert_block do
[ [ 0 , 1 ] , C . new ( [ 0 , 1 ] ) ] . all? do | i |
case i
in 0 , 1
true
end
end
end
assert_block do
[ [ 0 ] , C . new ( [ 0 ] ) ] . all? do | i |
case i
in 0 , 1
else
true
end
end
end
assert_block do
[ [ ] , C . new ( [ ] ) ] . all? do | i |
case i
in * a
a == [ ]
end
end
end
assert_block do
[ [ 0 ] , C . new ( [ 0 ] ) ] . all? do | i |
case i
in * a
a == [ 0 ]
end
end
end
assert_block do
[ [ 0 ] , C . new ( [ 0 ] ) ] . all? do | i |
case i
in * a , 0 , 1
2019-12-20 20:06:14 -05:00
raise a # suppress "unused variable: a" warning
2019-04-17 02:48:03 -04:00
else
true
end
end
end
assert_block do
[ [ 0 , 1 ] , C . new ( [ 0 , 1 ] ) ] . all? do | i |
case i
in * a , 0 , 1
a == [ ]
end
end
end
assert_block do
[ [ 0 , 1 , 2 ] , C . new ( [ 0 , 1 , 2 ] ) ] . all? do | i |
case i
in * a , 1 , 2
a == [ 0 ]
end
end
end
assert_block do
[ [ ] , C . new ( [ ] ) ] . all? do | i |
case i
in * ;
true
end
end
end
assert_block do
[ [ 0 ] , C . new ( [ 0 ] ) ] . all? do | i |
case i
in * , 0 , 1
else
true
end
end
end
assert_block do
[ [ 0 , 1 ] , C . new ( [ 0 , 1 ] ) ] . all? do | i |
case i
in * , 0 , 1
true
end
end
end
assert_block do
[ [ 0 , 1 , 2 ] , C . new ( [ 0 , 1 , 2 ] ) ] . all? do | i |
case i
in * , 1 , 2
true
end
end
end
assert_block do
case C . new ( [ 0 ] )
in C ( 0 )
true
end
end
assert_block do
case C . new ( [ 0 ] )
in Array ( 0 )
else
true
end
end
assert_block do
case C . new ( [ ] )
in C ( )
true
end
end
assert_block do
case C . new ( [ ] )
in Array ( )
else
true
end
end
assert_block do
case C . new ( [ 0 ] )
in C [ 0 ]
true
end
end
assert_block do
case C . new ( [ 0 ] )
in Array [ 0 ]
else
true
end
end
assert_block do
case C . new ( [ ] )
in C [ ]
true
end
end
assert_block do
case C . new ( [ ] )
in Array [ ]
else
true
end
end
assert_block do
case [ ]
in [ ]
true
end
end
assert_block do
case C . new ( [ ] )
in [ ]
true
end
end
assert_block do
case [ 0 ]
in [ 0 ]
true
end
end
assert_block do
case C . new ( [ 0 ] )
in [ 0 ]
true
end
end
2019-04-20 22:43:31 -04:00
assert_block do
case [ 0 ]
in [ 0 , ]
true
end
end
assert_block do
case [ 0 , 1 ]
in [ 0 , ]
true
end
end
2019-04-17 02:48:03 -04:00
assert_block do
case [ ]
in [ 0 , * a ]
2019-12-20 20:06:14 -05:00
raise a # suppress "unused variable: a" warning
2019-04-17 02:48:03 -04:00
else
true
end
end
assert_block do
case [ 0 ]
in [ 0 , * a ]
a == [ ]
end
end
assert_block do
case [ 0 ]
in [ 0 , * a , 1 ]
2019-12-20 20:06:14 -05:00
raise a # suppress "unused variable: a" warning
2019-04-17 02:48:03 -04:00
else
true
end
end
assert_block do
case [ 0 , 1 ]
in [ 0 , * a , 1 ]
a == [ ]
end
end
assert_block do
case [ 0 , 1 , 2 ]
in [ 0 , * a , 2 ]
a == [ 1 ]
end
end
assert_block do
case [ ]
in [ 0 , * ]
else
true
end
end
assert_block do
case [ 0 ]
in [ 0 , * ]
true
end
end
assert_block do
case [ 0 , 1 ]
in [ 0 , * ]
true
end
end
assert_block do
case [ ]
in [ 0 , * a ]
2019-12-20 20:06:14 -05:00
raise a # suppress "unused variable: a" warning
2019-04-17 02:48:03 -04:00
else
true
end
end
assert_block do
case [ 0 ]
in [ 0 , * a ]
a == [ ]
end
end
assert_block do
case [ 0 , 1 ]
in [ 0 , * a ]
a == [ 1 ]
end
end
2019-04-20 22:43:31 -04:00
assert_block do
case [ 0 ]
in [ 0 , * , 1 ]
else
true
end
end
assert_block do
case [ 0 , 1 ]
in [ 0 , * , 1 ]
true
end
end
2019-04-17 02:48:03 -04:00
end
2020-06-13 20:24:36 -04:00
def test_find_pattern
2020-10-26 05:00:24 -04:00
[ 0 , 1 , 2 ] = > [ * , 1 = > a , * ]
2020-06-13 20:24:36 -04:00
assert_equal ( 1 , a )
2020-10-26 05:00:24 -04:00
[ 0 , 1 , 2 ] = > [ * a , 1 = > b , * c ]
2020-06-13 20:24:36 -04:00
assert_equal ( [ 0 ] , a )
assert_equal ( 1 , b )
assert_equal ( [ 2 ] , c )
assert_block do
case [ 0 , 1 , 2 ]
in [ * , 9 , * ]
false
else
true
end
end
assert_block do
case [ 0 , 1 , 2 ]
in [ * , Integer , String , * ]
false
else
true
end
end
2020-10-26 05:00:24 -04:00
[ 0 , 1 , 2 ] = > [ * a , 1 = > b , 2 = > c , * d ]
2020-06-13 20:24:36 -04:00
assert_equal ( [ 0 ] , a )
assert_equal ( 1 , b )
assert_equal ( 2 , c )
assert_equal ( [ ] , d )
case [ 0 , 1 , 2 ]
in * , 1 = > a , * ;
assert_equal ( 1 , a )
end
assert_block do
case [ 0 , 1 , 2 ]
in String ( * , 1 , * )
false
in Array ( * , 1 , * )
true
end
end
assert_block do
case [ 0 , 1 , 2 ]
in String [ * , 1 , * ]
false
in Array [ * , 1 , * ]
true
end
end
2021-01-18 16:00:52 -05:00
# https://bugs.ruby-lang.org/issues/17534
assert_block do
case [ 0 , 1 , 2 ]
in x
2021-01-18 23:34:07 -05:00
x = x # avoid a warning "assigned but unused variable - x"
2021-01-18 16:00:52 -05:00
true
in [ * , 2 , * ]
false
end
end
2020-06-13 20:24:36 -04:00
end
2019-04-17 02:48:03 -04:00
def test_hash_pattern
assert_block do
[ { } , C . new ( { } ) ] . all? do | i |
case i
in a : 0
else
true
end
end
end
assert_block do
[ { a : 0 } , C . new ( { a : 0 } ) ] . all? do | i |
case i
in a : 0
true
end
end
end
assert_block do
[ { a : 0 , b : 1 } , C . new ( { a : 0 , b : 1 } ) ] . all? do | i |
case i
in a : 0
true
end
end
end
assert_block do
[ { a : 0 } , C . new ( { a : 0 } ) ] . all? do | i |
case i
in a : 0 , b : 1
else
true
end
end
end
assert_block do
[ { a : 0 , b : 1 } , C . new ( { a : 0 , b : 1 } ) ] . all? do | i |
case i
in a : 0 , b : 1
true
end
end
end
assert_block do
[ { a : 0 , b : 1 , c : 2 } , C . new ( { a : 0 , b : 1 , c : 2 } ) ] . all? do | i |
case i
in a : 0 , b : 1
true
end
end
end
assert_block do
[ { } , C . new ( { } ) ] . all? do | i |
case i
in a :
2019-12-20 20:06:14 -05:00
raise a # suppress "unused variable: a" warning
2019-04-17 02:48:03 -04:00
else
true
end
end
end
assert_block do
[ { a : 0 } , C . new ( { a : 0 } ) ] . all? do | i |
case i
in a :
a == 0
end
end
end
assert_block do
[ { a : 0 , b : 1 } , C . new ( { a : 0 , b : 1 } ) ] . all? do | i |
case i
in a :
a == 0
end
end
end
assert_block do
[ { a : 0 } , C . new ( { a : 0 } ) ] . all? do | i |
case i
in " a " : 0
true
end
end
end
assert_block do
[ { a : 0 } , C . new ( { a : 0 } ) ] . all? do | i |
case i
in " a " : ;
a == 0
end
end
end
assert_block do
[ { } , C . new ( { } ) ] . all? do | i |
case i
in ** a
a == { }
end
end
end
assert_block do
[ { a : 0 } , C . new ( { a : 0 } ) ] . all? do | i |
case i
in ** a
a == { a : 0 }
end
end
end
assert_block do
[ { } , C . new ( { } ) ] . all? do | i |
case i
in ** ;
true
end
end
end
assert_block do
[ { a : 0 } , C . new ( { a : 0 } ) ] . all? do | i |
case i
in ** ;
true
end
end
end
assert_block do
[ { } , C . new ( { } ) ] . all? do | i |
case i
in a : , ** b
2019-12-20 20:06:14 -05:00
raise a # suppress "unused variable: a" warning
raise b # suppress "unused variable: b" warning
2019-04-17 02:48:03 -04:00
else
true
end
end
end
assert_block do
[ { a : 0 } , C . new ( { a : 0 } ) ] . all? do | i |
case i
in a : , ** b
a == 0 && b == { }
end
end
end
assert_block do
[ { a : 0 , b : 1 } , C . new ( { a : 0 , b : 1 } ) ] . all? do | i |
case i
in a : , ** b
a == 0 && b == { b : 1 }
end
end
end
2019-09-01 03:39:34 -04:00
assert_block do
[ { } , C . new ( { } ) ] . all? do | i |
case i
in ** nil
true
end
end
end
assert_block do
[ { a : 0 } , C . new ( { a : 0 } ) ] . all? do | i |
case i
in ** nil
else
true
end
end
end
assert_block do
[ { a : 0 } , C . new ( { a : 0 } ) ] . all? do | i |
case i
in a : , ** nil
2019-12-20 20:06:14 -05:00
assert_equal ( 0 , a )
2019-09-01 03:39:34 -04:00
true
end
end
end
assert_block do
[ { a : 0 , b : 1 } , C . new ( { a : 0 , b : 1 } ) ] . all? do | i |
case i
in a : , ** nil
2019-12-20 20:06:14 -05:00
assert_equal ( 0 , a )
2019-09-01 03:39:34 -04:00
else
true
end
end
end
2019-04-17 02:48:03 -04:00
assert_block do
case C . new ( { a : 0 } )
in C ( a : 0 )
true
end
end
assert_block do
case { a : 0 }
in C ( a : 0 )
else
true
end
end
assert_block do
case C . new ( { a : 0 } )
in C [ a : 0 ]
true
end
end
assert_block do
case { a : 0 }
in C [ a : 0 ]
else
true
end
end
assert_block do
[ { } , C . new ( { } ) ] . all? do | i |
case i
in { a : 0 }
else
true
end
end
end
assert_block do
[ { a : 0 } , C . new ( { a : 0 } ) ] . all? do | i |
case i
in { a : 0 }
true
end
end
end
assert_block do
[ { a : 0 , b : 1 } , C . new ( { a : 0 , b : 1 } ) ] . all? do | i |
case i
in { a : 0 }
true
end
end
end
assert_block do
[ { } , C . new ( { } ) ] . all? do | i |
case i
in { }
true
end
end
end
assert_block do
[ { a : 0 } , C . new ( { a : 0 } ) ] . all? do | i |
case i
in { }
else
true
end
end
end
assert_syntax_error ( %q{
case _
in a : , a :
end
} , / duplicated key name / )
assert_syntax_error ( %q{
case _
in a? :
end
} , / key must be valid as local variables / )
assert_block do
case { a? : true }
in a? : true
true
end
end
2020-03-01 00:23:51 -05:00
assert_block do
case { a : 0 , b : 1 }
in { a : 1 , }
false
in { a : , }
2020-03-02 08:37:04 -05:00
_a = a
2020-03-01 00:23:51 -05:00
true
end
end
2020-03-02 01:49:03 -05:00
assert_block do
case { a : 0 }
in { a : 1
}
false
in { a :
2 }
false
2020-03-03 01:48:53 -05:00
in a : { b : } , c :
2020-03-03 06:54:31 -05:00
_b = b
2020-03-03 01:48:53 -05:00
p c
2020-03-02 01:49:03 -05:00
in { a :
}
2020-03-02 08:37:04 -05:00
_a = a
2020-03-02 01:49:03 -05:00
true
end
end
2019-04-17 02:48:03 -04:00
assert_syntax_error ( %q{
case _
in " a-b " :
end
} , / key must be valid as local variables / )
assert_block do
case { " a-b " : true }
in " a-b " : true
true
end
end
assert_syntax_error ( %q{
case _
in " #{ a } " : a
end
} , / symbol literal with interpolation is not allowed / )
assert_syntax_error ( %q{
case _
in " #{ a } " :
end
} , / symbol literal with interpolation is not allowed / )
end
def test_paren
assert_block do
case 0
in ( 0 )
true
end
end
end
2020-12-22 12:31:02 -05:00
def test_nomatchingpatternerror
assert_equal ( StandardError , NoMatchingPatternError . superclass )
end
2019-04-17 02:48:03 -04:00
def test_invalid_syntax
assert_syntax_error ( %q{
case 0
in a , b :
end
} , / unexpected / )
assert_syntax_error ( %q{
case 0
in [ a : ]
end
} , / unexpected / )
assert_syntax_error ( %q{
case 0
in { a }
end
} , / unexpected / )
assert_syntax_error ( %q{
case 0
in { 0 = > a }
end
} , / unexpected / )
end
################################################################
class CTypeError
def deconstruct
nil
end
def deconstruct_keys ( keys )
nil
end
end
def test_deconstruct
assert_raise ( TypeError ) do
case CTypeError . new
in [ ]
end
end
end
def test_deconstruct_keys
assert_raise ( TypeError ) do
case CTypeError . new
in { }
end
end
assert_block do
case { }
in { }
2019-06-29 20:40:23 -04:00
C . keys == nil
2019-04-17 02:48:03 -04:00
end
end
assert_block do
case C . new ( { a : 0 , b : 0 , c : 0 } )
in { a : 0 , b : }
2019-12-20 20:06:14 -05:00
assert_equal ( 0 , b )
2019-04-17 02:48:03 -04:00
C . keys == [ :a , :b ]
end
end
assert_block do
case C . new ( { a : 0 , b : 0 , c : 0 } )
in { a : 0 , b : , ** }
2019-12-20 20:06:14 -05:00
assert_equal ( 0 , b )
2019-04-17 02:48:03 -04:00
C . keys == [ :a , :b ]
end
end
assert_block do
case C . new ( { a : 0 , b : 0 , c : 0 } )
in { a : 0 , b : , ** r }
2019-12-20 20:06:14 -05:00
assert_equal ( 0 , b )
assert_equal ( { c : 0 } , r )
2019-04-17 02:48:03 -04:00
C . keys == nil
end
end
assert_block do
case C . new ( { a : 0 , b : 0 , c : 0 } )
in { ** }
C . keys == [ ]
end
end
assert_block do
case C . new ( { a : 0 , b : 0 , c : 0 } )
in { ** r }
2019-12-20 20:06:14 -05:00
assert_equal ( { a : 0 , b : 0 , c : 0 } , r )
2019-04-17 02:48:03 -04:00
C . keys == nil
end
end
end
################################################################
2020-03-03 18:42:48 -05:00
class CDeconstructCache
def initialize ( v )
@v = v
end
def deconstruct
@v . shift
end
end
def test_deconstruct_cache
assert_block do
case CDeconstructCache . new ( [ [ 0 ] ] )
in [ 1 ]
in [ 0 ]
true
end
end
assert_block do
case CDeconstructCache . new ( [ [ 0 , 1 ] ] )
in [ 1 , ]
in [ 0 , ]
true
end
end
assert_block do
case CDeconstructCache . new ( [ [ [ 0 ] ] ] )
in [ [ 1 ] ]
in [ [ * a ] ]
2020-06-27 00:52:23 -04:00
a == [ 0 ]
2020-03-03 18:42:48 -05:00
end
end
assert_block do
case CDeconstructCache . new ( [ [ 0 ] ] )
in [ x ] if x > 0
in [ 0 ]
true
end
end
assert_block do
case CDeconstructCache . new ( [ [ 0 ] ] )
in [ ]
in [ 1 ] | [ 0 ]
true
end
end
assert_block do
case CDeconstructCache . new ( [ [ 0 ] ] )
2020-06-27 00:52:23 -04:00
in [ 1 ] = > _
in [ 0 ] = > _
2020-03-03 18:42:48 -05:00
true
end
end
assert_block do
case CDeconstructCache . new ( [ [ 0 ] ] )
in C [ 0 ]
in CDeconstructCache [ 0 ]
true
end
end
assert_block do
case [ CDeconstructCache . new ( [ [ 0 ] , [ 1 ] ] ) ]
in [ [ 1 ] ]
false
in [ [ 1 ] ]
true
end
end
2020-06-14 15:00:51 -04:00
assert_block do
case CDeconstructCache . new ( [ [ 0 , :a , 1 ] ] )
in [ * , String = > x , * ]
false
in [ * , Symbol = > x , * ]
2020-06-27 00:52:23 -04:00
x == :a
2020-06-14 15:00:51 -04:00
end
end
2020-03-03 18:42:48 -05:00
end
################################################################
2019-04-17 02:48:03 -04:00
class TestPatternMatchingRefinements < Test :: Unit :: TestCase
class C1
def deconstruct
[ :C1 ]
end
end
class C2
end
module M
refine Array do
def deconstruct
[ 0 ]
end
end
refine Hash do
def deconstruct_keys ( _ )
{ a : 0 }
end
end
refine C2 . singleton_class do
def === ( obj )
obj . kind_of? ( C1 )
end
end
end
using M
def test_refinements
assert_block do
case [ ]
in [ 0 ]
true
end
end
assert_block do
case { }
in { a : 0 }
true
end
end
assert_block do
case C1 . new
in C2 ( :C1 )
true
end
end
end
end
2019-04-17 02:48:05 -04:00
################################################################
def test_struct
assert_block do
s = Struct . new ( :a , :b )
case s [ 0 , 1 ]
in 0 , 1
true
end
end
2019-11-07 21:37:07 -05:00
s = Struct . new ( :a , :b , keyword_init : true )
assert_block do
case s [ a : 0 , b : 1 ]
in ** r
r == { a : 0 , b : 1 }
end
end
assert_block do
s = Struct . new ( :a , :b , keyword_init : true )
case s [ a : 0 , b : 1 ]
in a : , b :
a == 0 && b == 1
end
end
assert_block do
s = Struct . new ( :a , :b , keyword_init : true )
case s [ a : 0 , b : 1 ]
in a : , c :
2019-12-20 20:06:14 -05:00
raise a # suppress "unused variable: a" warning
raise c # suppress "unused variable: c" warning
2019-11-07 21:37:07 -05:00
flunk
2019-11-19 09:53:01 -05:00
in a : , b : , c :
flunk
2019-11-07 21:37:07 -05:00
in b :
b == 1
end
end
2019-04-17 02:48:05 -04:00
end
2019-05-20 21:29:34 -04:00
################################################################
2020-12-12 21:50:14 -05:00
def test_one_line
2020-10-26 05:00:24 -04:00
1 = > a
2019-05-20 21:29:34 -04:00
assert_equal 1 , a
2019-11-27 23:44:25 -05:00
assert_raise ( NoMatchingPatternError ) do
2020-10-26 05:00:24 -04:00
{ a : 1 } = > { a : 0 }
2019-11-27 23:44:25 -05:00
end
2021-08-19 04:03:17 -04:00
[ 1 , 2 ] = > a , b
assert_equal 1 , a
assert_equal 2 , b
{ a : 1 } = > a :
assert_equal 1 , a
2020-12-12 21:50:14 -05:00
assert_equal true , ( 1 in 1 )
assert_equal false , ( 1 in 2 )
2019-05-20 21:29:34 -04:00
end
2019-12-20 09:48:15 -05:00
def assert_experimental_warning ( code )
w = Warning [ :experimental ]
Warning [ :experimental ] = false
assert_warn ( '' ) { eval ( code ) }
Warning [ :experimental ] = true
2020-11-01 00:28:24 -04:00
assert_warn ( / is experimental / ) { eval ( code ) }
2019-12-20 09:48:15 -05:00
ensure
Warning [ :experimental ] = w
end
def test_experimental_warning
2020-11-01 00:28:24 -04:00
assert_experimental_warning ( " case [0]; in [*, 0, *]; end " )
2019-12-20 09:48:15 -05:00
end
2021-08-14 20:38:24 -04:00
################################################################
def test_single_pattern_error_value_pattern
assert_raise_with_message ( NoMatchingPatternError , " 0: 1 === 0 does not return true " ) do
0 = > 1
end
end
def test_single_pattern_error_array_pattern
assert_raise_with_message ( NoMatchingPatternError , " []: Hash === [] does not return true " ) do
[ ] = > Hash [ ]
end
assert_raise_with_message ( NoMatchingPatternError , " 0: 0 does not respond to # deconstruct " ) do
0 = > [ ]
end
assert_raise_with_message ( NoMatchingPatternError , " [0]: [0] length mismatch (given 1, expected 0) " ) do
[ 0 ] = > [ ]
end
assert_raise_with_message ( NoMatchingPatternError , " []: [] length mismatch (given 0, expected 1+) " ) do
[ ] = > [ _ , * ]
end
assert_raise_with_message ( NoMatchingPatternError , " [0, 0]: 1 === 0 does not return true " ) do
[ 0 , 0 ] = > [ 0 , 1 ]
end
assert_raise_with_message ( NoMatchingPatternError , " [0, 0]: 1 === 0 does not return true " ) do
[ 0 , 0 ] = > [ * , 0 , 1 ]
end
end
def test_single_pattern_error_find_pattern
assert_raise_with_message ( NoMatchingPatternError , " []: Hash === [] does not return true " ) do
[ ] = > Hash [ * , _ , * ]
end
assert_raise_with_message ( NoMatchingPatternError , " 0: 0 does not respond to # deconstruct " ) do
0 = > [ * , _ , * ]
end
assert_raise_with_message ( NoMatchingPatternError , " []: [] length mismatch (given 0, expected 1+) " ) do
[ ] = > [ * , _ , * ]
end
assert_raise_with_message ( NoMatchingPatternError , " [0]: [0] does not match to find pattern " ) do
[ 0 ] = > [ * , 1 , * ]
end
assert_raise_with_message ( NoMatchingPatternError , " [0]: [0] does not match to find pattern " ) do
[ 0 ] = > [ * , { a : } , * ]
raise a # suppress "unused variable: a" warning
end
end
def test_single_pattern_error_hash_pattern
assert_raise_with_message ( NoMatchingPatternError , " {}: Array === {} does not return true " ) do
{ } = > Array [ a : ]
raise a # suppress "unused variable: a" warning
end
assert_raise_with_message ( NoMatchingPatternError , " 0: 0 does not respond to # deconstruct_keys " ) do
0 = > { a : }
raise a # suppress "unused variable: a" warning
end
assert_raise_with_message ( NoMatchingPatternKeyError , " {:a=>0}: key not found: :aa " ) do
{ a : 0 } = > { aa : }
raise aa # suppress "unused variable: aa" warning
rescue NoMatchingPatternKeyError = > e
assert_equal ( { a : 0 } , e . matchee )
assert_equal ( :aa , e . key )
raise e
end
assert_raise_with_message ( NoMatchingPatternKeyError , " {:a=>{:b=>0}}: key not found: :bb " ) do
{ a : { b : 0 } } = > { a : { bb : } }
raise bb # suppress "unused variable: bb" warning
rescue NoMatchingPatternKeyError = > e
assert_equal ( { b : 0 } , e . matchee )
assert_equal ( :bb , e . key )
raise e
end
assert_raise_with_message ( NoMatchingPatternError , " {:a=>0}: 1 === 0 does not return true " ) do
{ a : 0 } = > { a : 1 }
end
assert_raise_with_message ( NoMatchingPatternError , " {:a=>0}: {:a=>0} is not empty " ) do
{ a : 0 } = > { }
end
assert_raise_with_message ( NoMatchingPatternError , " [{:a=>0}]: rest of {:a=>0} is not empty " ) do
[ { a : 0 } ] = > [ { ** nil } ]
end
end
def test_single_pattern_error_as_pattern
assert_raise_with_message ( NoMatchingPatternError , " [0]: 1 === 0 does not return true " ) do
case [ 0 ]
in [ 1 ] = > _
end
end
end
def test_single_pattern_error_alternative_pattern
assert_raise_with_message ( NoMatchingPatternError , " 0: 2 === 0 does not return true " ) do
0 = > 1 | 2
end
end
def test_single_pattern_error_guard_clause
assert_raise_with_message ( NoMatchingPatternError , " 0: guard clause does not return true " ) do
case 0
in _ if false
end
end
assert_raise_with_message ( NoMatchingPatternError , " 0: guard clause does not return true " ) do
case 0
in _ unless true
end
end
end
2019-04-17 02:48:03 -04:00
end
2019-05-20 21:30:13 -04:00
END_of_GUARD
2019-12-20 09:48:15 -05:00
Warning [ :experimental ] = experimental