1#[macro_export]
34macro_rules! assert_series_equal {
35 ($left:expr, $right:expr $(, $options:expr)?) => {
36 {
37 #[allow(unused_assignments)]
38 #[allow(unused_mut)]
39 let mut options = $crate::asserts::SeriesEqualOptions::default();
40 $(options = $options;)?
41
42 match $crate::asserts::assert_series_equal($left, $right, options) {
43 Ok(_) => {},
44 Err(e) => panic!("{}", e),
45 }
46 }
47 };
48}
49
50#[cfg(test)]
51mod tests {
52 use polars_core::prelude::*;
53
54 #[test]
56 fn test_series_equal_options() {
57 let options = crate::asserts::SeriesEqualOptions::default();
58
59 assert!(options.check_dtypes);
60 assert!(options.check_names);
61 assert!(options.check_order);
62 assert!(options.check_exact);
63 assert_eq!(options.rel_tol, 1e-5);
64 assert_eq!(options.abs_tol, 1e-8);
65 assert!(!options.categorical_as_str);
66 }
67
68 #[test]
70 #[should_panic(expected = "length mismatch")]
71 fn test_series_length_mismatch() {
72 let s1 = Series::new("".into(), &[1, 2]);
73 let s2 = Series::new("".into(), &[1, 2, 3]);
74
75 assert_series_equal!(&s1, &s2);
76 }
77
78 #[test]
79 #[should_panic(expected = "name mismatch")]
80 fn test_series_names_mismatch() {
81 let s1 = Series::new("s1".into(), &[1, 2, 3]);
82 let s2 = Series::new("s2".into(), &[1, 2, 3]);
83
84 assert_series_equal!(&s1, &s2);
85 }
86
87 #[test]
88 fn test_series_check_names_false() {
89 let s1 = Series::new("s1".into(), &[1, 2, 3]);
90 let s2 = Series::new("s2".into(), &[1, 2, 3]);
91
92 let options = crate::asserts::SeriesEqualOptions::default().with_check_names(false);
93
94 assert_series_equal!(&s1, &s2, options);
95 }
96
97 #[test]
98 #[should_panic(expected = "dtype mismatch")]
99 fn test_series_dtype_mismatch() {
100 let s1 = Series::new("".into(), &[1, 2, 3]);
101 let s2 = Series::new("".into(), &["1", "2", "3"]);
102
103 assert_series_equal!(&s1, &s2);
104 }
105
106 #[test]
107 fn test_series_check_dtypes_false() {
108 let s1 = Series::new("s1".into(), &[1, 2, 3]);
109 let s2 = Series::new("s1".into(), &[1.0, 2.0, 3.0]);
110
111 let options = crate::asserts::SeriesEqualOptions::default().with_check_dtypes(false);
112
113 assert_series_equal!(&s1, &s2, options);
114 }
115
116 #[test]
118 #[should_panic(expected = "exact value mismatch")]
119 fn test_series_value_mismatch_int() {
120 let s1 = Series::new("".into(), &[1, 2, 3]);
121 let s2 = Series::new("".into(), &[2, 3, 4]);
122
123 assert_series_equal!(&s1, &s2);
124 }
125
126 #[test]
127 fn test_series_values_match_int() {
128 let s1 = Series::new("".into(), &[1, 2, 3]);
129 let s2 = Series::new("".into(), &[1, 2, 3]);
130
131 assert_series_equal!(&s1, &s2);
132 }
133
134 #[test]
135 #[should_panic(expected = "exact value mismatch")]
136 fn test_series_value_mismatch_str() {
137 let s1 = Series::new("".into(), &["foo", "bar"]);
138 let s2 = Series::new("".into(), &["moo", "car"]);
139
140 assert_series_equal!(&s1, &s2);
141 }
142
143 #[test]
144 fn test_series_values_match_str() {
145 let s1 = Series::new("".into(), &["foo", "bar"]);
146 let s2 = Series::new("".into(), &["foo", "bar"]);
147
148 assert_series_equal!(&s1, &s2);
149 }
150
151 #[test]
152 #[should_panic(expected = "exact value mismatch")]
153 fn test_series_values_mismatch_float() {
154 let s1 = Series::new("".into(), &[1.1, 2.2, 3.3]);
155 let s2 = Series::new("".into(), &[2.2, 3.3, 4.4]);
156
157 assert_series_equal!(&s1, &s2);
158 }
159
160 #[test]
161 fn test_series_values_match_float() {
162 let s1 = Series::new("".into(), &[1.1, 2.2, 3.3]);
163 let s2 = Series::new("".into(), &[1.1, 2.2, 3.3]);
164
165 assert_series_equal!(&s1, &s2);
166 }
167
168 #[test]
170 #[should_panic(expected = "values not within tolerance")]
171 fn test_series_float_exceeded_tol() {
172 let s1 = Series::new("".into(), &[1.0, 2.2, 3.3]);
173 let s2 = Series::new("".into(), &[1.00012, 2.200025, 3.300035]);
174
175 let options = crate::asserts::SeriesEqualOptions::default().with_check_exact(false);
176
177 assert_series_equal!(&s1, &s2, options);
178 }
179
180 #[test]
181 fn test_series_float_within_tol() {
182 let s1 = Series::new("".into(), &[1.0, 2.0, 3.0]);
183 let s2 = Series::new("".into(), &[1.000005, 2.000015, 3.000025]);
184
185 let options = crate::asserts::SeriesEqualOptions::default().with_check_exact(false);
186
187 assert_series_equal!(&s1, &s2, options);
188 }
189
190 #[test]
191 fn test_series_float_exact_tolerance_boundary() {
192 let s1 = Series::new("".into(), &[1.0, 2.0, 3.0]);
193 let s2 = Series::new("".into(), &[1.0, 2.0 + 1e-5, 3.0]);
194
195 let options = crate::asserts::SeriesEqualOptions::default().with_check_exact(false);
196
197 assert_series_equal!(&s1, &s2, options);
198 }
199
200 #[test]
201 fn test_series_float_custom_rel_tol() {
202 let s1 = Series::new("".into(), &[10.0, 100.0, 1000.0]);
203 let s2 = Series::new("".into(), &[10.05, 100.1, 1000.2]);
204
205 let options = crate::asserts::SeriesEqualOptions::default()
206 .with_check_exact(false)
207 .with_rel_tol(0.01);
208
209 assert_series_equal!(&s1, &s2, options);
210 }
211
212 #[test]
213 #[should_panic(expected = "values not within tolerance")]
214 fn test_series_float_custom_abs_tol() {
215 let s1 = Series::new("".into(), &[0.001, 0.01, 0.1]);
216 let s2 = Series::new("".into(), &[0.001, 0.02, 0.1]);
217
218 let options = crate::asserts::SeriesEqualOptions::default()
219 .with_check_exact(false)
220 .with_abs_tol(0.005);
221
222 assert_series_equal!(&s1, &s2, options);
223 }
224
225 #[test]
227 fn test_series_empty_equal() {
228 let s1 = Series::default();
229 let s2 = Series::default();
230
231 assert_series_equal!(&s1, &s2);
232 }
233
234 #[test]
235 fn test_series_nan_equal() {
236 let s1 = Series::new("".into(), &[f64::NAN, f64::NAN, f64::NAN]);
237 let s2 = Series::new("".into(), &[f64::NAN, f64::NAN, f64::NAN]);
238
239 assert_series_equal!(&s1, &s2);
240 }
241
242 #[test]
243 fn test_series_null_equal() {
244 let s1 = Series::new("".into(), &[None::<i32>, None::<i32>, None::<i32>]);
245 let s2 = Series::new("".into(), &[None::<i32>, None::<i32>, None::<i32>]);
246
247 assert_series_equal!(&s1, &s2);
248 }
249
250 #[test]
251 #[should_panic(expected = "exact value mismatch")]
252 fn test_series_infinity_values_mismatch() {
253 let s1 = Series::new("".into(), &[1.0, f64::INFINITY, 3.0]);
254 let s2 = Series::new("".into(), &[1.0, f64::NEG_INFINITY, 3.0]);
255
256 assert_series_equal!(&s1, &s2);
257 }
258
259 #[test]
260 fn test_series_infinity_values_match() {
261 let s1 = Series::new("".into(), &[1.0, f64::INFINITY, f64::NEG_INFINITY]);
262 let s2 = Series::new("".into(), &[1.0, f64::INFINITY, f64::NEG_INFINITY]);
263
264 assert_series_equal!(&s1, &s2);
265 }
266
267 #[test]
269 #[should_panic(expected = "null value mismatch")]
270 fn test_series_check_exact_false_null() {
271 let s1 = Series::new("".into(), &[Some(1.0), None::<f64>, Some(3.0)]);
272 let s2 = Series::new("".into(), &[Some(1.0), Some(2.0), Some(3.0)]);
273
274 let options = crate::asserts::SeriesEqualOptions::default().with_check_exact(false);
275
276 assert_series_equal!(&s1, &s2, options);
277 }
278
279 #[test]
280 #[should_panic(expected = "nan value mismatch")]
281 fn test_series_check_exact_false_nan() {
282 let s1 = Series::new("".into(), &[1.0, f64::NAN, 3.0]);
283 let s2 = Series::new("".into(), &[1.0, 2.0, 3.0]);
284
285 let options = crate::asserts::SeriesEqualOptions::default().with_check_exact(false);
286
287 assert_series_equal!(&s1, &s2, options);
288 }
289
290 #[test]
292 #[should_panic(expected = "exact value mismatch")]
293 fn test_series_sorting_unequal() {
294 let s1 = Series::new("".into(), &[Some(1), Some(2), Some(3), None::<i32>]);
295 let s2 = Series::new("".into(), &[Some(2), None::<i32>, Some(3), Some(1)]);
296
297 let options = crate::asserts::SeriesEqualOptions::default();
298
299 assert_series_equal!(&s1, &s2, options);
300 }
301
302 #[test]
303 fn test_series_sorting_equal() {
304 let s1 = Series::new("".into(), &[Some(1), Some(2), Some(3), None::<i32>]);
305 let s2 = Series::new("".into(), &[Some(2), None::<i32>, Some(3), Some(1)]);
306
307 let options = crate::asserts::SeriesEqualOptions::default().with_check_order(false);
308
309 assert_series_equal!(&s1, &s2, options);
310 }
311
312 #[test]
314 #[should_panic(expected = "exact value mismatch")]
315 fn test_series_categorical_mismatch() {
316 let s1 = Series::new("".into(), &["apple", "banana", "cherry"])
317 .cast(&DataType::from_categories(Categories::global()))
318 .unwrap();
319 let s2 = Series::new("".into(), &["apple", "orange", "cherry"])
320 .cast(&DataType::from_categories(Categories::global()))
321 .unwrap();
322
323 assert_series_equal!(&s1, &s2);
324 }
325
326 #[test]
327 fn test_series_categorical_match() {
328 let s1 = Series::new("".into(), &["apple", "banana", "cherry"])
329 .cast(&DataType::from_categories(Categories::global()))
330 .unwrap();
331 let s2 = Series::new("".into(), &["apple", "banana", "cherry"])
332 .cast(&DataType::from_categories(Categories::global()))
333 .unwrap();
334
335 assert_series_equal!(&s1, &s2);
336 }
337
338 #[test]
339 #[should_panic(expected = "exact value mismatch")]
340 fn test_series_categorical_str_mismatch() {
341 let s1 = Series::new("".into(), &["apple", "banana", "cherry"])
342 .cast(&DataType::from_categories(Categories::global()))
343 .unwrap();
344 let s2 = Series::new("".into(), &["apple", "orange", "cherry"])
345 .cast(&DataType::from_categories(Categories::global()))
346 .unwrap();
347
348 let options = crate::asserts::SeriesEqualOptions::default().with_categorical_as_str(true);
349
350 assert_series_equal!(&s1, &s2, options);
351 }
352
353 #[test]
354 fn test_series_categorical_str_match() {
355 let s1 = Series::new("".into(), &["apple", "banana", "cherry"])
356 .cast(&DataType::from_categories(Categories::global()))
357 .unwrap();
358 let s2 = Series::new("".into(), &["apple", "banana", "cherry"])
359 .cast(&DataType::from_categories(Categories::global()))
360 .unwrap();
361
362 let options = crate::asserts::SeriesEqualOptions::default().with_categorical_as_str(true);
363
364 assert_series_equal!(&s1, &s2, options);
365 }
366
367 #[test]
369 #[should_panic(expected = "exact value mismatch")]
370 fn test_series_list_values_int_mismatch() {
371 let s1 = Series::new(
372 "".into(),
373 &[
374 [1, 2, 3].iter().collect::<Series>(),
375 [4, 5, 6].iter().collect::<Series>(),
376 [7, 8, 9].iter().collect::<Series>(),
377 ],
378 );
379
380 let s2 = Series::new(
381 "".into(),
382 &[
383 [0, 2, 3].iter().collect::<Series>(),
384 [4, 7, 6].iter().collect::<Series>(),
385 [7, 8, 10].iter().collect::<Series>(),
386 ],
387 );
388
389 assert_series_equal!(&s1, &s2);
390 }
391
392 #[test]
393 fn test_series_list_values_int_match() {
394 let s1 = Series::new(
395 "".into(),
396 &[
397 [1, 2, 3].iter().collect::<Series>(),
398 [4, 5, 6].iter().collect::<Series>(),
399 [7, 8, 9].iter().collect::<Series>(),
400 ],
401 );
402
403 let s2 = Series::new(
404 "".into(),
405 &[
406 [1, 2, 3].iter().collect::<Series>(),
407 [4, 5, 6].iter().collect::<Series>(),
408 [7, 8, 9].iter().collect::<Series>(),
409 ],
410 );
411
412 assert_series_equal!(&s1, &s2);
413 }
414
415 #[test]
416 #[should_panic(expected = "nested value mismatch")]
417 fn test_series_list_values_float_mismatch() {
418 let s1 = Series::new(
419 "".into(),
420 &[
421 [1.1, 2.0, 3.0].iter().collect::<Series>(),
422 [4.0, 5.0, 6.0].iter().collect::<Series>(),
423 [7.0, 8.0, 9.0].iter().collect::<Series>(),
424 ],
425 );
426
427 let s2 = Series::new(
428 "".into(),
429 &[
430 [0.5, 2.0, 3.0].iter().collect::<Series>(),
431 [4.0, 7.5, 6.0].iter().collect::<Series>(),
432 [7.0, 8.0, 10.2].iter().collect::<Series>(),
433 ],
434 );
435
436 assert_series_equal!(&s1, &s2);
437 }
438
439 #[test]
440 fn test_series_list_values_float_match() {
441 let s1 = Series::new(
442 "".into(),
443 &[
444 [1.1, 2.0, 3.0].iter().collect::<Series>(),
445 [4.0, 5.0, 6.0].iter().collect::<Series>(),
446 [7.0, 8.0, 9.0].iter().collect::<Series>(),
447 ],
448 );
449
450 let s2 = Series::new(
451 "".into(),
452 &[
453 [1.1, 2.0, 3.0].iter().collect::<Series>(),
454 [4.0, 5.0, 6.0].iter().collect::<Series>(),
455 [7.0, 8.0, 9.0].iter().collect::<Series>(),
456 ],
457 );
458
459 assert_series_equal!(&s1, &s2);
460 }
461
462 #[test]
463 #[should_panic(expected = "exact value mismatch")]
464 fn test_series_struct_values_str_mismatch() {
465 let field1 = Series::new("field1".into(), &["a", "d", "g"]);
466 let field2 = Series::new("field2".into(), &["b", "e", "h"]);
467
468 let s1_fields = [field1.clone(), field2];
469 let s1_struct =
470 StructChunked::from_series("".into(), field1.len(), s1_fields.iter()).unwrap();
471 let s1 = s1_struct.into_series();
472
473 let field1_alt = Series::new("field1".into(), &["a", "DIFFERENT", "g"]);
474 let field2_alt = Series::new("field2".into(), &["b", "e", "h"]);
475
476 let s2_fields = [field1_alt.clone(), field2_alt];
477 let s2_struct =
478 StructChunked::from_series("".into(), field1_alt.len(), s2_fields.iter()).unwrap();
479 let s2 = s2_struct.into_series();
480
481 assert_series_equal!(&s1, &s2);
482 }
483
484 #[test]
485 fn test_series_struct_values_str_match() {
486 let field1 = Series::new("field1".into(), &["a", "d", "g"]);
487 let field2 = Series::new("field2".into(), &["b", "e", "h"]);
488
489 let s1_fields = [field1.clone(), field2.clone()];
490 let s1_struct =
491 StructChunked::from_series("".into(), field1.len(), s1_fields.iter()).unwrap();
492 let s1 = s1_struct.into_series();
493
494 let s2_fields = [field1.clone(), field2];
495 let s2_struct =
496 StructChunked::from_series("".into(), field1.len(), s2_fields.iter()).unwrap();
497 let s2 = s2_struct.into_series();
498
499 assert_series_equal!(&s1, &s2);
500 }
501
502 #[test]
503 #[should_panic(expected = "exact value mismatch")]
504 fn test_series_struct_values_mixed_mismatch() {
505 let id = Series::new("id".into(), &[1, 2, 3]);
506 let value = Series::new("value".into(), &["a", "b", "c"]);
507 let active = Series::new("active".into(), &[true, false, true]);
508
509 let s1_fields = [id.clone(), value.clone(), active.clone()];
510 let s1_struct = StructChunked::from_series("".into(), id.len(), s1_fields.iter()).unwrap();
511 let s1 = s1_struct.into_series();
512
513 let id_alt = Series::new("id".into(), &[1, 99, 3]);
514 let s2_fields = [id_alt, value, active];
515 let s2_struct = StructChunked::from_series("".into(), id.len(), s2_fields.iter()).unwrap();
516 let s2 = s2_struct.into_series();
517
518 assert_series_equal!(&s1, &s2);
519 }
520
521 #[test]
522 fn test_series_struct_values_mixed_match() {
523 let id = Series::new("id".into(), &[1, 2, 3]);
524 let value = Series::new("value".into(), &["a", "b", "c"]);
525 let active = Series::new("active".into(), &[true, false, true]);
526
527 let s1_fields = [id.clone(), value.clone(), active.clone()];
528 let s1_struct = StructChunked::from_series("".into(), id.len(), s1_fields.iter()).unwrap();
529 let s1 = s1_struct.into_series();
530
531 let s2_fields = [id.clone(), value, active];
532 let s2_struct = StructChunked::from_series("".into(), id.len(), s2_fields.iter()).unwrap();
533 let s2 = s2_struct.into_series();
534
535 assert_series_equal!(&s1, &s2);
536 }
537
538 #[test]
540 #[should_panic(expected = "nested value mismatch")]
541 fn test_deeply_nested_list_float_mismatch() {
542 let inner_list_1 = Series::new("inner".into(), &[1.0, 2.0]);
543 let outer_list_1 = Series::new("outer".into(), &[inner_list_1]);
544 let s1 = Series::new("nested".into(), &[outer_list_1]);
545
546 let inner_list_2 = Series::new("inner".into(), &[1.0, 3.0]);
547 let outer_list_2 = Series::new("outer".into(), &[inner_list_2]);
548 let s2 = Series::new("nested".into(), &[outer_list_2]);
549
550 assert_series_equal!(&s1, &s2);
551 }
552 #[test]
553 fn test_deeply_nested_list_float_match() {
554 let inner_list_1 = Series::new("".into(), &[1.0, 2.0]);
555 let outer_list_1 = Series::new("".into(), &[inner_list_1]);
556
557 let s1 = Series::new("".into(), &[outer_list_1]);
558
559 let inner_list_2 = Series::new("".into(), &[1.0, 2.0]);
560 let outer_list_2 = Series::new("".into(), &[inner_list_2]);
561 let s2 = Series::new("".into(), &[outer_list_2]);
562
563 assert_series_equal!(&s1, &s2);
564 }
565
566 #[test]
568 #[should_panic(expected = "exact value mismatch")]
569 fn test_series_datetime_values_mismatch() {
570 let dt1: i64 = 1672567200000000000;
571 let dt2: i64 = 1672653600000000000;
572 let dt3: i64 = 1672657200000000000;
573
574 let s1 = Series::new("".into(), &[dt1, dt2])
575 .cast(&DataType::Datetime(TimeUnit::Nanoseconds, None))
576 .unwrap();
577 let s2 = Series::new("".into(), &[dt1, dt3])
578 .cast(&DataType::Datetime(TimeUnit::Nanoseconds, None))
579 .unwrap();
580
581 assert_series_equal!(&s1, &s2);
582 }
583
584 #[test]
585 fn test_series_datetime_values_match() {
586 let dt1: i64 = 1672567200000000000;
587 let dt2: i64 = 1672653600000000000;
588
589 let s1 = Series::new("".into(), &[dt1, dt2])
590 .cast(&DataType::Datetime(TimeUnit::Nanoseconds, None))
591 .unwrap();
592 let s2 = Series::new("".into(), &[dt1, dt2])
593 .cast(&DataType::Datetime(TimeUnit::Nanoseconds, None))
594 .unwrap();
595
596 assert_series_equal!(&s1, &s2);
597 }
598
599 #[test]
601 #[should_panic(expected = "exact value mismatch")]
602 fn test_series_decimal_values_mismatch() {
603 let s1 = Series::new("".into(), &[1, 2])
604 .cast(&DataType::Decimal(10, 2))
605 .unwrap();
606 let s2 = Series::new("".into(), &[1, 3])
607 .cast(&DataType::Decimal(10, 2))
608 .unwrap();
609
610 assert_series_equal!(&s1, &s2);
611 }
612
613 #[test]
614 fn test_series_decimal_values_match() {
615 let s1 = Series::new("".into(), &[1, 2])
616 .cast(&DataType::Decimal(10, 2))
617 .unwrap();
618 let s2 = Series::new("".into(), &[1, 2])
619 .cast(&DataType::Decimal(10, 2))
620 .unwrap();
621
622 assert_series_equal!(&s1, &s2);
623 }
624
625 #[test]
627 #[should_panic(expected = "exact value mismatch")]
628 fn test_series_binary_values_mismatch() {
629 let s1 = Series::new("".into(), &[vec![1u8, 2, 3], vec![4, 5, 6]])
630 .cast(&DataType::Binary)
631 .unwrap();
632 let s2 = Series::new("".into(), &[vec![1u8, 2, 3], vec![4, 5, 7]])
633 .cast(&DataType::Binary)
634 .unwrap();
635
636 assert_series_equal!(&s1, &s2);
637 }
638
639 #[test]
640 fn test_series_binary_values_match() {
641 let s1 = Series::new("".into(), &[vec![1u8, 2, 3], vec![4, 5, 6]])
642 .cast(&DataType::Binary)
643 .unwrap();
644 let s2 = Series::new("".into(), &[vec![1u8, 2, 3], vec![4, 5, 6]])
645 .cast(&DataType::Binary)
646 .unwrap();
647
648 assert_series_equal!(&s1, &s2);
649 }
650}