@@ -47,7 +47,7 @@ pub(crate) fn create_diff(
47
47
"\n Difference({} / {}):{}" ,
48
48
LineStyle :: extra_actual_style( ) . style( "actual" ) ,
49
49
LineStyle :: extra_expected_style( ) . style( "expected" ) ,
50
- edit_list_summary ( & edit_list)
50
+ edit_list. into_iter ( ) . collect :: < BufferedSummary > ( ) ,
51
51
)
52
52
. into ( ) ,
53
53
edit_distance:: Difference :: Unrelated => "" . into ( ) ,
@@ -83,73 +83,150 @@ pub(crate) fn create_diff_reversed(
83
83
"\n Difference({} / {}):{}" ,
84
84
LineStyle :: extra_actual_style( ) . style( "actual" ) ,
85
85
LineStyle :: extra_expected_style( ) . style( "expected" ) ,
86
- edit_list_summary ( & edit_list)
86
+ edit_list. into_iter ( ) . collect :: < BufferedSummary > ( ) ,
87
87
)
88
88
. into ( )
89
89
}
90
90
edit_distance:: Difference :: Unrelated => "" . into ( ) ,
91
91
}
92
92
}
93
93
94
- fn edit_list_summary ( edit_list : & [ edit_distance:: Edit < & str > ] ) -> String {
95
- let mut summary = String :: new ( ) ;
96
- // Use to collect common line and compress them.
97
- let mut common_line_buffer = vec ! [ ] ;
98
- for edit in edit_list {
99
- let ( style, line) = match edit {
100
- edit_distance:: Edit :: Both ( same) => {
101
- common_line_buffer. push ( * same) ;
102
- continue ;
103
- }
104
- edit_distance:: Edit :: ExtraActual ( actual) => ( LineStyle :: extra_actual_style ( ) , * actual) ,
105
- edit_distance:: Edit :: ExtraExpected ( expected) => {
106
- ( LineStyle :: extra_expected_style ( ) , * expected)
107
- }
108
- edit_distance:: Edit :: AdditionalActual => {
109
- ( LineStyle :: comment_style ( ) , "<---- remaining lines omitted ---->" )
110
- }
111
- } ;
112
- summary. push_str ( & compress_common_lines ( std:: mem:: take ( & mut common_line_buffer) ) ) ;
94
+ // Aggregator collecting the lines to be printed in the difference summary.
95
+ //
96
+ // This is buffered in order to allow a future line to potentially impact how
97
+ // the current line would be printed.
98
+ struct BufferedSummary < ' a > {
99
+ summary : String ,
100
+ buffer : Buffer < ' a > ,
101
+ }
102
+
103
+ impl < ' a > BufferedSummary < ' a > {
104
+ // Appends a new line which is common to both actual and expected.
105
+ fn feed_common_lines ( & mut self , common_line : & ' a str ) {
106
+ let Buffer :: CommonLineBuffer ( ref mut common_lines) = self . buffer ;
107
+ common_lines. push ( common_line) ;
108
+ }
109
+
110
+ // Appends a new line which is found only in the actual string.
111
+ fn feed_extra_actual ( & mut self , extra_actual : & ' a str ) {
112
+ self . buffer . flush ( & mut self . summary ) . unwrap ( ) ;
113
+ write ! ( & mut self . summary, "\n {}" , LineStyle :: extra_actual_style( ) . style( extra_actual) )
114
+ . unwrap ( ) ;
115
+ }
113
116
114
- write ! ( & mut summary, "\n {}" , style. style( line) ) . unwrap ( ) ;
117
+ // Appends a new line which is found only in the expected string.
118
+ fn feed_extra_expected ( & mut self , extra_expected : & str ) {
119
+ self . flush_buffer ( ) ;
120
+ write ! ( & mut self . summary, "\n {}" , LineStyle :: extra_expected_style( ) . style( extra_expected) )
121
+ . unwrap ( ) ;
115
122
}
116
- summary. push_str ( & compress_common_lines ( common_line_buffer) ) ;
117
123
118
- summary
124
+ // Appends a comment for the additional line at the start or the end of the
125
+ // actual string which should be omitted.
126
+ fn feed_additional_actual ( & mut self ) {
127
+ self . flush_buffer ( ) ;
128
+ write ! (
129
+ & mut self . summary,
130
+ "\n {}" ,
131
+ LineStyle :: comment_style( ) . style( "<---- remaining lines omitted ---->" )
132
+ )
133
+ . unwrap ( ) ;
134
+ }
135
+
136
+ fn flush_buffer ( & mut self ) {
137
+ self . buffer . flush ( & mut self . summary ) . unwrap ( ) ;
138
+ }
119
139
}
120
140
121
- // The number of the lines kept before and after the compressed lines.
122
- const COMMON_LINES_CONTEXT_SIZE : usize = 2 ;
141
+ impl < ' a > FromIterator < edit_distance:: Edit < & ' a str > > for BufferedSummary < ' a > {
142
+ fn from_iter < T : IntoIterator < Item = edit_distance:: Edit < & ' a str > > > ( iter : T ) -> Self {
143
+ let mut buffered_summary =
144
+ BufferedSummary { summary : String :: new ( ) , buffer : Buffer :: CommonLineBuffer ( vec ! [ ] ) } ;
145
+ for edit in iter {
146
+ match edit {
147
+ edit_distance:: Edit :: Both ( same) => {
148
+ buffered_summary. feed_common_lines ( same) ;
149
+ }
150
+ edit_distance:: Edit :: ExtraActual ( actual) => {
151
+ buffered_summary. feed_extra_actual ( actual) ;
152
+ }
153
+ edit_distance:: Edit :: ExtraExpected ( expected) => {
154
+ buffered_summary. feed_extra_expected ( expected) ;
155
+ }
156
+ edit_distance:: Edit :: AdditionalActual => {
157
+ buffered_summary. feed_additional_actual ( ) ;
158
+ }
159
+ } ;
160
+ }
161
+ buffered_summary. flush_buffer ( ) ;
123
162
124
- fn compress_common_lines ( common_lines : Vec < & str > ) -> String {
125
- if common_lines. len ( ) <= 2 * COMMON_LINES_CONTEXT_SIZE + 1 {
126
- let mut all_lines = String :: new ( ) ;
127
- for line in common_lines {
128
- write ! ( & mut all_lines, "\n {}" , LineStyle :: unchanged_style( ) . style( line) ) . unwrap ( ) ;
163
+ buffered_summary
164
+ }
165
+ }
166
+
167
+ impl < ' a > Display for BufferedSummary < ' a > {
168
+ fn fmt ( & self , f : & mut std:: fmt:: Formatter < ' _ > ) -> std:: fmt:: Result {
169
+ if !matches ! ( self . buffer, Buffer :: CommonLineBuffer ( ref b) if b. is_empty( ) ) {
170
+ panic ! ( "Buffer is not empty. This is a bug in gtest_rust." )
129
171
}
130
- return all_lines ;
172
+ self . summary . fmt ( f )
131
173
}
174
+ }
132
175
133
- let mut truncated_lines = String :: new ( ) ;
176
+ // This needs to be an enum as there will be in a follow-up PR new types of
177
+ // buffer, most likely actual and expected lines, to be compared with expected
178
+ // and actual lines for line to line comparison.
179
+ enum Buffer < ' a > {
180
+ CommonLineBuffer ( Vec < & ' a str > ) ,
181
+ }
134
182
135
- for line in & common_lines[ 0 ..COMMON_LINES_CONTEXT_SIZE ] {
136
- write ! ( & mut truncated_lines, "\n {}" , LineStyle :: unchanged_style( ) . style( line) ) . unwrap ( ) ;
183
+ impl < ' a > Buffer < ' a > {
184
+ fn flush ( & mut self , writer : impl std:: fmt:: Write ) -> std:: fmt:: Result {
185
+ match self {
186
+ Buffer :: CommonLineBuffer ( common_lines) => {
187
+ Self :: flush_common_lines ( std:: mem:: take ( common_lines) , writer) ?
188
+ }
189
+ } ;
190
+ Ok ( ( ) )
137
191
}
138
192
139
- write ! (
140
- & mut truncated_lines,
141
- "\n {}" ,
142
- LineStyle :: comment_style( ) . style( & format!(
143
- "<---- {} common lines omitted ---->" ,
144
- common_lines. len( ) - 2 * COMMON_LINES_CONTEXT_SIZE
145
- ) ) ,
146
- )
147
- . unwrap ( ) ;
148
-
149
- for line in & common_lines[ common_lines. len ( ) - COMMON_LINES_CONTEXT_SIZE ..common_lines. len ( ) ] {
150
- write ! ( & mut truncated_lines, "\n {}" , LineStyle :: unchanged_style( ) . style( line) ) . unwrap ( ) ;
193
+ fn flush_common_lines (
194
+ common_lines : Vec < & ' a str > ,
195
+ mut writer : impl std:: fmt:: Write ,
196
+ ) -> std:: fmt:: Result {
197
+ // The number of the lines kept before and after the compressed lines.
198
+ const COMMON_LINES_CONTEXT_SIZE : usize = 2 ;
199
+
200
+ if common_lines. len ( ) <= 2 * COMMON_LINES_CONTEXT_SIZE + 1 {
201
+ for line in common_lines {
202
+ write ! ( writer, "\n {}" , LineStyle :: unchanged_style( ) . style( line) ) ?;
203
+ }
204
+ return Ok ( ( ) ) ;
205
+ }
206
+
207
+ let start_context = & common_lines[ 0 ..COMMON_LINES_CONTEXT_SIZE ] ;
208
+
209
+ for line in start_context {
210
+ write ! ( writer, "\n {}" , LineStyle :: unchanged_style( ) . style( line) ) ?;
211
+ }
212
+
213
+ write ! (
214
+ writer,
215
+ "\n {}" ,
216
+ LineStyle :: comment_style( ) . style( & format!(
217
+ "<---- {} common lines omitted ---->" ,
218
+ common_lines. len( ) - 2 * COMMON_LINES_CONTEXT_SIZE
219
+ ) ) ,
220
+ ) ?;
221
+
222
+ let end_context =
223
+ & common_lines[ common_lines. len ( ) - COMMON_LINES_CONTEXT_SIZE ..common_lines. len ( ) ] ;
224
+
225
+ for line in end_context {
226
+ write ! ( writer, "\n {}" , LineStyle :: unchanged_style( ) . style( line) ) ?;
227
+ }
228
+ Ok ( ( ) )
151
229
}
152
- truncated_lines
153
230
}
154
231
155
232
// Use ANSI code to enable styling on the summary lines.
0 commit comments