Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added Byte.shouldBeBetween(min, max) matcher; added bounds to Arb.byt… #1408

Merged
merged 2 commits into from Apr 25, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
@@ -0,0 +1,14 @@
package io.kotest.matchers.bytes

import io.kotest.matchers.Matcher
import io.kotest.matchers.MatcherResult
import io.kotest.matchers.shouldBe

fun Byte.shouldBeBetween(lower: Byte, upper: Byte) = this shouldBe between(lower, upper)
fun between(lower: Byte, upper: Byte) = object : Matcher<Int> {
override fun test(value: Int) = MatcherResult(
value in lower..upper,
"$value should be between ($lower, $upper) inclusive",
"$value should not be between ($lower, $upper) inclusive"
)
}
Expand Up @@ -24,7 +24,7 @@ fun <A> Arb<A>.next(rs: RandomSource = RandomSource.Default): A = single(rs)

/**
* Creates a new [Arb] that performs no shrinking, and generates values from the given function
* that is invoked once.
* that is invoked once to return a sequence of values.
*/
fun <A> arb(edgecases: List<A> = emptyList(), f: (RandomSource) -> Sequence<A>) = object : Arb<A>() {
override fun edgecases(): List<A> = edgecases
Expand Down
Expand Up @@ -3,10 +3,14 @@ package io.kotest.property.arbitrary
import io.kotest.property.Arb

/**
* The edge cases are [[Byte.MIN_VALUE], [Byte.MAX_VALUE], 0]
* Returns an [Arb] that produces [Byte]s, where the edge cases are 0, -1, 1, min and max.
* 0, -1, and 1 will only be included if they are within the specified min and max bounds.
*/
fun Arb.Companion.byte() = arb(ByteShrinker, listOf(0, Byte.MIN_VALUE, Byte.MAX_VALUE)) {
it.random.nextBytes(1).first()
fun Arb.Companion.byte(min: Byte = Byte.MIN_VALUE, max: Byte = Byte.MAX_VALUE): Arb<Byte> {
val edges = byteArrayOf(1, -1, 0, min, max).filter { it in min..max }.distinct()
return arb(ByteShrinker, edges) {
generateSequence { it.random.nextBytes(1).first() }.filter { it in min..max }.first()
}
}

val ByteShrinker = IntShrinker.bimap({ it.toInt() }, { it.toByte() })
@@ -0,0 +1,21 @@
package io.kotest.property.arbitrary

import io.kotest.property.Arb
import io.kotest.property.Gen

/**
* Returns an [Arb] that generates one dimension [ByteArray]s.
*
* @param generateArrayLength [Gen] to produce the size of the arrays
* @param generateContents [Arb] to produce random bytes as the values for the array.
*/
fun Arb.Companion.byteArrays(generateArrayLength: Gen<Int>, generateContents: Arb<Byte>): Arb<ByteArray> {
return arb { rs ->
val lengths = generateArrayLength.generate(rs).iterator()
val bytes = generateContents.values(rs).iterator()
sequence<ByteArray> {
val length = lengths.next().value
ByteArray(length) { bytes.next().value }
}
}
}
@@ -0,0 +1,31 @@
package com.sksamuel.kotest.property.arbitrary

import io.kotest.core.spec.style.DescribeSpec
import io.kotest.inspectors.forAll
import io.kotest.matchers.ints.shouldBeGreaterThanOrEqual
import io.kotest.matchers.ints.shouldBeLessThanOrEqual
import io.kotest.matchers.shouldBe
import io.kotest.property.Arb
import io.kotest.property.arbitrary.byte
import io.kotest.property.arbitrary.byteArrays
import io.kotest.property.arbitrary.constant
import io.kotest.property.arbitrary.int
import io.kotest.property.arbitrary.take

class ByteArrayTest : DescribeSpec() {
init {
describe("Arb.byteArrays") {
it("should generate specified lengths") {
Arb.byteArrays(Arb.int(5, 15), Arb.byte()).take(1000).toList().forAll {
it.size.shouldBeGreaterThanOrEqual(5)
it.size.shouldBeLessThanOrEqual(15)
}
}
it("should populate random byte values") {
Arb.byteArrays(Arb.constant(1000000), Arb.byte()).take(10).toList().forAll {
it.toSet().size shouldBe 255
}
}
}
}
}
@@ -0,0 +1,45 @@
package com.sksamuel.kotest.property.arbitrary

import io.kotest.core.spec.style.DescribeSpec
import io.kotest.inspectors.forAll
import io.kotest.inspectors.forNone
import io.kotest.inspectors.forOne
import io.kotest.matchers.bytes.shouldBeBetween
import io.kotest.matchers.shouldBe
import io.kotest.property.Arb
import io.kotest.property.arbitrary.byte
import io.kotest.property.arbitrary.take

class ByteTest : DescribeSpec() {
init {
describe("Arb.byte") {
it("should respect min / max") {
Arb.byte(5.toByte(), 9.toByte()).take(1000).forAll {
it.shouldBeBetween(5, 9)
}
}
it("should only include 0 in the edge cases if within the bounds") {
Arb.byte(5.toByte(), 9.toByte()).edgecases().forNone { it shouldBe 0.toByte() }
Arb.byte(0.toByte(), 9.toByte()).edgecases().forOne { it shouldBe 0.toByte() }
Arb.byte((-5).toByte(), 0.toByte()).edgecases().forOne { it shouldBe 0.toByte() }
}
it("should only include 1 in the edge cases if within the bounds") {
Arb.byte(5.toByte(), 9.toByte()).edgecases().forNone { it shouldBe 1.toByte() }
Arb.byte(0.toByte(), 9.toByte()).edgecases().forOne { it shouldBe 1.toByte() }
Arb.byte(1.toByte(), 9.toByte()).edgecases().forOne { it shouldBe 1.toByte() }
Arb.byte(1.toByte(), 1.toByte()).edgecases().forOne { it shouldBe 1.toByte() }
Arb.byte((-5).toByte(), 1.toByte()).edgecases().forOne { it shouldBe 1.toByte() }
Arb.byte((-5).toByte(), 2.toByte()).edgecases().forOne { it shouldBe 1.toByte() }
}
it("should only include -1 in the edge cases if within the bounds") {
Arb.byte(5.toByte(), 9.toByte()).edgecases().forNone { it shouldBe (-1).toByte() }
Arb.byte(0.toByte(), 9.toByte()).edgecases().forNone { it shouldBe (-1).toByte() }
Arb.byte((-1).toByte(), 9.toByte()).edgecases().forOne { it shouldBe (-1).toByte() }
Arb.byte((-1).toByte(), (-1).toByte()).edgecases().forOne { it shouldBe (-1).toByte() }
Arb.byte((-2).toByte(), 0.toByte()).edgecases().forOne { it shouldBe (-1).toByte() }
Arb.byte((-5).toByte(), 0.toByte()).edgecases().forOne { it shouldBe (-1).toByte() }
Arb.byte((-5).toByte(), (-1).toByte()).edgecases().forOne { it shouldBe (-1).toByte() }
}
}
}
}