-
Notifications
You must be signed in to change notification settings - Fork 8
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Replace expecty with clue #64
Conversation
6f24200
to
1bda9bb
Compare
1bda9bb
to
e6bc0a6
Compare
import c.universe._ | ||
|
||
def fromContext: Tree = { | ||
def fromContext: c.Tree = { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
"This function can only be used within `expect` or `assert`.") | ||
final def clue[A](@unused a: Clue[A]): A = { | ||
// This function is removed as part of the `expect` macro expansion. | ||
throw new Error("compileTimeOnly annotation not respected! This is likely to be a bug in weaver-test. Report it at https://github.com/typelevel/weaver-test/issues/new") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
override def transform(input: Tree): Tree = input match { | ||
case c.universe.Apply(fun, List(clueValue)) | ||
if fun.symbol == clueMethodSymbol => | ||
val transformedClueValue = super.transform(clueValue) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm curious about this transformation here. Can you explain ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Of course!
For context, the user writes clue(x)
where clue
refers to ClueHelpers.clue
. There's an implicit conversion from x
to a Clue
. Explicitly, this is written as clue(Clue.generateClue(x))
.
The transformation replaces ClueHelpers.clue
with addClue
on a clues collection. In other words, it replaces:
clue(Clue.generateClue(x))
with clues.addClue(Clue.generateClue(x))
.
The clues collection is generated as part of the overall expect
macro. For example:
expect(clue(List(x, clue(y))))
becomes
expect {
val clues = new Clues()
clues.addClue(List(x, clues.addClue(y)))
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
oh gotcha, hadn't thought of nested clues, but it makes sense 👍
This is great ! Thank you so much for taking that on !🥇 I just have a minor question, but I'm happy with the code, tests, and documentation. |
This PR replaces expecty with an munit-like
clue
function.It uses macros to generate clues. Unlike munit, clues are stored locally to the expect call. This avoids the need for a global lock, and means tests can run concurrently, and add clues, without relying on any extra concurrency primitives.
It assumes that the code within an expect call is synchronous.
The behaviour is identical for Scala 2 and 3, but the macros are implemented differently.
Note that the signatures for
expect
aren't identical for Scala 2 and 3. The Scala 3expect
functions use context functions.Behaviour
A user can write:
and will see the following on test failure:
They can also nest calls to
clue
:Scala 2 implementation
The Scala 2 implementation has a couple of macros:
ClueMacro
generates a clue for a value expression. This is identical to munit's clue macro.ExpectMacro
constructs a local collection ofClues
. Calls to theclue
function are rewritten to call theaddClue
function of the local collection.Scala 3 implementation
In Scala 3, we can use context functions to provide the
Clues
collection. It still has a couple of macros:ClueMacro
generates a clue for a value expression using simpler logic for obtaining the source code and type.ExpectMacro
gets the source location to ensure that the tracing behaviour ofexpect
is the same as it was previously. Calls toclue
don't need to be rewritten.