use std::{
ffi::OsString,
fs,
path::{Path, PathBuf},
};
use tempfile::TempDir;
use super::Host;
#[cfg(unix)]
const FAKE_TOOL_SCRIPT: &str = include_str!("testdata/fake_tools.sh");
#[cfg(windows)]
const FAKE_TOOL_SCRIPT: &str = include_str!("testdata/fake_tools.cmd");
pub struct TestMachine {
root: TempDir,
}
impl TestMachine {
pub fn new() -> Self {
let root = tempfile::tempdir().expect("create test machine root");
let machine = Self { root };
fs::create_dir_all(machine.bin()).expect("create fake bin dir");
fs::create_dir_all(machine.home()).expect("create fake home dir");
machine
}
pub fn root(&self) -> &Path {
self.root.path()
}
pub fn bin(&self) -> PathBuf {
self.root.path().join("bin")
}
pub fn home(&self) -> PathBuf {
self.root.path().join("home")
}
pub fn responses(&self) -> PathBuf {
self.root.path().join("responses")
}
pub fn install(&self, name: &str) -> PathBuf {
Self::script(self.bin().join(tool_file_name(name)))
}
pub fn executable(&self, relative: impl AsRef<Path>) -> PathBuf {
Self::script(self.root.path().join(relative))
}
pub fn file(&self, relative: impl AsRef<Path>, contents: &str) -> PathBuf {
let path = self.root.path().join(relative);
if let Some(parent) = path.parent() {
fs::create_dir_all(parent).expect("create parent dirs");
}
fs::write(&path, contents).expect("write fixture file");
path
}
pub fn dir(&self, relative: impl AsRef<Path>) -> PathBuf {
let path = self.root.path().join(relative);
fs::create_dir_all(&path).expect("create fixture dir");
path
}
pub fn install_android_sdk(&self) -> PathBuf {
let sdk = self.dir("sdk");
self.executable(
Path::new("sdk")
.join("cmdline-tools/latest/bin")
.join(sdkmanager_file_name()),
);
sdk
}
pub fn install_adb(&self) -> PathBuf {
self.executable(
Path::new("sdk")
.join("platform-tools")
.join(adb_file_name()),
)
}
pub fn install_android_platform(&self, api_dir: &str) -> PathBuf {
self.file(
Path::new("sdk")
.join("platforms")
.join(api_dir)
.join("android.jar"),
"",
)
}
pub fn install_android_build_tools(&self, version: &str) -> PathBuf {
self.file(
Path::new("sdk")
.join("build-tools")
.join(version)
.join("lib/d8.jar"),
"",
)
}
pub fn install_android_ndk(&self, version: &str) -> PathBuf {
self.executable(
Path::new("sdk")
.join("ndk")
.join(version)
.join("toolchains/llvm/prebuilt/test-host/bin")
.join(ndk_clang_file_name()),
);
self.dir(Path::new("sdk").join("ndk").join(version))
}
pub fn install_android_emulator(&self) -> PathBuf {
self.executable(Path::new("sdk").join("emulator").join(emulator_file_name()))
}
pub fn respond(&self, key: &str, contents: &str) {
let dir = self.responses();
fs::create_dir_all(&dir).expect("create responses dir");
fs::write(dir.join(key), contents).expect("write canned response");
}
#[cfg(target_os = "linux")]
pub fn respond_pkg_config_module(&self, module: &str, modversion: &str) {
self.respond(&format!("PKG_CONFIG_{module}"), modversion);
}
#[cfg(target_os = "linux")]
pub fn respond_pkg_config_var(&self, variable: &str, value: &str) {
self.respond(&format!("PKG_CONFIG_VAR_{variable}"), value);
}
pub fn host<K, V>(&self, vars: impl IntoIterator<Item = (K, V)>) -> Host
where
K: AsRef<std::ffi::OsStr>,
V: AsRef<std::ffi::OsStr>,
{
let mut declared: Vec<(OsString, OsString)> = vec![
(
OsString::from("WATERUI_FAKE_RESPONSES"),
self.responses().into_os_string(),
),
(OsString::from("HOME"), self.home().into_os_string()),
(OsString::from("USERPROFILE"), self.home().into_os_string()),
];
declared.extend(
vars.into_iter()
.map(|(k, v)| (k.as_ref().to_os_string(), v.as_ref().to_os_string())),
);
Host::new([self.bin()], declared).with_cwd(self.root.path().to_path_buf())
}
fn script(path: PathBuf) -> PathBuf {
if let Some(parent) = path.parent() {
fs::create_dir_all(parent).expect("create fake tool dir");
}
fs::write(&path, FAKE_TOOL_SCRIPT).expect("write fake tool");
make_executable(&path);
path
}
}
pub fn tool_file_name(name: &str) -> String {
if cfg!(windows) {
format!("{name}.cmd")
} else {
name.to_string()
}
}
fn sdkmanager_file_name() -> &'static str {
if cfg!(windows) {
"sdkmanager.bat"
} else {
"sdkmanager"
}
}
fn adb_file_name() -> &'static str {
if cfg!(windows) { "adb.exe" } else { "adb" }
}
fn emulator_file_name() -> &'static str {
if cfg!(windows) {
"emulator.exe"
} else {
"emulator"
}
}
const NDK_WRAPPER_API_LEVEL: u32 = 21;
fn ndk_clang_file_name() -> String {
let suffix = if cfg!(windows) { ".cmd" } else { "" };
format!("aarch64-linux-android{NDK_WRAPPER_API_LEVEL}-clang{suffix}")
}
#[cfg(unix)]
fn make_executable(path: &Path) {
use std::os::unix::fs::PermissionsExt as _;
fs::set_permissions(path, fs::Permissions::from_mode(0o755))
.expect("mark fake tool executable");
}
#[cfg(windows)]
fn make_executable(_path: &Path) {}