use borrowscope_macro::trace_borrow;
use borrowscope_runtime::{get_events, reset, Event};
use serial_test::serial;
use std::borrow::Cow;
use std::rc::Rc;
use std::sync::Arc;
use std::sync::mpsc;
use std::thread;
use std::time::Duration;
fn has_event_type(events: &[Event], type_name: &str) -> bool {
events.iter().any(|e| format!("{:?}", e).contains(type_name))
}
fn count_event_type(events: &[Event], type_name: &str) -> usize {
events.iter().filter(|e| format!("{:?}", e).contains(type_name)).count()
}
#[test]
#[serial]
#[serial]
fn test_cow_borrowed_creation() {
reset();
#[trace_borrow]
fn create_borrowed() {
let _cow: Cow<str> = Cow::Borrowed("hello");
}
create_borrowed();
let events = get_events();
assert!(has_event_type(&events, "CowBorrowed"), "Should track CowBorrowed creation");
}
#[test]
#[serial]
fn test_cow_owned_creation() {
reset();
#[trace_borrow]
fn create_owned() {
let _cow: Cow<str> = Cow::Owned(String::from("hello"));
}
create_owned();
let events = get_events();
assert!(has_event_type(&events, "CowOwned"), "Should track CowOwned creation");
}
#[test]
#[serial]
fn test_cow_to_mut_tracking() {
reset();
#[trace_borrow]
fn use_to_mut() {
let mut cow: Cow<str> = Cow::Borrowed("hello");
cow.to_mut().push_str(" world");
}
use_to_mut();
let events = get_events();
assert!(has_event_type(&events, "CowBorrowed"), "Should track initial Cow creation");
assert!(has_event_type(&events, "CowToMut"), "Should track to_mut call");
}
#[test]
#[serial]
fn test_weak_new_from_rc_downgrade() {
reset();
#[trace_borrow]
fn create_weak() {
let strong = Rc::new(42);
let _weak = Rc::downgrade(&strong);
}
create_weak();
let events = get_events();
assert!(has_event_type(&events, "WeakNew"), "Should track Weak creation from Rc::downgrade");
}
#[test]
#[serial]
fn test_weak_new_from_arc_downgrade() {
reset();
#[trace_borrow]
fn create_weak_sync() {
let strong = Arc::new(42);
let _weak = Arc::downgrade(&strong);
}
create_weak_sync();
let events = get_events();
assert!(has_event_type(&events, "WeakNew"), "Should track Weak creation from Arc::downgrade");
}
#[test]
#[serial]
fn test_weak_clone_tracking() {
reset();
#[trace_borrow]
fn clone_weak() {
let strong = Rc::new(42);
let weak = Rc::downgrade(&strong);
let _weak2 = weak.clone();
}
clone_weak();
let events = get_events();
assert!(has_event_type(&events, "WeakNew"), "Should track initial Weak creation");
assert!(has_event_type(&events, "WeakClone"), "Should track Weak clone");
}
#[test]
#[serial]
fn test_weak_upgrade_tracking() {
reset();
#[trace_borrow]
fn upgrade_weak() {
let strong = Rc::new(42);
let weak = Rc::downgrade(&strong);
let _upgraded = weak.upgrade();
}
upgrade_weak();
let events = get_events();
assert!(has_event_type(&events, "WeakNew"), "Should track Weak creation");
assert!(has_event_type(&events, "WeakUpgrade"), "Should track Weak upgrade");
}
#[test]
#[serial]
fn test_weak_upgrade_after_drop() {
reset();
#[trace_borrow]
fn upgrade_after_drop() {
let strong = Rc::new(42);
let weak = Rc::downgrade(&strong);
drop(strong);
let _result = weak.upgrade(); }
upgrade_after_drop();
let events = get_events();
assert!(has_event_type(&events, "WeakUpgrade"), "Should track failed Weak upgrade");
}
#[test]
#[serial]
fn test_thread_spawn_tracking() {
reset();
#[trace_borrow]
fn spawn_thread() {
let handle = thread::spawn(|| 42);
let _ = handle.join();
}
spawn_thread();
let events = get_events();
assert!(has_event_type(&events, "ThreadSpawn"), "Should track thread spawn");
}
#[test]
#[serial]
fn test_thread_join_tracking() {
reset();
#[trace_borrow]
fn join_thread() {
let handle = thread::spawn(|| {
thread::sleep(Duration::from_millis(1));
42
});
let _ = handle.join();
}
join_thread();
let events = get_events();
assert!(has_event_type(&events, "ThreadSpawn"), "Should track thread spawn");
assert!(has_event_type(&events, "ThreadJoin"), "Should track thread join");
}
#[test]
#[serial]
fn test_channel_creation_tracking() {
reset();
#[trace_borrow]
fn create_channel() {
let (_tx, _rx) = mpsc::channel::<i32>();
}
create_channel();
let events = get_events();
assert!(has_event_type(&events, "ChannelSenderNew") || has_event_type(&events, "Channel"),
"Should track channel creation");
}
#[test]
#[serial]
fn test_channel_tuple_destructuring() {
reset();
#[trace_borrow]
fn channel_with_names() {
let (sender, receiver) = mpsc::channel::<i32>();
drop(sender);
drop(receiver);
}
channel_with_names();
let events = get_events();
let channel_events = events.iter()
.filter(|e| {
let s = format!("{:?}", e);
s.contains("Channel") || s.contains("Sender") || s.contains("Receiver")
})
.count();
assert!(channel_events >= 1, "Should track channel creation events");
}
#[test]
#[serial]
fn test_combined_smart_pointer_operations() {
reset();
#[trace_borrow]
fn combined_ops() {
let mut cow: Cow<str> = Cow::Borrowed("test");
cow.to_mut().push_str("!");
let rc = Rc::new(100);
let weak = Rc::downgrade(&rc);
let weak2 = weak.clone();
let _ = weak.upgrade();
let _ = weak2.upgrade();
}
combined_ops();
let events = get_events();
assert!(has_event_type(&events, "CowBorrowed"), "Should track Cow");
assert!(has_event_type(&events, "CowToMut"), "Should track to_mut");
assert!(has_event_type(&events, "WeakNew"), "Should track Weak creation");
assert!(has_event_type(&events, "WeakClone"), "Should track Weak clone");
assert!(count_event_type(&events, "WeakUpgrade") >= 2, "Should track both upgrades");
}
#[test]
#[serial]
fn test_thread_with_channel() {
reset();
#[trace_borrow]
fn thread_channel_combo() {
let (tx, rx) = mpsc::channel();
let handle = thread::spawn(move || {
tx.send(42).unwrap();
});
let _ = rx.recv();
let _ = handle.join();
}
thread_channel_combo();
let events = get_events();
assert!(has_event_type(&events, "ThreadSpawn"), "Should track thread spawn");
assert!(has_event_type(&events, "ThreadJoin"), "Should track thread join");
let has_channel = has_event_type(&events, "Channel") ||
has_event_type(&events, "Sender") ||
has_event_type(&events, "Receiver");
assert!(has_channel, "Should track channel creation");
}