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

Commit

Permalink
feat: Convenience functions to create pair/triple generator/simplifie…
Browse files Browse the repository at this point in the history
…r/fuzzer when elements are using the same generator/simplifier/fuzzer (#248)
  • Loading branch information
jcornaz committed Nov 22, 2020
1 parent 6515899 commit 692c253
Show file tree
Hide file tree
Showing 8 changed files with 157 additions and 20 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import com.github.jcornaz.kwik.ExperimentalKwikApi
import com.github.jcornaz.kwik.fuzzer.api.simplifier.Simplifier
import com.github.jcornaz.kwik.fuzzer.api.simplifier.pair
import com.github.jcornaz.kwik.fuzzer.api.simplifier.triple
import com.github.jcornaz.kwik.generator.api.Generator
import com.github.jcornaz.kwik.generator.api.combineWith
import kotlin.random.Random

Expand All @@ -21,6 +20,13 @@ public fun <A, B> Arbitrary.pair(first: Fuzzer<A>, second: Fuzzer<B>): Fuzzer<Pa
simplifier = Simplifier.pair(first.simplifier, second.simplifier)
)

/**
* Returns a [Fuzzer] for pair, using [fuzzer] to fuzz both elements of the pair.
*/
@ExperimentalKwikApi
public fun <T> Arbitrary.pair(fuzzer: Fuzzer<T>): Fuzzer<Pair<T, T>> =
pair(fuzzer, fuzzer)

/**
* Returns a [Fuzzer] for triple of [A], [B] and [C].
*
Expand All @@ -31,7 +37,7 @@ public fun <A, B> Arbitrary.pair(first: Fuzzer<A>, second: Fuzzer<B>): Fuzzer<Pa
@ExperimentalKwikApi
public fun <A, B, C> Arbitrary.triple(first: Fuzzer<A>, second: Fuzzer<B>, third: Fuzzer<C>): Fuzzer<Triple<A, B, C>> =
Fuzzer(
generator = Generator { random: Random ->
generator = { random: Random ->
Triple(
first.generator.generate(random),
second.generator.generate(random),
Expand All @@ -40,3 +46,10 @@ public fun <A, B, C> Arbitrary.triple(first: Fuzzer<A>, second: Fuzzer<B>, third
},
simplifier = Simplifier.triple(first.simplifier, second.simplifier, third.simplifier)
)

/**
* Returns a [Fuzzer] for triple, using [fuzzer] for all elements.
*/
@ExperimentalKwikApi
public fun <T> Arbitrary.triple(fuzzer: Fuzzer<T>): Fuzzer<Triple<T, T, T>> =
triple(fuzzer, fuzzer, fuzzer)
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,15 @@ public fun <A, B> Simplifier.Companion.pair(
}
}

/**
* Create a [Simplifier] that can simplify pairs using [simplifier] for both elements of the pair.
*
* This is essentially an alias for `Simplifier.pair(simplifier, simplifier)`
*/
@ExperimentalKwikApi
public fun <T> Simplifier.Companion.pair(simplifier: Simplifier<T>): Simplifier<Pair<T, T>> =
pair(simplifier, simplifier)

/**
* Create a [Simplifier] that can simplify triples.
*
Expand All @@ -51,3 +60,12 @@ public fun <A, B, C> Simplifier.Companion.triple(
}
}
}

/**
* Create a [Simplifier] that can simplify triples using [simplifier] for all elements of the triple.
*
* This is essentially an alias for `Simplifier.triple(simplifier, simplifier, simplifier)`
*/
@ExperimentalKwikApi
public fun <T> Simplifier.Companion.triple(simplifier: Simplifier<T>): Simplifier<Triple<T, T, T>> =
triple(simplifier, simplifier, simplifier)
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,17 @@ class FuzzerPairTest {

assertEquals(listOf(3 to 50, 10 to 42), pair.simplifier.simplify(10 to 50).toList())
}
}

