@@ -77,4 +77,239 @@ public Task ScrubLinesContaining_case_sensitive()
7777 f
7878 """ ) ;
7979 }
80+
81+ [ Fact ]
82+ public void FilterLines_RemovesSingleLine ( )
83+ {
84+ var builder = new StringBuilder ( "line1\n line2\n line3" ) ;
85+
86+ builder . FilterLines ( line => line == "line2" ) ;
87+
88+ Assert . Equal ( "line1\n line3" , builder . ToString ( ) ) ;
89+ }
90+
91+ [ Fact ]
92+ public void FilterLines_RemovesMultipleLines ( )
93+ {
94+ var builder = new StringBuilder ( "keep1\n remove1\n keep2\n remove2\n keep3" ) ;
95+
96+ builder . FilterLines ( line => line . StartsWith ( "remove" ) ) ;
97+
98+ Assert . Equal ( "keep1\n keep2\n keep3" , builder . ToString ( ) ) ;
99+ }
100+
101+ [ Fact ]
102+ public void FilterLines_RemovesAllLines ( )
103+ {
104+ var builder = new StringBuilder ( "line1\n line2\n line3" ) ;
105+
106+ builder . FilterLines ( _ => true ) ;
107+
108+ Assert . Equal ( string . Empty , builder . ToString ( ) ) ;
109+ }
110+
111+ [ Fact ]
112+ public void FilterLines_RemovesNoLines ( )
113+ {
114+ var builder = new StringBuilder ( "line1\n line2\n line3" ) ;
115+ var original = builder . ToString ( ) ;
116+
117+ builder . FilterLines ( _ => false ) ;
118+
119+ Assert . Equal ( original , builder . ToString ( ) ) ;
120+ }
121+
122+ [ Fact ]
123+ public void FilterLines_EmptyStringBuilder ( )
124+ {
125+ var builder = new StringBuilder ( ) ;
126+
127+ builder . FilterLines ( _ => true ) ;
128+
129+ Assert . Equal ( string . Empty , builder . ToString ( ) ) ;
130+ }
131+
132+ [ Fact ]
133+ public void FilterLines_SingleLineNoNewline ( )
134+ {
135+ var builder = new StringBuilder ( "single line" ) ;
136+
137+ builder . FilterLines ( _ => false ) ;
138+
139+ Assert . Equal ( "single line" , builder . ToString ( ) ) ;
140+ }
141+
142+ [ Fact ]
143+ public void FilterLines_SingleLineWithNewline ( )
144+ {
145+ var builder = new StringBuilder ( "single line\n " ) ;
146+
147+ builder . FilterLines ( _ => false ) ;
148+
149+ Assert . Equal ( "single line\n " , builder . ToString ( ) ) ;
150+ }
151+
152+ [ Fact ]
153+ public void FilterLines_PreservesTrailingNewline ( )
154+ {
155+ var builder = new StringBuilder ( "line1\n line2\n " ) ;
156+
157+ builder . FilterLines ( line => line == "line2" ) ;
158+
159+ Assert . Equal ( "line1\n " , builder . ToString ( ) ) ;
160+ }
161+
162+ [ Fact ]
163+ public void FilterLines_DoesNotAddTrailingNewlineWhenOriginalLacked ( )
164+ {
165+ var builder = new StringBuilder ( "line1\n line2" ) ;
166+
167+ builder . FilterLines ( line => line == "line1" ) ;
168+
169+ Assert . Equal ( "line2" , builder . ToString ( ) ) ;
170+ }
171+
172+ [ Fact ]
173+ public void FilterLines_HandlesEmptyLines ( )
174+ {
175+ var builder = new StringBuilder ( "line1\n \n line3" ) ;
176+
177+ builder . FilterLines ( string . IsNullOrEmpty ) ;
178+
179+ Assert . Equal ( "line1\n line3" , builder . ToString ( ) ) ;
180+ }
181+
182+ [ Fact ]
183+ public void FilterLines_KeepsEmptyLines ( )
184+ {
185+ var builder = new StringBuilder ( "line1\n \n line3" ) ;
186+
187+ builder . FilterLines ( line => line == "line1" ) ;
188+
189+ Assert . Equal ( "\n line3" , builder . ToString ( ) ) ;
190+ }
191+
192+ [ Fact ]
193+ public void FilterLines_OnlyEmptyLines ( )
194+ {
195+ var builder = new StringBuilder ( "\n \n " ) ;
196+
197+ builder . FilterLines ( _ => false ) ;
198+
199+ Assert . Equal ( "\n \n " , builder . ToString ( ) ) ;
200+ }
201+
202+ [ Fact ]
203+ public void FilterLines_RemovesFirstLine ( )
204+ {
205+ var builder = new StringBuilder ( "remove\n keep1\n keep2" ) ;
206+
207+ builder . FilterLines ( line => line == "remove" ) ;
208+
209+ Assert . Equal ( "keep1\n keep2" , builder . ToString ( ) ) ;
210+ }
211+
212+ [ Fact ]
213+ public void FilterLines_RemovesLastLine ( )
214+ {
215+ var builder = new StringBuilder ( "keep1\n keep2\n remove" ) ;
216+
217+ builder . FilterLines ( line => line == "remove" ) ;
218+
219+ Assert . Equal ( "keep1\n keep2" , builder . ToString ( ) ) ;
220+ }
221+
222+ [ Fact ]
223+ public void FilterLines_RemovesLastLineWithTrailingNewline ( )
224+ {
225+ var builder = new StringBuilder ( "keep1\n keep2\n remove\n " ) ;
226+
227+ builder . FilterLines ( line => line == "remove" ) ;
228+
229+ Assert . Equal ( "keep1\n keep2\n " , builder . ToString ( ) ) ;
230+ }
231+
232+ [ Fact ]
233+ public void FilterLines_ComplexPredicate ( )
234+ {
235+ var builder = new StringBuilder ( "abc123\n def456\n ghi789\n jkl012" ) ;
236+
237+ builder . FilterLines ( line => line . Any ( char . IsDigit ) && line . Contains ( '4' ) ) ;
238+
239+ Assert . Equal ( "abc123\n ghi789\n jkl012" , builder . ToString ( ) ) ;
240+ }
241+
242+ [ Fact ]
243+ public void FilterLines_WindowsLineEndings ( )
244+ {
245+ var builder = new StringBuilder ( "line1\r \n line2\r \n line3" ) ;
246+
247+ builder . FilterLines ( line => line == "line2" ) ;
248+
249+ // Note: StringReader normalizes \r\n to \n
250+ Assert . Equal ( "line1\n line3" , builder . ToString ( ) ) ;
251+ }
252+
253+ [ Fact ]
254+ public void FilterLines_MixedLineEndings ( )
255+ {
256+ var builder = new StringBuilder ( "line1\n line2\r \n line3" ) ;
257+
258+ builder . FilterLines ( line => line == "line2" ) ;
259+
260+ Assert . Equal ( "line1\n line3" , builder . ToString ( ) ) ;
261+ }
262+
263+ [ Fact ]
264+ public void FilterLines_LargeContent ( )
265+ {
266+ var lines = Enumerable . Range ( 1 , 1000 ) . Select ( i => $ "line{ i } ") ;
267+ var builder = new StringBuilder ( string . Join ( '\n ' , lines ) ) ;
268+
269+ builder . FilterLines ( line => int . Parse ( line [ 4 ..] ) % 2 == 0 ) ;
270+
271+ var remaining = builder . ToString ( ) . Split ( '\n ' ) ;
272+ Assert . Equal ( 500 , remaining . Length ) ;
273+ Assert . All ( remaining , line => Assert . True ( int . Parse ( line [ 4 ..] ) % 2 == 1 ) ) ;
274+ }
275+
276+ [ Fact ]
277+ public void FilterLines_PreservesWhitespace ( )
278+ {
279+ var builder = new StringBuilder ( " line1 \n \t line2\t \n line3 " ) ;
280+
281+ builder . FilterLines ( line => line . Trim ( ) == "line2" ) ;
282+
283+ Assert . Equal ( " line1 \n line3 " , builder . ToString ( ) ) ;
284+ }
285+
286+ [ Fact ]
287+ public void FilterLines_SingleLineRemoved ( )
288+ {
289+ var builder = new StringBuilder ( "remove this" ) ;
290+
291+ builder . FilterLines ( _ => true ) ;
292+
293+ Assert . Equal ( string . Empty , builder . ToString ( ) ) ;
294+ }
295+
296+ [ Fact ]
297+ public void FilterLines_AllButLastRemoved ( )
298+ {
299+ var builder = new StringBuilder ( "remove1\n remove2\n keep\n " ) ;
300+
301+ builder . FilterLines ( line => line . StartsWith ( "remove" ) ) ;
302+
303+ Assert . Equal ( "keep\n " , builder . ToString ( ) ) ;
304+ }
305+
306+ [ Fact ]
307+ public void FilterLines_MultipleConsecutiveRemoved ( )
308+ {
309+ var builder = new StringBuilder ( "keep1\n remove1\n remove2\n remove3\n keep2" ) ;
310+
311+ builder . FilterLines ( line => line . StartsWith ( "remove" ) ) ;
312+
313+ Assert . Equal ( "keep1\n keep2" , builder . ToString ( ) ) ;
314+ }
80315}
0 commit comments