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

Commit

Permalink
feat: Generators for ranges (#216)
Browse files Browse the repository at this point in the history
Thanks to @Kantis
  • Loading branch information
Kantis authored Oct 12, 2020
1 parent 41f0749 commit d3956d3
Show file tree
Hide file tree
Showing 3 changed files with 155 additions and 0 deletions.
15 changes: 15 additions & 0 deletions docs/generators.rst
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,21 @@ Sequences

Note that there is also a ``nonEmptySequences`` alternative

Ranges
------

``Generator.ranges(elementGen)``
Generate ranges. ``elementGen`` can be used to define the generator of the elements.

``Generator.intRanges(elementGen = Generator.ints())``
Generates ``ClosedRanged<Int>``. Includes empty and singleton ranges as samples

``Generator.longRanges(elementGen = Generator.longs())``
Generates ``ClosedRanged<Long>``. Includes empty and singleton ranges as samples

``Generator.charRanges(elementGen = Generator.characters())``
Generates ``ClosedRanged<Char>``. Includes empty and singleton ranges as samples

Enums
-----

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
@file:Suppress("EmptyRange")

package com.github.jcornaz.kwik.generator.stdlib

import com.github.jcornaz.kwik.generator.api.Generator
import com.github.jcornaz.kwik.generator.api.withSamples


/**
* Returns a generator of ClosedRange<T>, which uses the provided Generator for creating start and end elements
*
* @param <T> The type of the ClosedRange
* @param elementGen A generator producing T, which will create the start and end elements of the range
*/
fun <T : Comparable<T>> Generator.Companion.ranges(elementGen: Generator<T>): Generator<ClosedRange<T>> =
Generator { rng -> elementGen.generate(rng)..elementGen.generate(rng) }


/**
* Creates a Generator for ClosedRange<Int>, includes samples for empty range and single item range
*
* @param elementGen A generator producing T, which will create the start and end elements of the range
*/
@Suppress("InvalidRange")
fun Generator.Companion.intRanges(elementGen: Generator<Int> = ints()): Generator<ClosedRange<Int>> =
ranges(elementGen).withSamples(
1..0,
0..0
)


/**
* Creates a Generator for ClosedRange<Char>, includes samples for empty range and single item range
*
* @param elementGen A generator producing T, which will create the start and end elements of the range
*/
@Suppress("InvalidRange")
fun Generator.Companion.charRanges(elementGen: Generator<Char> = characters()): Generator<ClosedRange<Char>> =
ranges(elementGen).withSamples(
'B'..'A',
'A'..'A'
)


/**
* Creates a Generator for ClosedRange<Long>, includes samples for empty range and single item range
*
* @param elementGen A generator producing T, which will create the start and end elements of the range
*/
@Suppress("InvalidRange")
fun Generator.Companion.longRanges(elementGen: Generator<Long> = longs()): Generator<ClosedRange<Long>> =
ranges(elementGen).withSamples(
1L..0L,
0L..0L
)

Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
@file:Suppress("EmptyRange")

package com.github.jcornaz.kwik.generator.stdlib

import com.github.jcornaz.kwik.generator.api.Generator
import com.github.jcornaz.kwik.generator.api.randomSequence
import com.github.jcornaz.kwik.generator.test.AbstractGeneratorTest
import kotlin.test.Test
import kotlin.test.assertTrue

class RangeGeneratorTest : AbstractGeneratorTest() {
override val generator = Generator.ranges(Generator.booleans())

@Test
fun `generates all possible ranges`() {
// False .. True
// False .. False
// True .. True
// Empty

assertTrue(
generator.randomSequence(0L)
.take(100)
.distinct()
.count() == 4
)
}
}

class IntRangeGeneratorTest : AbstractGeneratorTest() {

override val generator = Generator.intRanges()

@Test
fun `empty range is sampled`() {
generator.randomSequence(0L)
.take(10)
.contains(1..0)
}

@Test
fun `single element range is sampled`() {
generator.randomSequence(0L)
.take(10)
.contains(1..1)
}
}

class CharRangeGeneratorTest : AbstractGeneratorTest() {
override val generator: Generator<ClosedRange<Char>> = Generator.charRanges()

@Test
fun `empty range is sampled`() {
generator.randomSequence(0L)
.take(10)
.contains('C'..'B')
}

@Test
fun `single element range is sampled`() {
generator.randomSequence(0L)
.take(10)
.contains('A'..'A')
}
}


class LongRangeGeneratorTest : AbstractGeneratorTest() {
override val generator = Generator.longRanges()

@Test
fun `empty range is sampled`() {
generator.randomSequence(0L)
.take(10)
.contains(1L..0L)
}

@Test
fun `single element range is sampled`() {
generator.randomSequence(0L)
.take(10)
.contains(1L..1L)
}
}

0 comments on commit d3956d3

Please sign in to comment.