use grip::function_purity::FunctionPurity;
use syn::{ItemFn, parse_str};
fn parse_fn(source: &str) -> ItemFn {
parse_str(source).expect("valid fn source")
}
#[test]
fn has_mut_param_with_mut_self_reference_returns_true() {
let item_fn = parse_fn("fn f(&mut self) {}");
let result = FunctionPurity::has_mut_param(&item_fn.sig);
assert!(result, "&mut self is a real mutable reference");
}
#[test]
fn has_mut_param_with_by_value_mut_self_returns_false() {
let item_fn = parse_fn("fn f(mut self) {}");
let result = FunctionPurity::has_mut_param(&item_fn.sig);
assert!(
!result,
"mut self is by-value, locally-mutable, no observable side effect"
);
}
#[test]
fn has_mut_param_with_mut_reference_typed_arg_returns_true() {
let item_fn = parse_fn("fn f(x: &mut i32) {}");
let result = FunctionPurity::has_mut_param(&item_fn.sig);
assert!(result, "a &mut typed parameter is a real mutable reference");
}
#[test]
fn has_mut_param_with_mut_reference_in_parens_returns_true() {
let item_fn = parse_fn("fn f(x: (&mut i32)) {}");
let result = FunctionPurity::has_mut_param(&item_fn.sig);
assert!(result, "a parenthesized &mut type must still be recognized");
}
#[test]
fn has_mut_param_with_plain_self_returns_false() {
let item_fn = parse_fn("fn f(&self) {}");
let result = FunctionPurity::has_mut_param(&item_fn.sig);
assert!(!result);
}
#[test]
fn has_mut_param_with_no_params_returns_false() {
let item_fn = parse_fn("fn f() {}");
let result = FunctionPurity::has_mut_param(&item_fn.sig);
assert!(!result);
}
#[test]
fn is_unit_return_with_no_return_type_returns_true() {
let item_fn = parse_fn("fn f() {}");
let result = FunctionPurity::is_unit_return(&item_fn.sig);
assert!(result);
}
#[test]
fn is_unit_return_with_explicit_unit_tuple_returns_true() {
let item_fn = parse_fn("fn f() -> () {}");
let result = FunctionPurity::is_unit_return(&item_fn.sig);
assert!(result);
}
#[test]
fn is_unit_return_with_non_unit_type_returns_false() {
let item_fn = parse_fn("fn f() -> i32 { 0 }");
let result = FunctionPurity::is_unit_return(&item_fn.sig);
assert!(!result);
}
#[test]
fn is_unit_return_with_non_empty_tuple_returns_false() {
let item_fn = parse_fn("fn f() -> (i32, i32) { (0, 0) }");
let result = FunctionPurity::is_unit_return(&item_fn.sig);
assert!(!result, "a non-empty tuple return is not the same as unit");
}
#[test]
fn has_unsafe_block_with_unsafe_block_returns_true() {
let item_fn = parse_fn("fn f() { unsafe {} }");
let result = FunctionPurity::has_unsafe_block(&item_fn.block);
assert!(result);
}
#[test]
fn has_unsafe_block_with_no_unsafe_returns_false() {
let item_fn = parse_fn("fn f() { let x = 1; }");
let result = FunctionPurity::has_unsafe_block(&item_fn.block);
assert!(!result);
}
#[test]
fn has_io_call_with_io_call_returns_true() {
let item_fn = parse_fn(r#"fn f() { fs::read_to_string("x").unwrap(); }"#);
let result = FunctionPurity::has_io_call(&item_fn.block);
assert!(result);
}
#[test]
fn has_io_call_with_no_io_call_returns_false() {
let item_fn = parse_fn("fn f() { let x = 1; }");
let result = FunctionPurity::has_io_call(&item_fn.block);
assert!(!result);
}