@@ -16,11 +16,11 @@ use walkdir::WalkDir;
1616
1717lazy_static ! {
1818 static ref HEADER_REGEX : ByteRegex =
19- ByteRegexBuilder :: new( r"^===+ (?P<suffix1>[^=\r\n][^\r\n]*)?\r?\n(?P<test_name>([^=\r\n][^\r\n]*\r?\n)+)===+(?P<suffix2>[^=\r\n][^\r\n]*)?\r?\n" )
19+ ByteRegexBuilder :: new( r"^(?P<equals>(?:=+){3,}) (?P<suffix1>[^=\r\n][^\r\n]*)?\r?\n(?P<test_name>([^=\r\n][^\r\n]*\r?\n)+)===+(?P<suffix2>[^=\r\n][^\r\n]*)?\r?\n" )
2020 . multi_line( true )
2121 . build( )
2222 . unwrap( ) ;
23- static ref DIVIDER_REGEX : ByteRegex = ByteRegexBuilder :: new( r"^---+ (?P<suffix>[^-\r\n][^\r\n]*)?\r?\n" )
23+ static ref DIVIDER_REGEX : ByteRegex = ByteRegexBuilder :: new( r"^(?P<hyphens>(?:-+){3,}) (?P<suffix>[^-\r\n][^\r\n]*)?\r?\n" )
2424 . multi_line( true )
2525 . build( )
2626 . unwrap( ) ;
@@ -40,6 +40,8 @@ pub enum TestEntry {
4040 name : String ,
4141 input : Vec < u8 > ,
4242 output : String ,
43+ header_delim_len : usize ,
44+ divider_delim_len : usize ,
4345 has_fields : bool ,
4446 } ,
4547}
@@ -179,21 +181,29 @@ fn run_tests(
179181 mut indent_level : i32 ,
180182 failures : & mut Vec < ( String , String , String ) > ,
181183 update : bool ,
182- corrected_entries : & mut Vec < ( String , String , String ) > ,
184+ corrected_entries : & mut Vec < ( String , String , String , usize , usize ) > ,
183185) -> Result < ( ) > {
184186 match test_entry {
185187 TestEntry :: Example {
186188 name,
187189 input,
188190 output,
191+ header_delim_len,
192+ divider_delim_len,
189193 has_fields,
190194 } => {
191195 if let Some ( filter) = filter {
192196 if !name. contains ( filter) {
193197 if update {
194198 let input = String :: from_utf8 ( input) . unwrap ( ) ;
195199 let output = format_sexp ( & output) ;
196- corrected_entries. push ( ( name, input, output) ) ;
200+ corrected_entries. push ( (
201+ name,
202+ input,
203+ output,
204+ header_delim_len,
205+ divider_delim_len,
206+ ) ) ;
197207 }
198208 return Ok ( ( ) ) ;
199209 }
@@ -203,21 +213,31 @@ fn run_tests(
203213 if !has_fields {
204214 actual = strip_sexp_fields ( actual) ;
205215 }
206- for _ in 0 ..indent_level {
207- print ! ( " " ) ;
208- }
216+ print ! ( "{}" , " " . repeat( indent_level as usize ) ) ;
209217 if actual == output {
210218 println ! ( "✓ {}" , Colour :: Green . paint( & name) ) ;
211219 if update {
212220 let input = String :: from_utf8 ( input) . unwrap ( ) ;
213221 let output = format_sexp ( & output) ;
214- corrected_entries. push ( ( name, input, output) ) ;
222+ corrected_entries. push ( (
223+ name,
224+ input,
225+ output,
226+ header_delim_len,
227+ divider_delim_len,
228+ ) ) ;
215229 }
216230 } else {
217231 if update {
218232 let input = String :: from_utf8 ( input) . unwrap ( ) ;
219233 let output = format_sexp ( & actual) ;
220- corrected_entries. push ( ( name. clone ( ) , input, output) ) ;
234+ corrected_entries. push ( (
235+ name. clone ( ) ,
236+ input,
237+ output,
238+ header_delim_len,
239+ divider_delim_len,
240+ ) ) ;
221241 println ! ( "✓ {}" , Colour :: Blue . paint( & name) ) ;
222242 } else {
223243 println ! ( "✗ {}" , Colour :: Red . paint( & name) ) ;
@@ -231,9 +251,7 @@ fn run_tests(
231251 file_path,
232252 } => {
233253 if indent_level > 0 {
234- for _ in 0 ..indent_level {
235- print ! ( " " ) ;
236- }
254+ print ! ( "{}" , " " . repeat( indent_level as usize ) ) ;
237255 println ! ( "{}:" , name) ;
238256 }
239257
@@ -314,27 +332,32 @@ fn format_sexp_indented(sexp: &String, initial_indent_level: u32) -> String {
314332 formatted
315333}
316334
317- fn write_tests ( file_path : & Path , corrected_entries : & Vec < ( String , String , String ) > ) -> Result < ( ) > {
335+ fn write_tests (
336+ file_path : & Path ,
337+ corrected_entries : & Vec < ( String , String , String , usize , usize ) > ,
338+ ) -> Result < ( ) > {
318339 let mut buffer = fs:: File :: create ( file_path) ?;
319340 write_tests_to_buffer ( & mut buffer, corrected_entries)
320341}
321342
322343fn write_tests_to_buffer (
323344 buffer : & mut impl Write ,
324- corrected_entries : & Vec < ( String , String , String ) > ,
345+ corrected_entries : & Vec < ( String , String , String , usize , usize ) > ,
325346) -> Result < ( ) > {
326- for ( i, ( name, input, output) ) in corrected_entries. iter ( ) . enumerate ( ) {
347+ for ( i, ( name, input, output, header_delim_len, divider_delim_len) ) in
348+ corrected_entries. iter ( ) . enumerate ( )
349+ {
327350 if i > 0 {
328351 write ! ( buffer, "\n " ) ?;
329352 }
330353 write ! (
331354 buffer,
332355 "{}\n {}\n {}\n {}\n {}\n \n {}\n " ,
333- "=" . repeat( 80 ) ,
356+ "=" . repeat( * header_delim_len ) ,
334357 name,
335- "=" . repeat( 80 ) ,
358+ "=" . repeat( * header_delim_len ) ,
336359 input,
337- "-" . repeat( 80 ) ,
360+ "-" . repeat( * divider_delim_len ) ,
338361 output. trim( )
339362 ) ?;
340363 }
@@ -398,6 +421,7 @@ fn parse_test_content(name: String, content: String, file_path: Option<PathBuf>)
398421 // Ignore any matches whose suffix does not match the first header
399422 // suffix in the file.
400423 let header_matches = HEADER_REGEX . captures_iter ( & bytes) . filter_map ( |c| {
424+ let header_delim_len = c. name ( "equals" ) . map ( |n| n. as_bytes ( ) . len ( ) ) . unwrap_or ( 80 ) ;
401425 let suffix1 = c
402426 . name ( "suffix1" )
403427 . map ( |m| String :: from_utf8_lossy ( m. as_bytes ( ) ) ) ;
@@ -409,33 +433,43 @@ fn parse_test_content(name: String, content: String, file_path: Option<PathBuf>)
409433 let test_name = c
410434 . name ( "test_name" )
411435 . map ( |c| String :: from_utf8_lossy ( c. as_bytes ( ) ) . trim_end ( ) . to_string ( ) ) ;
412- Some ( ( header_range, test_name) )
436+ let res = Some ( ( header_delim_len, header_range, test_name) ) ;
437+ res
413438 } else {
414439 None
415440 }
416441 } ) ;
417442
418- for ( header_range, test_name) in header_matches. chain ( Some ( ( bytes. len ( ) ..bytes. len ( ) , None ) ) ) {
443+ let mut prev_header_len = 80 ;
444+ for ( header_delim_len, header_range, test_name) in
445+ header_matches. chain ( Some ( ( 80 , bytes. len ( ) ..bytes. len ( ) , None ) ) )
446+ {
419447 // Find the longest line of dashes following each test description. That line
420448 // separates the input from the expected output. Ignore any matches whose suffix
421449 // does not match the first suffix in the file.
422450 if prev_header_end > 0 {
423451 let divider_range = DIVIDER_REGEX
424452 . captures_iter ( & bytes[ prev_header_end..header_range. start ] )
425453 . filter_map ( |m| {
454+ let divider_delim_len =
455+ m. name ( "hyphens" ) . map ( |m| m. as_bytes ( ) . len ( ) ) . unwrap_or ( 80 ) ;
426456 let suffix = m
427457 . name ( "suffix" )
428458 . map ( |m| String :: from_utf8_lossy ( m. as_bytes ( ) ) ) ;
429459 if suffix == first_suffix {
430460 let range = m. get ( 0 ) . unwrap ( ) . range ( ) ;
431- Some ( ( prev_header_end + range. start ) ..( prev_header_end + range. end ) )
461+ let res = Some ( (
462+ divider_delim_len,
463+ ( prev_header_end + range. start ) ..( prev_header_end + range. end ) ,
464+ ) ) ;
465+ res
432466 } else {
433467 None
434468 }
435469 } )
436- . max_by_key ( |range| range. len ( ) ) ;
470+ . max_by_key ( |( _ , range) | range. len ( ) ) ;
437471
438- if let Some ( divider_range) = divider_range {
472+ if let Some ( ( divider_delim_len , divider_range) ) = divider_range {
439473 if let Ok ( output) = str:: from_utf8 ( & bytes[ divider_range. end ..header_range. start ] ) {
440474 let mut input = bytes[ prev_header_end..divider_range. start ] . to_vec ( ) ;
441475
@@ -460,12 +494,15 @@ fn parse_test_content(name: String, content: String, file_path: Option<PathBuf>)
460494 name : prev_name,
461495 input,
462496 output,
497+ header_delim_len : prev_header_len,
498+ divider_delim_len,
463499 has_fields,
464500 } ) ;
465501 }
466502 }
467503 }
468504 prev_name = test_name. unwrap_or ( String :: new ( ) ) ;
505+ prev_header_len = header_delim_len;
469506 prev_header_end = header_range. end ;
470507 }
471508 TestEntry :: Group {
516553 name: "The first test" . to_string( ) ,
517554 input: "\n a b c\n " . as_bytes( ) . to_vec( ) ,
518555 output: "(a (b c))" . to_string( ) ,
556+ header_delim_len: 15 ,
557+ divider_delim_len: 3 ,
519558 has_fields: false ,
520559 } ,
521560 TestEntry :: Example {
522561 name: "The second test" . to_string( ) ,
523562 input: "d" . as_bytes( ) . to_vec( ) ,
524563 output: "(d)" . to_string( ) ,
564+ header_delim_len: 16 ,
565+ divider_delim_len: 3 ,
525566 has_fields: false ,
526567 } ,
527568 ] ,
@@ -570,12 +611,16 @@ abc
570611 name: "Code with dashes" . to_string( ) ,
571612 input: "abc\n ---\n defg\n ----\n hijkl" . as_bytes( ) . to_vec( ) ,
572613 output: "(a (b))" . to_string( ) ,
614+ header_delim_len: 18 ,
615+ divider_delim_len: 7 ,
573616 has_fields: false ,
574617 } ,
575618 TestEntry :: Example {
576619 name: "Code ending with dashes" . to_string( ) ,
577620 input: "abc\n -----------" . as_bytes( ) . to_vec( ) ,
578621 output: "(c (d))" . to_string( ) ,
622+ header_delim_len: 25 ,
623+ divider_delim_len: 19 ,
579624 has_fields: false ,
580625 } ,
581626 ] ,
@@ -619,11 +664,15 @@ abc
619664 "title 1" . to_string( ) ,
620665 "input 1" . to_string( ) ,
621666 "output 1" . to_string( ) ,
667+ 80 ,
668+ 80 ,
622669 ) ,
623670 (
624671 "title 2" . to_string( ) ,
625672 "input 2" . to_string( ) ,
626673 "output 2" . to_string( ) ,
674+ 80 ,
675+ 80 ,
627676 ) ,
628677 ] ;
629678 write_tests_to_buffer ( & mut buffer, & corrected_entries) . unwrap ( ) ;
@@ -700,18 +749,24 @@ code
700749 name: "sexp with comment" . to_string( ) ,
701750 input: "code" . as_bytes( ) . to_vec( ) ,
702751 output: "(a (b))" . to_string( ) ,
752+ header_delim_len: 18 ,
753+ divider_delim_len: 3 ,
703754 has_fields: false ,
704755 } ,
705756 TestEntry :: Example {
706757 name: "sexp with comment between" . to_string( ) ,
707758 input: "code" . as_bytes( ) . to_vec( ) ,
708759 output: "(a (b))" . to_string( ) ,
760+ header_delim_len: 18 ,
761+ divider_delim_len: 3 ,
709762 has_fields: false ,
710763 } ,
711764 TestEntry :: Example {
712765 name: "sexp with ';'" . to_string( ) ,
713766 input: "code" . as_bytes( ) . to_vec( ) ,
714767 output: "(MISSING \" ;\" )" . to_string( ) ,
768+ header_delim_len: 25 ,
769+ divider_delim_len: 3 ,
715770 has_fields: false ,
716771 }
717772 ] ,
@@ -784,18 +839,24 @@ NOT A TEST HEADER
784839 name: "First test" . to_string( ) ,
785840 input: expected_input. clone( ) ,
786841 output: "(a)" . to_string( ) ,
842+ header_delim_len: 18 ,
843+ divider_delim_len: 3 ,
787844 has_fields: false ,
788845 } ,
789846 TestEntry :: Example {
790847 name: "Second test" . to_string( ) ,
791848 input: expected_input. clone( ) ,
792849 output: "(a)" . to_string( ) ,
850+ header_delim_len: 18 ,
851+ divider_delim_len: 3 ,
793852 has_fields: false ,
794853 } ,
795854 TestEntry :: Example {
796855 name: "Test name with = symbol" . to_string( ) ,
797856 input: expected_input. clone( ) ,
798857 output: "(a)" . to_string( ) ,
858+ header_delim_len: 25 ,
859+ divider_delim_len: 3 ,
799860 has_fields: false ,
800861 }
801862 ] ,
@@ -839,12 +900,16 @@ code with ----
839900 name: "name\n with\n newlines" . to_string( ) ,
840901 input: b"a" . to_vec( ) ,
841902 output: "(b)" . to_string( ) ,
903+ header_delim_len: 15 ,
904+ divider_delim_len: 3 ,
842905 has_fields: false ,
843906 } ,
844907 TestEntry :: Example {
845908 name: "name with === signs" . to_string( ) ,
846909 input: b"code with ----" . to_vec( ) ,
847910 output: "(d)" . to_string( ) ,
911+ header_delim_len: 20 ,
912+ divider_delim_len: 3 ,
848913 has_fields: false ,
849914 }
850915 ]
0 commit comments