diff options
author | Viktor Klang <viktor.klang@gmail.com> | 2014-09-26 12:05:37 +0200 |
---|---|---|
committer | Viktor Klang <viktor.klang@gmail.com> | 2014-10-20 23:55:44 +0200 |
commit | fa0743c32338f147eaf7a5d69566bbc15d193f85 (patch) | |
tree | 24f6b6d5cbab337174d48f0d0876ac0de93141f5 /test/files/jvm/scala-concurrent-tck.scala | |
parent | c0ceffb865ff4b2146aacec547cc42bb7605ee93 (diff) | |
download | scala-fa0743c32338f147eaf7a5d69566bbc15d193f85.tar.gz scala-fa0743c32338f147eaf7a5d69566bbc15d193f85.tar.bz2 scala-fa0743c32338f147eaf7a5d69566bbc15d193f85.zip |
Add missing canonical combinators:
- `def transform[S](f: Try[T] => Try[S])(implicit executor: ExecutionContext): Future[S]`
- `def transformWith[S](f: Try[T] => Future[S])(implicit executor: ExecutionContext): Future[S]`
- `def flatten[S](implicit ev: T <:< Future[S]): Future[S]`
- `def zipWith[U, R](that: Future[U])(f: (T, U) => R)(implicit executor: ExecutionContext): Future[R]`
Add missing utilities:
- `val unit: Future[Unit]` in `object Future`
- `object never extends Future[Nothing]` in `object Future`
- `def defaultBlockContext: BlockContext` in `object BlockContext`
- `def toString: String` on stdlib implementations of `Future`
Refactors:
- the `scala.concurrent.Future` trait to not explicit create any `Promises`,
so that implementations can control implementation type,
this is mainly facilitated through adding of the `transform` and `transformWith` methods.
- the implementation of `ExecutionContextImpl` has been cleaned up
- the `scala.concurrent.impl.DefaultPromise` has been reimplemented to not use `sun.misc.Unsafe`
Securing:
- Add a self-check in `completeWith` and `tryCompleteWith` to avoid cycles in trait Promise
- Capping the maximum number of threads for the global `ExecutionContext` to the max parallelism
- Implementing (almost) all `Future` combinators on `transformWith` and `transform` means
that `DefaultPromise` linking works on both `(flat)map` and `recover(With)`
- Nested `blocking {}` should not spawn extra threads beyond the first.
Removes:
- the private `internalExecutor` method in favor of an import in trait `Future`
- the private `internalExecutor` method in favor of an import in trait `Promise`
- the `AtomicReferenceFieldUpdater` in `AbstractPromise` since we're using `Unsafe`
- `scala.concurrent.impl.Future` is no longer needed
Deprecates:
- `Future.onSuccess` - discourage the use of callbacks
(and is also redundant considering `foreach` and `onComplete`)
- `Future.onFailure` - discourage the use of callbacks
(and is also redundant considering `onComplete` and `failed.foreach`)
- `ExecutionContext.prepare` - it was ill specced and it is too easy to forget to call it
(or even know when to call it or call it more times than needed)
- All classes in scala.concurrent.forkjoin. Scala 2.12 will be Java 8+ and as such the jsr166e
should be used as included in java.util.concurrent.
Reimplements:
- `failed` - in terms of `transform`
- `map` - in terms of `transform`
- `flatMap` - in terms of `transformWith`
- `recover` - in terms of `transform`
- `recoverWith` - in terms of `transformWith`
- `zip` - in terms of `flatMap` + `map`
- `fallbackTo` - in terms of `recoverWith` + `recoverWith`
- `andThen` - in terms of `transform`
Miscellaneous:
- Giving the threads of `ExecutionContext.global` sensible names
- Optimizes `object Future.successful` and `object Future.failed` are now separate implementations,
to optimize for the result, avoiding doing work for the "other branch".
- Optimizes `compressedRoot()` by avoiding double-calls to volatile get.
Documentation:
- Almost all methods on `Future` and `Promise` have been revisited and had their ScalaDoc updated
Tests:
- Yes
Diffstat (limited to 'test/files/jvm/scala-concurrent-tck.scala')
-rw-r--r-- | test/files/jvm/scala-concurrent-tck.scala | 124 |
1 files changed, 124 insertions, 0 deletions
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 { |