1 // Copyright 2022 Google LLC 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 // There are no visible documentation elements in this module. 16 #![doc(hidden)] 17 18 use crate::{ 19 description::Description, 20 matcher::{Matcher, MatcherResult}, 21 }; 22 use std::fmt::Debug; 23 24 /// Matcher created by [`Matcher::and`]. 25 /// 26 /// **For internal use only. API stablility is not guaranteed!** 27 #[doc(hidden)] 28 pub struct ConjunctionMatcher<M1, M2> { 29 m1: M1, 30 m2: M2, 31 } 32 33 impl<M1, M2> ConjunctionMatcher<M1, M2> { new(m1: M1, m2: M2) -> Self34 pub(crate) fn new(m1: M1, m2: M2) -> Self { 35 Self { m1, m2 } 36 } 37 } 38 39 impl<M1: Matcher, M2: Matcher<ActualT = M1::ActualT>> Matcher for ConjunctionMatcher<M1, M2> 40 where 41 M1::ActualT: Debug, 42 { 43 type ActualT = M1::ActualT; 44 matches(&self, actual: &M1::ActualT) -> MatcherResult45 fn matches(&self, actual: &M1::ActualT) -> MatcherResult { 46 match (self.m1.matches(actual), self.m2.matches(actual)) { 47 (MatcherResult::Match, MatcherResult::Match) => MatcherResult::Match, 48 _ => MatcherResult::NoMatch, 49 } 50 } 51 explain_match(&self, actual: &M1::ActualT) -> Description52 fn explain_match(&self, actual: &M1::ActualT) -> Description { 53 match (self.m1.matches(actual), self.m2.matches(actual)) { 54 (MatcherResult::Match, MatcherResult::Match) => Description::new() 55 .nested(self.m1.explain_match(actual)) 56 .text("and") 57 .nested(self.m2.explain_match(actual)), 58 (MatcherResult::NoMatch, MatcherResult::Match) => self.m1.explain_match(actual), 59 (MatcherResult::Match, MatcherResult::NoMatch) => self.m2.explain_match(actual), 60 (MatcherResult::NoMatch, MatcherResult::NoMatch) => Description::new() 61 .nested(self.m1.explain_match(actual)) 62 .text("and") 63 .nested(self.m2.explain_match(actual)), 64 } 65 } 66 describe(&self, matcher_result: MatcherResult) -> Description67 fn describe(&self, matcher_result: MatcherResult) -> Description { 68 format!("{}, and {}", self.m1.describe(matcher_result), self.m2.describe(matcher_result)) 69 .into() 70 } 71 } 72 73 #[cfg(test)] 74 mod tests { 75 use crate::prelude::*; 76 use indoc::indoc; 77 78 #[test] and_true_true_matches() -> Result<()>79 fn and_true_true_matches() -> Result<()> { 80 verify_that!(1, anything().and(anything())) 81 } 82 83 #[test] and_true_false_does_not_match() -> Result<()>84 fn and_true_false_does_not_match() -> Result<()> { 85 let result = verify_that!(1, anything().and(not(anything()))); 86 verify_that!( 87 result, 88 err(displays_as(contains_substring(indoc!( 89 " 90 Value of: 1 91 Expected: is anything, and never matches 92 Actual: 1, 93 which is anything 94 " 95 )))) 96 ) 97 } 98 99 #[test] and_false_true_does_not_match() -> Result<()>100 fn and_false_true_does_not_match() -> Result<()> { 101 let result = verify_that!(1, not(anything()).and(anything())); 102 verify_that!( 103 result, 104 err(displays_as(contains_substring(indoc!( 105 " 106 Value of: 1 107 Expected: never matches, and is anything 108 Actual: 1, 109 which is anything 110 " 111 )))) 112 ) 113 } 114 115 #[test] and_false_false_does_not_match() -> Result<()>116 fn and_false_false_does_not_match() -> Result<()> { 117 let result = verify_that!(1, not(anything()).and(not(anything()))); 118 verify_that!( 119 result, 120 err(displays_as(contains_substring(indoc!( 121 " 122 Value of: 1 123 Expected: never matches, and never matches 124 Actual: 1, 125 which is anything 126 and 127 which is anything 128 " 129 )))) 130 ) 131 } 132 133 #[test] chained_and_matches() -> Result<()>134 fn chained_and_matches() -> Result<()> { 135 #[derive(Debug)] 136 struct Struct { 137 a: i32, 138 b: i32, 139 c: i32, 140 } 141 verify_that!( 142 Struct { a: 1, b: 2, c: 3 }, 143 field!(Struct.a, eq(1)).and(field!(Struct.b, eq(2))).and(field!(Struct.c, eq(3))) 144 ) 145 } 146 147 #[test] works_with_str_slices() -> Result<()>148 fn works_with_str_slices() -> Result<()> { 149 verify_that!("A string", starts_with("A").and(ends_with("string"))) 150 } 151 152 #[test] works_with_owned_strings() -> Result<()>153 fn works_with_owned_strings() -> Result<()> { 154 verify_that!("A string".to_string(), starts_with("A").and(ends_with("string"))) 155 } 156 } 157