Skip to content

Commit ab24047

Browse files
committed
add tests for FixedSizeList vectors
Signed-off-by: Connor Tsui <[email protected]>
1 parent 9ded5bc commit ab24047

File tree

2 files changed

+346
-0
lines changed

2 files changed

+346
-0
lines changed

vortex-vector/src/fixed_size_list/vector.rs

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,3 +179,127 @@ impl VectorOps for FixedSizeListVector {
179179
}
180180
}
181181
}
182+
183+
#[cfg(test)]
184+
mod tests {
185+
use std::sync::Arc;
186+
187+
use vortex_mask::Mask;
188+
189+
use super::*;
190+
use crate::{PVectorMut, Vector, VectorMutOps};
191+
192+
#[test]
193+
fn test_constructor_and_validation() {
194+
// Valid construction with new().
195+
let elements: Arc<Vector> = Arc::new(
196+
PVectorMut::<i32>::from_iter([1, 2, 3, 4, 5, 6])
197+
.freeze()
198+
.into(),
199+
);
200+
let validity = Mask::new_true(2);
201+
let vec = FixedSizeListVector::new(elements.clone(), 3, validity.clone());
202+
assert_eq!(vec.len(), 2);
203+
assert_eq!(vec.list_size(), 3);
204+
205+
// Valid construction with try_new().
206+
let result = FixedSizeListVector::try_new(elements.clone(), 3, validity);
207+
assert!(result.is_ok());
208+
assert_eq!(result.unwrap().len(), 2);
209+
210+
// Length mismatch error - elements length != list_size * validity length.
211+
let bad_validity = Mask::new_true(3); // Should be 2 for 6 elements with list_size=3.
212+
let result = FixedSizeListVector::try_new(elements.clone(), 3, bad_validity);
213+
assert!(result.is_err());
214+
215+
// Degenerate case (list_size = 0) with empty elements is valid.
216+
let empty_elements: Arc<Vector> = Arc::new(
217+
PVectorMut::<i32>::from_iter(Vec::<i32>::new())
218+
.freeze()
219+
.into(),
220+
);
221+
let validity = Mask::new_true(5);
222+
let result = FixedSizeListVector::try_new(empty_elements, 0, validity);
223+
assert!(result.is_ok());
224+
let vec = result.unwrap();
225+
assert_eq!(vec.len(), 5);
226+
assert_eq!(vec.list_size(), 0);
227+
228+
// Degenerate case with non-empty elements should fail.
229+
let result = FixedSizeListVector::try_new(elements, 0, Mask::new_true(1));
230+
assert!(result.is_err());
231+
232+
// Test unsafe new_unchecked in debug mode (it should still validate).
233+
let elements: Arc<Vector> =
234+
Arc::new(PVectorMut::<i32>::from_iter([1, 2, 3, 4]).freeze().into());
235+
let validity = Mask::new_true(2);
236+
let vec = unsafe { FixedSizeListVector::new_unchecked(elements, 2, validity) };
237+
assert_eq!(vec.len(), 2);
238+
assert_eq!(vec.list_size(), 2);
239+
}
240+
241+
#[test]
242+
fn test_try_into_mut_conversion() {
243+
// Create a vector that we solely own.
244+
let elements: Arc<Vector> = Arc::new(
245+
PVectorMut::<i32>::from_iter([1, 2, 3, 4, 5, 6])
246+
.freeze()
247+
.into(),
248+
);
249+
let validity = Mask::new_true(2);
250+
let vec = FixedSizeListVector::new(elements, 3, validity);
251+
252+
// Successful conversion when solely owned.
253+
let result = vec.try_into_mut();
254+
assert!(result.is_ok());
255+
let mut_vec = result.unwrap();
256+
assert_eq!(mut_vec.len(), 2);
257+
assert_eq!(mut_vec.list_size(), 3);
258+
259+
// Freeze and try again - roundtrip test.
260+
let vec = mut_vec.freeze();
261+
let result = vec.try_into_mut();
262+
assert!(result.is_ok());
263+
264+
// Test failed conversion with shared ownership.
265+
let elements: Arc<Vector> =
266+
Arc::new(PVectorMut::<i32>::from_iter([1, 2, 3, 4]).freeze().into());
267+
let validity = Mask::new_true(2);
268+
let vec = FixedSizeListVector::new(elements, 2, validity);
269+
270+
// Keep a clone to maintain shared ownership.
271+
let _shared = vec.clone();
272+
273+
let result = vec.try_into_mut();
274+
assert!(result.is_err());
275+
276+
// The error case should return the original vector.
277+
if let Err(returned_vec) = result {
278+
assert_eq!(returned_vec.len(), 2);
279+
assert_eq!(returned_vec.list_size(), 2);
280+
}
281+
}
282+
283+
#[test]
284+
fn test_accessors_and_parts() {
285+
let elements: Arc<Vector> = Arc::new(
286+
PVectorMut::<i32>::from_iter([1, 2, 3, 4, 5, 6])
287+
.freeze()
288+
.into(),
289+
);
290+
let validity = Mask::new_true(3);
291+
let vec = FixedSizeListVector::new(elements, 2, validity);
292+
293+
// Test accessors.
294+
assert_eq!(vec.len(), 3);
295+
assert_eq!(vec.list_size(), 2);
296+
assert_eq!(vec.elements().len(), 6);
297+
assert_eq!(vec.validity().true_count(), 3);
298+
299+
// Test into_parts.
300+
let (parts_elements, list_size, parts_validity) = vec.into_parts();
301+
assert_eq!(parts_elements.len(), 6);
302+
assert_eq!(list_size, 2);
303+
assert_eq!(parts_validity.true_count(), 3);
304+
}
305+
}

