Skip to content

Commit dc6c6d4

Browse files
authored
feat(runner): support <slt:ignore> (#266)
Signed-off-by: xxchan <[email protected]>
1 parent facb127 commit dc6c6d4

File tree

3 files changed

+85
-0
lines changed

3 files changed

+85
-0
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## Unreleased
99

10+
* runner: Add `<slt:ignore>` to skip the volatile parts of the output.
11+
1012
## [0.28.3] - 2025-05-16
1113

1214
* bin: Add `--shutdown-timeout` to set a timeout for shutting down the database connections after a test file is finished. By default, this is unspecified, meaning to wait forever.

README.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,19 @@ SELECT * FROM foo;
7373
4 5
7474
```
7575

76+
### Extension: Ignore volatile parts of output
77+
78+
You can use `<slt:ignore>` to skip the volatile parts of the output. This is helpful for e.g., testing the format
79+
of `EXPLAIN`-like statements.
80+
81+
```text
82+
query T
83+
EXPLAIN SELECT * FROM foo;
84+
----
85+
Seq Scan on t (cost=<slt:ignore> rows=<slt:ignore> width=<slt:ignore>)
86+
Filter: (x > 1)
87+
```
88+
7689
### Extension: Run a query/statement that should fail with the expacted error message
7790

7891
The syntax:

sqllogictest/src/runner.rs

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -487,6 +487,44 @@ pub fn default_validator(
487487
actual: &[Vec<String>],
488488
expected: &[String],
489489
) -> bool {
490+
// Support ignore marker <slt:ignore> to skip volatile parts of output.
491+
const IGNORE_MARKER: &str = "<slt:ignore>";
492+
let contains_ignore_marker = expected.iter().any(|line| line.contains(IGNORE_MARKER));
493+
494+
// Normalize expected lines.
495+
// If ignore marker present, perform fragment-based matching on the full snapshot.
496+
if contains_ignore_marker {
497+
// If ignore marker present, perform fragment-based matching on the full snapshot.
498+
// The actual results might contain \n, and may not be a normal "row", which is not suitable to normalize.
499+
let expected_results = expected;
500+
let actual_rows = actual
501+
.iter()
502+
.map(|strs| strs.iter().join(" "))
503+
.collect_vec();
504+
505+
let expected_snapshot = expected_results.join("\n");
506+
let actual_snapshot = actual_rows.join("\n");
507+
let fragments: Vec<&str> = expected_snapshot.split(IGNORE_MARKER).collect();
508+
let mut pos = 0;
509+
for frag in fragments {
510+
if frag.is_empty() {
511+
continue;
512+
}
513+
if let Some(idx) = actual_snapshot[pos..].find(frag) {
514+
pos += idx + frag.len();
515+
} else {
516+
tracing::error!(
517+
"mismatch at: {}\nexpected: {}\nactual: {}",
518+
pos,
519+
frag,
520+
&actual_snapshot[pos..]
521+
);
522+
return false;
523+
}
524+
}
525+
return true;
526+
}
527+
490528
let expected_results = expected.iter().map(normalizer).collect_vec();
491529
// Default, we compare normalized results. Whitespace characters are ignored.
492530
let normalized_rows = actual
@@ -2294,4 +2332,36 @@ Caused by:
22942332
write!(f, "TestError: {}", self.0)
22952333
}
22962334
}
2335+
2336+
#[test]
2337+
fn test_default_validator_ignore_simple() {
2338+
let normalizer = default_normalizer;
2339+
let actual = vec![vec!["foo".to_string(), "bar".to_string()]];
2340+
let expected = vec!["foo<slt:ignore>bar".to_string()];
2341+
assert!(default_validator(normalizer, &actual, &expected));
2342+
}
2343+
2344+
#[test]
2345+
fn test_default_validator_ignore_multiple_fragments() {
2346+
let normalizer = default_normalizer;
2347+
let actual = vec![vec![
2348+
"one".to_string(),
2349+
"two".to_string(),
2350+
"three".to_string(),
2351+
]];
2352+
let expected = vec!["one<slt:ignore>three".to_string()];
2353+
assert!(default_validator(normalizer, &actual, &expected));
2354+
}
2355+
2356+
#[test]
2357+
fn test_default_validator_ignore_fail() {
2358+
let normalizer = default_normalizer;
2359+
let actual = vec![vec![
2360+
"alpha".to_string(),
2361+
"beta".to_string(),
2362+
"gamma".to_string(),
2363+
]];
2364+
let expected = vec!["alpha<slt:ignore>delta".to_string()];
2365+
assert!(!default_validator(normalizer, &actual, &expected));
2366+
}
22972367
}

0 commit comments

Comments
 (0)