Skip to content

Commit bc826b1

Browse files
authored
Fix kotest#2793 by handling the edge cases of lenient json number comparison (kotest#2794)
1 parent 0946823 commit bc826b1

File tree

3 files changed

+26
-10
lines changed

3 files changed

+26
-10
lines changed

kotest-assertions/kotest-assertions-json/src/commonMain/kotlin/io/kotest/assertions/json/compare.kt

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -377,23 +377,15 @@ private fun compareNumbers(
377377
}
378378
}
379379

380-
private val fractionalZeroesRegex =
381-
"""(\.\d*)0+""".toRegex()
382380

383381
private fun compareNumberNodes(
384382
path: List<String>,
385383
expected: JsonNode.NumberNode,
386384
actual: JsonNode.NumberNode
387385
): JsonError? {
388-
/**
389-
* Removes insignificant part of a number. e.g. 1.0 -> 1 or 3.1400 -> 3.14
390-
*/
391-
fun trimInsignificant(value: String): String =
392-
value.replace(fractionalZeroesRegex) { it.groupValues[1].trimEnd('0') }
393-
.trimEnd('.')
394386

395387
return when {
396-
trimInsignificant(expected.asString()) == trimInsignificant(actual.asString()) -> null
388+
expected.lenientEquals(actual) -> null
397389
else -> JsonError.UnequalValues(path, expected.content, actual.content)
398390
}
399391
}

kotest-assertions/kotest-assertions-json/src/commonMain/kotlin/io/kotest/assertions/json/nodes.kt

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,27 @@ sealed class JsonNode {
3737
private val exponentRegex = """.+[eE][+-]?\d+""".toRegex()
3838
}
3939

40-
fun asString() = if (content.matches(exponentRegex)) content.toDouble().toString() else content
40+
fun lenientEquals(other: NumberNode): Boolean {
41+
42+
if (other.content == content) return true
43+
44+
// if one or the other is exponent notation, we must compare by parsed value
45+
if (content.matches(exponentRegex) xor other.content.matches(exponentRegex)) {
46+
return content.toDouble() == other.content.toDouble()
47+
}
48+
49+
val fractionalZeroesRegex = """(\.\d*)0+$""".toRegex()
50+
/**
51+
* Removes insignificant part of a number. e.g. 1.0 -> 1 or 3.1400 -> 3.14
52+
*/
53+
fun trimInsignificant(value: String): String =
54+
value.replace(fractionalZeroesRegex) { it.groupValues[1].trimEnd('0') }
55+
.trimEnd('.')
56+
57+
return trimInsignificant(content) == trimInsignificant(other.content)
58+
59+
}
60+
4161
}
4262

4363
object NullNode : JsonNode(), ValueNode

kotest-assertions/kotest-assertions-json/src/jvmTest/kotlin/com/sksamuel/kotest/tests/json/JsonLiteralsTest.kt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,10 @@ class JsonLiteralsTest : FunSpec(
4646
"1000.0" shouldEqualJson "1000"
4747
"5E0" shouldEqualJson "5.0"
4848
"2E-1" shouldEqualJson "0.2"
49+
shouldFail {
50+
"1.0E-3" shouldEqualJson "0.0001"
51+
}
52+
"1.0E-4" shouldEqualJson "0.0001"
4953
}
5054

5155
test("comparing high-precision floating point numbers") {

0 commit comments

Comments
 (0)