summaryrefslogtreecommitdiff
path: root/test/files/jvm/duration-tck.scala
blob: 7db6c49964e21beca4733ee4a6485bba5de0f7af (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
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
/**
 *  Copyright (C) 2012 Typesafe Inc. <http://www.typesafe.com>
 */

import scala.concurrent.duration._
import scala.reflect._
import scala.tools.partest.TestUtil.intercept

import scala.language.{ postfixOps }

object Test extends App {

  implicit class Assert(val left: Any) extends AnyVal {
    import Duration.Undefined
    def mustBe(right: Any) = right match {
      case r: Double if r.isNaN                        => assert(left.asInstanceOf[Double].isNaN, s"$left was not NaN")
      case r: Double if r == 0 && r.compareTo(0) == -1 => assert(left == 0 && left.asInstanceOf[Double].compareTo(0) == -1, s"$left was not -0.0")
      case Undefined                                   => assert(left.asInstanceOf[AnyRef] eq Undefined, s"$left was not Undefined")
      case _                                           => assert(left == right, s"$left was not equal to $right")
    }
  }

  val zero = 0 seconds
  val one = 1 second
  val two = one + one
  val three = 3 * one
  val inf = Duration.Inf
  val minf = Duration.MinusInf
  val undef = Duration.Undefined
  val inputs = List(zero, one, inf, minf, undef)
  val nan = Double.NaN

  // test field ops
  one.isFinite mustBe true
  0 * one mustBe zero
  2 * one mustBe two
  three - two mustBe one
  three / 3 mustBe one
  two / one mustBe 2
  one + zero mustBe one
  one / 1000000 mustBe 1.micro


  // test infinities

   inf.isFinite mustBe false
  minf.isFinite mustBe false

    inf mustBe  inf
   minf mustBe minf
   -inf mustBe minf
  -minf mustBe  inf

  minf +  inf mustBe undef
   inf -  inf mustBe undef
   inf + minf mustBe undef
  minf - minf mustBe undef

   inf +  inf mustBe  inf
   inf - minf mustBe  inf
  minf -  inf mustBe minf
  minf + minf mustBe minf

  for (i <- Seq(zero, one, two, three)) {
    i - inf mustBe minf
    i - minf mustBe inf
  }

  inf.compareTo(inf) mustBe 0
  inf.compareTo(one) mustBe 1
  inf.compareTo(minf) mustBe 1
  minf.compareTo(minf) mustBe 0
  minf.compareTo(one) mustBe -1
  minf.compareTo(inf) mustBe -1

  assert(inf != minf)
  assert(minf != inf)
  assert(one != inf)
  assert(minf != one)

  inf mustBe (minf * -1d)
  inf mustBe (minf / -1d)

   one /  inf mustBe  0d
  -one /  inf mustBe -0d
   one / minf mustBe -0d
  -one / minf mustBe  0d

  inputs filterNot (_.isFinite) foreach (x => x / zero mustBe x.toUnit(DAYS))
  inputs filterNot (_.isFinite) foreach (_ * 0d mustBe undef)
  inputs filterNot (_.isFinite) foreach (_ * -0d mustBe undef)
  inputs filterNot (_.isFinite) foreach (x => x * Double.PositiveInfinity mustBe x)
  inputs filterNot (_.isFinite) foreach (x => x * Double.NegativeInfinity mustBe -x)

  inf.toUnit(SECONDS) mustBe Double.PositiveInfinity
  minf.toUnit(MINUTES) mustBe Double.NegativeInfinity
  Duration.fromNanos(Double.PositiveInfinity) mustBe inf
  Duration.fromNanos(Double.NegativeInfinity) mustBe minf


  // test undefined & NaN

  undef.isFinite mustBe false
  -undef mustBe undef
  assert(undef != undef)
  assert(undef eq undef)

  inputs foreach (_ + undef mustBe undef)
  inputs foreach (_ - undef mustBe undef)
  inputs foreach (_ / undef mustBe nan)
  inputs foreach (_ / nan mustBe undef)
  inputs foreach (_ * nan mustBe undef)
  inputs foreach (undef + _ mustBe undef)
  inputs foreach (undef - _ mustBe undef)
  inputs foreach (undef / _ mustBe nan)
  undef / 1 mustBe undef
  undef / nan mustBe undef
  undef * 1 mustBe undef
  undef * nan mustBe undef
  inputs foreach (x => x / zero mustBe x.toUnit(SECONDS) / 0d)
  inputs foreach (x => x / 0d mustBe Duration.fromNanos(x.toUnit(NANOSECONDS) / 0d))
  inputs foreach (x => x / -0d mustBe Duration.fromNanos(x.toUnit(NANOSECONDS) / -0d))

  inputs filterNot (_ eq undef) foreach (_ compareTo undef mustBe -1)
  inputs filterNot (_ eq undef) foreach (undef compareTo _ mustBe 1)
  undef compare undef mustBe 0

  undef.toUnit(DAYS) mustBe nan
  Duration.fromNanos(nan) mustBe undef


  // test overflow protection
  for (unit  Seq(DAYS, HOURS, MINUTES, SECONDS, MILLISECONDS, MICROSECONDS, NANOSECONDS)) {
    val x = unit.convert(Long.MaxValue, NANOSECONDS)
    val dur = Duration(x, unit)
    val mdur = Duration(-x, unit)
    -mdur mustBe (dur)
    intercept[IllegalArgumentException] { Duration(x + 10000000d, unit) }
    intercept[IllegalArgumentException] { Duration(-x - 10000000d, unit) }
    if (unit != NANOSECONDS) {
      intercept[IllegalArgumentException] { Duration(x + 1, unit) }
      intercept[IllegalArgumentException] { Duration(-x - 1, unit) }
    }
    intercept[IllegalArgumentException] { dur + 1.day }
    intercept[IllegalArgumentException] { mdur - 1.day }
    intercept[IllegalArgumentException] { dur * 1.1 }
    intercept[IllegalArgumentException] { mdur * 1.1 }
    intercept[IllegalArgumentException] { dur * 2.1 }
    intercept[IllegalArgumentException] { mdur * 2.1 }
    intercept[IllegalArgumentException] { dur / 0.9 }
    intercept[IllegalArgumentException] { mdur / 0.9 }
    intercept[IllegalArgumentException] { dur / 0.4 }
    intercept[IllegalArgumentException] { mdur / 0.4 }
    Duration(x + unit.toString.toLowerCase)
    Duration("-" + x + unit.toString.toLowerCase)
    intercept[IllegalArgumentException] { Duration("%.0f".format(x + 10000000d) + unit.toString.toLowerCase) }
    intercept[IllegalArgumentException] { Duration("-%.0f".format(x + 10000000d) + unit.toString.toLowerCase) }
  }
  intercept[IllegalArgumentException] { Duration.fromNanos(1e20) }
  intercept[IllegalArgumentException] { Duration.fromNanos(-1e20) }


  // test precision
  1.second + 1.millisecond mustBe 1001.milliseconds
  100000.days + 1.nanosecond mustBe 8640000000000000001L.nanoseconds
  1.5.seconds.toSeconds mustBe 1
  (-1.5).seconds.toSeconds mustBe -1


  // test unit stability
  1000.millis.unit mustBe MILLISECONDS
  (1000.millis + 0.days).unit mustBe MILLISECONDS
  1.second.unit mustBe SECONDS
  (1.second + 1.millisecond).unit mustBe MILLISECONDS


  // test Deadline
  val dead = 2.seconds.fromNow
  val dead2 = 2 seconds fromNow

  { val l = dead.timeLeft; assert(l > 1.second, s"$l <= 1.second") }
  { val l = dead2.timeLeft; assert(l > 1.second, s"$l <= 1.second") }

  Thread.sleep(1.second.toMillis)

  // unfortunately it can happen that the sleep() returns early without throwing
  { val l = dead.timeLeft; assert(l <= 1100.millis, s"$l > 1100.millis") }
  { val l = dead2.timeLeft; assert(l <= 1100.millis, s"$l > 1100.millis") }


  // test integer mul/div
  500.millis * 2 mustBe 1.second
  (500.millis * 2).unit mustBe MILLISECONDS
  1.second / 2 mustBe 500.millis
  (1.second / 2).unit mustBe MILLISECONDS


  // check statically retaining finite-ness
  val finiteDuration: FiniteDuration = 1.second * 2 / 3 mul 5 div 4 plus 3.seconds minus 1.millisecond min 1.second max 1.second
  val finite2: FiniteDuration = 2 * 1.second + 3L * 2.seconds
  finite2 mustBe 8.seconds
  ((2 seconds fromNow).timeLeft: FiniteDuration) < 4.seconds mustBe true
  val finite3: FiniteDuration = 3.5 seconds span

}