use super::*;
#[test]
fn test_api_response() {
let success: ApiResponse<String> = ApiResponse::success("test".to_string());
assert!(success.is_success());
assert!(!success.is_error());
assert!(success.into_result().is_ok());
let error: ApiResponse<String> = ApiResponse::error(404, "Not found");
assert!(!error.is_success());
assert!(error.is_error());
assert!(error.into_result().is_err());
}
#[test]
fn test_pagination() {
let pagination = Pagination::new(2, 10, 25);
assert_eq!(pagination.total_pages, 3);
assert!(pagination.has_prev);
assert!(pagination.has_next);
let last_page = Pagination::new(3, 10, 25);
assert!(!last_page.has_next);
assert!(last_page.has_prev);
}
#[test]
fn test_rate_limit() {
let rate_limit = RateLimit {
bucket: Some("global".to_string()),
limit: 100,
remaining: 0,
reset: chrono::Utc::now().timestamp() as u64 + 60,
retry_after: Some(60),
};
assert!(rate_limit.is_exceeded());
assert!(rate_limit.reset_in() > 0);
}
#[test]
fn test_api_error() {
let error = ApiError::new(429, "Rate limited");
assert!(error.is_rate_limit());
assert!(!error.is_auth_error());
assert!(!error.is_not_found());
assert!(!error.is_server_error());
let auth_error = ApiError::new(401, "Unauthorized");
assert!(auth_error.is_auth_error());
}
#[test]
fn websocket_ap_keeps_official_json_shape() {
let ap: WebsocketAP = serde_json::from_value(serde_json::json!({
"url": "wss://api.sgroup.qq.com/websocket",
"shards": 2,
"session_start_limit": {
"total": 10,
"remaining": 9,
"reset_after": 1000,
"max_concurrency": 1
}
}))
.unwrap();
assert_eq!(ap.url, "wss://api.sgroup.qq.com/websocket");
assert_eq!(ap.shards, 2);
assert_eq!(ap.session_start_limit.total, 10);
assert_eq!(ap.session_start_limit.remaining, 9);
assert_eq!(ap.session_start_limit.reset_after, 1000);
assert_eq!(ap.session_start_limit.max_concurrency, 1);
let value = serde_json::to_value(&ap).unwrap();
assert_eq!(value["session_start_limit"]["reset_after"], 1000);
}
#[test]
fn audio_action_uses_required_zero_value_fields() {
let action: AudioAction = serde_json::from_value(serde_json::json!({})).unwrap();
assert_eq!(action.guild_id, "");
assert_eq!(action.channel_id, "");
assert_eq!(action.audio_url, "");
assert_eq!(action.text, "");
}
#[test]
fn audio_action_keeps_official_json_shape() {
let action = AudioAction {
guild_id: "guild-1".to_string(),
channel_id: "channel-1".to_string(),
audio_url: "https://example.com/audio.mp3".to_string(),
text: "now playing".to_string(),
};
let value = serde_json::to_value(&action).unwrap();
assert_eq!(value["guild_id"], "guild-1");
assert_eq!(value["channel_id"], "channel-1");
assert_eq!(value["audio_url"], "https://example.com/audio.mp3");
assert_eq!(value["text"], "now playing");
}
#[test]
fn audio_action_from_value_tolerates_missing_fields() {
let action = AudioAction::from_value(&serde_json::json!({
"guild_id": "guild-1",
"channel_id": 123,
}));
assert_eq!(action.guild_id, "guild-1");
assert_eq!(action.channel_id, "");
assert_eq!(action.audio_url, "");
assert_eq!(action.text, "");
}
#[test]
fn pins_message_uses_required_zero_value_fields() {
let pins: PinsMessage = serde_json::from_value(serde_json::json!({})).unwrap();
assert!(pins.guild_id.is_empty());
assert!(pins.channel_id.is_empty());
assert!(pins.message_ids.is_empty());
}
#[test]
fn pins_message_keeps_official_json_shape() {
let pins = PinsMessage {
guild_id: "guild-1".to_string(),
channel_id: "channel-1".to_string(),
message_ids: vec!["message-1".to_string(), "message-2".to_string()],
};
let value = serde_json::to_value(&pins).unwrap();
assert_eq!(value["guild_id"], "guild-1");
assert_eq!(value["channel_id"], "channel-1");
assert_eq!(value["message_ids"][0], "message-1");
}