@@ -132,6 +132,7 @@ pub enum Record {
132
132
} ,
133
133
Condition ( Condition ) ,
134
134
Comment ( Vec < String > ) ,
135
+ Whitespace ( String ) ,
135
136
/// Internally injected record which should not occur in the test file.
136
137
Injected ( Injected ) ,
137
138
}
@@ -242,6 +243,9 @@ impl std::fmt::Display for Record {
242
243
}
243
244
Ok ( ( ) )
244
245
}
246
+ Record :: Whitespace ( w) => {
247
+ write ! ( f, "{}" , w)
248
+ }
245
249
Record :: Injected ( p) => panic ! ( "unexpected injected record: {:?}" , p) ,
246
250
}
247
251
}
@@ -397,6 +401,7 @@ fn parse_inner(loc: &Location, script: &str) -> Result<Vec<Record>, ParseError>
397
401
}
398
402
399
403
if line. is_empty ( ) {
404
+ records. push ( Record :: Whitespace ( line. to_string ( ) ) ) ;
400
405
continue ;
401
406
}
402
407
@@ -609,11 +614,87 @@ fn parse_file_inner(loc: Location) -> Result<Vec<Record>, ParseError> {
609
614
610
615
#[ cfg( test) ]
611
616
mod tests {
612
- use crate :: parse_file;
617
+ use difference:: { Changeset , Difference } ;
618
+
619
+ use super :: * ;
613
620
614
621
#[ test]
615
622
fn test_include_glob ( ) {
616
623
let records = parse_file ( "../examples/include/include_1.slt" ) . unwrap ( ) ;
617
- assert_eq ! ( 14 , records. len( ) ) ;
624
+ assert_eq ! ( 16 , records. len( ) ) ;
625
+ }
626
+
627
+ #[ test]
628
+ fn test_basic ( ) {
629
+ parse_roundtrip ( "../examples/basic/basic.slt" )
630
+ }
631
+
632
+ /// Parses the specified file into Records, and ensures the
633
+ /// results of unparsing them are the same
634
+ ///
635
+ /// Prints a hopefully useful message on failure
636
+ fn parse_roundtrip ( filename : impl AsRef < Path > ) {
637
+ let filename = filename. as_ref ( ) ;
638
+ let input_contents = std:: fs:: read_to_string ( filename) . expect ( "reading file" ) ;
639
+
640
+ let records = parse_file ( filename) . expect ( "parsing to complete" ) ;
641
+
642
+ println ! ( "Parsed records:\n {:#?}" , records) ;
643
+
644
+ let unparsed = records
645
+ . into_iter ( )
646
+ . map ( |r| record_to_string ( r) )
647
+ . collect :: < Vec < _ > > ( ) ;
648
+
649
+ let output_contents = unparsed. join ( "\n " ) ;
650
+
651
+ let changeset = Changeset :: new ( & input_contents, & output_contents, "\n " ) ;
652
+
653
+ assert ! (
654
+ no_diffs( & changeset) ,
655
+ "Mismatch for {:?}\n \
656
+ *********\n \
657
+ diff:\n \
658
+ *********\n \
659
+ {}\n \n \
660
+ *********\n \
661
+ output:\n \
662
+ *********\n \
663
+ {}\n \n ",
664
+ filename,
665
+ UsefulDiffDisplay ( & changeset) ,
666
+ output_contents,
667
+ ) ;
668
+ }
669
+
670
+ fn record_to_string ( record : Record ) -> String {
671
+ if matches ! ( & record, Record :: Statement { .. } | Record :: Query { .. } ) {
672
+ // the statement parser includes a newline between the items but the display
673
+ // output does not, so add it here
674
+ // Not sure about this one
675
+ format ! ( "{}\n " , record)
676
+ } else {
677
+ record. to_string ( )
678
+ }
679
+ }
680
+
681
+ /// returns true if there are no differences in the changeset
682
+ fn no_diffs ( changeset : & Changeset ) -> bool {
683
+ changeset
684
+ . diffs
685
+ . iter ( )
686
+ . all ( |diff| matches ! ( diff, Difference :: Same ( _) ) )
687
+ }
688
+
689
+ struct UsefulDiffDisplay < ' a > ( & ' a Changeset ) ;
690
+
691
+ impl < ' a > std:: fmt:: Display for UsefulDiffDisplay < ' a > {
692
+ fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
693
+ self . 0 . diffs . iter ( ) . try_for_each ( |diff| match diff {
694
+ Difference :: Same ( x) => writeln ! ( f, "{x}" ) ,
695
+ Difference :: Add ( x) => writeln ! ( f, "+ {x}" ) ,
696
+ Difference :: Rem ( x) => writeln ! ( f, "- {x}" ) ,
697
+ } )
698
+ }
618
699
}
619
700
}
0 commit comments