1use std::time::Duration;
4
5#[derive(Debug, Clone)]
11pub struct SpinnerFrames {
12 pub frames: &'static [&'static str],
13 pub interval: f64, }
15
16pub const SPINNER_DOTS: SpinnerFrames = SpinnerFrames {
21 frames: &["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"],
22 interval: 0.08,
23};
24
25pub const SPINNER_LINE: SpinnerFrames = SpinnerFrames {
26 frames: &["-", "\\", "|", "/"],
27 interval: 0.1,
28};
29
30pub const SPINNER_DOTS2: SpinnerFrames = SpinnerFrames {
31 frames: &["⣾", "⣽", "⣻", "⢿", "⡿", "⣟", "⣯", "⣷"],
32 interval: 0.08,
33};
34
35pub const SPINNER_DOTS3: SpinnerFrames = SpinnerFrames {
36 frames: &["⠋", "⠙", "⠚", "⠞", "⠖", "⠦", "⠴", "⠲", "⠳", "⠓"],
37 interval: 0.08,
38};
39
40pub const SPINNER_DOTS4: SpinnerFrames = SpinnerFrames {
41 frames: &["⠄", "⠆", "⠇", "⠋", "⠙", "⠸", "⠰", "⠠", "⠰", "⠸", "⠙", "⠋", "⠇", "⠆"],
42 interval: 0.08,
43};
44
45pub const SPINNER_DOTS5: SpinnerFrames = SpinnerFrames {
46 frames: &["⠋", "⠙", "⠚", "⠒", "⠂", "⠂", "⠒", "⠲", "⠴", "⠦", "⠖", "⠒", "⠐", "⠐", "⠒", "⠓", "⠋"],
47 interval: 0.08,
48};
49
50pub const SPINNER_DOTS6: SpinnerFrames = SpinnerFrames {
51 frames: &[
52 "⠁", "⠉", "⠙", "⠚", "⠒", "⠂", "⠂", "⠒", "⠲", "⠴", "⠤", "⠄", "⠄", "⠤", "⠴", "⠲", "⠒",
53 "⠂", "⠂", "⠒", "⠚", "⠙", "⠉", "⠁",
54 ],
55 interval: 0.08,
56};
57
58pub const SPINNER_DOTS7: SpinnerFrames = SpinnerFrames {
59 frames: &[
60 "⠈", "⠉", "⠋", "⠓", "⠒", "⠐", "⠐", "⠒", "⠖", "⠦", "⠤", "⠠", "⠠", "⠤", "⠦", "⠖", "⠒",
61 "⠐", "⠐", "⠒", "⠓", "⠋", "⠉", "⠈",
62 ],
63 interval: 0.08,
64};
65
66pub const SPINNER_DOTS8: SpinnerFrames = SpinnerFrames {
67 frames: &[
68 "⠁", "⠁", "⠉", "⠙", "⠚", "⠒", "⠂", "⠂", "⠒", "⠲", "⠴", "⠤", "⠄", "⠄", "⠤", "⠠", "⠠",
69 "⠤", "⠦", "⠖", "⠒", "⠐", "⠐", "⠒", "⠓", "⠋", "⠉", "⠈", "⠈",
70 ],
71 interval: 0.08,
72};
73
74pub const SPINNER_DOTS9: SpinnerFrames = SpinnerFrames {
75 frames: &["⢹", "⢺", "⢼", "⣸", "⣇", "⡧", "⡗", "⡏"],
76 interval: 0.08,
77};
78
79pub const SPINNER_DOTS10: SpinnerFrames = SpinnerFrames {
80 frames: &["⢄", "⢂", "⢁", "⡁", "⡈", "⡐", "⡠"],
81 interval: 0.08,
82};
83
84pub const SPINNER_DOTS11: SpinnerFrames = SpinnerFrames {
85 frames: &["⠁", "⠂", "⠄", "⡀", "⢀", "⠠", "⠐", "⠈"],
86 interval: 0.1,
87};
88
89pub const SPINNER_SIMPLE_DOTS: SpinnerFrames = SpinnerFrames {
90 frames: &[". ", ".. ", "...", " ..", " .", " "],
91 interval: 0.2,
92};
93
94pub const SPINNER_MOON: SpinnerFrames = SpinnerFrames {
99 frames: &["🌑", "🌒", "🌓", "🌔", "🌕", "🌖", "🌗", "🌘"],
100 interval: 0.08,
101};
102
103pub const SPINNER_SMILEY: SpinnerFrames = SpinnerFrames {
104 frames: &["😄", "😝"],
105 interval: 0.2,
106};
107
108pub const SPINNER_ARC: SpinnerFrames = SpinnerFrames {
113 frames: &["◜", "◠", "◝", "◞", "◡", "◟"],
114 interval: 0.1,
115};
116
117pub const SPINNER_ARROW: SpinnerFrames = SpinnerFrames {
118 frames: &["←", "↖", "↑", "↗", "→", "↘", "↓", "↙"],
119 interval: 0.1,
120};
121
122pub const SPINNER_ARROW2: SpinnerFrames = SpinnerFrames {
123 frames: &["⬆️", "↗️", "➡️", "↘️", "⬇️", "↙️", "⬅️", "↖️"],
124 interval: 0.1,
125};
126
127pub const SPINNER_ARROW3: SpinnerFrames = SpinnerFrames {
128 frames: &["▹", "▸", "▹", "▸", "▹", "▸"],
129 interval: 0.1,
130};
131
132pub const SPINNER_BOUNCING_BAR: SpinnerFrames = SpinnerFrames {
133 frames: &["[ ]", "[= ]", "[== ]", "[=== ]", "[ ===]", "[ ==]", "[ =]", "[ ]"],
134 interval: 0.15,
135};
136
137pub const SPINNER_BOUNCING_BALL: SpinnerFrames = SpinnerFrames {
138 frames: &[
139 "( ● )", "( ● )", "( ● )", "( ● )", "( ●)", "( ● )", "( ● )",
140 "( ● )",
141 ],
142 interval: 0.15,
143};
144
145pub const SPINNER_CHRISTMAS: SpinnerFrames = SpinnerFrames {
146 frames: &["🌲", "🎄"],
147 interval: 0.4,
148};
149
150pub const SPINNER_CIRCLE: SpinnerFrames = SpinnerFrames {
151 frames: &["◐", "◓", "◑", "◒"],
152 interval: 0.1,
153};
154
155pub const SPINNER_CLOCK: SpinnerFrames = SpinnerFrames {
156 frames: &[
157 "🕐", "🕑", "🕒", "🕓", "🕔", "🕕", "🕖", "🕗", "🕘", "🕙", "🕚", "🕛",
158 ],
159 interval: 0.1,
160};
161
162pub const SPINNER_EARTH: SpinnerFrames = SpinnerFrames {
163 frames: &["🌍", "🌎", "🌏"],
164 interval: 0.2,
165};
166
167pub const SPINNER_GRENADE: SpinnerFrames = SpinnerFrames {
168 frames: &["، 💣 ", "۔ 💣 ", " ﹒ 💣 "],
169 interval: 0.1,
170};
171
172pub const SPINNER_GROW_HORIZONTAL: SpinnerFrames = SpinnerFrames {
173 frames: &["▏", "▎", "▍", "▌", "▋", "▊", "▉", "▉", "▊", "▋", "▌", "▍", "▎", "▏"],
174 interval: 0.08,
175};
176
177pub const SPINNER_GROW_VERTICAL: SpinnerFrames = SpinnerFrames {
178 frames: &["▁", "▂", "▃", "▄", "▅", "▆", "▇", "█", "▇", "▆", "▅", "▄", "▃", "▁"],
179 interval: 0.08,
180};
181
182pub const SPINNER_HAMBURGER: SpinnerFrames = SpinnerFrames {
183 frames: &["☱", "☲", "☴"],
184 interval: 0.12,
185};
186
187pub const SPINNER_HEARTS: SpinnerFrames = SpinnerFrames {
188 frames: &["🩷", "❤️", "🧡", "💛", "💚", "💙", "🩵", "💜", "🤎", "🖤", "🩶", "🤍"],
189 interval: 0.12,
190};
191
192pub const SPINNER_MONKEY: SpinnerFrames = SpinnerFrames {
193 frames: &["🐒", "🐒", "🐒", "🐒", "🙈", "🙉", "🙊", "🐒", "🐒", "🐒", "🐒"],
194 interval: 0.15,
195};
196
197pub const SPINNER_NOISE: SpinnerFrames = SpinnerFrames {
198 frames: &["▓", "▒", "░", "▓", "▒", "░", "▓", "▒", "░"],
199 interval: 0.08,
200};
201
202pub const SPINNER_PONG: SpinnerFrames = SpinnerFrames {
203 frames: &[
204 "▐⠂ ▌", "▐⠈ ▌", "▐ ⠂ ▌", "▐ ⠠ ▌",
205 "▐ ⡀ ▌", "▐ ⠠ ▌", "▐ ⠂ ▌", "▐ ⠈ ▌",
206 "▐ ⠂ ▌", "▐ ⠠ ▌", "▐ ⡀ ▌", "▐ ⠠ ▌",
207 "▐ ⠂ ▌", "▐ ⠈ ▌", "▐ ⠂▌", "▐ ⠠▌",
208 "▐ ⡀▌", "▐ ⠠ ▌", "▐ ⠂ ▌", "▐ ⠈ ▌",
209 "▐ ⠂ ▌", "▐ ⠠ ▌", "▐ ⡀ ▌", "▐ ⠠ ▌",
210 "▐ ⠂ ▌", "▐ ⠈ ▌", "▐ ⠂ ▌", "▐ ⠠ ▌",
211 "▐ ⠂ ▌", "▐⠈ ▌",
212 ],
213 interval: 0.08,
214};
215
216pub const SPINNER_RUNNER: SpinnerFrames = SpinnerFrames {
217 frames: &["🚶", "🏃", "🏃", "🏃", "🚶", "🚶"],
218 interval: 0.15,
219};
220
221pub const SPINNER_SHARK: SpinnerFrames = SpinnerFrames {
222 frames: &["🦈", "🌀", "🦈", "🌀", "🦈", "🌀"],
223 interval: 0.15,
224};
225
226pub const SPINNER_TOGGLE: SpinnerFrames = SpinnerFrames {
227 frames: &["⊶", "⊷"],
228 interval: 0.2,
229};
230
231pub const SPINNER_TRIANGLE: SpinnerFrames = SpinnerFrames {
232 frames: &["◢", "◣", "◤", "◥"],
233 interval: 0.1,
234};
235
236pub const SPINNER_VERTICAL_BARS: SpinnerFrames = SpinnerFrames {
237 frames: &["▁", "▂", "▃", "▄", "▅", "▆", "▇", "█", "▇", "▆", "▅", "▄", "▃", "▂", "▁"],
238 interval: 0.08,
239};
240
241pub const SPINNER_DOTS12: SpinnerFrames = SpinnerFrames {
247 frames: &["⣀", "⣤", "⣶", "⣿", "⣶", "⣤"],
248 interval: 0.08,
249};
250
251pub const SPINNER_DOTS13: SpinnerFrames = SpinnerFrames {
253 frames: &["⣼", "⣹", "⢻", "⠿", "⡟", "⣏", "⣧", "⣶"],
254 interval: 0.08,
255};
256
257pub const SPINNER_DOTS8_BIT: SpinnerFrames = SpinnerFrames {
259 frames: &["⠀", "⠁", "⠂", "⠃", "⠇", "⠏", "⠟", "⠿", "⡿", "⣿", "⣿", "⣿"],
260 interval: 0.08,
261};
262
263pub const SPINNER_SIMPLE_DOTS_SCROLLING: SpinnerFrames = SpinnerFrames {
265 frames: &[". ", ".. ", "...", " ..", " .", " ..", "...", ".. "],
266 interval: 0.2,
267};
268
269pub const SPINNER_STAR: SpinnerFrames = SpinnerFrames {
271 frames: &["✶", "✸", "✹", "✺", "✹", "✷"],
272 interval: 0.1,
273};
274
275pub const SPINNER_STAR2: SpinnerFrames = SpinnerFrames {
277 frames: &["+", "x", "*"],
278 interval: 0.12,
279};
280
281pub const SPINNER_FLIP: SpinnerFrames = SpinnerFrames {
283 frames: &["_", "_", "_", "-", "`", "`", "'", "¯", "_", "_", "_", "-"],
284 interval: 0.1,
285};
286
287pub const SPINNER_BALLOON: SpinnerFrames = SpinnerFrames {
289 frames: &[". ", "o ", "O ", "@ ", "* ", " "],
290 interval: 0.12,
291};
292
293pub const SPINNER_BALLOON2: SpinnerFrames = SpinnerFrames {
295 frames: &[".", "o", "O", "°", "O", "o", "."],
296 interval: 0.12,
297};
298
299pub const SPINNER_PIPE: SpinnerFrames = SpinnerFrames {
301 frames: &["┤", "┘", "┴", "└", "├", "┌", "┬", "┐"],
302 interval: 0.1,
303};
304
305pub const SPINNER_SQUARE_CORNERS: SpinnerFrames = SpinnerFrames {
307 frames: &["◰", "◳", "◲", "◱"],
308 interval: 0.12,
309};
310
311pub const SPINNER_CIRCLE_QUARTERS: SpinnerFrames = SpinnerFrames {
313 frames: &["◴", "◷", "◶", "◵"],
314 interval: 0.12,
315};
316
317pub const SPINNER_CIRCLE_HALVES: SpinnerFrames = SpinnerFrames {
319 frames: &["◐", "◓", "◑", "◒"],
320 interval: 0.12,
321};
322
323pub const SPINNER_AESTHETIC: SpinnerFrames = SpinnerFrames {
325 frames: &["▰", "▱"],
326 interval: 0.15,
327};
328
329pub const SPINNER_BRAILLE_LONG: SpinnerFrames = SpinnerFrames {
331 frames: &["⠁", "⠂", "⠄", "⠠", "⠐", "⠈", "⡀", "⢀"],
332 interval: 0.08,
333};
334
335pub const SPINNER_BRAILLE_CRAWL: SpinnerFrames = SpinnerFrames {
337 frames: &["⡀", "⡄", "⡆", "⡇", "⡏", "⡟", "⡿", "⣿"],
338 interval: 0.08,
339};
340
341pub const SPINNER_PULSE: SpinnerFrames = SpinnerFrames {
343 frames: &["█", "▓", "▒", "░"],
344 interval: 0.1,
345};
346
347pub const SPINNER_BOUNCE: SpinnerFrames = SpinnerFrames {
349 frames: &["⠁", "⠂", "⠄", "⠂"],
350 interval: 0.12,
351};
352
353pub const SPINNER_MATERIAL: SpinnerFrames = SpinnerFrames {
355 frames: &["◐", "◓", "◑", "◒"],
356 interval: 0.08,
357};
358
359pub const SPINNER_WINDOWS: SpinnerFrames = SpinnerFrames {
361 frames: &["/", "-", "\\", "|"],
362 interval: 0.1,
363};
364
365pub const SPINNER_SHADED_BLOCKS: SpinnerFrames = SpinnerFrames {
367 frames: &["░", "▒", "▓", "█", "▓", "▒"],
368 interval: 0.08,
369};
370
371pub const DEFAULT_SPINNER: SpinnerFrames = SPINNER_DOTS;
373
374pub const SPINNERS: &[(&str, &SpinnerFrames)] = &[
380 ("arc", &SPINNER_ARC),
381 ("arrow", &SPINNER_ARROW),
382 ("arrow2", &SPINNER_ARROW2),
383 ("arrow3", &SPINNER_ARROW3),
384 ("bouncingBar", &SPINNER_BOUNCING_BAR),
385 ("bouncingBall", &SPINNER_BOUNCING_BALL),
386 ("christmas", &SPINNER_CHRISTMAS),
387 ("circle", &SPINNER_CIRCLE),
388 ("clock", &SPINNER_CLOCK),
389 ("dots", &SPINNER_DOTS),
390 ("dots2", &SPINNER_DOTS2),
391 ("dots3", &SPINNER_DOTS3),
392 ("dots4", &SPINNER_DOTS4),
393 ("dots5", &SPINNER_DOTS5),
394 ("dots6", &SPINNER_DOTS6),
395 ("dots7", &SPINNER_DOTS7),
396 ("dots8", &SPINNER_DOTS8),
397 ("dots9", &SPINNER_DOTS9),
398 ("dots10", &SPINNER_DOTS10),
399 ("dots11", &SPINNER_DOTS11),
400 ("earth", &SPINNER_EARTH),
401 ("grenade", &SPINNER_GRENADE),
402 ("growHorizontal", &SPINNER_GROW_HORIZONTAL),
403 ("growVertical", &SPINNER_GROW_VERTICAL),
404 ("hamburger", &SPINNER_HAMBURGER),
405 ("hearts", &SPINNER_HEARTS),
406 ("line", &SPINNER_LINE),
407 ("monkey", &SPINNER_MONKEY),
408 ("moon", &SPINNER_MOON),
409 ("noise", &SPINNER_NOISE),
410 ("pong", &SPINNER_PONG),
411 ("runner", &SPINNER_RUNNER),
412 ("shark", &SPINNER_SHARK),
413 ("simpleDots", &SPINNER_SIMPLE_DOTS),
414 ("smiley", &SPINNER_SMILEY),
415 ("toggle", &SPINNER_TOGGLE),
416 ("triangle", &SPINNER_TRIANGLE),
417 ("verticalBars", &SPINNER_VERTICAL_BARS),
418 ("dots12", &SPINNER_DOTS12),
419 ("dots13", &SPINNER_DOTS13),
420 ("dots8Bit", &SPINNER_DOTS8_BIT),
421 ("simpleDotsScrolling", &SPINNER_SIMPLE_DOTS_SCROLLING),
422 ("star", &SPINNER_STAR),
423 ("star2", &SPINNER_STAR2),
424 ("flip", &SPINNER_FLIP),
425 ("balloon", &SPINNER_BALLOON),
426 ("balloon2", &SPINNER_BALLOON2),
427 ("pipe", &SPINNER_PIPE),
428 ("squareCorners", &SPINNER_SQUARE_CORNERS),
429 ("circleQuarters", &SPINNER_CIRCLE_QUARTERS),
430 ("circleHalves", &SPINNER_CIRCLE_HALVES),
431 ("aesthetic", &SPINNER_AESTHETIC),
432 ("brailleLong", &SPINNER_BRAILLE_LONG),
433 ("brailleCrawl", &SPINNER_BRAILLE_CRAWL),
434 ("pulse", &SPINNER_PULSE),
435 ("bounce", &SPINNER_BOUNCE),
436 ("material", &SPINNER_MATERIAL),
437 ("windows", &SPINNER_WINDOWS),
438 ("shadedBlocks", &SPINNER_SHADED_BLOCKS),
439];
440
441pub fn get_spinner(name: &str) -> Option<&'static SpinnerFrames> {
454 for (key, spinner) in SPINNERS {
456 if key.eq_ignore_ascii_case(name) {
457 return Some(spinner);
458 }
459 }
460 let normalized: String = name.chars().filter(|c| !c.is_whitespace()).collect();
462 let normalized = normalized.to_lowercase();
463 for (key, spinner) in SPINNERS {
464 let key_normalized: String = key.chars().filter(|c| !c.is_whitespace()).collect();
465 let key_normalized = key_normalized.to_lowercase();
466 if key_normalized == normalized {
467 return Some(spinner);
468 }
469 }
470 None
471}
472
473#[derive(Debug, Clone)]
479pub struct Spinner {
480 pub frames: &'static [&'static str],
481 pub interval: f64,
482 pub text: String,
484 pub style: crate::style::Style,
486}
487
488impl Spinner {
489 pub fn new(spinner: &'static SpinnerFrames) -> Self {
491 Self {
492 frames: spinner.frames,
493 interval: spinner.interval,
494 text: String::new(),
495 style: crate::style::Style::new(),
496 }
497 }
498
499 pub fn text(mut self, text: impl Into<String>) -> Self {
501 self.text = text.into();
502 self
503 }
504
505 pub fn style(mut self, style: crate::style::Style) -> Self {
507 self.style = style;
508 self
509 }
510
511 pub fn frame_at(&self, elapsed: Duration) -> &'static str {
513 let idx = (elapsed.as_secs_f64() / self.interval) as usize % self.frames.len();
514 self.frames[idx]
515 }
516
517 pub fn render(&self, elapsed: Duration) -> String {
519 let frame = self.frame_at(elapsed);
520 let style_ansi = self.style.to_ansi();
521 let reset = if style_ansi.is_empty() { "" } else { "\x1b[0m" };
522 if self.text.is_empty() {
523 format!("{style_ansi}{frame}{reset}")
524 } else {
525 format!("{style_ansi}{frame}{reset} {}", self.text)
526 }
527 }
528}
529
530impl Default for Spinner {
531 fn default() -> Self {
532 Self::new(&DEFAULT_SPINNER)
533 }
534}
535
536#[cfg(test)]
541mod tests {
542 use super::*;
543
544 #[test]
545 fn test_spinner_frame_at() {
546 let s = Spinner::new(&SPINNER_LINE);
547 let f = s.frame_at(Duration::from_millis(200));
548 assert!(f == "-" || f == "\\" || f == "|" || f == "/");
549 }
550
551 #[test]
552 fn test_get_spinner_found() {
553 let s = get_spinner("dots").unwrap();
554 assert!(!s.frames.is_empty());
555
556 let s = get_spinner("DOTS").unwrap();
557 assert!(!s.frames.is_empty());
558
559 let s = get_spinner("arc").unwrap();
560 assert_eq!(s.frames.len(), 6);
561 }
562
563 #[test]
564 fn test_get_spinner_not_found() {
565 assert!(get_spinner("nonexistent").is_none());
566 }
567
568 #[test]
569 fn test_get_spinner_case_insensitive() {
570 let s1 = get_spinner("ARC").unwrap();
571 let s2 = get_spinner("arc").unwrap();
572 assert_eq!(s1.frames, s2.frames);
573 }
574
575 #[test]
576 fn test_get_spinner_camel_case() {
577 let s = get_spinner("bouncingBar").unwrap();
578 assert!(!s.frames.is_empty());
579
580 let s = get_spinner("BOUNCINGBAR").unwrap();
581 assert!(!s.frames.is_empty());
582 }
583
584 #[test]
585 fn test_spinners_list_all_accessible() {
586 for (name, frames) in SPINNERS {
587 let found = get_spinner(name).unwrap();
588 assert!(!frames.frames.is_empty(), "spinner '{}' has no frames", name);
589 assert_eq!(
592 frames.frames, found.frames,
593 "spinner '{}' points to different frames than expected",
594 name
595 );
596 assert!(
597 (frames.interval - found.interval).abs() < f64::EPSILON,
598 "spinner '{}' interval mismatch",
599 name
600 );
601 }
602 }
603
604 #[test]
605 fn test_spinner_arc_frames() {
606 assert_eq!(SPINNER_ARC.frames.len(), 6);
607 assert!(SPINNER_ARC.interval > 0.0);
608 }
609
610 #[test]
611 fn test_spinner_arrow_frames() {
612 assert_eq!(SPINNER_ARROW.frames.len(), 8);
613 }
614
615 #[test]
616 fn test_spinner_arrow2_frames() {
617 assert_eq!(SPINNER_ARROW2.frames.len(), 8);
618 }
619
620 #[test]
621 fn test_spinner_arrow3_frames() {
622 assert_eq!(SPINNER_ARROW3.frames.len(), 6);
623 }
624
625 #[test]
626 fn test_spinner_bouncing_bar() {
627 assert_eq!(SPINNER_BOUNCING_BAR.frames.len(), 8);
628 }
629
630 #[test]
631 fn test_spinner_bouncing_ball() {
632 assert_eq!(SPINNER_BOUNCING_BALL.frames.len(), 8);
633 }
634
635 #[test]
636 fn test_spinner_christmas() {
637 assert_eq!(SPINNER_CHRISTMAS.frames.len(), 2);
638 }
639
640 #[test]
641 fn test_spinner_circle() {
642 assert_eq!(SPINNER_CIRCLE.frames.len(), 4);
643 }
644
645 #[test]
646 fn test_spinner_clock() {
647 assert_eq!(SPINNER_CLOCK.frames.len(), 12);
648 }
649
650 #[test]
651 fn test_spinner_earth() {
652 assert_eq!(SPINNER_EARTH.frames.len(), 3);
653 }
654
655 #[test]
656 fn test_spinner_grenade() {
657 assert_eq!(SPINNER_GRENADE.frames.len(), 3);
658 }
659
660 #[test]
661 fn test_spinner_grow_horizontal() {
662 assert_eq!(SPINNER_GROW_HORIZONTAL.frames.len(), 14);
663 }
664
665 #[test]
666 fn test_spinner_grow_vertical() {
667 assert_eq!(SPINNER_GROW_VERTICAL.frames.len(), 14);
668 }
669
670 #[test]
671 fn test_spinner_hamburger() {
672 assert_eq!(SPINNER_HAMBURGER.frames.len(), 3);
673 }
674
675 #[test]
676 fn test_spinner_hearts() {
677 assert_eq!(SPINNER_HEARTS.frames.len(), 12);
678 }
679
680 #[test]
681 fn test_spinner_monkey() {
682 assert_eq!(SPINNER_MONKEY.frames.len(), 11);
683 }
684
685 #[test]
686 fn test_spinner_noise() {
687 assert_eq!(SPINNER_NOISE.frames.len(), 9);
688 }
689
690 #[test]
691 fn test_spinner_pong() {
692 assert_eq!(SPINNER_PONG.frames.len(), 30);
693 }
694
695 #[test]
696 fn test_spinner_runner() {
697 assert_eq!(SPINNER_RUNNER.frames.len(), 6);
698 }
699
700 #[test]
701 fn test_spinner_shark() {
702 assert_eq!(SPINNER_SHARK.frames.len(), 6);
703 }
704
705 #[test]
706 fn test_spinner_toggle() {
707 assert_eq!(SPINNER_TOGGLE.frames.len(), 2);
708 }
709
710 #[test]
711 fn test_spinner_triangle() {
712 assert_eq!(SPINNER_TRIANGLE.frames.len(), 4);
713 }
714
715 #[test]
716 fn test_spinner_vertical_bars() {
717 assert_eq!(SPINNER_VERTICAL_BARS.frames.len(), 15);
718 }
719
720 #[test]
721 fn test_spinner_interval_positive() {
722 for (name, frames) in SPINNERS {
723 assert!(
724 frames.interval > 0.0,
725 "spinner '{}' has non-positive interval",
726 name
727 );
728 }
729 }
730
731 #[test]
732 fn test_default_spinner_is_dots() {
733 assert_eq!(DEFAULT_SPINNER.frames, SPINNER_DOTS.frames);
734 }
735
736 #[test]
737 fn test_spinner_dots12() { assert!(!SPINNER_DOTS12.frames.is_empty()); assert!(SPINNER_DOTS12.interval > 0.0); }
738 #[test]
739 fn test_spinner_dots13() { assert!(!SPINNER_DOTS13.frames.is_empty()); assert!(SPINNER_DOTS13.interval > 0.0); }
740 #[test]
741 fn test_spinner_star() { assert!(!SPINNER_STAR.frames.is_empty()); assert!(SPINNER_STAR.interval > 0.0); }
742 #[test]
743 fn test_spinner_flip() { assert!(!SPINNER_FLIP.frames.is_empty()); assert!(SPINNER_FLIP.interval > 0.0); }
744 #[test]
745 fn test_spinner_balloon() { assert!(!SPINNER_BALLOON.frames.is_empty()); assert!(SPINNER_BALLOON.interval > 0.0); }
746 #[test]
747 fn test_spinner_pipe() { assert!(!SPINNER_PIPE.frames.is_empty()); assert!(SPINNER_PIPE.interval > 0.0); }
748 #[test]
749 fn test_spinner_pulse() { assert!(!SPINNER_PULSE.frames.is_empty()); assert!(SPINNER_PULSE.interval > 0.0); }
750 #[test]
751 fn test_spinner_windows() { assert!(!SPINNER_WINDOWS.frames.is_empty()); assert!(SPINNER_WINDOWS.interval > 0.0); }
752 #[test]
753 fn test_spinner_shaded_blocks() { assert!(!SPINNER_SHADED_BLOCKS.frames.is_empty()); assert!(SPINNER_SHADED_BLOCKS.interval > 0.0); }
754}