use perceive_color::Color;
use perceive_cvd::types::{CvdType, Severity};
use perceive_cvd::{simulate, simulate_fast};
fn assert_srgb8_close(actual: Color, expected: (u8, u8, u8), tolerance: i16, label: &str) {
let (ar, ag, ab) = actual.to_srgb8();
let (er, eg, eb) = expected;
let dr = (i16::from(ar) - i16::from(er)).abs();
let dg = (i16::from(ag) - i16::from(eg)).abs();
let db = (i16::from(ab) - i16::from(eb)).abs();
assert!(
dr <= tolerance && dg <= tolerance && db <= tolerance,
"{label}: expected ({er}, {eg}, {eb}), got ({ar}, {ag}, {ab}), \
delta=({dr}, {dg}, {db}), tolerance={tolerance}"
);
}
#[test]
fn brettel_protan_red() {
let sim = simulate(
Color::from_srgb8(255, 0, 0),
CvdType::Protan,
Severity::FULL,
);
assert_srgb8_close(sim, (108, 92, 12), 2, "brettel protan red");
}
#[test]
fn brettel_protan_green() {
let sim = simulate(
Color::from_srgb8(0, 255, 0),
CvdType::Protan,
Severity::FULL,
);
assert_srgb8_close(sim, (255, 237, 0), 2, "brettel protan green");
}
#[test]
fn brettel_protan_blue() {
let sim = simulate(
Color::from_srgb8(0, 0, 255),
CvdType::Protan,
Severity::FULL,
);
assert_srgb8_close(sim, (0, 56, 255), 2, "brettel protan blue");
}
#[test]
fn brettel_protan_orange() {
let sim = simulate(
Color::from_srgb8(255, 128, 0),
CvdType::Protan,
Severity::FULL,
);
assert_srgb8_close(sim, (171, 147, 9), 2, "brettel protan orange");
}
#[test]
fn brettel_protan_skin() {
let sim = simulate(
Color::from_srgb8(200, 150, 120),
CvdType::Protan,
Severity::FULL,
);
assert_srgb8_close(sim, (167, 155, 120), 2, "brettel protan skin");
}
#[test]
fn brettel_deutan_red() {
let sim = simulate(
Color::from_srgb8(255, 0, 0),
CvdType::Deutan,
Severity::FULL,
);
assert_srgb8_close(sim, (164, 139, 0), 2, "brettel deutan red");
}
#[test]
fn brettel_deutan_green() {
let sim = simulate(
Color::from_srgb8(0, 255, 0),
CvdType::Deutan,
Severity::FULL,
);
assert_srgb8_close(sim, (241, 209, 46), 2, "brettel deutan green");
}
#[test]
fn brettel_deutan_blue() {
let sim = simulate(
Color::from_srgb8(0, 0, 255),
CvdType::Deutan,
Severity::FULL,
);
assert_srgb8_close(sim, (0, 87, 254), 2, "brettel deutan blue");
}
#[test]
fn brettel_deutan_orange() {
let sim = simulate(
Color::from_srgb8(255, 128, 0),
CvdType::Deutan,
Severity::FULL,
);
assert_srgb8_close(sim, (198, 169, 0), 2, "brettel deutan orange");
}
#[test]
fn brettel_deutan_skin() {
let sim = simulate(
Color::from_srgb8(200, 150, 120),
CvdType::Deutan,
Severity::FULL,
);
assert_srgb8_close(sim, (176, 162, 119), 2, "brettel deutan skin");
}
#[test]
fn brettel_tritan_red() {
let sim = simulate(
Color::from_srgb8(255, 0, 0),
CvdType::Tritan,
Severity::FULL,
);
assert_srgb8_close(sim, (255, 0, 78), 2, "brettel tritan red");
}
#[test]
fn brettel_tritan_green() {
let sim = simulate(
Color::from_srgb8(0, 255, 0),
CvdType::Tritan,
Severity::FULL,
);
assert_srgb8_close(sim, (121, 233, 255), 2, "brettel tritan green");
}
#[test]
fn brettel_tritan_blue() {
let sim = simulate(
Color::from_srgb8(0, 0, 255),
CvdType::Tritan,
Severity::FULL,
);
assert_srgb8_close(sim, (0, 98, 136), 2, "brettel tritan blue");
}
#[test]
fn brettel_tritan_yellow() {
let sim = simulate(
Color::from_srgb8(255, 255, 0),
CvdType::Tritan,
Severity::FULL,
);
assert_srgb8_close(sim, (255, 238, 241), 2, "brettel tritan yellow");
}
#[test]
fn brettel_tritan_skin() {
let sim = simulate(
Color::from_srgb8(200, 150, 120),
CvdType::Tritan,
Severity::FULL,
);
assert_srgb8_close(sim, (203, 145, 151), 2, "brettel tritan skin");
}
#[test]
fn vienot_protan_red() {
let sim = simulate_fast(Color::from_srgb8(255, 0, 0), CvdType::Protan);
assert_srgb8_close(sim, (94, 94, 13), 2, "vienot protan red");
}
#[test]
fn vienot_protan_green() {
let sim = simulate_fast(Color::from_srgb8(0, 255, 0), CvdType::Protan);
assert_srgb8_close(sim, (242, 242, 0), 2, "vienot protan green");
}
#[test]
fn vienot_protan_blue() {
let sim = simulate_fast(Color::from_srgb8(0, 0, 255), CvdType::Protan);
assert_srgb8_close(sim, (0, 0, 255), 2, "vienot protan blue");
}
#[test]
fn vienot_protan_skin() {
let sim = simulate_fast(Color::from_srgb8(200, 150, 120), CvdType::Protan);
assert_srgb8_close(sim, (157, 157, 120), 2, "vienot protan skin");
}
#[test]
fn vienot_deutan_red() {
let sim = simulate_fast(Color::from_srgb8(255, 0, 0), CvdType::Deutan);
assert_srgb8_close(sim, (147, 147, 0), 2, "vienot deutan red");
}
#[test]
fn vienot_deutan_green() {
let sim = simulate_fast(Color::from_srgb8(0, 255, 0), CvdType::Deutan);
assert_srgb8_close(sim, (219, 219, 41), 2, "vienot deutan green");
}
#[test]
fn vienot_deutan_skin() {
let sim = simulate_fast(Color::from_srgb8(200, 150, 120), CvdType::Deutan);
assert_srgb8_close(sim, (167, 167, 118), 2, "vienot deutan skin");
}
#[test]
fn vienot_tritan_green() {
let sim = simulate_fast(Color::from_srgb8(0, 255, 0), CvdType::Tritan);
assert_srgb8_close(sim, (106, 239, 239), 2, "vienot tritan green");
}
#[test]
fn vienot_tritan_blue() {
let sim = simulate_fast(Color::from_srgb8(0, 0, 255), CvdType::Tritan);
assert_srgb8_close(sim, (0, 105, 105), 2, "vienot tritan blue");
}
#[test]
fn vienot_tritan_skin() {
let sim = simulate_fast(Color::from_srgb8(200, 150, 120), CvdType::Tritan);
assert_srgb8_close(sim, (203, 146, 146), 2, "vienot tritan skin");
}
#[test]
fn cross_model_protan_agreement() {
let colors = [
Color::from_srgb8(255, 128, 0),
Color::from_srgb8(200, 150, 120),
Color::from_srgb8(100, 200, 50),
];
for c in &colors {
let brettel = simulate(*c, CvdType::Protan, Severity::FULL);
let vienot = simulate_fast(*c, CvdType::Protan);
let (br, bg, bb) = brettel.to_srgb8();
let (vr, vg, vb) = vienot.to_srgb8();
let dr = (i16::from(br) - i16::from(vr)).abs();
let dg = (i16::from(bg) - i16::from(vg)).abs();
let db = (i16::from(bb) - i16::from(vb)).abs();
assert!(
dr <= 30 && dg <= 30 && db <= 30,
"protan cross-model divergence too large: \
brettel=({br},{bg},{bb}), vienot=({vr},{vg},{vb})"
);
}
}
#[test]
fn cross_model_deutan_agreement() {
let colors = [
Color::from_srgb8(255, 128, 0),
Color::from_srgb8(200, 150, 120),
Color::from_srgb8(100, 200, 50),
];
for c in &colors {
let brettel = simulate(*c, CvdType::Deutan, Severity::FULL);
let vienot = simulate_fast(*c, CvdType::Deutan);
let (br, bg, bb) = brettel.to_srgb8();
let (vr, vg, vb) = vienot.to_srgb8();
let dr = (i16::from(br) - i16::from(vr)).abs();
let dg = (i16::from(bg) - i16::from(vg)).abs();
let db = (i16::from(bb) - i16::from(vb)).abs();
assert!(
dr <= 30 && dg <= 30 && db <= 30,
"deutan cross-model divergence too large: \
brettel=({br},{bg},{bb}), vienot=({vr},{vg},{vb})"
);
}
}
#[test]
fn cross_model_tritan_agreement() {
let colors = [
Color::from_srgb8(200, 150, 120),
Color::from_srgb8(100, 200, 50),
];
for c in &colors {
let brettel = simulate(*c, CvdType::Tritan, Severity::FULL);
let vienot = simulate_fast(*c, CvdType::Tritan);
let (br, bg, bb) = brettel.to_srgb8();
let (vr, vg, vb) = vienot.to_srgb8();
let dr = (i16::from(br) - i16::from(vr)).abs();
let dg = (i16::from(bg) - i16::from(vg)).abs();
let db = (i16::from(bb) - i16::from(vb)).abs();
assert!(
dr <= 30 && dg <= 30 && db <= 30,
"tritan cross-model divergence too large: \
brettel=({br},{bg},{bb}), vienot=({vr},{vg},{vb})"
);
}
}
#[test]
fn brettel_protan_half_plane_differentiation() {
let green = Color::from_srgb8(0, 255, 0);
let blue = Color::from_srgb8(0, 0, 255);
let sim_green = simulate(green, CvdType::Protan, Severity::FULL);
let sim_blue = simulate(blue, CvdType::Protan, Severity::FULL);
let (gr, gg, gb) = sim_green.to_srgb8();
let (br, bg, bb) = sim_blue.to_srgb8();
let diff = (i16::from(gr) - i16::from(br)).abs()
+ (i16::from(gg) - i16::from(bg)).abs()
+ (i16::from(gb) - i16::from(bb)).abs();
assert!(
diff > 100,
"half-plane differentiation too small: green=({gr},{gg},{gb}), blue=({br},{bg},{bb})"
);
}
#[test]
fn brettel_tritan_half_plane_differentiation() {
let red = Color::from_srgb8(255, 0, 0);
let green = Color::from_srgb8(0, 255, 0);
let sim_red = simulate(red, CvdType::Tritan, Severity::FULL);
let sim_green = simulate(green, CvdType::Tritan, Severity::FULL);
let (rr, rg, rb) = sim_red.to_srgb8();
let (gr, gg, gb) = sim_green.to_srgb8();
let diff = (i16::from(rr) - i16::from(gr)).abs()
+ (i16::from(rg) - i16::from(gg)).abs()
+ (i16::from(rb) - i16::from(gb)).abs();
assert!(
diff > 100,
"half-plane differentiation too small: red=({rr},{rg},{rb}), green=({gr},{gg},{gb})"
);
}
#[test]
fn brettel_deutan_half_plane_differentiation() {
let blue = Color::from_srgb8(0, 0, 255);
let red = Color::from_srgb8(255, 0, 0);
let sim_blue = simulate(blue, CvdType::Deutan, Severity::FULL);
let sim_red = simulate(red, CvdType::Deutan, Severity::FULL);
let (br, bg, bb) = sim_blue.to_srgb8();
let (rr, rg, rb) = sim_red.to_srgb8();
let diff = (i16::from(br) - i16::from(rr)).abs()
+ (i16::from(bg) - i16::from(rg)).abs()
+ (i16::from(bb) - i16::from(rb)).abs();
assert!(
diff > 100,
"half-plane differentiation too small: blue=({br},{bg},{bb}), red=({rr},{rg},{rb})"
);
}