vortex_array/compute/conformance/
mask.rs1use vortex_error::VortexExpect;
5use vortex_mask::Mask;
6
7use crate::Array;
8use crate::arrays::BoolArray;
9use crate::compute::mask;
10
11pub fn test_mask_conformance(array: &dyn Array) {
14 let len = array.len();
15
16 if len > 0 {
17 test_heterogenous_mask(array);
18 test_empty_mask(array);
19 test_full_mask(array);
20 test_alternating_mask(array);
21 test_sparse_mask(array);
22 test_single_element_mask(array);
23 }
24
25 if len >= 5 {
26 test_double_mask(array);
27 }
28
29 if len > 0 {
30 test_nullable_mask_input(array);
31 }
32}
33
34fn test_heterogenous_mask(array: &dyn Array) {
36 let len = array.len();
37
38 let mask_pattern: Vec<bool> = (0..len).map(|i| i % 3 != 1).collect();
40 let mask_array = Mask::from_iter(mask_pattern.clone());
41
42 let masked = mask(array, &mask_array).vortex_expect("mask should succeed in conformance test");
43 assert_eq!(masked.len(), array.len());
44
45 for (i, &masked_out) in mask_pattern.iter().enumerate() {
47 if masked_out {
48 assert!(
49 !masked
50 .is_valid(i)
51 .vortex_expect("is_valid should succeed in conformance test")
52 );
53 } else {
54 assert_eq!(
55 masked
56 .scalar_at(i)
57 .vortex_expect("scalar_at should succeed in conformance test"),
58 array
59 .scalar_at(i)
60 .vortex_expect("scalar_at should succeed in conformance test")
61 .into_nullable()
62 );
63 }
64 }
65}
66
67fn test_empty_mask(array: &dyn Array) {
69 let len = array.len();
70 let all_unmasked = vec![false; len];
71 let mask_array = Mask::from_iter(all_unmasked);
72
73 let masked = mask(array, &mask_array).vortex_expect("mask should succeed in conformance test");
74 assert_eq!(masked.len(), array.len());
75
76 for i in 0..len {
78 assert_eq!(
79 masked
80 .scalar_at(i)
81 .vortex_expect("scalar_at should succeed in conformance test"),
82 array
83 .scalar_at(i)
84 .vortex_expect("scalar_at should succeed in conformance test")
85 .into_nullable()
86 );
87 }
88}
89
90fn test_full_mask(array: &dyn Array) {
92 let len = array.len();
93 let all_masked = vec![true; len];
94 let mask_array = Mask::from_iter(all_masked);
95
96 let masked = mask(array, &mask_array).vortex_expect("mask should succeed in conformance test");
97 assert_eq!(masked.len(), array.len());
98
99 for i in 0..len {
101 assert!(
102 !masked
103 .is_valid(i)
104 .vortex_expect("is_valid should succeed in conformance test")
105 );
106 }
107}
108
109fn test_alternating_mask(array: &dyn Array) {
111 let len = array.len();
112 let pattern: Vec<bool> = (0..len).map(|i| i % 2 == 0).collect();
113 let mask_array = Mask::from_iter(pattern);
114
115 let masked = mask(array, &mask_array).vortex_expect("mask should succeed in conformance test");
116 assert_eq!(masked.len(), array.len());
117
118 for i in 0..len {
119 if i % 2 == 0 {
120 assert!(
121 !masked
122 .is_valid(i)
123 .vortex_expect("is_valid should succeed in conformance test")
124 );
125 } else {
126 assert_eq!(
127 masked
128 .scalar_at(i)
129 .vortex_expect("scalar_at should succeed in conformance test"),
130 array
131 .scalar_at(i)
132 .vortex_expect("scalar_at should succeed in conformance test")
133 .into_nullable()
134 );
135 }
136 }
137}
138
139fn test_sparse_mask(array: &dyn Array) {
141 let len = array.len();
142 if len < 10 {
143 return; }
145
146 let pattern: Vec<bool> = (0..len).map(|i| i % 10 == 0).collect();
148 let mask_array = Mask::from_iter(pattern.clone());
149
150 let masked = mask(array, &mask_array).vortex_expect("mask should succeed in conformance test");
151 assert_eq!(masked.len(), array.len());
152
153 let valid_count = (0..len)
155 .filter(|&i| {
156 masked
157 .is_valid(i)
158 .vortex_expect("is_valid should succeed in conformance test")
159 })
160 .count();
161
162 let expected_invalid_count = (0..len)
166 .filter(|&i| {
167 pattern[i]
168 || !array
169 .is_valid(i)
170 .vortex_expect("is_valid should succeed in conformance test")
171 })
172 .count();
173
174 assert_eq!(valid_count, len - expected_invalid_count);
175}
176
177fn test_single_element_mask(array: &dyn Array) {
179 let len = array.len();
180
181 let mut pattern = vec![false; len];
183 pattern[0] = true;
184 let mask_array = Mask::from_iter(pattern);
185
186 let masked = mask(array, &mask_array).vortex_expect("mask should succeed in conformance test");
187 assert!(
188 !masked
189 .is_valid(0)
190 .vortex_expect("is_valid should succeed in conformance test")
191 );
192
193 for i in 1..len {
194 assert_eq!(
195 masked
196 .scalar_at(i)
197 .vortex_expect("scalar_at should succeed in conformance test"),
198 array
199 .scalar_at(i)
200 .vortex_expect("scalar_at should succeed in conformance test")
201 .into_nullable()
202 );
203 }
204}
205
206fn test_double_mask(array: &dyn Array) {
208 let len = array.len();
209
210 let mask1_pattern: Vec<bool> = (0..len).map(|i| i % 3 == 0).collect();
212 let mask2_pattern: Vec<bool> = (0..len).map(|i| i % 2 == 0).collect();
213
214 let mask1 = Mask::from_iter(mask1_pattern.clone());
215 let mask2 = Mask::from_iter(mask2_pattern.clone());
216
217 let first_masked = mask(array, &mask1).vortex_expect("mask should succeed in conformance test");
218 let double_masked =
219 mask(&first_masked, &mask2).vortex_expect("mask should succeed in conformance test");
220
221 for i in 0..len {
223 if mask1_pattern[i] || mask2_pattern[i] {
224 assert!(
225 !double_masked
226 .is_valid(i)
227 .vortex_expect("is_valid should succeed in conformance test")
228 );
229 } else {
230 assert_eq!(
231 double_masked
232 .scalar_at(i)
233 .vortex_expect("scalar_at should succeed in conformance test"),
234 array
235 .scalar_at(i)
236 .vortex_expect("scalar_at should succeed in conformance test")
237 .into_nullable()
238 );
239 }
240 }
241}
242
243fn test_nullable_mask_input(array: &dyn Array) {
245 let len = array.len();
246 if len < 3 {
247 return; }
249
250 let bool_values: Vec<bool> = (0..len).map(|i| i % 2 == 0).collect();
252 let validity_values: Vec<bool> = (0..len).map(|i| i % 3 != 0).collect();
253
254 let bool_array = BoolArray::from_iter(bool_values.clone());
255 let validity = crate::validity::Validity::from_iter(validity_values.clone());
256 let nullable_mask = BoolArray::new(bool_array.to_bit_buffer(), validity);
257
258 let mask_array = nullable_mask.to_mask_fill_null_false();
259 let masked = mask(array, &mask_array).vortex_expect("mask should succeed in conformance test");
260
261 for i in 0..len {
263 if bool_values[i] && validity_values[i] {
264 assert!(
265 !masked
266 .is_valid(i)
267 .vortex_expect("is_valid should succeed in conformance test")
268 );
269 } else {
270 assert_eq!(
271 masked
272 .scalar_at(i)
273 .vortex_expect("scalar_at should succeed in conformance test"),
274 array
275 .scalar_at(i)
276 .vortex_expect("scalar_at should succeed in conformance test")
277 .into_nullable()
278 );
279 }
280 }
281}