use serde::Deserialize;
#[derive(Debug, Deserialize)]
pub struct CreditsData {
pub total_credits: f64,
pub total_usage: f64,
}
impl CreditsData {
#[must_use]
pub fn is_limited(&self) -> bool {
self.total_usage >= self.total_credits
}
#[must_use]
pub fn utilization(&self) -> f64 {
if self.total_credits > 0.0 {
self.total_usage / self.total_credits * 100.0
} else {
100.0
}
}
}
#[derive(Debug, Deserialize)]
pub struct CreditsResponse {
pub data: CreditsData,
}
#[cfg(test)]
mod tests {
use super::*;
type TestResult = Result<(), Box<dyn std::error::Error>>;
#[test]
fn test_deserialize_credits_response_with_positive_balance() -> TestResult {
let json = r#"{"data": {"total_credits": 10.0, "total_usage": 5.0}}"#;
let response: CreditsResponse = serde_json::from_str(json)?;
assert!((response.data.total_credits - 10.0).abs() < f64::EPSILON);
assert!((response.data.total_usage - 5.0).abs() < f64::EPSILON);
Ok(())
}
#[test]
fn test_is_not_limited_when_usage_is_less_than_credits() -> TestResult {
let json = r#"{"data": {"total_credits": 10.0, "total_usage": 3.0}}"#;
let response: CreditsResponse = serde_json::from_str(json)?;
assert!(!response.data.is_limited());
Ok(())
}
#[test]
fn test_is_limited_when_usage_equals_credits() -> TestResult {
let json = r#"{"data": {"total_credits": 5.0, "total_usage": 5.0}}"#;
let response: CreditsResponse = serde_json::from_str(json)?;
assert!(response.data.is_limited());
Ok(())
}
#[test]
fn test_is_limited_when_usage_exceeds_credits() -> TestResult {
let json = r#"{"data": {"total_credits": 5.0, "total_usage": 7.5}}"#;
let response: CreditsResponse = serde_json::from_str(json)?;
assert!(response.data.is_limited());
Ok(())
}
#[test]
fn test_is_limited_when_zero_credits() -> TestResult {
let json = r#"{"data": {"total_credits": 0.0, "total_usage": 0.0}}"#;
let response: CreditsResponse = serde_json::from_str(json)?;
assert!(response.data.is_limited());
Ok(())
}
#[test]
fn test_deserialize_credits_response_integer_values_as_floats() -> TestResult {
let json = r#"{"data": {"total_credits": 10, "total_usage": 0}}"#;
let response: CreditsResponse = serde_json::from_str(json)?;
assert!((response.data.total_credits - 10.0).abs() < f64::EPSILON);
assert!((response.data.total_usage - 0.0).abs() < f64::EPSILON);
Ok(())
}
}