Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

'should contain allOf' on java.util.Map?

How do I do a contains allOf assertion on a Java Map?

The following did not work

val testMap = new java.util.LinkedHashMap[Int, Int]()
testMap.put(1,2)
testMap.put(2,4)
testMap.put(3,6)
testMap should contain allOf (1->2, 2->4, 3->6)

it gives

{1=2, 2=4, 3=6} did not contain all of ((1,2), (2,4), (3,6))

The docs say

The Aggregating companion object provides implicit instances of Aggregating[L] for types GenTraversable[E], java.util.Collection[E], java.util.Map[K, V], String, Array[E].

— http://www.scalatest.org/user_guide/using_matchers#workingWithAggregations

What am I doing wrong?

Scala     v2.11
ScalaTest v3.1.1
like image 848
Gabriel Avatar asked Sep 05 '25 07:09

Gabriel


2 Answers

Alternatively consider CollectionConverters

import scala.jdk.CollectionConverters._
testMap.asScala should contain allOf (1->2, 2->4, 3->6)

If we wish to maintain the following DSL

testMap should contain allOf (1->2, 2->4, 3->6)

then we could provide a custom instance of Aggregating typeclass which compares equality of Entry with Scala tuples

trait JavaMapHelpers {
  def javaEntryEqualsScalaTuple[K, V]: Equality[java.util.Map.Entry[K, V]] =
    (a: java.util.Map.Entry[K, V], b: Any) => b match {
      case (k, v) => a.getKey == k && a.getValue == v
      case _ => false
    }

  implicit def aggregatingNatureOfJavaMapWithScalaTuples[K, V, JMAP[k, v] <: java.util.Map[k, v]]: Aggregating[JMAP[K, V]] =
    Aggregating.aggregatingNatureOfJavaMap(javaEntryEqualsScalaTuple)

  def javaMap[K, V](elements: (K, V)*): java.util.LinkedHashMap[K, V] = {
    val m = new java.util.LinkedHashMap[K, V]
    elements.foreach(e => m.put(e._1, e._2))
    m
  }
}


class JavaMapSpec extends AnyFlatSpec with Matchers with JavaMapHelpers {
  "Java Map" should "be checkable with Scala tuples" in {
    javaMap((1,2), (2,4), (3,6)) should contain allOf (1->2, 2->4, 3->6)
  }
}

Defining custom equality which compares Java Entry with Scala tuple works because under the hood containsAllOf calls entrySet on Java map and then checks with provided Equality

def containsAllOf(map: JMAP[K, V], elements: scala.collection.Seq[Any]): Boolean = {
  checkAllOf(map.entrySet.asScala, elements, equality)
}
like image 107
Mario Galic Avatar answered Sep 07 '25 20:09

Mario Galic


One difference to note between the syntax supported on Java and Scala collections is that in Java, Map is not a subtype of Collection, and does not actually define an element type. You can ask a Java Map for an "entry set" via the entrySet method, which will return the Map's key/value pairs wrapped in a set of java.util.Map.Entry, but a Map is not actually a collection of Entry. To make Java Maps easier to work with, however, ScalaTest matchers allows you to treat a Java Map as a collection of Entry, and defines a convenience implementation of java.util.Map.Entry in org.scalatest.Entry. — http://www.scalatest.org/user_guide/using_matchers#javaCollectionsAndMaps

Try:

val testMap = new java.util.LinkedHashMap[Int, Int]()
testMap.put(1,2)
testMap.put(2,4)
testMap.put(3,6)
testMap should contain allOf (Entry(1, 2), Entry(2, 4), Entry(3, 6))
like image 24
Gabriel Avatar answered Sep 07 '25 21:09

Gabriel