Skip to content

Commit dda1212

Browse files
hovinenbcopybara-github
authored andcommitted
Support showing a diff of the actual and expected multi-line strings in StrMatcher.
This can make the diagnosis of a mismatched string much easier, since it highlights exactly which lines differ. Previously, the actual and expected strings were shown as debug output, making finding the difference extremely tedious. This is anlogous to the recent work on `EqMatcher`. Currently this does not support the additional options of `StrMatcher` such as ignoring leading and trailing whitespace. When any of those options are set, the diff output will not appear. There are TODOs in the code to cover this. PiperOrigin-RevId: 533480053
1 parent c6303be commit dda1212

File tree

2 files changed

+125
-5
lines changed

2 files changed

+125
-5
lines changed

googletest/src/matcher_support/edit_distance.rs

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -109,13 +109,10 @@ pub(crate) enum Mode {
109109
/// `right` is fully matching `left`
110110
FullMatch,
111111
/// `right` should match the beginning of `left`
112-
#[allow(unused)]
113112
StartsWith,
114113
/// `right` should match the end of `left`
115-
#[allow(unused)]
116114
EndsWith,
117115
/// `right` should be contained in `left`
118-
#[allow(unused)]
119116
Contains,
120117
}
121118

googletest/src/matchers/str_matcher.rs

Lines changed: 125 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,14 @@
1212
// See the License for the specific language governing permissions and
1313
// limitations under the License.
1414

15-
use crate::matcher::{Matcher, MatcherResult};
16-
use crate::matchers::{eq_deref_of_matcher::EqDerefOfMatcher, eq_matcher::EqMatcher};
15+
use crate::{
16+
matcher::{Matcher, MatcherResult},
17+
matcher_support::edit_distance,
18+
matchers::{
19+
eq_deref_of_matcher::EqDerefOfMatcher,
20+
eq_matcher::{create_diff, EqMatcher},
21+
},
22+
};
1723
use std::borrow::Cow;
1824
use std::fmt::Debug;
1925
use std::marker::PhantomData;
@@ -300,6 +306,10 @@ where
300306
fn describe(&self, matcher_result: MatcherResult) -> String {
301307
self.configuration.describe(matcher_result, self.expected.deref())
302308
}
309+
310+
fn explain_match(&self, actual: &ActualT) -> String {
311+
self.configuration.explain_match(self.expected.deref(), actual.as_ref())
312+
}
303313
}
304314

305315
impl<ActualT: ?Sized, ExpectedT, MatcherT: Into<StrMatcher<ActualT, ExpectedT>>>
@@ -485,6 +495,55 @@ impl Configuration {
485495
format!("{match_mode_description} {expected:?}{extra}")
486496
}
487497

498+
fn explain_match(&self, expected: &str, actual: &str) -> String {
499+
let default_explanation = format!(
500+
"which {}",
501+
self.describe(self.do_strings_match(expected, actual).into(), expected)
502+
);
503+
if !expected.contains('\n') || !actual.contains('\n') {
504+
return default_explanation;
505+
}
506+
507+
if self.ignore_leading_whitespace {
508+
// TODO - b/283448414 : Support StrMatcher with ignore_leading_whitespace.
509+
return default_explanation;
510+
}
511+
512+
if self.ignore_trailing_whitespace {
513+
// TODO - b/283448414 : Support StrMatcher with ignore_trailing_whitespace.
514+
return default_explanation;
515+
}
516+
517+
if self.times.is_some() {
518+
// TODO - b/283448414 : Support StrMatcher with times.
519+
return default_explanation;
520+
}
521+
if matches!(self.case_policy, CasePolicy::IgnoreAscii) {
522+
// TODO - b/283448414 : Support StrMatcher with ignore ascii case policy.
523+
return default_explanation;
524+
}
525+
if self.do_strings_match(expected, actual) {
526+
// TODO - b/283448414 : Consider supporting debug difference if the
527+
// strings match. This can be useful when a small contains is found
528+
// in a long string.
529+
return default_explanation;
530+
}
531+
532+
format!(
533+
"{default_explanation}\n{}",
534+
create_diff(expected, actual, self.get_edit_distance_mode())
535+
)
536+
}
537+
538+
fn get_edit_distance_mode(&self) -> edit_distance::Mode {
539+
match self.mode {
540+
MatchMode::Equals => edit_distance::Mode::FullMatch,
541+
MatchMode::Contains => edit_distance::Mode::Contains,
542+
MatchMode::StartsWith => edit_distance::Mode::StartsWith,
543+
MatchMode::EndsWith => edit_distance::Mode::EndsWith,
544+
}
545+
}
546+
488547
fn ignoring_leading_whitespace(self) -> Self {
489548
Self { ignore_leading_whitespace: true, ..self }
490549
}
@@ -523,6 +582,7 @@ mod tests {
523582
use super::{contains_substring, ends_with, starts_with, StrMatcher, StrMatcherConfigurator};
524583
use crate::matcher::{Matcher, MatcherResult};
525584
use crate::prelude::*;
585+
use indoc::indoc;
526586

527587
#[test]
528588
fn matches_string_reference_with_equal_string_reference() -> Result<()> {
@@ -881,4 +941,67 @@ mod tests {
881941
eq("does not end with \"A string\"")
882942
)
883943
}
944+
945+
#[test]
946+
fn match_explanation_contains_diff_of_strings_if_more_than_one_line() -> Result<()> {
947+
let result = verify_that!(
948+
indoc!(
949+
"
950+
First line
951+
Second line
952+
Third line
953+
"
954+
),
955+
starts_with(indoc!(
956+
"
957+
First line
958+
Second lines
959+
Third line
960+
"
961+
))
962+
);
963+
964+
verify_that!(
965+
result,
966+
err(displays_as(contains_substring(indoc!(
967+
"
968+
First line
969+
+Second line
970+
-Second lines
971+
Third line
972+
"
973+
))))
974+
)
975+
}
976+
977+
#[test]
978+
fn match_explanation_does_not_show_diff_if_actual_value_is_single_line() -> Result<()> {
979+
let result = verify_that!(
980+
"First line",
981+
starts_with(indoc!(
982+
"
983+
Second line
984+
Third line
985+
"
986+
))
987+
);
988+
989+
verify_that!(result, err(displays_as(not(contains_substring("Difference:")))))
990+
}
991+
992+
#[test]
993+
fn match_explanation_does_not_show_diff_if_expected_value_is_single_line() -> Result<()> {
994+
let result = verify_that!(
995+
indoc!(
996+
"
997+
First line
998+
Second line
999+
Third line
1000+
"
1001+
),
1002+
starts_with("Second line")
1003+
);
1004+
1005+
verify_that!(result, err(displays_as(not(contains_substring("Difference:")))))
1006+
}
8841007
}

0 commit comments

Comments
 (0)