Skip to content

Commit

Permalink
Code cleanup
Browse files Browse the repository at this point in the history
  • Loading branch information
propensive committed Feb 27, 2024
1 parent afa022a commit 81d873a
Show file tree
Hide file tree
Showing 5 changed files with 124 additions and 82 deletions.
25 changes: 14 additions & 11 deletions src/bench/benchmark.scala
Original file line number Diff line number Diff line change
Expand Up @@ -22,15 +22,18 @@ import anticipation.*
import scala.collection.mutable as scm

extension [TestType](test: Test[TestType])
inline def benchmark
[DurationType, ReportType]
(confidence: Optional[Benchmark.Percentiles] = Unset, iterations: Optional[Int] = Unset,
duration: Optional[DurationType] = Unset, warmup: Optional[DurationType] = Unset,
baseline: Optional[Baseline] = Unset)
(using runner: Runner[ReportType], inc: Inclusion[ReportType, Benchmark],
specificDuration: SpecificDuration[DurationType] = timeInterfaces.long,
genericDuration: GenericDuration[DurationType] = timeInterfaces.long)
: Unit =
inline def benchmark[DurationType, ReportType]
( confidence: Optional[Benchmark.Percentiles] = Unset,
iterations: Optional[Int] = Unset,
duration: Optional[DurationType] = Unset,
warmup: Optional[DurationType] = Unset,
baseline: Optional[Baseline] = Unset )
( using runner: Runner[ReportType],
inc: Inclusion[ReportType, Benchmark],
specificDuration: SpecificDuration[DurationType] = timeInterfaces.long,
genericDuration: GenericDuration[DurationType] = timeInterfaces.long )
: Unit =

val action = test.action
var end = System.currentTimeMillis + warmup.or(SpecificDuration(10000L)).milliseconds
val times: scm.ArrayBuffer[Long] = scm.ArrayBuffer()
Expand Down Expand Up @@ -61,7 +64,7 @@ extension [TestType](test: Test[TestType])
val variance: Double = (times.map { t => (mean - t)*(mean - t) }.sum)/count
val stdDev: Double = math.sqrt(variance)

val benchmark = Benchmark(total, times.size, min.toDouble, mean, max.toDouble, stdDev,
confidence.or(95), baseline)
val benchmark =
Benchmark(total, times.size, min.toDouble, mean, max.toDouble, stdDev, confidence.or(95), baseline)

inc.include(runner.report, test.id, benchmark)
83 changes: 52 additions & 31 deletions src/core/macros.scala
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,16 @@ import dotty.tools.dotc.util as dtdu
import scala.quoted.*

object Probably:
protected def general
[TestType: Type, ReportType: Type, ResultType: Type]
(test: Expr[Test[TestType]], predicate: Expr[TestType => Boolean], runner: Expr[Runner[ReportType]],
inc: Expr[Inclusion[ReportType, Outcome]], inc2: Expr[Inclusion[ReportType, DebugInfo]],
action: Expr[TestRun[TestType] => ResultType])
protected def general[TestType: Type, ReportType: Type, ResultType: Type]
( test: Expr[Test[TestType]],
predicate: Expr[TestType => Boolean],
runner: Expr[Runner[ReportType]],
inc: Expr[Inclusion[ReportType, Outcome]],
inc2: Expr[Inclusion[ReportType, DebugInfo]],
action: Expr[TestRun[TestType] => ResultType])
(using Quotes)
: Expr[ResultType] =
: Expr[ResultType] =

import quotes.reflect.*

val exp: Option[Expr[Any]] = predicate.asTerm match
Expand All @@ -53,49 +56,67 @@ object Probably:

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) }
'{
assertion[t | 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, TextConversion.any) }
'{
assertion[TestType, TestType, ReportType, ResultType]
($runner, $test, $predicate, $action, Contrast.nothing[TestType], None, $inc, $inc2,
TextConversion.any)
}

