@@ -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,85 @@ 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
+ let unparsed = records
643
+ . into_iter ( )
644
+ . map ( record_to_string)
645
+ . collect :: < Vec < _ > > ( ) ;
646
+
647
+ let output_contents = unparsed. join ( "\n " ) ;
648
+
649
+ let changeset = Changeset :: new ( & input_contents, & output_contents, "\n " ) ;
650
+
651
+ assert ! (
652
+ no_diffs( & changeset) ,
653
+ "Mismatch for {:?}\n \
654
+ *********\n \
655
+ diff:\n \
656
+ *********\n \
657
+ {}\n \n \
658
+ *********\n \
659
+ output:\n \
660
+ *********\n \
661
+ {}\n \n ",
662
+ filename,
663
+ UsefulDiffDisplay ( & changeset) ,
664
+ output_contents,
665
+ ) ;
666
+ }
667
+
668
+ fn record_to_string ( record : Record ) -> String {
669
+ if matches ! ( & record, Record :: Statement { .. } | Record :: Query { .. } ) {
670
+ // the statement parser includes a newline between the items but the display
671
+ // output does not, so add it here
672
+ // Not sure about this one
673
+ format ! ( "{}\n " , record)
674
+ } else {
675
+ record. to_string ( )
676
+ }
677
+ }
678
+
679
+ /// returns true if there are no differences in the changeset
680
+ fn no_diffs ( changeset : & Changeset ) -> bool {
681
+ changeset
682
+ . diffs
683
+ . iter ( )
684
+ . all ( |diff| matches ! ( diff, Difference :: Same ( _) ) )
685
+ }
686
+
687
+ struct UsefulDiffDisplay < ' a > ( & ' a Changeset ) ;
688
+
689
+ impl < ' a > std:: fmt:: Display for UsefulDiffDisplay < ' a > {
690
+ fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
691
+ self . 0 . diffs . iter ( ) . try_for_each ( |diff| match diff {
692
+ Difference :: Same ( x) => writeln ! ( f, "{x}" ) ,
693
+ Difference :: Add ( x) => writeln ! ( f, "+ {x}" ) ,
694
+ Difference :: Rem ( x) => writeln ! ( f, "- {x}" ) ,
695
+ } )
696
+ }
618
697
}
619
698
}
0 commit comments