use super::*;
#[test]
fn async_block_body_is_lenient() {
let calls = own_calls_of("fn g() {} fn f() { let _ = async { g() }; }", "f");
assert!(
calls.is_empty(),
"calls inside async are lenient, got {calls:?}"
);
}
#[test]
fn async_depth_pops_after_block() {
let calls = own_calls_of("fn g() {} fn f() { let _ = async {}; g(); }", "f");
assert!(
!calls.is_empty(),
"an own call after an async block must still count, got {calls:?}"
);
}
#[test]
fn non_iterator_own_method_call_is_counted() {
let calls = own_calls_of(
"struct S; impl S { fn helper(&self) {} } fn f(s: S) { s.helper(); let _ = 0; }",
"f",
);
assert!(
calls.iter().any(|c| c.contains("helper")),
"a non-iterator own method call is an own call, got {calls:?}"
);
}
#[test]
fn recursive_own_method_call_is_counted_when_recursion_disallowed() {
let calls = own_calls_of(
"struct S; impl S { fn f(&self) -> i32 { let _ = 0; self.f() } }",
"f",
);
assert!(
calls.iter().any(|c| c.contains("f")),
"a recursive own method call counts when recursion is disallowed, got {calls:?}"
);
}
#[test]
fn receiver_of_wrong_type_is_not_an_own_call() {
let calls = own_calls_of(
"struct A; struct B; impl A { fn foo(&self) {} fn f(&self, b: B) { b.foo(); let _ = 0; } }",
"f",
);
assert!(
calls.is_empty(),
"a method call on a wrong-typed receiver is not an own call, got {calls:?}"
);
}
#[test]
fn self_receiver_resolves_to_parent_type_only() {
let calls = own_calls_of(
"struct A; impl A { fn foo(&self) {} } struct B; impl B { fn f(&self) { self.foo(); let _ = 0; } }",
"f",
);
assert!(
calls.is_empty(),
"self.foo() resolves to the parent type only, got {calls:?}"
);
}
#[test]
fn reference_typed_receiver_is_resolved() {
let calls = own_calls_of(
"struct A; struct B; impl A { fn foo(&self) {} fn f(&self, b: &B) { b.foo(); let _ = 0; } }",
"f",
);
assert!(
calls.is_empty(),
"a &B receiver resolves to B; A::foo on it is not an own call, got {calls:?}"
);
}
#[test]
fn method_with_extra_param_is_not_a_trivial_getter() {
let calls = own_calls_of(
"struct S { x: i32 } impl S { fn g(&self, n: i32) -> i32 { self.x } fn f(&self) -> i32 { self.g(1) } }",
"f",
);
assert!(
calls.iter().any(|c| c.contains("g")),
"a call to a non-trivial (extra-param) method is an own call, got {calls:?}"
);
}
#[test]
fn cast_accessor_body_is_a_trivial_getter() {
let calls = own_calls_of(
"struct S { x: i32 } impl S { fn g(&self) -> f64 { self.x as f64 } fn f(&self) -> f64 { self.g() } }",
"f",
);
assert!(
calls.is_empty(),
"a cast-accessor getter call is not an own call, got {calls:?}"
);
}
#[test]
fn unary_accessor_body_is_a_trivial_getter() {
let calls = own_calls_of(
"struct S { x: i32 } impl S { fn g(&self) -> i32 { -self.x } fn f(&self) -> i32 { self.g() } }",
"f",
);
assert!(
calls.is_empty(),
"a unary-accessor getter call is not an own call, got {calls:?}"
);
}
#[test]
fn paren_accessor_body_is_a_trivial_getter() {
let calls = own_calls_of(
"struct S { x: i32 } impl S { fn g(&self) -> i32 { (self.x) } fn f(&self) -> i32 { self.g() } }",
"f",
);
assert!(
calls.is_empty(),
"a paren-accessor getter call is not an own call, got {calls:?}"
);
}
#[test]
fn non_get_one_arg_method_breaks_trivial_accessor() {
let calls = own_calls_of(
"struct S { items: Vec<i32> } impl S { fn g(&self) -> i32 { self.items.bar(0) } fn f(&self) -> i32 { self.g() } }",
"f",
);
assert!(
calls.iter().any(|c| c.contains("g")),
"a one-arg non-get call is not a trivial accessor, so g is an own call, got {calls:?}"
);
}
#[test]
fn get_with_non_self_path_arg_breaks_trivial_accessor() {
let calls = own_calls_of(
"const IDX: usize = 0; struct S { items: Vec<i32> } impl S { fn g(&self) -> i32 { self.items.get(IDX) } fn f(&self) -> i32 { self.g() } }",
"f",
);
assert!(
calls.iter().any(|c| c.contains("g")),
"get(non_self_path) is not a trivial accessor, so g is an own call, got {calls:?}"
);
}