From 029952895b858f47684df3346e63dfac22a84b40 Mon Sep 17 00:00:00 2001 From: Dale Wijnand Date: Thu, 5 Apr 2018 09:43:22 +0100 Subject: [PATCH] Enforce invariant in StringTypeTag optimisation Or, put differently, "Add a test for sbt/util#153". --- .../src/main/scala/sbt/util/LogExchange.scala | 19 ++++++++++--------- .../src/test/scala/LogExchangeSpec.scala | 16 ++++++++++++++++ 2 files changed, 26 insertions(+), 9 deletions(-) create mode 100644 internal/util-logging/src/test/scala/LogExchangeSpec.scala diff --git a/internal/util-logging/src/main/scala/sbt/util/LogExchange.scala b/internal/util-logging/src/main/scala/sbt/util/LogExchange.scala index 7879eb80a..2341a4395 100644 --- a/internal/util-logging/src/main/scala/sbt/util/LogExchange.scala +++ b/internal/util-logging/src/main/scala/sbt/util/LogExchange.scala @@ -62,20 +62,21 @@ sealed abstract class LogExchange { config.getLoggerConfig(loggerName) } + // Construct these StringTypeTags manually, because they're used at the very startup of sbt + // and we'll try not to initialize the universe by using the StringTypeTag.apply that requires a TypeTag + // A better long-term solution could be to make StringTypeTag.apply a macro. + lazy val stringTypeTagThrowable = StringTypeTag[Throwable]("scala.Throwable") + lazy val stringTypeTagTraceEvent = StringTypeTag[TraceEvent]("sbt.internal.util.TraceEvent") + lazy val stringTypeTagSuccessEvent = StringTypeTag[SuccessEvent]("sbt.internal.util.SuccessEvent") + private[sbt] def initStringCodecs(): Unit = { import sbt.internal.util.codec.ThrowableShowLines._ import sbt.internal.util.codec.TraceEventShowLines._ import sbt.internal.util.codec.SuccessEventShowLines._ - // Register these StringCodecs manually, because this method will be called at the very startup of sbt - // and we'll try not to initialize the universe in StringTypeTag.apply - // If these classes are moved around, both the fully qualified names and the strings need to be adapted. - // A better long-term solution could be to make StringTypeTag.apply a macro. - registerStringCodecByStringTypeTag[_root_.scala.Throwable](StringTypeTag("scala.Throwable")) - registerStringCodecByStringTypeTag[_root_.sbt.internal.util.TraceEvent]( - StringTypeTag("sbt.internal.util.TraceEvent")) - registerStringCodecByStringTypeTag[_root_.sbt.internal.util.SuccessEvent]( - StringTypeTag("sbt.internal.util.SuccessEvent")) + registerStringCodecByStringTypeTag(stringTypeTagThrowable) + registerStringCodecByStringTypeTag(stringTypeTagTraceEvent) + registerStringCodecByStringTypeTag(stringTypeTagSuccessEvent) } // This is a dummy layout to avoid casting error during PatternLayout.createDefaultLayout() diff --git a/internal/util-logging/src/test/scala/LogExchangeSpec.scala b/internal/util-logging/src/test/scala/LogExchangeSpec.scala new file mode 100644 index 000000000..b29512296 --- /dev/null +++ b/internal/util-logging/src/test/scala/LogExchangeSpec.scala @@ -0,0 +1,16 @@ +package sbt.util + +import sbt.internal.util._ + +import org.scalatest._ + +class LogExchangeSpec extends FlatSpec with Matchers { + import LogExchange._ + + checkTypeTag("stringTypeTagThrowable", stringTypeTagThrowable, StringTypeTag[Throwable]) + checkTypeTag("stringTypeTagTraceEvent", stringTypeTagTraceEvent, StringTypeTag[TraceEvent]) + checkTypeTag("stringTypeTagSuccessEvent", stringTypeTagSuccessEvent, StringTypeTag[SuccessEvent]) + + private def checkTypeTag[A, B](name: String, actual: A, expected: B): Unit = + s"LogExchange.$name" should s"match real StringTypeTag[$expected]" in assert(actual == expected) +}