use lean_string::{LeanString, ToLeanString};
use std::{borrow::Cow, panic};
pub trait IntoCow<'a, B: ?Sized>
where
B: ToOwned,
{
fn into_cow(self) -> Cow<'a, B>;
}
impl<'a> IntoCow<'a, str> for String {
fn into_cow(self) -> Cow<'a, str> {
Cow::Owned(self)
}
}
impl<'a> IntoCow<'a, str> for &'a str {
fn into_cow(self) -> Cow<'a, str> {
Cow::Borrowed(self)
}
}
#[test]
fn test_from_str() {
let owned: Option<LeanString> = "string".parse().ok();
assert_eq!(owned.as_deref(), Some("string"));
}
#[test]
fn test_from_cow_str() {
assert_eq!(LeanString::from(Cow::Borrowed("string")), "string");
assert_eq!(LeanString::from(Cow::Owned(String::from("string"))), "string");
}
#[test]
fn test_from_utf8() {
let xs = b"hello".to_vec();
assert_eq!(LeanString::from_utf8(&xs).unwrap(), LeanString::from("hello"));
let xs = "ศไทย中华Việt Nam".as_bytes().to_vec();
assert_eq!(LeanString::from_utf8(&xs).unwrap(), LeanString::from("ศไทย中华Việt Nam"));
}
#[test]
fn test_from_utf8_lossy() {
let xs = b"hello";
let ys: Cow<'_, str> = "hello".into_cow();
assert_eq!(LeanString::from_utf8_lossy(xs), ys);
let xs = "ศไทย中华Việt Nam".as_bytes();
let ys: Cow<'_, str> = "ศไทย中华Việt Nam".into_cow();
assert_eq!(LeanString::from_utf8_lossy(xs), ys);
let xs = b"Hello\xC2 There\xFF Goodbye";
assert_eq!(
LeanString::from_utf8_lossy(xs),
String::from("Hello\u{FFFD} There\u{FFFD} Goodbye").into_cow()
);
let xs = b"Hello\xC0\x80 There\xE6\x83 Goodbye";
assert_eq!(
LeanString::from_utf8_lossy(xs),
String::from("Hello\u{FFFD}\u{FFFD} There\u{FFFD} Goodbye").into_cow()
);
let xs = b"\xF5foo\xF5\x80bar";
assert_eq!(
LeanString::from_utf8_lossy(xs),
String::from("\u{FFFD}foo\u{FFFD}\u{FFFD}bar").into_cow()
);
let xs = b"\xF1foo\xF1\x80bar\xF1\x80\x80baz";
assert_eq!(
LeanString::from_utf8_lossy(xs),
String::from("\u{FFFD}foo\u{FFFD}bar\u{FFFD}baz").into_cow()
);
let xs = b"\xF4foo\xF4\x80bar\xF4\xBFbaz";
assert_eq!(
LeanString::from_utf8_lossy(xs),
String::from("\u{FFFD}foo\u{FFFD}bar\u{FFFD}\u{FFFD}baz").into_cow()
);
let xs = b"\xF0\x80\x80\x80foo\xF0\x90\x80\x80bar";
assert_eq!(
LeanString::from_utf8_lossy(xs),
String::from("\u{FFFD}\u{FFFD}\u{FFFD}\u{FFFD}foo\u{10000}bar").into_cow()
);
let xs = b"\xED\xA0\x80foo\xED\xBF\xBFbar";
assert_eq!(
LeanString::from_utf8_lossy(xs),
String::from("\u{FFFD}\u{FFFD}\u{FFFD}foo\u{FFFD}\u{FFFD}\u{FFFD}bar").into_cow()
);
}
#[test]
fn test_from_utf16() {
let pairs = [
(
LeanString::from("𐍅𐌿𐌻𐍆𐌹𐌻𐌰\n"),
vec![
0xd800, 0xdf45, 0xd800, 0xdf3f, 0xd800, 0xdf3b, 0xd800, 0xdf46, 0xd800, 0xdf39,
0xd800, 0xdf3b, 0xd800, 0xdf30, 0x000a,
],
),
(
LeanString::from("𐐒𐑉𐐮𐑀𐐲𐑋 𐐏𐐲𐑍\n"),
vec![
0xd801, 0xdc12, 0xd801, 0xdc49, 0xd801, 0xdc2e, 0xd801, 0xdc40, 0xd801, 0xdc32,
0xd801, 0xdc4b, 0x0020, 0xd801, 0xdc0f, 0xd801, 0xdc32, 0xd801, 0xdc4d, 0x000a,
],
),
(
LeanString::from("𐌀𐌖𐌋𐌄𐌑𐌉·𐌌𐌄𐌕𐌄𐌋𐌉𐌑\n"),
vec![
0xd800, 0xdf00, 0xd800, 0xdf16, 0xd800, 0xdf0b, 0xd800, 0xdf04, 0xd800, 0xdf11,
0xd800, 0xdf09, 0x00b7, 0xd800, 0xdf0c, 0xd800, 0xdf04, 0xd800, 0xdf15, 0xd800,
0xdf04, 0xd800, 0xdf0b, 0xd800, 0xdf09, 0xd800, 0xdf11, 0x000a,
],
),
(
LeanString::from("𐒋𐒘𐒈𐒑𐒛𐒒 𐒕𐒓 𐒈𐒚𐒍 𐒏𐒜𐒒𐒖𐒆 𐒕𐒆\n"),
vec![
0xd801, 0xdc8b, 0xd801, 0xdc98, 0xd801, 0xdc88, 0xd801, 0xdc91, 0xd801, 0xdc9b,
0xd801, 0xdc92, 0x0020, 0xd801, 0xdc95, 0xd801, 0xdc93, 0x0020, 0xd801, 0xdc88,
0xd801, 0xdc9a, 0xd801, 0xdc8d, 0x0020, 0xd801, 0xdc8f, 0xd801, 0xdc9c, 0xd801,
0xdc92, 0xd801, 0xdc96, 0xd801, 0xdc86, 0x0020, 0xd801, 0xdc95, 0xd801, 0xdc86,
0x000a,
],
),
(LeanString::from("\u{20000}"), vec![0xD840, 0xDC00]),
];
for p in &pairs {
let (s, u) = (*p).clone();
let s_as_utf16 = s.encode_utf16().collect::<Vec<u16>>();
let u_as_string = LeanString::from_utf16(&u).unwrap();
assert!(core::char::decode_utf16(u.iter().cloned()).all(|r| r.is_ok()));
assert_eq!(s_as_utf16, u);
assert_eq!(u_as_string, s);
assert_eq!(LeanString::from_utf16_lossy(&u), s);
assert_eq!(LeanString::from_utf16(&s_as_utf16).unwrap(), s);
assert_eq!(u_as_string.encode_utf16().collect::<Vec<u16>>(), u);
}
}
#[test]
fn test_utf16_invalid() {
assert!(LeanString::from_utf16(&[0xD800]).is_err());
assert!(LeanString::from_utf16(&[0xD800, 0xD800]).is_err());
assert!(LeanString::from_utf16(&[0x0061, 0xDC00]).is_err());
assert!(LeanString::from_utf16(&[0xD800, 0xd801, 0xdc8b, 0xD800]).is_err());
}
#[test]
fn test_from_utf16_lossy() {
assert_eq!(LeanString::from_utf16_lossy(&[0xD800]), String::from("\u{FFFD}"));
assert_eq!(LeanString::from_utf16_lossy(&[0xD800, 0xD800]), String::from("\u{FFFD}\u{FFFD}"));
assert_eq!(LeanString::from_utf16_lossy(&[0x0061, 0xDC00]), String::from("a\u{FFFD}"));
assert_eq!(
LeanString::from_utf16_lossy(&[0xD800, 0xd801, 0xdc8b, 0xD800]),
String::from("\u{FFFD}𐒋\u{FFFD}")
);
}
#[test]
fn test_push_str() {
let mut s = LeanString::new();
s.push_str("");
assert_eq!(&s[0..], "");
s.push_str("abc");
assert_eq!(&s[0..], "abc");
s.push_str("ประเทศไทย中华Việt Nam");
assert_eq!(&s[0..], "abcประเทศไทย中华Việt Nam");
}
#[test]
fn test_add_assign() {
let mut s = LeanString::new();
s += "";
assert_eq!(s.as_str(), "");
s += "abc";
assert_eq!(s.as_str(), "abc");
s += "ประเทศไทย中华Việt Nam";
assert_eq!(s.as_str(), "abcประเทศไทย中华Việt Nam");
}
#[test]
fn test_push() {
let mut data = LeanString::from("ประเทศไทย中");
data.push('华');
data.push('b'); data.push('¢'); data.push('€'); data.push('𤭢'); assert_eq!(data, "ประเทศไทย中华b¢€𤭢");
}
#[test]
fn test_pop() {
let mut data = LeanString::from("ประเทศไทย中华b¢€𤭢");
assert_eq!(data.pop().unwrap(), '𤭢'); assert_eq!(data.pop().unwrap(), '€'); assert_eq!(data.pop().unwrap(), '¢'); assert_eq!(data.pop().unwrap(), 'b'); assert_eq!(data.pop().unwrap(), '华');
assert_eq!(data, "ประเทศไทย中");
}
#[test]
fn test_split_off_empty() {
let orig = "Hello, world!";
let mut split = LeanString::from(orig);
let empty: LeanString = split.split_off(orig.len());
assert!(empty.is_empty());
}
#[test]
#[should_panic]
fn test_split_off_past_end() {
let orig = "Hello, world!";
let mut split = LeanString::from(orig);
let _ = split.split_off(orig.len() + 1);
}
#[test]
#[should_panic]
fn test_split_off_mid_char() {
let mut shan = LeanString::from("山");
let _broken_mountain = shan.split_off(1);
}
#[test]
fn test_split_off_ascii() {
let mut ab = LeanString::from("ABCD");
let orig_capacity = ab.capacity();
let cd = ab.split_off(2);
assert_eq!(ab, "AB");
assert_eq!(cd, "CD");
assert_eq!(ab.capacity(), orig_capacity);
}
#[test]
fn test_split_off_unicode() {
let mut nihon = LeanString::from("日本語");
let orig_capacity = nihon.capacity();
let go = nihon.split_off("日本".len());
assert_eq!(nihon, "日本");
assert_eq!(go, "語");
assert_eq!(nihon.capacity(), orig_capacity);
}
#[test]
fn test_str_truncate() {
let mut s = LeanString::from("12345");
s.truncate(5);
assert_eq!(s, "12345");
s.truncate(3);
assert_eq!(s, "123");
s.truncate(0);
assert_eq!(s, "");
let mut s = LeanString::from("12345");
let p = s.as_ptr();
s.truncate(3);
s.push_str("6");
let p_ = s.as_ptr();
assert_eq!(p_, p);
}
#[test]
fn test_str_truncate_invalid_len() {
let mut s = LeanString::from("12345");
s.truncate(6);
assert_eq!(s, "12345");
}
#[test]
#[should_panic(expected = "index is not a char boundary or out of bounds (index: 1)")]
fn test_str_truncate_split_codepoint() {
let mut s = LeanString::from("\u{FC}"); s.truncate(1);
}
#[test]
fn test_str_clear() {
let mut s = LeanString::from("12345");
s.clear();
assert_eq!(s.len(), 0);
assert_eq!(s, "");
}
#[test]
fn test_str_add() {
let a = LeanString::from("12345");
let b = a + "2";
let b = b + "2";
assert_eq!(b.len(), 7);
assert_eq!(b, "1234522");
}
#[test]
fn remove() {
let mut s = "ศไทย中华Việt Nam; foobar".to_lean_string();
assert_eq!(s.remove(0), 'ศ');
assert_eq!(s.len(), 33);
assert_eq!(s, "ไทย中华Việt Nam; foobar");
assert_eq!(s.remove(17), 'ệ');
assert_eq!(s, "ไทย中华Vit Nam; foobar");
}
#[test]
#[should_panic(expected = "index is not a char boundary or out of bounds (index: 1)")]
fn remove_bad() {
"ศ".to_lean_string().remove(1);
}
#[test]
#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")]
fn test_retain() {
let mut s = LeanString::from("α_β_γ");
s.retain(|_| true);
assert_eq!(s, "α_β_γ");
s.retain(|c| c != '_');
assert_eq!(s, "αβγ");
s.retain(|c| c != 'β');
assert_eq!(s, "αγ");
s.retain(|c| c == 'α');
assert_eq!(s, "α");
s.retain(|_| false);
assert_eq!(s, "");
let mut s = LeanString::from("0è0");
let _ = panic::catch_unwind(panic::AssertUnwindSafe(|| {
let mut count = 0;
s.retain(|_| {
count += 1;
match count {
1 => false,
2 => true,
_ => panic!(),
}
});
}));
assert!(std::str::from_utf8(s.as_bytes()).is_ok());
}
#[test]
fn insert() {
let mut s = "foobar".to_lean_string();
s.insert(0, 'ệ');
assert_eq!(s, "ệfoobar");
s.insert(6, 'ย');
assert_eq!(s, "ệfooยbar");
}
#[test]
#[should_panic(expected = "index is not a char boundary or out of bounds (index: 1)")]
fn insert_bad1() {
"".to_lean_string().insert(1, 't');
}
#[test]
#[should_panic(expected = "index is not a char boundary or out of bounds (index: 1)")]
fn insert_bad2() {
"ệ".to_lean_string().insert(1, 't');
}
#[test]
fn test_slicing() {
let s = "foobar".to_lean_string();
assert_eq!("foobar", &s[..]);
assert_eq!("foo", &s[..3]);
assert_eq!("bar", &s[3..]);
assert_eq!("oob", &s[1..4]);
}
#[test]
fn test_simple_types() {
assert_eq!(1.to_lean_string(), "1");
assert_eq!((-1).to_lean_string(), "-1");
assert_eq!(200.to_lean_string(), "200");
assert_eq!(2.to_lean_string(), "2");
assert_eq!(true.to_lean_string(), "true");
assert_eq!(false.to_lean_string(), "false");
assert_eq!(("hi".to_lean_string()).to_lean_string(), "hi");
}
#[test]
fn test_from_iterator() {
let s = "ศไทย中华Việt Nam".to_string();
let t = "ศไทย中华";
let u = "Việt Nam";
let a: LeanString = s.chars().collect();
assert_eq!(s, a);
let mut b = t.to_lean_string();
b.extend(u.chars());
assert_eq!(s, b);
let c: LeanString = [t, u].into_iter().collect();
assert_eq!(s, c);
let mut d = t.to_lean_string();
d.extend(vec![u]);
assert_eq!(s, d);
}
#[test]
fn test_extend_ref() {
let mut a = "foo".to_lean_string();
a.extend(&['b', 'a', 'r']);
assert_eq!(&a, "foobar");
}
#[test]
fn test_try_with_capacity() {
let string = LeanString::try_with_capacity(1000).unwrap();
assert_eq!(0, string.len());
assert!(string.capacity() >= 1000 && string.capacity() <= isize::MAX as usize);
assert!(LeanString::try_with_capacity(usize::MAX).is_err());
}
#[test]
fn test_from_char() {
assert_eq!(LeanString::from('a'), 'a'.to_string());
let s: LeanString = 'x'.into();
assert_eq!(s, 'x'.to_string());
}