summaryrefslogtreecommitdiff
path: root/test/junit/scala/collection/immutable/RangeConsistencyTest.scala
blob: 135796979dd0140b65c2c46a47accc16ac93e9b6 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
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)) )
  }
}