#![cfg(feature = "live-engine")]
use std::path::Path;
use rs_teststand::{AcquireLicenseOptions, ApplicationLicense, Engine, Error, LicenseType};
#[test]
#[ignore = "requires a live TestStand engine"]
fn engine_reports_a_plausible_version() -> Result<(), Error> {
let engine = Engine::new()?;
let major = engine.major_version()?;
assert!(major >= 16, "unexpected major version: {major}");
let version = engine.version_string()?;
assert!(
version.contains(&format!("({major}.")),
"version string {version:?} does not contain numeric major ({major}.)",
);
let is_64bit = engine.is_64bit()?;
if cfg!(target_pointer_width = "64") {
assert!(is_64bit, "expected 64-bit engine process for x86_64 target");
} else {
assert!(!is_64bit, "expected 32-bit engine process for i686 target");
}
Ok(())
}
#[test]
#[ignore = "requires a live TestStand engine"]
fn engine_reports_directories_of_the_active_installation() -> Result<(), Error> {
let engine = Engine::new()?;
for (label, value) in [
("TestStandDirectory", engine.teststand_directory()?),
("BinDirectory", engine.bin_directory()?),
("ConfigDirectory", engine.config_directory()?),
] {
assert!(!value.is_empty(), "{label} was empty");
assert!(
Path::new(&value).is_dir(),
"{label} does not exist on disk: {value}"
);
}
Ok(())
}
#[test]
#[ignore = "requires a live TestStand engine"]
fn breakpoint_switches_round_trip_and_are_restored() -> Result<(), Error> {
let engine = Engine::new()?;
let breakpoints = engine.breakpoints_enabled()?;
let persist = engine.persist_breakpoints()?;
engine.set_breakpoints_enabled(!breakpoints)?;
assert_eq!(
engine.breakpoints_enabled()?,
!breakpoints,
"the engine did not take the new breakpoint setting"
);
engine.set_persist_breakpoints(!persist)?;
assert_eq!(
engine.persist_breakpoints()?,
!persist,
"the engine did not take the new persistence setting"
);
engine.set_breakpoints_enabled(breakpoints)?;
engine.set_persist_breakpoints(persist)?;
assert_eq!(engine.breakpoints_enabled()?, breakpoints);
assert_eq!(engine.persist_breakpoints()?, persist);
Ok(())
}
#[test]
#[ignore = "requires a live TestStand engine"]
fn unloading_every_module_succeeds_with_nothing_loaded() -> Result<(), Error> {
let engine = Engine::new()?;
engine.unload_all_modules()?;
Ok(())
}
#[test]
#[ignore = "requires a live TestStand engine"]
fn dot_net_collection_runs_and_its_interval_round_trips() -> Result<(), Error> {
let engine = Engine::new()?;
let interval = engine.dot_net_garbage_collection_interval()?;
for candidate in [5_000, -1] {
engine.set_dot_net_garbage_collection_interval(candidate)?;
assert_eq!(
engine.dot_net_garbage_collection_interval()?,
candidate,
"the engine did not take the interval {candidate}"
);
}
engine.set_dot_net_garbage_collection_interval(interval)?;
assert_eq!(engine.dot_net_garbage_collection_interval()?, interval);
engine.do_dot_net_garbage_collection()?;
let clr = engine.dot_net_clr_version()?;
assert!(
clr.is_empty() || clr.chars().any(|character| character.is_ascii_digit()),
"unexpected CLR version string: {clr:?}"
);
Ok(())
}
#[test]
#[ignore = "requires a live TestStand engine"]
fn a_dialog_raised_while_the_engine_starts_does_not_block_it() -> Result<(), Error> {
let engine = Engine::new()?;
let dialogs = engine.startup_dialogs();
if dialogs.is_empty() {
println!("clean start: no dialog was raised");
} else {
for dialog in dialogs {
println!(
"closed during startup: {:?} / {:?}",
dialog.title, dialog.body
);
}
}
assert!(
engine.major_version()? >= 16,
"engine unusable after the startup sweep"
);
Ok(())
}
#[test]
#[ignore = "requires a live TestStand engine"]
fn a_license_is_acquired_before_it_can_be_reported() -> Result<(), Error> {
let engine = Engine::new()?;
assert_eq!(
engine.license_type()?,
LicenseType::NoLicense,
"a freshly created engine should be using no license yet"
);
match engine.require_license() {
Ok(held) => {
assert_ne!(held.handle(), 0, "a granted license never has handle zero");
assert_eq!(engine.license_type()?, held.kind());
println!(
"granted handle {}, engine using {:?}",
held.handle(),
held.kind()
);
held.release()?;
}
Err(Error::NoLicense) => {
println!("station holds no license; refused cleanly");
}
Err(other) => return Err(other),
}
Ok(())
}
#[test]
#[ignore = "requires a live TestStand engine"]
fn naming_a_license_kind_is_a_constraint_not_a_preference() -> Result<(), Error> {
let engine = Engine::new()?;
let unspecified = engine.acquire_license(
ApplicationLicense::Unspecified,
AcquireLicenseOptions::SUPPRESS_STARTUP_DIALOG,
);
match unspecified {
Ok(handle) => {
assert_ne!(handle, 0);
engine.release_license(handle)?;
}
Err(Error::NoLicense) => {
println!("station holds no license; nothing further to check");
return Ok(());
}
Err(other) => return Err(other),
}
let named = engine.acquire_license(
ApplicationLicense::OperatorInterface,
AcquireLicenseOptions::SUPPRESS_STARTUP_DIALOG,
);
println!("operator-interface request answered {named:?}");
if let Ok(handle) = named {
assert_ne!(handle, 0);
engine.release_license(handle)?;
}
Ok(())
}
#[test]
#[ignore = "requires a live TestStand engine"]
fn a_held_license_is_given_back_when_dropped() -> Result<(), Error> {
let engine = Engine::new()?;
let Ok(held) = engine.require_license() else {
println!("station holds no license; nothing to drop");
return Ok(());
};
drop(held);
let again = engine.require_license()?;
assert_ne!(again.handle(), 0);
again.release()?;
Ok(())
}
#[test]
#[ignore = "requires a live TestStand engine"]
fn license_description_and_addons_answer_on_any_station() -> Result<(), Error> {
let engine = Engine::new()?;
assert!(!engine.get_license_description()?.is_empty());
let addon = engine.has_addon_license("rs-teststand-nonexistent-feature");
assert!(
matches!(addon, Ok(false) | Err(_)),
"unexpected add-on answer: {addon:?}"
);
Ok(())
}