def check
[TestType: Type, ReportType: Type]
(test: Expr[Test[TestType]], predicate: Expr[TestType => Boolean], runner: Expr[Runner[ReportType]],
inc: Expr[Inclusion[ReportType, Outcome]], inc2: Expr[Inclusion[ReportType, DebugInfo]])
def check[TestType: Type, ReportType: Type]
( test: Expr[Test[TestType]],
predicate: Expr[TestType => Boolean],
runner: Expr[Runner[ReportType]],
inc: Expr[Inclusion[ReportType, Outcome]],
inc2: Expr[Inclusion[ReportType, DebugInfo]] )
(using Quotes)
: Expr[TestType] =
: 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], runner: Expr[Runner[ReportType]],
inc: Expr[Inclusion[ReportType, Outcome]], inc2: Expr[Inclusion[ReportType, DebugInfo]])
def assert[TestType: Type, ReportType: Type]
( test: Expr[Test[TestType]],
predicate: Expr[TestType => Boolean],
runner: Expr[Runner[ReportType]],
inc: Expr[Inclusion[ReportType, Outcome]],
inc2: Expr[Inclusion[ReportType, DebugInfo]] )
(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]], inc: Expr[Inclusion[ReportType, Outcome]],
inc2: Expr[Inclusion[ReportType, DebugInfo]])
def aspire[TestType: Type, ReportType: Type]
( test: Expr[Test[TestType]],
runner: Expr[Runner[ReportType]],
inc: Expr[Inclusion[ReportType, Outcome]],
inc2: Expr[Inclusion[ReportType, DebugInfo]] )
(using Quotes)
: Expr[Unit] =
: Expr[Unit] =

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], predicate: TestType2 => Boolean, result: TestRun[TestType2] => ResultType,
contrast: Contrast[TestType], exp: Option[TestType], inc: Inclusion[ReportType, Outcome],
inc2: Inclusion[ReportType, DebugInfo], display: Debug[TestType]): ResultType =
def assertion[TestType, TestType2 <: TestType, ReportType, ResultType]
( runner: Runner[ReportType],
test: Test[TestType2],
predicate: TestType2 => Boolean,
result: TestRun[TestType2] => ResultType,
contrast: Contrast[TestType],
exp: Option[TestType],
inc: Inclusion[ReportType, Outcome],
inc2: Inclusion[ReportType, DebugInfo],
display: Debug[TestType] )
: ResultType =

runner.run(test).pipe: run =>
val outcome = run match
case TestRun.Throws(err, duration, map) =>
val exception: Exception =
try err() catch case exc: Exception => exc
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)

Expand Down
79 changes: 44 additions & 35 deletions src/core/probably.scala
Original file line number Diff line number Diff line change
Expand Up @@ -30,21 +30,21 @@ import scala.collection.mutable as scm

given realm: Realm = realm"probably"

extension [T](inline value: T)(using inline test: TestContext)
inline def inspect: T = ${Probably.inspect('value, 'test)}
extension [ValueType](inline value: ValueType)(using inline test: TestContext)
inline def inspect: ValueType = ${Probably.inspect('value, 'test)}

package testContexts:
given threadLocal: TestContext = new TestContext():
private val delegate: Option[TestContext] = Option(Runner.testContextThreadLocal.get()).map(_.nn).flatten

