是否有更简洁的方法来断言数组的每个元素都匹配一个谓词?
Is there a more concise way to assert that an array's elements each match a predicate?
我们都知道您不应该断言浮点数完全相等。 assertk
提供了一种更好的便捷方法:
assertThat(value).isCloseTo(3.0, 0.000001)
我想将其扩展到数组:
assertThat(array).isCloseTo(doubleArrayOf(2.0, 3.0), 0.000001)
但我能做的最好的是:
fun Assert<DoubleArray>.isCloseTo(expected: DoubleArray, delta: Double) {
hasSameSizeAs(expected)
this.matchesPredicate { actual : DoubleArray ->
expected.indices.forEach { index ->
if (!actual[index].isCloseTo(expected[index], epsilon)) {
return@matchesPredicate false
}
}
true
}
}
fun Double.isCloseTo(expected: Double, epsilon: Double): Boolean {
abs(this - expected) <= epsilon
}
有什么方法可以将这个 matchesPredicate
减少为类似(伪代码)的东西:
hasElementsMatchingPredicate { index, actual ->
actual.isCloseTo(expected, epsilon)
}
回答标题中的问题:
assert that an array's elements each match a predicate
您可以为 DoubleArray
编写一个新的 AssertK 断言:
fun Assert<DoubleArray>.allMatchPredicate(f: (Double) -> Boolean) = given { actual ->
if (actual.all(f)) return
val rejected = actual.filterNot(f)
expected("all items to satisfy the predicate, but these items didn't: ${show(rejected)}")
}
然后像这样使用它:
@Test
fun test() {
val positive = doubleArrayOf(1.0, 2.0, 3.0)
val mixed = doubleArrayOf(-1.0, 1.0, -4.0)
assertThat(positive).allMatchPredicate { it > 0.0 }
assertThat(mixed).allMatchPredicate { it > 0.0 }
}
结果:
org.opentest4j.AssertionFailedError: expected all items to satisfy the predicate, but these items didn't: <[-1.0, -4.0]>
要比较两个 DoubleArrays
,如问题 body 所要求的,您可以这样做:
fun Assert<DoubleArray>.allCloseTo(expected: DoubleArray, delta: Double) = given { actual ->
if (actual.size != expected.size)
expected("array to have size ${expected.size} but was ${actual.size}")
val rejected = actual.asSequence()
.withIndex().filterNot {
// adapted from Assert<Double>.isCloseTo
it.value >= expected[it.index].minus(delta) &&
it.value <= expected[it.index].plus(delta)
}
.map { it.value }.toList()
if (rejected.isNotEmpty())
expected("all items to satisfy the predicate, but these items didn't: ${show(rejected)}")
}
用法:
@Test
fun test() {
val same = doubleArrayOf(1.001, 2.001, 3.001)
val diff = doubleArrayOf(1.1, 2.001, 3.1)
val expected = doubleArrayOf(1.0, 2.0, 3.0)
assertThat(same).allCloseTo(expected, 0.01)
assertThat(diff).allCloseTo(expected, 0.01)
}
结果:
org.opentest4j.AssertionFailedError: expected all items to satisfy the predicate, but these items didn't: <[1.1, 3.1]>
我们都知道您不应该断言浮点数完全相等。 assertk
提供了一种更好的便捷方法:
assertThat(value).isCloseTo(3.0, 0.000001)
我想将其扩展到数组:
assertThat(array).isCloseTo(doubleArrayOf(2.0, 3.0), 0.000001)
但我能做的最好的是:
fun Assert<DoubleArray>.isCloseTo(expected: DoubleArray, delta: Double) {
hasSameSizeAs(expected)
this.matchesPredicate { actual : DoubleArray ->
expected.indices.forEach { index ->
if (!actual[index].isCloseTo(expected[index], epsilon)) {
return@matchesPredicate false
}
}
true
}
}
fun Double.isCloseTo(expected: Double, epsilon: Double): Boolean {
abs(this - expected) <= epsilon
}
有什么方法可以将这个 matchesPredicate
减少为类似(伪代码)的东西:
hasElementsMatchingPredicate { index, actual ->
actual.isCloseTo(expected, epsilon)
}
回答标题中的问题:
assert that an array's elements each match a predicate
您可以为 DoubleArray
编写一个新的 AssertK 断言:
fun Assert<DoubleArray>.allMatchPredicate(f: (Double) -> Boolean) = given { actual ->
if (actual.all(f)) return
val rejected = actual.filterNot(f)
expected("all items to satisfy the predicate, but these items didn't: ${show(rejected)}")
}
然后像这样使用它:
@Test
fun test() {
val positive = doubleArrayOf(1.0, 2.0, 3.0)
val mixed = doubleArrayOf(-1.0, 1.0, -4.0)
assertThat(positive).allMatchPredicate { it > 0.0 }
assertThat(mixed).allMatchPredicate { it > 0.0 }
}
结果:
org.opentest4j.AssertionFailedError: expected all items to satisfy the predicate, but these items didn't: <[-1.0, -4.0]>
要比较两个 DoubleArrays
,如问题 body 所要求的,您可以这样做:
fun Assert<DoubleArray>.allCloseTo(expected: DoubleArray, delta: Double) = given { actual ->
if (actual.size != expected.size)
expected("array to have size ${expected.size} but was ${actual.size}")
val rejected = actual.asSequence()
.withIndex().filterNot {
// adapted from Assert<Double>.isCloseTo
it.value >= expected[it.index].minus(delta) &&
it.value <= expected[it.index].plus(delta)
}
.map { it.value }.toList()
if (rejected.isNotEmpty())
expected("all items to satisfy the predicate, but these items didn't: ${show(rejected)}")
}
用法:
@Test
fun test() {
val same = doubleArrayOf(1.001, 2.001, 3.001)
val diff = doubleArrayOf(1.1, 2.001, 3.1)
val expected = doubleArrayOf(1.0, 2.0, 3.0)
assertThat(same).allCloseTo(expected, 0.01)
assertThat(diff).allCloseTo(expected, 0.01)
}
结果:
org.opentest4j.AssertionFailedError: expected all items to satisfy the predicate, but these items didn't: <[1.1, 3.1]>