Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix Range#eql? checks that start and end of range are same using MethodNames.EQL #3960

Closed
wants to merge 9 commits into from

Conversation

@monkstone
Copy link
Contributor

monkstone commented Jun 9, 2016

Just be clear checks start of one range is same numeric type as start of second and end of one range is same numeric type as end of second.

@enebo
Copy link
Member

enebo commented Jun 9, 2016

@monkstone @kares You have fixed the compat in this case but you could go a little further. I see in MRI that it dispatches to begin.eql?(other.begin) + same for end. In theory, definiing a new eql? on an arbrtrary type (for begin or end) could still work whereas this PR will assume it has to be a builtin numeric type.

Since these are new checks and we were not checking at all this PR could break existing code.

@monkstone
Copy link
Contributor Author

monkstone commented Jun 9, 2016

I had kind of assumed that it is numeric equalInternal that is anomalous, and that's why I came up with this PR, all falls through to original logic unless there is an obvious mismatch in the numeric type. I don't think I'm up to the job if it goes deeper than that.

@monkstone
Copy link
Contributor Author

monkstone commented Jun 10, 2016

@enebo you are right of course just check this out:-

class Xs                # represent a string of 'x's
  include Comparable
  attr :length
  def initialize(n)
    @length = n
  end
  def succ
    Xs.new(@length + 1)
  end
  def <=>(other)
    @length <=> other.length
  end
  def to_s
    sprintf "%2d #{inspect}", @length
  end
  def inspect
    'x' * @length
  end
end

class Ys                # represent a string of 'y's
  include Comparable
  attr :length
  def initialize(n)
    @length = n
  end
  def succ
    Ys.new(@length + 1)
  end
  def <=>(other)
    @length <=> other.length
  end
  def to_s
    sprintf "%2d #{inspect}", @length
  end
  def inspect
    'y' * @length
  end
end

fred = (Xs.new(3)..Xs.new(5))

ted = (Ys.new(3)..Ys.new(5))

puts fred.eql?(ted)

yields false MRI ruby true jruby http://ruby-doc.org/core-2.2.0/Range.html I'll happily close this PR and suggest @kares removes beginner tag

@enebo
Copy link
Member

enebo commented Jun 10, 2016

@monkstone if there is not a test for this in ruby/spec then maybe you could pr spec for this.

Also really all you need to do is something like:

invokedynamic(context, begin, MethodNames.OP_EQL, other.begin).isTrue()

So you could still take a quick stab at convering the instanceof stuff to that?

@monkstone
Copy link
Contributor Author

monkstone commented Jun 10, 2016

# frozen_string_literal: false
gem 'minitest' # don't use bundled minitest
require 'delegate'
require 'timeout'
require 'bigdecimal'
require 'minitest/autorun'
require 'minitest/pride'

# Custom Range classes Xs and Ys
class Xs # represent a string of 'x's
  include Comparable
  attr :length
  def initialize(n)
    @length = n
  end
  def succ
    Xs.new(@length + 1)
  end
  def <=>(other)
    @length <=> other.length
  end
  def to_s
    sprintf "%2d #{inspect}", @length
  end
  def inspect
    'x' * @length
  end
end

class Ys # represent a string of 'y's
  include Comparable
  attr :length
  def initialize(n)
    @length = n
  end
  def succ
    Ys.new(@length + 1)
  end
  def <=>(other)
    @length <=> other.length
  end
  def to_s
    sprintf "%2d #{inspect}", @length
  end
  def inspect
    'y' * @length
  end
end

