seher/openrouter/
types.rs1use serde::Deserialize;
2
3#[derive(Debug, Deserialize)]
4pub struct CreditsData {
5 pub total_credits: f64,
6 pub total_usage: f64,
7}
8
9impl CreditsData {
10 #[must_use]
11 pub fn is_limited(&self) -> bool {
12 self.total_usage >= self.total_credits
13 }
14
15 #[must_use]
16 pub fn utilization(&self) -> f64 {
17 if self.total_credits > 0.0 {
18 self.total_usage / self.total_credits * 100.0
19 } else {
20 100.0
21 }
22 }
23}
24
25#[derive(Debug, Deserialize)]
26pub struct CreditsResponse {
27 pub data: CreditsData,
28}
29
30#[cfg(test)]
31mod tests {
32 use super::*;
33
34 type TestResult = Result<(), Box<dyn std::error::Error>>;
35
36 #[test]
37 fn test_deserialize_credits_response_with_positive_balance() -> TestResult {
38 let json = r#"{"data": {"total_credits": 10.0, "total_usage": 5.0}}"#;
40
41 let response: CreditsResponse = serde_json::from_str(json)?;
43
44 assert!((response.data.total_credits - 10.0).abs() < f64::EPSILON);
46 assert!((response.data.total_usage - 5.0).abs() < f64::EPSILON);
47 Ok(())
48 }
49
50 #[test]
51 fn test_is_not_limited_when_usage_is_less_than_credits() -> TestResult {
52 let json = r#"{"data": {"total_credits": 10.0, "total_usage": 3.0}}"#;
54
55 let response: CreditsResponse = serde_json::from_str(json)?;
57
58 assert!(!response.data.is_limited());
60 Ok(())
61 }
62
63 #[test]
64 fn test_is_limited_when_usage_equals_credits() -> TestResult {
65 let json = r#"{"data": {"total_credits": 5.0, "total_usage": 5.0}}"#;
67
68 let response: CreditsResponse = serde_json::from_str(json)?;
70
71 assert!(response.data.is_limited());
73 Ok(())
74 }
75
76 #[test]
77 fn test_is_limited_when_usage_exceeds_credits() -> TestResult {
78 let json = r#"{"data": {"total_credits": 5.0, "total_usage": 7.5}}"#;
80
81 let response: CreditsResponse = serde_json::from_str(json)?;
83
84 assert!(response.data.is_limited());
86 Ok(())
87 }
88
89 #[test]
90 fn test_is_limited_when_zero_credits() -> TestResult {
91 let json = r#"{"data": {"total_credits": 0.0, "total_usage": 0.0}}"#;
93
94 let response: CreditsResponse = serde_json::from_str(json)?;
96
97 assert!(response.data.is_limited());
99 Ok(())
100 }
101
102 #[test]
103 fn test_deserialize_credits_response_integer_values_as_floats() -> TestResult {
104 let json = r#"{"data": {"total_credits": 10, "total_usage": 0}}"#;
106
107 let response: CreditsResponse = serde_json::from_str(json)?;
109
110 assert!((response.data.total_credits - 10.0).abs() < f64::EPSILON);
112 assert!((response.data.total_usage - 0.0).abs() < f64::EPSILON);
113 Ok(())
114 }
115}