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