1crate::ix!();
2
3#[derive(Debug)]
4pub enum Token {
5 String(String),
6 Number(String),
7 Symbol(char),
8 Whitespace,
9 Comment,
10}
11
12pub fn repair_json_add_missing_quotes(input: &str) -> Result<String, JsonRepairError> {
13
14 let mut changed = false;
15 let mut tokens = tokenize(input, &mut changed)?;
16 let json_value = parse_value(&mut tokens)?;
17 let output = serde_json::to_string(&json_value).map_err(|inner| JsonRepairError::SerdeParseError { inner })?;
18
19 if changed {
20 info!("added missing quotations where necessary");
21 }
22
23 Ok(output)
24}
25
26pub fn tokenize(input: &str, changed: &mut bool) -> Result<VecDeque<Token>, JsonRepairError> {
27 let mut tokens = VecDeque::new();
28 let mut chars = input.chars().peekable();
29
30 while let Some(&c) = chars.peek() {
31 match c {
32 '"' | '\'' => {
33 let string = parse_quoted_string(&mut chars)?;
34 tokens.push_back(Token::String(string));
35 }
36 '{' | '}' | '[' | ']' | ':' | ',' => {
37 chars.next(); tokens.push_back(Token::Symbol(c));
39 }
40 '/' if chars.clone().nth(1) == Some('/') => {
41 consume_comment(&mut chars);
42 tokens.push_back(Token::Comment);
43 }
44 c if c.is_whitespace() => {
45 consume_whitespace(&mut chars);
46 tokens.push_back(Token::Whitespace);
47 }
48 c if c.is_digit(10) || c == '-' => {
49 let number = parse_number(&mut chars)?;
50 tokens.push_back(Token::Number(number));
51 }
52 _ => {
53 let string = parse_unquoted_string(&mut chars)?;
54 if !string.is_empty() {
55 *changed = true;
57 }
58 tokens.push_back(Token::String(string));
59 }
60 }
61 }
62
63 Ok(tokens)
64}
65
66fn parse_quoted_string(chars: &mut Peekable<Chars>) -> Result<String, JsonRepairError> {
67 let quote_char = chars.next().ok_or(JsonRepairError::UnexpectedEOF)?; let mut s = String::new();
69
70 while let Some(&c) = chars.peek() {
71 if c == quote_char {
72 chars.next(); break;
74 } else if c == '\\' {
75 chars.next(); if let Some(escaped_char) = chars.next() {
77 s.push(match escaped_char {
78 'n' => '\n',
79 't' => '\t',
80 'r' => '\r',
81 'b' => '\x08',
82 'f' => '\x0C',
83 '\\' => '\\',
84 '\'' => '\'',
85 '"' => '"',
86 other => other,
87 });
88 } else {
89 s.push('\\');
91 }
92 } else if ":,{}[]\"'".contains(c) {
93 break;
95 } else {
96 s.push(chars.next().unwrap());
97 }
98 }
99
100 Ok(s)
101}
102
103fn parse_unquoted_string(chars: &mut Peekable<Chars>) -> Result<String, JsonRepairError> {
104 let mut s = String::new();
105
106 while let Some(&c) = chars.peek() {
107 if c.is_whitespace() || ":,{}[]\"'".contains(c) {
108 break;
109 } else {
110 s.push(chars.next().unwrap());
111 }
112 }
113
114 Ok(s.trim().to_string())
115}
116
117fn consume_comment(chars: &mut Peekable<Chars>) {
118 chars.next(); chars.next(); while let Some(c) = chars.next() {
121 if c == '\n' {
122 break;
123 }
124 }
125}
126
127fn consume_whitespace(chars: &mut Peekable<Chars>) {
128 while let Some(&c) = chars.peek() {
129 if c.is_whitespace() {
130 chars.next();
131 } else {
132 break;
133 }
134 }
135}
136
137fn parse_number(chars: &mut Peekable<Chars>) -> Result<String, JsonRepairError> {
138 let mut num = String::new();
139
140 while let Some(&c) = chars.peek() {
141 if c.is_digit(10) || c == '.' || c == 'e' || c == 'E' || c == '+' || c == '-' {
142 num.push(chars.next().ok_or(JsonRepairError::UnexpectedEOF)?);
143 } else {
144 break;
145 }
146 }
147
148 Ok(num)
149}
150
151pub fn unescape_string(s: &str) -> String {
152 let mut result = String::new();
153 let mut chars = s.chars().peekable();
154
155 while let Some(c) = chars.next() {
156 if c == '\\' {
157 if let Some(next_char) = chars.next() {
158 match next_char {
159 'n' => result.push('\n'),
160 't' => result.push('\t'),
161 'r' => result.push('\r'),
162 'b' => result.push('\x08'),
163 'f' => result.push('\x0C'),
164 '\\' => result.push('\\'),
165 '\'' => result.push('\''),
166 '"' => result.push('"'),
167 other => {
168 result.push('\\');
169 result.push(other);
170 }
171 }
172 } else {
173 result.push('\\');
174 }
175 } else {
176 result.push(c);
177 }
178 }
179
180 result
181}
182
183pub fn parse_value(tokens: &mut VecDeque<Token>) -> Result<JsonValue, JsonRepairError> {
184 while let Some(token) = tokens.pop_front() {
185 match token {
186 Token::Symbol('{') => return parse_object(tokens),
187 Token::Symbol('[') => return parse_array(tokens),
188 Token::String(s) | Token::Number(s) => {
189 let mut value_parts = vec![s];
190
191 loop {
192 let continue_loop = {
193 let next_token = tokens.front();
194 if let Some(next_token) = next_token {
195 match next_token {
196 Token::Whitespace | Token::Comment => {
197 tokens.pop_front(); true
199 }
200 Token::String(s) | Token::Number(s) => {
201 let s = s.clone();
202 tokens.pop_front(); value_parts.push(s);
204 true
205 }
206 _ => false,
207 }
208 } else {
209 false
210 }
211 };
212 if !continue_loop {
213 break;
214 }
215 }
216
217 let s_trimmed = value_parts.join(" ").trim().to_string();
218 match s_trimmed.as_str() {
219 "true" => return Ok(JsonValue::Bool(true)),
220 "false" => return Ok(JsonValue::Bool(false)),
221 "null" => return Ok(JsonValue::Null),
222 _ => {
223 if let Ok(num) = s_trimmed.parse::<i64>() {
224 return Ok(JsonValue::Number(num.into()));
225 } else if let Ok(num) = s_trimmed.parse::<f64>() {
226 if let Some(n) = serde_json::Number::from_f64(num) {
227 return Ok(JsonValue::Number(n));
228 } else {
229 return Err(JsonRepairError::InvalidNumber(s_trimmed.to_string()));
230 }
231 } else {
232 return Ok(JsonValue::String(unescape_string(&s_trimmed)));
233 }
234 }
235 }
236 }
237 Token::Symbol(c) => {
238 if c == ']' || c == '}' {
239 if c == ']' {
240 return Ok(JsonValue::Array(vec![]));
241 } else {
242 return Ok(JsonValue::Object(serde_json::Map::new()));
243 }
244 }
245 }
246 Token::Whitespace | Token::Comment => continue,
247 }
248 }
249 Ok(JsonValue::Null)
250}
251
252pub fn parse_object(tokens: &mut VecDeque<Token>) -> Result<JsonValue, JsonRepairError> {
253 if matches!(tokens.front(), Some(Token::Symbol('{'))) {
254 tokens.pop_front();
255 }
256
257 let mut map = serde_json::Map::new();
258
259 while tokens.front().is_some() {
260 while matches!(
261 tokens.front(),
262 Some(Token::Symbol(',')) | Some(Token::Symbol(':')) | Some(Token::Whitespace) | Some(Token::Comment)
263 ) {
264 tokens.pop_front();
265 }
266
267 match tokens.front() {
268 Some(Token::Symbol('}')) => {
269 tokens.pop_front(); break;
271 }
272 _ => {
273 let mut key_parts = Vec::new();
275
276 while let Some(token) = tokens.front() {
277 match token {
278 Token::String(_) | Token::Number(_) => {
279 if let Some(token) = tokens.pop_front() {
280 match token {
281 Token::String(s) | Token::Number(s) => key_parts.push(s),
282 _ => {}
283 }
284 }
285 }
286 Token::Whitespace | Token::Comment => {
287 tokens.pop_front(); }
289 _ => break,
290 }
291 }
292
293 let key = key_parts.join(" ");
294
295 while matches!(
296 tokens.front(),
297 Some(Token::Whitespace) | Some(Token::Comment) | Some(Token::Symbol(','))
298 ) {
299 tokens.pop_front();
300 }
301
302 let colon_found = if let Some(Token::Symbol(':')) = tokens.front() {
303 tokens.pop_front(); true
305 } else {
306 false
307 };
308
309 while matches!(tokens.front(), Some(Token::Whitespace) | Some(Token::Comment)) {
310 tokens.pop_front();
311 }
312
313 if colon_found {
314 let value = parse_value(tokens)?;
315 map.insert(key, value);
316 } else {
317 match tokens.front() {
318 Some(Token::String(_))
319 | Some(Token::Number(_))
320 | Some(Token::Symbol('{'))
321 | Some(Token::Symbol('[')) => {
322 let value = parse_value(tokens)?;
323 map.insert(key, value);
324 }
325 _ => {
326 if key_parts.len() > 1 {
328 let value_str = key_parts.pop().unwrap();
329 let key = key_parts.join(" ");
330 let value = JsonValue::String(value_str);
331 map.insert(key, value);
332 } else {
333 map.insert(key, JsonValue::Null);
334 }
335 }
336 }
337 }
338 }
339 }
340 }
341
342 Ok(JsonValue::Object(map))
343}
344
345pub fn parse_array(tokens: &mut VecDeque<Token>) -> Result<JsonValue, JsonRepairError> {
346 if let Some(Token::Symbol('[')) = tokens.front() {
347 tokens.pop_front();
348 }
349
350 let mut arr = vec![];
351
352 while let Some(token) = tokens.front() {
353 match token {
354 Token::Symbol(']') => {
355 tokens.pop_front(); break;
357 }
358 Token::Whitespace | Token::Comment | Token::Symbol(',') => {
359 tokens.pop_front(); continue;
361 }
362 _ => {
363 let value = parse_value(tokens)?;
364 arr.push(value);
365 }
366 }
367 }
368
369 Ok(JsonValue::Array(arr))
370}
371
372#[cfg(test)]
373mod tokenize_tests {
374 use super::*;
375
376 #[traced_test]
377 fn test_parse_quoted_string() {
378 let input = r#""Hello\nWorld""#;
379 let mut chars = input.chars().peekable();
380 let result = parse_quoted_string(&mut chars).unwrap();
381 assert_eq!(result, "Hello\nWorld");
382 }
383
384 #[traced_test]
385 fn test_parse_unquoted_string() {
386 let input = "unquotedString ";
387 let mut chars = input.chars().peekable();
388 let result = parse_unquoted_string(&mut chars).unwrap();
389 assert_eq!(result, "unquotedString");
390 }
391
392 #[traced_test]
393 fn test_parse_number() {
394 let input = "12345.67e-2";
395 let mut chars = input.chars().peekable();
396 let result = parse_number(&mut chars).unwrap();
397 assert_eq!(result, "12345.67e-2");
398 }
399
400 #[traced_test]
401 fn test_consume_whitespace() {
402 let input = " \t\n\rabc";
403 let mut chars = input.chars().peekable();
404 consume_whitespace(&mut chars);
405 assert_eq!(chars.next(), Some('a'));
406 }
407
408 #[traced_test]
409 fn test_consume_comment() {
410 let input = "// This is a comment\nNextLine";
411 let mut chars = input.chars().peekable();
412 consume_comment(&mut chars);
413 assert_eq!(chars.next(), Some('N'));
414 }
415}
416
417#[cfg(test)]
418mod unescape_string_tests {
419 use super::*;
420
421 #[traced_test]
422 fn test_unescape_basic() {
423 assert_eq!(unescape_string("Hello\\nWorld"), "Hello\nWorld");
424 assert_eq!(unescape_string("Tab\\tSeparated"), "Tab\tSeparated");
425 assert_eq!(unescape_string("Carriage\\rReturn"), "Carriage\rReturn");
426 }
427
428 #[traced_test]
429 fn test_unescape_quotes() {
430 assert_eq!(unescape_string("\\\"Quoted\\\""), "\"Quoted\"");
431 assert_eq!(unescape_string("\\'Single Quoted\\'"), "'Single Quoted'");
432 }
433
434 #[traced_test]
435 fn test_unescape_backslash() {
436 assert_eq!(unescape_string("Back\\\\Slash"), "Back\\Slash");
437 }
438
439 #[traced_test]
440 fn test_unescape_no_escapes() {
441 assert_eq!(unescape_string("NoEscapes"), "NoEscapes");
442 }
443}
444
445#[cfg(test)]
446mod parse_value_tests {
447 use super::*;
448 use serde_json::Value as JsonValue;
449
450 #[traced_test]
451 fn test_parse_value_string() {
452 let mut tokens = VecDeque::from(vec![Token::String("Hello".to_string())]);
453 let result = parse_value(&mut tokens).unwrap();
454 assert_eq!(result, JsonValue::String("Hello".to_string()));
455 }
456
457 #[traced_test]
458 fn test_parse_value_number() {
459 let mut tokens = VecDeque::from(vec![Token::Number("123".to_string())]);
460 let result = parse_value(&mut tokens).unwrap();
461 assert_eq!(result, JsonValue::Number(123.into()));
462 }
463
464 #[traced_test]
465 fn test_parse_value_bool() {
466 let mut tokens = VecDeque::from(vec![Token::String("true".to_string())]);
467 let result = parse_value(&mut tokens).unwrap();
468 assert_eq!(result, JsonValue::Bool(true));
469 }
470
471 #[traced_test]
472 fn test_parse_value_null() {
473 let mut tokens = VecDeque::from(vec![Token::String("null".to_string())]);
474 let result = parse_value(&mut tokens).unwrap();
475 assert_eq!(result, JsonValue::Null);
476 }
477
478 #[traced_test]
479 fn test_parse_value_array() {
480 let mut tokens = VecDeque::from(vec![Token::Symbol('['), Token::Symbol(']')]);
481 let result = parse_value(&mut tokens).unwrap();
482 assert_eq!(result, JsonValue::Array(vec![]));
483 }
484
485 #[traced_test]
486 fn test_parse_value_object() {
487 let mut tokens = VecDeque::from(vec![Token::Symbol('{'), Token::Symbol('}')]);
488 let result = parse_value(&mut tokens).unwrap();
489 assert_eq!(result, JsonValue::Object(serde_json::Map::new()));
490 }
491}
492
493#[cfg(test)]
494mod parse_object_tests {
495 use super::*;
496 use serde_json::Value as JsonValue;
497
498 #[traced_test]
499 fn test_parse_empty_object() {
500 let mut tokens = VecDeque::from(vec![Token::Symbol('{'), Token::Symbol('}')]);
501 let result = parse_object(&mut tokens).unwrap();
502 assert_eq!(result, JsonValue::Object(serde_json::Map::new()));
503 }
504
505 #[traced_test]
506 fn test_parse_simple_object() {
507 let mut tokens = VecDeque::from(vec![
508 Token::Symbol('{'),
509 Token::String("key".to_string()),
510 Token::Symbol(':'),
511 Token::String("value".to_string()),
512 Token::Symbol('}'),
513 ]);
514 let result = parse_object(&mut tokens).unwrap();
515 let mut expected = serde_json::Map::new();
516 expected.insert("key".to_string(), JsonValue::String("value".to_string()));
517 assert_eq!(result, JsonValue::Object(expected));
518 }
519
520 #[traced_test]
521 fn test_parse_object_missing_colon() {
522 let mut tokens = VecDeque::from(vec![
523 Token::Symbol('{'),
524 Token::String("key".to_string()),
525 Token::String("value".to_string()), Token::Symbol('}'),
527 ]);
528 let result = parse_object(&mut tokens).unwrap();
529 let mut expected = serde_json::Map::new();
530 expected.insert("key".to_string(), JsonValue::String("value".to_string()));
531 assert_eq!(result, JsonValue::Object(expected));
532 }
533
534 #[traced_test]
535 fn test_parse_object_unquoted_keys_with_spaces() {
536 let mut tokens = VecDeque::from(vec![
537 Token::Symbol('{'),
538 Token::String("key".to_string()),
539 Token::String("with".to_string()),
540 Token::String("spaces".to_string()),
541 Token::Symbol(':'),
542 Token::String("value".to_string()),
543 Token::Symbol('}'),
544 ]);
545 let result = parse_object(&mut tokens).unwrap();
546 let mut expected = serde_json::Map::new();
547 expected.insert("key with spaces".to_string(), JsonValue::String("value".to_string()));
548 assert_eq!(result, JsonValue::Object(expected));
549 }
550}
551
552#[cfg(test)]
553mod parse_array_tests {
554 use super::*;
555 use serde_json::Value as JsonValue;
556
557 #[traced_test]
558 fn test_parse_empty_array() {
559 let mut tokens = VecDeque::from(vec![Token::Symbol('['), Token::Symbol(']')]);
560 let result = parse_array(&mut tokens).unwrap();
561 assert_eq!(result, JsonValue::Array(vec![]));
562 }
563
564 #[traced_test]
565 fn test_parse_simple_array() {
566 let mut tokens = VecDeque::from(vec![
567 Token::Symbol('['),
568 Token::String("value1".to_string()),
569 Token::Symbol(','),
570 Token::String("value2".to_string()),
571 Token::Symbol(']'),
572 ]);
573 let result = parse_array(&mut tokens).unwrap();
574 let expected = JsonValue::Array(vec![
575 JsonValue::String("value1".to_string()),
576 JsonValue::String("value2".to_string()),
577 ]);
578 assert_eq!(result, expected);
579 }
580
581 #[traced_test]
582 fn test_parse_array_with_numbers() {
583 let mut tokens = VecDeque::from(vec![
584 Token::Symbol('['),
585 Token::Number("1".to_string()),
586 Token::Symbol(','),
587 Token::Number("2".to_string()),
588 Token::Symbol(','),
589 Token::Number("3".to_string()),
590 Token::Symbol(']'),
591 ]);
592 let result = parse_array(&mut tokens).unwrap();
593 let expected = JsonValue::Array(vec![
594 JsonValue::Number(1.into()),
595 JsonValue::Number(2.into()),
596 JsonValue::Number(3.into()),
597 ]);
598 assert_eq!(result, expected);
599 }
600}
601
602#[cfg(test)]
603mod repair_json_add_missing_quotes_tests {
604 use super::*;
605 use serde_json::json;
606 use serde_json::Value as JsonValue;
607
608 fn assert_expected_matches_output_result(input: &str, output: &str, expected: &JsonValue) {
609 match serde_json::from_str::<JsonValue>(output) {
610 Ok(parsed_output) => {
611 assert_eq!(
612 &parsed_output, expected,
613 "Parsed output does not match expected value"
614 );
615 }
616 Err(e) => {
617 panic!(
618 "Failed to parse output JSON: {}\nInput: {}\nOutput: {}",
619 e, input, output
620 );
621 }
622 }
623 }
624
625 #[traced_test]
626 fn test_no_missing_quotes() {
627 let input = r#"{"key": "value", "number": 123}"#;
628 let expected = json!({"key": "value", "number": 123});
629 let output = repair_json_add_missing_quotes(input).unwrap();
630 assert_expected_matches_output_result(input, &output, &expected);
631 }
632
633 #[traced_test]
634 fn test_missing_quotes_around_value() {
635 let input = r#"{"key": value, "number": 123}"#;
636 let expected = json!({"key": "value", "number": 123});
637 let output = repair_json_add_missing_quotes(input).unwrap();
638 assert_expected_matches_output_result(input, &output, &expected);
639 }
640
641 #[traced_test]
642 fn test_missing_quotes_around_key() {
643 let input = r#"{key: "value", "number": 123}"#;
644 let expected = json!({"key": "value", "number": 123});
645 let output = repair_json_add_missing_quotes(input).unwrap();
646 assert_expected_matches_output_result(input, &output, &expected);
647 }
648
649 #[traced_test]
650 fn test_missing_quotes_around_key_and_value() {
651 let input = r#"{key: value, "number": 123}"#;
652 let expected = json!({"key": "value", "number": 123});
653 let output = repair_json_add_missing_quotes(input).unwrap();
654 assert_expected_matches_output_result(input, &output, &expected);
655 }
656
657 #[traced_test]
658 fn test_unclosed_string_at_eof() {
659 let input = r#"{"key": "value"#;
660 let expected = json!({"key": "value"});
661 let output = repair_json_add_missing_quotes(input).unwrap_or_else(|_| "null".to_string());
662 let parsed_output: JsonValue = serde_json::from_str(&output).unwrap_or(JsonValue::Null);
663 assert_eq!(parsed_output, expected);
664 }
665
666 #[traced_test]
667 fn test_missing_quotes_in_array_elements() {
668 let input = r#"["value1", value2, "value3", value4]"#;
669 let expected = json!(["value1", "value2", "value3", "value4"]);
670 let output = repair_json_add_missing_quotes(input).unwrap();
671 assert_expected_matches_output_result(input, &output, &expected);
672 }
673
674 #[traced_test]
675 fn test_nested_missing_quotes() {
676 let input = r#"{"outer": {"inner": value}}"#;
677 let expected = json!({"outer": {"inner": "value"}});
678 let output = repair_json_add_missing_quotes(input).unwrap();
679 assert_expected_matches_output_result(input, &output, &expected);
680 }
681
682 #[traced_test]
683 fn test_missing_quotes_with_escaped_characters() {
684 let input = r#"{"key": value\n, "another_key": value\t}"#;
685 let expected = json!({"key": "value\n", "another_key": "value\t"});
686 let output = repair_json_add_missing_quotes(input).unwrap();
687 assert_expected_matches_output_result(input, &output, &expected);
688 }
689
690 #[traced_test]
691 fn test_missing_quotes_in_keys_with_spaces() {
692 let input = r#"{key with spaces: "value", "number": 123}"#;
693 let expected = json!({"key with spaces": "value", "number": 123});
694 let output = repair_json_add_missing_quotes(input).unwrap();
695 assert_expected_matches_output_result(input, &output, &expected);
696 }
697
698 #[traced_test]
699 fn test_input_with_only_commas_and_no_quotes() {
700 let input = r#"{key1: value1, key2: value2, key3: value3}"#;
701 let expected = json!({"key1": "value1", "key2": "value2", "key3": "value3"});
702 let output = repair_json_add_missing_quotes(input).unwrap();
703 assert_expected_matches_output_result(input, &output, &expected);
704 }
705
706 #[traced_test]
707 fn test_input_with_colons_but_missing_quotes() {
708 let input = r#"{key1: value1: key2: value2}"#;
709 let expected = json!({"key1": "value1", "key2": "value2"});
710 let output = repair_json_add_missing_quotes(input).unwrap_or_else(|_| "null".to_string());
711 let parsed_output: JsonValue = serde_json::from_str(&output).unwrap_or(JsonValue::Null);
713 assert_eq!(parsed_output, expected);
714 }
715
716 #[traced_test]
717 fn test_missing_quotes_with_numbers_and_booleans() {
718 let input = r#"{"number": 123, "boolean": true, key: value}"#;
719 let expected = json!({"number": 123, "boolean": true, "key": "value"});
720 let output = repair_json_add_missing_quotes(input).unwrap();
721 assert_expected_matches_output_result(input, &output, &expected);
722 }
723
724 #[traced_test]
725 fn test_missing_quotes_with_null() {
726 let input = r#"{key: null, "another_key": value}"#;
727 let expected = json!({"key": null, "another_key": "value"});
728 let output = repair_json_add_missing_quotes(input).unwrap();
729 assert_expected_matches_output_result(input, &output, &expected);
730 }
731
732 #[traced_test]
733 fn test_empty_input() {
734 let input = r#""#;
735 let expected = json!(null);
736 let output = repair_json_add_missing_quotes(input).unwrap_or_else(|_| "null".to_string());
737 let parsed_output: JsonValue = serde_json::from_str(&output).unwrap_or(JsonValue::Null);
738 assert_eq!(parsed_output, expected);
739 }
740
741 #[traced_test]
742 fn test_input_with_only_whitespace() {
743 let input = r#" "#;
744 let expected = json!(null);
745 let output = repair_json_add_missing_quotes(input).unwrap_or_else(|_| "null".to_string());
746 let parsed_output: JsonValue = serde_json::from_str(&output).unwrap_or(JsonValue::Null);
747 assert_eq!(parsed_output, expected);
748 }
749
750 #[test]
751 fn test_complex_nested_structure_with_missing_quotes() -> Result<(), JsonRepairError> {
752 let input = r#"
753 {
754 person: {
755 name: John Doe,
756 age: 30,
757 address: {
758 street: 123 Main St,
759 city: Anytown
760 }
761 },
762 hobbies: [reading, hiking, coding]
763 }
764 "#;
765 let expected = json!({
766 "person": {
767 "name": "John Doe",
768 "age": 30,
769 "address": {
770 "street": "123 Main St",
771 "city": "Anytown"
772 }
773 },
774 "hobbies": ["reading", "hiking", "coding"]
775 });
776
777 let output = repair_json_add_missing_quotes(input)?;
778 let parsed_output: Value = serde_json::from_str(&output)
779 .map_err(|inner| JsonRepairError::SerdeParseError { inner })?;
780
781 assert_eq!(parsed_output, expected);
782
783 Ok(())
784 }
785
786 #[traced_test]
787 fn test_input_with_special_characters() {
788 let input = r#"{key$: value@, "another_key#": value%}"#;
789 let expected = json!({"key$": "value@", "another_key#": "value%"});
790 let output = repair_json_add_missing_quotes(input).unwrap();
791 assert_expected_matches_output_result(input, &output, &expected);
792 }
793
794 #[traced_test]
795 fn test_missing_quotes_with_unicode_characters() {
796 let input = r#"{ключ: значение, "另一个键": 值}"#;
797 let expected = json!({"ключ": "значение", "另一个键": "值"});
798 let output = repair_json_add_missing_quotes(input).unwrap();
799 assert_expected_matches_output_result(input, &output, &expected);
800 }
801
802 #[traced_test]
803 fn test_unclosed_string_with_missing_quotes() {
804 let input = r#"{"key": "value, "another_key": value}"#;
805 let expected = json!({"key": "value", "another_key": "value"});
806 let output = repair_json_add_missing_quotes(input).unwrap_or_else(|_| "null".to_string());
807 let parsed_output: JsonValue = serde_json::from_str(&output).unwrap_or(JsonValue::Null);
808 assert_eq!(parsed_output, expected);
809 }
810
811 #[traced_test]
812 fn test_array_with_mixed_quoted_and_unquoted_strings() {
813 let input = r#"["value1", value2, "value3", value4, "value5"]"#;
814 let expected = json!(["value1", "value2", "value3", "value4", "value5"]);
815 let output = repair_json_add_missing_quotes(input).unwrap();
816 assert_expected_matches_output_result(input, &output, &expected);
817 }
818
819 #[traced_test]
820 fn test_object_with_mixed_quoted_and_unquoted_keys_and_values() {
821 let input = r#"{key1: value1, "key2": value2, key3: "value3", "key4": "value4"}"#;
822 let expected = json!({
823 "key1": "value1",
824 "key2": "value2",
825 "key3": "value3",
826 "key4": "value4"
827 });
828 let output = repair_json_add_missing_quotes(input).unwrap();
829 assert_expected_matches_output_result(input, &output, &expected);
830 }
831
832 #[traced_test]
833 fn test_missing_quotes_with_trailing_commas() {
834 let input = r#"{key1: value1, key2: value2,}"#;
835 let expected = json!({"key1": "value1", "key2": "value2"});
836 let output = repair_json_add_missing_quotes(input).unwrap();
837 assert_expected_matches_output_result(input, &output, &expected);
838 }
839
840 #[traced_test]
841 fn test_input_with_comments_and_missing_quotes() {
842 let input = r#"{key1: value1, // This is a comment
843 key2: value2}"#;
844 let expected = json!({"key1": "value1", "key2": "value2"});
845 let output = repair_json_add_missing_quotes(input).unwrap_or_else(|_| "null".to_string());
846 let parsed_output: JsonValue = serde_json::from_str(&output).unwrap_or(JsonValue::Null);
848 assert_eq!(parsed_output, expected);
849 }
850
851 #[traced_test]
852 fn test_input_with_malformed_json() {
853 warn!("is this test testing what we want?");
854 let input = r#"{key1 value1, key2: value2}"#; let expected = json!({"key1 value1": "key2", "value2": null});
856 let output = repair_json_add_missing_quotes(input).unwrap_or_else(|_| "null".to_string());
857 let parsed_output: JsonValue = serde_json::from_str(&output).unwrap_or(JsonValue::Null);
858 assert_eq!(parsed_output, expected);
859 }
860
861 #[traced_test]
862 fn test_input_with_extra_commas_and_missing_quotes() {
863 let input = r#"{key1: value1,, key2: value2,,}"#;
864 let expected = json!({"key1": "value1", "key2": "value2"});
865 let output = repair_json_add_missing_quotes(input).unwrap_or_else(|_| "null".to_string());
866 let parsed_output: JsonValue = serde_json::from_str(&output).unwrap_or(JsonValue::Null);
868 assert_eq!(parsed_output, expected);
869 }
870
871 #[traced_test]
872 fn test_missing_quotes_in_deeply_nested_structure() {
873 let input = r#"
874 {
875 level1: {
876 level2: {
877 level3: {
878 key: value
879 }
880 }
881 }
882 }
883 "#;
884 let expected = json!({
885 "level1": {
886 "level2": {
887 "level3": {
888 "key": "value"
889 }
890 }
891 }
892 });
893 let output = repair_json_add_missing_quotes(input).unwrap();
894 assert_expected_matches_output_result(input, &output, &expected);
895 }
896}