class TestRange < Minitest::Test
  def test_new
    assert_equal((0..2), Range.new(0, 2))
    assert_equal((0..2), Range.new(0, 2, false))
    assert_equal((0...2), Range.new(0, 2, true))
  end

  def test_range_string
    # XXX: Is this really the test of Range?
    assert_equal([], ("a" ... "a").to_a)
    assert_equal(["a"], ("a" .. "a").to_a)
    assert_equal(["a"], ("a" ... "b").to_a)
    assert_equal(["a", "b"], ("a" .. "b").to_a)
  end

  def test_range_numeric_string
    assert_equal(["6", "7", "8"], ("6".."8").to_a, "[ruby-talk:343187]")
    assert_equal(["6", "7"], ("6"..."8").to_a)
    assert_equal(["9", "10"], ("9".."10").to_a)
    assert_equal(["09", "10"], ("09".."10").to_a, "[ruby-dev:39361]")
    assert_equal(["9", "10"], (SimpleDelegator.new("9").."10").to_a)
    assert_equal(["9", "10"], ("9"..SimpleDelegator.new("10")).to_a)
  end

  def test_range_symbol
    assert_equal([:a, :b], (:a .. :b).to_a)
  end

  def test_evaluation_order
    arr = [1,2]
    r = (arr.shift)..(arr.shift)
    assert_equal(1..2, r, "[ruby-dev:26383]")
  end

  class DuckRange
    def initialize(b,e,excl=false)
      @begin = b
      @end = e
      @excl = excl
    end
    attr_reader :begin, :end

    def exclude_end?
      @excl
    end
  end

  def test_duckrange
    assert_equal("bc", "abcd"[DuckRange.new(1,2)])
  end

  def test_min
    assert_equal(1, (1..2).min)
    assert_equal(nil, (2..1).min)
    assert_equal(1, (1...2).min)

    assert_equal(1.0, (1.0..2.0).min)
    assert_equal(nil, (2.0..1.0).min)
    assert_equal(1, (1.0...2.0).min)

    assert_equal(0, (0..0).min)
    assert_equal(nil, (0...0).min)

    assert_equal([0,1,2], (0..10).min(3))
    assert_equal([0,1], (0..1).min(3))
  end

  def test_max
    assert_equal(2, (1..2).max)
    assert_equal(nil, (2..1).max)
    assert_equal(1, (1...2).max)

    assert_equal(2.0, (1.0..2.0).max)
    assert_equal(nil, (2.0..1.0).max)
    assert_raises(TypeError) { (1.0...2.0).max }
    assert_raises(TypeError) { (1...1.5).max }
    assert_raises(TypeError) { (1.5...2).max }

    assert_equal(-0x80000002, ((-0x80000002)...(-0x80000001)).max)

    assert_equal(0, (0..0).max)
    assert_equal(nil, (0...0).max)

    assert_equal([10,9,8], (0..10).max(3))
    assert_equal([9,8,7], (0...10).max(3))
  end

  def test_initialize_twice
    r = eval("1..2")
    assert_raises(NameError) { r.instance_eval { initialize 3, 4 } }
    assert_raises(NameError) { r.instance_eval { initialize_copy 3..4 } }
  end

  def test_uninitialized_range
    r = Range.allocate
    s = Marshal.dump(r)
    r = Marshal.load(s)
    assert_silent { r.instance_eval { initialize 5, 6} }
  end

  def test_bad_value
    assert_raises(ArgumentError) { (1 .. :a) }
  end

  def test_exclude_end
    refute_predicate(0..1, :exclude_end?)
    assert_predicate(0...1, :exclude_end?)
  end

  def test_eq
    r = (0..1)
    assert_equal(r, r)
    assert_equal(r, (0..1))
    refute_equal(r, 0)
    refute_equal(r, (1..2))
    refute_equal(r, (0..2))
    refute_equal(r, (0...1))
    subclass = Class.new(Range)
    assert_equal(r, subclass.new(0,1))
  end

  def test_eql
    r = (0..1)
    assert_operator(r, :eql?, r)
    assert_operator(r, :eql?, 0..1)
    refute_operator(r, :eql?, 0..1.0)
    refute_operator(r, :eql?, 0)
    refute_operator(r, :eql?, 1..2)
    refute_operator(r, :eql?, 0..2)
    refute_operator(r, :eql?, 0...1)
    subclass = Class.new(Range)
    assert_operator(r, :eql?, subclass.new(0,1))
  end

  def test_custom_range_eql
    r = (Xs.new(3)..Xs.new(5))
    assert_operator(r, :eql?, r)
    assert_operator(r, :eql?, (Xs.new(3)..Xs.new(5)))
    refute_operator(r, :eql?, (Ys.new(3)..Ys.new(5)))
    assert_operator(r, :eql?, subclass.new(Xs.new(3), Xs.new(5)))
  end

  def test_hash
    assert_kind_of(Fixnum, (0..1).hash)
    assert_equal((0..1).hash, (0..1).hash)
    refute_equal((0..1).hash, (0...1).hash)
  end

  def test_step
    a = []
    (0..10).step {|x| a << x }
    assert_equal([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10], a)

    a = []
    (0..10).step(2) {|x| a << x }
    assert_equal([0, 2, 4, 6, 8, 10], a)

    assert_raises(ArgumentError) { (0..10).step(-1) { } }
    assert_raises(ArgumentError) { (0..10).step(0) { } }

    a = []
    ("a" .. "z").step(2) {|x| a << x }
    assert_equal(%w(a c e g i k m o q s u w y), a)

    a = []
    ("a" .. "z").step(2**32) {|x| a << x }
    assert_equal(["a"], a)

    a = []
    (2**32-1 .. 2**32+1).step(2) {|x| a << x }
    assert_equal([4294967295, 4294967297], a)
    zero = (2**32).coerce(0).first
    assert_raises(ArgumentError) { (2**32-1 .. 2**32+1).step(zero) { } }

    o1 = Object.new
    o2 = Object.new
    def o1.<=>(x); -1; end
    def o2.<=>(x); 0; end
    assert_raises(TypeError) { (o1..o2).step(1) { } }

    class << o1; self; end.class_eval do
      define_method(:succ) { o2 }
    end
    a = []
    (o1..o2).step(1) {|x| a << x }
    assert_equal([o1, o2], a)

    a = []
    (o1...o2).step(1) {|x| a << x }
    assert_equal([o1], a)

    assert_silent { (0..2).step(0.5) {|x| } } # ("[ruby-dev:34557]")

    a = []
    (0..2).step(0.5) {|x| a << x }
    assert_equal([0, 0.5, 1.0, 1.5, 2.0], a)

    a = []
    (0x40000000..0x40000002).step(0.5) {|x| a << x }
    assert_equal([1073741824, 1073741824.5, 1073741825.0, 1073741825.5, 1073741826], a)

    o = Object.new
    def o.to_int() 1 end
    assert_silent { (0..2).step(o) {|x| } } # ("[ruby-dev:34558]")
  end

  def test_step_ruby_core_35753
    assert_equal(6, (1...6.3).step.to_a.size)
    assert_equal(5, (1.1...6).step.to_a.size)
    assert_equal(5, (1...6).step(1.1).to_a.size)
    assert_equal(3, (1.0...5.4).step(1.5).to_a.size)
    assert_equal(3, (1.0...5.5).step(1.5).to_a.size)
    assert_equal(4, (1.0...5.6).step(1.5).to_a.size)
  end

  def test_each
    a = []
    (0..10).each {|x| a << x }
    assert_equal([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10], a)

    o1 = Object.new
    o2 = Object.new
    def o1.setcmp(v) @cmpresult = v end
    o1.setcmp(-1)
    def o1.<=>(x); @cmpresult; end
    def o2.setcmp(v) @cmpresult = v end
    o2.setcmp(0)
    def o2.<=>(x); @cmpresult; end
    class << o1; self; end.class_eval do
      define_method(:succ) { o2 }
    end

    r1 = (o1..o2)
    r2 = (o1...o2)

    a = []
    r1.each {|x| a << x }
    assert_equal([o1, o2], a)

    a = []
    r2.each {|x| a << x }
    assert_equal([o1], a)

    o2.setcmp(1)

    a = []
    r1.each {|x| a << x }
    assert_equal([o1], a)

    o2.setcmp(nil)

    a = []
    r1.each {|x| a << x }
    assert_equal([o1], a)

    o1.setcmp(nil)

    a = []
    r2.each {|x| a << x }
    assert_equal([], a)
  end

  def test_begin_end
    assert_equal(0, (0..1).begin)
    assert_equal(1, (0..1).end)
    assert_equal(1, (0...1).end)
  end

  def test_first_last
    assert_equal([0, 1, 2], (0..10).first(3))
    assert_equal([8, 9, 10], (0..10).last(3))
    assert_equal(0, (0..10).first)
    assert_equal(10, (0..10).last)
    assert_equal("a", ("a".."c").first)
    assert_equal("c", ("a".."c").last)
    assert_equal(0, (2..0).last)

    assert_equal([0, 1, 2], (0...10).first(3))
    assert_equal([7, 8, 9], (0...10).last(3))
    assert_equal(0, (0...10).first)
    assert_equal(10, (0...10).last)
    assert_equal("a", ("a"..."c").first)
    assert_equal("c", ("a"..."c").last)
    assert_equal(0, (2...0).last)
  end

  def test_to_s
    assert_equal("0..1", (0..1).to_s)
    assert_equal("0...1", (0...1).to_s)

    bug11767 = '[ruby-core:71811] [Bug #11767]'
    assert_predicate(("0".taint.."1").to_s, :tainted?, bug11767)
    assert_predicate(("0".."1".taint).to_s, :tainted?, bug11767)
    assert_predicate(("0".."1").taint.to_s, :tainted?, bug11767)
  end

  def test_inspect
    assert_equal("0..1", (0..1).inspect)
    assert_equal("0...1", (0...1).inspect)

    bug11767 = '[ruby-core:71811] [Bug #11767]'
    assert_predicate(("0".taint.."1").inspect, :tainted?, bug11767)
    assert_predicate(("0".."1".taint).inspect, :tainted?, bug11767)
    assert_predicate(("0".."1").taint.inspect, :tainted?, bug11767)
  end

  def test_eqq
    assert_operator(0..10, :===, 5)
    refute_operator(0..10, :===, 11)
  end

  def test_eqq_time
    skip "TypeError: can't iterate from Time jruby"
    bug11113 = '[ruby-core:69052] [Bug #11113]'
    t = Time.now
    assert_silent {
    assert_operator(t..(t + 10), :===, t + 5)
    }
  end

  def test_include
    assert_includes("a".."z", "c")
    refute_includes("a".."z", "5")
    assert_includes("a"..."z", "y")
    refute_includes("a"..."z", "z")
    refute_includes("a".."z", "cc")
    assert_includes(0...10, 5)
  end

  def test_cover
    assert_operator("a".."z", :cover?, "c")
    refute_operator("a".."z", :cover?, "5")
    assert_operator("a"..."z", :cover?, "y")
    refute_operator("a"..."z", :cover?, "z")
    assert_operator("a".."z", :cover?, "cc")
  end

  def test_beg_len
    o = Object.new
    assert_raises(TypeError) { [][o] }
    class << o; attr_accessor :begin end
    o.begin = -10
    assert_raises(TypeError) { [][o] }
    class << o; attr_accessor :end end
    o.end = 0
    assert_raises(NoMethodError) { [][o] }
    def o.exclude_end=(v) @exclude_end = v end
    def o.exclude_end?() @exclude_end end
    o.exclude_end = false
    assert_nil([0][o])
    assert_raises(RangeError) { [0][o] = 1 }
    o.begin = 10
    o.end = 10
    assert_nil([0][o])
    o.begin = 0
    assert_equal([0], [0][o])
    o.begin = 2
    o.end = 0
    assert_equal([], [0, 1, 2][o])
  end
