#![allow(
clippy::indexing_slicing,
reason = "unwraps are allowed anywhere in tests"
)]
use std::{borrow::Cow, sync::Arc};
use assert_matches::assert_matches;
use crate::json;
use super::{unescape_str, Warning};
fn test_elem() -> json::Element<'static> {
json::Element {
id: 0.into(),
path_node: Arc::new(json::PathNode::Root),
span: json::parser::Span::default(),
value: json::Value::Null,
}
}
#[test]
fn should_unescape_empty_str() {
const INPUT: &str = "";
let elem = test_elem();
let (string, warnings) = unescape_str(INPUT, &elem).into_parts();
assert_matches!(string, Cow::Borrowed(""));
assert!(warnings.is_empty(), "{:#?}", warnings.path_id_map());
}
#[test]
fn should_unescape_str_without_escapes() {
const INPUT: &str = "ab";
let elem = test_elem();
let (string, warnings) = unescape_str(INPUT, &elem).into_parts();
assert_matches!(string, Cow::Borrowed(INPUT));
assert!(warnings.is_empty(), "{:#?}", warnings.path_id_map());
}
#[test]
fn should_unescape_str_with_forward_slash_escape() {
const INPUT: &str = r"a\/b";
let elem = test_elem();
let (string, warnings) = unescape_str(INPUT, &elem).into_parts();
let s = assert_matches!(
string,
Cow::Owned(s) => s
);
assert_eq!(s, "a/b");
assert!(warnings.is_empty(), "{:#?}", warnings.path_id_map());
}
#[test]
fn should_unescape_str_with_many_escapes() {
const INPUT: &str = r#"a\/\"b\""#;
let elem = test_elem();
let (string, warnings) = unescape_str(INPUT, &elem).into_parts();
let s = assert_matches!(
string,
Cow::Owned(s) => s
);
assert_eq!(s, r#"a/"b""#);
assert!(warnings.is_empty(), "{:#?}", warnings.path_id_map());
}
#[test]
fn should_fail_to_unescape_str_with_invalid_escape() {
{
const INPUT: &str = r"\a/c";
let elem = test_elem();
let (string, warnings) = unescape_str(INPUT, &elem).into_parts();
let warnings = warnings.into_path_as_str_map();
let warnings = &warnings["$"];
assert_matches!(string, Cow::Borrowed(_));
assert_matches!(warnings.as_slice(), [Warning::InvalidEscape(1)]);
}
{
const INPUT: &str = r"a\c";
let elem = test_elem();
let (string, warnings) = unescape_str(INPUT, &elem).into_parts();
let warnings = warnings.into_path_as_str_map();
let warnings = &warnings["$"];
assert_matches!(string, Cow::Borrowed(_));
assert_matches!(warnings.as_slice(), [Warning::InvalidEscape(2)]);
}
{
const INPUT: &str = r"a/c\";
let elem = test_elem();
let (string, warnings) = unescape_str(INPUT, &elem).into_parts();
let warnings = warnings.into_path_as_str_map();
let warnings = &warnings["$"];
assert_matches!(string, Cow::Borrowed(_));
assert_matches!(warnings.as_slice(), [Warning::UnexpectedEndOfString(3)]);
}
}
#[test]
fn should_fail_to_unescape_str_with_control_char() {
const INPUT: &str = "hello\u{0019}world";
let elem = test_elem();
let (string, warnings) = unescape_str(INPUT, &elem).into_parts();
let warnings = warnings.into_path_as_str_map();
let warnings = &warnings["$"];
assert_matches!(string, Cow::Borrowed(_));
assert_matches!(
warnings.as_slice(),
[Warning::ControlCharacterWhileParsingString(5)]
);
}
#[test]
fn should_fail_to_unescape_raw_str_with_rust_unicode_literal_control_char() {
const INPUT: &str = r"hello\u{0019}world";
let elem = test_elem();
let (string, warnings) = unescape_str(INPUT, &elem).into_parts();
let warnings = warnings.into_path_as_str_map();
let warnings = &warnings["$"];
assert_matches!(string, Cow::Borrowed(_));
assert_matches!(warnings.as_slice(), [Warning::InvalidEscape(10)]);
}
#[test]
fn should_fail_to_unescape_json_control_escape() {
const INPUT: &str = r"hello\u0019world";
let elem = test_elem();
let (string, warnings) = unescape_str(INPUT, &elem).into_parts();
let warnings = warnings.into_path_as_str_map();
let warnings = &warnings["$"];
assert_matches!(string, Cow::Borrowed(_));
assert_matches!(
warnings.as_slice(),
[Warning::ControlCharacterWhileParsingString(10)]
);
}
#[test]
fn should_unescape_unicode_literals() {
const INPUT: &str = r"hello\u0020world\u0021";
let elem = test_elem();
let (string, warnings) = unescape_str(INPUT, &elem).into_parts();
let s = assert_matches!(
string,
Cow::Owned(s) => s
);
assert_eq!(s, "hello world!");
assert!(warnings.is_empty(), "{:#?}", warnings.path_id_map());
}
#[test]
fn should_unescape_utf_16_surrogate_pair() {
const INPUT: &str = r"hello\uD834\uDD1Eworld";
let elem = test_elem();
let (string, warnings) = unescape_str(INPUT, &elem).into_parts();
let s = assert_matches!(
string,
Cow::Owned(s) => s
);
assert_eq!(s, "hello\u{1D11E}world");
assert!(warnings.is_empty(), "{:#?}", warnings.path_id_map());
}
#[test]
fn should_unescape_unicode_literal_followed_by_simple_escape() {
const INPUT: &str = r"hello\u0020\/world\u0021";
let elem = test_elem();
let (string, warnings) = unescape_str(INPUT, &elem).into_parts();
let s = assert_matches!(
string,
Cow::Owned(s) => s
);
assert_eq!(s, "hello /world!");
assert!(warnings.is_empty(), "{:#?}", warnings.path_id_map());
}