override def capture[T](name: Text, value: T)(using Debug[T]): T =
delegate.map(_.capture[T](name, value)).getOrElse(value)
override def capture[ValueType](name: Text, value: ValueType)(using Debug[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[T](name: Text, value: T)(using Debug[T]): T =
def capture[ValueType](name: Text, value: ValueType)(using Debug[ValueType]): ValueType =
captured.append(name -> value.debug)
value

Expand All @@ -56,7 +56,10 @@ 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[T](ctx: TestContext ?=> T): Test[T] = Test[T](this, ctx(using _))

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):
Expand Down Expand Up @@ -131,53 +134,59 @@ class Runner[ReportType]()(using reporter: TestReporter[ReportType]):

def complete(): Unit = reporter.complete(report)

case class Test[+Return](id: TestId, action: TestContext => Return)
case class Test[+ReturnType](id: TestId, action: TestContext => ReturnType)

def test[ReportType](name: Text)(using suite: TestSuite, codepoint: Codepoint): TestId =
TestId(name, suite, codepoint)

def suite
[ReportType](name: Text)(using suite: TestSuite, runner: Runner[ReportType])
(block: TestSuite ?=> Unit): Unit =
def suite[ReportType](name: Text)(using suite: TestSuite, runner: Runner[ReportType])
(block: TestSuite ?=> Unit)
: Unit =

runner.suite(TestSuite(name, suite), block)

extension [TestType](test: Test[TestType])
inline def aspire[ReportType]
(inline pred: TestType => Boolean)
inline def aspire[ReportType](inline predicate: TestType => Boolean)
(using runner: Runner[ReportType], inc: Inclusion[ReportType, Outcome],
inc2: Inclusion[ReportType, DebugInfo])
: Unit =
${Probably.aspire[TestType, ReportType]('test, 'runner, 'inc, 'inc2)}

inline def assert[ReportType]
(inline pred: TestType => Boolean)
(using runner: Runner[ReportType], inc: Inclusion[ReportType, Outcome],
inc2: Inclusion[ReportType, DebugInfo])
: Unit =
${Probably.assert[TestType, ReportType]('test, 'pred, 'runner, 'inc, 'inc2)}
(inline predicate: TestType => Boolean)
( using runner: Runner[ReportType],
inclusion: Inclusion[ReportType, Outcome],
inclusion2: Inclusion[ReportType, DebugInfo] )
: Unit =
${Probably.assert[TestType, ReportType]('test, 'predicate, 'runner, 'inclusion, 'inclusion2)}

inline def check[ReportType]
(inline pred: TestType => Boolean)
(using runner: Runner[ReportType], inc: Inclusion[ReportType, Outcome],
inc2: Inclusion[ReportType, DebugInfo])
: TestType =
${Probably.check[TestType, ReportType]('test, 'pred, 'runner, 'inc, 'inc2)}
(inline predicate: TestType => Boolean)
( using runner: Runner[ReportType],
inclusion: Inclusion[ReportType, Outcome],
inclusion2: Inclusion[ReportType, DebugInfo] )
: TestType =
${Probably.check[TestType, ReportType]('test, 'predicate, 'runner, 'inclusion, 'inclusion2)}

inline def assert[ReportType]()
(using runner: Runner[ReportType], inc: Inclusion[ReportType, Outcome],
inc2: Inclusion[ReportType, DebugInfo])
: Unit =
${Probably.assert[TestType, ReportType]('test, '{Probably.succeed}, 'runner, 'inc, 'inc2)}
( using runner: Runner[ReportType],
inclusion: Inclusion[ReportType, Outcome],
inclusion2: Inclusion[ReportType, DebugInfo] )
: Unit =
${Probably.assert[TestType, ReportType]('test, '{Probably.succeed}, 'runner, 'inclusion, 'inclusion2)}

inline def check[ReportType]()
(using runner: Runner[ReportType], inc: Inclusion[ReportType, Outcome],
inc2: Inclusion[ReportType, DebugInfo])
: TestType =
${Probably.check[TestType, ReportType]('test, '{Probably.succeed}, 'runner, 'inc, 'inc2)}
( using runner: Runner[ReportType],
inclusion: Inclusion[ReportType, Outcome],
inclusion2: Inclusion[ReportType, DebugInfo] )
: 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],
inc2: Inclusion[ReportType, DebugInfo])
: Unit =
inline def matches[ReportType](inline pf: PartialFunction[TestType, Any])
( using runner: Runner[ReportType],
inc: Inclusion[ReportType, Outcome],
inc2: Inclusion[ReportType, DebugInfo] )
: Unit =

assert[ReportType](pf.isDefinedAt(_))
4 changes: 1 addition & 3 deletions src/core/tolerance.scala
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,9 @@ package probably
import rudiments.*

case class Tolerance(value: Double, tolerance: Double):
def covers(right: Double): Boolean =
value >= (value - tolerance) && value <= (value + tolerance)
def covers(right: Double): Boolean = value >= (value - tolerance) && value <= (value + tolerance)

extension (value: Double)
@targetName("plusOrMinus")
infix def +/- (tolerance: Double): Tolerance = Tolerance(value, tolerance)

infix def meets (tolerance: Tolerance): Boolean = tolerance.covers(value)
15 changes: 13 additions & 2 deletions src/coverage/coverage.scala
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,19 @@ object Juncture:
given Ordering[Juncture] = Ordering.by[Juncture, Int](_.start).orElseBy(-_.end)

case class Juncture
(id: Int, path: Text, className: Text, methodName: Text, start: Int, end: Int, lineNo: Int,
symbolName: Text, treeName: Text, branch: Boolean, ignored: Boolean, code: List[Text]):
( id: Int,
path: Text,
className: Text,
methodName: Text,
start: Int,
end: Int,
lineNo: Int,
symbolName: Text,
treeName: Text,
branch: Boolean,
ignored: Boolean,
code: List[Text] ):

def contains(right: Juncture): Boolean =
(right.start >= start && right.end <= end && !(right.start == start && right.end == end)) ||
treeName == t"DefDef" && right.treeName != t"DefDef" && className == right.className &&
Expand Down

0 comments on commit 81d873a

Please sign in to comment.