1#[macro_export]
40macro_rules! assert_dataframe_equal {
41 ($left:expr, $right:expr $(, $options:expr)?) => {
42 #[allow(unused_assignments)]
43 #[allow(unused_mut)]
44 let mut options = $crate::asserts::DataFrameEqualOptions::default();
45 $(options = $options;)?
46
47 match $crate::asserts::assert_dataframe_equal($left, $right, options) {
48 Ok(_) => {},
49 Err(e) => panic!("{}", e),
50 }
51 };
52}
53
54#[cfg(test)]
55mod tests {
56 #[allow(unused_imports)]
57 use polars_core::prelude::*;
58
59 #[test]
61 fn test_dataframe_equal_options() {
62 let options = crate::asserts::DataFrameEqualOptions::default();
63
64 assert!(options.check_row_order);
65 assert!(options.check_column_order);
66 assert!(options.check_dtypes);
67 assert!(!options.check_exact);
68 assert_eq!(options.rel_tol, 1e-5);
69 assert_eq!(options.abs_tol, 1e-8);
70 assert!(!options.categorical_as_str);
71 }
72
73 #[test]
75 #[should_panic(expected = "height (row count) mismatch")]
76 fn test_dataframe_height_mismatch() {
77 let df1 = DataFrame::new(vec![
78 Series::new("col1".into(), &[1, 2]).into(),
79 Series::new("col2".into(), &["a", "b"]).into(),
80 ])
81 .unwrap();
82
83 let df2 = DataFrame::new(vec![
84 Series::new("col1".into(), &[1, 2, 3]).into(),
85 Series::new("col2".into(), &["a", "b", "c"]).into(),
86 ])
87 .unwrap();
88
89 assert_dataframe_equal!(&df1, &df2);
90 }
91
92 #[test]
93 #[should_panic(expected = "columns mismatch")]
94 fn test_dataframe_column_mismatch() {
95 let df1 = DataFrame::new(vec![
96 Series::new("col1".into(), &[1, 2, 3]).into(),
97 Series::new("col2".into(), &["a", "b", "c"]).into(),
98 ])
99 .unwrap();
100
101 let df2 = DataFrame::new(vec![
102 Series::new("col1".into(), &[1, 2, 3]).into(),
103 Series::new("different_col".into(), &["a", "b", "c"]).into(),
104 ])
105 .unwrap();
106
107 assert_dataframe_equal!(&df1, &df2);
108 }
109
110 #[test]
111 #[should_panic(expected = "dtypes do not match")]
112 fn test_dataframe_dtype_mismatch() {
113 let df1 = DataFrame::new(vec![
114 Series::new("col1".into(), &[1, 2, 3]).into(),
115 Series::new("col2".into(), &["a", "b", "c"]).into(),
116 ])
117 .unwrap();
118
119 let df2 = DataFrame::new(vec![
120 Series::new("col1".into(), &[1.0, 2.0, 3.0]).into(),
121 Series::new("col2".into(), &["a", "b", "c"]).into(),
122 ])
123 .unwrap();
124
125 assert_dataframe_equal!(&df1, &df2);
126 }
127
128 #[test]
129 fn test_dataframe_dtype_mismatch_ignored() {
130 let df1 = DataFrame::new(vec![
131 Series::new("col1".into(), &[1, 2, 3]).into(),
132 Series::new("col2".into(), &["a", "b", "c"]).into(),
133 ])
134 .unwrap();
135
136 let df2 = DataFrame::new(vec![
137 Series::new("col1".into(), &[1.0, 2.0, 3.0]).into(),
138 Series::new("col2".into(), &["a", "b", "c"]).into(),
139 ])
140 .unwrap();
141
142 let options = crate::asserts::DataFrameEqualOptions::default().with_check_dtypes(false);
143 assert_dataframe_equal!(&df1, &df2, options);
144 }
145
146 #[test]
147 #[should_panic(expected = "columns are not in the same order")]
148 fn test_dataframe_column_order_mismatch() {
149 let df1 = DataFrame::new(vec![
150 Series::new("col1".into(), &[1, 2, 3]).into(),
151 Series::new("col2".into(), &["a", "b", "c"]).into(),
152 ])
153 .unwrap();
154
155 let df2 = DataFrame::new(vec![
156 Series::new("col2".into(), &["a", "b", "c"]).into(),
157 Series::new("col1".into(), &[1, 2, 3]).into(),
158 ])
159 .unwrap();
160
161 assert_dataframe_equal!(&df1, &df2);
162 }
163
164 #[test]
165 fn test_dataframe_column_order_mismatch_ignored() {
166 let df1 = DataFrame::new(vec![
167 Series::new("col1".into(), &[1, 2, 3]).into(),
168 Series::new("col2".into(), &["a", "b", "c"]).into(),
169 ])
170 .unwrap();
171
172 let df2 = DataFrame::new(vec![
173 Series::new("col2".into(), &["a", "b", "c"]).into(),
174 Series::new("col1".into(), &[1, 2, 3]).into(),
175 ])
176 .unwrap();
177
178 let options =
179 crate::asserts::DataFrameEqualOptions::default().with_check_column_order(false);
180 assert_dataframe_equal!(&df1, &df2, options);
181 }
182
183 #[test]
184 #[should_panic(expected = "columns mismatch: [\"col3\"] in left, but not in right")]
185 fn test_dataframe_left_has_extra_column() {
186 let df1 = DataFrame::new(vec![
187 Series::new("col1".into(), &[1, 2, 3]).into(),
188 Series::new("col2".into(), &["a", "b", "c"]).into(),
189 Series::new("col3".into(), &[true, false, true]).into(),
190 ])
191 .unwrap();
192
193 let df2 = DataFrame::new(vec![
194 Series::new("col1".into(), &[1, 2, 3]).into(),
195 Series::new("col2".into(), &["a", "b", "c"]).into(),
196 ])
197 .unwrap();
198
199 assert_dataframe_equal!(&df1, &df2);
200 }
201
202 #[test]
203 #[should_panic(expected = "columns mismatch: [\"col3\"] in right, but not in left")]
204 fn test_dataframe_right_has_extra_column() {
205 let df1 = DataFrame::new(vec![
206 Series::new("col1".into(), &[1, 2, 3]).into(),
207 Series::new("col2".into(), &["a", "b", "c"]).into(),
208 ])
209 .unwrap();
210
211 let df2 = DataFrame::new(vec![
212 Series::new("col1".into(), &[1, 2, 3]).into(),
213 Series::new("col2".into(), &["a", "b", "c"]).into(),
214 Series::new("col3".into(), &[true, false, true]).into(),
215 ])
216 .unwrap();
217
218 assert_dataframe_equal!(&df1, &df2);
219 }
220
221 #[test]
223 #[should_panic(expected = "value mismatch for column")]
224 fn test_dataframe_value_mismatch() {
225 let df1 = DataFrame::new(vec![
226 Series::new("col1".into(), &[1, 2, 3]).into(),
227 Series::new("col2".into(), &["a", "b", "c"]).into(),
228 Series::new("col3".into(), &[true, false, true]).into(),
229 ])
230 .unwrap();
231
232 let df2 = DataFrame::new(vec![
233 Series::new("col1".into(), &[1, 2, 3]).into(),
234 Series::new("col2".into(), &["a", "b", "changed"]).into(),
235 Series::new("col3".into(), &[true, false, true]).into(),
236 ])
237 .unwrap();
238
239 assert_dataframe_equal!(&df1, &df2);
240 }
241
242 #[test]
243 fn test_dataframe_equal() {
244 let df1 = DataFrame::new(vec![
245 Series::new("col1".into(), &[1, 2, 3]).into(),
246 Series::new("col2".into(), &["a", "b", "c"]).into(),
247 Series::new("col3".into(), &[true, false, true]).into(),
248 ])
249 .unwrap();
250
251 let df2 = DataFrame::new(vec![
252 Series::new("col1".into(), &[1, 2, 3]).into(),
253 Series::new("col2".into(), &["a", "b", "c"]).into(),
254 Series::new("col3".into(), &[true, false, true]).into(),
255 ])
256 .unwrap();
257
258 assert_dataframe_equal!(&df1, &df2);
259 }
260
261 #[test]
262 #[should_panic(expected = "value mismatch")]
263 fn test_dataframe_row_order_mismatch() {
264 let df1 = DataFrame::new(vec![
265 Series::new("col1".into(), &[1, 2, 3]).into(),
266 Series::new("col2".into(), &["a", "b", "c"]).into(),
267 ])
268 .unwrap();
269
270 let df2 = DataFrame::new(vec![
271 Series::new("col1".into(), &[3, 1, 2]).into(),
272 Series::new("col2".into(), &["c", "a", "b"]).into(),
273 ])
274 .unwrap();
275
276 assert_dataframe_equal!(&df1, &df2);
277 }
278
279 #[test]
280 fn test_dataframe_row_order_ignored() {
281 let df1 = DataFrame::new(vec![
282 Series::new("col1".into(), &[1, 2, 3]).into(),
283 Series::new("col2".into(), &["a", "b", "c"]).into(),
284 ])
285 .unwrap();
286
287 let df2 = DataFrame::new(vec![
288 Series::new("col1".into(), &[3, 1, 2]).into(),
289 Series::new("col2".into(), &["c", "a", "b"]).into(),
290 ])
291 .unwrap();
292
293 let options = crate::asserts::DataFrameEqualOptions::default().with_check_row_order(false);
294 assert_dataframe_equal!(&df1, &df2, options);
295 }
296
297 #[test]
299 #[should_panic(expected = "value mismatch")]
300 fn test_dataframe_complex_mismatch() {
301 let df1 = DataFrame::new(vec![
302 Series::new("integers".into(), &[1, 2, 3, 4, 5]).into(),
303 Series::new("floats".into(), &[1.1, 2.2, 3.3, 4.4, 5.5]).into(),
304 Series::new("strings".into(), &["a", "b", "c", "d", "e"]).into(),
305 Series::new("booleans".into(), &[true, false, true, false, true]).into(),
306 Series::new("opt_ints".into(), &[Some(1), None, Some(3), Some(4), None]).into(),
307 ])
308 .unwrap();
309
310 let df2 = DataFrame::new(vec![
311 Series::new("integers".into(), &[1, 2, 99, 4, 5]).into(),
312 Series::new("floats".into(), &[1.1, 2.2, 3.3, 9.9, 5.5]).into(),
313 Series::new("strings".into(), &["a", "b", "c", "CHANGED", "e"]).into(),
314 Series::new("booleans".into(), &[true, false, false, false, true]).into(),
315 Series::new("opt_ints".into(), &[Some(1), None, Some(3), None, None]).into(),
316 ])
317 .unwrap();
318
319 assert_dataframe_equal!(&df1, &df2);
320 }
321
322 #[test]
323 fn test_dataframe_complex_match() {
324 let df1 = DataFrame::new(vec![
325 Series::new("integers".into(), &[1, 2, 3, 4, 5]).into(),
326 Series::new("floats".into(), &[1.1, 2.2, 3.3, 4.4, 5.5]).into(),
327 Series::new("strings".into(), &["a", "b", "c", "d", "e"]).into(),
328 Series::new("booleans".into(), &[true, false, true, false, true]).into(),
329 Series::new("opt_ints".into(), &[Some(1), None, Some(3), Some(4), None]).into(),
330 ])
331 .unwrap();
332
333 let df2 = DataFrame::new(vec![
334 Series::new("integers".into(), &[1, 2, 3, 4, 5]).into(),
335 Series::new("floats".into(), &[1.1, 2.2, 3.3, 4.4, 5.5]).into(),
336 Series::new("strings".into(), &["a", "b", "c", "d", "e"]).into(),
337 Series::new("booleans".into(), &[true, false, true, false, true]).into(),
338 Series::new("opt_ints".into(), &[Some(1), None, Some(3), Some(4), None]).into(),
339 ])
340 .unwrap();
341
342 assert_dataframe_equal!(&df1, &df2);
343 }
344
345 #[test]
347 #[should_panic(expected = "value mismatch")]
348 fn test_dataframe_numeric_exact_fail() {
349 let df1 = DataFrame::new(vec![
350 Series::new("col1".into(), &[1.0000001, 2.0000002, 3.0000003]).into(),
351 ])
352 .unwrap();
353
354 let df2 =
355 DataFrame::new(vec![Series::new("col1".into(), &[1.0, 2.0, 3.0]).into()]).unwrap();
356
357 let options = crate::asserts::DataFrameEqualOptions::default().with_check_exact(true);
358 assert_dataframe_equal!(&df1, &df2, options);
359 }
360
361 #[test]
362 fn test_dataframe_numeric_tolerance_pass() {
363 let df1 = DataFrame::new(vec![
364 Series::new("col1".into(), &[1.0000001, 2.0000002, 3.0000003]).into(),
365 ])
366 .unwrap();
367
368 let df2 =
369 DataFrame::new(vec![Series::new("col1".into(), &[1.0, 2.0, 3.0]).into()]).unwrap();
370
371 assert_dataframe_equal!(&df1, &df2);
372 }
373
374 #[test]
376 fn test_empty_dataframe_equal() {
377 let df1 = DataFrame::default();
378 let df2 = DataFrame::default();
379
380 assert_dataframe_equal!(&df1, &df2);
381 }
382
383 #[test]
384 fn test_empty_dataframe_schema_equal() {
385 let df1 = DataFrame::new(vec![
386 Series::new("col1".into(), &Vec::<i32>::new()).into(),
387 Series::new("col2".into(), &Vec::<String>::new()).into(),
388 ])
389 .unwrap();
390
391 let df2 = DataFrame::new(vec![
392 Series::new("col1".into(), &Vec::<i32>::new()).into(),
393 Series::new("col2".into(), &Vec::<String>::new()).into(),
394 ])
395 .unwrap();
396
397 assert_dataframe_equal!(&df1, &df2);
398 }
399
400 #[test]
401 #[should_panic(expected = "value mismatch")]
402 fn test_dataframe_single_row_mismatch() {
403 let df1 = DataFrame::new(vec![
404 Series::new("col1".into(), &[42]).into(),
405 Series::new("col2".into(), &["value"]).into(),
406 Series::new("col3".into(), &[true]).into(),
407 ])
408 .unwrap();
409
410 let df2 = DataFrame::new(vec![
411 Series::new("col1".into(), &[42]).into(),
412 Series::new("col2".into(), &["different"]).into(),
413 Series::new("col3".into(), &[true]).into(),
414 ])
415 .unwrap();
416
417 assert_dataframe_equal!(&df1, &df2);
418 }
419
420 #[test]
421 fn test_dataframe_single_row_match() {
422 let df1 = DataFrame::new(vec![
423 Series::new("col1".into(), &[42]).into(),
424 Series::new("col2".into(), &["value"]).into(),
425 Series::new("col3".into(), &[true]).into(),
426 ])
427 .unwrap();
428
429 let df2 = DataFrame::new(vec![
430 Series::new("col1".into(), &[42]).into(),
431 Series::new("col2".into(), &["value"]).into(),
432 Series::new("col3".into(), &[true]).into(),
433 ])
434 .unwrap();
435
436 assert_dataframe_equal!(&df1, &df2);
437 }
438
439 #[test]
440 #[should_panic(expected = "value mismatch")]
441 fn test_dataframe_null_values_mismatch() {
442 let df1 = DataFrame::new(vec![
443 Series::new("col1".into(), &[Some(1), None, Some(3)]).into(),
444 ])
445 .unwrap();
446
447 let df2 = DataFrame::new(vec![
448 Series::new("col1".into(), &[Some(1), Some(2), None]).into(),
449 ])
450 .unwrap();
451
452 assert_dataframe_equal!(&df1, &df2);
453 }
454
455 #[test]
456 fn test_dataframe_null_values_match() {
457 let df1 = DataFrame::new(vec![
458 Series::new("col1".into(), &[Some(1), None, Some(3)]).into(),
459 ])
460 .unwrap();
461
462 let df2 = DataFrame::new(vec![
463 Series::new("col1".into(), &[Some(1), None, Some(3)]).into(),
464 ])
465 .unwrap();
466
467 assert_dataframe_equal!(&df1, &df2);
468 }
469
470 #[test]
471 #[should_panic(expected = "value mismatch")]
472 fn test_dataframe_nan_values_mismatch() {
473 let df1 = DataFrame::new(vec![
474 Series::new("col1".into(), &[1.0, f64::NAN, 3.0]).into(),
475 ])
476 .unwrap();
477
478 let df2 = DataFrame::new(vec![
479 Series::new("col1".into(), &[1.0, 2.0, f64::NAN]).into(),
480 ])
481 .unwrap();
482
483 assert_dataframe_equal!(&df1, &df2);
484 }
485
486 #[test]
487 fn test_dataframe_nan_values_match() {
488 let df1 = DataFrame::new(vec![
489 Series::new("col1".into(), &[1.0, f64::NAN, 3.0]).into(),
490 ])
491 .unwrap();
492
493 let df2 = DataFrame::new(vec![
494 Series::new("col1".into(), &[1.0, f64::NAN, 3.0]).into(),
495 ])
496 .unwrap();
497
498 assert_dataframe_equal!(&df1, &df2);
499 }
500
501 #[test]
502 #[should_panic(expected = "value mismatch")]
503 fn test_dataframe_infinity_values_mismatch() {
504 let df1 = DataFrame::new(vec![
505 Series::new("col1".into(), &[1.0, f64::INFINITY, 3.0]).into(),
506 ])
507 .unwrap();
508
509 let df2 = DataFrame::new(vec![
510 Series::new("col1".into(), &[1.0, f64::NEG_INFINITY, 3.0]).into(),
511 ])
512 .unwrap();
513
514 assert_dataframe_equal!(&df1, &df2);
515 }
516
517 #[test]
518 fn test_dataframe_infinity_values_match() {
519 let df1 = DataFrame::new(vec![
520 Series::new("col1".into(), &[1.0, f64::INFINITY, 3.0]).into(),
521 ])
522 .unwrap();
523
524 let df2 = DataFrame::new(vec![
525 Series::new("col1".into(), &[1.0, f64::INFINITY, 3.0]).into(),
526 ])
527 .unwrap();
528
529 assert_dataframe_equal!(&df1, &df2);
530 }
531
532 #[test]
534 #[should_panic(expected = "value mismatch")]
535 fn test_dataframe_categorical_as_string_mismatch() {
536 let mut categorical1 = Series::new("categories".into(), &["a", "b", "c", "d"]);
537 categorical1 = categorical1
538 .cast(&DataType::from_categories(Categories::global()))
539 .unwrap();
540 let df1 = DataFrame::new(vec![categorical1.into()]).unwrap();
541
542 let mut categorical2 = Series::new("categories".into(), &["a", "b", "c", "e"]);
543 categorical2 = categorical2
544 .cast(&DataType::from_categories(Categories::global()))
545 .unwrap();
546 let df2 = DataFrame::new(vec![categorical2.into()]).unwrap();
547
548 let options =
549 crate::asserts::DataFrameEqualOptions::default().with_categorical_as_str(true);
550 assert_dataframe_equal!(&df1, &df2, options);
551 }
552
553 #[test]
554 fn test_dataframe_categorical_as_string_match() {
555 let mut categorical1 = Series::new("categories".into(), &["a", "b", "c", "d"]);
556 categorical1 = categorical1
557 .cast(&DataType::from_categories(Categories::global()))
558 .unwrap();
559 let df1 = DataFrame::new(vec![categorical1.into()]).unwrap();
560
561 let mut categorical2 = Series::new("categories".into(), &["a", "b", "c", "d"]);
562 categorical2 = categorical2
563 .cast(&DataType::from_categories(Categories::global()))
564 .unwrap();
565 let df2 = DataFrame::new(vec![categorical2.into()]).unwrap();
566
567 let options =
568 crate::asserts::DataFrameEqualOptions::default().with_categorical_as_str(true);
569 assert_dataframe_equal!(&df1, &df2, options);
570 }
571
572 #[test]
574 #[should_panic(expected = "value mismatch")]
575 fn test_dataframe_nested_values_mismatch() {
576 let df1 = DataFrame::new(vec![
577 Series::new(
578 "list_col".into(),
579 &[
580 Some(vec![1, 2, 3]),
581 Some(vec![4, 5, 6]),
582 None,
583 Some(vec![7, 8, 9]),
584 ],
585 )
586 .into(),
587 ])
588 .unwrap();
589
590 let df2 = DataFrame::new(vec![
591 Series::new(
592 "list_col".into(),
593 &[
594 Some(vec![1, 2, 3]),
595 Some(vec![4, 5, 99]),
596 None,
597 Some(vec![7, 8, 9]),
598 ],
599 )
600 .into(),
601 ])
602 .unwrap();
603
604 assert_dataframe_equal!(&df1, &df2);
605 }
606
607 #[test]
608 fn test_dataframe_nested_values_match() {
609 let df1 = DataFrame::new(vec![
610 Series::new(
611 "list_col".into(),
612 &[Some(vec![1, 2, 3]), Some(vec![]), None, Some(vec![7, 8, 9])],
613 )
614 .into(),
615 ])
616 .unwrap();
617
618 let df2 = DataFrame::new(vec![
619 Series::new(
620 "list_col".into(),
621 &[Some(vec![1, 2, 3]), Some(vec![]), None, Some(vec![7, 8, 9])],
622 )
623 .into(),
624 ])
625 .unwrap();
626
627 assert_dataframe_equal!(&df1, &df2);
628 }
629}