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