128 lines
3.5 KiB
Rust
Raw Normal View History

2026-02-08 20:18:46 +00:00
//! Test helper utilities
use anyhow::Result;
use serde_json::Value;
use std::fs;
use std::path::Path;
use tempfile::TempDir;
/// Test feature manifest builder
pub struct TestFeatureBuilder {
pub name: String,
pub version: String,
pub dependencies: Vec<String>,
pub environment_vars: Vec<(String, String, bool)>, // (name, default, required)
}
impl TestFeatureBuilder {
pub fn new(name: &str) -> Self {
Self {
name: name.to_string(),
version: "0.1.0".to_string(),
dependencies: Vec::new(),
environment_vars: Vec::new(),
}
}
2026-02-08 20:37:49 +00:00
2026-02-08 20:18:46 +00:00
pub fn with_dependency(mut self, dep: &str) -> Self {
self.dependencies.push(dep.to_string());
self
}
2026-02-08 20:37:49 +00:00
2026-02-08 20:18:46 +00:00
pub fn with_env_var(mut self, name: &str, default: &str, required: bool) -> Self {
self.environment_vars.push((name.to_string(), default.to_string(), required));
self
}
2026-02-08 20:37:49 +00:00
2026-02-08 20:18:46 +00:00
pub fn build_manifest(&self) -> String {
let mut manifest = format!(
r#"[feature]
name = "{}"
version = "{}"
source = "test"
description = "Test feature"
requires = []
[dependencies]
workspace = {:?}
external = []
"#,
self.name, self.version, self.dependencies
);
2026-02-08 20:37:49 +00:00
2026-02-08 20:18:46 +00:00
if !self.environment_vars.is_empty() {
manifest.push_str("\n");
for (name, default, required) in &self.environment_vars {
manifest.push_str(&format!(
"\n[[environment.variables]]\nname = \"{}\"\ndefault = \"{}\"\nrequired = {}\n",
name, default, required
));
}
}
2026-02-08 20:37:49 +00:00
2026-02-08 20:18:46 +00:00
manifest
}
2026-02-08 20:37:49 +00:00
2026-02-08 20:18:46 +00:00
pub fn create_in_project(&self, project_root: &Path) -> Result<()> {
let feature_dir = project_root.join("features").join(&self.name);
fs::create_dir_all(&feature_dir)?;
2026-02-08 20:37:49 +00:00
2026-02-08 20:18:46 +00:00
let manifest_path = feature_dir.join("feature.toml");
fs::write(&manifest_path, self.build_manifest())?;
2026-02-08 20:37:49 +00:00
2026-02-08 20:18:46 +00:00
Ok(())
}
}
/// Assert that a file contains specific content
pub fn assert_file_contains(file_path: &Path, content: &str) -> Result<()> {
let file_content = fs::read_to_string(file_path)?;
2026-02-08 20:37:49 +00:00
assert!(file_content.contains(content),
"File {} does not contain expected content: {}",
2026-02-08 20:18:46 +00:00
file_path.display(), content);
Ok(())
}
/// Assert that a JSON file has a specific value at a path
pub fn assert_json_value(file_path: &Path, json_path: &str, expected: &Value) -> Result<()> {
let content = fs::read_to_string(file_path)?;
let json: Value = serde_json::from_str(&content)?;
2026-02-08 20:37:49 +00:00
2026-02-08 20:18:46 +00:00
// Simple path traversal (e.g., "dependencies.analytics")
let parts: Vec<&str> = json_path.split('.').collect();
let mut current = &json;
2026-02-08 20:37:49 +00:00
2026-02-08 20:18:46 +00:00
for part in parts {
current = current.get(part)
.ok_or_else(|| anyhow::anyhow!("Path {} not found in JSON", json_path))?;
}
2026-02-08 20:37:49 +00:00
2026-02-08 20:18:46 +00:00
assert_eq!(current, expected, "JSON value at {} does not match expected", json_path);
Ok(())
}
/// Create a mock feature registry
pub fn create_mock_registry(project_root: &Path) -> Result<()> {
let registry_content = r#"
# Test Features Registry
[features]
[features.test-analytics]
description = "Test analytics system"
source = "test"
status = "available"
requires = []
[features.test-build]
description = "Test build system"
source = "test"
status = "available"
requires = []
"#;
2026-02-08 20:37:49 +00:00
2026-02-08 20:18:46 +00:00
let registry_path = project_root.join("registry/features.toml");
fs::write(&registry_path, registry_content)?;
Ok(())
2026-02-08 20:37:49 +00:00
}