use workspace_tools :: { Workspace, WorkspaceError };
use std :: { env, fs, path ::PathBuf };
use std ::sync ::Mutex;
static ENV_TEST_MUTEX: Mutex< () > = Mutex ::new( () );
use tempfile :: { TempDir, NamedTempFile };
fn create_test_workspace_at( path: &std ::path ::Path ) -> Workspace
{
Workspace ::new( path )
}
#[ test ]
fn test_validate_file_instead_of_directory()
{
let temp_file = NamedTempFile ::new().unwrap();
let original = env ::var( "WORKSPACE_PATH" ).ok();
env ::set_var( "WORKSPACE_PATH", temp_file.path() );
let workspace_result = Workspace ::resolve();
match original
{
Some( value ) => env ::set_var( "WORKSPACE_PATH", value ),
None => env ::remove_var( "WORKSPACE_PATH" ),
}
if let Ok( workspace ) = workspace_result
{
let validation = workspace.validate();
assert!( validation.is_err(), "Validation should fail when workspace root is a file" );
}
else
{
match workspace_result.unwrap_err()
{
WorkspaceError ::IoError( _ ) | WorkspaceError ::PathNotFound( _ ) => {}, other => panic!( "Expected IoError or PathNotFound, got {other:?}" ),
}
}
}
#[ test ]
fn test_validate_existing_directory_success()
{
let temp_dir = TempDir ::new().unwrap();
let workspace = create_test_workspace_at( temp_dir.path() );
let result = workspace.validate();
assert!( result.is_ok(), "validate() should succeed for existing directory" );
}
#[ test ]
fn test_validate_nonexistent_directory()
{
let temp_dir = TempDir ::new().unwrap();
let nonexistent = temp_dir.path().join( "nonexistent" );
let original = env ::var( "WORKSPACE_PATH" ).ok();
env ::set_var( "WORKSPACE_PATH", &nonexistent );
let result = Workspace ::resolve();
match original
{
Some( value ) => env ::set_var( "WORKSPACE_PATH", value ),
None => env ::remove_var( "WORKSPACE_PATH" ),
}
assert!( result.is_err() );
match result.unwrap_err()
{
WorkspaceError ::PathNotFound( path ) => assert_eq!( path, nonexistent ),
other => panic!( "Expected PathNotFound, got {other:?}" ),
}
}
#[ test ]
fn test_is_workspace_file_exact_root()
{
let temp_dir = TempDir ::new().unwrap();
let workspace = create_test_workspace_at( temp_dir.path() );
let is_workspace = workspace.is_workspace_file( temp_dir.path() );
assert!( is_workspace, "Workspace root should be considered a workspace file" );
}
#[ test ]
fn test_is_workspace_file_parent_directory()
{
let temp_dir = TempDir ::new().unwrap();
let workspace = create_test_workspace_at( temp_dir.path() );
if let Some( parent ) = temp_dir.path().parent()
{
let is_workspace = workspace.is_workspace_file( parent );
assert!( !is_workspace, "Parent of workspace root should not be considered a workspace file" );
}
}
#[ test ]
fn test_is_workspace_file_deeply_nested()
{
let temp_dir = TempDir ::new().unwrap();
let workspace = create_test_workspace_at( temp_dir.path() );
let nested_path = temp_dir.path()
.join( "level1" )
.join( "level2" )
.join( "level3" )
.join( "deep_file.txt" );
let is_workspace = workspace.is_workspace_file( &nested_path );
assert!( is_workspace, "Deeply nested path should be considered a workspace file" );
}
#[ test ]
fn test_is_workspace_file_with_traversal()
{
let temp_dir = TempDir ::new().unwrap();
let workspace = create_test_workspace_at( temp_dir.path() );
let traversal_path = temp_dir.path()
.join( "subdir" )
.join( ".." )
.join( "file.txt" );
let is_workspace = workspace.is_workspace_file( &traversal_path );
assert!( is_workspace, "Path with .. traversal that stays within workspace should be considered workspace file" );
}
#[ test ]
fn test_is_workspace_file_absolute_outside()
{
let temp_dir = TempDir ::new().unwrap();
let workspace = create_test_workspace_at( temp_dir.path() );
let outside_paths = vec![
PathBuf ::from( "/etc/passwd" ),
PathBuf ::from( "/tmp/outside.txt" ),
PathBuf ::from( "/usr/bin/ls" ),
];
for outside_path in outside_paths
{
let is_workspace = workspace.is_workspace_file( &outside_path );
assert!( !is_workspace, "Path {} should not be considered a workspace file", outside_path.display() );
}
}
#[ test ]
fn test_workspace_creation_empty_path()
{
let _lock = ENV_TEST_MUTEX.lock().unwrap();
let original = env ::var( "WORKSPACE_PATH" ).ok();
env ::set_var( "WORKSPACE_PATH", "" );
let result = Workspace ::resolve();
match original
{
Some( value ) => env ::set_var( "WORKSPACE_PATH", value ),
None => env ::remove_var( "WORKSPACE_PATH" ),
}
assert!( result.is_err(), "Empty WORKSPACE_PATH should result in error" );
}
#[ test ]
fn test_workspace_creation_root_directory()
{
let original = env ::var( "WORKSPACE_PATH" ).ok();
#[ cfg( windows ) ]
let root_path = "C:\\";
#[ cfg( not( windows ) ) ]
let root_path = "/";
env ::set_var( "WORKSPACE_PATH", root_path );
let result = Workspace ::resolve();
match original
{
Some( value ) => env ::set_var( "WORKSPACE_PATH", value ),
None => env ::remove_var( "WORKSPACE_PATH" ),
}
if let Ok( workspace ) = result
{
assert_eq!( workspace.root(), PathBuf ::from( root_path ) );
}
}
#[ test ]
fn test_workspace_creation_relative_path()
{
let temp_dir = TempDir ::new().unwrap();
let original = env ::var( "WORKSPACE_PATH" ).ok();
let original_cwd = env ::current_dir().unwrap();
env ::set_current_dir( temp_dir.path() ).unwrap();
env ::set_var( "WORKSPACE_PATH", "." );
let result = Workspace ::resolve();
env ::set_current_dir( original_cwd ).unwrap();
match original
{
Some( value ) => env ::set_var( "WORKSPACE_PATH", value ),
None => env ::remove_var( "WORKSPACE_PATH" ),
}
assert!( result.is_ok() );
let workspace = result.unwrap();
assert!( workspace.root().exists() );
let validation = workspace.validate();
assert!( validation.is_ok(), "Workspace should be valid even if path is relative" );
}
#[ test ]
fn test_boundary_edge_case_paths()
{
let temp_dir = TempDir ::new().unwrap();
let workspace = create_test_workspace_at( temp_dir.path() );
let edge_cases = vec![
temp_dir.path().join( "" ),
temp_dir.path().join( "." ),
temp_dir.path().join( "./subdir/../file.txt" ),
temp_dir.path().join( "config//app.toml" ),
];
for edge_case in edge_cases
{
let is_workspace = workspace.is_workspace_file( &edge_case );
assert!( is_workspace, "Edge case path should be within workspace: {}", edge_case.display() );
}
}
#[ test ]
fn test_validation_with_special_files()
{
let temp_dir = TempDir ::new().unwrap();
fs ::write( temp_dir.path().join( "Cargo.toml" ), "[package]\nname = \"test\"\n" ).unwrap();
fs ::write( temp_dir.path().join( ".gitignore" ), "target/\n" ).unwrap();
fs ::write( temp_dir.path().join( "README.md" ), "# Test Workspace\n" ).unwrap();
let workspace = create_test_workspace_at( temp_dir.path() );
let result = workspace.validate();
assert!( result.is_ok(), "Validation should succeed for directory with typical workspace files" );
assert!( workspace.is_workspace_file( workspace.cargo_toml() ) );
assert!( workspace.is_workspace_file( workspace.readme() ) );
assert!( workspace.is_workspace_file( temp_dir.path().join( ".gitignore" ) ) );
}
#[ test ]
fn test_path_join_edge_cases()
{
let temp_dir = TempDir ::new().unwrap();
let workspace = create_test_workspace_at( temp_dir.path() );
let edge_cases = vec![
".",
"./",
"subdir/..",
"subdir/../other",
"",
];
for edge_case in edge_cases
{
let joined = workspace.join( edge_case );
assert!( joined.is_absolute(), "Joined path should be absolute for: {edge_case}" );
assert!( joined.starts_with( temp_dir.path() ), "Joined path should start with workspace root for: {edge_case}" );
}
}
#[ test ]
fn test_large_workspace_structure()
{
let temp_dir = TempDir ::new().unwrap();
let workspace = create_test_workspace_at( temp_dir.path() );
let dirs = vec![
"src/main",
"src/lib",
"tests/integration",
"tests/unit",
"config/dev",
"config/prod",
"data/migrations",
"docs/api",
"docs/user",
".workspace/cache",
];
for dir in &dirs
{
fs ::create_dir_all( temp_dir.path().join( dir ) ).unwrap();
}
let result = workspace.validate();
assert!( result.is_ok(), "Validation should work with complex directory structure" );
for dir in &dirs
{
let dir_path = temp_dir.path().join( dir );
assert!( workspace.is_workspace_file( &dir_path ), "Directory {dir} should be within workspace" );
}
}
#[ test ]
fn test_deeply_nested_workspace()
{
let temp_dir = TempDir ::new().unwrap();
let mut deep_path = temp_dir.path().to_path_buf();
for i in 1..=20
{
deep_path.push( format!( "level{i}" ) );
}
fs ::create_dir_all( &deep_path ).unwrap();
let workspace = create_test_workspace_at( temp_dir.path() );
let result = workspace.validate();
assert!( result.is_ok(), "Validation should work with deeply nested structure" );
assert!( workspace.is_workspace_file( &deep_path ), "Deeply nested path should be within workspace" );
}