#[macro_export]
macro_rules! assert_dataframe_equal {
($left:expr, $right:expr $(, $options:expr)?) => {
#[allow(unused_assignments)]
#[allow(unused_mut)]
let mut options = $crate::asserts::DataFrameEqualOptions::default();
$(options = $options;)?
match $crate::asserts::assert_dataframe_equal($left, $right, options) {
Ok(_) => {},
Err(e) => panic!("{}", e),
}
};
}
#[cfg(test)]
mod tests {
#[allow(unused_imports)]
use polars_core::prelude::*;
#[test]
fn test_dataframe_equal_options() {
let options = crate::asserts::DataFrameEqualOptions::default();
assert!(options.check_row_order);
assert!(options.check_column_order);
assert!(options.check_dtypes);
assert!(!options.check_exact);
assert_eq!(options.rel_tol, 1e-5);
assert_eq!(options.abs_tol, 1e-8);
assert!(!options.categorical_as_str);
}
#[test]
#[should_panic(expected = "height (row count) mismatch")]
fn test_dataframe_height_mismatch() {
let df1 = DataFrame::new_infer_height(vec![
Series::new("col1".into(), &[1, 2]).into(),
Series::new("col2".into(), &["a", "b"]).into(),
])
.unwrap();
let df2 = DataFrame::new_infer_height(vec![
Series::new("col1".into(), &[1, 2, 3]).into(),
Series::new("col2".into(), &["a", "b", "c"]).into(),
])
.unwrap();
assert_dataframe_equal!(&df1, &df2);
}
#[test]
#[should_panic(expected = "columns mismatch")]
fn test_dataframe_column_mismatch() {
let df1 = DataFrame::new_infer_height(vec![
Series::new("col1".into(), &[1, 2, 3]).into(),
Series::new("col2".into(), &["a", "b", "c"]).into(),
])
.unwrap();
let df2 = DataFrame::new_infer_height(vec![
Series::new("col1".into(), &[1, 2, 3]).into(),
Series::new("different_col".into(), &["a", "b", "c"]).into(),
])
.unwrap();
assert_dataframe_equal!(&df1, &df2);
}
#[test]
#[should_panic(expected = "dtypes do not match")]
fn test_dataframe_dtype_mismatch() {
let df1 = DataFrame::new_infer_height(vec![
Series::new("col1".into(), &[1, 2, 3]).into(),
Series::new("col2".into(), &["a", "b", "c"]).into(),
])
.unwrap();
let df2 = DataFrame::new_infer_height(vec![
Series::new("col1".into(), &[1.0, 2.0, 3.0]).into(),
Series::new("col2".into(), &["a", "b", "c"]).into(),
])
.unwrap();
assert_dataframe_equal!(&df1, &df2);
}
#[test]
fn test_dataframe_dtype_mismatch_ignored() {
let df1 = DataFrame::new_infer_height(vec![
Series::new("col1".into(), &[1, 2, 3]).into(),
Series::new("col2".into(), &["a", "b", "c"]).into(),
])
.unwrap();
let df2 = DataFrame::new_infer_height(vec![
Series::new("col1".into(), &[1.0, 2.0, 3.0]).into(),
Series::new("col2".into(), &["a", "b", "c"]).into(),
])
.unwrap();
let options = crate::asserts::DataFrameEqualOptions::default().with_check_dtypes(false);
assert_dataframe_equal!(&df1, &df2, options);
}
#[test]
#[should_panic(expected = "columns are not in the same order")]
fn test_dataframe_column_order_mismatch() {
let df1 = DataFrame::new_infer_height(vec![
Series::new("col1".into(), &[1, 2, 3]).into(),
Series::new("col2".into(), &["a", "b", "c"]).into(),
])
.unwrap();
let df2 = DataFrame::new_infer_height(vec![
Series::new("col2".into(), &["a", "b", "c"]).into(),
Series::new("col1".into(), &[1, 2, 3]).into(),
])
.unwrap();
assert_dataframe_equal!(&df1, &df2);
}
#[test]
fn test_dataframe_column_order_mismatch_ignored() {
let df1 = DataFrame::new_infer_height(vec![
Series::new("col1".into(), &[1, 2, 3]).into(),
Series::new("col2".into(), &["a", "b", "c"]).into(),
])
.unwrap();
let df2 = DataFrame::new_infer_height(vec![
Series::new("col2".into(), &["a", "b", "c"]).into(),
Series::new("col1".into(), &[1, 2, 3]).into(),
])
.unwrap();
let options =
crate::asserts::DataFrameEqualOptions::default().with_check_column_order(false);
assert_dataframe_equal!(&df1, &df2, options);
}
#[test]
#[should_panic(expected = "columns mismatch: [\"col3\"] in left, but not in right")]
fn test_dataframe_left_has_extra_column() {
let df1 = DataFrame::new_infer_height(vec![
Series::new("col1".into(), &[1, 2, 3]).into(),
Series::new("col2".into(), &["a", "b", "c"]).into(),
Series::new("col3".into(), &[true, false, true]).into(),
])
.unwrap();
let df2 = DataFrame::new_infer_height(vec![
Series::new("col1".into(), &[1, 2, 3]).into(),
Series::new("col2".into(), &["a", "b", "c"]).into(),
])
.unwrap();
assert_dataframe_equal!(&df1, &df2);
}
#[test]
#[should_panic(expected = "columns mismatch: [\"col3\"] in right, but not in left")]
fn test_dataframe_right_has_extra_column() {
let df1 = DataFrame::new_infer_height(vec![
Series::new("col1".into(), &[1, 2, 3]).into(),
Series::new("col2".into(), &["a", "b", "c"]).into(),
])
.unwrap();
let df2 = DataFrame::new_infer_height(vec![
Series::new("col1".into(), &[1, 2, 3]).into(),
Series::new("col2".into(), &["a", "b", "c"]).into(),
Series::new("col3".into(), &[true, false, true]).into(),
])
.unwrap();
assert_dataframe_equal!(&df1, &df2);
}
#[test]
#[should_panic(expected = "value mismatch for column")]
fn test_dataframe_value_mismatch() {
let df1 = DataFrame::new_infer_height(vec![
Series::new("col1".into(), &[1, 2, 3]).into(),
Series::new("col2".into(), &["a", "b", "c"]).into(),
Series::new("col3".into(), &[true, false, true]).into(),
])
.unwrap();
let df2 = DataFrame::new_infer_height(vec![
Series::new("col1".into(), &[1, 2, 3]).into(),
Series::new("col2".into(), &["a", "b", "changed"]).into(),
Series::new("col3".into(), &[true, false, true]).into(),
])
.unwrap();
assert_dataframe_equal!(&df1, &df2);
}
#[test]
fn test_dataframe_equal() {
let df1 = DataFrame::new_infer_height(vec![
Series::new("col1".into(), &[1, 2, 3]).into(),
Series::new("col2".into(), &["a", "b", "c"]).into(),
Series::new("col3".into(), &[true, false, true]).into(),
])
.unwrap();
let df2 = DataFrame::new_infer_height(vec![
Series::new("col1".into(), &[1, 2, 3]).into(),
Series::new("col2".into(), &["a", "b", "c"]).into(),
Series::new("col3".into(), &[true, false, true]).into(),
])
.unwrap();
assert_dataframe_equal!(&df1, &df2);
}
#[test]
#[should_panic(expected = "value mismatch")]
fn test_dataframe_row_order_mismatch() {
let df1 = DataFrame::new_infer_height(vec![
Series::new("col1".into(), &[1, 2, 3]).into(),
Series::new("col2".into(), &["a", "b", "c"]).into(),
])
.unwrap();
let df2 = DataFrame::new_infer_height(vec![
Series::new("col1".into(), &[3, 1, 2]).into(),
Series::new("col2".into(), &["c", "a", "b"]).into(),
])
.unwrap();
assert_dataframe_equal!(&df1, &df2);
}
#[test]
fn test_dataframe_row_order_ignored() {
let df1 = DataFrame::new_infer_height(vec![
Series::new("col1".into(), &[1, 2, 3]).into(),
Series::new("col2".into(), &["a", "b", "c"]).into(),
])
.unwrap();
let df2 = DataFrame::new_infer_height(vec![
Series::new("col1".into(), &[3, 1, 2]).into(),
Series::new("col2".into(), &["c", "a", "b"]).into(),
])
.unwrap();
let options = crate::asserts::DataFrameEqualOptions::default().with_check_row_order(false);
assert_dataframe_equal!(&df1, &df2, options);
}
#[test]
#[should_panic(expected = "value mismatch")]
fn test_dataframe_complex_mismatch() {
let df1 = DataFrame::new_infer_height(vec![
Series::new("integers".into(), &[1, 2, 3, 4, 5]).into(),
Series::new("floats".into(), &[1.1, 2.2, 3.3, 4.4, 5.5]).into(),
Series::new("strings".into(), &["a", "b", "c", "d", "e"]).into(),
Series::new("booleans".into(), &[true, false, true, false, true]).into(),
Series::new("opt_ints".into(), &[Some(1), None, Some(3), Some(4), None]).into(),
])
.unwrap();
let df2 = DataFrame::new_infer_height(vec![
Series::new("integers".into(), &[1, 2, 99, 4, 5]).into(),
Series::new("floats".into(), &[1.1, 2.2, 3.3, 9.9, 5.5]).into(),
Series::new("strings".into(), &["a", "b", "c", "CHANGED", "e"]).into(),
Series::new("booleans".into(), &[true, false, false, false, true]).into(),
Series::new("opt_ints".into(), &[Some(1), None, Some(3), None, None]).into(),
])
.unwrap();
assert_dataframe_equal!(&df1, &df2);
}
#[test]
fn test_dataframe_complex_match() {
let df1 = DataFrame::new_infer_height(vec![
Series::new("integers".into(), &[1, 2, 3, 4, 5]).into(),
Series::new("floats".into(), &[1.1, 2.2, 3.3, 4.4, 5.5]).into(),
Series::new("strings".into(), &["a", "b", "c", "d", "e"]).into(),
Series::new("booleans".into(), &[true, false, true, false, true]).into(),
Series::new("opt_ints".into(), &[Some(1), None, Some(3), Some(4), None]).into(),
])
.unwrap();
let df2 = DataFrame::new_infer_height(vec![
Series::new("integers".into(), &[1, 2, 3, 4, 5]).into(),
Series::new("floats".into(), &[1.1, 2.2, 3.3, 4.4, 5.5]).into(),
Series::new("strings".into(), &["a", "b", "c", "d", "e"]).into(),
Series::new("booleans".into(), &[true, false, true, false, true]).into(),
Series::new("opt_ints".into(), &[Some(1), None, Some(3), Some(4), None]).into(),
])
.unwrap();
assert_dataframe_equal!(&df1, &df2);
}
#[test]
#[should_panic(expected = "value mismatch")]
fn test_dataframe_numeric_exact_fail() {
let df1 = DataFrame::new_infer_height(vec![
Series::new("col1".into(), &[1.0000001, 2.0000002, 3.0000003]).into(),
])
.unwrap();
let df2 =
DataFrame::new_infer_height(vec![Series::new("col1".into(), &[1.0, 2.0, 3.0]).into()])
.unwrap();
let options = crate::asserts::DataFrameEqualOptions::default().with_check_exact(true);
assert_dataframe_equal!(&df1, &df2, options);
}
#[test]
fn test_dataframe_numeric_tolerance_pass() {
let df1 = DataFrame::new_infer_height(vec![
Series::new("col1".into(), &[1.0000001, 2.0000002, 3.0000003]).into(),
])
.unwrap();
let df2 =
DataFrame::new_infer_height(vec![Series::new("col1".into(), &[1.0, 2.0, 3.0]).into()])
.unwrap();
assert_dataframe_equal!(&df1, &df2);
}
#[test]
fn test_empty_dataframe_equal() {
let df1 = DataFrame::empty();
let df2 = DataFrame::empty();
assert_dataframe_equal!(&df1, &df2);
}
#[test]
fn test_empty_dataframe_schema_equal() {
let df1 = DataFrame::new_infer_height(vec![
Series::new("col1".into(), &Vec::<i32>::new()).into(),
Series::new("col2".into(), &Vec::<String>::new()).into(),
])
.unwrap();
let df2 = DataFrame::new_infer_height(vec![
Series::new("col1".into(), &Vec::<i32>::new()).into(),
Series::new("col2".into(), &Vec::<String>::new()).into(),
])
.unwrap();
assert_dataframe_equal!(&df1, &df2);
}
#[test]
#[should_panic(expected = "value mismatch")]
fn test_dataframe_single_row_mismatch() {
let df1 = DataFrame::new_infer_height(vec![
Series::new("col1".into(), &[42]).into(),
Series::new("col2".into(), &["value"]).into(),
Series::new("col3".into(), &[true]).into(),
])
.unwrap();
let df2 = DataFrame::new_infer_height(vec![
Series::new("col1".into(), &[42]).into(),
Series::new("col2".into(), &["different"]).into(),
Series::new("col3".into(), &[true]).into(),
])
.unwrap();
assert_dataframe_equal!(&df1, &df2);
}
#[test]
fn test_dataframe_single_row_match() {
let df1 = DataFrame::new_infer_height(vec![
Series::new("col1".into(), &[42]).into(),
Series::new("col2".into(), &["value"]).into(),
Series::new("col3".into(), &[true]).into(),
])
.unwrap();
let df2 = DataFrame::new_infer_height(vec![
Series::new("col1".into(), &[42]).into(),
Series::new("col2".into(), &["value"]).into(),
Series::new("col3".into(), &[true]).into(),
])
.unwrap();
assert_dataframe_equal!(&df1, &df2);
}
#[test]
#[should_panic(expected = "value mismatch")]
fn test_dataframe_null_values_mismatch() {
let df1 = DataFrame::new_infer_height(vec![
Series::new("col1".into(), &[Some(1), None, Some(3)]).into(),
])
.unwrap();
let df2 = DataFrame::new_infer_height(vec![
Series::new("col1".into(), &[Some(1), Some(2), None]).into(),
])
.unwrap();
assert_dataframe_equal!(&df1, &df2);
}
#[test]
fn test_dataframe_null_values_match() {
let df1 = DataFrame::new_infer_height(vec![
Series::new("col1".into(), &[Some(1), None, Some(3)]).into(),
])
.unwrap();
let df2 = DataFrame::new_infer_height(vec![
Series::new("col1".into(), &[Some(1), None, Some(3)]).into(),
])
.unwrap();
assert_dataframe_equal!(&df1, &df2);
}
#[test]
#[should_panic(expected = "value mismatch")]
fn test_dataframe_nan_values_mismatch() {
let df1 = DataFrame::new_infer_height(vec![
Series::new("col1".into(), &[1.0, f64::NAN, 3.0]).into(),
])
.unwrap();
let df2 = DataFrame::new_infer_height(vec![
Series::new("col1".into(), &[1.0, 2.0, f64::NAN]).into(),
])
.unwrap();
assert_dataframe_equal!(&df1, &df2);
}
#[test]
fn test_dataframe_nan_values_match() {
let df1 = DataFrame::new_infer_height(vec![
Series::new("col1".into(), &[1.0, f64::NAN, 3.0]).into(),
])
.unwrap();
let df2 = DataFrame::new_infer_height(vec![
Series::new("col1".into(), &[1.0, f64::NAN, 3.0]).into(),
])
.unwrap();
assert_dataframe_equal!(&df1, &df2);
}
#[test]
#[should_panic(expected = "value mismatch")]
fn test_dataframe_infinity_values_mismatch() {
let df1 = DataFrame::new_infer_height(vec![
Series::new("col1".into(), &[1.0, f64::INFINITY, 3.0]).into(),
])
.unwrap();
let df2 = DataFrame::new_infer_height(vec![
Series::new("col1".into(), &[1.0, f64::NEG_INFINITY, 3.0]).into(),
])
.unwrap();
assert_dataframe_equal!(&df1, &df2);
}
#[test]
fn test_dataframe_infinity_values_match() {
let df1 = DataFrame::new_infer_height(vec![
Series::new("col1".into(), &[1.0, f64::INFINITY, 3.0]).into(),
])
.unwrap();
let df2 = DataFrame::new_infer_height(vec![
Series::new("col1".into(), &[1.0, f64::INFINITY, 3.0]).into(),
])
.unwrap();
assert_dataframe_equal!(&df1, &df2);
}
#[test]
#[should_panic(expected = "value mismatch")]
fn test_dataframe_categorical_as_string_mismatch() {
let mut categorical1 = Series::new("categories".into(), &["a", "b", "c", "d"]);
categorical1 = categorical1
.cast(&DataType::from_categories(Categories::global()))
.unwrap();
let df1 = DataFrame::new_infer_height(vec![categorical1.into()]).unwrap();
let mut categorical2 = Series::new("categories".into(), &["a", "b", "c", "e"]);
categorical2 = categorical2
.cast(&DataType::from_categories(Categories::global()))
.unwrap();
let df2 = DataFrame::new_infer_height(vec![categorical2.into()]).unwrap();
let options =
crate::asserts::DataFrameEqualOptions::default().with_categorical_as_str(true);
assert_dataframe_equal!(&df1, &df2, options);
}
#[test]
fn test_dataframe_categorical_as_string_match() {
let mut categorical1 = Series::new("categories".into(), &["a", "b", "c", "d"]);
categorical1 = categorical1
.cast(&DataType::from_categories(Categories::global()))
.unwrap();
let df1 = DataFrame::new_infer_height(vec![categorical1.into()]).unwrap();
let mut categorical2 = Series::new("categories".into(), &["a", "b", "c", "d"]);
categorical2 = categorical2
.cast(&DataType::from_categories(Categories::global()))
.unwrap();
let df2 = DataFrame::new_infer_height(vec![categorical2.into()]).unwrap();
let options =
crate::asserts::DataFrameEqualOptions::default().with_categorical_as_str(true);
assert_dataframe_equal!(&df1, &df2, options);
}
#[test]
#[should_panic(expected = "value mismatch")]
fn test_dataframe_nested_values_mismatch() {
let df1 = DataFrame::new_infer_height(vec![
Series::new(
"list_col".into(),
&[
Some(vec![1, 2, 3]),
Some(vec![4, 5, 6]),
None,
Some(vec![7, 8, 9]),
],
)
.into(),
])
.unwrap();
let df2 = DataFrame::new_infer_height(vec![
Series::new(
"list_col".into(),
&[
Some(vec![1, 2, 3]),
Some(vec![4, 5, 99]),
None,
Some(vec![7, 8, 9]),
],
)
.into(),
])
.unwrap();
assert_dataframe_equal!(&df1, &df2);
}
#[test]
fn test_dataframe_nested_values_match() {
let df1 = DataFrame::new_infer_height(vec![
Series::new(
"list_col".into(),
&[Some(vec![1, 2, 3]), Some(vec![]), None, Some(vec![7, 8, 9])],
)
.into(),
])
.unwrap();
let df2 = DataFrame::new_infer_height(vec![
Series::new(
"list_col".into(),
&[Some(vec![1, 2, 3]), Some(vec![]), None, Some(vec![7, 8, 9])],
)
.into(),
])
.unwrap();
assert_dataframe_equal!(&df1, &df2);
}
}