Skip to content
This repository has been archived by the owner on Aug 24, 2021. It is now read-only.

Commit

Permalink
feat: Generator for LocalDate (#220)
Browse files Browse the repository at this point in the history
Thanks to @mmiikkkkaa
  • Loading branch information
mmiikkkkaa authored Oct 13, 2020
1 parent d135ad9 commit 388afa7
Show file tree
Hide file tree
Showing 3 changed files with 116 additions and 6 deletions.
14 changes: 14 additions & 0 deletions docs/generators.rst
Original file line number Diff line number Diff line change
Expand Up @@ -134,3 +134,17 @@ Java

``Generator.uuids()``
Create a generator for UUID

Java Time API
-------------
``Generator.instants(min: Instant.MIN, max: Instant.MAX)``
Generates Instants (with nano seconds), includes the samples: ``Instant.EPOCH`` (1970-01-01T00:00:00.000Z), ``min`` and ``max``

``Generator.durations(min, max)``
Generates Durations (with nano seconds), Includes the samples: ``Duration.ZERO``, ``min`` and ``max``

``Generator.localTimes(min: LocalTime.MIN, max: LocalTime.MAX)``
Generates LocalTimes (with nano seconds), Includes the samples: ``LocalTime.NOON``, ``min`` and ``max``

``Generator.localDates(min: LocalDate.MIN, max: LocalDate.MAX)``
Generates LocalDates, includes the samples: ``LocalDate.EPOCH`` (1970-01-01), ``min`` and ``max``
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,16 @@ import com.github.jcornaz.kwik.generator.api.Generator
import com.github.jcornaz.kwik.generator.api.withSamples
import java.time.Duration
import java.time.Instant
import java.time.LocalDate
import java.time.LocalTime
import java.time.temporal.ChronoField
import kotlin.random.Random

private const val MAX_NANOSECONDS = 999_999_999
private val MIN_DURATION = Duration.ofSeconds(Long.MIN_VALUE)
private val MAX_DURATION = Duration.ofSeconds(Long.MAX_VALUE, MAX_NANOSECONDS.toLong())
private val EPOCH: LocalDate = LocalDate.ofEpochDay(0) // can be replaced by LocalDate.EPOCH with Java 9


/**
* Returns a generator of [Instant] between [min] and [max] (inclusive)
Expand All @@ -19,9 +22,7 @@ fun Generator.Companion.instants(
min: Instant = Instant.MIN,
max: Instant = Instant.MAX
): Generator<Instant> {
require(max >= min) {
"Max must be equal or after min but min was $min and max was $max"
}
requireMaxEqualOrHigherThanMin(max, min)

val range = min..max

Expand Down Expand Up @@ -100,9 +101,7 @@ fun Generator.Companion.localTimes(
min: LocalTime = LocalTime.MIN,
max: LocalTime = LocalTime.MAX
): Generator<LocalTime> {
require(max >= min) {
"Max must be equal or after min but min was $min and max was $max"
}
requireMaxEqualOrHigherThanMin(max, min)

val range = min..max

Expand All @@ -116,3 +115,31 @@ fun Generator.Companion.localTimes(
LocalTime.ofNanoOfDay(random.nextLong(min.toNanoOfDay(), max.toNanoOfDay()))
}.withSamples(samples)
}

/**
* Returns a generator of [LocalDate] between [min] and [max] (inclusive)
*/
fun Generator.Companion.localDates(
min: LocalDate = LocalDate.MIN,
max: LocalDate = LocalDate.MAX
): Generator<LocalDate> {
requireMaxEqualOrHigherThanMin(max, min)

val range = min..max

val samples = mutableListOf(min, max)

if (EPOCH in range && EPOCH !in samples) {
samples += EPOCH
}

return Generator { random: Random ->
LocalDate.ofEpochDay(random.nextLong(min.toEpochDay(), max.toEpochDay()))
}.withSamples(samples)
}

private fun <T> requireMaxEqualOrHigherThanMin(max: Comparable<T>, min: T) {
require(max >= min) {
"Max must be equal or after min but min was $min and max was $max"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,15 @@ import com.github.jcornaz.kwik.generator.api.randomSequence
import com.github.jcornaz.kwik.generator.test.AbstractGeneratorTest
import java.time.Duration
import java.time.Instant
import java.time.LocalDate
import java.time.LocalTime
import kotlin.test.Test
import kotlin.test.assertFailsWith
import kotlin.test.assertTrue

private const val MAX_NANOSECONDS = 999_999_999L
// can be replaced by LocalDate.EPOCH with Java 9
private val EPOCH: LocalDate = LocalDate.ofEpochDay(0)

class DurationGeneratorTest : AbstractGeneratorTest() {
override val generator: Generator<Duration> = Generator.durations(Duration.ZERO, Duration.ofDays(100))
Expand Down Expand Up @@ -220,3 +223,69 @@ class LocalTimeGeneratorTest : AbstractGeneratorTest() {
assertTrue(Generator.localTimes(min = min).randomSequence(0).take(50).any { it == min })
}
}


class LocalDateGeneratorTest : AbstractGeneratorTest() {

override val generator: Generator<LocalDate> = Generator.localDates()

@Test
fun `fail for invalid range`() {
assertFailsWith<IllegalArgumentException> {
Generator.localDates(LocalDate.MAX, LocalDate.MIN)
}
}

@Test
fun `produce inside given range`() {
val min = EPOCH
val max = min.plusWeeks(2)
assertTrue(Generator.localDates(min = min, max = max).randomSequence(0).take(50).all { it >= min && it <= max })
}

@Test
fun `do not produce EPOCH if not in range`() {
val min = EPOCH.plusDays(2)
val max = EPOCH.plusWeeks(2)
assertTrue(Generator.localDates(min = min, max = max).randomSequence(0).take(50).none { it == EPOCH })
}

@Test
fun `do not produce global max if not in range`() {
val max = LocalDate.MAX.minusDays(1)
assertTrue(Generator.localDates(max = max).randomSequence(0).take(50).none { it == LocalDate.MAX })
}

@Test
fun `do not produce global min if not in range`() {
val min = LocalDate.MIN.plusDays(1)
assertTrue(Generator.localDates(min = min).randomSequence(0).take(50).none { it == LocalDate.MIN })
}

@Test
fun `generate epoch`() {
assertTrue(Generator.localDates().randomSequence(0).take(50).any { it == EPOCH })
}

@Test
fun `generate global max`() {
assertTrue(Generator.localDates().randomSequence(0).take(50).any { it == LocalDate.MAX })
}

@Test
fun `generate global min`() {
assertTrue(Generator.localDates().randomSequence(0).take(50).any { it == LocalDate.MIN })
}

@Test
fun `generate max`() {
val max = EPOCH.plusDays(1)
assertTrue(Generator.localDates(max = max).randomSequence(0).take(50).any { it == max })
}

@Test
fun `generate min`() {
val min = EPOCH.plusDays(1)
assertTrue(Generator.localDates(min = min).randomSequence(0).take(50).any { it == min })
}
}

0 comments on commit 388afa7

Please sign in to comment.