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