vortex_array/arrays/
assertions.rs1use std::fmt::Display;
5
6use itertools::Itertools;
7use vortex_error::VortexExpect;
8
9use crate::ArrayRef;
10use crate::ExecutionCtx;
11use crate::IntoArray;
12use crate::LEGACY_SESSION;
13use crate::RecursiveCanonical;
14use crate::VortexSessionExecute;
15
16fn format_indices<I: IntoIterator<Item = usize>>(indices: I) -> impl Display {
17 indices.into_iter().format(",")
18}
19
20fn execute_to_canonical(array: ArrayRef, ctx: &mut ExecutionCtx) -> ArrayRef {
22 array
23 .execute::<RecursiveCanonical>(ctx)
24 .vortex_expect("failed to execute array to recursive canonical form")
25 .0
26 .into_array()
27}
28
29#[expect(clippy::unwrap_used)]
31fn find_mismatched_indices(left: &ArrayRef, right: &ArrayRef) -> Vec<usize> {
32 assert_eq!(left.len(), right.len());
33 let mut ctx = LEGACY_SESSION.create_execution_ctx();
34 (0..left.len())
35 .filter(|i| {
36 left.execute_scalar(*i, &mut ctx).unwrap()
37 != right.execute_scalar(*i, &mut ctx).unwrap()
38 })
39 .collect()
40}
41
42#[macro_export]
53macro_rules! assert_nth_scalar {
54 ($arr:expr, $n:expr, $expected:expr) => {{
55 use $crate::IntoArray as _;
56 use $crate::LEGACY_SESSION;
57 use $crate::VortexSessionExecute as _;
58 let arr_ref: $crate::ArrayRef = $crate::IntoArray::into_array($arr.clone());
59 assert_eq!(
60 arr_ref
61 .execute_scalar($n, &mut LEGACY_SESSION.create_execution_ctx())
62 .unwrap(),
63 $expected.try_into().unwrap()
64 );
65 }};
66}
67
68#[macro_export]
77macro_rules! assert_nth_scalar_is_null {
78 ($arr:expr, $n:expr) => {{
79 use $crate::LEGACY_SESSION;
80 use $crate::VortexSessionExecute as _;
81 let arr_ref: $crate::ArrayRef = $crate::IntoArray::into_array($arr.clone());
82 assert!(
83 arr_ref
84 .execute_scalar($n, &mut LEGACY_SESSION.create_execution_ctx())
85 .unwrap()
86 .is_null(),
87 "expected scalar at index {} to be null, but was {:?}",
88 $n,
89 arr_ref
90 .execute_scalar($n, &mut LEGACY_SESSION.create_execution_ctx())
91 .unwrap()
92 );
93 }};
94}
95
96#[macro_export]
97macro_rules! assert_arrays_eq {
98 ($left:expr, $right:expr) => {{
99
100
101 let left: $crate::ArrayRef = $crate::IntoArray::into_array($left.clone());
102 let right: $crate::ArrayRef = $crate::IntoArray::into_array($right.clone());
103 if left.dtype() != right.dtype() {
104 panic!(
105 "assertion left == right failed: arrays differ in type: {} != {}.\n left: {}\n right: {}",
106 left.dtype(),
107 right.dtype(),
108 left.display_values(),
109 right.display_values()
110 )
111 }
112
113 assert_eq!(
114 left.len(),
115 right.len(),
116 "assertion left == right failed: arrays differ in length: {} != {}.\n left: {}\n right: {}",
117 left.len(),
118 right.len(),
119 left.display_values(),
120 right.display_values()
121 );
122
123 let left = left.clone();
124 let right = right.clone();
125 $crate::arrays::assert_arrays_eq_impl(&left, &right);
126 }};
127}
128
129#[track_caller]
132#[expect(clippy::panic)]
133pub fn assert_arrays_eq_impl(left: &ArrayRef, right: &ArrayRef) {
134 let executed = execute_to_canonical(left.clone(), &mut LEGACY_SESSION.create_execution_ctx());
135
136 let left_right = find_mismatched_indices(left, right);
137 let executed_right = find_mismatched_indices(&executed, right);
138
139 if !left_right.is_empty() || !executed_right.is_empty() {
140 let mut msg = String::new();
141 if !left_right.is_empty() {
142 msg.push_str(&format!(
143 "\n left != right at indices: {}",
144 format_indices(left_right)
145 ));
146 }
147 if !executed_right.is_empty() {
148 msg.push_str(&format!(
149 "\n executed != right at indices: {}",
150 format_indices(executed_right)
151 ));
152 }
153 panic!(
154 "assertion failed: arrays do not match:{}\n left: {}\n right: {}\n executed: {}",
155 msg,
156 left.display_values(),
157 right.display_values(),
158 executed.display_values()
159 )
160 }
161}