Random data generators for Scala 3.
Find a file
Pat Garrity 2982d729bf
All checks were successful
/ Build and Release Library (push) Successful in 1m59s
(minor) Version updates, ScalaDoc, bug fixes. (#6)
Reviewed-on: #6
2025-03-23 20:02:08 +00:00
.forgejo/workflows (patch) Add automated builds to the project (#1) 2024-05-01 01:31:13 +00:00
modules/core/src (minor) Version updates, ScalaDoc, bug fixes. (#6) 2025-03-23 20:02:08 +00:00
project (minor) Version updates, ScalaDoc, bug fixes. (#6) 2025-03-23 20:02:08 +00:00
.gitignore Initializing repository with last-known-good implementation of datagen. 2024-04-30 20:24:15 -05:00
.pre-commit-config.yaml (patch) testing coursier (#2) 2024-05-01 02:35:41 +00:00
.scalafmt.conf (patch) Update readme, force build for prior merge. (#4) 2024-06-24 02:44:52 +00:00
build.sbt (minor) Version updates, ScalaDoc, bug fixes. (#6) 2025-03-23 20:02:08 +00:00
LICENSE Initializing repository with last-known-good implementation of datagen. 2024-04-30 20:24:15 -05:00
README.md (patch) Update readme, force build for prior merge. (#4) 2024-06-24 02:44:52 +00:00

gs-datagen

GS Open Source | License (MIT)

Test data generation library for Scala 3. gs-datagen provides composable generator definitions that can be reused across tests.

Usage

Dependency

object Gs {
  val Datagen: ModuleID =
    "gs" %% "gs-datagen-core-v0" % "$VERSION"
}

Imports

The standard way to use gs-datagen is to import the entire package, which pulls in Gen[A], Generated[A] and Datagen[A, -I]:

import gs.datagen.v0._

Examples

For the following examples, the following types (abbreviated) are relevant:

opaque type Name = String
opaque type DateOfBirth = LocalDate
opaque type Karma = Long

enum Role:
  case Regular, Mod, Admin

case class User(
  name: Name,
  dateOfBirth: DateOfBirth,
  karma: Karma,
  role: Role
)

Example: Generate a Random User

One way to go about this is to define generators for each type and then compose those generators for User:

import gs.datagen.v0._
import gs.datagen.v0.generators.MinMax

val nameGen: Gen[Name] =
  Gen.string.alpha(4, 16).map(Name(_))

val dateOfBirthGen: Gen[LocalDate] =
  Gen.date.beforeToday(
    days = MinMax.Zero,
    months = MinMax.nonNegative(0, 11),
    years = MinMax.nonNegative(18, 80)
  ).map(DateOfBirth(_))

val karmaGen: Gen[Karma] =
  Gen.long.inRange(-100L, 100L).map(Karma(_))

val roleGen: Gen[Role] =
  Gen.oneOf.fixedChoices(Role.Regular, Role.Mod, Role.Admin)

and the composition:

val userGen: Gen[User] =
  for
    name <- nameGen
    dateOfBirth <- dateOfBirthGen
    karma <- karmaGen
    role <- roleGen
  yield User(name, dateOfBirth, karma, role)

Generators may also be defined inline if separate definitions are not useful:

val userGen: Gen[User] =
  for
    name <- Gen.string.alpha(4, 16).map(Name(_))
    dateOfBirth <- dateOfBirthGen
    karma <- Gen.long.inRange(-100L, 100L).map(Karma(_))
    role <- roleGen
  yield User(name, dateOfBirth, karma, role)

Once that generator exists, users may be generated:

val user: User = userGen.gen()

The Generated type class can be used as well:

given Generated[User] = Generated.of(userGen)

val user2: User = Generated[User].generate()

Example: Require Input

What if we want a way to generate users randomly, but always require the caller to specify a user role? This can be accomplished by requiring input when generating data:

val roleUserGen: Datagen[User, Role] =
  for
    name <- Gen.string.alpha(4, 16).map(Name(_))
    dateOfBirth <- dateOfBirthGen
    karma <- Gen.long.inRange(-100L, 100L).map(Karma(_))
  yield (role: Role) => User(name, dateOfBirth, karma, role)

The usage of this type is different and does not support Generated:

val admin: User = roleUserGen.generate(Role.Admin)
val mod: User = roleUserGen.generate(Role.Mod)
val regular: User = roleUserGen.generate(Role.Regular)

Supported Generators

For a complete list of generators supported out of the box, please refer to the Gen definition, which enumerates and documents all options.

Donate

Enjoy this project or want to help me achieve my goals? Consider Donating to Pat on Ko-fi.