diff options
Diffstat (limited to 'test')
-rw-r--r-- | test/files/jvm/future-spec.check | 2 | ||||
-rw-r--r-- | test/files/jvm/future-spec/FutureTests.scala | 273 | ||||
-rw-r--r-- | test/files/jvm/scala-concurrent-tck.check | 1 | ||||
-rw-r--r-- | test/files/jvm/scala-concurrent-tck.scala | 124 | ||||
-rw-r--r-- | test/files/jvm/t7146.scala | 2 | ||||
-rw-r--r-- | test/files/run/future-flatmap-exec-count.check | 1 |
6 files changed, 401 insertions, 2 deletions
diff --git a/test/files/jvm/future-spec.check b/test/files/jvm/future-spec.check index df1629dd7e..5c80aa5586 100644 --- a/test/files/jvm/future-spec.check +++ b/test/files/jvm/future-spec.check @@ -1 +1 @@ -warning: there was one deprecation warning; re-run with -deprecation for details +warning: there were 21 deprecation warnings; re-run with -deprecation for details diff --git a/test/files/jvm/future-spec/FutureTests.scala b/test/files/jvm/future-spec/FutureTests.scala index a290af9cd3..6b34d5bfaa 100644 --- a/test/files/jvm/future-spec/FutureTests.scala +++ b/test/files/jvm/future-spec/FutureTests.scala @@ -17,6 +17,19 @@ class FutureTests extends MinimalScalaTest { case "NoReply" => Promise[String]().future } + def fail(msg: String): Nothing = throw new AssertionError(msg) + + def ECNotUsed[T](f: ExecutionContext => T): T = { + val p = Promise[Runnable]() + val unusedEC: ExecutionContext = new ExecutionContext { + def execute(r: Runnable) = p.success(r) + def reportFailure(t: Throwable): Unit = p.failure(t) + } + val t = f(unusedEC) + assert(p.future.value == None, "Future executed logic!") + t + } + val defaultTimeout = 5 seconds /* future specification */ @@ -68,6 +81,60 @@ class FutureTests extends MinimalScalaTest { } } + "Futures" should { + "have proper toString representations" in { + import ExecutionContext.Implicits.global + val s = 5 + val f = new Exception("foo") + val t = Try(throw f) + + val expectFailureString = "Future(Failure("+f+"))" + val expectSuccessString = "Future(Success(5))" + val expectNotCompleteString = "Future(<not completed>)" + + Future.successful(s).toString mustBe expectSuccessString + Future.failed(f).toString mustBe expectFailureString + Future.fromTry(t).toString mustBe expectFailureString + val p = Promise[Int]() + p.toString mustBe expectNotCompleteString + Promise[Int]().success(s).toString mustBe expectSuccessString + Promise[Int]().failure(f).toString mustBe expectFailureString + Await.ready(Future { throw f }, 2000 millis).toString mustBe expectFailureString + Await.ready(Future { s }, 2000 millis).toString mustBe expectSuccessString + + Future.never.toString mustBe "Future(<never>)" + Future.unit.toString mustBe "Future(Success(()))" + } + + "have proper const representation for success" in { + val s = "foo" + val f = Future.successful(s) + + ECNotUsed(ec => f.onFailure({ case _ => fail("onFailure should not have been called") })(ec)) + assert( ECNotUsed(ec => f.recover({ case _ => fail("recover should not have been called")})(ec)) eq f) + assert( ECNotUsed(ec => f.recoverWith({ case _ => fail("flatMap should not have been called")})(ec)) eq f) + assert(f.fallbackTo(f) eq f, "Future.fallbackTo must be the same instance as Future.fallbackTo") + } + + "have proper const representation for failure" in { + val e = new Exception("foo") + val f = Future.failed[Future[String]](e) + + assert(f.mapTo[String] eq f, "Future.mapTo must be the same instance as Future.mapTo") + assert(f.zip(f) eq f, "Future.zip must be the same instance as Future.zip") + assert(f.flatten eq f, "Future.flatten must be the same instance as Future.flatten") + assert(f.failed eq f, "Future.failed must be the same instance as Future.failed") + + ECNotUsed(ec => f.foreach(_ => fail("foreach should not have been called"))(ec)) + ECNotUsed(ec => f.onSuccess({ case _ => fail("onSuccess should not have been called") })(ec)) + assert( ECNotUsed(ec => f.map(_ => fail("map should not have been called"))(ec)) eq f) + assert( ECNotUsed(ec => f.flatMap(_ => fail("flatMap should not have been called"))(ec)) eq f) + assert( ECNotUsed(ec => f.filter(_ => fail("filter should not have been called"))(ec)) eq f) + assert( ECNotUsed(ec => f.collect({ case _ => fail("collect should not have been called")})(ec)) eq f) + assert( ECNotUsed(ec => f.zipWith(f)({ (_,_) => fail("zipWith should not have been called")})(ec)) eq f) + } + } + "The Future companion object" should { "call ExecutionContext.prepare on apply" in { val p = Promise[Boolean]() @@ -85,6 +152,49 @@ class FutureTests extends MinimalScalaTest { Await.result(f, defaultTimeout) mustBe ("foo") Await.result(p.future, defaultTimeout) mustBe (true) } + + "have a unit member representing an already completed Future containing Unit" in { + assert(Future.unit ne null, "Future.unit must not be null") + assert(Future.unit eq Future.unit, "Future.unit must be the same instance as Future.unit") + assert(Future.unit.isCompleted, "Future.unit must already be completed") + assert(Future.unit.value.get == Success(()), "Future.unit must contain a Success(())") + } + + "have a never member representing a never completed Future of Nothing" in { + + val test: Future[Nothing] = Future.never + + //Verify stable identifier + test match { + case Future.`never` => + case _ => fail("Future.never did not match Future.`never`") + } + + assert(test eq Future.never, "Future.never must be the same instance as Future.never") + assert(test ne null, "Future.never must not be null") + assert(!test.isCompleted && test.value.isEmpty, "Future.never must never be completed") + assert(test.failed eq test) + assert(test.asInstanceOf[Future[Future[Nothing]]].flatten eq test) + assert(test.zip(test) eq test) + assert(test.fallbackTo(test) eq test) + assert(test.mapTo[String] eq test) + + ECNotUsed(ec => test.foreach(_ => fail("foreach should not have been called"))(ec)) + ECNotUsed(ec => test.onSuccess({ case _ => fail("onSuccess should not have been called") })(ec)) + ECNotUsed(ec => test.onFailure({ case _ => fail("onFailure should not have been called") })(ec)) + ECNotUsed(ec => test.onComplete({ case _ => fail("onComplete should not have been called") })(ec)) + ECNotUsed(ec => test.transform(identity, identity)(ec) eq test) + ECNotUsed(ec => test.transform(identity)(ec) eq test) + ECNotUsed(ec => test.transformWith(_ => fail("transformWith should not have been called"))(ec) eq test) + ECNotUsed(ec => test.map(identity)(ec) eq test) + ECNotUsed(ec => test.flatMap(_ => fail("flatMap should not have been called"))(ec) eq test) + ECNotUsed(ec => test.filter(_ => fail("filter should not have been called"))(ec) eq test) + ECNotUsed(ec => test.collect({ case _ => fail("collect should not have been called")})(ec) eq test) + ECNotUsed(ec => test.recover({ case _ => fail("recover should not have been called")})(ec) eq test) + ECNotUsed(ec => test.recoverWith({ case _ => fail("recoverWith should not have been called")})(ec) eq test) + ECNotUsed(ec => test.andThen({ case _ => fail("andThen should not have been called")})(ec) eq test) + ECNotUsed(ec => test.zipWith(test)({ (_,_) => fail("zipWith should not have been called")})(ec) eq test) + } } "The default ExecutionContext" should { @@ -218,6 +328,142 @@ class FutureTests extends MinimalScalaTest { } mustBe (r) } + "transform results to results" in { + val f1 = Future.successful("foo").transform(_.map(_.toUpperCase)) + val f2 = Future("bar").transform(_.map(_.toUpperCase)) + Await.result(f1, defaultTimeout) mustBe "FOO" + Await.result(f2, defaultTimeout) mustBe "BAR" + } + + "transform failures to failures" in { + val initial = new Exception("Initial") + val expected1 = new Exception("Expected1") + val expected2 = new Exception("Expected2") + val f1 = Future(throw initial) transform { + case Failure(`initial`) => Failure(expected1) + case x => x + } + val f2 = Future.failed(initial) transform { + case Failure(`initial`) => Failure(expected2) + case x => x + } + + intercept[Exception] { Await.result(f1, defaultTimeout) } mustBe expected1 + intercept[Exception] { Await.result(f2, defaultTimeout) } mustBe expected2 + } + + "transform failures to results" in { + val initial1 = new Exception("Initial1") + val initial2 = new Exception("Initial2") + val f1 = Future.failed[String](initial1) transform { + case Failure(`initial1`) => Success("foo") + case x => x + } + val f2 = Future[String](throw initial2) transform { + case Failure(`initial2`) => Success("bar") + case x => x + } + Await.result(f1, defaultTimeout) mustBe "foo" + Await.result(f2, defaultTimeout) mustBe "bar" + } + + "transform results to failures" in { + val expected1 = new Exception("Expected1") + val expected2 = new Exception("Expected2") + val expected3 = new Exception("Expected3") + val f1 = Future.successful("foo") transform { + case Success("foo") => Failure(expected1) + case x => x + } + val f2 = Future("bar") transform { + case Success("bar") => Failure(expected2) + case x => x + } + val f3 = Future("bar") transform { + case Success("bar") => throw expected3 + case x => x + } + intercept[Exception] { Await.result(f1, defaultTimeout) } mustBe expected1 + intercept[Exception] { Await.result(f2, defaultTimeout) } mustBe expected2 + intercept[Exception] { Await.result(f3, defaultTimeout) } mustBe expected3 + } + + "transformWith results" in { + val f1 = Future.successful("foo").transformWith { + case Success(r) => Future(r.toUpperCase) + case f @ Failure(_) => Future.fromTry(f) + } + val f2 = Future("bar").transformWith { + case Success(r) => Future(r.toUpperCase) + case f @ Failure(_) => Future.fromTry(f) + } + Await.result(f1, defaultTimeout) mustBe "FOO" + Await.result(f2, defaultTimeout) mustBe "BAR" + } + + "transformWith failures" in { + val initial = new Exception("Initial") + val expected1 = new Exception("Expected1") + val expected2 = new Exception("Expected2") + val expected3 = new Exception("Expected3") + + val f1 = Future[Int](throw initial).transformWith { + case Failure(`initial`) => Future failed expected1 + case x => Future fromTry x + } + val f2 = Future.failed[Int](initial).transformWith { + case Failure(`initial`) => Future failed expected2 + case x => Future fromTry x + } + val f3 = Future[Int](throw initial).transformWith { + case Failure(`initial`) => throw expected3 + case x => Future fromTry x + } + + intercept[Exception] { Await.result(f1, defaultTimeout) } mustBe expected1 + intercept[Exception] { Await.result(f2, defaultTimeout) } mustBe expected2 + intercept[Exception] { Await.result(f3, defaultTimeout) } mustBe expected3 + } + + "transformWith failures to future success" in { + val initial = new Exception("Initial") + val f1 = Future.failed[String](initial).transformWith { + case Failure(`initial`) => Future("FOO") + case _ => Future failed initial + } + val f2 = Future[String](throw initial).transformWith { + case Failure(`initial`) => Future("BAR") + case _ => Future failed initial + } + Await.result(f1, defaultTimeout) mustBe "FOO" + Await.result(f2, defaultTimeout) mustBe "BAR" + } + + "transformWith results to future failures" in { + val initial = new Exception("Initial") + val expected1 = new Exception("Expected1") + val expected2 = new Exception("Expected2") + val expected3 = new Exception("Expected3") + + val f1 = Future[String]("FOO") transformWith { + case Success("FOO") => Future failed expected1 + case _ => Future successful "FOO" + } + val f2 = Future.successful("FOO") transformWith { + case Success("FOO") => Future failed expected2 + case _ => Future successful "FOO" + } + val f3 = Future.successful("FOO") transformWith { + case Success("FOO") => throw expected3 + case _ => Future successful "FOO" + } + + + intercept[Exception] { Await.result(f1, defaultTimeout) } mustBe expected1 + intercept[Exception] { Await.result(f2, defaultTimeout) } mustBe expected2 + intercept[Exception] { Await.result(f3, defaultTimeout) } mustBe expected3 + } + "andThen like a boss" in { val q = new java.util.concurrent.LinkedBlockingQueue[Int] for (i <- 1 to 1000) { @@ -281,6 +527,33 @@ class FutureTests extends MinimalScalaTest { Await.result(successful, timeout) mustBe (("foo", "foo")) } + "zipWith" in { + val timeout = 10000 millis + val f = new IllegalStateException("test") + intercept[IllegalStateException] { + val failed = Future.failed[String](f).zipWith(Future.successful("foo")) { _ -> _ } + Await.result(failed, timeout) + } mustBe (f) + + intercept[IllegalStateException] { + val failed = Future.successful("foo").zipWith(Future.failed[String](f)) { _ -> _ } + Await.result(failed, timeout) + } mustBe (f) + + intercept[IllegalStateException] { + val failed = Future.failed[String](f).zipWith(Future.failed[String](f)) { _ -> _ } + Await.result(failed, timeout) + } mustBe (f) + + val successful = Future.successful("foo").zipWith(Future.successful("foo")) { _ -> _ } + Await.result(successful, timeout) mustBe (("foo", "foo")) + + val failure = Future.successful("foo").zipWith(Future.successful("foo")) { (_,_) => throw f } + intercept[IllegalStateException] { + Await.result(failure, timeout) + } mustBe (f) + } + "fold" in { val timeout = 10000 millis def async(add: Int, wait: Int) = Future { diff --git a/test/files/jvm/scala-concurrent-tck.check b/test/files/jvm/scala-concurrent-tck.check new file mode 100644 index 0000000000..bbe73c9982 --- /dev/null +++ b/test/files/jvm/scala-concurrent-tck.check @@ -0,0 +1 @@ +warning: there were 74 deprecation warnings; re-run with -deprecation for details diff --git a/test/files/jvm/scala-concurrent-tck.scala b/test/files/jvm/scala-concurrent-tck.scala index ce86d4aef0..ba405e97bd 100644 --- a/test/files/jvm/scala-concurrent-tck.scala +++ b/test/files/jvm/scala-concurrent-tck.scala @@ -165,6 +165,100 @@ def testTransformFailure(): Unit = once { g onFailure { case e => done(e eq transformed) } } + def testTransformResultToResult(): Unit = once { + done => + Future("foo").transform { + case Success(s) => Success(s.toUpperCase) + case Failure(f) => throw new Exception("test failed") + } onComplete { + case Success("FOO") => done(true) + case _ => done(false) + } + } + + def testTransformResultToFailure(): Unit = once { + done => + val e = new Exception("expected") + Future("foo").transform { + case Success(s) => Failure(e) + case Failure(f) => throw new Exception("test failed") + } onComplete { + case Failure(`e`) => done(true) + case _ => done(false) + } + } + + def testTransformFailureToResult(): Unit = once { + done => + val e = "foo" + Future(throw new Exception("initial")).transform { + case Success(s) => throw new Exception("test failed") + case Failure(f) => Success(e) + } onComplete { + case Success(`e`) => done(true) + case _ => done(false) + } + } + + def testTransformFailureToFailure(): Unit = once { + done => + val e = new Exception("expected") + Future(throw new Exception("initial")).transform { + case Success(s) => throw new Exception("test failed") + case Failure(f) => Failure(e) + } onComplete { + case Failure(`e`) => done(true) + case _ => done(false) + } + } + + def testTransformWithResultToResult(): Unit = once { + done => + Future("foo").transformWith { + case Success(s) => Future(s.toUpperCase) + case Failure(f) => throw new Exception("test failed") + } onComplete { + case Success("FOO") => done(true) + case _ => done(false) + } + } + + def testTransformWithResultToFailure(): Unit = once { + done => + val e = new Exception("expected") + Future("foo").transformWith { + case Success(s) => Future(throw e) + case Failure(f) => throw new Exception("test failed") + } onComplete { + case Failure(`e`) => done(true) + case _ => done(false) + } + } + + def testTransformWithFailureToResult(): Unit = once { + done => + val e = "foo" + Future(throw new Exception("initial")).transformWith { + case Success(s) => throw new Exception("test failed") + case Failure(f) => Future(e) + } onComplete { + case Success(`e`) => done(true) + case _ => done(false) + } + } + + def testTransformWithFailureToFailure(): Unit = once { + done => + val e = new Exception("expected") + Future(throw new Exception("initial")).transformWith { + case Success(s) => throw new Exception("test failed") + case Failure(f) => Future(throw e) + } onComplete { + case Failure(`e`) => done(true) + case _ => done(false) + } + } + def testFoldFailure(): Unit = once { done => val f = Future[Unit] { throw new Exception("expected") } @@ -352,6 +446,14 @@ def testTransformFailure(): Unit = once { h onFailure { case e => done(e eq cause) } } + def testFallbackToThis(): Unit = { + def check(f: Future[Int]) = assert((f fallbackTo f) eq f) + + check(Future { 1 }) + check(Future.successful(1)) + check(Future.failed[Int](new Exception)) + } + testMapSuccess() testMapFailure() testFlatMapSuccess() @@ -373,6 +475,16 @@ def testTransformFailure(): Unit = once { testFallbackToFailure() testTransformSuccess() testTransformSuccessPF() + testTransformFailure() + testTransformFailurePF() + testTransformResultToResult() + testTransformResultToFailure() + testTransformFailureToResult() + testTransformFailureToFailure() + testTransformWithResultToResult() + testTransformWithResultToFailure() + testTransformWithFailureToResult() + testTransformWithFailureToFailure() } @@ -593,6 +705,17 @@ trait Exceptions extends TestBase { } +trait GlobalExecutionContext extends TestBase { + def testNameOfGlobalECThreads(): Unit = once { + done => Future({ + val expectedName = "scala-execution-context-global-"+ Thread.currentThread.getId + done(expectedName == Thread.currentThread.getName) + })(ExecutionContext.global) + } + + testNameOfGlobalECThreads() +} + trait CustomExecutionContext extends TestBase { import scala.concurrent.{ ExecutionContext, Awaitable } @@ -772,6 +895,7 @@ with FutureProjections with Promises with BlockContexts with Exceptions +with GlobalExecutionContext with CustomExecutionContext with ExecutionContextPrepare { diff --git a/test/files/jvm/t7146.scala b/test/files/jvm/t7146.scala index aaa3dc7ca4..ea734472d5 100644 --- a/test/files/jvm/t7146.scala +++ b/test/files/jvm/t7146.scala @@ -10,7 +10,7 @@ object Test { ExecutionContext.global.toString.startsWith("scala.concurrent.impl.ExecutionContextImpl")) val i = ExecutionContext.global.asInstanceOf[{ def executor: Executor }] println("should be scala.concurrent.forkjoin.ForkJoinPool == " + - i.executor.toString.startsWith("scala.concurrent.forkjoin.ForkJoinPool")) + (i.executor.getClass.getSuperclass.getName == "scala.concurrent.forkjoin.ForkJoinPool")) val u = i.executor. asInstanceOf[{ def getUncaughtExceptionHandler: Thread.UncaughtExceptionHandler }]. getUncaughtExceptionHandler diff --git a/test/files/run/future-flatmap-exec-count.check b/test/files/run/future-flatmap-exec-count.check index dd9dce64ed..7065c133e0 100644 --- a/test/files/run/future-flatmap-exec-count.check +++ b/test/files/run/future-flatmap-exec-count.check @@ -1,3 +1,4 @@ +warning: there was one deprecation warning; re-run with -deprecation for details mapping execute() flatmapping |