diff --git a/matcher-extra/jvm/src/test/scala/org/specs2/matcher/FilesContentMatchersSpec.scala b/matcher-extra/jvm/src/test/scala/org/specs2/matcher/FilesContentMatchersSpec.scala index 544dca482c..a91fdb641b 100644 --- a/matcher-extra/jvm/src/test/scala/org/specs2/matcher/FilesContentMatchersSpec.scala +++ b/matcher-extra/jvm/src/test/scala/org/specs2/matcher/FilesContentMatchersSpec.scala @@ -119,8 +119,7 @@ class FilesContentMatchersSpec extends Spec with FilesContentMatchers with Befor |MD5 mismatch: |file | MD5 |${(targetDir / actual / sub | f2).path} | 4392ebd49e53e2cfe36abb22e39601db - |${(targetDir / expected2 / sub | f2).path} | 1b7b2f1969fee054225ad6bbf7f6bdd7 - |""".stripMargin.replace(" ", "") + |${(targetDir / expected2 / sub | f2).path} | 1b7b2f1969fee054225ad6bbf7f6bdd7""".stripMargin.replace(" ", "") val targetDir: DirectoryPath = "target" / "test" / FileName.unsafe("fcm-" + hashCode) diff --git a/matcher/shared/src/main/scala/org/specs2/matcher/TraversableMatchers.scala b/matcher/shared/src/main/scala/org/specs2/matcher/TraversableMatchers.scala index a84990a8a4..6ec385e72a 100644 --- a/matcher/shared/src/main/scala/org/specs2/matcher/TraversableMatchers.scala +++ b/matcher/shared/src/main/scala/org/specs2/matcher/TraversableMatchers.scala @@ -446,7 +446,7 @@ import text.Plural.* case class ContainWithResult[T]( check: ValueCheck[T], - timesMin: Option[Times] = Some(1.times), + timesMin: Option[Times] = Some(Times(1)), timesMax: Option[Times] = None, checkAll: Boolean = true, negate: Boolean = false @@ -472,11 +472,18 @@ case class ContainWithResult[T]( failures.collect { case Failure(_, _, _, d) if d != NoDetails => d }.headOption.getOrElse(NoDetails) (timesMin, timesMax) match - case (None, None) => Result.result(successes.size == seq.size, koMessage, details) - case (Some(Times(min)), None) => Result.result(successes.size >= min, koMessage, details) - case (None, Some(Times(max))) => Result.result(successes.size <= max, koMessage, details) + case (None, None) => Result.result(successes.size == seq.size, koMessage, details) + case (Some(Times(min)), None) => + val message = koMessage + s"""\nNumber of successful matches: ${successes.size}. Expected: at least $min""" + Result.result(successes.size >= min, message, details) + case (None, Some(Times(max))) => + val message = koMessage + s"""\nNumber of successful matches: ${successes.size}. Expected: at most $max""" + Result.result(successes.size <= max, message, details) case (Some(Times(min)), Some(Times(max))) => - Result.result(successes.size >= min && successes.size <= max, koMessage, details) + val expected = + if min == max then s"exactly $min" else if min == 1 then s"at most $max" else s"between $min and $max" + val message = koMessage + s"""\nNumber of successful matches: ${successes.size}. Expected: $expected""" + Result.result(successes.size >= min && successes.size <= max, message, details) } if negate then Result.result(!r.isSuccess, "Expectation failed:\n" + r.message) @@ -500,11 +507,15 @@ case class ContainWithResult[T]( def foreach = copy(timesMin = None, timesMax = None) private def messages[S <: Traversable[T]](expectable: String, successes: Seq[Result], failures: Seq[Result]) = + def equalValueCheckMessages(expected: Any) = + val containsMessage = s"$expectable contains $expected" + val doesNotContainMessage = s"$expectable does not contain $expected" + (containsMessage, if successes.isEmpty then doesNotContainMessage else containsMessage) + check match - case BeEqualTypedValueCheck(expected) => - (s"$expectable contains $expected", s"$expectable does not contain $expected") - case BeEqualValueCheck(expected) => (s"$expectable contains $expected", s"$expectable does not contain $expected") - case _ => genericMessages(expectable, successes, failures) + case BeEqualTypedValueCheck(expected) => equalValueCheckMessages(expected) + case BeEqualValueCheck(expected) => equalValueCheckMessages(expected) + case _ => genericMessages(expectable, successes, failures) private def genericMessages( expectable: String, @@ -512,13 +523,13 @@ case class ContainWithResult[T]( failures: scala.collection.Seq[Result] ) = def elementsAre(results: scala.collection.Seq[Result], success: Boolean) = - if results.isEmpty then s"There are no matches" + if results.isEmpty then (if success then "There are no matches" else "There are no failures") else if results.size <= 1 then s"There is ${results.size} ${if success then "success" else "failure"}" else s"There are ${results.size} ${if success then "successes" else "failures"}" def messages(results: scala.collection.Seq[Result]) = if results.isEmpty then "" - else results.map(_.message).mkString("\n", "\n", "\n") + else results.map(_.message).mkString("\n", "\n", "") ( elementsAre(successes, success = true) + messages(successes), diff --git a/tests/jvm/src/test/scala/org/specs2/matcher/MatcherSpec.scala b/tests/jvm/src/test/scala/org/specs2/matcher/MatcherSpec.scala index 5dcff443f9..03de245ae0 100644 --- a/tests/jvm/src/test/scala/org/specs2/matcher/MatcherSpec.scala +++ b/tests/jvm/src/test/scala/org/specs2/matcher/MatcherSpec.scala @@ -112,7 +112,7 @@ Messages def collection2 = def beEven: Matcher[Int] = (i: Int) => (i % 2 == 0, i.toString + " is odd") - foreach(Seq(1, 2, 3))((i: Int) => i must beEven) returns "There are 2 failures\n1 is odd\n3 is odd\n" + foreach(Seq(1, 2, 3))((i: Int) => i must beEven) returns "There are 2 failures\n1 is odd\n3 is odd" def messages1 = def beEven: Matcher[Int] = (i: Int) => (i % 2 == 0, i.toString + " is odd") diff --git a/tests/shared/src/test/scala/org/specs2/matcher/TraversableMatchersSpec.scala b/tests/shared/src/test/scala/org/specs2/matcher/TraversableMatchersSpec.scala index b61aadcc07..4e4024cf3f 100644 --- a/tests/shared/src/test/scala/org/specs2/matcher/TraversableMatchersSpec.scala +++ b/tests/shared/src/test/scala/org/specs2/matcher/TraversableMatchersSpec.scala @@ -37,6 +37,11 @@ class TraversableMatchersSpec(val env: Env) extends Specification with ResultMat ${(Seq(1, 2, 3) must not(contain(be_>=(2)))) returns "Expectation failed:\nThere is 1 failure\n1 is strictly less than 2"} ${(Seq(1, 2, 3) must contain(be_>=(3)) .atLeast(2.times)) returns "There are 2 failures\n1 is strictly less than 3\n2 is strictly less than 3\n"} + ${(Seq(1, 2, 3) must contain(be_>=(3)).atLeast(2.times)) returns "There are 2 failures\n1 is strictly less than 3\n2 is strictly less than 3\nNumber of successful matches: 1. Expected: at least 2"} + ${(Seq(1, 2, 3) must contain(be_>=(1)).atMost(2.times)) returns "There are no failures\nNumber of successful matches: 3. Expected: at most 2"} + ${(Seq(1, 2, 3) must contain(be_>=(3)).exactly(2.times)) returns "There are 2 failures\n1 is strictly less than 3\n2 is strictly less than 3\nNumber of successful matches: 1. Expected: exactly 2"} + ${(Seq(1, 2, 3, 4) must contain(be_>=(2)).atMost(2.times)) returns "There is 1 failure\n1 is strictly less than 2\nNumber of successful matches: 3. Expected: at most 2"} + ${(Seq(1, 1, 2, 3) must contain(===(1)).exactly(1.times)) returns "There are 2 failures\n2 != 1\n3 != 1\nNumber of successful matches: 2. Expected: exactly 1"} We can compare a collection to another by using matchers