diff --git a/build.sbt b/build.sbt index 065fe30c..8bce0eba 100644 --- a/build.sbt +++ b/build.sbt @@ -1,5 +1,7 @@ // +import sbtcrossproject.CrossProject + // =====| Shared Settings |===== enablePlugins(GitVersioning) @@ -20,6 +22,7 @@ ThisBuild / sonatypeCredentialHost := "s01.oss.sonatype.org" ThisBuild / sonatypeRepository := "https://s01.oss.sonatype.org/service/local" lazy val testAndCompile = "test->test;compile->compile" +lazy val testToTest = "test->test" lazy val miscSettings = Seq( @@ -56,7 +59,7 @@ lazy val testSettings = // =====| Projects |===== -lazy val `harness-root` = +lazy val `harness-root`: Project = project .in(file(".")) .settings( @@ -71,7 +74,7 @@ lazy val `harness-root` = // `harness-archive`, ) -lazy val `harness-modules` = +lazy val `harness-modules`: Project = project .in(file("modules")) .settings( @@ -103,9 +106,6 @@ lazy val `harness-modules` = `harness-zio-json`.js, // Testing - `harness-test`.jvm, - `harness-test`.native, - `harness-test`.js, `harness-test-container`, `harness-test-container-postgres`, `harness-zio-mock`.jvm, @@ -146,11 +146,76 @@ lazy val `harness-modules` = `harness-payments`.js, `harness-sql`, `harness-sql-mock`, + + // Separate Unit Tests + `harness-core-ut`.jvm, + `harness-core-ut`.native, + `harness-core-ut`.js, + `harness-cli-ut`.jvm, + `harness-cli-ut`.native, + `harness-cli-ut`.js, + `harness-zio-ut`.jvm, + `harness-zio-ut`.native, + `harness-zio-ut`.js, + `harness-zio-json-ut`.jvm, + `harness-zio-json-ut`.native, + `harness-zio-json-ut`.js, + ) + +lazy val `harness-modules-jvm`: Project = + project + .in(file("modules/jvm")) + .settings( + publish / skip := true, + organization := MyOrg, + sonatypeCredentialHost := "s01.oss.sonatype.org", + sonatypeRepository := "https://s01.oss.sonatype.org/service/local", + ) + .aggregate( + // General + `harness-console`, + `harness-core`.jvm, + `harness-deriving`.jvm, + `harness-pk`.jvm, + `harness-schema`.jvm, + `harness-zio`.jvm, + `harness-zio-json`.jvm, + + // Testing + `harness-test-container`, + `harness-test-container-postgres`, + `harness-zio-mock`.jvm, + `harness-zio-test`.jvm, + + // Parsing + `harness-cli`.jvm, + `harness-csv`.jvm, + `harness-xml`, + + // Web + `harness-endpoint`.jvm, + `harness-http-client`.jvm, + `harness-http-server`, + `harness-web`.jvm, + + // Other + `harness-email`, + `harness-email-model`.jvm, + `harness-kafka`, + `harness-payments`.jvm, + `harness-sql`, + `harness-sql-mock`, + + // Separate Unit Tests + `harness-core-ut`.jvm, + `harness-cli-ut`.jvm, + `harness-zio-ut`.jvm, + `harness-zio-json-ut`.jvm, ) // =====| General |===== -lazy val `harness-console` = +lazy val `harness-console`: Project = project .in(file("modules/harness-console")) .settings( @@ -162,10 +227,10 @@ lazy val `harness-console` = ) .dependsOn( `harness-zio`.jvm, - `harness-zio-test`.jvm % Test, + `harness-zio-ut`.jvm % testToTest, ) -lazy val `harness-core` = +lazy val `harness-core`: CrossProject = crossProject(JSPlatform, JVMPlatform, NativePlatform) .in(file("modules/harness-core")) .settings( @@ -178,9 +243,23 @@ lazy val `harness-core` = ), sonatypeCredentialHost := "s01.oss.sonatype.org", ) - .dependsOn(`harness-test` % Test) +lazy val `harness-core-ut`: CrossProject = + crossProject(JSPlatform, JVMPlatform, NativePlatform) + .in(file("modules/harness-core-ut")) + .settings( + name := "harness-core-ut", + publishSettings, + miscSettings, + testSettings, + publish / skip := true, + sonatypeCredentialHost := "s01.oss.sonatype.org", + ) + .dependsOn( + `harness-core` % testAndCompile, + `harness-zio-test` % Test, + ) -lazy val `harness-deriving` = +lazy val `harness-deriving`: CrossProject = crossProject(JSPlatform, JVMPlatform, NativePlatform) .in(file("modules/harness-deriving")) .settings( @@ -195,7 +274,7 @@ lazy val `harness-deriving` = `harness-zio-test` % Test, ) -lazy val `harness-pk` = +lazy val `harness-pk`: CrossProject = crossProject(JSPlatform, JVMPlatform, NativePlatform) .in(file("modules/harness-pk")) .settings( @@ -212,7 +291,7 @@ lazy val `harness-pk` = `harness-schema` % testAndCompile, ) -lazy val `harness-schema` = +lazy val `harness-schema`: CrossProject = crossProject(JSPlatform, JVMPlatform, NativePlatform) .in(file("modules/harness-schema")) .settings( @@ -229,7 +308,7 @@ lazy val `harness-schema` = `harness-deriving` % testAndCompile, ) -lazy val `harness-zio` = +lazy val `harness-zio`: CrossProject = crossProject(JSPlatform, JVMPlatform, NativePlatform) .in(file("modules/harness-zio")) .settings( @@ -248,8 +327,30 @@ lazy val `harness-zio` = `harness-cli` % testAndCompile, `harness-zio-json` % testAndCompile, ) +lazy val `harness-zio-ut`: CrossProject = + crossProject(JSPlatform, JVMPlatform, NativePlatform) + .in(file("modules/harness-zio-ut")) + .settings( + name := "harness-zio-ut", + publishSettings, + miscSettings, + testSettings, + publish / skip := true, + libraryDependencies ++= Seq( + "dev.zio" %%% "zio" % Versions.zio, + ), + ) + .jvmSettings( + Test / fork := true, + ) + .dependsOn( + `harness-zio` % testAndCompile, + `harness-cli-ut` % testAndCompile, + `harness-zio-json-ut` % testAndCompile, + `harness-zio-test` % Test, + ) -lazy val `harness-zio-json` = +lazy val `harness-zio-json`: CrossProject = crossProject(JSPlatform, JVMPlatform, NativePlatform) .in(file("modules/harness-zio-json")) .settings( @@ -267,24 +368,31 @@ lazy val `harness-zio-json` = .dependsOn( `harness-core` % testAndCompile, ) - -// =====| Testing |===== - -lazy val `harness-test` = +lazy val `harness-zio-json-ut`: CrossProject = crossProject(JSPlatform, JVMPlatform, NativePlatform) - .in(file("modules/harness-test")) + .in(file("modules/harness-zio-json-ut")) .settings( - name := "harness-test", + name := "harness-zio-json", publishSettings, miscSettings, + testSettings, + publish / skip := true, libraryDependencies ++= Seq( - "org.typelevel" %%% "cats-core" % Versions.catsCore, - "dev.zio" %%% "zio-test" % Versions.zio, - "dev.zio" %%% "zio-test-sbt" % Versions.zio, + "dev.zio" %%% "zio-json" % Versions.zioJson, ), ) + .jvmSettings( + Test / fork := true, + ) + .dependsOn( + `harness-zio-json` % testAndCompile, + `harness-core-ut` % testAndCompile, + `harness-zio-test` % Test, + ) + +// =====| Testing |===== -lazy val `harness-test-container` = +lazy val `harness-test-container`: Project = project .in(file("modules/harness-test-container")) .settings( @@ -296,7 +404,7 @@ lazy val `harness-test-container` = `harness-zio-test`.jvm, ) -lazy val `harness-test-container-postgres` = +lazy val `harness-test-container-postgres`: Project = project .in(file("modules/harness-test-container-postgres")) .settings( @@ -305,11 +413,11 @@ lazy val `harness-test-container-postgres` = miscSettings, ) .dependsOn( - `harness-test-container`, - `harness-sql`, + `harness-test-container` % testAndCompile, + `harness-sql` % testAndCompile, ) -lazy val `harness-zio-mock` = +lazy val `harness-zio-mock`: CrossProject = crossProject(JSPlatform, JVMPlatform, NativePlatform) .in(file("modules/harness-zio-mock")) .settings( @@ -329,7 +437,7 @@ lazy val `harness-zio-mock` = `harness-zio-test` % Test, ) -lazy val `harness-zio-test` = +lazy val `harness-zio-test`: CrossProject = crossProject(JSPlatform, JVMPlatform, NativePlatform) .in(file("modules/harness-zio-test")) .settings( @@ -337,15 +445,18 @@ lazy val `harness-zio-test` = publishSettings, miscSettings, testSettings, + libraryDependencies ++= Seq( + "dev.zio" %%% "zio-test" % Versions.zio, + "dev.zio" %%% "zio-test-sbt" % Versions.zio, + ), ) .dependsOn( `harness-zio` % testAndCompile, - `harness-test` % testAndCompile, ) // =====| Parsing |===== -lazy val `harness-csv` = +lazy val `harness-csv`: CrossProject = crossProject(JSPlatform, JVMPlatform, NativePlatform) .in(file("modules/harness-csv")) .settings( @@ -357,9 +468,10 @@ lazy val `harness-csv` = ) .dependsOn( `harness-core` % testAndCompile, + `harness-core-ut` % testToTest, ) -lazy val `harness-xml` = +lazy val `harness-xml`: Project = project .in(file("modules/harness-xml")) .settings( @@ -374,9 +486,10 @@ lazy val `harness-xml` = ) .dependsOn( `harness-core`.jvm % testAndCompile, + `harness-core-ut`.jvm % testToTest, ) -lazy val `harness-cli` = +lazy val `harness-cli`: CrossProject = crossProject(JSPlatform, JVMPlatform, NativePlatform) .in(file("modules/harness-cli")) .settings( @@ -388,10 +501,25 @@ lazy val `harness-cli` = .dependsOn( `harness-core` % testAndCompile, ) +lazy val `harness-cli-ut`: CrossProject = + crossProject(JSPlatform, JVMPlatform, NativePlatform) + .in(file("modules/harness-cli-ut")) + .settings( + name := "harness-cli-ut", + publishSettings, + miscSettings, + testSettings, + publish / skip := true, + ) + .dependsOn( + `harness-cli` % testAndCompile, + `harness-core-ut` % testAndCompile, + `harness-zio-test` % Test, + ) // =====| Web |===== -lazy val `harness-endpoint` = +lazy val `harness-endpoint`: CrossProject = crossProject(JSPlatform, JVMPlatform) .in(file("modules/harness-endpoint")) .settings( @@ -406,7 +534,7 @@ lazy val `harness-endpoint` = `harness-schema` % testAndCompile, ) -lazy val `harness-http-client` = +lazy val `harness-http-client`: CrossProject = crossProject(JSPlatform, JVMPlatform) .in(file("modules/harness-http-client")) .settings( @@ -420,7 +548,7 @@ lazy val `harness-http-client` = `harness-endpoint` % testAndCompile, ) -lazy val `harness-http-server` = +lazy val `harness-http-server`: Project = project .in(file("modules/harness-http-server")) .settings( @@ -434,7 +562,7 @@ lazy val `harness-http-server` = `harness-http-client`.jvm % Test, ) -lazy val `harness-web` = +lazy val `harness-web`: CrossProject = crossProject(JSPlatform, JVMPlatform) .in(file("modules/harness-web")) .settings( @@ -453,10 +581,11 @@ lazy val `harness-web` = ) .dependsOn( `harness-zio` % testAndCompile, + `harness-zio-ut` % testToTest, `harness-pk` % testAndCompile, ) -lazy val `harness-web-ui` = +lazy val `harness-web-ui`: Project = project .in(file("modules/harness-web-ui")) .enablePlugins(ScalaJSPlugin) @@ -472,7 +601,7 @@ lazy val `harness-web-ui` = // =====| Plugins |===== -lazy val `harness-js-plugin` = +lazy val `harness-js-plugin`: Project = project .in(file("modules/harness-js-plugin")) .enablePlugins(SbtPlugin) @@ -486,7 +615,7 @@ lazy val `harness-js-plugin` = // =====| Integration Tests |===== -lazy val `it-modules` = +lazy val `it-modules`: Project = project .in(file("it-modules")) .settings( @@ -500,7 +629,7 @@ lazy val `it-modules` = `harness-test-containers-postgres-it`, ) -lazy val `harness-sql-it` = +lazy val `harness-sql-it`: Project = project .in(file("it-modules/harness-sql")) .settings( @@ -511,10 +640,10 @@ lazy val `harness-sql-it` = publish / skip := true, ) .dependsOn( - `harness-test-container-postgres`, + `harness-test-container-postgres` % testAndCompile, ) -lazy val `harness-test-containers-postgres-it` = +lazy val `harness-test-containers-postgres-it`: Project = project .in(file("it-modules/harness-test-containers-postgres")) .settings( @@ -525,12 +654,12 @@ lazy val `harness-test-containers-postgres-it` = publish / skip := true, ) .dependsOn( - `harness-test-container-postgres`, + `harness-test-container-postgres` % testAndCompile, ) // =====| Other |===== -lazy val `harness-email` = +lazy val `harness-email`: Project = project .in(file("modules/harness-email")) .settings( @@ -544,7 +673,7 @@ lazy val `harness-email` = `harness-email-model`.jvm % testAndCompile, ) -lazy val `harness-email-model` = +lazy val `harness-email-model`: CrossProject = crossProject(JSPlatform, JVMPlatform) .in(file("modules/harness-email-model")) .settings( @@ -562,9 +691,10 @@ lazy val `harness-email-model` = .dependsOn( `harness-schema` % testAndCompile, `harness-zio` % testAndCompile, + `harness-zio-ut` % testToTest, ) -lazy val `harness-kafka` = +lazy val `harness-kafka`: Project = project .in(file("modules/harness-kafka")) .settings( @@ -579,9 +709,10 @@ lazy val `harness-kafka` = ) .dependsOn( `harness-zio`.jvm % testAndCompile, + `harness-zio-ut`.jvm % testToTest, ) -lazy val `harness-payments` = +lazy val `harness-payments`: CrossProject = crossProject(JSPlatform, JVMPlatform) .in(file("modules/harness-payments")) .settings( @@ -602,7 +733,7 @@ lazy val `harness-payments` = `harness-pk` % testAndCompile, ) -lazy val `harness-sql` = +lazy val `harness-sql`: Project = project .in(file("modules/harness-sql")) .settings( @@ -617,11 +748,12 @@ lazy val `harness-sql` = ) .dependsOn( `harness-zio`.jvm % testAndCompile, + `harness-zio-ut`.jvm % testToTest, `harness-pk`.jvm % testAndCompile, `harness-deriving`.jvm % testAndCompile, ) -lazy val `harness-sql-mock` = +lazy val `harness-sql-mock`: Project = project .in(file("modules/harness-sql-mock")) .settings( diff --git a/harness-archive/client/shared/src/test/scala/harness/archive/client/QueuedSenderSpec.scala b/harness-archive/client/shared/src/test/scala/harness/archive/client/QueuedSenderSpec.scala index ee077f5d..716c4e68 100644 --- a/harness-archive/client/shared/src/test/scala/harness/archive/client/QueuedSenderSpec.scala +++ b/harness-archive/client/shared/src/test/scala/harness/archive/client/QueuedSenderSpec.scala @@ -15,7 +15,7 @@ object QueuedSenderSpec extends DefaultHarnessSpec { } } yield (ref, sender) - override def spec: TestSpec = + override def testSpec: TestSpec = suite("QueuedSenderSpec")( test("Case 1") { for { diff --git a/harness-web-app-template/modules/domain-impl/src/test/scala/template/domain/impl/storage/InMemoryPaymentMethodStorageSpec.scala b/harness-web-app-template/modules/domain-impl/src/test/scala/template/domain/impl/storage/InMemoryPaymentMethodStorageSpec.scala index 1e0cdfd0..3b7bb67e 100644 --- a/harness-web-app-template/modules/domain-impl/src/test/scala/template/domain/impl/storage/InMemoryPaymentMethodStorageSpec.scala +++ b/harness-web-app-template/modules/domain-impl/src/test/scala/template/domain/impl/storage/InMemoryPaymentMethodStorageSpec.scala @@ -5,11 +5,14 @@ import template.domain.impl.storage.inMemory.* import template.domain.storage.* import zio.* -object InMemoryPaymentMethodStorageSpec - extends DefaultHarnessSpec.ForContract[UserStorage & PaymentMethodStorage]("InMemoryPaymentMethodStorage", PaymentMethodStorageContract)( - ZLayer.make[UserStorage & PaymentMethodStorage]( +object InMemoryPaymentMethodStorageSpec extends ContractHarnessSpec[UserStorage & PaymentMethodStorage]("InMemoryPaymentMethodStorage", PaymentMethodStorageContract) { + + override def layerProvider: LayerProvider[R] = + LayerProvider + .providePerTest( DbState.layer, InMemoryUserStorage.layer, InMemoryPaymentMethodStorage.layer, - ), - ) + ) + +} diff --git a/harness-web-app-template/modules/domain-impl/src/test/scala/template/domain/impl/storage/InMemorySessionStorageSpec.scala b/harness-web-app-template/modules/domain-impl/src/test/scala/template/domain/impl/storage/InMemorySessionStorageSpec.scala index b63127d3..39287812 100644 --- a/harness-web-app-template/modules/domain-impl/src/test/scala/template/domain/impl/storage/InMemorySessionStorageSpec.scala +++ b/harness-web-app-template/modules/domain-impl/src/test/scala/template/domain/impl/storage/InMemorySessionStorageSpec.scala @@ -5,11 +5,14 @@ import template.domain.impl.storage.inMemory.* import template.domain.storage.* import zio.* -object InMemorySessionStorageSpec - extends DefaultHarnessSpec.ForContract[UserStorage & SessionStorage]("InMemorySessionStorage", SessionStorageContract)( - ZLayer.make[UserStorage & SessionStorage]( +object InMemorySessionStorageSpec extends ContractHarnessSpec[UserStorage & SessionStorage]("InMemorySessionStorage", SessionStorageContract) { + + override def layerProvider: LayerProvider[R] = + LayerProvider + .providePerTest( DbState.layer, InMemoryUserStorage.layer, InMemorySessionStorage.layer, - ), - ) + ) + +} diff --git a/harness-web-app-template/modules/domain-impl/src/test/scala/template/domain/impl/storage/InMemoryUserStorageSpec.scala b/harness-web-app-template/modules/domain-impl/src/test/scala/template/domain/impl/storage/InMemoryUserStorageSpec.scala index 6e8dfd10..14ac5be0 100644 --- a/harness-web-app-template/modules/domain-impl/src/test/scala/template/domain/impl/storage/InMemoryUserStorageSpec.scala +++ b/harness-web-app-template/modules/domain-impl/src/test/scala/template/domain/impl/storage/InMemoryUserStorageSpec.scala @@ -5,10 +5,13 @@ import template.domain.impl.storage.inMemory.* import template.domain.storage.* import zio.* -object InMemoryUserStorageSpec - extends DefaultHarnessSpec.ForContract[UserStorage]("InMemoryUserStorage", UserStorageContract)( - ZLayer.make[UserStorage]( +object InMemoryUserStorageSpec extends ContractHarnessSpec[UserStorage]("InMemoryUserStorage", UserStorageContract) { + + override def layerProvider: LayerProvider[R] = + LayerProvider + .providePerTest( DbState.layer, InMemoryUserStorage.layer, - ), - ) + ) + +} diff --git a/harness-web-app-template/modules/domain-impl/src/test/scala/template/domain/impl/storage/PaymentMethodStorageContract.scala b/harness-web-app-template/modules/domain-impl/src/test/scala/template/domain/impl/storage/PaymentMethodStorageContract.scala index 426c7e01..429d5d17 100644 --- a/harness-web-app-template/modules/domain-impl/src/test/scala/template/domain/impl/storage/PaymentMethodStorageContract.scala +++ b/harness-web-app-template/modules/domain-impl/src/test/scala/template/domain/impl/storage/PaymentMethodStorageContract.scala @@ -12,7 +12,7 @@ import zio.test.Assertion.* object PaymentMethodStorageContract extends Contract[UserStorage & PaymentMethodStorage] { - val contract: TestSpec = + override def testSpec: TestSpec = suite("PaymentMethodStorageContract")( suite("insert")( test("works") { diff --git a/harness-web-app-template/modules/domain-impl/src/test/scala/template/domain/impl/storage/SessionStorageContract.scala b/harness-web-app-template/modules/domain-impl/src/test/scala/template/domain/impl/storage/SessionStorageContract.scala index 6251960f..512abd3a 100644 --- a/harness-web-app-template/modules/domain-impl/src/test/scala/template/domain/impl/storage/SessionStorageContract.scala +++ b/harness-web-app-template/modules/domain-impl/src/test/scala/template/domain/impl/storage/SessionStorageContract.scala @@ -12,7 +12,7 @@ import zio.test.Assertion.* object SessionStorageContract extends Contract[UserStorage & SessionStorage] { - val contract: TestSpec = + override def testSpec: TestSpec = suite("SessionStorageContract")( suite("insert")( test("works") { diff --git a/harness-web-app-template/modules/domain-impl/src/test/scala/template/domain/impl/storage/UserStorageContract.scala b/harness-web-app-template/modules/domain-impl/src/test/scala/template/domain/impl/storage/UserStorageContract.scala index 10cb23b0..2af79968 100644 --- a/harness-web-app-template/modules/domain-impl/src/test/scala/template/domain/impl/storage/UserStorageContract.scala +++ b/harness-web-app-template/modules/domain-impl/src/test/scala/template/domain/impl/storage/UserStorageContract.scala @@ -14,7 +14,7 @@ import zio.test.Assertion.* object UserStorageContract extends Contract[UserStorage] { - override val contract: TestSpec = + override def testSpec: TestSpec = suite("UserStorageContract")( suite("insert")( test("works") { diff --git a/it-modules/harness-sql/src/test/scala/harness/sql/SqlISpec.scala b/it-modules/harness-sql/src/test/scala/harness/sql/SqlISpec.scala index 2846bcdd..9426b8d7 100644 --- a/it-modules/harness-sql/src/test/scala/harness/sql/SqlISpec.scala +++ b/it-modules/harness-sql/src/test/scala/harness/sql/SqlISpec.scala @@ -257,7 +257,7 @@ object SqlISpec extends DefaultHarnessSpec { ), ) - override def spec: TestSpec = + override def testSpec: TestSpec = innerSpec .provideSomeLayer[HarnessEnv & JDBCConnectionPool & Scope]( JDBCConnection.poolLayer, diff --git a/it-modules/harness-test-containers-postgres/src/test/scala/harness/testContainer/postgres/PostgresTestContainerISpec.scala b/it-modules/harness-test-containers-postgres/src/test/scala/harness/testContainer/postgres/PostgresTestContainerISpec.scala index 42e908ef..20a4b506 100644 --- a/it-modules/harness-test-containers-postgres/src/test/scala/harness/testContainer/postgres/PostgresTestContainerISpec.scala +++ b/it-modules/harness-test-containers-postgres/src/test/scala/harness/testContainer/postgres/PostgresTestContainerISpec.scala @@ -22,7 +22,7 @@ object PostgresTestContainerISpec extends DefaultHarnessSpec { }, ) - override def spec: TestSpec = + override def testSpec: TestSpec = innerSpec .provideSome[HarnessEnv & Scope & JDBCConnectionPool]( JDBCConnection.poolLayer, diff --git a/modules/harness-cli/shared/src/test/scala/harness/cli/ArgSpec.scala b/modules/harness-cli-ut/shared/src/test/scala/harness/cli/ArgSpec.scala similarity index 94% rename from modules/harness-cli/shared/src/test/scala/harness/cli/ArgSpec.scala rename to modules/harness-cli-ut/shared/src/test/scala/harness/cli/ArgSpec.scala index ccdd94d0..7b5dba36 100644 --- a/modules/harness-cli/shared/src/test/scala/harness/cli/ArgSpec.scala +++ b/modules/harness-cli-ut/shared/src/test/scala/harness/cli/ArgSpec.scala @@ -1,10 +1,10 @@ package harness.cli -import harness.test.* +import harness.zio.test.* import zio.test.* import zio.test.Assertion.* -object ArgSpec extends PlainHarnessSpec { +object ArgSpec extends DefaultHarnessSpec { private val parseSucceeds: TestSpec = { def makeTest(input: String)(expArgs: Arg*): TestSpec = @@ -63,7 +63,7 @@ object ArgSpec extends PlainHarnessSpec { ) } - override def spec: TestSpec = + override def testSpec: TestSpec = suite("ArgSpec")( parseSucceeds, parseFails, diff --git a/modules/harness-cli/shared/src/test/scala/harness/cli/NameSpec.scala b/modules/harness-cli-ut/shared/src/test/scala/harness/cli/NameSpec.scala similarity index 96% rename from modules/harness-cli/shared/src/test/scala/harness/cli/NameSpec.scala rename to modules/harness-cli-ut/shared/src/test/scala/harness/cli/NameSpec.scala index ffe2858a..3682e4d7 100644 --- a/modules/harness-cli/shared/src/test/scala/harness/cli/NameSpec.scala +++ b/modules/harness-cli-ut/shared/src/test/scala/harness/cli/NameSpec.scala @@ -1,13 +1,13 @@ package harness.cli -import harness.test.AssertionHelpers.* -import harness.test.PlainHarnessSpec +import harness.zio.test.* +import harness.zio.test.AssertionHelpers.* import scala.reflect.ClassTag import zio.* import zio.test.* import zio.test.Assertion.* -object NameSpec extends PlainHarnessSpec { +object NameSpec extends DefaultHarnessSpec { private val longName: TestSpec = { val applySucceeds: TestSpec = { @@ -126,7 +126,7 @@ object NameSpec extends PlainHarnessSpec { ) } - override def spec: TestSpec = + override def testSpec: TestSpec = suite("NameSpec")( longName, shortName, diff --git a/modules/harness-cli/shared/src/test/scala/harness/cli/ParserSpec.scala b/modules/harness-cli-ut/shared/src/test/scala/harness/cli/ParserSpec.scala similarity index 98% rename from modules/harness-cli/shared/src/test/scala/harness/cli/ParserSpec.scala rename to modules/harness-cli-ut/shared/src/test/scala/harness/cli/ParserSpec.scala index 9c9215d1..336600da 100644 --- a/modules/harness-cli/shared/src/test/scala/harness/cli/ParserSpec.scala +++ b/modules/harness-cli-ut/shared/src/test/scala/harness/cli/ParserSpec.scala @@ -2,13 +2,13 @@ package harness.cli import cats.data.{Ior, NonEmptyList} import cats.syntax.option.* -import harness.test.AssertionHelpers.* -import harness.test.PlainHarnessSpec +import harness.zio.test.* +import harness.zio.test.AssertionHelpers.* import scala.annotation.unused import zio.test.* import zio.test.Assertion.* -object ParserSpec extends PlainHarnessSpec { +object ParserSpec extends DefaultHarnessSpec { private def parserSuite[T](name: String)(parser: Parser[T])( tests: (FinalizedParser[T] ?=> TestSpec)*, @@ -302,7 +302,7 @@ object ParserSpec extends PlainHarnessSpec { makeTest()(isSuccess(equalTo(SumType.Case2(None)))), ) - override def spec: TestSpec = + override def testSpec: TestSpec = suite("ParserSpec")( help, suite("simple")( diff --git a/modules/harness-core/shared/src/test/scala/harness/core/StringOpsSpec.scala b/modules/harness-core-ut/shared/src/test/scala/harness/core/StringOpsSpec.scala similarity index 93% rename from modules/harness-core/shared/src/test/scala/harness/core/StringOpsSpec.scala rename to modules/harness-core-ut/shared/src/test/scala/harness/core/StringOpsSpec.scala index 170583e3..35c339fc 100644 --- a/modules/harness-core/shared/src/test/scala/harness/core/StringOpsSpec.scala +++ b/modules/harness-core-ut/shared/src/test/scala/harness/core/StringOpsSpec.scala @@ -1,10 +1,10 @@ package harness.core -import harness.test.PlainHarnessSpec +import harness.zio.test.* import zio.test.* import zio.test.Assertion.* -object StringOpsSpec extends PlainHarnessSpec { +object StringOpsSpec extends DefaultHarnessSpec { private def makeTest(input: String, convert: String => String, exp: => String): TestSpec = test(s"'$input' -> '$exp'")(assert(convert(input))(equalTo(exp))) @@ -30,7 +30,7 @@ object StringOpsSpec extends PlainHarnessSpec { */ - override def spec: TestSpec = + override def testSpec: TestSpec = suite("StringOps")( suite("camelToSnake")( makeTest("aBC", _.camelToSnake, "a_bc"), diff --git a/modules/harness-core-ut/shared/src/test/scala/harness/core/VersionSpec.scala b/modules/harness-core-ut/shared/src/test/scala/harness/core/VersionSpec.scala new file mode 100644 index 00000000..0897f19b --- /dev/null +++ b/modules/harness-core-ut/shared/src/test/scala/harness/core/VersionSpec.scala @@ -0,0 +1,176 @@ +package harness.core + +import cats.data.NonEmptyList +import cats.syntax.option.* +import harness.zio.test.* +import zio.internal.stacktracer.SourceLocation +import zio.test.* +import zio.test.Assertion.* + +object VersionSpec extends DefaultHarnessSpec { + + private object versionSpec { + + private def passingParseTest(string: String)(hasVPrefix: Boolean, suffix: Option[Version.Suffix.Repr], num0: Int, numN: Int*)(implicit loc: SourceLocation): TestSpec = + test(string) { + val version = Version.parse(string) + assert(version)(isSome(equalTo(Version(hasVPrefix, NonEmptyList(num0, numN.toList), suffix.map(_.toSuffix))))) && + assert(version.map(_.toString))(isSome(equalTo(string))) + } + + private def failingParseTest(string: String)(implicit loc: SourceLocation): TestSpec = + test(string) { + assert(Version.parse(string))(isNone) + } + + private def orderingTest(smaller: String, greater: String)(implicit loc: SourceLocation): TestSpec = + test(s"$smaller < $greater") { + val smallerVersion = Version.parseUnsafe(smaller) + val greaterVersion = Version.parseUnsafe(greater) + assertTrue( + Version.ordering.lt(smallerVersion, greaterVersion), + Version.ordering.gt(greaterVersion, smallerVersion), + ) + } + + private def equalsTest(a: String, b: String)(implicit loc: SourceLocation): TestSpec = + test(s"$a == $b") { + assertTrue(Version.parseUnsafe(a) == Version.parseUnsafe(b)) + } + + val spec: TestSpec = + suite("version")( + suite("parse")( + suite("passes")( + suite("basic")( + passingParseTest("1")(false, None, 1), + passingParseTest("1.2")(false, None, 1, 2), + passingParseTest("1.2.3")(false, None, 1, 2, 3), + passingParseTest("1.2.3.4")(false, None, 1, 2, 3, 4), + ), + suite("with v prefix")( + passingParseTest("v1")(true, None, 1), + passingParseTest("v1.2")(true, None, 1, 2), + passingParseTest("v1.2.3")(true, None, 1, 2, 3), + passingParseTest("v1.2.3.4")(true, None, 1, 2, 3, 4), + ), + suite("with suffix")( + passingParseTest("1-SNAPSHOT")(false, Version.Suffix.Snapshot(None).some, 1), + passingParseTest("1.2-SNAPSHOT")(false, Version.Suffix.Snapshot(None).some, 1, 2), + passingParseTest("1.2.3-SNAPSHOT")(false, Version.Suffix.Snapshot(None).some, 1, 2, 3), + passingParseTest("1.2.3.4-SNAPSHOT")(false, Version.Suffix.Snapshot(None).some, 1, 2, 3, 4), + ), + suite("with v prefix and suffix")( + passingParseTest("v1-SNAPSHOT")(true, Version.Suffix.Snapshot(None).some, 1), + passingParseTest("v1.2-SNAPSHOT")(true, Version.Suffix.Snapshot(None).some, 1, 2), + passingParseTest("v1.2.3-SNAPSHOT")(true, Version.Suffix.Snapshot(None).some, 1, 2, 3), + passingParseTest("v1.2.3.4-SNAPSHOT")(true, Version.Suffix.Snapshot(None).some, 1, 2, 3, 4), + ), + passingParseTest("v1.2.3.4---SNAPSHOT")(true, Version.Suffix.Other("--SNAPSHOT").some, 1, 2, 3, 4), + ), + suite("fails")( + failingParseTest(" 1.2.3"), + failingParseTest("1.2.3 "), + failingParseTest("v 1.2.3"), + failingParseTest("1.2.3 SNAPSHOT"), + ), + ), + suite("ordering")( + // without suffix + orderingTest("0", "1"), + orderingTest("2", "11"), + orderingTest("0", "0.1"), + orderingTest("0.1", "0.1.2"), + orderingTest("0.1.2", "0.1.2.3"), + orderingTest("0.0.1", "0.0.2"), + // with suffix + orderingTest("0-SNAPSHOT-2", "0-SNAPSHOT-11"), + orderingTest("0-SNAPSHOT-2", "0-RC1"), + orderingTest("0-RC2", "0-RC11"), + ), + suite("equals")( + equalsTest("0", "0"), + equalsTest("3", "3.0.0"), + equalsTest("v3", "3.0.0"), + ), + ) + + } + + private object suffixSpec { + + private def passingParseTest(string: String, suffix: Version.Suffix.Repr)(implicit loc: SourceLocation): TestSpec = + test(string) { + assertTrue(Version.Suffix.parse(string).repr == suffix) + } + + private def orderingTest(smaller: String, greater: String)(implicit loc: SourceLocation): TestSpec = + test(s"$smaller < $greater") { + val smallerSuffix = Version.Suffix.parse(smaller) + val greaterSuffix = Version.Suffix.parse(greater) + assertTrue( + Version.Suffix.ordering.lt(smallerSuffix, greaterSuffix), + Version.Suffix.ordering.gt(greaterSuffix, smallerSuffix), + ) + } + + private def equalsTest(a: String, b: String)(implicit loc: SourceLocation): TestSpec = + test(s"$a == $b") { + assertTrue(Version.Suffix.parse(a) == Version.Suffix.parse(b)) + } + + val spec: TestSpec = + suite("suffix")( + suite("parse")( + // snapshot + passingParseTest("snap", Version.Suffix.Snapshot(None)), + passingParseTest("snap1", Version.Suffix.Snapshot("1".some)), + passingParseTest("snap-1", Version.Suffix.Snapshot("-1".some)), + passingParseTest("snapshot", Version.Suffix.Snapshot(None)), + passingParseTest("snapshot1", Version.Suffix.Snapshot("1".some)), + passingParseTest("snapshot-1", Version.Suffix.Snapshot("-1".some)), + // rc + passingParseTest("RC1", Version.Suffix.RC(1)), + passingParseTest("rc2", Version.Suffix.RC(2)), + passingParseTest("RC-3", Version.Suffix.RC(3)), + // other + passingParseTest("snappy", Version.Suffix.Other("SNAPPY")), + passingParseTest("other", Version.Suffix.Other("OTHER")), + passingParseTest("RC--3", Version.Suffix.Other("RC--3")), + ), + suite("ordering")( + // same type + orderingTest("RC1", "RC2"), + orderingTest("RC2", "RC11"), + orderingTest("SNAPSHOT", "SNAPSHOT-1"), + orderingTest("SNAPSHOT-2", "SNAPSHOT-11"), + orderingTest("SNAPSHOT-2", "SNAPSHOT-11"), + orderingTest("snappy11", "snappy2"), + // different type + orderingTest("SNAPSHOT", "RC1"), + orderingTest("SNAPSHOT", "snappy"), + orderingTest("RC1", "snappy"), + ), + suite("equals")( + // snapshot + equalsTest("snapshot2", "SNAP-2"), + equalsTest("snapshot-2", "SNAP-2"), + equalsTest("snapshot2", "SNAP2"), + equalsTest("snapshot-2", "SNAP2"), + // rc + equalsTest("RC1", "rc1"), + equalsTest("RC1", "rc-1"), + // other + equalsTest("snappy", "SNAPPY"), + ), + ) + + } + + override def testSpec: TestSpec = + suite("VersionSpec")( + versionSpec.spec, + suffixSpec.spec, + ) + +} diff --git a/modules/harness-core/shared/src/test/scala/harness/core/ZipSpec.scala b/modules/harness-core-ut/shared/src/test/scala/harness/core/ZipSpec.scala similarity index 89% rename from modules/harness-core/shared/src/test/scala/harness/core/ZipSpec.scala rename to modules/harness-core-ut/shared/src/test/scala/harness/core/ZipSpec.scala index 561da1c1..0d7eec09 100644 --- a/modules/harness-core/shared/src/test/scala/harness/core/ZipSpec.scala +++ b/modules/harness-core-ut/shared/src/test/scala/harness/core/ZipSpec.scala @@ -1,14 +1,15 @@ package harness.core +import harness.zio.test.* import zio.* import zio.internal.stacktracer.SourceLocation import zio.test.* -object ZipSpec extends ZIOSpecDefault { +object ZipSpec extends DefaultHarnessSpec { private final class MakeTest[_1, _2, Out](in1: _1, in2: _2)(implicit zip: Zip.Out[_1, _2, Out], loc: SourceLocation) { - def expect(exp: Out): Spec[Any, Any] = + def expect(exp: Out): TestSpec = test(s"zip($in1, $in2) -> $exp") { val out: zip.Out = zip.zip(in1, in2) assertTrue( @@ -22,7 +23,7 @@ object ZipSpec extends ZIOSpecDefault { private def makeTest[_1, _2](in1: _1, in2: _2)(implicit zip: Zip[_1, _2], loc: SourceLocation): MakeTest[_1, _2, zip.Out] = new MakeTest[_1, _2, zip.Out](in1, in2) - override def spec: Spec[TestEnvironment & Scope, Any] = + override def testSpec: TestSpec = suite("ZipSpec")( makeTest(0, ()).expect(0), makeTest((), 0).expect(0), diff --git a/modules/harness-core/shared/src/main/scala/harness/core/Version.scala b/modules/harness-core/shared/src/main/scala/harness/core/Version.scala index 63eb871d..14df8c21 100644 --- a/modules/harness-core/shared/src/main/scala/harness/core/Version.scala +++ b/modules/harness-core/shared/src/main/scala/harness/core/Version.scala @@ -7,36 +7,121 @@ import scala.annotation.tailrec final case class Version( hasVPrefix: Boolean, numbers: NonEmptyList[Int], - suffixOpt: Option[String], + suffixOpt: Option[Version.Suffix], ) { private val numbersList: List[Int] = numbers.toList - private val numbersArray: IArray[Int] = IArray.from(numbersList) - final def major: Int = numbersArray(0) + def major: Int = numbers.head - final def minorOpt: Option[Int] = Option.when(numbersArray.length >= 2)(numbersArray(1)) - final def minor: Int = minorOpt.getOrElse(0) + def minorOpt: Option[Int] = numbersList match + case _ :: v :: _ => v.some + case _ => None + def minor: Int = minorOpt.getOrElse(0) - final def patchOpt: Option[Int] = Option.when(numbersArray.length >= 3)(numbersArray(2)) - final def patch: Int = minorOpt.getOrElse(0) + def patchOpt: Option[Int] = numbersList match + case _ :: _ :: v :: _ => v.some + case _ => None + def patch: Int = minorOpt.getOrElse(0) - final def strippedSuffixOpt: Option[String] = suffixOpt.map(_.toList.dropWhile(_ == '-').mkString) - final def strippedSuffix: String = strippedSuffixOpt.getOrElse("") + def suffixString: String = suffixOpt.fold("")(s => "-" + s.toString) - override def toString: String = numbersList.mkString(if (hasVPrefix) "v" else "", ".", suffixOpt.getOrElse("")) + override def toString: String = numbersList.mkString(if (hasVPrefix) "v" else "", ".", suffixString) override def equals(obj: Any): Boolean = - obj.asInstanceOf[Matchable] match { + obj.asInstanceOf[Matchable] match case that: Version => Version.ordering.equiv(this, that) case _ => false - } } object Version { val zero: Version = Version.make(0) - private val reg = "^(v)?([0-9]+(?:\\.[0-9]+)*)(-.+)?$".r + final case class Suffix private (raw: String, repr: Suffix.Repr) { + + override def toString: String = raw + + override def equals(obj: Any): Boolean = + obj.asInstanceOf[Matchable] match + case that: Version.Suffix => Version.Suffix.ordering.equiv(this, that) + case _ => false + + } + object Suffix { + + def fromRepr(repr: Suffix.Repr): Suffix = Suffix(repr.toString, repr) + def snapshot: Suffix = Repr.Snapshot(None).toSuffix + def snapshot(suffix: String): Suffix = Repr.Snapshot(suffix.some).toSuffix + def rc(rc: Int): Suffix = Repr.RC(rc).toSuffix + def other(other: String): Suffix = Repr.Other(other).toSuffix + + sealed trait Repr { + + override final def toString: String = this match + case Repr.Snapshot(suffix) => "SNAPSHOT" + suffix.getOrElse("") + case Repr.RC(rc) => s"RC$rc" + case Repr.Other(other) => other + + override def equals(obj: Any): Boolean = + obj.asInstanceOf[Matchable] match + case that: Version.Suffix.Repr => Version.Suffix.Repr.ordering.equiv(this, that) + case _ => false + + final def toSuffix: Suffix = Suffix(this.toString, this) + + } + object Repr { + + final case class Snapshot(suffix: Option[String]) extends Suffix.Repr + final case class RC(rc: Int) extends Suffix.Repr + final case class Other(other: String) extends Suffix.Repr + + private val getInt: Unapply[String, Int] = _.stripPrefix("-").toIntOption + + private def ord(suffix: Repr): Int = suffix match { + case Snapshot(_) => 1 + case RC(_) => 2 + case Other(_) => 3 + } + + implicit val ordering: Ordering[Repr] = { + case (Snapshot(a), Snapshot(b)) => + (a, b) match { + case (Some(getInt(a)), Some(getInt(b))) => Ordering[Int].compare(a, b) + case (Some(a), Some(b)) => Ordering[String].compare(a, b) + case (Some(_), None) => 1 + case (None, Some(_)) => -1 + case (None, None) => 0 + } + case (RC(a), RC(b)) => Ordering[Int].compare(a, b) + case (Other(a), Other(b)) => Ordering[String].compare(a, b) + case (a, b) => Ordering[Int].compare(ord(a), ord(b)) + } + + private val rcReg = "^RC-?(\\d+)$".r + private val snapshotReg1 = "^SNAPSHOT(.+)?$".r + private val snapshotReg2 = "^SNAP([^A-Z].*)$".r + + def parse(suffix: String): Repr = + suffix.toUpperCase match { + case rcReg(rc) => RC(rc.toInt) + case snapshotReg1(suffix) => Snapshot(Option(suffix)) + case "SNAP" => Snapshot(None) + case snapshotReg2(suffix) => Snapshot(suffix.some) + case suffix => Other(suffix) + } + + } + + export Suffix.Repr.{Other, RC, Snapshot} + + def parse(suffix: String): Suffix = Suffix(suffix, Repr.parse(suffix)) + + implicit val ordering: Ordering[Suffix] = Ordering.by(_.repr) + + } + + private val reg = "^(v)?([0-9]+(?:\\.[0-9]+)*)(?:-(.+))?$".r implicit val stringEncoder: StringEncoder[Version] = StringEncoder.usingToString implicit val stringDecoder: StringDecoder[Version] = StringDecoder.fromOptionF("Version", Version.parse) @@ -53,7 +138,7 @@ object Version { case (_, _) => (versionA.suffixOpt, versionB.suffixOpt) match { case (None, None) => 0 - case (Some(aSuffix), Some(bSuffix)) => Ordering[String].compare(aSuffix, bSuffix) + case (Some(aSuffix), Some(bSuffix)) => Ordering[Suffix].compare(aSuffix, bSuffix) case (Some(_), None) => -1 case (None, Some(_)) => 1 } @@ -67,7 +152,7 @@ object Version { def parse(string: String): Option[Version] = string match { - case reg(vPrefix, numbers, suffix) => Version(vPrefix != null, NonEmptyList.fromListUnsafe(numbers.split("\\.").toList.map(_.toInt)), Option(suffix)).some + case reg(vPrefix, numbers, suffix) => Version(vPrefix != null, NonEmptyList.fromListUnsafe(numbers.split("\\.").toList.map(_.toInt)), Option(suffix).map(Suffix.parse)).some case _ => None } @@ -77,4 +162,6 @@ object Version { case None => throw new RuntimeException(s"Invalid version: '$string'") } + val fromString: Unapply[String, Version] = parse(_) + } diff --git a/modules/harness-core/shared/src/test/scala/harness/core/VersionSpec.scala b/modules/harness-core/shared/src/test/scala/harness/core/VersionSpec.scala deleted file mode 100644 index 251ddb2d..00000000 --- a/modules/harness-core/shared/src/test/scala/harness/core/VersionSpec.scala +++ /dev/null @@ -1,87 +0,0 @@ -package harness.core - -import cats.data.NonEmptyList -import cats.syntax.option.* -import cats.syntax.traverse.* -import harness.test.PlainHarnessSpec -import zio.test.* -import zio.test.Assertion.* - -object VersionSpec extends PlainHarnessSpec { - - private def makePassingParseTest(string: String)(hasVPrefix: Boolean, suffix: Option[String], num0: Int, numN: Int*): TestSpec = - test(string) { - val version = Version.parse(string) - assert(version)(isSome(equalTo(Version(hasVPrefix, NonEmptyList(num0, numN.toList), suffix)))) && - assert(version.map(_.toString))(isSome(equalTo(string))) - } - - private def makeFailingParseTest(string: String): TestSpec = - test(string) { - assert(Version.parse(string))(isNone) - } - - private def makeOrderingTest(pairs: String*): TestSpec = { - val sortedVersions: List[Version] = pairs.toList.traverse(Version.parse).get - suite(sortedVersions.mkString("sorts to: [", ", ", "]"))( - sortedVersions.permutations.toList.map { versions => - test(versions.mkString("[", ", ", "]")) { - assert(versions.sorted)(equalTo(sortedVersions)) - } - } *, - ) - } - - override def spec: TestSpec = - suite("Version")( - suite("parse")( - suite("passes")( - suite("basic")( - makePassingParseTest("1")(false, None, 1), - makePassingParseTest("1.2")(false, None, 1, 2), - makePassingParseTest("1.2.3")(false, None, 1, 2, 3), - makePassingParseTest("1.2.3.4")(false, None, 1, 2, 3, 4), - ), - suite("with v prefix")( - makePassingParseTest("v1")(true, None, 1), - makePassingParseTest("v1.2")(true, None, 1, 2), - makePassingParseTest("v1.2.3")(true, None, 1, 2, 3), - makePassingParseTest("v1.2.3.4")(true, None, 1, 2, 3, 4), - ), - suite("with suffix")( - makePassingParseTest("1-SNAPSHOT")(false, "-SNAPSHOT".some, 1), - makePassingParseTest("1.2-SNAPSHOT")(false, "-SNAPSHOT".some, 1, 2), - makePassingParseTest("1.2.3-SNAPSHOT")(false, "-SNAPSHOT".some, 1, 2, 3), - makePassingParseTest("1.2.3.4-SNAPSHOT")(false, "-SNAPSHOT".some, 1, 2, 3, 4), - ), - suite("with v prefix and suffix")( - makePassingParseTest("v1-SNAPSHOT")(true, "-SNAPSHOT".some, 1), - makePassingParseTest("v1.2-SNAPSHOT")(true, "-SNAPSHOT".some, 1, 2), - makePassingParseTest("v1.2.3-SNAPSHOT")(true, "-SNAPSHOT".some, 1, 2, 3), - makePassingParseTest("v1.2.3.4-SNAPSHOT")(true, "-SNAPSHOT".some, 1, 2, 3, 4), - ), - makePassingParseTest("v1.2.3.4---SNAPSHOT")(true, "---SNAPSHOT".some, 1, 2, 3, 4), - ), - suite("fails")( - makeFailingParseTest(" 1.2.3"), - makeFailingParseTest("1.2.3 "), - makeFailingParseTest("v 1.2.3"), - makeFailingParseTest("1.2.3 SNAPSHOT"), - ), - ), - suite("ordering")( - makeOrderingTest(), - makeOrderingTest("1"), - makeOrderingTest("1", "1.1"), - makeOrderingTest("1.1", "1.2"), - makeOrderingTest("1", "1.1-RC1", "1.1"), - makeOrderingTest("1", "1.1-RC1", "1.1", "1.1.1", "1.1.2", "1.2", "1.2"), - ), - suite("equals")( - test("basic") { assertTrue(Version.parseUnsafe("0") == Version.parseUnsafe("0")) }, - test("extra zeros") { assertTrue(Version.parseUnsafe("3") == Version.parseUnsafe("3.0.0")) }, - test("with v") { assertTrue(Version.parseUnsafe("v3") == Version.parseUnsafe("3.0.0")) }, - ), - ) - -} diff --git a/modules/harness-csv/shared/src/test/scala/harness/csv/DecoderSpec.scala b/modules/harness-csv/shared/src/test/scala/harness/csv/DecoderSpec.scala index 25a9affd..30608b9e 100644 --- a/modules/harness-csv/shared/src/test/scala/harness/csv/DecoderSpec.scala +++ b/modules/harness-csv/shared/src/test/scala/harness/csv/DecoderSpec.scala @@ -1,11 +1,11 @@ package harness.csv import cats.syntax.option.* -import harness.test.* +import harness.zio.test.* import zio.test.* import zio.test.Assertion.* -object DecoderSpec extends PlainHarnessSpec { +object DecoderSpec extends DefaultHarnessSpec { private def passingTest[T: CsvDecoder](name: String)(csv: String, exp: List[T]): TestSpec = test(name) { @@ -24,7 +24,7 @@ object DecoderSpec extends PlainHarnessSpec { } - override def spec: TestSpec = + override def testSpec: TestSpec = suite("DecoderSpec")( suite("passes")( passingTest[Person]("case-1")("F,L,", List(Person("F", "L", None))), diff --git a/modules/harness-csv/shared/src/test/scala/harness/csv/HeaderDecoderSpec.scala b/modules/harness-csv/shared/src/test/scala/harness/csv/HeaderDecoderSpec.scala index 649aebcf..bc222b2e 100644 --- a/modules/harness-csv/shared/src/test/scala/harness/csv/HeaderDecoderSpec.scala +++ b/modules/harness-csv/shared/src/test/scala/harness/csv/HeaderDecoderSpec.scala @@ -1,11 +1,11 @@ package harness.csv import cats.syntax.option.* -import harness.test.* +import harness.zio.test.* import zio.test.* import zio.test.Assertion.* -object HeaderDecoderSpec extends PlainHarnessSpec { +object HeaderDecoderSpec extends DefaultHarnessSpec { private def passingTest[T: CsvHeaderDecoder](name: String)(csv: String, exp: List[T]): TestSpec = test(name) { @@ -29,7 +29,7 @@ object HeaderDecoderSpec extends PlainHarnessSpec { } - override def spec: TestSpec = + override def testSpec: TestSpec = suite("DecoderSpec")( suite("passes")( passingTest[Person]("case-1")("first-name,last-name,age\nF,L,", List(Person("F", "L", None))), diff --git a/modules/harness-csv/shared/src/test/scala/harness/csv/ParserSpec.scala b/modules/harness-csv/shared/src/test/scala/harness/csv/ParserSpec.scala index b5bfbf8f..da055125 100644 --- a/modules/harness-csv/shared/src/test/scala/harness/csv/ParserSpec.scala +++ b/modules/harness-csv/shared/src/test/scala/harness/csv/ParserSpec.scala @@ -1,18 +1,18 @@ package harness.csv import cats.syntax.option.* -import harness.test.* +import harness.zio.test.* import zio.test.* import zio.test.Assertion.* -object ParserSpec extends PlainHarnessSpec { +object ParserSpec extends DefaultHarnessSpec { private def passingTest(name: String)(csv: String, exp: List[List[Option[String]]]): TestSpec = test(name) { assert(Parser.parse(csv).map(_.map(_.toList)))(isRight(equalTo(exp))) } - override def spec: TestSpec = + override def testSpec: TestSpec = suite("ParserSpec")( suite("passes")( passingTest("case-1")( diff --git a/modules/harness-deriving/shared/src/test/scala/harness/deriving/ExampleK0DerivationSpec.scala b/modules/harness-deriving/shared/src/test/scala/harness/deriving/ExampleK0DerivationSpec.scala index 5555b0e2..85c0559d 100644 --- a/modules/harness-deriving/shared/src/test/scala/harness/deriving/ExampleK0DerivationSpec.scala +++ b/modules/harness-deriving/shared/src/test/scala/harness/deriving/ExampleK0DerivationSpec.scala @@ -77,9 +77,7 @@ object ExampleK0DerivationSpec extends DefaultHarnessSpec { } *, ) - // override def logLevel: Logger.LogLevel = Logger.LogLevel.Debug - - override def spec: TestSpec = + override def testSpec: TestSpec = suite("ExampleK0DerivationSpec")( makeSuite("ProductSimple")(productSimpleInstance, ProductSimple.instances), makeSuite("SumSimple")(sumSimpleInstance, SumSimple.instances), diff --git a/modules/harness-deriving/shared/src/test/scala/harness/deriving/ExampleK11DerivationSpec.scala b/modules/harness-deriving/shared/src/test/scala/harness/deriving/ExampleK11DerivationSpec.scala index 6ca0b47e..54d6075b 100644 --- a/modules/harness-deriving/shared/src/test/scala/harness/deriving/ExampleK11DerivationSpec.scala +++ b/modules/harness-deriving/shared/src/test/scala/harness/deriving/ExampleK11DerivationSpec.scala @@ -51,9 +51,7 @@ object ExampleK11DerivationSpec extends DefaultHarnessSpec { // =====| Test |===== - // override def logLevel: Logger.LogLevel = Logger.LogLevel.Debug - - override def spec: TestSpec = + override def testSpec: TestSpec = suite("ExampleK11DerivationSpec")( suite("ProductSimple")( test("works-1") { diff --git a/modules/harness-deriving/shared/src/test/scala/harness/deriving/ExampleK1DerivationSpec.scala b/modules/harness-deriving/shared/src/test/scala/harness/deriving/ExampleK1DerivationSpec.scala index 065fd824..c7e997af 100644 --- a/modules/harness-deriving/shared/src/test/scala/harness/deriving/ExampleK1DerivationSpec.scala +++ b/modules/harness-deriving/shared/src/test/scala/harness/deriving/ExampleK1DerivationSpec.scala @@ -61,9 +61,7 @@ object ExampleK1DerivationSpec extends DefaultHarnessSpec { // =====| Test |===== - // override def logLevel: Logger.LogLevel = Logger.LogLevel.Debug - - override def spec: TestSpec = + override def testSpec: TestSpec = suite("ExampleK1DerivationSpec")( suite("ProductSimple")( test("works-1") { diff --git a/modules/harness-pk/shared/src/test/scala/harness/pk/TUIDSpec.scala b/modules/harness-pk/shared/src/test/scala/harness/pk/TUIDSpec.scala index 874b4c53..deb60f3b 100644 --- a/modules/harness-pk/shared/src/test/scala/harness/pk/TUIDSpec.scala +++ b/modules/harness-pk/shared/src/test/scala/harness/pk/TUIDSpec.scala @@ -11,7 +11,7 @@ object TUIDSpec extends DefaultHarnessSpec { assertTrue(TUID.make(instant, highBytes, lowBytes).toUUID.toString.replaceAll("-", "") == exp.replaceAll("-", "")) } - override def spec: TestSpec = + override def testSpec: TestSpec = suite("TUIDSpec")( suite("epoch 0")( makeTest("0/0")(Instant.ofEpochSecond(0), 0L, 0L)("000000000-0000000-0000000000000000"), diff --git a/modules/harness-schema/shared/src/test/scala/harness/schema/SchemaDerivationSpec.scala b/modules/harness-schema/shared/src/test/scala/harness/schema/SchemaDerivationSpec.scala index c09f10fd..35bcb162 100644 --- a/modules/harness-schema/shared/src/test/scala/harness/schema/SchemaDerivationSpec.scala +++ b/modules/harness-schema/shared/src/test/scala/harness/schema/SchemaDerivationSpec.scala @@ -312,7 +312,7 @@ object SchemaDerivationSpec extends DefaultHarnessSpec { // override def logLevel: Logger.LogLevel = Logger.LogLevel.Debug - override def spec: TestSpec = + override def testSpec: TestSpec = suite("SchemaDerivationSpec")( makeSpec("ProductSimple")(productSimpleInstance), makeSpec("SumSimple")(sumSimpleInstance), diff --git a/modules/harness-sql-mock/src/test/scala/harness/sql/mock/ExampleSpec.scala b/modules/harness-sql-mock/src/test/scala/harness/sql/mock/ExampleSpec.scala index 7c3304c6..c1f4531f 100644 --- a/modules/harness-sql-mock/src/test/scala/harness/sql/mock/ExampleSpec.scala +++ b/modules/harness-sql-mock/src/test/scala/harness/sql/mock/ExampleSpec.scala @@ -6,30 +6,30 @@ import zio.{test as _, *} import zio.test.* import zio.test.Assertion.* -object ExampleSpec extends ZioDefaultHarnessSpec { +object ExampleSpec extends HarnessSpec[ExampleSpec.Storage] { - private type Ex1Id = Ex1Id.Id - private object Ex1Id extends TableKey + type Ex1Id = Ex1Id.Id + object Ex1Id extends TableKey - private final case class Ex1( + final case class Ex1( id: Ex1Id, value: String, ) - private type Ex2Id = Ex2Id.Id - private object Ex2Id extends TableKey + type Ex2Id = Ex2Id.Id + object Ex2Id extends TableKey - private final case class Ex2( + final case class Ex2( id: Ex2Id, ex1Id: Ex1Id, value: String, ) - private final case class State( + final case class State( ex1s: State.Ex1Table, ex2s: State.Ex2Table, ) - private object State { + object State { final class Ex1Table private (values: Chunk[Ex1]) extends MockTable[Ex1, Ex1Table]("Ex1", values) { val PK = primaryKeyIndex(_.id) @@ -48,7 +48,7 @@ object ExampleSpec extends ZioDefaultHarnessSpec { } - private final case class Storage(state: MockState[Throwable, State]) { + final case class Storage(state: MockState[Throwable, State]) { def insertEx1(ex1: Ex1): Task[Unit] = state.focusAndUpdate(_.ex1s)(_ + ex1) @@ -66,12 +66,22 @@ object ExampleSpec extends ZioDefaultHarnessSpec { state.focusAndUpdateW(_.ex2s) { (a, b) => a.ex1s.PK.get(ex2.ex1Id) *> (b + ex2) } } - private object Storage { + object Storage { val layer: URLayer[MockState[Throwable, State], Storage] = ZLayer.fromFunction { Storage.apply } } - private val innerSpec: Spec[Storage, Any] = + override def layerProvider: LayerProvider[R] = + LayerProvider.providePerTest( + MockState.layer[Throwable, State]( + State( + MockTable.empty, + MockTable.empty, + ), + ) >>> Storage.layer, + ) + + override def testSpec: TestSpec = suite("ExampleSpec")( test("insertEx1") { for { @@ -143,14 +153,4 @@ object ExampleSpec extends ZioDefaultHarnessSpec { }, ) - override def spec: TestSpec = - innerSpec.provideLayer { - MockState.layer[Throwable, State]( - State( - MockTable.empty, - MockTable.empty, - ), - ) >>> Storage.layer - } - } diff --git a/modules/harness-sql/src/main/scala/harness/sql/ConnectionFactory.scala b/modules/harness-sql/src/main/scala/harness/sql/ConnectionFactory.scala index e2fad1fb..439d834e 100644 --- a/modules/harness-sql/src/main/scala/harness/sql/ConnectionFactory.scala +++ b/modules/harness-sql/src/main/scala/harness/sql/ConnectionFactory.scala @@ -2,9 +2,8 @@ package harness.sql import harness.sql.error.ConnectionError import harness.zio.* -import zio.* - import java.sql.{Connection, DriverManager} +import zio.* final class ConnectionFactory private ( private[sql] val getJDBCConnection: ZIO[Scope, ConnectionError, JDBCConnection], diff --git a/modules/harness-sql/src/main/scala/harness/sql/autoSchema/MigrationPlan.scala b/modules/harness-sql/src/main/scala/harness/sql/autoSchema/MigrationPlan.scala index a5d2feb7..1c85c043 100644 --- a/modules/harness-sql/src/main/scala/harness/sql/autoSchema/MigrationPlan.scala +++ b/modules/harness-sql/src/main/scala/harness/sql/autoSchema/MigrationPlan.scala @@ -5,7 +5,6 @@ import cats.syntax.either.* import cats.syntax.traverse.* import harness.core.Version import harness.sql.autoSchema.MigrationStep.Encoded - import scala.annotation.tailrec final case class MigrationPlan private ( diff --git a/modules/harness-sql/src/main/scala/harness/sql/query/IntQueryResult.scala b/modules/harness-sql/src/main/scala/harness/sql/query/IntQueryResult.scala index 8f56627e..af3ab8c1 100644 --- a/modules/harness-sql/src/main/scala/harness/sql/query/IntQueryResult.scala +++ b/modules/harness-sql/src/main/scala/harness/sql/query/IntQueryResult.scala @@ -5,7 +5,7 @@ import harness.sql.error.QueryError import harness.zio.* import zio.* -final class IntQueryResult private[query](queryName: String, fragment: Fragment, effect: ZIO[JDBCConnection & Logger, QueryError, Int]) { +final class IntQueryResult private[query] (queryName: String, fragment: Fragment, effect: ZIO[JDBCConnection & Logger, QueryError, Int]) { def execute: ZIO[JDBCConnection & Logger & Telemetry, QueryError, Int] = effect.telemetrize("Executed SQL query", "query-name" -> queryName) diff --git a/modules/harness-test/shared/src/main/scala/harness/test/PlainHarnessSpec.scala b/modules/harness-test/shared/src/main/scala/harness/test/PlainHarnessSpec.scala deleted file mode 100644 index 83120ab5..00000000 --- a/modules/harness-test/shared/src/main/scala/harness/test/PlainHarnessSpec.scala +++ /dev/null @@ -1,15 +0,0 @@ -package harness.test - -import zio.* -import zio.test.* - -abstract class PlainHarnessSpec extends ZIOSpecDefault { - - final type TestSpec = Spec[TestEnvironment & Scope, Any] - - override def spec: TestSpec - - override def aspects: Chunk[TestAspectAtLeastR[TestEnvironment]] = - Chunk(TestAspect.samples(15), TestAspect.shrinks(0)) - -} diff --git a/modules/harness-web-ui/src/main/scala/harness/webUI/error/UIError.scala b/modules/harness-web-ui/src/main/scala/harness/webUI/error/UIError.scala index 0717586f..4b4f4d0e 100644 --- a/modules/harness-web-ui/src/main/scala/harness/webUI/error/UIError.scala +++ b/modules/harness-web-ui/src/main/scala/harness/webUI/error/UIError.scala @@ -51,5 +51,5 @@ object UIError { def fromEither[A](either: => Either[String, A]): IO[UIError.Failure, A] = ZIO.fromEither(either).mapError(UIError.Failure.internalDefect) - + } diff --git a/modules/harness-web-ui/src/test/scala/harness/webUI/style/StyleSheetSpec.scala b/modules/harness-web-ui/src/test/scala/harness/webUI/style/StyleSheetSpec.scala index aa9e0f69..7a4040aa 100644 --- a/modules/harness-web-ui/src/test/scala/harness/webUI/style/StyleSheetSpec.scala +++ b/modules/harness-web-ui/src/test/scala/harness/webUI/style/StyleSheetSpec.scala @@ -1,12 +1,12 @@ package harness.webUI.style -import harness.test.* import harness.webUI.style.ColorPalate.implicits.default +import harness.zio.test.* import zio.test.* -object StyleSheetSpec extends PlainHarnessSpec { +object StyleSheetSpec extends DefaultHarnessSpec { - override def spec: TestSpec = + override def testSpec: TestSpec = suite("StyleSheetSpec")( test("show toString") { val ss = new DefaultStyleSheet {} diff --git a/modules/harness-web/shared/src/test/scala/harness/web/PartialSpec.scala b/modules/harness-web/shared/src/test/scala/harness/web/PartialSpec.scala index d8f95d8c..bba81324 100644 --- a/modules/harness-web/shared/src/test/scala/harness/web/PartialSpec.scala +++ b/modules/harness-web/shared/src/test/scala/harness/web/PartialSpec.scala @@ -1,12 +1,12 @@ package harness.web -import harness.test.PlainHarnessSpec +import harness.zio.test.* import scala.reflect.ClassTag import zio.json.* import zio.test.* import zio.test.Assertion.* -object PartialSpec extends PlainHarnessSpec { +object PartialSpec extends DefaultHarnessSpec { // =====| Types |===== @@ -80,7 +80,7 @@ object PartialSpec extends PlainHarnessSpec { // =====| Spec |===== - override def spec: TestSpec = + override def testSpec: TestSpec = suite("PartialSpec")( makeTypeSuite( "Klass1", diff --git a/modules/harness-xml/src/test/scala/harness/xml/XmlDecoderSpec.scala b/modules/harness-xml/src/test/scala/harness/xml/XmlDecoderSpec.scala index 42d75af1..6ed1eb08 100644 --- a/modules/harness-xml/src/test/scala/harness/xml/XmlDecoderSpec.scala +++ b/modules/harness-xml/src/test/scala/harness/xml/XmlDecoderSpec.scala @@ -1,12 +1,12 @@ package harness.xml import cats.syntax.option.* -import harness.test.* +import harness.zio.test.* import scala.xml.XML import zio.test.* import zio.test.Assertion.* -object XmlDecoderSpec extends PlainHarnessSpec { +object XmlDecoderSpec extends DefaultHarnessSpec { private final case class Company( name: String, @@ -45,7 +45,7 @@ object XmlDecoderSpec extends PlainHarnessSpec { assert(decoder.decodeAccumulating(Seq(XML.loadString(xml))))(isRight(equalTo(exp))) } - override def spec: TestSpec = + override def testSpec: TestSpec = suite("XmlDecoderSpec")( suite("passes")( makePassingTest("person-1")( diff --git a/modules/harness-zio-json/shared/src/main/scala/harness/core/StringCodecOps.scala b/modules/harness-zio-json/shared/src/main/scala/harness/core/StringCodecOps.scala index 366c4cb4..ee1fa018 100644 --- a/modules/harness-zio-json/shared/src/main/scala/harness/core/StringCodecOps.scala +++ b/modules/harness-zio-json/shared/src/main/scala/harness/core/StringCodecOps.scala @@ -12,3 +12,7 @@ implicit class StringEncoderOps(self: StringEncoder.type) { implicit class StringDecoderOps(self: StringDecoder.type) { def fromJsonDecoder[T: JsonDecoder]: StringDecoder[T] = JsonDecoder[T].decodeJson(_).leftMap(NonEmptyList.one) } + +implicit class StringCodecOps(self: StringCodec.type) { + def fromJsonCodec[T: JsonCodec]: StringCodec[T] = StringCodec(StringEncoder.fromJsonEncoder[T], StringDecoder.fromJsonDecoder[T]) +} diff --git a/modules/harness-zio-mock/shared/src/test/scala/harness/zio/mock/ExampleSpec.scala b/modules/harness-zio-mock/shared/src/test/scala/harness/zio/mock/ExampleSpec.scala index 196751a7..0532a1eb 100644 --- a/modules/harness-zio-mock/shared/src/test/scala/harness/zio/mock/ExampleSpec.scala +++ b/modules/harness-zio-mock/shared/src/test/scala/harness/zio/mock/ExampleSpec.scala @@ -7,7 +7,7 @@ import java.util.UUID import zio.* import zio.test.* -object ExampleSpec extends DefaultHarnessSpec { +object ExampleSpec extends HarnessSpec[ExampleSpec.Service1 & ExampleSpec.Service2 & ExampleSpec.Service3 & Proxy] { // =====| Models |===== @@ -78,7 +78,17 @@ object ExampleSpec extends DefaultHarnessSpec { // =====| Tests |===== - private val specImpl: Spec[HarnessEnv & Service1 & Service2 & Service3 & Proxy, Any] = + override def layerProvider: LayerProvider[R] = + LayerProvider.providePerTest( + Proxy.layer, + ( + Service1Mock.GetPerson.implement.success(Person(UUID.randomUUID, "first", "last", 18)) ++ + Service2Mock.empty + ).toLayer, + Service3.layer, + ) + + override def testSpec: TestSpec = suite("ExampleSpec")( test("test-1") { for { @@ -95,14 +105,4 @@ object ExampleSpec extends DefaultHarnessSpec { }, ) - override def spec: TestSpec = - specImpl.provideSome[HarnessEnv]( - Proxy.layer, - ( - Service1Mock.GetPerson.implement.success(Person(UUID.randomUUID, "first", "last", 18)) ++ - Service2Mock.empty - ).toLayer, - Service3.layer, - ) - } diff --git a/modules/harness-zio-mock/shared/src/test/scala/harness/zio/mock/MockSpec.scala b/modules/harness-zio-mock/shared/src/test/scala/harness/zio/mock/MockSpec.scala index ebecd5e0..1418cc7f 100644 --- a/modules/harness-zio-mock/shared/src/test/scala/harness/zio/mock/MockSpec.scala +++ b/modules/harness-zio-mock/shared/src/test/scala/harness/zio/mock/MockSpec.scala @@ -220,7 +220,7 @@ object MockSpec extends DefaultHarnessSpec { }, ).provideSomeLayer[HarnessEnv](Proxy.layer >+> ExServiceMock.empty.toLayer) - override def spec: TestSpec = + override def testSpec: TestSpec = suite("ExServiceSpec")( suite("impl")( positiveImplSpec, diff --git a/modules/harness-test/shared/src/main/scala/harness/test/AssertionHelpers.scala b/modules/harness-zio-test/shared/src/main/scala/harness/zio/test/AssertionHelpers.scala similarity index 96% rename from modules/harness-test/shared/src/main/scala/harness/test/AssertionHelpers.scala rename to modules/harness-zio-test/shared/src/main/scala/harness/zio/test/AssertionHelpers.scala index 7ae12eb4..425af89b 100644 --- a/modules/harness-test/shared/src/main/scala/harness/test/AssertionHelpers.scala +++ b/modules/harness-zio-test/shared/src/main/scala/harness/zio/test/AssertionHelpers.scala @@ -1,4 +1,4 @@ -package harness.test +package harness.zio.test import cats.data.NonEmptyList import zio.test.* diff --git a/modules/harness-zio-test/shared/src/main/scala/harness/zio/test/Contract.scala b/modules/harness-zio-test/shared/src/main/scala/harness/zio/test/Contract.scala index 1f35bc2e..068679c0 100644 --- a/modules/harness-zio-test/shared/src/main/scala/harness/zio/test/Contract.scala +++ b/modules/harness-zio-test/shared/src/main/scala/harness/zio/test/Contract.scala @@ -1,13 +1,18 @@ package harness.zio.test -import harness.zio.* import zio.* import zio.test.* -abstract class Contract[R: EnvironmentTag] { +abstract class Contract[_R: EnvironmentTag] { - final type TestSpec = Spec[HarnessEnv & R & TestEnvironment & Scope, Any] + final type R = _R + final type DefaultEnv = HarnessSpec.DefaultEnv + final type Env = DefaultEnv & R - def contract: TestSpec + final type TestSpec = Spec[Env, Any] + + // =====| Abstract |===== + + def testSpec: TestSpec } diff --git a/modules/harness-zio-test/shared/src/main/scala/harness/zio/test/ContractHarnessSpec.scala b/modules/harness-zio-test/shared/src/main/scala/harness/zio/test/ContractHarnessSpec.scala new file mode 100644 index 00000000..332c3784 --- /dev/null +++ b/modules/harness-zio-test/shared/src/main/scala/harness/zio/test/ContractHarnessSpec.scala @@ -0,0 +1,21 @@ +package harness.zio.test + +import cats.syntax.option.* +import zio.* +import zio.test.* + +abstract class ContractHarnessSpec[_R: EnvironmentTag](implName: String, contract: Contract[_R]) extends HarnessSpec[_R] { + + private def modifyCase(spec: TestSpec): Option[TestSpec] = + spec.caseValue match { + case Spec.ExecCase(exec, spec) => modifyCase(spec).map(s => Spec(Spec.ExecCase(exec, s))) + case Spec.LabeledCase(label, spec) => Spec(Spec.LabeledCase(s"$label ($implName)", spec)).some + case _ => None + } + + override def testSpec: TestSpec = { + val built = suite(implName)(contract.testSpec) + modifyCase(built).getOrElse { suite(implName)(built) } + } + +} diff --git a/modules/harness-zio-test/shared/src/main/scala/harness/zio/test/DefaultHarnessSpec.scala b/modules/harness-zio-test/shared/src/main/scala/harness/zio/test/DefaultHarnessSpec.scala index bc5d1fa1..6d764573 100644 --- a/modules/harness-zio-test/shared/src/main/scala/harness/zio/test/DefaultHarnessSpec.scala +++ b/modules/harness-zio-test/shared/src/main/scala/harness/zio/test/DefaultHarnessSpec.scala @@ -2,15 +2,7 @@ package harness.zio.test import harness.zio.* import zio.* -import zio.test.* abstract class DefaultHarnessSpec extends HarnessSpec[Any] { - override final val layer: ULayer[Any] = ZLayer.empty -} -object DefaultHarnessSpec { - - abstract class ForContract[R: EnvironmentTag](name: String, contract: Contract[R])(_layer: ZLayer[HarnessEnv & Scope, Any, R]) extends DefaultHarnessSpec { - override final def spec: TestSpec = suite(name)(contract.contract).provideSomeLayer[HarnessEnv & TestEnvironment & Scope](_layer) - } - + override def layerProvider: LayerProvider[R] = LayerProvider.Empty } diff --git a/modules/harness-zio/shared/src/test/scala/harness/zio/test/ZioHarnessSpec.scala b/modules/harness-zio-test/shared/src/main/scala/harness/zio/test/HAspects.scala similarity index 57% rename from modules/harness-zio/shared/src/test/scala/harness/zio/test/ZioHarnessSpec.scala rename to modules/harness-zio-test/shared/src/main/scala/harness/zio/test/HAspects.scala index 7c6a124a..edef09ba 100644 --- a/modules/harness-zio/shared/src/test/scala/harness/zio/test/ZioHarnessSpec.scala +++ b/modules/harness-zio-test/shared/src/main/scala/harness/zio/test/HAspects.scala @@ -2,38 +2,36 @@ package harness.zio.test import harness.zio.* import zio.* +import zio.{Trace, ZIO} import zio.test.* -// NOTE : Any modifications to this file should be reflected in its sister file in harness-zio-test -abstract class ZioHarnessSpec[R: EnvironmentTag] extends ZIOSpec[HarnessEnv & R] { +object HAspects { - final type TestSpec = Spec[Environment & TestEnvironment & Scope, Any] + object logger { - // =====| Abstract |===== + def withLevel(logLevel: Logger.LogLevel): TestAspectAtLeastR[Logger] = + new TestAspect.PerTest.AtLeastR[Logger] { - override def spec: TestSpec + override def perTest[R <: Logger, E]( + test: ZIO[R, TestFailure[E], TestSuccess], + )(implicit trace: Trace): ZIO[R, TestFailure[E], TestSuccess] = + test.updateService[Logger] { _.copy(defaultMinLogTolerance = logLevel) } - val layer: ZLayer[HarnessEnv & Scope, Any, R] + } - // =====| Overridable |===== + def withContext(pairs: (String, Any)*): TestAspectAtLeastR[Logger] = + new TestAspect.PerTest.AtLeastR[Logger] { - def logLevel: Logger.LogLevel = Logger.LogLevel.Warning + override def perTest[R <: Logger, E]( + test: ZIO[R, TestFailure[E], TestSuccess], + )(implicit trace: Trace): ZIO[R, TestFailure[E], TestSuccess] = + test.updateService[Logger] { _.addContext(pairs.map { case (k, v) => (k, v.toString) }.toMap) } - def harnessEnv: ULayer[HarnessEnv] = - HarnessEnv.defaultLayer(logLevel) + } - override def aspects: Chunk[TestAspectAtLeastR[Environment & TestEnvironment]] = - Chunk(TestAspect.samples(15), TestAspect.shrinks(0), ZioHarnessSpec.logTestPathAndDuration) + } - // =====| Concrete |===== - - override final def bootstrap: Layer[Any, Environment] = - Scope.default >+> (harnessEnv >+> layer) - -} -object ZioHarnessSpec { - - final val logTestPathAndDuration: TestAspectAtLeastR[Logger & Telemetry] = + private[test] val logTestPathAndDuration: TestAspectAtLeastR[Logger & Telemetry] = new TestAspectAtLeastR[Logger & Telemetry] { private def modifySpec[R <: Logger & Telemetry, E](rPath: List[String], spec: Spec[R, E]): Spec[R, E] = diff --git a/modules/harness-zio-test/shared/src/main/scala/harness/zio/test/HarnessSpec.scala b/modules/harness-zio-test/shared/src/main/scala/harness/zio/test/HarnessSpec.scala index 0a180cc9..e817e11b 100644 --- a/modules/harness-zio-test/shared/src/main/scala/harness/zio/test/HarnessSpec.scala +++ b/modules/harness-zio-test/shared/src/main/scala/harness/zio/test/HarnessSpec.scala @@ -4,60 +4,45 @@ import harness.zio.* import zio.* import zio.test.* -// NOTE : Any modifications to this file should be reflected in its sister file in harness-zio-test -abstract class HarnessSpec[R: EnvironmentTag] extends ZIOSpec[HarnessEnv & R] { +abstract class HarnessSpec[_R: EnvironmentTag] extends ZIOSpecDefault { - final type TestSpec = Spec[Environment & TestEnvironment & Scope, Any] + final type R = _R + final type DefaultEnv = HarnessSpec.DefaultEnv + final type Env = DefaultEnv & R + + final type TestSpec = Spec[Env, Any] // =====| Abstract |===== - override def spec: TestSpec + def testSpec: TestSpec - val layer: ZLayer[HarnessEnv & Scope, Any, R] + def layerProvider: LayerProvider[R] // =====| Overridable |===== - def logLevel: Logger.LogLevel = Logger.LogLevel.Warning - - def harnessEnv: ULayer[HarnessEnv] = - HarnessEnv.defaultLayer(logLevel) + def withDefaultAspects: Boolean = true - override def aspects: Chunk[TestAspectAtLeastR[Environment & TestEnvironment]] = - Chunk(TestAspect.samples(15), TestAspect.shrinks(0), HarnessSpec.logTestPathAndDuration) + def testAspects: Chunk[TestAspectAtLeastR[Env]] = Chunk.empty // =====| Concrete |===== - override final def bootstrap: Layer[Any, Environment] = - Scope.default >+> (harnessEnv >+> layer) + override final def spec: Spec[TestEnvironment & Scope, Any] = { + val allAspects: Chunk[TestAspectAtLeastR[Env]] = + if (withDefaultAspects) HarnessSpec.defaultTestAspects ++ testAspects + else testAspects + val spec2: TestSpec = allAspects.foldLeft(testSpec)(_ @@ _) + val spec3: Spec[DefaultEnv, Any] = layerProvider.build(spec2) + val spec4: Spec[TestEnvironment & Scope, Any] = spec3.provideSomeLayer(HarnessTestEnv.layer) + + spec4 + } } object HarnessSpec { - final val logTestPathAndDuration: TestAspectAtLeastR[Logger & Telemetry] = - new TestAspectAtLeastR[Logger & Telemetry] { - - private def modifySpec[R <: Logger & Telemetry, E](rPath: List[String], spec: Spec[R, E]): Spec[R, E] = - Spec { - spec.caseValue match { - case Spec.ExecCase(exec, spec) => Spec.ExecCase(exec, modifySpec(rPath, spec)) - case Spec.LabeledCase(label, spec) => Spec.LabeledCase(label, modifySpec(label :: rPath, spec)) - case Spec.ScopedCase(scoped) => Spec.ScopedCase(scoped.map(modifySpec(rPath, _))) - case Spec.MultipleCase(specs) => Spec.MultipleCase(specs.map(modifySpec(rPath, _))) - case Spec.TestCase(test, annotations) => - Spec.TestCase( - ZIO.clock.flatMap { clock => - Logger.addContext("test-path" -> rPath.reverse.map(n => s"\"$n\"").mkString("[", "/", "]")) { - test.withClock(clock).telemetrize("Test Duration").withClock(Clock.ClockLive) - } - }, - annotations, - ) - } - } - - override def some[R <: Logger & Telemetry, E](spec: Spec[R, E])(implicit trace: Trace): Spec[R, E] = - modifySpec(Nil, spec) - - } + type DefaultEnv = HarnessEnv & HarnessTestEnv & TestEnvironment & Scope + + private val defaultTestAspects: Chunk[TestAspectAtLeastR[DefaultEnv]] = + Chunk(TestAspect.samples(15), TestAspect.shrinks(0), HAspects.logTestPathAndDuration) } diff --git a/modules/harness-zio-test/shared/src/main/scala/harness/zio/test/HarnessTestEnv.scala b/modules/harness-zio-test/shared/src/main/scala/harness/zio/test/HarnessTestEnv.scala new file mode 100644 index 00000000..21f85437 --- /dev/null +++ b/modules/harness-zio-test/shared/src/main/scala/harness/zio/test/HarnessTestEnv.scala @@ -0,0 +1,32 @@ +package harness.zio.test + +import cats.syntax.option.* +import harness.core.* +import harness.zio.* +import zio.* + +type HarnessTestEnv = LogCache +object HarnessTestEnv { + + private val loggerLayer: URLayer[LogCache.LoggerTarget, Logger] = + ZLayer.fromFunction { (logCacheTarget: LogCache.LoggerTarget) => + Logger.default( + sources = List( + Logger.Source.const(logCacheTarget, Logger.LogLevel.Trace.some), + Logger.Source.stdOut(None, ColorMode.Extended), + ), + defaultMinLogTolerance = Logger.LogLevel.Important, + ) + } + + val layer: ULayer[HarnessEnv & HarnessTestEnv] = + ZLayer.make[HarnessEnv & HarnessTestEnv]( + LogCache.layer, + loggerLayer, + ZLayer.succeed(Telemetry.log), + FileSystem.liveLayer.orDie, // TODO (KR) : mock + Sys.liveLayer(true), + HConfig.layer.empty, // TODO (KR) : configurable? + ) + +} diff --git a/modules/harness-zio-test/shared/src/main/scala/harness/zio/test/LayerProvider.scala b/modules/harness-zio-test/shared/src/main/scala/harness/zio/test/LayerProvider.scala new file mode 100644 index 00000000..b0e25095 --- /dev/null +++ b/modules/harness-zio-test/shared/src/main/scala/harness/zio/test/LayerProvider.scala @@ -0,0 +1,62 @@ +package harness.zio.test + +import harness.zio.test.HarnessSpec.DefaultEnv +import zio.* +import zio.test.* + +sealed trait LayerProvider[+R] { + private[test] def build(spec: Spec[R & HarnessSpec.DefaultEnv, Any]): Spec[HarnessSpec.DefaultEnv, Any] +} +object LayerProvider { + + inline def providePerTest[PerTestR: EnvironmentTag](inline layer: ZLayer[?, Any, ?]*): LayerProvider.PerTest[PerTestR] = + new LayerProvider.PerTest[PerTestR]( + ZLayer.makeSome[DefaultEnv, PerTestR](layer*), + ) + + inline def provideShared[SharedR: EnvironmentTag](inline layer: ZLayer[?, Any, ?]*): LayerProvider.Shared[SharedR] = + new LayerProvider.Shared[SharedR]( + ZLayer.makeSome[DefaultEnv, SharedR](layer*), + ) + + case object Empty extends LayerProvider[Any] { + + override private[test] def build(spec: Spec[DefaultEnv, Any]): Spec[DefaultEnv, Any] = spec + + } + + final class Shared[SharedR: EnvironmentTag]( + sharedLayer: ZLayer[DefaultEnv, Any, SharedR], + ) extends LayerProvider[SharedR] { + + override private[test] def build(spec: Spec[SharedR & DefaultEnv, Any]): Spec[DefaultEnv, Any] = + spec.provideSomeLayerShared(sharedLayer) + + inline def providePerTest[PerTestR: EnvironmentTag](inline layer: ZLayer[?, Any, ?]*): LayerProvider.SharedAndPerTest[SharedR, PerTestR] = + new LayerProvider.SharedAndPerTest[SharedR, PerTestR]( + sharedLayer, + ZLayer.makeSome[DefaultEnv, PerTestR](layer*), + ) + + } + + final class PerTest[PerTestR: EnvironmentTag]( + perTestLayer: ZLayer[DefaultEnv, Any, PerTestR], + ) extends LayerProvider[PerTestR] { + + override private[test] def build(spec: Spec[PerTestR & DefaultEnv, Any]): Spec[DefaultEnv, Any] = + spec.provideSomeLayer(perTestLayer) + + } + + final class SharedAndPerTest[SharedR: EnvironmentTag, PerTestR: EnvironmentTag]( + sharedLayer: ZLayer[DefaultEnv, Any, SharedR], + perTestLayer: ZLayer[DefaultEnv & SharedR, Any, PerTestR], + ) extends LayerProvider[SharedR & PerTestR] { + + override private[test] def build(spec: Spec[SharedR & PerTestR & DefaultEnv, Any]): Spec[DefaultEnv, Any] = + spec.provideSomeLayer(perTestLayer).provideSomeLayerShared(sharedLayer) + + } + +} diff --git a/modules/harness-zio-test/shared/src/main/scala/harness/zio/test/LogCache.scala b/modules/harness-zio-test/shared/src/main/scala/harness/zio/test/LogCache.scala new file mode 100644 index 00000000..099a9e2a --- /dev/null +++ b/modules/harness-zio-test/shared/src/main/scala/harness/zio/test/LogCache.scala @@ -0,0 +1,59 @@ +package harness.zio.test + +import harness.zio.* +import java.time.Instant +import zio.* + +trait LogCache { + + def add(event: Logger.ExecutedEvent): UIO[Unit] + def add(events: Chunk[Logger.ExecutedEvent]): UIO[Unit] + + def get: UIO[Chunk[Logger.ExecutedEvent]] + + final def exists( + message: String => Boolean = _ => true, + logLevel: Option[Logger.LogLevel] => Boolean = _ => true, + context: Map[String, String] => Boolean = _ => true, + at: Instant => Boolean = _ => true, + ): UIO[Boolean] = + get.map { _.exists { l => message(l.message) && logLevel(l.logLevel) && context(l.context) && at(l.at) } } + +} +object LogCache { + + val layer: ULayer[LogCache & LoggerTarget] = LogCache.Impl.layer >+> LogCache.LoggerTarget.layer + + // =====| API |===== + + def add(event: Logger.ExecutedEvent): URIO[LogCache, Unit] = ZIO.serviceWithZIO[LogCache](_.add(event)) + def add(events: Chunk[Logger.ExecutedEvent]): URIO[LogCache, Unit] = ZIO.serviceWithZIO[LogCache](_.add(events)) + def get: URIO[LogCache, Chunk[Logger.ExecutedEvent]] = ZIO.serviceWithZIO[LogCache](_.get) + + final def exists( + message: String => Boolean = _ => true, + logLevel: Option[Logger.LogLevel] => Boolean = _ => true, + context: Map[String, String] => Boolean = _ => true, + at: Instant => Boolean = _ => true, + ): URIO[LogCache, Boolean] = + ZIO.serviceWithZIO[LogCache](_.exists(message, logLevel, context, at)) + + // =====| |===== + + final case class Impl(ref: Ref[Chunk[Logger.ExecutedEvent]]) extends LogCache { + override def add(event: Logger.ExecutedEvent): UIO[Unit] = ref.update { _ :+ event } + override def add(events: Chunk[Logger.ExecutedEvent]): UIO[Unit] = ref.update { _ ++ events } + override def get: UIO[Chunk[Logger.ExecutedEvent]] = ref.get + } + object Impl { + val layer: ULayer[LogCache] = ZLayer.fromZIO { Ref.make(Chunk.empty[Logger.ExecutedEvent]).map(Impl(_)) } + } + + final case class LoggerTarget(logCache: LogCache) extends Logger.Target { + override def log(event: Logger.ExecutedEvent): UIO[Unit] = logCache.add(event) + } + object LoggerTarget { + val layer: URLayer[LogCache, LoggerTarget] = ZLayer.fromFunction { LoggerTarget.apply } + } + +} diff --git a/modules/harness-zio-test/shared/src/test/scala/harness/zio/test/HarnessSpecSpec.scala b/modules/harness-zio-test/shared/src/test/scala/harness/zio/test/HarnessSpecSpec.scala new file mode 100644 index 00000000..ed2fccc7 --- /dev/null +++ b/modules/harness-zio-test/shared/src/test/scala/harness/zio/test/HarnessSpecSpec.scala @@ -0,0 +1,53 @@ +package harness.zio.test + +import harness.zio.* +import zio.* +import zio.json.* +import zio.test.* + +object HarnessSpecSpec extends HarnessSpec[HarnessSpecSpec.Register] { + + final case class Register(ref: Ref[Set[String]]) { + def register(name: String): UIO[Unit] = ref.update(_ + name) + def get: UIO[Set[String]] = ref.get + } + + override def layerProvider: LayerProvider[R] = + LayerProvider.provideShared( + ZLayer.fromZIO { Ref.make(Set.empty[String]).map(Register(_)) }, + ) + + private val levels: Chunk[Logger.LogLevel] = + Chunk(Logger.LogLevel.Error, Logger.LogLevel.Warning, Logger.LogLevel.Important, Logger.LogLevel.Info, Logger.LogLevel.Debug) + + private def makeTest(level: Logger.LogLevel): TestSpec = { + val label = level.displayName + test(s"test-$label") { + for { + register <- ZIO.service[Register] + _ <- register.register(label) + showLevels = Logger.LogLevel.allLevels.filterNot(_ == Logger.LogLevel.Never) + _ <- ZIO.foreachDiscard(showLevels) { level => Logger.log(level, level.displayName, "test-label" -> label) } + _ <- Clock.sleep(1.second) + + logs <- LogCache.get + registered <- register.get + + _ <- Logger.log.info(logs.map(_.toJson).mkString("\n")) + } yield assertTrue( + logs.length == showLevels.length, + logs.forall(_.context.get("test-label").contains(label)), + registered.size == levels.length, + ) + } // @@ HAspects.logger.withLevel(level) + } + + override def testSpec: TestSpec = + suite("TmpSpec")( + levels.map(makeTest) *, + ) @@ + TestAspect.withLiveClock @@ + TestAspect.parallelN(25) @@ + HAspects.logger.withLevel(Logger.LogLevel.Never) + +} diff --git a/modules/harness-zio/jvm/src/test/resources/config-spec.json b/modules/harness-zio-ut/shared/src/test/resources/config-spec.json similarity index 100% rename from modules/harness-zio/jvm/src/test/resources/config-spec.json rename to modules/harness-zio-ut/shared/src/test/resources/config-spec.json diff --git a/modules/harness-zio/shared/src/test/scala/harness/zio/CacheSpec.scala b/modules/harness-zio-ut/shared/src/test/scala/harness/zio/CacheSpec.scala similarity index 94% rename from modules/harness-zio/shared/src/test/scala/harness/zio/CacheSpec.scala rename to modules/harness-zio-ut/shared/src/test/scala/harness/zio/CacheSpec.scala index 0e3833b9..50de2c50 100644 --- a/modules/harness-zio/shared/src/test/scala/harness/zio/CacheSpec.scala +++ b/modules/harness-zio-ut/shared/src/test/scala/harness/zio/CacheSpec.scala @@ -1,16 +1,14 @@ package harness.zio import cats.syntax.option.* -import harness.zio.test.ZioDefaultHarnessSpec +import harness.zio.test.* import zio.* import zio.test.* import zio.test.Assertion.* -object CacheSpec extends ZioDefaultHarnessSpec { +object CacheSpec extends DefaultHarnessSpec { - override def logLevel: Logger.LogLevel = Logger.LogLevel.Detailed - - override def spec: TestSpec = + override def testSpec: TestSpec = suite("CacheSpec")( test("check on missing value is None") { for { diff --git a/modules/harness-zio/shared/src/test/scala/harness/zio/HConfigSpec.scala b/modules/harness-zio-ut/shared/src/test/scala/harness/zio/HConfigSpec.scala similarity index 67% rename from modules/harness-zio/shared/src/test/scala/harness/zio/HConfigSpec.scala rename to modules/harness-zio-ut/shared/src/test/scala/harness/zio/HConfigSpec.scala index 811e155b..d1e953ce 100644 --- a/modules/harness-zio/shared/src/test/scala/harness/zio/HConfigSpec.scala +++ b/modules/harness-zio-ut/shared/src/test/scala/harness/zio/HConfigSpec.scala @@ -8,7 +8,7 @@ import zio.json.ast.Json import zio.test.* import zio.test.Assertion.* -object HConfigSpec extends ZioHarnessSpec[HConfig] { +object HConfigSpec extends HarnessSpec[HConfig] { private final case class Cfg( a: Int, @@ -22,23 +22,25 @@ object HConfigSpec extends ZioHarnessSpec[HConfig] { private val cfg1: Cfg = Cfg(1, "a", None) private val cfg2: Cfg = Cfg(2, "b", 2.some) - override val layer: ZLayer[HarnessEnv & Scope, Any, HConfig] = - HConfig.layer.json( - Json.Obj( - "key-1" -> cfg1.toJsonAST.toOption.get, - "key-2" -> Json.Obj( - "nested" -> cfg2.toJsonAST.toOption.get, + override def layerProvider: LayerProvider[R] = + LayerProvider.provideShared( + HConfig.layer.json( + Json.Obj( + "key-1" -> cfg1.toJsonAST.toOption.get, + "key-2" -> Json.Obj( + "nested" -> cfg2.toJsonAST.toOption.get, + ), ), - ), - ) >>> - HConfig.layer.append.jarResource("config-spec.json") + ) >>> + HConfig.layer.append.jarResource("config-spec.json"), + ) private def makeTest(i: Int)(path: String*)(assertion: Assertion[Either[Any, Cfg]]): TestSpec = test(s"test-$i") { assertZIO(HConfig.read[Cfg](path*).either)(assertion) } - override def spec: TestSpec = + override def testSpec: TestSpec = suite("ConfigSpec")( makeTest(1)("key-1")(isRight(equalTo(cfg1))), makeTest(2)("key-2", "nested")(isRight(equalTo(cfg2))), diff --git a/modules/harness-zio/shared/src/test/scala/harness/zio/TestMain.scala b/modules/harness-zio-ut/shared/src/test/scala/harness/zio/TestMain.scala similarity index 100% rename from modules/harness-zio/shared/src/test/scala/harness/zio/TestMain.scala rename to modules/harness-zio-ut/shared/src/test/scala/harness/zio/TestMain.scala diff --git a/modules/harness-zio/shared/src/main/scala/harness/zio/Cache.scala b/modules/harness-zio/shared/src/main/scala/harness/zio/Cache.scala index 9860472b..168e2d9f 100644 --- a/modules/harness-zio/shared/src/main/scala/harness/zio/Cache.scala +++ b/modules/harness-zio/shared/src/main/scala/harness/zio/Cache.scala @@ -123,7 +123,7 @@ object Cache { Ref.Synchronized .make(Map.empty[K, (Option[Instant], V)]) .map( - new Cache(_, name, s"[${Tag[K].typeName.prefixAll}, ${Tag[V].typeName.prefixAll}]", expireDuration), + new Cache(_, name, s"[${Tag[K].typeName.prefixObject}, ${Tag[V].typeName.prefixObject}]", expireDuration), ) } diff --git a/modules/harness-zio/shared/src/main/scala/harness/zio/FileSystem.scala b/modules/harness-zio/shared/src/main/scala/harness/zio/FileSystem.scala index 8dd9e47d..5114ab39 100644 --- a/modules/harness-zio/shared/src/main/scala/harness/zio/FileSystem.scala +++ b/modules/harness-zio/shared/src/main/scala/harness/zio/FileSystem.scala @@ -15,7 +15,7 @@ object FileSystem extends FileSystemCompanionPlatformSpecific with FileSystemCom def roots: ZIO[FileSystem, FSError.UnableToGetRoots, Chunk[Path]] = ZIO.service[FileSystem].flatMap(_.roots) val unimplementedLayer: ULayer[FileSystem] = ZLayer.succeed { FileSystem.Unimplemented } - + case object Unimplemented extends FileSystem { def path(string: String): IO[FSError.UnableToResolvePath, Path] = ZIO.dieMessage("??? : FileSystem.path") def homeDirectory: IO[FSError.UnableToGetHomeDirectory | FSError.UnableToResolvePath, Path] = ZIO.dieMessage("??? : FileSystem.homeDirectory") diff --git a/modules/harness-zio/shared/src/main/scala/harness/zio/Logger.scala b/modules/harness-zio/shared/src/main/scala/harness/zio/Logger.scala index 835b8fcb..ad2255b6 100644 --- a/modules/harness-zio/shared/src/main/scala/harness/zio/Logger.scala +++ b/modules/harness-zio/shared/src/main/scala/harness/zio/Logger.scala @@ -55,6 +55,9 @@ final case class Logger( def addContext(context: Map[String, String]): Logger = self.copy(defaultContext = defaultContext ++ context) + def withSource(source: Logger.Source): Logger = + self.copy(sources = source :: self.sources) + } object Logger { self => diff --git a/modules/harness-zio/shared/src/main/scala/harness/zio/error/SysError.scala b/modules/harness-zio/shared/src/main/scala/harness/zio/error/SysError.scala index d7616974..a8d0f7c8 100644 --- a/modules/harness-zio/shared/src/main/scala/harness/zio/error/SysError.scala +++ b/modules/harness-zio/shared/src/main/scala/harness/zio/error/SysError.scala @@ -26,13 +26,13 @@ sealed trait SysError extends Throwable { object SysError { final case class NonZeroExitCode( - cmd: Sys.Command, - exitCode: Int, + cmd: Sys.Command, + exitCode: Int, ) extends SysError final case class GenericError( - cmd: Sys.Command, - cause: Throwable, + cmd: Sys.Command, + cause: Throwable, ) extends SysError } diff --git a/modules/harness-zio/shared/src/test/scala/harness/zio/test/ZioDefaultHarnessSpec.scala b/modules/harness-zio/shared/src/test/scala/harness/zio/test/ZioDefaultHarnessSpec.scala deleted file mode 100644 index 1efcc346..00000000 --- a/modules/harness-zio/shared/src/test/scala/harness/zio/test/ZioDefaultHarnessSpec.scala +++ /dev/null @@ -1,7 +0,0 @@ -package harness.zio.test - -import zio.* - -abstract class ZioDefaultHarnessSpec extends ZioHarnessSpec[Any] { - override final val layer: ULayer[Any] = ZLayer.empty -} diff --git a/project/Versions.scala b/project/Versions.scala index bf283e20..e743f1fe 100644 --- a/project/Versions.scala +++ b/project/Versions.scala @@ -22,8 +22,8 @@ object Versions { val stripe = "24.11.0" - val zio = "2.0.20" - val zioJson = "0.6.2" - val zioKafka = "2.7.1" + val zio = "2.1.5" + val zioJson = "0.7.1" + val zioKafka = "2.7.5" }