Skip to content

Commit

Permalink
Raise an exception on assert.
Browse files Browse the repository at this point in the history
  • Loading branch information
zainab-ali committed Oct 9, 2024
1 parent 8aeb1bc commit e8c77fd
Show file tree
Hide file tree
Showing 7 changed files with 227 additions and 1 deletion.
68 changes: 68 additions & 0 deletions modules/core/shared/src/main/scala-2/weaver/AssertMacro.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package weaver

import scala.reflect.macros.blackbox

private[weaver] trait AssertMacro {

/**
* Asserts that a boolean value is true and raises an AssertionException on failure.
*
* Use the [[Expectations.Helpers.clue]] function to investigate any failures.
*/
def apply(value: Boolean): Unit = macro AssertMacro.applyImpl

/**
* Asserts that a boolean value is true and displays a failure message if not.
*
* Use the [[Expectations.Helpers.clue]] function to investigate any failures.
*/
def apply(value: Boolean, message: => String): Unit =
macro AssertMacro.messageImpl

/**
* Asserts that boolean values are all true.
*
* Use the [[Expectations.Helpers.clue]] function to investigate any failures.
*/
def all(values: Boolean*): Unit = macro AssertMacro.allImpl
}

private[weaver] object AssertMacro {

/**
* Asserts that several boolean values are true.
*
* If any value evaluates to false, all generated clues are displayed as part
* of the thrown exception.
*/
def allImpl(c: blackbox.Context)(values: c.Tree*): c.Tree = {
import c.universe._
val expectationsTree = ExpectMacro.allImpl(c)(values:_*)
q"_root_.weaver.Assert.throwWhenFailed($expectationsTree)"
}

/**
* Asserts that a boolean value is true.
*
* If the value evaluates to false, the message is displayed as part of the
* thrown exception.
*/
def messageImpl(c: blackbox.Context)(
value: c.Tree,
message: c.Tree): c.Tree = {
import c.universe._
val expectationsTree = ExpectMacro.messageImpl(c)(value, message)
q"_root_.weaver.Assert.throwWhenFailed($expectationsTree)"
}

/**
* Asserts that a boolean value is true.
*
* If the value evaluates to false, an exception is thrown.
*/
def applyImpl(c: blackbox.Context)(value: c.Tree): c.Tree = {
import c.universe._
val expectationsTree = ExpectMacro.applyImpl(c)(value)
q"_root_.weaver.Assert.throwWhenFailed($expectationsTree)"
}
}
75 changes: 75 additions & 0 deletions modules/core/shared/src/main/scala-3/weaver/AssertMacro.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
package weaver

import scala.quoted._
import scala.language.experimental.macros
import weaver.internals.Clues

private[weaver] trait AssertMacro {

/**
* Asserts that a boolean value is true.
*
* Use the [[Expectations.Helpers.clue]] function to investigate any failures.
*/
inline def apply(assertion: Clues ?=> Boolean): Unit =
${ AssertMacro.applyImpl('assertion) }

/**
* Asserts that a boolean value is true and displays a failure message if
* not.
*
* Use the [[Expectations.Helpers.clue]] function to investigate any
* failures.
*/
inline def apply(
assertion: Clues ?=> Boolean,
message: => String): Unit =
${ AssertMacro.applyMessageImpl('assertion, 'message) }

/**
* Asserts that boolean values are all true.
*
* Use the [[Expectations.Helpers.clue]] function to investigate any failures.
*/
inline def all(assertions: (Clues ?=> Boolean)*): Unit =
${ AssertMacro.allImpl('assertions) }
}
private[weaver] object AssertMacro {

/**
* Asserts that a boolean value is true.
*
* If the value evaluates to false, an exception is thrown.
*/
def applyImpl[T: Type](assertion: Expr[Clues ?=> Boolean])(using
q: Quotes): Expr[Unit] = {
val expectations = ExpectMacro.applyImpl[T](assertion)
'{ Assert.throwWhenFailed(${ expectations }) }
}

/**
* Asserts that a boolean value is true.
*
* If the value evaluates to false, the message is displayed as part of the
* thrown exception.
*/
def applyMessageImpl[T: Type](
assertion: Expr[Clues ?=> Boolean],
message: => Expr[String])(using q: Quotes): Expr[Unit] = {
val expectations = ExpectMacro.applyMessageImpl[T](assertion, message)
'{ Assert.throwWhenFailed(${ expectations }) }
}

/**
* Asserts that several boolean values are true.
*
* If any value evaluates to false, all generated clues are displayed as part
* of the thrown exception.
*/
def allImpl[T: Type](assertions: Expr[Seq[(Clues ?=> Boolean)]])(using
q: Quotes): Expr[Unit] = {
val expectations = ExpectMacro.allImpl[T](assertions)
'{ Assert.throwWhenFailed(${ expectations }) }
}

}
15 changes: 15 additions & 0 deletions modules/core/shared/src/main/scala/weaver/Assert.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package weaver

import internals._
import cats.data.Validated

class Assert extends ExpectSame with AssertMacro

object Assert {
private[weaver] def throwWhenFailed(expectations: Expectations): Unit = {
expectations.run match {
case Validated.Invalid(errs) => throw errs.head
case Validated.Valid(()) => ()
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ object Expectations {
* Expect macros
*/
def expect = new Expect
def assert = new Expect
def assert = new Assert

val success: Expectations = Monoid[Expectations].empty

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package weaver
package internals

import cats.Show
import cats.kernel.Eq

private[weaver] trait AssertSame {

def eql[A](
expected: A,
found: A)(
implicit comparisonA: Comparison[A],
loc: SourceLocation): Unit = {
val expectations = ExpectSame.eql(expected, found)(comparisonA, loc)
Assert.throwWhenFailed(expectations)
}

/**
* Same as eql but defaults to universal equality.
*/
def same[A](
expected: A,
found: A)(
implicit comparisonA: Comparison[A] =
Comparison.fromEq[A](Eq.fromUniversalEquals, Show.fromToString),
loc: SourceLocation): Unit = eql(expected, found)(comparisonA, loc)
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,5 @@ private[weaver] trait ExpectSame {
loc: SourceLocation): Expectations =
eql(expected, found)(comparisonA, loc)
}

private[weaver] object ExpectSame extends ExpectSame
39 changes: 39 additions & 0 deletions modules/framework-cats/shared/src/test/scala/AssertionsTests.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package weaver
package framework
package test

import cats.kernel.Eq

object AssertionsTests extends SimpleIOSuite {

pureTest("and") {
assert(1 == 1)
assert(2 == 2)
success
}

pureTest("all") {
assert.all(
1 == 1,
"a" + "b" == "ab",
true || false
)
success
}

pureTest("equality check") {
assert.same("foo", "foo")
}

pureTest("assert.eql respects cats.kernel.Eq") {
implicit val eqInt: Eq[Int] = Eq.allEqual
assert.eql(0, 1)
success
}

pureTest("assert.eql respects weaver.Comparison") {
implicit val comparison: Comparison[Int] = Comparison.fromEq(Eq.allEqual)
assert.eql(0, 1)
success
}
}

0 comments on commit e8c77fd

Please sign in to comment.