Skip to content

Commit 613c976

Browse files
committed
feat: strip the common path prefix from test database names
Each test runs in its own CREATE DATABASE'd database named after the test file path (sanitized) plus a random suffix, capped at 63 chars (Postgres' limit). The cap was enforced by truncating the tail of the full sanitized path -- but the tail is what distinguishes one test from another, so long, deeply-nested paths collapsed onto a shared prefix and were told apart only by the random suffix, leaving the names unreadable. Compute the directory prefix shared by every test in the run (longest common prefix trimmed back to the last '/', so a path component is never split: a/b/c1/d and a/b/c2/d share a/b/, not a/b/c) and strip it before building the name. The distinctive part of the path now survives; only when the stripped name still exceeds the limit is its tail truncated to leave room for the random suffix.
1 parent 9ec03bf commit 613c976

1 file changed

Lines changed: 38 additions & 7 deletions

File tree

sqllogictest-bin/src/main.rs

Lines changed: 38 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -508,17 +508,48 @@ fn test_db_name(test_case_name: String) -> String {
508508
format!("{test_case_prefix}_{random_id}")
509509
}
510510

511+
/// Length of the directory prefix shared by every name, trimmed back to the
512+
/// last `/` so a path component is never split (`a/b/c1/d` and `a/b/c2/d` share
513+
/// `a/b/`, not `a/b/c`). Stripping it keeps the part of the path that actually
514+
/// distinguishes a test, which matters because `test_db_name` truncates the
515+
/// suffix to fit the 63-char limit -- a long shared prefix would otherwise
516+
/// crowd the distinctive part out.
517+
fn common_dir_prefix_len(names: &[&str]) -> usize {
518+
let Some(first) = names.first() else {
519+
return 0;
520+
};
521+
let first = first.as_bytes();
522+
let mut lcp = first.len();
523+
for n in &names[1..] {
524+
let b = n.as_bytes();
525+
let mut i = 0;
526+
while i < lcp && i < b.len() && b[i] == first[i] {
527+
i += 1;
528+
}
529+
lcp = i;
530+
}
531+
// `/` is ASCII, so this is always a valid UTF-8 boundary.
532+
first[..lcp]
533+
.iter()
534+
.rposition(|&c| c == b'/')
535+
.map_or(0, |p| p + 1)
536+
}
537+
511538
fn test_db_names(
512539
files: Vec<PathBuf>,
513540
show_discovered_tests: bool,
514541
) -> Result<Vec<(String, PathBuf)>> {
515-
let mut test_databases = Vec::new();
542+
let filenames = files
543+
.iter()
544+
.map(|f| f.to_str().ok_or_else(|| anyhow!("not a UTF-8 filename")))
545+
.collect::<Result<Vec<_>>>()?;
546+
let prefix_len = common_dir_prefix_len(&filenames);
547+
548+
let mut test_databases = Vec::with_capacity(files.len());
516549
let mut test_cases = HashSet::new();
517-
for file in files {
518-
let filename = file
519-
.to_str()
520-
.ok_or_else(|| anyhow!("not a UTF-8 filename"))?;
521-
let test_case_name = filename.to_test_case_name();
550+
for (file, filename) in files.iter().zip(filenames) {
551+
let stripped: &str = &filename[prefix_len..];
552+
let test_case_name = stripped.to_test_case_name();
522553

523554
if show_discovered_tests {
524555
eprintln!("+ Discovered Test: {test_case_name}");
@@ -528,7 +559,7 @@ fn test_db_names(
528559
}
529560

530561
let db_name = test_db_name(test_case_name);
531-
test_databases.push((db_name, file));
562+
test_databases.push((db_name, file.clone()));
532563
}
533564
Ok(test_databases)
534565
}

0 commit comments

Comments
 (0)