diff options
Diffstat (limited to 'test/t')
| -rw-r--r-- | test/t/argumenterror.rb | 16 | ||||
| -rw-r--r-- | test/t/array.rb | 98 | ||||
| -rw-r--r-- | test/t/basicobject.rb | 1 | ||||
| -rw-r--r-- | test/t/bs_block.rb | 75 | ||||
| -rw-r--r-- | test/t/bs_literal.rb | 2 | ||||
| -rw-r--r-- | test/t/class.rb | 49 | ||||
| -rw-r--r-- | test/t/ensure.rb | 34 | ||||
| -rw-r--r-- | test/t/enumerable.rb | 6 | ||||
| -rw-r--r-- | test/t/exception.rb | 15 | ||||
| -rw-r--r-- | test/t/float.rb | 127 | ||||
| -rw-r--r-- | test/t/hash.rb | 1189 | ||||
| -rw-r--r-- | test/t/integer.rb | 128 | ||||
| -rw-r--r-- | test/t/iterations.rb | 2 | ||||
| -rw-r--r-- | test/t/kernel.rb | 105 | ||||
| -rw-r--r-- | test/t/literals.rb | 53 | ||||
| -rw-r--r-- | test/t/methods.rb | 29 | ||||
| -rw-r--r-- | test/t/module.rb | 146 | ||||
| -rw-r--r-- | test/t/nameerror.rb | 8 | ||||
| -rw-r--r-- | test/t/numeric.rb | 95 | ||||
| -rw-r--r-- | test/t/object.rb | 1 | ||||
| -rw-r--r-- | test/t/proc.rb | 2 | ||||
| -rw-r--r-- | test/t/range.rb | 105 | ||||
| -rw-r--r-- | test/t/string.rb | 366 | ||||
| -rw-r--r-- | test/t/superclass.rb | 23 | ||||
| -rw-r--r-- | test/t/symbol.rb | 8 | ||||
| -rw-r--r-- | test/t/syntax.rb | 92 | ||||
| -rw-r--r-- | test/t/unicode.rb | 14 | ||||
| -rw-r--r-- | test/t/vformat.rb | 58 |
28 files changed, 2143 insertions, 704 deletions
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], + ["&", "&"], + [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], + ["&", "&"], + [: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 |
