cvkg_render_gpu/types/
golden.rs1#[derive(Clone, Debug)]
7pub struct GoldenImageConfig {
8 pub pixel_tolerance: u8,
10 pub max_diff_percent: f32,
12 pub update_on_mismatch: bool,
14}
15
16impl Default for GoldenImageConfig {
17 fn default() -> Self {
18 Self {
19 pixel_tolerance: 3,
20 max_diff_percent: 0.1,
21 update_on_mismatch: false,
22 }
23 }
24}
25
26#[derive(Clone, Debug)]
28pub struct GoldenImageResult {
29 pub passed: bool,
31 pub diff_percent: f32,
33 pub diff_count: u64,
35 pub total_pixels: u64,
37}
38
39pub struct GoldenImageComparator;
41
42impl GoldenImageComparator {
43 pub fn compare(
50 actual: &[u8],
51 expected: &[u8],
52 config: &GoldenImageConfig,
53 ) -> GoldenImageResult {
54 if actual.len() != expected.len() {
55 return GoldenImageResult {
56 passed: false,
57 diff_percent: 100.0,
58 diff_count: actual.len() as u64 / 4,
59 total_pixels: actual.len() as u64 / 4,
60 };
61 }
62
63 let total_pixels = (actual.len() / 4) as u64;
64 if total_pixels == 0 {
65 return GoldenImageResult {
66 passed: true,
67 diff_percent: 0.0,
68 diff_count: 0,
69 total_pixels: 0,
70 };
71 }
72
73 let mut diff_count = 0u64;
74 for i in 0..(actual.len() / 4) {
75 let base = i * 4;
76 let mut pixel_differs = false;
77 for ch in 0..3 {
78 if actual[base + ch].abs_diff(expected[base + ch]) > config.pixel_tolerance {
80 pixel_differs = true;
81 break;
82 }
83 }
84 if pixel_differs {
85 diff_count += 1;
86 }
87 }
88
89 let diff_percent = (diff_count as f32 / total_pixels as f32) * 100.0;
90 GoldenImageResult {
91 passed: diff_percent <= config.max_diff_percent,
92 diff_percent,
93 diff_count,
94 total_pixels,
95 }
96 }
97}
98
99#[cfg(test)]
100mod tests {
101 use super::*;
102
103 #[test]
104 fn golden_image_identical() {
105 let pixels = vec![255u8; 400]; let config = GoldenImageConfig::default();
107 let result = GoldenImageComparator::compare(&pixels, &pixels, &config);
108 assert!(result.passed);
109 assert_eq!(result.diff_percent, 0.0);
110 }
111
112 #[test]
113 fn golden_image_detects_difference() {
114 let mut actual = vec![255u8; 400];
115 let expected = vec![255u8; 400];
116 actual[0] = 0;
118 let config = GoldenImageConfig::default();
119 let result = GoldenImageComparator::compare(&actual, &expected, &config);
120 assert!(!result.passed);
121 assert!(result.diff_percent > 0.0);
122 }
123
124 #[test]
125 fn golden_image_tolerance() {
126 let mut actual = vec![255u8; 400];
127 let expected = vec![255u8; 400];
128 actual[0] = 253; let config = GoldenImageConfig::default();
131 let result = GoldenImageComparator::compare(&actual, &expected, &config);
132 assert!(result.passed);
133 }
134
135 #[test]
136 fn golden_image_different_sizes() {
137 let actual = vec![255u8; 400];
138 let expected = vec![255u8; 800];
139 let config = GoldenImageConfig::default();
140 let result = GoldenImageComparator::compare(&actual, &expected, &config);
141 assert!(!result.passed);
142 assert_eq!(result.diff_percent, 100.0);
143 }
144
145 #[test]
146 fn golden_image_empty() {
147 let config = GoldenImageConfig::default();
148 let result = GoldenImageComparator::compare(&[], &[], &config);
149 assert!(result.passed);
150 }
151}