use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct TrendingRepo {
pub repo_id: String,
pub name: String,
pub owner_id: String,
pub owner_name: String,
pub description: Option<String>,
pub stars: i32,
pub stars_delta: i32,
pub weighted_score: f64,
pub created_at: DateTime<Utc>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct TrendingResponse {
pub window: String,
pub repos: Vec<TrendingRepo>,
pub computed_at: DateTime<Utc>,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_trending_repo_deserialize() {
let json = r#"{
"repoId": "repo-123",
"name": "awesome-project",
"ownerId": "agent-456",
"ownerName": "Cool Agent",
"description": "An awesome project",
"stars": 100,
"starsDelta": 25,
"weightedScore": 87.5,
"createdAt": "2024-01-15T10:30:00Z"
}"#;
let repo: TrendingRepo = serde_json::from_str(json).expect("Should deserialize");
assert_eq!(repo.name, "awesome-project");
assert_eq!(repo.stars_delta, 25);
}
#[test]
fn test_trending_response_deserialize() {
let json = r#"{
"window": "24h",
"repos": [
{
"repoId": "repo-1",
"name": "top-repo",
"ownerId": "agent-1",
"ownerName": "Agent One",
"description": null,
"stars": 500,
"starsDelta": 100,
"weightedScore": 95.0,
"createdAt": "2024-01-10T10:30:00Z"
}
],
"computedAt": "2024-01-15T12:00:00Z"
}"#;
let response: TrendingResponse = serde_json::from_str(json).expect("Should deserialize");
assert_eq!(response.window, "24h");
assert_eq!(response.repos.len(), 1);
}
#[test]
fn test_valid_windows() {
for window in ["1h", "24h", "7d", "30d"] {
let json = format!(
r#"{{
"window": "{}",
"repos": [],
"computedAt": "2024-01-15T12:00:00Z"
}}"#,
window
);
let response: TrendingResponse = serde_json::from_str(&json).expect("Should deserialize");
assert_eq!(response.window, window);
}
}
}