use neco_json::{encode, parse, JsonValue};
#[test]
fn acceptance_1_and_2_crate_build_contract_is_visible_from_public_api() {
let value = parse(br#"{"ok":true}"#).expect("public parse should work");
assert_eq!(value.required_bool("ok"), Ok(true));
assert_eq!(
encode(&value).expect("public encode should work"),
br#"{"ok":true}"#
);
}
#[test]
fn acceptance_3_and_7_parse_complex_structure_and_read_with_accessors() {
let payload = br#"{
"repo":"did:plc:alice",
"active":true,
"score":42.5,
"profile":{"handle":"alice.test","labels":["dev",null,"cat"]},
"posts":[
{"id":"p1","counts":{"likes":3,"replies":0}},
{"id":"p2","counts":{"likes":5,"replies":1}}
]
}"#;
let value = parse(payload).expect("complex payload should parse");
assert_eq!(value.required_str("repo"), Ok("did:plc:alice"));
assert_eq!(value.required_bool("active"), Ok(true));
assert_eq!(value.required_f64("score"), Ok(42.5));
let profile = value.get("profile").expect("profile should exist");
assert_eq!(profile.required_str("handle"), Ok("alice.test"));
let labels = profile
.required_array("labels")
.expect("labels should be array");
assert_eq!(labels.len(), 3);
assert_eq!(labels[0].as_str(), Some("dev"));
assert!(labels[1].is_null());
assert_eq!(labels[2].as_str(), Some("cat"));
let posts = value
.required_array("posts")
.expect("posts should be array");
assert_eq!(posts.len(), 2);
let first = posts[0].as_object().expect("post should be object");
let first = JsonValue::Object(first.to_vec());
assert_eq!(first.required_str("id"), Ok("p1"));
let counts = first.get("counts").expect("counts should exist");
assert_eq!(counts.required_f64("likes"), Ok(3.0));
assert_eq!(counts.required_f64("replies"), Ok(0.0));
}
#[test]
fn acceptance_4_unicode_surrogate_pair_roundtrips_through_public_api() {
let value = parse(br#"{"emoji":"\uD83D\uDE80"}"#).expect("unicode payload should parse");
assert_eq!(value.required_str("emoji"), Ok("🚀"));
}
#[test]
fn acceptance_5_roundtrip_preserves_complex_value_equivalence() {
let value = JsonValue::Object(vec![
(
"meta".into(),
JsonValue::Object(vec![
("version".into(), JsonValue::Number(1.0)),
("cursor".into(), JsonValue::Null),
]),
),
(
"items".into(),
JsonValue::Array(vec![
JsonValue::Object(vec![
("id".into(), JsonValue::String("one".into())),
("enabled".into(), JsonValue::Bool(true)),
]),
JsonValue::Object(vec![
("id".into(), JsonValue::String("two".into())),
("enabled".into(), JsonValue::Bool(false)),
("score".into(), JsonValue::Number(-1.5e-3)),
]),
]),
),
(
"message".into(),
JsonValue::String("hello\u{0000}world".into()),
),
]);
let encoded = encode(&value).expect("encode should succeed");
let reparsed = parse(&encoded).expect("encoded value should parse");
assert_eq!(reparsed, value);
let items = reparsed
.required_array("items")
.expect("items should be array");
assert_eq!(items.len(), 2);
}
#[test]
fn acceptance_6_depth_limit_is_enforced() {
let mut input = vec![b'['; 129];
input.extend(vec![b']'; 129]);
let error = parse(&input).expect_err("depth overflow should fail");
assert!(matches!(
error.kind,
neco_json::ParseErrorKind::NestingTooDeep
));
}
#[test]
fn acceptance_8_end_to_end_atproto_like_payload_parses_and_accesses() {
let response = br#"{
"did":"did:plc:alice",
"handle":"alice.test",
"active":true,
"viewer":{"muted":false,"blockedBy":null},
"followersCount":128,
"labels":[{"val":"verified","src":"did:plc:labeler"}]
}"#;
let value = parse(response).expect("ATProto-like response should parse");
assert_eq!(value.required_str("did"), Ok("did:plc:alice"));
assert_eq!(value.required_str("handle"), Ok("alice.test"));
assert_eq!(value.required_bool("active"), Ok(true));
assert_eq!(value.required_f64("followersCount"), Ok(128.0));
let viewer = value.get("viewer").expect("viewer should exist");
assert_eq!(viewer.required_bool("muted"), Ok(false));
assert_eq!(viewer.optional_bool("blockedBy"), Ok(None));
let labels = value
.required_array("labels")
.expect("labels should be array");
assert_eq!(labels.len(), 1);
let label = labels[0].as_object().expect("label should be object");
let label = JsonValue::Object(label.to_vec());
assert_eq!(label.required_str("val"), Ok("verified"));
assert_eq!(label.required_str("src"), Ok("did:plc:labeler"));
}