1#![cfg_attr(not(feature = "std"), no_std)]
43#![forbid(unsafe_code)]
44#![warn(missing_docs)]
45
46extern crate alloc;
47
48mod error;
49mod limits;
50mod number;
51mod parse;
52mod value;
53mod write;
54
55pub use error::{
56 JsonError, JsonErrorKind, JsonLimitKind, JsonNumberError, JsonPath, JsonPathSegment,
57};
58pub use limits::JsonLimits;
59pub use number::JsonNumber;
60pub use parse::{parse, parse_str, parse_with_limits};
61pub use value::{JsonMember, JsonObject, JsonValue};
62pub use write::{to_compact_string, to_compact_vec};
63
64#[cfg(test)]
65mod tests {
66 use super::*;
67 use alloc::string::{String, ToString};
68
69 fn parse_ok(input: &str) -> JsonValue {
70 parse_str(input).expect("should parse")
71 }
72
73 fn kind(input: &str) -> JsonErrorKind {
74 parse_str(input).expect_err("should fail").kind().clone()
75 }
76
77 #[test]
80 fn parses_scalars() {
81 assert_eq!(parse_ok("null"), JsonValue::Null);
82 assert_eq!(parse_ok("true"), JsonValue::Bool(true));
83 assert_eq!(parse_ok("false"), JsonValue::Bool(false));
84 assert_eq!(parse_ok("\"hi\"").as_str(), Some("hi"));
85 assert_eq!(parse_ok("42").as_number().unwrap().to_i64().unwrap(), 42);
86 }
87
88 #[test]
89 fn whitespace_is_allowed_around_values() {
90 assert_eq!(parse_ok(" \t\r\n 7 \n").as_number().unwrap().as_str(), "7");
91 }
92
93 #[test]
94 fn only_json_whitespace_is_accepted() {
95 assert_eq!(kind("\u{0B}1"), JsonErrorKind::UnexpectedByte);
97 }
98
99 #[test]
102 fn parses_object_and_array() {
103 let value = parse_ok(r#"{"a":[1,2,3],"b":{"c":null}}"#);
104 let obj = value.as_object().unwrap();
105 assert_eq!(obj.len(), 2);
106 assert_eq!(obj.get("a").unwrap().as_array().unwrap().len(), 3);
107 assert!(obj
108 .get("b")
109 .unwrap()
110 .as_object()
111 .unwrap()
112 .get("c")
113 .unwrap()
114 .is_null());
115 }
116
117 #[test]
118 fn empty_containers() {
119 assert_eq!(parse_ok("[]").as_array().unwrap().len(), 0);
120 assert_eq!(parse_ok("{}").as_object().unwrap().len(), 0);
121 }
122
123 #[test]
126 fn rejects_trailing_data() {
127 assert_eq!(kind("1 2"), JsonErrorKind::TrailingData);
128 assert_eq!(kind("{} x"), JsonErrorKind::TrailingData);
129 }
130
131 #[test]
132 fn rejects_comments_and_trailing_commas() {
133 assert_eq!(kind("1 // c"), JsonErrorKind::TrailingData);
134 assert_eq!(kind("[1,]"), JsonErrorKind::UnexpectedByte);
135 assert_eq!(kind(r#"{"a":1,}"#), JsonErrorKind::UnexpectedByte);
136 }
137
138 #[test]
139 fn rejects_bad_numbers() {
140 for bad in ["01", "1.", "-", "1e", "1e+", "00", "1.2.3"] {
141 assert_eq!(kind(bad), JsonErrorKind::InvalidNumber, "input {bad:?}");
142 }
143 assert_eq!(kind(".5"), JsonErrorKind::UnexpectedByte);
146 assert_eq!(kind("+1"), JsonErrorKind::UnexpectedByte);
147 assert_eq!(kind("0x1"), JsonErrorKind::TrailingData);
148 }
149
150 #[test]
151 fn rejects_nan_and_infinity() {
152 assert_eq!(kind("NaN"), JsonErrorKind::UnexpectedByte);
153 assert_eq!(kind("Infinity"), JsonErrorKind::UnexpectedByte);
154 assert_eq!(kind("-Infinity"), JsonErrorKind::InvalidNumber);
155 }
156
157 #[test]
158 fn rejects_unescaped_control_and_bad_escapes() {
159 assert_eq!(kind("\"\u{01}\""), JsonErrorKind::UnescapedControlCharacter);
160 assert_eq!(kind(r#""\x""#), JsonErrorKind::InvalidEscape);
161 assert_eq!(kind(r#""\u00""#), JsonErrorKind::InvalidUnicodeEscape);
162 }
163
164 #[test]
165 fn rejects_lone_surrogates() {
166 assert_eq!(kind(r#""\uD800""#), JsonErrorKind::LoneSurrogate);
167 assert_eq!(kind(r#""\uDC00""#), JsonErrorKind::LoneSurrogate);
168 assert_eq!(kind(r#""\uD800a""#), JsonErrorKind::LoneSurrogate);
169 }
170
171 #[test]
172 fn accepts_valid_surrogate_pair() {
173 assert_eq!(parse_ok(r#""𝄞""#).as_str(), Some("\u{1D11E}"));
174 }
175
176 #[test]
177 fn rejects_invalid_utf8_and_bom() {
178 assert_eq!(
179 parse(&[0xff]).unwrap_err().kind().clone(),
180 JsonErrorKind::InvalidUtf8
181 );
182 assert_eq!(
183 parse(&[0xEF, 0xBB, 0xBF, b'1']).unwrap_err().kind().clone(),
184 JsonErrorKind::InvalidUtf8
185 );
186 }
187
188 #[test]
191 fn escape_and_literal_decode_equally() {
192 assert_eq!(parse_ok(r#""a""#), parse_ok(r#""a""#));
193 }
194
195 #[test]
196 fn decodes_named_escapes() {
197 assert_eq!(
198 parse_ok(r#""\n\t\r\b\f\"\\\/""#).as_str(),
199 Some("\n\t\r\u{08}\u{0C}\"\\/")
200 );
201 }
202
203 #[test]
206 fn rejects_duplicate_keys() {
207 assert_eq!(kind(r#"{"a":1,"a":2}"#), JsonErrorKind::DuplicateKey);
208 }
209
210 #[test]
211 fn duplicate_detection_is_after_escape_decoding() {
212 assert_eq!(
213 kind(r#"{"role":"user","role":"admin"}"#),
214 JsonErrorKind::DuplicateKey
215 );
216 }
217
218 #[test]
221 fn enforces_depth_limit() {
222 let limits = JsonLimits::new().with_max_depth(3);
223 assert!(parse_with_limits(b"[[[1]]]", limits).is_ok());
224 assert_eq!(
225 parse_with_limits(b"[[[[1]]]]", limits)
226 .unwrap_err()
227 .kind()
228 .clone(),
229 JsonErrorKind::LimitExceeded(JsonLimitKind::Depth)
230 );
231 }
232
233 #[test]
234 fn enforces_count_limits() {
235 let limits = JsonLimits::new();
236 let limits = JsonLimits {
237 max_array_items: 2,
238 max_object_members: 2,
239 max_total_nodes: 100,
240 ..limits
241 };
242 assert_eq!(
243 parse_with_limits(b"[1,2,3]", limits)
244 .unwrap_err()
245 .kind()
246 .clone(),
247 JsonErrorKind::LimitExceeded(JsonLimitKind::ArrayItems)
248 );
249 assert_eq!(
250 parse_with_limits(br#"{"a":1,"b":2,"c":3}"#, limits)
251 .unwrap_err()
252 .kind()
253 .clone(),
254 JsonErrorKind::LimitExceeded(JsonLimitKind::ObjectMembers)
255 );
256 }
257
258 #[test]
259 fn enforces_total_nodes_and_input_bytes() {
260 let nodes = JsonLimits::new().with_max_total_nodes(2);
261 assert_eq!(
262 parse_with_limits(b"[1,2]", nodes)
263 .unwrap_err()
264 .kind()
265 .clone(),
266 JsonErrorKind::LimitExceeded(JsonLimitKind::TotalNodes)
267 );
268 let bytes = JsonLimits::new().with_max_input_bytes(2);
269 assert_eq!(
270 parse_with_limits(b"[1]", bytes).unwrap_err().kind().clone(),
271 JsonErrorKind::LimitExceeded(JsonLimitKind::InputBytes)
272 );
273 }
274
275 #[test]
276 fn enforces_string_and_number_byte_limits() {
277 let s = JsonLimits {
278 max_string_bytes: 3,
279 ..JsonLimits::new()
280 };
281 assert_eq!(
282 parse_with_limits(br#""abcd""#, s)
283 .unwrap_err()
284 .kind()
285 .clone(),
286 JsonErrorKind::LimitExceeded(JsonLimitKind::StringBytes)
287 );
288 let n = JsonLimits {
289 max_number_bytes: 2,
290 ..JsonLimits::new()
291 };
292 assert_eq!(
293 parse_with_limits(b"12345", n).unwrap_err().kind().clone(),
294 JsonErrorKind::LimitExceeded(JsonLimitKind::NumberBytes)
295 );
296 }
297
298 #[test]
301 fn number_conversions() {
302 assert_eq!(parse_ok("-7").as_number().unwrap().to_i64().unwrap(), -7);
303 assert_eq!(parse_ok("7").as_number().unwrap().to_u64().unwrap(), 7);
304 assert!((parse_ok("1.5").as_number().unwrap().to_f64().unwrap() - 1.5).abs() < 1e-12);
305 assert_eq!(
306 parse_ok("1.5").as_number().unwrap().to_i64(),
307 Err(JsonNumberError::NotAnInteger)
308 );
309 assert_eq!(
310 parse_ok("99999999999999999999999")
311 .as_number()
312 .unwrap()
313 .to_i64(),
314 Err(JsonNumberError::OutOfRange)
315 );
316 assert_eq!(
317 parse_ok("1e400").as_number().unwrap().to_f64(),
318 Err(JsonNumberError::NotFinite)
319 );
320 }
321
322 #[test]
323 fn number_preserves_representation() {
324 assert_eq!(parse_ok("1.0").as_number().unwrap().as_str(), "1.0");
325 assert_ne!(parse_ok("1.0"), parse_ok("1")); }
327
328 #[test]
329 fn json_number_from_f64() {
330 assert_eq!(JsonNumber::try_from_f64(1.5).unwrap().as_str(), "1.5");
331 assert_eq!(
332 JsonNumber::try_from_f64(f64::NAN),
333 Err(JsonNumberError::NotFinite)
334 );
335 assert_eq!(
336 JsonNumber::try_from_f64(f64::INFINITY),
337 Err(JsonNumberError::NotFinite)
338 );
339 assert_eq!(JsonNumber::new("01"), Err(JsonNumberError::InvalidNumber));
340 }
341
342 #[test]
345 fn error_reports_location_and_path() {
346 let err = parse_str(" @").unwrap_err();
347 assert_eq!(err.kind().clone(), JsonErrorKind::UnexpectedByte);
348 assert_eq!(err.offset(), 2);
349 assert_eq!(err.line(), 1);
350 assert_eq!(err.column(), 3);
351
352 let err = parse_str(r#"{"users":[{"name":1},{"name":}]}"#).unwrap_err();
353 let path = err.path().unwrap().to_string();
354 assert_eq!(path, "$.users[1].name");
355 }
356
357 #[test]
360 fn compact_roundtrip_and_golden_bytes() {
361 let value = parse_ok(r#"{"a":1,"b":true,"c":[null,"x"]}"#);
362 assert_eq!(
363 to_compact_vec(&value),
364 br#"{"a":1,"b":true,"c":[null,"x"]}"#
365 );
366 let again = parse_str(&to_compact_string(&value)).unwrap();
368 assert_eq!(value, again);
369 }
370
371 #[test]
372 fn writer_escapes_control_and_special_characters() {
373 let mut object = JsonObject::new();
374 object.insert(
375 String::from("k"),
376 JsonValue::String(String::from("a\nb\"c\\\u{01}")),
377 );
378 let value = JsonValue::Object(object);
379 assert_eq!(to_compact_string(&value), r#"{"k":"a\nb\"c\\\u0001"}"#);
380 }
381
382 #[test]
383 fn object_insert_replaces_in_place() {
384 let mut object = JsonObject::new();
385 assert!(object
386 .insert(String::from("a"), JsonValue::Bool(true))
387 .is_none());
388 let old = object.insert(String::from("a"), JsonValue::Bool(false));
389 assert_eq!(old, Some(JsonValue::Bool(true)));
390 assert_eq!(object.len(), 1);
391 }
392
393 #[test]
394 fn deeply_nested_within_limits_does_not_overflow() {
395 let depth = 64;
397 let mut s = String::new();
398 for _ in 0..depth {
399 s.push('[');
400 }
401 s.push('1');
402 for _ in 0..depth {
403 s.push(']');
404 }
405 let _ = parse_str(&s); assert!(parse_with_limits(s.as_bytes(), JsonLimits::new().with_max_depth(64)).is_ok());
408 }
409
410 #[test]
411 fn arbitrary_bytes_never_panic() {
412 for input in [
414 &b""[..],
415 b" ",
416 b"{",
417 b"[",
418 b"\"",
419 b"\"\\",
420 b"\"\\u",
421 b"tru",
422 b"-",
423 b"[,]",
424 b"{,}",
425 b"\xff\xfe",
426 b"[[[",
427 b"}}}",
428 b"\"\\uD800\"",
429 b"1e",
430 b"{\"a\"}",
431 ] {
432 let _ = parse(input);
433 }
434 }
435
436 #[test]
437 fn value_accessors_return_inner_or_none() {
438 let v = parse_ok(r#"{"b":true,"n":7,"s":"x","a":[1],"nil":null}"#);
439 let o = v.as_object().expect("object");
440 assert!(o.get("nil").unwrap().is_null());
441 assert_eq!(o.get("b").unwrap().as_bool(), Some(true));
442 assert_eq!(o.get("s").unwrap().as_str(), Some("x"));
443 assert_eq!(o.get("n").unwrap().as_number().unwrap().as_str(), "7");
444 assert_eq!(o.get("a").unwrap().as_array().unwrap().len(), 1);
445
446 let b = JsonValue::Bool(true);
448 assert!(!b.is_null());
449 assert_eq!(b.as_str(), None);
450 assert_eq!(b.as_number(), None);
451 assert_eq!(b.as_array(), None);
452 assert!(b.as_object().is_none());
453 assert_eq!(JsonValue::Null.as_bool(), None);
454 }
455
456 #[test]
457 fn object_insert_get_iter_and_len() {
458 let mut obj = JsonObject::new();
459 assert!(obj.is_empty());
460 assert_eq!(obj.len(), 0);
461 assert!(!obj.contains_key("k"));
462
463 assert_eq!(obj.insert("k".to_string(), JsonValue::Bool(false)), None);
464 assert!(obj.contains_key("k"));
465 assert_eq!(obj.len(), 1);
466
467 let old = obj.insert("k".to_string(), JsonValue::Bool(true));
469 assert_eq!(old, Some(JsonValue::Bool(false)));
470 assert_eq!(obj.len(), 1);
471 assert_eq!(obj.get("k"), Some(&JsonValue::Bool(true)));
472 assert_eq!(obj.get("missing"), None);
473
474 obj.insert("k2".to_string(), JsonValue::Null);
475 let members: Vec<&str> = obj.iter().map(|m| m.key()).collect();
476 assert_eq!(members, ["k", "k2"]);
477 assert_eq!(obj.iter().next().unwrap().value(), &JsonValue::Bool(true));
478
479 assert_eq!(JsonObject::default().len(), 0);
480 }
481
482 #[test]
483 fn number_conversions_cover_each_error() {
484 let int = JsonNumber::new("42").unwrap();
485 assert!(int.is_integer());
486 assert_eq!(int.to_i64(), Ok(42));
487 assert_eq!(int.to_u64(), Ok(42));
488 assert_eq!(int.to_f64(), Ok(42.0));
489
490 let neg = JsonNumber::new("-1").unwrap();
491 assert_eq!(neg.to_u64(), Err(JsonNumberError::OutOfRange));
492
493 let frac = JsonNumber::new("1.5").unwrap();
494 assert!(!frac.is_integer());
495 assert_eq!(frac.to_i64(), Err(JsonNumberError::NotAnInteger));
496 assert_eq!(frac.to_u64(), Err(JsonNumberError::NotAnInteger));
497 assert_eq!(frac.to_f64(), Ok(1.5));
498
499 let huge = JsonNumber::new("99999999999999999999").unwrap();
500 assert_eq!(huge.to_i64(), Err(JsonNumberError::OutOfRange));
501
502 let overflow = JsonNumber::new("1e400").unwrap();
503 assert_eq!(overflow.to_f64(), Err(JsonNumberError::NotFinite));
504
505 assert_eq!(JsonNumber::new("+1"), Err(JsonNumberError::InvalidNumber));
506 assert_eq!(JsonNumber::try_from_f64(2.5).unwrap().to_f64(), Ok(2.5));
507 assert_eq!(
508 JsonNumber::try_from_f64(f64::NAN),
509 Err(JsonNumberError::NotFinite)
510 );
511 assert_eq!(
512 JsonNumber::try_from_f64(f64::INFINITY),
513 Err(JsonNumberError::NotFinite)
514 );
515 }
516
517 #[test]
518 fn limits_profiles_and_builders() {
519 assert_eq!(JsonLimits::default(), JsonLimits::new());
520 assert!(JsonLimits::conservative().max_input_bytes < JsonLimits::new().max_input_bytes);
521 assert!(JsonLimits::permissive().max_input_bytes > JsonLimits::new().max_input_bytes);
522
523 let tuned = JsonLimits::new()
524 .with_max_depth(8)
525 .with_max_input_bytes(1024)
526 .with_max_string_bytes(16)
527 .with_max_total_nodes(32);
528 assert_eq!(tuned.max_depth, 8);
529 assert_eq!(tuned.max_input_bytes, 1024);
530 assert_eq!(tuned.max_string_bytes, 16);
531 assert_eq!(tuned.max_total_nodes, 32);
532 }
533
534 #[test]
535 fn error_display_covers_each_kind() {
536 let cases: &[(&str, &str)] = &[
538 ("", "unexpected end of input"),
539 ("@", "unexpected byte"),
540 ("\"a\\xb\"", "invalid escape sequence"),
541 ("\"\\uZZZZ\"", "invalid unicode escape"),
542 ("\"\\uD800\"", "unpaired UTF-16 surrogate"),
543 ("01", "invalid number"),
544 ("{\"a\":1,\"a\":2}", "duplicate object key"),
545 ("true false", "trailing data after JSON value"),
546 ];
547 for (input, expected) in cases {
548 let err = parse_str(input).unwrap_err();
549 assert!(
550 err.to_string().contains(expected),
551 "input {input:?} -> {err} (expected to contain {expected:?})"
552 );
553 }
554
555 let ctrl = parse(b"\"\x01\"").unwrap_err();
557 assert!(ctrl.to_string().contains("unescaped control character"));
558
559 let utf8 = parse(b"\xff").unwrap_err();
561 assert!(utf8.to_string().contains("invalid UTF-8"));
562 }
563
564 #[test]
565 fn error_accessors_and_limit_display_with_path() {
566 let limits = JsonLimits::new().with_max_depth(1);
567 let err = parse_with_limits(b"[[1]]", limits).unwrap_err();
568 assert_eq!(
569 err.kind(),
570 &JsonErrorKind::LimitExceeded(JsonLimitKind::Depth)
571 );
572 assert!(err.offset() >= 1);
573 assert_eq!(err.line(), 1);
574 assert!(err.column() >= 1);
575 let shown = err.to_string();
576 assert!(shown.contains("limit exceeded: nesting depth"));
577 assert!(shown.contains("path: $"));
578 assert_eq!(JsonLimitKind::Depth.as_str(), "nesting depth");
579 }
580
581 #[test]
582 fn path_display_formats_keys_and_indices() {
583 let path = JsonPath::from_segments(vec![
584 JsonPathSegment::Key("users".to_string()),
585 JsonPathSegment::Index(3),
586 JsonPathSegment::Key("email".to_string()),
587 ]);
588 assert_eq!(path.to_string(), "$.users[3].email");
589 assert_eq!(path.segments().len(), 3);
590 assert_eq!(JsonPath::default().to_string(), "$");
591 }
592
593 #[test]
594 fn number_error_display_is_distinct() {
595 assert_eq!(
596 JsonNumberError::OutOfRange.to_string(),
597 "number out of range for target type"
598 );
599 assert_eq!(
600 JsonNumberError::NotAnInteger.to_string(),
601 "number is not an integer"
602 );
603 assert_eq!(
604 JsonNumberError::NotFinite.to_string(),
605 "number is not finite"
606 );
607 assert_eq!(
608 JsonNumberError::InvalidNumber.to_string(),
609 "not a valid JSON number"
610 );
611 }
612
613 #[test]
614 fn writer_serializes_all_branches() {
615 let mut obj = JsonObject::new();
616 obj.insert("off".to_string(), JsonValue::Bool(false));
617 obj.insert(
618 "esc".to_string(),
619 JsonValue::String("\u{08}\u{0C}\n\r\t\u{1F}".to_string()),
621 );
622 obj.insert(
623 "arr".to_string(),
624 JsonValue::Array(vec![JsonValue::Null, JsonValue::Bool(true)]),
625 );
626 let value = JsonValue::Object(obj);
627
628 let s = to_compact_string(&value);
629 assert_eq!(parse_str(&s).unwrap(), value);
632 assert_eq!(to_compact_vec(&value), s.clone().into_bytes());
633 assert!(s.starts_with("{\"off\":false,"));
634 assert!(s.ends_with(",\"arr\":[null,true]}"));
635 }
636
637 #[cfg(feature = "std")]
638 #[test]
639 fn errors_implement_std_error() {
640 fn assert_error<E: std::error::Error>(_: &E) {}
641 let parse_err = parse_str("").unwrap_err();
642 assert_error(&parse_err);
643 let num_err = JsonNumber::new("1.5").unwrap().to_i64().unwrap_err();
644 assert_error(&num_err);
645 }
646}