diff --git a/src/core/macros.scala b/src/core/macros.scala index 5956eeb..a07025b 100644 --- a/src/core/macros.scala +++ b/src/core/macros.scala @@ -37,7 +37,7 @@ object Probably: : Expr[ResultType] = import quotes.reflect.* - + val exp: Option[Expr[Any]] = predicate.asTerm match case Inlined(_, _, Block(List(DefDef(a1, _, _, Some(expression))), Closure(Ident(a2), _))) if a1 == a2 => @@ -45,29 +45,29 @@ object Probably: case Apply(Select(Ident(_), "=="), List(term)) => Some(term.asExpr) case Apply(Select(term, "=="), List(Ident(_))) => Some(term.asExpr) case other => None - + case _ => None - + exp match - case Some('{ $expr: t }) => - val debug: Expr[Debug[t | TestType]] = - Expr.summon[Debug[t | TestType]].getOrElse('{ _.toString.tt }) - - val contrast = '{Contrast.general[t | TestType]} - //val contrast = Expr.summon[Contrast[t | TestType]].getOrElse('{Contrast.general[t | TestType]}) - '{ - assertion[t | TestType, TestType, ReportType, ResultType] - ($runner, $test, $predicate, $action, $contrast, Some($expr), $inc, $inc2, $debug) - } - + // case Some('{type testType >: TestType; $expr: testType}) => + // val debug: Expr[Debug[testType]] = + // Expr.summon[Debug[testType]].getOrElse('{ _.toString.tt }) + + // val contrast: Expr[Contrast[testType]] = '{Contrast.general[testType]} + // //val contrast = Expr.summon[Contrast[testType]].getOrElse('{Contrast.general[testType]}) + // '{ + // assertion[testType, TestType, ReportType, ResultType] + // ($runner, $test, $predicate, $action, $contrast, Some($expr), $inc, $inc2, $debug) + // } + case _ => '{ assertion[TestType, TestType, ReportType, ResultType] ($runner, $test, $predicate, $action, Contrast.nothing[TestType], None, $inc, $inc2, _.toString.tt) } - + def check[TestType: Type, ReportType: Type] (test: Expr[Test[TestType]], predicate: Expr[TestType => Boolean], @@ -78,7 +78,7 @@ object Probably: : Expr[TestType] = general[TestType, ReportType, TestType](test, predicate, runner, inc, inc2, '{ (t: TestRun[TestType]) => t.get }) - + def assert[TestType: Type, ReportType: Type] (test: Expr[Test[TestType]], predicate: Expr[TestType => Boolean], @@ -88,7 +88,7 @@ object Probably: (using Quotes) : Expr[Unit] = general[TestType, ReportType, Unit](test, predicate, runner, inc, inc2, '{ (t: TestRun[TestType]) => () }) - + def aspire[TestType: Type, ReportType: Type] (test: Expr[Test[TestType]], runner: Expr[Runner[ReportType]], @@ -100,7 +100,7 @@ object Probably: general[TestType, ReportType, Unit](test, '{ _ => true }, runner, inc, inc2, '{ (t: TestRun[TestType]) => () }) def succeed: Any => Boolean = (value: Any) => true - + def assertion[TestType, TestType2 <: TestType, ReportType, ResultType] (runner: Runner[ReportType], test: Test[TestType2], @@ -119,7 +119,7 @@ object Probably: val exception: Exception = try err() catch case exc: Exception => exc if !map.isEmpty then inc2.include(runner.report, test.id, DebugInfo.Captures(map)) Outcome.Throws(exception, duration) - + case TestRun.Returns(value, duration, map) => try if predicate(value) then Outcome.Pass(duration) else exp match @@ -128,9 +128,9 @@ object Probably: display.text(value), contrast(exp, value))) case None => //inc2.include(runner.report, test.id, DebugInfo.Compare(summon[Contrast[Any]].compare(value, 1))) - + if !map.isEmpty then inc2.include(runner.report, test.id, DebugInfo.Captures(map)) - + Outcome.Fail(duration) catch case err: Exception => Outcome.CheckThrows(err, duration) @@ -143,8 +143,8 @@ object Probably: val exprName: Text = expr.asTerm.pos match case pos: dtdu.SourcePosition => pos.lineContent.show.slice(pos.startColumn, pos.endColumn) case _ => t"" - + val debug: Expr[Debug[TestType]] = Expr.summon[Debug[TestType]].getOrElse('{ _.toString.tt }) - + '{ $test.capture(Text(${Expr[String](exprName.s)}), $expr)(using $debug) } diff --git a/src/core/probably.scala b/src/core/probably.scala index 4c5eff4..fba9993 100644 --- a/src/core/probably.scala +++ b/src/core/probably.scala @@ -36,15 +36,15 @@ extension [ValueType](inline value: ValueType)(using inline test: TestContext) package testContexts: given threadLocal: TestContext = new TestContext(): private val delegate: Option[TestContext] = Option(Runner.testContextThreadLocal.get()).map(_.nn).flatten - - override def capture[ValueType](name: Text, value: ValueType)(using Debug[ValueType]): ValueType = + + override def capture[ValueType: Debug](name: Text, value: ValueType): ValueType = delegate.map(_.capture[ValueType](name, value)).getOrElse(value) @annotation.capability class TestContext(): private[probably] val captured: scm.ArrayBuffer[(Text, Text)] = scm.ArrayBuffer() - - def capture[ValueType](name: Text, value: ValueType)(using Debug[ValueType]): ValueType = + + def capture[ValueType: Debug](name: Text, value: ValueType): ValueType = captured.append(name -> value.debug) value @@ -56,17 +56,17 @@ case class TestId(name: Text, suite: Optional[TestSuite], codepoint: Codepoint): import textMetrics.uniform lazy val id: Text = (suite.hashCode ^ name.hashCode).hex.pad(6, Rtl, '0').take(6, Rtl) lazy val ids: List[Text] = id :: suite.let(_.id.ids).or(Nil) - + def apply[ResultType](ctx: TestContext ?=> ResultType): Test[ResultType] = Test[ResultType](this, ctx(using _)) - + def depth: Int = suite.let(_.id.depth).or(0) + 1 class TestSuite(val name: Text, val parent: Optional[TestSuite] = Unset)(using codepoint: Codepoint): override def equals(that: Any): Boolean = that.matchable(using Unsafe) match case that: TestSuite => name == that.name && parent == that.parent case _ => false - + override def hashCode: Int = name.hashCode + parent.hashCode val id: TestId = TestId(name, parent, codepoint) @@ -103,24 +103,24 @@ class Runner[ReportType]()(using reporter: TestReporter[ReportType]): val ctx = TestContext() Runner.testContextThreadLocal.set(Some(ctx)) val ns0 = System.nanoTime - + try val ns0: Long = System.nanoTime val result: T = test.action(ctx) val ns: Long = System.nanoTime - ns0 TestRun.Returns(result, ns, ctx.captured.to(Map)).also: synchronized { active -= test.id } - + catch case err: Exception => val ns: Long = System.nanoTime - ns0 - + def lazyException(): Nothing = given CanThrow[Exception] = unsafeExceptions.canThrowAny throw err TestRun.Throws(lazyException, ns, ctx.captured.to(Map)).also: synchronized { active -= test.id } - + finally Runner.testContextThreadLocal.set(None) @@ -128,7 +128,7 @@ class Runner[ReportType]()(using reporter: TestReporter[ReportType]): if !skip(suite.id) then reporter.declareSuite(report, suite) block(using suite) - + def terminate(error: Throwable): Unit = synchronized: reporter.fail(report, error, active) @@ -151,7 +151,7 @@ extension [TestType](test: Test[TestType]) inc2: Inclusion[ReportType, DebugInfo]) : Unit = ${Probably.aspire[TestType, ReportType]('test, 'runner, 'inc, 'inc2)} - + inline def assert[ReportType] (inline predicate: TestType => Boolean) (using runner: Runner[ReportType], @@ -159,7 +159,7 @@ extension [TestType](test: Test[TestType]) inclusion2: Inclusion[ReportType, DebugInfo]) : Unit = ${Probably.assert[TestType, ReportType]('test, 'predicate, 'runner, 'inclusion, 'inclusion2)} - + inline def check[ReportType] (inline predicate: TestType => Boolean) (using runner: Runner[ReportType], @@ -174,7 +174,7 @@ extension [TestType](test: Test[TestType]) inclusion2: Inclusion[ReportType, DebugInfo]) : Unit = ${Probably.assert[TestType, ReportType]('test, '{Probably.succeed}, 'runner, 'inclusion, 'inclusion2)} - + inline def check[ReportType]() (using runner: Runner[ReportType], inclusion: Inclusion[ReportType, Outcome], @@ -182,7 +182,7 @@ extension [TestType](test: Test[TestType]) : TestType = ${Probably.check[TestType, ReportType]('test, '{Probably.succeed}, 'runner, 'inclusion, 'inclusion2)} - + inline def matches[ReportType](inline pf: PartialFunction[TestType, Any]) (using runner: Runner[ReportType], inc: Inclusion[ReportType, Outcome],