use workspace_tools :: { Workspace, WorkspaceError };
use std ::fs;
use tempfile ::TempDir;
#[ cfg( all( feature = "serde", feature = "serde" ) ) ]
#[ test ]
fn test_cargo_serde()
{
use serde :: { Serialize, Deserialize };
#[ derive( Debug, Serialize, Deserialize, PartialEq ) ]
struct ProjectConfig
{
name: String,
version: String,
features: Vec< String >,
}
let temp_dir = TempDir ::new().unwrap();
let cargo_toml = r#"
[workspace]
members = [ "test_crate" ]
[workspace.package]
version = "0.1.0"
edition = "2021"
"#;
fs ::write( temp_dir.path().join( "Cargo.toml" ), cargo_toml ).unwrap();
let member_dir = temp_dir.path().join( "test_crate" );
fs ::create_dir_all( member_dir.join( "src" ) ).unwrap();
fs ::write( member_dir.join( "Cargo.toml" ), r#"
[package]
name = "test_crate"
version.workspace = true
edition.workspace = true
"# ).unwrap();
fs ::write( member_dir.join( "src/lib.rs" ), "// test crate" ).unwrap();
let workspace = Workspace ::from_cargo_manifest( temp_dir.path().join( "Cargo.toml" ) ).unwrap();
fs ::create_dir_all( workspace.config_dir() ).unwrap();
let config = ProjectConfig {
name: "test_project".to_string(),
version: "0.1.0".to_string(),
features: vec![ "default".to_string(), "serde".to_string() ],
};
let save_result = workspace.save_config( "project", &config );
assert!( save_result.is_ok(), "Should save config in cargo workspace" );
let loaded: Result< ProjectConfig, WorkspaceError > = workspace.load_config( "project" );
assert!( loaded.is_ok(), "Should load config from cargo workspace" );
assert_eq!( loaded.unwrap(), config );
let metadata = workspace.cargo_metadata();
if let Err( ref e ) = metadata
{
println!( "Cargo metadata error: {e}" );
}
assert!( metadata.is_ok(), "Should get cargo metadata" );
}
#[ cfg( all( feature = "glob", feature = "secrets" ) ) ]
#[ test ]
fn test_glob_secret_management_integration()
{
let temp_dir = TempDir ::new().unwrap();
let workspace = Workspace ::new( temp_dir.path() );
fs ::create_dir_all( workspace.secret_dir() ).unwrap();
let secret_files = vec![
( "api.env", "API_KEY=secret123\nDATABASE_URL=postgres: //localhost\n" ),
( "auth.env", "JWT_SECRET=jwt456\nOAUTH_CLIENT=oauth789\n" ),
( "config.env", "DEBUG=true\nLOG_LEVEL=info\n" ),
];
for ( filename, content ) in &secret_files
{
fs ::write( workspace.secret_dir().join( filename ), content ).unwrap();
}
let secret_pattern = format!( "{}/*.env", workspace.secret_dir().display() );
let found_files = workspace.find_resources( &secret_pattern );
assert!( found_files.is_ok(), "Should find secret files with glob pattern" );
let files = found_files.unwrap();
assert_eq!( files.len(), 3, "Should find all 3 secret files" );
for file in &files
{
if let Some( filename ) = file.file_name()
{
let secrets = workspace.load_secrets_from_file( &filename.to_string_lossy() );
assert!( secrets.is_ok(), "Should load secrets from file: {filename:?}" );
assert!( !secrets.unwrap().is_empty(), "Secret file should not be empty" );
}
}
let api_key = workspace.load_secret_key( "API_KEY", "api.env" );
assert!( api_key.is_ok(), "Should load API_KEY from api.env" );
assert_eq!( api_key.unwrap(), "secret123" );
}
#[ cfg( all( feature = "serde", feature = "glob" ) ) ]
#[ test ]
fn test_cargo_glob_integration()
{
let temp_dir = TempDir ::new().unwrap();
let cargo_toml = r#"
[workspace]
members = [ "lib1", "lib2" ]
[workspace.package]
version = "0.1.0"
edition = "2021"
"#;
fs ::write( temp_dir.path().join( "Cargo.toml" ), cargo_toml ).unwrap();
for member in [ "lib1", "lib2" ]
{
let member_dir = temp_dir.path().join( member );
fs ::create_dir_all( member_dir.join( "src" ) ).unwrap();
let member_cargo = format!( r#"
[package]
name = "{member}"
version.workspace = true
edition.workspace = true
"# );
fs ::write( member_dir.join( "Cargo.toml" ), member_cargo ).unwrap();
fs ::write( member_dir.join( "src/lib.rs" ), "// library code" ).unwrap();
}
let workspace = Workspace ::from_cargo_manifest( temp_dir.path().join( "Cargo.toml" ) ).unwrap();
let cargo_files = workspace.find_resources( "**/Cargo.toml" );
assert!( cargo_files.is_ok(), "Should find Cargo.toml files" );
let files = cargo_files.unwrap();
assert!( files.len() >= 3, "Should find at least workspace + member Cargo.toml files" );
let rust_files = workspace.find_resources( "**/*.rs" );
assert!( rust_files.is_ok(), "Should find Rust source files" );
let rs_files = rust_files.unwrap();
assert!( rs_files.len() >= 2, "Should find at least member lib.rs files" );
let members = workspace.workspace_members();
assert!( members.is_ok(), "Should get workspace members" );
assert_eq!( members.unwrap().len(), 2, "Should have 2 workspace members" );
}
#[ cfg( all( feature = "serde", feature = "secrets" ) ) ]
#[ test ]
fn test_serde_secret_management_integration()
{
use serde :: { Serialize, Deserialize };
#[ derive( Debug, Serialize, Deserialize, PartialEq ) ]
struct DatabaseConfig
{
host: String,
port: u16,
username: String,
password: String,
}
let temp_dir = TempDir ::new().unwrap();
let workspace = Workspace ::new( temp_dir.path() );
fs ::create_dir_all( workspace.config_dir() ).unwrap();
fs ::create_dir_all( workspace.secret_dir() ).unwrap();
let secret_content = "DB_PASSWORD=super_secret_password\nDB_USERNAME=admin\n";
fs ::write( workspace.secret_dir().join( "database.env" ), secret_content ).unwrap();
let username = workspace.load_secret_key( "DB_USERNAME", "database.env" ).unwrap();
let password = workspace.load_secret_key( "DB_PASSWORD", "database.env" ).unwrap();
let db_config = DatabaseConfig {
host: "localhost".to_string(),
port: 5432,
username,
password,
};
let save_result = workspace.save_config( "database", &db_config );
assert!( save_result.is_ok(), "Should save database config" );
let loaded: Result< DatabaseConfig, WorkspaceError > = workspace.load_config( "database" );
assert!( loaded.is_ok(), "Should load database config" );
let loaded_config = loaded.unwrap();
assert_eq!( loaded_config.username, "admin" );
assert_eq!( loaded_config.password, "super_secret_password" );
assert_eq!( loaded_config, db_config );
}
#[ cfg( all(
feature = "serde",
feature = "serde",
feature = "glob",
feature = "secrets"
) ) ]
#[ test ]
fn test_all_features_integration()
{
use serde :: { Serialize, Deserialize };
#[ derive( Debug, Serialize, Deserialize, PartialEq ) ]
struct FullConfig
{
project_name: String,
database_url: String,
api_keys: Vec< String >,
debug_mode: bool,
}
let temp_dir = TempDir ::new().unwrap();
let cargo_toml = r#"
[workspace]
members = [ "app" ]
[workspace.package]
version = "0.2.0"
edition = "2021"
"#;
fs ::write( temp_dir.path().join( "Cargo.toml" ), cargo_toml ).unwrap();
let app_dir = temp_dir.path().join( "app" );
fs ::create_dir_all( app_dir.join( "src" ) ).unwrap();
fs ::write( app_dir.join( "Cargo.toml" ), r#"
[package]
name = "app"
version.workspace = true
edition.workspace = true
"# ).unwrap();
fs ::write( app_dir.join( "src/main.rs" ), "fn main() {}" ).unwrap();
let workspace = Workspace ::from_cargo_manifest( temp_dir.path().join( "Cargo.toml" ) ).unwrap();
fs ::create_dir_all( workspace.config_dir() ).unwrap();
fs ::create_dir_all( workspace.secret_dir() ).unwrap();
let api_secrets = "API_KEY_1=key123\nAPI_KEY_2=key456\nDATABASE_URL=postgres: //user: pass@localhost/db\n";
fs ::write( workspace.secret_dir().join( "api.env" ), api_secrets ).unwrap();
let db_url = workspace.load_secret_key( "DATABASE_URL", "api.env" ).unwrap();
let api_key_1 = workspace.load_secret_key( "API_KEY_1", "api.env" ).unwrap();
let api_key_2 = workspace.load_secret_key( "API_KEY_2", "api.env" ).unwrap();
let config = FullConfig {
project_name: "integration_test".to_string(),
database_url: db_url,
api_keys: vec![ api_key_1, api_key_2 ],
debug_mode: true,
};
let save_result = workspace.save_config( "full_app", &config );
assert!( save_result.is_ok(), "Should save full configuration" );
let config_pattern = format!( "{}/*.toml", workspace.config_dir().display() );
let config_files = workspace.find_resources( &config_pattern );
assert!( config_files.is_ok(), "Should find config files" );
assert!( !config_files.unwrap().is_empty(), "Should have config files" );
let secret_pattern = format!( "{}/*.env", workspace.secret_dir().display() );
let secret_files = workspace.find_resources( &secret_pattern );
assert!( secret_files.is_ok(), "Should find secret files" );
assert!( !secret_files.unwrap().is_empty(), "Should have secret files" );
let loaded: Result< FullConfig, WorkspaceError > = workspace.load_config( "full_app" );
assert!( loaded.is_ok(), "Should load full configuration" );
assert_eq!( loaded.unwrap(), config );
let metadata = workspace.cargo_metadata();
assert!( metadata.is_ok(), "Should get cargo metadata" );
let members = workspace.workspace_members();
assert!( members.is_ok(), "Should get workspace members" );
assert_eq!( members.unwrap().len(), 1, "Should have 1 member" );
}
#[ test ]
fn test_minimal_functionality()
{
let temp_dir = TempDir ::new().unwrap();
let workspace = Workspace ::new( temp_dir.path() );
assert!( workspace.validate().is_ok() );
assert_eq!( workspace.root(), temp_dir.path() );
assert_eq!( workspace.config_dir(), temp_dir.path().join( "config" ) );
assert_eq!( workspace.data_dir(), temp_dir.path().join( "data" ) );
assert_eq!( workspace.logs_dir(), temp_dir.path().join( "logs" ) );
let joined = workspace.join( "test.txt" );
assert_eq!( joined, temp_dir.path().join( "test.txt" ) );
assert!( joined.is_absolute() );
assert!( workspace.is_workspace_file( &joined ) );
assert!( !workspace.is_workspace_file( "/etc/passwd" ) );
let ws_result = workspace_tools ::workspace();
assert!( ws_result.is_ok() );
let ws = ws_result.unwrap();
assert!( ws.root().exists() );
}
#[ cfg( all(
feature = "serde",
feature = "serde",
feature = "glob",
feature = "secrets"
) ) ]
#[ test ]
fn test_all_features_performance()
{
use std ::time ::Instant;
let temp_dir = TempDir ::new().unwrap();
fs ::write( temp_dir.path().join( "Cargo.toml" ), "[workspace]\nmembers = []\n" ).unwrap();
let start = Instant ::now();
let workspace = Workspace ::from_cargo_manifest( temp_dir.path().join( "Cargo.toml" ) ).unwrap();
for i in 0..100
{
let _joined = workspace.join( format!( "file_{i}.txt" ) );
let _config_dir = workspace.config_dir();
let _is_cargo = workspace.is_cargo_workspace();
}
let duration = start.elapsed();
assert!( duration.as_millis() < 1000, "Operations should complete within 1 second" );
}
#[ cfg( all( feature = "serde", feature = "serde" ) ) ]
#[ test ]
fn test_feature_interaction_edge_cases()
{
use serde :: { Serialize, Deserialize };
#[ derive( Debug, Serialize, Deserialize, PartialEq ) ]
struct EdgeConfig
{
name: String,
values: Vec< i32 >,
}
let temp_dir = TempDir ::new().unwrap();
fs ::write( temp_dir.path().join( "Cargo.toml" ), "[workspace]\nmembers = []\n" ).unwrap();
let workspace = Workspace ::from_cargo_manifest( temp_dir.path().join( "Cargo.toml" ) ).unwrap();
fs ::create_dir_all( workspace.config_dir() ).unwrap();
let empty_config = EdgeConfig {
name: String ::new(),
values: vec![],
};
let save_result = workspace.save_config( "empty", &empty_config );
assert!( save_result.is_ok(), "Should save empty config" );
let loaded: Result< EdgeConfig, WorkspaceError > = workspace.load_config( "empty" );
assert!( loaded.is_ok(), "Should load empty config" );
assert_eq!( loaded.unwrap(), empty_config );
let large_config = EdgeConfig {
name: "x".repeat( 1000 ),
values: (0..1000).collect(),
};
let save_large = workspace.save_config( "large", &large_config );
assert!( save_large.is_ok(), "Should save large config" );
let loaded_large: Result< EdgeConfig, WorkspaceError > = workspace.load_config( "large" );
assert!( loaded_large.is_ok(), "Should load large config" );
assert_eq!( loaded_large.unwrap(), large_config );
}