@@ -15,9 +15,10 @@ final class StatusBarTextTests: XCTestCase {
15 balance: 42, isLoading: false,
15 balance: 42, isLoading: false,
16 hyperConfigured: true,
16 hyperConfigured: true,
17 claudeFiveHourPercent: 62, claudeSevenDayPercent: 8,
17 claudeFiveHourPercent: 62, claudeSevenDayPercent: 8,
18− zaiFiveHourPercent: nil, zaiWeeklyPercent: nil
18+ zaiFiveHourPercent: nil, zaiWeeklyPercent: nil,
19+ zaiInPeakHours: false
20− XCTAssertEqual(title, "⚡42 · 🕐62% · 📅8%")
21+ XCTAssertEqual(title, "⚡42 · \u{2055}62% 8%")
23 func testHyperOnly() {
24 func testHyperOnly() {
@@ -25,7 +26,8 @@ final class StatusBarTextTests: XCTestCase {
25 balance: 42, isLoading: false,
26 balance: 42, isLoading: false,
26 hyperConfigured: true,
27 hyperConfigured: true,
27 claudeFiveHourPercent: nil, claudeSevenDayPercent: nil,
28 claudeFiveHourPercent: nil, claudeSevenDayPercent: nil,
28− zaiFiveHourPercent: nil, zaiWeeklyPercent: nil
29+ zaiFiveHourPercent: nil, zaiWeeklyPercent: nil,
30+ zaiInPeakHours: false
30 XCTAssertEqual(title, "⚡42")
32 XCTAssertEqual(title, "⚡42")
@@ -35,9 +37,10 @@ final class StatusBarTextTests: XCTestCase {
35 balance: nil, isLoading: false,
37 balance: nil, isLoading: false,
36 hyperConfigured: false,
38 hyperConfigured: false,
37 claudeFiveHourPercent: 62, claudeSevenDayPercent: 8,
39 claudeFiveHourPercent: 62, claudeSevenDayPercent: 8,
38− zaiFiveHourPercent: nil, zaiWeeklyPercent: nil
40+ zaiFiveHourPercent: nil, zaiWeeklyPercent: nil,
41+ zaiInPeakHours: false
40− XCTAssertEqual(title, "🕐62% · 📅8%")
43+ XCTAssertEqual(title, "\u{2055}62% 8%")
43 func testLoadingWithNothingToShow() {
46 func testLoadingWithNothingToShow() {
@@ -45,7 +48,8 @@ final class StatusBarTextTests: XCTestCase {
45 balance: nil, isLoading: true,
48 balance: nil, isLoading: true,
46 hyperConfigured: false,
49 hyperConfigured: false,
47 claudeFiveHourPercent: nil, claudeSevenDayPercent: nil,
50 claudeFiveHourPercent: nil, claudeSevenDayPercent: nil,
48− zaiFiveHourPercent: nil, zaiWeeklyPercent: nil
51+ zaiFiveHourPercent: nil, zaiWeeklyPercent: nil,
52+ zaiInPeakHours: false
50 XCTAssertEqual(title, "…")
54 XCTAssertEqual(title, "…")
@@ -55,7 +59,8 @@ final class StatusBarTextTests: XCTestCase {
55 balance: nil, isLoading: false,
59 balance: nil, isLoading: false,
56 hyperConfigured: false,
60 hyperConfigured: false,
57 claudeFiveHourPercent: nil, claudeSevenDayPercent: nil,
61 claudeFiveHourPercent: nil, claudeSevenDayPercent: nil,
58− zaiFiveHourPercent: nil, zaiWeeklyPercent: nil
62+ zaiFiveHourPercent: nil, zaiWeeklyPercent: nil,
63+ zaiInPeakHours: false
60 XCTAssertEqual(title, "")
65 XCTAssertEqual(title, "")
@@ -68,9 +73,10 @@ final class StatusBarTextTests: XCTestCase {
68 balance: nil, isLoading: true,
73 balance: nil, isLoading: true,
69 hyperConfigured: false,
74 hyperConfigured: false,
70 claudeFiveHourPercent: 62, claudeSevenDayPercent: nil,
75 claudeFiveHourPercent: 62, claudeSevenDayPercent: nil,
71− zaiFiveHourPercent: nil, zaiWeeklyPercent: nil
76+ zaiFiveHourPercent: nil, zaiWeeklyPercent: nil,
77+ zaiInPeakHours: false
73− XCTAssertEqual(title, "🕐62%")
79+ XCTAssertEqual(title, "\u{2055}62%")
76 func testLoadingKeepsAStaleBalanceOnScreen() {
82 func testLoadingKeepsAStaleBalanceOnScreen() {
@@ -78,19 +84,21 @@ final class StatusBarTextTests: XCTestCase {
78 balance: 42, isLoading: true,
84 balance: 42, isLoading: true,
79 hyperConfigured: true,
85 hyperConfigured: true,
80 claudeFiveHourPercent: 62, claudeSevenDayPercent: 8,
86 claudeFiveHourPercent: 62, claudeSevenDayPercent: 8,
81− zaiFiveHourPercent: nil, zaiWeeklyPercent: nil
87+ zaiFiveHourPercent: nil, zaiWeeklyPercent: nil,
88+ zaiInPeakHours: false
83− XCTAssertEqual(title, "⚡42 · 🕐62% · 📅8%")
90+ XCTAssertEqual(title, "⚡42 · \u{2055}62% 8%")
86− func testZeroPercentIsShownRatherThanOmitted() {
93+ func testZeroPercentIsShown() {
87 let title = ViewModel.statusBarText(
94 let title = ViewModel.statusBarText(
88 balance: 42, isLoading: false,
95 balance: 42, isLoading: false,
89 hyperConfigured: true,
96 hyperConfigured: true,
90 claudeFiveHourPercent: 0, claudeSevenDayPercent: 8,
97 claudeFiveHourPercent: 0, claudeSevenDayPercent: 8,
91− zaiFiveHourPercent: nil, zaiWeeklyPercent: nil
98+ zaiFiveHourPercent: nil, zaiWeeklyPercent: nil,
99+ zaiInPeakHours: false
93− XCTAssertEqual(title, "⚡42 · 📅8%")
101+ XCTAssertEqual(title, "⚡42 · \u{2055}0% 8%")
96 func testBothClaudeWindowsZero() {
104 func testBothClaudeWindowsZero() {
@@ -98,9 +106,10 @@ final class StatusBarTextTests: XCTestCase {
98 balance: 42, isLoading: false,
106 balance: 42, isLoading: false,
99 hyperConfigured: true,
107 hyperConfigured: true,
100 claudeFiveHourPercent: 0, claudeSevenDayPercent: 0,
108 claudeFiveHourPercent: 0, claudeSevenDayPercent: 0,
101− zaiFiveHourPercent: nil, zaiWeeklyPercent: nil
109+ zaiFiveHourPercent: nil, zaiWeeklyPercent: nil,
110+ zaiInPeakHours: false
103− XCTAssertEqual(title, "⚡42")
112+ XCTAssertEqual(title, "⚡42 · \u{2055}0% 0%")
106 func testFiveHourOnly() {
115 func testFiveHourOnly() {
@@ -108,9 +117,10 @@ final class StatusBarTextTests: XCTestCase {
108 balance: nil, isLoading: false,
117 balance: nil, isLoading: false,
109 hyperConfigured: false,
118 hyperConfigured: false,
110 claudeFiveHourPercent: 62, claudeSevenDayPercent: nil,
119 claudeFiveHourPercent: 62, claudeSevenDayPercent: nil,
111− zaiFiveHourPercent: nil, zaiWeeklyPercent: nil
120+ zaiFiveHourPercent: nil, zaiWeeklyPercent: nil,
121+ zaiInPeakHours: false
113− XCTAssertEqual(title, "🕐62%")
123+ XCTAssertEqual(title, "\u{2055}62%")
116 func testSevenDayOnly() {
126 func testSevenDayOnly() {
@@ -118,9 +128,10 @@ final class StatusBarTextTests: XCTestCase {
118 balance: nil, isLoading: false,
128 balance: nil, isLoading: false,
119 hyperConfigured: false,
129 hyperConfigured: false,
120 claudeFiveHourPercent: nil, claudeSevenDayPercent: 8,
130 claudeFiveHourPercent: nil, claudeSevenDayPercent: 8,
121− zaiFiveHourPercent: nil, zaiWeeklyPercent: nil
131+ zaiFiveHourPercent: nil, zaiWeeklyPercent: nil,
132+ zaiInPeakHours: false
123− XCTAssertEqual(title, "📅8%")
134+ XCTAssertEqual(title, "\u{2055}8%")
126 // MARK: - Hyper not configured
137 // MARK: - Hyper not configured
@@ -132,7 +143,8 @@ final class StatusBarTextTests: XCTestCase {
132 balance: 42, isLoading: false,
143 balance: 42, isLoading: false,
133 hyperConfigured: false,
144 hyperConfigured: false,
134 claudeFiveHourPercent: nil, claudeSevenDayPercent: nil,
145 claudeFiveHourPercent: nil, claudeSevenDayPercent: nil,
135− zaiFiveHourPercent: nil, zaiWeeklyPercent: nil
146+ zaiFiveHourPercent: nil, zaiWeeklyPercent: nil,
147+ zaiInPeakHours: false
137 XCTAssertEqual(title, "")
149 XCTAssertEqual(title, "")
@@ -142,7 +154,8 @@ final class StatusBarTextTests: XCTestCase {
142 balance: nil, isLoading: true,
154 balance: nil, isLoading: true,
143 hyperConfigured: false,
155 hyperConfigured: false,
144 claudeFiveHourPercent: nil, claudeSevenDayPercent: nil,
156 claudeFiveHourPercent: nil, claudeSevenDayPercent: nil,
145− zaiFiveHourPercent: nil, zaiWeeklyPercent: nil
157+ zaiFiveHourPercent: nil, zaiWeeklyPercent: nil,
158+ zaiInPeakHours: false
147 XCTAssertEqual(title, "…")
160 XCTAssertEqual(title, "…")
@@ -152,9 +165,10 @@ final class StatusBarTextTests: XCTestCase {
152 balance: nil, isLoading: false,
165 balance: nil, isLoading: false,
153 hyperConfigured: false,
166 hyperConfigured: false,
154 claudeFiveHourPercent: 62, claudeSevenDayPercent: 8,
167 claudeFiveHourPercent: 62, claudeSevenDayPercent: 8,
155− zaiFiveHourPercent: nil, zaiWeeklyPercent: nil
168+ zaiFiveHourPercent: nil, zaiWeeklyPercent: nil,
169+ zaiInPeakHours: false
157− XCTAssertEqual(title, "🕐62% · 📅8%")
171+ XCTAssertEqual(title, "\u{2055}62% 8%")
160 // MARK: - z.ai in Title
174 // MARK: - z.ai in Title
@@ -164,9 +178,10 @@ final class StatusBarTextTests: XCTestCase {
164 balance: nil, isLoading: false,
178 balance: nil, isLoading: false,
165 hyperConfigured: false,
179 hyperConfigured: false,
166 claudeFiveHourPercent: nil, claudeSevenDayPercent: nil,
180 claudeFiveHourPercent: nil, claudeSevenDayPercent: nil,
167− zaiFiveHourPercent: 12, zaiWeeklyPercent: nil
181+ zaiFiveHourPercent: 12, zaiWeeklyPercent: nil,
182+ zaiInPeakHours: false
169− XCTAssertEqual(title, "🤖12%")
184+ XCTAssertEqual(title, "\u{005A}12%")
172 func testZaiWithHyper() {
187 func testZaiWithHyper() {
@@ -174,9 +189,10 @@ final class StatusBarTextTests: XCTestCase {
174 balance: 42, isLoading: false,
189 balance: 42, isLoading: false,
175 hyperConfigured: true,
190 hyperConfigured: true,
176 claudeFiveHourPercent: nil, claudeSevenDayPercent: nil,
191 claudeFiveHourPercent: nil, claudeSevenDayPercent: nil,
177− zaiFiveHourPercent: 12, zaiWeeklyPercent: nil
192+ zaiFiveHourPercent: 12, zaiWeeklyPercent: nil,
193+ zaiInPeakHours: false
179− XCTAssertEqual(title, "⚡42 · 🤖12%")
195+ XCTAssertEqual(title, "⚡42 · \u{005A}12%")
182 func testZaiWithClaude() {
198 func testZaiWithClaude() {
@@ -184,9 +200,10 @@ final class StatusBarTextTests: XCTestCase {
184 balance: nil, isLoading: false,
200 balance: nil, isLoading: false,
185 hyperConfigured: false,
201 hyperConfigured: false,
186 claudeFiveHourPercent: 62, claudeSevenDayPercent: 8,
202 claudeFiveHourPercent: 62, claudeSevenDayPercent: 8,
187− zaiFiveHourPercent: 12, zaiWeeklyPercent: nil
203+ zaiFiveHourPercent: 12, zaiWeeklyPercent: nil,
204+ zaiInPeakHours: false
189− XCTAssertEqual(title, "🕐62% · 📅8% · 🤖12%")
206+ XCTAssertEqual(title, "\u{2055}62% 8% · \u{005A}12%")
192 func testAllThreeServices() {
209 func testAllThreeServices() {
@@ -194,19 +211,21 @@ final class StatusBarTextTests: XCTestCase {
194 balance: 42, isLoading: false,
211 balance: 42, isLoading: false,
195 hyperConfigured: true,
212 hyperConfigured: true,
196 claudeFiveHourPercent: 62, claudeSevenDayPercent: 8,
213 claudeFiveHourPercent: 62, claudeSevenDayPercent: 8,
197− zaiFiveHourPercent: 12, zaiWeeklyPercent: 3
214+ zaiFiveHourPercent: 12, zaiWeeklyPercent: 3,
215+ zaiInPeakHours: false
199− XCTAssertEqual(title, "⚡42 · 🕐62% · 📅8% · 🤖12% · 📆3%")
217+ XCTAssertEqual(title, "⚡42 · \u{2055}62% 8% · \u{005A}12% 3%")
202− func testZaiZeroIsOmitted() {
220+ func testZaiZeroIsShown() {
203 let title = ViewModel.statusBarText(
221 let title = ViewModel.statusBarText(
204 balance: 42, isLoading: false,
222 balance: 42, isLoading: false,
205 hyperConfigured: true,
223 hyperConfigured: true,
206 claudeFiveHourPercent: nil, claudeSevenDayPercent: nil,
224 claudeFiveHourPercent: nil, claudeSevenDayPercent: nil,
207− zaiFiveHourPercent: 0, zaiWeeklyPercent: 0
225+ zaiFiveHourPercent: 0, zaiWeeklyPercent: 0,
226+ zaiInPeakHours: false
209− XCTAssertEqual(title, "⚡42")
228+ XCTAssertEqual(title, "⚡42 · \u{005A}0% 0%")
212 func testLoadingKeepsZaiPercentOnScreen() {
231 func testLoadingKeepsZaiPercentOnScreen() {
@@ -214,9 +233,10 @@ final class StatusBarTextTests: XCTestCase {
214 balance: nil, isLoading: true,
233 balance: nil, isLoading: true,
215 hyperConfigured: false,
234 hyperConfigured: false,
216 claudeFiveHourPercent: nil, claudeSevenDayPercent: nil,
235 claudeFiveHourPercent: nil, claudeSevenDayPercent: nil,
217− zaiFiveHourPercent: 12, zaiWeeklyPercent: nil
236+ zaiFiveHourPercent: 12, zaiWeeklyPercent: nil,
237+ zaiInPeakHours: false
219− XCTAssertEqual(title, "🤖12%")
239+ XCTAssertEqual(title, "\u{005A}12%")
222 // MARK: - z.ai Weekly
242 // MARK: - z.ai Weekly
@@ -226,9 +246,10 @@ final class StatusBarTextTests: XCTestCase {
226 balance: nil, isLoading: false,
246 balance: nil, isLoading: false,
227 hyperConfigured: false,
247 hyperConfigured: false,
228 claudeFiveHourPercent: nil, claudeSevenDayPercent: nil,
248 claudeFiveHourPercent: nil, claudeSevenDayPercent: nil,
229− zaiFiveHourPercent: nil, zaiWeeklyPercent: 3
249+ zaiFiveHourPercent: nil, zaiWeeklyPercent: 3,
250+ zaiInPeakHours: false
231− XCTAssertEqual(title, "📆3%")
252+ XCTAssertEqual(title, "\u{005A}3%")
234 func testZaiWeeklyWithFiveHour() {
255 func testZaiWeeklyWithFiveHour() {
@@ -236,19 +257,21 @@ final class StatusBarTextTests: XCTestCase {
236 balance: nil, isLoading: false,
257 balance: nil, isLoading: false,
237 hyperConfigured: false,
258 hyperConfigured: false,
238 claudeFiveHourPercent: nil, claudeSevenDayPercent: nil,
259 claudeFiveHourPercent: nil, claudeSevenDayPercent: nil,
239− zaiFiveHourPercent: 12, zaiWeeklyPercent: 3
260+ zaiFiveHourPercent: 12, zaiWeeklyPercent: 3,
261+ zaiInPeakHours: false
241− XCTAssertEqual(title, "🤖12% · 📆3%")
263+ XCTAssertEqual(title, "\u{005A}12% 3%")
244− func testZaiWeeklyZeroIsOmitted() {
266+ func testZaiWeeklyZeroIsShown() {
245 let title = ViewModel.statusBarText(
267 let title = ViewModel.statusBarText(
246 balance: nil, isLoading: false,
268 balance: nil, isLoading: false,
247 hyperConfigured: false,
269 hyperConfigured: false,
248 claudeFiveHourPercent: nil, claudeSevenDayPercent: nil,
270 claudeFiveHourPercent: nil, claudeSevenDayPercent: nil,
249− zaiFiveHourPercent: 12, zaiWeeklyPercent: 0
271+ zaiFiveHourPercent: 12, zaiWeeklyPercent: 0,
272+ zaiInPeakHours: false
251− XCTAssertEqual(title, "🤖12%")
274+ XCTAssertEqual(title, "\u{005A}12% 0%")
254 func testLoadingKeepsZaiWeeklyOnScreen() {
277 func testLoadingKeepsZaiWeeklyOnScreen() {
@@ -256,9 +279,46 @@ final class StatusBarTextTests: XCTestCase {
256 balance: nil, isLoading: true,
279 balance: nil, isLoading: true,
257 hyperConfigured: false,
280 hyperConfigured: false,
258 claudeFiveHourPercent: nil, claudeSevenDayPercent: nil,
281 claudeFiveHourPercent: nil, claudeSevenDayPercent: nil,
259− zaiFiveHourPercent: nil, zaiWeeklyPercent: 3
282+ zaiFiveHourPercent: nil, zaiWeeklyPercent: 3,
283+ zaiInPeakHours: false
285+ XCTAssertEqual(title, "\u{005A}3%")
288+ // MARK: - z.ai Peak Hours
290+ func testPeakHoursAddsDiamondToZaiSegment() {
291+ let title = ViewModel.statusBarText(
292+ balance: 42, isLoading: false,
293+ hyperConfigured: true,
294+ claudeFiveHourPercent: 62, claudeSevenDayPercent: 8,
295+ zaiFiveHourPercent: 12, zaiWeeklyPercent: 3,
296+ zaiInPeakHours: true
298+ XCTAssertEqual(title, "⚡42 · \u{2055}62% 8% · \u{005A}12% 3%\u{1F536}")
301+ func testPeakHoursWithZaiOnly() {
302+ let title = ViewModel.statusBarText(
303+ balance: nil, isLoading: false,
304+ hyperConfigured: false,
305+ claudeFiveHourPercent: nil, claudeSevenDayPercent: nil,
306+ zaiFiveHourPercent: 12, zaiWeeklyPercent: nil,
307+ zaiInPeakHours: true
309+ XCTAssertEqual(title, "\u{005A}12%\u{1F536}")
312+ func testPeakHoursIgnoredWhenZaiNotConfigured() {
313+ let title = ViewModel.statusBarText(
314+ balance: 42, isLoading: false,
315+ hyperConfigured: true,
316+ claudeFiveHourPercent: 62, claudeSevenDayPercent: 8,
317+ zaiFiveHourPercent: nil, zaiWeeklyPercent: nil,
318+ zaiInPeakHours: true
320+ // No z.ai segment, so peak marker has nothing to attach to.
261− XCTAssertEqual(title, "📆3%")
321+ XCTAssertEqual(title, "⚡42 · \u{2055}62% 8%")
264 // MARK: - Claude Window Percentages
324 // MARK: - Claude Window Percentages