mod verify_pred { use googletest::prelude::*; use indoc::indoc; #[test] fn supports_function_call_with_non_debug_types() -> Result<()> { // Non-Debug - cannot be printed. struct Apple; fn f(_a: &Apple, _b: u32, _c: u32) -> bool { false } fn g(_a: u32) -> u32 { 5 } let a = &Apple; let res = verify_pred!(f(a, g(g(3)), 1 + 2)); verify_that!( res, err(displays_as(contains_substring(indoc! {" f(a, g(g(3)), 1 + 2) was false with a does not implement Debug, g(g(3)) = 5, 1 + 2 = 3, at" }))) ) } #[test] fn supports_trailing_comma() -> Result<()> { verify_that!(verify_pred!(false,), err(anything())) } #[test] fn supports_non_function() -> Result<()> { verify_pred!(true)?; verify_that!(verify_pred!(false), err(anything())) } #[test] fn does_not_print_literals() -> Result<()> { trait Foo { fn f(&self, _a: u32, _b: i32, _c: u32, _d: &str) -> bool { false } } impl Foo for i32 {} let res = verify_pred!(0.f(1, 2_i32.abs(), 1 + 2, "hello")); verify_that!( res, err(displays_as(contains_substring(indoc! {r#" 0.f(1, 2_i32.abs(), 1 + 2, "hello") was false with 2_i32.abs() = 2, 1 + 2 = 3, at"# }))) ) } #[test] fn supports_chained_field_access_and_method_calls_with_non_debug_types() -> Result<()> { // Non-Debug struct Apple { b: Banana, } #[derive(Debug)] struct Banana; impl Banana { fn c(&self, _c: &Cherry, _d: u32) -> bool { false } } // Non-Debug - cannot be printed. struct Cherry; let a = Apple { b: Banana }; let c = &Cherry; let d = 3; let res = verify_pred!(a.b.c(c, d)); verify_that!( res, err(displays_as(contains_substring(indoc! {" a.b.c(c, d) was false with a does not implement Debug, a.b = Banana, c does not implement Debug, d = 3, at" }))) ) } #[test] fn evaluates_functions_and_arguments_exactly_once() -> Result<()> { let mut a = 0; let mut foo = |_b: u32| { a += 1; false }; let mut b = 0; let mut bar = || { b += 10; b }; let res = verify_pred!(foo(bar())); verify_that!( res, err(displays_as(contains_substring(indoc! {" foo(bar()) was false with bar() = 10, at" }))) )?; verify_that!((a, b), eq((1, 10))) } #[test] fn evaluates_methods_and_arguments_exactly_once() -> Result<()> { struct Apple(u32); impl Apple { fn c(&mut self, _b: bool) -> bool { self.0 += 1; false } } let mut a = Apple(0); let mut b = Apple(10); let res = verify_pred!(a.c(b.c(false))); verify_that!( res, err(displays_as(contains_substring(indoc! {" a.c(b.c(false)) was false with a does not implement Debug, b.c(false) = false, at" }))) )?; verify_that!((a.0, b.0), eq((1, 11))) } #[test] fn supports_chained_method_calls() -> Result<()> { #[derive(Debug)] struct Apple; impl Apple { fn b(&self, _b: u32) -> Banana { Banana } } // Non-Debug: not printed on error. struct Banana; impl Banana { fn c(&self, _c0: u32, _c1: Cherry) -> bool { false } } // Non-Debug: not printed on error. #[derive(Copy, Clone)] struct Cherry; let a = Apple; let v = 10; let res = verify_pred!(a.b(v).c(11, Cherry)); verify_that!( res, err(displays_as(contains_substring(indoc! {" a.b(v).c(11, Cherry) was false with a = Apple, v = 10, a.b(v) does not implement Debug, Cherry does not implement Debug, at" }))) ) } #[test] fn prints_consumed_values() -> Result<()> { // Non-Debug struct Apple; impl Apple { fn b(self) -> Banana { Banana } } #[derive(Debug)] struct Banana; impl Banana { fn c(self) -> bool { false } } let a = Apple; let res = verify_pred!(a.b().c()); verify_that!( res, err(displays_as(contains_substring(indoc! {" a.b().c() was false with a does not implement Debug, a.b() = Banana, at" }))) ) } #[test] fn works_with_realistic_example_with_consumed_intermediate_values() -> Result<()> { let res = verify_pred!(vec![1, 2].into_iter().map(|x| x * 2).collect::>().is_empty()); verify_that!( res, err(displays_as(contains_substring(indoc! {" vec! [1, 2].into_iter().map(| x | x * 2).collect :: < Vec < _ > > ().is_empty() was false with vec! [1, 2] = [1, 2], vec! [1, 2].into_iter() = IntoIter([1, 2]), | x | x * 2 does not implement Debug, vec! [1, 2].into_iter().map(| x | x * 2) = Map { iter: IntoIter([1, 2]) }, vec! [1, 2].into_iter().map(| x | x * 2).collect :: < Vec < _ > > () = [2, 4], at" }))) ) } #[test] fn values_should_be_accessible_after_test() -> Result<()> { // Not `Copy` and should not be consumed by the generated test code. #[derive(Debug)] struct Apple; impl Apple { fn b(&self, _c: &mut u32) -> bool { false } } let mut c = 0; let a = Apple; let res = verify_pred!(a.b(&mut c)); verify_that!( res, err(displays_as(contains_substring(indoc! {" a.b(& mut c) was false with a = Apple, & mut c = 0, at" }))) )?; // `a` and `&mut c` should still be accessible after the test despite not being // `Copy`. let _ = a.b(&mut c); Ok(()) } #[test] fn prints_values_for_mutating_expressions() -> Result<()> { let mut a = 1; let mut b = 2; let mut c = 0; trait Mutator { fn mutate_and_false(&mut self, b: &mut u32) -> bool; } impl Mutator for u32 { fn mutate_and_false(&mut self, b: &mut u32) -> bool { *self += 10; *b += 20; false } } // Macro to to avoid the inconsistency in how `;` and `&mut` are printed between // Rust versions when printing out the stringified version of the block. macro_rules! block_a { () => {{ c += 10; &mut a }}; } macro_rules! block_b { () => {{ c += 100; &mut b }}; } let res = verify_pred! { block_a!().mutate_and_false(block_b!()) }; verify_that!( res, err(displays_as(contains_substring(indoc! {" block_a! ().mutate_and_false(block_b! ()) was false with block_a! () = 1, block_b! () = 2, at" }))) )?; verify_that!((a, b, c), eq((11, 22, 110))) } #[test] fn values_can_be_insulated_with_parens() -> Result<()> { // Not `Copy` and has a consuming method. struct Apple; impl Apple { fn b(self) -> Banana { Banana } } #[derive(Debug)] struct Banana; impl Banana { fn c(&self) -> bool { false } } let a = Apple; let res = verify_pred!({ a.b() }.c()); verify_that!( res, err(displays_as(contains_substring(indoc! {" { a.b() }.c() was false with { a.b() } = Banana, at" }))) ) } #[test] fn binary_operator() -> Result<()> { // Add chaining and function calls. fn f(x: u32) -> u32 { x + 1 } #[derive(Debug)] struct Apple; impl Apple { fn b(&self, y: u32) -> u32 { y + 10 } } let a = Apple; let x = 1; let y = 2; let res = verify_pred!(f(x) - 1 == a.b(y + 1) + f(y)); verify_that!( res, err(displays_as(contains_substring(indoc! {" f(x) - 1 == a.b(y + 1) + f(y) was false with x = 1, f(x) = 2, f(x) - 1 = 1, a = Apple, y + 1 = 3, a.b(y + 1) = 13, y = 2, f(y) = 3, a.b(y + 1) + f(y) = 16, at" }))) ) } #[rustversion::before(1.77)] #[test] fn unary_operator() -> Result<()> { #[derive(Debug)] struct Apple; impl Apple { fn b(&self, _b: u32, _c: i32) -> i32 { 0 } } let a = Apple; let b = 1; let res = verify_pred!(!a.b(b, -1) == !-2); verify_that!( res, err(displays_as(contains_substring(indoc! {" ! a.b(b, - 1) ==! - 2 was false with a = Apple, b = 1, a.b(b, - 1) = 0, ! a.b(b, - 1) = -1, ! - 2 = 1, at" }))) ) } #[rustversion::since(1.77)] #[test] fn unary_operator() -> Result<()> { #[derive(Debug)] struct Apple; impl Apple { fn b(&self, _b: u32, _c: i32) -> i32 { 0 } } let a = Apple; let b = 1; let res = verify_pred!(!a.b(b, -1) == !-2); verify_that!( res, err(displays_as(contains_substring(indoc! {" ! a.b(b, - 1) == ! - 2 was false with a = Apple, b = 1, a.b(b, - 1) = 0, ! a.b(b, - 1) = -1, ! - 2 = 1, at" }))) ) } }