package scala.collection.immutable import org.junit.runner.RunWith import org.junit.runners.JUnit4 import org.junit.Test import scala.math._ import scala.util._ /* Tests various ranges by making sure they all agree on the same answers. */ @RunWith(classOf[JUnit4]) class RangeConsistencyTest { def r2nr[T: Integral]( r: Range, puff: T, stride: T, check: (T,T) => Boolean, bi: T => BigInt ): List[(BigInt,Try[Int])] = { val num = implicitly[Integral[T]] import num._ val one = num.one if (!check(puff, fromInt(r.start))) return Nil val start = puff * fromInt(r.start) val sp1 = start + one val sn1 = start - one if (!check(puff, fromInt(r.end))) return Nil val end = puff * fromInt(r.end) val ep1 = end + one val en1 = end - one if (!check(stride, fromInt(r.step))) return Nil val step = stride * fromInt(r.step) def NR(s: T, e: T, i: T) = { val delta = (bi(e) - bi(s)).abs - (if (r.isInclusive) 0 else 1) val n = if (r.length == 0) BigInt(0) else delta / bi(i).abs + 1 if (r.isInclusive) { (n, Try(NumericRange.inclusive(s,e,i).length)) } else { (n, Try(NumericRange(s,e,i).length)) } } List(NR(start, end, step)) ::: (if (sn1 < start) List(NR(sn1, end, step)) else Nil) ::: (if (start < sp1) List(NR(sp1, end, step)) else Nil) ::: (if (en1 < end) List(NR(start, en1, step)) else Nil) ::: (if (end < ep1) List(NR(start, ep1, step)) else Nil) } // Motivated by SI-4370: Wrong result for Long.MinValue to Long.MaxValue by Int.MaxValue @Test def rangeChurnTest() { val rn = new Random(4370) for (i <- 0 to 10000) { control.Breaks.breakable { val start = rn.nextInt val end = rn.nextInt val step = rn.nextInt(4) match { case 0 => 1 case 1 => -1 case 2 => (rn.nextInt(11)+2)*(2*rn.nextInt(2)+1) case 3 => var x = rn.nextInt; while (x==0) x = rn.nextInt; x } val r = if (rn.nextBoolean) Range.inclusive(start, end, step) else Range(start, end, step) try { r.length } catch { case iae: IllegalArgumentException => control.Breaks.break } val lpuff = rn.nextInt(4) match { case 0 => 1L case 1 => rn.nextInt(11)+2L case 2 => 1L << rn.nextInt(60) case 3 => math.max(1L, math.abs(rn.nextLong)) } val lstride = rn.nextInt(4) match { case 0 => lpuff case 1 => 1L case 2 => 1L << rn.nextInt(60) case 3 => math.max(1L, math.abs(rn.nextLong)) } val lr = r2nr[Long]( r, lpuff, lstride, (a,b) => { val x = BigInt(a)*BigInt(b); x.isValidLong }, x => BigInt(x) ) lr.foreach{ case (n,t) => assert( t match { case Failure(_) => n > Int.MaxValue case Success(m) => n == m }, (r.start, r.end, r.step, r.isInclusive, lpuff, lstride, n, t) )} val bipuff = rn.nextInt(3) match { case 0 => BigInt(1) case 1 => BigInt(rn.nextLong) + Long.MaxValue + 2 case 2 => BigInt("1" + "0"*(rn.nextInt(100)+1)) } val bistride = rn.nextInt(3) match { case 0 => bipuff case 1 => BigInt(1) case 2 => BigInt("1" + "0"*(rn.nextInt(100)+1)) } val bir = r2nr[BigInt](r, bipuff, bistride, (a,b) => true, identity) bir.foreach{ case (n,t) => assert( t match { case Failure(_) => n > Int.MaxValue case Success(m) => n == m }, (r.start, r.end, r.step, r.isInclusive, bipuff, bistride, n, t) )} }} } @Test def testSI4370() { assert{ Try((Long.MinValue to Long.MaxValue by Int.MaxValue).length) match { case Failure(iae: IllegalArgumentException) => true case _ => false } }} @Test def testSI6736() { // These operations on overfull ranges should all succeed. assert( (0 to Int.MaxValue).contains(4) ) assert( !((Int.MinValue to 0).contains(4)) ) assert( (Int.MinValue to 0).last == 0 ) assert( (Int.MinValue until 5).last == 4 ) assert( (-7 to -99 by -4).last == -99 && (-7 until -99 by -4).last == -95 ) assert( (Int.MinValue to 5) == (Int.MinValue until 6) ) assert( (-3 to Int.MaxValue).drop(4).length == Int.MaxValue ) assert( (-3 to Int.MaxValue).take(1234) == (-3 to 1230) ) assert( (-3 to Int.MaxValue).dropRight(4).length == Int.MaxValue ) assert( (-3 to Int.MaxValue).takeRight(1234).length == 1234 ) assert( (-3 to Int.MaxValue).dropWhile(_ <= 0).length == Int.MaxValue ) assert( (-3 to Int.MaxValue).span(_ <= 0) match { case (a,b) => a.length == 4 && b.length == Int.MaxValue } ) } @Test def testSI9348() { // Test exclusive range with (end-start) != 0 (mod step) assert( (0.0f until 0.4f by 0.25f) sameElements List(0.0f, 0.25f) ) assert( (1.0 until 2.2 by 0.5) sameElements List(1.0, 1.5, 2.0) ) def bd(d: Double) = BigDecimal(d) val bdRange = bd(-10.0) until bd(0.0) by bd(4.5) assert( bdRange sameElements List(bd(-10.0), bd(-5.5), bd(-1.0)) ) } @Test def test_SI9388() { val possiblyNotDefaultNumeric = new scala.math.Numeric[Int] { def fromInt(x: Int) = x def minus(x: Int, y: Int): Int = x - y def negate(x: Int): Int = -x def plus(x: Int, y: Int): Int = x + y def times(x: Int, y: Int): Int = x*y def toDouble(x: Int): Double = x.toDouble def toFloat(x: Int): Float = x.toFloat def toInt(x: Int): Int = x def toLong(x: Int): Long = x.toLong def compare(x: Int, y: Int) = x compare y } val r = (Int.MinValue to Int.MaxValue by (1<<23)) val nr = NumericRange(Int.MinValue, Int.MaxValue, 1 << 23) assert({ var i = 0; r.foreach(_ => i += 1); i } == 512) assert({ var i = 0; nr.foreach(_ => i += 1); i } == 512) assert(r.sum == Int.MinValue) assert(nr.sum == Int.MinValue) assert(r.sum(possiblyNotDefaultNumeric) == Int.MinValue) assert(nr.sum(possiblyNotDefaultNumeric) == Int.MinValue) } }