Do not follow this link

~eidolon/meager-datagen

Scala [test] data generation library.
Remove year from copyright
Fix copy/paste error
Added ADRs and meagerfile

refs

main
browse  log 

clone

read-only
https://git.sr.ht/~eidolon/meager-datagen
read/write
git@git.sr.ht:~eidolon/meager-datagen

You can also use your local clone with git send-email.

#meager-datagen

ADRs | Meagerfile | License (MIT) | Contributing

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

#Usage

This library is not yet published.

object Meager {
  val Test: ModuleID =
    "meager" %% "meager-datagen-v0" % "0.1.0-SNAPSHOT"
}

#Imports

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

import io.meager.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 io.meager.datagen.v0._
import io.meager.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.

Do not follow this link