use lean_string::LeanString;
const INLINE_LIMIT: usize = size_of::<LeanString>();
#[test]
fn new_empty() {
assert_eq!(LeanString::new(), "");
let s = LeanString::new();
assert_eq!(s.as_str(), "");
assert!(s.is_empty());
assert_eq!(s.len(), 0);
assert!(!s.is_heap_allocated());
assert_eq!(s.capacity(), INLINE_LIMIT);
}
#[test]
fn new_from_char() {
assert_eq!(LeanString::from('a'), "a");
assert_eq!(LeanString::from('👍'), "👍");
assert_eq!(LeanString::from(''), "");
}
#[test]
fn from_around_inline_limit() {
let s = &String::from("0123456789abcdefg");
let inline = LeanString::from(&s[..INLINE_LIMIT - 1]);
assert_eq!(inline, s[..INLINE_LIMIT - 1]);
assert!(!inline.is_heap_allocated());
assert_eq!(inline.capacity(), INLINE_LIMIT);
let inline = LeanString::from(&s[..INLINE_LIMIT]);
assert_eq!(inline, s[..INLINE_LIMIT]);
assert!(!inline.is_heap_allocated());
assert_eq!(inline.capacity(), INLINE_LIMIT);
let heap = LeanString::from(&s[..INLINE_LIMIT + 1]);
assert_eq!(heap, s[..INLINE_LIMIT + 1]);
assert!(heap.is_heap_allocated());
assert_eq!(heap.capacity(), INLINE_LIMIT + 1);
}
#[test]
fn from_around_inline_limit_static() {
let s: &'static str = "0123456789abcdefg";
let inline = LeanString::from_static_str(&s[..INLINE_LIMIT - 1]);
assert_eq!(inline, s[..INLINE_LIMIT - 1]);
assert!(!inline.is_heap_allocated());
assert_eq!(inline.capacity(), INLINE_LIMIT);
let inline = LeanString::from_static_str(&s[..INLINE_LIMIT]);
assert_eq!(inline, s[..INLINE_LIMIT]);
assert!(!inline.is_heap_allocated());
assert_eq!(inline.capacity(), INLINE_LIMIT);
let static_ = LeanString::from_static_str(&s[..INLINE_LIMIT + 1]);
assert_eq!(static_, s[..INLINE_LIMIT + 1]);
assert!(!static_.is_heap_allocated());
assert_eq!(static_.capacity(), INLINE_LIMIT + 1);
}
#[test]
fn shrink_to_inline_buffer() {
let mut inline = LeanString::from("Hello");
assert!(!inline.is_heap_allocated());
assert_eq!(inline.capacity(), INLINE_LIMIT);
inline.shrink_to(100);
assert_eq!(inline, "Hello");
assert_eq!(inline.capacity(), INLINE_LIMIT);
assert!(!inline.is_heap_allocated());
inline.shrink_to(3);
assert_eq!(inline, "Hello");
assert_eq!(inline.capacity(), INLINE_LIMIT);
assert!(!inline.is_heap_allocated());
}
#[test]
fn shrink_to_static_buffer() {
let text: &'static str = "A static str that is longer than inline limit";
let mut static_ = LeanString::from_static_str(text);
assert!(!static_.is_heap_allocated());
static_.shrink_to(30);
assert_eq!(static_.capacity(), text.len());
assert!(!static_.is_heap_allocated());
static_.shrink_to(10);
assert_eq!(static_.capacity(), text.len());
assert!(!static_.is_heap_allocated());
}
#[test]
fn shrink_to_heap_buffer() {
let text = "A heap allocated string that is longer than inline limit";
let mut heap = LeanString::from(text);
assert!(heap.is_heap_allocated());
let original_capacity = heap.capacity();
heap.shrink_to(100);
assert_eq!(heap.capacity(), original_capacity);
assert_eq!(heap, text);
assert!(heap.is_heap_allocated());
heap.shrink_to(30);
assert_eq!(heap.capacity(), original_capacity);
assert_eq!(heap, text);
assert!(heap.is_heap_allocated());
heap.shrink_to(0);
assert_eq!(heap.capacity(), heap.len());
assert_eq!(heap, text);
assert!(heap.is_heap_allocated());
}
#[test]
fn shrink_to_heap_to_inline() {
let mut heap = LeanString::with_capacity(100);
heap.push_str("Hello");
assert!(heap.is_heap_allocated());
assert_eq!(heap.capacity(), 100);
assert!(heap.len() < INLINE_LIMIT);
heap.shrink_to(100);
assert_eq!(heap.capacity(), 100);
assert_eq!(heap, "Hello");
heap.shrink_to(120);
assert_eq!(heap.capacity(), 100);
heap.shrink_to(50);
assert_eq!(heap.capacity(), 50);
assert_eq!(heap, "Hello");
assert!(heap.is_heap_allocated());
heap.shrink_to(INLINE_LIMIT);
assert_eq!(heap.capacity(), INLINE_LIMIT);
assert_eq!(heap, "Hello");
assert!(!heap.is_heap_allocated());
heap.shrink_to(0);
assert_eq!(heap.capacity(), INLINE_LIMIT);
assert_eq!(heap, "Hello");
assert!(!heap.is_heap_allocated());
}
#[test]
fn shrink_to_cow_shared_buffer() {
let mut heap1 = LeanString::with_capacity(100);
heap1.push_str("Shared");
let mut heap2 = heap1.clone();
assert_eq!(heap1.as_ptr(), heap2.as_ptr());
heap1.shrink_to(50);
assert_eq!(heap1.capacity(), 50);
assert_eq!(heap1, "Shared");
assert_eq!(heap2.capacity(), 100);
assert_eq!(heap2, "Shared");
assert_ne!(heap1.as_ptr(), heap2.as_ptr());
let heap3 = heap2.clone();
assert_eq!(heap2.as_ptr(), heap3.as_ptr());
heap2.shrink_to(0); assert_eq!(heap2.capacity(), INLINE_LIMIT);
assert_eq!(heap2, "Shared");
assert!(!heap2.is_heap_allocated());
assert_eq!(heap3.capacity(), 100);
assert_eq!(heap3, "Shared");
assert!(heap3.is_heap_allocated());
assert_ne!(heap2.as_ptr(), heap3.as_ptr());
}
#[test]
fn push_cow() {
let mut s = LeanString::new();
s.push('a');
s.push('b');
s.push_str("cdefgh");
assert_eq!(s, "abcdefgh");
assert_eq!(s.len(), 8);
s.push_str("12345678");
assert_eq!(s.len(), 16);
assert_eq!(s, "abcdefgh12345678");
let mut s1 = s.clone();
assert_eq!(s1, "abcdefgh12345678");
s1.push('0');
assert_eq!(s1, "abcdefgh123456780");
assert_eq!(s1.len(), 17);
let mut s2 = s.clone();
s2.push_str("90");
assert_eq!(s2, "abcdefgh1234567890");
assert_eq!(s2.len(), 18);
assert_eq!(s.len(), 16);
s.push_str("90");
assert!(s.is_heap_allocated());
assert_eq!(s.len(), 18);
let mut s3 = s.clone();
s3.push('');
assert_eq!(s3, "abcdefgh1234567890");
assert_eq!(s3.len(), 21);
let mut s4 = s.clone();
s4.push_str("👍👍");
assert_eq!(s4.len(), 26);
assert_eq!(s4, "abcdefgh1234567890👍👍");
}
#[test]
fn push_to_static() {
let mut inline = LeanString::from_static_str("abcdefgh");
assert_eq!(inline, "abcdefgh");
assert_eq!(inline.len(), 8);
assert!(!inline.is_heap_allocated());
assert_eq!(inline.capacity(), INLINE_LIMIT);
inline.push_str("12345678");
assert_eq!(inline, "abcdefgh12345678");
assert_eq!(inline.len(), 16);
if cfg!(target_pointer_width = "64") {
assert!(!inline.is_heap_allocated());
assert_eq!(inline.capacity(), 16);
} else {
assert!(inline.capacity() >= 16);
}
inline.push_str("90");
assert_eq!(inline, "abcdefgh1234567890");
assert_eq!(inline.len(), 18);
assert!(inline.is_heap_allocated());
let mut static_ = LeanString::from_static_str("abcdefghijklmnopqrstuvwxyz");
assert_eq!(static_, "abcdefghijklmnopqrstuvwxyz");
assert_eq!(static_.len(), 26);
assert!(!static_.is_heap_allocated());
static_.push('0');
assert_eq!(static_, "abcdefghijklmnopqrstuvwxyz0");
assert_eq!(static_.len(), 27);
assert!(static_.is_heap_allocated());
}
#[test]
fn pop_keep_capacity() {
let mut inline = LeanString::from("Hello!");
assert_eq!(inline.pop(), Some('!'));
assert_eq!(inline, "Hello");
assert_eq!(inline.len(), 5);
for _ in 0..4 {
inline.pop();
}
assert_eq!(inline, "H");
assert_eq!(inline.pop(), Some('H'));
assert_eq!(inline, "");
assert!(inline.is_empty());
assert_eq!(inline.capacity(), INLINE_LIMIT);
let mut heap = LeanString::from("abcdefghijklmnopqrstuvwxyz");
assert_eq!(heap.pop(), Some('z'));
assert_eq!(heap, "abcdefghijklmnopqrstuvwxy");
assert_eq!(heap.len(), 25);
for _ in 0..24 {
heap.pop();
}
assert_eq!(heap, "a");
assert_eq!(heap.pop(), Some('a'));
assert_eq!(heap, "");
assert!(heap.is_empty());
assert_eq!(heap.capacity(), 26);
}
#[test]
fn pop_share_buffer() {
let mut s = LeanString::from("abcdefgh");
assert_eq!(s.pop(), Some('h'));
assert_eq!(s.len(), 7);
let mut s1 = s.clone();
assert_eq!(s1.pop(), Some('g'));
assert_eq!(s1, "abcdef");
assert_eq!(s1.len(), 6);
assert_eq!(s, "abcdefg");
s.push_str("hijklmnopqrstuvwxyz");
let mut s2 = s.clone();
assert_eq!(s.as_ptr(), s2.as_ptr());
assert_eq!(s2.pop(), Some('z'));
assert_eq!(s2.len(), 25);
assert_eq!(s, "abcdefghijklmnopqrstuvwxyz");
assert_eq!(s.as_ptr(), s2.as_ptr());
s2.push('0');
assert_ne!(s.as_ptr(), s2.as_ptr());
}
#[test]
fn pop_from_static() {
let mut static_ = LeanString::from_static_str("abcdefghijklmnopqrstuvwxyz");
assert_eq!(static_.len(), 26);
assert_eq!(static_.pop(), Some('z'));
assert_eq!(static_, "abcdefghijklmnopqrstuvwxy");
assert_eq!(static_.len(), 25);
assert_eq!(static_.capacity(), static_.len());
assert!(!static_.is_heap_allocated());
}
#[test]
fn pop_from_static_cow() {
let mut static1 = LeanString::from_static_str("0123456789abcdef!");
assert_eq!(static1.pop(), Some('!'));
let static2 = static1.clone();
assert_eq!(static1.pop(), Some('f'));
assert_eq!(static1, "0123456789abcde");
assert_eq!(static1.capacity(), static1.len());
assert!(!static1.is_heap_allocated());
assert_eq!(static2, "0123456789abcdef");
assert_eq!(static2.capacity(), static2.len());
assert!(!static2.is_heap_allocated());
assert_eq!(static1.as_ptr(), static2.as_ptr());
}
#[test]
fn pop_from_empty() {
let mut inline = LeanString::new();
assert_eq!(inline, "");
assert_eq!(inline.pop(), None);
assert_eq!(inline, "");
let mut heap = LeanString::from("a".repeat(INLINE_LIMIT + 1));
for _ in 0..INLINE_LIMIT + 1 {
heap.pop();
}
assert_eq!(inline, "");
assert_eq!(heap.pop(), None);
assert_eq!(heap, "");
let mut static_ = LeanString::from_static_str("");
assert_eq!(static_.pop(), None);
assert_eq!(static_, "");
}
#[test]
fn remove_cow() {
let mut inline = LeanString::from("Hello");
assert_eq!(inline.remove(4), 'o');
assert_eq!(inline.remove(0), 'H');
assert_eq!(inline, "ell");
let mut heap = LeanString::from("abcdefghijklmnopqrstuvwxyz");
assert_eq!(heap.remove(0), 'a');
let cloned = heap.clone();
assert_eq!(heap.as_ptr(), cloned.as_ptr());
assert_eq!(heap.remove(24), 'z');
assert_eq!(heap, "bcdefghijklmnopqrstuvwxy");
assert_eq!(cloned, "bcdefghijklmnopqrstuvwxyz");
}
#[test]
#[should_panic(expected = "index out of bounds (index: 12, len: 12)")]
fn remove_fail() {
let mut s = LeanString::from("Hello World!");
assert_eq!(s.len(), 12);
s.remove(12);
}
#[test]
fn retain_f_apply_count() {
let mut inline = LeanString::from("012");
let mut count = 0;
inline.retain(|_| {
count += 1;
true
});
assert_eq!(count, 3);
let mut heap = LeanString::from("abcdefghijklmnopqrstuvwxyz");
let mut count = 0;
heap.retain(|_| {
count += 1;
true
});
assert_eq!(count, 26);
}
#[test]
fn retain_cow() {
let mut heap = LeanString::from("qwer tyui opas dfgh jklz xcvb nm");
let cloned = heap.clone();
assert_eq!(heap.as_ptr(), cloned.as_ptr());
heap.retain(|c| c.is_alphabetic());
assert_eq!(heap, "qwertyuiopasdfghjklzxcvbnm");
assert_eq!(cloned, "qwer tyui opas dfgh jklz xcvb nm");
let mut static_ = LeanString::from_static_str("aBcDeFgHiJkLmNoPqRsTuVwXyZ");
let cloned = static_.clone();
static_.retain(|c| c.is_lowercase());
assert!(!cloned.is_heap_allocated());
assert_eq!(static_, "acegikmoqsuwy");
assert_eq!(cloned, "aBcDeFgHiJkLmNoPqRsTuVwXyZ");
}
#[test]
fn insert() {
let mut s = LeanString::from("01234");
s.insert(3, 'a');
assert_eq!(s, "012a34");
assert_eq!(s.len(), 6);
assert_eq!(s.capacity(), INLINE_LIMIT);
s.insert(0, 'b');
assert_eq!(s, "b012a34");
assert_eq!(s.len(), 7);
assert_eq!(s.capacity(), INLINE_LIMIT);
s.insert(7, 'c');
assert_eq!(s, "b012a34c");
assert_eq!(s.len(), 8);
assert_eq!(s.capacity(), INLINE_LIMIT);
s.insert_str(8, "12345678");
assert_eq!(s, "b012a34c12345678");
assert_eq!(s.len(), 16);
if cfg!(target_pointer_width = "64") {
assert_eq!(s.capacity(), INLINE_LIMIT);
assert!(!s.is_heap_allocated());
}
s.insert_str(0, "ABCDEFGH");
assert_eq!(s, "ABCDEFGHb012a34c12345678");
s.insert(20, '.');
assert_eq!(s, "ABCDEFGHb012a34c1234.5678");
}
#[test]
fn insert_to_static() {
let mut static_ = LeanString::from_static_str("01234567890123456789");
let cloned = static_.clone();
static_.insert(10, 'a');
assert_eq!(static_, "0123456789a0123456789");
assert!(static_.is_heap_allocated());
assert_eq!(cloned, "01234567890123456789");
assert!(!cloned.is_heap_allocated());
}
#[test]
#[should_panic(expected = "index is not a char boundary or out of bounds (index: 7)")]
fn insert_fail() {
let mut s = LeanString::from("012345");
s.insert(7, 'a');
}
#[test]
fn repeat_inline() {
let s = LeanString::from("ab");
assert!(!s.is_heap_allocated());
assert_eq!(s.repeat(0), "");
assert!(!s.repeat(0).is_heap_allocated());
assert_eq!(s.repeat(1), "ab");
let repeated = s.repeat(INLINE_LIMIT);
assert_eq!(repeated, "ab".repeat(INLINE_LIMIT));
assert!(repeated.is_heap_allocated());
}
#[test]
fn repeat_heap() {
let s = LeanString::from("a".repeat(INLINE_LIMIT + 1).as_str());
assert!(s.is_heap_allocated());
assert_eq!(s.repeat(0), "");
assert!(!s.repeat(0).is_heap_allocated());
let r1 = s.repeat(1);
assert_eq!(r1, s);
assert_eq!(r1.as_ptr(), s.as_ptr());
let repeated = s.repeat(2);
assert_eq!(repeated.len(), s.len() * 2);
assert_eq!(repeated.capacity(), s.len() * 2);
assert!(repeated.is_heap_allocated());
}
#[test]
fn repeat_empty() {
let empty = LeanString::new();
assert_eq!(empty.repeat(0), "");
assert_eq!(empty.repeat(1), "");
assert_eq!(empty.repeat(100), "");
}
#[test]
#[should_panic(expected = "Cannot allocate memory to hold LeanString")]
fn repeat_overflow() {
let s = LeanString::from("ab");
let _ = s.repeat(usize::MAX);
}
#[test]
fn truncate_keep_capacity() {
let mut inline = LeanString::from("abcdef");
assert!(!inline.is_heap_allocated());
inline.truncate(3);
assert_eq!(inline, "abc");
assert_eq!(inline.len(), 3);
assert!(!inline.is_heap_allocated());
assert_eq!(inline.capacity(), INLINE_LIMIT);
let mut heap = LeanString::from("a".repeat(INLINE_LIMIT + 10).as_str());
let original_capacity = heap.capacity();
assert!(heap.is_heap_allocated());
heap.truncate(INLINE_LIMIT + 1);
assert_eq!(heap, "a".repeat(INLINE_LIMIT + 1));
assert_eq!(heap.len(), INLINE_LIMIT + 1);
assert!(heap.is_heap_allocated());
assert_eq!(heap.capacity(), original_capacity);
heap.truncate(1);
assert_eq!(heap, "a");
assert_eq!(heap.len(), 1);
assert!(heap.is_heap_allocated());
assert_eq!(heap.capacity(), original_capacity);
}
#[test]
fn truncate_from_static() {
let mut static_ = LeanString::from_static_str("abcdefghijklmnopqrstuvwxyz");
assert_eq!(static_.len(), 26);
assert!(!static_.is_heap_allocated());
static_.truncate(20);
assert_eq!(static_, "abcdefghijklmnopqrst");
assert_eq!(static_.len(), 20);
assert_eq!(static_.capacity(), 20);
assert!(!static_.is_heap_allocated());
}
#[test]
fn truncate_share_buffer() {
let mut s = LeanString::from("abcdefgh");
assert_eq!(s.len(), 8);
let mut s1 = s.clone();
s1.truncate(4);
assert_eq!(s1, "abcd");
assert_eq!(s1.len(), 4);
assert_eq!(s, "abcdefgh");
s.push_str("ijklmnopqrstuvwxyz");
assert_eq!(s.len(), 26);
assert!(s.is_heap_allocated());
let mut s2 = s.clone();
s2.truncate(20);
assert_eq!(s.as_ptr(), s2.as_ptr());
s2.push('0');
assert_ne!(s.as_ptr(), s2.as_ptr());
}
#[test]
fn convert_static_to_inline_with_reserve() {
let s: &'static str = "1234567890ABCDEFGHIJ";
let mut static_ = LeanString::from_static_str(s);
for _ in 0..14 {
static_.pop();
}
assert_eq!(static_, "123456");
assert_eq!(static_.capacity(), static_.len());
static_.reserve(1);
assert_eq!(static_.capacity(), INLINE_LIMIT);
}
#[test]
fn clear_cow() {
let mut inline = LeanString::from("foo");
inline.clear();
assert_eq!(inline, "");
let mut heap: LeanString = core::iter::repeat_n('a', 100).collect();
let cloned = heap.clone();
heap.clear();
assert_eq!(heap, "");
assert_eq!(cloned.len(), 100);
assert_eq!(heap.capacity(), INLINE_LIMIT);
assert!(!heap.is_heap_allocated());
}
#[test]
fn extend_char() {
let mut s = LeanString::from("Hello, ");
s.extend("world!".chars());
assert_eq!(s, "Hello, world!");
}