139 lines
4.6 KiB
Rust
139 lines
4.6 KiB
Rust
use std::{
|
|
env,
|
|
path::Path,
|
|
process::{Command, Stdio},
|
|
};
|
|
|
|
use anyhow::{anyhow, Result};
|
|
use regex::Regex;
|
|
|
|
use crate::{bail_on_err, Test};
|
|
|
|
pub fn run(args: &Test) -> Result<()> {
|
|
let test_flags = if args.address_sanitizer {
|
|
env::set_var("CFLAGS", "-fsanitize=undefined,address");
|
|
|
|
// When the Tree-sitter C library is compiled with the address sanitizer, the address
|
|
// sanitizer runtime library needs to be linked into the final test executable. When
|
|
// using Xcode clang, the Rust linker doesn't know where to find that library, so we
|
|
// need to specify linker flags directly.
|
|
let output = Command::new("cc").arg("-print-runtime-dir").output()?;
|
|
bail_on_err(&output, "Failed to get clang runtime dir")?;
|
|
let runtime_dir = String::from_utf8(output.stdout)?;
|
|
if runtime_dir.contains("/Xcode.app/") {
|
|
env::set_var(
|
|
"RUSTFLAGS",
|
|
format!(
|
|
"-C link-arg=-L{runtime_dir} -C link-arg=-lclang_rt.asan_osx_dynamic -C link-arg=-Wl,-rpath,{runtime_dir}"
|
|
),
|
|
);
|
|
}
|
|
|
|
// Specify a `--target` explicitly. This is required for address sanitizer support.
|
|
let output = Command::new("rustup")
|
|
.arg("show")
|
|
.arg("active-toolchain")
|
|
.output()?;
|
|
bail_on_err(&output, "Failed to get active Rust toolchain")?;
|
|
let toolchain = String::from_utf8(output.stdout)?;
|
|
let re = Regex::new(r"(stable|beta|nightly)-([_a-z0-9-]+).*")?;
|
|
let captures = re
|
|
.captures(&toolchain)
|
|
.ok_or_else(|| anyhow!("Failed to parse toolchain '{toolchain}'"))?;
|
|
let current_target = captures.get(2).unwrap().as_str();
|
|
format!("--target={current_target}")
|
|
} else {
|
|
String::new()
|
|
};
|
|
if let Some(language) = &args.language {
|
|
env::set_var("TREE_SITTER_LANGUAGE", language);
|
|
}
|
|
if let Some(example) = &args.example {
|
|
env::set_var("TREE_SITTER_EXAMPLE_INCLUDE", example);
|
|
}
|
|
if let Some(seed) = args.seed {
|
|
env::set_var("TREE_SITTER_SEED", seed.to_string());
|
|
}
|
|
if let Some(iterations) = args.iterations {
|
|
env::set_var("TREE_SITTER_ITERATIONS", iterations.to_string());
|
|
}
|
|
if args.debug {
|
|
env::set_var("TREE_SITTER_LOG", "1");
|
|
}
|
|
if args.debug_graph {
|
|
env::set_var("TREE_SITTER_LOG_GRAPHS", "1");
|
|
}
|
|
|
|
if args.g {
|
|
let cargo_cmd = Command::new("cargo")
|
|
.arg("test")
|
|
.arg(test_flags)
|
|
.arg("--no-run")
|
|
.arg("--message-format=json")
|
|
.stdout(Stdio::piped())
|
|
.spawn()?;
|
|
|
|
let jq_cmd = Command::new("jq")
|
|
.arg("-rs")
|
|
.arg(r#"map(select(.target.name == "tree_sitter_cli" and .executable))[0].executable"#)
|
|
.stdin(cargo_cmd.stdout.unwrap())
|
|
.output()?;
|
|
|
|
let test_binary = String::from_utf8(jq_cmd.stdout)?;
|
|
|
|
let mut lldb_cmd = Command::new("lldb");
|
|
lldb_cmd.arg(test_binary.trim()).arg("--").args(&args.args);
|
|
bail_on_err(
|
|
&lldb_cmd.spawn()?.wait_with_output()?,
|
|
&format!("Failed to run {lldb_cmd:?}"),
|
|
)?;
|
|
} else {
|
|
let mut cargo_cmd = Command::new("cargo");
|
|
cargo_cmd.arg("test");
|
|
if args.wasm {
|
|
cargo_cmd.arg("--features").arg("wasm");
|
|
}
|
|
if !test_flags.is_empty() {
|
|
cargo_cmd.arg(test_flags);
|
|
}
|
|
cargo_cmd.args(&args.args);
|
|
if args.nocapture {
|
|
cargo_cmd.arg("--").arg("--nocapture");
|
|
}
|
|
bail_on_err(
|
|
&cargo_cmd.spawn()?.wait_with_output()?,
|
|
&format!("Failed to run {cargo_cmd:?}"),
|
|
)?;
|
|
}
|
|
|
|
Ok(())
|
|
}
|
|
|
|
pub fn run_wasm() -> Result<()> {
|
|
std::env::set_current_dir("lib/binding_web")?;
|
|
|
|
let node_modules_dir = Path::new("node_modules");
|
|
let npm = if cfg!(target_os = "windows") {
|
|
"npm.cmd"
|
|
} else {
|
|
"npm"
|
|
};
|
|
|
|
if !node_modules_dir.join("chai").exists() || !node_modules_dir.join("mocha").exists() {
|
|
println!("Installing test dependencies...");
|
|
let output = Command::new(npm).arg("install").output()?;
|
|
bail_on_err(&output, "Failed to install test dependencies")?;
|
|
}
|
|
|
|
let child = Command::new(npm).arg("test").spawn()?;
|
|
let output = child.wait_with_output()?;
|
|
bail_on_err(&output, &format!("Failed to run `{npm} test`"))?;
|
|
|
|
// Display test results
|
|
let output = String::from_utf8_lossy(&output.stdout);
|
|
for line in output.lines() {
|
|
println!("{line}");
|
|
}
|
|
|
|
Ok(())
|
|
}
|