vortex-vector/src/fixed_size_list/vector_mut.rs

Lines changed: 222 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -327,3 +327,225 @@ impl VectorMutOps for FixedSizeListVectorMut {
327327
debug_assert_eq!(self.len, self.validity.len());
328328
}
329329
}
330+
331+
#[cfg(test)]
332+
mod tests {
333+
use std::sync::Arc;
334+
335+
use vortex_dtype::{DType, PType};
336+
use vortex_mask::{Mask, MaskMut};
337+
338+
use super::*;
339+
use crate::{PVectorMut, VectorOps};
340+
341+
#[test]
342+
fn test_core_operations() {
343+
// Test with_capacity constructor.
344+
let dtype = DType::Primitive(PType::I32, vortex_dtype::Nullability::Nullable);
345+
let mut vec = FixedSizeListVectorMut::with_capacity(&dtype, 3, 10);
346+
assert_eq!(vec.len(), 0);
347+
assert_eq!(vec.list_size(), 3);
348+
assert!(vec.capacity() >= 10);
349+
350+
// Create a vector to extend from.
351+
let elements = Arc::new(
352+
PVectorMut::<i32>::from_iter([1, 2, 3, 4, 5, 6])
353+
.freeze()
354+
.into(),
355+
);
356+
let validity = Mask::new_true(2);
357+
let immutable = FixedSizeListVector::new(elements, 3, validity);
358+
359+
// Test extend_from_vector.
360+
vec.extend_from_vector(&immutable);
361+
assert_eq!(vec.len(), 2);
362+
assert_eq!(vec.elements().len(), 6);
363+
364+
// Test append_nulls.
365+
vec.append_nulls(3);
366+
assert_eq!(vec.len(), 5);
367+
assert_eq!(vec.elements().len(), 15); // 5 lists * 3 elements each.
368+
369+
// Test freeze and accessors.
370+
let frozen = vec.freeze();
371+
assert_eq!(frozen.len(), 5);
372+
assert_eq!(frozen.list_size(), 3);
373+
assert_eq!(frozen.elements().len(), 15);
374+
}
375+
376+
#[test]
377+
fn test_split_unsplit_operations() {
378+
// Create a vector with 6 lists, each containing 2 elements.
379+
let elements = PVectorMut::<i32>::from_iter([
380+
1, 2, // List 0
381+
3, 4, // List 1
382+
5, 6, // List 2
383+
7, 8, // List 3
384+
9, 10, // List 4
385+
11, 12, // List 5
386+
]);
387+
let mut vec =
388+
FixedSizeListVectorMut::new(Box::new(elements.into()), 2, MaskMut::new_true(6));
389+
390+
// Test split at different positions.
391+
392+
// Split at position 0 (take nothing).
393+
let split = vec.split_off(0);
394+
assert_eq!(vec.len(), 0);
395+
assert_eq!(split.len(), 6);
396+
vec.unsplit(split);
397+
assert_eq!(vec.len(), 6);
398+
399+
// Split at middle position.
400+
let split = vec.split_off(3);
401+
assert_eq!(vec.len(), 3);
402+
assert_eq!(split.len(), 3);
403+
assert_eq!(vec.elements().len(), 6); // 3 lists * 2 elements.
404+
assert_eq!(split.elements().len(), 6); // 3 lists * 2 elements.
405+
406+
// Verify the correct elements are in each half.
407+
// First half should have [1,2,3,4,5,6].
408+
// Second half should have [7,8,9,10,11,12].
409+
410+
// Rejoin the parts.
411+
vec.unsplit(split);
412+
assert_eq!(vec.len(), 6);
413+
assert_eq!(vec.elements().len(), 12);
414+
415+
// Split at the end (take everything).
416+
let split = vec.split_off(6);
417+
assert_eq!(vec.len(), 6);
418+
assert_eq!(split.len(), 0);
419+
vec.unsplit(split);
420+
assert_eq!(vec.len(), 6);
421+
}
422+
423+
#[test]
424+
fn test_null_handling() {
425+
// Test nullable lists with non-null elements.
426+
let elements = PVectorMut::<i32>::from_iter([1, 2, 3, 4, 5, 6]);
427+
let validity = MaskMut::new_true(3);
428+
// We can't directly set individual validity, but we can create vectors with nulls.
429+
430+
let mut vec = FixedSizeListVectorMut::new(Box::new(elements.into()), 2, validity);
431+
432+
// Append null lists.
433+
vec.append_nulls(2);
434+
assert_eq!(vec.len(), 5);
435+
436+
// After freezing, check validity is preserved.
437+
let frozen = vec.freeze();
438+
assert_eq!(frozen.len(), 5);
439+
assert_eq!(frozen.validity().true_count(), 3); // First 3 are valid.
440+
441+
// Test non-null lists with nullable elements.
442+
let elements_with_nulls = PVectorMut::<i32>::from_iter([
443+
Some(1),
444+
None,
445+
Some(3), // First list has a null element.
446+
Some(4),
447+
Some(5),
448+
None, // Second list has a null element.
449+
]);
450+
let validity = MaskMut::new_true(2); // Both lists are valid.
451+
452+
let mut vec =
453+
FixedSizeListVectorMut::new(Box::new(elements_with_nulls.into()), 3, validity);
454+
455+
assert_eq!(vec.len(), 2);
456+
assert_eq!(vec.elements().len(), 6);
457+
458+
// Operations should preserve element nullability.
459+
let split = vec.split_off(1);
460+
assert_eq!(vec.len(), 1);
461+
assert_eq!(split.len(), 1);
462+
463+
vec.unsplit(split);
464+
assert_eq!(vec.len(), 2);
465+
}
466+
467+
#[test]
468+
fn test_edge_cases() {
469+
// Test empty vector (0 lists).
470+
let elements = PVectorMut::<i32>::from_iter(Vec::<i32>::new());
471+
let validity = MaskMut::new_true(0);
472+
let mut vec = FixedSizeListVectorMut::new(Box::new(elements.into()), 3, validity);
473+
assert_eq!(vec.len(), 0);
474+
assert_eq!(vec.list_size(), 3);
475+
assert_eq!(vec.elements().len(), 0);
476+
477+
// Operations on empty vector.
478+
vec.append_nulls(1);
479+
assert_eq!(vec.len(), 1);
480+
481+
// Test single element list.
482+
let elements = PVectorMut::<i32>::from_iter([42]);
483+
let validity = MaskMut::new_true(1);
484+
let vec = FixedSizeListVectorMut::new(
485+
Box::new(elements.into()),
486+
1, // List size of 1.
487+
validity,
488+
);
489+
assert_eq!(vec.len(), 1);
490+
assert_eq!(vec.list_size(), 1);
491+
492+
// Test large list size.
493+
let large_elements: Vec<i32> = (0..1000).collect();
494+
let elements = PVectorMut::<i32>::from_iter(large_elements);
495+
let validity = MaskMut::new_true(1); // Single list with 1000 elements.
496+
let vec = FixedSizeListVectorMut::new(Box::new(elements.into()), 1000, validity);
497+
assert_eq!(vec.len(), 1);
498+
assert_eq!(vec.list_size(), 1000);
499+
assert_eq!(vec.elements().len(), 1000);
500+
501+
// Verify operations work correctly.
502+
let frozen = vec.freeze();
503+
assert_eq!(frozen.len(), 1);
504+
assert_eq!(frozen.list_size(), 1000);
505+
}
506+
507+
#[test]
508+
fn test_capacity_management() {
509+
let dtype = DType::Primitive(PType::I32, vortex_dtype::Nullability::Nullable);
510+
511+
// Test initial capacity from with_capacity.
512+
let mut vec = FixedSizeListVectorMut::with_capacity(&dtype, 3, 10);
513+
assert!(vec.capacity() >= 10);
514+
assert!(vec.elements().capacity() >= 30); // At least 10 lists * 3 elements.
515+
516+
// Test reserve works without panicking.
517+
// The exact capacity increase depends on the underlying allocation strategy.
518+
vec.reserve(100);
519+
// After reserving, we should be able to hold at least the current length + reserved amount.
520+
// Since current length is 0, capacity should be at least 100.
521+
assert!(vec.capacity() >= 100);
522+
523+
// Test capacity calculation with different list sizes.
524+
let vec2 = FixedSizeListVectorMut::with_capacity(&dtype, 5, 20);
525+
assert!(vec2.capacity() >= 20);
526+
assert!(vec2.elements().capacity() >= 100); // At least 20 lists * 5 elements.
527+
528+
// Edge case: capacity when list_size = 0.
529+
// Based on the documentation, capacity is infinite (usize::MAX) for degenerate case.
530+
let vec3 = FixedSizeListVectorMut::with_capacity(&dtype, 0, 10);
531+
assert_eq!(vec3.capacity(), usize::MAX); // Infinite capacity for degenerate case.
532+
533+
// Test that capacity is preserved through operations.
534+
let elements = PVectorMut::<i32>::from_iter([1, 2, 3, 4, 5, 6]);
535+
vec.elements = Box::new(elements.into());
536+
vec.validity = MaskMut::new_true(2);
537+
vec.len = 2;
538+
vec.list_size = 3;
539+
540+
vec.reserve(8); // Reserve space for 8 more lists.
541+
assert!(vec.capacity() >= 10);
542+
543+
// Test that split_off and unsplit work without panicking.
544+
let split = vec.split_off(1);
545+
assert_eq!(vec.len(), 1);
546+
assert_eq!(split.len(), 1);
547+
548+
vec.unsplit(split);
549+
assert_eq!(vec.len(), 2);
550+
}
551+
}

0 commit comments

Comments
 (0)