@@ -13,6 +13,7 @@ import org.scalatest.time.Span
1313import scala .annotation .nowarn
1414import scala .concurrent .Await
1515import scala .concurrent .Future
16+ import scala .concurrent .Promise
1617// #imports
1718import akka .stream ._
1819
@@ -517,7 +518,63 @@ class SourceSpec extends StreamSpec with DefaultTimeout {
517518 }
518519 }
519520
521+ " Source.future" must {
522+ " optimize already completed future" in {
523+ val future = Future .successful(" done" )
524+ val source = Source .future(future)
525+ source.getAttributes.nameLifted should === (Some (" singleSource" ))
526+ source.runWith(Sink .head).futureValue should === (" done" )
527+ }
528+
529+ " optimize already failed future" in {
530+ val future = Future .failed(TE (" boom" ))
531+ val source = Source .future(future)
532+ source.getAttributes.nameLifted should === (Some (" failedSource" ))
533+ source.runWith(Sink .head).failed.futureValue shouldBe a[TE ]
534+ }
535+
536+ " handle regular future" in {
537+ val promise = Promise [String ]()
538+ val source = Source .future(promise.future)
539+ source.getAttributes.nameLifted should === (Some (" futureSource" ))
540+ promise.success(" done" )
541+ source.runWith(Sink .head).futureValue should === (" done" )
542+ }
543+ }
544+
520545 " Source.futureSource" must {
546+ " optimize already completed future" in {
547+ val future = Future .successful(Source .single(" done" ))
548+ val source = Source .futureSource(future)
549+ source.getAttributes.nameLifted should === (Some (" singleSource" ))
550+ source.runWith(Sink .head).futureValue should === (" done" )
551+ }
552+
553+ " pass along materialized value for already completed future" in {
554+ val future = Future .successful(Source .single(" done" ).mapMaterializedValue(_ => " materializedValue" ))
555+ val source = Source .futureSource(future)
556+ source.toMat(Sink .ignore)(Keep .left).run().futureValue should === (" materializedValue" )
557+ }
558+
559+ " handle already failed future" in {
560+ val future = Future .failed[Source [String , NotUsed ]](TE (" boom" ))
561+ val source = Source .futureSource(future)
562+ val (futureMat, streamResult) = source.toMat(Sink .head)(Keep .both).run()
563+
564+ streamResult.failed.futureValue should === (TE (" boom" ))
565+ futureMat.failed.futureValue should === (TE (" boom" ))
566+ }
567+
568+ " handle later failed future" in {
569+ val promise = Promise [Source [String , NotUsed ]]()
570+ val source = Source .futureSource(promise.future)
571+ promise.failure(TE (" boom" ))
572+
573+ val (futureMat, streamResult) = source.toMat(Sink .head)(Keep .both).run()
574+
575+ streamResult.failed.futureValue should === (TE (" boom" ))
576+ futureMat.failed.futureValue should === (TE (" boom" ))
577+ }
521578
522579 " not cancel substream twice" in {
523580 val result = Source
0 commit comments