Path: blob/main/crates/polars-testing/src/asserts/series.rs
6940 views
/// Asserts that two series are equal according to the specified options.1///2/// This macro compares two Polars Series objects and panics with a detailed error message if they are not equal.3/// It provides two forms:4/// - With custom comparison options5/// - With default comparison options6///7/// # Example8///9/// ```10/// use polars_core::prelude::*;11/// use polars_testing::assert_series_equal;12/// use polars_testing::asserts::SeriesEqualOptions;13///14/// // Create two series to compare15/// let s1 = Series::new("a".into(), &[1, 2, 3]);16/// let s2 = Series::new("a".into(), &[1, 2, 3]);17///18/// // Assert with default options19/// assert_series_equal!(&s1, &s2);20///21/// // Assert with custom options22/// let options = SeriesEqualOptions::default()23/// .with_check_exact(true)24/// .with_check_dtypes(false);25/// assert_series_equal!(&s1, &s2, options);26/// ```27///28/// # Panics29///30/// Panics when the series are not equal according to the specified comparison criteria.31///32#[macro_export]33macro_rules! assert_series_equal {34($left:expr, $right:expr $(, $options:expr)?) => {35{36#[allow(unused_assignments)]37#[allow(unused_mut)]38let mut options = $crate::asserts::SeriesEqualOptions::default();39$(options = $options;)?4041match $crate::asserts::assert_series_equal($left, $right, options) {42Ok(_) => {},43Err(e) => panic!("{}", e),44}45}46};47}4849#[cfg(test)]50mod tests {51use polars_core::prelude::*;5253// Testing default struct implementation54#[test]55fn test_series_equal_options() {56let options = crate::asserts::SeriesEqualOptions::default();5758assert!(options.check_dtypes);59assert!(options.check_names);60assert!(options.check_order);61assert!(options.check_exact);62assert_eq!(options.rel_tol, 1e-5);63assert_eq!(options.abs_tol, 1e-8);64assert!(!options.categorical_as_str);65}6667// Testing with basic parameters68#[test]69#[should_panic(expected = "length mismatch")]70fn test_series_length_mismatch() {71let s1 = Series::new("".into(), &[1, 2]);72let s2 = Series::new("".into(), &[1, 2, 3]);7374assert_series_equal!(&s1, &s2);75}7677#[test]78#[should_panic(expected = "name mismatch")]79fn test_series_names_mismatch() {80let s1 = Series::new("s1".into(), &[1, 2, 3]);81let s2 = Series::new("s2".into(), &[1, 2, 3]);8283assert_series_equal!(&s1, &s2);84}8586#[test]87fn test_series_check_names_false() {88let s1 = Series::new("s1".into(), &[1, 2, 3]);89let s2 = Series::new("s2".into(), &[1, 2, 3]);9091let options = crate::asserts::SeriesEqualOptions::default().with_check_names(false);9293assert_series_equal!(&s1, &s2, options);94}9596#[test]97#[should_panic(expected = "dtype mismatch")]98fn test_series_dtype_mismatch() {99let s1 = Series::new("".into(), &[1, 2, 3]);100let s2 = Series::new("".into(), &["1", "2", "3"]);101102assert_series_equal!(&s1, &s2);103}104105#[test]106fn test_series_check_dtypes_false() {107let s1 = Series::new("s1".into(), &[1, 2, 3]);108let s2 = Series::new("s1".into(), &[1.0, 2.0, 3.0]);109110let options = crate::asserts::SeriesEqualOptions::default().with_check_dtypes(false);111112assert_series_equal!(&s1, &s2, options);113}114115// Testing basic equality116#[test]117#[should_panic(expected = "exact value mismatch")]118fn test_series_value_mismatch_int() {119let s1 = Series::new("".into(), &[1, 2, 3]);120let s2 = Series::new("".into(), &[2, 3, 4]);121122assert_series_equal!(&s1, &s2);123}124125#[test]126fn test_series_values_match_int() {127let s1 = Series::new("".into(), &[1, 2, 3]);128let s2 = Series::new("".into(), &[1, 2, 3]);129130assert_series_equal!(&s1, &s2);131}132133#[test]134#[should_panic(expected = "exact value mismatch")]135fn test_series_value_mismatch_str() {136let s1 = Series::new("".into(), &["foo", "bar"]);137let s2 = Series::new("".into(), &["moo", "car"]);138139assert_series_equal!(&s1, &s2);140}141142#[test]143fn test_series_values_match_str() {144let s1 = Series::new("".into(), &["foo", "bar"]);145let s2 = Series::new("".into(), &["foo", "bar"]);146147assert_series_equal!(&s1, &s2);148}149150#[test]151#[should_panic(expected = "exact value mismatch")]152fn test_series_values_mismatch_float() {153let s1 = Series::new("".into(), &[1.1, 2.2, 3.3]);154let s2 = Series::new("".into(), &[2.2, 3.3, 4.4]);155156assert_series_equal!(&s1, &s2);157}158159#[test]160fn test_series_values_match_float() {161let s1 = Series::new("".into(), &[1.1, 2.2, 3.3]);162let s2 = Series::new("".into(), &[1.1, 2.2, 3.3]);163164assert_series_equal!(&s1, &s2);165}166167// Testing float value precision equality168#[test]169#[should_panic(expected = "values not within tolerance")]170fn test_series_float_exceeded_tol() {171let s1 = Series::new("".into(), &[1.0, 2.2, 3.3]);172let s2 = Series::new("".into(), &[1.00012, 2.200025, 3.300035]);173174let options = crate::asserts::SeriesEqualOptions::default().with_check_exact(false);175176assert_series_equal!(&s1, &s2, options);177}178179#[test]180fn test_series_float_within_tol() {181let s1 = Series::new("".into(), &[1.0, 2.0, 3.0]);182let s2 = Series::new("".into(), &[1.000005, 2.000015, 3.000025]);183184let options = crate::asserts::SeriesEqualOptions::default().with_check_exact(false);185186assert_series_equal!(&s1, &s2, options);187}188189#[test]190fn test_series_float_exact_tolerance_boundary() {191let s1 = Series::new("".into(), &[1.0, 2.0, 3.0]);192let s2 = Series::new("".into(), &[1.0, 2.0 + 1e-5, 3.0]);193194let options = crate::asserts::SeriesEqualOptions::default().with_check_exact(false);195196assert_series_equal!(&s1, &s2, options);197}198199#[test]200fn test_series_float_custom_rel_tol() {201let s1 = Series::new("".into(), &[10.0, 100.0, 1000.0]);202let s2 = Series::new("".into(), &[10.05, 100.1, 1000.2]);203204let options = crate::asserts::SeriesEqualOptions::default()205.with_check_exact(false)206.with_rel_tol(0.01);207208assert_series_equal!(&s1, &s2, options);209}210211#[test]212#[should_panic(expected = "values not within tolerance")]213fn test_series_float_custom_abs_tol() {214let s1 = Series::new("".into(), &[0.001, 0.01, 0.1]);215let s2 = Series::new("".into(), &[0.001, 0.02, 0.1]);216217let options = crate::asserts::SeriesEqualOptions::default()218.with_check_exact(false)219.with_abs_tol(0.005);220221assert_series_equal!(&s1, &s2, options);222}223224// Testing equality with special values225#[test]226fn test_series_empty_equal() {227let s1 = Series::default();228let s2 = Series::default();229230assert_series_equal!(&s1, &s2);231}232233#[test]234fn test_series_nan_equal() {235let s1 = Series::new("".into(), &[f64::NAN, f64::NAN, f64::NAN]);236let s2 = Series::new("".into(), &[f64::NAN, f64::NAN, f64::NAN]);237238assert_series_equal!(&s1, &s2);239}240241#[test]242fn test_series_null_equal() {243let s1 = Series::new("".into(), &[None::<i32>, None::<i32>, None::<i32>]);244let s2 = Series::new("".into(), &[None::<i32>, None::<i32>, None::<i32>]);245246assert_series_equal!(&s1, &s2);247}248249#[test]250#[should_panic(expected = "exact value mismatch")]251fn test_series_infinity_values_mismatch() {252let s1 = Series::new("".into(), &[1.0, f64::INFINITY, 3.0]);253let s2 = Series::new("".into(), &[1.0, f64::NEG_INFINITY, 3.0]);254255assert_series_equal!(&s1, &s2);256}257258#[test]259fn test_series_infinity_values_match() {260let s1 = Series::new("".into(), &[1.0, f64::INFINITY, f64::NEG_INFINITY]);261let s2 = Series::new("".into(), &[1.0, f64::INFINITY, f64::NEG_INFINITY]);262263assert_series_equal!(&s1, &s2);264}265266// Testing null and nan counts for floats267#[test]268#[should_panic(expected = "null value mismatch")]269fn test_series_check_exact_false_null() {270let s1 = Series::new("".into(), &[Some(1.0), None::<f64>, Some(3.0)]);271let s2 = Series::new("".into(), &[Some(1.0), Some(2.0), Some(3.0)]);272273let options = crate::asserts::SeriesEqualOptions::default().with_check_exact(false);274275assert_series_equal!(&s1, &s2, options);276}277278#[test]279#[should_panic(expected = "nan value mismatch")]280fn test_series_check_exact_false_nan() {281let s1 = Series::new("".into(), &[1.0, f64::NAN, 3.0]);282let s2 = Series::new("".into(), &[1.0, 2.0, 3.0]);283284let options = crate::asserts::SeriesEqualOptions::default().with_check_exact(false);285286assert_series_equal!(&s1, &s2, options);287}288289// Testing sorting operations290#[test]291#[should_panic(expected = "exact value mismatch")]292fn test_series_sorting_unequal() {293let s1 = Series::new("".into(), &[Some(1), Some(2), Some(3), None::<i32>]);294let s2 = Series::new("".into(), &[Some(2), None::<i32>, Some(3), Some(1)]);295296let options = crate::asserts::SeriesEqualOptions::default();297298assert_series_equal!(&s1, &s2, options);299}300301#[test]302fn test_series_sorting_equal() {303let s1 = Series::new("".into(), &[Some(1), Some(2), Some(3), None::<i32>]);304let s2 = Series::new("".into(), &[Some(2), None::<i32>, Some(3), Some(1)]);305306let options = crate::asserts::SeriesEqualOptions::default().with_check_order(false);307308assert_series_equal!(&s1, &s2, options);309}310311// Testing categorical operations312#[test]313#[should_panic(expected = "exact value mismatch")]314fn test_series_categorical_mismatch() {315let s1 = Series::new("".into(), &["apple", "banana", "cherry"])316.cast(&DataType::from_categories(Categories::global()))317.unwrap();318let s2 = Series::new("".into(), &["apple", "orange", "cherry"])319.cast(&DataType::from_categories(Categories::global()))320.unwrap();321322assert_series_equal!(&s1, &s2);323}324325#[test]326fn test_series_categorical_match() {327let s1 = Series::new("".into(), &["apple", "banana", "cherry"])328.cast(&DataType::from_categories(Categories::global()))329.unwrap();330let s2 = Series::new("".into(), &["apple", "banana", "cherry"])331.cast(&DataType::from_categories(Categories::global()))332.unwrap();333334assert_series_equal!(&s1, &s2);335}336337#[test]338#[should_panic(expected = "exact value mismatch")]339fn test_series_categorical_str_mismatch() {340let s1 = Series::new("".into(), &["apple", "banana", "cherry"])341.cast(&DataType::from_categories(Categories::global()))342.unwrap();343let s2 = Series::new("".into(), &["apple", "orange", "cherry"])344.cast(&DataType::from_categories(Categories::global()))345.unwrap();346347let options = crate::asserts::SeriesEqualOptions::default().with_categorical_as_str(true);348349assert_series_equal!(&s1, &s2, options);350}351352#[test]353fn test_series_categorical_str_match() {354let s1 = Series::new("".into(), &["apple", "banana", "cherry"])355.cast(&DataType::from_categories(Categories::global()))356.unwrap();357let s2 = Series::new("".into(), &["apple", "banana", "cherry"])358.cast(&DataType::from_categories(Categories::global()))359.unwrap();360361let options = crate::asserts::SeriesEqualOptions::default().with_categorical_as_str(true);362363assert_series_equal!(&s1, &s2, options);364}365366// Testing equality of nested values367#[test]368#[should_panic(expected = "exact value mismatch")]369fn test_series_list_values_int_mismatch() {370let s1 = Series::new(371"".into(),372&[373[1, 2, 3].iter().collect::<Series>(),374[4, 5, 6].iter().collect::<Series>(),375[7, 8, 9].iter().collect::<Series>(),376],377);378379let s2 = Series::new(380"".into(),381&[382[0, 2, 3].iter().collect::<Series>(),383[4, 7, 6].iter().collect::<Series>(),384[7, 8, 10].iter().collect::<Series>(),385],386);387388assert_series_equal!(&s1, &s2);389}390391#[test]392fn test_series_list_values_int_match() {393let s1 = Series::new(394"".into(),395&[396[1, 2, 3].iter().collect::<Series>(),397[4, 5, 6].iter().collect::<Series>(),398[7, 8, 9].iter().collect::<Series>(),399],400);401402let s2 = Series::new(403"".into(),404&[405[1, 2, 3].iter().collect::<Series>(),406[4, 5, 6].iter().collect::<Series>(),407[7, 8, 9].iter().collect::<Series>(),408],409);410411assert_series_equal!(&s1, &s2);412}413414#[test]415#[should_panic(expected = "nested value mismatch")]416fn test_series_list_values_float_mismatch() {417let s1 = Series::new(418"".into(),419&[420[1.1, 2.0, 3.0].iter().collect::<Series>(),421[4.0, 5.0, 6.0].iter().collect::<Series>(),422[7.0, 8.0, 9.0].iter().collect::<Series>(),423],424);425426let s2 = Series::new(427"".into(),428&[429[0.5, 2.0, 3.0].iter().collect::<Series>(),430[4.0, 7.5, 6.0].iter().collect::<Series>(),431[7.0, 8.0, 10.2].iter().collect::<Series>(),432],433);434435assert_series_equal!(&s1, &s2);436}437438#[test]439fn test_series_list_values_float_match() {440let s1 = Series::new(441"".into(),442&[443[1.1, 2.0, 3.0].iter().collect::<Series>(),444[4.0, 5.0, 6.0].iter().collect::<Series>(),445[7.0, 8.0, 9.0].iter().collect::<Series>(),446],447);448449let s2 = Series::new(450"".into(),451&[452[1.1, 2.0, 3.0].iter().collect::<Series>(),453[4.0, 5.0, 6.0].iter().collect::<Series>(),454[7.0, 8.0, 9.0].iter().collect::<Series>(),455],456);457458assert_series_equal!(&s1, &s2);459}460461#[test]462#[should_panic(expected = "exact value mismatch")]463fn test_series_struct_values_str_mismatch() {464let field1 = Series::new("field1".into(), &["a", "d", "g"]);465let field2 = Series::new("field2".into(), &["b", "e", "h"]);466467let s1_fields = [field1.clone(), field2];468let s1_struct =469StructChunked::from_series("".into(), field1.len(), s1_fields.iter()).unwrap();470let s1 = s1_struct.into_series();471472let field1_alt = Series::new("field1".into(), &["a", "DIFFERENT", "g"]);473let field2_alt = Series::new("field2".into(), &["b", "e", "h"]);474475let s2_fields = [field1_alt.clone(), field2_alt];476let s2_struct =477StructChunked::from_series("".into(), field1_alt.len(), s2_fields.iter()).unwrap();478let s2 = s2_struct.into_series();479480assert_series_equal!(&s1, &s2);481}482483#[test]484fn test_series_struct_values_str_match() {485let field1 = Series::new("field1".into(), &["a", "d", "g"]);486let field2 = Series::new("field2".into(), &["b", "e", "h"]);487488let s1_fields = [field1.clone(), field2.clone()];489let s1_struct =490StructChunked::from_series("".into(), field1.len(), s1_fields.iter()).unwrap();491let s1 = s1_struct.into_series();492493let s2_fields = [field1.clone(), field2];494let s2_struct =495StructChunked::from_series("".into(), field1.len(), s2_fields.iter()).unwrap();496let s2 = s2_struct.into_series();497498assert_series_equal!(&s1, &s2);499}500501#[test]502#[should_panic(expected = "exact value mismatch")]503fn test_series_struct_values_mixed_mismatch() {504let id = Series::new("id".into(), &[1, 2, 3]);505let value = Series::new("value".into(), &["a", "b", "c"]);506let active = Series::new("active".into(), &[true, false, true]);507508let s1_fields = [id.clone(), value.clone(), active.clone()];509let s1_struct = StructChunked::from_series("".into(), id.len(), s1_fields.iter()).unwrap();510let s1 = s1_struct.into_series();511512let id_alt = Series::new("id".into(), &[1, 99, 3]);513let s2_fields = [id_alt, value, active];514let s2_struct = StructChunked::from_series("".into(), id.len(), s2_fields.iter()).unwrap();515let s2 = s2_struct.into_series();516517assert_series_equal!(&s1, &s2);518}519520#[test]521fn test_series_struct_values_mixed_match() {522let id = Series::new("id".into(), &[1, 2, 3]);523let value = Series::new("value".into(), &["a", "b", "c"]);524let active = Series::new("active".into(), &[true, false, true]);525526let s1_fields = [id.clone(), value.clone(), active.clone()];527let s1_struct = StructChunked::from_series("".into(), id.len(), s1_fields.iter()).unwrap();528let s1 = s1_struct.into_series();529530let s2_fields = [id.clone(), value, active];531let s2_struct = StructChunked::from_series("".into(), id.len(), s2_fields.iter()).unwrap();532let s2 = s2_struct.into_series();533534assert_series_equal!(&s1, &s2);535}536537// Testing equality of deeply nested values538#[test]539#[should_panic(expected = "nested value mismatch")]540fn test_deeply_nested_list_float_mismatch() {541let inner_list_1 = Series::new("inner".into(), &[1.0, 2.0]);542let outer_list_1 = Series::new("outer".into(), &[inner_list_1]);543let s1 = Series::new("nested".into(), &[outer_list_1]);544545let inner_list_2 = Series::new("inner".into(), &[1.0, 3.0]);546let outer_list_2 = Series::new("outer".into(), &[inner_list_2]);547let s2 = Series::new("nested".into(), &[outer_list_2]);548549assert_series_equal!(&s1, &s2);550}551#[test]552fn test_deeply_nested_list_float_match() {553let inner_list_1 = Series::new("".into(), &[1.0, 2.0]);554let outer_list_1 = Series::new("".into(), &[inner_list_1]);555556let s1 = Series::new("".into(), &[outer_list_1]);557558let inner_list_2 = Series::new("".into(), &[1.0, 2.0]);559let outer_list_2 = Series::new("".into(), &[inner_list_2]);560let s2 = Series::new("".into(), &[outer_list_2]);561562assert_series_equal!(&s1, &s2);563}564565// Testing equality of temporal types566#[test]567#[should_panic(expected = "exact value mismatch")]568fn test_series_datetime_values_mismatch() {569let dt1: i64 = 1672567200000000000;570let dt2: i64 = 1672653600000000000;571let dt3: i64 = 1672657200000000000;572573let s1 = Series::new("".into(), &[dt1, dt2])574.cast(&DataType::Datetime(TimeUnit::Nanoseconds, None))575.unwrap();576let s2 = Series::new("".into(), &[dt1, dt3])577.cast(&DataType::Datetime(TimeUnit::Nanoseconds, None))578.unwrap();579580assert_series_equal!(&s1, &s2);581}582583#[test]584fn test_series_datetime_values_match() {585let dt1: i64 = 1672567200000000000;586let dt2: i64 = 1672653600000000000;587588let s1 = Series::new("".into(), &[dt1, dt2])589.cast(&DataType::Datetime(TimeUnit::Nanoseconds, None))590.unwrap();591let s2 = Series::new("".into(), &[dt1, dt2])592.cast(&DataType::Datetime(TimeUnit::Nanoseconds, None))593.unwrap();594595assert_series_equal!(&s1, &s2);596}597598// Testing equality of decimal types599#[test]600#[should_panic(expected = "exact value mismatch")]601fn test_series_decimal_values_mismatch() {602let s1 = Series::new("".into(), &[1, 2])603.cast(&DataType::Decimal(Some(10), Some(2)))604.unwrap();605let s2 = Series::new("".into(), &[1, 3])606.cast(&DataType::Decimal(Some(10), Some(2)))607.unwrap();608609assert_series_equal!(&s1, &s2);610}611612#[test]613fn test_series_decimal_values_match() {614let s1 = Series::new("".into(), &[1, 2])615.cast(&DataType::Decimal(Some(10), Some(2)))616.unwrap();617let s2 = Series::new("".into(), &[1, 2])618.cast(&DataType::Decimal(Some(10), Some(2)))619.unwrap();620621assert_series_equal!(&s1, &s2);622}623624// Testing equality of binary types625#[test]626#[should_panic(expected = "exact value mismatch")]627fn test_series_binary_values_mismatch() {628let s1 = Series::new("".into(), &[vec![1u8, 2, 3], vec![4, 5, 6]])629.cast(&DataType::Binary)630.unwrap();631let s2 = Series::new("".into(), &[vec![1u8, 2, 3], vec![4, 5, 7]])632.cast(&DataType::Binary)633.unwrap();634635assert_series_equal!(&s1, &s2);636}637638#[test]639fn test_series_binary_values_match() {640let s1 = Series::new("".into(), &[vec![1u8, 2, 3], vec![4, 5, 6]])641.cast(&DataType::Binary)642.unwrap();643let s2 = Series::new("".into(), &[vec![1u8, 2, 3], vec![4, 5, 6]])644.cast(&DataType::Binary)645.unwrap();646647assert_series_equal!(&s1, &s2);648}649}650651652