Skip to content

Commit

Permalink
Merge pull request #1023 from RustedBones/java-hash-map
Browse files Browse the repository at this point in the history
Add buildable for java.util.HashMap
  • Loading branch information
satorg authored May 24, 2024
2 parents c8bd5ae + 4fc914c commit 3a5601c
Show file tree
Hide file tree
Showing 5 changed files with 72 additions and 17 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

package org.scalacheck.util

import java.util.ArrayList
import java.util.{ArrayList, HashMap}

import collection.{Map => _, _}
import generic.CanBuildFrom
Expand All @@ -32,6 +32,18 @@ private[util] class ArrayListBuilder[T] extends Builder[T, ArrayList[T]] {
def result(): ArrayList[T] = al
}

private[util] class HashMapBuilder[K, V] extends Builder[(K, V), HashMap[K, V]] {
private val hm = new HashMap[K, V]

def +=(x: (K, V)): this.type = {
val (k, v) = x
hm.put(k, v)
this
}
def clear(): Unit = hm.clear()
def result(): HashMap[K, V] = hm
}

/** CanBuildFrom instances implementing Serializable, so that the objects capturing those can be serializable too.
*/
object SerializableCanBuildFroms {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,12 @@

package org.scalacheck.util

import java.util.ArrayList
import java.util.{ArrayList, HashMap}
import scala.collection.mutable.Builder
import scala.collection.{Map => _, _}

private[util] trait BuildableVersionSpecific {

implicit def buildableFactory[T, C](implicit f: Factory[T, C]): Buildable[T, C] =
new Buildable[T, C] {
def builder = f.newBuilder
Expand All @@ -30,6 +31,17 @@ private[util] class ArrayListBuilder[T] extends Builder[T, ArrayList[T]] {
def result(): ArrayList[T] = al
}

private[util] class HashMapBuilder[K, V] extends Builder[(K, V), HashMap[K, V]] {
private val hm = new HashMap[K, V]
def addOne(x: (K, V)): this.type = {
val (k, v) = x
hm.put(k, v)
this
}
def clear(): Unit = hm.clear()
def result(): HashMap[K, V] = hm
}

/** Factory instances implementing Serializable, so that the objects capturing those can be serializable too.
*/
// Named `...CanBuildFroms` for 2.12 source compatibility (`import SerializableCanBuildFroms._`)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,18 @@ trait Buildable[T, C] extends Serializable {
}

object Buildable extends BuildableVersionSpecific {
import java.util.ArrayList
import java.util.{ArrayList, HashMap}

implicit def buildableArrayList[T]: Buildable[T, ArrayList[T]] =
new Buildable[T, ArrayList[T]] {
def builder: mutable.Builder[T, ArrayList[T]] = new ArrayListBuilder[T]
}

implicit def buildableHashMap[K, V]: Buildable[(K, V), HashMap[K, V]] =
new Buildable[(K, V), HashMap[K, V]] {
def builder = new HashMapBuilder[K, V]
}

def buildableSeq[T]: Buildable[T, Seq[T]] =
new Buildable[T, Seq[T]] {
def builder: mutable.Builder[T, Seq[T]] =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ package util

import scala.collection._

import Buildable._
import ScalaVersionSpecific._

object BuildableSpecification {
Expand All @@ -20,6 +21,11 @@ object BuildableSpecification {
evt: C[String] => Traversable[String]
) = Gen.containerOf[C, String](Gen.alphaStr)

def buildable[C[_, _]](implicit
evb: Buildable[(String, Long), C[String, Long]],
evt: C[String, Long] => Traversable[(String, Long)]
) = Gen.buildableOf[C[String, Long], (String, Long)](Gen.zip(Gen.alphaStr, Gen.long))

implicit val listGen: Gen[List[String]] = container[List]

implicit val streamGen: Gen[Stream[String]] = container[Stream]
Expand Down Expand Up @@ -47,4 +53,17 @@ object BuildableSpecification {
implicit val iterableGen: Gen[immutable.Iterable[String]] = container[immutable.Iterable]

implicit val trieIteratorGen: Gen[immutable.Queue[String]] = container[immutable.Queue]

implicit val mapGen: Gen[Map[String, Long]] = buildable[Map]

Gen.buildableOf[Map[String, Int], (String, Int)](Gen.zip(Gen.alphaStr, Gen.choose(0, 100)))

// java containers
{
import scala.collection.convert.ImplicitConversionsToScala._

implicit val arrayListGen: Gen[java.util.ArrayList[String]] = container[java.util.ArrayList]

implicit val hashMapGen: Gen[java.util.HashMap[String, Long]] = buildable[java.util.HashMap]
}
}
34 changes: 20 additions & 14 deletions doc/UserGuide.md
Original file line number Diff line number Diff line change
Expand Up @@ -468,32 +468,38 @@ value ultimately reported as failing might not satisfy the condition given to
case that does. To avoid confusion, the corresponding shrink for the type can
use `suchThat` method too.

#### Generating Containers
#### Generating Buildables and Containers

There is a special generator, `Gen.containerOf`, that generates containers such
as lists and arrays. They take another generator as argument, that is
responsible for generating the individual items. You can use it in the
following way:
There are special generators
* `Gen.buildableOf`, that generates any buildable collection
* `Gen.containerOf`, a convenience method for single parameter buildable like lists and arrays

```scala
val genIntList = Gen.containerOf[List,Int](Gen.oneOf(1, 3, 5))
They take another generator as argument, that is responsible for generating the individual items.
You can use it in the following way:

val genStringLazyList = Gen.containerOf[LazyList,String](Gen.alphaStr)
```scala
val genInt: Gen[Int] = Gen.oneOf(1, 3, 5)
val genIntList = Gen.containerOf[List, Int](genInt)
val genStringLazyList = Gen.containerOf[LazyList, String](Gen.alphaStr)
val genBoolArray = Gen.containerOf[Array, Boolean](Gen.const(true))

val genBoolArray = Gen.containerOf[Array,Boolean](true)
val genTuple: Gen[(String, Int)] = Gen.zip(Gen.alphaStr, Gen.choose(0, 100))
val genMap = Gen.buildableOf[Map[String, Int], (String, Int)](genTuple)
```

By default, ScalaCheck supports generation of `List`, `Stream` (Scala 2.10 -
2.12, deprecated in 2.13), `LazyList` (Scala 2.13), `Set`, `Array`, and
`ArrayList` (from `java.util`). You can add support for additional containers
by adding implicit `Buildable` instances. See `Buildable.scala` for examples.
2.12, deprecated in 2.13), `LazyList` (Scala 2.13), `Set`, `Array` and `Map`.
Additionally, ScalaCheck can generate `java.util.ArrayList` and `java.util.HashMap` when an implicit
`Traversable` conversion evidence is in scope.

You can add support for additional containers by adding implicit `Buildable` instances.
See `Buildable.scala` for examples.

There is also `Gen.nonEmptyContainerOf` for generating non-empty containers, and
`Gen.containerOfN` for generating containers of a given size.

To generate a container by picking an arbitrary number of elements use
`Gen.someOf`, or by picking one or more elements with
`Gen.atLeastOne`.
`Gen.someOf`, or by picking one or more elements with `Gen.atLeastOne`.

```scala
val zeroOrMoreDigits = Gen.someOf(1 to 9)
Expand Down

0 comments on commit 3a5601c

Please sign in to comment.