use aspect_core::prelude::*;
use std::any::Any;
use std::sync::{Arc, Mutex};
#[derive(Clone)]
struct TestAspect {
log: Arc<Mutex<Vec<String>>>,
}
impl TestAspect {
fn new() -> Self {
Self {
log: Arc::new(Mutex::new(Vec::new())),
}
}
fn get_log(&self) -> Vec<String> {
self.log.lock().unwrap().clone()
}
}
impl Aspect for TestAspect {
fn before(&self, ctx: &JoinPoint) {
self.log
.lock()
.unwrap()
.push(format!("before:{}", ctx.function_name));
}
fn after(&self, ctx: &JoinPoint, _result: &dyn Any) {
self.log
.lock()
.unwrap()
.push(format!("after:{}", ctx.function_name));
}
fn after_error(&self, ctx: &JoinPoint, _error: &AspectError) {
self.log
.lock()
.unwrap()
.push(format!("error:{}", ctx.function_name));
}
}
#[test]
fn test_aspect_lifecycle() {
let aspect = TestAspect::new();
let ctx = JoinPoint {
function_name: "test_fn",
module_path: "test",
location: Location {
file: "test.rs",
line: 1,
},
};
aspect.before(&ctx);
aspect.after(&ctx, &42);
let log = aspect.get_log();
assert_eq!(log.len(), 2);
assert_eq!(log[0], "before:test_fn");
assert_eq!(log[1], "after:test_fn");
}
#[test]
fn test_aspect_error_handling() {
let aspect = TestAspect::new();
let ctx = JoinPoint {
function_name: "failing_fn",
module_path: "test",
location: Location {
file: "test.rs",
line: 10,
},
};
aspect.before(&ctx);
aspect.after_error(&ctx, &AspectError::execution("test error"));
let log = aspect.get_log();
assert_eq!(log.len(), 2);
assert_eq!(log[0], "before:failing_fn");
assert_eq!(log[1], "error:failing_fn");
}
#[test]
fn test_proceeding_joinpoint() {
let ctx = JoinPoint {
function_name: "wrapped_fn",
module_path: "test",
location: Location {
file: "test.rs",
line: 20,
},
};
let executed = Arc::new(Mutex::new(false));
let executed_clone = Arc::clone(&executed);
let pjp = ProceedingJoinPoint::new(
move || {
*executed_clone.lock().unwrap() = true;
Ok(Box::new(42) as Box<dyn Any>)
},
ctx,
);
assert!(!*executed.lock().unwrap());
let result = pjp.proceed();
assert!(*executed.lock().unwrap());
assert!(result.is_ok());
}