end

The modified jruby fails above test same as MRI ruby with custom test
Expected xxx..xxxxx to be eql? xxx..xxxxx so may'be we are now OK!!!

@kares @enebo
Will attempt to translate to Test/Unit

@kares
Copy link
Member

kares commented Jun 11, 2016

👍 najs ... btw. test-unit 3.x JRuby's using should have most of the minitest asserts, if smt's missing idd should be fairly simple to add it into test_helper.rb ... so that you do not have to convert stuff over.

@monkstone
Copy link
Contributor Author

monkstone commented Jun 11, 2016

# frozen_string_literal: false
gem 'minitest' # don't use bundled minitest
require 'delegate'
require 'timeout'
require 'bigdecimal'
require 'minitest/autorun'
require 'minitest/pride'

# Custom Range classes Xs and Ys
class Custom 
  include Comparable
  attr :length
  def initialize(n)
    @length = n
  end
  def eql?(other)
    inspect.eql? other.inspect
  end
  def inspect
    'custom'
  end
  def <=>(other)
    @length <=> other.length
  end
  def to_s
    sprintf "%2d #{inspect}", @length
  end
end

class Xs < Custom # represent a string of 'x's
  def succ
    Xs.new(@length + 1)
  end
  def inspect
    'x' * @length
  end
