use serde_fjson::{parse, stringify}; use serde_json::{Value, json}; #[test] fn parses_every_json_root_and_disambiguates_implicit_keys() { for (source, expected) in [ ("null", Value::Null), ("false /* tail */", json!(false)), ("// head\n42", json!(42)), ("-1.25e2", json!(-125.0)), ("'šŸ˜€'", json!("šŸ˜€")), ( "[1\ntrue\nnull\n{label: 'ok'}]", json!([1, true, null, {"label": "ok"}]), ), ("{}", json!({})), ("// empty", json!({})), ("true /* : */ : false", json!({"true": false})), ("'quoted'\n/* keep */ : 1", json!({"quoted": 1})), ("'not a key' /* : */", json!("not a key")), ( "name: 'fJSON'\nflags: [true, false,]", json!({"name": "fJSON", "flags": [true, false]}), ), ] { assert_eq!(parse(source).unwrap(), expected, "{source}"); } } #[test] fn numbers_convert_with_json_range_errors_at_the_original_span() { assert_eq!( parse("9007199254740993").unwrap(), json!(9007199254740993_u64) ); assert_eq!(parse("18446744073709551615").unwrap(), json!(u64::MAX)); let source = "number: 1e9999"; let error = parse(source).unwrap_err(); assert_eq!(&source[error.span.clone()], "1e9999"); assert_eq!(error.kind, serde_fjson::ErrorKind::Number); assert_eq!( error.render("test.fjson", source), "test.fjson:1:9: Invalid or out-of-range JSON number" ); } #[test] fn rejects_trailing_values_duplicates_and_invalid_roots() { for source in [ "1 2", "'a' 'b'", "[1],", "true, false", "bare", "a: 1\na: 2", "{a: 1} extra: 2", ] { assert!(parse(source).is_err(), "{source}"); } let source = "a: 'šŸ˜€'\n'\\u0061': false"; let error = parse(source).unwrap_err(); assert_eq!( error.render("test", source), "test:2:1: Duplicate key \"a\"\ntest:1:1: First defined here" ); } #[test] fn pretty_output_uses_fjson_keys_and_balanced_nested_indentation() { let value = json!({ "name": "fJSON", "options": {"enabled": true, "targets": ["linux", "macos"]}, "@scope/pkg": {"$valid_key2": "šŸ˜€\nquoted \"text\""}, }); let printed = stringify(&value).unwrap(); assert_eq!( printed, r#"name: "fJSON" options: { enabled: true targets: ["linux", "macos"] } "@scope/pkg": { $valid_key2: "šŸ˜€\nquoted \"text\"" }"# ); assert_eq!(parse(&printed).unwrap(), value); } #[test] fn long_arrays_expand_and_printing_is_stable() { let value = json!({ "records": [{"x": [1, 2]}, {"x": [null, false]}], "long": (0..40).collect::>(), }); let text = stringify(&value).unwrap(); assert!(text.contains("long: [\n")); assert!(text.lines().all(|line| line.chars().count() <= 80)); assert!(text.contains(" x: [1, 2]\n }")); assert_eq!(parse(&text).unwrap(), value); assert_eq!(stringify(&parse(&text).unwrap()).unwrap(), text); } #[test] fn parser_and_printer_accept_the_same_nesting_depths() { for leaf in [json!(null), json!([]), json!({})] { let mut value = leaf; for _ in 0..132 { for value in [&value, &json!({"root": value})] { let encoded = serde_json::to_string(value).unwrap(); let parsed = parse(&encoded); let printed = stringify(value); assert_eq!(printed.is_ok(), parsed.is_ok(), "{encoded}"); match printed { Ok(text) => assert_eq!(parse(&text).unwrap(), *value), Err(error) => { assert_eq!(error.kind, serde_fjson::ErrorKind::Nesting); assert_eq!(parsed.unwrap_err().kind, error.kind); } } } value = json!([value]); } } } #[test] fn arbitrary_json_values_round_trip_including_escaped_keys() { for value in [ json!(null), json!(true), json!(42), json!(-0.125), json!("\0\tšŸ˜€"), json!([]), json!({}), json!([{}, [], null]), json!({"0": 1, "": 2, "true": 3, "some-key": 4, "ę—„ęœ¬čŖž": "\r\n", "__proto__": {"ok": true}}), ] { let text = stringify(&value).unwrap(); assert_eq!(parse(&text).unwrap(), value, "{text}"); } }