diff --git a/munit-docs/src/main/scala/docs/MUnitModifier.scala b/munit-docs/src/main/scala/docs/MUnitModifier.scala index 20621b98..3e2dc547 100644 --- a/munit-docs/src/main/scala/docs/MUnitModifier.scala +++ b/munit-docs/src/main/scala/docs/MUnitModifier.scala @@ -11,7 +11,6 @@ import scala.collection.mutable import scala.collection.JavaConverters._ import com.google.cloud.storage.Blob import java.io.ByteArrayOutputStream -import munit.sbtmunit.MUnitTestReport import com.google.gson.Gson import java.nio.charset.StandardCharsets import munit.sbtmunit.MUnitTestReport diff --git a/munit/shared/src/main/scala/munit/Assertions.scala b/munit/shared/src/main/scala/munit/Assertions.scala index 72dee803..d6810c21 100644 --- a/munit/shared/src/main/scala/munit/Assertions.scala +++ b/munit/shared/src/main/scala/munit/Assertions.scala @@ -67,7 +67,7 @@ trait Assertions extends MacroCompat.CompileErrorMacro { )(implicit loc: Location, ev: A =:= B): Unit = { StackTraces.dropInside { if (obtained == expected) { - fail(munitPrint(clue)) + fail(s"${munitPrint(clue)} expected same: $expected was not: $obtained") } } } @@ -120,6 +120,46 @@ trait Assertions extends MacroCompat.CompileErrorMacro { } } + /** + * Asserts that two doubles are equal to within a positive delta. + * If the expected value is infinity then the delta value is ignored. + * NaNs are considered equal: assertEquals(Double.NaN, Double.NaN, *) passes. + */ + def assertEqualsDouble( + obtained: Double, + expected: Double, + delta: Double, + clue: => Any = "values are not the same" + )(implicit loc: Location): Unit = { + StackTraces.dropInside { + val exactlyTheSame = java.lang.Double.compare(expected, obtained) == 0 + val almostTheSame = Math.abs(expected - obtained) <= delta + if (!exactlyTheSame && !almostTheSame) { + fail(s"${munitPrint(clue)} expected: $expected but was: $obtained") + } + } + } + + /** + * Asserts that two floats are equal to within a positive delta. + * If the expected value is infinity then the delta value is ignored. + * NaNs are considered equal: assertEquals(Float.NaN, Float.NaN, *) passes. + */ + def assertEqualsFloat( + obtained: Float, + expected: Float, + delta: Float, + clue: => Any = "values are not the same" + )(implicit loc: Location): Unit = { + StackTraces.dropInside { + val exactlyTheSame = java.lang.Float.compare(expected, obtained) == 0 + val almostTheSame = Math.abs(expected - obtained) <= delta + if (!exactlyTheSame && !almostTheSame) { + fail(s"${munitPrint(clue)} expected: $expected but was: $obtained") + } + } + } + def intercept[T <: Throwable]( body: => Any )(implicit T: ClassTag[T], loc: Location): T = { diff --git a/tests/shared/src/test/scala/munit/DoubleAssertionsFrameworkSuite.scala b/tests/shared/src/test/scala/munit/DoubleAssertionsFrameworkSuite.scala new file mode 100644 index 00000000..c564c3ed --- /dev/null +++ b/tests/shared/src/test/scala/munit/DoubleAssertionsFrameworkSuite.scala @@ -0,0 +1,76 @@ +package munit + +class DoubleAssertionsFrameworkSuite extends BaseSuite { + test("Assert Equals NaN Fails".fail) { + assertEqualsDouble(1.234, Double.NaN, 0.0) + } + + test("Assert NaN Equals Fails".fail) { + assertEqualsDouble(Double.NaN, 1.234, 0.0) + } + + test("Assert NaN Equals NaN") { + assertEqualsDouble(Double.NaN, Double.NaN, 0.0) + } + + test("Assert Pos Infinity Not Equals Neg Infinity".fail) { + assertEqualsDouble(Double.PositiveInfinity, Double.NegativeInfinity, 0.0) + } + + test("Assert Pos Infinity Not Equals".fail) { + assertEqualsDouble(Double.PositiveInfinity, 1.23, 0.0) + } + + test("Assert Pos Infinity Equals Infinity") { + assertEqualsDouble(Double.PositiveInfinity, Double.PositiveInfinity, 0.0) + } + + test("Assert Neg Infinity Equals Infinity") { + assertEqualsDouble(Double.NegativeInfinity, Double.NegativeInfinity, 0.0) + } + + test("All Infinities") { + assertEqualsDouble( + Double.PositiveInfinity, + Double.NegativeInfinity, + Double.PositiveInfinity + ) + } + + // And now, the same with floats... + test("Assert Equals NaN Fails".fail) { + assertEqualsFloat(1.234f, Float.NaN, 0.0f) + } + + test("Assert NaN Equals Fails".fail) { + assertEqualsFloat(Float.NaN, 1.234f, 0.0f) + } + + test("Assert NaN Equals NaN") { + assertEqualsFloat(Float.NaN, Float.NaN, 0.0f) + } + + test("Assert Pos Infinity Not Equals Neg Infinity".fail) { + assertEqualsFloat(Float.PositiveInfinity, Float.NegativeInfinity, 0.0f) + } + + test("Assert Pos Infinity Not Equals".fail) { + assertEqualsFloat(Float.PositiveInfinity, 1.23f, 0.0f) + } + + test("Assert Pos Infinity Equals Infinity") { + assertEqualsFloat(Float.PositiveInfinity, Float.PositiveInfinity, 0.0f) + } + + test("Assert Neg Infinity Equals Infinity") { + assertEqualsFloat(Float.NegativeInfinity, Float.NegativeInfinity, 0.0f) + } + + test("All Infinities") { + assertEqualsFloat( + Float.PositiveInfinity, + Float.NegativeInfinity, + Float.PositiveInfinity + ) + } +}