end

class Ys < Custom # represent a string of 'y's
  def succ
    Ys.new(@length + 1)
  end
  def inspect
    'y' * @length
  end
end

class TestRange < Minitest::Test
  def test_new
    assert_equal((0..2), Range.new(0, 2))
    assert_equal((0..2), Range.new(0, 2, false))
    assert_equal((0...2), Range.new(0, 2, true))
  end

  def test_range_string
    # XXX: Is this really the test of Range?
    assert_equal([], ("a" ... "a").to_a)
    assert_equal(["a"], ("a" .. "a").to_a)
    assert_equal(["a"], ("a" ... "b").to_a)
    assert_equal(["a", "b"], ("a" .. "b").to_a)
  end

  def test_range_numeric_string
    assert_equal(["6", "7", "8"], ("6".."8").to_a, "[ruby-talk:343187]")
    assert_equal(["6", "7"], ("6"..."8").to_a)
    assert_equal(["9", "10"], ("9".."10").to_a)
    assert_equal(["09", "10"], ("09".."10").to_a, "[ruby-dev:39361]")
    assert_equal(["9", "10"], (SimpleDelegator.new("9").."10").to_a)
    assert_equal(["9", "10"], ("9"..SimpleDelegator.new("10")).to_a)
  end

  def test_range_symbol
    assert_equal([:a, :b], (:a .. :b).to_a)
  end

  def test_evaluation_order
    arr = [1,2]
    r = (arr.shift)..(arr.shift)
    assert_equal(1..2, r, "[ruby-dev:26383]")
  end

  class DuckRange
    def initialize(b,e,excl=false)
      @begin = b
      @end = e
      @excl = excl
    end
    attr_reader :begin, :end

    def exclude_end?
      @excl
    end
  end

  def test_duckrange
    assert_equal("bc", "abcd"[DuckRange.new(1,2)])
  end

  def test_min
    assert_equal(1, (1..2).min)
    assert_equal(nil, (2..1).min)
    assert_equal(1, (1...2).min)

    assert_equal(1.0, (1.0..2.0).min)
    assert_equal(nil, (2.0..1.0).min)
    assert_equal(1, (1.0...2.0).min)

    assert_equal(0, (0..0).min)
    assert_equal(nil, (0...0).min)

    assert_equal([0,1,2], (0..10).min(3))
    assert_equal([0,1], (0..1).min(3))
  end

  def test_max
    assert_equal(2, (1..2).max)
    assert_equal(nil, (2..1).max)
    assert_equal(1, (1...2).max)

    assert_equal(2.0, (1.0..2.0).max)
    assert_equal(nil, (2.0..1.0).max)
    assert_raises(TypeError) { (1.0...2.0).max }
    assert_raises(TypeError) { (1...1.5).max }
    assert_raises(TypeError) { (1.5...2).max }

    assert_equal(-0x80000002, ((-0x80000002)...(-0x80000001)).max)

    assert_equal(0, (0..0).max)
    assert_equal(nil, (0...0).max)

    assert_equal([10,9,8], (0..10).max(3))
    assert_equal([9,8,7], (0...10).max(3))
  end

  def test_initialize_twice
    r = eval("1..2")
    assert_raises(NameError) { r.instance_eval { initialize 3, 4 } }
    assert_raises(NameError) { r.instance_eval { initialize_copy 3..4 } }
  end

  def test_uninitialized_range
    r = Range.allocate
    s = Marshal.dump(r)
    r = Marshal.load(s)
    assert_silent { r.instance_eval { initialize 5, 6} }
  end

  def test_bad_value
    assert_raises(ArgumentError) { (1 .. :a) }
  end

  def test_exclude_end
    refute_predicate(0..1, :exclude_end?)
    assert_predicate(0...1, :exclude_end?)
  end

  def test_eq
    r = (0..1)
    assert_equal(r, r)
    assert_equal(r, (0..1))
    refute_equal(r, 0)
    refute_equal(r, (1..2))
    refute_equal(r, (0..2))
    refute_equal(r, (0...1))
    subclass = Class.new(Range)
    assert_equal(r, subclass.new(0,1))
  end

  def test_eql
    r = (0..1)
    assert_operator(r, :eql?, r)
    assert_operator(r, :eql?, 0..1)
    refute_operator(r, :eql?, 0..1.0)
    refute_operator(r, :eql?, 0)
    refute_operator(r, :eql?, 1..2)
    refute_operator(r, :eql?, 0..2)
    refute_operator(r, :eql?, 0...1)
    subclass = Class.new(Range)

    assert_operator(r, :eql?, subclass.new(0,1))
  end

  def test_custom_range_eql
    r = (Xs.new(3)..Xs.new(5))
    assert_operator(r, :eql?, r)
    assert_operator(r, :eql?, (Xs.new(3)..Xs.new(5)))
    refute_operator(r, :eql?, (Ys.new(3)..Ys.new(5)))
    subclass = Class.new(Range)
    assert_equal(r, subclass.new(Xs.new(3), Xs.new(5)))    
  end

  def test_hash
    assert_kind_of(Fixnum, (0..1).hash)
    assert_equal((0..1).hash, (0..1).hash)
    refute_equal((0..1).hash, (0...1).hash)
  end

  def test_step
    a = []
    (0..10).step {|x| a << x }
    assert_equal([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10], a)

    a = []
    (0..10).step(2) {|x| a << x }
    assert_equal([0, 2, 4, 6, 8, 10], a)

    assert_raises(ArgumentError) { (0..10).step(-1) { } }
    assert_raises(ArgumentError) { (0..10).step(0) { } }

    a = []
    ("a" .. "z").step(2) {|x| a << x }
    assert_equal(%w(a c e g i k m o q s u w y), a)

    a = []
    ("a" .. "z").step(2**32) {|x| a << x }
    assert_equal(["a"], a)

    a = []
    (2**32-1 .. 2**32+1).step(2) {|x| a << x }
    assert_equal([4294967295, 4294967297], a)
    zero = (2**32).coerce(0).first
    assert_raises(ArgumentError) { (2**32-1 .. 2**32+1).step(zero) { } }

    o1 = Object.new
    o2 = Object.new
    def o1.<=>(x); -1; end
    def o2.<=>(x); 0; end
    assert_raises(TypeError) { (o1..o2).step(1) { } }

    class << o1; self; end.class_eval do
      define_method(:succ) { o2 }
    end
    a = []
    (o1..o2).step(1) {|x| a << x }
    assert_equal([o1, o2], a)

    a = []
    (o1...o2).step(1) {|x| a << x }
    assert_equal([o1], a)

    assert_silent { (0..2).step(0.5) {|x| } } # ("[ruby-dev:34557]")

    a = []
    (0..2).step(0.5) {|x| a << x }
    assert_equal([0, 0.5, 1.0, 1.5, 2.0], a)

    a = []
    (0x40000000..0x40000002).step(0.5) {|x| a << x }
    assert_equal([1073741824, 1073741824.5, 1073741825.0, 1073741825.5, 1073741826], a)

    o = Object.new
    def o.to_int() 1 end
    assert_silent { (0..2).step(o) {|x| } } # ("[ruby-dev:34558]")
  end

  def test_step_ruby_core_35753
    assert_equal(6, (1...6.3).step.to_a.size)
    assert_equal(5, (1.1...6).step.to_a.size)
    assert_equal(5, (1...6).step(1.1).to_a.size)
    assert_equal(3, (1.0...5.4).step(1.5).to_a.size)
    assert_equal(3, (1.0...5.5).step(1.5).to_a.size)
    assert_equal(4, (1.0...5.6).step(1.5).to_a.size)
  end

  def test_each
    a = []
    (0..10).each {|x| a << x }
    assert_equal([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10], a)

    o1 = Object.new
    o2 = Object.new
    def o1.setcmp(v) @cmpresult = v end
    o1.setcmp(-1)
    def o1.<=>(x); @cmpresult; end
    def o2.setcmp(v) @cmpresult = v end
    o2.setcmp(0)
    def o2.<=>(x); @cmpresult; end
    class << o1; self; end.class_eval do
      define_method(:succ) { o2 }
    end

    r1 = (o1..o2)
    r2 = (o1...o2)

    a = []
    r1.each {|x| a << x }
    assert_equal([o1, o2], a)

    a = []
    r2.each {|x| a << x }
    assert_equal([o1], a)

    o2.setcmp(1)

    a = []
    r1.each {|x| a << x }
    assert_equal([o1], a)

    o2.setcmp(nil)

    a = []
    r1.each {|x| a << x }
    assert_equal([o1], a)

    o1.setcmp(nil)

    a = []
    r2.each {|x| a << x }
    assert_equal([], a)
  end

  def test_begin_end
    assert_equal(0, (0..1).begin)
    assert_equal(1, (0..1).end)
    assert_equal(1, (0...1).end)
  end

  def test_first_last
    assert_equal([0, 1, 2], (0..10).first(3))
    assert_equal([8, 9, 10], (0..10).last(3))
    assert_equal(0, (0..10).first)
    assert_equal(10, (0..10).last)
    assert_equal("a", ("a".."c").first)
    assert_equal("c", ("a".."c").last)
    assert_equal(0, (2..0).last)

    assert_equal([0, 1, 2], (0...10).first(3))
    assert_equal([7, 8, 9], (0...10).last(3))
    assert_equal(0, (0...10).first)
    assert_equal(10, (0...10).last)
    assert_equal("a", ("a"..."c").first)
    assert_equal("c", ("a"..."c").last)
    assert_equal(0, (2...0).last)
  end

  def test_to_s
    assert_equal("0..1", (0..1).to_s)
    assert_equal("0...1", (0...1).to_s)

    bug11767 = '[ruby-core:71811] [Bug #11767]'
    assert_predicate(("0".taint.."1").to_s, :tainted?, bug11767)
    assert_predicate(("0".."1".taint).to_s, :tainted?, bug11767)
    assert_predicate(("0".."1").taint.to_s, :tainted?, bug11767)
  end

  def test_inspect
    assert_equal("0..1", (0..1).inspect)
    assert_equal("0...1", (0...1).inspect)

    bug11767 = '[ruby-core:71811] [Bug #11767]'
    assert_predicate(("0".taint.."1").inspect, :tainted?, bug11767)
    assert_predicate(("0".."1".taint).inspect, :tainted?, bug11767)
    assert_predicate(("0".."1").taint.inspect, :tainted?, bug11767)
  end

  def test_eqq
    assert_operator(0..10, :===, 5)
    refute_operator(0..10, :===, 11)
  end

  def test_eqq_time
    skip "TypeError: can't iterate from Time jruby"
    bug11113 = '[ruby-core:69052] [Bug #11113]'
    t = Time.now
    assert_silent {
    assert_operator(t..(t + 10), :===, t + 5)
    }
  end

  def test_include
    assert_includes("a".."z", "c")
    refute_includes("a".."z", "5")
    assert_includes("a"..."z", "y")
    refute_includes("a"..."z", "z")
    refute_includes("a".."z", "cc")
    assert_includes(0...10, 5)
  end

  def test_cover
    assert_operator("a".."z", :cover?, "c")
    refute_operator("a".."z", :cover?, "5")
    assert_operator("a"..."z", :cover?, "y")
    refute_operator("a"..."z", :cover?, "z")
    assert_operator("a".."z", :cover?, "cc")
  end

  def test_beg_len
    o = Object.new
    assert_raises(TypeError) { [][o] }
    class << o; attr_accessor :begin end
    o.begin = -10
    assert_raises(TypeError) { [][o] }
    class << o; attr_accessor :end end
    o.end = 0
    assert_raises(NoMethodError) { [][o] }
    def o.exclude_end=(v) @exclude_end = v end
    def o.exclude_end?() @exclude_end end
    o.exclude_end = false
    assert_nil([0][o])
    assert_raises(RangeError) { [0][o] = 1 }
    o.begin = 10
    o.end = 10
    assert_nil([0][o])
    o.begin = 0
    assert_equal([0], [0][o])
    o.begin = 2
    o.end = 0
    assert_equal([], [0, 1, 2][o])
  end
