//! 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, 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(), } } pub fn with_dependency(mut self, dep: &str) -> Self { self.dependencies.push(dep.to_string()); self } 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 } 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 ); 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 )); } } manifest } 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)?; let manifest_path = feature_dir.join("feature.toml"); fs::write(&manifest_path, self.build_manifest())?; 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)?; assert!(file_content.contains(content), "File {} does not contain expected content: {}", 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)?; // Simple path traversal (e.g., "dependencies.analytics") let parts: Vec<&str> = json_path.split('.').collect(); let mut current = &json; for part in parts { current = current.get(part) .ok_or_else(|| anyhow::anyhow!("Path {} not found in JSON", json_path))?; } 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 = [] "#; let registry_path = project_root.join("registry/features.toml"); fs::write(®istry_path, registry_content)?; Ok(()) }