| 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::<Vec<_>>().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" |
| }))) |
| ) |
| } |
| } |