From 9da135880d0b78b440f4ce62dd8b7dc156571d71 Mon Sep 17 00:00:00 2001 From: Roland Date: Wed, 5 Sep 2012 18:50:58 +0200 Subject: several fixes to scala.concurrent.util.Duration - add test cases (migrated from Akka sources) - add overflow checking (will throw IllegalArgumentException instead of giving wrong results) - make string parsing more precise when giving >100days in nanoseconds - make method signatures more precise in retaining FiniteDuration throughout calculations - fix mul/div of infinities by negative number - add Ordering for Deadline (was accidentally left out earlier) --- test/files/jvm/duration-java.check | 46 +++++++------- test/files/jvm/duration-java/Test.java | 12 +++- test/files/jvm/duration-tck.scala | 107 +++++++++++++++++++++++++++++++++ 3 files changed, 141 insertions(+), 24 deletions(-) create mode 100644 test/files/jvm/duration-tck.scala (limited to 'test/files/jvm') diff --git a/test/files/jvm/duration-java.check b/test/files/jvm/duration-java.check index 7ae257dcc0..49d06fbe93 100644 --- a/test/files/jvm/duration-java.check +++ b/test/files/jvm/duration-java.check @@ -201,7 +201,7 @@ 6.0E7 seconds => 1000000 minutes 1.0E8 seconds => 100000000 seconds 1.0E9 seconds => 1000000000 seconds - 1.0E12 seconds => 9223372036854775807 nanoseconds + 1.0E12 seconds => class java.lang.IllegalArgumentException 0.0 minutes => 0 days 1.0 minutes => 1 minute 7.0 minutes => 7 minutes @@ -251,8 +251,8 @@ 3.0E7 minutes => 500000 hours 6.0E7 minutes => 1000000 hours 1.0E8 minutes => 100000000 minutes - 1.0E9 minutes => 9223372036854775807 nanoseconds - 1.0E12 minutes => 9223372036854775807 nanoseconds + 1.0E9 minutes => class java.lang.IllegalArgumentException + 1.0E12 minutes => class java.lang.IllegalArgumentException 0.0 hours => 0 days 1.0 hours => 1 hour 7.0 hours => 7 hours @@ -295,15 +295,15 @@ 60000.0 hours => 2500 days 100000.0 hours => 100000 hours 1000000.0 hours => 1000000 hours - 7000000.0 hours => 9223372036854775807 nanoseconds - 1.0E7 hours => 9223372036854775807 nanoseconds - 1.2E7 hours => 9223372036854775807 nanoseconds - 2.4E7 hours => 9223372036854775807 nanoseconds - 3.0E7 hours => 9223372036854775807 nanoseconds - 6.0E7 hours => 9223372036854775807 nanoseconds - 1.0E8 hours => 9223372036854775807 nanoseconds - 1.0E9 hours => 9223372036854775807 nanoseconds - 1.0E12 hours => 9223372036854775807 nanoseconds + 7000000.0 hours => class java.lang.IllegalArgumentException + 1.0E7 hours => class java.lang.IllegalArgumentException + 1.2E7 hours => class java.lang.IllegalArgumentException + 2.4E7 hours => class java.lang.IllegalArgumentException + 3.0E7 hours => class java.lang.IllegalArgumentException + 6.0E7 hours => class java.lang.IllegalArgumentException + 1.0E8 hours => class java.lang.IllegalArgumentException + 1.0E9 hours => class java.lang.IllegalArgumentException + 1.0E12 hours => class java.lang.IllegalArgumentException 0.0 days => 0 days 1.0 days => 1 day 7.0 days => 7 days @@ -345,16 +345,18 @@ 30000.0 days => 30000 days 60000.0 days => 60000 days 100000.0 days => 100000 days - 1000000.0 days => 9223372036854775807 nanoseconds - 7000000.0 days => 9223372036854775807 nanoseconds - 1.0E7 days => 9223372036854775807 nanoseconds - 1.2E7 days => 9223372036854775807 nanoseconds - 2.4E7 days => 9223372036854775807 nanoseconds - 3.0E7 days => 9223372036854775807 nanoseconds - 6.0E7 days => 9223372036854775807 nanoseconds - 1.0E8 days => 9223372036854775807 nanoseconds - 1.0E9 days => 9223372036854775807 nanoseconds - 1.0E12 days => 9223372036854775807 nanoseconds + 1000000.0 days => class java.lang.IllegalArgumentException + 7000000.0 days => class java.lang.IllegalArgumentException + 1.0E7 days => class java.lang.IllegalArgumentException + 1.2E7 days => class java.lang.IllegalArgumentException + 2.4E7 days => class java.lang.IllegalArgumentException + 3.0E7 days => class java.lang.IllegalArgumentException + 6.0E7 days => class java.lang.IllegalArgumentException + 1.0E8 days => class java.lang.IllegalArgumentException + 1.0E9 days => class java.lang.IllegalArgumentException + 1.0E12 days => class java.lang.IllegalArgumentException +10000000000000001 nanoseconds => 10000000000000001 nanoseconds +10000000000000002 nanoseconds => 10000000000000002 nanoseconds Inf => Duration.Inf -Inf => Duration.MinusInf +Inf => Duration.Inf diff --git a/test/files/jvm/duration-java/Test.java b/test/files/jvm/duration-java/Test.java index 02feb522b8..1c53ccb266 100644 --- a/test/files/jvm/duration-java/Test.java +++ b/test/files/jvm/duration-java/Test.java @@ -26,10 +26,18 @@ public class Test { for (TimeUnit t : TimeUnit.values()) { for (Double n: makeNumbers()) { String s = "" + n + " " + t.toString().toLowerCase(); - Duration d = Duration.create(n, t); - p(String.format("%25s => %s", s, d)); + String result; + try { + Duration d = Duration.create(n, t); + result = d.toString(); + } catch(Exception e) { + result = e.getClass().toString(); + } + p(String.format("%25s => %s", s, result)); } } + for (String s: new String[] {"10000000000000001 nanoseconds", "10000000000000002 nanoseconds"}) + p(String.format("%25s => %s", s, Duration.create(s))); for (String s: Arrays.asList("Inf", "-Inf", "+Inf", "PlusInf", "MinusInf")) { Duration d = Duration.create(s); p(String.format("%25s => %s", s, d)); diff --git a/test/files/jvm/duration-tck.scala b/test/files/jvm/duration-tck.scala new file mode 100644 index 0000000000..679712aa59 --- /dev/null +++ b/test/files/jvm/duration-tck.scala @@ -0,0 +1,107 @@ +/** + * Copyright (C) 2012 Typesafe Inc. + */ + +import scala.concurrent.util._ +import duration._ +import scala.reflect._ +import java.util.concurrent.TimeUnit._ + +object Test extends App { + + implicit class Assert(val left: Any) extends AnyVal { + def =!=(right: Any) = assert(left == right, s"$left was not equal to $right") + } + + def intercept[T <: Exception : ClassTag](code: => Unit) = + try { code; assert(false, "did not throw expected exception " + classTag[T]) } + catch { + case ex: Exception => if (classTag[T].runtimeClass isAssignableFrom ex.getClass) () else throw ex + } + + { // test field ops + val zero = 0 seconds + val one = 1 second + val two = one + one + val three = 3 * one + (0 * one) =!= (zero) + (2 * one) =!= (two) + (three - two) =!= (one) + (three / 3) =!= (one) + (two / one) =!= (2) + (one + zero) =!= (one) + (one / 1000000) =!= (1.micro) + } + + { // test infinities + val one = 1.second + val inf = Duration.Inf + val minf = Duration.MinusInf + (-inf) =!= (minf) + intercept[IllegalArgumentException] { minf + inf } + intercept[IllegalArgumentException] { inf - inf } + intercept[IllegalArgumentException] { inf + minf } + intercept[IllegalArgumentException] { minf - minf } + (inf + inf) =!= (inf) + (inf - minf) =!= (inf) + (minf - inf) =!= (minf) + (minf + minf) =!= (minf) + assert(inf == inf) + assert(minf == minf) + inf.compareTo(inf) =!= (0) + inf.compareTo(one) =!= (1) + minf.compareTo(minf) =!= (0) + minf.compareTo(one) =!= (-1) + assert(inf != minf) + assert(minf != inf) + assert(one != inf) + assert(minf != one) + inf =!= (minf * -1d) + inf =!= (minf / -1d) + } + + { // 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 =!= (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) } + } + } + + { // test Deadline + val dead = 2.seconds.fromNow + val dead2 = 2 seconds fromNow + // view bounds vs. very local type inference vs. operator precedence: sigh + assert(dead.timeLeft > (1 second: Duration)) + assert(dead2.timeLeft > (1 second: Duration)) + Thread.sleep(1.second.toMillis) + assert(dead.timeLeft < (1 second: Duration)) + assert(dead2.timeLeft < (1 second: Duration)) + } + + { // check statically retaining finite-ness + val d: FiniteDuration = 1.second * 2 / 1.4 mul 1.1 div 2.1 plus 3.seconds minus 1.millisecond min 1.second max 1.second + } + +} -- cgit v1.2.3