1use crossterm::style::Color as CrosstermColor;
4use presentar_core::Color;
5
6#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
8pub enum ColorMode {
9 #[default]
11 TrueColor,
12 Color256,
14 Color16,
16 Mono,
18}
19
20impl ColorMode {
21 #[must_use]
23 pub fn detect() -> Self {
24 Self::detect_with_env(std::env::var("COLORTERM").ok(), std::env::var("TERM").ok())
25 }
26
27 #[must_use]
30 #[allow(clippy::needless_pass_by_value)]
31 pub fn detect_with_env(colorterm: Option<String>, term: Option<String>) -> Self {
32 if let Some(ref ct) = colorterm {
34 if ct == "truecolor" || ct == "24bit" {
35 return Self::TrueColor;
36 }
37 }
38
39 match term.as_deref() {
41 Some(t) if t.contains("256color") => Self::Color256,
42 Some(t) if t.contains("color") || t.contains("xterm") => Self::Color16,
43 Some("dumb") | None => Self::Mono,
44 _ => Self::Color16,
45 }
46 }
47
48 #[must_use]
53 pub fn to_crossterm(&self, color: Color) -> CrosstermColor {
54 debug_assert!(color.r >= 0.0 && color.r <= 1.0, "r must be in 0.0-1.0");
55 debug_assert!(color.g >= 0.0 && color.g <= 1.0, "g must be in 0.0-1.0");
56 debug_assert!(color.b >= 0.0 && color.b <= 1.0, "b must be in 0.0-1.0");
57 debug_assert!(color.a >= 0.0 && color.a <= 1.0, "a must be in 0.0-1.0");
58
59 if color.a == 0.0 {
63 return CrosstermColor::Reset;
64 }
65
66 let r = (color.r * 255.0).round() as u8;
67 let g = (color.g * 255.0).round() as u8;
68 let b = (color.b * 255.0).round() as u8;
69
70 match self {
71 Self::TrueColor => CrosstermColor::Rgb { r, g, b },
72 Self::Color256 => CrosstermColor::AnsiValue(Self::rgb_to_256(r, g, b)),
73 Self::Color16 => Self::rgb_to_16(r, g, b),
74 Self::Mono => CrosstermColor::White,
75 }
76 }
77
78 fn rgb_to_256(r: u8, g: u8, b: u8) -> u8 {
80 if r == g && g == b {
82 if r < 8 {
83 return 16; }
85 if r > 248 {
86 return 231; }
88 return 232 + ((r - 8) / 10).min(23);
90 }
91
92 let r_idx = (u16::from(r) * 5 / 255) as u8;
94 let g_idx = (u16::from(g) * 5 / 255) as u8;
95 let b_idx = (u16::from(b) * 5 / 255) as u8;
96 16 + 36 * r_idx + 6 * g_idx + b_idx
97 }
98
99 fn rgb_to_16(r: u8, g: u8, b: u8) -> CrosstermColor {
101 let luminance = (u32::from(r) * 299 + u32::from(g) * 587 + u32::from(b) * 114) / 1000;
102 let bright = luminance > 127;
103
104 let max = r.max(g).max(b);
105 let threshold = max / 2;
106
107 let has_r = r > threshold;
108 let has_g = g > threshold;
109 let has_b = b > threshold;
110
111 match (has_r, has_g, has_b, bright) {
112 (false, false, false, false) => CrosstermColor::Black,
113 (false, false, false, true) => CrosstermColor::DarkGrey,
114 (true, false, false, false) => CrosstermColor::DarkRed,
115 (true, false, false, true) => CrosstermColor::Red,
116 (false, true, false, false) => CrosstermColor::DarkGreen,
117 (false, true, false, true) => CrosstermColor::Green,
118 (true, true, false, false) => CrosstermColor::DarkYellow,
119 (true, true, false, true) => CrosstermColor::Yellow,
120 (false, false, true, false) => CrosstermColor::DarkBlue,
121 (false, false, true, true) => CrosstermColor::Blue,
122 (true, false, true, false) => CrosstermColor::DarkMagenta,
123 (true, false, true, true) => CrosstermColor::Magenta,
124 (false, true, true, false) => CrosstermColor::DarkCyan,
125 (false, true, true, true) => CrosstermColor::Cyan,
126 (true, true, true, false) => CrosstermColor::Grey,
127 (true, true, true, true) => CrosstermColor::White,
128 }
129 }
130}
131
132#[cfg(test)]
133mod tests {
134 use super::*;
135
136 #[test]
137 fn test_color_mode_default() {
138 assert_eq!(ColorMode::default(), ColorMode::TrueColor);
139 }
140
141 #[test]
142 fn test_truecolor_conversion() {
143 let mode = ColorMode::TrueColor;
144 let color = Color::new(0.5, 0.25, 0.75, 1.0);
145 let result = mode.to_crossterm(color);
146 assert_eq!(
147 result,
148 CrosstermColor::Rgb {
149 r: 128,
150 g: 64,
151 b: 191
152 }
153 );
154 }
155
156 #[test]
157 fn test_256_grayscale() {
158 assert_eq!(ColorMode::rgb_to_256(0, 0, 0), 16);
160 assert_eq!(ColorMode::rgb_to_256(255, 255, 255), 231);
162 let mid = ColorMode::rgb_to_256(128, 128, 128);
164 assert!(mid >= 232);
165 }
166
167 #[test]
168 fn test_256_grayscale_near_black() {
169 assert_eq!(ColorMode::rgb_to_256(5, 5, 5), 16);
171 }
172
173 #[test]
174 fn test_256_grayscale_ramp() {
175 let gray50 = ColorMode::rgb_to_256(50, 50, 50);
177 assert!(gray50 >= 232);
178
179 let gray100 = ColorMode::rgb_to_256(100, 100, 100);
180 assert!(gray100 >= 232);
181
182 let gray200 = ColorMode::rgb_to_256(200, 200, 200);
183 assert!(gray200 >= 232);
184 }
185
186 #[test]
187 fn test_256_color_cube() {
188 let red = ColorMode::rgb_to_256(255, 0, 0);
190 assert!((16..=231).contains(&red));
191
192 let green = ColorMode::rgb_to_256(0, 255, 0);
194 assert!((16..=231).contains(&green));
195
196 let blue = ColorMode::rgb_to_256(0, 0, 255);
198 assert!((16..=231).contains(&blue));
199
200 let magenta = ColorMode::rgb_to_256(255, 0, 255);
202 assert!((16..=231).contains(&magenta));
203 }
204
205 #[test]
206 fn test_16_color_mapping() {
207 assert_eq!(ColorMode::rgb_to_16(0, 0, 0), CrosstermColor::Black);
209 assert_eq!(ColorMode::rgb_to_16(255, 255, 255), CrosstermColor::White);
211 assert!(matches!(
213 ColorMode::rgb_to_16(255, 0, 0),
214 CrosstermColor::Red | CrosstermColor::DarkRed
215 ));
216 }
217
218 #[test]
219 fn test_16_color_green() {
220 let result = ColorMode::rgb_to_16(0, 255, 0);
221 assert!(matches!(
222 result,
223 CrosstermColor::Green | CrosstermColor::DarkGreen
224 ));
225 }
226
227 #[test]
228 fn test_16_color_blue() {
229 let result = ColorMode::rgb_to_16(0, 0, 255);
230 assert!(matches!(
231 result,
232 CrosstermColor::Blue | CrosstermColor::DarkBlue
233 ));
234 }
235
236 #[test]
237 fn test_16_color_yellow() {
238 let result = ColorMode::rgb_to_16(255, 255, 0);
239 assert!(matches!(
240 result,
241 CrosstermColor::Yellow | CrosstermColor::DarkYellow
242 ));
243 }
244
245 #[test]
246 fn test_16_color_cyan() {
247 let result = ColorMode::rgb_to_16(0, 255, 255);
248 assert!(matches!(
249 result,
250 CrosstermColor::Cyan | CrosstermColor::DarkCyan
251 ));
252 }
253
254 #[test]
255 fn test_16_color_magenta() {
256 let result = ColorMode::rgb_to_16(255, 0, 255);
257 assert!(matches!(
258 result,
259 CrosstermColor::Magenta | CrosstermColor::DarkMagenta
260 ));
261 }
262
263 #[test]
264 fn test_16_color_dark_gray() {
265 let result = ColorMode::rgb_to_16(50, 50, 50);
266 assert!(matches!(
268 result,
269 CrosstermColor::Black | CrosstermColor::DarkGrey | CrosstermColor::Grey
270 ));
271 }
272
273 #[test]
274 fn test_16_color_gray() {
275 let result = ColorMode::rgb_to_16(192, 192, 192);
276 assert!(matches!(
277 result,
278 CrosstermColor::Grey | CrosstermColor::White
279 ));
280 }
281
282 #[test]
283 fn test_mono_conversion() {
284 let mode = ColorMode::Mono;
285 assert_eq!(mode.to_crossterm(Color::RED), CrosstermColor::White);
286 assert_eq!(mode.to_crossterm(Color::BLUE), CrosstermColor::White);
287 assert_eq!(mode.to_crossterm(Color::GREEN), CrosstermColor::White);
288 }
289
290 #[test]
291 fn test_transparent_returns_reset() {
292 for mode in [
295 ColorMode::TrueColor,
296 ColorMode::Color256,
297 ColorMode::Color16,
298 ColorMode::Mono,
299 ] {
300 assert_eq!(
301 mode.to_crossterm(Color::TRANSPARENT),
302 CrosstermColor::Reset,
303 "Mode {:?} should return Reset for TRANSPARENT",
304 mode
305 );
306
307 let zero_alpha = Color::new(1.0, 0.5, 0.25, 0.0);
309 assert_eq!(
310 mode.to_crossterm(zero_alpha),
311 CrosstermColor::Reset,
312 "Mode {:?} should return Reset for any color with alpha=0",
313 mode
314 );
315 }
316 }
317
318 #[test]
319 fn test_256_conversion() {
320 let mode = ColorMode::Color256;
321 let result = mode.to_crossterm(Color::new(0.5, 0.25, 0.75, 1.0));
322 assert!(matches!(result, CrosstermColor::AnsiValue(_)));
323 }
324
325 #[test]
326 fn test_16_conversion() {
327 let mode = ColorMode::Color16;
328 let result = mode.to_crossterm(Color::RED);
329 assert!(matches!(
330 result,
331 CrosstermColor::Red | CrosstermColor::DarkRed
332 ));
333 }
334
335 #[test]
336 fn test_color_mode_eq() {
337 assert_eq!(ColorMode::TrueColor, ColorMode::TrueColor);
338 assert_eq!(ColorMode::Color256, ColorMode::Color256);
339 assert_eq!(ColorMode::Color16, ColorMode::Color16);
340 assert_eq!(ColorMode::Mono, ColorMode::Mono);
341 assert_ne!(ColorMode::TrueColor, ColorMode::Color256);
342 }
343
344 #[test]
345 fn test_color_mode_clone() {
346 let mode = ColorMode::Color256;
347 let cloned = mode;
348 assert_eq!(mode, cloned);
349 }
350
351 #[test]
352 fn test_color_mode_debug() {
353 let mode = ColorMode::TrueColor;
354 assert!(format!("{:?}", mode).contains("TrueColor"));
355 }
356
357 #[test]
358 fn test_16_color_dim_colors() {
359 let dark_red = ColorMode::rgb_to_16(128, 0, 0);
361 assert!(matches!(
362 dark_red,
363 CrosstermColor::Red | CrosstermColor::DarkRed
364 ));
365
366 let dark_green = ColorMode::rgb_to_16(0, 100, 0);
368 assert!(matches!(
369 dark_green,
370 CrosstermColor::Green | CrosstermColor::DarkGreen
371 ));
372
373 let dark_blue = ColorMode::rgb_to_16(0, 0, 128);
375 assert!(matches!(
376 dark_blue,
377 CrosstermColor::Blue | CrosstermColor::DarkBlue
378 ));
379 }
380
381 #[test]
382 fn test_256_near_white() {
383 let near_white = ColorMode::rgb_to_256(250, 250, 250);
385 assert_eq!(near_white, 231);
386 }
387
388 #[test]
389 fn test_256_mixed_colors() {
390 let orange = ColorMode::rgb_to_256(255, 128, 0);
392 assert!((16..=231).contains(&orange));
393
394 let purple = ColorMode::rgb_to_256(128, 0, 255);
396 assert!((16..=231).contains(&purple));
397
398 let teal = ColorMode::rgb_to_256(0, 128, 128);
400 assert!((16..=231).contains(&teal));
401 }
402
403 #[test]
406 fn test_color_mode_detect() {
407 let mode = ColorMode::detect();
409 assert!(matches!(
410 mode,
411 ColorMode::TrueColor | ColorMode::Color256 | ColorMode::Color16 | ColorMode::Mono
412 ));
413 }
414
415 #[test]
416 fn test_16_color_all_dark_variants() {
417 let dark_red = ColorMode::rgb_to_16(180, 20, 20);
421 assert!(matches!(
422 dark_red,
423 CrosstermColor::DarkRed | CrosstermColor::Red
424 ));
425
426 let dark_green = ColorMode::rgb_to_16(20, 150, 20);
428 assert!(matches!(
429 dark_green,
430 CrosstermColor::DarkGreen | CrosstermColor::Green
431 ));
432
433 let dark_blue = ColorMode::rgb_to_16(20, 20, 180);
435 assert!(matches!(
436 dark_blue,
437 CrosstermColor::DarkBlue | CrosstermColor::Blue
438 ));
439
440 let dark_yellow = ColorMode::rgb_to_16(150, 150, 20);
442 assert!(matches!(
443 dark_yellow,
444 CrosstermColor::DarkYellow | CrosstermColor::Yellow
445 ));
446
447 let dark_cyan = ColorMode::rgb_to_16(20, 150, 150);
449 assert!(matches!(
450 dark_cyan,
451 CrosstermColor::DarkCyan | CrosstermColor::Cyan
452 ));
453
454 let dark_magenta = ColorMode::rgb_to_16(150, 20, 150);
456 assert!(matches!(
457 dark_magenta,
458 CrosstermColor::DarkMagenta | CrosstermColor::Magenta
459 ));
460 }
461
462 #[test]
463 fn test_16_color_bright_variants() {
464 let bright_red = ColorMode::rgb_to_16(255, 50, 50);
469 assert!(!matches!(bright_red, CrosstermColor::Black));
470
471 let bright_green = ColorMode::rgb_to_16(50, 255, 50);
473 assert!(!matches!(bright_green, CrosstermColor::Black));
474
475 let bright_blue = ColorMode::rgb_to_16(50, 50, 255);
477 assert!(!matches!(bright_blue, CrosstermColor::Black));
478 }
479
480 #[test]
481 fn test_16_color_dark_grey_explicit() {
482 let dark_grey = ColorMode::rgb_to_16(80, 80, 80);
484 assert!(matches!(
485 dark_grey,
486 CrosstermColor::DarkGrey | CrosstermColor::Black | CrosstermColor::Grey
487 ));
488 }
489
490 #[test]
491 fn test_to_crossterm_edge_values() {
492 let mode = ColorMode::TrueColor;
494
495 let black = mode.to_crossterm(Color::new(0.0, 0.0, 0.0, 1.0));
497 assert_eq!(black, CrosstermColor::Rgb { r: 0, g: 0, b: 0 });
498
499 let white = mode.to_crossterm(Color::new(1.0, 1.0, 1.0, 1.0));
501 assert_eq!(
502 white,
503 CrosstermColor::Rgb {
504 r: 255,
505 g: 255,
506 b: 255
507 }
508 );
509 }
510
511 #[test]
512 fn test_256_grayscale_boundary() {
513 assert_eq!(ColorMode::rgb_to_256(7, 7, 7), 16); assert_eq!(ColorMode::rgb_to_256(8, 8, 8), 232); assert_eq!(ColorMode::rgb_to_256(249, 249, 249), 231); }
518
519 #[test]
520 fn test_256_color_cube_corners() {
521 let c000 = ColorMode::rgb_to_256(1, 1, 2); assert!((16..=231).contains(&c000));
525
526 let c555 = ColorMode::rgb_to_256(254, 254, 255); assert!((16..=231).contains(&c555));
529 }
530
531 #[test]
532 fn test_color16_to_crossterm() {
533 let mode = ColorMode::Color16;
534
535 let red = mode.to_crossterm(Color::RED);
537 assert!(matches!(red, CrosstermColor::Red | CrosstermColor::DarkRed));
538
539 let green = mode.to_crossterm(Color::GREEN);
540 assert!(matches!(
541 green,
542 CrosstermColor::Green | CrosstermColor::DarkGreen
543 ));
544
545 let blue = mode.to_crossterm(Color::BLUE);
546 assert!(matches!(
547 blue,
548 CrosstermColor::Blue | CrosstermColor::DarkBlue
549 ));
550
551 let black = mode.to_crossterm(Color::BLACK);
552 assert!(matches!(black, CrosstermColor::Black));
553
554 let white = mode.to_crossterm(Color::WHITE);
555 assert!(matches!(white, CrosstermColor::White));
556 }
557
558 #[test]
559 fn test_color256_grayscale_through_mode() {
560 let mode = ColorMode::Color256;
561
562 let black = mode.to_crossterm(Color::BLACK);
564 assert!(matches!(black, CrosstermColor::AnsiValue(16)));
565
566 let gray = mode.to_crossterm(Color::new(0.5, 0.5, 0.5, 1.0));
568 if let CrosstermColor::AnsiValue(v) = gray {
569 assert!(v >= 232 || ((16..=231).contains(&v)));
570 }
571 }
572
573 #[test]
574 #[allow(clippy::absurd_extreme_comparisons)]
575 fn test_rgb_to_256_extensive() {
576 for r in [0, 51, 102, 153, 204, 255] {
578 for g in [0, 51, 102, 153, 204, 255] {
579 for b in [0, 51, 102, 153, 204, 255] {
580 let result = ColorMode::rgb_to_256(r, g, b);
581 let _ = result;
583 }
584 }
585 }
586 }
587
588 #[test]
589 fn test_rgb_to_16_extensive() {
590 for r in [0, 64, 128, 192, 255] {
592 for g in [0, 64, 128, 192, 255] {
593 for b in [0, 64, 128, 192, 255] {
594 let result = ColorMode::rgb_to_16(r, g, b);
595 let _ = format!("{:?}", result);
597 }
598 }
599 }
600 }
601
602 #[test]
603 fn test_to_crossterm_all_modes() {
604 let test_colors = [
605 Color::BLACK,
606 Color::WHITE,
607 Color::RED,
608 Color::GREEN,
609 Color::BLUE,
610 Color::new(0.5, 0.5, 0.5, 1.0),
611 Color::new(0.25, 0.75, 0.5, 1.0),
612 ];
613
614 for mode in [
615 ColorMode::TrueColor,
616 ColorMode::Color256,
617 ColorMode::Color16,
618 ColorMode::Mono,
619 ] {
620 for color in &test_colors {
621 let result = mode.to_crossterm(*color);
622 let _ = format!("{:?}", result);
624 }
625 }
626 }
627
628 #[test]
629 #[allow(clippy::absurd_extreme_comparisons)]
630 fn test_grayscale_ramp_comprehensive() {
631 for gray in 0..=255 {
633 let result = ColorMode::rgb_to_256(gray, gray, gray);
634 assert!(result == 16 || result == 231 || ((232..=255).contains(&result)));
636 }
637 }
638
639 #[test]
640 #[allow(clippy::assertions_on_constants)]
641 fn test_detect_returns_valid() {
642 let mode = ColorMode::detect();
645 match mode {
646 ColorMode::TrueColor => assert!(true),
647 ColorMode::Color256 => assert!(true),
648 ColorMode::Color16 => assert!(true),
649 ColorMode::Mono => assert!(true),
650 }
651 }
652
653 #[test]
654 fn test_color_mode_copy() {
655 let mode1 = ColorMode::TrueColor;
657 let mode2 = mode1; assert_eq!(mode1, mode2);
659 }
660
661 #[test]
664 fn test_detect_colorterm_truecolor() {
665 let mode = ColorMode::detect_with_env(Some("truecolor".to_string()), None);
666 assert_eq!(mode, ColorMode::TrueColor);
667 }
668
669 #[test]
670 fn test_detect_colorterm_24bit() {
671 let mode = ColorMode::detect_with_env(Some("24bit".to_string()), None);
672 assert_eq!(mode, ColorMode::TrueColor);
673 }
674
675 #[test]
676 fn test_detect_colorterm_other_falls_through() {
677 let mode = ColorMode::detect_with_env(
679 Some("other".to_string()),
680 Some("xterm-256color".to_string()),
681 );
682 assert_eq!(mode, ColorMode::Color256);
683 }
684
685 #[test]
686 fn test_detect_term_256color() {
687 let mode = ColorMode::detect_with_env(None, Some("xterm-256color".to_string()));
688 assert_eq!(mode, ColorMode::Color256);
689
690 let mode2 = ColorMode::detect_with_env(None, Some("screen-256color".to_string()));
691 assert_eq!(mode2, ColorMode::Color256);
692 }
693
694 #[test]
695 fn test_detect_term_xterm() {
696 let mode = ColorMode::detect_with_env(None, Some("xterm".to_string()));
697 assert_eq!(mode, ColorMode::Color16);
698 }
699
700 #[test]
701 fn test_detect_term_color() {
702 let mode = ColorMode::detect_with_env(None, Some("linux-color".to_string()));
703 assert_eq!(mode, ColorMode::Color16);
704 }
705
706 #[test]
707 fn test_detect_term_dumb() {
708 let mode = ColorMode::detect_with_env(None, Some("dumb".to_string()));
709 assert_eq!(mode, ColorMode::Mono);
710 }
711
712 #[test]
713 fn test_detect_term_none() {
714 let mode = ColorMode::detect_with_env(None, None);
715 assert_eq!(mode, ColorMode::Mono);
716 }
717
718 #[test]
719 fn test_detect_term_unknown() {
720 let mode = ColorMode::detect_with_env(None, Some("vt100".to_string()));
722 assert_eq!(mode, ColorMode::Color16);
723 }
724
725 #[test]
726 fn test_detect_colorterm_priority() {
727 let mode =
729 ColorMode::detect_with_env(Some("truecolor".to_string()), Some("dumb".to_string()));
730 assert_eq!(mode, ColorMode::TrueColor);
731 }
732
733 #[test]
734 #[allow(clippy::manual_string_new)]
735 fn test_detect_colorterm_empty_string() {
736 let mode = ColorMode::detect_with_env(Some("".to_string()), None);
738 assert_eq!(mode, ColorMode::Mono);
739 }
740
741 #[test]
742 fn test_detect_term_various() {
743 assert_eq!(
745 ColorMode::detect_with_env(None, Some("rxvt-256color".to_string())),
746 ColorMode::Color256
747 );
748 assert_eq!(
749 ColorMode::detect_with_env(None, Some("screen".to_string())),
750 ColorMode::Color16
751 );
752 assert_eq!(
753 ColorMode::detect_with_env(None, Some("ansi".to_string())),
754 ColorMode::Color16
755 );
756 }
757
758 #[test]
759 fn test_detect_colorterm_with_term_fallback() {
760 let mode =
762 ColorMode::detect_with_env(Some("something".to_string()), Some("xterm".to_string()));
763 assert_eq!(mode, ColorMode::Color16);
764 }
765
766 #[test]
767 fn test_to_crossterm_comprehensive() {
768 let colors = [
770 Color::new(0.0, 0.0, 0.0, 1.0),
771 Color::new(1.0, 1.0, 1.0, 1.0),
772 Color::new(1.0, 0.0, 0.0, 1.0),
773 Color::new(0.0, 1.0, 0.0, 1.0),
774 Color::new(0.0, 0.0, 1.0, 1.0),
775 Color::new(0.5, 0.5, 0.5, 1.0),
776 Color::new(0.25, 0.5, 0.75, 1.0),
777 Color::new(0.1, 0.2, 0.3, 1.0),
778 ];
779
780 for color in colors {
781 for mode in [
782 ColorMode::TrueColor,
783 ColorMode::Color256,
784 ColorMode::Color16,
785 ColorMode::Mono,
786 ] {
787 let _ = mode.to_crossterm(color);
788 }
789 }
790 }
791
792 #[test]
793 fn test_rgb_to_256_boundary_values() {
794 for v in [0, 51, 102, 153, 204, 255] {
796 let _ = ColorMode::rgb_to_256(v, 0, 0);
797 let _ = ColorMode::rgb_to_256(0, v, 0);
798 let _ = ColorMode::rgb_to_256(0, 0, v);
799 }
800 }
801
802 #[test]
803 fn test_rgb_to_16_all_combinations() {
804 let test_cases = [
806 (0, 0, 0), (50, 50, 50), (128, 0, 0), (255, 0, 0), (0, 128, 0), (0, 255, 0), (128, 128, 0), (255, 255, 0), (0, 0, 128), (0, 0, 255), (128, 0, 128), (255, 0, 255), (0, 128, 128), (0, 255, 255), (192, 192, 192), (255, 255, 255), ];
823
824 for (r, g, b) in test_cases {
825 let _ = ColorMode::rgb_to_16(r, g, b);
826 }
827 }
828
829 #[test]
830 fn test_color_lerp_boundary() {
831 let c1 = Color::RED;
833 let c2 = Color::BLUE;
834 let _ = c1.lerp(&c2, 0.0);
835 let _ = c1.lerp(&c2, 1.0);
836 let _ = c1.lerp(&c2, 0.5);
837 }
838
839 #[test]
840 fn test_detect_original_still_works() {
841 let _ = ColorMode::detect();
843 }
844}