diff --git a/build.sbt b/build.sbt index 8d16919..d7bd6de 100644 --- a/build.sbt +++ b/build.sbt @@ -14,11 +14,15 @@ name := "sclap" ThisBuild / organization := "io.jobial" -ThisBuild / crossScalaVersions := Seq("2.12.15", "2.13.7") -ThisBuild / version := "1.3.6" +ThisBuild / crossScalaVersions := Seq("2.11.12", "2.12.15", "2.13.7") +ThisBuild / scalaVersion := "2.13.7" +ThisBuild / version := "1.4.0" +ThisBuild / scalacOptions += "-target:jvm-1.8" +ThisBuild / javacOptions ++= Seq("-source", "11", "-target", "11") ThisBuild / publishArtifact in (Test, packageBin) := true ThisBuild / publishArtifact in (Test, packageSrc) := true ThisBuild / publishArtifact in (Test, packageDoc) := true +ThisBuild / Test / fork := true import sbt.Keys.{description, publishConfiguration} import xerial.sbt.Sonatype._ @@ -34,13 +38,13 @@ lazy val commonSettings = Seq( addCompilerPlugin("org.typelevel" % "kind-projector" % "0.13.2" cross CrossVersion.full), scalacOptions ++= (if (scalaBinaryVersion.value != "2.13") Seq("-Ypartial-unification") else Seq()) ) - -lazy val CatsVersion = "2.7.0" -lazy val CatsEffectVersion = "2.5.4" + +lazy val CatsVersion = "2.0.0" +lazy val CatsEffectVersion = "2.0.0" lazy val ScalaLoggingVersion = "3.9.2" lazy val PicocliVersion = "4.6.1" lazy val ScalatestVersion = "3.2.3" -lazy val ZioVersion = "2.5.1.0" // TODO: upgrade when Cats version is upgraded +lazy val ZioVersion = "2.0.0.0-RC13" // TODO: upgrade when Cats version is upgraded lazy val root: Project = project .in(file(".")) diff --git a/sclap-app/src/test/scala/io/jobial/sclap/CommandLineParserTest.scala b/sclap-app/src/test/scala/io/jobial/sclap/CommandLineParserTest.scala index 2fd4c25..eba9b29 100644 --- a/sclap-app/src/test/scala/io/jobial/sclap/CommandLineParserTest.scala +++ b/sclap-app/src/test/scala/io/jobial/sclap/CommandLineParserTest.scala @@ -13,6 +13,7 @@ package io.jobial.sclap import cats.effect.IO +import cats.evidence.=== import io.jobial.sclap.core.{ArgumentValueParser, ArgumentValuePrinter, IncorrectCommandLineUsage, IncorrectCommandLineUsageInSubcommand} import org.scalatest.flatspec.AsyncFlatSpec @@ -32,167 +33,16 @@ class CommandLineParserTest } yield IO.raiseError[Unit](new Throwable("an error")) } - + runCommandLineTestCases(spec)( - Seq() -> failWithThrowable[Unit, Throwable](t => assert(t.getMessage == "an error"), - out = Some(""), err = Some("""an error + Seq() -> failWithThrowable[Unit, Throwable]({ t: Throwable => assert(t.getMessage == "an error") }, + { out: String => out == "" }, (_: String).startsWith("""an error java.lang.Throwable: an error - at io.jobial.sclap.CommandLineParserTest.$anonfun$new$1(CommandLineParserTest.scala:33) - at cats.free.Free.$anonfun$map$1(Free.scala:18) - at cats.free.Free.$anonfun$foldMap$3(Free.scala:156) - at cats.Monad.$anonfun$map$1(Monad.scala:16) - at cats.data.IndexedStateT.$anonfun$flatMap$3(IndexedStateT.scala:28) - at cats.Eval$.loop$1(Eval.scala:363) - at cats.Eval$.cats$Eval$$evaluate(Eval.scala:368) - at cats.Eval$FlatMap.value(Eval.scala:307) - at io.jobial.sclap.impl.picocli.PicocliCommandLineParser.$anonfun$executeCommandLine$5(PicocliCommandLineParser.scala:381) - at cats.effect.internals.IORunLoop$.liftedTree3$1(IORunLoop.scala:229) - at cats.effect.internals.IORunLoop$.step(IORunLoop.scala:229) - at cats.effect.IO.unsafeRunTimed(IO.scala:320) - at cats.effect.IO.unsafeRunSync(IO.scala:239) - at io.jobial.sclap.CommandLineParserTestHelperNoImplicits.$anonfun$runCommandLineTest$1(CommandLineParserTestHelperNoImplicits.scala:49) - at scala.util.Try$.apply(Try.scala:213) - at io.jobial.sclap.OutputCaptureUtils.$anonfun$captureOutput$1(OutputCaptureUtils.scala:99) - at cats.effect.internals.IORunLoop$.cats$effect$internals$IORunLoop$$loop(IORunLoop.scala:87) - at cats.effect.internals.IORunLoop$.start(IORunLoop.scala:34) - at cats.effect.IO.unsafeRunAsync(IO.scala:257) - at cats.effect.IO.unsafeToFuture(IO.scala:344) - at io.jobial.sclap.CommandLineParserTestHelperNoImplicits.$anonfun$runCommandLineTestCases$3(CommandLineParserTestHelperNoImplicits.scala:75) - at org.scalatest.flatspec.AsyncFlatSpecLike.transformToOutcomeParam$1(AsyncFlatSpecLike.scala:139) - at org.scalatest.flatspec.AsyncFlatSpecLike.$anonfun$registerTestToRun$1(AsyncFlatSpecLike.scala:145) - at org.scalatest.AsyncTestSuite.$anonfun$transformToOutcome$1(AsyncTestSuite.scala:240) - at org.scalatest.flatspec.AsyncFlatSpecLike$$anon$5.apply(AsyncFlatSpecLike.scala:1698) - at org.scalatest.AsyncTestSuite.withFixture(AsyncTestSuite.scala:313) - at org.scalatest.AsyncTestSuite.withFixture$(AsyncTestSuite.scala:312) - at org.scalatest.flatspec.AsyncFlatSpec.withFixture(AsyncFlatSpec.scala:2221) - at org.scalatest.flatspec.AsyncFlatSpecLike.invokeWithAsyncFixture$1(AsyncFlatSpecLike.scala:1696) - at org.scalatest.flatspec.AsyncFlatSpecLike.$anonfun$runTest$1(AsyncFlatSpecLike.scala:1710) - at org.scalatest.AsyncSuperEngine.runTestImpl(AsyncEngine.scala:374) - at org.scalatest.flatspec.AsyncFlatSpecLike.runTest(AsyncFlatSpecLike.scala:1710) - at org.scalatest.flatspec.AsyncFlatSpecLike.runTest$(AsyncFlatSpecLike.scala:1689) - at org.scalatest.flatspec.AsyncFlatSpec.runTest(AsyncFlatSpec.scala:2221) - at org.scalatest.flatspec.AsyncFlatSpecLike.$anonfun$runTests$1(AsyncFlatSpecLike.scala:1768) - at org.scalatest.AsyncSuperEngine.$anonfun$runTestsInBranch$1(AsyncEngine.scala:432) - at scala.collection.LinearSeqOptimized.foldLeft(LinearSeqOptimized.scala:126) - at scala.collection.LinearSeqOptimized.foldLeft$(LinearSeqOptimized.scala:122) - at scala.collection.immutable.List.foldLeft(List.scala:91) - at org.scalatest.AsyncSuperEngine.traverseSubNodes$1(AsyncEngine.scala:406) - at org.scalatest.AsyncSuperEngine.runTestsInBranch(AsyncEngine.scala:479) - at org.scalatest.AsyncSuperEngine.$anonfun$runTestsInBranch$1(AsyncEngine.scala:460) - at scala.collection.LinearSeqOptimized.foldLeft(LinearSeqOptimized.scala:126) - at scala.collection.LinearSeqOptimized.foldLeft$(LinearSeqOptimized.scala:122) - at scala.collection.immutable.List.foldLeft(List.scala:91) - at org.scalatest.AsyncSuperEngine.traverseSubNodes$1(AsyncEngine.scala:406) - at org.scalatest.AsyncSuperEngine.runTestsInBranch(AsyncEngine.scala:487) - at org.scalatest.AsyncSuperEngine.runTestsImpl(AsyncEngine.scala:555) - at org.scalatest.flatspec.AsyncFlatSpecLike.runTests(AsyncFlatSpecLike.scala:1768) - at org.scalatest.flatspec.AsyncFlatSpecLike.runTests$(AsyncFlatSpecLike.scala:1767) - at org.scalatest.flatspec.AsyncFlatSpec.runTests(AsyncFlatSpec.scala:2221) - at org.scalatest.Suite.run(Suite.scala:1112) - at org.scalatest.Suite.run$(Suite.scala:1094) - at org.scalatest.flatspec.AsyncFlatSpec.org$scalatest$flatspec$AsyncFlatSpecLike$$super$run(AsyncFlatSpec.scala:2221) - at org.scalatest.flatspec.AsyncFlatSpecLike.$anonfun$run$1(AsyncFlatSpecLike.scala:1813) - at org.scalatest.AsyncSuperEngine.runImpl(AsyncEngine.scala:625) - at org.scalatest.flatspec.AsyncFlatSpecLike.run(AsyncFlatSpecLike.scala:1813) - at org.scalatest.flatspec.AsyncFlatSpecLike.run$(AsyncFlatSpecLike.scala:1811) - at org.scalatest.flatspec.AsyncFlatSpec.run(AsyncFlatSpec.scala:2221) - at org.scalatest.tools.SuiteRunner.run(SuiteRunner.scala:45) - at org.scalatest.tools.Runner$.$anonfun$doRunRunRunDaDoRunRun$13(Runner.scala:1320) - at org.scalatest.tools.Runner$.$anonfun$doRunRunRunDaDoRunRun$13$adapted(Runner.scala:1314) - at scala.collection.immutable.List.foreach(List.scala:431) - at org.scalatest.tools.Runner$.doRunRunRunDaDoRunRun(Runner.scala:1314) - at org.scalatest.tools.Runner$.$anonfun$runOptionallyWithPassFailReporter$24(Runner.scala:993) - at org.scalatest.tools.Runner$.$anonfun$runOptionallyWithPassFailReporter$24$adapted(Runner.scala:971) - at org.scalatest.tools.Runner$.withClassLoaderAndDispatchReporter(Runner.scala:1480) - at org.scalatest.tools.Runner$.runOptionallyWithPassFailReporter(Runner.scala:971) - at org.scalatest.tools.Runner$.run(Runner.scala:798) - at org.scalatest.tools.Runner.run(Runner.scala) - at org.jetbrains.plugins.scala.testingSupport.scalaTest.ScalaTestRunner.runScalaTest2or3(ScalaTestRunner.java:38) - at org.jetbrains.plugins.scala.testingSupport.scalaTest.ScalaTestRunner.main(ScalaTestRunner.java:25) -""")), - Seq("-a", "hello") -> failWithThrowable[Unit, Throwable](t => assert(t.getMessage == "an error"), - out = Some(""), err = Some("""an error + at io.jobial.sclap.CommandLineParserTest""")), + Seq("-a", "hello") -> failWithThrowable[Unit, Throwable]({ t: Throwable => assert(t.getMessage == "an error") }, + { out: String => out == "" }, (_: String).startsWith("""an error java.lang.Throwable: an error - at io.jobial.sclap.CommandLineParserTest.$anonfun$new$1(CommandLineParserTest.scala:33) - at cats.free.Free.$anonfun$map$1(Free.scala:18) - at cats.free.Free.$anonfun$foldMap$3(Free.scala:156) - at cats.Monad.$anonfun$map$1(Monad.scala:16) - at cats.data.IndexedStateT.$anonfun$flatMap$3(IndexedStateT.scala:28) - at cats.Eval$.loop$1(Eval.scala:363) - at cats.Eval$.cats$Eval$$evaluate(Eval.scala:368) - at cats.Eval$FlatMap.value(Eval.scala:307) - at io.jobial.sclap.impl.picocli.PicocliCommandLineParser.$anonfun$executeCommandLine$5(PicocliCommandLineParser.scala:381) - at cats.effect.internals.IORunLoop$.liftedTree3$1(IORunLoop.scala:229) - at cats.effect.internals.IORunLoop$.step(IORunLoop.scala:229) - at cats.effect.IO.unsafeRunTimed(IO.scala:320) - at cats.effect.IO.unsafeRunSync(IO.scala:239) - at io.jobial.sclap.CommandLineParserTestHelperNoImplicits.$anonfun$runCommandLineTest$1(CommandLineParserTestHelperNoImplicits.scala:49) - at scala.util.Try$.apply(Try.scala:213) - at io.jobial.sclap.OutputCaptureUtils.$anonfun$captureOutput$1(OutputCaptureUtils.scala:99) - at cats.effect.internals.IORunLoop$.cats$effect$internals$IORunLoop$$loop(IORunLoop.scala:87) - at cats.effect.internals.IORunLoop$.start(IORunLoop.scala:34) - at cats.effect.IO.unsafeRunAsync(IO.scala:257) - at cats.effect.IO.unsafeToFuture(IO.scala:344) - at io.jobial.sclap.CommandLineParserTestHelperNoImplicits.$anonfun$runCommandLineTestCases$3(CommandLineParserTestHelperNoImplicits.scala:75) - at org.scalatest.flatspec.AsyncFlatSpecLike.transformToOutcomeParam$1(AsyncFlatSpecLike.scala:139) - at org.scalatest.flatspec.AsyncFlatSpecLike.$anonfun$registerTestToRun$1(AsyncFlatSpecLike.scala:145) - at org.scalatest.AsyncTestSuite.$anonfun$transformToOutcome$1(AsyncTestSuite.scala:240) - at org.scalatest.flatspec.AsyncFlatSpecLike$$anon$5.apply(AsyncFlatSpecLike.scala:1698) - at org.scalatest.AsyncTestSuite.withFixture(AsyncTestSuite.scala:313) - at org.scalatest.AsyncTestSuite.withFixture$(AsyncTestSuite.scala:312) - at org.scalatest.flatspec.AsyncFlatSpec.withFixture(AsyncFlatSpec.scala:2221) - at org.scalatest.flatspec.AsyncFlatSpecLike.invokeWithAsyncFixture$1(AsyncFlatSpecLike.scala:1696) - at org.scalatest.flatspec.AsyncFlatSpecLike.$anonfun$runTest$1(AsyncFlatSpecLike.scala:1710) - at org.scalatest.AsyncSuperEngine.runTestImpl(AsyncEngine.scala:374) - at org.scalatest.flatspec.AsyncFlatSpecLike.runTest(AsyncFlatSpecLike.scala:1710) - at org.scalatest.flatspec.AsyncFlatSpecLike.runTest$(AsyncFlatSpecLike.scala:1689) - at org.scalatest.flatspec.AsyncFlatSpec.runTest(AsyncFlatSpec.scala:2221) - at org.scalatest.flatspec.AsyncFlatSpecLike.$anonfun$runTests$1(AsyncFlatSpecLike.scala:1768) - at org.scalatest.AsyncSuperEngine.$anonfun$runTestsInBranch$3(AsyncEngine.scala:435) - at org.scalatest.Status.$anonfun$thenRun$1(Status.scala:227) - at org.scalatest.Status.$anonfun$thenRun$1$adapted(Status.scala:225) - at org.scalatest.ScalaTestStatefulStatus.whenCompleted(Status.scala:648) - at org.scalatest.Status.thenRun(Status.scala:225) - at org.scalatest.Status.thenRun$(Status.scala:220) - at org.scalatest.ScalaTestStatefulStatus.thenRun(Status.scala:511) - at org.scalatest.AsyncSuperEngine.$anonfun$runTestsInBranch$1(AsyncEngine.scala:435) - at scala.collection.LinearSeqOptimized.foldLeft(LinearSeqOptimized.scala:126) - at scala.collection.LinearSeqOptimized.foldLeft$(LinearSeqOptimized.scala:122) - at scala.collection.immutable.List.foldLeft(List.scala:91) - at org.scalatest.AsyncSuperEngine.traverseSubNodes$1(AsyncEngine.scala:406) - at org.scalatest.AsyncSuperEngine.runTestsInBranch(AsyncEngine.scala:479) - at org.scalatest.AsyncSuperEngine.$anonfun$runTestsInBranch$1(AsyncEngine.scala:460) - at scala.collection.LinearSeqOptimized.foldLeft(LinearSeqOptimized.scala:126) - at scala.collection.LinearSeqOptimized.foldLeft$(LinearSeqOptimized.scala:122) - at scala.collection.immutable.List.foldLeft(List.scala:91) - at org.scalatest.AsyncSuperEngine.traverseSubNodes$1(AsyncEngine.scala:406) - at org.scalatest.AsyncSuperEngine.runTestsInBranch(AsyncEngine.scala:487) - at org.scalatest.AsyncSuperEngine.runTestsImpl(AsyncEngine.scala:555) - at org.scalatest.flatspec.AsyncFlatSpecLike.runTests(AsyncFlatSpecLike.scala:1768) - at org.scalatest.flatspec.AsyncFlatSpecLike.runTests$(AsyncFlatSpecLike.scala:1767) - at org.scalatest.flatspec.AsyncFlatSpec.runTests(AsyncFlatSpec.scala:2221) - at org.scalatest.Suite.run(Suite.scala:1112) - at org.scalatest.Suite.run$(Suite.scala:1094) - at org.scalatest.flatspec.AsyncFlatSpec.org$scalatest$flatspec$AsyncFlatSpecLike$$super$run(AsyncFlatSpec.scala:2221) - at org.scalatest.flatspec.AsyncFlatSpecLike.$anonfun$run$1(AsyncFlatSpecLike.scala:1813) - at org.scalatest.AsyncSuperEngine.runImpl(AsyncEngine.scala:625) - at org.scalatest.flatspec.AsyncFlatSpecLike.run(AsyncFlatSpecLike.scala:1813) - at org.scalatest.flatspec.AsyncFlatSpecLike.run$(AsyncFlatSpecLike.scala:1811) - at org.scalatest.flatspec.AsyncFlatSpec.run(AsyncFlatSpec.scala:2221) - at org.scalatest.tools.SuiteRunner.run(SuiteRunner.scala:45) - at org.scalatest.tools.Runner$.$anonfun$doRunRunRunDaDoRunRun$13(Runner.scala:1320) - at org.scalatest.tools.Runner$.$anonfun$doRunRunRunDaDoRunRun$13$adapted(Runner.scala:1314) - at scala.collection.immutable.List.foreach(List.scala:431) - at org.scalatest.tools.Runner$.doRunRunRunDaDoRunRun(Runner.scala:1314) - at org.scalatest.tools.Runner$.$anonfun$runOptionallyWithPassFailReporter$24(Runner.scala:993) - at org.scalatest.tools.Runner$.$anonfun$runOptionallyWithPassFailReporter$24$adapted(Runner.scala:971) - at org.scalatest.tools.Runner$.withClassLoaderAndDispatchReporter(Runner.scala:1480) - at org.scalatest.tools.Runner$.runOptionallyWithPassFailReporter(Runner.scala:971) - at org.scalatest.tools.Runner$.run(Runner.scala:798) - at org.scalatest.tools.Runner.run(Runner.scala) - at org.jetbrains.plugins.scala.testingSupport.scalaTest.ScalaTestRunner.runScalaTest2or3(ScalaTestRunner.java:38) - at org.jetbrains.plugins.scala.testingSupport.scalaTest.ScalaTestRunner.main(ScalaTestRunner.java:25) -""")) + at io.jobial.sclap.CommandLineParserTest""")) ) } diff --git a/sclap-app/src/test/scala/io/jobial/sclap/CommandLineParserTestHelperNoImplicits.scala b/sclap-app/src/test/scala/io/jobial/sclap/CommandLineParserTestHelperNoImplicits.scala index fc653c6..9473563 100644 --- a/sclap-app/src/test/scala/io/jobial/sclap/CommandLineParserTestHelperNoImplicits.scala +++ b/sclap-app/src/test/scala/io/jobial/sclap/CommandLineParserTestHelperNoImplicits.scala @@ -123,28 +123,49 @@ trait CommandLineParserTestHelperNoImplicits extends CommandLineParserNoImplicit } }) + def failWith[T](check: Throwable => Assertion, out: String => Boolean, err: String => Boolean) = + TestFailureCheck[T]( + { testResult: TestResult[T] => + testResult.result match { + case Right(r) => + IO(fail(s"expected failure, got $testResult")) + case Left(t) => + IO(assert(out(testResult.out))) *> + IO(assert(err(testResult.err))) *> + IO(check(t)) + } + }) + def failWithThrowable[T, X <: Throwable : ClassTag](f: X => Assertion = { _: X => Succeeded }, out: Option[String] = None, err: Option[String] = None) = failWith[T]({ case x: X => f(x) case x: Throwable => fail(s"wrong exception is thrown: ", x) - }, out, err) + }: Throwable => Assertion, out, err) + + def failWithThrowable[T, X <: Throwable : ClassTag](f: X => Assertion, out: String => Boolean, err: String => Boolean) = + failWith[T]({ + case x: X => + f(x) + case x: Throwable => + fail(s"wrong exception is thrown: ", x) + }: Throwable => Assertion, out, err) def failCommandExecutionWith[X <: Throwable : ClassTag](f: X => Assertion = { _: X => Succeeded }, out: Option[String] = None, err: Option[String] = None) = failWithThrowable[(Option[String], Any), X](f, out, err) def failWithUsageHelpRequested[T](help: String) = - failWithThrowable[T, UsageHelpRequested](_ => Succeeded, out = Some(help), None) + failWithThrowable[T, UsageHelpRequested]({ _: Throwable => Succeeded }, out = Some(help), None) def failWithVersionHelpRequested[T](version: String) = - failWithThrowable[T, VersionHelpRequested](_ => Succeeded, out = Some(version), None) + failWithThrowable[T, VersionHelpRequested]({ _: Throwable => Succeeded }, out = Some(version), None) def failCommandLineParsingWith[T](message: String) = - failWithThrowable[T, CommandLineParsingFailed](t => assert(t.getMessage == message)) + failWithThrowable[T, CommandLineParsingFailed] { t: Throwable => assert(t.getMessage == message) } def failSubcommandLineParsingWith[T](message: String) = - failWithThrowable[T, CommandLineParsingFailedForSubcommand](t => assert(t.getMessage == message)) + failWithThrowable[T, CommandLineParsingFailedForSubcommand] { t: Throwable => assert(t.getMessage == message) } def createNewInstanceOf[T <: {def main(args: Array[String]): Unit}](o: T) = createNewInstanceOfWithConstructor(o) { classOfApp => diff --git a/sclap-app/src/test/scala/io/jobial/sclap/OutputCaptureUtils.scala b/sclap-app/src/test/scala/io/jobial/sclap/OutputCaptureUtils.scala index cee7c12..43293c5 100644 --- a/sclap-app/src/test/scala/io/jobial/sclap/OutputCaptureUtils.scala +++ b/sclap-app/src/test/scala/io/jobial/sclap/OutputCaptureUtils.scala @@ -1,20 +1,25 @@ package io.jobial.sclap import cats.effect.IO +import io.jobial.sclap.core.implicits.TryExtensionInstance import java.io.{BufferedOutputStream, ByteArrayOutputStream, FilterOutputStream, OutputStream, PrintStream} import java.lang.reflect.{Field, Modifier} import java.security.Permission import scala.util.{DynamicVariable, Failure, Try} -object OutputCaptureUtils { +object OutputCaptureUtils extends TryExtensionInstance { - System.setSecurityManager(new SecurityManager { + try { + System.setSecurityManager(new SecurityManager { - override def checkPermission(perm: Permission) = { - // Allow other activities by default - } - }) + override def checkPermission(perm: Permission) = { + // Allow other activities by default + } + }) + } catch { + case t: Throwable => + } val originalSystemOut = System.out val originalSystemErr = System.err @@ -32,7 +37,17 @@ object OutputCaptureUtils { } } + val consoleOut = new PrintStream(testOut) + + val consoleErr = new PrintStream(testErr) + def writeField(target: AnyRef, fieldName: String, value: Any) = { + import sun.misc.Unsafe + import java.lang.reflect.Field + val unsafeField = classOf[Unsafe].getDeclaredField("theUnsafe") + unsafeField.setAccessible(true) + + val unsafe = unsafeField.get(null).asInstanceOf[Unsafe] val field = Try(target.getClass.getField(fieldName)).getOrElse { target.getClass.getDeclaredFields.find { f => f.setAccessible(true) @@ -44,23 +59,32 @@ object OutputCaptureUtils { modifiers.setAccessible(true); modifiers.setInt(field, field.getModifiers() & ~Modifier.FINAL); } - - field.setAccessible(true) - field.set(target, value) + + Try { + field.setAccessible(true) + field.set(target, value) + val staticFieldBase = unsafe.staticFieldBase(field) + val staticFieldOffset = unsafe.staticFieldOffset(field) + unsafe.putObject(staticFieldBase, staticFieldOffset, value) + } } def redirectSystemOutAndErr = { System.out.flush System.err.flush - try { - writeField(Console, "outVar", new DynamicVariable[PrintStream](new PrintStream(testOut))) - writeField(Console, "errVar", new DynamicVariable[PrintStream](new PrintStream(testErr))) - } catch { - case t => - t.printStackTrace() - } - System.setOut(new PrintStream(testOut)) - System.setErr(new PrintStream(testErr)) + System.setOut(consoleOut) + System.setErr(consoleErr) + redirectScalaOutAndErr + } + + def redirectScalaOutAndErr = { + // TODO: this only works for the current thread at the moment + val setOutDirect = Console.getClass.getDeclaredMethod("setOutDirect", classOf[PrintStream]) + setOutDirect.setAccessible(true) + setOutDirect.invoke(Console, consoleOut) + val setErrDirect = Console.getClass.getDeclaredMethod("setErrDirect", classOf[PrintStream]) + setErrDirect.setAccessible(true) + setErrDirect.invoke(Console, consoleErr) } def setSystemOutAndErr(out: OutputStream, err: OutputStream) = { @@ -86,6 +110,7 @@ trait OutputCaptureUtils { */ def captureOutput[T](f: => T) = IO { OutputCaptureUtils.synchronized { + redirectScalaOutAndErr val inIntellij = Thread.currentThread().getStackTrace.find(_.getClassName.contains("org.jetbrains")).isDefined if (inIntellij) Thread.sleep(200) diff --git a/sclap-core/src/main/scala/io/jobial/sclap/core/implicits/ArgumentValueParserInstances.scala b/sclap-core/src/main/scala/io/jobial/sclap/core/implicits/ArgumentValueParserInstances.scala index 1591c5d..a72644a 100644 --- a/sclap-core/src/main/scala/io/jobial/sclap/core/implicits/ArgumentValueParserInstances.scala +++ b/sclap-core/src/main/scala/io/jobial/sclap/core/implicits/ArgumentValueParserInstances.scala @@ -21,23 +21,7 @@ import scala.concurrent.duration.{Duration, FiniteDuration} import scala.reflect.ClassTag import scala.util.{Failure, Success, Try} -trait ArgumentValueParserInstances { - - /** - * This is only needed for Scala 2.11 compatibility. - * - * @param t - * @tparam T - */ - implicit class TryExtension[T](t: Try[T]) { - - def toEither = t match { - case Success(value) => - Right(value) - case Failure(t) => - Left(t) - } - } +trait ArgumentValueParserInstances extends TryExtensionInstance { implicit val stringArgumentValueParser: ArgumentValueParserFromMonoid[String] = new ArgumentValueParserFromMonoid[String] { diff --git a/sclap-core/src/main/scala/io/jobial/sclap/core/implicits/ArgumentValuePrinterInstances.scala b/sclap-core/src/main/scala/io/jobial/sclap/core/implicits/ArgumentValuePrinterInstances.scala index d1bd3ff..9587f43 100644 --- a/sclap-core/src/main/scala/io/jobial/sclap/core/implicits/ArgumentValuePrinterInstances.scala +++ b/sclap-core/src/main/scala/io/jobial/sclap/core/implicits/ArgumentValuePrinterInstances.scala @@ -23,6 +23,16 @@ trait ArgumentValuePrinterInstances { implicit def argumentValuePrinterFromShow[T: Show] = new ArgumentValuePrinterFromShow[T] {} + implicit def durationArgumentValuePrinter = + new ArgumentValuePrinter[Duration] { + def print(value: Duration) = value.toString + } + + implicit def finiteDurationArgumentValuePrinter = + new ArgumentValuePrinter[FiniteDuration] { + def print(value: FiniteDuration) = value.toString + } + implicit val fileArgumentValuePrinter = new ArgumentValuePrinter[File] { def print(value: File) = diff --git a/sclap-core/src/main/scala/io/jobial/sclap/core/implicits/TryExtensionInstance.scala b/sclap-core/src/main/scala/io/jobial/sclap/core/implicits/TryExtensionInstance.scala new file mode 100644 index 0000000..ab78557 --- /dev/null +++ b/sclap-core/src/main/scala/io/jobial/sclap/core/implicits/TryExtensionInstance.scala @@ -0,0 +1,22 @@ +package io.jobial.sclap.core.implicits + +import scala.util.{Failure, Success, Try} + +trait TryExtensionInstance { + + /** + * This is only needed for Scala 2.11 compatibility. + * + * @param t + * @tparam T + */ + implicit class TryExtension[T](t: Try[T]) { + + def toEither = t match { + case Success(value) => + Right(value) + case Failure(t) => + Left(t) + } + } +}