end

@kares @enebo fixed the test now passes all

@monkstone monkstone changed the title Fix Range#eql? that checks that start and end of range are same numeric type Fix Range#eql? that checks that start and end of range are same using Method.EQL Jun 11, 2016
@monkstone monkstone changed the title Fix Range#eql? that checks that start and end of range are same using Method.EQL Fix Range#eql? checks that start and end of range are same using MethodNames.EQL Jun 11, 2016
@kares
Copy link
Member

kares commented Jun 13, 2016

I usually do not add cases under test/mri/ruby ... since its easy to overwrite with a new Ruby version.
instead would either add ruby-specs or just move the test-case into a JRuby specific test/jruby/...
@enebo is it fine to do new test methods under test/mri/ruby ?

@enebo
Copy link
Member

enebo commented Jun 13, 2016

@kares I end up asking @headius to commit back to MRI since he has a commit bit but I agree that these tests would probably be better added as specs. @monkstone sorry we are not messing with you :)

@monkstone
Copy link
Contributor Author

monkstone commented Jun 13, 2016

@enebo @kares I've reverted mri test (perhaps not by approved github way) and modified spec test as best I could, I've gone off rspec completely and favour minitest seems to make much more sense to me and on the odd occasion has behaved more correctly than rspec (which I since mistrust).

