use axum::{ http::StatusCode, response::IntoResponse, }; use mock_server::upload::{UploadResult, FileInfo}; use tempfile::TempDir; use tokio::runtime::Runtime; /// 创建模拟的 multipart 数据 fn create_multipart_body(boundary: &str, files: Vec<(&str, &str, &[u8])>) -> Vec { let mut body = Vec::new(); for (field_name, filename, content) in files { body.extend_from_slice( format!( "--{}\r\nContent-Disposition: form-data; name=\"{}\"; filename=\"{}\"\r\n\r\n", boundary, field_name, filename ) .as_bytes(), ); body.extend_from_slice(content); body.extend_from_slice(b"\r\n"); } body.extend_from_slice(format!("--{}--\r\n", boundary).as_bytes()); body } #[test] fn test_upload_result_success() { let file_info = FileInfo { original_name: "test.txt".to_string(), stored_name: "uuid-test.txt".to_string(), path: "storage/2026-03-19/uuid-test.txt".to_string(), size: 1024, content_type: Some("text/plain".to_string()), }; let result = UploadResult::success(vec![file_info]); // 验证序列化 let json = serde_json::to_string(&result).unwrap(); assert!(json.contains("test.txt")); assert!(json.contains("success")); assert!(json.contains("1024")); } #[test] fn test_upload_result_error() { let result = UploadResult::error("Test error message".to_string()); assert!(!result.success); assert_eq!(result.message, "Test error message"); assert!(result.files.is_empty()); let json = serde_json::to_string(&result).unwrap(); assert!(json.contains("Test error message")); } #[test] fn test_file_info_serialization() { let file_info = FileInfo { original_name: "document.pdf".to_string(), stored_name: "550e8400-e29b-41d4-a716-446655440000.pdf".to_string(), path: "storage/2026-03-19/550e8400-e29b-41d4-a716-446655440000.pdf".to_string(), size: 2048, content_type: Some("application/pdf".to_string()), }; let json = serde_json::to_string(&file_info).unwrap(); assert!(json.contains("document.pdf")); assert!(json.contains("2048")); assert!(json.contains("application/pdf")); } #[test] fn test_upload_result_into_response() { let rt = Runtime::new().unwrap(); rt.block_on(async { let result = UploadResult::success(vec![]); let response = result.into_response(); assert_eq!(response.status(), StatusCode::OK); let result_error = UploadResult::error("Error".to_string()); let response_error = result_error.into_response(); assert_eq!(response_error.status(), StatusCode::BAD_REQUEST); }); } #[test] fn test_storage_directory_creation() { let rt = Runtime::new().unwrap(); rt.block_on(async { let temp_dir = TempDir::new().unwrap(); let storage_path = temp_dir.path().join("storage"); // 测试目录创建 tokio::fs::create_dir_all(&storage_path).await.unwrap(); assert!(storage_path.exists()); // 测试日期目录创建 let date_dir_name = chrono::Local::now().format("%Y-%m-%d").to_string(); let date_dir = storage_path.join(&date_dir_name); tokio::fs::create_dir_all(&date_dir).await.unwrap(); assert!(date_dir.exists()); }); } #[test] fn test_file_save_and_read() { let rt = Runtime::new().unwrap(); rt.block_on(async { let temp_dir = TempDir::new().unwrap(); let file_path = temp_dir.path().join("test_file.txt"); let content = b"Test file content"; // 写入文件 tokio::fs::write(&file_path, content).await.unwrap(); assert!(file_path.exists()); // 读取文件 let read_content = tokio::fs::read(&file_path).await.unwrap(); assert_eq!(read_content, content); }); } #[test] fn test_multipart_body_creation() { let boundary = "----WebKitFormBoundary7MA4YWxkTrZu0gW"; let content = b"Hello, World!"; let body = create_multipart_body(boundary, vec![("file", "test.txt", content)]); let body_str = String::from_utf8_lossy(&body); assert!(body_str.contains(boundary)); assert!(body_str.contains("test.txt")); assert!(body_str.contains("Hello, World!")); } #[test] fn test_multiple_files_multipart() { let boundary = "----WebKitFormBoundary"; let files = vec![ ("file1", "a.txt", b"content a" as &[u8]), ("file2", "b.txt", b"content b" as &[u8]), ]; let body = create_multipart_body(boundary, files); let body_str = String::from_utf8_lossy(&body); assert!(body_str.contains("a.txt")); assert!(body_str.contains("b.txt")); assert!(body_str.contains("content a")); assert!(body_str.contains("content b")); } #[test] fn test_uuid_generation() { use uuid::Uuid; let uuid1 = Uuid::new_v4(); let uuid2 = Uuid::new_v4(); // UUID 应该是唯一的 assert_ne!(uuid1, uuid2); // UUID 应该是有效的 assert!(!uuid1.is_nil()); assert!(!uuid2.is_nil()); } #[test] fn test_date_directory_format() { let date_dir_name = chrono::Local::now().format("%Y-%m-%d").to_string(); // 验证日期格式 assert!(date_dir_name.contains('-')); let parts: Vec<&str> = date_dir_name.split('-').collect(); assert_eq!(parts.len(), 3); } #[test] fn test_file_extension_extraction() { let test_cases = vec![ ("test.txt", ".txt"), ("document.pdf", ".pdf"), ("image.png", ".png"), ("archive.tar.gz", ".gz"), ("noextension", ""), ]; for (filename, expected_ext) in test_cases { let extension = std::path::Path::new(filename) .extension() .and_then(|s| s.to_str()) .map(|s| format!(".{}", s)) .unwrap_or_default(); assert_eq!(extension, expected_ext); } } #[test] fn test_large_file_content() { let rt = Runtime::new().unwrap(); rt.block_on(async { let temp_dir = TempDir::new().unwrap(); let file_path = temp_dir.path().join("large_file.bin"); // 创建 1MB 的数据 let large_content = vec![0u8; 1024 * 1024]; tokio::fs::write(&file_path, &large_content).await.unwrap(); let file_size = tokio::fs::metadata(&file_path).await.unwrap().len(); assert_eq!(file_size, 1024 * 1024); }); } #[test] fn test_binary_file_content() { let rt = Runtime::new().unwrap(); rt.block_on(async { let temp_dir = TempDir::new().unwrap(); let file_path = temp_dir.path().join("binary.bin"); // 创建二进制数据 let binary_data: Vec = (0..=255).collect(); tokio::fs::write(&file_path, &binary_data).await.unwrap(); let read_data = tokio::fs::read(&file_path).await.unwrap(); assert_eq!(read_data.len(), 256); assert_eq!(read_data, binary_data); }); }