Skip to content

Commit 18c67a2

Browse files
committed
Implement BufferedSummary to collect the Edit
1 parent 7b3fa40 commit 18c67a2

File tree

1 file changed

+113
-48
lines changed

1 file changed

+113
-48
lines changed

googletest/src/matcher_support/summarize_diff.rs

Lines changed: 113 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ pub(crate) fn create_diff(
4949
"\nDifference({} / {}):{}",
5050
LineStyle::extra_actual_style().style("actual"),
5151
LineStyle::extra_expected_style().style("expected"),
52-
edit_list_summary(&edit_list)
52+
edit_list.into_iter().collect::<BufferedSummary>(),
5353
)
5454
.into(),
5555
edit_distance::Difference::Unrelated => "".into(),
@@ -85,73 +85,138 @@ pub(crate) fn create_diff_reversed(
8585
"\nDifference({} / {}):{}",
8686
LineStyle::extra_actual_style().style("actual"),
8787
LineStyle::extra_expected_style().style("expected"),
88-
edit_list_summary(&edit_list)
88+
edit_list.into_iter().collect::<BufferedSummary>(),
8989
)
9090
.into()
9191
}
9292
edit_distance::Difference::Unrelated => "".into(),
9393
}
9494
}
9595

96-
fn edit_list_summary(edit_list: &[edit_distance::Edit<&str>]) -> String {
97-
let mut summary = String::new();
98-
// Use to collect common line and compress them.
99-
let mut common_line_buffer = vec![];
100-
for edit in edit_list {
101-
let (style, line) = match edit {
102-
edit_distance::Edit::Both(same) => {
103-
common_line_buffer.push(*same);
104-
continue;
105-
}
106-
edit_distance::Edit::ExtraActual(actual) => (LineStyle::extra_actual_style(), *actual),
107-
edit_distance::Edit::ExtraExpected(expected) => {
108-
(LineStyle::extra_expected_style(), *expected)
109-
}
110-
edit_distance::Edit::AdditionalActual => {
111-
(LineStyle::comment_style(), "<---- remaining lines omitted ---->")
112-
}
113-
};
114-
summary.push_str(&compress_common_lines(std::mem::take(&mut common_line_buffer)));
96+
struct BufferedSummary<'a> {
97+
summary: String,
98+
buffer: Buffer<'a>,
99+
}
100+
101+
impl<'a> BufferedSummary<'a> {
102+
fn new() -> Self {
103+
Self { summary: String::new(), buffer: Buffer::CommonLineBuffer(vec![]) }
104+
}
105+
106+
fn feed_common_lines(&mut self, common_line: &'a str) {
107+
let Buffer::CommonLineBuffer(ref mut common_lines) = self.buffer;
108+
common_lines.push(common_line);
109+
}
110+
fn feed_extra_actual(&mut self, extra_actual: &'a str) {
111+
self.buffer.flush(&mut self.summary).unwrap();
112+
write!(&mut self.summary, "\n{}", LineStyle::extra_actual_style().style(extra_actual))
113+
.unwrap();
114+
}
115+
116+
fn feed_extra_expected(&mut self, extra_expected: &str) {
117+
self.flush_buffer();
118+
write!(&mut self.summary, "\n{}", LineStyle::extra_expected_style().style(extra_expected))
119+
.unwrap();
120+
}
115121

116-
write!(&mut summary, "\n{}", style.style(line)).unwrap();
122+
fn feed_additional_actual(&mut self) {
123+
self.flush_buffer();
124+
write!(
125+
&mut self.summary,
126+
"\n{}",
127+
LineStyle::comment_style().style("<---- remaining lines omitted ---->")
128+
)
129+
.unwrap();
117130
}
118-
summary.push_str(&compress_common_lines(common_line_buffer));
119131

120-
summary
132+
fn flush_buffer(&mut self) {
133+
self.buffer.flush(&mut self.summary).unwrap();
134+
}
121135
}
122136

123-
// The number of the lines kept before and after the compressed lines.
124-
const COMMON_LINES_CONTEXT_SIZE: usize = 2;
137+
impl<'a> FromIterator<edit_distance::Edit<&'a str>> for BufferedSummary<'a> {
138+
fn from_iter<T: IntoIterator<Item = edit_distance::Edit<&'a str>>>(iter: T) -> Self {
139+
let mut buffered_summary = BufferedSummary::new();
140+
for edit in iter {
141+
match edit {
142+
edit_distance::Edit::Both(same) => {
143+
buffered_summary.feed_common_lines(same);
144+
}
145+
edit_distance::Edit::ExtraActual(actual) => {
146+
buffered_summary.feed_extra_actual(actual);
147+
}
148+
edit_distance::Edit::ExtraExpected(expected) => {
149+
buffered_summary.feed_extra_expected(expected);
150+
}
151+
edit_distance::Edit::AdditionalActual => {
152+
buffered_summary.feed_additional_actual();
153+
}
154+
};
155+
}
156+
buffered_summary.flush_buffer();
157+
158+
buffered_summary
159+
}
160+
}
125161

