1#![cfg_attr(not(feature = "std"), no_std)]
2
3#![allow(unsafe_code)]
103
104#[cfg(feature = "alloc")]
105extern crate alloc;
106
107#[cfg(feature = "derive")]
112extern crate self as json_bourne;
113
114mod casing;
115mod de;
116mod error;
117mod event;
118#[cfg(feature = "alloc")]
119mod float;
120mod lexer;
121mod parser;
122mod ser;
123#[cfg(all(test, feature = "std"))]
124mod teju_gen;
125
126#[doc(hidden)]
127pub use casing::{Casing as __Casing, Renamed as __Renamed};
128pub use de::{FromJson, parse, parse_str};
129#[cfg(feature = "alloc")]
130pub use de::{MapKey, key_to_cow};
131pub use error::{Error, ErrorKind, LineColumn, Position};
132pub use event::{Event, JsonNum, JsonStr, MAX_INPUT_LEN};
133pub use lexer::{Checkpoint, DEFAULT_MAX_DEPTH, Lexer, ValueKind};
134pub use parser::Parser;
135#[cfg(feature = "alloc")]
136pub use ser::{
137 ByteSink, FmtWriteSink, MapKeyOut, PrettyStringSink, StringSink, to_fmt, to_string,
138 to_string_pretty, to_vec,
139};
140#[cfg(feature = "std")]
141pub use ser::{IoWriteSink, to_writer};
142pub use ser::{JsonWrite, ToJson};
143
144#[cfg(feature = "derive")]
160pub use bourne_derive::{FromJson, ToJson};
161
162#[cfg(all(test, feature = "std"))]
163mod tests {
164 use super::*;
165
166 #[test]
174 fn object_first_key_then_next_event_for_value() {
175 let mut p: Parser<'_> = Parser::new(br#"{"flag":true}"#);
176 let start = p.next_event().unwrap().unwrap();
177 assert!(matches!(start, Event::StartObject));
178
179 let key = p.object_first_key().unwrap().unwrap();
181 assert_eq!(key, "flag");
182
183 let val = p.next_event().unwrap().unwrap();
185 assert_eq!(val, Event::Bool(true));
186
187 let close = p.next_event().unwrap().unwrap();
189 assert!(matches!(close, Event::EndObject));
190 assert!(p.next_event().unwrap().is_none());
191 }
192
193 #[test]
196 fn object_next_key_handoff_to_next_event() {
197 let mut p: Parser<'_> = Parser::new(br#"{"a":1,"b":true}"#);
198 let _ = p.next_event().unwrap().unwrap(); let k1 = p.object_first_key().unwrap().unwrap();
201 assert_eq!(k1, "a");
202 let v1 = p.parse_i64_value().unwrap();
203 assert_eq!(v1, 1);
204
205 let k2 = p.object_next_key().unwrap().unwrap();
206 assert_eq!(k2, "b");
207 let v2 = p.next_event().unwrap().unwrap();
208 assert_eq!(v2, Event::Bool(true));
209
210 assert!(p.object_next_key().unwrap().is_none());
211 assert!(p.next_event().unwrap().is_none());
212 }
213
214 #[test]
215 fn primitives_round_through_typed_parse() {
216 assert!(parse_str::<bool>("true").unwrap());
217 assert!(!parse_str::<bool>("false").unwrap());
218 assert_eq!(parse_str::<i32>("-7").unwrap(), -7);
219 assert_eq!(parse_str::<u64>("9999999999").unwrap(), 9_999_999_999);
220 let f: f64 = parse_str("1.5e2").unwrap();
221 assert!((f - 150.0).abs() < f64::EPSILON);
222 assert_eq!(parse_str::<&str>("\"hello\"").unwrap(), "hello");
223 }
224
225 #[test]
226 fn integer_overflow_is_rejected_at_parse_site() {
227 let r = parse_str::<u8>("256");
228 assert_eq!(r.unwrap_err().kind, ErrorKind::NumberOutOfRange);
229 }
230
231 #[test]
232 fn type_mismatch_is_rejected_at_parse_site() {
233 let r = parse_str::<u32>("\"five\"");
234 assert_eq!(r.unwrap_err().kind, ErrorKind::ExpectedNumber);
235 }
236
237 #[test]
238 fn option_handles_null_and_value() {
239 let none: Option<u32> = parse_str("null").unwrap();
240 assert_eq!(none, None);
241 let some: Option<u32> = parse_str("17").unwrap();
242 assert_eq!(some, Some(17));
243 }
244
245 #[test]
246 fn fixed_array_exact_length() {
247 let arr: [i32; 3] = parse_str("[1,2,3]").unwrap();
248 assert_eq!(arr, [1, 2, 3]);
249 }
250
251 #[test]
252 fn fixed_array_too_short_errors() {
253 let r = parse_str::<[i32; 3]>("[1,2]");
254 assert!(r.is_err());
255 }
256
257 #[test]
258 fn fixed_array_too_long_errors() {
259 let r = parse_str::<[i32; 3]>("[1,2,3,4]");
260 assert!(r.is_err());
261 }
262
263 #[test]
264 fn tuple_heterogeneous() {
265 let v: (i32, &str, bool) = parse_str(r#"[1, "hi", true]"#).unwrap();
266 assert_eq!(v, (1, "hi", true));
267 }
268
269 #[test]
270 fn borrowed_str_lifetime() {
271 let input = String::from(r#""borrowed""#);
272 let s: &str = parse_str(&input).unwrap();
273 assert_eq!(s, "borrowed");
274 }
275
276 #[test]
277 fn rejects_trailing_data_at_typed_layer() {
278 let r = parse_str::<u32>("1 2");
279 assert!(r.is_err());
280 }
281
282 #[cfg(feature = "std")]
288 #[test]
289 fn duration_round_trips_fractional_seconds() {
290 use std::time::Duration;
291 let d: Duration = parse_str("1.5").unwrap();
292 assert_eq!(d, Duration::new(1, 500_000_000));
293 let d: Duration = parse_str("0").unwrap();
294 assert_eq!(d, Duration::ZERO);
295 assert!(parse_str::<Duration>("-1").is_err());
297 }
298
299 #[cfg(feature = "std")]
300 #[test]
301 fn system_time_round_trips_around_epoch() {
302 use std::time::{Duration, SystemTime, UNIX_EPOCH};
303 let t: SystemTime = parse_str("0").unwrap();
305 assert_eq!(t, UNIX_EPOCH);
306 let t: SystemTime = parse_str("1.5").unwrap();
308 assert_eq!(t, UNIX_EPOCH + Duration::new(1, 500_000_000));
309 let t: SystemTime = parse_str("-2").unwrap();
312 assert_eq!(t, UNIX_EPOCH - Duration::from_secs(2));
313 let s = to_string(&(UNIX_EPOCH + Duration::from_secs(42))).unwrap();
315 let back: SystemTime = parse_str(&s).unwrap();
316 assert_eq!(back, UNIX_EPOCH + Duration::from_secs(42));
317 }
318
319 #[cfg(feature = "std")]
320 #[test]
321 fn ip_and_socket_addrs_parse_from_strings() {
322 use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr};
323 let v4: Ipv4Addr = parse_str(r#""127.0.0.1""#).unwrap();
324 assert_eq!(v4, Ipv4Addr::LOCALHOST);
325 let v6: Ipv6Addr = parse_str(r#""::1""#).unwrap();
326 assert_eq!(v6, Ipv6Addr::LOCALHOST);
327 let ip: IpAddr = parse_str(r#""10.0.0.1""#).unwrap();
328 assert!(matches!(ip, IpAddr::V4(_)));
329 let sa: SocketAddr = parse_str(r#""127.0.0.1:8080""#).unwrap();
330 assert_eq!(sa.port(), 8080);
331 assert!(parse_str::<Ipv4Addr>(r#""not-an-ip""#).is_err());
333 }
334
335 #[cfg(feature = "std")]
336 #[test]
337 fn pathbuf_parses_from_string() {
338 use std::path::PathBuf;
339 let p: PathBuf = parse_str(r#""/etc/hosts""#).unwrap();
340 assert_eq!(p, PathBuf::from("/etc/hosts"));
341 }
342
343 #[cfg(feature = "std")]
344 #[test]
345 fn hashmap_string_key() {
346 use std::collections::HashMap;
347 let m: HashMap<String, i32> = parse_str(r#"{"a":1,"b":2}"#).unwrap();
348 assert_eq!(m.get("a"), Some(&1));
349 assert_eq!(m.get("b"), Some(&2));
350 assert_eq!(m.len(), 2);
351 }
352
353 #[cfg(feature = "std")]
354 #[test]
355 fn hashmap_borrowed_key_zero_copy() {
356 use std::collections::HashMap;
357 let input = String::from(r#"{"alpha":1,"beta":2}"#);
358 let m: HashMap<&str, i32> = parse_str(&input).unwrap();
359 let input_start = input.as_ptr() as usize;
361 let input_end = input_start + input.len();
362 for k in m.keys() {
363 let p = k.as_ptr() as usize;
364 assert!((input_start..input_end).contains(&p), "key was copied");
365 }
366 }
367
368 #[cfg(feature = "alloc")]
369 #[test]
370 fn btreemap_round_trips() {
371 use std::collections::BTreeMap;
372 let m: BTreeMap<String, Vec<i32>> = parse_str(r#"{"x":[1,2],"y":[3]}"#).unwrap();
373 assert_eq!(m["x"], vec![1, 2]);
374 assert_eq!(m["y"], vec![3]);
375 }
376
377 #[cfg(feature = "std")]
378 #[test]
379 fn map_rejects_duplicate_key() {
380 use std::collections::HashMap;
381 let r: Result<HashMap<String, i32>, _> = parse_str(r#"{"a":1,"a":2}"#);
382 assert_eq!(r.unwrap_err().kind, ErrorKind::DuplicateKey);
383 }
384
385 #[cfg(feature = "std")]
386 #[test]
387 fn map_rejects_non_object() {
388 use std::collections::HashMap;
389 let r: Result<HashMap<String, i32>, _> = parse_str("[1,2]");
390 assert!(r.is_err());
391 }
392
393 #[cfg(feature = "std")]
394 #[test]
395 fn hashset_round_trips() {
396 use std::collections::HashSet;
397 let s: HashSet<i32> = parse_str("[1,2,3,2,1]").unwrap();
398 assert_eq!(s.len(), 3);
399 assert!(s.contains(&1));
400 assert!(s.contains(&2));
401 assert!(s.contains(&3));
402 }
403
404 #[cfg(feature = "alloc")]
405 #[test]
406 fn btreeset_round_trips() {
407 use std::collections::BTreeSet;
408 let s: BTreeSet<i32> = parse_str("[3,1,2]").unwrap();
409 assert_eq!(s.into_iter().collect::<Vec<_>>(), vec![1, 2, 3]);
410 }
411
412 #[cfg(feature = "alloc")]
413 #[test]
414 fn box_rc_arc_are_transparent_wrappers() {
415 let b: Box<u32> = parse_str("42").unwrap();
416 assert_eq!(*b, 42);
417 let r: std::rc::Rc<&str> = parse_str(r#""hello""#).unwrap();
418 assert_eq!(*r, "hello");
419 let a: std::sync::Arc<Vec<i32>> = parse_str("[1,2,3]").unwrap();
420 assert_eq!(*a, vec![1, 2, 3]);
421 }
422
423 #[cfg(feature = "alloc")]
424 #[test]
425 fn char_accepts_single_scalar() {
426 assert_eq!(parse_str::<char>(r#""a""#).unwrap(), 'a');
427 assert_eq!(parse_str::<char>(r#""中""#).unwrap(), '中');
428 assert_eq!(parse_str::<char>(r#""\n""#).unwrap(), '\n');
430 assert_eq!(parse_str::<char>(r#""😀""#).unwrap(), '😀');
432 }
433
434 #[cfg(feature = "alloc")]
435 #[test]
436 #[allow(clippy::unicode_not_nfc)] fn char_rejects_empty_or_multiple() {
438 assert!(parse_str::<char>(r#""""#).is_err());
439 assert!(parse_str::<char>(r#""ab""#).is_err());
440 assert!(parse_str::<char>(r#""é""#).is_err());
444 assert!(parse_str::<char>("42").is_err());
446 }
447
448 #[test]
449 fn i128_round_trips_full_range() {
450 assert_eq!(parse_str::<i128>("0").unwrap(), 0);
451 assert_eq!(
452 parse_str::<i128>("170141183460469231731687303715884105727").unwrap(),
453 i128::MAX,
454 );
455 assert_eq!(
456 parse_str::<i128>("-170141183460469231731687303715884105728").unwrap(),
457 i128::MIN,
458 );
459 assert!(parse_str::<i128>("170141183460469231731687303715884105728").is_err());
460 }
461
462 #[test]
463 fn u128_round_trips_full_range() {
464 assert_eq!(parse_str::<u128>("0").unwrap(), 0);
465 assert_eq!(
466 parse_str::<u128>("340282366920938463463374607431768211455").unwrap(),
467 u128::MAX,
468 );
469 assert!(parse_str::<u128>("340282366920938463463374607431768211456").is_err());
470 assert!(parse_str::<u128>("-1").is_err());
472 }
473
474 #[test]
481 fn i128_38_vs_39_digit_boundary() {
482 let thirty_eight_nines = "9".repeat(38);
484 let v: i128 = parse_str(&thirty_eight_nines).unwrap();
485 assert_eq!(v.to_string(), thirty_eight_nines);
486
487 let ten_pow_38 = format!("1{}", "0".repeat(38));
489 let v: i128 = parse_str(&ten_pow_38).unwrap();
490 assert_eq!(v.to_string(), ten_pow_38);
491
492 let thirty_nine_nines = "9".repeat(39);
494 assert!(parse_str::<i128>(&thirty_nine_nines).is_err());
495 }
496
497 #[test]
498 fn vec_i128_round_trips() {
499 let v: Vec<i128> = parse_str(
501 "[0,1,-1,170141183460469231731687303715884105727,-170141183460469231731687303715884105728]",
502 )
503 .unwrap();
504 assert_eq!(v, vec![0, 1, -1, i128::MAX, i128::MIN]);
505 }
506
507 #[test]
508 fn vec_u128_round_trips() {
509 let v: Vec<u128> = parse_str("[0,1,2,340282366920938463463374607431768211455]").unwrap();
510 assert_eq!(v, vec![0, 1, 2, u128::MAX]);
511 }
512
513 #[test]
520 fn f32_rejects_overflow_to_infinity() {
521 let r = parse_str::<f32>("1e40");
524 assert_eq!(r.unwrap_err().kind, ErrorKind::NumberOutOfRange);
525 let r = parse_str::<f32>("-1e40");
526 assert_eq!(r.unwrap_err().kind, ErrorKind::NumberOutOfRange);
527 let v: f32 = parse_str("3.4028235e38").unwrap();
529 assert!(v.is_finite());
530 }
531
532 #[test]
533 fn f64_rejects_overflow_to_infinity() {
534 let r = parse_str::<f64>("1e400");
535 assert_eq!(r.unwrap_err().kind, ErrorKind::NumberOutOfRange);
536 let r = parse_str::<f64>("-1e400");
537 assert_eq!(r.unwrap_err().kind, ErrorKind::NumberOutOfRange);
538 }
539
540 #[test]
541 fn i64_min_is_parseable() {
542 assert_eq!(parse_str::<i64>("-9223372036854775808").unwrap(), i64::MIN);
543 assert_eq!(
544 parse_str::<i64>("-9223372036854775807").unwrap(),
545 i64::MIN + 1,
546 );
547 assert_eq!(parse_str::<i64>("9223372036854775807").unwrap(), i64::MAX);
548 assert!(parse_str::<i64>("-9223372036854775809").is_err());
550 assert!(parse_str::<i64>("9223372036854775808").is_err());
552 let v: Vec<i64> = parse_str("[-9223372036854775808]").unwrap();
554 assert_eq!(v, vec![i64::MIN]);
555 }
556
557 #[cfg(feature = "alloc")]
558 #[test]
559 fn vec_and_string() {
560 let v: Vec<i32> = parse_str("[10, 20, 30]").unwrap();
561 assert_eq!(v, vec![10, 20, 30]);
562 let s: String = parse_str(r#""owned""#).unwrap();
563 assert_eq!(s, "owned");
564 }
565
566 #[cfg(feature = "alloc")]
567 #[test]
568 fn nested_vec() {
569 let v: Vec<Vec<i32>> = parse_str("[[1,2],[3]]").unwrap();
570 assert_eq!(v, vec![vec![1, 2], vec![3]]);
571 }
572
573 #[cfg(feature = "alloc")]
578 #[test]
579 fn string_decodes_simple_escapes() {
580 let s: String = parse_str(r#""line1\nline2\ttab\"quote\\back\/slash""#).unwrap();
581 assert_eq!(s, "line1\nline2\ttab\"quote\\back/slash");
582 }
583
584 #[cfg(feature = "alloc")]
585 #[test]
586 fn string_decodes_b_and_f_escapes() {
587 let s: String = parse_str(r#""\b\f""#).unwrap();
589 assert_eq!(s, "\u{0008}\u{000C}");
590 }
591
592 #[cfg(feature = "alloc")]
593 #[test]
594 fn string_decodes_unicode_bmp_escape() {
595 let s: String = parse_str(r#""café 中文 ~""#).unwrap();
598 assert_eq!(s, "café 中文 ~");
599 }
600
601 #[cfg(feature = "alloc")]
602 #[test]
603 fn string_decodes_surrogate_pair() {
604 let s: String = parse_str(r#""hi 😀 there""#).unwrap();
607 assert_eq!(s, "hi 😀 there");
608 }
609
610 #[cfg(feature = "alloc")]
611 #[test]
612 fn string_rejects_lone_surrogate() {
613 let r = parse_str::<String>(r#""\uD800""#);
614 assert_eq!(r.unwrap_err().kind, ErrorKind::UnpairedSurrogate);
615 let r = parse_str::<String>(r#""\uDC00""#);
616 assert_eq!(r.unwrap_err().kind, ErrorKind::UnpairedSurrogate);
617 }
618
619 #[cfg(feature = "alloc")]
620 #[test]
621 fn string_rejects_high_surrogate_then_non_low() {
622 let r = parse_str::<String>(r#""\uD800A""#);
624 assert_eq!(r.unwrap_err().kind, ErrorKind::UnpairedSurrogate);
625 }
626
627 #[cfg(feature = "alloc")]
628 #[test]
629 fn string_decodes_long_mixed_input() {
630 let json = r#""one\ttwo\nthreeAfour\\five\"six""#;
634 let s: String = parse_str(json).unwrap();
635 assert_eq!(s, "one\ttwo\nthreeAfour\\five\"six");
636 }
637
638 #[cfg(feature = "alloc")]
639 #[test]
640 fn vec_string_with_escapes_roundtrips() {
641 let json = r#"["","a","\n","mixéd","\\\"\/"]"#;
645 let v: Vec<String> = parse_str(json).unwrap();
646 assert_eq!(v, vec!["", "a", "\n", "mixéd", "\\\"/"]);
647 }
648
649 #[cfg(feature = "alloc")]
650 #[test]
651 fn cow_borrows_when_no_escapes() {
652 use std::borrow::Cow;
653 let input = String::from(r#""borrowed""#);
654 let c: Cow<'_, str> = parse_str(&input).unwrap();
655 assert_eq!(c, "borrowed");
656 match c {
659 Cow::Borrowed(s) => {
660 let input_start = input.as_ptr() as usize;
661 let input_end = input_start + input.len();
662 let s_ptr = s.as_ptr() as usize;
663 assert!(
664 (input_start..input_end).contains(&s_ptr),
665 "Cow::Borrowed pointer should be inside input",
666 );
667 }
668 Cow::Owned(_) => panic!("expected Borrowed for un-escaped input"),
669 }
670 }
671
672 #[cfg(feature = "alloc")]
673 #[test]
674 fn cow_owns_when_escapes_present() {
675 use std::borrow::Cow;
676 let c: Cow<'_, str> = parse_str(r#""line\nwrap""#).unwrap();
677 assert_eq!(c, "line\nwrap");
678 assert!(matches!(c, Cow::Owned(_)));
679 }
680
681 #[test]
686 fn parser_object_key_lex_with_escapes() {
687 let input = br#"{"a\nb":1,"c":2}"#;
688 let mut p: Parser<'_> = Parser::new(input);
689 assert!(matches!(
690 p.next_event().unwrap().unwrap(),
691 Event::StartObject
692 ));
693 let k1 = p.object_first_key_lex().unwrap().unwrap();
694 assert!(k1.has_escapes());
695 assert_eq!(p.parse_i64_value().unwrap(), 1);
696 let k2 = p.object_next_key_lex().unwrap().unwrap();
697 assert!(!k2.has_escapes());
698 assert_eq!(p.parse_i64_value().unwrap(), 2);
699 assert!(p.object_next_key_lex().unwrap().is_none());
700 assert!(p.next_event().unwrap().is_none());
701 }
702
703 #[test]
704 fn parser_object_key_lex_empty() {
705 let mut p: Parser<'_> = Parser::new(b"{}");
706 assert!(matches!(
707 p.next_event().unwrap().unwrap(),
708 Event::StartObject
709 ));
710 assert!(p.object_first_key_lex().unwrap().is_none());
711 assert!(p.next_event().unwrap().is_none());
712 }
713
714 #[test]
719 fn parser_array_start_continue() {
720 let mut p: Parser<'_> = Parser::new(b"[1,2,3]");
721 assert!(!p.array_start().unwrap());
722 assert_eq!(p.parse_i64_value().unwrap(), 1);
723 assert!(!p.array_continue(b']').unwrap());
724 assert_eq!(p.parse_i64_value().unwrap(), 2);
725 assert!(!p.array_continue(b']').unwrap());
726 assert_eq!(p.parse_i64_value().unwrap(), 3);
727 assert!(p.array_continue(b']').unwrap());
728 assert!(p.next_event().unwrap().is_none());
729 }
730
731 #[test]
732 fn parser_array_start_empty() {
733 let mut p: Parser<'_> = Parser::new(b"[]");
734 assert!(p.array_start().unwrap());
735 assert!(p.next_event().unwrap().is_none());
736 }
737
738 #[test]
739 fn parser_array_nested_in_object() {
740 let mut p: Parser<'_> = Parser::new(br#"{"v":[1,2]}"#);
741 assert!(matches!(
742 p.next_event().unwrap().unwrap(),
743 Event::StartObject
744 ));
745 let key = p.object_first_key().unwrap().unwrap();
746 assert_eq!(key, "v");
747 assert!(!p.array_start().unwrap());
748 assert_eq!(p.parse_i64_value().unwrap(), 1);
749 assert!(!p.array_continue(b']').unwrap());
750 assert_eq!(p.parse_i64_value().unwrap(), 2);
751 assert!(p.array_continue(b']').unwrap());
752 assert!(p.object_next_key().unwrap().is_none());
753 assert!(p.next_event().unwrap().is_none());
754 }
755
756 #[test]
761 fn error_kind_display_covers_all_variants() {
762 use alloc::format;
763 let cases: &[(ErrorKind, &str)] = &[
764 (ErrorKind::UnexpectedEof, "unexpected end of input"),
765 (ErrorKind::InvalidEscape, "invalid string escape"),
766 (ErrorKind::InvalidUnicodeEscape, "invalid \\u escape"),
767 (
768 ErrorKind::UnpairedSurrogate,
769 "unpaired UTF-16 surrogate in \\u escape",
770 ),
771 (ErrorKind::InvalidUtf8, "invalid UTF-8"),
772 (ErrorKind::InvalidNumber, "invalid number literal"),
773 (
774 ErrorKind::NumberOutOfRange,
775 "number does not fit target type",
776 ),
777 (
778 ErrorKind::ControlCharInString,
779 "control character in string literal",
780 ),
781 (ErrorKind::TrailingData, "trailing data after JSON value"),
782 (
783 ErrorKind::DepthLimitExceeded,
784 "nesting depth limit exceeded",
785 ),
786 (ErrorKind::ExpectedValue, "expected JSON value"),
787 (ErrorKind::ExpectedString, "expected string"),
788 (ErrorKind::ExpectedNumber, "expected number"),
789 (ErrorKind::ExpectedBool, "expected boolean"),
790 (ErrorKind::ExpectedNull, "expected null"),
791 (ErrorKind::ExpectedArray, "expected array"),
792 (ErrorKind::ExpectedObject, "expected object"),
793 (ErrorKind::TypeMismatch, "type mismatch"),
794 (ErrorKind::DuplicateKey, "duplicate object key"),
795 (ErrorKind::MissingField, "missing required field"),
796 (ErrorKind::UnknownField, "unknown field"),
797 (
798 ErrorKind::NonFiniteFloat,
799 "non-finite float not representable in JSON",
800 ),
801 (ErrorKind::UnexpectedByte(0x7B), "unexpected byte 0x7b"),
802 ];
803 for (kind, expected) in cases {
804 assert_eq!(format!("{kind}"), *expected, "mismatch for {kind:?}");
805 }
806 }
807
808 #[test]
813 fn utf8_f4_leading_byte_valid() {
814 let s = "\"\u{100000}\"";
815 let v: &str = parse_str(s).unwrap();
816 assert_eq!(v, "\u{100000}");
817 }
818
819 #[test]
820 fn utf8_f4_leading_byte_invalid_continuation() {
821 let mut bytes = b"\"".to_vec();
822 bytes.push(0xF4);
823 bytes.push(0x90); bytes.push(0x80);
825 bytes.push(0x80);
826 bytes.push(b'"');
827 let r = parse::<&str>(&bytes);
828 assert_eq!(r.unwrap_err().kind, ErrorKind::InvalidUtf8);
829 }
830
831 #[test]
832 fn utf8_multibyte_all_leading_ranges() {
833 let cases: &[&str] = &[
834 "\"\u{0080}\"", "\"\u{0800}\"", "\"\u{1000}\"", "\"\u{D7FF}\"", "\"\u{E000}\"", "\"\u{10000}\"", "\"\u{40000}\"", "\"\u{100000}\"", ];
843 for input in cases {
844 let v: &str = parse_str(input).unwrap();
845 let expected = &input[1..input.len() - 1];
846 assert_eq!(v, expected);
847 }
848 }
849
850 #[test]
855 fn serialize_all_control_bytes() {
856 for b in 0x00_u8..=0x1F {
857 let s = alloc::string::String::from(b as char);
858 let json = to_string(&s).unwrap();
859 assert!(json.starts_with('"') && json.ends_with('"'));
860 let inner = &json[1..json.len() - 1];
861 match b {
862 b'"' | b'\\' => unreachable!(),
863 b'\n' => assert_eq!(inner, "\\n"),
864 b'\r' => assert_eq!(inner, "\\r"),
865 b'\t' => assert_eq!(inner, "\\t"),
866 0x08 => assert_eq!(inner, "\\b"),
867 0x0C => assert_eq!(inner, "\\f"),
868 _ => {
869 let expected = alloc::format!("\\u00{b:02x}");
870 assert_eq!(inner, expected, "byte 0x{b:02x}");
871 }
872 }
873 }
874 }
875
876 #[test]
881 fn next_event_rejects_trailing_comma_in_array() {
882 let mut p: Parser<'_> = Parser::new(b"[1,]");
883 assert!(matches!(
884 p.next_event().unwrap().unwrap(),
885 Event::StartArray
886 ));
887 let _ = p.next_event().unwrap().unwrap(); let err = p.next_event().unwrap_err();
889 assert_eq!(err.kind, ErrorKind::UnexpectedByte(b']'));
890 }
891
892 #[test]
893 fn next_event_rejects_trailing_comma_in_object() {
894 let mut p: Parser<'_> = Parser::new(br#"{"a":1,}"#);
895 assert!(matches!(
896 p.next_event().unwrap().unwrap(),
897 Event::StartObject
898 ));
899 assert!(matches!(p.next_event().unwrap().unwrap(), Event::Key(_)));
900 let _ = p.next_event().unwrap().unwrap(); let err = p.next_event().unwrap_err();
902 assert_eq!(err.kind, ErrorKind::UnexpectedByte(b'}'));
903 }
904
905 #[test]
906 fn next_event_object_colon_eof() {
907 let mut p: Parser<'_> = Parser::new(br#"{"a""#);
908 assert!(matches!(
909 p.next_event().unwrap().unwrap(),
910 Event::StartObject
911 ));
912 assert!(matches!(p.next_event().unwrap().unwrap(), Event::Key(_)));
913 let err = p.next_event().unwrap_err();
914 assert_eq!(err.kind, ErrorKind::UnexpectedEof);
915 }
916
917 #[test]
918 fn next_event_object_colon_wrong_byte() {
919 let mut p: Parser<'_> = Parser::new(br#"{"a";"#);
920 assert!(matches!(
921 p.next_event().unwrap().unwrap(),
922 Event::StartObject
923 ));
924 assert!(matches!(p.next_event().unwrap().unwrap(), Event::Key(_)));
925 let err = p.next_event().unwrap_err();
926 assert_eq!(err.kind, ErrorKind::UnexpectedByte(b';'));
927 }
928
929 #[test]
930 fn next_event_empty_input() {
931 let mut p: Parser<'_> = Parser::new(b"");
932 let err = p.next_event().unwrap_err();
933 assert_eq!(err.kind, ErrorKind::UnexpectedEof);
934 }
935
936 #[test]
937 fn next_event_eof_inside_array() {
938 let mut p: Parser<'_> = Parser::new(b"[");
939 assert!(matches!(
940 p.next_event().unwrap().unwrap(),
941 Event::StartArray
942 ));
943 let err = p.next_event().unwrap_err();
944 assert_eq!(err.kind, ErrorKind::UnexpectedEof);
945 }
946
947 #[test]
948 fn next_event_eof_after_array_comma() {
949 let mut p: Parser<'_> = Parser::new(b"[1,");
950 assert!(matches!(
951 p.next_event().unwrap().unwrap(),
952 Event::StartArray
953 ));
954 let _ = p.next_event().unwrap().unwrap(); let err = p.next_event().unwrap_err();
956 assert_eq!(err.kind, ErrorKind::UnexpectedEof);
957 }
958
959 #[test]
960 fn next_event_bad_byte_after_array_value() {
961 let mut p: Parser<'_> = Parser::new(b"[1;");
962 assert!(matches!(
963 p.next_event().unwrap().unwrap(),
964 Event::StartArray
965 ));
966 let _ = p.next_event().unwrap().unwrap(); let err = p.next_event().unwrap_err();
968 assert_eq!(err.kind, ErrorKind::UnexpectedByte(b';'));
969 }
970
971 #[test]
972 fn next_event_eof_in_object_key_position() {
973 let mut p: Parser<'_> = Parser::new(b"{");
974 assert!(matches!(
975 p.next_event().unwrap().unwrap(),
976 Event::StartObject
977 ));
978 let err = p.next_event().unwrap_err();
979 assert_eq!(err.kind, ErrorKind::UnexpectedEof);
980 }
981
982 #[test]
983 fn next_event_bad_byte_in_object_key_position() {
984 let mut p: Parser<'_> = Parser::new(b"{1");
985 assert!(matches!(
986 p.next_event().unwrap().unwrap(),
987 Event::StartObject
988 ));
989 let err = p.next_event().unwrap_err();
990 assert_eq!(err.kind, ErrorKind::UnexpectedByte(b'1'));
991 }
992
993 #[test]
994 fn next_event_eof_after_object_value() {
995 let mut p: Parser<'_> = Parser::new(br#"{"a":1"#);
996 assert!(matches!(
997 p.next_event().unwrap().unwrap(),
998 Event::StartObject
999 ));
1000 assert!(matches!(p.next_event().unwrap().unwrap(), Event::Key(_)));
1001 let _ = p.next_event().unwrap().unwrap(); let err = p.next_event().unwrap_err();
1003 assert_eq!(err.kind, ErrorKind::UnexpectedEof);
1004 }
1005
1006 #[test]
1007 fn next_event_bad_byte_after_object_value() {
1008 let mut p: Parser<'_> = Parser::new(br#"{"a":1;"#);
1009 assert!(matches!(
1010 p.next_event().unwrap().unwrap(),
1011 Event::StartObject
1012 ));
1013 assert!(matches!(p.next_event().unwrap().unwrap(), Event::Key(_)));
1014 let _ = p.next_event().unwrap().unwrap(); let err = p.next_event().unwrap_err();
1016 assert_eq!(err.kind, ErrorKind::UnexpectedByte(b';'));
1017 }
1018
1019 #[test]
1020 fn next_event_object_value_state_via_fast_path() {
1021 let mut p: Parser<'_> = Parser::new(br#"{"x":42,"y":99}"#);
1022 assert!(matches!(
1023 p.next_event().unwrap().unwrap(),
1024 Event::StartObject
1025 ));
1026 let k1 = p.object_first_key().unwrap().unwrap();
1027 assert_eq!(k1, "x");
1028 let v1 = p.next_event().unwrap().unwrap();
1029 assert!(matches!(v1, Event::Number(_)));
1030 let k2 = p.object_next_key().unwrap().unwrap();
1031 assert_eq!(k2, "y");
1032 let v2 = p.next_event().unwrap().unwrap();
1033 assert!(matches!(v2, Event::Number(_)));
1034 assert!(p.object_next_key().unwrap().is_none());
1035 assert!(p.next_event().unwrap().is_none());
1036 }
1037
1038 #[test]
1039 fn next_event_nested_containers_close_correctly() {
1040 let mut p: Parser<'_> = Parser::new(br#"{"a":[1],"b":{"c":2}}"#);
1041 assert!(matches!(
1042 p.next_event().unwrap().unwrap(),
1043 Event::StartObject
1044 ));
1045 assert!(matches!(p.next_event().unwrap().unwrap(), Event::Key(_))); assert!(matches!(
1047 p.next_event().unwrap().unwrap(),
1048 Event::StartArray
1049 ));
1050 assert!(matches!(p.next_event().unwrap().unwrap(), Event::Number(_)));
1051 assert!(matches!(p.next_event().unwrap().unwrap(), Event::EndArray));
1052 assert!(matches!(p.next_event().unwrap().unwrap(), Event::Key(_))); assert!(matches!(
1054 p.next_event().unwrap().unwrap(),
1055 Event::StartObject
1056 ));
1057 assert!(matches!(p.next_event().unwrap().unwrap(), Event::Key(_))); assert!(matches!(p.next_event().unwrap().unwrap(), Event::Number(_)));
1059 assert!(matches!(p.next_event().unwrap().unwrap(), Event::EndObject));
1060 assert!(matches!(p.next_event().unwrap().unwrap(), Event::EndObject));
1061 assert!(p.next_event().unwrap().is_none());
1062 }
1063
1064 #[test]
1065 fn next_event_nested_array_in_array() {
1066 let input = b"[[],[1,2]]";
1067 let mut p: Parser<'_> = Parser::new(input);
1068 assert!(matches!(
1069 p.next_event().unwrap().unwrap(),
1070 Event::StartArray
1071 ));
1072 assert!(matches!(
1073 p.next_event().unwrap().unwrap(),
1074 Event::StartArray
1075 ));
1076 assert!(matches!(p.next_event().unwrap().unwrap(), Event::EndArray));
1077 assert!(matches!(
1078 p.next_event().unwrap().unwrap(),
1079 Event::StartArray
1080 ));
1081 assert!(matches!(p.next_event().unwrap().unwrap(), Event::Number(_)));
1082 assert!(matches!(p.next_event().unwrap().unwrap(), Event::Number(_)));
1083 assert!(matches!(p.next_event().unwrap().unwrap(), Event::EndArray));
1084 assert!(matches!(p.next_event().unwrap().unwrap(), Event::EndArray));
1085 assert!(p.next_event().unwrap().is_none());
1086 }
1087
1088 #[test]
1089 fn serialize_string_with_quote_and_backslash() {
1090 let s = "a\"b\\c";
1091 let json = to_string(&s).unwrap();
1092 assert_eq!(json, r#""a\"b\\c""#);
1093 }
1094
1095 #[test]
1096 fn serialize_string_with_all_named_escapes() {
1097 let s = "\x08\x0C\n\r\t";
1098 let json = to_string(&s).unwrap();
1099 assert_eq!(json, r#""\b\f\n\r\t""#);
1100 }
1101
1102 #[test]
1107 fn parser_object_first_key_empty_inside_array() {
1108 let mut p: Parser<'_> = Parser::new(b"[{}]");
1109 assert!(matches!(
1110 p.next_event().unwrap().unwrap(),
1111 Event::StartArray
1112 ));
1113 assert!(matches!(
1114 p.next_event().unwrap().unwrap(),
1115 Event::StartObject
1116 ));
1117 assert!(p.object_first_key().unwrap().is_none());
1118 assert!(matches!(p.next_event().unwrap().unwrap(), Event::EndArray));
1119 assert!(p.next_event().unwrap().is_none());
1120 }
1121
1122 #[test]
1123 fn parser_object_first_key_empty_inside_object() {
1124 let mut p: Parser<'_> = Parser::new(br#"{"a":{}}"#);
1125 assert!(matches!(
1126 p.next_event().unwrap().unwrap(),
1127 Event::StartObject
1128 ));
1129 let k = p.object_first_key().unwrap().unwrap();
1130 assert_eq!(k, "a");
1131 assert!(matches!(
1132 p.next_event().unwrap().unwrap(),
1133 Event::StartObject
1134 ));
1135 assert!(p.object_first_key().unwrap().is_none());
1136 assert!(p.object_next_key().unwrap().is_none());
1137 assert!(p.next_event().unwrap().is_none());
1138 }
1139
1140 #[test]
1141 fn parser_object_first_key_lex_empty_inside_array() {
1142 let mut p: Parser<'_> = Parser::new(b"[{}]");
1143 assert!(matches!(
1144 p.next_event().unwrap().unwrap(),
1145 Event::StartArray
1146 ));
1147 assert!(matches!(
1148 p.next_event().unwrap().unwrap(),
1149 Event::StartObject
1150 ));
1151 assert!(p.object_first_key_lex().unwrap().is_none());
1152 assert!(matches!(p.next_event().unwrap().unwrap(), Event::EndArray));
1153 assert!(p.next_event().unwrap().is_none());
1154 }
1155
1156 #[test]
1157 fn parser_object_next_key_close_inside_array() {
1158 let mut p: Parser<'_> = Parser::new(br#"[{"a":1}]"#);
1159 assert!(matches!(
1160 p.next_event().unwrap().unwrap(),
1161 Event::StartArray
1162 ));
1163 assert!(matches!(
1164 p.next_event().unwrap().unwrap(),
1165 Event::StartObject
1166 ));
1167 let k = p.object_first_key().unwrap().unwrap();
1168 assert_eq!(k, "a");
1169 assert_eq!(p.parse_i64_value().unwrap(), 1);
1170 assert!(p.object_next_key().unwrap().is_none());
1171 assert!(matches!(p.next_event().unwrap().unwrap(), Event::EndArray));
1172 assert!(p.next_event().unwrap().is_none());
1173 }
1174
1175 #[test]
1176 fn parser_object_next_key_lex_close_inside_array() {
1177 let mut p: Parser<'_> = Parser::new(br#"[{"a":1}]"#);
1178 assert!(matches!(
1179 p.next_event().unwrap().unwrap(),
1180 Event::StartArray
1181 ));
1182 assert!(matches!(
1183 p.next_event().unwrap().unwrap(),
1184 Event::StartObject
1185 ));
1186 let k = p.object_first_key_lex().unwrap().unwrap();
1187 assert!(!k.has_escapes());
1188 assert_eq!(p.parse_i64_value().unwrap(), 1);
1189 assert!(p.object_next_key_lex().unwrap().is_none());
1190 assert!(matches!(p.next_event().unwrap().unwrap(), Event::EndArray));
1191 assert!(p.next_event().unwrap().is_none());
1192 }
1193
1194 #[test]
1199 fn lexer_object_first_key_bad_byte() {
1200 let mut lex: Lexer<'_> = Lexer::new(b"{1");
1201 lex.object_start().unwrap();
1202 let err = lex.object_first_key().unwrap_err();
1203 assert_eq!(err.kind, ErrorKind::UnexpectedByte(b'1'));
1204 }
1205
1206 #[test]
1207 fn lexer_object_first_key_eof() {
1208 let mut lex: Lexer<'_> = Lexer::new(b"{");
1209 lex.object_start().unwrap();
1210 let err = lex.object_first_key().unwrap_err();
1211 assert_eq!(err.kind, ErrorKind::UnexpectedEof);
1212 }
1213
1214 #[test]
1215 fn lexer_object_first_key_lex_bad_byte() {
1216 let mut lex: Lexer<'_> = Lexer::new(b"{1");
1217 lex.object_start().unwrap();
1218 let err = lex.object_first_key_lex().unwrap_err();
1219 assert_eq!(err.kind, ErrorKind::UnexpectedByte(b'1'));
1220 }
1221
1222 #[test]
1223 fn lexer_object_first_key_lex_eof() {
1224 let mut lex: Lexer<'_> = Lexer::new(b"{");
1225 lex.object_start().unwrap();
1226 let err = lex.object_first_key_lex().unwrap_err();
1227 assert_eq!(err.kind, ErrorKind::UnexpectedEof);
1228 }
1229
1230 #[test]
1231 fn lexer_object_next_key_bad_byte() {
1232 let mut lex: Lexer<'_> = Lexer::new(br#"{"a":1;"#);
1233 lex.object_start().unwrap();
1234 let _ = lex.object_first_key().unwrap();
1235 let _ = lex.parse_i64_value().unwrap();
1236 let err = lex.object_next_key().unwrap_err();
1237 assert_eq!(err.kind, ErrorKind::UnexpectedByte(b';'));
1238 }
1239
1240 #[test]
1241 fn lexer_object_next_key_eof() {
1242 let mut lex: Lexer<'_> = Lexer::new(br#"{"a":1"#);
1243 lex.object_start().unwrap();
1244 let _ = lex.object_first_key().unwrap();
1245 let _ = lex.parse_i64_value().unwrap();
1246 let err = lex.object_next_key().unwrap_err();
1247 assert_eq!(err.kind, ErrorKind::UnexpectedEof);
1248 }
1249
1250 #[test]
1251 fn lexer_object_next_key_bad_byte_after_comma() {
1252 let mut lex: Lexer<'_> = Lexer::new(br#"{"a":1,2"#);
1253 lex.object_start().unwrap();
1254 let _ = lex.object_first_key().unwrap();
1255 let _ = lex.parse_i64_value().unwrap();
1256 let err = lex.object_next_key().unwrap_err();
1257 assert_eq!(err.kind, ErrorKind::UnexpectedByte(b'2'));
1258 }
1259
1260 #[test]
1261 fn lexer_object_next_key_lex_bad_byte() {
1262 let mut lex: Lexer<'_> = Lexer::new(br#"{"a":1;"#);
1263 lex.object_start().unwrap();
1264 let _ = lex.object_first_key_lex().unwrap();
1265 let _ = lex.parse_i64_value().unwrap();
1266 let err = lex.object_next_key_lex().unwrap_err();
1267 assert_eq!(err.kind, ErrorKind::UnexpectedByte(b';'));
1268 }
1269
1270 #[test]
1271 fn lexer_object_next_key_lex_eof() {
1272 let mut lex: Lexer<'_> = Lexer::new(br#"{"a":1"#);
1273 lex.object_start().unwrap();
1274 let _ = lex.object_first_key_lex().unwrap();
1275 let _ = lex.parse_i64_value().unwrap();
1276 let err = lex.object_next_key_lex().unwrap_err();
1277 assert_eq!(err.kind, ErrorKind::UnexpectedEof);
1278 }
1279
1280 #[test]
1281 fn lexer_object_next_key_lex_bad_byte_after_comma() {
1282 let mut lex: Lexer<'_> = Lexer::new(br#"{"a":1,2"#);
1283 lex.object_start().unwrap();
1284 let _ = lex.object_first_key_lex().unwrap();
1285 let _ = lex.parse_i64_value().unwrap();
1286 let err = lex.object_next_key_lex().unwrap_err();
1287 assert_eq!(err.kind, ErrorKind::UnexpectedByte(b'2'));
1288 }
1289
1290 #[test]
1291 fn lexer_expect_colon_bad_byte() {
1292 let mut lex: Lexer<'_> = Lexer::new(br#"{"a";"#);
1293 lex.object_start().unwrap();
1294 let err = lex.object_first_key().unwrap_err();
1295 assert_eq!(err.kind, ErrorKind::UnexpectedByte(b';'));
1296 }
1297
1298 #[test]
1299 fn lexer_expect_colon_eof() {
1300 let mut lex: Lexer<'_> = Lexer::new(br#"{"a""#);
1301 lex.object_start().unwrap();
1302 let err = lex.object_first_key().unwrap_err();
1303 assert_eq!(err.kind, ErrorKind::UnexpectedEof);
1304 }
1305
1306 #[test]
1311 fn fixed_array_zero_length() {
1312 let arr: [i32; 0] = parse_str("[]").unwrap();
1313 assert_eq!(arr, [0_i32; 0]);
1314 }
1315
1316 #[test]
1317 fn fixed_array_empty_but_expected_nonempty() {
1318 let r = parse_str::<[i32; 3]>("[]");
1319 assert!(r.is_err());
1320 }
1321
1322 #[test]
1323 fn fixed_array_closed_early() {
1324 let r = parse_str::<[i32; 3]>("[1]");
1325 assert!(r.is_err());
1326 }
1327
1328 #[test]
1333 fn static_msg_cross_category() {
1334 use alloc::format;
1335 let kind = ErrorKind::UnexpectedEof;
1336 let msg = format!("{kind}");
1337 assert_eq!(msg, "unexpected end of input");
1338
1339 let kind = ErrorKind::ExpectedNull;
1340 let msg = format!("{kind}");
1341 assert_eq!(msg, "expected null");
1342 }
1343
1344 #[test]
1349 fn serialize_string_containing_only_quote() {
1350 let s = "\"";
1351 let json = to_string(&s).unwrap();
1352 assert_eq!(json, r#""\"""#);
1353 }
1354
1355 #[test]
1356 fn serialize_string_containing_only_backslash() {
1357 let s = "\\";
1358 let json = to_string(&s).unwrap();
1359 assert_eq!(json, r#""\\""#);
1360 }
1361
1362 #[test]
1367 fn utf8_invalid_leading_byte() {
1368 let bytes = b"\"\xFF\"";
1369 let r = parse::<&str>(bytes);
1370 assert_eq!(r.unwrap_err().kind, ErrorKind::InvalidUtf8);
1371 }
1372
1373 #[test]
1374 fn utf8_truncated_3byte_sequence() {
1375 let mut bytes = b"\"".to_vec();
1376 bytes.push(0xE1);
1377 bytes.push(0x80);
1378 let r = parse::<&str>(&bytes);
1380 assert_eq!(r.unwrap_err().kind, ErrorKind::InvalidUtf8);
1381 }
1382
1383 #[test]
1384 fn utf8_bad_third_continuation_byte() {
1385 let mut bytes = b"\"".to_vec();
1386 bytes.push(0xE1);
1387 bytes.push(0x80);
1388 bytes.push(0x00); let r = parse::<&str>(&bytes);
1390 assert!(r.is_err());
1391 }
1392
1393 #[test]
1394 fn utf8_4byte_bad_third_continuation() {
1395 let mut bytes = b"\"".to_vec();
1396 bytes.push(0xF0);
1397 bytes.push(0x90);
1398 bytes.push(0x80);
1399 bytes.push(0x00); let r = parse::<&str>(&bytes);
1401 assert!(r.is_err());
1402 }
1403
1404 #[test]
1405 fn utf8_e0_bad_second_byte() {
1406 let mut bytes = b"\"".to_vec();
1407 bytes.push(0xE0);
1408 bytes.push(0x80); bytes.push(0x80);
1410 bytes.push(b'"');
1411 let r = parse::<&str>(&bytes);
1412 assert_eq!(r.unwrap_err().kind, ErrorKind::InvalidUtf8);
1413 }
1414
1415 #[test]
1416 fn utf8_ed_bad_second_byte() {
1417 let mut bytes = b"\"".to_vec();
1418 bytes.push(0xED);
1419 bytes.push(0xA0); bytes.push(0x80);
1421 bytes.push(b'"');
1422 let r = parse::<&str>(&bytes);
1423 assert_eq!(r.unwrap_err().kind, ErrorKind::InvalidUtf8);
1424 }
1425
1426 #[test]
1427 fn utf8_f0_bad_second_byte() {
1428 let mut bytes = b"\"".to_vec();
1429 bytes.push(0xF0);
1430 bytes.push(0x80); bytes.push(0x80);
1432 bytes.push(0x80);
1433 bytes.push(b'"');
1434 let r = parse::<&str>(&bytes);
1435 assert_eq!(r.unwrap_err().kind, ErrorKind::InvalidUtf8);
1436 }
1437
1438 #[test]
1443 fn fixed_array_non_array_input() {
1444 let r = parse_str::<[i32; 2]>("42");
1445 assert!(r.is_err());
1446 }
1447}
1448
1449#[cfg(all(test, feature = "std"))]
1455mod ser_roundtrip {
1456 use super::{parse_str, to_string};
1457
1458 #[allow(clippy::needless_pass_by_value)]
1464 fn rt<T>(v: T)
1465 where
1466 T: crate::ToJson + for<'a> crate::FromJson<'a> + PartialEq + core::fmt::Debug,
1467 {
1468 let s = to_string(&v).expect("serialize");
1469 let v2: T = parse_str(&s).expect("parse back");
1470 assert_eq!(v, v2, "round-trip diverged via {s:?}");
1471 }
1472
1473 #[test]
1474 fn bool_roundtrips() {
1475 rt(true);
1476 rt(false);
1477 }
1478
1479 #[test]
1480 fn unit_roundtrips() {
1481 rt(());
1482 }
1483
1484 #[test]
1485 fn signed_ints_roundtrip() {
1486 rt(0_i8);
1487 rt(i8::MIN);
1488 rt(i8::MAX);
1489 rt(0_i16);
1490 rt(i16::MIN);
1491 rt(i16::MAX);
1492 rt(0_i32);
1493 rt(i32::MIN);
1494 rt(i32::MAX);
1495 rt(0_i64);
1496 rt(i64::MIN);
1497 rt(i64::MAX);
1498 rt(0_isize);
1499 rt(isize::MIN);
1500 rt(isize::MAX);
1501 }
1502
1503 #[test]
1504 fn unsigned_ints_roundtrip() {
1505 rt(0_u8);
1506 rt(u8::MAX);
1507 rt(0_u16);
1508 rt(u16::MAX);
1509 rt(0_u32);
1510 rt(u32::MAX);
1511 rt(0_u64);
1512 rt(u64::MAX);
1513 rt(0_usize);
1514 rt(usize::MAX);
1515 }
1516
1517 #[test]
1518 fn wide_ints_roundtrip() {
1519 rt(0_i128);
1520 rt(i128::MIN);
1521 rt(i128::MAX);
1522 rt(0_u128);
1523 rt(u128::MAX);
1524 }
1525
1526 #[test]
1527 fn strings_roundtrip() {
1528 for s in [
1530 "",
1531 "hello",
1532 "a\\b",
1533 "with \"quotes\"",
1534 "tab\tnewline\nreturn\rbs\x08ff\x0cnul\x00ctl\x1f",
1535 "café 中文 😀",
1536 ] {
1537 rt(String::from(s));
1538 }
1539 }
1540
1541 #[test]
1546 fn cow_roundtrips() {
1547 use std::borrow::Cow;
1548 for src in ["owned", "with\nescape", ""] {
1549 let v = Cow::<str>::Owned(String::from(src));
1550 let s = to_string(&v).unwrap();
1551 let back: Cow<'_, str> = parse_str(&s).unwrap();
1552 assert_eq!(back, src);
1553 }
1554 }
1555
1556 #[test]
1557 fn char_roundtrips() {
1558 for c in ['a', 'Z', '中', '😀', '\n', '\t', '"', '\\'] {
1559 rt(c);
1560 }
1561 }
1562
1563 #[test]
1564 fn option_roundtrips() {
1565 rt(Option::<u32>::None);
1566 rt(Some(42_u32));
1567 rt(Option::<String>::None);
1568 rt(Some(String::from("x")));
1569 }
1570
1571 #[test]
1574 fn reference_forwarding() {
1575 let v: u32 = 7;
1576 let owned = to_string(&v).unwrap();
1577 let by_ref = to_string(&&v).unwrap();
1578 assert_eq!(owned, by_ref);
1579 }
1580
1581 #[test]
1584 fn wrapper_types_transparent() {
1585 use std::rc::Rc;
1586 use std::sync::Arc;
1587 let v: u32 = 9;
1588 assert_eq!(to_string(&v).unwrap(), to_string(&Box::new(v)).unwrap());
1589 assert_eq!(to_string(&v).unwrap(), to_string(&Rc::new(v)).unwrap());
1590 assert_eq!(to_string(&v).unwrap(), to_string(&Arc::new(v)).unwrap());
1591 }
1592
1593 #[test]
1597 fn pinned_wire_format() {
1598 assert_eq!(to_string(&true).unwrap(), "true");
1599 assert_eq!(to_string(&false).unwrap(), "false");
1600 assert_eq!(to_string(&()).unwrap(), "null");
1601 assert_eq!(to_string(&0_i64).unwrap(), "0");
1602 assert_eq!(to_string(&-1_i64).unwrap(), "-1");
1603 assert_eq!(to_string(&i64::MIN).unwrap(), "-9223372036854775808");
1604 assert_eq!(to_string(&u64::MAX).unwrap(), "18446744073709551615");
1605 assert_eq!(to_string(&"hi").unwrap(), "\"hi\"");
1606 assert_eq!(to_string(&"\x01").unwrap(), "\"\\u0001\"");
1608 }
1609
1610 #[test]
1611 fn vec_roundtrips() {
1612 rt(Vec::<i32>::new());
1613 rt(vec![1_i32, 2, 3]);
1614 rt(vec![String::from("a"), String::from("b")]);
1615 rt(vec![Some(1_u32), None, Some(3)]);
1616 }
1617
1618 #[test]
1619 fn nested_vec_roundtrips() {
1620 rt(vec![vec![1_i32, 2], vec![3], Vec::new()]);
1621 }
1622
1623 #[test]
1624 fn fixed_array_roundtrips() {
1625 rt([1_i32, 2, 3]);
1626 rt([true, false, true]);
1627 let zero: [i32; 0] = [];
1628 rt(zero);
1629 }
1630
1631 #[test]
1632 fn tuple_roundtrips() {
1633 rt((1_i32, String::from("hi"), true));
1634 rt((1_u8, 2_u16, 3_u32, 4_u64));
1635 }
1636
1637 #[test]
1638 fn slice_pinned() {
1639 let s: &[i32] = &[10, 20, 30];
1642 assert_eq!(to_string(&s).unwrap(), "[10,20,30]");
1643 let empty: &[u8] = &[];
1644 assert_eq!(to_string(&empty).unwrap(), "[]");
1645 }
1646
1647 #[test]
1648 fn btreemap_roundtrips() {
1649 use std::collections::BTreeMap;
1650 let mut m = BTreeMap::new();
1651 m.insert(String::from("a"), 1_i32);
1652 m.insert(String::from("b"), 2);
1653 rt(m);
1654 }
1655
1656 #[test]
1657 fn btreemap_with_escape_in_key() {
1658 use std::collections::BTreeMap;
1659 let mut m = BTreeMap::new();
1660 m.insert(String::from("a\nb"), 1_i32);
1661 rt(m);
1662 }
1663
1664 #[test]
1665 fn btreeset_roundtrips() {
1666 use std::collections::BTreeSet;
1667 let mut s = BTreeSet::new();
1668 s.insert(1_i32);
1669 s.insert(2);
1670 s.insert(3);
1671 rt(s);
1672 }
1673
1674 #[cfg(feature = "std")]
1675 #[test]
1676 fn hashmap_roundtrips() {
1677 use std::collections::HashMap;
1680 let mut m = HashMap::new();
1681 m.insert(String::from("alpha"), 1_i32);
1682 m.insert(String::from("beta"), 2);
1683 let s = to_string(&m).unwrap();
1684 let back: HashMap<String, i32> = parse_str(&s).unwrap();
1685 assert_eq!(back, m);
1686 }
1687
1688 #[cfg(feature = "std")]
1689 #[test]
1690 fn hashset_roundtrips() {
1691 use std::collections::HashSet;
1692 let mut s = HashSet::new();
1693 s.insert(1_i32);
1694 s.insert(2);
1695 s.insert(3);
1696 let json = to_string(&s).unwrap();
1697 let back: HashSet<i32> = parse_str(&json).unwrap();
1698 assert_eq!(back, s);
1699 }
1700
1701 #[cfg(feature = "std")]
1702 #[test]
1703 fn ip_addrs_roundtrip() {
1704 use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr};
1705 rt(Ipv4Addr::LOCALHOST);
1706 rt(Ipv6Addr::LOCALHOST);
1707 rt(IpAddr::V4(Ipv4Addr::new(10, 0, 0, 1)));
1708 rt(SocketAddr::from(([127, 0, 0, 1], 8080)));
1709 }
1710
1711 #[cfg(feature = "std")]
1712 #[test]
1713 fn pathbuf_roundtrips() {
1714 use std::path::PathBuf;
1715 rt(PathBuf::from("/etc/hosts"));
1716 }
1717
1718 #[test]
1719 fn empty_collections_pinned() {
1720 use std::collections::BTreeMap;
1721 assert_eq!(to_string(&Vec::<i32>::new()).unwrap(), "[]");
1722 let empty: [i32; 0] = [];
1723 assert_eq!(to_string(&empty).unwrap(), "[]");
1724 let m: BTreeMap<String, i32> = BTreeMap::new();
1725 assert_eq!(to_string(&m).unwrap(), "{}");
1726 }
1727
1728 #[test]
1733 fn finite_f64_roundtrips() {
1734 for v in [
1735 0.0_f64,
1736 -0.0,
1737 1.0,
1738 -1.0,
1739 1.5,
1740 -1.5,
1741 1.5e2,
1742 1.5e-2,
1743 f64::MIN_POSITIVE,
1744 f64::MAX,
1745 f64::MIN,
1746 std::f64::consts::PI,
1747 ] {
1748 rt(v);
1749 }
1750 }
1751
1752 #[test]
1753 fn finite_f32_roundtrips() {
1754 for v in [0.0_f32, 1.5, -1.5, f32::MIN_POSITIVE, f32::MAX] {
1755 rt(v);
1756 }
1757 }
1758
1759 #[test]
1760 fn nonfinite_f64_rejected() {
1761 use crate::ErrorKind;
1762 let r = to_string(&f64::INFINITY);
1763 assert_eq!(r.unwrap_err().kind, ErrorKind::NonFiniteFloat);
1764 let r = to_string(&f64::NEG_INFINITY);
1765 assert_eq!(r.unwrap_err().kind, ErrorKind::NonFiniteFloat);
1766 let r = to_string(&f64::NAN);
1767 assert_eq!(r.unwrap_err().kind, ErrorKind::NonFiniteFloat);
1768 }
1769
1770 #[cfg(feature = "std")]
1771 #[test]
1772 fn duration_roundtrips() {
1773 use std::time::Duration;
1774 rt(Duration::from_secs(0));
1775 rt(Duration::from_millis(1500));
1776 rt(Duration::new(42, 750_000_000));
1777 }
1778}
1779
1780#[cfg(all(test, feature = "std"))]
1785mod to_json_macro_tests {
1786 use super::{parse_str, to_string};
1787 use crate::{FromJson, ToJson};
1788
1789 #[derive(Debug, PartialEq, ToJson)]
1791 struct Plain {
1792 id: u32,
1793 name: String,
1794 }
1795
1796 #[derive(Debug, PartialEq, FromJson)]
1797 struct PlainParse {
1798 id: u32,
1799 name: String,
1800 }
1801
1802 #[test]
1803 fn plain_struct_emits_object() {
1804 let v = Plain {
1805 id: 7,
1806 name: String::from("alice"),
1807 };
1808 let s = to_string(&v).unwrap();
1809 assert_eq!(s, r#"{"id":7,"name":"alice"}"#);
1811 let back: PlainParse = parse_str(&s).unwrap();
1813 assert_eq!(
1814 back,
1815 PlainParse {
1816 id: 7,
1817 name: String::from("alice")
1818 }
1819 );
1820 }
1821
1822 #[derive(Debug, PartialEq, ToJson)]
1823 struct Borrowed<'input> {
1824 tag: &'input str,
1825 count: u32,
1826 }
1827
1828 #[test]
1829 fn struct_with_lifetime() {
1830 let v = Borrowed {
1831 tag: "hi",
1832 count: 3,
1833 };
1834 let s = to_string(&v).unwrap();
1835 assert_eq!(s, r#"{"tag":"hi","count":3}"#);
1836 }
1837
1838 #[derive(Debug, PartialEq, ToJson)]
1840 struct Decorated {
1841 #[bourne(rename = "user-id")]
1842 user_id: u32,
1843 #[bourne(skip)]
1844 cached: u32,
1845 #[bourne(skip_if_none)]
1846 note: Option<String>,
1847 value: u32,
1848 }
1849
1850 #[test]
1851 fn rename_emits_new_key() {
1852 let v = Decorated {
1853 user_id: 1,
1854 cached: 99,
1855 note: None,
1856 value: 42,
1857 };
1858 let s = to_string(&v).unwrap();
1859 assert_eq!(s, r#"{"user-id":1,"value":42}"#);
1861 }
1862
1863 #[test]
1864 fn skip_if_none_emits_when_some() {
1865 let v = Decorated {
1866 user_id: 1,
1867 cached: 0,
1868 note: Some(String::from("hi")),
1869 value: 7,
1870 };
1871 let s = to_string(&v).unwrap();
1872 assert_eq!(s, r#"{"user-id":1,"note":"hi","value":7}"#);
1873 }
1874
1875 #[derive(Debug, PartialEq, ToJson)]
1877 struct Empty {}
1878
1879 #[test]
1880 fn empty_struct_emits_empty_object() {
1881 assert_eq!(to_string(&Empty {}).unwrap(), "{}");
1882 }
1883
1884 #[derive(Debug, PartialEq, ToJson)]
1888 struct WithEscape {
1889 text: String,
1890 }
1891
1892 #[test]
1893 fn macro_passes_strings_to_escape_path() {
1894 let v = WithEscape {
1895 text: String::from("a\nb\"c"),
1896 };
1897 let s = to_string(&v).unwrap();
1898 assert_eq!(s, r#"{"text":"a\nb\"c"}"#);
1899 }
1900
1901 #[derive(Debug, PartialEq, ToJson)]
1903 struct UserId(u64);
1904
1905 #[test]
1906 fn newtype_emits_bare_value() {
1907 let v = UserId(42);
1908 assert_eq!(to_string(&v).unwrap(), "42");
1909 }
1910
1911 #[derive(Debug, PartialEq, ToJson)]
1912 struct BorrowedTag<'input>(&'input str);
1913
1914 #[test]
1915 fn newtype_with_lifetime() {
1916 let v = BorrowedTag("hello");
1917 assert_eq!(to_string(&v).unwrap(), r#""hello""#);
1918 }
1919
1920 #[derive(Debug, PartialEq, ToJson)]
1922 struct Point(i32, i32);
1923
1924 #[test]
1925 fn tuple_struct_emits_array() {
1926 let v = Point(3, -7);
1927 assert_eq!(to_string(&v).unwrap(), "[3,-7]");
1928 }
1929
1930 #[derive(Debug, PartialEq, ToJson)]
1931 struct Triple(i32, String, bool);
1932
1933 #[test]
1934 fn three_field_tuple_struct() {
1935 let v = Triple(1, String::from("hi"), true);
1936 assert_eq!(to_string(&v).unwrap(), r#"[1,"hi",true]"#);
1937 }
1938
1939 #[derive(Debug, PartialEq, ToJson)]
1941 enum Shape {
1942 Circle,
1943 Wrapper(u32),
1944 Pair(u32, String),
1945 Box {
1946 w: u32,
1947 h: u32,
1948 },
1949 #[bourne(rename = "tri")]
1950 Triangle,
1951 }
1952
1953 #[test]
1954 fn enum_unit_emits_string() {
1955 assert_eq!(to_string(&Shape::Circle).unwrap(), r#""Circle""#);
1956 }
1957
1958 #[test]
1959 fn enum_renamed_unit() {
1960 assert_eq!(to_string(&Shape::Triangle).unwrap(), r#""tri""#);
1961 }
1962
1963 #[test]
1964 fn enum_newtype_emits_object() {
1965 assert_eq!(to_string(&Shape::Wrapper(7)).unwrap(), r#"{"Wrapper":7}"#);
1966 }
1967
1968 #[test]
1969 fn enum_tuple_emits_object_with_array() {
1970 let v = Shape::Pair(1, String::from("x"));
1971 assert_eq!(to_string(&v).unwrap(), r#"{"Pair":[1,"x"]}"#);
1972 }
1973
1974 #[test]
1975 fn enum_struct_variant_emits_nested_object() {
1976 let v = Shape::Box { w: 10, h: 20 };
1977 assert_eq!(to_string(&v).unwrap(), r#"{"Box":{"w":10,"h":20}}"#);
1978 }
1979
1980 #[derive(Debug, PartialEq, ToJson)]
1982 #[bourne(tag = "type")]
1983 enum Event {
1984 Heartbeat,
1985 #[bourne(rename = "click")]
1986 Click {
1987 x: u32,
1988 y: u32,
1989 },
1990 }
1991
1992 #[test]
1993 fn internal_tag_unit_emits_object_with_tag() {
1994 assert_eq!(
1995 to_string(&Event::Heartbeat).unwrap(),
1996 r#"{"type":"Heartbeat"}"#
1997 );
1998 }
1999
2000 #[test]
2001 fn internal_tag_struct_inlines_fields() {
2002 let v = Event::Click { x: 1, y: 2 };
2003 assert_eq!(to_string(&v).unwrap(), r#"{"type":"click","x":1,"y":2}"#);
2004 }
2005
2006 #[derive(Debug, PartialEq, ToJson)]
2008 #[bourne(tag = "t", content = "c")]
2009 enum Msg {
2010 Ping,
2011 Echo(String),
2012 Pair(u32, u32),
2013 Body { text: String },
2014 }
2015
2016 #[test]
2017 fn adjacent_unit_emits_only_tag() {
2018 assert_eq!(to_string(&Msg::Ping).unwrap(), r#"{"t":"Ping"}"#);
2019 }
2020
2021 #[test]
2022 fn adjacent_newtype_emits_content() {
2023 let v = Msg::Echo(String::from("hi"));
2024 assert_eq!(to_string(&v).unwrap(), r#"{"t":"Echo","c":"hi"}"#);
2025 }
2026
2027 #[test]
2028 fn adjacent_tuple_emits_content_array() {
2029 let v = Msg::Pair(1, 2);
2030 assert_eq!(to_string(&v).unwrap(), r#"{"t":"Pair","c":[1,2]}"#);
2031 }
2032
2033 #[test]
2034 fn adjacent_struct_emits_content_object() {
2035 let v = Msg::Body {
2036 text: String::from("ok"),
2037 };
2038 assert_eq!(to_string(&v).unwrap(), r#"{"t":"Body","c":{"text":"ok"}}"#);
2039 }
2040
2041 #[derive(Debug, PartialEq, ToJson)]
2043 #[bourne(untagged)]
2044 enum Mixed {
2045 Nothing,
2046 One(u32),
2047 Two(u32, u32),
2048 Body { name: String },
2049 }
2050
2051 #[test]
2052 fn untagged_unit_emits_null() {
2053 assert_eq!(to_string(&Mixed::Nothing).unwrap(), "null");
2054 }
2055
2056 #[test]
2057 fn untagged_newtype_emits_inner() {
2058 assert_eq!(to_string(&Mixed::One(42)).unwrap(), "42");
2059 }
2060
2061 #[test]
2062 fn untagged_tuple_emits_array() {
2063 assert_eq!(to_string(&Mixed::Two(1, 2)).unwrap(), "[1,2]");
2064 }
2065
2066 #[test]
2067 fn untagged_struct_emits_object() {
2068 let v = Mixed::Body {
2069 name: String::from("x"),
2070 };
2071 assert_eq!(to_string(&v).unwrap(), r#"{"name":"x"}"#);
2072 }
2073}
2074
2075#[cfg(all(test, feature = "std"))]
2078mod sink_adapter_tests {
2079 use super::{to_fmt, to_string};
2080
2081 #[test]
2082 fn fmt_sink_matches_to_string_for_struct() {
2083 let m = vec![("a", 1_i32), ("b", 2)]
2084 .into_iter()
2085 .collect::<std::collections::BTreeMap<_, _>>();
2086 let canonical = to_string(&m).unwrap();
2087 let mut out = String::new();
2088 to_fmt(&m, &mut out).unwrap();
2089 assert_eq!(out, canonical);
2090 }
2091
2092 #[test]
2093 fn fmt_sink_handles_floats_with_grisu3() {
2094 let canonical = to_string(&1.5_f64).unwrap();
2095 let mut out = String::new();
2096 to_fmt(&1.5_f64, &mut out).unwrap();
2097 assert_eq!(out, canonical);
2098 }
2099
2100 #[test]
2101 fn fmt_sink_rejects_non_finite() {
2102 let mut out = String::new();
2103 let err = to_fmt(&f64::INFINITY, &mut out).unwrap_err();
2104 assert_eq!(err.kind, crate::ErrorKind::NonFiniteFloat);
2105 }
2106
2107 #[cfg(feature = "std")]
2108 #[test]
2109 fn io_writer_matches_to_string_for_struct() {
2110 use super::to_writer;
2111 let v = vec![1_i32, 2, 3];
2112 let canonical = to_string(&v).unwrap();
2113 let mut buf = Vec::<u8>::new();
2114 to_writer(&v, &mut buf).unwrap();
2115 assert_eq!(String::from_utf8(buf).unwrap(), canonical);
2116 }
2117
2118 #[cfg(feature = "std")]
2119 #[test]
2120 fn io_writer_handles_floats() {
2121 use super::to_writer;
2122 let canonical = to_string(&-2.7e-5_f64).unwrap();
2123 let mut buf = Vec::<u8>::new();
2124 to_writer(&-2.7e-5_f64, &mut buf).unwrap();
2125 assert_eq!(String::from_utf8(buf).unwrap(), canonical);
2126 }
2127
2128 #[cfg(feature = "std")]
2129 #[test]
2130 fn io_writer_rejects_non_finite() {
2131 use super::to_writer;
2132 let mut buf = Vec::<u8>::new();
2133 let err = to_writer(&f64::NAN, &mut buf).unwrap_err();
2134 assert_eq!(err.kind(), std::io::ErrorKind::InvalidData);
2135 }
2136
2137 #[test]
2138 fn pretty_empty_object_compact() {
2139 use super::to_string_pretty;
2140 let m: std::collections::BTreeMap<String, i32> = std::collections::BTreeMap::new();
2141 assert_eq!(to_string_pretty(&m).unwrap(), "{}");
2142 }
2143
2144 #[test]
2145 fn pretty_empty_array_compact() {
2146 use super::to_string_pretty;
2147 let v: Vec<i32> = Vec::new();
2148 assert_eq!(to_string_pretty(&v).unwrap(), "[]");
2149 }
2150
2151 #[test]
2152 fn pretty_array_indents_two_spaces() {
2153 use super::to_string_pretty;
2154 let v = vec![1_i32, 2, 3];
2155 assert_eq!(to_string_pretty(&v).unwrap(), "[\n 1,\n 2,\n 3\n]");
2156 }
2157
2158 #[test]
2159 fn pretty_object_keys_have_one_space_after_colon() {
2160 use super::to_string_pretty;
2161 let m: std::collections::BTreeMap<&str, i32> = [("a", 1), ("b", 2)].into_iter().collect();
2162 assert_eq!(
2163 to_string_pretty(&m).unwrap(),
2164 "{\n \"a\": 1,\n \"b\": 2\n}",
2165 );
2166 }
2167
2168 #[test]
2169 fn pretty_nested_indents_proportionally() {
2170 use super::to_string_pretty;
2171 let v: Vec<Vec<i32>> = vec![vec![1, 2], vec![3]];
2172 assert_eq!(
2173 to_string_pretty(&v).unwrap(),
2174 "[\n [\n 1,\n 2\n ],\n [\n 3\n ]\n]",
2175 );
2176 }
2177
2178 #[cfg(feature = "indexmap")]
2179 #[test]
2180 fn indexmap_preserves_insertion_order_on_parse() {
2181 use crate::parse_str;
2182 let json = r#"{"zebra":1,"alpha":2,"mango":3}"#;
2186 let m: indexmap::IndexMap<String, i32> = parse_str(json).unwrap();
2187 let keys: Vec<&str> = m.keys().map(String::as_str).collect();
2188 assert_eq!(keys, ["zebra", "alpha", "mango"]);
2189 assert_eq!(m["alpha"], 2);
2190 }
2191
2192 #[cfg(feature = "indexmap")]
2193 #[test]
2194 fn indexmap_round_trips_preserving_order() {
2195 use super::to_string;
2196 use crate::parse_str;
2197 let mut m = indexmap::IndexMap::<String, i32>::new();
2198 m.insert("z".into(), 1);
2199 m.insert("a".into(), 2);
2200 m.insert("m".into(), 3);
2201 let s = to_string(&m).unwrap();
2202 assert_eq!(s, r#"{"z":1,"a":2,"m":3}"#);
2204 let back: indexmap::IndexMap<String, i32> = parse_str(&s).unwrap();
2206 assert_eq!(
2207 back.keys().map(String::as_str).collect::<Vec<_>>(),
2208 ["z", "a", "m"],
2209 );
2210 }
2211
2212 #[cfg(feature = "indexmap")]
2213 #[test]
2214 fn indexmap_rejects_duplicate_keys() {
2215 use crate::parse_str;
2216 let r: Result<indexmap::IndexMap<String, i32>, _> = parse_str(r#"{"a":1,"a":2}"#);
2217 assert_eq!(r.unwrap_err().kind, crate::ErrorKind::DuplicateKey);
2218 }
2219
2220 #[cfg(feature = "indexmap")]
2221 #[test]
2222 fn indexset_round_trips() {
2223 use super::to_string;
2224 use crate::parse_str;
2225 let mut s = indexmap::IndexSet::<i32>::new();
2226 s.insert(3);
2227 s.insert(1);
2228 s.insert(2);
2229 let json = to_string(&s).unwrap();
2230 assert_eq!(json, "[3,1,2]");
2231 let back: indexmap::IndexSet<i32> = parse_str(&json).unwrap();
2232 assert_eq!(back.iter().copied().collect::<Vec<_>>(), [3, 1, 2]);
2233 }
2234
2235 #[test]
2236 fn pretty_round_trips_through_compact_parse() {
2237 use super::{parse_str, to_string_pretty};
2238 let m: std::collections::BTreeMap<String, Vec<i32>> = [
2239 (String::from("a"), vec![1, 2]),
2240 (String::from("b"), vec![3]),
2241 ]
2242 .into_iter()
2243 .collect();
2244 let pretty = to_string_pretty(&m).unwrap();
2245 let back: std::collections::BTreeMap<String, Vec<i32>> = parse_str(&pretty).unwrap();
2248 assert_eq!(back, m);
2249 }
2250
2251 #[cfg(feature = "std")]
2252 #[test]
2253 fn io_writer_propagates_underlying_error() {
2254 use super::to_writer;
2255 struct FailingWriter;
2258 impl std::io::Write for FailingWriter {
2259 fn write(&mut self, _: &[u8]) -> std::io::Result<usize> {
2260 Err(std::io::Error::other("disk full"))
2261 }
2262 fn flush(&mut self) -> std::io::Result<()> {
2263 Ok(())
2264 }
2265 }
2266 let mut w = FailingWriter;
2267 let err = to_writer(&"hi", &mut w).unwrap_err();
2268 assert_eq!(err.to_string(), "disk full");
2269 }
2270}
2271
2272#[cfg(all(test, feature = "std"))]
2275mod json_macro_tests {
2276 use super::{parse_str, to_string};
2277 use crate::{FromJson, ToJson};
2278
2279 #[derive(Debug, PartialEq, FromJson, ToJson)]
2280 struct Plain {
2281 id: u32,
2282 name: String,
2283 }
2284
2285 #[test]
2286 fn plain_struct_round_trips() {
2287 let v = Plain {
2288 id: 7,
2289 name: String::from("alice"),
2290 };
2291 let s = to_string(&v).unwrap();
2292 assert_eq!(s, r#"{"id":7,"name":"alice"}"#);
2293 let back: Plain = parse_str(&s).unwrap();
2294 assert_eq!(back, v);
2295 }
2296
2297 #[derive(Debug, PartialEq, FromJson, ToJson)]
2298 struct Borrowed<'input> {
2299 tag: &'input str,
2300 count: u32,
2301 }
2302
2303 #[test]
2304 fn struct_with_lifetime_round_trips() {
2305 let json = r#"{"tag":"hi","count":3}"#;
2306 let v: Borrowed<'_> = parse_str(json).unwrap();
2307 assert_eq!(
2308 v,
2309 Borrowed {
2310 tag: "hi",
2311 count: 3
2312 }
2313 );
2314 assert_eq!(to_string(&v).unwrap(), json);
2315 }
2316
2317 #[derive(Debug, PartialEq, FromJson, ToJson)]
2318 struct Decorated {
2319 #[bourne(rename = "user-id")]
2320 user_id: u32,
2321 #[bourne(skip)]
2322 cached: u32,
2323 #[bourne(skip_if_none)]
2324 note: Option<String>,
2325 value: u32,
2326 }
2327
2328 #[test]
2329 fn rename_skip_skip_if_none() {
2330 let v = Decorated {
2331 user_id: 1,
2332 cached: 99,
2333 note: None,
2334 value: 42,
2335 };
2336 let s = to_string(&v).unwrap();
2337 assert_eq!(s, r#"{"user-id":1,"value":42}"#);
2338 let back: Decorated = parse_str(&s).unwrap();
2339 assert_eq!(back.user_id, 1);
2340 assert_eq!(back.value, 42);
2341 }
2342
2343 #[derive(Debug, PartialEq, FromJson, ToJson)]
2344 struct UserId(u64);
2345
2346 #[test]
2347 fn newtype_round_trips() {
2348 let v = UserId(42);
2349 let s = to_string(&v).unwrap();
2350 assert_eq!(s, "42");
2351 let back: UserId = parse_str(&s).unwrap();
2352 assert_eq!(back, v);
2353 }
2354
2355 #[derive(Debug, PartialEq, FromJson, ToJson)]
2356 struct Pair(i32, i32);
2357
2358 #[test]
2359 fn tuple_struct_round_trips() {
2360 let v = Pair(3, -7);
2361 let s = to_string(&v).unwrap();
2362 assert_eq!(s, "[3,-7]");
2363 let back: Pair = parse_str(&s).unwrap();
2364 assert_eq!(back, v);
2365 }
2366
2367 #[derive(Debug, PartialEq, FromJson, ToJson)]
2368 enum Shape {
2369 Circle,
2370 Wrapper(u32),
2371 Pair(u32, String),
2372 Box {
2373 w: u32,
2374 h: u32,
2375 },
2376 #[bourne(rename = "tri")]
2377 Triangle,
2378 }
2379
2380 #[test]
2381 fn externally_tagged_enum_round_trips() {
2382 let cases: Vec<(Shape, &str)> = vec![
2383 (Shape::Circle, r#""Circle""#),
2384 (Shape::Wrapper(7), r#"{"Wrapper":7}"#),
2385 (Shape::Pair(1, String::from("x")), r#"{"Pair":[1,"x"]}"#),
2386 (Shape::Box { w: 10, h: 20 }, r#"{"Box":{"w":10,"h":20}}"#),
2387 (Shape::Triangle, r#""tri""#),
2388 ];
2389 for (val, expected) in cases {
2390 let s = to_string(&val).unwrap();
2391 assert_eq!(s, expected);
2392 let back: Shape = parse_str(&s).unwrap();
2393 assert_eq!(back, val);
2394 }
2395 }
2396
2397 #[derive(Debug, PartialEq, FromJson, ToJson)]
2398 #[bourne(tag = "type")]
2399 enum Event {
2400 Heartbeat,
2401 #[bourne(rename = "click")]
2402 Click {
2403 x: u32,
2404 y: u32,
2405 },
2406 }
2407
2408 #[test]
2409 fn internally_tagged_enum_round_trips() {
2410 let hb = Event::Heartbeat;
2411 let s = to_string(&hb).unwrap();
2412 assert_eq!(s, r#"{"type":"Heartbeat"}"#);
2413 let back: Event = parse_str(&s).unwrap();
2414 assert_eq!(back, hb);
2415
2416 let click = Event::Click { x: 1, y: 2 };
2417 let s = to_string(&click).unwrap();
2418 assert_eq!(s, r#"{"type":"click","x":1,"y":2}"#);
2419 let back: Event = parse_str(&s).unwrap();
2420 assert_eq!(back, click);
2421 }
2422
2423 #[derive(Debug, PartialEq, FromJson, ToJson)]
2424 #[bourne(tag = "t", content = "c")]
2425 enum Msg {
2426 Ping,
2427 Echo(String),
2428 Pair(u32, u32),
2429 Body { text: String },
2430 }
2431
2432 #[test]
2433 fn adjacently_tagged_enum_round_trips() {
2434 let cases: Vec<(Msg, &str)> = vec![
2435 (Msg::Ping, r#"{"t":"Ping"}"#),
2436 (Msg::Echo(String::from("hi")), r#"{"t":"Echo","c":"hi"}"#),
2437 (Msg::Pair(1, 2), r#"{"t":"Pair","c":[1,2]}"#),
2438 (
2439 Msg::Body {
2440 text: String::from("ok"),
2441 },
2442 r#"{"t":"Body","c":{"text":"ok"}}"#,
2443 ),
2444 ];
2445 for (val, expected) in cases {
2446 let s = to_string(&val).unwrap();
2447 assert_eq!(s, expected);
2448 let back: Msg = parse_str(&s).unwrap();
2449 assert_eq!(back, val);
2450 }
2451 }
2452
2453 #[derive(Debug, PartialEq, FromJson, ToJson)]
2454 #[bourne(untagged)]
2455 enum Mixed {
2456 Nothing,
2457 One(u32),
2458 Two(u32, u32),
2459 Body { name: String },
2460 }
2461
2462 #[derive(Debug, PartialEq, Eq, FromJson, ToJson)]
2463 pub struct PubFields {
2464 pub id: u32,
2465 pub(crate) name: String,
2466 value: u32,
2467 }
2468
2469 #[test]
2470 fn pub_fields_round_trip() {
2471 let v = PubFields {
2472 id: 1,
2473 name: String::from("hi"),
2474 value: 2,
2475 };
2476 let s = to_string(&v).unwrap();
2477 assert_eq!(s, r#"{"id":1,"name":"hi","value":2}"#);
2478 let back: PubFields = parse_str(&s).unwrap();
2479 assert_eq!(back, v);
2480 }
2481
2482 #[test]
2483 fn untagged_enum_serializes() {
2484 assert_eq!(to_string(&Mixed::Nothing).unwrap(), "null");
2485 assert_eq!(to_string(&Mixed::One(42)).unwrap(), "42");
2486 assert_eq!(to_string(&Mixed::Two(1, 2)).unwrap(), "[1,2]");
2487 assert_eq!(
2488 to_string(&Mixed::Body {
2489 name: String::from("x")
2490 })
2491 .unwrap(),
2492 r#"{"name":"x"}"#,
2493 );
2494 }
2495}
2496
2497#[cfg(all(test, feature = "std"))]
2506mod unsafe_boundary_tests {
2507 use super::*;
2508 use alloc::string::String;
2509 use alloc::vec::Vec;
2510
2511 #[test]
2518 fn bytesink_slice_floats_exact_capacity() {
2519 for n in [0usize, 1, 2, 3, 7, 16, 17, 32, 33] {
2520 #[allow(clippy::cast_precision_loss)]
2521 let data: Vec<f64> = (0..n).map(|i| i as f64 + 0.5).collect();
2522 let mut out: Vec<u8> = Vec::with_capacity(2 + n * 33);
2523 let mut sink = ByteSink::new(&mut out);
2524 (data.as_slice()).write_json(&mut sink).expect("ser");
2525 let s = core::str::from_utf8(&out).expect("ASCII");
2526 let back: Vec<f64> = parse_str(s).expect("parse back");
2528 assert_eq!(back.len(), n, "n={n}");
2529 #[allow(clippy::cast_precision_loss, clippy::float_cmp)]
2530 for (i, &v) in back.iter().enumerate() {
2531 assert_eq!(v, i as f64 + 0.5, "n={n} i={i}");
2532 }
2533 }
2534 }
2535
2536 #[test]
2539 fn bytesink_slice_f32_exact_capacity() {
2540 for n in [0usize, 1, 2, 16, 17] {
2541 #[allow(clippy::cast_precision_loss)]
2542 let data: Vec<f32> = (0..n).map(|i| i as f32 + 0.25).collect();
2543 let mut out: Vec<u8> = Vec::with_capacity(2 + n * 33);
2544 let mut sink = ByteSink::new(&mut out);
2545 (data.as_slice()).write_json(&mut sink).expect("ser");
2546 let s = core::str::from_utf8(&out).expect("ASCII");
2547 let back: Vec<f32> = parse_str(s).expect("parse back");
2548 assert_eq!(back.len(), n);
2549 #[allow(clippy::cast_precision_loss, clippy::float_cmp)]
2550 for (i, &v) in back.iter().enumerate() {
2551 assert_eq!(v, i as f32 + 0.25, "n={n} i={i}");
2552 }
2553 }
2554 }
2555
2556 #[test]
2560 fn bytesink_slice_nonfinite_taint_path() {
2561 for (name, bad_idx, bad_val) in [
2565 ("inf at 0", 0usize, f64::INFINITY),
2566 ("nan at end", 4usize, f64::NAN),
2567 ("neg_inf middle", 2usize, f64::NEG_INFINITY),
2568 ] {
2569 let mut data: Vec<f64> = (0..5).map(f64::from).collect();
2570 data[bad_idx] = bad_val;
2571 let r = to_string(data.as_slice());
2572 assert!(r.is_err(), "{name}: expected non-finite error");
2573 }
2574 }
2575
2576 #[test]
2580 fn bytesink_slice_ints_exact_capacity() {
2581 for n in [0usize, 1, 5, 16, 17] {
2584 #[allow(clippy::cast_possible_wrap)]
2585 let n_i64 = n as i64;
2586 #[allow(clippy::cast_possible_wrap)]
2587 let data: Vec<i64> = (0..n).map(|i| (i as i64) - n_i64 / 2).collect();
2588 let mut out: Vec<u8> = Vec::with_capacity(2 + n * 21);
2589 let mut sink = ByteSink::new(&mut out);
2590 (data.as_slice()).write_json(&mut sink).expect("ser");
2591 let s = core::str::from_utf8(&out).expect("ASCII");
2592 let back: Vec<i64> = parse_str(s).expect("parse back");
2593 assert_eq!(back, data, "n={n}");
2594 }
2595 }
2596
2597 #[test]
2603 fn decode_escapes_multibyte_in_literal_chunk() {
2604 let cases: &[(&str, &str)] = &[
2608 (r#""café\nfin""#, "café\nfin"),
2609 (r#""price: 5€\tea""#, "price: 5€\tea"),
2610 (r#""note 𝄞\nplayed""#, "note 𝄞\nplayed"),
2611 (r#""éé\nçç\tüü""#, "éé\nçç\tüü"),
2613 (r#""\n𝄞café\t""#, "\n𝄞café\t"),
2615 (
2618 r#""aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaéé\n""#,
2619 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaéé\n",
2620 ),
2621 ];
2622 for (json, expected) in cases {
2623 let s: String = parse_str(json).expect("parse");
2624 assert_eq!(s, *expected, "case {json}");
2625 }
2626 }
2627
2628 #[test]
2631 fn bytesink_empty_slice_writes_brackets_only() {
2632 let empty: Vec<i64> = Vec::new();
2633 let s = to_string(empty.as_slice()).expect("ser");
2634 assert_eq!(s, "[]");
2635
2636 let empty: Vec<f64> = Vec::new();
2637 let s = to_string(empty.as_slice()).expect("ser");
2638 assert_eq!(s, "[]");
2639 }
2640
2641 #[test]
2644 fn bytesink_single_element_slice() {
2645 let one = [42_i64];
2646 assert_eq!(to_string(one.as_slice()).unwrap(), "[42]");
2647 let one = [1.5_f64];
2648 assert_eq!(to_string(one.as_slice()).unwrap(), "[1.5]");
2649 let one = [1.5_f32];
2650 assert_eq!(to_string(one.as_slice()).unwrap(), "[1.5]");
2651 }
2652
2653 #[test]
2657 fn decode_escapes_empty_string() {
2658 let s: String = parse_str(r#""""#).expect("parse");
2659 assert_eq!(s, "");
2660 }
2661
2662 #[test]
2666 fn decode_escapes_no_escapes_pure_ascii() {
2667 let v: Vec<String> = parse_str(r#"["hello world","no escapes here"]"#).expect("parse");
2670 assert_eq!(
2671 v,
2672 [String::from("hello world"), String::from("no escapes here")]
2673 );
2674 }
2675
2676 #[test]
2679 fn decode_escapes_escape_at_start() {
2680 let v: Vec<String> = parse_str(r#"["\nhello","\tworld"]"#).expect("parse");
2681 assert_eq!(v, [String::from("\nhello"), String::from("\tworld")]);
2682 }
2683
2684 #[test]
2687 fn decode_escapes_escape_at_end() {
2688 let v: Vec<String> = parse_str(r#"["hello\n","world\t"]"#).expect("parse");
2689 assert_eq!(v, [String::from("hello\n"), String::from("world\t")]);
2690 }
2691
2692 #[test]
2694 fn decode_escapes_consecutive_escapes() {
2695 let v: Vec<String> = parse_str(r#"["\n\t\r\\","\"\"\""]"#).expect("parse");
2696 assert_eq!(v, [String::from("\n\t\r\\"), String::from(r#"""""#)]);
2697 }
2698
2699 #[test]
2709 fn vec_borrowed_str_fast_path() {
2710 let v: Vec<&str> = parse_str("[]").expect("empty");
2712 assert_eq!(v, Vec::<&str>::new());
2713
2714 let v: Vec<&str> = parse_str(r#"["only"]"#).expect("single");
2716 assert_eq!(v, ["only"]);
2717
2718 let v: Vec<&str> = parse_str(r#"["a","b","c","d","e"]"#).expect("many");
2720 assert_eq!(v, ["a", "b", "c", "d", "e"]);
2721
2722 let r: Result<Vec<&str>, _> = parse_str(r#"["plain","esc\nbad"]"#);
2724 assert!(r.is_err(), "borrowed path must reject escape");
2725 }
2726
2727 #[cfg(feature = "std")]
2729 #[test]
2730 fn vec_duration_fast_path() {
2731 use std::time::Duration;
2732
2733 let v: Vec<Duration> = parse_str("[]").expect("empty");
2735 assert!(v.is_empty());
2736
2737 let v: Vec<Duration> = parse_str("[1.5]").expect("single");
2739 assert_eq!(v, [Duration::from_secs_f64(1.5)]);
2740
2741 let v: Vec<Duration> = parse_str("[0.0,1.0,1.5,2.25,100.125]").expect("many");
2743 assert_eq!(v.len(), 5);
2744 assert_eq!(v[0], Duration::ZERO);
2745 assert_eq!(v[4], Duration::from_secs_f64(100.125));
2746
2747 let r: Result<Vec<Duration>, _> = parse_str("[1.0,-2.0]");
2749 assert!(r.is_err());
2750 }
2751
2752 #[test]
2755 fn vec_i64_fast_path() {
2756 let v: Vec<i64> = parse_str("[]").expect("empty");
2757 assert!(v.is_empty());
2758
2759 let v: Vec<i64> = parse_str("[42]").expect("single");
2760 assert_eq!(v, [42]);
2761
2762 let v: Vec<i64> =
2763 parse_str("[1,-1,9223372036854775807,-9223372036854775808]").expect("many");
2764 assert_eq!(v, [1, -1, i64::MAX, i64::MIN]);
2765
2766 let r: Result<Vec<u32>, _> = parse_str("[1,99999999999]");
2768 assert!(r.is_err(), "u32 should overflow");
2769 }
2770
2771 #[test]
2773 fn vec_u128_fast_path() {
2774 let v: Vec<u128> = parse_str("[]").expect("empty");
2775 assert!(v.is_empty());
2776
2777 let v: Vec<u128> = parse_str("[0,170141183460469231731687303715884105727]").expect("many");
2778 assert_eq!(v, [0u128, i128::MAX as u128]);
2779 }
2780
2781 #[test]
2788 fn decode_all_simple_escapes() {
2789 let cases: &[(&str, &str)] = &[
2792 (r#""\b""#, "\u{0008}"), (r#""\f""#, "\u{000C}"), (r#""\/""#, "/"), (r#""\\""#, "\\"), (r#""\"""#, "\""), (r#""\n""#, "\n"),
2798 (r#""\r""#, "\r"),
2799 (r#""\t""#, "\t"),
2800 ];
2801 for &(json, expected) in cases {
2802 let s: String = parse_str(json).expect(json);
2803 assert_eq!(s, expected, "case {json}");
2804 }
2805 }
2806
2807 #[test]
2808 fn decode_unknown_escape_errors() {
2809 let r: Result<String, _> = parse_str(r#""\x""#);
2811 assert!(r.is_err(), "unknown escape should error");
2812
2813 let r: Result<String, _> = parse_str("\"\\\"");
2815 assert!(r.is_err(), "lone trailing backslash should error");
2816 }
2817
2818 #[test]
2819 fn decode_unicode_escape_short_input_errors() {
2820 let r: Result<String, _> = parse_str(r#""\u00""#);
2822 assert!(r.is_err(), "short \\u should error");
2823 let r: Result<String, _> = parse_str(r#""\u""#);
2824 assert!(r.is_err());
2825 }
2826
2827 #[test]
2828 fn decode_unicode_lone_low_surrogate_errors() {
2829 let r: Result<String, _> = parse_str(r#""\uDC00""#);
2832 assert!(r.is_err(), "lone low surrogate should error");
2833 }
2834
2835 #[test]
2836 fn decode_unicode_high_surrogate_then_invalid_low_errors() {
2837 let json = "\"\\uD800\\u0041\""; let r: Result<String, _> = parse_str(json);
2843 assert!(
2844 r.is_err(),
2845 "high surrogate then non-low-surrogate \\u must error"
2846 );
2847 }
2848
2849 #[test]
2853 fn decode_unicode_high_surrogate_then_short_second_escape_errors() {
2854 let json = r#""\uD800\u""#;
2855 let r: Result<String, _> = parse_str(json);
2856 assert!(r.is_err(), "high surrogate then truncated \\u must error");
2857 }
2858
2859 #[test]
2861 fn decode_unicode_high_surrogate_then_invalid_hex_errors() {
2862 let json = "\"\\uD800\\uZZZZ\"";
2863 let r: Result<String, _> = parse_str(json);
2864 assert!(r.is_err(), "high surrogate then bad hex must error");
2865 }
2866
2867 #[test]
2868 fn decode_unicode_high_surrogate_then_non_u_escape_errors() {
2869 let r: Result<String, _> = parse_str(r#""\uD800\n""#);
2871 assert!(
2872 r.is_err(),
2873 "high surrogate not followed by \\u should error"
2874 );
2875
2876 let r: Result<String, _> = parse_str(r#""\uD800A""#);
2878 assert!(
2879 r.is_err(),
2880 "high surrogate not followed by escape should error"
2881 );
2882 }
2883
2884 #[test]
2885 fn decode_unicode_surrogate_pair_round_trips() {
2886 let json = "\"\\uD83D\\uDE00\"";
2891 let s: String = parse_str(json).expect("parse");
2892 assert_eq!(s, "\u{1F600}");
2893
2894 let json = "\"a\\uD83D\\uDE00b\\uD83D\\uDE01c\"";
2896 let s: String = parse_str(json).expect("parse");
2897 assert_eq!(s, "a\u{1F600}b\u{1F601}c");
2898 }
2899
2900 #[test]
2901 fn decode_unicode_bmp_escape_round_trips() {
2902 let json = "\"\\u00E9\"";
2906 let s: String = parse_str(json).expect("parse");
2907 assert_eq!(s, "é");
2908
2909 let json = "\"A\\u00A3\\u20AC\""; let s: String = parse_str(json).expect("parse");
2912 assert_eq!(s, "A£€");
2913 }
2914
2915 #[test]
2916 fn decode_invalid_hex_in_u_escape_errors() {
2917 let r: Result<String, _> = parse_str(r#""\u00ZX""#);
2919 assert!(r.is_err(), "invalid hex should error");
2920 }
2921
2922 #[test]
2932 fn to_decimal_uncentred_powers_of_two_round_trip() {
2933 let cases = [
2936 2.0_f64,
2937 4.0,
2938 8.0,
2939 16.0,
2940 32.0,
2941 64.0,
2942 128.0,
2943 256.0,
2944 512.0,
2945 1024.0,
2946 2.0_f64.powi(20),
2947 2.0_f64.powi(50),
2948 2.0_f64.powi(100),
2949 2.0_f64.powi(500),
2950 2.0_f64.powi(1023), 2.0_f64.powi(-1), 2.0_f64.powi(-2), 2.0_f64.powi(-10),
2955 2.0_f64.powi(-50),
2956 2.0_f64.powi(-100),
2957 2.0_f64.powi(-1000),
2958 ];
2959 for &v in &cases {
2960 let s = to_string(&v).expect("ser");
2961 let back: f64 = parse_str(&s).expect("parse back");
2962 #[allow(clippy::float_cmp)]
2963 {
2964 assert_eq!(back, v, "round-trip for {v:e}: emitted {s:?}");
2965 }
2966 }
2967 }
2968
2969 #[test]
2971 fn to_decimal_uncentred_negative_powers_round_trip() {
2972 for k in [-30, -10, -1, 1, 10, 30, 100, 500] {
2973 let v = -(2.0_f64.powi(k));
2974 let s = to_string(&v).expect("ser");
2975 let back: f64 = parse_str(&s).expect("parse back");
2976 #[allow(clippy::float_cmp)]
2977 {
2978 assert_eq!(back, v, "round-trip for {v:e}: emitted {s:?}");
2979 }
2980 }
2981 }
2982
2983 #[test]
2986 fn to_decimal_uncentred_subnormals_round_trip() {
2987 let cases = [
2988 5e-324_f64, f64::MIN_POSITIVE, -f64::MIN_POSITIVE,
2991 f64::MAX,
2992 -f64::MAX,
2993 ];
2994 for &v in &cases {
2995 let s = to_string(&v).expect("ser");
2996 let back: f64 = parse_str(&s).expect("parse back");
2997 #[allow(clippy::float_cmp)]
2998 {
2999 assert_eq!(back, v, "round-trip for {v:e}: emitted {s:?}");
3000 }
3001 }
3002 }
3003
3004 #[test]
3013 fn string_sink_writes_directly() {
3014 let mut out = String::new();
3015 let mut sink = StringSink::new(&mut out);
3016 sink.write_byte(b'[').unwrap();
3018 sink.write_str_raw("1").unwrap();
3019 sink.write_byte(b',').unwrap();
3020 sink.write_float_f64(2.5).unwrap();
3022 sink.write_byte(b']').unwrap();
3023 assert_eq!(out, "[1,2.5]");
3024
3025 let mut out = String::new();
3027 let mut sink = StringSink::new(&mut out);
3028 assert!(sink.write_float_f64(f64::NAN).is_err());
3029 }
3030
3031 #[test]
3034 fn pretty_sink_with_indent_uses_custom_indent() {
3035 let mut out = String::new();
3036 let mut sink = PrettyStringSink::with_indent(&mut out, "\t");
3037 let data = (1_i32, 2_i32, 3_i32);
3038 data.write_json(&mut sink).unwrap();
3039 assert!(out.contains("\n\t"), "got: {out:?}");
3041 }
3042
3043 #[test]
3046 fn pretty_sink_handles_floats() {
3047 let v: alloc::vec::Vec<f64> = alloc::vec![1.5, 2.5, 3.0];
3048 let s = to_string_pretty(v.as_slice()).unwrap();
3049 assert!(s.contains("1.5"));
3050 assert!(s.contains("3.0"));
3051 }
3052
3053 #[test]
3056 fn bytesink_unchecked_float_nonfinite_returns_error() {
3057 let mut out: Vec<u8> = Vec::with_capacity(64);
3058 let mut sink = ByteSink::new(&mut out);
3059 #[allow(unsafe_code)]
3061 let r = unsafe { sink.write_float_f64_unchecked(f64::INFINITY) };
3062 assert!(r.is_err(), "non-finite must error through cold arm");
3063 }
3064
3065 #[test]
3068 fn bytesink_unchecked_finite_writes_value() {
3069 let mut out: Vec<u8> = Vec::with_capacity(64);
3070 let mut sink = ByteSink::new(&mut out);
3071 let value = 2.5_f64;
3075 #[allow(unsafe_code)]
3077 unsafe {
3078 sink.write_float_f64_unchecked_finite(value).unwrap();
3079 }
3080 let s = core::str::from_utf8(&out).unwrap();
3081 let parsed: f64 = s.parse().unwrap();
3082 assert_eq!(parsed.to_bits(), value.to_bits());
3084 }
3085
3086 #[cfg(feature = "std")]
3088 #[test]
3089 fn path_serializes_via_to_string() {
3090 use std::path::Path;
3091 let p = Path::new("/tmp/file.txt");
3092 let s = to_string(p).unwrap();
3093 assert_eq!(s, "\"/tmp/file.txt\"");
3094 }
3095
3096 #[test]
3099 fn map_with_cow_str_keys_serializes() {
3100 use alloc::borrow::Cow;
3101 use alloc::collections::BTreeMap;
3102 let mut m: BTreeMap<Cow<'_, str>, i32> = BTreeMap::new();
3103 m.insert(Cow::Borrowed("a"), 1);
3104 m.insert(Cow::Owned(String::from("b")), 2);
3105 let s = to_string(&m).unwrap();
3106 assert!(s.contains(r#""a":1"#));
3107 assert!(s.contains(r#""b":2"#));
3108 }
3109
3110 #[test]
3113 fn f64_pre_validate_slice_is_noop() {
3114 let slice: &[f64] = &[1.0, 2.0, f64::INFINITY];
3115 let r = <f64 as ToJson>::pre_validate_slice(slice);
3118 assert!(r.is_ok());
3119 }
3120
3121 #[test]
3127 fn to_fmt_writes_finite_and_rejects_nonfinite() {
3128 let mut s = String::new();
3129 to_fmt(&1.5_f64, &mut s).unwrap();
3130 assert_eq!(s, "1.5");
3131
3132 let mut s = String::new();
3133 assert!(to_fmt(&f64::INFINITY, &mut s).is_err());
3134 }
3135
3136 #[test]
3141 fn to_fmt_propagates_underlying_write_failure() {
3142 use core::fmt;
3143
3144 struct AlwaysFail;
3146 impl fmt::Write for AlwaysFail {
3147 fn write_str(&mut self, _s: &str) -> fmt::Result {
3148 Err(fmt::Error)
3149 }
3150 }
3151
3152 let mut sink = AlwaysFail;
3155 let r = to_fmt(&42_i64, &mut sink);
3156 assert!(r.is_err(), "expected propagated error from failing writer");
3157
3158 let mut sink = AlwaysFail;
3161 let r = to_fmt(&1.5_f64, &mut sink);
3162 assert!(r.is_err());
3163 }
3164}