summaryrefslogtreecommitdiffhomepage
path: root/test
diff options
context:
space:
mode:
Diffstat (limited to 'test')
-rw-r--r--test/assert.rb211
-rw-r--r--test/t/array.rb40
-rw-r--r--test/t/class.rb26
-rw-r--r--test/t/enumerable.rb4
-rw-r--r--test/t/float.rb34
-rw-r--r--test/t/hash.rb2
-rw-r--r--test/t/integer.rb20
-rw-r--r--test/t/kernel.rb57
-rw-r--r--test/t/module.rb101
-rw-r--r--test/t/numeric.rb88
-rw-r--r--test/t/range.rb8
-rw-r--r--test/t/string.rb260
-rw-r--r--test/t/syntax.rb21
-rw-r--r--test/t/vformat.rb92
14 files changed, 797 insertions, 167 deletions
diff --git a/test/assert.rb b/test/assert.rb
index c57b04c12..9b04f5b48 100644
--- a/test/assert.rb
+++ b/test/assert.rb
@@ -1,17 +1,53 @@
+$undefined = Object.new
$ok_test = 0
$ko_test = 0
$kill_test = 0
+$warning_test = 0
$skip_test = 0
$asserts = []
$test_start = Time.now if Object.const_defined?(:Time)
+# For bintest on Ruby
unless RUBY_ENGINE == "mruby"
- # For bintest on Ruby
def t_print(*args)
print(*args)
$stdout.flush
nil
end
+
+ def _str_match?(pattern, str)
+ File.fnmatch?(pattern, str, File::FNM_EXTGLOB|File::FNM_DOTMATCH)
+ end
+end
+
+class Array
+ def _assertion_join
+ join("-")
+ end
+end
+
+class String
+ def _assertion_indent(indent)
+ indent = indent.to_s
+ off = 0
+ str = self
+ while nl = index("\n", off)
+ nl += 1
+ nl += 1 while slice(nl) == "\n"
+ break if nl >= size
+ str = indent.dup if off == 0
+ str += slice(off, nl - off) + indent
+ off = nl
+ end
+
+ if off == 0
+ str = indent + self
+ else
+ str += slice(off..-1)
+ end
+
+ str
+ end
end
##
@@ -21,14 +57,14 @@ def assertion_string(err, str, iso=nil, e=nil, bt=nil)
msg += " [#{iso}]" if iso && !iso.empty?
msg += " => #{e}" if e && !e.to_s.empty?
msg += " (#{GEMNAME == 'mruby-test' ? 'core' : "mrbgems: #{GEMNAME}"})"
- if $mrbtest_assert && $mrbtest_assert.size > 0
+ if $mrbtest_assert
$mrbtest_assert.each do |idx, assert_msg, diff|
msg += "\n - Assertion[#{idx}]"
msg += " #{assert_msg}." if assert_msg && !assert_msg.empty?
msg += "\n#{diff}" if diff && !diff.empty?
end
end
- msg += "\nbacktrace:\n\t#{bt.join("\n\t")}" if bt
+ msg += "\nbacktrace:\n #{bt.join("\n ")}" if bt
msg
end
@@ -40,16 +76,42 @@ end
# iso : The ISO reference code of the feature
# which will be tested by this
# assertion
-def assert(str = 'Assertion failed', iso = '')
+def assert(str = 'assert', iso = '')
t_print(str, (iso != '' ? " [#{iso}]" : ''), ' : ') if $mrbtest_verbose
begin
+ $mrbtest_child_noassert ||= [0]
+ $mrbtest_child_noassert << 0
+ parent_asserts = $asserts
+ $asserts = []
+ parent_mrbtest_assert = $mrbtest_assert
$mrbtest_assert = []
- $mrbtest_assert_idx = 0
+
+ if $mrbtest_assert_idx && !$mrbtest_assert_idx.empty?
+ $mrbtest_assert_idx[-1] += 1
+ $mrbtest_assert_idx << 0
+ else
+ $mrbtest_assert_idx = [0]
+ class << $mrbtest_assert_idx
+ alias to_s _assertion_join
+ end
+ end
+
yield
- if($mrbtest_assert.size > 0)
- $asserts.push(assertion_string('Fail: ', str, iso))
- $ko_test += 1
- t_print('F')
+ if $mrbtest_assert.size > 0
+ if $mrbtest_assert.size == $mrbtest_child_noassert[-1]
+ $asserts.push(assertion_string('Skip: ', str, iso))
+ $mrbtest_child_noassert[-2] += 1
+ $skip_test += 1
+ t_print('?')
+ else
+ $asserts.push(assertion_string('Fail: ', str, iso))
+ $ko_test += 1
+ t_print('F')
+ end
+ elsif $mrbtest_assert_idx[-1] == 0
+ $asserts.push(assertion_string('Warn: ', str, iso, 'no assertion'))
+ $warning_test += 1
+ t_print('W')
else
$ok_test += 1
t_print('.')
@@ -57,6 +119,7 @@ def assert(str = 'Assertion failed', iso = '')
rescue MRubyTestSkip => e
$asserts.push(assertion_string('Skip: ', str, iso, e))
$skip_test += 1
+ $mrbtest_child_noassert[-2] += 1
t_print('?')
rescue Exception => e
bt = e.backtrace if $mrbtest_verbose
@@ -64,7 +127,25 @@ def assert(str = 'Assertion failed', iso = '')
$kill_test += 1
t_print('X')
ensure
- $mrbtest_assert = nil
+ if $mrbtest_assert_idx.size > 1
+ $asserts.each do |mesg|
+ idx = $mrbtest_assert_idx[0..-2]._assertion_join
+ mesg = mesg._assertion_indent(" ")
+
+ # Give `mesg` as a `diff` argument to avoid adding extra periods.
+ parent_mrbtest_assert << [idx, nil, mesg]
+ end
+ else
+ parent_asserts.concat $asserts
+ end
+ $asserts = parent_asserts
+
+ $mrbtest_assert = parent_mrbtest_assert
+ $mrbtest_assert_idx.pop
+ $mrbtest_assert_idx = nil if $mrbtest_assert_idx.empty?
+ $mrbtest_child_noassert.pop
+
+ nil
end
t_print("\n") if $mrbtest_verbose
end
@@ -75,11 +156,11 @@ def assertion_diff(exp, act)
end
def assert_true(obj, msg = nil, diff = nil)
- if $mrbtest_assert
- $mrbtest_assert_idx += 1
+ if $mrbtest_assert_idx && $mrbtest_assert_idx.size > 0
+ $mrbtest_assert_idx[-1] += 1
unless obj == true
diff ||= " Expected #{obj.inspect} to be true."
- $mrbtest_assert.push([$mrbtest_assert_idx, msg, diff])
+ $mrbtest_assert.push([$mrbtest_assert_idx.to_s, msg, diff])
end
end
obj
@@ -127,6 +208,13 @@ def assert_nil(obj, msg = nil)
assert_true(ret, msg, diff)
end
+def assert_not_nil(obj, msg = nil)
+ if ret = obj.nil?
+ diff = " Expected #{obj.inspect} to not be nil."
+ end
+ assert_false(ret, msg, diff)
+end
+
def assert_include(*args); _assert_include(true, *args) end
def assert_not_include(*args); _assert_include(false, *args) end
def _assert_include(affirmed, collection, obj, msg = nil)
@@ -136,6 +224,55 @@ def _assert_include(affirmed, collection, obj, msg = nil)
assert_true(ret, msg, diff)
end
+def assert_predicate(*args); _assert_predicate(true, *args) end
+def assert_not_predicate(*args); _assert_predicate(false, *args) end
+def _assert_predicate(affirmed, obj, op, msg = nil)
+ unless ret = obj.__send__(op) == affirmed
+ diff = " Expected #{obj.inspect} to #{'not ' unless affirmed}be #{op}."
+ end
+ assert_true(ret, msg, diff)
+end
+
+def assert_operator(*args); _assert_operator(true, *args) end
+def assert_not_operator(*args); _assert_operator(false, *args) end
+def _assert_operator(affirmed, obj1, op, obj2 = $undefined, msg = nil)
+ return _assert_predicate(affirmed, obj1, op, msg) if $undefined.equal?(obj2)
+ unless ret = obj1.__send__(op, obj2) == affirmed
+ diff = " Expected #{obj1.inspect} to #{'not ' unless affirmed}be #{op} #{obj2.inspect}."
+ end
+ assert_true(ret, msg, diff)
+end
+
+##
+# Fail unless +str+ matches against +pattern+.
+#
+# +pattern+ is interpreted as pattern for File.fnmatch?. It may contain the
+# following metacharacters:
+#
+# <code>*</code> ::
+# Matches any string.
+#
+# <code>?</code> ::
+# Matches any one character.
+#
+# <code>[_SET_]</code>, <code>[^_SET_]</code> (<code>[!_SET_]</code>) ::
+# Matches any one character in _SET_. Behaves like character sets in
+# Regexp, including set negation (<code>[^a-z]</code>).
+#
+# <code>{_A_,_B_}</code> ::
+# Matches pattern _A_ or pattern _B_.
+#
+# <code> \ </code> ::
+# Escapes the next character.
+def assert_match(*args); _assert_match(true, *args) end
+def assert_not_match(*args); _assert_match(false, *args) end
+def _assert_match(affirmed, pattern, str, msg = nil)
+ unless ret = _str_match?(pattern, str) == affirmed
+ diff = " Expected #{pattern.inspect} to #{'not ' unless affirmed}match #{str.inspect}."
+ end
+ assert_true(ret, msg, diff)
+end
+
##
# Fails unless +obj+ is a kind of +cls+.
def assert_kind_of(cls, obj, msg = nil)
@@ -149,11 +286,11 @@ end
# Fails unless +exp+ is equal to +act+ in terms of a Float
def assert_float(exp, act, msg = nil)
e, a = exp.to_f, act.to_f
- if (e.infinite? || a.infinite?) && e != a ||
+ if e.finite? && a.finite? && (n = (e - a).abs) > Mrbtest::FLOAT_TOLERANCE
+ flunk(msg, " Expected |#{exp} - #{act}| (#{n}) to be <= #{Mrbtest::FLOAT_TOLERANCE}.")
+ elsif (e.infinite? || a.infinite?) && e != a ||
e.nan? && !a.nan? || !e.nan? && a.nan?
flunk(msg, " Expected #{act} to be #{exp}.")
- elsif (n = (e - a).abs) > Mrbtest::FLOAT_TOLERANCE
- flunk(msg, " Expected |#{exp} - #{act}| (#{n}) to be <= #{Mrbtest::FLOAT_TOLERANCE}.")
else
pass
end
@@ -164,8 +301,9 @@ def assert_raise(*exc)
exc = exc.empty? ? StandardError : exc.size == 1 ? exc[0] : exc
begin
yield
- rescue *exc
+ rescue *exc => e
pass
+ e
rescue Exception => e
diff = " #{exc} exception expected, not\n" \
" Class: <#{e.class}>\n" \
@@ -190,11 +328,33 @@ def assert_nothing_raised(msg = nil)
end
end
+def assert_raise_with_message(*args, &block)
+ _assert_raise_with_message(:plain, *args, &block)
+end
+def assert_raise_with_message_pattern(*args, &block)
+ _assert_raise_with_message(:pattern, *args, &block)
+end
+def _assert_raise_with_message(type, exc, exp_msg, msg = nil, &block)
+ e = msg ? assert_raise(exc, msg, &block) : assert_raise(exc, &block)
+ e ? ($mrbtest_assert_idx[-1]-=1) : (return e)
+
+ err_msg = e.message
+ unless ret = type == :pattern ? _str_match?(exp_msg, err_msg) : exp_msg == err_msg
+ diff = " Expected Exception(#{exc}) was raised, but the message doesn't match.\n"
+ if type == :pattern
+ diff += " Expected #{exp_msg.inspect} to match #{err_msg.inspect}."
+ else
+ diff += assertion_diff(exp_msg, err_msg)
+ end
+ end
+ assert_true(ret, msg, diff)
+end
+
def pass
assert_true(true)
end
-def flunk(msg = nil, diff = "Epic Fail!")
+def flunk(msg = "Epic Fail!", diff = "")
assert_true(false, msg, diff)
end
@@ -208,17 +368,18 @@ def report
t_print("#{msg}\n")
end
- $total_test = $ok_test + $ko_test + $kill_test + $skip_test
- t_print("Total: #{$total_test}\n")
+ $total_test = $ok_test + $ko_test + $kill_test + $warning_test + $skip_test
+ t_print(" Total: #{$total_test}\n")
- t_print(" OK: #{$ok_test}\n")
- t_print(" KO: #{$ko_test}\n")
- t_print("Crash: #{$kill_test}\n")
- t_print(" Skip: #{$skip_test}\n")
+ t_print(" OK: #{$ok_test}\n")
+ t_print(" KO: #{$ko_test}\n")
+ t_print(" Crash: #{$kill_test}\n")
+ t_print("Warning: #{$warning_test}\n")
+ t_print(" Skip: #{$skip_test}\n")
if Object.const_defined?(:Time)
t_time = Time.now - $test_start
- t_print(" Time: #{t_time.round(2)} seconds\n")
+ t_print(" Time: #{t_time.round(2)} seconds\n")
end
$ko_test == 0 && $kill_test == 0
diff --git a/test/t/array.rb b/test/t/array.rb
index 2b19fe0d4..eec31d751 100644
--- a/test/t/array.rb
+++ b/test/t/array.rb
@@ -298,11 +298,38 @@ assert('Array#size', '15.2.12.5.28') do
end
assert('Array#slice', '15.2.12.5.29') do
- a = "12345".slice(1, 3)
- b = a.slice(0)
-
- assert_equal("2:", "#{b}:")
- assert_equal(2, [1,2,3].[](1))
+ a = [*(1..100)]
+ b = a.dup
+
+ assert_equal(1, a.slice(0))
+ assert_equal(100, a.slice(99))
+ assert_nil(a.slice(100))
+ assert_equal(100, a.slice(-1))
+ assert_equal(99, a.slice(-2))
+ assert_equal(1, a.slice(-100))
+ assert_nil(a.slice(-101))
+ assert_equal([1], a.slice(0,1))
+ assert_equal([100], a.slice(99,1))
+ assert_equal([], a.slice(100,1))
+ assert_equal([100], a.slice(99,100))
+ assert_equal([100], a.slice(-1,1))
+ assert_equal([99], a.slice(-2,1))
+ assert_equal([10, 11, 12], a.slice(9, 3))
+ assert_equal([10, 11, 12], a.slice(-91, 3))
+ assert_nil(a.slice(-101, 2))
+ assert_equal([1], a.slice(0..0))
+ assert_equal([100], a.slice(99..99))
+ assert_equal([], a.slice(100..100))
+ assert_equal([100], a.slice(99..200))
+ assert_equal([100], a.slice(-1..-1))
+ assert_equal([99], a.slice(-2..-2))
+ assert_equal([10, 11, 12], a.slice(9..11))
+ assert_equal([10, 11, 12], a.slice(-91..-89))
+ assert_equal([10, 11, 12], a.slice(-91..-89))
+ assert_nil(a.slice(-101..-1))
+ assert_nil(a.slice(10, -3))
+ assert_equal([], a.slice(10..7))
+ assert_equal(b, a)
end
assert('Array#unshift', '15.2.12.5.30') do
@@ -319,11 +346,12 @@ end
assert('Array#to_s', '15.2.12.5.31 / 15.2.12.5.32') do
a = [2, 3, 4, 5]
+ a[4] = a
r1 = a.to_s
r2 = a.inspect
assert_equal(r2, r1)
- assert_equal("[2, 3, 4, 5]", r1)
+ assert_equal("[2, 3, 4, 5, [...]]", r1)
end
assert('Array#==', '15.2.12.5.33') do
diff --git a/test/t/class.rb b/test/t/class.rb
index 290ecf74a..e2839111c 100644
--- a/test/t/class.rb
+++ b/test/t/class.rb
@@ -356,6 +356,13 @@ assert('singleton tests') do
end
end
end if Object.const_defined?(:Float)
+
+ o = Object.new
+ sc = class << o; self end
+ o.freeze
+ assert_predicate(sc, :frozen?)
+
+ assert_predicate(class << Object.new.freeze; self end, :frozen?)
end
assert('clone Class') do
@@ -433,6 +440,25 @@ assert('overriding class variable with a module (#3235)') do
end
end
+assert('class variable for frozen class/module') do
+ module CVarForFrozenModule
+ freeze
+ assert_raise(FrozenError) { @@cv = 1 }
+ end
+
+ class CVarForFrozenClassA
+ @@a = nil
+ freeze
+ end
+ class CVarForFrozenClassB < CVarForFrozenClassA
+ def a=(v)
+ @@a = v
+ end
+ end
+ b = CVarForFrozenClassB.new
+ assert_raise(FrozenError) { b.a = 1 }
+end
+
assert('class with non-class/module outer raises TypeError') do
assert_raise(TypeError) { class 0::C1; end }
assert_raise(TypeError) { class []::C2; end }
diff --git a/test/t/enumerable.rb b/test/t/enumerable.rb
index 652c304da..9e7602db7 100644
--- a/test/t/enumerable.rb
+++ b/test/t/enumerable.rb
@@ -45,7 +45,7 @@ end
assert('Enumerable#detect', '15.3.2.2.4') do
assert_equal 1, [1,2,3].detect() { true }
- assert_equal 'a', [1,2,3].detect("a") { false }
+ assert_equal 'a', [1,2,3].detect(->{"a"}) { false }
end
assert('Array#each_with_index', '15.3.2.2.5') do
@@ -64,7 +64,7 @@ end
assert('Enumerable#find', '15.3.2.2.7') do
assert_equal 1, [1,2,3].find() { true }
- assert_equal 'a', [1,2,3].find("a") { false }
+ assert_equal 'a', [1,2,3].find(->{"a"}) { false }
end
assert('Enumerable#find_all', '15.3.2.2.8') do
diff --git a/test/t/float.rb b/test/t/float.rb
index 4e9d347b8..dc989636f 100644
--- a/test/t/float.rb
+++ b/test/t/float.rb
@@ -82,8 +82,8 @@ assert('Float#ceil', '15.2.9.3.8') do
end
assert('Float#finite?', '15.2.9.3.9') do
- assert_true 3.123456789.finite?
- assert_false (1.0 / 0.0).finite?
+ assert_predicate 3.123456789, :finite?
+ assert_not_predicate 1.0 / 0.0, :finite?
end
assert('Float#floor', '15.2.9.3.10') do
@@ -139,7 +139,7 @@ assert('Float#round', '15.2.9.3.12') do
nan = 0.0/0.0
assert_raise(FloatDomainError){ nan.round }
assert_raise(FloatDomainError){ nan.round(-1) }
- assert_true(nan.round(1).nan?)
+ assert_predicate(nan.round(1), :nan?)
end
assert('Float#to_f', '15.2.9.3.13') do
@@ -178,10 +178,10 @@ assert('Float#divmod') do
end
assert('Float#nan?') do
- assert_true (0.0/0.0).nan?
- assert_false 0.0.nan?
- assert_false (1.0/0.0).nan?
- assert_false (-1.0/0.0).nan?
+ assert_predicate(0.0/0.0, :nan?)
+ assert_not_predicate(0.0, :nan?)
+ assert_not_predicate(1.0/0.0, :nan?)
+ assert_not_predicate(-1.0/0.0, :nan?)
end
assert('Float#<<') do
@@ -212,10 +212,10 @@ assert('Float#to_s') do
assert_equal("Infinity", Float::INFINITY.to_s)
assert_equal("-Infinity", (-Float::INFINITY).to_s)
assert_equal("NaN", Float::NAN.to_s)
- assert_equal("0.0", 0.0.to_s)
- assert_equal("-0.0", -0.0.to_s)
+ assert_equal("0", 0.0.to_s)
+ assert_equal("-0", -0.0.to_s)
assert_equal("-3.25", -3.25.to_s)
- assert_equal("50.0", 50.0.to_s)
+ assert_equal("50", 50.0.to_s)
assert_equal("0.0125", 0.0125.to_s)
assert_equal("-0.0125", -0.0125.to_s)
assert_equal("1.0e-10", 0.0000000001.to_s)
@@ -224,8 +224,8 @@ assert('Float#to_s') do
assert_equal("-1.0e+20", -1e20.to_s)
assert_equal("1.0e+16", 10000000000000000.0.to_s)
assert_equal("-1.0e+16", -10000000000000000.0.to_s)
- assert_equal("100000.0", 100000.0.to_s)
- assert_equal("-100000.0", -100000.0.to_s)
+ assert_equal("100000", 100000.0.to_s)
+ assert_equal("-100000", -100000.0.to_s)
if uses_float
assert_equal("1.0e+08", 100000000.0.to_s)
assert_equal("-1.0e+08", -100000000.0.to_s)
@@ -234,15 +234,15 @@ assert('Float#to_s') do
else
assert_equal("1.0e+15", 1000000000000000.0.to_s)
assert_equal("-1.0e+15", -1000000000000000.0.to_s)
- assert_equal("100000000000000.0", 100000000000000.0.to_s)
- assert_equal("-100000000000000.0", -100000000000000.0.to_s)
+ assert_equal("100000000000000", 100000000000000.0.to_s)
+ assert_equal("-100000000000000", -100000000000000.0.to_s)
end
end
assert('Float#eql?') do
- assert_true(5.0.eql?(5.0))
- assert_false(5.0.eql?(5))
- assert_false(5.0.eql?("5.0"))
+ assert_operator(5.0, :eql?, 5.0)
+ assert_not_operator(5.0, :eql?, 5)
+ assert_not_operator(5.0, :eql?, "5.0")
end
end # const_defined?(:Float)
diff --git a/test/t/hash.rb b/test/t/hash.rb
index 156991f4a..cd47d251d 100644
--- a/test/t/hash.rb
+++ b/test/t/hash.rb
@@ -352,11 +352,13 @@ end
assert('Hash#inspect') do
h = { "c" => 300, "a" => 100, "d" => 400, "c" => 300 }
+ h["recur"] = h
ret = h.to_s
assert_include ret, '"c"=>300'
assert_include ret, '"a"=>100'
assert_include ret, '"d"=>400'
+ assert_include ret, '"recur"=>{...}'
end
assert('Hash#rehash') do
diff --git a/test/t/integer.rb b/test/t/integer.rb
index 4ab49eb0a..f9c44a64f 100644
--- a/test/t/integer.rb
+++ b/test/t/integer.rb
@@ -154,11 +154,11 @@ assert('Integer#<<', '15.2.8.3.12') do
# Left Shift by a negative is Right Shift
assert_equal 23, 46 << -1
- # Left Shift by 31 is bitShift overflow to SignedInt
- assert_equal 2147483648, 1 << 31
+ skip unless Object.const_defined?(:Float)
- # -3 Left Shift by 30 is bitShift overflow to SignedInt
- assert_equal(-3221225472, -3 << 30)
+ # Overflow to Fixnum
+ assert_float 9223372036854775808.0, 1 << 63
+ assert_float(-13835058055282163712.0, -3 << 62)
end
assert('Integer#>>', '15.2.8.3.13') do
@@ -232,8 +232,16 @@ assert('Integer#to_i', '15.2.8.3.24') do
end
assert('Integer#to_s', '15.2.8.3.25') do
- assert_equal '1', 1.to_s
- assert_equal("-1", -1.to_s)
+ assert_equal "1", 1.to_s
+ assert_equal "-1", -1.to_s
+ assert_equal "1010", 10.to_s(2)
+ assert_equal "a", 10.to_s(36)
+ assert_equal "-a", -10.to_s(36)
+ assert_equal "30071", 12345.to_s(8)
+ assert_raise(ArgumentError) { 10.to_s(-1) }
+ assert_raise(ArgumentError) { 10.to_s(0) }
+ assert_raise(ArgumentError) { 10.to_s(1) }
+ assert_raise(ArgumentError) { 10.to_s(37) }
end
assert('Integer#truncate', '15.2.8.3.26') do
diff --git a/test/t/kernel.rb b/test/t/kernel.rb
index d99358c0c..c2eeee1a5 100644
--- a/test/t/kernel.rb
+++ b/test/t/kernel.rb
@@ -31,10 +31,6 @@ end
# Kernel.eval is provided by the mruby-gem mrbgem. '15.3.1.2.3'
-assert('Kernel.global_variables', '15.3.1.2.4') do
- assert_equal Array, Kernel.global_variables.class
-end
-
assert('Kernel.iterator?', '15.3.1.2.5') do
assert_false Kernel.iterator?
end
@@ -92,6 +88,20 @@ assert('Kernel#__id__', '15.3.1.3.3') do
assert_equal Fixnum, __id__.class
end
+assert('Kernel#__send__', '15.3.1.3.4') do
+ # test with block
+ l = __send__(:lambda) do
+ true
+ end
+
+ assert_true l.call
+ assert_equal Proc, l.class
+ # test with argument
+ assert_true __send__(:respond_to?, :nil?)
+ # test without argument and without block
+ assert_equal String, __send__(:to_s).class
+end
+
assert('Kernel#block_given?', '15.3.1.3.6') do
def bg_try(&b)
if block_given?
@@ -230,6 +240,9 @@ assert('Kernel#extend', '15.3.1.3.13') do
assert_true a.respond_to?(:test_method)
assert_false b.respond_to?(:test_method)
+
+ assert_raise(FrozenError) { Object.new.freeze.extend(Test4ExtendModule) }
+ assert_raise(FrozenError, TypeError) { :sym.extend(Test4ExtendModule) }
end
assert('Kernel#extend works on toplevel', '15.3.1.3.13') do
@@ -247,10 +260,23 @@ assert('Kernel#freeze') do
assert_equal obj, obj.freeze
assert_equal 0, 0.freeze
assert_equal :a, :a.freeze
+ assert_equal true, true.freeze
+ assert_equal false, false.freeze
+ assert_equal nil, nil.freeze
+ skip unless Object.const_defined?(:Float)
+ assert_equal 0.0, 0.0.freeze
end
-assert('Kernel#global_variables', '15.3.1.3.14') do
- assert_equal Array, global_variables.class
+assert('Kernel#frozen?') do
+ assert_false "".frozen?
+ assert_true "".freeze.frozen?
+ assert_true 0.frozen?
+ assert_true :a.frozen?
+ assert_true true.frozen?
+ assert_true false.frozen?
+ assert_true nil.frozen?
+ skip unless Object.const_defined?(:Float)
+ assert_true 0.0.frozen?
end
assert('Kernel#hash', '15.3.1.3.15') do
@@ -329,17 +355,15 @@ assert('Kernel#method_missing', '15.3.1.3.30') do
end
end
no_super_test = NoSuperMethodTestClass.new
- begin
+ msg = "undefined method 'no_super_method_named_this'"
+ assert_raise_with_message(NoMethodError, msg) do
no_super_test.no_super_method_named_this
- rescue NoMethodError => e
- assert_equal "undefined method 'no_super_method_named_this'", e.message
end
a = String.new
- begin
+ msg = "undefined method 'no_method_named_this'"
+ assert_raise_with_message(NoMethodError, msg) do
a.no_method_named_this
- rescue NoMethodError => e
- assert_equal "undefined method 'no_method_named_this'", e.message
end
end
@@ -395,6 +419,8 @@ assert('Kernel#remove_instance_variable', '15.3.1.3.41') do
assert_equal nil, tri.var
assert_raise(NameError) { tri.remove }
assert_raise(NameError) { tri.remove_instance_variable(:var) }
+ assert_raise(FrozenError) { tri.freeze.remove }
+ assert_raise(FrozenError, NameError) { :a.remove_instance_variable(:@v) }
end
# Kernel#require is defined in mruby-require. '15.3.1.3.42'
@@ -471,13 +497,6 @@ assert('Kernel#respond_to_missing?') do
assert_false Test4RespondToMissing.new.respond_to?(:no_method)
end
-assert('Kernel#global_variables') do
- variables = global_variables
- 1.upto(9) do |i|
- assert_equal variables.include?(:"$#{i}"), true
- end
-end
-
assert('stack extend') do
def recurse(count, stop)
return count if count > stop
diff --git a/test/t/module.rb b/test/t/module.rb
index ec36855e8..12b7f1344 100644
--- a/test/t/module.rb
+++ b/test/t/module.rb
@@ -21,10 +21,29 @@ def labeled_class(name, supklass = Object, &block)
end
end
+def assert_uninitialized_const(&block)
+ assert_raise_with_message_pattern(NameError, "uninitialized constant *", &block)
+end
+
+def assert_wrong_const_name(&block)
+ assert_raise_with_message_pattern(NameError, "wrong constant name *", &block)
+end
+
assert('Module', '15.2.2') do
assert_equal Class, Module.class
end
+assert('Module#alias_method', '15.2.2.4.8') do
+ cls = Class.new do
+ def foo
+ "FOO"
+ end
+ end
+
+ assert_same(cls, cls.alias_method(:bar, :foo))
+ assert_equal("FOO", cls.new.bar)
+end
+
# TODO not implemented ATM assert('Module.constants', '15.2.2.3.1') do
assert('Module#ancestors', '15.2.2.4.9') do
@@ -48,6 +67,7 @@ assert('Module#append_features', '15.2.2.4.10') do
end
assert_equal Test4AppendFeatures2, Test4AppendFeatures2.const_get(:Const4AppendFeatures2)
+ assert_raise(FrozenError) { Module.new.append_features Class.new.freeze }
end
assert('Module#attr NameError') do
@@ -210,7 +230,7 @@ assert('Module#const_defined?', '15.2.2.4.20') do
assert_true Test4ConstDefined.const_defined?(:Const4Test4ConstDefined)
assert_false Test4ConstDefined.const_defined?(:NotExisting)
- assert_raise(NameError){ Test4ConstDefined.const_defined?(:wrong_name) }
+ assert_wrong_const_name{ Test4ConstDefined.const_defined?(:wrong_name) }
end
assert('Module#const_get', '15.2.2.4.21') do
@@ -223,9 +243,9 @@ assert('Module#const_get', '15.2.2.4.21') do
assert_equal 42, Object.const_get("Test4ConstGet::Const4Test4ConstGet")
assert_raise(TypeError){ Test4ConstGet.const_get(123) }
- assert_raise(NameError){ Test4ConstGet.const_get(:I_DO_NOT_EXIST) }
- assert_raise(NameError){ Test4ConstGet.const_get("I_DO_NOT_EXIST::ME_NEITHER") }
- assert_raise(NameError){ Test4ConstGet.const_get(:wrong_name) }
+ assert_uninitialized_const{ Test4ConstGet.const_get(:I_DO_NOT_EXIST) }
+ assert_uninitialized_const{ Test4ConstGet.const_get("I_DO_NOT_EXIST::ME_NEITHER") }
+ assert_wrong_const_name{ Test4ConstGet.const_get(:wrong_name) }
end
assert('Module#const_set', '15.2.2.4.23') do
@@ -236,7 +256,7 @@ assert('Module#const_set', '15.2.2.4.23') do
assert_equal 23, Test4ConstSet.const_set(:Const4Test4ConstSet, 23)
assert_equal 23, Test4ConstSet.const_get(:Const4Test4ConstSet)
["", "wrongNAME", "Wrong-Name"].each do |n|
- assert_raise(NameError) { Test4ConstSet.const_set(n, 1) }
+ assert_wrong_const_name { Test4ConstSet.const_set(n, 1) }
end
end
@@ -247,10 +267,13 @@ assert('Module#remove_const', '15.2.2.4.40') do
assert_equal 23, Test4RemoveConst.remove_const(:ExistingConst)
assert_false Test4RemoveConst.const_defined?(:ExistingConst)
- assert_raise(NameError) { Test4RemoveConst.remove_const(:NonExistingConst) }
+ assert_raise_with_message_pattern(NameError, "constant * not defined") do
+ Test4RemoveConst.remove_const(:NonExistingConst)
+ end
%i[x X!].each do |n|
- assert_raise(NameError) { Test4RemoveConst.remove_const(n) }
+ assert_wrong_const_name { Test4RemoveConst.remove_const(n) }
end
+ assert_raise(FrozenError) { Test4RemoveConst.freeze.remove_const(:A) }
end
assert('Module#const_missing', '15.2.2.4.22') do
@@ -263,6 +286,18 @@ assert('Module#const_missing', '15.2.2.4.22') do
assert_equal 42, Test4ConstMissing.const_get(:ConstDoesntExist)
end
+assert('Module#extend_object', '15.2.2.4.25') do
+ cls = Class.new
+ mod = Module.new { def foo; end }
+ a = cls.new
+ b = cls.new
+ mod.extend_object(b)
+ assert_false a.respond_to?(:foo)
+ assert_true b.respond_to?(:foo)
+ assert_raise(FrozenError) { mod.extend_object(cls.new.freeze) }
+ assert_raise(FrozenError, TypeError) { mod.extend_object(1) }
+end
+
assert('Module#include', '15.2.2.4.27') do
module Test4Include
Const4Include = 42
@@ -276,6 +311,7 @@ assert('Module#include', '15.2.2.4.27') do
assert_equal 42, Test4Include2.const_get(:Const4Include)
assert_equal Test4Include2, Test4Include2.include_result
+ assert_raise(FrozenError) { Module.new.freeze.include Test4Include }
end
assert('Module#include?', '15.2.2.4.28') do
@@ -374,6 +410,29 @@ end
# Not ISO specified
+assert('Module#dup') do
+ module TestModuleDup
+ @@cvar = :cvar
+ class << self
+ attr_accessor :cattr
+ def cmeth; :cmeth end
+ end
+ def cvar; @@cvar end
+ def imeth; :imeth end
+ self.cattr = :cattr
+ end
+
+ m = TestModuleDup.dup
+ o = Object.include(m).new
+ assert_equal(:cattr, m.cattr)
+ assert_equal(:cmeth, m.cmeth)
+ assert_equal(:cvar, o.cvar)
+ assert_equal(:imeth, o.imeth)
+ assert_match("#<Module:0x*>", m.to_s)
+ assert_not_predicate(m, :frozen?)
+ assert_not_predicate(TestModuleDup.freeze.dup, :frozen?)
+end
+
assert('Module#define_method') do
c = Class.new {
define_method(:m1) { :ok }
@@ -386,6 +445,15 @@ assert('Module#define_method') do
end
end
+assert 'Module#prepend_features' do
+ mod = Module.new { def m; :mod end }
+ cls = Class.new { def m; :cls end }
+ assert_equal :cls, cls.new.m
+ mod.prepend_features(cls)
+ assert_equal :mod, cls.new.m
+ assert_raise(FrozenError) { Module.new.prepend_features(Class.new.freeze) }
+end
+
# @!group prepend
assert('Module#prepend') do
module M0
@@ -620,6 +688,10 @@ end
# end
# end;
#end
+
+ assert 'Module#prepend to frozen class' do
+ assert_raise(FrozenError) { Class.new.freeze.prepend Module.new }
+ end
# @!endgroup prepend
assert('Module#to_s') do
@@ -640,11 +712,12 @@ assert('Module#to_s') do
assert_equal 'SetOuter', SetOuter.to_s
assert_equal 'SetOuter::SetInner', SetOuter::SetInner.to_s
- mod = Module.new
- cls = Class.new
+ assert_match "#<Module:0x*>", Module.new.to_s
+ assert_match "#<Class:0x*>", Class.new.to_s
- assert_equal "#<Module:0x", mod.to_s[0,11]
- assert_equal "#<Class:0x", cls.to_s[0,10]
+ assert_equal "FrozenClassToS", (FrozenClassToS = Class.new.freeze).to_s
+ assert_equal "Outer::A", (Outer::A = Module.new.freeze).to_s
+ assert_match "#<Module:0x*>::A", (Module.new::A = Class.new.freeze).to_s
end
assert('Module#inspect') do
@@ -672,8 +745,8 @@ assert('Issue 1467') do
include M1
end
- C1.new
- C2.new
+ assert_kind_of(M1, C1.new)
+ assert_kind_of(M1, C2.new)
end
assert('clone Module') do
@@ -687,7 +760,7 @@ assert('clone Module') do
include M1.clone
end
- B.new.foo
+ assert_true(B.new.foo)
end
assert('Module#module_function') do
diff --git a/test/t/numeric.rb b/test/t/numeric.rb
index d73dfdb61..5b1e79153 100644
--- a/test/t/numeric.rb
+++ b/test/t/numeric.rb
@@ -1,6 +1,19 @@
##
# Numeric ISO Test
+def assert_step(exp, receiver, args, inf: false)
+ act = []
+ ret = receiver.step(*args) do |i|
+ act << i
+ break if inf && exp.size == act.size
+ end
+ expr = "#{receiver.inspect}.step(#{args.map(&:inspect).join(', ')})"
+ assert "assert_step" do
+ assert_true(exp.eql?(act), "#{expr}: counters", assertion_diff(exp, act))
+ assert_same(receiver, ret, "#{expr}: return value") unless inf
+ end
+end
+
assert('Numeric', '15.2.7') do
assert_equal(Class, Numeric.class)
end
@@ -42,31 +55,60 @@ assert('Numeric#**') do
end
assert('Numeric#step') do
- assert_step = ->(exp, receiver, args) do
- inf = !args[0]
- act = []
- ret = receiver.step(*args) do |i|
- act << i
- break if inf && exp.size == act.size
- end
- expr = "#{receiver.inspect}.step(#{args.map(&:inspect).join(', ')})"
- assert_true(exp.eql?(act), "#{expr}: counters", assertion_diff(exp, act))
- assert_same(receiver, ret, "#{expr}: return value") unless inf
- end
-
assert_raise(ArgumentError) { 1.step(2, 0) { break } }
- assert_step.([2, 3, 4], 2, [4])
- assert_step.([10, 8, 6, 4, 2], 10, [1, -2])
- assert_step.([], 2, [1, 3])
- assert_step.([], -2, [-1, -3])
- assert_step.([10, 11, 12, 13], 10, [])
- assert_step.([10, 7, 4], 10, [nil, -3])
+ assert_step([2, 3, 4], 2, [4])
+ assert_step([10, 8, 6, 4, 2], 10, [1, -2])
+ assert_step([], 2, [1, 3])
+ assert_step([], -2, [-1, -3])
+ assert_step([10, 11, 12, 13], 10, [], inf: true)
+ assert_step([10, 7, 4], 10, [nil, -3], inf: true)
skip unless Object.const_defined?(:Float)
+ inf = Float::INFINITY
assert_raise(ArgumentError) { 1.step(2, 0.0) { break } }
- assert_step.([2.0, 3.0, 4.0], 2, [4.0])
- assert_step.([7.0, 4.0, 1.0, -2.0], 7, [-4, -3.0])
- assert_step.([2.0, 3.0, 4.0], 2.0, [4])
- assert_step.([10.0, 11.0, 12.0, 13.0], 10.0, [])
- assert_step.([10.0, 7.0, 4.0], 10, [nil, -3.0])
+ assert_step([2.0, 3.0, 4.0], 2, [4.0])
+ assert_step([7.0, 4.0, 1.0, -2.0], 7, [-4, -3.0])
+ assert_step([2.0, 3.0, 4.0], 2.0, [4])
+ assert_step([10.0, 11.0, 12.0, 13.0], 10.0, [], inf: true)
+ assert_step([10.0, 7.0, 4.0], 10, [nil, -3.0], inf: true)
+ assert_step([1.0], 1, [nil, inf])
+ assert_step([1.0], 1, [nil, -inf])
+ assert_step([1.0], 1, [3, inf])
+ assert_step([], 1, [-3, inf])
+ assert_step([], 1, [3, -inf])
+ assert_step([1.0], 1, [-3, -inf])
+ assert_step([1.0], 1, [inf, inf])
+ assert_step([], 1, [inf, -inf])
+ assert_step([], 1, [-inf, inf])
+ assert_step([1.0], 1, [-inf, -inf])
+ assert_step([], inf, [2])
+ assert_step([], inf, [-2])
+ assert_step([], inf, [2, 3])
+ assert_step([inf, inf, inf], inf, [2, -3], inf: true)
+ assert_step([], inf, [2, inf])
+ assert_step([inf], inf, [2, -inf])
+ assert_step([], inf, [-2, inf])
+ assert_step([inf], inf, [-2, -inf])
+ assert_step([], inf, [-2, 3])
+ assert_step([inf, inf, inf], inf, [-2, -3], inf: true)
+ assert_step([inf], inf, [inf])
+ assert_step([], inf, [-inf])
+ assert_step([inf], inf, [inf, inf])
+ assert_step([inf], inf, [inf, -inf])
+ assert_step([inf], inf, [-inf, -inf])
+ assert_step([-inf, -inf, -inf], -inf, [2], inf: true)
+ assert_step([-inf, -inf, -inf], -inf, [-2], inf: true)
+ assert_step([-inf, -inf, -inf], -inf, [2, 3], inf: true)
+ assert_step([], -inf, [2, -3])
+ assert_step([-inf], -inf, [2, inf])
+ assert_step([], -inf, [2, -inf])
+ assert_step([-inf], -inf, [-2, inf])
+ assert_step([], -inf, [-2, -inf])
+ assert_step([-inf, -inf, -inf], -inf, [-2, 3], inf: true)
+ assert_step([], -inf, [-2, -3])
+ assert_step([-inf, -inf, -inf], -inf, [inf], inf: true)
+ assert_step([-inf], -inf, [-inf])
+ assert_step([-inf], -inf, [inf, inf])
+ assert_step([], -inf, [inf, -inf])
+ assert_step([-inf], -inf, [-inf, -inf])
end
diff --git a/test/t/range.rb b/test/t/range.rb
index d71fe8946..106c2866e 100644
--- a/test/t/range.rb
+++ b/test/t/range.rb
@@ -101,12 +101,12 @@ end
assert('Range#dup') do
r = (1..3).dup
- assert_equal r.begin, 1
- assert_equal r.end, 3
+ assert_equal 1, r.begin
+ assert_equal 3, r.end
assert_false r.exclude_end?
r = ("a"..."z").dup
- assert_equal r.begin, "a"
- assert_equal r.end, "z"
+ assert_equal "a", r.begin
+ assert_equal "z", r.end
assert_true r.exclude_end?
end
diff --git a/test/t/string.rb b/test/t/string.rb
index cf3702cbe..65ad13103 100644
--- a/test/t/string.rb
+++ b/test/t/string.rb
@@ -2,7 +2,7 @@
##
# String ISO Test
-UTF8STRING = ("\343\201\202".size == 1)
+UTF8STRING = __ENCODING__ == "UTF-8"
assert('String', '15.2.10') do
assert_equal Class, String.class
@@ -37,49 +37,37 @@ end
assert('String#*', '15.2.10.5.5') do
assert_equal 'aaaaa', 'a' * 5
assert_equal '', 'a' * 0
- assert_raise(ArgumentError) do
- 'a' * -1
- end
+ assert_raise(ArgumentError) { 'a' * -1 }
+ assert_raise(TypeError) { 'a' * '1' }
+ assert_raise(TypeError) { 'a' * nil }
+
+ skip unless Object.const_defined?(:Float)
+ assert_equal 'aa', 'a' * 2.1
+ assert_raise(RangeError) { '' * 1e30 }
+ assert_raise(RangeError) { '' * Float::INFINITY }
+ assert_raise(RangeError) { '' * Float::NAN }
end
assert('String#[]', '15.2.10.5.6') do
# length of args is 1
- a = 'abc'[0]
- b = 'abc'[-1]
- c = 'abc'[10]
- d = 'abc'[-10]
- e = 'abc'[1.1]
+ assert_equal 'a', 'abc'[0]
+ assert_equal 'c', 'abc'[-1]
+ assert_nil 'abc'[10]
+ assert_nil 'abc'[-10]
+ assert_equal 'b', 'abc'[1.1] if Object.const_defined?(:Float)
# length of args is 2
- a1 = 'abc'[0, -1]
- b1 = 'abc'[10, 0]
- c1 = 'abc'[-10, 0]
- d1 = 'abc'[0, 0]
- e1 = 'abc'[1, 2]
-
- # args is RegExp
- # It will be tested in mrbgems.
+ assert_nil 'abc'[0, -1]
+ assert_nil 'abc'[10, 0]
+ assert_nil 'abc'[-10, 0]
+ assert_equal '', 'abc'[0, 0]
+ assert_equal 'bc', 'abc'[1, 2]
# args is String
- a3 = 'abc'['bc']
- b3 = 'abc'['XX']
-
- assert_equal 'a', 'a'
- # assert_equal 'c', b
- # assert_nil c
- # assert_nil d
- # assert_equal 'b', e
- # assert_nil a1
- # assert_nil b1
- # assert_nil c1
- # assert_equal '', d1
- # assert_equal 'bc', e1
- # assert_equal 'bc', a3
- # assert_nil b3
-
- # assert_raise(TypeError) do
- # a[nil]
- # end
+ assert_equal 'bc', 'abc'['bc']
+ assert_nil 'abc'['XX']
+
+ assert_raise(TypeError) { 'abc'[nil] }
end
assert('String#[](UTF-8)', '15.2.10.5.6') do
@@ -161,6 +149,9 @@ assert('String#[]=') do
assert_equal 'aXc', e
end
+ assert_raise(TypeError) { 'a'[0] = 1 }
+ assert_raise(TypeError) { 'a'[:a] = '1' }
+
# length of args is 2
a1 = 'abc'
assert_raise(IndexError) do
@@ -197,8 +188,62 @@ assert('String#[]=') do
assert_raise(IndexError) do
b3['XX'] = 'Y'
end
+
+ assert_raise(TypeError) { 'a'[:a, 0] = '1' }
+ assert_raise(TypeError) { 'a'[0, :a] = '1' }
+ assert_raise(TypeError) { 'a'[0, 1] = 1 }
end
+assert('String[]=(UTF-8)') do
+ a = "➀➁➂➃➄"
+ a[3] = "⚃"
+ assert_equal "➀➁➂⚃➄", a
+
+ b = "➀➁➂➃➄"
+ b[3, 0] = "⛄"
+ assert_equal "➀➁➂⛄➃➄", b
+
+ c = "➀➁➂➃➄"
+ c[3, 2] = "⚃⚄"
+ assert_equal "➀➁➂⚃⚄", c
+
+ d = "➀➁➂➃➄"
+ d[5] = "⛄"
+ assert_equal "➀➁➂➃➄⛄", d
+
+ e = "➀➁➂➃➄"
+ e[5, 0] = "⛄"
+ assert_equal "➀➁➂➃➄⛄", e
+
+ f = "➀➁➂➃➄"
+ f[5, 2] = "⛄"
+ assert_equal "➀➁➂➃➄⛄", f
+
+ g = "➀➁➂➃➄"
+ assert_raise(IndexError) { g[6] = "⛄" }
+
+ h = "➀➁➂➃➄"
+ assert_raise(IndexError) { h[6, 0] = "⛄" }
+
+ i = "➀➁➂➃➄"
+ assert_raise(IndexError) { i[6, 2] = "⛄" }
+
+ j = "➀➁➂➃➄"
+ j["➃"] = "⚃"
+ assert_equal "➀➁➂⚃➄", j
+
+ k = "➀➁➂➃➄"
+ assert_raise(IndexError) { k["⛄"] = "⛇" }
+
+ l = "➀➁➂➃➄"
+ assert_nothing_raised { l["➂"] = "" }
+ assert_equal "➀➁➃➄", l
+
+ m = "➀➁➂➃➄"
+ assert_raise(TypeError) { m["➂"] = nil }
+ assert_equal "➀➁➂➃➄", m
+end if UTF8STRING
+
assert('String#capitalize', '15.2.10.5.7') do
a = 'abc'
a.capitalize
@@ -406,7 +451,22 @@ assert('String#index', '15.2.10.5.22') do
assert_equal 3, 'abcabc'.index('a', 1)
assert_equal 5, "hello".index("", 5)
assert_equal nil, "hello".index("", 6)
-end
+ assert_equal 3, "hello".index("l", -2)
+ assert_raise(ArgumentError) { "hello".index }
+ assert_raise(TypeError) { "hello".index(101) }
+end
+
+assert('String#index(UTF-8)', '15.2.10.5.22') do
+ assert_equal 0, '⓿➊➋➌➍➎'.index('⓿')
+ assert_nil '⓿➊➋➌➍➎'.index('➓')
+ assert_equal 6, '⓿➊➋➌➍➎⓿➊➋➌➍➎'.index('⓿', 1)
+ assert_equal 6, '⓿➊➋➌➍➎⓿➊➋➌➍➎'.index('⓿', -7)
+ assert_equal 6, "⓿➊➋➌➍➎".index("", 6)
+ assert_equal nil, "⓿➊➋➌➍➎".index("", 7)
+ assert_equal 0, '⓿➊➋➌➍➎'.index("\xe2")
+ assert_equal nil, '⓿➊➋➌➍➎'.index("\xe3")
+ assert_equal 6, "\xd1\xd1\xd1\xd1\xd1\xd1⓿➊➋➌➍➎".index('⓿')
+end if UTF8STRING
assert('String#initialize', '15.2.10.5.23') do
a = ''
@@ -469,6 +529,7 @@ assert('String#reverse(UTF-8)', '15.2.10.5.29') do
assert_equal 'こんにちは世界!', a
assert_equal '!界世はちにんこ', 'こんにちは世界!'.reverse
+ assert_equal 'あ', 'あ'.reverse
end if UTF8STRING
assert('String#reverse!', '15.2.10.5.30') do
@@ -485,24 +546,44 @@ assert('String#reverse!(UTF-8)', '15.2.10.5.30') do
assert_equal '!界世はちにんこ', a
assert_equal '!界世はちにんこ', 'こんにちは世界!'.reverse!
+
+ b = 'あ'
+ b.reverse!
+ assert_equal 'あ', b
end if UTF8STRING
assert('String#rindex', '15.2.10.5.31') do
assert_equal 0, 'abc'.rindex('a')
+ assert_equal 0, 'abc'.rindex('a', 3)
+ assert_nil 'abc'.rindex('a', -4)
assert_nil 'abc'.rindex('d')
+ assert_equal 6, 'abcabc'.rindex('')
+ assert_equal 3, 'abcabc'.rindex('a')
assert_equal 0, 'abcabc'.rindex('a', 1)
assert_equal 3, 'abcabc'.rindex('a', 4)
+ assert_equal 0, 'abcabc'.rindex('a', -4)
+ assert_raise(ArgumentError) { "hello".rindex }
+ assert_raise(TypeError) { "hello".rindex(101) }
end
assert('String#rindex(UTF-8)', '15.2.10.5.31') do
str = "こんにちは世界!\nこんにちは世界!"
- assert_nil str.index('さ')
- assert_equal 3, str.index('ち')
- assert_equal 12, str.index('ち', 10)
- assert_equal nil, str.index("さ")
+ assert_nil str.rindex('さ')
+ assert_equal 12, str.rindex('ち')
+ assert_equal 3, str.rindex('ち', 10)
+ assert_equal 3, str.rindex('ち', -6)
+
+ broken = "\xf0☀\xf1☁\xf2☂\xf3☃\xf0☀\xf1☁\xf2☂\xf3☃"
+ assert_nil broken.rindex("\x81") # "\x81" is a part of "☁" ("\xe2\x98\x81")
+ assert_equal 11, broken.rindex("☁")
+ assert_equal 11, broken.rindex("☁", 12)
+ assert_equal 11, broken.rindex("☁", 11)
+ assert_equal 3, broken.rindex("☁", 10)
end if UTF8STRING
-# 'String#scan', '15.2.10.5.32' will be tested in mrbgems.
+# assert('String#scan', '15.2.10.5.32') do
+# # Not implemented yet
+# end
assert('String#size', '15.2.10.5.33') do
assert_equal 3, 'abc'.size
@@ -667,12 +748,18 @@ assert('String#upcase!', '15.2.10.5.43') do
end
assert('String#inspect', '15.2.10.5.46') do
+ assert_equal "\"\\x00\"", "\0".inspect
+ assert_equal "\"foo\"", "foo".inspect
+ if UTF8STRING
+ assert_equal '"る"', "る".inspect
+ else
+ assert_equal '"\xe3\x82\x8b"', "る".inspect
+ end
+
# should not raise an exception - regress #1210
assert_nothing_raised do
- ("\1" * 100).inspect
+ ("\1" * 100).inspect
end
-
- assert_equal "\"\\x00\"", "\0".inspect
end
# Not ISO specified
@@ -682,10 +769,6 @@ assert('String interpolation (mrb_str_concat for shared strings)') do
assert_equal "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA:", "#{a}:"
end
-assert('Check the usage of a NUL character') do
- "qqq\0ppp"
-end
-
assert('String#bytes') do
str1 = "hello"
bytes1 = [104, 101, 108, 108, 111]
@@ -719,3 +802,82 @@ assert('String literal concatenation') do
assert_equal 3, ('A' "B" 'C').size
assert_equal 4, (%(A) "B#{?C}" "D").size
end
+
+assert('String#getbyte') do
+ str1 = "hello"
+ bytes1 = [104, 101, 108, 108, 111]
+ assert_equal bytes1[0], str1.getbyte(0)
+ assert_equal bytes1[-1], str1.getbyte(-1)
+ assert_equal bytes1[6], str1.getbyte(6)
+
+ str2 = "\xFF"
+ bytes2 = [0xFF]
+ assert_equal bytes2[0], str2.getbyte(0)
+end
+
+assert('String#setbyte') do
+ str1 = "hello"
+ h = "H".getbyte(0)
+ str1.setbyte(0, h)
+ assert_equal(h, str1.getbyte(0))
+ assert_equal("Hello", str1)
+end
+
+assert('String#byteslice') do
+ str1 = "hello"
+ str2 = "\u3042ab" # "\xE3\x81\x82ab"
+
+ assert_equal("h", str1.byteslice(0))
+ assert_equal("e", str1.byteslice(1))
+ assert_equal(nil, str1.byteslice(5))
+ assert_equal("o", str1.byteslice(-1))
+ assert_equal(nil, str1.byteslice(-6))
+ assert_equal("\xE3", str2.byteslice(0))
+ assert_equal("\x81", str2.byteslice(1))
+ assert_equal(nil, str2.byteslice(5))
+ assert_equal("b", str2.byteslice(-1))
+ assert_equal(nil, str2.byteslice(-6))
+
+ assert_equal("", str1.byteslice(0, 0))
+ assert_equal(str1, str1.byteslice(0, 6))
+ assert_equal("el", str1.byteslice(1, 2))
+ assert_equal("", str1.byteslice(5, 1))
+ assert_equal("o", str1.byteslice(-1, 6))
+ assert_equal(nil, str1.byteslice(-6, 1))
+ assert_equal(nil, str1.byteslice(0, -1))
+ assert_equal("", str2.byteslice(0, 0))
+ assert_equal(str2, str2.byteslice(0, 6))
+ assert_equal("\x81\x82", str2.byteslice(1, 2))
+ assert_equal("", str2.byteslice(5, 1))
+ assert_equal("b", str2.byteslice(-1, 6))
+ assert_equal(nil, str2.byteslice(-6, 1))
+ assert_equal(nil, str2.byteslice(0, -1))
+
+ assert_equal("ell", str1.byteslice(1..3))
+ assert_equal("el", str1.byteslice(1...3))
+ assert_equal("h", str1.byteslice(0..0))
+ assert_equal("", str1.byteslice(5..0))
+ assert_equal("o", str1.byteslice(4..5))
+ assert_equal(nil, str1.byteslice(6..0))
+ assert_equal("", str1.byteslice(-1..0))
+ assert_equal("llo", str1.byteslice(-3..5))
+ assert_equal("\x81\x82a", str2.byteslice(1..3))
+ assert_equal("\x81\x82", str2.byteslice(1...3))
+ assert_equal("\xE3", str2.byteslice(0..0))
+ assert_equal("", str2.byteslice(5..0))
+ assert_equal("b", str2.byteslice(4..5))
+ assert_equal(nil, str2.byteslice(6..0))
+ assert_equal("", str2.byteslice(-1..0))
+ assert_equal("\x82ab", str2.byteslice(-3..5))
+
+ assert_raise(ArgumentError) { str1.byteslice }
+ assert_raise(ArgumentError) { str1.byteslice(1, 2, 3) }
+ assert_raise(TypeError) { str1.byteslice("1") }
+ assert_raise(TypeError) { str1.byteslice("1", 2) }
+ assert_raise(TypeError) { str1.byteslice(1, "2") }
+ assert_raise(TypeError) { str1.byteslice(1..2, 3) }
+
+ skip unless Object.const_defined?(:Float)
+ assert_equal("o", str1.byteslice(4.0))
+ assert_equal("\x82ab", str2.byteslice(2.0, 3.0))
+end
diff --git a/test/t/syntax.rb b/test/t/syntax.rb
index 603547c7c..2740789ae 100644
--- a/test/t/syntax.rb
+++ b/test/t/syntax.rb
@@ -423,10 +423,11 @@ assert('parenthesed do-block in cmdarg') do
end
assert('method definition in cmdarg') do
- if false
+ result = class MethodDefinitionInCmdarg
+ def self.bar(arg); arg end
bar def foo; self.each do end end
end
- true
+ assert_equal(:foo, result)
end
assert('optional argument in the rhs default expressions') do
@@ -450,6 +451,18 @@ assert('optional block argument in the rhs default expressions') do
assert_nil(Proc.new {|foo = foo| foo}.call)
end
+assert('local variable definition in default value and subsequent arguments') do
+ def m(a = b = 1, c) [a, b, c] end
+ assert_equal([1, 1, :c], m(:c))
+ assert_equal([:a, nil, :c], m(:a, :c))
+
+ def m(a = b = 1, &c) [a, b, c ? true : nil] end
+ assert_equal([1, 1, nil], m)
+ assert_equal([1, 1, true], m{})
+ assert_equal([:a, nil, nil], m(:a))
+ assert_equal([:a, nil, true], m(:a){})
+end
+
assert('multiline comments work correctly') do
=begin
this is a comment with nothing after begin and end
@@ -653,4 +666,8 @@ assert 'keyword arguments' do
result = m(1, 2, e: 3, g: 4, h: 5, i: 6, &(l = ->{}))
assert_equal([1, 1, [], 2, 3, 2, 4, { h: 5, i: 6 }, l], result)
=end
+
+ def m(a: b = 1, c:) [a, b, c] end
+ assert_equal([1, 1, :c], m(c: :c))
+ assert_equal([:a, nil, :c], m(a: :a, c: :c))
end
diff --git a/test/t/vformat.rb b/test/t/vformat.rb
new file mode 100644
index 000000000..679f30407
--- /dev/null
+++ b/test/t/vformat.rb
@@ -0,0 +1,92 @@
+def assert_format(exp, args)
+ assert_equal(exp, TestVFormat.format(*args))
+end
+
+def assert_format_pattern(exp_pattern, args)
+ assert_match(exp_pattern, TestVFormat.format(*args))
+end
+
+# Pass if ArgumentError is raised or return value is +exp+.
+def assert_implementation_dependent(exp, args)
+ begin
+ ret = TestVFormat.format(*args)
+ rescue ArgumentError
+ return pass
+ end
+ if ret == exp
+ pass
+ else
+ flunk "", "Expected ArgumentError is raised or #{ret.inspect} to be #{exp}."
+ end
+end
+
+def sclass(v)
+ class << v
+ self
+ end
+end
+
+assert('mrb_vformat') do
+ n = TestVFormat::Native
+ assert_format '', ['']
+ assert_format 'No specifier!', ['No specifier!']
+ assert_format '`c`: C', ['`c`: %c', n.c(?C)]
+ assert_format '`d`: 123', ['`d`: %d', n.d(123)]
+ assert_format '`d`: -79', ['`d`: %d', n.d(-79)]
+ assert_format '`i`: 514', ['`i`: %i', n.i(514)]
+ assert_format '`i`: -83', ['`i`: %i', n.i(-83)]
+ assert_format '`t`: NilClass', ['`t`: %t', nil]
+ assert_format '`t`: FalseClass', ['`t`: %t', false]
+ assert_format '`t`: TrueClass', ['`t`: %t', true]
+ assert_format '`t`: Fixnum', ['`t`: %t', 0]
+ assert_format '`t`: Hash', ['`t`: %t', k: "value"]
+ assert_format_pattern '#<Class:#<Class:#<Hash:0x*>>>', ['%t', sclass({})]
+# assert_format 'string and length', ['string %l length', n.s('andante'), n.l(3)]
+ assert_format '`n`: sym', ['`n`: %n', n.n(:sym)]
+ assert_format '%C文字列%', ['%s', n.s('%C文字列%')]
+ assert_format '`C`: Kernel module', ['`C`: %C module', n.C(Kernel)]
+ assert_format '`C`: NilClass', ['`C`: %C', n.C(nil.class)]
+ assert_format_pattern '#<Class:#<String:0x*>>', ['%C', n.C(sclass(""))]
+ assert_format '`T`: NilClass', ['`T`: %T', nil]
+ assert_format '`T`: FalseClass', ['`T`: %T', false]
+ assert_format '`T`: TrueClass', ['`T`: %T', true]
+ assert_format '`T`: Fixnum', ['`T`: %T', 0]
+ assert_format '`T`: Hash', ['`T`: %T', k: "value"]
+ assert_format_pattern 'Class', ['%T', sclass({})]
+ assert_format '`Y`: nil', ['`Y`: %Y', nil]
+ assert_format '`Y`: false', ['`Y`: %Y', false]
+ assert_format '`Y`: true', ['`Y`: %Y', true]
+ assert_format '`Y`: Fixnum', ['`Y`: %Y', 0]
+ assert_format '`Y`: Hash', ['`Y`: %Y', k: "value"]
+ assert_format 'Class', ['%Y', sclass({})]
+ assert_format_pattern '#<Class:#<String:0x*>>', ['%v', sclass("")]
+ assert_format '`v`: 1...3', ['`v`: %v', 1...3]
+ assert_format '`S`: {:a=>1, "b"=>"c"}', ['`S`: %S', a: 1, "b" => ?c]
+ assert_format 'percent: %', ['percent: %%']
+ assert_format '"I": inspect char', ['%!c: inspect char', n.c(?I)]
+ assert_format '709: inspect mrb_int', ['%!d: inspect mrb_int', n.i(709)]
+# assert_format '"a\x00b\xff"', ['%!l', n.s("a\000b\xFFc\000d"), n.l(4)]
+ assert_format ':"&.": inspect symbol', ['%!n: inspect symbol', n.n(:'&.')]
+ assert_format 'inspect "String"', ['inspect %!v', 'String']
+ assert_format 'inspect Array: [1, :x, {}]', ['inspect Array: %!v', [1,:x,{}]]
+ assert_format_pattern '`!C`: #<Class:0x*>', ['`!C`: %!C', n.C(Class.new)]
+ assert_format 'to_s -> to_s: ab,cd', ['to_s -> to_s: %n,%v', n.n(:ab), 'cd']
+ assert_format 'to_s -> inspect: x:y', ['to_s -> inspect: %v%!v', 'x', :y]
+ assert_format 'inspect -> to_s: "a"b', ['inspect -> to_s: %!v%n', 'a', n.n(:b)]
+ assert_format 'Y -> to_s: nile', ['Y -> to_s: %Y%v', nil, "e"]
+ assert_format '"abc":Z', ['%!s%!n', n.s('abc'), n.n('Z'.to_sym)]
+ assert_format 'escape: \\%a,b,c,d', ['escape: \\\\\%a,b,\c%v', ',d']
+
+ assert_implementation_dependent 'unknown specifier: %^',
+ ['unknown specifier: %^']
+ assert_implementation_dependent 'unknown specifier with modifier: %!^',
+ ['unknown specifier with modifier: %!^']
+ assert_implementation_dependent 'termination is \\', ['termination is \\']
+ assert_implementation_dependent 'termination is %', ['termination is %']
+ assert_implementation_dependent 'termination is %!', ['termination is %!']
+
+ skip unless Object.const_defined?(:Float)
+ assert_format '`f`: 0.0125', ['`f`: %f', n.f(0.0125)]
+ assert_format '-Infinity', ['%f', n.f(-Float::INFINITY)]
+ assert_format 'NaN: Not a Number', ['%f: Not a Number', n.f(Float::NAN)]
+end