Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/faqs/directory.conf
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@ laika.navigationOrder = [
typelevel_stewardship.md
ide_faqs.md,
other_effects.md
expecty_removal.md
]
30 changes: 30 additions & 0 deletions docs/faqs/expecty_removal.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
Why are my error messages worse ?
=====================================

Weaver `0.9.0` reduced the error reporting power of `expect`.

Prior to `0.9.0`, `expect` would capture the values of its contents on failure. This used the [expecty](https://github.com/eed3si9n/expecty/) macro library to introspect code. While the macro behaved well in most cases, it came with a high maintenance burden. Users reported many bugs in the Scala 3 implementation that were non-trivial to fix.

As the stewardship of weaver moved to Typelevel, it was decided to cut the cord with expecty in order to eliminate this maintenance burden, and to bring in `clue` (inspired from munit) as a much simpler alternative.

Expecty's error messages were useful, and this decision may be disappointing for users. However, it will allow maintainers to focus on improving other aspects of weaver.

## How can I improve my error messages?

You can rewrite your `expect` assertions into `expect.same` calls, and add `clue` to any remaining assertions.

We recommend you do this automatically by [applying a scalafix rule](https://scalacenter.github.io/scalafix/docs/rules/external-rules.html).

Run the `RewriteExpect` rule to rewrite `expect` and `expect.all` into assertions with better failure messages.

```sh
sbt scalafixAll github:typelevel/weaver-test/RewriteExpect?sha=@VERSION@
```

Run the `AddClueToExpect` rule to add `clue` calls to the remaining `expect` assertions.

```sh
sbt scalafixAll github:typelevel/weaver-test/AddClueToExpect?sha=@VERSION@
```

Your failure messages will now include the values captured in `clue`.
26 changes: 26 additions & 0 deletions scalafix/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,29 @@ To develop rule:
sbt ~tests/test
# edit rules/src/main/scala/fix/RenameAssertToExpect.scala
```

## Exploring symbols for the `SymbolMatcher`

Create an input file containing the symbol.

```
# create v0_9_0/input/src/main/scala/fix/AddClueToExpectTest.scala
```

Compile the code

```
sbt compile
```

Find the corresponding `.semanticdb` file.

```
ls v0_9_0/input/target/jvm-3/meta/META-INF/semanticdb/v0_9_0/input/src/main/scala/fix/AddClueToExpectTest.scala.semanticdb
```

Explore the symbols using the [metap](https://scalameta.org/docs/semanticdb/guide.html#installation) tool.

```
metap v0_9_0/input/target/jvm-3/meta/META-INF/semanticdb/v0_9_0/input/src/main/scala/fix/AddClueToExpectTest.scala.semanticdb
```
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
fix.RenameAssertToExpect
fix.RenameExpectToExpectSame
fix.RewriteExpect
fix.AddClueToExpect
70 changes: 43 additions & 27 deletions scalafix/rules/src/main/scala/fix/AddClueToExpect.scala
Original file line number Diff line number Diff line change
Expand Up @@ -8,34 +8,17 @@ class AddClueToExpect extends SemanticRule("AddClueToExpect") {
override def fix(implicit doc: SemanticDocument): Patch = {
val expectMethod =
SymbolMatcher.normalized("weaver/Expectations.Helpers#expect.")
val expectAllMethod = SymbolMatcher.normalized("weaver/ExpectMacro#all().")

doc.tree.collect {
case expectMethod(tree) =>
val clues = tree.collect {
case q"clue" => ()
}
if (clues.isEmpty) {
tree match {
case q"expect($lhs $op $rhs)" =>
Patch.replaceTree(
tree,
s"expect(${makeClue(lhs)} $op ${makeClue(rhs)})")
case q"expect($lhs.$op(...$exprss))" =>
val clues = exprss.map(_.map(makeClue))
Patch.replaceTree(
tree,
q"expect(${makeClue(lhs)}.$op(...$clues))".toString)
case q"expect($op(...$exprss))" =>
val clues = exprss.map(_.map(makeClue))
Patch.replaceTree(tree, q"expect($op(...$clues))".toString)
case q"expect" =>
Patch.empty
case other =>
println(s"Ignoring $other")
Patch.empty
}
} else {
Patch.empty
}
case Term.Apply.After_4_6_0(expectMethod(_),
Term.ArgClause(List(tree), _)) =>
Patch.replaceTree(tree, addClues(tree).toString)
case Term.Apply.After_4_6_0(expectAllMethod(_),
Term.ArgClause(trees, _)) =>
trees.map { tree =>
Patch.replaceTree(tree, addClues(tree).toString)
}.asPatch
}.asPatch
}

Expand All @@ -47,4 +30,37 @@ class AddClueToExpect extends SemanticRule("AddClueToExpect") {
case _ => q"clue($expr)"
}
}

private def addClues(tree: Tree)(implicit doc: SemanticDocument): Tree = {
val clueSymbol =
SymbolMatcher.normalized("weaver/internals/ClueHelpers#clue().")
val clues = tree.collect {
case clueSymbol(_) => ()
}
if (clues.isEmpty) {
tree match {
case q"$lhs $op $rhs" =>
q"${makeClue(lhs)} $op ${makeClue(rhs)}"
case q"$lhs.$op(...$exprss)" =>
val clues = exprss.map(_.map(makeClue))
q"${makeClue(lhs)}.$op(...$clues)"
case q"!$lhs.$op(...$exprss)" =>
val clues = exprss.map(_.map(makeClue))
q"!${makeClue(lhs)}.$op(...$clues)"
case q"$expr.$op[..$tpes]" =>
q"${makeClue(expr)}.$op[..$tpes]"
case q"!$expr.$op[..$tpes]" =>
q"!${makeClue(expr)}.$op[..$tpes]"
case q"!$op(...$exprss)" =>
val clues = exprss.map(_.map(makeClue))
q"!$op(...$clues)"
case q"$op(...$exprss)" =>
val clues = exprss.map(_.map(makeClue))
q"$op(...$clues)"
case other => other
}
} else {
tree
}
}
}
22 changes: 0 additions & 22 deletions scalafix/rules/src/main/scala/fix/RenameExpectToExpectSame.scala

This file was deleted.

Loading