234 lines
6.7 KiB
Rust
234 lines
6.7 KiB
Rust
use std::{
|
|
ffi::OsStr,
|
|
fs,
|
|
path::{Path, PathBuf},
|
|
process::{Command, Output},
|
|
sync::atomic::{AtomicUsize, Ordering},
|
|
};
|
|
|
|
static NEXT_FIXTURE_ID: AtomicUsize = AtomicUsize::new(0);
|
|
|
|
#[test]
|
|
fn result_helpers_alpha_fixture_formats_lowers_and_runs() {
|
|
let fixture = Path::new(env!("CARGO_MANIFEST_DIR")).join("../tests/result-helpers.slo");
|
|
|
|
let formatted = run_glagol([OsStr::new("--format"), fixture.as_os_str()]);
|
|
assert_success_stdout(
|
|
formatted,
|
|
&fs::read_to_string(&fixture).expect("read result helpers formatter fixture"),
|
|
"result helpers formatter fixture",
|
|
);
|
|
|
|
let surface = run_glagol([
|
|
OsStr::new("--inspect-lowering=surface"),
|
|
fixture.as_os_str(),
|
|
]);
|
|
assert_success("result helpers surface lowering", &surface);
|
|
assert_eq!(
|
|
String::from_utf8_lossy(&surface.stdout),
|
|
fs::read_to_string("../tests/result-helpers.surface.lower")
|
|
.expect("read result helpers surface snapshot"),
|
|
"result helpers surface lowering drifted"
|
|
);
|
|
|
|
let checked = run_glagol([
|
|
OsStr::new("--inspect-lowering=checked"),
|
|
fixture.as_os_str(),
|
|
]);
|
|
assert_success("result helpers checked lowering", &checked);
|
|
assert_eq!(
|
|
String::from_utf8_lossy(&checked.stdout),
|
|
fs::read_to_string("../tests/result-helpers.checked.lower")
|
|
.expect("read result helpers checked snapshot"),
|
|
"result helpers checked lowering drifted"
|
|
);
|
|
|
|
let tests = run_glagol([OsStr::new("--run-tests"), fixture.as_os_str()]);
|
|
assert_success_stdout(
|
|
tests,
|
|
concat!(
|
|
"test \"std result i32 observers\" ... ok\n",
|
|
"test \"std result i32 unwraps\" ... ok\n",
|
|
"test \"std result string observers\" ... ok\n",
|
|
"test \"std result string unwraps\" ... ok\n",
|
|
"test \"legacy result helpers still work\" ... ok\n",
|
|
"5 test(s) passed\n",
|
|
),
|
|
"result helpers test runner output",
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn result_helpers_alpha_compiles_without_new_runtime_symbols() {
|
|
let fixture = Path::new(env!("CARGO_MANIFEST_DIR")).join("../examples/result-helpers.slo");
|
|
let compile = run_glagol([fixture.as_os_str()]);
|
|
assert_success("compile result helpers fixture", &compile);
|
|
let stdout = String::from_utf8_lossy(&compile.stdout);
|
|
|
|
assert!(
|
|
stdout.contains("define i1 @observe_i32_ok()")
|
|
&& stdout.contains("define i32 @unwrap_i32_ok()")
|
|
&& stdout.contains("define i1 @observe_text_ok()")
|
|
&& stdout.contains("define ptr @unwrap_text_ok()")
|
|
&& stdout.contains("extractvalue")
|
|
&& stdout.contains("__glagol_unwrap_ok_trap")
|
|
&& stdout.contains("__glagol_unwrap_err_trap")
|
|
&& !stdout.contains("@std.result.is_ok")
|
|
&& !stdout.contains("@std.result.is_err")
|
|
&& !stdout.contains("@std.result.unwrap_ok")
|
|
&& !stdout.contains("@std.result.unwrap_err"),
|
|
"LLVM output did not contain expected result helper lowering shape\nstdout:\n{}",
|
|
stdout
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn result_helpers_alpha_rejects_deferred_and_misused_std_names() {
|
|
let cases = [
|
|
(
|
|
"map-deferred",
|
|
r#"
|
|
(module main)
|
|
|
|
(fn main () -> i32
|
|
(std.result.map (ok i32 i32 1))
|
|
0)
|
|
"#,
|
|
"UnsupportedGenericStandardLibraryCall",
|
|
),
|
|
(
|
|
"unwrap-or-deferred",
|
|
r#"
|
|
(module main)
|
|
|
|
(fn main () -> i32
|
|
(std.result.unwrap_or (err i32 i32 1) 0))
|
|
"#,
|
|
"UnsupportedStandardLibraryCall",
|
|
),
|
|
(
|
|
"and-then-deferred",
|
|
r#"
|
|
(module main)
|
|
|
|
(fn main () -> i32
|
|
(std.result.and_then (ok i32 i32 1))
|
|
0)
|
|
"#,
|
|
"UnsupportedStandardLibraryCall",
|
|
),
|
|
(
|
|
"observer-non-result",
|
|
r#"
|
|
(module main)
|
|
|
|
(fn main () -> i32
|
|
(if (std.result.is_ok 1) 1 0))
|
|
"#,
|
|
"ResultObservationTypeMismatch",
|
|
),
|
|
(
|
|
"unwrap-non-result",
|
|
r#"
|
|
(module main)
|
|
|
|
(fn main () -> i32
|
|
(std.result.unwrap_ok 1))
|
|
"#,
|
|
"ResultUnwrapTypeMismatch",
|
|
),
|
|
(
|
|
"std-result-helper-shadow",
|
|
r#"
|
|
(module main)
|
|
|
|
(fn std.result.is_ok ((value (result i32 i32))) -> bool
|
|
true)
|
|
|
|
(fn main () -> i32
|
|
0)
|
|
"#,
|
|
"DuplicateFunction",
|
|
),
|
|
];
|
|
|
|
for (name, source, expected_code) in cases {
|
|
let fixture = write_fixture(name, source);
|
|
let output = run_glagol([fixture.as_os_str()]);
|
|
let stdout = String::from_utf8_lossy(&output.stdout);
|
|
let stderr = String::from_utf8_lossy(&output.stderr);
|
|
|
|
assert!(
|
|
!output.status.success(),
|
|
"compiler unexpectedly accepted `{}`\nstdout:\n{}\nstderr:\n{}",
|
|
name,
|
|
stdout,
|
|
stderr
|
|
);
|
|
assert!(
|
|
stdout.is_empty(),
|
|
"rejected result helper diagnostic case `{}` wrote stdout:\n{}",
|
|
name,
|
|
stdout
|
|
);
|
|
assert!(
|
|
stderr.contains(expected_code),
|
|
"diagnostic `{}` was not reported for `{}`\nstderr:\n{}",
|
|
expected_code,
|
|
name,
|
|
stderr
|
|
);
|
|
}
|
|
}
|
|
|
|
fn run_glagol<I, S>(args: I) -> Output
|
|
where
|
|
I: IntoIterator<Item = S>,
|
|
S: AsRef<OsStr>,
|
|
{
|
|
Command::new(env!("CARGO_BIN_EXE_glagol"))
|
|
.args(args)
|
|
.current_dir(Path::new(env!("CARGO_MANIFEST_DIR")))
|
|
.output()
|
|
.expect("run glagol")
|
|
}
|
|
|
|
fn write_fixture(name: &str, source: &str) -> PathBuf {
|
|
let mut path = std::env::temp_dir();
|
|
path.push(format!(
|
|
"glagol-exp15-result-helpers-{}-{}-{}.slo",
|
|
name,
|
|
std::process::id(),
|
|
NEXT_FIXTURE_ID.fetch_add(1, Ordering::Relaxed)
|
|
));
|
|
fs::write(&path, source).unwrap_or_else(|err| panic!("write `{}`: {}", path.display(), err));
|
|
path
|
|
}
|
|
|
|
fn assert_success(context: &str, output: &Output) {
|
|
let stdout = String::from_utf8_lossy(&output.stdout);
|
|
let stderr = String::from_utf8_lossy(&output.stderr);
|
|
assert!(
|
|
output.status.success(),
|
|
"{} failed\nstdout:\n{}\nstderr:\n{}",
|
|
context,
|
|
stdout,
|
|
stderr
|
|
);
|
|
assert!(stderr.is_empty(), "{} wrote stderr:\n{}", context, stderr);
|
|
}
|
|
|
|
fn assert_success_stdout(output: Output, expected: &str, context: &str) {
|
|
let stdout = String::from_utf8_lossy(&output.stdout);
|
|
let stderr = String::from_utf8_lossy(&output.stderr);
|
|
assert!(
|
|
output.status.success(),
|
|
"{} failed\nstdout:\n{}\nstderr:\n{}",
|
|
context,
|
|
stdout,
|
|
stderr
|
|
);
|
|
assert_eq!(stdout, expected, "{} stdout drifted", context);
|
|
assert!(stderr.is_empty(), "{} wrote stderr:\n{}", context, stderr);
|
|
}
|