diff --git a/build.sbt b/build.sbt index 5f090e3..c26ed57 100644 --- a/build.sbt +++ b/build.sbt @@ -1,4 +1,4 @@ -val scala3: String = "3.4.1" +val scala3: String = "3.4.2" ThisBuild / scalaVersion := scala3 ThisBuild / versionScheme := Some("semver-spec") @@ -22,7 +22,7 @@ val sharedSettings = Seq( lazy val testSettings = Seq( libraryDependencies ++= Seq( - "org.scalameta" %% "munit" % "1.0.0-M12" % Test + "org.scalameta" %% "munit" % "1.0.0" % Test ) ) @@ -39,6 +39,6 @@ lazy val core = project .settings(name := s"${gsProjectName.value}-core-v${semVerMajor.value}") .settings( libraryDependencies ++= Seq( - "gs" %% "gs-uuid-v0" % "0.2.3" + "gs" %% "gs-uuid-v0" % "0.2.4" ) ) diff --git a/modules/core/src/main/scala/gs/datagen/v0/gen.scala b/modules/core/src/main/scala/gs/datagen/v0/gen.scala index 637110b..84e3f07 100644 --- a/modules/core/src/main/scala/gs/datagen/v0/gen.scala +++ b/modules/core/src/main/scala/gs/datagen/v0/gen.scala @@ -1,6 +1,7 @@ package gs.datagen.v0 import gs.datagen.v0.generators.Alphabet +import gs.datagen.v0.generators.GenBool import gs.datagen.v0.generators.GenFiniteDuration import gs.datagen.v0.generators.GenInteger import gs.datagen.v0.generators.GenList @@ -9,6 +10,7 @@ import gs.datagen.v0.generators.GenLong import gs.datagen.v0.generators.GenMap import gs.datagen.v0.generators.GenOneOf import gs.datagen.v0.generators.GenOneOfGen +import gs.datagen.v0.generators.GenOption import gs.datagen.v0.generators.GenSet import gs.datagen.v0.generators.GenString import gs.datagen.v0.generators.GenUUID @@ -88,6 +90,61 @@ object Gen: */ def single[A](value: A): Gen[A] = Datagen.pure(value) + /** Generator which produces Boolean values. + * + * @return + * New generator that randomly produces true/false. + */ + def boolean(): Gen[Boolean] = new GenBool() + + object option: + + /** Generator that will randomly determine whether `Some` or `None` is + * returned for the given underlying generator. + * + * @param generator + * The generator that populates the content. + * @return + * The generator for the optional content. + */ + def apply[A](generator: Gen[A]): Gen[Option[A]] = + GenOption[A](generator) + + /** Generator that will randomly determine whether `Some` or `None` is + * returned for the given underlying generator. + * + * @param generator + * The generator that populates the content. + * @return + * The generator for the optional content. + */ + def random[A](generator: Gen[A]): Gen[Option[A]] = + apply(generator) + + /** Generator that will always return `Some`, using some underlying + * generator. + * + * @param generator + * The generator that populates the content. + * @return + * The generator for the optional content. + */ + def alwaysSome[A](generator: Gen[A]): GenOption[A] = + GenOption.alwaysSome(generator) + + /** Generator that will always return `None`, and therefore will never + * actually invoke the underlying generator. + * + * @param generator + * The generator that populates the content. + * @return + * The generator for the optional content. + */ + def alwaysNone[A](generator: Gen[A]): GenOption[A] = + GenOption.alwaysNone(generator) + + end option + /** Generator for a list of some [[Size]] based on a generator for the list * elements. * diff --git a/modules/core/src/main/scala/gs/datagen/v0/generators/GenBool.scala b/modules/core/src/main/scala/gs/datagen/v0/generators/GenBool.scala new file mode 100644 index 0000000..6feb3c6 --- /dev/null +++ b/modules/core/src/main/scala/gs/datagen/v0/generators/GenBool.scala @@ -0,0 +1,8 @@ +package gs.datagen.v0.generators + +import gs.datagen.v0.Gen + +final class GenBool() extends Gen[Boolean]: + + override def generate(input: Any): Boolean = + Gen.rng().nextBoolean() diff --git a/modules/core/src/main/scala/gs/datagen/v0/generators/GenOption.scala b/modules/core/src/main/scala/gs/datagen/v0/generators/GenOption.scala new file mode 100644 index 0000000..f7c8012 --- /dev/null +++ b/modules/core/src/main/scala/gs/datagen/v0/generators/GenOption.scala @@ -0,0 +1,42 @@ +package gs.datagen.v0.generators + +import GenOption.DeterminationType +import gs.datagen.v0.Gen + +final class GenOption[A]( + val determinationType: DeterminationType, + val generator: Gen[A] +) extends Gen[Option[A]]: + + override def generate(input: Any): Option[A] = + determinationType match + case DeterminationType.AlwaysSome => + Some(generator.gen()) + case DeterminationType.AlwaysNone => + None + case DeterminationType.Random => + if Gen.rng().nextBoolean() then Some(generator.gen()) else None + +object GenOption: + + def apply[A](generator: Gen[A]): GenOption[A] = + new GenOption[A](DeterminationType.Random, generator) + + def random[A](generator: Gen[A]): GenOption[A] = apply[A](generator) + + def alwaysSome[A](generator: Gen[A]): GenOption[A] = + new GenOption[A](DeterminationType.AlwaysSome, generator) + + def alwaysNone[A](generator: Gen[A]): GenOption[A] = + new GenOption[A](DeterminationType.AlwaysNone, generator) + + enum DeterminationType: + case AlwaysSome, AlwaysNone, Random + + object DeterminationType: + + given CanEqual[DeterminationType, DeterminationType] = CanEqual.derived + + end DeterminationType + +end GenOption diff --git a/project/build.properties b/project/build.properties index 04267b1..081fdbb 100644 --- a/project/build.properties +++ b/project/build.properties @@ -1 +1 @@ -sbt.version=1.9.9 +sbt.version=1.10.0 diff --git a/project/plugins.sbt b/project/plugins.sbt index e897854..8830bf1 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -28,6 +28,6 @@ externalResolvers := Seq( "Garrity Software Releases" at "https://maven.garrity.co/gs" ) -addSbtPlugin("org.scoverage" % "sbt-scoverage" % "2.0.11") +addSbtPlugin("org.scoverage" % "sbt-scoverage" % "2.0.12") addSbtPlugin("gs" % "sbt-garrity-software" % "0.3.0") addSbtPlugin("gs" % "sbt-gs-semver" % "0.3.0")