aboutsummaryrefslogtreecommitdiff
path: root/src/main/scala/xyz/driver/core/generators.scala
blob: 3c854472987e15d2111b73437937ce52c24717e2 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
package xyz.driver.core

import enumeratum._
import java.math.MathContext
import java.util.UUID

import xyz.driver.core.time.{Time, TimeOfDay, TimeRange}
import xyz.driver.core.date.{Date, DayOfWeek}

import scala.reflect.ClassTag
import scala.util.Random
import eu.timepit.refined.refineV
import eu.timepit.refined.api.Refined
import eu.timepit.refined.collection._

object generators {

  private val random = new Random
  import random._

  private val DefaultMaxLength       = 10
  private val StringLetters          = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ ".toSet
  private val NonAmbigiousCharacters = "abcdefghijkmnpqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23456789".toSet
  private val Numbers                = "0123456789".toSet

  private def nextTokenString(length: Int, charSet: Set[Char]): String =
    List.fill(length)(oneOf(charSet)).mkString

  def nextToken(length: Int): String = nextTokenString(length, NonAmbigiousCharacters)

  def nextNumericToken(length: Int): String = nextTokenString(length, Numbers)

  def nextInt(maxValue: Int, minValue: Int = 0): Int = random.nextInt(maxValue - minValue) + minValue

  def nextBoolean(): Boolean = random.nextBoolean()

  def nextDouble(): Double = random.nextDouble()

  def nextId[T](): Id[T] = Id[T](nextUuid().toString)

  def nextId[T](maxLength: Int): Id[T] = Id[T](nextString(maxLength))

  def nextNumericId[T](): Id[T] = Id[T](nextLong.abs.toString)

  def nextNumericId[T](maxValue: Int): Id[T] = Id[T](nextInt(maxValue).toString)

  def nextName[T](maxLength: Int = DefaultMaxLength): Name[T] = Name[T](nextString(maxLength))

  def nextNonEmptyName[T](maxLength: Int = DefaultMaxLength): NonEmptyName[T] =
    NonEmptyName[T](nextNonEmptyString(maxLength))

  def nextUuid(): UUID = java.util.UUID.randomUUID

  def nextRevision[T](): Revision[T] = Revision[T](nextUuid().toString)

  def nextString(maxLength: Int = DefaultMaxLength): String =
    (oneOf[Char](StringLetters) +: arrayOf(oneOf[Char](StringLetters), maxLength - 1)).mkString

  def nextNonEmptyString(maxLength: Int = DefaultMaxLength): String Refined NonEmpty = {
    refineV[NonEmpty](
      (oneOf[Char](StringLetters) +: arrayOf(oneOf[Char](StringLetters), maxLength - 1)).mkString
    ).right.get
  }

  def nextOption[T](value: => T): Option[T] = if (nextBoolean()) Option(value) else None

  def nextPair[L, R](left: => L, right: => R): (L, R) = (left, right)

  def nextTriad[F, S, T](first: => F, second: => S, third: => T): (F, S, T) = (first, second, third)

  def nextTime(): Time = Time(math.abs(nextLong() % System.currentTimeMillis))

  def nextTimeOfDay: TimeOfDay = TimeOfDay(java.time.LocalTime.MIN.plusSeconds(nextLong), java.util.TimeZone.getDefault)

  def nextTimeRange(): TimeRange = {
    val oneTime     = nextTime()
    val anotherTime = nextTime()

    TimeRange(
      Time(scala.math.min(oneTime.millis, anotherTime.millis)),
      Time(scala.math.max(oneTime.millis, anotherTime.millis)))
  }

  def nextDate(): Date = nextTime().toDate(java.util.TimeZone.getTimeZone("UTC"))

  def nextDayOfWeek(): DayOfWeek = oneOf(DayOfWeek.All)

  def nextBigDecimal(multiplier: Double = 1000000.00, precision: Int = 2): BigDecimal =
    BigDecimal(multiplier * nextDouble, new MathContext(precision))

  def oneOf[T](items: T*): T = oneOf(items.toSet)

  def oneOf[T](items: Set[T]): T = items.toSeq(nextInt(items.size))

  def oneOf[T <: EnumEntry](enum: Enum[T]): T = oneOf(enum.values: _*)

  def arrayOf[T: ClassTag](generator: => T, maxLength: Int = DefaultMaxLength, minLength: Int = 0): Array[T] =
    Array.fill(nextInt(maxLength, minLength))(generator)

  def seqOf[T](generator: => T, maxLength: Int = DefaultMaxLength, minLength: Int = 0): Seq[T] =
    Seq.fill(nextInt(maxLength, minLength))(generator)

  def vectorOf[T](generator: => T, maxLength: Int = DefaultMaxLength, minLength: Int = 0): Vector[T] =
    Vector.fill(nextInt(maxLength, minLength))(generator)

  def listOf[T](generator: => T, maxLength: Int = DefaultMaxLength, minLength: Int = 0): List[T] =
    List.fill(nextInt(maxLength, minLength))(generator)

  def setOf[T](generator: => T, maxLength: Int = DefaultMaxLength, minLength: Int = 0): Set[T] =
    seqOf(generator, maxLength, minLength).toSet

  def mapOf[K, V](
      keyGenerator: => K,
      valueGenerator: => V,
      maxLength: Int = DefaultMaxLength,
      minLength: Int = 0): Map[K, V] =
    seqOf(nextPair(keyGenerator, valueGenerator), maxLength, minLength).toMap
}