1
0
Fork 0
mirror of https://github.com/ruby/ruby.git synced 2022-11-09 12:17:21 -05:00
ruby--ruby/spec/ruby/language/case_spec.rb
2020-10-24 15:53:53 +02:00

436 lines
8.6 KiB
Ruby

require_relative '../spec_helper'
describe "The 'case'-construct" do
it "evaluates the body of the when clause matching the case target expression" do
case 1
when 2; false
when 1; true
end.should == true
end
it "evaluates the body of the when clause whose array expression includes the case target expression" do
case 2
when 3, 4; false
when 1, 2; true
end.should == true
end
it "evaluates the body of the when clause in left-to-right order if it's an array expression" do
@calls = []
def foo; @calls << :foo; end
def bar; @calls << :bar; end
case true
when foo, bar;
end
@calls.should == [:foo, :bar]
end
it "evaluates the body of the when clause whose range expression includes the case target expression" do
case 5
when 21..30; false
when 1..20; true
end.should == true
end
it "returns nil when no 'then'-bodies are given" do
case "a"
when "a"
when "b"
end.should == nil
end
it "evaluates the 'else'-body when no other expression matches" do
case "c"
when "a"; 'foo'
when "b"; 'bar'
else 'zzz'
end.should == 'zzz'
end
it "returns nil when no expression matches and 'else'-body is empty" do
case "c"
when "a"; "a"
when "b"; "b"
else
end.should == nil
end
it "returns 2 when a then body is empty" do
case Object.new
when Numeric then
1
when String then
# ok
else
2
end.should == 2
end
it "returns the statement following 'then'" do
case "a"
when "a" then 'foo'
when "b" then 'bar'
end.should == 'foo'
end
it "tests classes with case equality" do
case "a"
when String
'foo'
when Symbol
'bar'
end.should == 'foo'
end
it "tests with matching regexps" do
case "hello"
when /abc/; false
when /^hell/; true
end.should == true
end
it "tests with matching regexps and sets $~ and captures" do
case "foo42"
when /oo(\d+)/
$~.should be_kind_of(MatchData)
$1.should == "42"
else
flunk
end
$~.should be_kind_of(MatchData)
$1.should == "42"
end
it "tests with a regexp interpolated within another regexp" do
digits = '\d+'
case "foo44"
when /oo(#{digits})/
$~.should be_kind_of(MatchData)
$1.should == "44"
else
flunk
end
$~.should be_kind_of(MatchData)
$1.should == "44"
end
it "tests with a string interpolated in a regexp" do
digits_regexp = /\d+/
case "foo43"
when /oo(#{digits_regexp})/
$~.should be_kind_of(MatchData)
$1.should == "43"
else
flunk
end
$~.should be_kind_of(MatchData)
$1.should == "43"
end
it "does not test with equality when given classes" do
case :symbol.class
when Symbol
"bar"
when String
"bar"
else
"foo"
end.should == "foo"
end
it "takes lists of values" do
case 'z'
when 'a', 'b', 'c', 'd'
"foo"
when 'x', 'y', 'z'
"bar"
end.should == "bar"
case 'b'
when 'a', 'b', 'c', 'd'
"foo"
when 'x', 'y', 'z'
"bar"
end.should == "foo"
end
it "expands arrays to lists of values" do
case 'z'
when *['a', 'b', 'c', 'd']
"foo"
when *['x', 'y', 'z']
"bar"
end.should == "bar"
end
it "takes an expanded array in addition to a list of values" do
case 'f'
when 'f', *['a', 'b', 'c', 'd']
"foo"
when *['x', 'y', 'z']
"bar"
end.should == "foo"
case 'b'
when 'f', *['a', 'b', 'c', 'd']
"foo"
when *['x', 'y', 'z']
"bar"
end.should == "foo"
end
it "takes an expanded array before additional listed values" do
case 'f'
when *['a', 'b', 'c', 'd'], 'f'
"foo"
when *['x', 'y', 'z']
"bar"
end.should == 'foo'
end
it "expands arrays from variables before additional listed values" do
a = ['a', 'b', 'c']
case 'a'
when *a, 'd', 'e'
"foo"
when 'x'
"bar"
end.should == "foo"
end
it "expands arrays from variables before a single additional listed value" do
a = ['a', 'b', 'c']
case 'a'
when *a, 'd'
"foo"
when 'x'
"bar"
end.should == "foo"
end
it "expands multiple arrays from variables before additional listed values" do
a = ['a', 'b', 'c']
b = ['d', 'e', 'f']
case 'f'
when *a, *b, 'g', 'h'
"foo"
when 'x'
"bar"
end.should == "foo"
end
# MR: critical
it "concats arrays before expanding them" do
a = ['a', 'b', 'c', 'd']
b = ['f']
case 'f'
when 'f', *a|b
"foo"
when *['x', 'y', 'z']
"bar"
end.should == "foo"
end
it "never matches when clauses with no values" do
case nil
when *[]
"foo"
end.should == nil
end
it "lets you define a method after the case statement" do
case (def foo; 'foo'; end; 'f')
when 'a'
'foo'
when 'f'
'bar'
end.should == 'bar'
end
it "raises a SyntaxError when 'else' is used when no 'when' is given" do
-> {
eval <<-CODE
case 4
else
true
end
CODE
}.should raise_error(SyntaxError)
end
it "raises a SyntaxError when 'else' is used before a 'when' was given" do
-> {
eval <<-CODE
case 4
else
true
when 4; false
end
CODE
}.should raise_error(SyntaxError)
end
it "supports nested case statements" do
result = false
case :x
when Symbol
case :y
when Symbol
result = true
end
end
result.should == true
end
it "supports nested case statements followed by a when with a splatted array" do
result = false
case :x
when Symbol
case :y
when Symbol
result = true
end
when *[Symbol]
result = false
end
result.should == true
end
it "supports nested case statements followed by a when with a splatted non-array" do
result = false
case :x
when Symbol
case :y
when Symbol
result = true
end
when *Symbol
result = false
end
result.should == true
end
it "works even if there's only one when statement" do
case 1
when 1
100
end.should == 100
end
end
describe "The 'case'-construct with no target expression" do
it "evaluates the body of the first clause when at least one of its condition expressions is true" do
case
when true, false; 'foo'
end.should == 'foo'
end
it "evaluates the body of the first when clause that is not false/nil" do
case
when false; 'foo'
when 2; 'bar'
when 1 == 1; 'baz'
end.should == 'bar'
case
when false; 'foo'
when nil; 'foo'
when 1 == 1; 'bar'
end.should == 'bar'
end
it "evaluates the body of the else clause if all when clauses are false/nil" do
case
when false; 'foo'
when nil; 'foo'
when 1 == 2; 'bar'
else 'baz'
end.should == 'baz'
end
it "evaluates multiple conditional expressions as a boolean disjunction" do
case
when true, false; 'foo'
else 'bar'
end.should == 'foo'
case
when false, true; 'foo'
else 'bar'
end.should == 'foo'
end
it "evaluates true as only 'true' when true is the first clause" do
case 1
when true; "bad"
when Integer; "good"
end.should == "good"
end
it "evaluates false as only 'false' when false is the first clause" do
case nil
when false; "bad"
when nil; "good"
end.should == "good"
end
it "treats a literal array as its own when argument, rather than a list of arguments" do
case 'foo'
when ['foo', 'foo']; 'bad'
when 'foo'; 'good'
end.should == 'good'
end
it "takes multiple expanded arrays" do
a1 = ['f', 'o', 'o']
a2 = ['b', 'a', 'r']
case 'f'
when *a1, *['x', 'y', 'z']
"foo"
when *a2, *['x', 'y', 'z']
"bar"
end.should == "foo"
case 'b'
when *a1, *['x', 'y', 'z']
"foo"
when *a2, *['x', 'y', 'z']
"bar"
end.should == "bar"
end
it "calls === even when private" do
klass = Class.new do
def ===(o)
true
end
private :===
end
case 1
when klass.new
:called
end.should == :called
end
it "accepts complex expressions within ()" do
case 'a'
when (raise if 2+2 == 3; /a/)
:called
end.should == :called
end
# Homogeneous cases are often optimized to avoid === using a jump table, and should be tested separately.
# See https://github.com/jruby/jruby/issues/6440
it "handles homogeneous cases" do
case
when 1; 'foo'
when 2; 'bar'
end.should == 'foo'
end
end