1use std::borrow::Cow;
2use std::collections::HashMap;
3use std::rc::Rc;
4
5use super::ast::*;
6use super::common::Range;
7use super::errors::*;
8use super::scanner::Scanner;
9use super::scanner::ScannerOptions;
10use super::tokens::Token;
11use super::tokens::TokenAndRange;
12
13pub type CommentMap<'a> = HashMap<usize, Rc<Vec<Comment<'a>>>>;
17
18#[derive(Default, Debug, PartialEq, Clone)]
23pub enum CommentCollectionStrategy {
24 #[default]
26 Off,
27 Separate,
33 AsTokens,
38}
39
40#[derive(Default, Clone)]
42pub struct CollectOptions {
43 pub comments: CommentCollectionStrategy,
45 pub tokens: bool,
47}
48
49#[derive(Clone)]
51pub struct ParseOptions {
52 pub allow_comments: bool,
54 pub allow_loose_object_property_names: bool,
56 pub allow_trailing_commas: bool,
58 pub allow_missing_commas: bool,
60 pub allow_single_quoted_strings: bool,
62 pub allow_hexadecimal_numbers: bool,
64 pub allow_unary_plus_numbers: bool,
66}
67
68impl Default for ParseOptions {
69 fn default() -> Self {
70 Self {
71 allow_comments: true,
72 allow_loose_object_property_names: true,
73 allow_trailing_commas: true,
74 allow_missing_commas: true,
75 allow_single_quoted_strings: true,
76 allow_hexadecimal_numbers: true,
77 allow_unary_plus_numbers: true,
78 }
79 }
80}
81
82pub struct ParseResult<'a> {
84 pub comments: Option<CommentMap<'a>>,
90 pub value: Option<Value<'a>>,
92 pub tokens: Option<Vec<TokenAndRange<'a>>>,
96}
97
98struct Context<'a> {
99 scanner: Scanner<'a>,
100 comments: Option<CommentMap<'a>>,
101 current_comments: Option<Vec<Comment<'a>>>,
102 last_token_end: usize,
103 range_stack: Vec<Range>,
104 tokens: Option<Vec<TokenAndRange<'a>>>,
105 collect_comments_as_tokens: bool,
106 allow_comments: bool,
107 allow_trailing_commas: bool,
108 allow_missing_commas: bool,
109 allow_loose_object_property_names: bool,
110 maximum_nesting_depth: usize,
111}
112
113impl<'a> Context<'a> {
114 pub fn scan(&mut self) -> Result<Option<Token<'a>>, ParseError> {
115 let previous_end = self.last_token_end;
116 let token = self.scan_handling_comments()?;
117 self.last_token_end = self.scanner.token_end();
118
119 if let Some(comments) = self.comments.as_mut()
121 && let Some(current_comments) = self.current_comments.take()
122 {
123 let current_comments = Rc::new(current_comments);
124 comments.insert(previous_end, current_comments.clone());
125 comments.insert(self.scanner.token_start(), current_comments);
126 }
127
128 if let Some(token) = &token
129 && self.tokens.is_some()
130 {
131 self.capture_token(token.clone());
132 }
133
134 Ok(token)
135 }
136
137 pub fn token(&self) -> Option<Token<'a>> {
138 self.scanner.token()
139 }
140
141 pub fn start_range(&mut self) {
142 self.range_stack.push(Range {
143 start: self.scanner.token_start(),
144 end: 0,
145 });
146 }
147
148 pub fn end_range(&mut self) -> Range {
149 let mut range = self
150 .range_stack
151 .pop()
152 .expect("Range was popped from the stack, but the stack was empty.");
153 range.end = self.scanner.token_end();
154 range
155 }
156
157 pub fn create_range_from_last_token(&self) -> Range {
158 Range {
159 start: self.scanner.token_start(),
160 end: self.scanner.token_end(),
161 }
162 }
163
164 pub fn create_error(&self, kind: ParseErrorKind) -> ParseError {
165 self.scanner.create_error_for_current_token(kind)
166 }
167
168 pub fn create_error_for_current_range(&mut self, kind: ParseErrorKind) -> ParseError {
169 let range = self.end_range();
170 self.create_error_for_range(range, kind)
171 }
172
173 pub fn create_error_for_range(&self, range: Range, kind: ParseErrorKind) -> ParseError {
174 self.scanner.create_error_for_range(range, kind)
175 }
176
177 fn scan_handling_comments(&mut self) -> Result<Option<Token<'a>>, ParseError> {
178 loop {
179 let token = self.scanner.scan()?;
180 match token {
181 Some(token @ Token::CommentLine(_) | token @ Token::CommentBlock(_)) if self.collect_comments_as_tokens => {
182 self.capture_token(token);
183 }
184 Some(Token::CommentLine(text)) => {
185 self.handle_comment(Comment::Line(CommentLine {
186 range: self.create_range_from_last_token(),
187 text,
188 }))?;
189 }
190 Some(Token::CommentBlock(text)) => {
191 self.handle_comment(Comment::Block(CommentBlock {
192 range: self.create_range_from_last_token(),
193 text,
194 }))?;
195 }
196 _ => return Ok(token),
197 }
198 }
199 }
200
201 fn capture_token(&mut self, token: Token<'a>) {
202 let range = self.create_range_from_last_token();
203 if let Some(tokens) = self.tokens.as_mut() {
204 tokens.push(TokenAndRange {
205 token: token.clone(),
206 range,
207 });
208 }
209 }
210
211 fn handle_comment(&mut self, comment: Comment<'a>) -> Result<(), ParseError> {
212 if !self.allow_comments {
213 return Err(self.create_error(ParseErrorKind::CommentsNotAllowed));
214 }
215
216 if self.comments.is_some() {
217 if let Some(comments) = self.current_comments.as_mut() {
218 comments.push(comment);
219 } else {
220 self.current_comments = Some(vec![comment]);
221 }
222 }
223
224 Ok(())
225 }
226}
227
228pub fn parse_to_ast<'a>(
245 text: &'a str,
246 collect_options: &CollectOptions,
247 parse_options: &ParseOptions,
248) -> Result<ParseResult<'a>, ParseError> {
249 let mut context = Context {
250 scanner: Scanner::new(
251 text,
252 &ScannerOptions {
253 allow_single_quoted_strings: parse_options.allow_single_quoted_strings,
254 allow_hexadecimal_numbers: parse_options.allow_hexadecimal_numbers,
255 allow_unary_plus_numbers: parse_options.allow_unary_plus_numbers,
256 },
257 ),
258 comments: match collect_options.comments {
259 CommentCollectionStrategy::Separate => Some(Default::default()),
260 CommentCollectionStrategy::Off | CommentCollectionStrategy::AsTokens => None,
261 },
262 current_comments: None,
263 last_token_end: 0,
264 range_stack: Vec::new(),
265 tokens: if collect_options.tokens { Some(Vec::new()) } else { None },
266 collect_comments_as_tokens: collect_options.comments == CommentCollectionStrategy::AsTokens,
267 allow_comments: parse_options.allow_comments,
268 allow_trailing_commas: parse_options.allow_trailing_commas,
269 allow_missing_commas: parse_options.allow_missing_commas,
270 allow_loose_object_property_names: parse_options.allow_loose_object_property_names,
271 maximum_nesting_depth: 512,
272 };
273 context.scan()?;
274 let value = parse_value(&mut context)?;
275
276 if context.scan()?.is_some() {
277 return Err(context.create_error(ParseErrorKind::MultipleRootJsonValues));
278 }
279
280 debug_assert!(context.range_stack.is_empty());
281
282 Ok(ParseResult {
283 comments: context.comments,
284 tokens: context.tokens,
285 value,
286 })
287}
288
289fn parse_value<'a>(context: &mut Context<'a>) -> Result<Option<Value<'a>>, ParseError> {
290 if context.range_stack.len() > context.maximum_nesting_depth {
291 return Err(context.create_error_for_current_range(ParseErrorKind::NestingDepthExceeded));
292 }
293
294 match context.token() {
295 None => Ok(None),
296 Some(token) => match token {
297 Token::OpenBrace => Ok(Some(Value::Object(parse_object(context)?))),
298 Token::OpenBracket => Ok(Some(Value::Array(parse_array(context)?))),
299 Token::String(value) => Ok(Some(Value::StringLit(create_string_lit(context, value)))),
300 Token::Boolean(value) => Ok(Some(Value::BooleanLit(create_boolean_lit(context, value)))),
301 Token::Number(value) => Ok(Some(Value::NumberLit(create_number_lit(context, value)))),
302 Token::Null => Ok(Some(Value::NullKeyword(create_null_keyword(context)))),
303 Token::CloseBracket => Err(context.create_error(ParseErrorKind::UnexpectedCloseBracket)),
304 Token::CloseBrace => Err(context.create_error(ParseErrorKind::UnexpectedCloseBrace)),
305 Token::Comma => Err(context.create_error(ParseErrorKind::UnexpectedComma)),
306 Token::Colon => Err(context.create_error(ParseErrorKind::UnexpectedColon)),
307 Token::Word(_) => Err(context.create_error(ParseErrorKind::UnexpectedWord)),
308 Token::CommentLine(_) => unreachable!(),
309 Token::CommentBlock(_) => unreachable!(),
310 },
311 }
312}
313
314fn parse_object<'a>(context: &mut Context<'a>) -> Result<Object<'a>, ParseError> {
315 debug_assert!(context.token() == Some(Token::OpenBrace));
316 let mut properties = Vec::new();
317
318 context.start_range();
319 context.scan()?;
320
321 loop {
322 match context.token() {
323 Some(Token::CloseBrace) => break,
324 Some(Token::String(prop_name)) => {
325 properties.push(parse_object_property(context, PropName::String(prop_name))?);
326 }
327 Some(Token::Word(prop_name)) | Some(Token::Number(prop_name)) => {
328 properties.push(parse_object_property(context, PropName::Word(prop_name))?);
329 }
330 None => return Err(context.create_error_for_current_range(ParseErrorKind::UnterminatedObject)),
331 _ => return Err(context.create_error(ParseErrorKind::UnexpectedTokenInObject)),
332 }
333
334 let after_value_end = context.last_token_end;
336 match context.scan()? {
337 Some(Token::Comma) => {
338 let comma_range = context.create_range_from_last_token();
339 if let Some(Token::CloseBrace) = context.scan()?
340 && !context.allow_trailing_commas
341 {
342 return Err(context.create_error_for_range(comma_range, ParseErrorKind::TrailingCommasNotAllowed));
343 }
344 }
345 Some(Token::String(_) | Token::Word(_) | Token::Number(_)) if !context.allow_missing_commas => {
346 let range = Range {
347 start: after_value_end,
348 end: after_value_end,
349 };
350 return Err(context.create_error_for_range(range, ParseErrorKind::ExpectedComma));
351 }
352 _ => {}
353 }
354 }
355
356 Ok(Object {
357 range: context.end_range(),
358 properties,
359 })
360}
361
362enum PropName<'a> {
363 String(Cow<'a, str>),
364 Word(&'a str),
365}
366
367fn parse_object_property<'a>(context: &mut Context<'a>, prop_name: PropName<'a>) -> Result<ObjectProp<'a>, ParseError> {
368 context.start_range();
369
370 let name = match prop_name {
371 PropName::String(prop_name) => ObjectPropName::String(create_string_lit(context, prop_name)),
372 PropName::Word(prop_name) => {
373 if context.allow_loose_object_property_names {
374 ObjectPropName::Word(create_word(context, prop_name))
375 } else {
376 return Err(context.create_error(ParseErrorKind::ExpectedStringObjectProperty));
377 }
378 }
379 };
380
381 match context.scan()? {
382 Some(Token::Colon) => {}
383 _ => return Err(context.create_error(ParseErrorKind::ExpectedColonAfterObjectKey)),
384 }
385
386 context.scan()?;
387 let value = parse_value(context)?;
388
389 match value {
390 Some(value) => Ok(ObjectProp {
391 range: context.end_range(),
392 name,
393 value,
394 }),
395 None => Err(context.create_error(ParseErrorKind::ExpectedObjectValue)),
396 }
397}
398
399fn parse_array<'a>(context: &mut Context<'a>) -> Result<Array<'a>, ParseError> {
400 debug_assert!(context.token() == Some(Token::OpenBracket));
401 let mut elements = Vec::new();
402
403 context.start_range();
404 context.scan()?;
405
406 loop {
407 match context.token() {
408 Some(Token::CloseBracket) => break,
409 None => return Err(context.create_error_for_current_range(ParseErrorKind::UnterminatedArray)),
410 _ => match parse_value(context)? {
411 Some(value) => elements.push(value),
412 None => return Err(context.create_error_for_current_range(ParseErrorKind::UnterminatedArray)),
413 },
414 }
415
416 let after_value_end = context.last_token_end;
418 match context.scan()? {
419 Some(Token::Comma) => {
420 let comma_range = context.create_range_from_last_token();
421 if let Some(Token::CloseBracket) = context.scan()?
422 && !context.allow_trailing_commas
423 {
424 return Err(context.create_error_for_range(comma_range, ParseErrorKind::TrailingCommasNotAllowed));
425 }
426 }
427 Some(token) if !context.allow_missing_commas && token.is_value_start() => {
428 let range = Range {
429 start: after_value_end,
430 end: after_value_end,
431 };
432 return Err(context.create_error_for_range(range, ParseErrorKind::ExpectedComma));
433 }
434 _ => {}
435 }
436 }
437
438 Ok(Array {
439 range: context.end_range(),
440 elements,
441 })
442}
443
444fn create_string_lit<'a>(context: &Context<'a>, value: Cow<'a, str>) -> StringLit<'a> {
447 StringLit {
448 range: context.create_range_from_last_token(),
449 value,
450 }
451}
452
453fn create_word<'a>(context: &Context<'a>, value: &'a str) -> WordLit<'a> {
454 WordLit {
455 range: context.create_range_from_last_token(),
456 value,
457 }
458}
459
460fn create_boolean_lit(context: &Context, value: bool) -> BooleanLit {
461 BooleanLit {
462 range: context.create_range_from_last_token(),
463 value,
464 }
465}
466
467fn create_number_lit<'a>(context: &Context<'a>, value: &'a str) -> NumberLit<'a> {
468 NumberLit {
469 range: context.create_range_from_last_token(),
470 value,
471 }
472}
473
474fn create_null_keyword(context: &Context) -> NullKeyword {
475 NullKeyword {
476 range: context.create_range_from_last_token(),
477 }
478}
479
480#[cfg(test)]
481mod tests {
482 use super::*;
483 use pretty_assertions::assert_eq;
484
485 #[test]
486 fn it_should_error_when_has_multiple_values() {
487 assert_has_error(
488 "[][]",
489 "Text cannot contain more than one JSON value on line 1 column 3",
490 );
491 }
492
493 #[test]
494 fn it_should_error_when_object_is_not_terminated() {
495 assert_has_error("{", "Unterminated object on line 1 column 1");
496 }
497
498 #[test]
499 fn it_should_error_when_object_has_unexpected_token() {
500 assert_has_error("{ [] }", "Unexpected token in object on line 1 column 3");
501 }
502
503 #[test]
504 fn it_should_error_when_object_has_two_non_string_tokens() {
505 assert_has_error(
506 "{ asdf asdf: 5 }",
507 "Expected colon after the string or word in object property on line 1 column 8",
508 );
509 }
510
511 #[test]
512 fn it_should_error_when_array_is_not_terminated() {
513 assert_has_error("[", "Unterminated array on line 1 column 1");
514 }
515
516 #[test]
517 fn it_should_error_when_array_has_unexpected_token() {
518 assert_has_error("[:]", "Unexpected colon on line 1 column 2");
519 }
520
521 #[test]
522 fn it_should_error_when_comment_block_not_closed() {
523 assert_has_error("/* test", "Unterminated comment block on line 1 column 1");
524 }
525
526 #[test]
527 fn it_should_error_when_string_lit_not_closed() {
528 assert_has_error("\" test", "Unterminated string literal on line 1 column 1");
529 }
530
531 fn assert_has_error(text: &str, message: &str) {
532 let result = parse_to_ast(text, &Default::default(), &Default::default());
533 match result {
534 Ok(_) => panic!("Expected error, but did not find one."),
535 Err(err) => assert_eq!(err.to_string(), message),
536 }
537 }
538
539 #[test]
540 fn strict_should_error_object_trailing_comma() {
541 assert_has_strict_error(
542 r#"{ "test": 5, }"#,
543 "Trailing commas are not allowed on line 1 column 12",
544 );
545 }
546
547 #[test]
548 fn strict_should_error_array_trailing_comma() {
549 assert_has_strict_error(r#"[ "test", ]"#, "Trailing commas are not allowed on line 1 column 9");
550 }
551
552 #[test]
553 fn strict_should_error_comment_line() {
554 assert_has_strict_error(r#"[ "test" ] // 1"#, "Comments are not allowed on line 1 column 12");
555 }
556
557 #[test]
558 fn strict_should_error_comment_block() {
559 assert_has_strict_error(r#"[ "test" /* 1 */]"#, "Comments are not allowed on line 1 column 10");
560 }
561
562 #[test]
563 fn strict_should_error_word_property() {
564 assert_has_strict_error(
565 r#"{ word: 5 }"#,
566 "Expected string for object property on line 1 column 3",
567 );
568 }
569
570 #[test]
571 fn strict_should_error_single_quoted_string() {
572 assert_has_strict_error(
573 r#"{ "key": 'value' }"#,
574 "Single-quoted strings are not allowed on line 1 column 10",
575 );
576 }
577
578 #[test]
579 fn strict_should_error_hexadecimal_number() {
580 assert_has_strict_error(
581 r#"{ "key": 0xFF }"#,
582 "Hexadecimal numbers are not allowed on line 1 column 10",
583 );
584 }
585
586 #[test]
587 fn strict_should_error_unary_plus_number() {
588 assert_has_strict_error(
589 r#"{ "key": +42 }"#,
590 "Unary plus on numbers is not allowed on line 1 column 10",
591 );
592 }
593
594 #[track_caller]
595 fn assert_has_strict_error(text: &str, message: &str) {
596 let result = parse_to_ast(text, &Default::default(), &strict_options());
597 match result {
598 Ok(_) => panic!("Expected error, but did not find one."),
599 Err(err) => assert_eq!(err.to_string(), message),
600 }
601 }
602
603 fn strict_options() -> ParseOptions {
604 ParseOptions {
605 allow_comments: false,
606 allow_loose_object_property_names: false,
607 allow_trailing_commas: false,
608 allow_missing_commas: false,
609 allow_single_quoted_strings: false,
610 allow_hexadecimal_numbers: false,
611 allow_unary_plus_numbers: false,
612 }
613 }
614
615 #[test]
616 fn it_should_not_include_tokens_by_default() {
617 let result = parse_to_ast("{}", &Default::default(), &Default::default()).unwrap();
618 assert!(result.tokens.is_none());
619 }
620
621 #[test]
622 fn it_should_include_tokens_when_specified() {
623 let result = parse_to_ast(
624 "{}",
625 &CollectOptions {
626 tokens: true,
627 ..Default::default()
628 },
629 &Default::default(),
630 )
631 .unwrap();
632 let tokens = result.tokens.unwrap();
633 assert_eq!(tokens.len(), 2);
634 }
635
636 #[test]
637 fn it_should_not_include_comments_by_default() {
638 let result = parse_to_ast("{}", &Default::default(), &Default::default()).unwrap();
639 assert!(result.comments.is_none());
640 }
641
642 #[test]
643 fn it_should_include_comments_when_specified() {
644 let result = parse_to_ast(
645 "{} // 2",
646 &CollectOptions {
647 comments: CommentCollectionStrategy::Separate,
648 ..Default::default()
649 },
650 &Default::default(),
651 )
652 .unwrap();
653 let comments = result.comments.unwrap();
654 assert_eq!(comments.len(), 2); }
656
657 #[cfg(not(feature = "error_unicode_width"))]
658 #[test]
659 fn error_correct_line_column_unicode_width() {
660 assert_has_strict_error(r#"["🧑🦰", ["#, "Unterminated array on line 1 column 9");
661 }
662
663 #[cfg(feature = "error_unicode_width")]
664 #[test]
665 fn error_correct_line_column_unicode_width() {
666 assert_has_strict_error(r#"["🧑🦰", ["#, "Unterminated array on line 1 column 10");
667 }
668
669 #[test]
670 fn it_should_parse_unquoted_keys_with_hex_and_trailing_comma() {
671 let text = r#"{
672 CP_CanFuncReqId: 0x7DF, // 2015
673 }"#;
674 {
675 let parse_result = parse_to_ast(text, &Default::default(), &Default::default()).unwrap();
676
677 let value = parse_result.value.unwrap();
678 let obj = value.as_object().unwrap();
679 assert_eq!(obj.properties.len(), 1);
680 assert_eq!(obj.properties[0].name.as_str(), "CP_CanFuncReqId");
681
682 let number_value = obj.properties[0].value.as_number_lit().unwrap();
683 assert_eq!(number_value.value, "0x7DF");
684 }
685 #[cfg(feature = "serde")]
686 {
687 let value: serde_json::Value = crate::parse_to_serde_value(text, &Default::default()).unwrap();
688 assert_eq!(
690 value,
691 serde_json::json!({
692 "CP_CanFuncReqId": 2015
693 })
694 );
695 }
696 }
697
698 #[test]
699 fn it_should_parse_unary_plus_numbers() {
700 let result = parse_to_ast(r#"{ "test": +42 }"#, &Default::default(), &Default::default()).unwrap();
701
702 let value = result.value.unwrap();
703 let obj = value.as_object().unwrap();
704 assert_eq!(obj.properties.len(), 1);
705 assert_eq!(obj.properties[0].name.as_str(), "test");
706
707 let number_value = obj.properties[0].value.as_number_lit().unwrap();
708 assert_eq!(number_value.value, "+42");
709 }
710
711 #[test]
712 fn missing_comma_between_properties() {
713 let text = r#"{
714 "name": "alice"
715 "age": 25
716}"#;
717 let result = parse_to_ast(text, &Default::default(), &Default::default()).unwrap();
718 assert_eq!(
719 result
720 .value
721 .unwrap()
722 .as_object()
723 .unwrap()
724 .get_number("age")
725 .unwrap()
726 .value,
727 "25"
728 );
729
730 assert_has_strict_error(text, "Expected comma on line 2 column 18");
732 }
733
734 #[test]
735 fn missing_comma_with_comment_between_properties() {
736 let result = parse_to_ast(
739 r#"{
740 "name": "alice" // comment here
741 "age": 25
742}"#,
743 &Default::default(),
744 &ParseOptions {
745 allow_comments: true,
746 allow_missing_commas: false,
747 ..Default::default()
748 },
749 );
750 match result {
751 Ok(_) => panic!("Expected error, but did not find one."),
752 Err(err) => assert_eq!(err.to_string(), "Expected comma on line 2 column 18"),
753 }
754 }
755
756 #[test]
757 fn missing_comma_between_array_elements() {
758 let text = "[1 2]";
759 let result = parse_to_ast(text, &Default::default(), &Default::default()).unwrap();
760 let value = result.value.unwrap();
761 let elements = &value.as_array().unwrap().elements;
762 assert_eq!(elements.len(), 2);
763
764 assert_has_strict_error(text, "Expected comma on line 1 column 3");
766 assert_has_strict_error("[01]", "Expected comma on line 1 column 3");
767 assert_has_strict_error(r#"["a" "b"]"#, "Expected comma on line 1 column 5");
768 assert_has_strict_error("[true false]", "Expected comma on line 1 column 6");
769 assert_has_strict_error("[null null]", "Expected comma on line 1 column 6");
770 assert_has_strict_error("[[1] [2]]", "Expected comma on line 1 column 5");
771 assert_has_strict_error(r#"[{"a":1} {"b":2}]"#, "Expected comma on line 1 column 9");
772 assert_has_strict_error("[1 2", "Expected comma on line 1 column 3");
773
774 assert_has_strict_error("[1", "Unterminated array on line 1 column 1");
776 assert_has_strict_error("[1 a ]", "Unexpected word on line 1 column 4");
777
778 for text in ["[]", "[ ]", "[1,2]", "[1 , 2]", "[[1],[2]]", r#"[{"a":1},{"b":2}]"#] {
779 parse_to_ast(text, &Default::default(), &strict_options()).unwrap();
780 }
781 }
782
783 #[test]
784 fn missing_comma_not_allowed_with_trailing_commas_allowed_in_array() {
785 let options = ParseOptions {
786 allow_missing_commas: false,
787 allow_trailing_commas: true,
788 ..Default::default()
789 };
790 for text in ["[]", "[1,]", "[1, 2,]", "[[1,],[2,],]"] {
791 parse_to_ast(text, &Default::default(), &options).unwrap();
792 }
793 }
794
795 #[test]
796 fn missing_comma_with_comment_between_array_elements() {
797 let result = parse_to_ast(
800 r#"[
801 1 // comment here
802 2
803]"#,
804 &Default::default(),
805 &ParseOptions {
806 allow_comments: true,
807 allow_missing_commas: false,
808 ..Default::default()
809 },
810 );
811 match result {
812 Ok(_) => panic!("Expected error, but did not find one."),
813 Err(err) => assert_eq!(err.to_string(), "Expected comma on line 2 column 4"),
814 }
815 }
816
817 #[test]
818 fn it_should_error_when_arrays_are_deeply_nested() {
819 let mut json = String::new();
821 let depth = 30_000;
822
823 for _ in 0..depth {
824 json += "[";
825 }
826
827 for _ in 0..depth {
828 json += "]";
829 }
830
831 let result = parse_to_ast(&json, &Default::default(), &ParseOptions::default());
832
833 match result {
834 Ok(_) => panic!("Expected error, but did not find one."),
835 Err(err) => assert_eq!(err.to_string(), "Maximum nesting depth exceeded on line 1 column 513"),
836 }
837 }
838
839 #[test]
840 fn it_should_error_when_objects_are_deeply_nested() {
841 let mut json = String::new();
843 let depth = 30_000;
844
845 for _ in 0..depth {
846 json += "{\"q\":";
847 }
848
849 for _ in 0..depth {
850 json += "}";
851 }
852
853 let result = parse_to_ast(&json, &Default::default(), &ParseOptions::default());
854
855 match result {
856 Ok(_) => panic!("Expected error, but did not find one."),
857 Err(err) => assert_eq!(err.to_string(), "Maximum nesting depth exceeded on line 1 column 1282"),
858 }
859 }
860
861 #[test]
862 fn it_should_parse_large_shallow_objects() {
863 let mut json = "{\"q\":[".to_string();
865 let size = 1_000;
866
867 for _ in 0..size {
868 json += "{\"q\":[{}]}, [\"hello\"], ";
869 }
870
871 json += "]}";
872
873 let result = parse_to_ast(&json, &Default::default(), &ParseOptions::default());
874
875 match result {
876 Ok(_) => {}
877 Err(_) => panic!("Expected Ok, but did not find one."),
878 }
879 }
880}