use std::collections::HashMap;
use reqwest::Method;
use crate::core::constants::AccessTokenType;
#[derive(Debug, Clone, Default)]
pub struct ApiRequest {
pub(crate) http_method: Method,
pub api_path: String,
pub body: Vec<u8>,
pub query_params: HashMap<&'static str, String>,
pub path_params: HashMap<String, Vec<String>>,
pub(crate) supported_access_token_types: Vec<AccessTokenType>,
pub file: Vec<u8>,
}
#[cfg(test)]
mod tests {
use super::*;
use crate::core::constants::AccessTokenType;
use reqwest::Method;
#[test]
fn test_api_request_creation() {
let api_req = ApiRequest {
http_method: Method::POST,
api_path: "/open-apis/test/v1/endpoint".to_string(),
body: b"test body".to_vec(),
query_params: HashMap::new(),
path_params: HashMap::new(),
supported_access_token_types: vec![AccessTokenType::Tenant],
file: Vec::new(),
};
assert_eq!(api_req.http_method, Method::POST);
assert_eq!(api_req.api_path, "/open-apis/test/v1/endpoint");
assert_eq!(api_req.body, b"test body".to_vec());
assert!(api_req.query_params.is_empty());
assert!(api_req.path_params.is_empty());
assert_eq!(
api_req.supported_access_token_types,
vec![AccessTokenType::Tenant]
);
assert!(api_req.file.is_empty());
}
#[test]
fn test_api_request_default() {
let api_req = ApiRequest::default();
assert_eq!(api_req.http_method, Method::GET);
assert!(api_req.api_path.is_empty());
assert!(api_req.body.is_empty());
assert!(api_req.query_params.is_empty());
assert!(api_req.path_params.is_empty());
assert!(api_req.supported_access_token_types.is_empty());
assert!(api_req.file.is_empty());
}
#[test]
fn test_api_request_clone() {
let original = ApiRequest {
http_method: Method::PUT,
api_path: "/open-apis/clone/test".to_string(),
body: b"original body".to_vec(),
query_params: {
let mut params = HashMap::new();
params.insert("page_size", "10".to_string());
params
},
path_params: {
let mut params = HashMap::new();
params.insert("file_id".to_string(), vec!["123".to_string()]);
params
},
supported_access_token_types: vec![AccessTokenType::User, AccessTokenType::Tenant],
file: b"file content".to_vec(),
};
let cloned = original.clone();
assert_eq!(original.http_method, cloned.http_method);
assert_eq!(original.api_path, cloned.api_path);
assert_eq!(original.body, cloned.body);
assert_eq!(original.query_params, cloned.query_params);
assert_eq!(original.path_params, cloned.path_params);
assert_eq!(
original.supported_access_token_types,
cloned.supported_access_token_types
);
assert_eq!(original.file, cloned.file);
}
#[test]
fn test_api_request_debug() {
let api_req = ApiRequest {
http_method: Method::DELETE,
api_path: "/debug/test".to_string(),
body: b"debug body".to_vec(),
..Default::default()
};
let debug_str = format!("{:?}", api_req);
assert!(debug_str.contains("ApiRequest"));
assert!(debug_str.contains("DELETE"));
assert!(debug_str.contains("/debug/test"));
}
#[test]
fn test_api_request_with_different_http_methods() {
let methods = vec![
Method::GET,
Method::POST,
Method::PUT,
Method::DELETE,
Method::PATCH,
Method::HEAD,
Method::OPTIONS,
];
for method in methods {
let api_req = ApiRequest {
http_method: method.clone(),
..Default::default()
};
assert_eq!(api_req.http_method, method);
}
}
#[test]
fn test_api_request_with_query_params() {
let mut api_req = ApiRequest::default();
api_req.query_params.insert("page_size", "20".to_string());
api_req
.query_params
.insert("page_token", "token123".to_string());
api_req
.query_params
.insert("filter", "status=active".to_string());
assert_eq!(api_req.query_params.len(), 3);
assert_eq!(
api_req.query_params.get("page_size"),
Some(&"20".to_string())
);
assert_eq!(
api_req.query_params.get("page_token"),
Some(&"token123".to_string())
);
assert_eq!(
api_req.query_params.get("filter"),
Some(&"status=active".to_string())
);
}
#[test]
fn test_api_request_with_path_params() {
let mut api_req = ApiRequest::default();
api_req
.path_params
.insert("user_id".to_string(), vec!["user123".to_string()]);
api_req
.path_params
.insert("file_id".to_string(), vec!["file456".to_string()]);
api_req.path_params.insert(
"multiple".to_string(),
vec!["val1".to_string(), "val2".to_string()],
);
assert_eq!(api_req.path_params.len(), 3);
assert_eq!(
api_req.path_params.get("user_id"),
Some(&vec!["user123".to_string()])
);
assert_eq!(
api_req.path_params.get("file_id"),
Some(&vec!["file456".to_string()])
);
assert_eq!(
api_req.path_params.get("multiple"),
Some(&vec!["val1".to_string(), "val2".to_string()])
);
}
#[test]
fn test_api_request_with_different_access_token_types() {
let token_types = vec![
vec![AccessTokenType::User],
vec![AccessTokenType::Tenant],
vec![AccessTokenType::App],
vec![AccessTokenType::User, AccessTokenType::Tenant],
vec![
AccessTokenType::User,
AccessTokenType::Tenant,
AccessTokenType::App,
],
];
for token_type_vec in token_types {
let api_req = ApiRequest {
supported_access_token_types: token_type_vec.clone(),
..Default::default()
};
assert_eq!(api_req.supported_access_token_types, token_type_vec);
}
}
#[test]
fn test_api_request_with_body_serialization() {
let json_data = serde_json::json!({
"name": "test file",
"parent_id": "folder123"
});
let json_bytes = serde_json::to_vec(&json_data).unwrap();
let api_req = ApiRequest {
body: json_bytes.clone(),
..Default::default()
};
assert_eq!(api_req.body, json_bytes);
let deserialized: serde_json::Value = serde_json::from_slice(&api_req.body).unwrap();
assert_eq!(deserialized, json_data);
}
#[test]
fn test_api_request_with_empty_body() {
let api_req = ApiRequest {
body: Vec::new(),
..Default::default()
};
assert!(api_req.body.is_empty());
}
#[test]
fn test_api_request_with_large_body() {
let large_body = vec![0u8; 1024 * 1024]; let api_req = ApiRequest {
body: large_body.clone(),
..Default::default()
};
assert_eq!(api_req.body.len(), 1024 * 1024);
assert_eq!(api_req.body, large_body);
}
#[test]
fn test_api_request_with_file_upload() {
let file_content = b"binary file content";
let metadata = serde_json::json!({
"filename": "test.txt",
"size": file_content.len()
});
let api_req = ApiRequest {
http_method: Method::POST,
api_path: "/upload".to_string(),
body: serde_json::to_vec(&metadata).unwrap(),
file: file_content.to_vec(),
..Default::default()
};
assert_eq!(api_req.http_method, Method::POST);
assert_eq!(api_req.api_path, "/upload");
assert!(!api_req.body.is_empty());
assert_eq!(api_req.file, file_content.to_vec());
}
#[test]
fn test_api_request_with_empty_file() {
let api_req = ApiRequest {
file: Vec::new(),
..Default::default()
};
assert!(api_req.file.is_empty());
}
#[test]
fn test_api_request_with_large_file() {
let large_file = vec![1u8; 10 * 1024 * 1024]; let api_req = ApiRequest {
file: large_file.clone(),
..Default::default()
};
assert_eq!(api_req.file.len(), 10 * 1024 * 1024);
assert_eq!(api_req.file, large_file);
}
#[test]
fn test_api_request_multipart_structure() {
let metadata = serde_json::json!({
"name": "document.pdf",
"parent_id": "folder123"
});
let file_content = b"PDF file binary content";
let api_req = ApiRequest {
http_method: Method::POST,
api_path: "/upload/multipart".to_string(),
body: serde_json::to_vec(&metadata).unwrap(),
file: file_content.to_vec(),
supported_access_token_types: vec![AccessTokenType::Tenant],
..Default::default()
};
assert_eq!(api_req.http_method, Method::POST);
assert!(!api_req.body.is_empty()); assert!(!api_req.file.is_empty()); assert_eq!(
api_req.supported_access_token_types,
vec![AccessTokenType::Tenant]
);
}
#[test]
fn test_api_request_path_variations() {
let paths = vec![
"/open-apis/drive/v1/files",
"/open-apis/drive/v1/files/{file_id}",
"/open-apis/contact/v3/users/{user_id}/update",
"",
"/",
"/simple",
"/very/deep/nested/path/structure/endpoint",
];
for path in paths {
let api_req = ApiRequest {
api_path: path.to_string(),
..Default::default()
};
assert_eq!(api_req.api_path, path);
}
}
#[test]
fn test_api_request_special_characters_in_paths() {
let special_paths = vec![
"/path/with spaces",
"/path/with-dashes",
"/path/with_underscores",
"/path/with.dots",
"/path/with@symbols",
"/path/with中文字符",
"/path/with🚀emoji",
];
for path in special_paths {
let api_req = ApiRequest {
api_path: path.to_string(),
..Default::default()
};
assert_eq!(api_req.api_path, path);
}
}
#[test]
fn test_api_request_query_params_special_values() {
let mut api_req = ApiRequest::default();
api_req.query_params.insert("empty", "".to_string());
api_req
.query_params
.insert("space", "value with space".to_string());
api_req
.query_params
.insert("special", "value@#$%^&*()".to_string());
api_req
.query_params
.insert("unicode", "中文值🚀".to_string());
api_req
.query_params
.insert("url_encoded", "value%20with%20encoding".to_string());
assert_eq!(api_req.query_params.len(), 5);
assert_eq!(api_req.query_params.get("empty"), Some(&"".to_string()));
assert_eq!(
api_req.query_params.get("space"),
Some(&"value with space".to_string())
);
assert_eq!(
api_req.query_params.get("special"),
Some(&"value@#$%^&*()".to_string())
);
assert_eq!(
api_req.query_params.get("unicode"),
Some(&"中文值🚀".to_string())
);
assert_eq!(
api_req.query_params.get("url_encoded"),
Some(&"value%20with%20encoding".to_string())
);
}
#[test]
fn test_api_request_path_params_complex() {
let mut api_req = ApiRequest::default();
api_req
.path_params
.insert("single".to_string(), vec!["one".to_string()]);
api_req.path_params.insert(
"multiple".to_string(),
vec![
"first".to_string(),
"second".to_string(),
"third".to_string(),
],
);
api_req.path_params.insert("empty".to_string(), vec![]);
api_req.path_params.insert(
"special".to_string(),
vec![
"value@#$".to_string(),
"中文".to_string(),
"🚀emoji".to_string(),
],
);
assert_eq!(api_req.path_params.len(), 4);
assert_eq!(
api_req.path_params.get("single"),
Some(&vec!["one".to_string()])
);
assert_eq!(
api_req.path_params.get("multiple"),
Some(&vec![
"first".to_string(),
"second".to_string(),
"third".to_string()
])
);
assert_eq!(api_req.path_params.get("empty"), Some(&vec![]));
assert_eq!(
api_req.path_params.get("special"),
Some(&vec![
"value@#$".to_string(),
"中文".to_string(),
"🚀emoji".to_string()
])
);
}
#[test]
fn test_api_request_binary_data_handling() {
let binary_data = vec![0, 1, 2, 3, 4, 255, 254, 253];
let api_req = ApiRequest {
body: binary_data.clone(),
file: binary_data.clone(),
..Default::default()
};
assert_eq!(api_req.body, binary_data);
assert_eq!(api_req.file, binary_data);
}
#[test]
fn test_api_request_memory_efficiency() {
let requests: Vec<ApiRequest> = (0..100)
.map(|i| ApiRequest {
api_path: format!("/api/path/{}", i),
body: format!("body_{}", i).into_bytes(),
..Default::default()
})
.collect();
assert_eq!(requests.len(), 100);
for (i, req) in requests.iter().enumerate() {
assert_eq!(req.api_path, format!("/api/path/{}", i));
assert_eq!(req.body, format!("body_{}", i).into_bytes());
}
}
#[test]
fn test_api_request_field_independence() {
let mut api_req = ApiRequest {
http_method: Method::POST,
api_path: "/test".to_string(),
body: b"test body".to_vec(),
..Default::default()
};
api_req.query_params.insert("test", "value".to_string());
api_req
.path_params
.insert("id".to_string(), vec!["123".to_string()]);
api_req
.supported_access_token_types
.push(AccessTokenType::User);
api_req.file = b"file content".to_vec();
assert_eq!(api_req.http_method, Method::POST);
assert_eq!(api_req.api_path, "/test");
assert_eq!(api_req.body, b"test body");
assert_eq!(api_req.query_params.len(), 1);
assert_eq!(api_req.path_params.len(), 1);
assert_eq!(api_req.supported_access_token_types.len(), 1);
assert_eq!(api_req.file, b"file content");
}
}