Skip to content
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

Relax assertEquals strictness about type equality. #70

Merged
merged 6 commits into from
Mar 20, 2020
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
2 changes: 2 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
* eol=lf
*.png eol=autocrlf
3 changes: 2 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,8 @@ jobs:
steps:
- uses: actions/checkout@v2
- uses: olafurpg/setup-scala@v7
- run: sbt +testsJVM/test
- run: csbt +testsJVM/test
shell: bash
env:
GOOGLE_APPLICATION_CREDENTIALS:
${{ secrets.GOOGLE_APPLICATION_CREDENTIALS }}
Expand Down
2 changes: 1 addition & 1 deletion .jvmopts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
-Xss4m
-Xss2m
-Xms1G
-Xmx2G
-XX:ReservedCodeCacheSize=1024m
Expand Down
1 change: 1 addition & 0 deletions .scalafmt.conf
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
version = "2.3.2"
assumeStandardLibraryStripMargin = true
docstrings = JavaDoc
project.git=true
project.excludeFilters = [
".*scala-3"
Expand Down
21 changes: 15 additions & 6 deletions docs/assertions.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,19 +83,28 @@ Comparing two values of different types is a compile error.
assertEquals(1, "")
```

The two types must match exactly, it's a type error to compare two values even
if one value is a subtype of the other.
The "expected" value (second argument) must be a subtype of the "obtained" value
(first argument).

```scala mdoc
assertEquals(Option(1), Some(1))
```

It's a compile error if you swap the order of the arguments.

```scala mdoc:fail
assertEquals(Some(1), Option(1))
```

Upcast the subtype using a type ascription `subtype: Supertype` when you want to
compare a subtype with a supertype.
Use `assertEquals[Any, Any]` if you really want to compare two different types.

```scala mdoc
// OK
assertEquals(Some(1): Option[Int], Option(1))
val right1: Either[String , Int] = Right(42)
val right2: Either[List[String], Int] = Right(42)
```

```scala mdoc
assertEquals[Any, Any](right1, right2)
```

## `assertNotEquals()`
Expand Down
38 changes: 19 additions & 19 deletions munit/js/src/main/scala/munit/internal/JSIO.scala
Original file line number Diff line number Diff line change
Expand Up @@ -5,30 +5,30 @@ import scala.scalajs.js.annotation.JSImport
import scala.scalajs.js.annotation.JSImport.Namespace

/** Facade for the native nodejs process API
*
* The process object is a global that provides information about, and
* control over, the current Node.js process. As a global, it is always
* available to Node.js applications without using require().
*
* @see https://nodejs.org/api/process.html
*/
*
* The process object is a global that provides information about, and
* control over, the current Node.js process. As a global, it is always
* available to Node.js applications without using require().
*
* @see https://nodejs.org/api/process.html
*/
@js.native
trait JSProcess extends js.Any {
def cwd(): String = js.native
}

/** Facade for native nodejs module "fs".
*
* @see https://nodejs.org/api/fs.html
*/
*
* @see https://nodejs.org/api/fs.html
*/
@js.native
@JSImport("fs", Namespace)
object JSFs extends js.Any {

/** Returns the file contents as Buffer using blocking apis.
*
* NOTE: The actual return value is a Node.js buffer and not js.Array[Int].
* However, both support .length and angle bracket access (foo[1]).
*
* NOTE: The actual return value is a Node.js buffer and not js.Array[Int].
* However, both support .length and angle bracket access (foo[1]).
**/
def readFileSync(path: String): js.Array[Int] = js.native

Expand All @@ -52,9 +52,9 @@ object JSFs extends js.Any {
}

/** Facade for nodejs class fs.Stats.
*
* @see https://nodejs.org/api/fs.html#fs_class_fs_stats
*/
*
* @see https://nodejs.org/api/fs.html#fs_class_fs_stats
*/
@js.native
@JSImport("fs", Namespace)
class JSStats extends js.Any {
Expand All @@ -63,9 +63,9 @@ class JSStats extends js.Any {
}

/** Facade for native nodejs module "path".
*
* @see https://nodejs.org/api/path.html
*/
*
* @see https://nodejs.org/api/path.html
*/
@js.native
@JSImport("path", Namespace)
object JSPath extends js.Any {
Expand Down
21 changes: 20 additions & 1 deletion munit/shared/src/main/scala/munit/Assertions.scala
Original file line number Diff line number Diff line change
Expand Up @@ -72,11 +72,30 @@ trait Assertions extends MacroCompat.CompileErrorMacro {
}
}

/**
* Asserts that two elements are equal using `==` equality.
*
* The "expected" value (second argument) must have the same type or be a
* subtype of the "obtained" value (first argument). For example:
* {{{
* assertEquals(Option(1), Some(1)) // OK
* assertEquals(Some(1), Option(1)) // Error: Option[Int] is not a subtype of Some[Int]
* }}}
*
* Use `assertEquals[Any, Any](a, b)` as an escape hatch to compare two
* values of different types. For example:
* {{{
* val a: Either[List[String], Int] = Right(42)
* val b: Either[String, Int] = Right(42)
* assertEquals[Any, Any](a, b) // OK
* assertEquals(a, b) // Error: Either[String, Int] is not a subtype of Either[List[String], Int]
* }}}
*/
def assertEquals[A, B](
obtained: A,
expected: B,
clue: => Any = "values are not the same"
)(implicit loc: Location, ev: A =:= B): Unit = {
)(implicit loc: Location, ev: B <:< A): Unit = {
StackTraces.dropInside {
if (obtained != expected) {
Diffs.assertNoDiff(
Expand Down
12 changes: 6 additions & 6 deletions munit/shared/src/main/scala/munit/GenericTest.scala
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@ import java.lang.annotation.Annotation
import scala.collection.mutable

/**
* Metadata about a single test case.
*
* @param body the function to be evaluated for this test case.
* @param tags the annotated tags for this test case.
* @param location the file and line number where this test was defined.
*/
* Metadata about a single test case.
*
* @param body the function to be evaluated for this test case.
* @param tags the annotated tags for this test case.
* @param location the file and line number where this test was defined.
*/
class GenericTest[T](
val name: String,
val body: () => T,
Expand Down
4 changes: 2 additions & 2 deletions munit/shared/src/main/scala/munit/Printable.scala
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
package munit

/**
* Override this class to customize the default pretty-printer.
*/
* Override this class to customize the default pretty-printer.
*/
trait Printable {
def print(out: StringBuilder, indent: Int): Unit
}
12 changes: 6 additions & 6 deletions munit/shared/src/main/scala/munit/Printer.scala
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
package munit

/**
* Implement this trait to customize the default printer
*/
* Implement this trait to customize the default printer
*/
trait Printer {

/**
* Pretty-print a single value during pretty printing.
*
* Returns true if this value has been printed, false if FunSuite should fallback to the default pretty-printer.
*/
* Pretty-print a single value during pretty printing.
*
* Returns true if this value has been printed, false if FunSuite should fallback to the default pretty-printer.
*/
def print(value: Any, out: StringBuilder, indent: Int): Boolean
def height: Int = 100
def isMultiline(string: String): Boolean =
Expand Down
24 changes: 12 additions & 12 deletions munit/shared/src/main/scala/munit/Suite.scala
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ import org.junit.runner.RunWith
import scala.concurrent.ExecutionContext

/** The base class for all test suites.
* Extend this class if you don't need the functionality in FunSuite.
*/
* Extend this class if you don't need the functionality in FunSuite.
*/
@RunWith(classOf[MUnitRunner])
abstract class Suite extends PlatformSuite {

Expand All @@ -28,10 +28,10 @@ abstract class Suite extends PlatformSuite {
def munitExecutionContext: ExecutionContext = parasiticExecutionContext

/**
*
* @param name The name of this fixture, used for displaying an error message if
* `beforeAll()` or `afterAll()` fail.
*/
*
* @param name The name of this fixture, used for displaying an error message if
* `beforeAll()` or `afterAll()` fail.
*/
abstract class Fixture[T](val fixtureName: String) {

/** The value produced by this suite-local fixture that can be reused for all test cases. */
Expand All @@ -41,8 +41,8 @@ abstract class Suite extends PlatformSuite {
def beforeAll(): Unit = ()

/** Runs before each individual test case.
* An error in this method aborts the test case.
*/
* An error in this method aborts the test case.
*/
def beforeEach(context: BeforeEach): Unit = ()

/** Runs after each individual test case. */
Expand All @@ -54,16 +54,16 @@ abstract class Suite extends PlatformSuite {
}

/** Runs once before all test cases and before all suite-local fixtures are setup.
* An error in this method aborts the test suite.
*/
* An error in this method aborts the test suite.
*/
def beforeAll(): Unit = ()

/** Runs once after all test cases and after all suite-local fixtures have been tear down. */
def afterAll(): Unit = ()

/** Runs before each individual test case.
* An error in this method aborts the test case.
*/
* An error in this method aborts the test case.
*/
def beforeEach(context: BeforeEach): Unit = ()

/** Runs after each individual test case. */
Expand Down
18 changes: 9 additions & 9 deletions munit/shared/src/main/scala/munit/TestOptions.scala
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
package munit

/**
* Options used when running a test. It can be built implicitly from a [[String]]
* (@see [[munit.TestOptionsConversions]])
*
* @param name the test name, used in the UI and to select it with testOnly
* @param tags a set of [[munit.Tag]], used to attach semantic information to a test
*/
* Options used when running a test. It can be built implicitly from a [[String]]
* (@see [[munit.TestOptionsConversions]])
*
* @param name the test name, used in the UI and to select it with testOnly
* @param tags a set of [[munit.Tag]], used to attach semantic information to a test
*/
final class TestOptions(
val name: String,
val tags: Set[Tag],
Expand Down Expand Up @@ -40,9 +40,9 @@ final class TestOptions(
trait TestOptionsConversions {

/**
* Implicitly create a TestOptions given a test name.
* This allows writing `test("name") { ... }` even if `test` accepts a `TestOptions`
*/
* Implicitly create a TestOptions given a test name.
* This allows writing `test("name") { ... }` even if `test` accepts a `TestOptions`
*/
implicit def testOptionsFromString(
name: String
)(implicit loc: Location): TestOptions =
Expand Down
4 changes: 2 additions & 2 deletions munit/shared/src/main/scala/munit/TestValues.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ package munit
import scala.util.control.NoStackTrace

/**
* Values that have special treatment when evaluating values produced by tests.
*/
* Values that have special treatment when evaluating values produced by tests.
*/
object TestValues {

/** The test failed with the given exception but was ignored but its marked as flaky */
Expand Down
11 changes: 11 additions & 0 deletions tests/shared/src/test/scala/munit/AssertionsSuite.scala
Original file line number Diff line number Diff line change
Expand Up @@ -47,4 +47,15 @@ class AssertionsSuite extends BaseSuite {
|}
|""".stripMargin
)

test("subtype".tag(NoDotty)) {
assertEquals(Option(1), Some(1))
assertNoDiff(
compileErrors("assertEquals(Some(1), Option(1))"),
"""|error: Cannot prove that Option[Int] <:< Some[Int].
|assertEquals(Some(1), Option(1))
| ^
|""".stripMargin
)
}
}