Skip to content

Commit f33545b

Browse files
committed
Add test for reparsing
Signed-off-by: Andrew Lamb <[email protected]>
1 parent c2ff663 commit f33545b

File tree

2 files changed

+84
-2
lines changed

2 files changed

+84
-2
lines changed

sqllogictest/src/parser.rs

+83-2
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,7 @@ pub enum Record {
132132
},
133133
Condition(Condition),
134134
Comment(Vec<String>),
135+
Whitespace(String),
135136
/// Internally injected record which should not occur in the test file.
136137
Injected(Injected),
137138
}
@@ -242,6 +243,9 @@ impl std::fmt::Display for Record {
242243
}
243244
Ok(())
244245
}
246+
Record::Whitespace(w) => {
247+
write!(f, "{}", w)
248+
}
245249
Record::Injected(p) => panic!("unexpected injected record: {:?}", p),
246250
}
247251
}
@@ -397,6 +401,7 @@ fn parse_inner(loc: &Location, script: &str) -> Result<Vec<Record>, ParseError>
397401
}
398402

399403
if line.is_empty() {
404+
records.push(Record::Whitespace(line.to_string()));
400405
continue;
401406
}
402407

@@ -609,11 +614,87 @@ fn parse_file_inner(loc: Location) -> Result<Vec<Record>, ParseError> {
609614

610615
#[cfg(test)]
611616
mod tests {
612-
use crate::parse_file;
617+
use difference::{Changeset, Difference};
618+
619+
use super::*;
613620

614621
#[test]
615622
fn test_include_glob() {
616623
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+
}
618699
}
619700
}

sqllogictest/src/runner.rs

+1
Original file line numberDiff line numberDiff line change
@@ -546,6 +546,7 @@ impl<D: AsyncDB> Runner<D> {
546546
}
547547
Record::Include { .. }
548548
| Record::Comment(_)
549+
| Record::Whitespace(_)
549550
| Record::Subtest { .. }
550551
| Record::Halt { .. }
551552
| Record::Injected(_)

0 commit comments

Comments
 (0)