tieskedh
12/15/2020, 2:34 PMopen class FlatmapCombinedShrinker2<Original, value1, value2>(
private val select1: (Original) -> value1,
private val shrinker1: Shrinker<value1>,
private val select2: (Original) -> value2,
private val shrinker2: Shrinker<value2>,
private val composer: Original.(value1, value2) -> Original
) : Shrinker<Original> {
override fun shrink(value: Original): List<Original> {
val hasShrinks = BooleanArray(2) { true }
val value1 = select1(value)
val shrinks1 = shrinker1.shrink(value1).ifEmpty {
hasShrinks[0] = false
listOf(value1)
}
val value2 = select2(value)
val shrinks2 = shrinker2.shrink(value2).ifEmpty {
hasShrinks[1] = false
listOf(value2)
}
return if (hasShrinks.any { it }) {
shrinks1.flatMap { val1 ->
shrinks2.map { val2 ->
value.composer(val1, val2)
}
}
} else emptyList()
}
}
sam
12/15/2020, 2:41 PMtieskedh
12/15/2020, 2:59 PMclass NestedListShrinker<T>(
private val range: IntRange,
val shrinker: Shrinker<T>
) : Shrinker<List<T>> {
val shrinkMap = mutableMapOf<T, List<T>>()
private fun T.getShrinks() = shrinkMap.getOrPut(this){
shrinker.shrink(this)
}
override fun shrink(value: List<T>): List<List<T>> {
return ListShrinker<T>(range).shrink(value).mapNotNull { list ->
var shrinkFound = false
val childShrinks = list.map { t ->
val shrinks = t.getShrinks()
if (shrinks.isNotEmpty()){
shrinkFound = true
shrinks
} else listOf(t)
}
if (shrinkFound) {
childShrinks.crossProduct { outer, inner ->
outer + inner
}
} else null
}.flatten().distinct()
}
}
sam
12/15/2020, 2:59 PMsam
12/15/2020, 3:00 PMtieskedh
12/15/2020, 3:08 PMsam
12/15/2020, 3:12 PMtieskedh
12/15/2020, 3:24 PMsam
12/15/2020, 3:25 PMtieskedh
12/15/2020, 3:29 PMsam
12/15/2020, 3:29 PMtieskedh
12/15/2020, 3:35 PMtieskedh
12/18/2020, 8:16 PMfun <T> Arb<T>.shrinkWith(
shrinker: Shrinker<T>
) = arbitrary(edgecases(), shrinker) { next(it) }
infix fun <Original, T> KProperty1<Original, T>.shrinkWith(
shrinker: Shrinker<T>
) = PartialShrinker<Original, T>(
{ this.get(it) },
shrinker
)
infix fun <Original, V> ShrinkerSelectPart<Original, V>.shrinkWith(
shrinker: Shrinker<V>
) = PartialShrinker(
selection,
shrinker
)
class ShrinkerSelectPart<Original, V>(
val selection: (Original) -> V
)
fun <Original, A> ShrinkerBuilder<Original>.build(
partialShrinkerA: PartialShrinker<Original, A>,
completeFn: Original.(A) -> Original
): Shrinker<Original> =
partialShrinkerA.build(completeFn)
fun <Original, A, B> ShrinkerBuilder<Original>.build(
partialShrinkerA: PartialShrinker<Original, A>,
partialShrinkerB: PartialShrinker<Original, B>,
completeFn: Original.(A, B) -> Original
): Shrinker<Original> =
partialShrinkerA.bind(partialShrinkerB).build { (a, b) ->
completeFn(a, b)
}
fun <Original, A, B, C> ShrinkerBuilder<Original>.build(
partialShrinkerA: PartialShrinker<Original, A>,
partialShrinkerB: PartialShrinker<Original, B>,
partialShrinkerC: PartialShrinker<Original, C>,
completeFn: Original.(A, B, C) -> Original
): Shrinker<Original> = partialShrinkerA.bind(partialShrinkerB).bind(partialShrinkerC)
.build { (ab, c) ->
val (a, b) = ab
completeFn(a, b, c)
}
fun <Original, A, B, C, D> ShrinkerBuilder<Original>.build(
partialShrinkerA: PartialShrinker<Original, A>,
partialShrinkerB: PartialShrinker<Original, B>,
partialShrinkerC: PartialShrinker<Original, C>,
partialShrinkerD: PartialShrinker<Original, D>,
completeFn: Original.(A, B, C, D) -> Original
): Shrinker<Original> = partialShrinkerA.bind(partialShrinkerB).bind(partialShrinkerC)
.bind(partialShrinkerD).build { (abc, d) ->
val (ab, c) = abc
val (a, b) = ab
completeFn(a, b, c, d)
}
fun <Original, A, B, C, D, E> ShrinkerBuilder<Original>.build(
partialShrinkerA: PartialShrinker<Original, A>,
partialShrinkerB: PartialShrinker<Original, B>,
partialShrinkerC: PartialShrinker<Original, C>,
partialShrinkerD: PartialShrinker<Original, D>,
partialShrinkerE: PartialShrinker<Original, E>,
completeFn: Original.(A, B, C, D, E) -> Original
): Shrinker<Original> =
partialShrinkerA.bind(partialShrinkerB).bind(partialShrinkerC).bind(partialShrinkerD)
.bind(partialShrinkerE).build { (abcd, e) ->
val (abc, d) = abcd
val (ab, c) = abc
val (a, b) = ab
this.completeFn(a, b, c, d, e)
}
fun <Original, A, B, C, D, E, F> ShrinkerBuilder<Original>.build(
partialShrinkerA: PartialShrinker<Original, A>,
partialShrinkerB: PartialShrinker<Original, B>,
partialShrinkerC: PartialShrinker<Original, C>,
partialShrinkerD: PartialShrinker<Original, D>,
partialShrinkerE: PartialShrinker<Original, E>,
partialShrinkerF: PartialShrinker<Original, F>,
completeFn: Original.(A, B, C, D, E, F) -> Original
): Shrinker<Original> =
partialShrinkerA.bind(partialShrinkerB).bind(partialShrinkerC).bind(partialShrinkerD)
.bind(partialShrinkerE).bind(partialShrinkerF).build { (abcde, f) ->
val (abcd, e) = abcde
val (abc, d) = abcd
val (ab, c) = abc
val (a, b) = ab
completeFn(a, b, c, d, e, f)
}
fun <Original, A, B, C, D, E, F, G> ShrinkerBuilder<Original>.build(
partialShrinkerA: PartialShrinker<Original, A>,
partialShrinkerB: PartialShrinker<Original, B>,
partialShrinkerC: PartialShrinker<Original, C>,
partialShrinkerD: PartialShrinker<Original, D>,
partialShrinkerE: PartialShrinker<Original, E>,
partialShrinkerF: PartialShrinker<Original, F>,
partialShrinkerG: PartialShrinker<Original, G>,
completeFn: Original.(A, B, C, D, E, F, G) -> Original
): Shrinker<Original> = partialShrinkerA.bind(partialShrinkerB).bind(partialShrinkerC)
.bind(partialShrinkerD).bind(partialShrinkerE).bind(partialShrinkerF)
.bind(partialShrinkerG).build { (abcdef, g) ->
val (abcde, f) = abcdef
val (abcd, e) = abcde
val (abc, d) = abcd
val (ab, c) = abc
val (a, b) = ab
completeFn(a, b, c, d, e, f, g)
}
fun <Original, A, B, C, D, E, F, G, H, T> ShrinkerBuilder<Original>.build(
partialShrinkerA: PartialShrinker<Original, A>,
partialShrinkerB: PartialShrinker<Original, B>,
partialShrinkerC: PartialShrinker<Original, C>,
partialShrinkerD: PartialShrinker<Original, D>,
partialShrinkerE: PartialShrinker<Original, E>,
partialShrinkerF: PartialShrinker<Original, F>,
partialShrinkerG: PartialShrinker<Original, G>,
partialShrinkerH: PartialShrinker<Original, H>,
completeFn: Original.(A, B, C, D, E, F, G, H) -> Original
): Shrinker<Original> = partialShrinkerA.bind(partialShrinkerB).bind(partialShrinkerC)
.bind(partialShrinkerD).bind(partialShrinkerE).bind(partialShrinkerF)
.bind(partialShrinkerG).bind(partialShrinkerH)
.build { (abcdefg, h) ->
val (abcdef, g) = abcdefg
val (abcde, f) = abcdef
val (abcd, e) = abcde
val (abc, d) = abcd
val (ab, c) = abc
val (a, b) = ab
completeFn(a, b, c, d, e, f, g, h)
}
fun <Original, A, B, C, D, E, F, G, H, I> ShrinkerBuilder<Original>.build(
partialShrinkerA: PartialShrinker<Original, A>,
partialShrinkerB: PartialShrinker<Original, B>,
partialShrinkerC: PartialShrinker<Original, C>,
partialShrinkerD: PartialShrinker<Original, D>,
partialShrinkerE: PartialShrinker<Original, E>,
partialShrinkerF: PartialShrinker<Original, F>,
partialShrinkerG: PartialShrinker<Original, G>,
partialShrinkerH: PartialShrinker<Original, H>,
partialShrinkerI: PartialShrinker<Original, I>,
completeFn: Original.(A, B, C, D, E, F, G, H, I) -> Original
): Shrinker<Original> = partialShrinkerA.bind(partialShrinkerB).bind(partialShrinkerC)
.bind(partialShrinkerD).bind(partialShrinkerE).bind(partialShrinkerF)
.bind(partialShrinkerG).bind(partialShrinkerH).bind(partialShrinkerI)
.build { (abcdefgh, i) ->
val (abcdefg, h) = abcdefgh
val (abcdef, g) = abcdefg
val (abcde, f) = abcdef
val (abcd, e) = abcde
val (abc, d) = abcd
val (ab, c) = abc
val (a, b) = ab
completeFn(a, b, c, d, e, f, g, h, i)
}
fun <Original, A, B, C, D, E, F, G, H, I, J> ShrinkerBuilder<Original>.build(
partialShrinkerA: PartialShrinker<Original, A>,
partialShrinkerB: PartialShrinker<Original, B>,
partialShrinkerC: PartialShrinker<Original, C>,
partialShrinkerD: PartialShrinker<Original, D>,
partialShrinkerE: PartialShrinker<Original, E>,
partialShrinkerF: PartialShrinker<Original, F>,
partialShrinkerG: PartialShrinker<Original, G>,
partialShrinkerH: PartialShrinker<Original, H>,
partialShrinkerI: PartialShrinker<Original, I>,
partialShrinkerJ: PartialShrinker<Original, J>,
completeFn: Original.(A, B, C, D, E, F, G, H, I, J) -> Original
): Shrinker<Original> = partialShrinkerA
.bind(partialShrinkerB)
.bind(partialShrinkerC)
.bind(partialShrinkerD)
.bind(partialShrinkerE)
.bind(partialShrinkerF)
.bind(partialShrinkerG)
.bind(partialShrinkerH)
.bind(partialShrinkerI)
.bind(partialShrinkerJ)
.build { (abcdefghi, j) ->
val (abcdefgh, i) = abcdefghi
val (abcdefg, h) = abcdefgh
val (abcdef, g) = abcdefg
val (abcde, f) = abcdef
val (abcd, e) = abcde
val (abc, d) = abcd
val (ab, c) = abc
val (a, b) = ab
completeFn(a, b, c, d, e, f, g, h, i, j)
}
fun <Original, Value> PartialShrinker<Original, Value>.build(
shrinkFn: Original.(Value) -> Original
) = object : Shrinker<Original> {
override fun shrink(
value: Original
): List<Original> {
return shrinker
.shrink(selection(value))
.map { shrinkFn(value, it) }
}
}
fun <Original, A, B> ShrinkerBuilder<Original>.bind(
selectionA: PartialShrinker<Original, A>,
selectionB: PartialShrinker<Original, B>,
) = selectionA.bind(selectionB)
fun <Original, A, B> PartialShrinker<Original, A>.bind(
other: PartialShrinker<Original, B>
) = PartialShrinker<Original, Pair<A, B>>(
{ this.selection(it) to other.selection(it) },
FlatmapShrinker(this.shrinker, other.shrinker)
)
class PartialShrinker<Original, V>(
val selection: (Original) -> V,
val shrinker: Shrinker<V>
) {
companion object
}
fun <T> Shrinker<T>.withCache() = when (this) {
is ShrinkerWithCache -> this
else -> ShrinkerWithCache(this)
}
open class ShrinkerWithCache<T>(
private val shrinker: Shrinker<T>
) : Shrinker<T> {
val shrinks = mutableMapOf<T, List<T>>()
override fun shrink(
value: T
) = shrinks.getOrPut(
value
) { shrinker.shrink(value) }
}
open class FlatmapShrinker<value1, value2>(
shrinker1: Shrinker<value1>,
shrinker2: Shrinker<value2>,
) : Shrinker<Pair<value1, value2>> {
val shrinker1 = shrinker1.withCache()
val shrinker2 = shrinker2.withCache()
override fun shrink(value: Pair<value1, value2>): List<Pair<value1, value2>> {
val shrinks1 = shrinker1.shrink(value.first)
val shrinks2 = shrinker2.shrink(value.second)
if (shrinks1.isEmpty() && shrinks2.isEmpty()) return emptyList()
val nonEmptyShrinks1 = shrinks1.ifEmpty { listOf(value.first) }
val nonEmptyShrinks2 = shrinks2.ifEmpty { listOf(value.second) }
return nonEmptyShrinks1.flatMap { value1 ->
nonEmptyShrinks2.map { value2 ->
value1 to value2
}
}
}
}
class ShrinkerBuilder<Original> {
fun <T> select(
lambda: Original.() -> T
) = ShrinkerSelectPart(lambda)
infix fun <T> ShrinkerSelectPart<Original, T>.shrinkWith(
shrinker: Shrinker<T>
) = PartialShrinker(selection, shrinker)
}
fun <Original> createShrinker(
shrinkerBuilder: ShrinkerBuilder<Original>.() -> Shrinker<Original>
) = ShrinkerBuilder<Original>().shrinkerBuilder()
tieskedh
12/18/2020, 8:16 PMval OrganisationShrinker = createShrinker<Organisation> {
build(
select { organisationID.value } shrinkWith StringShrinker,
Organisation::name shrinkWith StringShrinker,
Organisation::type shrinkWith StringShrinker,
Organisation::thumbnail shrinkWith StringShrinker,
Organisation::clientId shrinkWith IntShrinker(0..100)
) { orgId, name, type, thumb, clientId ->
copy(
OrganisationID(orgId),
name,
type,
clientId,
thumb,
baseUrl,
primaryColor
)
}
}
this can be achieved with the following code:sam
12/18/2020, 8:17 PMtieskedh
12/18/2020, 8:18 PMsam
12/18/2020, 8:18 PMsam
12/18/2020, 8:18 PMtieskedh
12/18/2020, 9:45 PM