1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
//! Cache Efficiency Card Tests
//!
//! Tests for CacheStats struct, percentage calculation, and edge cases.
use crate::usage::data::CacheStats;
// ─────────────────────────────────────────────────────────────────────────────
// CacheStats struct tests
// ─────────────────────────────────────────────────────────────────────────────
#[test]
fn cache_stats_default_is_zero() {
let stats = CacheStats::default();
assert_eq!(stats.cache_hit_pct, 0.0);
assert_eq!(stats.cached_tokens, 0);
assert_eq!(stats.total_input_tokens, 0);
}
// ─────────────────────────────────────────────────────────────────────────────
// Cache hit percentage calculation
// ─────────────────────────────────────────────────────────────────────────────
#[test]
fn cache_hit_pct_simple_case() {
// 800 cached out of 1000 total = 80%
let cached = 800i64;
let total = 1000i64;
let pct = (cached as f64 / total as f64) * 100.0;
assert!((pct - 80.0).abs() < 0.01);
}
#[test]
fn cache_hit_pct_zero_cached() {
let cached = 0i64;
let total = 1000i64;
let pct = (cached as f64 / total as f64) * 100.0;
assert!((pct - 0.0).abs() < 0.01);
}
#[test]
fn cache_hit_pct_all_cached() {
let cached = 1000i64;
let total = 1000i64;
let pct = (cached as f64 / total as f64) * 100.0;
assert!((pct - 100.0).abs() < 0.01);
}
#[test]
fn cache_hit_pct_partial_cache() {
// Simulating real Anthropic numbers:
// input_tokens=1000, cache_creation=80000, cache_read=15000
// total_input = 1000 + 80000 + 15000 = 96000
// cached = 15000
// pct = 15000/96000 = 15.625%
let cached = 15000i64;
let total = 96000i64;
let pct = (cached as f64 / total as f64) * 100.0;
assert!((pct - 15.625).abs() < 0.01);
}
// ─────────────────────────────────────────────────────────────────────────────
// CacheStats construction with realistic data
// ─────────────────────────────────────────────────────────────────────────────
#[test]
fn cache_stats_construction() {
let stats = CacheStats {
cache_hit_pct: 67.5,
cached_tokens: 1_200_000,
total_input_tokens: 1_800_000,
};
assert!((stats.cache_hit_pct - 67.5).abs() < 0.01);
assert_eq!(stats.cached_tokens, 1_200_000);
assert_eq!(stats.total_input_tokens, 1_800_000);
}
#[test]
fn cache_stats_no_cache_data() {
// When there's no cache data, DashboardData.cache should be None
// This simulates a fresh install with no messages yet
let stats: Option<CacheStats> = None;
assert!(stats.is_none());
}
// ─────────────────────────────────────────────────────────────────────────────
// Color thresholds (matching render_cache_efficiency logic)
// ─────────────────────────────────────────────────────────────────────────────
#[test]
fn cache_pct_green_threshold() {
// >= 60% should be green
let pct = 67.0;
assert!(pct >= 60.0);
}
#[test]
fn cache_pct_yellow_threshold() {
// 30-60% should be yellow
let pct = 45.0;
assert!((30.0..60.0).contains(&pct));
}
#[test]
fn cache_pct_red_threshold() {
// < 30% should be red
let pct = 15.0;
assert!(pct < 30.0);
}
#[test]
fn cache_pct_boundary_60() {
// Exactly 60% should be green (>= 60)
let pct = 60.0;
assert!(pct >= 60.0);
}
#[test]
fn cache_pct_boundary_30() {
// Exactly 30% should be yellow (>= 30 and < 60)
let pct = 30.0;
assert!((30.0..60.0).contains(&pct));
}
// ─────────────────────────────────────────────────────────────────────────────
// DashboardData cache field
// ─────────────────────────────────────────────────────────────────────────────
#[test]
fn dashboard_data_cache_field_defaults_to_none() {
use crate::usage::data::DashboardData;
let d = DashboardData::default();
assert!(d.cache.is_none());
}