diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 450503e..fd048b3 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,41 +1,13 @@ name: CI -on: [push, pull_request] +on: + push: + branches: [ master ] + pull_request: jobs: test: - - runs-on: ubuntu-latest - - strategy: - matrix: - scala: - - 2.13.5 - - 2.12.13 - - steps: - - uses: actions/checkout@v2 - - - uses: coursier/cache-action@v5 - - - name: scala - uses: olafurpg/setup-scala@v10 - with: - java-version: openjdk@1.11 - - - name: build ${{ matrix.scala }} - run: sbt ++${{ matrix.scala }} clean coverage test - - - name: test coverage - if: success() - env: - COVERALLS_REPO_TOKEN: ${{ secrets.COVERALLS_REPO_TOKEN }} - run: sbt ++${{ matrix.scala }} coverageReport coverageAggregate coveralls - - - name: slack - uses: homoluctus/slatify@master - if: failure() && github.ref == 'refs/heads/master' - with: - type: ${{ job.status }} - job_name: Build - url: ${{ secrets.SLACK_WEBHOOK }} \ No newline at end of file + uses: evolution-gaming/scala-github-actions/.github/workflows/ci.yml@dde27b9bd793d41d5aacf8fb74403c9de5da1146 # v6.3.0 + # TODO remove after first release with Scala 3 support + with: + version_policy_check: false \ No newline at end of file diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index a8a2f2b..3b7a7cc 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,11 +1,11 @@ -name: Publish new Release +name: Publish Release on: - release: - types: [published] - branches: [master] + push: + tags: + - 'v*' jobs: release: - uses: evolution-gaming/scala-github-actions/.github/workflows/release.yml@v1 + uses: evolution-gaming/scala-github-actions/.github/workflows/release.yml@v5 secrets: inherit diff --git a/.scalafmt.conf b/.scalafmt.conf new file mode 100644 index 0000000..d31bdbb --- /dev/null +++ b/.scalafmt.conf @@ -0,0 +1,96 @@ +# Main goals: +# - nicer commit diffs (trailing commas, no alignment for pattern matching, force new lines) +# - better interop with default IntelliJ IDEA setup (matching import and modifiers sorting logic) +# - better developer experience on laptop screens (like 16' MBPs) with IntelliJ IDEA (line wraps) + +version = 3.11.5 + +runner.dialect = scala213source3 + +# only format files tracked by git +project.git = true + +maxColumn = 120 +trailingCommas = always + +preset = default +# do not align to make nicer commit diffs +align.preset = none + +indent { + # altering defnSite and extendSite to have this: + # final class MyErr extends RuntimeException( + # "super error message", + # ) + # instead of this: + # final class MyErr extends RuntimeException( + # "super error message", + # ) + defnSite = 2 + extendSite = 0 +} + +spaces { + # makes string interpolation with curlies more visually distinct + inInterpolatedStringCurlyBraces = true +} + +newlines { + # keep author new lines where possible + source = keep + # force new line after "(implicit" for multi-line arg lists + implicitParamListModifierForce = [after] + avoidForSimpleOverflow = [ + tooLong, # if the line would be too long even after newline inserted, do nothing + slc, # do nothing if overflow caused by single line comment + ] +} + +verticalMultiline { + atDefnSite = true + arityThreshold = 4 # more than 3 args in a list will be turned vertical + newlineAfterOpenParen = true # for nicer commit diffs +} + +# for nicer commit diffs - forces new line before last parenthesis: +# class MyCls( +# arg1: String, +# arg2: String, +# ) extends MyTrait { +# +# without it: +# class MyCls( +# arg1: String, +# arg2: String) extends MyTrait { +danglingParentheses.exclude = [] + +docstrings { + # easier to view diffs in IDEA on 16' MBP screen if docs max line are shorter than code + wrapMaxColumn = 100 + # next settings make it similar to the default IDEA javadoc formatting + style = Asterisk + oneline = unfold + blankFirstLine = unfold +} + +rewrite.rules = [ + Imports, + RedundantParens, + SortModifiers, + prefercurlyfors, +] + +# put visibility modifier first +rewrite.sortModifiers.preset = styleGuide + +# Import sorting as similar as possible to scalafix's "OrganizeImports.preset = INTELLIJ_2020_3". +# Scalafix is not used as its commands mess up "all .." build aliases and it takes long time to run, +# while its code semantic based features are not needed here. +# I.e. detection of unused imports is done with Scala compiler options. +rewrite.imports { + sort = ascii + groups = [ + [".*"], + ["java\\..*", "javax\\..*", "scala\\..*"], + ] +} diff --git a/build.sbt b/build.sbt index f9e98c4..08db6f9 100644 --- a/build.sbt +++ b/build.sbt @@ -1,33 +1,72 @@ +import sbtversionpolicy.Compatibility.BinaryCompatible + name := "serially" organization := "com.evolutiongaming" -homepage := Some(url("https://github.com/evolution-gaming/serially")) +homepage := Some(uri("https://github.com/evolution-gaming/serially")) startYear := Some(2018) organizationName := "Evolution" -organizationHomepage := Some(url("https://evolution.com")) +organizationHomepage := Some(uri("https://evolution.com")) scalaVersion := crossScalaVersions.value.head -crossScalaVersions := Seq("2.13.5", "2.12.13") +crossScalaVersions := Seq("2.13.18", "3.3.8") + +scalacOptions ++= crossSettings( + scalaVersion = scalaVersion.value, + // Good compiler options for Scala 2.13 are coming from com.evolution:sbt-scalac-opts-plugin:0.1.0, + // but its support for Scala 3 is limited, especially what concerns linting options. + // + // If Scala 3 is made the primary target, good linting scalac options for it should be added first. + if3 = Seq( + "-Ykind-projector:underscores", + + // disable new brace-less syntax: + // https://alexn.org/blog/2022/10/24/scala-3-optional-braces/ + "-no-indent", + + // improve error messages: + "-explain", + "-explain-types", + ), + if2 = Seq( + "-Xsource:3", + ), +) Compile / doc / scalacOptions ++= Seq("-groups", "-implicits", "-no-link-warnings") publishTo := Some(Resolver.evolutionReleases) +versionPolicyIntention := BinaryCompatible + libraryDependencies ++= Seq( - "com.evolutiongaming" %% "future-helper" % "1.0.6", - "com.typesafe.akka" %% "akka-actor" % "2.6.8", - "com.typesafe.akka" %% "akka-testkit" % "2.6.8" % Test, - "org.scalatest" %% "scalatest" % "3.2.9" % Test) + "com.evolutiongaming" %% "future-helper" % "1.0.7", + "com.typesafe.akka" %% "akka-actor" % "2.6.21", // scala-steward:off + "com.typesafe.akka" %% "akka-testkit" % "2.6.21" % Test, // scala-steward:off + "org.scalatest" %% "scalatest" % "3.2.20" % Test, +) + +// TODO remove after first release with Scala 3 support +versionPolicyIgnored ++= Seq( + // add libraries here that are known to be binary compatible, like: + "com.typesafe.akka" %% "akka-actor", + "org.scala-lang.modules" %% "scala-java8-compat", +) -licenses := Seq(("MIT", url("https://opensource.org/licenses/MIT"))) +licenses := Seq(("MIT", uri("https://opensource.org/licenses/MIT"))) -releaseCrossBuild := true +def crossSettings[T](scalaVersion: String, if3: T, if2: T): T = { + scalaVersion match { + case version if version.startsWith("3") => if3 + case _ => if2 + } +} -//addCommandAlias("check", "all versionPolicyCheck Compile/doc") -addCommandAlias("check", "show version") -addCommandAlias("build", "+all compile test") +addCommandAlias("check", "+all scalafmtCheckRepo versionPolicyCheck Compile/doc") +addCommandAlias("fmt", "+all scalafmtRepo") +addCommandAlias("build", "+all compile testFull") diff --git a/project/build.properties b/project/build.properties index 19479ba..fdcf9af 100644 --- a/project/build.properties +++ b/project/build.properties @@ -1 +1 @@ -sbt.version=1.5.2 +sbt.version = 2.0.6 diff --git a/project/plugins.sbt b/project/plugins.sbt index 8f253da..54e584d 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -1,9 +1,11 @@ -addSbtPlugin("org.scoverage" % "sbt-scoverage" % "1.7.2") +addSbtPlugin("org.scoverage" % "sbt-scoverage" % "2.4.4") -addSbtPlugin("org.scoverage" % "sbt-coveralls" % "1.2.7") - -addSbtPlugin("com.github.sbt" % "sbt-release" % "1.0.15") +addSbtPlugin("com.github.sbt" % "sbt-dynver" % "5.1.1") addSbtPlugin("com.evolution" % "sbt-scalac-opts-plugin" % "0.2.0") -addSbtPlugin("com.evolution" % "sbt-artifactory-plugin" % "0.1.2") \ No newline at end of file +addSbtPlugin("com.evolution" % "sbt-artifactory-plugin" % "0.1.2") + +addSbtPlugin("ch.epfl.scala" % "sbt-version-policy" % "3.3.0") + +addSbtPlugin("org.scalameta" % "sbt-scalafmt" % "2.6.2") diff --git a/src/main/scala/com/evolutiongaming/concurrent/serially/AsyncVar.scala b/src/main/scala/com/evolutiongaming/concurrent/serially/AsyncVar.scala index 089fee3..4207a87 100644 --- a/src/main/scala/com/evolutiongaming/concurrent/serially/AsyncVar.scala +++ b/src/main/scala/com/evolutiongaming/concurrent/serially/AsyncVar.scala @@ -2,7 +2,7 @@ package com.evolutiongaming.concurrent.serially import akka.actor.ActorRefFactory import com.evolutiongaming.concurrent.CurrentThreadExecutionContext -import com.evolutiongaming.concurrent.FutureHelper._ +import com.evolutiongaming.concurrent.FutureHelper.* import scala.concurrent.Future @@ -15,20 +15,24 @@ trait AsyncVar[S] extends StateVar[S] { object AsyncVar { - def apply[S](state: S)(implicit factory: ActorRefFactory): AsyncVar[S] = { + def apply[S]( + state: S, + )(implicit + factory: ActorRefFactory, + ): AsyncVar[S] = { val serially = SeriallyAsync() apply(state, serially) } def apply[S](state: S, serially: SeriallyAsync): AsyncVar[S] = { - implicit val ec = CurrentThreadExecutionContext + implicit val ec: CurrentThreadExecutionContext.type = CurrentThreadExecutionContext @volatile var s = state new AsyncVar[S] { - def value() = s + def value(): S = s def async[SS](f: S => Future[(S, SS)]): Future[SS] = { serially.async[SS] { diff --git a/src/main/scala/com/evolutiongaming/concurrent/serially/Serially.scala b/src/main/scala/com/evolutiongaming/concurrent/serially/Serially.scala index b0291c1..1c702b1 100644 --- a/src/main/scala/com/evolutiongaming/concurrent/serially/Serially.scala +++ b/src/main/scala/com/evolutiongaming/concurrent/serially/Serially.scala @@ -1,9 +1,8 @@ package com.evolutiongaming.concurrent.serially -import java.util.concurrent.atomic.AtomicBoolean - import akka.actor.{Actor, ActorRef, ActorRefFactory, Props} +import java.util.concurrent.atomic.AtomicBoolean import scala.concurrent.{Future, Promise} import scala.util.Try import scala.util.control.NoStackTrace @@ -19,24 +18,24 @@ object Serially { private val StoppedFailure = Future.failed(Stopped) - def apply(name: Option[String] = None)(implicit factory: ActorRefFactory): Serially = { - - case class Func(f: () => Unit) - case class StopPrepare(promise: Promise[Unit]) - case class StopCommit(promise: Promise[Unit]) + def apply( + name: Option[String] = None, + )(implicit + factory: ActorRefFactory, + ): Serially = { def actor() = new Actor { def receive: Receive = { - case Func(f) => f() + case Func(f) => f() case StopPrepare(promise) => self.tell(StopCommit(promise), ActorRef.noSender) - case StopCommit(promise) => promise.success(()); context.stop(self); + case StopCommit(promise) => promise.success(()); context.stop(self); } } val props = Props(actor()) val ref = name match { - case None => factory.actorOf(props) + case None => factory.actorOf(props) case Some(name) => factory.actorOf(props, name) } @@ -61,7 +60,7 @@ object Serially { } } - def stop() = { + def stop(): Future[Unit] = { running { if (stopped.compareAndSet(false, true)) { val promise = Promise[Unit]() @@ -75,14 +74,16 @@ object Serially { } } - def now: Serially = new Serially { def apply[T](f: => T): Future[T] = Future.fromTry(Try(f)) - def stop() = Future.unit + def stop(): Future[Unit] = Future.unit } + private case class Func(f: () => Unit) + private case class StopPrepare(promise: Promise[Unit]) + private case class StopCommit(promise: Promise[Unit]) case object Stopped extends RuntimeException with NoStackTrace -} \ No newline at end of file +} diff --git a/src/main/scala/com/evolutiongaming/concurrent/serially/SeriallyAsync.scala b/src/main/scala/com/evolutiongaming/concurrent/serially/SeriallyAsync.scala index f8208e7..bb4c6dd 100644 --- a/src/main/scala/com/evolutiongaming/concurrent/serially/SeriallyAsync.scala +++ b/src/main/scala/com/evolutiongaming/concurrent/serially/SeriallyAsync.scala @@ -2,7 +2,7 @@ package com.evolutiongaming.concurrent.serially import akka.actor.ActorRefFactory import com.evolutiongaming.concurrent.CurrentThreadExecutionContext -import com.evolutiongaming.concurrent.FutureHelper._ +import com.evolutiongaming.concurrent.FutureHelper.* import scala.concurrent.Future import scala.util.{Success, Try} @@ -18,7 +18,11 @@ trait SeriallyAsync extends Serially { object SeriallyAsync { - def apply(name: Option[String] = None)(implicit factory: ActorRefFactory): SeriallyAsync = { + def apply( + name: Option[String] = None, + )(implicit + factory: ActorRefFactory, + ): SeriallyAsync = { val serially = Serially(name) apply(serially) } @@ -27,13 +31,13 @@ object SeriallyAsync { var future = Future.unit - implicit val ec = CurrentThreadExecutionContext + implicit val ec: CurrentThreadExecutionContext.type = CurrentThreadExecutionContext val tryUnit = Success(()) - val tryToUnit = (_: Try[_]) => tryUnit + val tryToUnit = (_: Try[?]) => tryUnit new SeriallyAsync { - def async[T](f: => Future[T]) = { + def async[T](f: => Future[T]): Future[T] = { serially { val result = if (future.isCompleted) f else future.flatMap(_ => f) future = FutureOps(result).transform(tryToUnit) @@ -41,15 +45,14 @@ object SeriallyAsync { }.flatten } - def stop() = serially.stop() + def stop(): Future[Unit] = serially.stop() } } - def now: SeriallyAsync = new SeriallyAsync { - def async[T](f: => Future[T]) = f + def async[T](f: => Future[T]): Future[T] = f - def stop() = Future.unit + def stop(): Future[Unit] = Future.unit } -} \ No newline at end of file +} diff --git a/src/main/scala/com/evolutiongaming/concurrent/serially/StateVar.scala b/src/main/scala/com/evolutiongaming/concurrent/serially/StateVar.scala index 7819a43..03dbbcf 100644 --- a/src/main/scala/com/evolutiongaming/concurrent/serially/StateVar.scala +++ b/src/main/scala/com/evolutiongaming/concurrent/serially/StateVar.scala @@ -11,8 +11,9 @@ trait StateVar[S] { def apply[SS](f: S => (S, SS)): Future[SS] /** - * @return previous value - */ + * @return + * previous value + */ final def set(value: S): Future[S] = getAndUpdate(_ => value) final def update(f: S => S): Future[S] = updateAndGet(f) @@ -41,7 +42,11 @@ trait StateVar[S] { object StateVar { - def apply[S](state: S)(implicit factory: ActorRefFactory): StateVar[S] = { + def apply[S]( + state: S, + )(implicit + factory: ActorRefFactory, + ): StateVar[S] = { val serially = Serially() apply(state, serially) } @@ -52,7 +57,7 @@ object StateVar { new StateVar[S] { - def value() = s + def value(): S = s def apply[SS](f: S => (S, SS)): Future[SS] = { serially { @@ -65,4 +70,4 @@ object StateVar { override def toString = s"StateVar($s)" } } -} \ No newline at end of file +} diff --git a/src/test/scala/com/evolutiongaming/concurrent/serially/AsyncVarSpec.scala b/src/test/scala/com/evolutiongaming/concurrent/serially/AsyncVarSpec.scala index 1f11ab9..0a0feba 100644 --- a/src/test/scala/com/evolutiongaming/concurrent/serially/AsyncVarSpec.scala +++ b/src/test/scala/com/evolutiongaming/concurrent/serially/AsyncVarSpec.scala @@ -1,16 +1,17 @@ package com.evolutiongaming.concurrent.serially - -import scala.util.Success import org.scalatest.matchers.should.Matchers import org.scalatest.wordspec.AnyWordSpec +import scala.concurrent.Future +import scala.util.Success + class AsyncVarSpec extends AnyWordSpec with Matchers { "AsyncVar" should { "apply" in new Scope { - val result = state { before => + val result: Future[Int] = state { before => val after = before + 1 (after, before) } @@ -23,19 +24,19 @@ class AsyncVarSpec extends AnyWordSpec with Matchers { } "update" in new Scope { - val result = state.update(_ + 1) + val result: Future[Int] = state.update(_ + 1) result.value shouldEqual Some(Success(1)) state.value() shouldEqual 1 } "updateAndGet" in new Scope { - val result = state.updateAndGet(_ + 1) + val result: Future[Int] = state.updateAndGet(_ + 1) result.value shouldEqual Some(Success(1)) state.value() shouldEqual 1 } "getAndUpdate" in new Scope { - val result = state.getAndUpdate(_ + 1) + val result: Future[Int] = state.getAndUpdate(_ + 1) result.value shouldEqual Some(Success(0)) state.value() shouldEqual 1 } @@ -47,7 +48,7 @@ class AsyncVarSpec extends AnyWordSpec with Matchers { } "set" in new Scope { - val result = state.set(1) + val result: Future[Int] = state.set(1) result.value shouldEqual Some(Success(0)) state.value() shouldEqual 1 } @@ -58,7 +59,7 @@ class AsyncVarSpec extends AnyWordSpec with Matchers { } private trait Scope { - val serially = SeriallyAsync.now + private val serially = SeriallyAsync.now val state = AsyncVar(0, serially) } -} \ No newline at end of file +} diff --git a/src/test/scala/com/evolutiongaming/concurrent/serially/SeriallyAsyncSpec.scala b/src/test/scala/com/evolutiongaming/concurrent/serially/SeriallyAsyncSpec.scala index ecff974..5fa2624 100644 --- a/src/test/scala/com/evolutiongaming/concurrent/serially/SeriallyAsyncSpec.scala +++ b/src/test/scala/com/evolutiongaming/concurrent/serially/SeriallyAsyncSpec.scala @@ -2,13 +2,12 @@ package com.evolutiongaming.concurrent.serially import com.evolutiongaming.concurrent.CurrentThreadExecutionContext import org.scalatest.concurrent.ScalaFutures - -import scala.concurrent.duration._ -import scala.concurrent.{Await, Promise, TimeoutException} -import scala.util.control.NoStackTrace import org.scalatest.matchers.should.Matchers import org.scalatest.wordspec.AnyWordSpec +import scala.concurrent.duration.* +import scala.concurrent.{Await, Future, Promise, TimeoutException} +import scala.util.control.NoStackTrace class SeriallyAsyncSpec extends AnyWordSpec with ActorSpec with Matchers with ScalaFutures { @@ -18,7 +17,7 @@ class SeriallyAsyncSpec extends AnyWordSpec with ActorSpec with Matchers with Sc var value = 0 val promise = Promise[Int]() serially { value = promise.future.futureValue } - val future = serially { value = 2 } + val future: Future[Unit] = serially { value = 2 } intercept[TimeoutException] { Await.result(future, 100.millis) } promise.success(1) Await.result(future, timeout.duration) @@ -29,7 +28,7 @@ class SeriallyAsyncSpec extends AnyWordSpec with ActorSpec with Matchers with Sc var value = 0 val promise = Promise[Int]() serially.async { promise.future.map(value = _)(CurrentThreadExecutionContext) } - val future = serially { value = 2 } + val future: Future[Unit] = serially { value = 2 } intercept[TimeoutException] { Await.result(future, 100.millis) } promise.success(1) Await.result(future, timeout.duration) @@ -37,20 +36,20 @@ class SeriallyAsyncSpec extends AnyWordSpec with ActorSpec with Matchers with Sc } "not fail on exceptions" in new Scope { - val future1 = serially { throw TestException } + val future1: Future[Nothing] = serially { throw TestException } intercept[TestException.type] { Await.result(future1, timeout.duration) } - val future2 = serially { 1 } + val future2: Future[Int] = serially { 1 } Await.result(future2, timeout.duration) shouldEqual 1 } "fail tasks when stopped" in new Scope { val promise = Promise[Int]() - val result0 = serially { promise.future.futureValue } - val result1 = serially { 1 } - val resultStop = serially.stop() - val result2 = serially { 2 } + val result0: Future[Int] = serially { promise.future.futureValue } + val result1: Future[Int] = serially { 1 } + val resultStop: Future[Unit] = serially.stop() + val result2: Future[Int] = serially { 2 } promise.success(0) @@ -60,14 +59,14 @@ class SeriallyAsyncSpec extends AnyWordSpec with ActorSpec with Matchers with Sc intercept[Serially.Stopped.type] { Await.result(result2, timeout.duration) } - val result3 = serially { 3 } + val result3: Future[Int] = serially { 3 } intercept[Serially.Stopped.type] { Await.result(result3, timeout.duration) } } } private trait Scope extends ActorScope { - val serially = SeriallyAsync()(system) + val serially: SeriallyAsync = SeriallyAsync()(system) } case object TestException extends RuntimeException with NoStackTrace diff --git a/src/test/scala/com/evolutiongaming/concurrent/serially/SeriallySpec.scala b/src/test/scala/com/evolutiongaming/concurrent/serially/SeriallySpec.scala index 96e72be..b892e85 100644 --- a/src/test/scala/com/evolutiongaming/concurrent/serially/SeriallySpec.scala +++ b/src/test/scala/com/evolutiongaming/concurrent/serially/SeriallySpec.scala @@ -1,13 +1,13 @@ package com.evolutiongaming.concurrent.serially import org.scalatest.concurrent.ScalaFutures - -import scala.concurrent.duration._ -import scala.concurrent.{Await, Promise, TimeoutException} -import scala.util.control.NoStackTrace import org.scalatest.matchers.should.Matchers import org.scalatest.wordspec.AnyWordSpec +import scala.concurrent.duration.* +import scala.concurrent.{Await, Future, Promise, TimeoutException} +import scala.util.control.NoStackTrace + class SeriallySpec extends AnyWordSpec with ActorSpec with Matchers with ScalaFutures { "Serially" should { @@ -16,7 +16,7 @@ class SeriallySpec extends AnyWordSpec with ActorSpec with Matchers with ScalaFu var value = 0 val promise = Promise[Int]() serially { value = promise.future.futureValue } - val future = serially { value = 2 } + val future: Future[Unit] = serially { value = 2 } intercept[TimeoutException] { Await.result(future, 100.millis) } promise.success(1) Await.result(future, timeout.duration) @@ -24,20 +24,20 @@ class SeriallySpec extends AnyWordSpec with ActorSpec with Matchers with ScalaFu } "not fail on exceptions" in new Scope { - val future1 = serially { throw TestException } + val future1: Future[Nothing] = serially { throw TestException } intercept[TestException.type] { Await.result(future1, timeout.duration) } - val future2 = serially { 1 } + val future2: Future[Int] = serially { 1 } Await.result(future2, timeout.duration) shouldEqual 1 } "fail tasks when stopped" in new Scope { val promise = Promise[Int]() - val result0 = serially { promise.future.futureValue } - val result1 = serially { 1 } - val resultStop = serially.stop() - val result2 = serially { 2 } + val result0: Future[Int] = serially { promise.future.futureValue } + val result1: Future[Int] = serially { 1 } + val resultStop: Future[Unit] = serially.stop() + val result2: Future[Int] = serially { 2 } promise.success(0) @@ -47,7 +47,7 @@ class SeriallySpec extends AnyWordSpec with ActorSpec with Matchers with ScalaFu intercept[Serially.Stopped.type] { Await.result(result2, timeout.duration) } - val result3 = serially { 3 } + val result3: Future[Int] = serially { 3 } intercept[Serially.Stopped.type] { Await.result(result3, timeout.duration) } } @@ -59,4 +59,3 @@ class SeriallySpec extends AnyWordSpec with ActorSpec with Matchers with ScalaFu case object TestException extends RuntimeException with NoStackTrace } - diff --git a/src/test/scala/com/evolutiongaming/concurrent/serially/StateVarSpec.scala b/src/test/scala/com/evolutiongaming/concurrent/serially/StateVarSpec.scala index 2dbdf54..a2363f9 100644 --- a/src/test/scala/com/evolutiongaming/concurrent/serially/StateVarSpec.scala +++ b/src/test/scala/com/evolutiongaming/concurrent/serially/StateVarSpec.scala @@ -1,16 +1,17 @@ package com.evolutiongaming.concurrent.serially - -import scala.util.Success import org.scalatest.matchers.should.Matchers import org.scalatest.wordspec.AnyWordSpec +import scala.concurrent.Future +import scala.util.Success + class StateVarSpec extends AnyWordSpec with Matchers { "StateVar" should { "apply" in new Scope { - val result = state { before => + val result: Future[Int] = state { before => val after = before + 1 (after, before) } @@ -23,19 +24,19 @@ class StateVarSpec extends AnyWordSpec with Matchers { } "update" in new Scope { - val result = state.update(_ + 1) + val result: Future[Int] = state.update(_ + 1) result.value shouldEqual Some(Success(1)) state.value() shouldEqual 1 } "updateAndGet" in new Scope { - val result = state.updateAndGet(_ + 1) + val result: Future[Int] = state.updateAndGet(_ + 1) result.value shouldEqual Some(Success(1)) state.value() shouldEqual 1 } "getAndUpdate" in new Scope { - val result = state.getAndUpdate(_ + 1) + val result: Future[Int] = state.getAndUpdate(_ + 1) result.value shouldEqual Some(Success(0)) state.value() shouldEqual 1 } @@ -47,7 +48,7 @@ class StateVarSpec extends AnyWordSpec with Matchers { } "set" in new Scope { - val result = state.set(1) + val result: Future[Int] = state.set(1) result.value shouldEqual Some(Success(0)) state.value() shouldEqual 1 } @@ -58,7 +59,7 @@ class StateVarSpec extends AnyWordSpec with Matchers { } private trait Scope { - val serially = Serially.now + val serially: Serially = Serially.now val state = StateVar(0, serially) } } diff --git a/version.sbt b/version.sbt deleted file mode 100644 index 2094d25..0000000 --- a/version.sbt +++ /dev/null @@ -1 +0,0 @@ -ThisBuild / version := "1.0.6-SNAPSHOT"