#![deny(missing_docs)]
#![expect(clippy::print_stdout, reason = "test suite")]
#![expect(clippy::tests_outside_test_module, reason = "integration test")]
#![expect(clippy::use_debug, reason = "test suite")]
use std::env::{self, VarError};
use std::process::{Command, Stdio};
use std::sync::LazyLock;
use anyhow::{Context as _, Result, bail};
use camino::{Utf8Path, Utf8PathBuf};
use roundlet::test_exe::{self, PathsMapResult};
fn get_exe_path() -> Result<&'static Utf8Path> {
static EXE_NAMES: [&str; 1] = ["u8loc"];
static PATHS_RES: LazyLock<PathsMapResult<'_>> =
LazyLock::new(|| test_exe::find_exe_paths(&EXE_NAMES));
(*PATHS_RES)
.get_exe_path("u8loc")
.context("find/get_exe_path(u8loc)")
}
fn find_uv() -> Result<Option<String>> {
let uv_prog = match env::var("UV") {
Ok(prog) => prog,
Err(VarError::NotPresent) => "uv".to_owned(),
Err(VarError::NotUnicode(_)) => {
bail!("Could not parse the UV environment variable as a UTF-8 string");
}
};
let res = match Command::new(&uv_prog)
.arg("--version")
.stdin(Stdio::null())
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.output()
{
Ok(res) => res,
Err(err) => {
println!("Could not run `{uv_prog} --version`: {err}");
return Ok(None);
}
};
if !res.status.success() {
println!("The `{uv_prog} --version` command failed: {res:?}");
return Ok(None);
}
let output = match String::from_utf8(res.stdout) {
Ok(output) => output,
Err(err) => {
println!("Could not parse the output of `{uv_prog} --version` as valid UTF-8: {err}");
return Ok(None);
}
};
if !output.starts_with("uv ") {
println!("The output of `{uv_prog} --version` did not start with 'uv': {output:?}");
return Ok(None);
}
println!("Looks like we can use {uv_prog}");
Ok(Some(uv_prog))
}
fn find_topdir() -> Result<Utf8PathBuf> {
let u8loc: Utf8PathBuf = env!("CARGO_MANIFEST_DIR").into();
let Some(rust) = u8loc.parent() else {
bail!("Could not get the parent directory of {u8loc}");
};
let Some(topdir) = rust.parent() else {
bail!("Could not get the parent directory of {rust}");
};
Ok(topdir.into())
}
#[test]
fn functional_python() -> Result<()> {
let exe = get_exe_path()?;
let Some(uv_prog) = find_uv()? else {
println!("No suitable `uv` program, skipping the Python functional test");
return Ok(());
};
let topdir = find_topdir()?;
println!("Setting up the Python virtual environment for the unit tests");
if !Command::new(&uv_prog)
.args(["sync", "--group", "testenv-unit-tests"])
.current_dir(&topdir)
.stdin(Stdio::null())
.status()
.with_context(|| format!("Could not run `{uv_prog} --sync`"))?
.success()
{
bail!("`{uv_prog} sync` failed");
}
println!("Running the functional test against {exe}");
let python = topdir.join(".venv").join("bin").join("python3");
if !Command::new(&python)
.args([
"--",
topdir.join("tests").join("functional.py").as_ref(),
"-p",
exe.as_ref(),
])
.stdin(Stdio::null())
.status()
.with_context(|| format!("Could not run {python}"))?
.success()
{
bail!("The functional tests failed for {exe}");
}
Ok(())
}