#[cfg(test)]
mod types_tests {
use crate::{RgbColor, MunsellColor, IsccNbsName, MunsellPoint, IsccNbsPolygon, MunsellError};
#[test]
fn test_rgb_color_new() {
let color = RgbColor::new(255, 128, 64);
assert_eq!(color.r, 255);
assert_eq!(color.g, 128);
assert_eq!(color.b, 64);
}
#[test]
fn test_rgb_color_from_array() {
let color = RgbColor::from_array([100, 200, 50]);
assert_eq!(color.r, 100);
assert_eq!(color.g, 200);
assert_eq!(color.b, 50);
}
#[test]
fn test_rgb_color_to_array() {
let color = RgbColor::new(75, 150, 225);
let array = color.to_array();
assert_eq!(array, [75, 150, 225]);
}
#[test]
fn test_rgb_color_is_grayscale() {
assert!(RgbColor::new(0, 0, 0).is_grayscale()); assert!(RgbColor::new(255, 255, 255).is_grayscale()); assert!(RgbColor::new(128, 128, 128).is_grayscale()); assert!(RgbColor::new(1, 1, 1).is_grayscale());
assert!(!RgbColor::new(255, 0, 0).is_grayscale()); assert!(!RgbColor::new(100, 200, 50).is_grayscale()); assert!(!RgbColor::new(128, 128, 129).is_grayscale()); assert!(!RgbColor::new(0, 0, 1).is_grayscale()); }
#[test]
fn test_rgb_color_display() {
let color = RgbColor::new(255, 128, 64);
assert_eq!(format!("{}", color), "RGB(255, 128, 64)");
let black = RgbColor::new(0, 0, 0);
assert_eq!(format!("{}", black), "RGB(0, 0, 0)");
}
#[test]
fn test_rgb_color_from_trait() {
let array = [200, 100, 50];
let color: RgbColor = array.into();
assert_eq!(color.r, 200);
assert_eq!(color.g, 100);
assert_eq!(color.b, 50);
}
#[test]
fn test_rgb_color_into_array() {
let color = RgbColor::new(75, 150, 225);
let array: [u8; 3] = color.into();
assert_eq!(array, [75, 150, 225]);
}
#[test]
fn test_rgb_color_equality() {
let color1 = RgbColor::new(255, 128, 64);
let color2 = RgbColor::new(255, 128, 64);
let color3 = RgbColor::new(255, 128, 65);
assert_eq!(color1, color2);
assert_ne!(color1, color3);
}
#[test]
fn test_rgb_color_boundary_values() {
let black = RgbColor::new(0, 0, 0);
let white = RgbColor::new(255, 255, 255);
let mixed_boundaries = RgbColor::new(0, 255, 128);
assert_eq!(black.to_array(), [0, 0, 0]);
assert_eq!(white.to_array(), [255, 255, 255]);
assert_eq!(mixed_boundaries.to_array(), [0, 255, 128]);
}
#[test]
fn test_munsell_color_new_chromatic() {
let color = MunsellColor::new_chromatic("5R".to_string(), 4.0, 14.0);
assert_eq!(color.notation, "5R 4.0/14.0");
assert_eq!(color.hue, Some("5R".to_string()));
assert_eq!(color.value, 4.0);
assert_eq!(color.chroma, Some(14.0));
assert!(color.is_chromatic());
assert!(!color.is_neutral());
}
#[test]
fn test_munsell_color_new_neutral() {
let gray = MunsellColor::new_neutral(5.6);
assert_eq!(gray.notation, "N 5.6/");
assert_eq!(gray.hue, None);
assert_eq!(gray.value, 5.6);
assert_eq!(gray.chroma, None);
assert!(gray.is_neutral());
assert!(!gray.is_chromatic());
let black = MunsellColor::new_neutral(0.0);
assert_eq!(black.notation, "N 0.0");
}
#[test]
fn test_munsell_color_from_notation_chromatic() {
let color = MunsellColor::from_notation("5R 4.0/14.0").unwrap();
assert_eq!(color.hue, Some("5R".to_string()));
assert_eq!(color.value, 4.0);
assert_eq!(color.chroma, Some(14.0));
assert_eq!(color.notation, "5R 4.0/14.0");
let color2 = MunsellColor::from_notation("2.5YR 6.5/8.5").unwrap();
assert_eq!(color2.hue, Some("2.5YR".to_string()));
assert_eq!(color2.value, 6.5);
assert_eq!(color2.chroma, Some(8.5));
}
#[test]
fn test_munsell_color_from_notation_neutral() {
let gray = MunsellColor::from_notation("N 5.6/").unwrap();
assert_eq!(gray.hue, None);
assert_eq!(gray.value, 5.6);
assert_eq!(gray.chroma, None);
assert!(gray.is_neutral());
let gray2 = MunsellColor::from_notation("N 3.2").unwrap();
assert_eq!(gray2.value, 3.2);
assert!(gray2.is_neutral());
let black = MunsellColor::from_notation("N 0.0").unwrap();
assert_eq!(black.value, 0.0);
}
#[test]
fn test_munsell_color_from_notation_invalid() {
assert!(MunsellColor::from_notation("").is_err());
assert!(MunsellColor::from_notation("5X 4.0/14.0").is_err());
assert!(MunsellColor::from_notation("5R 4.0 14.0").is_err());
assert!(MunsellColor::from_notation("5R 11.0/14.0").is_err());
assert!(MunsellColor::from_notation("5R -1.0/14.0").is_err());
assert!(MunsellColor::from_notation("5R 4.0/-1.0").is_err());
assert!(MunsellColor::from_notation("N 11.0/").is_err());
assert!(MunsellColor::from_notation("5R 4.0/14.0 extra").is_err());
assert!(MunsellColor::from_notation("5R").is_err());
assert!(MunsellColor::from_notation("5R 4.0").is_err());
}
#[test]
fn test_munsell_color_hue_family() {
let red = MunsellColor::new_chromatic("5R".to_string(), 4.0, 14.0);
assert_eq!(red.hue_family(), Some("R".to_string()));
let yellow_red = MunsellColor::new_chromatic("2.5YR".to_string(), 6.0, 8.0);
assert_eq!(yellow_red.hue_family(), Some("YR".to_string()));
let blue_green = MunsellColor::new_chromatic("7.5BG".to_string(), 3.0, 12.0);
assert_eq!(blue_green.hue_family(), Some("BG".to_string()));
let neutral = MunsellColor::new_neutral(5.0);
assert_eq!(neutral.hue_family(), None);
}
#[test]
fn test_munsell_color_display() {
let color = MunsellColor::new_chromatic("5R".to_string(), 4.0, 14.0);
assert_eq!(format!("{}", color), "5R 4.0/14.0");
let neutral = MunsellColor::new_neutral(5.6);
assert_eq!(format!("{}", neutral), "N 5.6/");
}
#[test]
fn test_munsell_color_all_hue_families() {
let hue_families = ["R", "YR", "Y", "GY", "G", "BG", "B", "PB", "P", "RP"];
for family in &hue_families {
let hue = format!("5{}", family);
let color = MunsellColor::from_notation(&format!("{} 5.0/10.0", hue)).unwrap();
assert_eq!(color.hue_family(), Some(family.to_string()));
assert!(color.is_chromatic());
}
}
#[test]
fn test_munsell_color_edge_case_values() {
let min_color = MunsellColor::from_notation("5R 0.0/0.0").unwrap();
assert_eq!(min_color.value, 0.0);
assert_eq!(min_color.chroma, Some(0.0));
let max_color = MunsellColor::from_notation("10R 10.0/50.0").unwrap();
assert_eq!(max_color.value, 10.0);
assert_eq!(max_color.chroma, Some(50.0));
let decimal_hue = MunsellColor::from_notation("2.5YR 6.5/8.5").unwrap();
assert_eq!(decimal_hue.hue, Some("2.5YR".to_string()));
}
#[test]
fn test_iscc_nbs_name_basic() {
let name = IsccNbsName::new(
1,
"vivid pink".to_string(),
"pink".to_string(),
Some("vivid".to_string()),
"pink".to_string(),
);
assert_eq!(name.color_number, 1);
assert_eq!(name.descriptor, "vivid pink");
assert_eq!(name.color_name, "pink");
assert_eq!(name.modifier, Some("vivid".to_string()));
assert_eq!(name.revised_name, "vivid pink");
assert_eq!(name.shade, "pink");
}
#[test]
fn test_iscc_nbs_name_no_modifier() {
let white = IsccNbsName::new(
263,
"white".to_string(),
"white".to_string(),
None,
"white".to_string(),
);
assert_eq!(white.modifier, None);
assert_eq!(white.revised_name, "white");
assert_eq!(white.shade, "white");
}
#[test]
fn test_iscc_nbs_name_ish_white_transformation() {
let pinkish_white = IsccNbsName::new(
5,
"pinkish white".to_string(),
"pink".to_string(),
Some("-ish white".to_string()),
"pink".to_string(),
);
assert_eq!(pinkish_white.revised_name, "pinkishish white");
assert_eq!(pinkish_white.shade, "white");
}
#[test]
fn test_iscc_nbs_name_ish_gray_transformation() {
let bluish_gray = IsccNbsName::new(
200,
"bluish gray".to_string(),
"blue".to_string(),
Some("-ish gray".to_string()),
"blue".to_string(),
);
assert_eq!(bluish_gray.revised_name, "blueishish gray");
assert_eq!(bluish_gray.shade, "gray");
}
#[test]
fn test_iscc_nbs_name_dark_ish_transformation() {
let dark_greenish_gray = IsccNbsName::new(
150,
"dark greenish gray".to_string(),
"green".to_string(),
Some("dark -ish gray".to_string()),
"green".to_string(),
);
assert_eq!(dark_greenish_gray.revised_name, "dark greenishish gray");
assert_eq!(dark_greenish_gray.shade, "gray");
}
#[test]
fn test_iscc_nbs_name_red_ish_special_case() {
let reddish_name = IsccNbsName::new(
50,
"reddish brown".to_string(),
"red".to_string(),
Some("-ish brown".to_string()),
"red".to_string(),
);
assert_eq!(reddish_name.revised_name, "-ish brown red");
assert_eq!(reddish_name.shade, "red");
}
#[test]
fn test_iscc_nbs_name_olive_special_case() {
let olive_name = IsccNbsName::new(
100,
"olive gray".to_string(),
"olive".to_string(),
Some("-ish gray".to_string()),
"olive".to_string(),
);
assert_eq!(olive_name.revised_name, "oliveish gray");
}
#[test]
fn test_iscc_nbs_name_display() {
let name = IsccNbsName::new(
1,
"vivid pink".to_string(),
"pink".to_string(),
Some("vivid".to_string()),
"pink".to_string(),
);
assert_eq!(format!("{}", name), "vivid pink");
}
#[test]
fn test_munsell_point_new() {
let point = MunsellPoint::new(
"5R".to_string(),
"10R".to_string(),
14.0,
6.0,
false,
);
assert_eq!(point.hue1, "5R");
assert_eq!(point.hue2, "10R");
assert_eq!(point.chroma, 14.0);
assert_eq!(point.value, 6.0);
assert!(!point.is_open_chroma);
}
#[test]
fn test_munsell_point_parse_chroma_normal() {
let (chroma, open) = MunsellPoint::parse_chroma("12.5");
assert_eq!(chroma, 12.5);
assert!(!open);
let (chroma, open) = MunsellPoint::parse_chroma("0.0");
assert_eq!(chroma, 0.0);
assert!(!open);
let (chroma, open) = MunsellPoint::parse_chroma("25.7");
assert_eq!(chroma, 25.7);
assert!(!open);
}
#[test]
fn test_munsell_point_parse_chroma_open_ended() {
let (chroma, open) = MunsellPoint::parse_chroma(">15");
assert_eq!(chroma, 15.0);
assert!(open);
let (chroma, open) = MunsellPoint::parse_chroma(">20");
assert_eq!(chroma, 20.0);
assert!(open);
}
#[test]
fn test_munsell_point_parse_chroma_invalid() {
let (chroma, open) = MunsellPoint::parse_chroma("invalid");
assert_eq!(chroma, 0.0);
assert!(!open);
let (chroma, open) = MunsellPoint::parse_chroma(">invalid");
assert_eq!(chroma, 15.0);
assert!(open);
}
#[test]
fn test_iscc_nbs_polygon_new() {
let points = vec![
MunsellPoint::new("5R".to_string(), "10R".to_string(), 14.0, 4.0, false),
MunsellPoint::new("10R".to_string(), "5YR".to_string(), 16.0, 5.0, false),
MunsellPoint::new("5YR".to_string(), "5R".to_string(), 12.0, 6.0, false),
];
let polygon = IsccNbsPolygon::new(
1,
"vivid red".to_string(),
"red".to_string(),
Some("vivid".to_string()),
"red".to_string(),
points.clone(),
);
assert_eq!(polygon.color_number, 1);
assert_eq!(polygon.descriptor, "vivid red");
assert_eq!(polygon.color_name, "red");
assert_eq!(polygon.modifier, Some("vivid".to_string()));
assert_eq!(polygon.revised_color, "red");
assert_eq!(polygon.points.len(), 3);
assert_eq!(polygon.points, points);
}
#[test]
fn test_iscc_nbs_polygon_contains_neutral_point() {
let points = vec![
MunsellPoint::new("N".to_string(), "N".to_string(), 0.5, 4.0, false),
MunsellPoint::new("N".to_string(), "N".to_string(), 0.8, 6.0, false),
];
let polygon = IsccNbsPolygon::new(
200,
"gray".to_string(),
"gray".to_string(),
None,
"gray".to_string(),
points,
);
let neutral_color = MunsellColor::new_neutral(5.0);
let result = polygon.contains_point(&neutral_color);
assert!(result == true || result == false);
}
#[test]
fn test_hue_format_validation_through_parsing() {
let valid_hues = ["5R", "2.5YR", "10G", "0.5PB", "7.5RP", "1.0B", "9.9Y"];
for hue in &valid_hues {
let notation = format!("{} 5.0/10.0", hue);
let result = MunsellColor::from_notation(¬ation);
assert!(result.is_ok(), "Valid hue format '{}' should parse successfully", hue);
}
let families = ["R", "YR", "Y", "GY", "G", "BG", "B", "PB", "P", "RP"];
for family in &families {
let hue = format!("5{}", family);
let notation = format!("{} 5.0/10.0", hue);
let result = MunsellColor::from_notation(¬ation);
assert!(result.is_ok(), "Hue family '{}' should be valid", family);
}
}
#[test]
fn test_hue_format_validation_invalid_through_parsing() {
let invalid_hues = [
"X", "5", "R", "5RX", "-5R", "11R", "aR", ];
for hue in &invalid_hues {
let notation = format!("{} 5.0/10.0", hue);
let result = MunsellColor::from_notation(¬ation);
assert!(result.is_err(), "Invalid hue format '{}' should fail to parse", hue);
}
}
#[test]
fn test_polygon_point_containment_logic() {
let points = vec![
MunsellPoint::new("4R".to_string(), "6R".to_string(), 10.0, 4.0, false),
MunsellPoint::new("6R".to_string(), "4R".to_string(), 15.0, 6.0, false),
MunsellPoint::new("4R".to_string(), "6R".to_string(), 12.0, 5.0, false),
];
let polygon = IsccNbsPolygon::new(
1,
"test red".to_string(),
"red".to_string(),
None,
"red".to_string(),
points,
);
let red_color = MunsellColor::new_chromatic("5R".to_string(), 5.0, 12.0);
let result = polygon.contains_point(&red_color);
assert!(result == true || result == false);
let blue_color = MunsellColor::new_chromatic("5B".to_string(), 5.0, 12.0);
let result2 = polygon.contains_point(&blue_color);
assert!(result2 == true || result2 == false);
}
#[test]
fn test_munsell_error_types() {
let error = MunsellColor::from_notation("invalid notation").unwrap_err();
match error {
MunsellError::InvalidNotation { notation, reason } => {
assert_eq!(notation, "invalid notation");
assert!(!reason.is_empty());
}
_ => panic!("Expected InvalidNotation error"),
}
let error = MunsellColor::from_notation("5R 15.0/10.0").unwrap_err();
match error {
MunsellError::InvalidNotation { notation, reason } => {
assert_eq!(notation, "5R 15.0/10.0");
assert!(reason.contains("Value must be between 0.0 and 10.0"));
}
_ => panic!("Expected InvalidNotation error for value out of range"),
}
}
#[test]
fn test_rgb_color_serialization() {
let color = RgbColor::new(255, 128, 64);
let json = serde_json::to_string(&color).unwrap();
assert!(json.contains("255"));
assert!(json.contains("128"));
assert!(json.contains("64"));
let deserialized: RgbColor = serde_json::from_str(&json).unwrap();
assert_eq!(deserialized, color);
}
#[test]
fn test_munsell_color_serialization() {
let color = MunsellColor::new_chromatic("5R".to_string(), 4.0, 14.0);
let json = serde_json::to_string(&color).unwrap();
assert!(json.contains("5R 4.0/14.0"));
assert!(json.contains("5R"));
let deserialized: MunsellColor = serde_json::from_str(&json).unwrap();
assert_eq!(deserialized, color);
}
#[test]
fn test_iscc_nbs_name_serialization() {
let name = IsccNbsName::new(
1,
"vivid pink".to_string(),
"pink".to_string(),
Some("vivid".to_string()),
"pink".to_string(),
);
let json = serde_json::to_string(&name).unwrap();
assert!(json.contains("vivid pink"));
assert!(json.contains("pink"));
let deserialized: IsccNbsName = serde_json::from_str(&json).unwrap();
assert_eq!(deserialized, name);
}
}