summaryrefslogtreecommitdiffhomepage
path: root/test
diff options
context:
space:
mode:
Diffstat (limited to 'test')
-rw-r--r--test/assert.rb427
-rw-r--r--test/bintest.rb17
-rw-r--r--test/report.rb4
-rw-r--r--test/t/argumenterror.rb16
-rw-r--r--test/t/array.rb98
-rw-r--r--test/t/basicobject.rb1
-rw-r--r--test/t/bs_block.rb75
-rw-r--r--test/t/bs_literal.rb2
-rw-r--r--test/t/class.rb49
-rw-r--r--test/t/ensure.rb34
-rw-r--r--test/t/enumerable.rb6
-rw-r--r--test/t/exception.rb15
-rw-r--r--test/t/float.rb127
-rw-r--r--test/t/hash.rb1189
-rw-r--r--test/t/integer.rb128
-rw-r--r--test/t/iterations.rb2
-rw-r--r--test/t/kernel.rb105
-rw-r--r--test/t/literals.rb53
-rw-r--r--test/t/methods.rb29
-rw-r--r--test/t/module.rb146
-rw-r--r--test/t/nameerror.rb8
-rw-r--r--test/t/numeric.rb95
-rw-r--r--test/t/object.rb1
-rw-r--r--test/t/proc.rb2
-rw-r--r--test/t/range.rb105
-rw-r--r--test/t/string.rb366
-rw-r--r--test/t/superclass.rb23
-rw-r--r--test/t/symbol.rb8
-rw-r--r--test/t/syntax.rb92
-rw-r--r--test/t/unicode.rb14
-rw-r--r--test/t/vformat.rb58
31 files changed, 2445 insertions, 850 deletions
diff --git a/test/assert.rb b/test/assert.rb
index a9baae5e1..8cd2b375b 100644
--- a/test/assert.rb
+++ b/test/assert.rb
@@ -1,17 +1,52 @@
+$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)
-# Implementation of print due to the reason that there might be no print
-def t_print(*args)
- i = 0
- len = args.size
- while i < len
- str = args[i].to_s
- __t_printstr__ str rescue print str
- i += 1
+# For bintest on Ruby
+unless RUBY_ENGINE == "mruby"
+ 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
@@ -19,16 +54,19 @@ end
# Create the assertion in a readable way
def assertion_string(err, str, iso=nil, e=nil, bt=nil)
msg = "#{err}#{str}"
- msg += " [#{iso}]" if iso && iso != ''
- msg += " => #{e.cause}" if e && e.respond_to?(:cause)
- msg += " => #{e.message}" if e && !e.respond_to?(:cause)
- msg += " (mrbgems: #{GEMNAME})" if Object.const_defined?(:GEMNAME)
- if $mrbtest_assert && $mrbtest_assert.size > 0
+ msg += " [#{iso}]" if iso && !iso.empty?
+ msg += " => #{e}" if e && !e.to_s.empty?
+ if Object.const_defined?(:GEMNAME)
+ msg += " (#{GEMNAME == 'mruby-test' ? 'core' : "mrbgems: #{GEMNAME}"})"
+ end
+ if $mrbtest_assert
$mrbtest_assert.each do |idx, assert_msg, diff|
- msg += "\n - Assertion[#{idx}] Failed: #{assert_msg}\n#{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 && !bt.empty?
msg
end
@@ -40,209 +78,326 @@ 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, nil))
- $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('.')
end
+ 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
- if e.class.to_s == 'MRubyTestSkip'
- $asserts.push(assertion_string('Skip: ', str, iso, e, nil))
- t_print('?')
+ $asserts.push(assertion_string("#{e.class}: ", str, iso, e, e.backtrace))
+ $kill_test += 1
+ t_print('X')
+ ensure
+ 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
- $asserts.push(assertion_string("#{e.class}: ", str, iso, e, bt))
- $kill_test += 1
- t_print('X')
+ parent_asserts.concat $asserts
end
- ensure
- $mrbtest_assert = nil
+ $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
def assertion_diff(exp, act)
- " Expected: #{exp.inspect}\n" +
+ " Expected: #{exp.inspect}\n" \
" Actual: #{act.inspect}"
end
-def assert_true(ret, msg = nil, diff = nil)
- if $mrbtest_assert
- $mrbtest_assert_idx += 1
- unless ret
- msg = "Expected #{ret.inspect} to be true" unless msg
- diff = assertion_diff(true, ret) unless diff
- $mrbtest_assert.push([$mrbtest_assert_idx, msg, diff])
+def assert_true(obj, msg = nil, diff = nil)
+ 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.to_s, msg, diff])
end
end
- ret
+ obj
end
-def assert_false(ret, msg = nil, diff = nil)
- if $mrbtest_assert
- $mrbtest_assert_idx += 1
- if ret
- msg = "Expected #{ret.inspect} to be false" unless msg
- diff = assertion_diff(false, ret) unless diff
+def assert_false(obj, msg = nil, diff = nil)
+ unless obj == false
+ diff ||= " Expected #{obj.inspect} to be false."
+ end
+ assert_true(!obj, msg, diff)
+end
- $mrbtest_assert.push([$mrbtest_assert_idx, msg, diff])
+def assert_equal(exp, act_or_msg = nil, msg = nil, &block)
+ ret, exp, act, msg = _eval_assertion(:==, exp, act_or_msg, msg, block)
+ unless ret
+ diff = assertion_diff(exp, act)
+ end
+ assert_true(ret, msg, diff)
+end
+
+def assert_not_equal(exp, act_or_msg = nil, msg = nil, &block)
+ ret, exp, act, msg = _eval_assertion(:==, exp, act_or_msg, msg, block)
+ if ret
+ diff = " Expected #{act.inspect} to not be equal to #{exp.inspect}."
+ end
+ assert_true(!ret, msg, diff)
+end
+
+def assert_same(*args); _assert_same(true, *args) end
+def assert_not_same(*args); _assert_same(false, *args) end
+def _assert_same(affirmed, exp, act, msg = nil)
+ unless ret = exp.equal?(act) == affirmed
+ exp_str, act_str = [exp, act].map do |o|
+ "#{o.inspect} (class=#{o.class}, oid=#{o.__id__})"
end
+ diff = " Expected #{act_str} to #{'not ' unless affirmed}be the same as #{exp_str}."
end
- !ret
+ assert_true(ret, msg, diff)
end
-def assert_equal(arg1, arg2 = nil, arg3 = nil)
- if block_given?
- exp, act, msg = arg1, yield, arg2
- else
- exp, act, msg = arg1, arg2, arg3
+def assert_nil(obj, msg = nil)
+ unless ret = obj.nil?
+ diff = " Expected #{obj.inspect} to be nil."
end
+ assert_true(ret, msg, diff)
+end
- msg = "Expected to be equal" unless msg
- diff = assertion_diff(exp, act)
- assert_true(exp == act, msg, diff)
+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_not_equal(arg1, arg2 = nil, arg3 = nil)
- if block_given?
- exp, act, msg = arg1, yield, arg2
- else
- exp, act, msg = arg1, arg2, arg3
+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)
+ unless ret = collection.include?(obj) == affirmed
+ diff = " Expected #{collection.inspect} to #{'not ' unless affirmed}include #{obj.inspect}."
end
+ assert_true(ret, msg, diff)
+end
- msg = "Expected to be not equal" unless msg
- diff = assertion_diff(exp, act)
- assert_false(exp == act, msg, diff)
+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_nil(obj, msg = nil)
- msg = "Expected #{obj.inspect} to be nil" unless msg
- diff = assertion_diff(nil, obj)
- assert_true(obj.nil?, msg, diff)
+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
-def assert_include(collection, obj, msg = nil)
- msg = "Expected #{collection.inspect} to include #{obj.inspect}" unless msg
- diff = " Collection: #{collection.inspect}\n" +
- " Object: #{obj.inspect}"
- assert_true(collection.include?(obj), msg, diff)
+##
+# 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
-def assert_not_include(collection, obj, msg = nil)
- msg = "Expected #{collection.inspect} to not include #{obj.inspect}" unless msg
- diff = " Collection: #{collection.inspect}\n" +
- " Object: #{obj.inspect}"
- assert_false(collection.include?(obj), msg, diff)
+##
+# Fails unless +obj+ is a kind of +cls+.
+def assert_kind_of(cls, obj, msg = nil)
+ unless ret = obj.kind_of?(cls)
+ diff = " Expected #{obj.inspect} to be a kind of #{cls}, not #{obj.class}."
+ end
+ assert_true(ret, msg, diff)
end
-def assert_raise(*exc)
- return true unless $mrbtest_assert
- $mrbtest_assert_idx += 1
+##
+# 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.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}.")
+ else
+ pass
+ end
+end
+def assert_raise(*exc)
msg = (exc.last.is_a? String) ? exc.pop : nil
-
+ exc = exc.empty? ? StandardError : exc.size == 1 ? exc[0] : exc
begin
yield
- msg ||= "Expected to raise #{exc} but nothing was raised."
- diff = nil
- $mrbtest_assert.push [$mrbtest_assert_idx, msg, diff]
- false
- rescue *exc
- true
+ rescue *exc => e
+ pass
+ e
rescue Exception => e
- msg ||= "Expected to raise #{exc}, not"
- diff = " Class: <#{e.class}>\n" +
- " Message: #{e.message}"
- $mrbtest_assert.push [$mrbtest_assert_idx, msg, diff]
- false
+ diff = " #{exc} exception expected, not\n" \
+ " Class: <#{e.class}>\n" \
+ " Message: <#{e}>"
+ flunk(msg, diff)
+ else
+ diff = " #{exc} expected but nothing was raised."
+ flunk(msg, diff)
end
end
def assert_nothing_raised(msg = nil)
- return true unless $mrbtest_assert
- $mrbtest_assert_idx += 1
-
begin
yield
- true
rescue Exception => e
- msg ||= "Expected not to raise #{exc.join(', ')} but it raised"
- diff = " Class: <#{e.class}>\n" +
- " Message: #{e.message}"
- $mrbtest_assert.push [$mrbtest_assert_idx, msg, diff]
- false
+ diff = " Exception raised:\n" \
+ " Class: <#{e.class}>\n" \
+ " Message: <#{e}>"
+ flunk(msg, diff)
+ else
+ pass
end
end
-##
-# Fails unless +obj+ is a kind of +cls+.
-def assert_kind_of(cls, obj, msg = nil)
- msg = "Expected #{obj.inspect} to be a kind of #{cls}, not #{obj.class}" unless msg
- diff = assertion_diff(cls, obj.class)
- assert_true(obj.kind_of?(cls), msg, diff)
+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)
-##
-# Fails unless +exp+ is equal to +act+ in terms of a Float
-def assert_float(exp, act, msg = nil)
- msg = "Float #{exp} expected to be equal to float #{act}" unless msg
- diff = assertion_diff(exp, act)
- assert_true check_float(exp, act), msg, diff
+ 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 = "Epic Fail!", diff = "")
+ assert_true(false, msg, diff)
end
##
# Report the test result and print all assertions
# which were reported broken.
-def report()
+def report
t_print("\n")
$asserts.each do |msg|
- t_print "#{msg}\n"
+ t_print("#{msg}\n")
end
- $total_test = $ok_test+$ko_test+$kill_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(" 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
end
-##
-# Performs fuzzy check for equality on methods returning floats
-def check_float(a, b)
- tolerance = Mrbtest::FLOAT_TOLERANCE
- a = a.to_f
- b = b.to_f
- if a.finite? and b.finite?
- (a-b).abs < tolerance
+def _eval_assertion(meth, exp, act_or_msg, msg, block)
+ if block
+ exp, act, msg = exp, block.call, act_or_msg
else
- true
+ exp, act, msg = exp, act_or_msg, msg
end
+ return exp.__send__(meth, act), exp, act, msg
end
##
# Skip the test
-class MRubyTestSkip < NotImplementedError
- attr_accessor :cause
- def initialize(cause)
- @cause = cause
- end
-end
+class MRubyTestSkip < NotImplementedError; end
def skip(cause = "")
raise MRubyTestSkip.new(cause)
diff --git a/test/bintest.rb b/test/bintest.rb
index b62419d44..a6888c9fb 100644
--- a/test/bintest.rb
+++ b/test/bintest.rb
@@ -1,13 +1,15 @@
$:.unshift File.dirname(File.dirname(File.expand_path(__FILE__)))
require 'test/assert.rb'
+GEMNAME = ""
+
def cmd(s)
- case RbConfig::CONFIG['host_os']
- when /mswin(?!ce)|mingw|bccwin/
- "bin\\#{s}.exe"
- else
- "bin/#{s}"
+ path = s == "mrbc" ? ENV['MRBCFILE'] : "#{ENV['BUILD_DIR']}/bin/#{s}"
+ path = path.sub(/\.exe\z/, "")
+ if /mswin(?!ce)|mingw|bccwin/ =~ RbConfig::CONFIG['host_os']
+ path = "#{path}.exe".tr("/", "\\")
end
+ path
end
def shellquote(s)
@@ -19,6 +21,8 @@ def shellquote(s)
end
end
+print "bintest - Command Binary Test\n\n"
+
ARGV.each do |gem|
case gem
when '-v'; $mrbtest_verbose = true
@@ -30,8 +34,9 @@ ARGV.each do |gem|
end
Dir["#{gem}/bintest/**/*.rb"].each do |file|
+ GEMNAME.replace(File.basename(gem))
load file
end
end
-load 'test/report.rb'
+exit report
diff --git a/test/report.rb b/test/report.rb
deleted file mode 100644
index fb77fd0aa..000000000
--- a/test/report.rb
+++ /dev/null
@@ -1,4 +0,0 @@
-report
-if $ko_test > 0 or $kill_test > 0
- raise "mrbtest failed (KO:#{$ko_test}, Crash:#{$kill_test})"
-end
diff --git a/test/t/argumenterror.rb b/test/t/argumenterror.rb
index abb53429b..3dcb29a4b 100644
--- a/test/t/argumenterror.rb
+++ b/test/t/argumenterror.rb
@@ -1,6 +1,13 @@
##
# ArgumentError ISO Test
+def assert_argnum_error(given, expected, &block)
+ assert("wrong number of arguments") do
+ message = "wrong number of arguments (given #{given}, expected #{expected})"
+ assert_raise_with_message(ArgumentError, message, &block)
+ end
+end
+
assert('ArgumentError', '15.2.24') do
e2 = nil
a = []
@@ -14,3 +21,12 @@ assert('ArgumentError', '15.2.24') do
assert_equal(Class, ArgumentError.class)
assert_equal(ArgumentError, e2.class)
end
+
+assert("'wrong number of arguments' from mrb_get_args") do
+ assert_argnum_error(0, "1+"){__send__}
+ assert_argnum_error(0, 1..2){Object.const_defined?}
+ assert_argnum_error(3, 1..2){Object.const_defined?(:A, true, 2)}
+ assert_argnum_error(2, 0..1){{}.default(1, 2)}
+ assert_argnum_error(1, 2){Object.const_set(:B)}
+ assert_argnum_error(3, 2){Object.const_set(:C, 1, 2)}
+end
diff --git a/test/t/array.rb b/test/t/array.rb
index ecec39363..5f26259f2 100644
--- a/test/t/array.rb
+++ b/test/t/array.rb
@@ -5,7 +5,7 @@ assert('Array', '15.2.12') do
assert_equal(Class, Array.class)
end
-assert('Array inclueded modules', '15.2.12.3') do
+assert('Array included modules', '15.2.12.3') do
assert_true(Array.include?(Enumerable))
end
@@ -55,9 +55,12 @@ assert('Array#[]', '15.2.12.5.4') do
assert_equal(nil, [1,2,3].[](-4))
a = [ "a", "b", "c", "d", "e" ]
- assert_equal("b", a[1.1]) if class_defined?("Float")
assert_equal(["b", "c"], a[1,2])
assert_equal(["b", "c", "d"], a[1..-2])
+ assert_equal(["b", "c", "d", "e"], a[1..])
+ assert_equal(["a", "b", "c"], a[..2])
+ skip unless Object.const_defined?(:Float)
+ assert_equal("b", a[1.1])
end
assert('Array#[]=', '15.2.12.5.5') do
@@ -91,6 +94,10 @@ assert('Array#[]=', '15.2.12.5.5') do
a[2...4] = 6
assert_equal([1,2,6,5], a)
+ a = [1,2,3,4,5]
+ a[2...] = 6
+ assert_equal([1,2,6], a)
+
# passing self (#3274)
a = [1,2,3]
a[1,0] = a
@@ -238,7 +245,7 @@ assert('Array#pop', '15.2.12.5.21') do
assert_equal([1,2], a)
assert_equal(3, b)
- assert_raise(RuntimeError) { [].freeze.pop }
+ assert_raise(FrozenError) { [].freeze.pop }
end
assert('Array#push', '15.2.12.5.22') do
@@ -287,7 +294,25 @@ assert('Array#shift', '15.2.12.5.27') do
assert_equal([2,3], a)
assert_equal(1, b)
- assert_raise(RuntimeError) { [].freeze.shift }
+ assert_raise(FrozenError) { [].freeze.shift }
+
+ # Array#shift with argument
+ assert_equal([], [].shift(1))
+
+ a = [1,2,3]
+ b = a.shift(1)
+ assert_equal([2,3], a)
+ assert_equal([1], b)
+
+ a = [1,2,3,4]
+ b = a.shift(3)
+ assert_equal([4], a)
+ assert_equal([1,2,3], b)
+
+ a = [1,2,3]
+ b = a.shift(4)
+ assert_equal([], a)
+ assert_equal([1,2,3], b)
end
assert('Array#size', '15.2.12.5.28') do
@@ -297,11 +322,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
@@ -318,11 +370,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
@@ -343,8 +396,7 @@ end
assert('Array#hash', '15.2.12.5.35') do
a = [ 1, 2, 3 ]
- #assert_true(a.hash.is_a? Integer)
- assert_true(a.hash.is_a? Integral) # mruby special
+ assert_true(a.hash.is_a? Integer)
assert_equal([1,2].hash, [1,2].hash)
end
@@ -360,13 +412,6 @@ end
# Not ISO specified
-assert("Array (Shared Array Corruption)") do
- a = [ "a", "b", "c", "d", "e", "f" ]
- b = a.slice(1, 3)
- a.clear
- b.clear
-end
-
assert("Array (Longish inline array)") do
ary = [[0, 0], [1, 1], [2, 2], [3, 3], [4, 4], [5, 5], [6, 6], [7, 7], [8, 8], [9, 9], [10, 10], [11, 11], [12, 12], [13, 13], [14, 14], [15, 15], [16, 16], [17, 17], [18, 18], [19, 19], [20, 20], [21, 21], [22, 22], [23, 23], [24, 24], [25, 25], [26, 26], [27, 27], [28, 28], [29, 29], [30, 30], [31, 31], [32, 32], [33, 33], [34, 34], [35, 35], [36, 36], [37, 37], [38, 38], [39, 39], [40, 40], [41, 41], [42, 42], [43, 43], [44, 44], [45, 45], [46, 46], [47, 47], [48, 48], [49, 49], [50, 50], [51, 51], [52, 52], [53, 53], [54, 54], [55, 55], [56, 56], [57, 57], [58, 58], [59, 59], [60, 60], [61, 61], [62, 62], [63, 63], [64, 64], [65, 65], [66, 66], [67, 67], [68, 68], [69, 69], [70, 70], [71, 71], [72, 72], [73, 73], [74, 74], [75, 75], [76, 76], [77, 77], [78, 78], [79, 79], [80, 80], [81, 81], [82, 82], [83, 83], [84, 84], [85, 85], [86, 86], [87, 87], [88, 88], [89, 89], [90, 90], [91, 91], [92, 92], [93, 93], [94, 94], [95, 95], [96, 96], [97, 97], [98, 98], [99, 99], [100, 100], [101, 101], [102, 102], [103, 103], [104, 104], [105, 105], [106, 106], [107, 107], [108, 108], [109, 109], [110, 110], [111, 111], [112, 112], [113, 113], [114, 114], [115, 115], [116, 116], [117, 117], [118, 118], [119, 119], [120, 120], [121, 121], [122, 122], [123, 123], [124, 124], [125, 125], [126, 126], [127, 127], [128, 128], [129, 129], [130, 130], [131, 131], [132, 132], [133, 133], [134, 134], [135, 135], [136, 136], [137, 137], [138, 138], [139, 139], [140, 140], [141, 141], [142, 142], [143, 143], [144, 144], [145, 145], [146, 146], [147, 147], [148, 148], [149, 149], [150, 150], [151, 151], [152, 152], [153, 153], [154, 154], [155, 155], [156, 156], [157, 157], [158, 158], [159, 159], [160, 160], [161, 161], [162, 162], [163, 163], [164, 164], [165, 165], [166, 166], [167, 167], [168, 168], [169, 169], [170, 170], [171, 171], [172, 172], [173, 173], [174, 174], [175, 175], [176, 176], [177, 177], [178, 178], [179, 179], [180, 180], [181, 181], [182, 182], [183, 183], [184, 184], [185, 185], [186, 186], [187, 187], [188, 188], [189, 189], [190, 190], [191, 191], [192, 192], [193, 193], [194, 194], [195, 195], [196, 196], [197, 197], [198, 198], [199, 199]]
h = Hash.new(0)
@@ -386,16 +431,15 @@ assert("Array#rindex") do
assert_equal 0, $a.rindex(1)
end
+assert('Array#sort!') do
+ a = [3, 2, 1]
+ assert_equal a, a.sort! # sort! returns self.
+ assert_equal [1, 2, 3], a # it is sorted.
+end
+
assert('Array#freeze') do
a = [].freeze
- assert_raise(RuntimeError) do
+ assert_raise(FrozenError) do
a[0] = 1
end
end
-
-assert('shared array replace') do
- a = [0] * 40
- b = [0, 1, 2]
- b.replace a[1, 20].dup
- assert_equal 20, b.size
-end
diff --git a/test/t/basicobject.rb b/test/t/basicobject.rb
index f33171266..c5aa3f171 100644
--- a/test/t/basicobject.rb
+++ b/test/t/basicobject.rb
@@ -8,4 +8,3 @@ end
assert('BasicObject superclass') do
assert_nil(BasicObject.superclass)
end
-
diff --git a/test/t/bs_block.rb b/test/t/bs_block.rb
index 62eb7e32e..f4e4da375 100644
--- a/test/t/bs_block.rb
+++ b/test/t/bs_block.rb
@@ -408,42 +408,43 @@ assert('BS Block 32') do
end
assert('BS Block [ruby-core:14395]') do
- class Controller
- def respond_to(&block)
- responder = Responder.new
- block.call(responder)
- responder.respond
- end
- def test_for_bug
- respond_to{|format|
- format.js{
- "in test"
- render{|obj|
- obj
+ assert_nothing_raised do
+ class Controller
+ def respond_to(&block)
+ responder = Responder.new
+ block.call(responder)
+ responder.respond
+ end
+ def test_for_bug
+ respond_to{|format|
+ format.js{
+ "in test"
+ render{|obj|
+ obj
+ }
}
}
- }
- end
- def render(&block)
- "in render"
- end
- end
-
- class Responder
- def method_missing(symbol, &block)
- "enter method_missing"
- @response = Proc.new{
- 'in method missing'
- block.call
- }
- "leave method_missing"
+ end
+ def render(&block)
+ "in render"
+ end
end
- def respond
- @response.call
+ class Responder
+ def method_missing(symbol, &block)
+ "enter method_missing"
+ @response = Proc.new{
+ 'in method missing'
+ block.call
+ }
+ "leave method_missing"
+ end
+ def respond
+ @response.call
+ end
end
+ t = Controller.new
+ t.test_for_bug
end
- t = Controller.new
- assert_true t.test_for_bug
end
assert("BS Block 33") do
@@ -519,3 +520,15 @@ assert('BS Block 38') do
assert_equal [1,2,3,4,5], iter{|a,b,c=:c,d,e| [a,b,c,d,e]}
end
+
+assert('BS Block 39') do
+ def iter
+ yield 1
+ end
+
+ assert_equal([1, 2, nil]) do
+ iter{|a, b=2, c|
+ [a, b, c]
+ }
+ end
+end
diff --git a/test/t/bs_literal.rb b/test/t/bs_literal.rb
index c6c38140b..d60957f0b 100644
--- a/test/t/bs_literal.rb
+++ b/test/t/bs_literal.rb
@@ -34,5 +34,5 @@ assert('BS Literal 8') do
end
assert('BS Literal 9') do
- assert_equal Fixnum, 1234.class
+ assert_equal Integer, 1234.class
end
diff --git a/test/t/class.rb b/test/t/class.rb
index 85450f200..1b4b84890 100644
--- a/test/t/class.rb
+++ b/test/t/class.rb
@@ -236,6 +236,11 @@ assert('class to return the last value') do
assert_equal(m, :m)
end
+assert('class to return nil if body is empty') do
+ assert_nil(class C end)
+ assert_nil(class << self; end)
+end
+
assert('raise when superclass is not a class') do
module FirstModule; end
assert_raise(TypeError, 'should raise TypeError') do
@@ -350,7 +355,14 @@ assert('singleton tests') do
7
end
end
- end if class_defined?("Float")
+ 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
@@ -360,7 +372,21 @@ assert('clone Class') do
end
end
- Foo.clone.new.func
+ assert_true(Foo.clone.new.func)
+end
+
+assert('class definition in singleton class') do
+ class AClassS
+ class << self
+ class BClass
+ end
+
+ def iclass
+ BClass
+ end
+ end
+ end
+ assert_equal(Class, AClassS.iclass.class)
end
assert('class variable and class << self style class method') do
@@ -428,6 +454,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/ensure.rb b/test/t/ensure.rb
index bef397059..bdb5bffc4 100644
--- a/test/t/ensure.rb
+++ b/test/t/ensure.rb
@@ -1,16 +1,16 @@
##
# ensure Test
-assert('ensure - context - yield') do
- class EnsureYieldBreak
- attr_reader :ensure_context
- def try
- yield
- ensure
- @ensure_context = self
- end
+class EnsureYieldBreak
+ attr_reader :ensure_context
+ def try
+ yield
+ ensure
+ @ensure_context = self
end
+end
+assert('ensure - context - yield') do
yielder = EnsureYieldBreak.new
yielder.try do
end
@@ -18,15 +18,6 @@ assert('ensure - context - yield') do
end
assert('ensure - context - yield and break') do
- class EnsureYieldBreak
- attr_reader :ensure_context
- def try
- yield
- ensure
- @ensure_context = self
- end
- end
-
yielder = EnsureYieldBreak.new
yielder.try do
break
@@ -35,15 +26,6 @@ assert('ensure - context - yield and break') do
end
assert('ensure - context - yield and return') do
- class EnsureYieldBreak
- attr_reader :ensure_context
- def try
- yield
- ensure
- @ensure_context = self
- end
- end
-
yielder = EnsureYieldBreak.new
lambda do
yielder.try do
diff --git a/test/t/enumerable.rb b/test/t/enumerable.rb
index 359c3451b..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,11 +64,11 @@ 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
- assert_true [1,2,3,4,5,6,7,8,9].find_all() {|i| i%2 == 0}, [2,4,6,8]
+ assert_equal [2,4,6,8], [1,2,3,4,5,6,7,8,9].find_all() {|i| i%2 == 0}
end
assert('Enumerable#grep', '15.3.2.2.9') do
diff --git a/test/t/exception.rb b/test/t/exception.rb
index ce7b5841e..6f517a5c3 100644
--- a/test/t/exception.rb
+++ b/test/t/exception.rb
@@ -263,10 +263,10 @@ assert('Exception 13') do
end
assert('Exception 14') do
- def exception_test14; UnknownConstant; end
+ def (o = Object.new).exception_test14; UnknownConstant end
a = :ng
begin
- send(:exception_test14)
+ o.__send__(:exception_test14)
rescue
a = :ok
end
@@ -352,8 +352,10 @@ assert('Exception 19') do
assert_equal [true, true], Class4Exception19.new.a
end
-assert('Exception#inspect without message') do
+assert('Exception#inspect') do
assert_equal "Exception", Exception.new.inspect
+ assert_equal "Exception", Exception.new("").inspect
+ assert_equal "error! (Exception)", Exception.new("error!").inspect
end
assert('Exception#backtrace') do
@@ -380,7 +382,8 @@ def backtrace_available?
begin
raise "XXX"
rescue => exception
- not exception.backtrace.empty?
+ return false if exception.backtrace.empty?
+ not exception.backtrace[0].include?("unknown")
end
end
@@ -398,7 +401,7 @@ assert('GC in rescue') do
end
rescue => exception
GC.start
- assert_equal("#{__FILE__}:#{line}:in call",
+ assert_equal("#{__FILE__}:#{line}",
exception.backtrace.first)
end
end
@@ -416,7 +419,7 @@ assert('Method call in rescue') do
rescue => exception
[3].each do
end
- assert_equal("#{__FILE__}:#{line}:in call",
+ assert_equal("#{__FILE__}:#{line}",
exception.backtrace.first)
end
end
diff --git a/test/t/float.rb b/test/t/float.rb
index 92f7a15f1..f6f6d01dd 100644
--- a/test/t/float.rb
+++ b/test/t/float.rb
@@ -1,7 +1,7 @@
##
# Float ISO Test
-if class_defined?("Float")
+if Object.const_defined?(:Float)
assert('Float', '15.2.9') do
assert_equal Class, Float.class
@@ -35,11 +35,66 @@ assert('Float#*', '15.2.9.3.3') do
end
assert('Float#/', '15.2.9.3.4') do
- a = 3.123456789 / 3.123456789
- b = 3.123456789 / 1
-
- assert_float(1.0 , a)
- assert_float(3.123456789, b)
+ assert_float(1.0, 3.123456789 / 3.123456789)
+ assert_float(3.123456789, 3.123456789 / 1)
+ assert_float(2.875, -5.75 / -2.0)
+ assert_float(-2.875, 5.75 / -2)
+ assert_float(-2.875, -5.75 / 2.0)
+ assert_float(Float::NAN, 0.0 / 0.0)
+ assert_float(Float::NAN, -0.0 / -0.0)
+ assert_float(Float::NAN, -0.0 / 0.0)
+ assert_float(Float::NAN, Float::NAN / Float::NAN)
+ assert_float(Float::NAN, Float::NAN / 0.0)
+ assert_float(Float::NAN, Float::NAN / -0.0)
+ assert_float(Float::NAN, Float::NAN / 2.0)
+ assert_float(Float::NAN, Float::NAN / -2.0)
+ assert_float(Float::NAN, 0.0 / Float::NAN)
+ assert_float(Float::NAN, -0.0 / Float::NAN)
+ assert_float(Float::NAN, 2.0 / Float::NAN)
+ assert_float(Float::NAN, -2.0 / Float::NAN)
+ assert_float(Float::NAN, Float::INFINITY / Float::INFINITY)
+ assert_float(Float::NAN, -Float::INFINITY / Float::INFINITY)
+ assert_float(Float::NAN, Float::INFINITY / -Float::INFINITY)
+ assert_float(Float::NAN, -Float::INFINITY / -Float::INFINITY)
+ assert_float(Float::INFINITY, 1.0 / 0.0)
+ assert_float(Float::INFINITY, -1.0 / -0.0)
+ assert_float(-Float::INFINITY, 1.0 / -0.0)
+ assert_float(-Float::INFINITY, -1.0 / 0.0)
+ assert_float(0.0, 1.0 / Float::INFINITY)
+ assert_float(0.0, -1.0 / -Float::INFINITY)
+ assert_float(-0.0, -1.0 / Float::INFINITY)
+ assert_float(-0.0, 1.0 / -Float::INFINITY)
+end
+assert('Float#quo') do
+ assert_float(1.0, 3.123456789.quo(3.123456789))
+ assert_float(3.123456789, 3.123456789.quo(1))
+ assert_float(2.875, -5.75.quo(-2.0))
+ assert_float(-2.875, 5.75.quo(-2))
+ assert_float(-2.875, -5.75.quo(2.0))
+ assert_float(Float::NAN, 0.0.quo(0.0))
+ assert_float(Float::NAN, -0.0.quo(-0.0))
+ assert_float(Float::NAN, -0.0.quo(0.0))
+ assert_float(Float::NAN, Float::NAN.quo(Float::NAN))
+ assert_float(Float::NAN, Float::NAN.quo(0.0))
+ assert_float(Float::NAN, Float::NAN.quo(-0.0))
+ assert_float(Float::NAN, Float::NAN.quo(2.0))
+ assert_float(Float::NAN, Float::NAN.quo(-2.0))
+ assert_float(Float::NAN, 0.0.quo(Float::NAN))
+ assert_float(Float::NAN, -0.0.quo(Float::NAN))
+ assert_float(Float::NAN, 2.0.quo(Float::NAN))
+ assert_float(Float::NAN, -2.0.quo(Float::NAN))
+ assert_float(Float::NAN, Float::INFINITY.quo(Float::INFINITY))
+ assert_float(Float::NAN, -Float::INFINITY.quo(Float::INFINITY))
+ assert_float(Float::NAN, Float::INFINITY.quo(-Float::INFINITY))
+ assert_float(Float::NAN, -Float::INFINITY.quo(-Float::INFINITY))
+ assert_float(Float::INFINITY, 1.0.quo(0.0))
+ assert_float(Float::INFINITY, -1.0.quo(-0.0))
+ assert_float(-Float::INFINITY, 1.0.quo(-0.0))
+ assert_float(-Float::INFINITY, -1.0.quo(0.0))
+ assert_float(0.0, 1.0.quo(Float::INFINITY))
+ assert_float(0.0, -1.0.quo(-Float::INFINITY))
+ assert_float(-0.0, -1.0.quo(Float::INFINITY))
+ assert_float(-0.0, 1.0.quo(-Float::INFINITY))
end
assert('Float#%', '15.2.9.3.5') do
@@ -82,8 +137,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 +194,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 +233,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
@@ -206,4 +261,48 @@ assert('Float#>>') do
assert_equal(-1, -23.0 >> 128)
end
-end # class_defined?("Float")
+assert('Float#to_s') do
+ uses_float = 4e38.infinite? # enable MRB_USE_FLOAT32?
+
+ 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("-3.25", -3.25.to_s)
+ assert_equal("50.0", 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)
+ assert_equal("-1.0e-10", -0.0000000001.to_s)
+ assert_equal("1.0e+20", 1e20.to_s)
+ 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)
+ if uses_float
+ assert_equal("1.0e+08", 100000000.0.to_s)
+ assert_equal("-1.0e+08", -100000000.0.to_s)
+ assert_equal("1.0e+07", 10000000.0.to_s)
+ assert_equal("-1.0e+07", -10000000.0.to_s)
+ 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)
+ end
+end
+
+assert('Float#inspect') do
+ assert_equal("-3.25", -3.25.inspect)
+ assert_equal("50.0", 50.0.inspect)
+end
+
+assert('Float#eql?') do
+ 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 8088bfa21..9bc2668ae 100644
--- a/test/t/hash.rb
+++ b/test/t/hash.rb
@@ -1,375 +1,1008 @@
##
# Hash ISO Test
-assert('Hash', '15.2.13') do
- assert_equal Class, Hash.class
-end
+class HashKey
+ attr_accessor :value, :error, :callback
-assert('Hash#==', '15.2.13.4.1') do
- assert_true({ 'abc' => 'abc' } == { 'abc' => 'abc' })
- assert_false({ 'abc' => 'abc' } == { 'cba' => 'cba' })
- assert_true({ :equal => 1 } == { :equal => 1.0 }) if class_defined?("Float")
- assert_false({ :a => 1 } == true)
-end
+ self.class.alias_method :[], :new
-assert('Hash#[]', '15.2.13.4.2') do
- a = { 'abc' => 'abc' }
+ def initialize(value, error: nil, callback: nil)
+ @value = value
+ @error = error
+ @callback = callback
+ end
- assert_equal 'abc', a['abc']
+ def ==(other)
+ @callback.(:==, self, other) if @callback
+ return raise_error(:==) if @error == true || @error == :==
+ other.kind_of?(self.class) && @value == other.value
+ end
- # Hash#[] should call #default (#3272)
- hash = {}
- def hash.default(k); self[k] = 1; end
- hash[:foo] += 1
+ def eql?(other)
+ @callback.(:eql?, self, other) if @callback
+ return raise_error(:eql?) if @error == true || @error == :eql?
+ other.kind_of?(self.class) && @value.eql?(other.value)
+ end
- assert_equal 2, hash[:foo]
-end
+ def hash
+ @callback.(:hash, self) if @callback
+ return raise_error(:hash) if @error == true || @error == :hash
+ @value % 3
+ end
-assert('Hash#[]=', '15.2.13.4.3') do
- a = Hash.new
- a['abc'] = 'abc'
+ def to_s
+ "#{self.class}[#{@value}]"
+ end
+ alias inspect to_s
- assert_equal 'abc', a['abc']
+ def raise_error(name)
+ raise "##{self}: #{name} error"
+ end
end
-assert('Hash#clear', '15.2.13.4.4') do
- a = { 'abc' => 'abc' }
- a.clear
-
- assert_equal({ }, a)
+class HashEntries < Array
+ self.class.alias_method :[], :new
+
+ def initialize(entries) self.replace(entries) end
+ def key(index, k=get=true) get ? self[index][0] : (self[index][0] = k) end
+ def value(index, v=get=true) get ? self[index][1] : (self[index][1] = v) end
+ def keys; map{|k, v| k} end
+ def values; map{|k, v| v} end
+ def each_key(&block) each{|k, v| block.(k)} end
+ def each_value(&block) each{|k, v| block.(v)} end
+ def dup2; self.class[*map{|k, v| [k.dup, v.dup]}] end
+ def to_s; "#{self.class}#{super}" end
+ alias inspect to_s
+
+ def hash_for(hash={}, &block)
+ each{|k, v| hash[k] = v}
+ block.(hash) if block
+ hash
+ end
end
-assert('Hash#dup') do
- a = { 'a' => 1 }
- b = a.dup
- a['a'] = 2
- assert_equal({'a' => 1}, b)
-
- c = Hash.new { |h, k| h[k] = k.upcase }
- d = c.dup
- assert_equal("FOO", d["foo"])
+def ar_entries
+ HashEntries[
+ [1, "one"],
+ [HashKey[2], :two],
+ [nil, :two],
+ [:one, 1],
+ ["&", "&amp;"],
+ [HashKey[6], :six],
+ [HashKey[5], :five], # same hash code as HashKey[2]
+ ]
+end
+
+def ht_entries
+ ar_entries.dup.push(
+ ["id", 32],
+ [:date, "2020-05-02"],
+ [200, "OK"],
+ ["modifiers", ["left_shift", "control"]],
+ [:banana, :yellow],
+ ["JSON", "JavaScript Object Notation"],
+ [:size, :large],
+ ["key_code", "h"],
+ ["h", 0x04],
+ [[3, 2, 1], "three, two, one"],
+ [:auto, true],
+ [HashKey[12], "December"],
+ [:path, "/path/to/file"],
+ [:name, "Ruby"],
+ )
+end
+
+def merge_entries!(entries1, entries2)
+ entries2.each do |k2, v2|
+ entry1 = entries1.find{|k1, _| k1.eql?(k2)}
+ entry1 ? (entry1[1] = v2) : (entries1 << [k2, v2])
+ end
+ entries1
+end
+
+def product(*arrays, &block)
+ sizes = Array.new(arrays.size+1, 1)
+ (arrays.size-1).downto(0){|i| sizes[i] = arrays[i].size * sizes[i+1]}
+ size = sizes[0]
+ results = Array.new(size){[]}
+ arrays.each_with_index do |array, arrays_i|
+ results_i = -1
+ (size / sizes[arrays_i]).times do
+ array.each do |v|
+ sizes[arrays_i+1].times{results[results_i+=1] << v}
+ end
+ end
+ end
+ results.each{block.(_1)}
end
-assert('Hash#default', '15.2.13.4.5') do
- a = Hash.new
- b = Hash.new('abc')
- c = Hash.new {|s,k| s[k] = k}
-
- assert_nil a.default
- assert_equal 'abc', b.default
- assert_nil c.default
- assert_equal 'abc', c.default('abc')
+def assert_iterator(exp, obj, meth)
+ params = []
+ obj.__send__(meth) {|param| params << param}
+ assert_equal(exp, params)
end
-assert('Hash#default=', '15.2.13.4.6') do
- a = { 'abc' => 'abc' }
- a.default = 'cba'
-
- assert_equal 'abc', a['abc']
- assert_equal 'cba', a['notexist']
+def assert_nothing_crashed(&block)
+ block.call rescue nil
+ pass
end
-assert('Hash#default_proc', '15.2.13.4.7') do
- a = Hash.new
- b = Hash.new {|s,k| s[k] = k + k}
- c = b[2]
- d = b['cat']
-
- assert_nil a.default_proc
- assert_equal Proc, b.default_proc.class
- assert_equal 4, c
- assert_equal 'catcat', d
+assert('Hash', '15.2.13') do
+ assert_equal(Class, Hash.class)
+end
+
+[[:==, '15.2.13.4.1'], [:eql?, '']].each do |meth, iso|
+ assert("Hash##{meth}", iso) do
+ cls = Class.new(Hash){attr_accessor :foo}
+ [ar_entries, ht_entries].each do |entries|
+ h1 = entries.hash_for
+ h2 = entries.dup.reverse!.hash_for
+ assert_operator(h1, meth, h2)
+ assert_operator(h1, meth, h1)
+ assert_not_operator(h1, meth, true)
+ assert_operator({}, meth, Hash.new)
+
+ h1 = entries.hash_for(cls.new(1)) {|h| h.foo = 1}
+ h2 = entries.hash_for(cls.new(2)) {|h| h.foo = 2}
+ assert_operator(h1, meth, h2)
+
+ h1 = entries.hash_for
+ h2 = entries.hash_for(cls.new)
+ assert_operator(h1, meth, h2)
+
+ h1 = (entries.dup << [:_k, 1]).hash_for
+ h2 = (entries.dup << [:_k, 2]).hash_for
+ assert_not_operator(h1, meth, h2)
+
+ h1 = (entries.dup << [:_k1, 0]).hash_for
+ h2 = (entries.dup << [:_k2, 0]).hash_for
+ assert_not_operator(h1, meth, h2)
+
+ h1 = entries.hash_for
+ h2 = (entries.dup << [:_k, 2]).hash_for
+ assert_not_operator(h1, meth, h2)
+
+ k1, v1 = HashKey[-1], HashKey[-2]
+ k2, v2 = HashKey[-1], HashKey[-2]
+ h1 = (entries.dup << [k1, v1]).hash_for
+ h2 = (entries.dup << [k2, v2]).hash_for
+ product([h1, h2], [k1, k2], %i[eql? hash]) do |h, k, m|
+ [k1, k2].each{_1.callback = nil}
+ k.callback = ->(name, *){h.clear if name == m}
+ assert_nothing_crashed{h1.__send__(meth, h2)}
+ end
+ product([h1, h2], [v1, v2]) do |h, v|
+ [v1, v2].each{_1.callback = nil}
+ v.callback = ->(name, *){h.clear if name == meth}
+ assert_nothing_crashed{h1.__send__(meth, h2)}
+ end
+
+ if Object.const_defined?(:Float)
+ h1 = (entries.dup << [-1, true]).hash_for
+ h2 = (entries.dup << [-1.0, true]).hash_for
+ assert_not_operator(h1, meth, h2)
+ h1 = (entries.dup << [-1.0, true]).hash_for
+ h2 = (entries.dup << [-1, true]).hash_for
+ assert_not_operator(h1, meth, h2)
+
+ h1 = (entries.dup << [:_k, 1]).hash_for
+ h2 = (entries.dup << [:_k, 1.0]).hash_for
+ if meth == :==
+ assert_operator(h1, meth, h2)
+ else
+ assert_not_operator(h1, meth, h2)
+ end
+ end
+ end
+ end
end
-assert('Hash#delete', '15.2.13.4.8') do
- a = { 'abc' => 'ABC' }
- b = { 'abc' => 'ABC' }
- b_tmp_1 = false
- b_tmp_2 = false
-
- assert_equal 'ABC', a.delete('abc')
- b.delete('abc') do |k|
- b_tmp_1 = true
- end
- b.delete('abc') do |k|
- b_tmp_2 = true
+assert('Hash#[]', '15.2.13.4.2') do
+ [ar_entries, ht_entries].each do |entries|
+ h = entries.hash_for
+ assert_equal(entries.size, h.size)
+ entries.each{|k, v| assert_equal(v, h[k])}
+ assert_equal(nil, h["_not_found_"])
+ assert_equal(nil, h[:_not_dound_])
+ assert_equal(nil, h[-2])
+
+ k = HashKey[-4]
+ h[HashKey[-1]] = -1
+ h[k] = -4
+ h.delete(k)
+ assert_equal(nil, h[k])
+
+ if Object.const_defined?(:Float)
+ h[-2] = 22
+ assert_equal(nil, h[-2.0])
+ h[-3.0] = 33
+ assert_equal(nil, h[-3])
+ assert_equal(33, h[-3.0])
+ end
+
+ k = HashKey[-2]
+ k.callback = ->(name, *){h.clear if name == :eql?}
+ assert_nothing_crashed{h[k]}
+ k.callback = ->(name, *){h.clear if name == :hash}
+ assert_nothing_crashed{h[k]}
end
- assert_nil a.delete('cba')
- assert_false a.has_key?('abc')
- assert_false b_tmp_1
- assert_true b_tmp_2
+ # Hash#[] should call #default (#3272)
+ h = {}
+ def h.default(k); self[k] = 1; end
+ h[:foo] += 1
+ assert_equal(2, h[:foo])
+end
+
+[%w[[]= 3], %w[store 26]].each do |meth, no|
+ assert("Hash##{meth}", "15.2.13.4.#{no}") do
+ [{}, ht_entries.hash_for].each do |h|
+ # duplicated key
+ k = :_dup_key
+ h.__send__(meth, k, 1)
+ size = h.size
+ h.__send__(meth, k, 2)
+ assert_equal(size, h.size)
+ assert_equal(2, h[k])
+
+ # freeze string key
+ k = "_mutable"
+ h.__send__(meth, k, 1)
+ h_k = h.keys[-1]
+ assert_not_same(k, h_k)
+ assert_predicate(h_k, :frozen?)
+ assert_not_predicate(k, :frozen?)
+
+ # frozen string key
+ k = "_immutable".freeze
+ h.__send__(meth, k, 2)
+ h_k = h.keys[-1]
+ assert_same(k, h_k)
+ assert_predicate(h_k, :frozen?)
+
+ # numeric key
+ if Object.const_defined?(:Float)
+ h.__send__(meth, 3, :fixnum)
+ h.__send__(meth, 3.0, :float)
+ assert_equal(:fixnum, h[3])
+ assert_equal(:float, h[3.0])
+ h.__send__(meth, 4.0, :float)
+ h.__send__(meth, 4, :fixnum)
+ assert_equal(:fixnum, h[4])
+ assert_equal(:float, h[4.0])
+ end
+
+ # other key
+ k = [:_array]
+ h.__send__(meth, k, :_array)
+ h_k = h.keys[-1]
+ assert_same(k, h_k)
+ assert_not_predicate(h_k, :frozen?)
+ assert_not_predicate(k, :frozen?)
+
+ # deleted key
+ k1, k2, k3 = HashKey[-1], HashKey[-4], HashKey[-7] # same hash code
+ h.__send__(meth, k1, 1)
+ h.__send__(meth, k2, -4)
+ h.__send__(meth, k3, 73)
+ size = h.size
+ h.delete(k1)
+ h.delete(k2)
+ h.__send__(meth, k2, 40)
+ assert_equal(nil, h[k1])
+ assert_equal(40, h[k2])
+ assert_equal(73, h[k3])
+ assert_equal(size - 1, h.size)
+
+ # frozen
+ h.freeze
+ assert_raise(FrozenError){h.__send__(meth, -100, 1)}
+ end
+
+ [ar_entries.hash_for, ht_entries.hash_for].each do |h|
+ k = HashKey[-2]
+ k.callback = ->(name, *){h.clear if name == :eql?}
+ assert_nothing_crashed{h.__send__(meth, k, 2)}
+ k.callback = ->(name, *){h.clear if name == :hash}
+ assert_nothing_crashed{h.__send__(meth, k, 2)}
+ end
+ end
end
-assert('Hash#each', '15.2.13.4.9') do
- a = { 'abc_key' => 'abc_value' }
- key = nil
- value = nil
-
- a.each do |k,v|
- key = k
- value = v
+assert('Hash#clear', '15.2.13.4.4') do
+ [ar_entries, ht_entries].each do |entries|
+ h = entries.hash_for
+ assert_same(h, h.clear)
+ assert_equal(0, h.size)
+ assert_nil(h[entries.key(3)])
+
+ h.freeze
+ assert_raise(FrozenError){h.clear}
end
- assert_equal 'abc_key', key
- assert_equal 'abc_value', value
+ h = {}.freeze
+ assert_raise(FrozenError){h.clear}
end
-assert('Hash#each_key', '15.2.13.4.10') do
- a = { 'abc_key' => 'abc_value' }
- key = nil
-
- a.each_key do |k|
- key = k
+assert('Hash#dup') do
+ cls = Class.new(Hash){attr_accessor :foo}
+ [ar_entries, ht_entries].each do |entries|
+ h1 = entries.hash_for(cls.new(61)){|h| h.foo = 23}.freeze
+ h2 = h1.dup
+ assert_not_predicate(h2, :frozen?)
+ assert_equal(h1.class, h2.class)
+ assert_equal(entries, h2.to_a)
+ assert_equal(23, h2.foo)
+ assert_equal(61, h2["_not_found_"])
+ h2[-10] = 10
+ assert_equal(10, h2[-10])
+ assert_not_operator(h1, :key?, -10)
+
+ h = entries.hash_for
+ k = HashKey[-1]
+ h[k] = 1
+ k.callback = ->(*){h.clear}
+ assert_nothing_crashed{h.dup}
end
-
- assert_equal 'abc_key', key
end
-assert('Hash#each_value', '15.2.13.4.11') do
- a = { 'abc_key' => 'abc_value' }
- value = nil
-
- a.each_value do |v|
- value = v
+assert('Hash#default', '15.2.13.4.5') do
+ [ar_entries, ht_entries].each do |entries|
+ h = entries.hash_for(Hash.new)
+ assert_equal(nil, h.default)
+ assert_equal(nil, h.default(-2))
+
+ h = entries.hash_for(Hash.new(-88))
+ assert_equal(-88, h.default)
+ assert_equal(-88, h.default(-2))
+ assert_not_operator(h, :key?, -2)
+ assert_raise(ArgumentError){h.default(-2,-2)}
+
+ proc = ->(h, k){h[k] = k * 3}
+ h = entries.hash_for(Hash.new(proc))
+ assert_equal(proc, h.default(-2))
+
+ h = entries.hash_for(Hash.new(&proc))
+ assert_equal(nil, h.default)
+ assert_not_operator(h, :key?, -2)
+ assert_equal(-6, h.default(-2))
+ assert_equal(-6, h[-2])
+ h[-2] = -5
+ assert_equal(-6, h.default(-2))
+ assert_equal(-6, h[-2])
end
-
- assert_equal 'abc_value', value
end
-assert('Hash#empty?', '15.2.13.4.12') do
- a = { 'abc_key' => 'abc_value' }
- b = Hash.new
-
- assert_false a.empty?
- assert_true b.empty?
-end
+assert('Hash#default=', '15.2.13.4.6') do
+ [ar_entries, ht_entries].each do |entries|
+ h = entries.hash_for(Hash.new)
+ h.default = 3
+ assert_equal(3, h[-2])
+ assert_equal(entries.value(0), h[entries.key(0)])
-assert('Hash#has_key?', '15.2.13.4.13') do
- a = { 'abc_key' => 'abc_value' }
- b = Hash.new
+ h.default = 4
+ assert_equal(4, h[-2])
- assert_true a.has_key?('abc_key')
- assert_false b.has_key?('cba')
-end
+ h.default = nil
+ assert_equal(nil, h[-2])
-assert('Hash#has_value?', '15.2.13.4.14') do
- a = { 'abc_key' => 'abc_value' }
- b = Hash.new
+ h.default = [5]
+ assert_same(h[-2], h[-3])
- assert_true a.has_value?('abc_value')
- assert_false b.has_value?('cba')
+ h.freeze
+ assert_raise(FrozenError){h.default = 3}
+ end
end
-assert('Hash#include?', '15.2.13.4.15') do
- a = { 'abc_key' => 'abc_value' }
- b = Hash.new
-
- assert_true a.include?('abc_key')
- assert_false b.include?('cba')
+assert('Hash#default_proc', '15.2.13.4.7') do
+ [ar_entries, ht_entries].each do |entries|
+ h = entries.hash_for({})
+ assert_nil(h.default_proc)
+
+ h = entries.hash_for(Hash.new(34))
+ assert_nil(h.default_proc)
+
+ h = entries.hash_for(Hash.new{|h, k| h[k] = k * 3})
+ proc = h.default_proc
+ assert_equal(Proc, proc.class)
+ assert_equal(6, proc.(h, 2))
+ assert_equal([2, 6], h.to_a[-1])
+ end
end
-assert('Hash#initialize', '15.2.13.4.16') do
- # Testing initialize by new.
- h = Hash.new
- h2 = Hash.new(:not_found)
-
- assert_true h.is_a? Hash
- assert_equal({ }, h)
- assert_nil h["hello"]
- assert_equal :not_found, h2["hello"]
-end
+assert('Hash#delete', '15.2.13.4.8') do
+ [ar_entries, ht_entries].each do |entries|
+ h = entries.hash_for
+ pairs = entries.dup
+ [0, 2, -1].each do |i|
+ k, v = pairs.delete_at(i)
+ assert_equal(v, h.delete(k))
+ assert_equal(nil, h[k])
+ assert_equal(false, h.key?(k))
+ end
+ [entries.key(0), "_not_found_"].each {|k|assert_equal(nil, h.delete(k))}
+ assert_equal(pairs.size, h.size)
+ assert_equal(pairs, h.to_a)
+ pairs.each {|k, v| assert_equal(v, h[k])}
+
+ h = entries.hash_for
+ pairs = entries.dup
+ [pairs.delete_at(1), ["_not_found_", "_default"]].each do |k, v|
+ assert_equal(v, h.delete(k){"_default"})
+ assert_equal(nil, h[k])
+ assert_equal(false, h.key?(k))
+ end
+ assert_equal(pairs.size, h.size)
+ assert_equal(pairs, h.to_a)
+ pairs.each {|k, v| assert_equal(v, h[k])}
+
+ if Object.const_defined?(:Float)
+ h = entries.dup.push([-5, 1], [-5.0, 2], [-6.0, 3], [-6, 4]).hash_for
+ assert_equal(1, h.delete(-5))
+ assert_equal(3, h.delete(-6.0))
+ end
+
+ # nil value with block
+ h = entries.hash_for
+ k = "_nil"
+ h[k] = nil
+ assert_equal(nil, h.delete(k){"blk"})
+ assert_equal(false, h.key?(k))
+
+ k = HashKey[-31, callback: ->(*){h.clear}]
+ assert_nothing_crashed{h.delete(k)}
+ end
-assert('Hash#initialize_copy', '15.2.13.4.17') do
- a = { 'abc_key' => 'abc_value' }
- b = Hash.new.initialize_copy(a)
+ assert_raise(ArgumentError){{}.delete}
+ assert_raise(ArgumentError){{}.delete(1,2)}
- assert_equal({ 'abc_key' => 'abc_value' }, b)
+ h = {}.freeze
+ assert_raise(FrozenError){h.delete(1)}
+end
+
+[%w[each 9], %w[each_key 10], %w[each_value 11]].each do |meth, no|
+ assert("Hash##{meth}", "15.2.13.4.#{no}") do
+ [ar_entries, ht_entries].each do |entries|
+ exp = []
+ entries.__send__(meth){|param| exp << param}
+ assert_iterator(exp, entries.hash_for, meth)
+
+ h = entries.hash_for
+ entries.shift
+ h.shift
+ entry = entries.delete_at(1)
+ h.delete(entry[0])
+ h.delete(entries.delete_at(-4)[0])
+ entries << entry
+ h.store(*entry)
+ exp = []
+ entries.__send__(meth){|param| exp << param}
+ assert_iterator(exp, h, meth)
+ end
+
+ assert_iterator([], {}, meth)
+ end
end
-assert('Hash#key?', '15.2.13.4.18') do
- a = { 'abc_key' => 'abc_value' }
- b = Hash.new
+assert('Hash#empty?', '15.2.13.4.12') do
+ [ar_entries, ht_entries].each do |entries|
+ assert_not_predicate entries.hash_for, :empty?
- assert_true a.key?('abc_key')
- assert_false b.key?('cba')
-end
+ h = entries.hash_for
+ h.shift
+ h.delete(entries.key(-1))
+ assert_not_predicate h, :empty?
-assert('Hash#keys', '15.2.13.4.19') do
- a = { 'abc_key' => 'abc_value' }
+ h = entries.hash_for
+ entries.size.times{h.shift}
+ assert_predicate(h, :empty?)
- assert_equal ['abc_key'], a.keys
-end
-
-assert('Hash#length', '15.2.13.4.20') do
- a = { 'abc_key' => 'abc_value' }
- b = Hash.new
+ h = entries.hash_for
+ entries.each {|k, v| h.delete(k)}
+ assert_predicate(h, :empty?)
+ end
- assert_equal 1, a.length
- assert_equal 0, b.length
+ assert_predicate(Hash.new, :empty?)
+ assert_predicate(Hash.new(1), :empty?)
+ assert_predicate(Hash.new{|h, k| h[k] = 2}, :empty?)
end
-assert('Hash#member?', '15.2.13.4.21') do
- a = { 'abc_key' => 'abc_value' }
- b = Hash.new
-
- assert_true a.member?('abc_key')
- assert_false b.member?('cba')
-end
+[%w[has_key? 13], %w[include? 15], %w[key? 18], %w[member? 21]].each do |meth,no|
+ assert("Hash##{meth}", "15.2.13.4.#{no}") do
+ [ar_entries, ht_entries].each do |entries|
+ pairs = entries.dup.push([HashKey[-3], 3], [nil, "NIL"])
+ h = pairs.hash_for
+ pairs.each{|k, v| assert_operator(h, meth, k)}
+ assert_not_operator(h, meth, HashKey[-6])
+ assert_not_operator(h, meth, 3)
-assert('Hash#merge', '15.2.13.4.22') do
- a = { 'abc_key' => 'abc_value', 'cba_key' => 'cba_value' }
- b = { 'cba_key' => 'XXX', 'xyz_key' => 'xyz_value' }
+ if Object.const_defined?(:Float)
+ hh = entries.push([-7, :i], [-8.0, :f]).hash_for
+ assert_not_operator(hh, meth, -7.0)
+ assert_not_operator(hh, meth, -8)
+ assert_operator(hh, meth, -8.0)
+ end
- result_1 = a.merge b
- result_2 = a.merge(b) do |key, original, new|
- original
- end
+ h.shift
+ assert_not_operator(h, meth, pairs.key(0))
- assert_equal({'abc_key' => 'abc_value', 'cba_key' => 'XXX',
- 'xyz_key' => 'xyz_value' }, result_1)
- assert_equal({'abc_key' => 'abc_value', 'cba_key' => 'cba_value',
- 'xyz_key' => 'xyz_value' }, result_2)
+ h.delete(pairs.key(3))
+ assert_not_operator(h, meth, pairs.key(3))
- assert_raise(TypeError) do
- { 'abc_key' => 'abc_value' }.merge "a"
+ k = HashKey[-31, callback: ->(*){h.clear}]
+ assert_nothing_crashed{h.__send__(meth, k)}
+ end
end
-end
-assert('Hash#replace', '15.2.13.4.23') do
- a = { 'abc_key' => 'abc_value' }
- b = Hash.new.replace(a)
+ h = Hash.new{|h, k| h[1] = 1}
+ assert_not_operator(h, meth, 1)
+end
- assert_equal({ 'abc_key' => 'abc_value' }, b)
+[%w[has_value? 14], %w[value? 24]].each do |meth, no|
+ assert("Hash##{meth}", "15.2.13.4.#{no}") do
+ [ar_entries, ht_entries].each do |entries|
+ entries.push([HashKey[-5], -8], ["NIL", nil])
+ h = entries.hash_for
+ entries.each{|k, v| assert_operator(h, meth, v)}
+ assert_operator(h, meth, -8.0) if Object.const_defined?(:Float)
+ assert_not_operator(h, meth, "-8")
- a = Hash.new(42)
- b = {}
- b.replace(a)
- assert_equal(42, b[1])
+ h.shift
+ assert_not_operator(h, meth, entries.value(0))
- a = Hash.new{|h,x| x}
- b.replace(a)
- assert_equal(127, b[127])
+ h.delete(entries.key(3))
+ assert_not_operator(h, meth, entries.value(3))
- assert_raise(TypeError) do
- { 'abc_key' => 'abc_value' }.replace "a"
+ v = HashKey[-31, callback: ->(*){h.clear}]
+ assert_nothing_crashed{h.__send__(meth, v)}
+ end
end
-end
-
-assert('Hash#shift', '15.2.13.4.24') do
- a = { 'abc_key' => 'abc_value', 'cba_key' => 'cba_value' }
- b = a.shift
-
- assert_equal Array, b.class
- assert_equal 2, b.size
- assert_equal 1, a.size
- b = a.shift
-
- assert_equal Array, b.class
- assert_equal 2, b.size
- assert_equal 0, a.size
+ h = Hash.new{|h, k| h[1] = 1}
+ assert_not_operator(h, meth, 1)
end
-assert('Hash#size', '15.2.13.4.25') do
- a = { 'abc_key' => 'abc_value' }
- b = Hash.new
-
- assert_equal 1, a.size
- assert_equal 0, b.size
+assert('Hash#initialize', '15.2.13.4.16') do
+ h = Hash.new
+ assert_equal(Hash, h.class)
+ assert_not_operator(h, :key?, 1)
+ assert_equal(nil, h[1])
+
+ h = Hash.new([8])
+ assert_not_operator(h, :key?, 1)
+ assert_equal([8], h[1])
+ assert_same(h[1], h[2])
+
+ k = "key"
+ h = Hash.new{|hash, key| [hash, key]}
+ assert_not_operator(h, :key?, k)
+ assert_equal([h, k], h[k])
+ assert_same(h, h[k][0])
+ assert_same(k, h[k][1])
+
+ assert_raise(ArgumentError){Hash.new(1,2)}
+ assert_raise(ArgumentError){Hash.new(1){}}
+end
+
+[%w[keys 19], %w[values 28]].each do |meth, no|
+ assert("Hash##{meth}", "15.2.13.4.#{no}") do
+ [ar_entries, ht_entries].each do |entries|
+ h = entries.hash_for
+ assert_equal(entries.__send__(meth), h.__send__(meth))
+
+ h.shift
+ entries.shift
+ h.delete(entries.delete_at(3)[0])
+ assert_equal(entries.__send__(meth), h.__send__(meth))
+ end
+
+ assert_equal([], {}.__send__(meth))
+ end
end
-assert('Hash#store', '15.2.13.4.26') do
- a = Hash.new
- a.store('abc', 'abc')
+[%w[length 20], %w[size 25]].each do |meth, no|
+ assert("Hash##{meth}", "15.2.13.4.#{no}") do
+ [ar_entries, ht_entries].each do |entries|
+ h = entries.hash_for
+ assert_equal(entries.size, h.__send__(meth))
+
+ h.shift
+ entries.shift
+ h.delete(entries.delete_at(3)[0])
+ assert_equal(entries.size, h.__send__(meth))
+ end
- assert_equal 'abc', a['abc']
+ assert_equal(0, Hash.new.__send__(meth))
+ end
end
-assert('Hash#value?', '15.2.13.4.27') do
- a = { 'abc_key' => 'abc_value' }
- b = Hash.new
+assert('Hash#merge', '15.2.13.4.22') do
+ cls = Class.new(Hash){attr_accessor :foo}
+ ar_pairs = HashEntries[
+ ["id", 32],
+ [nil, :two],
+ ["&", "&amp;"],
+ [:same_key, :AR],
+ [HashKey[2], 20],
+ ]
+ ht_pairs = HashEntries[
+ *(1..20).map{[_1, _1.to_s]},
+ [:same_key, :HT],
+ [:age, 32],
+ [HashKey[5], 500],
+ ]
+
+ [[ar_pairs, ht_pairs], [ht_pairs, ar_pairs]].each do |entries1, entries2|
+ h1 = entries1.hash_for(cls.new(:dv1)){|h| h.foo = :iv1}.freeze
+ h2 = entries2.hash_for(Hash.new(:dv2)).freeze
+ h3 = h1.merge(h2)
+ assert_equal(entries1, h1.to_a)
+ assert_equal(merge_entries!(entries1.dup2, entries2), h3.to_a)
+ assert_equal(cls, h3.class)
+ assert_equal(:dv1, h3.default)
+ assert_equal(:iv1, h3.foo)
+
+ h3 = {}.merge(entries2.hash_for(cls.new))
+ assert_equal(merge_entries!([], entries2), h3.to_a)
+ assert_equal(Hash, h3.class)
+
+ h3 = entries1.hash_for.merge({})
+ assert_equal(merge_entries!(entries1.dup2, []), h3.to_a)
+
+ h1 = entries1.hash_for
+ h2 = entries2.hash_for
+ h3 = h1.merge(h2){|k, v1, v2| [k, v1, v2]}
+ exp = merge_entries!(entries1.dup2, entries2)
+ exp.find{|k, _| k == :same_key}[1] = [
+ :same_key,
+ entries1.find{|k, _| k == :same_key}[1],
+ entries2.find{|k, _| k == :same_key}[1],
+ ]
+ assert_equal(exp, h3.to_a)
+
+ assert_raise(TypeError){entries1.hash_for.merge("str")}
+
+ k2 = HashKey[-2]
+ entries2 << [k2, 234]
+ h1, h2 = entries1.hash_for, entries2.hash_for
+ k2.callback = ->(name, *){h1.clear if name == :eql?}
+ assert_nothing_crashed{h1.merge(h2)}
+ h1, h2 = entries1.hash_for, entries2.hash_for
+ k2.callback = ->(name, *){h2.clear if name == :eql?}
+ assert_nothing_crashed{h1.merge(h2)}
+ h1, h2 = entries1.hash_for, entries2.hash_for
+ k2.callback = ->(name, *){h1.clear if name == :hash}
+ assert_nothing_crashed{h1.merge(h2)}
+ h1, h2 = entries1.hash_for, entries2.hash_for
+ k2.callback = ->(name, *){h2.clear if name == :hash}
+ assert_nothing_crashed{h1.merge(h2)}
+ end
+end
- assert_true a.value?('abc_value')
- assert_false b.value?('cba')
+assert("Hash#replace", "15.2.13.4.23") do
+ cls = Class.new(Hash){attr_accessor :foo}
+ e = [ar_entries, ht_entries]
+ [e, e.reverse].each do |entries1, entries2|
+ h1 = entries1.hash_for
+ assert_same(h1, h1.replace(h1))
+ assert_equal(entries1, h1.to_a)
+
+ h1 = {}
+ assert_same(h1, h1.replace(entries2.hash_for))
+ assert_equal(entries2, h1.to_a)
+
+ h1 = entries1.hash_for
+ assert_same(h1, h1.replace({}))
+ assert_predicate(h1, :empty?)
+
+ pairs2 = entries2.dup
+ h2 = pairs2.hash_for
+ pairs2.shift
+ h2.shift
+ h2.delete(pairs2.delete_at(2)[0])
+ h2.delete(pairs2.delete_at(4)[0])
+ h1 = entries1.hash_for
+ assert_same(h1, h1.replace(h2))
+ assert_equal(pairs2, h1.to_a)
+
+ h1 = entries1.hash_for(Hash.new(10))
+ h2 = entries2.hash_for(Hash.new(20))
+ assert_same(h1, h1.replace(h2))
+ assert_equal(entries2, h1.to_a)
+ assert_equal(20, h1.default)
+
+ h1 = entries1.hash_for(Hash.new{_2})
+ h2 = entries2.hash_for(Hash.new{_2.to_s})
+ assert_same(h1, h1.replace(h2))
+ assert_equal(entries2, h1.to_a)
+ assert_equal("-11", h1[-11])
+
+ h1 = entries1.hash_for(Hash.new(10))
+ h2 = entries2.hash_for(Hash.new{_2.to_s})
+ assert_same(h1, h1.replace(h2))
+ assert_equal(entries2, h1.to_a)
+ assert_equal("-11", h1[-11])
+
+ h1 = entries1.hash_for(Hash.new{_2})
+ h2 = entries2.hash_for(Hash.new(20))
+ assert_same(h1, h1.replace(h2))
+ assert_equal(entries2, h1.to_a)
+ assert_equal(20, h1[-1])
+
+ h1 = entries1.hash_for(cls.new(10)){|h| h.foo = 41}
+ h2 = entries2.hash_for(cls.new(20)){|h| h.foo = 42}.freeze
+ assert_same(h1, h1.replace(h2))
+ assert_equal(entries2, h1.to_a)
+ assert_equal(20, h1.default)
+ assert_equal(41, h1.foo)
+
+ h1 = entries1.hash_for
+ h2 = entries2.hash_for(cls.new)
+ assert_same(h1, h1.replace(h2))
+ assert_equal(entries2, h1.to_a)
+
+ assert_raise(TypeError){entries1.hash_for.replace([])}
+
+ k2 = HashKey[-2]
+ pairs2 = entries2.dup
+ pairs2 << [k2, 23]
+ h1 = entries1.hash_for
+ h2 = pairs2.hash_for
+ k2.callback = ->(*){h1.clear; h2.clear}
+ assert_nothing_crashed{h1.replace(h2)}
+
+ assert_raise(FrozenError){h1.freeze.replace(h1)}
+ assert_raise(FrozenError){{}.freeze.replace({})}
+ end
end
-assert('Hash#values', '15.2.13.4.28') do
- a = { 'abc_key' => 'abc_value' }
+assert('Hash#shift', '15.2.13.4.24') do
+ [ar_entries, ht_entries].each do |entries|
+ pairs = entries.dup
+ h = pairs.hash_for
+ h.delete(pairs.delete_at(0)[0])
+ h.delete(pairs.delete_at(3)[0])
+ until pairs.empty?
+ exp = pairs.shift
+ act = h.shift
+ assert_equal(Array, act.class)
+ assert_equal(exp, act)
+ assert_equal(exp.size, act.size)
+ assert_not_operator(h, :key?, exp[0])
+ end
+
+ assert_equal(nil, h.shift)
+ assert_equal(0, h.size)
+
+ h.default = -456
+ assert_equal(nil, h.shift)
+ assert_equal(0, h.size)
+
+ h.freeze
+ assert_raise(FrozenError){h.shift}
+ end
- assert_equal ['abc_value'], a.values
+ h = Hash.new{|h, k| [h, k]}
+ assert_equal(0, h.size)
+ assert_equal(nil, h.shift)
end
# Not ISO specified
-assert('Hash#eql?') do
- a = { 'a' => 1, 'b' => 2, 'c' => 3 }
- b = { 'a' => 1, 'b' => 2, 'c' => 3 }
- c = { 'a' => 1.0, 'b' => 2, 'c' => 3 }
- assert_true(a.eql?(b))
- assert_false(a.eql?(c))
- assert_false(a.eql?(true))
-end
-
-assert('Hash#reject') do
- h = {:one => 1, :two => 2, :three => 3, :four => 4}
- ret = h.reject do |k,v|
- v % 2 == 0
+%i[reject select].each do |meth|
+ assert("Hash##{meth}") do
+ cls = Class.new(Hash){attr_accessor :foo}
+ [ar_entries, ht_entries].each do |entries|
+ params = nil
+ filter = ->((k, v)) do
+ params << [k, v]
+ String === k
+ end
+
+ h = entries.hash_for(cls.new(1))
+ params = []
+ ret = h.__send__(meth, &filter)
+ assert_equal(entries, params)
+ assert_equal(entries, h.to_a)
+ assert_equal(1, h.default)
+ assert_equal(entries.__send__(meth, &filter), ret.to_a)
+ assert_equal(Hash, ret.class)
+ assert_equal(nil, ret.default)
+
+ params = []
+ assert_predicate({}.__send__(meth, &filter), :empty?)
+ assert_predicate(params, :empty?)
+ end
end
- assert_equal({:one => 1, :three => 3}, ret)
- assert_equal({:one => 1, :two => 2, :three => 3, :four => 4}, h)
end
-assert('Hash#reject!') do
- h = {:one => 1, :two => 2, :three => 3, :four => 4}
- ret = h.reject! do |k,v|
- v % 2 == 0
+%i[reject! select!].each do |meth|
+ assert("Hash##{meth}") do
+ [ar_entries, ht_entries].each do |entries|
+ params = nil
+ filter = ->((k, v)) do
+ params << [k, v]
+ String === k
+ end
+
+ pairs = entries.dup << ["_str", 5]
+ h = pairs.hash_for(Hash.new(1))
+ params = []
+ ret = h.__send__(meth, &filter)
+ assert_same(h, ret)
+ assert_equal(pairs, params)
+ assert_equal(pairs.__send__(meth.to_s[0..-2], &filter), h.to_a)
+ assert_equal(1, h.default)
+
+ h = pairs.hash_for
+ ret = h.__send__(meth){meth == :select!}
+ assert_nil(ret)
+ assert_equal(pairs, h.to_a)
+
+ assert_raise(FrozenError){h.freeze.__send__(meth, &filter)}
+ end
+
+ h = {}
+ assert_nil(h.__send__(meth){})
+ assert_predicate(h, :empty?)
end
- assert_equal({:one => 1, :three => 3}, ret)
- assert_equal({:one => 1, :three => 3}, h)
end
-assert('Hash#select') do
- h = {:one => 1, :two => 2, :three => 3, :four => 4}
- ret = h.select do |k,v|
- v % 2 == 0
+%i[inspect to_s].each do |meth|
+ assert("Hash##{meth}") do
+ assert_equal('{}', Hash.new.__send__(meth))
+
+ h1 = {:s => 0, :a => [1,2], 37 => :b, :d => "del", "c" => nil}
+ h1.shift
+ h1.delete(:d)
+ s1 = ':a=>[1, 2], 37=>:b, "c"=>nil'
+ h2 = Hash.new(100)
+
+ (1..14).each{h2[_1] = _1 * 2}
+ h2 = {**h2, **h1}
+ s2 = "1=>2, 2=>4, 3=>6, 4=>8, 5=>10, 6=>12, 7=>14, 8=>16, " \
+ "9=>18, 10=>20, 11=>22, 12=>24, 13=>26, 14=>28, #{s1}"
+
+ [[h1, s1], [h2, s2]].each do |h, s|
+ assert_equal("{#{s}}", h.__send__(meth))
+
+ hh = {}
+ hh[:recur] = hh
+ h.each{|k, v| hh[k] = v}
+ assert_equal("{:recur=>{...}, #{s}}", hh.__send__(meth))
+
+ hh = h.dup
+ hh[hh] = :recur
+ assert_equal("{#{s}, {...}=>:recur}", hh.__send__(meth))
+ end
+
+ [ar_entries, ht_entries].each do |entries|
+ cls = Class.new do
+ attr_accessor :h
+ def inspect; @h.replace(@h.dup); to_s; end
+ end
+ v = cls.new
+ h = entries.hash_for({_k: v})
+ v.h = h
+ assert_nothing_raised{h.__send__(meth)}
+ end
end
- assert_equal({:two => 2, :four => 4}, ret)
- assert_equal({:one => 1, :two => 2, :three => 3, :four => 4}, h)
end
-assert('Hash#select!') do
- h = {:one => 1, :two => 2, :three => 3, :four => 4}
- ret = h.select! do |k,v|
- v % 2 == 0
+assert('Hash#rehash') do
+ cls = Class.new(Hash){attr_accessor :foo}
+ [ar_entries, ht_entries].each do |entries|
+ k1, k2, k3 = HashKey[-1], HashKey[-2], HashKey[-3]
+ pairs = entries.dup.push(
+ [-4, -40],
+ [HashKey[-11], -5],
+ [:_del, "_del"],
+ [k1, :_k1],
+ ["_a", "_b"],
+ [k2, :_k2],
+ ["_c", "_d"],
+ [HashKey[-22], -21],
+ [k3, :_k3],
+ )
+ h = pairs.hash_for(cls.new(:defvar)){|h| h.foo = "f"}
+ k1.value, k2.value, k3.value = -11, -11, -22
+ pairs1 = pairs.dup
+ pairs1.delete([:_del, h.delete(:_del)])
+ exp_pairs1 = pairs1.hash_for.to_a
+ h.freeze
+ assert_same(h, h.rehash)
+ assert_equal(exp_pairs1, h.to_a)
+ assert_equal(exp_pairs1.size, h.size)
+ assert_equal(:defvar, h.default)
+ assert_equal("f", h.foo)
+ exp_pairs1.each {|k, v| assert_equal(v, h[k])}
+
+ # If an error occurs during rehash, at least the entry list is not broken.
+ k1.value, k2.value, k3.value = -1, -2, -3
+ h = pairs.hash_for
+ k1.value = -11
+ pairs2 = pairs.dup
+ pairs2.delete([:_del, h.delete(:_del)])
+ exp_pairs2 = pairs2.hash_for.to_a
+ k2.error = :eql?
+ assert_raise{h.rehash}
+ act_pairs2 = h.to_a
+ unless pairs2 == act_pairs2 && pairs2.size == h.size
+ assert_equal(exp_pairs2, act_pairs2)
+ assert_equal(exp_pairs2.size, h.size)
+ end
+
+ k1.value = -1
+ k2.error = false
+ h = pairs.hash_for
+ k1.callback = ->(name, *){h.clear if name == :eql?}
+ assert_nothing_crashed{h.rehash}
+ k1.callback = ->(name, *){h.clear if name == :hash}
+ assert_nothing_crashed{h.rehash}
end
- assert_equal({:two => 2, :four => 4}, ret)
- assert_equal({:two => 2, :four => 4}, h)
-end
-
-# Not ISO specified
-
-assert('Hash#inspect') do
- h = { "c" => 300, "a" => 100, "d" => 400, "c" => 300 }
- ret = h.to_s
- assert_include ret, '"c"=>300'
- assert_include ret, '"a"=>100'
- assert_include ret, '"d"=>400'
+ h = {}
+ assert_same(h, h.rehash)
+ assert_predicate(h, :empty?)
+
+ h = {}
+ (1..17).each{h[_1] = _1 * 2}
+ (2..16).each{h.delete(_1)}
+ assert_same(h, h.rehash)
+ assert_equal([[1, 2], [17, 34]], h.to_a)
+ assert_equal(2, h.size)
+ [1, 17].each{assert_equal(_1 * 2, h[_1])}
+end
+
+assert('#eql? receiver should be specified key') do
+ [ar_entries, ht_entries].each do |entries|
+ h = entries.hash_for
+ k0 = HashKey[-99]
+ h[k0] = 1
+
+ k1 = HashKey[-3, error: :eql?]
+ assert_raise{h[k1]}
+ k0.error = :eql?
+ k1.error = false
+ assert_nothing_raised{h[k1]}
+
+ k0.error = false
+ k1.error = :eql?
+ assert_raise{h[k1] = 1}
+ k0.error = :eql?
+ k1.error = false
+ assert_nothing_raised{h[k1] = 1}
+
+ k0.error = false
+ k2 = HashKey[-6, error: :eql?]
+ assert_raise{h.delete(k2)}
+ k0.error = :eql?
+ k2.error = false
+ assert_nothing_raised{h.delete(k2)}
+
+ k0.error = false
+ k3 = HashKey[-9, error: :eql?]
+ %i[has_key? include? key? member?].each do |m|
+ assert_raise{h.__send__(m, k3)}
+ end
+ k0.error = :eql?
+ k3.error = false
+ %i[has_key? include? key? member?].each do |m|
+ assert_nothing_raised{h.__send__(m, k3)}
+ end
+ end
end
-assert('Hash#rehash') do
- h = {[:a] => "b"}
- # hash key modified
- h.keys[0][0] = :b
- # h[[:b]] => nil
- h.rehash
- assert_equal("b", h[[:b]])
-end
+assert('#== receiver should be specified value') do
+ [ar_entries, ht_entries].each do |entries|
+ h = entries.hash_for
+ v0 = HashKey[-99]
+ h[-99] = v0
-assert('Hash#freeze') do
- h = {}.freeze
- assert_raise(RuntimeError) do
- h[:a] = 'b'
+ v1 = HashKey[-3, error: :==]
+ %i[has_value? value?].each{|m| assert_raise{h.__send__(m, v1)}}
+ v0.error = :==
+ v1.error = false
+ %i[has_value? value?].each{|m| assert_nothing_raised{h.__send__(m, v1)}}
end
end
diff --git a/test/t/integer.rb b/test/t/integer.rb
index cea97a1e6..d4076f38a 100644
--- a/test/t/integer.rb
+++ b/test/t/integer.rb
@@ -7,97 +7,72 @@ end
assert('Integer#+', '15.2.8.3.1') do
a = 1+1
- b = 1+1.0 if class_defined?("Float")
+ b = 1+1.0 if Object.const_defined?(:Float)
assert_equal 2, a
- assert_equal 2.0, b if class_defined?("Float")
+ assert_equal 2.0, b if Object.const_defined?(:Float)
assert_raise(TypeError){ 0+nil }
assert_raise(TypeError){ 1+nil }
-
- c = Mrbtest::FIXNUM_MAX + 1
- d = Mrbtest::FIXNUM_MAX.__send__(:+, 1)
-
- if class_defined?("Float")
- e = Mrbtest::FIXNUM_MAX + 1.0
- assert_equal Float, c.class
- assert_equal Float, d.class
- assert_float e, c
- assert_float e, d
- end
end
assert('Integer#-', '15.2.8.3.2') do
a = 2-1
- b = 2-1.0 if class_defined?("Float")
+ b = 2-1.0 if Object.const_defined?(:Float)
assert_equal 1, a
- assert_equal 1.0, b if class_defined?("Float")
-
- c = Mrbtest::FIXNUM_MIN - 1
- d = Mrbtest::FIXNUM_MIN.__send__(:-, 1)
-
- if class_defined?("Float")
- e = Mrbtest::FIXNUM_MIN - 1.0
- assert_equal Float, c.class
- assert_equal Float, d.class
- assert_float e, c
- assert_float e, d
- end
+ assert_equal 1.0, b if Object.const_defined?(:Float)
end
assert('Integer#*', '15.2.8.3.3') do
a = 1*1
- b = 1*1.0 if class_defined?("Float")
-
assert_equal 1, a
- assert_equal 1.0, b if class_defined?("Float")
-
+ if Object.const_defined?(:Float)
+ b = 1*1.0
+ assert_equal 1.0, b
+ end
assert_raise(TypeError){ 0*nil }
assert_raise(TypeError){ 1*nil }
-
- c = Mrbtest::FIXNUM_MAX * 2
- d = Mrbtest::FIXNUM_MAX.__send__(:*, 2)
-
- if class_defined?("Float")
- e = Mrbtest::FIXNUM_MAX * 2.0
- assert_equal Float, c.class
- assert_equal Float, d.class
- assert_float e, c
- assert_float e, d
- end
end
assert('Integer#/', '15.2.8.3.4') do
a = 2/1
- b = 2/1.0
-
assert_equal 2, a
+ a = 5/2
+ assert_equal 2, a
+ skip unless Object.const_defined?(:Float)
+ b = 2/1.0
assert_equal 2.0, b
end
+assert('Integer#quo') do
+ a = 6.quo(5)
+ assert_equal 1.2, a
+end if Object.const_defined?(:Float)
+
assert('Integer#%', '15.2.8.3.5') do
a = 1%1
- b = 1%1.0
- c = 2%4
- d = 2%5
- e = 2%-5
- f = -2%5
- g = -2%-5
- h = 2%-2
- i = -2%2
- j = -2%-2
+ b = 2%4
+ c = 2%5
+ d = 2%-5
+ e = -2%5
+ f = -2%-5
+ g = 2%-2
+ h = -2%2
+ i = -2%-2
assert_equal 0, a
- assert_equal 0.0, b
+ assert_equal 2, b
assert_equal 2, c
- assert_equal 2, d
- assert_equal(-3, e)
- assert_equal 3, f
- assert_equal(-2, g)
+ assert_equal(-3, d)
+ assert_equal 3, e
+ assert_equal(-2, f)
+ assert_equal 0, g
assert_equal 0, h
assert_equal 0, i
- assert_equal 0, j
+ skip unless Object.const_defined?(:Float)
+ j = 1%1.0
+ assert_equal 0.0, j
end
assert('Integer#<=>', '15.2.9.3.6') do
@@ -157,11 +132,7 @@ 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
-
- # -3 Left Shift by 30 is bitShift overflow to SignedInt
- assert_equal(-3221225472, -3 << 30)
+ skip unless Object.const_defined?(:Float)
end
assert('Integer#>>', '15.2.8.3.13') do
@@ -226,16 +197,25 @@ assert('Integer#times', '15.2.8.3.22') do
end
assert('Integer#to_f', '15.2.8.3.23') do
+ skip unless Object.const_defined?(:Float)
assert_equal 1.0, 1.to_f
-end if class_defined?("Float")
+end
assert('Integer#to_i', '15.2.8.3.24') do
assert_equal 1, 1.to_i
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
@@ -259,19 +239,3 @@ assert('Integer#divmod', '15.2.8.3.30') do
assert_equal [-2, -1], 25.divmod(-13)
assert_equal [ 1, -6], -13.divmod(-7)
end
-
-# Not ISO specified
-
-assert('Integer#step') do
- a = []
- b = []
- 1.step(3) do |i|
- a << i
- end
- 1.step(6, 2) do |i|
- b << i
- end
-
- assert_equal [1, 2, 3], a
- assert_equal [1, 3, 5], b
-end
diff --git a/test/t/iterations.rb b/test/t/iterations.rb
index f227a6037..9611388ea 100644
--- a/test/t/iterations.rb
+++ b/test/t/iterations.rb
@@ -58,4 +58,4 @@ assert('next expression', '11.5.2.4.4') do
end
all
end
-end \ No newline at end of file
+end
diff --git a/test/t/kernel.rb b/test/t/kernel.rb
index 74176fbd0..0a70ec0d2 100644
--- a/test/t/kernel.rb
+++ b/test/t/kernel.rb
@@ -29,11 +29,7 @@ assert('Kernel.block_given?', '15.3.1.2.2') do
end
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
+# Kernel.eval is provided by the mruby-eval mrbgem. '15.3.1.2.3'
assert('Kernel.iterator?', '15.3.1.2.5') do
assert_false Kernel.iterator?
@@ -63,20 +59,11 @@ assert('Kernel.loop', '15.3.1.2.8') do
assert_equal 100, i
end
-assert('Kernel.p', '15.3.1.2.9') do
- # TODO search for a way to test p to stdio
- assert_true true
-end
+# Kernel.p is provided by the mruby-print mrbgem. '15.3.1.2.9'
-assert('Kernel.print', '15.3.1.2.10') do
- # TODO search for a way to test print to stdio
- assert_true true
-end
+# Kernel.print is provided by the mruby-print mrbgem. '15.3.1.2.10'
-assert('Kernel.puts', '15.3.1.2.11') do
- # TODO search for a way to test puts to stdio
- assert_true true
-end
+# Kernel.puts is provided by the mruby-print mrbgem. '15.3.1.2.11'
assert('Kernel.raise', '15.3.1.2.12') do
assert_raise RuntimeError do
@@ -89,7 +76,25 @@ assert('Kernel.raise', '15.3.1.2.12') do
end
assert('Kernel#__id__', '15.3.1.3.3') do
- assert_equal Fixnum, __id__.class
+ assert_equal Integer, __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
+
+ args = [:respond_to?, :nil?]
+ assert_true __send__(*args)
+ assert_equal [:respond_to?, :nil?], args
end
assert('Kernel#block_given?', '15.3.1.3.6') do
@@ -111,6 +116,13 @@ assert('Kernel#block_given?', '15.3.1.3.6') do
"block"
end
end
+
+ def bg_try_in_block
+ -> { block_given? }[]
+ end
+
+ assert_false bg_try_in_block
+ assert_true bg_try_in_block{}
end
assert('Kernel#class', '15.3.1.3.7') do
@@ -187,17 +199,6 @@ assert('Kernel#dup', '15.3.1.3.9') do
a.set(2)
c = a.dup
- immutables = [ 1, :foo, true, false, nil ]
- error_count = 0
- immutables.each do |i|
- begin
- i.dup
- rescue TypeError
- error_count += 1
- end
- end
-
- assert_equal immutables.size, error_count
assert_equal 2, a.get
assert_equal 1, b.get
assert_equal 2, c.get
@@ -230,6 +231,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 +251,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 +346,15 @@ assert('Kernel#method_missing', '15.3.1.3.30') do
end
end
no_super_test = NoSuperMethodTestClass.new
- begin
+ msg = "no superclass 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
@@ -391,11 +406,12 @@ assert('Kernel#remove_instance_variable', '15.3.1.3.41') do
tri = Test4RemoveInstanceVar.new
assert_equal 99, tri.var
- tri.remove
+ assert_equal 99, tri.remove
assert_equal nil, tri.var
- assert_raise NameError do
- tri.remove
- end
+ 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'
@@ -472,13 +488,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/literals.rb b/test/t/literals.rb
index 6344219aa..f93968650 100644
--- a/test/t/literals.rb
+++ b/test/t/literals.rb
@@ -90,7 +90,7 @@ assert('Literals Strings Here documents', '8.7.6.3.6') do
a = <<AAA
aaa
AAA
- b = <<b_b
+ b = <<b_b
bbb
b_b
c = [<<CCC1, <<"CCC2", <<'CCC3']
@@ -162,6 +162,47 @@ qq
QQ2
"o")
+ r = <<~RRR
+ rrr
+ rrr
+ RRR
+ s = <<~"SSS"
+ sss
+ sss
+ SSS
+ t = <<~'TTT'
+ ttt
+ ttt
+ TTT
+ u = [<<~UUU1 , <<~"UUU2" , <<~'UUU3' ]
+ u#{1}u
+ UUU1
+ u#{2}u
+ UUU2
+ u#{3}u
+ UUU3
+ v1 = <<~VVV
+
+ vvv
+ #{"vvv"}
+ VVV
+ v2 = <<~VVV
+\tvvv
+ vvv
+ VVV
+ v3 = <<~VVV
+ v v v
+ vvv
+ VVV
+ v4 = <<~VVV
+ vvv \
+ vvv
+ VVV
+ v5 = <<~VVV
+ vvv \
+ vvv
+ VVV
+
w = %W( 1 #{<<WWW} 3
www
WWW
@@ -197,10 +238,18 @@ ZZZ
assert_equal [1, "nn1\n", 3, 4], n
assert_equal "a $ q\n $ c $ d", q1
assert_equal "l $ mqq\nn $ o", q2
+ assert_equal "rrr\n rrr\n", r
+ assert_equal "sss\n sss\n", s
+ assert_equal "ttt\n ttt\n", t
+ assert_equal ["u1u\n", "u2u\n", "u\#{3}u\n"], u
+ assert_equal "\nvvv\nvvv\n", v1
+ assert_equal "\tvvv\n vvv\n", v2
+ assert_equal "v v v\n vvv\n", v3
+ assert_equal "vvv vvv\n", v4
+ assert_equal " vvv vvv\n", v5
assert_equal ["1", "www\n", "3", "4", "5"], w
assert_equal [1, "foo 222 333\n 444\n5\n bar\n6\n", 9], x
assert_equal "", z
-
end
diff --git a/test/t/methods.rb b/test/t/methods.rb
index f9c25dc33..9005d7976 100644
--- a/test/t/methods.rb
+++ b/test/t/methods.rb
@@ -107,3 +107,32 @@ assert('The undef statement (method undefined)', '13.3.7 a) 5)') do
undef :non_existing_method
end
end
+
+assert('method_added hook') do
+ c = Class.new do
+ # method to retrieve @name
+ def self.name; @name; end
+ # hook method on method definition
+ def self.method_added(name) @name = name; end
+ # method definition
+ def foo; end
+ end
+ assert_equal(:foo, c.name)
+ c.define_method(:bar){}
+ assert_equal(:bar, c.name)
+end
+
+assert('singleton_method_added hook') do
+ a = Object.new
+ # method to retrieve @name
+ def a.name; @name; end
+ # hook method on singleton method definition
+ def a.singleton_method_added(name) @name = name; end
+ # singleton method definition
+ def a.foo; end
+ assert_equal(:foo, a.name)
+ class <<a
+ def bar; end
+ end
+ assert_equal(:bar, a.name)
+end
diff --git a/test/t/module.rb b/test/t/module.rb
index 78cb5d07f..9aa018280 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,6 +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_wrong_const_name{ Test4ConstDefined.const_defined?(:wrong_name) }
end
assert('Module#const_get', '15.2.2.4.21') do
@@ -222,8 +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_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
@@ -231,8 +253,11 @@ assert('Module#const_set', '15.2.2.4.23') do
Const4Test4ConstSet = 42
end
- assert_true Test4ConstSet.const_set(:Const4Test4ConstSet, 23)
+ assert_equal 23, Test4ConstSet.const_set(:Const4Test4ConstSet, 23)
assert_equal 23, Test4ConstSet.const_get(:Const4Test4ConstSet)
+ ["", "wrongNAME", "Wrong-Name"].each do |n|
+ assert_wrong_const_name { Test4ConstSet.const_set(n, 1) }
+ end
end
assert('Module#remove_const', '15.2.2.4.40') do
@@ -240,21 +265,15 @@ assert('Module#remove_const', '15.2.2.4.40') do
ExistingConst = 23
end
- result = Test4RemoveConst.module_eval { remove_const :ExistingConst }
-
- name_error = false
- begin
- Test4RemoveConst.module_eval { remove_const :NonExistingConst }
- rescue NameError
- name_error = true
+ assert_equal 23, Test4RemoveConst.remove_const(:ExistingConst)
+ assert_false Test4RemoveConst.const_defined?(:ExistingConst)
+ assert_raise_with_message_pattern(NameError, "constant * not defined") do
+ Test4RemoveConst.remove_const(:NonExistingConst)
end
-
- # Constant removed from Module
- assert_false Test4RemoveConst.const_defined? :ExistingConst
- # Return value of binding
- assert_equal 23, result
- # Name Error raised when Constant doesn't exist
- assert_true name_error
+ %i[x X!].each do |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
@@ -267,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
@@ -280,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
@@ -359,15 +391,15 @@ assert('Module#undef_method', '15.2.2.4.42') do
class Parent
def hello
end
- end
+ end
- class Child < Parent
+ class Child < Parent
def hello
end
- end
+ end
- class GrandChild < Child
- end
+ class GrandChild < Child
+ end
end
Test4UndefMethod::Child.class_eval{ undef_method :hello }
@@ -378,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 }
@@ -390,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
@@ -529,7 +593,7 @@ end
# to_f / other
# end
# end
- # Fixnum.send(:prepend, M)
+ # Integer.send(:prepend, M)
# assert_equal(0.5, 1 / 2, "#{bug7983}")
# }
# assert_equal(0, 1 / 2)
@@ -610,7 +674,7 @@ end
c1 = labeled_class("C1")
c2 = labeled_class("C2", c1) {prepend m}
c1.class_eval {prepend m}
- assert_equal([m, c2, m, c1], c2.ancestors[0, 4], "should accesisble prepended module in superclass")
+ assert_equal([m, c2, m, c1], c2.ancestors[0, 4], "should accessible prepended module in superclass")
end
# requires #assert_separately
@@ -624,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
@@ -644,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
@@ -667,17 +736,17 @@ assert('Issue 1467') do
class C1
include M1
- def initialize()
- super()
- end
+ def initialize()
+ super()
+ end
end
class C2
include M1
end
- C1.new
- C2.new
+ assert_kind_of(M1, C1.new)
+ assert_kind_of(M1, C2.new)
end
assert('clone Module') do
@@ -691,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
@@ -708,6 +777,15 @@ assert('module with non-class/module outer raises TypeError') do
assert_raise(TypeError) { module []::M2 end }
end
+assert('module to return the last value') do
+ m = module M; :m end
+ assert_equal(m, :m)
+end
+
+assert('module to return nil if body is empty') do
+ assert_nil(module M end)
+end
+
assert('get constant of parent module in singleton class; issue #3568') do
actual = module GetConstantInSingletonTest
EXPECTED = "value"
diff --git a/test/t/nameerror.rb b/test/t/nameerror.rb
index 28682bedc..9d2e2a470 100644
--- a/test/t/nameerror.rb
+++ b/test/t/nameerror.rb
@@ -20,9 +20,9 @@ assert('NameError#name', '15.2.31.2.1') do
end
assert('NameError#initialize', '15.2.31.2.2') do
- e = NameError.new('a', :foo)
+ e = NameError.new('a', :foo)
- assert_equal NameError, e.class
- assert_equal 'a', e.message
- assert_equal :foo, e.name
+ assert_equal NameError, e.class
+ assert_equal 'a', e.message
+ assert_equal :foo, e.name
end
diff --git a/test/t/numeric.rb b/test/t/numeric.rb
index 38c62a669..8baf6c883 100644
--- a/test/t/numeric.rb
+++ b/test/t/numeric.rb
@@ -1,8 +1,21 @@
##
# 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
+ assert_equal(Class, Numeric.class)
end
assert('Numeric#+@', '15.2.7.4.1') do
@@ -15,22 +28,15 @@ end
assert('Numeric#abs', '15.2.7.4.3') do
assert_equal(1, 1.abs)
- assert_equal(1.0, -1.abs) if class_defined?("Float")
-end
-
-assert('Numeric#pow') do
- assert_equal(8, 2 ** 3)
- assert_equal(-8, -2 ** 3)
- assert_equal(1, 2 ** 0)
- assert_equal(1, 2.2 ** 0)
- assert_equal(0.5, 2 ** -1)
+ skip unless Object.const_defined?(:Float)
+ assert_equal(1.0, -1.abs)
end
assert('Numeric#/', '15.2.8.3.4') do
n = Class.new(Numeric){ def /(x); 15.1;end }.new
assert_equal(2, 10/5)
- assert_equal(0.0625, 1/16)
+ assert_equal(0, 1/16)
assert_equal(15.1, n/10)
assert_raise(TypeError){ 1/n }
assert_raise(TypeError){ 1/nil }
@@ -39,5 +45,70 @@ end
# Not ISO specified
assert('Numeric#**') do
- assert_equal 8.0, 2.0**3
+ assert_equal(8, 2 ** 3)
+ assert_equal(-8, -2 ** 3)
+ assert_equal(1, 2 ** 0)
+ skip unless Object.const_defined?(:Float)
+ assert_equal(1.0, 2.2 ** 0)
+ assert_equal(0.5, 2 ** -1)
+ assert_equal(8.0, 2.0**3)
+end
+
+assert('Numeric#step') do
+ 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, [], 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, [], 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/object.rb b/test/t/object.rb
index 6a755d3ba..b65f298e6 100644
--- a/test/t/object.rb
+++ b/test/t/object.rb
@@ -8,4 +8,3 @@ end
assert('Object superclass', '15.2.1.2') do
assert_equal BasicObject, Object.superclass
end
-
diff --git a/test/t/proc.rb b/test/t/proc.rb
index 42ac3b941..b17b21e8c 100644
--- a/test/t/proc.rb
+++ b/test/t/proc.rb
@@ -157,7 +157,7 @@ assert('&obj call to_proc if defined') do
def mock(&b)
b
end
- assert_equal pr.object_id, mock(&pr).object_id
+ assert_same pr, mock(&pr)
assert_equal pr, mock(&pr)
obj = Object.new
diff --git a/test/t/range.rb b/test/t/range.rb
index 3e67fcc1c..5f29b4514 100644
--- a/test/t/range.rb
+++ b/test/t/range.rb
@@ -8,18 +8,39 @@ end
assert('Range#==', '15.2.14.4.1') do
assert_true (1..10) == (1..10)
assert_false (1..10) == (1..100)
- assert_true (1..10) == Range.new(1.0, 10.0) if class_defined?("Float")
+ assert_false (1..10) == (1..)
+ assert_false (1..10) == (..10)
+
+ assert_true (1..) == (1..nil)
+ assert_true (1..) == (1..)
+ assert_false (1..) == (1...)
+
+ assert_true (..1) == (nil..1)
+ assert_true (..1) == (..1)
+ assert_false (..1) == (...1)
+
+ skip unless Object.const_defined?(:Float)
+ assert_true (1..10) == Range.new(1.0, 10.0)
+
end
assert('Range#===', '15.2.14.4.2') do
a = (1..10)
+ b = (1..)
+ c = (..10)
assert_true a === 5
assert_false a === 20
+ assert_true b === 20
+ assert_false b === 0
+ assert_false c === 20
+ assert_true c === 0
end
assert('Range#begin', '15.2.14.4.3') do
assert_equal 1, (1..10).begin
+ assert_equal 1, (1..).begin
+ assert_nil (..1).begin
end
assert('Range#each', '15.2.14.4.4') do
@@ -27,27 +48,45 @@ assert('Range#each', '15.2.14.4.4') do
b = 0
a.each {|i| b += i}
assert_equal 6, b
+ c = []
+ (1..).each { |i| c << i; break if c.size == 10 }
+ assert_equal [1, 2, 3, 4, 5, 6, 7, 8 ,9, 10], c
end
assert('Range#end', '15.2.14.4.5') do
assert_equal 10, (1..10).end
+ assert_nil (1..).end
+ assert_equal 10, (..10).end
end
assert('Range#exclude_end?', '15.2.14.4.6') do
assert_true (1...10).exclude_end?
assert_false (1..10).exclude_end?
+ assert_true (1...).exclude_end?
+ assert_false (1..).exclude_end?
+ assert_true (...1).exclude_end?
+ assert_false (..1).exclude_end?
end
assert('Range#first', '15.2.14.4.7') do
assert_equal 1, (1..10).first
+ assert_equal 1, (1..).first
end
assert('Range#include?', '15.2.14.4.8') do
assert_true (1..10).include?(10)
assert_false (1..10).include?(11)
+ assert_true (1..).include?(10)
+ assert_false (1..).include?(0)
+ assert_true (..10).include?(10)
+ assert_true (..10).include?(0)
assert_true (1...10).include?(9)
assert_false (1...10).include?(10)
+ assert_true (1...).include?(10)
+ assert_false (1...).include?(0)
+ assert_false (...10).include?(10)
+ assert_true (...10).include?(0)
end
assert('Range#initialize', '15.2.14.4.9') do
@@ -59,18 +98,30 @@ assert('Range#initialize', '15.2.14.4.9') do
assert_equal (1..10), b
assert_false b.exclude_end?
- assert_raise(NameError) { (0..1).send(:initialize, 1, 3) }
+ assert_raise(NameError) { (0..1).__send__(:initialize, 1, 3) }
+
+ c = Range.new(1, nil, true)
+ d = Range.new(1, nil, false)
+
+ assert_equal (1...nil), c
+ assert_true c.exclude_end?
+ assert_equal (1..nil), d
+ assert_false d.exclude_end?
end
assert('Range#last', '15.2.14.4.10') do
assert_equal 10, (1..10).last
+ assert_nil (1..).last
end
assert('Range#member?', '15.2.14.4.11') do
a = (1..10)
+ b = (1..)
assert_true a.member?(5)
assert_false a.member?(20)
+ assert_true b.member?(20)
+ assert_false b.member?(0)
end
assert('Range#to_s', '15.2.14.4.12') do
@@ -78,6 +129,10 @@ assert('Range#to_s', '15.2.14.4.12') do
assert_equal "0...1", (0...1).to_s
assert_equal "a..b", ("a".."b").to_s
assert_equal "a...b", ("a"..."b").to_s
+ assert_equal "0..", (0..).to_s
+ assert_equal "0...", (0...).to_s
+ assert_equal "a..", ("a"..).to_s
+ assert_equal "a...", ("a"...).to_s
end
assert('Range#inspect', '15.2.14.4.13') do
@@ -85,11 +140,55 @@ assert('Range#inspect', '15.2.14.4.13') do
assert_equal "0...1", (0...1).inspect
assert_equal "\"a\"..\"b\"", ("a".."b").inspect
assert_equal "\"a\"...\"b\"", ("a"..."b").inspect
+ assert_equal "0..", (0..).inspect
+ assert_equal "0...", (0...).inspect
+ assert_equal "\"a\"..", ("a"..).inspect
+ assert_equal "\"a\"...", ("a"...).inspect
end
assert('Range#eql?', '15.2.14.4.14') do
assert_true (1..10).eql? (1..10)
assert_false (1..10).eql? (1..100)
- assert_false (1..10).eql? (Range.new(1.0, 10.0))
assert_false (1..10).eql? "1..10"
+ assert_true (1..).eql? (1..)
+ assert_false (1..).eql? (2..)
+ assert_false (1..).eql? "1.."
+ skip unless Object.const_defined?(:Float)
+ assert_false (1..10).eql? (Range.new(1.0, 10.0))
+ assert_false (1..).eql? (Range.new(1.0, nil))
+end
+
+assert('Range#initialize_copy', '15.2.14.4.15') do
+ assert_raise(NameError) { (0..1).__send__(:initialize_copy, 1..3) }
+end
+
+assert('Range#hash', '15.3.1.3.15') do
+ assert_kind_of(Integer, (1..10).hash)
+ assert_equal (1..10).hash, (1..10).hash
+ assert_not_equal (1..10).hash, (1...10).hash
+ assert_equal (1..).hash, (1..).hash
+ assert_not_equal (1..).hash, (1...).hash
+end
+
+assert('Range#dup') do
+ r = (1..3).dup
+ assert_equal 1, r.begin
+ assert_equal 3, r.end
+ assert_false r.exclude_end?
+
+ r = ("a"..."z").dup
+ assert_equal "a", r.begin
+ assert_equal "z", r.end
+ assert_true r.exclude_end?
+
+ r = (1..).dup
+ assert_equal 1, r.begin
+ assert_nil r.end
+ assert_false r.exclude_end?
+end
+
+assert('Range#to_a') do
+ assert_equal([1, 2, 3, 4, 5], (1..5).to_a)
+ assert_equal([1, 2, 3, 4], (1...5).to_a)
+ assert_raise(RangeError) { (1..).to_a }
end
diff --git a/test/t/string.rb b/test/t/string.rb
index e91b915fe..447493227 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
@@ -102,6 +90,7 @@ assert('String#[] with Range') do
h1 = 'abc'[3..4]
i1 = 'abc'[4..5]
j1 = 'abcdefghijklmnopqrstuvwxyz'[1..3]
+ k1 = 'abcdefghijklmnopqrstuvwxyz'[-3..]
a2 = 'abc'[1...0]
b2 = 'abc'[1...1]
c2 = 'abc'[1...2]
@@ -112,6 +101,7 @@ assert('String#[] with Range') do
h2 = 'abc'[3...4]
i2 = 'abc'[4...5]
j2 = 'abcdefghijklmnopqrstuvwxyz'[1...3]
+ k2 = 'abcdefghijklmnopqrstuvwxyz'[-3...]
assert_equal '', a1
assert_equal 'b', b1
@@ -123,6 +113,7 @@ assert('String#[] with Range') do
assert_equal '', h1
assert_nil i2
assert_equal 'bcd', j1
+ assert_equal 'xyz', k1
assert_equal '', a2
assert_equal '', b2
assert_equal 'b', c2
@@ -133,6 +124,7 @@ assert('String#[] with Range') do
assert_equal '', h2
assert_nil i2
assert_equal 'bc', j2
+ assert_equal 'xyz', k2
end
assert('String#[]=') do
@@ -155,12 +147,15 @@ assert('String#[]=') do
d[-10] = 'X'
end
- if class_defined?("Float")
- e = 'abc'
- e[1.1] = 'X'
- assert_equal 'aXc', e
+ if Object.const_defined?(:Float)
+ e = 'abc'
+ e[1.1] = 'X'
+ 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 +192,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
@@ -253,19 +302,6 @@ assert('String#chomp!', '15.2.10.5.10') do
assert_equal 'abc', e
end
-assert('String#chomp! uses the correct length') do
- class A
- def to_str
- $s.replace("AA")
- "A"
- end
- end
-
- $s = "AAA"
- $s.chomp!(A.new)
- assert_equal $s, "A"
-end
-
assert('String#chop', '15.2.10.5.11') do
a = ''.chop
b = 'abc'.chop
@@ -419,7 +455,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 = ''
@@ -477,12 +528,12 @@ assert('String#reverse', '15.2.10.5.29') do
end
assert('String#reverse(UTF-8)', '15.2.10.5.29') do
- assert_equal "ち", "こんにちは世界"[3]
- assert_equal nil, "こんにちは世界"[20]
- assert_equal "世", "こんにちは世界"[-2]
- assert_equal "世界", "こんにちは世界"[-2..-1]
- assert_equal "んに", "こんにちは世界"[1,2]
- assert_equal "世", "こんにちは世界"["世"]
+ a = 'こんにちは世界!'
+ a.reverse
+
+ assert_equal 'こんにちは世界!', a
+ assert_equal '!界世はちにんこ', 'こんにちは世界!'.reverse
+ assert_equal 'あ', 'あ'.reverse
end if UTF8STRING
assert('String#reverse!', '15.2.10.5.30') do
@@ -499,24 +550,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
@@ -592,7 +663,7 @@ assert('String#sub', '15.2.10.5.36') do
str = "abc"
miss = str.sub("X", "Z")
assert_equal str, miss
- assert_not_equal str.object_id, miss.object_id
+ assert_not_same str, miss
a = []
assert_equal '.abc', "abc".sub("") { |i| a << i; "." }
@@ -620,31 +691,45 @@ assert('String#sub!', '15.2.10.5.37') do
end
assert('String#to_f', '15.2.10.5.38') do
- a = ''.to_f
- b = '123456789'.to_f
- c = '12345.6789'.to_f
- d = '1e-2147483648'.to_f
- e = '1e2147483648'.to_f
-
- assert_float(0.0, a)
- assert_float(123456789.0, b)
- assert_float(12345.6789, c)
- assert_float(0, d)
- assert_float(Float::INFINITY, e)
-end if class_defined?("Float")
+ assert_operator(0.0, :eql?, ''.to_f)
+ assert_operator(123456789.0, :eql?, '123456789'.to_f)
+ assert_operator(12345.6789, :eql?, '12345.6789'.to_f)
+ assert_operator(0.0, :eql?, '1e-2147483648'.to_f)
+ assert_operator(Float::INFINITY, :eql?, '1e2147483648'.to_f)
+ assert_operator(0.0, :eql?, 'a'.to_f)
+ assert_operator(4.0, :eql?, '4a5'.to_f)
+ assert_operator(12.0, :eql?, '1_2__3'.to_f)
+ assert_operator(123.0, :eql?, '1_2_3'.to_f)
+ assert_operator(68.0, :eql?, '68_'.to_f)
+ assert_operator(68.0, :eql?, '68._7'.to_f)
+ assert_operator(68.7, :eql?, '68.7_'.to_f)
+ assert_operator(68.7, :eql?, '68.7_ '.to_f)
+ assert_operator(6.0, :eql?, '6 8.7'.to_f)
+ assert_operator(68.0, :eql?, '68. 7'.to_f)
+ assert_operator(0.0, :eql?, '_68'.to_f)
+ assert_operator(0.0, :eql?, ' _68'.to_f)
+ assert_operator(12.34, :eql?, '1_2.3_4'.to_f)
+ assert_operator(12.3, :eql?, '1_2.3__4'.to_f)
+ assert_operator(0.9, :eql?, '.9'.to_f)
+ assert_operator(0.9, :eql?, "\t\r\n\f\v .9 \t\r\n\f\v".to_f)
+end if Object.const_defined?(:Float)
assert('String#to_i', '15.2.10.5.39') do
- a = ''.to_i
- b = '32143'.to_i
- c = 'a'.to_i(16)
- d = '100'.to_i(2)
- e = '1_000'.to_i
-
- assert_equal 0, a
- assert_equal 32143, b
- assert_equal 10, c
- assert_equal 4, d
- assert_equal 1_000, e
+ assert_operator 0, :eql?, ''.to_i
+ assert_operator 32143, :eql?, '32143'.to_i
+ assert_operator 10, :eql?, 'a'.to_i(16)
+ assert_operator 4, :eql?, '100'.to_i(2)
+ assert_operator 1_000, :eql?, '1_000'.to_i
+ assert_operator 0, :eql?, 'a'.to_i
+ assert_operator 4, :eql?, '4a5'.to_i
+ assert_operator 12, :eql?, '1_2__3'.to_i
+ assert_operator 123, :eql?, '1_2_3'.to_i
+ assert_operator 68, :eql?, '68_'.to_i
+ assert_operator 68, :eql?, '68_ '.to_i
+ assert_operator 0, :eql?, '_68'.to_i
+ assert_operator 0, :eql?, ' _68'.to_i
+ assert_operator 68, :eql?, "\t\r\n\f\v 68 \t\r\n\f\v".to_i
+ assert_operator 6, :eql?, ' 6 8 '.to_i
end
assert('String#to_s', '15.2.10.5.40') do
@@ -681,12 +766,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
@@ -696,10 +787,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]
@@ -725,5 +812,90 @@ assert('String#freeze') do
str = "hello"
str.freeze
- assert_raise(RuntimeError) { str.upcase! }
+ assert_raise(FrozenError) { str.upcase! }
+end
+
+assert('String literal concatenation') do
+ assert_equal 2, ("A" "B").size
+ 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/superclass.rb b/test/t/superclass.rb
index 10b6438d3..81630192d 100644
--- a/test/t/superclass.rb
+++ b/test/t/superclass.rb
@@ -23,22 +23,21 @@
[:Exception, :Object, '15.2.22.2'],
[:StandardError, :Exception, '15.2.23.2'],
[:ArgumentError, :StandardError, '15.2.24.2'],
- # [:LocalJumpError, :StandardError, '15.2.25.2'],
- [:LocalJumpError, :ScriptError, '15.2.25.2'], # mruby specific
- [:RangeError, :StandardError, '12.2.26.2'],
- [:RegexpError, :StandardError, '12.2.27.2'],
- [:RuntimeError, :StandardError, '12.2.28.2'],
- [:TypeError, :StandardError, '12.2.29.2'],
-# [:ZeroDivisionError, :StandardError, '12.2.30.2'], # No ZeroDivisionError in mruby
+ [:LocalJumpError, :StandardError, '15.2.25.2'],
+ [:RangeError, :StandardError, '15.2.26.2'],
+ [:RegexpError, :StandardError, '15.2.27.2'],
+ [:RuntimeError, :StandardError, '15.2.28.2'],
+ [:TypeError, :StandardError, '15.2.29.2'],
+ [:ZeroDivisionError, :StandardError, '15.2.30.2'],
[:NameError, :StandardError, '15.2.31.2'],
[:NoMethodError, :NameError, '15.2.32.2'],
[:IndexError, :StandardError, '15.2.33.2'],
-# [:IOError, :StandardError, '12.2.34.2'],
-# [:EOFError, :IOError, '12.2.35.2'],
+# [:IOError, :StandardError, '15.2.34.2'],
+# [:EOFError, :IOError, '15.2.35.2'],
# [:SystemCallError, :StandardError, '15.2.36.2'],
- [:ScriptError, :Exception, '12.2.37.2'],
- [:SyntaxError, :ScriptError, '12.2.38.2'],
-# [:LoadError, :ScriptError, '12.2.39,2'],
+ [:ScriptError, :Exception, '15.2.37.2'],
+ [:SyntaxError, :ScriptError, '15.2.38.2'],
+# [:LoadError, :ScriptError, '15.2.39,2'],
].each do |cls, super_cls, iso|
assert "Direct superclass of #{cls}", iso do
skip "#{cls} isn't defined" unless Object.const_defined? cls
diff --git a/test/t/symbol.rb b/test/t/symbol.rb
index fdce0f378..4cb210757 100644
--- a/test/t/symbol.rb
+++ b/test/t/symbol.rb
@@ -13,12 +13,8 @@ assert('Symbol', '15.2.11') do
end
assert('Symbol#===', '15.2.11.3.1') do
- assert_true :abc == :abc
- assert_false :abc == :cba
-end
-
-assert('Symbol#id2name', '15.2.11.3.2') do
- assert_equal 'abc', :abc.id2name
+ assert_true :abc === :abc
+ assert_false :abc === :cba
end
assert('Symbol#to_s', '15.2.11.3.3') do
diff --git a/test/t/syntax.rb b/test/t/syntax.rb
index a726719f8..c4c99242b 100644
--- a/test/t/syntax.rb
+++ b/test/t/syntax.rb
@@ -35,9 +35,10 @@ assert('super', '11.3.4') do
end
assert('yield', '11.3.5') do
- assert_raise LocalJumpError do
- yield
- end
+# it's syntax error now
+# assert_raise LocalJumpError do
+# yield
+# end
assert_raise LocalJumpError do
o = Object.new
def o.foo
@@ -357,6 +358,11 @@ assert('splat object in assignment') do
assert_equal [2], (a = *o)
end
+assert('one-line pattern match') do
+ 1 => a
+ assert_equal(1, a)
+end
+
assert('splat object in case statement') do
o = Object.new
def o.to_a
@@ -435,10 +441,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
@@ -462,6 +469,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
@@ -483,6 +502,10 @@ this is a comment that has extra after =begin and =end with tabs after it
end
assert 'keyword arguments' do
+ def m(a, b:1) [a, b] end
+ assert_equal [1, 1], m(1)
+ assert_equal [1, 2], m(1, b: 2)
+
def m(a, b:) [a, b] end
assert_equal [1, 2], m(1, b: 2)
assert_raise(ArgumentError) { m b: 1 }
@@ -661,4 +684,63 @@ 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
+
+assert('numbered parameters') do
+ assert_equal(15, [1,2,3,4,5].reduce {_1+_2})
+ assert_equal(45, Proc.new do _1 + _2 + _3 + _4 + _5 + _6 + _7 + _8 + _9 end.call(*[1, 2, 3, 4, 5, 6, 7, 8, 9]))
+end
+
+assert('_0 is not numbered parameter') do
+ _0 = :l
+ assert_equal(:l, ->{_0}.call)
+end
+
+assert('argument forwarding') do
+ c = Class.new {
+ def a0(*a,&b)
+ assert_equal([1,2,3], a)
+ assert_not_nil(b)
+ end
+ def a(...)
+ a0(...)
+ end
+ def b(a,...)
+ assert_equal(a,1)
+ a0(1,...)
+ end
+ }
+ o = c.new
+ o.a(1,2,3){}
+ o.b(1,2,3){}
+end
+
+assert('endless def') do
+ c = Class.new {
+ def m1 = 42
+ def m2() = 42
+ def m3(x) = x+1
+ def self.s1 = 42
+ def self.s2() = 42
+ def self.s3(x) = x + 1
+ def cm1 = m3 42
+ def cm2() = m3 42
+ def cm3(x) = m3 x+1
+ def self.cs1 = s3 42
+ def self.cs2() = s3 42
+ def self.cs3(x) = s3 x + 1
+ }
+ o = c.new
+ assert_equal(42, o.m1)
+ assert_equal(43, o.m3(o.m2))
+ assert_equal(42, c.s1)
+ assert_equal(43, c.s3(c.s2))
+ assert_equal(43, o.cm1)
+ assert_equal(45, o.cm3(o.cm2))
+ assert_equal(43, c.cs1)
+ assert_equal(45, c.cs3(c.cs2))
end
diff --git a/test/t/unicode.rb b/test/t/unicode.rb
index 8622ae08a..c8602da5a 100644
--- a/test/t/unicode.rb
+++ b/test/t/unicode.rb
@@ -1,15 +1,15 @@
# Test of the \u notation
assert('bare \u notation test') do
- # Mininum and maximum one byte characters
+ # Minimum and maximum one byte characters
assert_equal("\x00", "\u0000")
assert_equal("\x7F", "\u007F")
- # Mininum and maximum two byte characters
+ # Minimum and maximum two byte characters
assert_equal("\xC2\x80", "\u0080")
assert_equal("\xDF\xBF", "\u07FF")
- # Mininum and maximum three byte characters
+ # Minimum and maximum three byte characters
assert_equal("\xE0\xA0\x80", "\u0800")
assert_equal("\xEF\xBF\xBF", "\uFFFF")
@@ -17,19 +17,19 @@ assert('bare \u notation test') do
end
assert('braced \u notation test') do
- # Mininum and maximum one byte characters
+ # Minimum and maximum one byte characters
assert_equal("\x00", "\u{0000}")
assert_equal("\x7F", "\u{007F}")
- # Mininum and maximum two byte characters
+ # Minimum and maximum two byte characters
assert_equal("\xC2\x80", "\u{0080}")
assert_equal("\xDF\xBF", "\u{07FF}")
- # Mininum and maximum three byte characters
+ # Minimum and maximum three byte characters
assert_equal("\xE0\xA0\x80", "\u{0800}")
assert_equal("\xEF\xBF\xBF", "\u{FFFF}")
- # Mininum and maximum four byte characters
+ # Minimum and maximum four byte characters
assert_equal("\xF0\x90\x80\x80", "\u{10000}")
assert_equal("\xF4\x8F\xBF\xBF", "\u{10FFFF}")
end
diff --git a/test/t/vformat.rb b/test/t/vformat.rb
new file mode 100644
index 000000000..f645351ee
--- /dev/null
+++ b/test/t/vformat.rb
@@ -0,0 +1,58 @@
+# coding: utf-8-emacs
+def sclass(v)
+ class << v
+ self
+ end
+end
+
+assert('mrb_vformat') do
+ vf = TestVFormat
+ assert_equal '', vf.z('')
+ assert_equal 'No specifier!', vf.z('No specifier!')
+ assert_equal '`c`: C', vf.c('`c`: %c', ?C)
+ assert_equal '`d`: 123', vf.d('`d`: %d', 123)
+ assert_equal '`d`: -79', vf.d('`d`: %d', -79)
+ assert_equal '`i`: 514', vf.i('`i`: %i', 514)
+ assert_equal '`i`: -83', vf.i('`i`: %i', -83)
+ assert_equal '`t`: NilClass', vf.v('`t`: %t', nil)
+ assert_equal '`t`: FalseClass', vf.v('`t`: %t', false)
+ assert_equal '`t`: TrueClass', vf.v('`t`: %t', true)
+ assert_equal '`t`: Integer', vf.v('`t`: %t', 0)
+ assert_equal '`t`: Hash', vf.v('`t`: %t', {k: "value"})
+ assert_match '#<Class:#<Class:#<Hash:0x*>>>', vf.v('%t', sclass({}))
+ assert_equal 'string and length', vf.l('string %l length', 'andante', 3)
+ assert_equal '`n`: sym', vf.n('`n`: %n', :sym)
+ assert_equal '%C文字列����%', vf.s('%s', '%C文字列����%')
+ assert_equal '`C`: Kernel module', vf.C('`C`: %C module', Kernel)
+ assert_equal '`C`: NilClass', vf.C('`C`: %C', nil.class)
+ assert_match '#<Class:#<String:0x*>>', vf.C('%C', sclass(""))
+ assert_equal '`T`: NilClass', vf.v('`T`: %T', nil)
+ assert_equal '`T`: FalseClass', vf.v('`T`: %T', false)
+ assert_equal '`T`: TrueClass', vf.v('`T`: %T', true)
+ assert_equal '`T`: Integer', vf.v('`T`: %T', 0)
+ assert_equal '`T`: Hash', vf.v('`T`: %T', {k: "value"})
+ assert_match 'Class', vf.v('%T', sclass({}))
+ assert_equal '`Y`: nil', vf.v('`Y`: %Y', nil)
+ assert_equal '`Y`: false', vf.v('`Y`: %Y', false)
+ assert_equal '`Y`: true', vf.v('`Y`: %Y', true)
+ assert_equal '`Y`: Integer', vf.v('`Y`: %Y', 0)
+ assert_equal '`Y`: Hash', vf.v('`Y`: %Y', {k: "value"})
+ assert_equal 'Class', vf.v('%Y', sclass({}))
+ assert_match '#<Class:#<String:0x*>>', vf.v('%v', sclass(""))
+ assert_equal '`v`: 1...3', vf.v('`v`: %v', 1...3)
+ assert_equal '`S`: {:a=>1, "b"=>"c"}', vf.v('`S`: %S', {a: 1, "b" => ?c})
+ assert_equal 'percent: %', vf.z('percent: %%')
+ assert_equal '"I": inspect char', vf.c('%!c: inspect char', ?I)
+ assert_equal '709: inspect mrb_int', vf.i('%!d: inspect mrb_int', 709)
+ assert_equal '"a\x00b\xff"', vf.l('%!l', "a\000b\xFFc\000d", 4)
+ assert_equal ':"&.": inspect symbol', vf.n('%!n: inspect symbol', :'&.')
+ assert_equal 'inspect "String"', vf.v('inspect %!v', 'String')
+ assert_equal 'inspect Array: [1, :x, {}]', vf.v('inspect Array: %!v', [1,:x,{}])
+ assert_match '`!C`: #<Class:0x*>', vf.C('`!C`: %!C', Class.new)
+ assert_equal 'escape: \\%a,b,c,d', vf.v('escape: \\\\\%a,b,\c%v', ',d')
+
+ skip unless Object.const_defined?(:Float)
+ assert_equal '`f`: 0.0125', vf.f('`f`: %f', 0.0125)
+ assert_equal '-Infinity', vf.f('%f', -Float::INFINITY)
+ assert_equal 'NaN: Not a Number', vf.f('%f: Not a Number', Float::NAN)
+end