use crate::parse_schema_diagnostics;
fn strip_ansi(text: &str) -> String {
let mut out = String::with_capacity(text.len());
let mut chars = text.chars();
while let Some(ch) = chars.next() {
if ch == '\u{1b}' {
for escape in chars.by_ref() {
if escape.is_ascii_alphabetic() {
break;
}
}
} else {
out.push(ch);
}
}
out
}
const THREE_UNKNOWN_TYPES: &str = r#"datasource db {
provider = "postgresql"
}
model User {
id Int @id
role Rolle
}
model Post {
id Int @id
status Statuss
}
model Comment {
id Int @id
kind Kindd
}
"#;
#[test]
fn each_collected_error_exposes_the_file_it_came_from() {
let (_, errors) = parse_schema_diagnostics("t.cstack", THREE_UNKNOWN_TYPES);
assert_eq!(errors.len(), 3);
assert!(errors.iter().all(|error| error.file() == "t.cstack"));
}
#[test]
fn errors_from_two_files_in_one_run_keep_their_own_file_and_source() {
let source_a = "model User {\n id Int @id\n role Rolle\n}\n";
let source_b = "model Post {\n id Int @id\n status Statuss\n}\n";
let (_, errors_a) = parse_schema_diagnostics("a.cstack", source_a);
let (_, errors_b) = parse_schema_diagnostics("b.cstack", source_b);
let mut combined = errors_a;
combined.extend(errors_b);
assert_eq!(combined.len(), 2, "{combined:?}");
assert_eq!(combined[0].file(), "a.cstack");
assert_eq!(combined[1].file(), "b.cstack");
let rendered_a = combined[0].render();
let plain_a = strip_ansi(&rendered_a);
let rendered_b = combined[1].render();
let plain_b = strip_ansi(&rendered_b);
assert!(plain_a.contains("a.cstack"), "{plain_a}");
assert!(plain_a.contains("Rolle"), "{plain_a}");
assert!(!plain_a.contains("b.cstack"), "{plain_a}");
assert!(!plain_a.contains("Statuss"), "{plain_a}");
assert!(plain_b.contains("b.cstack"), "{plain_b}");
assert!(plain_b.contains("Statuss"), "{plain_b}");
assert!(!plain_b.contains("a.cstack"), "{plain_b}");
assert!(!plain_b.contains("Rolle"), "{plain_b}");
}
#[test]
fn unvalidated_parse_errors_still_render_a_code_frame() {
let source = "model Post {\n id Int @id\n title Titel\n";
let error = crate::parse_schema_unvalidated(source)
.expect_err("an unterminated model block must not parse");
assert_eq!(
error.file(),
crate::ANONYMOUS_SCHEMA,
"a path-less entry point tags the placeholder, not an empty string"
);
let plain = strip_ansi(&error.render());
assert!(
plain.contains(crate::ANONYMOUS_SCHEMA),
"render() must name the file it resolved: {plain}"
);
assert!(
plain.contains("model Post {"),
"render() must quote the source — a bare message means the source \
was never attached: {plain}"
);
}