Skip to content

Commit 0531061

Browse files
committed
add tests
Signed-off-by: Connor Tsui <[email protected]>
1 parent f6098ff commit 0531061

File tree

4 files changed

+158
-0
lines changed

4 files changed

+158
-0
lines changed

vortex-compute/src/take/mod.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,11 @@
33

44
//! Take function.
55
6+
mod bit_buffer;
67
mod buffer;
8+
mod mask;
79
pub mod slice;
10+
mod vector;
811

912
/// Function for taking based on indices (which can have different representations).
1013
pub trait Take<Indices: ?Sized> {

vortex-compute/src/take/vector/mod.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@ mod bool;
1111
mod primitive;
1212
mod pvector;
1313

14+
#[cfg(test)]
15+
mod tests;
16+
1417
impl<T> Take<PrimitiveVector> for &T
1518
where
1619
for<'a> &'a T: Take<PVector<u8>, Output = T>,
Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
// SPDX-License-Identifier: Apache-2.0
2+
// SPDX-FileCopyrightText: Copyright the Vortex contributors
3+
4+
use vortex_vector::VectorMutOps;
5+
use vortex_vector::bool::BoolVector;
6+
use vortex_vector::bool::BoolVectorMut;
7+
use vortex_vector::primitive::PVector;
8+
use vortex_vector::primitive::PVectorMut;
9+
use vortex_vector::primitive::PrimitiveVector;
10+
11+
use crate::take::Take;
12+
13+
/// Tests `Take` on `PVector` with mixed validity in both data and indices.
14+
///
15+
/// This test covers:
16+
/// - Taking from a vector with some null values.
17+
/// - Using indices that have some null values.
18+
/// - Verifying that nulls in the data propagate correctly.
19+
/// - Verifying that nulls in indices result in null outputs.
20+
/// - Using non-sequential indices to test the general case.
21+
#[test]
22+
fn test_pvector_take_with_nullable_indices() {
23+
// Data: [10, null, 30, 40, null, 60]
24+
let data: PVectorMut<i32> = [Some(10), None, Some(30), Some(40), None, Some(60)]
25+
.into_iter()
26+
.collect();
27+
let data = data.freeze();
28+
29+
// Indices: [0, null, 2, 5, null] (u32 indices with nulls)
30+
let indices: PVectorMut<u32> = [Some(0), None, Some(2), Some(5), None]
31+
.into_iter()
32+
.collect();
33+
let indices = indices.freeze();
34+
35+
let result = (&data).take(&indices);
36+
37+
// Expected: [10, null, 30, 60, null]
38+
// - Index 0 -> data[0] = 10 (valid)
39+
// - Index null -> null (null index produces null)
40+
// - Index 2 -> data[2] = 30 (valid)
41+
// - Index 5 -> data[5] = 60 (valid)
42+
// - Index null -> null (null index produces null)
43+
assert_eq!(result.get(0), Some(&10));
44+
assert_eq!(result.get(1), None); // Null index.
45+
assert_eq!(result.get(2), Some(&30));
46+
assert_eq!(result.get(3), Some(&60));
47+
assert_eq!(result.get(4), None); // Null index.
48+
}
49+
50+
/// Tests `Take` on `PVector` using `PrimitiveVector` indices (type-erased).
51+
///
52+
/// This ensures the generic `Take<PrimitiveVector>` impl works correctly by dispatching to the
53+
/// typed implementation.
54+
#[test]
55+
fn test_pvector_take_with_primitive_vector_indices() {
56+
// Data: [100, 200, null, 400, 500]
57+
let data: PVectorMut<i64> = [Some(100), Some(200), None, Some(400), Some(500)]
58+
.into_iter()
59+
.collect();
60+
let data = data.freeze();
61+
62+
// Indices as PrimitiveVector (u16): [4, 2, 0, 1]
63+
let indices: PVectorMut<u16> = [4u16, 2, 0, 1].into_iter().collect();
64+
let indices: PrimitiveVector = indices.freeze().into();
65+
66+
let result: PVector<i64> = (&data).take(&indices);
67+
68+
// Expected: [500, null, 100, 200]
69+
assert_eq!(result.get(0), Some(&500));
70+
assert_eq!(result.get(1), None); // data[2] is null.
71+
assert_eq!(result.get(2), Some(&100));
72+
assert_eq!(result.get(3), Some(&200));
73+
}
74+
75+
/// Tests `Take` on `BoolVector` with mixed validity in both data and indices.
76+
///
77+
/// This test covers:
78+
/// - Taking from a boolean vector with some null values.
79+
/// - Using indices that have some null values.
80+
/// - Verifying that nulls in the data propagate correctly.
81+
/// - Verifying that nulls in indices result in null outputs.
82+
#[test]
83+
fn test_bool_vector_take_with_nullable_indices() {
84+
// Data: [true, null, false, true, null, false]
85+
let data: BoolVectorMut = [Some(true), None, Some(false), Some(true), None, Some(false)]
86+
.into_iter()
87+
.collect();
88+
let data = data.freeze();
89+
90+
// Indices: [5, null, 0, 3, null, 2] (u32 indices with nulls)
91+
let indices: PVectorMut<u32> = [Some(5), None, Some(0), Some(3), None, Some(2)]
92+
.into_iter()
93+
.collect();
94+
let indices = indices.freeze();
95+
96+
let result = (&data).take(&indices);
97+
98+
// Expected: [false, null, true, true, null, false]
99+
// - Index 5 -> data[5] = false (valid)
100+
// - Index null -> null (null index produces null)
101+
// - Index 0 -> data[0] = true (valid)
102+
// - Index 3 -> data[3] = true (valid)
103+
// - Index null -> null (null index produces null)
104+
// - Index 2 -> data[2] = false (valid)
105+
assert_eq!(result.get(0), Some(false));
106+
assert_eq!(result.get(1), None); // Null index.
107+
assert_eq!(result.get(2), Some(true));
108+
assert_eq!(result.get(3), Some(true));
109+
assert_eq!(result.get(4), None); // Null index.
110+
assert_eq!(result.get(5), Some(false));
111+
}
112+
113+
/// Tests `Take` on `BoolVector` using `PrimitiveVector` indices (type-erased).
114+
///
115+
/// This ensures the generic `Take<PrimitiveVector>` impl works correctly for `BoolVector`.
116+
#[test]
117+
fn test_bool_vector_take_with_primitive_vector_indices() {
118+
// Data: [true, false, null, true, false]
119+
let data: BoolVectorMut = [Some(true), Some(false), None, Some(true), Some(false)]
120+
.into_iter()
121+
.collect();
122+
let data = data.freeze();
123+
124+
// Indices as PrimitiveVector (u64): [4, 2, 1, 0, 3]
125+
let indices: PVectorMut<u64> = [4u64, 2, 1, 0, 3].into_iter().collect();
126+
let indices: PrimitiveVector = indices.freeze().into();
127+
128+
let result: BoolVector = (&data).take(&indices);
129+
130+
// Expected: [false, null, false, true, true]
131+
assert_eq!(result.get(0), Some(false)); // data[4]
132+
assert_eq!(result.get(1), None); // data[2] is null.
133+
assert_eq!(result.get(2), Some(false)); // data[1]
134+
assert_eq!(result.get(3), Some(true)); // data[0]
135+
assert_eq!(result.get(4), Some(true)); // data[3]
136+
}

vortex-vector/src/bool/vector.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,22 @@ impl BoolVector {
7373
pub fn bits(&self) -> &BitBuffer {
7474
&self.bits
7575
}
76+
77+
/// Gets a nullable element at the given index, panicking on out-of-bounds.
78+
///
79+
/// If the element at the given index is null, returns `None`. Otherwise, returns `Some(x)`,
80+
/// where `x: bool`.
81+
///
82+
/// Note that this `get` method is different from the standard library [`slice::get`], which
83+
/// returns `None` if the index is out of bounds. This method will panic if the index is out of
84+
/// bounds, and return `None` if the element is null.
85+
///
86+
/// # Panics
87+
///
88+
/// Panics if the index is out of bounds.
89+
pub fn get(&self, index: usize) -> Option<bool> {
90+
self.validity.value(index).then(|| self.bits.value(index))
91+
}
7692
}
7793

7894
impl VectorOps for BoolVector {

0 commit comments

Comments
 (0)