use borrowscope_macro::trace_borrow;
use borrowscope_runtime::*;
use serial_test::serial;
#[test]
#[serial]
fn test_vec_macro() {
reset();
#[trace_borrow]
fn test_fn() {
let v = vec![1, 2, 3];
assert_eq!(v.len(), 3);
}
test_fn();
let events = get_events();
assert!(!events.is_empty());
assert!(events.iter().any(|e| e.is_new()));
}
#[test]
#[serial]
fn test_vec_macro_with_capacity() {
reset();
#[trace_borrow]
fn test_fn() {
let mut v = Vec::with_capacity(10);
v.push(1);
v.push(2);
assert_eq!(v.len(), 2);
}
test_fn();
let events = get_events();
assert!(!events.is_empty());
}
#[test]
#[serial]
fn test_vec_macro_repeat() {
reset();
#[trace_borrow]
fn test_fn() {
let v = vec![0; 5];
assert_eq!(v.len(), 5);
}
test_fn();
let events = get_events();
assert!(!events.is_empty());
}
#[test]
#[serial]
fn test_format_macro() {
reset();
#[trace_borrow]
fn test_fn() {
let name = String::from("Alice");
let greeting = format!("Hello, {}!", name);
assert!(greeting.contains("Alice"));
}
test_fn();
let events = get_events();
assert!(!events.is_empty());
assert!(events.iter().filter(|e| e.is_new()).count() >= 2);
}
#[test]
#[serial]
fn test_println_macro() {
reset();
#[trace_borrow]
fn test_fn() {
let x = 42;
println!("Value: {}", x);
}
test_fn();
let events = get_events();
assert!(!events.is_empty());
}
#[test]
#[serial]
fn test_assert_macro() {
reset();
#[trace_borrow]
fn test_fn() {
let x = 42;
assert!(x > 0);
assert_eq!(x, 42);
assert_ne!(x, 0);
}
test_fn();
let events = get_events();
assert!(!events.is_empty());
}
#[test]
#[serial]
fn test_debug_assert_macro() {
reset();
#[trace_borrow]
fn test_fn() {
let x = 42;
debug_assert!(x > 0);
debug_assert_eq!(x, 42);
}
test_fn();
let events = get_events();
assert!(!events.is_empty());
}
#[test]
#[serial]
fn test_matches_macro() {
reset();
#[trace_borrow]
fn test_fn() {
let value = Some(42);
let result = matches!(value, Some(x) if x > 0);
assert!(result);
}
test_fn();
let events = get_events();
assert!(!events.is_empty());
}
#[test]
#[serial]
fn test_write_macro() {
reset();
#[trace_borrow]
fn test_fn() {
use std::fmt::Write;
let mut s = String::new();
write!(&mut s, "Hello, world!").unwrap();
assert_eq!(s, "Hello, world!");
}
test_fn();
let events = get_events();
assert!(!events.is_empty());
}
#[test]
#[serial]
fn test_writeln_macro() {
reset();
#[trace_borrow]
fn test_fn() {
use std::fmt::Write;
let mut s = String::new();
writeln!(&mut s, "Line 1").unwrap();
writeln!(&mut s, "Line 2").unwrap();
assert!(s.contains("Line 1"));
}
test_fn();
let events = get_events();
assert!(!events.is_empty());
}
#[test]
#[serial]
fn test_panic_macro() {
reset();
#[trace_borrow]
fn test_fn() -> std::result::Result<(), String> {
let x = 42;
if x > 100 {
panic!("Value too large: {}", x);
}
Ok(())
}
let _ = test_fn();
let events = get_events();
assert!(!events.is_empty());
}
#[test]
#[serial]
fn test_unimplemented_macro() {
reset();
#[trace_borrow]
fn test_fn() -> i32 {
let x = 42;
if x < 0 {
unimplemented!("Negative values not supported");
}
x
}
let result = test_fn();
assert_eq!(result, 42);
let events = get_events();
assert!(!events.is_empty());
}
#[test]
#[serial]
fn test_todo_macro() {
reset();
#[trace_borrow]
fn test_fn() -> i32 {
let x = 42;
if x < 0 {
todo!("Handle negative values");
}
x
}
let result = test_fn();
assert_eq!(result, 42);
let events = get_events();
assert!(!events.is_empty());
}
#[test]
#[serial]
fn test_unreachable_macro() {
reset();
#[trace_borrow]
fn test_fn() -> i32 {
let x = 42;
match x {
42 => x,
_ => unreachable!("x is always 42"),
}
}
let result = test_fn();
assert_eq!(result, 42);
let events = get_events();
assert!(!events.is_empty());
}
#[test]
#[serial]
fn test_hashmap_macro_pattern() {
reset();
#[trace_borrow]
fn test_fn() {
use std::collections::HashMap;
let mut map = HashMap::new();
map.insert("key1", 1);
map.insert("key2", 2);
assert_eq!(map.len(), 2);
}
test_fn();
let events = get_events();
assert!(!events.is_empty());
}
#[test]
#[serial]
fn test_hashset_macro_pattern() {
reset();
#[trace_borrow]
fn test_fn() {
use std::collections::HashSet;
let mut set = HashSet::new();
set.insert(1);
set.insert(2);
set.insert(3);
assert_eq!(set.len(), 3);
}
test_fn();
let events = get_events();
assert!(!events.is_empty());
}
#[test]
#[serial]
fn test_btreemap_macro_pattern() {
reset();
#[trace_borrow]
fn test_fn() {
use std::collections::BTreeMap;
let mut map = BTreeMap::new();
map.insert(1, "one");
map.insert(2, "two");
assert_eq!(map.len(), 2);
}
test_fn();
let events = get_events();
assert!(!events.is_empty());
}
macro_rules! create_variable {
($name:ident, $value:expr) => {
let $name = $value;
};
}
#[test]
#[serial]
fn test_custom_macro_simple() {
reset();
#[trace_borrow]
fn test_fn() {
create_variable!(x, 42);
let y = x + 1; assert_eq!(y, 43);
}
test_fn();
let events = get_events();
assert!(!events.is_empty());
}
macro_rules! create_vec {
($($item:expr),*) => {
{
vec![$($item),*]
}
};
}
#[test]
#[serial]
fn test_custom_macro_complex() {
reset();
#[trace_borrow]
fn test_fn() {
let v = create_vec!(1, 2, 3, 4, 5);
assert_eq!(v.len(), 5);
}
test_fn();
let events = get_events();
assert!(!events.is_empty());
}
macro_rules! swap_values {
($a:expr, $b:expr) => {
std::mem::swap(&mut $a, &mut $b)
};
}
#[test]
#[serial]
fn test_custom_macro_with_mutation() {
reset();
#[trace_borrow]
fn test_fn() {
let mut x = 1;
let mut y = 2;
swap_values!(x, y);
assert_eq!(x, 2);
assert_eq!(y, 1);
}
test_fn();
let events = get_events();
assert!(!events.is_empty());
}
macro_rules! nested_macro {
($name:ident) => {
let $name = 100;
};
}
#[test]
#[serial]
fn test_nested_macros() {
reset();
#[trace_borrow]
fn test_fn() {
nested_macro!(inner);
let result = inner + 1; assert_eq!(result, 101);
}
test_fn();
let events = get_events();
assert!(!events.is_empty());
}
macro_rules! hygienic_macro {
() => {{
let hidden = 42;
hidden
}};
}
#[test]
#[serial]
fn test_macro_hygiene() {
reset();
#[trace_borrow]
fn test_fn() {
let result = hygienic_macro!();
assert_eq!(result, 42);
}
test_fn();
let events = get_events();
assert!(!events.is_empty());
}
#[derive(Debug, Clone, PartialEq)]
struct Point {
x: i32,
y: i32,
}
#[test]
#[serial]
fn test_derive_debug() {
reset();
#[trace_borrow]
fn test_fn() {
let p = Point { x: 1, y: 2 };
let s = format!("{:?}", p);
assert!(s.contains("Point"));
}
test_fn();
let events = get_events();
assert!(!events.is_empty());
}
#[test]
#[serial]
fn test_derive_clone() {
reset();
#[trace_borrow]
fn test_fn() {
let p1 = Point { x: 1, y: 2 };
let p2 = p1.clone();
assert_eq!(p1, p2);
}
test_fn();
let events = get_events();
assert!(!events.is_empty());
}
#[derive(Default)]
struct Config {
value: i32,
}
#[test]
#[serial]
fn test_derive_default() {
reset();
#[trace_borrow]
fn test_fn() {
let config = Config::default();
assert_eq!(config.value, 0);
}
test_fn();
let events = get_events();
assert!(!events.is_empty());
}
#[test]
#[serial]
fn test_cfg_attribute() {
reset();
#[trace_borrow]
fn test_fn() {
#[cfg(test)]
let x = 42;
#[cfg(not(test))]
let x = 0;
assert_eq!(x, 42);
}
test_fn();
let events = get_events();
assert!(!events.is_empty());
}
#[test]
#[serial]
fn test_allow_attribute() {
reset();
#[trace_borrow]
fn test_fn() {
#[allow(unused_variables)]
let unused = 42;
let used = 100;
assert_eq!(used, 100);
}
test_fn();
let events = get_events();
assert!(!events.is_empty());
}
#[test]
#[serial]
fn test_multiple_macros_combined() {
reset();
#[trace_borrow]
fn test_fn() {
let v = vec![1, 2, 3];
let s = format!("Vector: {:?}", v);
println!("{}", s);
assert!(matches!(v.len(), 3));
}
test_fn();
let events = get_events();
assert!(!events.is_empty());
assert!(events.iter().filter(|e| e.is_new()).count() >= 2);
}
#[test]
#[serial]
fn test_macro_in_match() {
reset();
#[trace_borrow]
fn test_fn() {
let value = Some(42);
let result = matches!(value, Some(x) if (40..=50).contains(&x));
assert!(result);
}
test_fn();
let events = get_events();
assert!(!events.is_empty());
}
#[test]
#[serial]
fn test_macro_in_closure() {
reset();
#[trace_borrow]
fn test_fn() {
let v = vec![1, 2, 3];
let doubled: Vec<_> = v.iter().map(|x| format!("{}", x * 2)).collect();
assert_eq!(doubled.len(), 3);
}
test_fn();
let events = get_events();
assert!(!events.is_empty());
}
#[test]
#[serial]
fn test_macro_with_generics() {
reset();
#[trace_borrow]
fn test_fn() {
let v1 = vec![1, 2, 3];
let v2 = vec!["a", "b", "c"];
assert_eq!(v1.len(), v2.len());
}
test_fn();
let events = get_events();
assert!(!events.is_empty());
}
#[test]
#[serial]
fn test_try_macro_pattern() {
reset();
#[trace_borrow]
fn test_fn() -> std::result::Result<i32, String> {
let x: std::result::Result<i32, String> = Ok(42);
let y = x?;
Ok(y)
}
let result = test_fn();
assert_eq!(result, Ok(42));
let events = get_events();
assert!(!events.is_empty());
}
#[test]
#[serial]
fn test_option_macro_pattern() {
reset();
#[trace_borrow]
fn test_fn() -> Option<i32> {
let x = Some(42);
let y = x?;
Some(y)
}
let result = test_fn();
assert_eq!(result, Some(42));
let events = get_events();
assert!(!events.is_empty());
}
#[tokio::test]
#[serial]
async fn test_async_with_macros() {
reset();
#[trace_borrow]
async fn test_fn() {
let v = vec![1, 2, 3];
tokio::time::sleep(tokio::time::Duration::from_millis(1)).await;
assert_eq!(v.len(), 3);
}
test_fn().await;
let events = get_events();
assert!(!events.is_empty());
}
#[tokio::test]
#[serial]
async fn test_select_macro() {
reset();
#[trace_borrow]
async fn test_fn() {
let v = vec![1, 2, 3];
tokio::select! {
_ = tokio::time::sleep(tokio::time::Duration::from_millis(1)) => {
assert_eq!(v.len(), 3);
}
}
}
test_fn().await;
let events = get_events();
assert!(!events.is_empty());
}
#[test]
#[serial]
fn test_empty_vec_macro() {
reset();
#[trace_borrow]
fn test_fn() {
let v: Vec<i32> = vec![];
assert_eq!(v.len(), 0);
}
test_fn();
let events = get_events();
assert!(!events.is_empty());
}
#[test]
#[serial]
fn test_macro_with_trailing_comma() {
reset();
#[trace_borrow]
fn test_fn() {
let v = vec![1, 2, 3];
assert_eq!(v.len(), 3);
}
test_fn();
let events = get_events();
assert!(!events.is_empty());
}
#[test]
#[serial]
fn test_macro_with_complex_expressions() {
reset();
#[trace_borrow]
fn test_fn() {
let x = 2;
let v = vec![x * 2, x * 3, x * 4];
assert_eq!(v, vec![4, 6, 8]);
}
test_fn();
let events = get_events();
assert!(!events.is_empty());
}
macro_rules! conditional_code {
(debug) => {
"debug"
};
(release) => {
"release"
};
}
#[test]
#[serial]
fn test_conditional_macro() {
reset();
#[trace_borrow]
fn test_fn() {
#[cfg(debug_assertions)]
let mode = conditional_code!(debug);
#[cfg(not(debug_assertions))]
let mode = conditional_code!(release);
assert!(mode == "debug" || mode == "release");
}
test_fn();
let events = get_events();
assert!(!events.is_empty());
}
#[test]
#[serial]
fn test_macro_with_lifetime_annotations() {
reset();
#[trace_borrow]
fn test_fn() {
let s = String::from("hello");
let v = vec![&s];
assert_eq!(v.len(), 1);
}
test_fn();
let events = get_events();
assert!(!events.is_empty());
}
#[test]
#[serial]
fn test_macro_with_type_inference() {
reset();
#[trace_borrow]
fn test_fn() {
let v = vec![1, 2, 3];
let sum: i32 = v.iter().sum();
assert_eq!(sum, 6);
}
test_fn();
let events = get_events();
assert!(!events.is_empty());
}
#[test]
#[serial]
fn test_macro_with_turbofish() {
reset();
#[trace_borrow]
fn test_fn() {
let v = vec![1, 2, 3];
let collected = v.iter().collect::<Vec<_>>();
assert_eq!(collected.len(), 3);
}
test_fn();
let events = get_events();
assert!(!events.is_empty());
}
#[test]
#[serial]
fn test_nested_vec_macro() {
reset();
#[trace_borrow]
fn test_fn() {
let matrix = vec![vec![1, 2], vec![3, 4]];
assert_eq!(matrix.len(), 2);
}
test_fn();
let events = get_events();
assert!(!events.is_empty());
}
#[test]
#[serial]
fn test_macro_with_const_generics() {
reset();
#[trace_borrow]
fn test_fn() {
let arr = [1, 2, 3, 4, 5];
let v = Vec::from(arr);
assert_eq!(v.len(), 5);
}
test_fn();
let events = get_events();
assert!(!events.is_empty());
}
#[test]
#[serial]
fn test_macro_with_dyn_trait() {
reset();
#[trace_borrow]
fn test_fn() {
let v: Vec<Box<dyn std::fmt::Debug>> = vec![Box::new(1), Box::new("hello")];
assert_eq!(v.len(), 2);
}
test_fn();
let events = get_events();
assert!(!events.is_empty());
}
#[test]
#[serial]
fn test_macro_with_impl_trait() {
reset();
#[trace_borrow]
fn test_fn() {
let v = vec![1, 2, 3];
let sum: i32 = v.iter().sum();
assert_eq!(sum, 6);
}
test_fn();
let events = get_events();
assert!(!events.is_empty());
}
#[test]
#[serial]
fn test_macro_in_if_let() {
reset();
#[trace_borrow]
fn test_fn() {
let opt = Some(vec![1, 2, 3]);
if let Some(v) = opt {
assert_eq!(v.len(), 3);
}
}
test_fn();
let events = get_events();
assert!(!events.is_empty());
}
#[test]
#[serial]
fn test_macro_in_while_let() {
reset();
#[trace_borrow]
fn test_fn() {
let mut v = vec![1, 2, 3];
while v.pop().is_some() {
}
assert_eq!(v.len(), 0);
}
test_fn();
let events = get_events();
assert!(!events.is_empty());
}
#[test]
#[serial]
fn test_macro_in_for_loop() {
reset();
#[trace_borrow]
fn test_fn() {
let v = vec![1, 2, 3];
let mut sum = 0;
for x in v {
sum += x;
}
assert_eq!(sum, 6);
}
test_fn();
let events = get_events();
assert!(!events.is_empty());
}
#[test]
#[serial]
fn test_macro_with_pattern_matching() {
reset();
#[trace_borrow]
fn test_fn() {
let v = vec![1, 2, 3];
match v.as_slice() {
[first, .., last] => assert_eq!(first + last, 4),
_ => panic!("unexpected pattern"),
}
}
test_fn();
let events = get_events();
assert!(!events.is_empty());
}
#[test]
#[serial]
fn test_macro_with_destructuring() {
reset();
#[trace_borrow]
fn test_fn() {
let v = vec![(1, 2), (3, 4)];
if let [(a, b), (c, d)] = v.as_slice() {
assert_eq!(a + b + c + d, 10);
}
}
test_fn();
let events = get_events();
assert!(!events.is_empty());
}
#[test]
#[serial]
fn test_macro_with_range() {
reset();
#[trace_borrow]
fn test_fn() {
let v: Vec<_> = (1..=5).collect();
assert_eq!(v, vec![1, 2, 3, 4, 5]);
}
test_fn();
let events = get_events();
assert!(!events.is_empty());
}
#[test]
#[serial]
fn test_macro_with_iterator_chain() {
reset();
#[trace_borrow]
fn test_fn() {
let v1 = vec![1, 2];
let v2 = vec![3, 4];
let combined: Vec<_> = v1.iter().chain(v2.iter()).collect();
assert_eq!(combined.len(), 4);
}
test_fn();
let events = get_events();
assert!(!events.is_empty());
}
#[test]
#[serial]
fn test_macro_with_filter_map() {
reset();
#[trace_borrow]
fn test_fn() {
let v = vec![Some(1), None, Some(3)];
let filtered: Vec<_> = v.into_iter().flatten().collect();
assert_eq!(filtered, vec![1, 3]);
}
test_fn();
let events = get_events();
assert!(!events.is_empty());
}
#[test]
#[serial]
fn test_macro_with_zip() {
reset();
#[trace_borrow]
fn test_fn() {
let v1 = vec![1, 2, 3];
let v2 = vec!["a", "b", "c"];
let zipped: Vec<_> = v1.into_iter().zip(v2).collect();
assert_eq!(zipped.len(), 3);
}
test_fn();
let events = get_events();
assert!(!events.is_empty());
}
#[test]
#[serial]
fn test_macro_with_enumerate() {
reset();
#[trace_borrow]
fn test_fn() {
let v = vec!["a", "b", "c"];
let enumerated: Vec<_> = v.iter().enumerate().collect();
assert_eq!(enumerated.len(), 3);
}
test_fn();
let events = get_events();
assert!(!events.is_empty());
}
#[test]
#[serial]
fn test_macro_with_partition() {
reset();
#[trace_borrow]
fn test_fn() {
let v = vec![1, 2, 3, 4, 5];
let (even, odd): (Vec<_>, Vec<_>) = v.into_iter().partition(|x| x % 2 == 0);
assert_eq!(even.len() + odd.len(), 5);
}
test_fn();
let events = get_events();
assert!(!events.is_empty());
}
#[test]
#[serial]
fn test_macro_with_fold() {
reset();
#[trace_borrow]
fn test_fn() {
let v = vec![1, 2, 3, 4];
let product = v.iter().fold(1, |acc, x| acc * x);
assert_eq!(product, 24);
}
test_fn();
let events = get_events();
assert!(!events.is_empty());
}
#[test]
#[serial]
fn test_macro_with_windows() {
reset();
#[trace_borrow]
fn test_fn() {
let v = vec![1, 2, 3, 4];
let windows: Vec<_> = v.windows(2).collect();
assert_eq!(windows.len(), 3);
}
test_fn();
let events = get_events();
assert!(!events.is_empty());
}
#[test]
#[serial]
fn test_macro_with_chunks() {
reset();
#[trace_borrow]
fn test_fn() {
let v = vec![1, 2, 3, 4, 5];
let chunks: Vec<_> = v.chunks(2).collect();
assert_eq!(chunks.len(), 3);
}
test_fn();
let events = get_events();
assert!(!events.is_empty());
}
#[test]
#[serial]
fn test_macro_with_sort() {
reset();
#[trace_borrow]
fn test_fn() {
let mut v = vec![3, 1, 4, 1, 5];
v.sort();
assert_eq!(v[0], 1);
}
test_fn();
let events = get_events();
assert!(!events.is_empty());
}
#[test]
#[serial]
fn test_macro_with_dedup() {
reset();
#[trace_borrow]
fn test_fn() {
let mut v = vec![1, 1, 2, 2, 3];
v.dedup();
assert_eq!(v, vec![1, 2, 3]);
}
test_fn();
let events = get_events();
assert!(!events.is_empty());
}
#[test]
#[serial]
fn test_macro_with_retain() {
reset();
#[trace_borrow]
fn test_fn() {
let mut v = vec![1, 2, 3, 4, 5];
v.retain(|&x| x % 2 == 0);
assert_eq!(v, vec![2, 4]);
}
test_fn();
let events = get_events();
assert!(!events.is_empty());
}
#[test]
#[serial]
fn test_macro_with_drain() {
reset();
#[trace_borrow]
fn test_fn() {
let mut v = vec![1, 2, 3, 4, 5];
let drained: Vec<_> = v.drain(1..3).collect();
assert_eq!(drained, vec![2, 3]);
assert_eq!(v, vec![1, 4, 5]);
}
test_fn();
let events = get_events();
assert!(!events.is_empty());
}
#[test]
#[serial]
fn test_macro_with_extend() {
reset();
#[trace_borrow]
fn test_fn() {
let mut v1 = vec![1, 2];
let v2 = vec![3, 4];
v1.extend(v2);
assert_eq!(v1, vec![1, 2, 3, 4]);
}
test_fn();
let events = get_events();
assert!(!events.is_empty());
}
#[test]
#[serial]
fn test_macro_with_repeat() {
reset();
#[trace_borrow]
fn test_fn() {
let v: Vec<_> = std::iter::repeat(1).take(5).collect();
assert_eq!(v, vec![1, 1, 1, 1, 1]);
}
test_fn();
let events = get_events();
assert!(!events.is_empty());
}