#![cfg(any(test, feature = "benchmark"))]
use std::path::{Path, PathBuf};
pub const FIXTURE_INSTALL_GUIDANCE: &str = "Telemetry fixtures are stored under test-data/. Install Git LFS and run `git lfs pull` to download them.";
#[derive(Debug, Clone)]
pub struct FixtureError {
message: String,
}
impl FixtureError {
fn new(message: impl Into<String>) -> Self {
Self { message: message.into() }
}
}
impl std::fmt::Display for FixtureError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(&self.message)
}
}
impl std::error::Error for FixtureError {}
pub fn require_fixture<P: AsRef<Path>>(path: P) -> Result<PathBuf, FixtureError> {
let path_ref = path.as_ref();
if path_ref.exists() {
Ok(path_ref.to_path_buf())
} else {
Err(FixtureError::new(format!(
"Missing telemetry fixture: {}. {}",
path_ref.display(),
FIXTURE_INSTALL_GUIDANCE
)))
}
}
pub fn find_git_repository_root() -> Result<PathBuf, Box<dyn std::error::Error>> {
let mut current_dir = std::env::current_dir()?;
loop {
let git_dir = current_dir.join(".git");
if git_dir.exists() {
return Ok(current_dir);
}
if let Some(parent) = current_dir.parent() {
current_dir = parent.to_path_buf();
} else {
return Err("Git repository root not found".into());
}
}
}
pub fn get_test_data_dir() -> Result<PathBuf, Box<dyn std::error::Error>> {
let repo_root = find_git_repository_root()?;
Ok(repo_root.join("test-data"))
}
pub fn get_ibt_test_files() -> Vec<PathBuf> {
let test_data_dir = match get_test_data_dir() {
Ok(dir) => dir,
Err(_) => return vec![],
};
let ibt_dir = test_data_dir.join("ibt");
if !ibt_dir.exists() {
return vec![];
}
let mut ibt_files = vec![];
if let Ok(entries) = std::fs::read_dir(&ibt_dir) {
for entry in entries.flatten() {
let path = entry.path();
if path.extension().and_then(|s| s.to_str()) == Some("ibt") {
ibt_files.push(path);
}
}
}
ibt_files.sort();
ibt_files
}
pub fn get_smallest_ibt_test_file() -> Option<PathBuf> {
let test_files = get_ibt_test_files();
if test_files.is_empty() {
return None;
}
let mut smallest_file = None;
let mut smallest_size = u64::MAX;
for file in test_files {
if let Ok(metadata) = std::fs::metadata(&file) {
if metadata.len() < smallest_size {
smallest_size = metadata.len();
smallest_file = Some(file);
}
}
}
smallest_file
}
pub fn require_ibt_fixtures() -> Result<Vec<PathBuf>, FixtureError> {
let fixtures = get_ibt_test_files();
if fixtures.is_empty() {
Err(FixtureError::new(format!(
"No IBT telemetry fixtures found in test-data/ibt. {}",
FIXTURE_INSTALL_GUIDANCE
)))
} else {
Ok(fixtures)
}
}
pub fn require_named_ibt_fixture(file_name: &str) -> Result<PathBuf, FixtureError> {
let fixtures = require_ibt_fixtures()?;
fixtures
.into_iter()
.find(|path| path.file_name().and_then(|n| n.to_str()) == Some(file_name))
.ok_or_else(|| {
FixtureError::new(format!(
"Expected telemetry fixture '{}' in test-data/ibt. {}",
file_name, FIXTURE_INSTALL_GUIDANCE
))
})
}
pub fn require_smallest_ibt_fixture() -> Result<PathBuf, FixtureError> {
get_smallest_ibt_test_file().ok_or_else(|| {
FixtureError::new(format!(
"No IBT telemetry fixtures found in test-data/ibt. {}",
FIXTURE_INSTALL_GUIDANCE
))
})
}
#[cfg(all(test, windows))]
pub fn require_test_data_file(file_name: &str) -> Result<PathBuf, FixtureError> {
let test_data_dir = get_test_data_dir().map_err(|err| {
FixtureError::new(format!(
"Failed to resolve test-data directory: {}. {}",
err, FIXTURE_INSTALL_GUIDANCE
))
})?;
require_fixture(test_data_dir.join(file_name))
}
#[cfg(test)]
mod tests {
use super::*;
use std::path::Path;
#[test]
fn test_find_git_repository_root_works() {
let repo_root = find_git_repository_root().expect("Should find git repository root");
assert!(repo_root.join(".git").exists(), "Repository root should contain .git directory");
assert!(
repo_root.join("Cargo.toml").exists(),
"Repository root should contain workspace Cargo.toml"
);
assert!(repo_root.join("README.md").exists(), "Repository root should contain README.md");
println!("Found git repository root: {}", repo_root.display());
}
#[test]
fn test_get_test_data_dir() {
let test_data_dir = get_test_data_dir().expect("Should find test-data directory");
assert!(test_data_dir.exists(), "test-data directory should exist");
assert!(test_data_dir.is_dir(), "test-data should be a directory");
println!("Found test-data directory: {}", test_data_dir.display());
}
#[test]
fn test_get_ibt_test_files() {
let ibt_files = get_ibt_test_files();
if !ibt_files.is_empty() {
println!("Found {} IBT test files:", ibt_files.len());
for file in &ibt_files {
println!(" {}", file.display());
}
for file in &ibt_files {
assert_eq!(file.extension().and_then(|s| s.to_str()), Some("ibt"));
}
} else {
println!("No IBT test files found (this is expected in CI or clean checkouts)");
}
}
#[test]
fn test_get_smallest_ibt_test_file() {
let smallest_file = get_smallest_ibt_test_file();
if let Some(file) = smallest_file {
println!("Smallest IBT test file: {}", file.display());
if let Ok(metadata) = std::fs::metadata(&file) {
println!("Size: {} bytes", metadata.len());
}
assert_eq!(file.extension().and_then(|s| s.to_str()), Some("ibt"));
} else {
println!("No IBT test files found for smallest file selection");
}
}
#[test]
fn test_require_fixture_errors_when_missing() {
let result = require_fixture(Path::new("test-data/__missing_fixture"));
assert!(result.is_err());
let message = result.unwrap_err().to_string();
assert!(message.contains("Missing telemetry fixture"));
assert!(message.contains("git lfs pull"));
}
}