use crate::driver::tests::setup_graph_raw;
fn build(files: &[(&str, &str)]) -> (bool, String) {
let v = env!("CARGO_PKG_VERSION").split('-').next().unwrap();
let owned: Vec<(&str, String)> = files
.iter()
.map(|(p, c)| (*p, c.replace("{v}", v)))
.collect();
let refs: Vec<(&str, &str)> = owned.iter().map(|(p, c)| (*p, c.as_str())).collect();
let (graph_opt, _, _ws, diagnostics) = setup_graph_raw(refs);
let ok = graph_opt.is_some() && !diagnostics.has_errors();
(ok, diagnostics.to_string())
}
fn assert_builds(files: &[(&str, &str)]) {
let (ok, errors) = build(files);
assert!(ok, "build failed unexpectedly. Errors:\n{errors}");
}
fn assert_build_fails(expected_err: &str, files: &[(&str, &str)]) {
let (ok, errors) = build(files);
assert!(!ok, "build succeeded when it should have failed");
assert!(
errors.contains(expected_err),
"Expected error containing '{expected_err}' but got:\n{errors}"
);
}
#[test]
fn mixed_valid_operators() {
assert_builds(&[
(
"main.simf",
r#"simc "^{v}";
use lib::A::foo;
fn main() {}"#,
),
(
"libs/lib/A.simf",
r#"simc "={v}";
use crate::B::foo;
pub fn foo() {}"#,
),
(
"libs/lib/B.simf",
r#"simc ">0.1.0";
use crate::C::foo;
pub fn foo() {}"#,
),
(
"libs/lib/C.simf",
r#"simc "*";
pub fn foo() {}"#,
),
]);
}
#[test]
fn main_too_old_fails() {
assert_build_fails(
"Incompatible compiler version",
&[
(
"main.simf",
r#"simc ">99.0.0";
use lib::A::foo;
fn main() {}"#,
),
(
"libs/lib/A.simf",
r#"simc "={v}";
pub fn foo() {}"#,
),
],
);
}
#[test]
fn lib_too_old_fails() {
assert_build_fails(
"Incompatible compiler version",
&[
(
"main.simf",
r#"simc "={v}";
use lib::A::foo;
fn main() {}"#,
),
(
"libs/lib/A.simf",
r#"simc ">99.0.0";
pub fn foo() {}"#,
),
],
);
}
#[test]
fn unreferenced_file_with_invalid_version_ignored() {
assert_builds(&[
(
"main.simf",
r#"simc "={v}";
use lib::A::foo;
fn main() {}"#,
),
(
"libs/lib/A.simf",
r#"simc "={v}";
pub fn foo() {}"#,
),
(
"libs/lib/B.simf",
r#"simc ">99.0.0";
pub fn unused() {}"#,
),
]);
}
#[test]
fn directive_omitted() {
assert_builds(&[("main.simf", "fn main() {}")]);
}
#[test]
fn incompatible_reported_despite_unlexable_body() {
assert_build_fails(
"Incompatible compiler version",
&[(
"main.simf",
r#"simc ">99.0.0";
fn main() { let s = "future syntax"; }"#,
)],
);
}
#[test]
fn stray_directive_reports_single_error() {
let (ok, errors) = build(&[(
"main.simf",
r#"simc "={v}";
simc "={v}";
fn main() {}"#,
)]);
assert!(!ok, "duplicate directive must fail the build");
assert!(
errors.contains("reserved"),
"expected the reserved-keyword error, got:\n{errors}"
);
assert!(
!errors.contains("Cannot parse"),
"remnant noise must be suppressed, got:\n{errors}"
);
}
#[test]
fn multiple_directives_same_file_fails() {
assert_build_fails(
"must be the first item",
&[(
"main.simf",
r#"simc "={v}";
simc "={v}";
fn main() {}"#,
)],
);
}
#[test]
fn directive_after_item_fails() {
let (ok, errors) = build(&[(
"main.simf",
r#"fn main() {}
simc "={v}";"#,
)]);
assert!(!ok, "misplaced directive must fail the build");
assert!(
errors.contains("must be the first item"),
"expected the reserved-keyword error, got:\n{errors}"
);
assert!(
!errors.contains("Cannot parse"),
"remnant noise must be suppressed, got:\n{errors}"
);
}
#[test]
fn invalid_syntax_main() {
assert_build_fails(
"Invalid version requirement",
&[
(
"main.simf",
r#"simc "foo";
use lib::A::foo;
fn main() {}"#,
),
(
"libs/lib/A.simf",
r#"simc "={v}";
pub fn foo() {}"#,
),
],
);
}
#[test]
fn version_in_comment_ignored() {
assert_builds(&[(
"main.simf",
r#"// simc "=99.0.0";
simc "={v}";
fn main() {}"#,
)]);
}
#[test]
fn version_in_block_comment_ignored() {
assert_builds(&[(
"main.simf",
r#"/*
simc "=99.0.0";
*/
simc "={v}";
fn main() {}"#,
)]);
}