#![cfg(feature = "utf16")]
mod common;
mod utf16_smoke {
use multitude::Arena;
use multitude::strings::{ArcUtf16Str, BoxUtf16Str, RcUtf16Str};
use widestring::utf16str;
#[expect(unused_imports, reason = "merged test module re-exports common helpers")]
use crate::common;
#[test]
fn alloc_utf16_str_rc() {
let arena = Arena::new();
let s = arena.alloc_utf16_str_rc(utf16str!("hello"));
assert_eq!(&*s, utf16str!("hello"));
assert_eq!(s.len(), 5);
let s2 = s.clone();
assert_eq!(&*s, &*s2);
}
#[test]
fn alloc_utf16_str_box() {
let arena = Arena::new();
let s = arena.alloc_utf16_str_box(utf16str!("hello"));
assert_eq!(&*s, utf16str!("hello"));
assert_eq!(s.len(), 5);
}
#[test]
fn alloc_utf16_str_arc() {
let arena = Arena::new();
let s = arena.alloc_utf16_str_arc(utf16str!("shared"));
let _: ArcUtf16Str = s;
assert_eq!(&*s, utf16str!("shared"));
}
#[test]
fn alloc_utf16_str_rc_from_str() {
let arena = Arena::new();
let s = arena.alloc_utf16_str_rc_from_str("hello, world");
assert_eq!(&*s, utf16str!("hello, world"));
}
#[test]
fn alloc_utf16_str_box_from_str() {
let arena = Arena::new();
let s = arena.alloc_utf16_str_box_from_str("hello");
assert_eq!(&*s, utf16str!("hello"));
}
#[test]
fn alloc_utf16_str_arc_from_str() {
let arena = Arena::new();
let s = arena.alloc_utf16_str_arc_from_str("hello");
assert_eq!(&*s, utf16str!("hello"));
}
#[test]
fn empty_string_round_trip() {
let arena = Arena::new();
let r: RcUtf16Str = arena.alloc_utf16_str_rc(utf16str!(""));
assert!(r.is_empty());
assert_eq!(r.len(), 0);
}
#[test]
fn box_into_rc() {
let arena = Arena::new();
let b: BoxUtf16Str = arena.alloc_utf16_str_box(utf16str!("hello"));
let r: RcUtf16Str = b.into();
assert_eq!(&*r, utf16str!("hello"));
}
#[test]
fn rc_into_arena_rc_slice() {
let arena = Arena::new();
let r = arena.alloc_utf16_str_rc(utf16str!("abc"));
let bytes: multitude::Rc<[u16]> = r.into();
assert_eq!(&*bytes, &[u16::from(b'a'), u16::from(b'b'), u16::from(b'c')][..]);
}
#[test]
fn arc_into_arena_arc_slice() {
let arena = Arena::new();
let a = arena.alloc_utf16_str_arc(utf16str!("abc"));
let bytes: multitude::Arc<[u16]> = a.into();
assert_eq!(&*bytes, &[u16::from(b'a'), u16::from(b'b'), u16::from(b'c')][..]);
}
#[test]
fn surrogate_pair_round_trip() {
let arena = Arena::new();
let r = arena.alloc_utf16_str_rc(utf16str!("💖"));
assert_eq!(r.len(), 2); assert_eq!(&*r, utf16str!("💖"));
let s = r.as_utf16_str().to_string();
assert_eq!(s, "💖");
}
#[test]
fn empty_builder_into_arena_str() {
let arena = Arena::new();
let b = arena.alloc_utf16_string();
let r = b.into_arena_utf16_str();
assert!(r.is_empty());
}
#[test]
fn comparison_traits() {
let arena = Arena::new();
let a = arena.alloc_utf16_str_rc(utf16str!("aaa"));
let b = arena.alloc_utf16_str_rc(utf16str!("aab"));
assert!(a < b);
assert_ne!(a, b);
assert_eq!(a, a.clone());
let _ = format!("{a}");
let _ = format!("{a:?}");
}
}
mod utf16_string_builder {
use multitude::Arena;
use widestring::utf16str;
#[expect(unused_imports, reason = "merged test module re-exports common helpers")]
use crate::common;
#[test]
fn push_and_pop() {
let arena = Arena::new();
let mut s = arena.alloc_utf16_string();
s.push('a');
s.push('b');
s.push('💖'); assert_eq!(s.len(), 4);
assert_eq!(s.pop(), Some('💖'));
assert_eq!(s.len(), 2);
s.push_str(utf16str!("xyz"));
assert_eq!(s.as_utf16_str(), utf16str!("abxyz"));
}
#[test]
fn push_from_str_transcodes() {
let arena = Arena::new();
let mut s = arena.alloc_utf16_string();
s.push_from_str("hello, 💖");
assert_eq!(s.as_utf16_str(), utf16str!("hello, 💖"));
assert_eq!(s.len(), 9); }
#[test]
fn truncate_and_clear() {
let arena = Arena::new();
let mut s = arena.alloc_utf16_string();
s.push_str(utf16str!("hello"));
s.truncate(3);
assert_eq!(s.as_utf16_str(), utf16str!("hel"));
assert_eq!(s.len(), 3);
s.clear();
assert!(s.is_empty());
}
#[test]
#[should_panic(expected = "is not on a UTF-16 char boundary")]
fn truncate_mid_surrogate_panics() {
let arena = Arena::new();
let mut s = arena.alloc_utf16_string();
s.push('💖'); s.truncate(1);
}
#[test]
fn insert_and_remove() {
let arena = Arena::new();
let mut s = arena.alloc_utf16_string();
s.push_str(utf16str!("hello"));
s.insert(0, 'X');
assert_eq!(s.as_utf16_str(), utf16str!("Xhello"));
s.insert_utf16_str(2, utf16str!("YY"));
assert_eq!(s.as_utf16_str(), utf16str!("XhYYello"));
let removed = s.remove(0);
assert_eq!(removed, 'X');
assert_eq!(s.as_utf16_str(), utf16str!("hYYello"));
}
#[test]
fn replace_range_grows_and_shrinks() {
let arena = Arena::new();
let mut s = arena.alloc_utf16_string();
s.push_str(utf16str!("Hello, world!"));
s.replace_range(7..12, utf16str!("everyone"));
assert_eq!(s.as_utf16_str(), utf16str!("Hello, everyone!"));
s.replace_range(7..15, utf16str!("X"));
assert_eq!(s.as_utf16_str(), utf16str!("Hello, X!"));
}
#[test]
fn retain_drops_predicate_failures() {
let arena = Arena::new();
let mut s = arena.alloc_utf16_string();
s.push_from_str("Hello, World!");
s.retain(|c| c.is_ascii_alphabetic());
assert_eq!(s.as_utf16_str(), utf16str!("HelloWorld"));
}
#[test]
fn capacity_growth() {
let arena = Arena::new();
let mut s = arena.alloc_utf16_string();
let n = if cfg!(miri) { 256 } else { 1000 };
for _ in 0..n {
s.push('a');
}
assert_eq!(s.len(), n);
assert!(s.capacity() >= n);
}
#[test]
fn shrink_to_fit_at_bump_cursor() {
let arena = Arena::builder().build();
let mut s = arena.alloc_utf16_string_with_capacity(64);
s.push_str(utf16str!("hi"));
let cap_before = s.capacity();
assert!(cap_before >= 64);
s.shrink_to_fit();
assert_eq!(s.capacity(), 2);
}
#[test]
fn extend_with_chars_str_and_utf16str() {
let arena = Arena::new();
let mut s = arena.alloc_utf16_string();
s.extend(['a', 'b', 'c'].iter().copied());
s.extend(["12", "34"].iter().copied());
s.extend([utf16str!("XY"), utf16str!("Z")].iter().copied());
assert_eq!(s.as_utf16_str(), utf16str!("abc1234XYZ"));
}
#[test]
fn from_str_in_and_from_utf16_str_in() {
let arena = Arena::new();
let a = multitude::strings::Utf16String::from_str_in("hello", &arena);
assert_eq!(a.as_utf16_str(), utf16str!("hello"));
let b = multitude::strings::Utf16String::from_utf16_str_in(utf16str!("world"), &arena);
assert_eq!(b.as_utf16_str(), utf16str!("world"));
}
#[test]
fn clone_builder() {
let arena = Arena::new();
let mut s = arena.alloc_utf16_string();
s.push_str(utf16str!("hello"));
let c = s.clone();
assert_eq!(c.as_utf16_str(), s.as_utf16_str());
}
#[test]
fn freeze_tail_reclamation() {
let arena = Arena::builder().build();
let stats_before = arena.alloc_utf16_string_with_capacity(64);
let cap_before = stats_before.capacity();
drop(stats_before);
let mut s = arena.alloc_utf16_string_with_capacity(64);
s.push_str(utf16str!("hi"));
let r = s.into_arena_utf16_str();
let s2 = arena.alloc_utf16_string_with_capacity(50);
assert!(s2.capacity() >= 50);
assert_eq!(&*r, utf16str!("hi"));
assert!(cap_before >= 64);
}
#[test]
fn push_str_accepts_borrowed_utf16str() {
let arena = Arena::new();
let mut s = arena.alloc_utf16_string();
let lit: &widestring::Utf16Str = utf16str!("ab");
s.push_str(lit);
assert_eq!(s.as_utf16_str(), utf16str!("ab"));
}
#[test]
fn push_str_accepts_utf16string_via_as_ref() {
let arena = Arena::new();
let mut a = arena.alloc_utf16_string();
a.push_str(utf16str!("hello"));
let mut b = arena.alloc_utf16_string();
b.push_str(&a);
assert_eq!(b.as_utf16_str(), utf16str!("hello"));
}
#[test]
fn push_str_accepts_box_rc_arc_utf16_str() {
let arena = Arena::new();
let mut src = arena.alloc_utf16_string();
src.push_str(utf16str!("xyz"));
let boxed = arena.alloc_utf16_str_box(utf16str!("xyz"));
let rc = arena.alloc_utf16_str_rc(utf16str!("xyz"));
let arc = arena.alloc_utf16_str_arc(utf16str!("xyz"));
let mut out = arena.alloc_utf16_string();
out.push_str(&boxed);
out.push_str(&rc);
out.push_str(&arc);
assert_eq!(out.as_utf16_str(), utf16str!("xyzxyzxyz"));
}
#[test]
fn try_push_str_accepts_as_ref_kinds() {
let arena = Arena::new();
let lit = utf16str!("lit-");
let mut owned = arena.alloc_utf16_string();
owned.push_str(utf16str!("own-"));
let boxed = arena.alloc_utf16_str_box(utf16str!("box-"));
let rc = arena.alloc_utf16_str_rc(utf16str!("rc-"));
let arc = arena.alloc_utf16_str_arc(utf16str!("arc"));
let mut out = arena.alloc_utf16_string();
out.try_push_str(lit).unwrap();
out.try_push_str(&owned).unwrap();
out.try_push_str(&boxed).unwrap();
out.try_push_str(&rc).unwrap();
out.try_push_str(&arc).unwrap();
assert_eq!(out.as_utf16_str(), utf16str!("lit-own-box-rc-arc"));
}
#[test]
fn push_from_str_accepts_str_like_types() {
let arena = Arena::new();
let owned = alloc::string::String::from("own-");
let boxed: alloc::boxed::Box<str> = alloc::boxed::Box::from("box-");
let rc: alloc::rc::Rc<str> = alloc::rc::Rc::from("rc-");
let arc: alloc::sync::Arc<str> = alloc::sync::Arc::from("arc");
let mut out = arena.alloc_utf16_string();
out.push_from_str("lit-");
out.push_from_str(&owned);
out.push_from_str(&boxed);
out.push_from_str(&rc);
out.push_from_str(&arc);
assert_eq!(out.as_utf16_str(), utf16str!("lit-own-box-rc-arc"));
}
#[test]
fn try_push_from_str_accepts_str_like_types() {
let arena = Arena::new();
let owned = alloc::string::String::from("hello, 💖");
let mut out = arena.alloc_utf16_string();
out.try_push_from_str(&owned).unwrap();
out.try_push_from_str("!").unwrap();
assert_eq!(out.as_utf16_str(), utf16str!("hello, 💖!"));
}
#[test]
fn len_is_zero_for_fresh_string() {
let arena = Arena::new();
let s = arena.alloc_utf16_string();
assert_eq!(s.len(), 0);
assert!(s.is_empty());
}
#[test]
fn len_tracks_number_of_u16_code_units_after_push_str() {
let arena = Arena::new();
let mut s = arena.alloc_utf16_string();
s.push_str(utf16str!("abc"));
assert_eq!(s.len(), 3);
s.push_str(utf16str!("de"));
assert_eq!(s.len(), 5);
}
#[test]
fn len_handles_non_bmp_chars_as_two_code_units() {
let arena = Arena::new();
let mut s = arena.alloc_utf16_string();
s.push('🦀'); assert_eq!(s.len(), 2);
s.push('a');
assert_eq!(s.len(), 3);
}
#[test]
fn len_returns_zero_after_clear() {
let arena = Arena::new();
let mut s = arena.alloc_utf16_string();
s.push_str(utf16str!("nonempty"));
assert!(!s.is_empty());
s.clear();
assert_eq!(s.len(), 0);
}
#[test]
fn try_with_capacity_in_zero_does_not_allocate_but_is_usable() {
let arena = Arena::new();
let s = multitude::strings::Utf16String::try_with_capacity_in(0, &arena).unwrap();
assert_eq!(s.len(), 0);
assert_eq!(s.capacity(), 0);
assert!(s.is_empty());
}
#[test]
fn try_with_capacity_in_respects_requested_capacity() {
let arena = Arena::new();
let s = multitude::strings::Utf16String::try_with_capacity_in(8, &arena).unwrap();
assert!(s.capacity() >= 8);
assert_eq!(s.len(), 0);
}
#[test]
fn try_with_capacity_in_one_allocates_at_least_one_unit() {
let arena = Arena::new();
let s = multitude::strings::Utf16String::try_with_capacity_in(1, &arena).unwrap();
assert!(s.capacity() >= 1);
assert_eq!(s.len(), 0);
}
#[test]
fn reserve_grows_capacity_and_preserves_contents() {
let arena = Arena::new();
let mut s = arena.alloc_utf16_string();
s.push_str(utf16str!("abc"));
let cap_before = s.capacity();
s.reserve(cap_before + 32);
assert!(s.capacity() >= s.len() + cap_before + 32);
assert_eq!(s.as_utf16_str(), utf16str!("abc"));
assert_eq!(s.len(), 3);
}
#[test]
fn reserve_grows_from_zero_capacity() {
let arena = Arena::new();
let mut s = arena.alloc_utf16_string();
assert_eq!(s.capacity(), 0);
s.reserve(64);
assert!(s.capacity() >= 64);
assert_eq!(s.len(), 0);
}
#[test]
fn try_reserve_zero_additional_is_noop() {
let arena = Arena::new();
let mut s = arena.alloc_utf16_string();
s.push_str(utf16str!("xy"));
let cap_before = s.capacity();
s.try_reserve(0).unwrap();
assert_eq!(s.capacity(), cap_before);
assert_eq!(s.as_utf16_str(), utf16str!("xy"));
}
#[test]
fn extend_chars_appends_in_order() {
let arena = Arena::new();
let mut s = arena.alloc_utf16_string();
s.extend(['a', 'b', 'c'].iter().copied());
assert_eq!(s.as_utf16_str(), utf16str!("abc"));
assert_eq!(s.len(), 3);
s.extend(std::iter::once(&'d').copied());
assert_eq!(s.as_utf16_str(), utf16str!("abcd"));
assert_eq!(s.len(), 4);
}
#[test]
fn extend_chars_handles_surrogate_pairs() {
let arena = Arena::new();
let mut s = arena.alloc_utf16_string();
s.extend(['a', '🦀', 'b'].iter().copied());
assert_eq!(s.as_utf16_str(), utf16str!("a🦀b"));
assert_eq!(s.len(), 4); }
#[test]
fn extend_str_slices_appends_in_order() {
let arena = Arena::new();
let mut s = arena.alloc_utf16_string();
s.extend(["ab", "cd"].iter().copied());
assert_eq!(s.as_utf16_str(), utf16str!("abcd"));
assert_eq!(s.len(), 4);
}
#[test]
fn extend_utf16_str_slices_appends_in_order() {
let arena = Arena::new();
let mut s = arena.alloc_utf16_string();
s.extend([utf16str!("ab"), utf16str!("cd")].iter().copied());
assert_eq!(s.as_utf16_str(), utf16str!("abcd"));
assert_eq!(s.len(), 4);
}
extern crate alloc;
}
mod utf16_format {
use core::fmt;
use multitude::Arena;
use multitude::strings::format_utf16;
use widestring::utf16str;
#[expect(unused_imports, reason = "merged test module re-exports common helpers")]
use crate::common;
#[test]
fn format_utf16_basic() {
let arena = Arena::new();
let n = 42_i32;
let s = format_utf16!(in &arena, "n = {n}");
assert_eq!(s.as_utf16_str(), utf16str!("n = 42"));
}
#[test]
fn format_utf16_with_unicode() {
let arena = Arena::new();
let s = format_utf16!(in &arena, "love {}", '💖');
assert_eq!(s.as_utf16_str(), utf16str!("love 💖"));
}
struct Fragmented<'a>(&'a [&'a str]);
impl fmt::Display for Fragmented<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
for piece in self.0 {
f.write_str(piece)?;
}
Ok(())
}
}
#[test]
fn format_utf16_fragmented_writes() {
let arena = Arena::new();
let pieces = ["he", "llo, ", "💖", " bye"];
let f = Fragmented(&pieces);
let s = format_utf16!(in &arena, "{f}");
assert_eq!(s.as_utf16_str(), utf16str!("hello, 💖 bye"));
}
#[test]
fn format_utf16_freeze() {
let arena = Arena::new();
let s = format_utf16!(in &arena, "x={}", 7);
let frozen: multitude::strings::RcUtf16Str = s.into_arena_utf16_str();
assert_eq!(&*frozen, utf16str!("x=7"));
}
}
mod utf16_serde {
use multitude::Arena;
use widestring::utf16str;
#[expect(unused_imports, reason = "merged test module re-exports common helpers")]
use crate::common;
#[test]
fn rc_serializes_as_utf8_string() {
let arena = Arena::new();
let s = arena.alloc_utf16_str_rc(utf16str!("hello, 💖"));
let json = serde_json::to_string(&s).unwrap();
assert_eq!(json, r#""hello, 💖""#);
}
#[test]
fn arc_serializes_as_utf8_string() {
let arena = Arena::new();
let s = arena.alloc_utf16_str_arc(utf16str!("shared"));
let json = serde_json::to_string(&s).unwrap();
assert_eq!(json, r#""shared""#);
}
#[test]
fn box_serializes_as_utf8_string() {
let arena = Arena::new();
let s = arena.alloc_utf16_str_box(utf16str!("boxed"));
let json = serde_json::to_string(&s).unwrap();
assert_eq!(json, r#""boxed""#);
}
#[test]
fn string_serializes_as_utf8_string() {
let arena = Arena::new();
let mut s = arena.alloc_utf16_string();
s.push_str(utf16str!("growable"));
let json = serde_json::to_string(&s).unwrap();
assert_eq!(json, r#""growable""#);
}
}
mod utf16_cross_thread {
use core::sync::atomic::{AtomicUsize, Ordering};
use std::thread;
use multitude::Arena;
use widestring::utf16str;
#[expect(unused_imports, reason = "merged test module re-exports common helpers")]
use crate::common;
#[test]
fn arc_send_across_threads() {
let arena = Arena::new();
let s = arena.alloc_utf16_str_arc(utf16str!("shared utf16"));
let s2 = s.clone();
let h = thread::spawn(move || s2.len());
assert_eq!(h.join().unwrap(), 12);
assert_eq!(&*s, utf16str!("shared utf16"));
}
#[test]
fn arc_concurrent_clone_drop() {
let arena = Arena::new();
let s = arena.alloc_utf16_str_arc(utf16str!("concurrent"));
let counter = std::sync::Arc::new(AtomicUsize::new(0));
let mut handles = std::vec::Vec::new();
for _ in 0..8 {
let s = s.clone();
let c = std::sync::Arc::clone(&counter);
handles.push(thread::spawn(move || {
for _ in 0..100 {
let copy = s.clone();
let _ = c.fetch_add(copy.len(), Ordering::Relaxed);
}
}));
}
for h in handles {
h.join().unwrap();
}
assert_eq!(counter.load(Ordering::Relaxed), 8 * 100 * 10);
assert_eq!(&*s, utf16str!("concurrent"));
}
}
mod utf16_coverage {
#![allow(clippy::std_instead_of_core, reason = "tests use std")]
#![allow(clippy::unwrap_used, reason = "test code")]
#![allow(unused_results, reason = "test code")]
use std::collections::hash_map::DefaultHasher;
use std::hash::{Hash, Hasher};
use std::panic::AssertUnwindSafe;
use multitude::Arena;
use multitude::strings::{ArcStr, BoxStr, RcStr, RcUtf16Str, String, Utf16String};
use widestring::{Utf16Str, utf16str};
#[expect(unused_imports, reason = "merged test module re-exports common helpers")]
use crate::common;
use crate::common::{FailingAllocator, SendFailingAllocator};
fn expect_panic<F: FnOnce()>(f: F) {
let r = std::panic::catch_unwind(AssertUnwindSafe(f));
assert!(r.is_err(), "expected panic but call returned");
}
fn fail_arena() -> Arena<FailingAllocator> {
Arena::new_in(FailingAllocator::new(0))
}
fn send_fail_arena() -> Arena<SendFailingAllocator> {
Arena::new_in(SendFailingAllocator::new(0))
}
#[test]
fn panic_alloc_utf16_str_rc() {
expect_panic(|| {
let a = fail_arena();
let _ = a.alloc_utf16_str_rc(utf16str!("x"));
});
}
#[test]
fn panic_alloc_utf16_str_arc() {
expect_panic(|| {
let a = send_fail_arena();
let _ = a.alloc_utf16_str_arc(utf16str!("x"));
});
}
#[test]
fn panic_alloc_utf16_str_box() {
expect_panic(|| {
let a = fail_arena();
let _ = a.alloc_utf16_str_box(utf16str!("x"));
});
}
#[test]
fn panic_alloc_utf16_str_rc_from_str() {
expect_panic(|| {
let a = fail_arena();
let _ = a.alloc_utf16_str_rc_from_str("x");
});
}
#[test]
fn panic_alloc_utf16_str_arc_from_str() {
expect_panic(|| {
let a = send_fail_arena();
let _ = a.alloc_utf16_str_arc_from_str("x");
});
}
#[test]
fn panic_alloc_utf16_str_box_from_str() {
expect_panic(|| {
let a = fail_arena();
let _ = a.alloc_utf16_str_box_from_str("x");
});
}
#[test]
fn panic_alloc_utf16_string_with_capacity() {
expect_panic(|| {
let a = fail_arena();
let _ = a.alloc_utf16_string_with_capacity(64);
});
}
#[test]
fn try_alloc_utf16_str_rc_err() {
let a = fail_arena();
a.try_alloc_utf16_str_rc(utf16str!("x")).unwrap_err();
}
#[test]
fn try_alloc_utf16_str_arc_err() {
let a = send_fail_arena();
a.try_alloc_utf16_str_arc(utf16str!("x")).unwrap_err();
}
#[test]
fn try_alloc_utf16_str_box_err() {
let a = fail_arena();
a.try_alloc_utf16_str_box(utf16str!("x")).unwrap_err();
}
#[test]
fn try_alloc_utf16_str_rc_from_str_err() {
let a = fail_arena();
a.try_alloc_utf16_str_rc_from_str("x").unwrap_err();
}
#[test]
fn try_alloc_utf16_str_arc_from_str_err() {
let a = send_fail_arena();
a.try_alloc_utf16_str_arc_from_str("x").unwrap_err();
}
#[test]
fn try_alloc_utf16_str_box_from_str_err() {
let a = fail_arena();
a.try_alloc_utf16_str_box_from_str("x").unwrap_err();
}
#[test]
fn try_alloc_utf16_string_with_capacity_err() {
let a = fail_arena();
a.try_alloc_utf16_string_with_capacity(64).unwrap_err();
}
#[test]
fn try_alloc_utf16_string_with_capacity_zero_no_alloc() {
let a = fail_arena();
let s = a.try_alloc_utf16_string_with_capacity(0).unwrap();
assert_eq!(s.capacity(), 0);
}
#[test]
fn empty_builder_accessors() {
let arena = Arena::new();
let s = arena.alloc_utf16_string();
assert_eq!(s.len(), 0);
assert!(s.is_empty());
assert_eq!(s.capacity(), 0);
assert_eq!(s.as_utf16_str(), utf16str!(""));
let empty: &[u16] = &[];
assert_eq!(s.as_slice(), empty);
let p: *const u16 = s.as_ptr();
assert!(!p.is_null());
}
#[test]
fn empty_builder_as_mut() {
let arena = Arena::new();
let mut s = arena.alloc_utf16_string();
let m: &mut Utf16Str = s.as_mut_utf16_str();
assert_eq!(m, utf16str!(""));
let p: *mut u16 = s.as_mut_ptr();
assert!(!p.is_null());
}
#[test]
fn pop_on_empty_returns_none() {
let arena = Arena::new();
let mut s = arena.alloc_utf16_string();
assert_eq!(s.pop(), None);
}
#[test]
fn truncate_noop_when_new_len_ge_len() {
let arena = Arena::new();
let mut s = arena.alloc_utf16_string();
s.push_str(utf16str!("abc"));
s.truncate(10);
assert_eq!(s.as_utf16_str(), utf16str!("abc"));
s.truncate(3);
assert_eq!(s.as_utf16_str(), utf16str!("abc"));
assert_eq!(s.len(), 3);
}
#[test]
fn shrink_to_fit_noop_when_full() {
let arena = Arena::new();
let mut s = Utf16String::with_capacity_in(0, &arena);
s.shrink_to_fit();
assert_eq!(s.capacity(), 0);
let mut tight = arena.alloc_utf16_string_with_capacity(3);
tight.push_from_str("abc");
tight.shrink_to_fit();
assert_eq!(tight.len(), 3);
s.push_str(utf16str!("hi"));
let cap = s.capacity();
let len = s.len();
if cap == len {
s.shrink_to_fit(); assert_eq!(s.capacity(), cap);
}
let mut s2 = Utf16String::with_capacity_in(8, &arena);
s2.push_str(utf16str!("ab"));
drop(s); let _other = arena.alloc_utf16_str_rc(utf16str!("xx"));
let cap_before = s2.capacity();
s2.shrink_to_fit(); assert_eq!(s2.capacity(), cap_before);
}
#[test]
fn insert_str_empty_is_noop() {
let arena = Arena::new();
let mut s = arena.alloc_utf16_string();
s.push_str(utf16str!("abc"));
s.insert_utf16_str(1, utf16str!(""));
assert_eq!(s.as_utf16_str(), utf16str!("abc"));
}
#[test]
fn insert_at_end() {
let arena = Arena::new();
let mut s = arena.alloc_utf16_string();
s.push_str(utf16str!("abc"));
s.insert_utf16_str(3, utf16str!("XY"));
assert_eq!(s.as_utf16_str(), utf16str!("abcXY"));
}
#[test]
fn replace_range_unbounded() {
let arena = Arena::new();
let mut s = arena.alloc_utf16_string();
s.push_str(utf16str!("hello"));
s.replace_range(.., utf16str!("world"));
assert_eq!(s.as_utf16_str(), utf16str!("world"));
}
#[test]
fn replace_range_inclusive_excluded_bounds() {
use core::ops::Bound;
let arena = Arena::new();
let mut s = arena.alloc_utf16_string();
s.push_str(utf16str!("abcdef"));
s.replace_range((Bound::Excluded(0), Bound::Included(2)), utf16str!("X"));
assert_eq!(s.as_utf16_str(), utf16str!("aXdef"));
}
#[test]
fn replace_range_equal_size() {
let arena = Arena::new();
let mut s = arena.alloc_utf16_string();
s.push_str(utf16str!("abcdef"));
s.replace_range(2..4, utf16str!("XY")); assert_eq!(s.as_utf16_str(), utf16str!("abXYef"));
}
#[test]
fn try_push_err() {
let a = fail_arena();
let mut s = Utf16String::new_in(&a);
assert!(s.try_push('a').is_err());
}
#[test]
fn try_push_str_err() {
let a = fail_arena();
let mut s = Utf16String::new_in(&a);
assert!(s.try_push_str(utf16str!("abc")).is_err());
}
#[test]
fn try_push_from_str_err() {
let a = fail_arena();
let mut s = Utf16String::new_in(&a);
assert!(s.try_push_from_str("abc").is_err());
}
#[test]
fn try_reserve_zero_is_noop() {
let arena = Arena::new();
let mut s = arena.alloc_utf16_string();
s.try_reserve(0).unwrap();
assert_eq!(s.capacity(), 0);
}
#[test]
fn reserve_panics_when_alloc_fails() {
expect_panic(|| {
let a = fail_arena();
let mut s = Utf16String::new_in(&a);
s.reserve(64);
});
}
#[test]
fn try_reserve_err() {
let a = fail_arena();
let mut s = Utf16String::new_in(&a);
assert!(s.try_reserve(64).is_err());
}
#[test]
fn push_empty_str_is_noop() {
let arena = Arena::new();
let mut s = arena.alloc_utf16_string();
s.push_str(utf16str!(""));
assert!(s.is_empty());
s.push_from_str("");
assert!(s.is_empty());
}
#[test]
fn try_push_from_str_with_surrogate_pair() {
let arena = Arena::new();
let mut s = arena.alloc_utf16_string();
s.try_push_from_str("a💖b").unwrap();
assert_eq!(s.as_utf16_str(), utf16str!("a💖b"));
}
#[test]
fn arena_utf16_string_traits() {
use core::borrow::{Borrow, BorrowMut};
let arena = Arena::new();
let mut s = arena.alloc_utf16_string();
s.push_str(utf16str!("hello"));
let _: &Utf16Str = &s;
let _: &mut Utf16Str = &mut s;
let _: &Utf16Str = AsRef::as_ref(&s);
let _: &mut Utf16Str = AsMut::as_mut(&mut s);
let _: &Utf16Str = Borrow::borrow(&s);
let _: &mut Utf16Str = BorrowMut::borrow_mut(&mut s);
let c = s.clone();
assert_eq!(c, s);
assert_eq!(c.as_utf16_str(), s.as_utf16_str());
let mut other = arena.alloc_utf16_string();
other.push_str(utf16str!("hellp"));
assert!(s < other);
assert!(s.partial_cmp(&other).is_some());
assert_eq!(s.cmp(&s.clone()), core::cmp::Ordering::Equal);
let lit = utf16str!("hello");
assert_eq!(s, lit);
assert!(s == lit);
let mut h = DefaultHasher::new();
s.hash(&mut h);
let _ = h.finish();
let _ = format!("{s}");
let _ = format!("{s:?}");
}
#[test]
fn rc_utf16_traits_and_pointer() {
use core::borrow::Borrow;
let arena = Arena::new();
let r = arena.alloc_utf16_str_rc(utf16str!("hello"));
let _: &Utf16Str = &r;
let _: &Utf16Str = AsRef::as_ref(&r);
let _: &Utf16Str = Borrow::borrow(&r);
assert!(r == *utf16str!("hello"));
assert!(r == utf16str!("hello"));
let _ = format!("{r}");
let _ = format!("{r:?}");
let _ = format!("{r:p}");
let mut h = DefaultHasher::new();
r.hash(&mut h);
let _ = h.finish();
let r2 = r.clone();
assert_eq!(r.cmp(&r2), core::cmp::Ordering::Equal);
assert_eq!(r.partial_cmp(&r2), Some(core::cmp::Ordering::Equal));
let bytes: multitude::Rc<[u16]> = r.into();
assert_eq!(
&*bytes,
&[u16::from(b'h'), u16::from(b'e'), u16::from(b'l'), u16::from(b'l'), u16::from(b'o')][..]
);
}
#[test]
fn arc_utf16_traits_and_pointer() {
use core::borrow::Borrow;
let arena = Arena::new();
let a = arena.alloc_utf16_str_arc(utf16str!("hello"));
let _: &Utf16Str = &a;
let _: &Utf16Str = AsRef::as_ref(&a);
let _: &Utf16Str = Borrow::borrow(&a);
assert!(a == *utf16str!("hello"));
assert!(a == utf16str!("hello"));
let _ = format!("{a}");
let _ = format!("{a:?}");
let _ = format!("{a:p}");
let mut h = DefaultHasher::new();
a.hash(&mut h);
let _ = h.finish();
let a2 = a.clone();
assert_eq!(a.cmp(&a2), core::cmp::Ordering::Equal);
assert_eq!(a.partial_cmp(&a2), Some(core::cmp::Ordering::Equal));
let bytes: multitude::Arc<[u16]> = a.into();
assert_eq!(
&*bytes,
&[u16::from(b'h'), u16::from(b'e'), u16::from(b'l'), u16::from(b'l'), u16::from(b'o')][..]
);
}
#[test]
fn box_utf16_traits_pointer_and_mutators() {
use core::borrow::{Borrow, BorrowMut};
let arena = Arena::new();
let mut b = arena.alloc_utf16_str_box(utf16str!("hello"));
let _: &Utf16Str = &b;
let _: &mut Utf16Str = &mut b;
let _: &Utf16Str = AsRef::as_ref(&b);
let _: &mut Utf16Str = AsMut::as_mut(&mut b);
let _: &Utf16Str = Borrow::borrow(&b);
let _: &mut Utf16Str = BorrowMut::borrow_mut(&mut b);
assert!(b == *utf16str!("hello"));
assert!(b == utf16str!("hello"));
let _ = format!("{b}");
let _ = format!("{b:?}");
let _ = format!("{b:p}");
let mut h = DefaultHasher::new();
b.hash(&mut h);
let _ = h.finish();
let b2 = arena.alloc_utf16_str_box(utf16str!("hello"));
assert_eq!(b.cmp(&b2), core::cmp::Ordering::Equal);
assert_eq!(b.partial_cmp(&b2), Some(core::cmp::Ordering::Equal));
let r: RcUtf16Str = b.into();
assert_eq!(&*r, utf16str!("hello"));
}
#[test]
fn utf8_smart_pointer_partial_eq_str() {
let arena = Arena::new();
let r: RcStr = arena.alloc_str_rc("hi");
assert!(r == *"hi");
assert!(r == "hi");
let a: ArcStr = arena.alloc_str_arc("hi");
assert!(a == *"hi");
assert!(a == "hi");
let b: BoxStr = arena.alloc_str_box("hi");
assert!(b == *"hi");
assert!(b == "hi");
let mut g: String = arena.alloc_string();
g.push_str("hi");
assert!(g == *"hi");
assert!(g == "hi");
}
#[test]
fn from_utf16_str_in_and_from_str_in() {
let arena = Arena::new();
let a = Utf16String::from_str_in("hello, 💖", &arena);
assert_eq!(a.as_utf16_str(), utf16str!("hello, 💖"));
let b = Utf16String::from_utf16_str_in(utf16str!("world"), &arena);
assert_eq!(b.as_utf16_str(), utf16str!("world"));
}
#[test]
fn extend_chars_with_size_hint() {
let arena = Arena::new();
let mut s = arena.alloc_utf16_string();
let chars = ['a', 'b', 'c', '💖'];
s.extend(chars.iter().copied()); assert_eq!(s.as_utf16_str(), utf16str!("abc💖"));
}
#[test]
fn extend_chars_zero_lower_bound() {
let arena = Arena::new();
let mut s = arena.alloc_utf16_string();
s.extend(core::iter::empty::<char>()); assert!(s.is_empty());
}
#[test]
fn extend_str_slices() {
let arena = Arena::new();
let mut s = arena.alloc_utf16_string();
s.extend(["ab", "cd"]);
assert_eq!(s.as_utf16_str(), utf16str!("abcd"));
}
#[test]
fn extend_utf16_str_slices() {
let arena = Arena::new();
let mut s = arena.alloc_utf16_string();
s.extend([utf16str!("ab"), utf16str!("cd")]);
assert_eq!(s.as_utf16_str(), utf16str!("abcd"));
}
#[test]
#[should_panic(expected = "not on a UTF-16 char boundary")]
fn insert_at_mid_surrogate_panics() {
let arena = Arena::new();
let mut s = arena.alloc_utf16_string();
s.push('💖');
s.insert(1, 'X');
}
#[test]
#[should_panic(expected = "not on a UTF-16 char boundary")]
fn remove_at_mid_surrogate_panics() {
let arena = Arena::new();
let mut s = arena.alloc_utf16_string();
s.push('💖');
s.remove(1);
}
#[test]
#[should_panic(expected = "not on a UTF-16 char boundary")]
fn replace_range_start_mid_surrogate_panics() {
let arena = Arena::new();
let mut s = arena.alloc_utf16_string();
s.push_str(utf16str!("a💖b"));
s.replace_range(2..3, utf16str!(""));
}
#[test]
#[should_panic(expected = "Utf16String::replace_range")]
fn replace_range_end_oob_panics() {
let arena = Arena::new();
let mut s = arena.alloc_utf16_string();
s.push_str(utf16str!("abc"));
s.replace_range(0..10, utf16str!(""));
}
#[test]
#[should_panic(expected = "Utf16String::replace_range")]
fn replace_range_start_greater_than_end_panics() {
let arena = Arena::new();
let mut s = arena.alloc_utf16_string();
s.push_str(utf16str!("abc"));
#[expect(clippy::reversed_empty_ranges, reason = "intentionally inverted to trigger panic")]
s.replace_range(2..1, utf16str!(""));
}
#[test]
fn grow_doubling_path() {
let arena = Arena::new();
let mut s = Utf16String::with_capacity_in(4, &arena);
s.push_str(utf16str!("abcd"));
s.push('e'); assert!(s.capacity() >= 8);
assert_eq!(s.as_utf16_str(), utf16str!("abcde"));
}
#[test]
fn grow_uses_min_cap_when_doubling_too_small() {
let arena = Arena::new();
let mut s = Utf16String::with_capacity_in(4, &arena);
s.push_str(utf16str!("abcd"));
let big = "x".repeat(100);
s.push_from_str(&big); assert!(s.capacity() >= 104);
}
#[test]
fn arena_utf16_string_drop_releases_chunk() {
let arena = Arena::new();
{
let mut s = arena.alloc_utf16_string();
s.push_str(utf16str!("data"));
}
}
#[test]
fn retain_keep_all() {
let arena = Arena::new();
let mut s = arena.alloc_utf16_string();
s.push_str(utf16str!("abc"));
s.retain(|_| true);
assert_eq!(s.as_utf16_str(), utf16str!("abc"));
}
#[test]
fn retain_drop_all() {
let arena = Arena::new();
let mut s = arena.alloc_utf16_string();
s.push_str(utf16str!("abc"));
s.retain(|_| false);
assert!(s.is_empty());
}
#[test]
fn retain_with_surrogate() {
let arena = Arena::new();
let mut s = arena.alloc_utf16_string();
s.push_str(utf16str!("a💖b"));
s.retain(|c| c.is_ascii());
assert_eq!(s.as_utf16_str(), utf16str!("ab"));
}
#[test]
fn clear_resets_len_only() {
let arena = Arena::new();
let mut s = arena.alloc_utf16_string();
s.push_str(utf16str!("hello"));
let cap = s.capacity();
s.clear();
assert_eq!(s.len(), 0);
assert_eq!(s.capacity(), cap);
}
#[test]
fn into_arena_utf16_str_zero_cap() {
let arena = Arena::new();
let s = arena.alloc_utf16_string();
let r = s.into_arena_utf16_str();
assert!(r.is_empty());
}
#[test]
fn into_arena_utf16_str_with_data_reclaims_tail() {
let arena = Arena::builder().build();
let mut s = arena.alloc_utf16_string_with_capacity(64);
s.push_str(utf16str!("hi"));
let r = s.into_arena_utf16_str();
assert_eq!(&*r, utf16str!("hi"));
let _follow = arena.alloc_utf16_string_with_capacity(50);
}
#[test]
fn from_arena_utf16_string_for_rc() {
let arena = Arena::new();
let mut s = arena.alloc_utf16_string();
s.push_str(utf16str!("frozen"));
let r: RcUtf16Str = s.into();
assert_eq!(&*r, utf16str!("frozen"));
}
#[test]
fn display_passes_through() {
let arena = Arena::new();
let r = arena.alloc_utf16_str_rc(utf16str!("hi💖"));
assert_eq!(format!("{r}"), "hi💖");
let a = arena.alloc_utf16_str_arc(utf16str!("hi💖"));
assert_eq!(format!("{a}"), "hi💖");
let b = arena.alloc_utf16_str_box(utf16str!("hi💖"));
assert_eq!(format!("{b}"), "hi💖");
let mut s = arena.alloc_utf16_string();
s.push_str(utf16str!("hello"));
assert_eq!(std::format!("{s}"), "hello");
}
#[test]
fn insert_grows_capacity() {
let arena = Arena::new();
let mut s = Utf16String::with_capacity_in(4, &arena);
s.push_str(utf16str!("abcd"));
s.insert_utf16_str(2, utf16str!("XYZW"));
assert_eq!(s.as_utf16_str(), utf16str!("abXYZWcd"));
assert!(s.capacity() >= 8);
}
#[test]
fn replace_range_grows_capacity() {
let arena = Arena::new();
let mut s = Utf16String::with_capacity_in(4, &arena);
s.push_str(utf16str!("abcd"));
s.replace_range(0..1, utf16str!("XXXXX")); assert_eq!(s.as_utf16_str(), utf16str!("XXXXXbcd"));
assert!(s.capacity() >= 8);
}
#[test]
fn as_slice_non_empty() {
let arena = Arena::new();
let mut s = arena.alloc_utf16_string();
s.push_str(utf16str!("ab"));
let slice: &[u16] = s.as_slice();
assert_eq!(slice, &[u16::from(b'a'), u16::from(b'b')][..]);
}
#[test]
fn arena_utf16_string_eq_utf16str_value() {
let arena = Arena::new();
let mut s = arena.alloc_utf16_string();
s.push_str(utf16str!("hi"));
let lit: &Utf16Str = utf16str!("hi");
assert!(<Utf16String<'_, _> as PartialEq<Utf16Str>>::eq(&s, lit));
assert!(<Utf16String<'_, _> as PartialEq<&Utf16Str>>::eq(&s, &lit));
}
#[test]
fn try_alloc_utf16_str_arc_from_str_err_on_alloc_failure() {
let arena = Arena::new_in(SendFailingAllocator::new(0));
arena.try_alloc_utf16_str_arc_from_str("xyz").unwrap_err();
}
#[test]
fn try_alloc_utf16_str_rc_from_str_success() {
let arena = Arena::new();
let r = arena.try_alloc_utf16_str_rc_from_str("hello, 💖").unwrap();
assert_eq!(&*r, utf16str!("hello, 💖"));
}
#[test]
fn try_alloc_utf16_str_arc_from_str_success() {
let arena = Arena::new();
let a = arena.try_alloc_utf16_str_arc_from_str("hello").unwrap();
assert_eq!(&*a, utf16str!("hello"));
}
#[test]
fn try_alloc_utf16_str_box_from_str_success() {
let arena = Arena::new();
let b = arena.try_alloc_utf16_str_box_from_str("hello").unwrap();
assert_eq!(&*b, utf16str!("hello"));
}
#[test]
fn try_alloc_utf16_str_box_from_str_err_on_alloc_failure() {
let arena = Arena::new_in(FailingAllocator::new(0));
arena.try_alloc_utf16_str_box_from_str("xyz").unwrap_err();
}
#[test]
fn panic_alloc_utf16_str_arc_from_str_when_alloc_fails() {
expect_panic(|| {
let arena = Arena::new_in(SendFailingAllocator::new(0));
let _ = arena.alloc_utf16_str_arc_from_str("xyz");
});
}
#[test]
fn panic_alloc_utf16_str_box_from_str_when_alloc_fails() {
expect_panic(|| {
let arena = Arena::new_in(FailingAllocator::new(0));
let _ = arena.alloc_utf16_str_box_from_str("xyz");
});
}
#[test]
fn grow_for_string_err_on_relocation() {
let arena = Arena::builder().allocator_in(FailingAllocator::new(1)).build();
let mut s = Utf16String::try_with_capacity_in(4, &arena).unwrap();
s.try_push_str(utf16str!("abcd")).unwrap();
assert!(s.try_reserve(64 * 1024).is_err());
}
#[test]
fn panic_grow_to_at_least() {
expect_panic(|| {
let arena = Arena::builder().allocator_in(FailingAllocator::new(1)).build();
let mut s = Utf16String::try_with_capacity_in(4, &arena).unwrap();
s.try_push_str(utf16str!("abcd")).unwrap();
s.push_from_str("x".repeat(64 * 1024));
});
}
#[test]
fn panic_push_when_alloc_fails() {
expect_panic(|| {
let a = fail_arena();
let mut s = Utf16String::new_in(&a);
s.push('a');
});
}
#[test]
fn panic_push_str_when_alloc_fails() {
expect_panic(|| {
let a = fail_arena();
let mut s = Utf16String::new_in(&a);
s.push_str(utf16str!("abc"));
});
}
#[test]
fn panic_push_from_str_when_alloc_fails() {
expect_panic(|| {
let a = fail_arena();
let mut s = Utf16String::new_in(&a);
s.push_from_str("abc");
});
}
#[test]
fn reserve_no_growth_path() {
let arena = Arena::new();
let mut s = Utf16String::with_capacity_in(16, &arena);
s.reserve(4); assert_eq!(s.capacity(), 16);
assert_eq!(s.len(), 0);
}
#[test]
fn try_with_capacity_isize_overflow_guard() {
let arena = Arena::new();
let cap = (isize::MAX.unsigned_abs() / 2) + 1000;
let r = Utf16String::try_with_capacity_in(cap, &arena);
r.unwrap_err();
}
#[test]
fn try_grow_isize_overflow_guard() {
let arena = Arena::new();
let mut s = Utf16String::try_with_capacity_in(4, &arena).unwrap();
let huge = (isize::MAX.unsigned_abs() / 2) + 1000;
let r = s.try_reserve(huge);
assert!(r.is_err());
}
}
mod mutants_for_utf16_strings {
#![allow(clippy::std_instead_of_core, reason = "test code")]
#![allow(clippy::unwrap_used, reason = "test code")]
#![allow(clippy::doc_markdown, reason = "doc comments cite raw identifier names")]
#![allow(clippy::cast_possible_truncation, reason = "bounded indices fit in u16")]
#![allow(clippy::unnecessary_cast, reason = "explicit width clarifies intent")]
#![allow(clippy::cast_lossless, reason = "test code")]
use multitude::Arena;
use multitude::strings::Utf16String;
use widestring::utf16str;
#[expect(unused_imports, reason = "merged test module re-exports common helpers")]
use crate::common;
#[test]
fn truncate_to_zero_clears_string() {
let arena = Arena::new();
let mut s = Utf16String::from_utf16_str_in(utf16str!("abc"), &arena);
s.truncate(0);
assert_eq!(s.len(), 0);
assert_eq!(s.as_utf16_str(), utf16str!(""));
}
#[test]
fn shrink_to_fit_reduces_capacity_to_len() {
let arena = Arena::new();
let mut s = Utf16String::with_capacity_in(64, &arena);
s.push_str(utf16str!("abc"));
assert_eq!(s.len(), 3);
let cap_before = s.capacity();
assert!(cap_before >= 64);
s.shrink_to_fit();
assert_eq!(s.len(), 3);
assert_eq!(s.as_utf16_str(), utf16str!("abc"));
assert_eq!(s.capacity(), 3);
}
#[test]
fn reserve_exact_capacity_does_not_regrow() {
let arena = Arena::new();
let mut s = Utf16String::with_capacity_in(8, &arena);
assert!(s.capacity() >= 8);
let cap = s.capacity();
let ptr_before = s.as_ptr();
s.reserve(cap);
let ptr_after = s.as_ptr();
assert_eq!(s.capacity(), cap, "no regrow when cap already suffices");
assert_eq!(
ptr_before, ptr_after,
"reserve at exact-fit boundary must not reallocate (kills `> → >=`)"
);
}
#[test]
fn push_slice_at_exact_fit_does_not_regrow() {
let arena = Arena::new();
let mut s = Utf16String::with_capacity_in(8, &arena);
let cap = s.capacity();
let ptr_before = s.as_ptr();
let payload: Vec<u16> = (0..cap as u16).collect();
let payload_str = widestring::Utf16Str::from_slice(&payload).expect("valid utf16");
s.push_str(payload_str);
let ptr_after = s.as_ptr();
assert_eq!(s.len(), cap);
assert_eq!(s.capacity(), cap);
assert_eq!(ptr_before, ptr_after, "push at exact-fit must not reallocate");
}
#[test]
fn insert_slice_preserves_content() {
let arena = Arena::new();
let mut s = Utf16String::from_utf16_str_in(utf16str!("hello"), &arena);
s.insert_utf16_str(1, utf16str!("XX"));
assert_eq!(s.as_utf16_str(), utf16str!("hXXello"));
assert_eq!(s.len(), 7);
s.insert_utf16_str(s.len(), utf16str!("!"));
assert_eq!(s.as_utf16_str(), utf16str!("hXXello!"));
let mut appended = arena.alloc_utf16_string();
appended.push_str(utf16str!("hi"));
appended.insert_utf16_str(appended.len(), utf16str!("!"));
assert_eq!(appended.as_utf16_str(), utf16str!("hi!"));
s.insert_utf16_str(0, utf16str!(">"));
assert_eq!(s.as_utf16_str(), utf16str!(">hXXello!"));
let mut t = Utf16String::with_capacity_in(8, &arena);
t.push_str(utf16str!("abcd"));
let ptr_before = t.as_ptr();
let cap = t.capacity();
let extra = vec![b'x' as u16; cap - t.len()];
let extra_str = widestring::Utf16Str::from_slice(&extra).expect("valid utf16");
t.insert_utf16_str(t.len(), extra_str);
assert_eq!(t.len(), cap);
assert_eq!(t.as_ptr(), ptr_before, "insert at exact-fit must not reallocate");
}
#[test]
fn remove_middle_preserves_content() {
let arena = Arena::new();
let mut s = Utf16String::from_utf16_str_in(utf16str!("hello"), &arena);
let removed = s.remove(1); assert_eq!(removed, 'e');
assert_eq!(s.as_utf16_str(), utf16str!("hllo"));
assert_eq!(s.len(), 4);
let removed = s.remove(s.len() - 1);
assert_eq!(removed, 'o');
assert_eq!(s.as_utf16_str(), utf16str!("hll"));
let removed = s.remove(0);
assert_eq!(removed, 'h');
assert_eq!(s.as_utf16_str(), utf16str!("ll"));
let mut s = Utf16String::new_in(&arena);
s.push_from_str("abcdefghij");
assert_eq!(s.remove(4), 'e');
assert_eq!(s.as_slice().to_vec(), widestring::Utf16String::from_str("abcdfghij").into_vec());
assert_eq!(s.remove(0), 'a');
assert_eq!(s.as_slice().to_vec(), widestring::Utf16String::from_str("bcdfghij").into_vec());
assert_eq!(s.remove(s.len() - 1), 'j');
assert_eq!(s.as_slice().to_vec(), widestring::Utf16String::from_str("bcdfghi").into_vec());
}
#[test]
fn replace_range_at_boundaries() {
let arena = Arena::new();
let mut s = Utf16String::from_utf16_str_in(utf16str!("hello"), &arena);
s.replace_range(.., utf16str!("WORLD"));
assert_eq!(s.as_utf16_str(), utf16str!("WORLD"));
let mut s = arena.alloc_utf16_string();
s.push_str(utf16str!("abc"));
s.replace_range(0..3, utf16str!("xyzw"));
assert_eq!(s.as_utf16_str(), utf16str!("xyzw"));
let mut s = arena.alloc_utf16_string();
s.push_str(utf16str!("abcdef"));
s.replace_range(0..6, utf16str!("xy"));
assert_eq!(s.as_utf16_str(), utf16str!("xy"));
let mut s = Utf16String::from_utf16_str_in(utf16str!("hello"), &arena);
s.replace_range(1..4, utf16str!("XXXX"));
assert_eq!(s.as_utf16_str(), utf16str!("hXXXXo"));
let mut s = Utf16String::from_utf16_str_in(utf16str!("hello"), &arena);
s.replace_range(1..4, utf16str!("X"));
assert_eq!(s.as_utf16_str(), utf16str!("hXo"));
let mut s = Utf16String::from_utf16_str_in(utf16str!("hello"), &arena);
s.replace_range(..2, utf16str!("HE"));
assert_eq!(s.as_utf16_str(), utf16str!("HEllo"));
let mut s = Utf16String::from_utf16_str_in(utf16str!("hello"), &arena);
s.replace_range(3.., utf16str!("LO"));
assert_eq!(s.as_utf16_str(), utf16str!("helLO"));
let mut s = Utf16String::from_utf16_str_in(utf16str!("hello"), &arena);
s.replace_range(2..2, utf16str!("--"));
assert_eq!(s.as_utf16_str(), utf16str!("he--llo"));
let mut s = arena.alloc_utf16_string();
s.push_str(utf16str!("abc"));
let n = s.len();
s.replace_range(n..n, utf16str!("xyz"));
assert_eq!(s.as_utf16_str(), utf16str!("abcxyz"));
let mut s = Utf16String::new_in(&arena);
s.replace_range(0..0, utf16str!("abc"));
assert_eq!(s.as_utf16_str(), utf16str!("abc"));
}
#[test]
fn into_arena_box_utf16_str_handles_empty_and_non_empty() {
let arena = Arena::new();
let s = Utf16String::new_in(&arena);
let b = s.into_arena_box_utf16_str();
assert_eq!(&*b, utf16str!(""));
assert_eq!(b.len(), 0);
let s = Utf16String::from_utf16_str_in(utf16str!("hello, world"), &arena);
let b = s.into_arena_box_utf16_str();
assert_eq!(&*b, utf16str!("hello, world"));
assert_eq!(b.len(), 12);
}
#[test]
fn reclaim_tail_does_not_corrupt_frozen_string() {
let arena = Arena::new();
let mut s = Utf16String::with_capacity_in(256, &arena);
s.push_str(utf16str!("frozen"));
let frozen = s.into_arena_box_utf16_str();
let _filler: multitude::vec::Vec<'_, u64> = {
let mut v = arena.alloc_vec_with_capacity::<u64>(64);
for i in 0..64 {
v.push(i);
}
v
};
assert_eq!(&*frozen, utf16str!("frozen"));
}
}
mod mutation_coverage {
#![allow(clippy::std_instead_of_core, reason = "tests use std")]
#![allow(clippy::unwrap_used, reason = "test code")]
#![allow(clippy::large_stack_arrays, reason = "boundary-focused tests use large values")]
#![allow(clippy::undocumented_unsafe_blocks, reason = "test code")]
#![allow(unused_results, reason = "test code")]
#![allow(clippy::needless_pass_by_value, reason = "test code")]
use std::collections::hash_map::DefaultHasher;
use std::hash::{Hash, Hasher};
use std::panic::catch_unwind;
use std::sync::Arc as StdArc;
use std::sync::atomic::{AtomicUsize, Ordering};
use multitude::strings::{BoxStr, BoxUtf16Str, String as ArenaString, Utf16String};
use multitude::vec::Vec as ArenaVec;
use multitude::{Arena, ArenaBuilder};
use widestring::{Utf16Str, utf16str};
use crate::common;
fn hash_value<T: Hash>(value: &T) -> u64 {
let mut hasher = DefaultHasher::new();
value.hash(&mut hasher);
hasher.finish()
}
struct DropCounter(StdArc<AtomicUsize>);
impl Drop for DropCounter {
fn drop(&mut self) {
self.0.fetch_add(1, Ordering::Relaxed);
}
}
#[test]
fn test_string_is_empty_false_when_nonempty() {
let arena = Arena::new();
let s = ArenaString::from_str_in("alpha", &arena);
assert!(!s.is_empty());
}
#[test]
fn test_string_partial_eq_distinguishes_different_values() {
let arena = Arena::new();
let a = ArenaString::from_str_in("alpha", &arena);
let b = ArenaString::from_str_in("beta", &arena);
let beta = "beta";
assert_ne!(a, b);
assert!(a != "beta");
assert!(a != beta);
}
#[test]
fn test_string_hash_depends_on_contents() {
let arena = Arena::new();
let a = ArenaString::from_str_in("alpha", &arena);
let b = ArenaString::from_str_in("beta", &arena);
assert_ne!(hash_value(&a), hash_value(&b));
}
#[test]
fn test_string_as_ref_returns_expected_contents() {
let arena = Arena::new();
let s = ArenaString::from_str_in("expected", &arena);
let r: &str = s.as_ref();
assert_eq!(r, "expected");
assert_ne!(r, "");
}
#[test]
fn test_string_insert_str_grows_at_full_capacity() {
let arena = Arena::new();
let mut s = arena.alloc_string_with_capacity(5);
s.push_str("hello");
s.insert_str(5, "!!");
assert_eq!(s.as_str(), "hello!!");
assert!(s.capacity() >= s.len());
}
#[test]
fn test_string_insert_str_middle_preserves_surrounding_bytes() {
let arena = Arena::new();
let mut s = arena.alloc_string_with_capacity(8);
s.push_str("abef");
s.insert_str(2, "cd");
assert_eq!(s.as_str(), "abcdef");
}
#[test]
fn test_string_remove_from_middle_preserves_tail() {
let arena = Arena::new();
let mut s = ArenaString::from_str_in("abcde", &arena);
assert_eq!(s.remove(2), 'c');
assert_eq!(s.as_str(), "abde");
}
#[test]
fn test_string_retain_keeps_only_requested_chars() {
let arena = Arena::new();
let mut s = ArenaString::from_str_in("abracadabra", &arena);
s.retain(|ch| ch == 'a');
assert_eq!(s.as_str(), "aaaaa");
}
#[test]
fn test_string_replace_range_longer_grows_and_shifts_tail() {
let arena = Arena::new();
let mut s = arena.alloc_string_with_capacity(5);
s.push_str("abYZ");
s.replace_range(2..2, "1234");
assert_eq!(s.as_str(), "ab1234YZ");
}
#[test]
fn test_string_replace_range_shorter_shifts_tail_left() {
let arena = Arena::new();
let mut s = ArenaString::from_str_in("abcXYZdef", &arena);
s.replace_range(3..6, "Q");
assert_eq!(s.as_str(), "abcQdef");
}
#[test]
fn test_string_shrink_to_fit_reclaims_capacity_and_preserves_contents() {
let arena = Arena::new();
let mut s = arena.alloc_string_with_capacity(16);
s.push_str("hello");
s.shrink_to_fit();
let _follow_on = arena.alloc_str("zzzz");
assert_eq!(s.capacity(), s.len());
assert_eq!(s.as_str(), "hello");
}
#[test]
fn test_string_drop_releases_retired_chunk() {
let alloc = common::TrackingAllocator::new();
{
let arena = Arena::builder().allocator_in(alloc.clone()).build();
let mut s = arena.alloc_string_with_capacity(3500);
s.push_str("hello");
let filler = arena.alloc_slice_copy_rc(std::vec![1_u8; 4000]);
drop(filler);
drop(s);
}
assert_eq!(alloc.live_chunks(), 0);
assert_eq!(alloc.live_bytes(), 0);
}
#[test]
fn test_utf16_string_is_empty_false_when_nonempty() {
let arena = Arena::new();
let s = Utf16String::from_utf16_str_in(utf16str!("alpha"), &arena);
assert!(!s.is_empty());
}
#[test]
fn test_utf16_string_partial_eq_distinguishes_different_values() {
let arena = Arena::new();
let a = Utf16String::from_utf16_str_in(utf16str!("alpha"), &arena);
let b = Utf16String::from_utf16_str_in(utf16str!("beta"), &arena);
let beta = utf16str!("beta");
assert_ne!(a, b);
assert!(a != utf16str!("beta"));
assert!(a != beta);
}
#[test]
fn test_utf16_string_hash_depends_on_contents() {
let arena = Arena::new();
let a = Utf16String::from_utf16_str_in(utf16str!("alpha"), &arena);
let b = Utf16String::from_utf16_str_in(utf16str!("beta"), &arena);
assert_ne!(hash_value(&a), hash_value(&b));
}
#[test]
fn test_utf16_string_as_mut_utf16_str_returns_live_contents() {
let arena = Arena::new();
let mut s = Utf16String::from_utf16_str_in(utf16str!("ab"), &arena);
let view: &mut Utf16Str = s.as_mut_utf16_str();
assert_eq!(view, utf16str!("ab"));
unsafe {
*s.as_mut_ptr() = 'z' as u16;
}
assert_eq!(s.as_utf16_str(), utf16str!("zb"));
}
#[test]
fn test_utf16_string_pop_reduces_length() {
let arena = Arena::new();
let mut s = Utf16String::from_utf16_str_in(utf16str!("ab"), &arena);
assert_eq!(s.pop(), Some('b'));
assert_eq!(s.as_utf16_str(), utf16str!("a"));
}
#[test]
fn test_utf16_string_shrink_to_fit_reclaims_capacity_and_preserves_contents() {
let arena = Arena::new();
let mut s = arena.alloc_utf16_string_with_capacity(10);
s.push_str(utf16str!("hello"));
s.shrink_to_fit();
let _follow_on = arena.alloc_utf16_str_rc(utf16str!("zzzz"));
assert_eq!(s.capacity(), s.len());
assert_eq!(s.as_utf16_str(), utf16str!("hello"));
#[cfg(all(feature = "stats", feature = "utf16"))]
{
let mut s = arena.alloc_utf16_string_with_capacity(128);
s.push_from_str("hi");
let before_chunks = arena.stats().normal_local_chunks_allocated;
s.shrink_to_fit();
let _r: multitude::Rc<u8> = arena.alloc_rc(0);
assert_eq!(arena.stats().normal_local_chunks_allocated, before_chunks);
}
}
#[test]
fn test_utf16_string_insert_middle_preserves_tail() {
let arena = Arena::new();
let mut s = arena.alloc_utf16_string_with_capacity(8);
s.push_str(utf16str!("abef"));
s.insert_utf16_str(2, utf16str!("cd"));
assert_eq!(s.as_utf16_str(), utf16str!("abcdef"));
}
#[test]
fn test_utf16_string_remove_from_middle_preserves_tail() {
let arena = Arena::new();
let mut s = Utf16String::from_utf16_str_in(utf16str!("abcde"), &arena);
assert_eq!(s.remove(2), 'c');
assert_eq!(s.as_utf16_str(), utf16str!("abde"));
}
#[test]
fn test_utf16_string_retain_keeps_only_requested_chars() {
let arena = Arena::new();
let mut s = Utf16String::from_utf16_str_in(utf16str!("abracadabra"), &arena);
s.retain(|ch| ch == 'a');
assert_eq!(s.as_utf16_str(), utf16str!("aaaaa"));
}
#[test]
fn test_utf16_string_replace_range_longer_grows_and_shifts_tail() {
let arena = Arena::new();
let mut s = arena.alloc_utf16_string_with_capacity(4);
s.push_str(utf16str!("abYZ"));
s.replace_range(2..2, utf16str!("1234"));
assert_eq!(s.as_utf16_str(), utf16str!("ab1234YZ"));
}
#[test]
fn test_utf16_string_replace_range_shorter_shifts_tail_left() {
let arena = Arena::new();
let mut s = Utf16String::from_utf16_str_in(utf16str!("abcXYZdef"), &arena);
s.replace_range(3..6, utf16str!("Q"));
assert_eq!(s.as_utf16_str(), utf16str!("abcQdef"));
}
#[test]
fn test_utf16_into_arena_utf16_str_preserves_contents_after_tail_reclaim() {
let arena = Arena::new();
let mut s = arena.alloc_utf16_string_with_capacity(10);
s.push_str(utf16str!("hello"));
let frozen = s.into_arena_utf16_str();
let _follow_on = arena.alloc_utf16_str_rc(utf16str!("zzzz"));
assert_eq!(&*frozen, utf16str!("hello"));
let mut s = arena.alloc_utf16_string_with_capacity(64);
s.push_str(utf16str!("abcd"));
let frozen = s.into_arena_utf16_str();
let frozen_end_addr = frozen.as_ptr() as usize + frozen.len() * core::mem::size_of::<u16>();
let next: multitude::Rc<u32> = arena.alloc_rc(0_u32);
let next_addr = multitude::Rc::as_ptr(&next) as usize;
let gap = next_addr.saturating_sub(frozen_end_addr);
assert!(gap < 120, "gap was {gap} bytes");
}
#[test]
fn test_utf16_string_drop_releases_retired_chunk() {
let alloc = common::TrackingAllocator::new();
{
let arena = Arena::builder().allocator_in(alloc.clone()).build();
let mut s = arena.alloc_utf16_string_with_capacity(1800);
s.push_str(utf16str!("hello"));
let filler = arena.alloc_slice_copy_rc(std::vec![1_u8; 4000]);
drop(filler);
drop(s);
}
assert_eq!(alloc.live_chunks(), 0);
assert_eq!(alloc.live_bytes(), 0);
}
#[test]
fn test_box_str_partial_eq_distinguishes_different_values() {
let arena = Arena::new();
let boxed: BoxStr = arena.alloc_str_box("alpha");
let beta = "beta";
assert!(boxed != "beta");
assert!(boxed != beta);
}
#[test]
fn test_box_utf16_str_partial_eq_distinguishes_different_values() {
let arena = Arena::new();
let boxed: BoxUtf16Str = arena.alloc_utf16_str_box(utf16str!("alpha"));
let beta = utf16str!("beta");
assert!(boxed != utf16str!("beta"));
assert!(boxed != beta);
}
#[test]
fn test_box_utf16_str_drop_releases_chunk_after_arena_drop() {
let alloc = common::TrackingAllocator::new();
let boxed: BoxUtf16Str<_> = {
let arena = Arena::builder().allocator_in(alloc.clone()).build();
arena.alloc_utf16_str_box(utf16str!("hello"))
};
assert_eq!(&*boxed, utf16str!("hello"));
drop(boxed);
assert_eq!(alloc.live_chunks(), 0);
assert_eq!(alloc.live_bytes(), 0);
}
#[test]
fn test_vec_is_empty_false_when_nonempty() {
let arena = Arena::new();
let mut v: ArenaVec<u32, _> = ArenaVec::new_in(&arena);
v.push(1);
assert!(!v.is_empty());
}
#[test]
fn test_vec_from_iter_in_uses_nonzero_size_hint() {
let arena = Arena::new_in(common::FailingAllocator::new(1));
let v = ArenaVec::from_iter_in([1_u32, 2, 3], &arena);
assert_eq!(v.as_slice(), &[1, 2, 3]);
}
#[test]
fn test_vec_insert_middle_preserves_positions() {
let arena = Arena::new();
let mut v = arena.alloc_vec();
v.extend([1_u32, 2, 4, 5]);
v.insert(2, 3);
assert_eq!(v.as_slice(), &[1, 2, 3, 4, 5]);
}
#[test]
fn test_vec_remove_middle_preserves_positions() {
let arena = Arena::new();
let mut v = arena.alloc_vec();
v.extend([1_u32, 2, 3, 4, 5]);
assert_eq!(v.remove(2), 3);
assert_eq!(v.as_slice(), &[1, 2, 4, 5]);
}
#[test]
fn test_vec_truncate_drops_removed_elements() {
let arena = Arena::new();
let drops = StdArc::new(AtomicUsize::new(0));
let mut v = arena.alloc_vec();
for _ in 0..4 {
v.push(DropCounter(StdArc::clone(&drops)));
}
v.truncate(2);
assert_eq!(drops.load(Ordering::Relaxed), 2);
assert_eq!(v.len(), 2);
}
#[test]
fn test_vec_shrink_to_fit_reduces_capacity_and_preserves_values() {
let arena = Arena::new();
let mut v = arena.alloc_vec_with_capacity::<u32>(16);
v.extend(0_u32..5);
v.shrink_to_fit();
let _follow_on = arena.alloc_str("tail");
assert_eq!(v.capacity(), v.len());
assert_eq!(v.as_slice(), &[0, 1, 2, 3, 4]);
}
#[test]
fn test_vec_resize_with_adds_expected_elements() {
let arena = Arena::new();
let mut v = arena.alloc_vec();
v.extend([1_u32, 2]);
let mut next = 10_u32;
v.resize_with(5, || {
let value = next;
next += 1;
value
});
assert_eq!(v.as_slice(), &[1, 2, 10, 11, 12]);
}
#[test]
fn test_vec_into_arena_rc_preserves_values_after_tail_reclaim() {
let arena = Arena::new();
let mut v = arena.alloc_vec_with_capacity::<u32>(16);
v.extend(0_u32..5);
let frozen = v.into_arena_rc();
let _follow_on = arena.alloc_str("tail");
assert_eq!(&*frozen, &[0, 1, 2, 3, 4]);
}
#[test]
fn test_vec_hash_depends_on_contents() {
let arena = Arena::new();
let mut a = arena.alloc_vec();
a.extend([1_u32, 2, 3]);
let mut b = arena.alloc_vec();
b.extend([1_u32, 2, 4]);
assert_ne!(hash_value(&a), hash_value(&b));
}
#[test]
fn test_vec_drop_runs_element_drops() {
let drops = StdArc::new(AtomicUsize::new(0));
{
let arena = Arena::new();
let mut v = arena.alloc_vec();
for _ in 0..3 {
v.push(DropCounter(StdArc::clone(&drops)));
}
}
assert_eq!(drops.load(Ordering::Relaxed), 3);
}
#[test]
fn test_vec_drop_deallocates_retired_buffer() {
let alloc = common::TrackingAllocator::new();
{
let arena = Arena::builder().allocator_in(alloc.clone()).build();
let mut v = arena.alloc_vec_with_capacity::<u64>(512);
v.extend(0_u64..4);
let filler = arena.alloc_slice_copy_rc(std::vec![1_u8; 4000]);
drop(filler);
drop(v);
}
assert_eq!(alloc.live_chunks(), 0);
assert_eq!(alloc.live_bytes(), 0);
}
#[test]
fn test_vec_drain_size_hint_tracks_remaining_items() {
let arena = Arena::new();
let mut v = arena.alloc_vec();
v.extend(0_u32..6);
{
let mut drain = v.drain(1..5);
assert_eq!(drain.size_hint(), (4, Some(4)));
assert_eq!(drain.len(), 4);
assert_eq!(drain.next(), Some(1));
assert_eq!(drain.size_hint(), (3, Some(3)));
assert_eq!(drain.next_back(), Some(4));
assert_eq!(drain.size_hint(), (2, Some(2)));
}
assert_eq!(v.as_slice(), &[0, 5]);
}
#[test]
fn test_vec_drain_drop_moves_tail_after_partial_iteration() {
let arena = Arena::new();
let mut v = arena.alloc_vec();
v.extend(0_u32..6);
{
let mut drain = v.drain(1..4);
assert_eq!(drain.next(), Some(1));
}
assert_eq!(v.as_slice(), &[0, 4, 5]);
}
#[test]
fn test_arena_alloc_str_keeps_pinned_chunk_alive_across_rotation() {
let arena = ArenaBuilder::new().build();
let s: &mut str = arena.alloc_str("hello");
let a = arena.alloc_slice_copy(std::vec![1_u8; 4000]);
let b = arena.alloc_slice_copy(std::vec![2_u8; 4000]);
assert_eq!(a.len(), 4000);
assert_eq!(b.len(), 4000);
s.make_ascii_uppercase();
assert_eq!(s, "HELLO");
}
#[cfg(feature = "stats")]
#[test]
fn test_arena_slice_fill_with_rc_initializes_items_and_charges_stats() {
let arena = Arena::new();
let before = arena.stats().total_bytes_allocated;
let slice = arena.alloc_slice_fill_with_rc(5, |i| u32::try_from(i).unwrap() * 2);
assert_eq!(&*slice, &[0, 2, 4, 6, 8]);
assert_eq!(arena.stats().total_bytes_allocated, before + (5 * size_of::<u32>()) as u64);
}
#[cfg(feature = "stats")]
#[test]
fn test_oversized_slice_copy_rc_survives_arena_drop() {
let rc = {
let arena = Arena::new();
let rc = arena.alloc_slice_copy_rc(std::vec![7_u8; 32 * 1024]);
assert!(arena.stats().oversized_local_chunks_allocated >= 1);
rc
};
assert_eq!(rc.len(), 32 * 1024);
assert_eq!(rc[0], 7);
assert_eq!(rc[rc.len() - 1], 7);
}
#[cfg(feature = "stats")]
#[test]
fn test_vec_into_arena_rc_slow_path_oversized_survives_arena_drop() {
struct NeedsDrop(u16);
impl Drop for NeedsDrop {
fn drop(&mut self) {
let _ = self.0;
}
}
let rc = {
let arena = Arena::new();
let mut v = arena.alloc_vec_with_capacity::<NeedsDrop>(20_000);
for i in 0..17_000_u16 {
v.push(NeedsDrop(i % 251));
}
let before = arena.stats().oversized_local_chunks_allocated;
let rc = v.into_arena_rc();
assert!(arena.stats().oversized_local_chunks_allocated > before);
rc
};
assert_eq!(rc.len(), 17_000);
assert_eq!(rc[123].0, 123);
assert_eq!(rc[16_000].0, (16_000 % 251) as u16);
}
#[cfg(feature = "stats")]
#[test]
fn test_arena_builder_default_max_normal_alloc_is_chunk_size_div_4() {
let arena = ArenaBuilder::new().build();
let _ = arena.alloc_slice_copy_rc(std::vec![0_u8; 5 * 1024]);
assert_eq!(arena.stats().oversized_local_chunks_allocated, 0);
}
#[test]
fn test_rc_drop_after_arena_drop_frees_chunk_instead_of_caching_it() {
let alloc = common::TrackingAllocator::new();
let rc = {
let arena = Arena::builder().allocator_in(alloc.clone()).build();
arena.alloc_rc(std::string::String::from("persist"))
};
assert_eq!(&*rc, "persist");
drop(rc);
assert_eq!(alloc.live_chunks(), 0);
assert_eq!(alloc.live_bytes(), 0);
}
#[cfg(feature = "stats")]
#[test]
fn test_aligned_drop_allocation_is_correctly_aligned_and_not_oversized() {
#[repr(align(256))]
struct HighAlignDrop(u8);
impl Drop for HighAlignDrop {
fn drop(&mut self) {
let _ = self.0;
}
}
let arena = Arena::builder().build();
let value = arena.alloc_rc(HighAlignDrop(1));
let ptr = (&raw const *value) as usize;
assert_eq!(ptr % 256, 0);
assert_eq!(arena.stats().oversized_local_chunks_allocated, 0);
}
#[cfg(feature = "stats")]
#[test]
fn test_vec_reserve_grows_in_place_without_relocation() {
let arena = Arena::new();
let mut v = arena.alloc_vec_with_capacity::<u32>(4);
v.extend([1_u32, 2, 3, 4]);
let before = arena.stats().relocations;
v.reserve(8);
assert_eq!(arena.stats().relocations, before);
assert_eq!(v.as_slice(), &[1, 2, 3, 4]);
}
#[test]
fn test_cache_overflow_rejected_chunk_is_freed() {
let alloc = common::TrackingAllocator::new();
{
let arena = Arena::builder().allocator_in(alloc.clone()).build();
let a = arena.alloc_slice_copy_rc(std::vec![1_u8; 4000]);
let b = arena.alloc_slice_copy_rc(std::vec![2_u8; 4000]);
let c = arena.alloc_slice_copy_rc(std::vec![3_u8; 4000]);
drop(a);
drop(b);
drop(c);
}
assert_eq!(alloc.live_chunks(), 0);
assert_eq!(alloc.live_bytes(), 0);
}
#[test]
fn test_arena_drop_clears_current_chunk_slots() {
let alloc = common::TrackingAllocator::new();
{
let arena = Arena::builder().allocator_in(alloc.clone()).build();
let value = arena.alloc(123_u64);
assert_eq!(*value, 123);
}
assert_eq!(alloc.live_chunks(), 0);
assert_eq!(alloc.live_bytes(), 0);
}
#[test]
fn test_box_str_partial_eq_str_returns_false_for_mismatch() {
let arena = Arena::new();
let boxed: BoxStr = arena.alloc_str_box("alpha");
assert!(!<BoxStr as PartialEq<str>>::eq(&boxed, "beta"));
}
#[test]
fn test_box_utf16_str_partial_eq_utf16str_returns_false_for_mismatch() {
let arena = Arena::new();
let boxed: BoxUtf16Str = arena.alloc_utf16_str_box(utf16str!("alpha"));
assert!(!<BoxUtf16Str as PartialEq<Utf16Str>>::eq(&boxed, utf16str!("beta")));
}
#[test]
fn test_string_partial_eq_str_returns_false_for_mismatch() {
let arena = Arena::new();
let s = ArenaString::from_str_in("alpha", &arena);
assert!(!<ArenaString as PartialEq<str>>::eq(&s, "beta"));
}
#[test]
fn test_utf16_string_partial_eq_utf16str_returns_false_for_mismatch() {
let arena = Arena::new();
let s = Utf16String::from_utf16_str_in(utf16str!("alpha"), &arena);
assert!(!<Utf16String as PartialEq<Utf16Str>>::eq(&s, utf16str!("beta")));
}
#[test]
fn test_vec_try_with_capacity_in_zero_does_not_allocate() {
let arena = Arena::new();
let v = ArenaVec::<u32>::try_with_capacity_in(0, &arena).unwrap();
assert_eq!(v.capacity(), 0);
assert_eq!(v.len(), 0);
}
#[test]
fn test_vec_try_reserve_at_exact_boundary_does_not_grow() {
let arena = Arena::new();
let mut v = ArenaVec::<u32>::try_with_capacity_in(8, &arena).unwrap();
v.push(1);
v.push(2);
let cap_before = v.capacity();
v.try_reserve(6).unwrap(); assert_eq!(v.capacity(), cap_before);
}
#[test]
fn test_vec_from_iter_in_with_zero_size_hint() {
let arena = Arena::new();
let iter = std::iter::from_fn({
let mut i = 0_u32;
move || {
(i < 3).then(|| {
i += 1;
i
})
}
});
let v = ArenaVec::from_iter_in(iter, &arena);
assert_eq!(v.as_slice(), &[1, 2, 3]);
}
#[test]
fn test_vec_insert_at_start_shifts_all() {
let arena = Arena::new();
let mut v = arena.alloc_vec();
v.extend([2_u32, 3, 4, 5]);
v.insert(0, 1);
assert_eq!(v.as_slice(), &[1, 2, 3, 4, 5]);
}
#[test]
fn test_vec_remove_at_start_shifts_all() {
let arena = Arena::new();
let mut v = arena.alloc_vec();
v.extend([1_u32, 2, 3, 4, 5]);
assert_eq!(v.remove(0), 1);
assert_eq!(v.as_slice(), &[2, 3, 4, 5]);
}
#[test]
fn test_vec_remove_second_to_last_shifts_one() {
let arena = Arena::new();
let mut v = arena.alloc_vec();
v.extend([1_u32, 2, 3]);
assert_eq!(v.remove(1), 2);
assert_eq!(v.as_slice(), &[1, 3]);
}
#[test]
fn test_vec_truncate_to_zero_drops_all() {
let arena = Arena::new();
let drops = StdArc::new(AtomicUsize::new(0));
let mut v = arena.alloc_vec();
for _ in 0..5 {
v.push(DropCounter(StdArc::clone(&drops)));
}
v.truncate(0);
assert_eq!(drops.load(Ordering::Relaxed), 5);
assert_eq!(v.len(), 0);
}
#[test]
fn test_vec_truncate_to_one_drops_rest() {
let arena = Arena::new();
let drops = StdArc::new(AtomicUsize::new(0));
let mut v = arena.alloc_vec();
for _ in 0..3 {
v.push(DropCounter(StdArc::clone(&drops)));
}
v.truncate(1);
assert_eq!(drops.load(Ordering::Relaxed), 2);
assert_eq!(v.len(), 1);
}
#[test]
fn test_vec_shrink_to_fit_zst_is_noop() {
let arena = Arena::new();
let mut v: ArenaVec<()> = arena.alloc_vec();
v.push(());
v.push(());
let cap_before = v.capacity();
v.shrink_to_fit();
assert_eq!(v.capacity(), cap_before);
assert_eq!(v.len(), 2);
}
#[test]
fn test_vec_try_reserve_exact_at_boundary_does_not_grow() {
let arena = Arena::new();
let mut v = ArenaVec::<u32>::try_with_capacity_in(8, &arena).unwrap();
v.push(1);
v.push(2);
let cap_before = v.capacity();
v.try_reserve_exact(6).unwrap();
assert_eq!(v.capacity(), cap_before);
}
#[test]
fn test_vec_resize_with_same_len_is_noop() {
let arena = Arena::new();
let mut v = arena.alloc_vec();
v.extend([1_u32, 2, 3]);
let cap_before = v.capacity();
v.resize_with(3, || panic!("should not be called"));
assert_eq!(v.as_slice(), &[1, 2, 3]);
assert_eq!(v.capacity(), cap_before);
}
#[test]
fn test_vec_into_arena_rc_empty_with_capacity() {
let arena = Arena::new();
let v = arena.alloc_vec_with_capacity::<u32>(16);
let frozen = v.into_arena_rc();
assert!(frozen.is_empty());
}
#[test]
fn test_vec_extend_empty_iterator() {
let arena = Arena::new();
let mut v = arena.alloc_vec();
v.extend([1_u32, 2, 3]);
let cap_before = v.capacity();
v.extend(std::iter::empty::<u32>());
assert_eq!(v.as_slice(), &[1, 2, 3]);
assert_eq!(v.capacity(), cap_before);
}
#[test]
fn test_vec_extend_ref_empty_iterator() {
let arena = Arena::new();
let mut v = arena.alloc_vec();
v.extend([1_u32, 2, 3]);
let cap_before = v.capacity();
let empty: &[u32] = &[];
v.extend(empty.iter());
assert_eq!(v.as_slice(), &[1, 2, 3]);
assert_eq!(v.capacity(), cap_before);
}
#[test]
fn test_vec_drain_all_elements_no_tail() {
let arena = Arena::new();
let mut v = arena.alloc_vec();
v.extend([1_u32, 2, 3]);
{
let drained: std::vec::Vec<_> = v.drain(0..3).collect();
assert_eq!(drained, vec![1, 2, 3]);
}
assert!(v.is_empty());
}
#[test]
fn test_vec_drain_suffix_no_tail() {
let arena = Arena::new();
let mut v = arena.alloc_vec();
v.extend([1_u32, 2, 3, 4]);
{
let drained: std::vec::Vec<_> = v.drain(2..4).collect();
assert_eq!(drained, vec![3, 4]);
}
assert_eq!(v.as_slice(), &[1, 2]);
}
#[test]
fn test_string_shrink_to_fit_cap_equals_len_is_noop() {
let arena = Arena::new();
let mut s = ArenaString::from_str_in("hello", &arena);
s.shrink_to_fit();
let cap_after_first = s.capacity();
s.shrink_to_fit();
assert_eq!(s.capacity(), cap_after_first);
assert_eq!(s.as_str(), "hello");
}
#[test]
fn test_string_shrink_to_fit_cap_zero_is_noop() {
let arena = Arena::new();
let s = arena.alloc_string_with_capacity(0);
assert_eq!(s.capacity(), 0);
let mut s2: ArenaString = ArenaString::new_in(&arena);
s2.shrink_to_fit(); assert_eq!(s2.len(), 0);
}
#[test]
fn test_string_insert_str_at_start_shifts_all() {
let arena = Arena::new();
let mut s = ArenaString::from_str_in("world", &arena);
s.insert_str(0, "hello ");
assert_eq!(s.as_str(), "hello world");
}
#[test]
fn test_string_insert_str_at_exact_capacity_boundary() {
let arena = Arena::new();
let mut s = arena.alloc_string_with_capacity(5);
s.push_str("hello");
assert_eq!(s.capacity(), 5);
s.insert_str(5, "!");
assert_eq!(s.as_str(), "hello!");
assert!(s.capacity() >= 6);
}
#[test]
fn test_string_remove_first_char_shifts_all() {
let arena = Arena::new();
let mut s = ArenaString::from_str_in("abcde", &arena);
assert_eq!(s.remove(0), 'a');
assert_eq!(s.as_str(), "bcde");
}
#[test]
fn test_string_remove_multibyte_char() {
let arena = Arena::new();
let mut s = ArenaString::from_str_in("aéc", &arena);
assert_eq!(s.remove(1), 'é');
assert_eq!(s.as_str(), "ac");
}
#[test]
fn test_string_retain_removes_alternating() {
let arena = Arena::new();
let mut s = ArenaString::from_str_in("abcdef", &arena);
let mut toggle = false;
s.retain(|_| {
toggle = !toggle;
toggle
});
assert_eq!(s.as_str(), "ace");
}
#[test]
fn test_string_retain_removes_none() {
let arena = Arena::new();
let mut s = ArenaString::from_str_in("abc", &arena);
s.retain(|_| true);
assert_eq!(s.as_str(), "abc");
}
#[test]
fn test_string_retain_removes_all() {
let arena = Arena::new();
let mut s = ArenaString::from_str_in("abc", &arena);
s.retain(|_| false);
assert_eq!(s.as_str(), "");
}
#[test]
fn test_string_replace_range_grow_at_exact_capacity() {
let arena = Arena::new();
let mut s = arena.alloc_string_with_capacity(6);
s.push_str("abcdef");
s.replace_range(2..4, "1234");
assert_eq!(s.as_str(), "ab1234ef");
}
#[test]
fn test_string_replace_range_shrink_by_exact_amount() {
let arena = Arena::new();
let mut s = ArenaString::from_str_in("abcdef", &arena);
s.replace_range(1..5, "X");
assert_eq!(s.as_str(), "aXf");
}
#[test]
fn test_string_replace_range_same_size() {
let arena = Arena::new();
let mut s = ArenaString::from_str_in("abcdef", &arena);
s.replace_range(2..4, "CD");
assert_eq!(s.as_str(), "abCDef");
}
#[test]
fn test_string_replace_range_shrink_at_end() {
let arena = Arena::new();
let mut s = ArenaString::from_str_in("abcdef", &arena);
s.replace_range(4..6, "");
assert_eq!(s.as_str(), "abcd");
}
#[test]
fn test_string_try_push_str_at_exact_capacity() {
let arena = Arena::new();
let mut s = arena.alloc_string_with_capacity(5);
s.push_str("hello");
let cap_before = s.capacity();
s.try_push_str("!").unwrap();
assert_eq!(s.as_str(), "hello!");
assert!(s.capacity() > cap_before);
}
#[test]
fn test_string_try_push_str_within_capacity() {
let arena = Arena::new();
let mut s = arena.alloc_string_with_capacity(10);
s.push_str("hello");
let cap_before = s.capacity();
s.try_push_str("!").unwrap();
assert_eq!(s.as_str(), "hello!");
assert_eq!(s.capacity(), cap_before); }
#[test]
fn test_string_reserve_at_exact_boundary_does_not_grow() {
let arena = Arena::new();
let mut s = arena.alloc_string_with_capacity(10);
s.push_str("hello"); let cap_before = s.capacity();
s.reserve(5); assert_eq!(s.capacity(), cap_before);
}
#[test]
fn test_string_try_reserve_at_exact_boundary_does_not_grow() {
let arena = Arena::new();
let mut s = arena.alloc_string_with_capacity(10);
s.push_str("hello"); let cap_before = s.capacity();
s.try_reserve(5).unwrap(); assert_eq!(s.capacity(), cap_before);
}
#[test]
fn test_string_extend_empty_chars() {
let arena = Arena::new();
let mut s = ArenaString::from_str_in("hello", &arena);
let cap_before = s.capacity();
s.extend(std::iter::empty::<char>());
assert_eq!(s.as_str(), "hello");
assert_eq!(s.capacity(), cap_before);
}
#[test]
fn test_utf16_string_shrink_to_fit_cap_equals_len_is_noop() {
let arena = Arena::new();
let mut s = Utf16String::from_utf16_str_in(utf16str!("hello"), &arena);
s.shrink_to_fit();
let cap_after_first = s.capacity();
s.shrink_to_fit();
assert_eq!(s.capacity(), cap_after_first);
assert_eq!(s.as_utf16_str(), utf16str!("hello"));
}
#[test]
fn test_utf16_string_shrink_to_fit_cap_zero_is_noop() {
let arena = Arena::new();
let mut s = Utf16String::new_in(&arena);
s.shrink_to_fit();
assert_eq!(s.len(), 0);
}
#[test]
fn test_utf16_string_insert_at_start_shifts_all() {
let arena = Arena::new();
let mut s = Utf16String::from_utf16_str_in(utf16str!("world"), &arena);
s.insert_utf16_str(0, utf16str!("hello "));
assert_eq!(s.as_utf16_str(), utf16str!("hello world"));
}
#[test]
fn test_utf16_string_insert_at_exact_capacity_boundary() {
let arena = Arena::new();
let mut s = arena.alloc_utf16_string_with_capacity(5);
s.push_str(utf16str!("hello"));
assert_eq!(s.capacity(), 5);
s.insert_utf16_str(5, utf16str!("!"));
assert_eq!(s.as_utf16_str(), utf16str!("hello!"));
}
#[test]
fn test_utf16_string_remove_first_shifts_all() {
let arena = Arena::new();
let mut s = Utf16String::from_utf16_str_in(utf16str!("abcde"), &arena);
assert_eq!(s.remove(0), 'a');
assert_eq!(s.as_utf16_str(), utf16str!("bcde"));
}
#[test]
fn test_utf16_string_retain_removes_alternating() {
let arena = Arena::new();
let mut s = Utf16String::from_utf16_str_in(utf16str!("abcdef"), &arena);
let mut toggle = false;
s.retain(|_| {
toggle = !toggle;
toggle
});
assert_eq!(s.as_utf16_str(), utf16str!("ace"));
}
#[test]
fn test_utf16_string_retain_removes_all() {
let arena = Arena::new();
let mut s = Utf16String::from_utf16_str_in(utf16str!("abc"), &arena);
s.retain(|_| false);
assert!(s.is_empty());
}
#[test]
fn test_utf16_string_retain_removes_none() {
let arena = Arena::new();
let mut s = Utf16String::from_utf16_str_in(utf16str!("abc"), &arena);
s.retain(|_| true);
assert_eq!(s.as_utf16_str(), utf16str!("abc"));
}
#[test]
fn test_utf16_string_replace_range_grow_at_exact_capacity() {
let arena = Arena::new();
let mut s = arena.alloc_utf16_string_with_capacity(6);
s.push_str(utf16str!("abcdef"));
s.replace_range(2..4, utf16str!("1234"));
assert_eq!(s.as_utf16_str(), utf16str!("ab1234ef"));
}
#[test]
fn test_utf16_string_replace_range_shrink_exact() {
let arena = Arena::new();
let mut s = Utf16String::from_utf16_str_in(utf16str!("abcdef"), &arena);
s.replace_range(1..5, utf16str!("X"));
assert_eq!(s.as_utf16_str(), utf16str!("aXf"));
}
#[test]
fn test_utf16_string_replace_range_same_size() {
let arena = Arena::new();
let mut s = Utf16String::from_utf16_str_in(utf16str!("abcdef"), &arena);
s.replace_range(2..4, utf16str!("CD"));
assert_eq!(s.as_utf16_str(), utf16str!("abCDef"));
}
#[test]
fn test_utf16_string_replace_range_shrink_at_end() {
let arena = Arena::new();
let mut s = Utf16String::from_utf16_str_in(utf16str!("abcdef"), &arena);
s.replace_range(4..6, utf16str!(""));
assert_eq!(s.as_utf16_str(), utf16str!("abcd"));
}
#[test]
fn test_utf16_string_try_push_from_str_at_capacity() {
let arena = Arena::new();
let mut s = arena.alloc_utf16_string_with_capacity(5);
s.push_str(utf16str!("hello"));
let cap_before = s.capacity();
s.try_push_from_str("!").unwrap();
assert!(s.capacity() > cap_before);
}
#[test]
fn test_utf16_string_try_push_slice_at_capacity() {
let arena = Arena::new();
let mut s = arena.alloc_utf16_string_with_capacity(5);
s.push_str(utf16str!("hello"));
let cap_before = s.capacity();
s.try_push_str(utf16str!("!")).unwrap();
assert!(s.capacity() > cap_before);
}
#[test]
fn test_utf16_string_try_push_slice_within_capacity() {
let arena = Arena::new();
let mut s = arena.alloc_utf16_string_with_capacity(10);
s.push_str(utf16str!("hello"));
let cap_before = s.capacity();
s.try_push_str(utf16str!("!")).unwrap();
assert_eq!(s.capacity(), cap_before);
}
#[test]
fn test_utf16_string_reserve_at_exact_boundary() {
let arena = Arena::new();
let mut s = arena.alloc_utf16_string_with_capacity(10);
s.push_str(utf16str!("hello")); let cap_before = s.capacity();
s.reserve(5); assert_eq!(s.capacity(), cap_before);
}
#[test]
fn test_utf16_string_extend_empty_chars() {
let arena = Arena::new();
let mut s = Utf16String::from_utf16_str_in(utf16str!("hello"), &arena);
let cap_before = s.capacity();
s.extend(std::iter::empty::<char>());
assert_eq!(s.as_utf16_str(), utf16str!("hello"));
assert_eq!(s.capacity(), cap_before);
}
#[test]
fn test_arena_builder_max_normal_alloc_at_exact_min_succeeds() {
let result = ArenaBuilder::new().max_normal_alloc(4096).try_build();
result.unwrap();
}
#[test]
#[should_panic(expected = "max_normal_alloc must be in")]
fn test_arena_builder_max_normal_alloc_below_min_fails() {
let _ = ArenaBuilder::new().max_normal_alloc(4095).try_build();
}
#[test]
fn test_slice_fill_with_panic_drops_initialized_elements() {
let drops = StdArc::new(AtomicUsize::new(0));
let arena = Arena::new();
let result = catch_unwind(std::panic::AssertUnwindSafe(|| {
let drops_clone = StdArc::clone(&drops);
let _ = arena.alloc_slice_fill_with(5, |i| {
assert!(i != 3, "intentional panic at index 3");
DropCounter(StdArc::clone(&drops_clone))
});
}));
assert!(result.is_err());
assert_eq!(drops.load(Ordering::Relaxed), 3);
}
}
mod utf16_tests {
use multitude::Arena;
#[test]
fn utf16_191_truncate_to_zero() {
let arena = Arena::new();
let mut s = arena.alloc_utf16_string_with_capacity(10);
s.push('A');
s.push('B');
s.truncate(0);
assert_eq!(s.len(), 0);
}
#[test]
fn utf16_191_truncate_boundary() {
let arena = Arena::new();
let mut s = arena.alloc_utf16_string_with_capacity(10);
s.push('A'); s.push('B'); s.push('C'); assert_eq!(s.len(), 3);
s.truncate(1); assert_eq!(s.len(), 1);
}
#[test]
fn utf16_203_shrink_to_fit_or_to_and() {
let arena = Arena::new();
let mut s = arena.alloc_utf16_string_with_capacity(5);
s.push('A');
s.push('B');
s.push('C');
s.push('D');
s.push('E');
assert_eq!(s.len(), 5);
s.shrink_to_fit();
assert_eq!(s.len(), 5);
let s2 = arena.alloc_utf16_string_with_capacity(0);
assert_eq!(s2.len(), 0);
}
#[test]
fn utf16_206_shrink_reclaim_units() {
let arena = Arena::new();
let mut s = arena.alloc_utf16_string_with_capacity(20);
s.push('A');
s.push('B');
s.shrink_to_fit();
}
#[test]
fn utf16_207_shrink_reclaim_bytes() {
let arena = Arena::new();
let mut s = arena.alloc_utf16_string_with_capacity(50);
for _ in 0..5 {
s.push('X');
}
s.shrink_to_fit();
assert_eq!(s.len(), 5);
}
#[test]
fn utf16_260_push_from_str_boundary() {
let arena = Arena::new();
let mut s = arena.alloc_utf16_string_with_capacity(5);
s.try_push_from_str("A").unwrap();
s.try_push_from_str("B").unwrap();
s.try_push_from_str("C").unwrap();
s.try_push_from_str("D").unwrap();
s.try_push_from_str("E").unwrap();
assert_eq!(s.len(), 5);
s.try_push_from_str("F").unwrap();
assert_eq!(s.len(), 6);
}
#[test]
fn utf16_277_push_slice_boundary() {
let arena = Arena::new();
let mut s = arena.alloc_utf16_string_with_capacity(3);
s.push('A');
s.push('B');
s.push('C');
assert_eq!(s.len(), 3); s.push('D');
assert_eq!(s.len(), 4);
}
#[test]
fn utf16_298_try_reserve_boundary() {
let arena = Arena::new();
let mut s = arena.alloc_utf16_string_with_capacity(10);
s.push('A'); let cap_before = s.capacity();
s.try_reserve(9).unwrap(); assert_eq!(s.capacity(), cap_before);
s.try_reserve(10).unwrap(); }
#[test]
fn utf16_318_330_insert_slice() {
let arena = Arena::new();
let mut s = arena.alloc_utf16_string_with_capacity(5);
s.push('A');
s.push('B');
s.push('C');
s.insert(3, 'D');
assert_eq!(s.len(), 4);
s.insert(0, 'Z');
assert_eq!(s.len(), 5);
s.insert(2, 'X');
assert_eq!(s.len(), 6);
}
#[test]
fn utf16_337_insert_copy_length() {
let arena = Arena::new();
let mut s = arena.alloc_utf16_string_with_capacity(20);
s.push('A');
s.push('B');
s.push('C');
s.push('D');
s.push('E');
s.insert(2, 'X');
let slice = s.as_slice();
assert_eq!(slice[0], 'A' as u16);
assert_eq!(slice[1], 'B' as u16);
assert_eq!(slice[2], 'X' as u16);
assert_eq!(slice[3], 'C' as u16);
assert_eq!(slice[4], 'D' as u16);
assert_eq!(slice[5], 'E' as u16);
}
#[test]
fn utf16_356_remove_shift() {
let arena = Arena::new();
let mut s = arena.alloc_utf16_string_with_capacity(20);
s.push('A');
s.push('B');
s.push('C');
s.push('D');
s.push('E');
let ch = s.remove(2);
assert_eq!(ch, 'C');
assert_eq!(s.len(), 4);
let slice = s.as_slice();
assert_eq!(slice[0], 'A' as u16);
assert_eq!(slice[1], 'B' as u16);
assert_eq!(slice[2], 'D' as u16);
assert_eq!(slice[3], 'E' as u16);
}
#[test]
fn utf16_396_replace_range_start_boundary() {
let arena = Arena::new();
let mut s = arena.alloc_utf16_string_with_capacity(20);
s.push('A');
s.push('B');
s.push('C');
s.push('D');
let replacement = widestring::utf16str!("XY");
s.replace_range(0..1, replacement);
assert_eq!(s.len(), 5); let empty = widestring::utf16str!("");
s.replace_range(5..5, empty);
assert_eq!(s.len(), 5);
}
#[test]
fn utf16_403_replace_range_end_boundary() {
let arena = Arena::new();
let mut s = arena.alloc_utf16_string_with_capacity(20);
s.push('A');
s.push('B');
s.push('C');
let empty = widestring::utf16str!("");
s.replace_range(0..0, empty);
assert_eq!(s.len(), 3);
let x = widestring::utf16str!("Z");
s.replace_range(2..3, x);
assert_eq!(s.len(), 3);
}
#[test]
fn utf16_418_replace_range_grow_boundary() {
let arena = Arena::new();
let mut s = arena.alloc_utf16_string_with_capacity(5);
s.push('A');
s.push('B');
s.push('C');
s.push('D');
s.push('E');
let x = widestring::utf16str!("X");
s.replace_range(2..3, x);
assert_eq!(s.len(), 5);
assert_eq!(s.as_slice()[2], 'X' as u16);
}
#[test]
fn utf16_424_replace_range_copy() {
let arena = Arena::new();
let mut s = arena.alloc_utf16_string_with_capacity(20);
s.push('A');
s.push('B');
s.push('C');
s.push('D');
s.push('E');
let xyz = widestring::utf16str!("XYZ");
s.replace_range(1..3, xyz);
assert_eq!(s.len(), 6); let slice = s.as_slice();
assert_eq!(slice[0], 'A' as u16);
assert_eq!(slice[1], 'X' as u16);
assert_eq!(slice[2], 'Y' as u16);
assert_eq!(slice[3], 'Z' as u16);
assert_eq!(slice[4], 'D' as u16);
assert_eq!(slice[5], 'E' as u16);
}
#[test]
fn utf16_491_reclaim_tail() {
let arena = Arena::new();
let mut s = arena.alloc_utf16_string_with_capacity(100);
s.push('A');
s.push('B');
let _frozen = s.into_arena_utf16_str();
let _v = arena.alloc(42u64);
}
}
mod utf16_round2 {
use multitude::Arena;
#[test]
fn utf16_337_insert_copy_oob() {
let arena = Arena::new();
let mut s = arena.alloc_utf16_string_with_capacity(20);
for ch in "ABCDEFGHIJ".chars() {
s.push(ch);
}
assert_eq!(s.len(), 10);
s.insert(3, 'X');
assert_eq!(s.len(), 11);
let slice = s.as_slice();
assert_eq!(slice[0], 'A' as u16);
assert_eq!(slice[1], 'B' as u16);
assert_eq!(slice[2], 'C' as u16);
assert_eq!(slice[3], 'X' as u16);
assert_eq!(slice[4], 'D' as u16);
assert_eq!(slice[5], 'E' as u16);
assert_eq!(slice[6], 'F' as u16);
assert_eq!(slice[7], 'G' as u16);
assert_eq!(slice[8], 'H' as u16);
assert_eq!(slice[9], 'I' as u16);
assert_eq!(slice[10], 'J' as u16);
}
#[test]
fn utf16_356_remove_long_string() {
let arena = Arena::new();
let mut s = arena.alloc_utf16_string_with_capacity(20);
for ch in "ABCDEFGHIJ".chars() {
s.push(ch);
}
assert_eq!(s.len(), 10);
let removed = s.remove(2);
assert_eq!(removed, 'C');
assert_eq!(s.len(), 9);
let expected = [
'A' as u16, 'B' as u16, 'D' as u16, 'E' as u16, 'F' as u16, 'G' as u16, 'H' as u16, 'I' as u16, 'J' as u16,
];
assert_eq!(s.as_slice(), &expected);
}
#[test]
fn utf16_403_end_boundary_mid_string() {
let arena = Arena::new();
let mut s = arena.alloc_utf16_string_with_capacity(20);
s.push('A');
s.push('😀');
s.push('B');
assert_eq!(s.len(), 4);
let replacement = widestring::utf16str!("X");
s.replace_range(3..4, replacement); assert_eq!(s.len(), 4);
assert_eq!(s.as_slice()[3], 'X' as u16);
}
#[test]
fn utf16_403_end_zero() {
let arena = Arena::new();
let mut s = arena.alloc_utf16_string_with_capacity(10);
s.push('A');
s.push('B');
let empty = widestring::utf16str!("");
s.replace_range(0..0, empty);
assert_eq!(s.len(), 2);
}
#[test]
fn utf16_403_27_end_surrogate_check() {
let arena = Arena::new();
let mut s = arena.alloc_utf16_string_with_capacity(20);
s.push('A');
s.push('😀');
s.push('B');
let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
let x = widestring::utf16str!("");
s.replace_range(0..2, x);
}));
assert!(result.is_err(), "replace_range ending at low surrogate must panic");
}
#[test]
fn utf16_424_replace_range_tail_copy() {
let arena = Arena::new();
let mut s = arena.alloc_utf16_string_with_capacity(20);
for ch in "ABCDEFGHIJ".chars() {
s.push(ch);
}
let xy = widestring::utf16str!("XY");
s.replace_range(2..5, xy);
assert_eq!(s.len(), 9); let expected = [
'A' as u16, 'B' as u16, 'X' as u16, 'Y' as u16, 'F' as u16, 'G' as u16, 'H' as u16, 'I' as u16, 'J' as u16,
];
assert_eq!(s.as_slice(), &expected);
}
#[test]
fn utf16_491_reclaim_tail_v2() {
let arena = Arena::new();
let mut s = arena.alloc_utf16_string_with_capacity(100);
s.push('A');
s.push('B');
let _frozen = s.into_arena_utf16_str();
let mut s2 = arena.alloc_utf16_string_with_capacity(50);
s2.push('X');
let _frozen2 = s2.into_arena_utf16_str();
}
#[test]
fn utf16_206_shrink_reclaim_v2() {
let arena = Arena::new();
let mut s = arena.alloc_utf16_string_with_capacity(20);
s.push('A');
s.push('B');
s.shrink_to_fit();
assert_eq!(s.len(), 2);
assert_eq!(s.as_slice()[0], 'A' as u16);
}
#[test]
fn utf16_207_shrink_bytes_v2() {
let arena = Arena::new();
let mut s = arena.alloc_utf16_string_with_capacity(100);
for _ in 0..10 {
s.push('X');
}
s.shrink_to_fit();
assert_eq!(s.len(), 10);
}
}
mod from_coverage_extras_utf16 {
#![allow(clippy::items_after_statements, reason = "relocated tests put inner types near use")]
#![allow(clippy::clone_on_ref_ptr, reason = "relocated tests use .clone() on Arc/Rc")]
#![allow(dead_code, reason = "relocated helpers retain fields for layout")]
#![allow(
unfulfilled_lint_expectations,
reason = "relocated #[expect] may be fulfilled at file or feature level"
)]
#![allow(
clippy::undocumented_unsafe_blocks,
reason = "relocated test bodies preserve original safety reasoning"
)]
#![allow(clippy::multiple_unsafe_ops_per_block, reason = "relocated tests group related unsafe ops")]
#![allow(clippy::cast_possible_truncation, reason = "relocated tests use bounded values")]
#![allow(clippy::cast_sign_loss, reason = "relocated tests use non-negative values")]
#![allow(clippy::empty_drop, reason = "relocated tests use empty Drop impls to mark dropability")]
#![allow(clippy::assertions_on_result_states, reason = "relocated tests deliberately assert error returns")]
#![allow(clippy::empty_line_after_doc_comments, reason = "relocated test doc-comments")]
use multitude::strings::Utf16String;
use multitude::vec::FromIteratorIn;
use multitude::{Arena, ArenaBuilder};
use widestring::utf16str;
#[expect(unused_imports, reason = "relocated tests may reference common helpers")]
use crate::common::{self, FailingAllocator};
#[test]
#[should_panic(expected = "allocator returned AllocError")]
fn utf16_string_push_panics_on_allocator_error() {
let arena = ArenaBuilder::new_in(FailingAllocator::new(0)).build();
let mut s = arena.alloc_utf16_string();
s.push('x');
}
#[test]
#[should_panic(expected = "allocator returned AllocError")]
fn utf16_string_insert_panics_from_grow_to_at_least() {
let arena = ArenaBuilder::new_in(FailingAllocator::new(1)).build();
let mut s = Utf16String::from_str_in("a", &arena);
let replacement = widestring::Utf16String::from_str(&"x".repeat(70_000));
s.insert_utf16_str(0, replacement.as_utfstr());
}
#[test]
fn utf16_string_reserve_zero_on_nonempty_string_is_noop() {
let arena = Arena::new();
let mut s = Utf16String::from_str_in("already allocated", &arena);
let cap = s.capacity();
s.reserve(0);
assert_eq!(s.capacity(), cap);
assert_eq!(s.as_utf16_str().to_string(), "already allocated");
}
#[test]
fn utf16_string_from_iterator_in_impls() {
let arena = Arena::new();
let chars = Utf16String::from_iter_in(['a', 'β', '🦀'], &arena);
assert_eq!(chars.as_utf16_str().to_string(), "aβ🦀");
let parts = [utf16str!("hi"), utf16str!("!")];
let from_utf16 = Utf16String::from_iter_in(parts, &arena);
assert_eq!(from_utf16.as_utf16_str().to_string(), "hi!");
let from_strs = Utf16String::from_iter_in(["wide", " ", "string"], &arena);
assert_eq!(from_strs.as_utf16_str().to_string(), "wide string");
}
#[cfg(all(feature = "utf16", feature = "serde"))]
#[test]
fn utf16_string_serialize_impl_body() {
let arena = Arena::new();
let mut s = arena.alloc_utf16_string();
s.push_str(utf16str!("serde 🦀"));
let json = serde_json::to_string(&s).unwrap();
assert_eq!(json, r#""serde 🦀""#);
}
#[test]
fn alloc_utf16_str_rc_oversized_routes_via_oversized_local() {
let arena = Arena::new();
let len_u16 = 16 * 1024;
let buf: Vec<u16> = (0..len_u16).map(|i: usize| u16::try_from(i & 0xFFFF).unwrap()).collect();
let src = widestring::Utf16Str::from_slice(&buf).unwrap();
let rc = arena.alloc_utf16_str_rc(src);
assert_eq!(rc.len(), len_u16);
}
#[test]
fn alloc_utf16_str_box_oversized_routes_via_oversized_local() {
let arena = Arena::new();
let len_u16 = 16 * 1024;
let buf: Vec<u16> = (0..len_u16).map(|i: usize| u16::try_from(i & 0xFFFF).unwrap()).collect();
let src = widestring::Utf16Str::from_slice(&buf).unwrap();
let b = arena.alloc_utf16_str_box(src);
assert_eq!(b.len(), len_u16);
}
#[test]
fn alloc_utf16_str_arc_oversized_routes_via_oversized_shared() {
let arena = Arena::new();
let len_u16 = 16 * 1024;
let buf: Vec<u16> = (0..len_u16).map(|i: usize| u16::try_from(i & 0xFFFF).unwrap()).collect();
let src = widestring::Utf16Str::from_slice(&buf).unwrap();
let arc = arena.alloc_utf16_str_arc(src);
assert_eq!(arc.len(), len_u16);
}
}
mod from_mutants_extras_utf16_scattered {
#![allow(clippy::items_after_statements, reason = "relocated tests put inner types near use")]
#![allow(clippy::clone_on_ref_ptr, reason = "relocated tests use .clone() on Arc/Rc")]
#![allow(dead_code, reason = "relocated helpers retain fields for layout")]
#![allow(
unfulfilled_lint_expectations,
reason = "relocated #[expect] may be fulfilled at file or feature level"
)]
#![allow(
clippy::undocumented_unsafe_blocks,
reason = "relocated test bodies preserve original safety reasoning"
)]
#![allow(clippy::multiple_unsafe_ops_per_block, reason = "relocated tests group related unsafe ops")]
#![allow(clippy::cast_possible_truncation, reason = "relocated tests use bounded values")]
#![allow(clippy::cast_sign_loss, reason = "relocated tests use non-negative values")]
#![allow(clippy::empty_drop, reason = "relocated tests use empty Drop impls to mark dropability")]
#![allow(clippy::assertions_on_result_states, reason = "relocated tests deliberately assert error returns")]
#![allow(clippy::empty_line_after_doc_comments, reason = "relocated test doc-comments")]
extern crate alloc;
use multitude::{Arena, Rc};
#[expect(unused_imports, reason = "relocated tests may reference common helpers")]
use crate::common::{self, FailingAllocator, SendFailingAllocator};
#[test]
fn vec_362_shrink_to_fit_boundary() {
let arena = Arena::new();
let mut v = arena.alloc_vec_with_capacity::<u64>(10);
v.push(1);
v.push(2);
v.push(3);
assert_eq!(v.len(), 3);
assert!(v.capacity() >= 10);
v.shrink_to_fit();
assert_eq!(v.capacity(), v.len());
v.shrink_to_fit(); assert_eq!(v.len(), 3);
}
#[test]
fn vec_451_resize_tight_budget() {
let arena = Arena::builder().byte_budget(128 * 1024).build();
let mut v = arena.alloc_vec_with_capacity::<u64>(5);
v.push(1);
v.push(2);
v.resize(5, 42);
assert_eq!(v.len(), 5);
assert_eq!(v[0], 1);
assert_eq!(v[1], 2);
assert_eq!(v[2], 42);
assert_eq!(v[3], 42);
assert_eq!(v[4], 42);
}
#[test]
fn utf16_shrink_to_fit_uses_multiplication() {
use multitude::strings::Utf16String;
let arena = Arena::new();
let mut s: Utf16String<'_> = Utf16String::new_in(&arena);
s.reserve(32);
for _ in 0..8_u16 {
s.push('a');
}
let cap_before = s.capacity();
let len = s.len();
assert!(cap_before >= len + 8, "test prerequisites: cap={cap_before}, len={len}");
s.shrink_to_fit();
s.push('z');
assert_eq!(s.len(), len + 1);
let units: alloc::vec::Vec<u16> = s.as_slice().to_vec();
let last = units.last().copied().expect("non-empty");
assert_eq!(last, u16::from(b'z'));
}
#[test]
fn utf16_exact_fit_push_is_observably_identical() {
use multitude::strings::Utf16String;
let arena = Arena::new();
let mut s: Utf16String<'_> = Utf16String::new_in(&arena);
s.reserve(4);
let cap = s.capacity();
for _ in 0..cap {
s.push('x');
}
assert_eq!(s.len(), cap);
assert!(s.capacity() >= cap);
}
#[test]
fn utf16_insert_at_start_preserves_tail() {
use widestring::utf16str;
let arena = Arena::new();
let mut s = arena.alloc_utf16_string();
s.push_from_str("World");
s.insert_utf16_str(0, utf16str!("Hello, "));
let actual: std::string::String = std::char::decode_utf16(s.as_slice().iter().copied()).map(|r| r.unwrap()).collect();
assert_eq!(actual, "Hello, World");
}
#[test]
fn utf16_insert_in_middle_preserves_surrounding() {
use widestring::utf16str;
let arena = Arena::new();
let mut s = arena.alloc_utf16_string();
s.push_from_str("HelloWorld");
s.insert_utf16_str(5, utf16str!(", "));
let actual: std::string::String = std::char::decode_utf16(s.as_slice().iter().copied()).map(|r| r.unwrap()).collect();
assert_eq!(actual, "Hello, World");
}
#[test]
fn utf16_remove_first_preserves_rest() {
let arena = Arena::new();
let mut s = arena.alloc_utf16_string();
s.push_from_str("hello");
let removed = s.remove(0);
assert_eq!(removed, 'h');
assert_eq!(s.len(), 4);
}
#[test]
fn utf16_replace_range_replaces_exact_range() {
use widestring::utf16str;
let arena = Arena::new();
let mut s = arena.alloc_utf16_string();
s.push_from_str("Hello, World!");
s.replace_range(7..12, utf16str!("Rust"));
let actual: std::string::String = std::char::decode_utf16(s.as_slice().iter().copied()).map(|r| r.unwrap()).collect();
assert_eq!(actual, "Hello, Rust!");
}
#[cfg(feature = "stats")]
#[test]
fn utf16_string_into_arena_str_reclaim_lets_followup_fit_in_chunk() {
let arena = Arena::new();
let mut s = arena.alloc_utf16_string_with_capacity(1800);
s.push_from_str("hi");
let chunks_before = arena.stats().normal_local_chunks_allocated;
let _rs = s.into_arena_utf16_str();
let big: Rc<[u8; 2000]> = arena.alloc_rc([3_u8; 2000]);
assert_eq!(big[0], 3);
assert_eq!(big[1999], 3);
assert_eq!(arena.stats().normal_local_chunks_allocated, chunks_before);
}
#[cfg(feature = "stats")]
#[test]
fn utf16_string_shrink_to_fit_reclaim_lets_followup_fit_in_chunk() {
let arena = Arena::new();
let mut s = arena.alloc_utf16_string_with_capacity(1800);
s.push_from_str("hi");
s.shrink_to_fit();
let chunks_before = arena.stats().normal_local_chunks_allocated;
let big: Rc<[u8; 2000]> = arena.alloc_rc([4_u8; 2000]);
assert_eq!(big[0], 4);
assert_eq!(big[1999], 4);
assert_eq!(s.len(), 2);
assert_eq!(arena.stats().normal_local_chunks_allocated, chunks_before);
}
}