@kares
Copy link
Member

kares commented Jun 13, 2016

@monkstone do not see no spec changes except for an empty space change. you could have just moved the new test case into a (new) test_range.rb under: https://github.com/jruby/jruby/tree/master/test/jruby

(0.5..2.4).send(@method, Range.new(0.5, 2.4)).should == true
(0xffff..0xfffff).send(@method, 0xffff..0xfffff).should == true
(0xffff..0xfffff).send(@method, Range.new(0xffff,0xfffff)).should == true
(Xs.new(3)..Xs.new(5)).send(@method, Range.new(Xs.new(3), Xs.new(5)).should == true

This comment has been minimized.

@kares

kares Jun 13, 2016 Member

missed a closing ) here

monkstone added 2 commits Jun 13, 2016
@monkstone
Copy link
Contributor Author

monkstone commented Jun 14, 2016

@kares @enebo I can't get on with mspec (at all), it doesn't seem to work correctly in my hands yet it seems that the above test is passing on travis. So to make permanent changes to ruby spec can someone else do it. I'm sure it would be more encouraging to contributors to have simpler standalone test per class/module etc ruby-spec is a confusing behemoth with lots of indirection (a lot like rspec and rails etc).

@kares
Copy link
Member

kares commented Jun 14, 2016

did some commit squashing and pushed your commits to master those LICENSE block formatting changes are really annoying - watch out for them next time, please. thanks for the hard work!

@enebo
Copy link
Member

enebo commented Jun 14, 2016

@monkstone thanks for going the extra mile for us. :)

@eregon
Copy link
Member

eregon commented Jun 15, 2016

Just a note, if the commit are just pushed and rebased, it would be useful to have a back link to this PR (in one of the commit messages) 😃

@eregon
Copy link
Member

eregon commented Jun 27, 2016

Please review the specs before they come in master, this one just duplicated a shared spec and had no namespacing whatsoever.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Linked issues

Successfully merging this pull request may close these issues.

None yet

4 participants
You can’t perform that action at this time.