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!(red >= 16 && red <= 231);
191
192 let green = ColorMode::rgb_to_256(0, 255, 0);
194 assert!(green >= 16 && green <= 231);
195
196 let blue = ColorMode::rgb_to_256(0, 0, 255);
198 assert!(blue >= 16 && blue <= 231);
199
200 let magenta = ColorMode::rgb_to_256(255, 0, 255);
202 assert!(magenta >= 16 && magenta <= 231);
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!(orange >= 16 && orange <= 231);
393
394 let purple = ColorMode::rgb_to_256(128, 0, 255);
396 assert!(purple >= 16 && purple <= 231);
397
398 let teal = ColorMode::rgb_to_256(0, 128, 128);
400 assert!(teal >= 16 && teal <= 231);
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!(c000 >= 16 && c000 <= 231);
525
526 let c555 = ColorMode::rgb_to_256(254, 254, 255); assert!(c555 >= 16 && c555 <= 231);
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 || (v >= 16 && v <= 231));
570 }
571 }
572
573 #[test]
574 fn test_rgb_to_256_extensive() {
575 for r in [0, 51, 102, 153, 204, 255] {
577 for g in [0, 51, 102, 153, 204, 255] {
578 for b in [0, 51, 102, 153, 204, 255] {
579 let result = ColorMode::rgb_to_256(r, g, b);
580 assert!(result <= 255);
582 }
583 }
584 }
585 }
586
587 #[test]
588 fn test_rgb_to_16_extensive() {
589 for r in [0, 64, 128, 192, 255] {
591 for g in [0, 64, 128, 192, 255] {
592 for b in [0, 64, 128, 192, 255] {
593 let result = ColorMode::rgb_to_16(r, g, b);
594 let _ = format!("{:?}", result);
596 }
597 }
598 }
599 }
600
601 #[test]
602 fn test_to_crossterm_all_modes() {
603 let test_colors = [
604 Color::BLACK,
605 Color::WHITE,
606 Color::RED,
607 Color::GREEN,
608 Color::BLUE,
609 Color::new(0.5, 0.5, 0.5, 1.0),
610 Color::new(0.25, 0.75, 0.5, 1.0),
611 ];
612
613 for mode in [
614 ColorMode::TrueColor,
615 ColorMode::Color256,
616 ColorMode::Color16,
617 ColorMode::Mono,
618 ] {
619 for color in &test_colors {
620 let result = mode.to_crossterm(*color);
621 let _ = format!("{:?}", result);
623 }
624 }
625 }
626
627 #[test]
628 fn test_grayscale_ramp_comprehensive() {
629 for gray in 0..=255 {
631 let result = ColorMode::rgb_to_256(gray, gray, gray);
632 assert!(result == 16 || result == 231 || (result >= 232 && result <= 255));
634 }
635 }
636
637 #[test]
638 fn test_detect_returns_valid() {
639 let mode = ColorMode::detect();
642 match mode {
643 ColorMode::TrueColor => assert!(true),
644 ColorMode::Color256 => assert!(true),
645 ColorMode::Color16 => assert!(true),
646 ColorMode::Mono => assert!(true),
647 }
648 }
649
650 #[test]
651 fn test_color_mode_copy() {
652 let mode1 = ColorMode::TrueColor;
654 let mode2 = mode1; assert_eq!(mode1, mode2);
656 }
657
658 #[test]
661 fn test_detect_colorterm_truecolor() {
662 let mode = ColorMode::detect_with_env(Some("truecolor".to_string()), None);
663 assert_eq!(mode, ColorMode::TrueColor);
664 }
665
666 #[test]
667 fn test_detect_colorterm_24bit() {
668 let mode = ColorMode::detect_with_env(Some("24bit".to_string()), None);
669 assert_eq!(mode, ColorMode::TrueColor);
670 }
671
672 #[test]
673 fn test_detect_colorterm_other_falls_through() {
674 let mode = ColorMode::detect_with_env(
676 Some("other".to_string()),
677 Some("xterm-256color".to_string()),
678 );
679 assert_eq!(mode, ColorMode::Color256);
680 }
681
682 #[test]
683 fn test_detect_term_256color() {
684 let mode = ColorMode::detect_with_env(None, Some("xterm-256color".to_string()));
685 assert_eq!(mode, ColorMode::Color256);
686
687 let mode2 = ColorMode::detect_with_env(None, Some("screen-256color".to_string()));
688 assert_eq!(mode2, ColorMode::Color256);
689 }
690
691 #[test]
692 fn test_detect_term_xterm() {
693 let mode = ColorMode::detect_with_env(None, Some("xterm".to_string()));
694 assert_eq!(mode, ColorMode::Color16);
695 }
696
697 #[test]
698 fn test_detect_term_color() {
699 let mode = ColorMode::detect_with_env(None, Some("linux-color".to_string()));
700 assert_eq!(mode, ColorMode::Color16);
701 }
702
703 #[test]
704 fn test_detect_term_dumb() {
705 let mode = ColorMode::detect_with_env(None, Some("dumb".to_string()));
706 assert_eq!(mode, ColorMode::Mono);
707 }
708
709 #[test]
710 fn test_detect_term_none() {
711 let mode = ColorMode::detect_with_env(None, None);
712 assert_eq!(mode, ColorMode::Mono);
713 }
714
715 #[test]
716 fn test_detect_term_unknown() {
717 let mode = ColorMode::detect_with_env(None, Some("vt100".to_string()));
719 assert_eq!(mode, ColorMode::Color16);
720 }
721
722 #[test]
723 fn test_detect_colorterm_priority() {
724 let mode =
726 ColorMode::detect_with_env(Some("truecolor".to_string()), Some("dumb".to_string()));
727 assert_eq!(mode, ColorMode::TrueColor);
728 }
729
730 #[test]
731 fn test_detect_colorterm_empty_string() {
732 let mode = ColorMode::detect_with_env(Some("".to_string()), None);
734 assert_eq!(mode, ColorMode::Mono);
735 }
736
737 #[test]
738 fn test_detect_term_various() {
739 assert_eq!(
741 ColorMode::detect_with_env(None, Some("rxvt-256color".to_string())),
742 ColorMode::Color256
743 );
744 assert_eq!(
745 ColorMode::detect_with_env(None, Some("screen".to_string())),
746 ColorMode::Color16
747 );
748 assert_eq!(
749 ColorMode::detect_with_env(None, Some("ansi".to_string())),
750 ColorMode::Color16
751 );
752 }
753
754 #[test]
755 fn test_detect_colorterm_with_term_fallback() {
756 let mode =
758 ColorMode::detect_with_env(Some("something".to_string()), Some("xterm".to_string()));
759 assert_eq!(mode, ColorMode::Color16);
760 }
761
762 #[test]
763 fn test_to_crossterm_comprehensive() {
764 let colors = [
766 Color::new(0.0, 0.0, 0.0, 1.0),
767 Color::new(1.0, 1.0, 1.0, 1.0),
768 Color::new(1.0, 0.0, 0.0, 1.0),
769 Color::new(0.0, 1.0, 0.0, 1.0),
770 Color::new(0.0, 0.0, 1.0, 1.0),
771 Color::new(0.5, 0.5, 0.5, 1.0),
772 Color::new(0.25, 0.5, 0.75, 1.0),
773 Color::new(0.1, 0.2, 0.3, 1.0),
774 ];
775
776 for color in colors {
777 for mode in [
778 ColorMode::TrueColor,
779 ColorMode::Color256,
780 ColorMode::Color16,
781 ColorMode::Mono,
782 ] {
783 let _ = mode.to_crossterm(color);
784 }
785 }
786 }
787
788 #[test]
789 fn test_rgb_to_256_boundary_values() {
790 for v in [0, 51, 102, 153, 204, 255] {
792 let _ = ColorMode::rgb_to_256(v, 0, 0);
793 let _ = ColorMode::rgb_to_256(0, v, 0);
794 let _ = ColorMode::rgb_to_256(0, 0, v);
795 }
796 }
797
798 #[test]
799 fn test_rgb_to_16_all_combinations() {
800 let test_cases = [
802 (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), ];
819
820 for (r, g, b) in test_cases {
821 let _ = ColorMode::rgb_to_16(r, g, b);
822 }
823 }
824
825 #[test]
826 fn test_color_lerp_boundary() {
827 let c1 = Color::RED;
829 let c2 = Color::BLUE;
830 let _ = c1.lerp(&c2, 0.0);
831 let _ = c1.lerp(&c2, 1.0);
832 let _ = c1.lerp(&c2, 0.5);
833 }
834
835 #[test]
836 fn test_detect_original_still_works() {
837 let _ = ColorMode::detect();
839 }
840}