use javascript::{Value, evaluate_script};
#[test]
fn string_iterator_simple() {
let script = r#"
let out = [];
for (let ch of "abc") { out.push(ch); }
JSON.stringify(out)
"#;
let res = evaluate_script(script, None::<&std::path::Path>);
match res {
Ok(Value::String(s)) => {
let s = String::from_utf16_lossy(&s);
assert_eq!(s, "[\"a\",\"b\",\"c\"]");
}
other => panic!("Expected JSON string result, got {:?}", other),
}
}
#[test]
fn string_iterator_unicode() {
let script = r#"
let s = "a𠮷b";
console.log(s);
let out = [];
out.push(s.length);
out.push(s.charCodeAt(0)); out.push(s.charCodeAt(1)); out.push(s.charCodeAt(2)); out.push(s.charCodeAt(3));
for (let ch of s) { out.push(ch); }
JSON.stringify(out)
"#;
let res = evaluate_script(script, None::<&std::path::Path>);
match res {
Ok(Value::String(s)) => {
let s = String::from_utf16_lossy(&s);
assert!(s.contains("55362"));
assert!(s.contains("57271"));
let v: serde_json::Value = serde_json::from_str(&s).unwrap_or_else(|_| panic!("invalid json: {s}"));
let arr = v.as_array().expect("expected array");
assert_eq!(arr[5].as_str().unwrap(), "a");
assert_eq!(arr[6].as_str().unwrap(), "𠮷");
assert_eq!(arr[7].as_str().unwrap(), "b");
}
other => panic!("Expected JSON string result, got {:?}", other),
}
}
#[test]
fn string_char_codes_direct() {
let script = r#"
(function(){
let s = "a𠮷b";
return JSON.stringify([s.length, s.charCodeAt(0), s.charCodeAt(1), s.charCodeAt(2), s.charCodeAt(3)]);
})()
"#;
let res = evaluate_script(script, None::<&std::path::Path>);
match res {
Ok(Value::String(s)) => {
let s = String::from_utf16_lossy(&s);
let v: serde_json::Value = serde_json::from_str(&s).unwrap_or_else(|_| panic!("invalid json: {s}"));
let arr = v.as_array().expect("expected array");
assert_eq!(arr[0].as_i64().unwrap(), 4);
assert_eq!(arr[1].as_i64().unwrap(), 97);
assert_eq!(arr[2].as_i64().unwrap(), 55362);
assert_eq!(arr[3].as_i64().unwrap(), 57271);
assert_eq!(arr[4].as_i64().unwrap(), 98);
}
other => panic!("Expected JSON string result, got {:?}", other),
}
}
#[test]
fn string_charcode_single() {
let script = r#"
(function(){
let s = "a𠮷b";
return s.charCodeAt(1);
})()
"#;
let res = evaluate_script(script, None::<&std::path::Path>);
match res {
Ok(Value::Number(n)) => {
assert_eq!(n as u32, 0xD842);
}
other => panic!("Expected number result, got {:?}", other),
}
}
#[test]
fn string_iterator_combining_mark() {
let script = r#"
let s = "y̆";
let out = [];
for (let ch of s) { out.push(ch); }
JSON.stringify(out)
"#;
let res = evaluate_script(script, None::<&std::path::Path>);
match res {
Ok(Value::String(s)) => {
let s = String::from_utf16_lossy(&s);
let v: serde_json::Value = serde_json::from_str(&s).unwrap_or_else(|_| panic!("invalid json: {s}"));
let arr = v.as_array().expect("expected array");
assert_eq!(arr.len(), 2);
assert_eq!(arr[0].as_str().unwrap(), "y");
assert_eq!(arr[1].as_str().unwrap(), "\u{0306}");
}
other => panic!("Expected JSON string result, got {:?}", other),
}
}
#[test]
fn string_iterator_flag_regional_indicators() {
let script = r#"
let s = "🇨🇦";
let out = [];
for (let ch of s) { out.push(ch.length); out.push(ch.charCodeAt(0)); out.push(ch.charCodeAt(1)); }
JSON.stringify(out)
"#;
let res = evaluate_script(script, None::<&std::path::Path>);
match res {
Ok(Value::String(s)) => {
let s = String::from_utf16_lossy(&s);
let v: serde_json::Value = serde_json::from_str(&s).unwrap_or_else(|_| panic!("invalid json: {s}"));
let arr = v.as_array().expect("expected array");
assert_eq!(arr[0].as_i64().unwrap(), 2);
assert_eq!(arr[3].as_i64().unwrap(), 2);
let h1 = arr[1].as_i64().unwrap() as u32;
let l1 = arr[2].as_i64().unwrap() as u32;
let h2 = arr[4].as_i64().unwrap() as u32;
let l2 = arr[5].as_i64().unwrap() as u32;
assert!((0xD800..=0xDBFF).contains(&h1));
assert!((0xDC00..=0xDFFF).contains(&l1));
assert!((0xD800..=0xDBFF).contains(&h2));
assert!((0xDC00..=0xDFFF).contains(&l2));
}
other => panic!("Expected JSON string result, got {:?}", other),
}
}
#[test]
fn string_iterator_zwj_sequence() {
let script = r#"
let s = "👩👩👧👦";
let out = [];
for (let ch of s) { out.push(ch); }
JSON.stringify(out)
"#;
let res = evaluate_script(script, None::<&std::path::Path>);
match res {
Ok(Value::String(s)) => {
let s = String::from_utf16_lossy(&s);
let v: serde_json::Value = serde_json::from_str(&s).unwrap_or_else(|_| panic!("invalid json: {s}"));
let arr = v.as_array().expect("expected array");
assert!(arr.len() > 1);
for item in arr.iter() {
assert_ne!(item.as_str().unwrap(), "�");
}
}
other => panic!("Expected JSON string result, got {:?}", other),
}
}
#[test]
fn string_object_iterator_behaves_same() {
let script = r#"
let s = new String("a𠮷b");
let out = [];
for (let ch of s) { out.push(ch); }
JSON.stringify(out)
"#;
let res = evaluate_script(script, None::<&std::path::Path>);
match res {
Ok(Value::String(s)) => {
let s = String::from_utf16_lossy(&s);
let v: serde_json::Value = serde_json::from_str(&s).unwrap_or_else(|_| panic!("invalid json: {s}"));
let arr = v.as_array().expect("expected array");
assert_eq!(arr[0].as_str().unwrap(), "a");
assert_eq!(arr[1].as_str().unwrap(), "𠮷");
assert_eq!(arr[2].as_str().unwrap(), "b");
}
other => panic!("Expected JSON string result, got {:?}", other),
}
}