Looking for dependencies on test for a better UX
This commit is contained in:
@@ -9,8 +9,10 @@
|
||||
// test.sh / test/run_tests.sh --> cmake, g++ (or clang++), git
|
||||
// build.sh --> arduino-cli (with arduino:avr core)
|
||||
//
|
||||
// If any dependency is missing the test FAILS -- that is intentional.
|
||||
// A build machine that ships Anvil binaries MUST have these tools.
|
||||
// If a dependency is missing, the test is SKIPPED (shown as "ignored"
|
||||
// in cargo test output). Detection happens at compile time via build.rs
|
||||
// which sets cfg flags: has_cmake, has_cpp_compiler, has_git,
|
||||
// has_arduino_cli.
|
||||
//
|
||||
// On Windows the .bat variants are tested instead.
|
||||
// ==========================================================================
|
||||
@@ -122,91 +124,6 @@ fn run_script_with_args(dir: &Path, script: &str, args: &[&str]) -> (bool, Strin
|
||||
(output.status.success(), stdout, stderr)
|
||||
}
|
||||
|
||||
/// Assert that a command-line tool is available in PATH.
|
||||
/// Panics with a clear message if not found.
|
||||
fn require_tool(name: &str) {
|
||||
let check = if cfg!(windows) {
|
||||
Command::new("where").arg(name).output()
|
||||
} else {
|
||||
Command::new("which").arg(name).output()
|
||||
};
|
||||
|
||||
match check {
|
||||
Ok(output) if output.status.success() => {}
|
||||
_ => panic!(
|
||||
"\n\n\
|
||||
===================================================================\n\
|
||||
MISSING BUILD DEPENDENCY: {name}\n\
|
||||
===================================================================\n\
|
||||
\n\
|
||||
Anvil's cargo tests REQUIRE build-machine dependencies.\n\
|
||||
Install '{name}' and re-run. See 'anvil doctor' for guidance.\n\
|
||||
\n\
|
||||
===================================================================\n"
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
/// Check that at least one C++ compiler is present.
|
||||
///
|
||||
/// On Windows, cmake discovers MSVC through the Visual Studio installation
|
||||
/// even when cl.exe is not directly in PATH, so we check for cl.exe as
|
||||
/// well as g++ and clang++. If none are found in PATH we still let cmake
|
||||
/// try -- it will fail at configure time with a clear message.
|
||||
fn require_cpp_compiler() {
|
||||
let check_tool = |name: &str| -> bool {
|
||||
Command::new(if cfg!(windows) { "where" } else { "which" })
|
||||
.arg(name)
|
||||
.output()
|
||||
.map(|o| o.status.success())
|
||||
.unwrap_or(false)
|
||||
};
|
||||
|
||||
let has_gpp = check_tool("g++");
|
||||
let has_clangpp = check_tool("clang++");
|
||||
let has_cl = if cfg!(windows) { check_tool("cl") } else { false };
|
||||
|
||||
// On Windows, cmake can discover MSVC even when cl.exe is not in
|
||||
// the current PATH (via vswhere / VS installation registry). So
|
||||
// we only hard-fail on Linux/macOS where the compiler really must
|
||||
// be in PATH.
|
||||
if !has_gpp && !has_clangpp && !has_cl {
|
||||
if cfg!(windows) {
|
||||
// Warn but don't panic -- cmake will try to find MSVC
|
||||
eprintln!(
|
||||
"\n\
|
||||
WARNING: No C++ compiler (g++, clang++, cl) found in PATH.\n\
|
||||
cmake may still find MSVC via Visual Studio installation.\n\
|
||||
If tests fail, open a VS Developer Command Prompt or install\n\
|
||||
Build Tools for Visual Studio.\n"
|
||||
);
|
||||
} else {
|
||||
panic!(
|
||||
"\n\n\
|
||||
===================================================================\n\
|
||||
MISSING BUILD DEPENDENCY: C++ compiler (g++ or clang++)\n\
|
||||
===================================================================\n\
|
||||
\n\
|
||||
Install g++ or clang++ and re-run.\n\
|
||||
\n\
|
||||
===================================================================\n"
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Require cmake + C++ compiler + git (the test script prereqs).
|
||||
fn require_test_script_deps() {
|
||||
require_tool("cmake");
|
||||
require_tool("git");
|
||||
require_cpp_compiler();
|
||||
}
|
||||
|
||||
/// Require arduino-cli (the build script prereqs).
|
||||
fn require_build_script_deps() {
|
||||
require_tool("arduino-cli");
|
||||
}
|
||||
|
||||
/// Platform-appropriate script paths.
|
||||
fn root_test_script() -> &'static str {
|
||||
if cfg!(windows) { "test.bat" } else { "test.sh" }
|
||||
@@ -283,9 +200,10 @@ fn find_file_recursive(dir: &Path, prefix: &str) -> bool {
|
||||
// ==========================================================================
|
||||
|
||||
#[test]
|
||||
#[cfg_attr(not(has_cmake), ignore = "cmake not found")]
|
||||
#[cfg_attr(not(has_cpp_compiler), ignore = "C++ compiler not found")]
|
||||
#[cfg_attr(not(has_git), ignore = "git not found")]
|
||||
fn test_root_test_script_executes_successfully() {
|
||||
require_test_script_deps();
|
||||
|
||||
let tmp = extract_project("root_test");
|
||||
|
||||
#[cfg(unix)]
|
||||
@@ -306,9 +224,10 @@ fn test_root_test_script_executes_successfully() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg_attr(not(has_cmake), ignore = "cmake not found")]
|
||||
#[cfg_attr(not(has_cpp_compiler), ignore = "C++ compiler not found")]
|
||||
#[cfg_attr(not(has_git), ignore = "git not found")]
|
||||
fn test_root_test_script_tests_actually_ran() {
|
||||
require_test_script_deps();
|
||||
|
||||
let tmp = extract_project("root_verify");
|
||||
|
||||
#[cfg(unix)]
|
||||
@@ -338,9 +257,10 @@ fn test_root_test_script_tests_actually_ran() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg_attr(not(has_cmake), ignore = "cmake not found")]
|
||||
#[cfg_attr(not(has_cpp_compiler), ignore = "C++ compiler not found")]
|
||||
#[cfg_attr(not(has_git), ignore = "git not found")]
|
||||
fn test_root_test_script_idempotent() {
|
||||
require_test_script_deps();
|
||||
|
||||
let tmp = extract_project("root_idem");
|
||||
|
||||
#[cfg(unix)]
|
||||
@@ -367,9 +287,10 @@ fn test_root_test_script_idempotent() {
|
||||
// ==========================================================================
|
||||
|
||||
#[test]
|
||||
#[cfg_attr(not(has_cmake), ignore = "cmake not found")]
|
||||
#[cfg_attr(not(has_cpp_compiler), ignore = "C++ compiler not found")]
|
||||
#[cfg_attr(not(has_git), ignore = "git not found")]
|
||||
fn test_inner_run_tests_script_executes_successfully() {
|
||||
require_test_script_deps();
|
||||
|
||||
let tmp = extract_project("inner_test");
|
||||
|
||||
#[cfg(unix)]
|
||||
@@ -390,9 +311,10 @@ fn test_inner_run_tests_script_executes_successfully() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg_attr(not(has_cmake), ignore = "cmake not found")]
|
||||
#[cfg_attr(not(has_cpp_compiler), ignore = "C++ compiler not found")]
|
||||
#[cfg_attr(not(has_git), ignore = "git not found")]
|
||||
fn test_inner_run_tests_google_tests_actually_ran() {
|
||||
require_test_script_deps();
|
||||
|
||||
let tmp = extract_project("inner_gtest");
|
||||
|
||||
#[cfg(unix)]
|
||||
@@ -421,9 +343,10 @@ fn test_inner_run_tests_google_tests_actually_ran() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg_attr(not(has_cmake), ignore = "cmake not found")]
|
||||
#[cfg_attr(not(has_cpp_compiler), ignore = "C++ compiler not found")]
|
||||
#[cfg_attr(not(has_git), ignore = "git not found")]
|
||||
fn test_inner_run_tests_clean_flag_rebuilds() {
|
||||
require_test_script_deps();
|
||||
|
||||
let tmp = extract_project("inner_clean");
|
||||
|
||||
#[cfg(unix)]
|
||||
@@ -457,9 +380,10 @@ fn test_inner_run_tests_clean_flag_rebuilds() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg_attr(not(has_cmake), ignore = "cmake not found")]
|
||||
#[cfg_attr(not(has_cpp_compiler), ignore = "C++ compiler not found")]
|
||||
#[cfg_attr(not(has_git), ignore = "git not found")]
|
||||
fn test_inner_run_tests_produces_test_binary() {
|
||||
require_test_script_deps();
|
||||
|
||||
let tmp = extract_project("inner_bin");
|
||||
|
||||
#[cfg(unix)]
|
||||
@@ -482,9 +406,10 @@ fn test_inner_run_tests_produces_test_binary() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg_attr(not(has_cmake), ignore = "cmake not found")]
|
||||
#[cfg_attr(not(has_cpp_compiler), ignore = "C++ compiler not found")]
|
||||
#[cfg_attr(not(has_git), ignore = "git not found")]
|
||||
fn test_inner_run_tests_idempotent() {
|
||||
require_test_script_deps();
|
||||
|
||||
let tmp = extract_project("inner_idem");
|
||||
|
||||
#[cfg(unix)]
|
||||
@@ -513,9 +438,8 @@ fn test_inner_run_tests_idempotent() {
|
||||
|
||||
#[test]
|
||||
#[serial]
|
||||
#[cfg_attr(not(has_arduino_cli), ignore = "arduino-cli not found")]
|
||||
fn test_build_script_compiles_sketch() {
|
||||
require_build_script_deps();
|
||||
|
||||
let tmp = extract_project("build_test");
|
||||
|
||||
#[cfg(unix)]
|
||||
@@ -536,9 +460,9 @@ fn test_build_script_compiles_sketch() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[serial]
|
||||
#[cfg_attr(not(has_arduino_cli), ignore = "arduino-cli not found")]
|
||||
fn test_build_script_produces_compilation_output() {
|
||||
require_build_script_deps();
|
||||
|
||||
let tmp = extract_project("compile_out");
|
||||
|
||||
#[cfg(unix)]
|
||||
@@ -568,9 +492,9 @@ fn test_build_script_produces_compilation_output() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[serial]
|
||||
#[cfg_attr(not(has_arduino_cli), ignore = "arduino-cli not found")]
|
||||
fn test_build_script_idempotent() {
|
||||
require_build_script_deps();
|
||||
|
||||
let tmp = extract_project("build_idem");
|
||||
|
||||
#[cfg(unix)]
|
||||
@@ -594,10 +518,12 @@ fn test_build_script_idempotent() {
|
||||
// ==========================================================================
|
||||
|
||||
#[test]
|
||||
#[serial]
|
||||
#[cfg_attr(not(has_cmake), ignore = "cmake not found")]
|
||||
#[cfg_attr(not(has_cpp_compiler), ignore = "C++ compiler not found")]
|
||||
#[cfg_attr(not(has_git), ignore = "git not found")]
|
||||
#[cfg_attr(not(has_arduino_cli), ignore = "arduino-cli not found")]
|
||||
fn test_full_project_all_scripts_pass() {
|
||||
require_test_script_deps();
|
||||
require_build_script_deps();
|
||||
|
||||
let tmp = extract_project("full_e2e");
|
||||
|
||||
#[cfg(unix)]
|
||||
|
||||
Reference in New Issue
Block a user