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