@Test
fun canCreatePairWithSingleItemFuzzer() {
val itemFuzz = Generator.of(1).toFuzzer { sequenceOf(it - 1) }
assertEquals(
Arbitrary.pair(itemFuzz).generator.generate(Random(0)),
Arbitrary.pair(itemFuzz, itemFuzz).generator.generate(Random(0))
)
assertEquals(
Arbitrary.pair(itemFuzz).simplifier.simplify(2 to 3).toList(),
Arbitrary.pair(itemFuzz, itemFuzz).simplifier.simplify(2 to 3).toList()
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -53,4 +53,19 @@ class FuzzerTripleTest {
pair.simplifier.simplify(Triple(10, 20, 30)).toList()
)
}

@Test
fun canCreatePairWithSingleItemFuzzer() {
val itemFuzz = Generator.of(1).toFuzzer { sequenceOf(it - 1) }
assertEquals(
Arbitrary.triple(itemFuzz).generator.generate(Random(0)),
Arbitrary.triple(itemFuzz, itemFuzz, itemFuzz).generator.generate(Random(0))
)
assertEquals(
Arbitrary.triple(itemFuzz).simplifier
.simplify(Triple(1, 2, 3)).toList(),
Arbitrary.triple(itemFuzz, itemFuzz, itemFuzz).simplifier
.simplify(Triple(1, 2, 3)).toList()
)
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package com.github.jcornaz.kwik.fuzzer.api.simplifier

import com.github.jcornaz.kwik.ExperimentalKwikApi
import kotlin.random.Random
import kotlin.random.nextUInt
import kotlin.test.Test
import kotlin.test.assertEquals

Expand Down Expand Up @@ -33,6 +35,19 @@ class PairTest {
)
}

@Test
fun canUseSameSimplifierForBothElements() {
val itemSimplifier = Simplifier { it: Int -> if (it > 0) sequenceOf(it - 1) else emptySequence() }

repeat(100) {
val initialValue = Random.nextInt(0, 5) to Random.nextInt(0, 5)
assertEquals(
Simplifier.pair(itemSimplifier).simplify(initialValue).toList(),
Simplifier.pair(itemSimplifier, itemSimplifier).simplify(initialValue).toList(),
)
}
}

@Test
fun returnEmptySequenceIfBothHaveNoSimplerValue() {
val pair = Simplifier.pair(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.github.jcornaz.kwik.fuzzer.api.simplifier

import com.github.jcornaz.kwik.ExperimentalKwikApi
import kotlin.random.Random
import kotlin.test.Test
import kotlin.test.assertEquals

Expand Down Expand Up @@ -37,6 +38,18 @@ class TripleTest {
)
}

@Test
fun canUseSameSimplifierForAllElements() {
val itemSimplifier = Simplifier { it: Int -> if (it > 0) sequenceOf(it - 1) else emptySequence() }

repeat(100) {
val initialValue = Triple(Random.nextInt(0, 5), Random.nextInt(0, 5), Random.nextInt(0, 5))
assertEquals(
Simplifier.triple(itemSimplifier).simplify(initialValue).toList(),
Simplifier.triple(itemSimplifier, itemSimplifier, itemSimplifier).simplify(initialValue).toList(),
)
}
}

@Test
fun returnEmptySequenceIfNoneHaveSimplerValue() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,29 @@ public fun <A, B, R> Generator.Companion.combine(
CombinedGenerators(generator1, generator2, transform)

/**
* Returns a generator of combining the elements of [generator1] and [generator2]
* Returns a generator of pairs using [generator1] (for the left) and [generator2] (for the right)
*/
@Deprecated("Use pair instead", ReplaceWith("pair(generator1, generator2)"))
public fun <A, B> Generator.Companion.combine(
generator1: Generator<A>,
generator2: Generator<B>
): Generator<Pair<A, B>> =
combine(generator1, generator2, ::Pair)
pair(generator1, generator2)

/**
* Returns a generator of pairs using [leftGen] and [rightGen]
*/
public fun <A, B> Generator.Companion.pair(
leftGen: Generator<A>,
rightGen: Generator<B>
): Generator<Pair<A, B>> =
combine(leftGen, rightGen, ::Pair)

/**
* Returns a generator of pairs using the same [generator] for left and right elements.
*/
public fun <T> Generator.Companion.pair(generator: Generator<T>): Generator<Pair<T, T>> =
pair(generator, generator)

private class CombinedGenerators<A, B, R>(
private val generator1: Generator<A>,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
package com.github.jcornaz.kwik.generator.api

import com.github.jcornaz.kwik.generator.test.AbstractGeneratorTest
import kotlin.random.Random
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertTrue

@Suppress("DEPRECATION")
class CombineTest : AbstractGeneratorTest() {

override val generator: Generator<*> = Generator.combine(
Generator { it: Random -> it.nextInt() },
Generator { it: Random -> it.nextDouble() }
{ it.nextInt() },
{ it.nextDouble() }
)

@Test
Expand All @@ -20,20 +21,53 @@ class CombineTest : AbstractGeneratorTest() {
@Test
fun combineDifferentValues() {
val gen = Generator.combine(
Generator { it: Random -> it.nextInt() },
Generator { it: Random -> it.nextInt() }
{ it.nextInt() },
{ it.nextInt() }
)

assertTrue(gen.randomSequence(123).take(200).count { (a, b) -> a != b } > 150)
}
}

class PairTest : AbstractGeneratorTest() {

override val generator: Generator<*> = Generator.pair(
{ it.nextInt() },
{ it.nextDouble() }
)

@Test
fun combineTheValues() {
assertTrue(generator.randomSequence(0).take(200).distinct().count() > 190)
}

@Test
fun combineDifferentValues() {
val gen = Generator.pair(
{ it.nextInt() },
{ it.nextInt() }
)

assertTrue(gen.randomSequence(123).take(200).count { (a, b) -> a != b } > 150)
}

@Test
fun canUseSameGeneratorForBothElements() {
val itemGen = Generator { it.nextInt() }

assertEquals(
Generator.pair(itemGen).randomSequence(0).take(100).toList(),
Generator.pair(itemGen, itemGen).randomSequence(0).take(100).toList()
)
}
}

class CombineWithTransformTest : AbstractGeneratorTest() {

override val generator: Generator<*> =
Generator.combine(
Generator { it: Random -> it.nextInt() },
Generator { it: Random -> it.nextDouble() }
{ it.nextInt() },
{ it.nextDouble() }
) { x, y -> CombinedValues(x, y) }

@Test
Expand All @@ -44,8 +78,8 @@ class CombineWithTransformTest : AbstractGeneratorTest() {
@Test
fun combineDifferentValues() {
val gen = Generator.combine(
Generator { it: Random -> it.nextInt() }.withSamples(1, 2),
Generator { it: Random -> it.nextDouble() }.withSamples(3.0, 4.0)
Generator { it.nextInt() }.withSamples(1, 2),
Generator { it.nextDouble() }.withSamples(3.0, 4.0)
) { a, b -> CombinedValues(a, b) }

assertTrue(gen.randomSequence(0).take(200).count { (a, b) -> a != b.toInt() } > 150)
Expand All @@ -57,7 +91,7 @@ class CombineWithTransformTest : AbstractGeneratorTest() {
class CombineWithTest : AbstractGeneratorTest() {

override val generator: Generator<*> =
Generator { it: Random -> it.nextInt() }.combineWith(Generator { it: Random -> it.nextDouble() })
Generator { it.nextInt() }.combineWith { it.nextDouble() }

@Test
fun combineTheValues() {
Expand All @@ -66,7 +100,7 @@ class CombineWithTest : AbstractGeneratorTest() {

@Test
fun combineDifferentValues() {
val gen = Generator { it: Random -> it.nextInt() }.combineWith(Generator { it: Random -> it.nextInt() })
val gen = Generator { it.nextInt() }.combineWith { it.nextInt() }

assertTrue(gen.randomSequence(123).take(200).count { (a, b) -> a != b } > 150)
}
Expand All @@ -75,8 +109,8 @@ class CombineWithTest : AbstractGeneratorTest() {
class CombineWithWithTransformTest : AbstractGeneratorTest() {

override val generator: Generator<*> =
Generator { it: Random -> it.nextInt() }
.combineWith(Generator { it: Random -> it.nextDouble() }) { x, y ->
Generator { it.nextInt() }
.combineWith({ it.nextDouble() }) { x, y ->
CombinedValues(
x,
y
Expand All @@ -90,8 +124,8 @@ class CombineWithWithTransformTest : AbstractGeneratorTest() {

@Test
fun combineDifferentValues() {
val gen = Generator { it: Random -> it.nextInt() }
.combineWith(Generator { it: Random -> it.nextInt() }) { a, b -> a to b }
val gen = Generator { it.nextInt() }
.combineWith({ it.nextInt() }) { a, b -> a to b }

assertTrue(gen.randomSequence(123).take(200).count { (a, b) -> a != b } > 150)
}
Expand Down

0 comments on commit 692c253

Please sign in to comment.