Skip to content

Commit 8110a04

Browse files
cgwalterschamptar
andauthored
tests: Also test arbitrary floating point (#6)
* tests: Also test arbitrary floating point Signed-off-by: Colin Walters <[email protected]> Signed-off-by: Etienne Champetier <[email protected]> Co-authored-by: Etienne Champetier <[email protected]>
1 parent de391b8 commit 8110a04

File tree

2 files changed

+24
-6
lines changed

2 files changed

+24
-6
lines changed

Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,3 +21,5 @@ sha2 = "0.10.9"
2121
# For cross-integration testing
2222
olpc-cjson = "0.1"
2323
cjson = "0.1.2"
24+
# For round trip testing
25+
serde_json = { version = "1.0", features = ["float_roundtrip"] }

src/lib.rs

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -553,11 +553,27 @@ mod tests {
553553
assert_eq!(&buf, &expected);
554554
}
555555

556-
fn arbitrary_json(keyspace: &'static str) -> impl Strategy<Value = serde_json::Value> {
556+
/// As it says, generate arbitrary JSON. This is based on
557+
/// https://proptest-rs.github.io/proptest/proptest/tutorial/recursive.html
558+
///
559+
/// We support controlling the regex for keys, and whether or not floating point values are emitted.
560+
fn arbitrary_json(
561+
keyspace: &'static str,
562+
allow_fp: bool,
563+
) -> impl Strategy<Value = serde_json::Value> {
557564
use serde_json::Value;
558565
let leaf = prop_oneof![
559566
Just(Value::Null),
560-
any::<u32>().prop_map(|v| Value::Number(Number::from_u128(v.into()).unwrap())),
567+
any::<f64>().prop_filter_map("valid f64 for JSON", move |v| {
568+
let n = if allow_fp && v.fract() != 0.0 {
569+
Number::from_f64(v).unwrap()
570+
} else {
571+
// Constrain to values clearly lower than
572+
// the https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/MAX_SAFE_INTEGER
573+
Number::from_u128(v as u32 as u128).unwrap()
574+
};
575+
Some(Value::Number(n))
576+
}),
561577
any::<bool>().prop_map(Value::Bool),
562578
keyspace.prop_map(Value::String),
563579
];
@@ -578,7 +594,7 @@ mod tests {
578594

579595
proptest! {
580596
#[test]
581-
fn roundtrip_rfc8785(v in arbitrary_json(".*")) {
597+
fn roundtrip_rfc8785(v in arbitrary_json(".*", true)) {
582598
let buf = encode!(&v).unwrap();
583599
let v2: serde_json::Value = serde_json::from_slice(&buf)
584600
.map_err(|e| format!("Failed to parse {v:?} -> {}: {e}", String::from_utf8_lossy(&buf))).unwrap();
@@ -684,7 +700,7 @@ mod tests {
684700
proptest! {
685701
// Verify strict equivalency with printable ASCII only keys
686702
#[test]
687-
fn crosscheck_olpc_cjson_ascii(v in arbitrary_json(ASCII_ALPHANUMERIC)) {
703+
fn crosscheck_olpc_cjson_ascii(v in arbitrary_json(ASCII_ALPHANUMERIC, false)) {
688704
let canon_json = String::from_utf8(encode!(&v).unwrap()).unwrap();
689705
let mut olpc_cjson_serialized = Vec::new();
690706
let mut ser = serde_json::Serializer::with_formatter(&mut olpc_cjson_serialized, olpc_cjson::CanonicalFormatter::new());
@@ -696,15 +712,15 @@ mod tests {
696712
proptest! {
697713
// Verify strict equivalency with printable ASCII only keys
698714
#[test]
699-
fn crosscheck_cjson_ascii(v in arbitrary_json(ASCII_ALPHANUMERIC)) {
715+
fn crosscheck_cjson_ascii(v in arbitrary_json(ASCII_ALPHANUMERIC, false)) {
700716
let canon_json = String::from_utf8(encode!(&v).unwrap()).unwrap();
701717
let cjson = String::from_utf8(cjson::to_vec(&v).unwrap()).unwrap();
702718
assert_eq!(canon_json, cjson);
703719
}
704720

705721
// Verify equivalency (after sorting) with non-ASCII keys
706722
#[test]
707-
fn crosscheck_cjson(v in arbitrary_json(".*")) {
723+
fn crosscheck_cjson(v in arbitrary_json(".*", false)) {
708724
let buf = encode!(&v).unwrap();
709725
let self_reparsed = serde_json::from_slice::<serde_json::Value>(&buf).unwrap();
710726
let buf = cjson::to_vec(&v).unwrap();

0 commit comments

Comments
 (0)