126-
fn compress_common_lines(common_lines: Vec<&str>) -> String {
127-
if common_lines.len() <= 2 * COMMON_LINES_CONTEXT_SIZE + 1 {
128-
let mut all_lines = String::new();
129-
for line in common_lines {
130-
write!(&mut all_lines, "\n{}", LineStyle::unchanged_style().style(line)).unwrap();
162+
impl<'a> Display for BufferedSummary<'a> {
163+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
164+
if !matches!(self.buffer, Buffer::CommonLineBuffer(ref b) if b.is_empty()) {
165+
panic!("Buffer is not empty. This is a bug in gtest_rust.")
131166
}
132-
return all_lines;
167+
self.summary.fmt(f)
133168
}
169+
}
134170

135-
let mut truncated_lines = String::new();
171+
// This needs to be an enum as there will be in a follow-up PR new types of buffer, most likely actual and expected lines, to be compared with expected and actual lines for line to line comparison.
172+
enum Buffer<'a> {
173+
CommonLineBuffer(Vec<&'a str>),
174+
}
136175

137-
for line in &common_lines[0..COMMON_LINES_CONTEXT_SIZE] {
138-
write!(&mut truncated_lines, "\n{}", LineStyle::unchanged_style().style(line)).unwrap();
176+
impl<'a> Buffer<'a> {
177+
fn flush(&mut self, writer: impl std::fmt::Write) -> std::fmt::Result {
178+
match self {
179+
Buffer::CommonLineBuffer(common_lines) => {
180+
Self::flush_common_lines(std::mem::take(common_lines), writer)?
181+
}
182+
};
183+
Ok(())
139184
}
140185

141-
write!(
142-
&mut truncated_lines,
143-
"\n{}",
144-
LineStyle::comment_style().style(&format!(
145-
"<---- {} common lines omitted ---->",
146-
common_lines.len() - 2 * COMMON_LINES_CONTEXT_SIZE
147-
)),
148-
)
149-
.unwrap();
150-
151-
for line in &common_lines[common_lines.len() - COMMON_LINES_CONTEXT_SIZE..common_lines.len()] {
152-
write!(&mut truncated_lines, "\n{}", LineStyle::unchanged_style().style(line)).unwrap();
186+
fn flush_common_lines(
187+
common_lines: Vec<&'a str>,
188+
mut writer: impl std::fmt::Write,
189+
) -> std::fmt::Result {
190+
// The number of the lines kept before and after the compressed lines.
191+
const COMMON_LINES_CONTEXT_SIZE: usize = 2;
192+
193+
if common_lines.len() <= 2 * COMMON_LINES_CONTEXT_SIZE + 1 {
194+
for line in common_lines {
195+
write!(writer, "\n{}", LineStyle::unchanged_style().style(line))?;
196+
}
197+
return Ok(());
198+
}
199+
200+
for line in &common_lines[0..COMMON_LINES_CONTEXT_SIZE] {
201+
write!(writer, "\n{}", LineStyle::unchanged_style().style(line))?;
202+
}
203+
204+
write!(
205+
writer,
206+
"\n{}",
207+
LineStyle::comment_style().style(&format!(
208+
"<---- {} common lines omitted ---->",
209+
common_lines.len() - 2 * COMMON_LINES_CONTEXT_SIZE
210+
)),
211+
)?;
212+
213+
for line in
214+
&common_lines[common_lines.len() - COMMON_LINES_CONTEXT_SIZE..common_lines.len()]
215+
{
216+
write!(writer, "\n{}", LineStyle::unchanged_style().style(line))?;
217+
}
218+
Ok(())
153219
}
154-
truncated_lines
155220
}
156221

157222
struct LineStyle {

0 commit comments

Comments
 (0)