import numpy as np
import pytest

from pandas.errors import Pandas4Warning

import pandas as pd
import pandas._testing as tm


def _assert_series_equal_both(a, b, **kwargs):
    """
    Check that two Series equal.

    This check is performed commutatively.

    Parameters
    ----------
    a : Series
        The first Series to compare.
    b : Series
        The second Series to compare.
    kwargs : dict
        The arguments passed to `tm.assert_series_equal`.
    """
    tm.assert_series_equal(a, b, **kwargs)
    tm.assert_series_equal(b, a, **kwargs)


def _assert_not_series_equal(a, b, **kwargs):
    """
    Check that two Series are not equal.

    Parameters
    ----------
    a : Series
        The first Series to compare.
    b : Series
        The second Series to compare.
    kwargs : dict
        The arguments passed to `tm.assert_series_equal`.
    """
    try:
        tm.assert_series_equal(a, b, **kwargs)
        msg = "The two Series were equal when they shouldn't have been"

        pytest.fail(msg=msg)
    except AssertionError:
        pass


def _assert_not_series_equal_both(a, b, **kwargs):
    """
    Check that two Series are not equal.

    This check is performed commutatively.

    Parameters
    ----------
    a : Series
        The first Series to compare.
    b : Series
        The second Series to compare.
    kwargs : dict
        The arguments passed to `tm.assert_series_equal`.
    """
    _assert_not_series_equal(a, b, **kwargs)
    _assert_not_series_equal(b, a, **kwargs)


@pytest.mark.parametrize("data", [range(3), list("abc"), list("áàä")])
def test_series_equal(data):
    _assert_series_equal_both(pd.Series(data), pd.Series(data))


@pytest.mark.parametrize(
    "data1,data2",
    [
        (range(3), range(1, 4)),
        (list("abc"), list("xyz")),
        (list("áàä"), list("éèë")),
        (list("áàä"), list(b"aaa")),
        (range(3), range(4)),
    ],
)
def test_series_not_equal_value_mismatch(data1, data2):
    _assert_not_series_equal_both(pd.Series(data1), pd.Series(data2))


@pytest.mark.parametrize(
    "kwargs",
    [
        {"dtype": "float64"},  # dtype mismatch
        {"index": [1, 2, 4]},  # index mismatch
        {"name": "foo"},  # name mismatch
    ],
)
def test_series_not_equal_metadata_mismatch(kwargs):
    data = range(3)
    s1 = pd.Series(data)

    s2 = pd.Series(data, **kwargs)
    _assert_not_series_equal_both(s1, s2)


@pytest.mark.parametrize("data1,data2", [(0.12345, 0.12346), (0.1235, 0.1236)])
@pytest.mark.parametrize("decimals", [0, 1, 2, 3, 5, 10])
def test_less_precise(data1, data2, any_float_dtype, decimals):
    rtol = 10**-decimals
    s1 = pd.Series([data1], dtype=any_float_dtype)
    s2 = pd.Series([data2], dtype=any_float_dtype)

    if decimals in (5, 10) or (decimals >= 3 and abs(data1 - data2) >= 0.0005):
        msg = "Series values are different"
        with pytest.raises(AssertionError, match=msg):
            tm.assert_series_equal(s1, s2, rtol=rtol)
    else:
        _assert_series_equal_both(s1, s2, rtol=rtol)


@pytest.mark.parametrize(
    "s1,s2,msg",
    [
        # Index
        (
            pd.Series(["l1", "l2"], index=[1, 2]),
            pd.Series(["l1", "l2"], index=[1.0, 2.0]),
            "Series\\.index are different",
        ),
        # MultiIndex
        (
            pd.DataFrame({"a": [1, 2], "b": [2.1, 1.5], "c": ["l1", "l2"]}).set_index(
                ["a", "b"]
            )["c"],
            pd.DataFrame(
                {"a": [1.0, 2.0], "b": [2.1, 1.5], "c": ["l1", "l2"]}
            ).set_index(["a", "b"])["c"],
            "Series\\.index level \\[0\\] are different",
        ),
    ],
)
def test_series_equal_index_dtype(s1, s2, msg, check_index_type):
    kwargs = {"check_index_type": check_index_type}

    if check_index_type:
        with pytest.raises(AssertionError, match=msg):
            tm.assert_series_equal(s1, s2, **kwargs)
    else:
        tm.assert_series_equal(s1, s2, **kwargs)


@pytest.mark.parametrize("check_like", [True, False])
def test_series_equal_order_mismatch(check_like):
    s1 = pd.Series([1, 2, 3], index=["a", "b", "c"])
    s2 = pd.Series([3, 2, 1], index=["c", "b", "a"])

    if not check_like:  # Do not ignore index ordering.
        with pytest.raises(AssertionError, match="Series.index are different"):
            tm.assert_series_equal(s1, s2, check_like=check_like)
    else:
        _assert_series_equal_both(s1, s2, check_like=check_like)


@pytest.mark.parametrize("check_index", [True, False])
def test_series_equal_index_mismatch(check_index):
    s1 = pd.Series([1, 2, 3], index=["a", "b", "c"])
    s2 = pd.Series([1, 2, 3], index=["c", "b", "a"])

    if check_index:  # Do not ignore index.
        with pytest.raises(AssertionError, match="Series.index are different"):
            tm.assert_series_equal(s1, s2, check_index=check_index)
    else:
        _assert_series_equal_both(s1, s2, check_index=check_index)


def test_series_invalid_param_combination():
    left = pd.Series(dtype=object)
    right = pd.Series(dtype=object)
    with pytest.raises(
        ValueError, match="check_like must be False if check_index is False"
    ):
        tm.assert_series_equal(left, right, check_index=False, check_like=True)


def test_series_equal_length_mismatch(rtol):
    msg = """Series are different

Series length are different
\\[left\\]:  3, RangeIndex\\(start=0, stop=3, step=1\\)
\\[right\\]: 4, RangeIndex\\(start=0, stop=4, step=1\\)"""

    s1 = pd.Series([1, 2, 3])
    s2 = pd.Series([1, 2, 3, 4])

    with pytest.raises(AssertionError, match=msg):
        tm.assert_series_equal(s1, s2, rtol=rtol)


def test_series_equal_numeric_values_mismatch(rtol):
    msg = """Series are different

Series values are different \\(33\\.33333 %\\)
\\[index\\]: \\[0, 1, 2\\]
\\[left\\]:  \\[1, 2, 3\\]
\\[right\\]: \\[1, 2, 4\\]"""

    s1 = pd.Series([1, 2, 3])
    s2 = pd.Series([1, 2, 4])

    with pytest.raises(AssertionError, match=msg):
        tm.assert_series_equal(s1, s2, rtol=rtol)


def test_series_equal_categorical_values_mismatch(rtol, using_infer_string):
    dtype = "str" if using_infer_string else "object"
    msg = f"""Series are different

Series values are different \\(66\\.66667 %\\)
\\[index\\]: \\[0, 1, 2\\]
\\[left\\]:  \\['a', 'b', 'c'\\]
Categories \\(3, {dtype}\\): \\['a', 'b', 'c'\\]
\\[right\\]: \\['a', 'c', 'b'\\]
Categories \\(3, {dtype}\\): \\['a', 'b', 'c'\\]"""

    s1 = pd.Series(pd.Categorical(["a", "b", "c"]))
    s2 = pd.Series(pd.Categorical(["a", "c", "b"]))

    with pytest.raises(AssertionError, match=msg):
        tm.assert_series_equal(s1, s2, rtol=rtol)


def test_series_equal_datetime_values_mismatch(rtol):
    msg = """Series are different

Series values are different \\(100.0 %\\)
\\[index\\]: \\[0, 1, 2\\]
\\[left\\]:  \\[1514764800000000000, 1514851200000000000, 1514937600000000000\\]
\\[right\\]: \\[1549065600000000000, 1549152000000000000, 1549238400000000000\\]"""

    s1 = pd.Series(pd.date_range("2018-01-01", periods=3, freq="D", unit="ns"))
    s2 = pd.Series(pd.date_range("2019-02-02", periods=3, freq="D", unit="ns"))

    with pytest.raises(AssertionError, match=msg):
        tm.assert_series_equal(s1, s2, rtol=rtol)


def test_series_equal_categorical_mismatch(check_categorical, using_infer_string):
    if using_infer_string:
        dtype = "str"
    else:
        dtype = "object"
    msg = f"""Attributes of Series are different

Attribute "dtype" are different
\\[left\\]:  CategoricalDtype\\(categories=\\['a', 'b'\\], ordered=False, \
categories_dtype={dtype}\\)
\\[right\\]: CategoricalDtype\\(categories=\\['a', 'b', 'c'\\], \
ordered=False, categories_dtype={dtype}\\)"""

    s1 = pd.Series(pd.Categorical(["a", "b"]))
    s2 = pd.Series(pd.Categorical(["a", "b"], categories=list("abc")))

    if check_categorical:
        with pytest.raises(AssertionError, match=msg):
            tm.assert_series_equal(s1, s2, check_categorical=check_categorical)
    else:
        _assert_series_equal_both(s1, s2, check_categorical=check_categorical)


def test_assert_series_equal_extension_dtype_mismatch():
    # https://github.com/pandas-dev/pandas/issues/32747
    left = pd.Series(pd.array([1, 2, 3], dtype="Int64"))
    right = left.astype(int)

    msg = """Attributes of Series are different

Attribute "dtype" are different
\\[left\\]:  Int64
\\[right\\]: int[32|64]"""

    tm.assert_series_equal(left, right, check_dtype=False)

    with pytest.raises(AssertionError, match=msg):
        tm.assert_series_equal(left, right, check_dtype=True)


def test_assert_series_equal_interval_dtype_mismatch():
    # https://github.com/pandas-dev/pandas/issues/32747
    left = pd.Series([pd.Interval(0, 1)], dtype="interval")
    right = left.astype(object)

    msg = """Attributes of Series are different

Attribute "dtype" are different
\\[left\\]:  interval\\[int64, right\\]
\\[right\\]: object"""

    tm.assert_series_equal(left, right, check_dtype=False)

    with pytest.raises(AssertionError, match=msg):
        tm.assert_series_equal(left, right, check_dtype=True)


def test_series_equal_series_type():
    class MySeries(pd.Series):
        pass

    s1 = pd.Series([1, 2])
    s2 = pd.Series([1, 2])
    s3 = MySeries([1, 2])

    tm.assert_series_equal(s1, s2, check_series_type=False)
    tm.assert_series_equal(s1, s2, check_series_type=True)

    tm.assert_series_equal(s1, s3, check_series_type=False)
    tm.assert_series_equal(s3, s1, check_series_type=False)

    with pytest.raises(AssertionError, match="Series classes are different"):
        tm.assert_series_equal(s1, s3, check_series_type=True)

    with pytest.raises(AssertionError, match="Series classes are different"):
        tm.assert_series_equal(s3, s1, check_series_type=True)


def test_series_equal_ndarray_subclass_values():
    # GH#65770
    class OtherArray(np.ndarray):
        pass

    left = pd.Series(np.array([1, 2, 3]))
    right = pd.Series(np.array([1, 2, 3]).view(OtherArray), copy=False)

    msg = """Series values are different

Series values classes are different
\\[left\\]:  ndarray
\\[right\\]: OtherArray"""
    with pytest.raises(AssertionError, match=msg):
        tm.assert_series_equal(left, right, check_series_type=False)


def test_series_equal_exact_for_nonnumeric():
    # https://github.com/pandas-dev/pandas/issues/35446
    s1 = pd.Series(["a", "b"])
    s2 = pd.Series(["a", "b"])
    s3 = pd.Series(["b", "a"])

    tm.assert_series_equal(s1, s2, check_exact=True)
    tm.assert_series_equal(s2, s1, check_exact=True)

    msg = """Series are different

Series values are different \\(100\\.0 %\\)
\\[index\\]: \\[0, 1\\]
\\[left\\]:  \\[a, b\\]
\\[right\\]: \\[b, a\\]"""
    with pytest.raises(AssertionError, match=msg):
        tm.assert_series_equal(s1, s3, check_exact=True)

    msg = """Series are different

Series values are different \\(100\\.0 %\\)
\\[index\\]: \\[0, 1\\]
\\[left\\]:  \\[b, a\\]
\\[right\\]: \\[a, b\\]"""
    with pytest.raises(AssertionError, match=msg):
        tm.assert_series_equal(s3, s1, check_exact=True)


def test_assert_series_equal_ignore_extension_dtype_mismatch():
    # https://github.com/pandas-dev/pandas/issues/35715
    left = pd.Series([1, 2, 3], dtype="Int64")
    right = pd.Series([1, 2, 3], dtype="Int32")
    tm.assert_series_equal(left, right, check_dtype=False)


def test_assert_series_equal_ignore_extension_dtype_mismatch_cross_class():
    # https://github.com/pandas-dev/pandas/issues/35715
    left = pd.Series([1, 2, 3], dtype="Int64")
    right = pd.Series([1, 2, 3], dtype="int64")
    tm.assert_series_equal(left, right, check_dtype=False)


def test_allows_duplicate_labels():
    left = pd.Series([1])
    right = pd.Series([1]).set_flags(allows_duplicate_labels=False)
    tm.assert_series_equal(left, left)
    tm.assert_series_equal(right, right)
    tm.assert_series_equal(left, right, check_flags=False)
    tm.assert_series_equal(right, left, check_flags=False)

    with pytest.raises(AssertionError, match="<Flags"):
        tm.assert_series_equal(left, right)

    with pytest.raises(AssertionError, match="<Flags"):
        tm.assert_series_equal(left, right)


def test_assert_series_equal_identical_na(nulls_fixture):
    ser = pd.Series([nulls_fixture])

    tm.assert_series_equal(ser, ser.copy())

    # while we're here do Index too
    idx = pd.Index(ser)
    tm.assert_index_equal(idx, idx.copy(deep=True))


def test_identical_nested_series_is_equal():
    # GH#22400
    x = pd.Series(
        [
            0,
            0.0131142231938,
            1.77774652865e-05,
            np.array([0.4722720840328748, 0.4216929783681722]),
        ]
    )
    y = pd.Series(
        [
            0,
            0.0131142231938,
            1.77774652865e-05,
            np.array([0.4722720840328748, 0.4216929783681722]),
        ]
    )
    # These two arrays should be equal, nesting could cause issue

    tm.assert_series_equal(x, x)
    tm.assert_series_equal(x, x, check_exact=True)
    tm.assert_series_equal(x, y)
    tm.assert_series_equal(x, y, check_exact=True)


@pytest.mark.parametrize(
    "left,right",
    [
        (
            pd.Series([pd.array([1, 2, 3])], dtype=object),
            pd.Series([np.array([1, 2, 3])], dtype=object),
        ),
        (
            pd.Series([[1, 2, 3]], dtype=object),
            pd.Series([np.array([1, 2, 3])], dtype=object),
        ),
    ],
    ids=["extensionarray-vs-ndarray", "list-vs-ndarray"],
)
def test_assert_series_equal_nested_arraylike_type_mismatch_check_exact(left, right):
    # GH#63904
    msg = "Series are different"

    with pytest.raises(AssertionError, match=msg):
        tm.assert_series_equal(left, right, check_exact=True)

    with pytest.raises(AssertionError, match=msg):
        tm.assert_series_equal(right, left, check_exact=True)


@pytest.mark.parametrize("dtype", ["datetime64", "timedelta64"])
def test_check_dtype_false_different_reso(dtype):
    # GH 52449
    ser_s = pd.Series([1000213, 2131232, 21312331]).astype(f"{dtype}[s]")
    ser_ms = ser_s.astype(f"{dtype}[ms]")
    with pytest.raises(AssertionError, match="Attributes of Series are different"):
        tm.assert_series_equal(ser_s, ser_ms)
    tm.assert_series_equal(ser_ms, ser_s, check_dtype=False)

    ser_ms -= pd.Series([1, 1, 1]).astype(f"{dtype}[ms]")

    with pytest.raises(AssertionError, match="Series are different"):
        tm.assert_series_equal(ser_s, ser_ms)

    with pytest.raises(AssertionError, match="Series are different"):
        tm.assert_series_equal(ser_s, ser_ms, check_dtype=False)


@pytest.mark.parametrize("dtype", ["Int64", "int64"])
def test_large_unequal_ints(dtype):
    # https://github.com/pandas-dev/pandas/issues/55882
    left = pd.Series([1577840521123000], dtype=dtype)
    right = pd.Series([1577840521123543], dtype=dtype)
    with pytest.raises(AssertionError, match="Series are different"):
        tm.assert_series_equal(left, right)


@pytest.mark.parametrize("dtype", [None, object])
@pytest.mark.parametrize("check_exact", [True, False])
@pytest.mark.parametrize("val", [3, 3.5])
def test_ea_and_numpy_no_dtype_check(val, check_exact, dtype):
    # GH#56651
    left = pd.Series([1, 2, val], dtype=dtype)
    right = pd.Series(pd.array([1, 2, val]))
    tm.assert_series_equal(left, right, check_dtype=False, check_exact=check_exact)


def test_assert_series_equal_int_tol():
    # GH#56646
    left = pd.Series([81, 18, 121, 38, 74, 72, 81, 81, 146, 81, 81, 170, 74, 74])
    right = pd.Series([72, 9, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72, 72])
    tm.assert_series_equal(left, right, rtol=1.5)

    tm.assert_frame_equal(left.to_frame(), right.to_frame(), rtol=1.5)
    tm.assert_extension_array_equal(
        left.astype("Int64").values, right.astype("Int64").values, rtol=1.5
    )


@pytest.mark.parametrize(
    "left_idx, right_idx",
    [
        (
            pd.Index([0, 0.2, 0.4, 0.6, 0.8, 1]),
            pd.Index(np.linspace(0, 1, 6)),
        ),
        (
            pd.MultiIndex.from_arrays([[0, 0, 0, 0, 1, 1], [0, 0.2, 0.4, 0.6, 0.8, 1]]),
            pd.MultiIndex.from_arrays([[0, 0, 0, 0, 1, 1], np.linspace(0, 1, 6)]),
        ),
        (
            pd.MultiIndex.from_arrays(
                [["a", "a", "a", "b", "b", "b"], [1, 2, 3, 4, 5, 10000000000001]]
            ),
            pd.MultiIndex.from_arrays(
                [["a", "a", "a", "b", "b", "b"], [1, 2, 3, 4, 5, 10000000000002]]
            ),
        ),
        pytest.param(
            pd.Index([1, 2, 3, 4, 5, 10000000000001]),
            pd.Index([1, 2, 3, 4, 5, 10000000000002]),
            marks=pytest.mark.xfail(reason="check_exact_index defaults to True"),
        ),
        pytest.param(
            pd.MultiIndex.from_arrays(
                [[0, 0, 0, 0, 1, 1], [1, 2, 3, 4, 5, 10000000000001]]
            ),
            pd.MultiIndex.from_arrays(
                [[0, 0, 0, 0, 1, 1], [1, 2, 3, 4, 5, 10000000000002]]
            ),
            marks=pytest.mark.xfail(reason="check_exact_index defaults to True"),
        ),
    ],
)
def test_assert_series_equal_check_exact_index_default(left_idx, right_idx):
    # GH#57067
    ser1 = pd.Series(np.zeros(6, dtype=int), left_idx)
    ser2 = pd.Series(np.zeros(6, dtype=int), right_idx)
    tm.assert_series_equal(ser1, ser2)
    tm.assert_frame_equal(ser1.to_frame(), ser2.to_frame())


def test_assert_series_equal_int_near_bounds():
    # GH#40719 - integer comparisons near int64 bounds should be exact by default
    min_val = np.iinfo(np.int64).min
    ser1 = pd.Series([min_val], dtype=np.int64)
    ser2 = pd.Series([min_val + 1], dtype=np.int64)

    msg = "Series are different"
    with pytest.raises(AssertionError, match=msg):
        tm.assert_series_equal(ser1, ser2)


@pytest.mark.parametrize(
    "left_values,right_values,left_dtype,right_dtype",
    [
        ([2**60 + 1], [float(2**60)], "int64", "float64"),
        ([2**63 + 1], [float(2**63)], "uint64", "float64"),
        ([pd.NA, 2**60 + 1], [pd.NA, float(2**60)], "Int64", "Float64"),
    ],
)
def test_assert_series_equal_large_mixed_integer_float_atol(
    left_values, right_values, left_dtype, right_dtype
):
    # GH#66699 comparison must retain integer precision with check_dtype=False.
    left = pd.Series(left_values, dtype=left_dtype)
    right = pd.Series(right_values, dtype=right_dtype)

    for first, second in [(left, right), (right, left)]:
        with pytest.raises(AssertionError, match="Series are different"):
            tm.assert_series_equal(
                first,
                second,
                check_dtype=False,
                check_exact=False,
                rtol=0,
                atol=0.5,
            )
    _assert_series_equal_both(
        left, right, check_dtype=False, check_exact=False, rtol=0, atol=1
    )


def test_assert_series_equal_large_mixed_integer_float_rtol():
    left = pd.Series([2**60 + 1], dtype="int64")
    right = pd.Series([float(2**60)], dtype="float64")

    for first, second in [(left, right), (right, left)]:
        with pytest.raises(AssertionError, match="Series are different"):
            tm.assert_series_equal(
                first,
                second,
                check_dtype=False,
                check_exact=False,
                rtol=0.5 / 2**60,
                atol=0,
            )
    _assert_series_equal_both(
        left,
        right,
        check_dtype=False,
        check_exact=False,
        rtol=1 / 2**60,
        atol=0,
    )


@pytest.mark.parametrize(
    "left_values,right_values,left_dtype,right_dtype",
    [
        ([2**60], [float(2**60)], "int64", "float64"),
        ([2**63], [float(2**63)], "uint64", "float64"),
    ],
)
def test_assert_series_equal_large_mixed_integer_float_equal(
    left_values, right_values, left_dtype, right_dtype
):
    # GH#66699 the same equal-direction guarantee, at Series level
    left = pd.Series(left_values, dtype=left_dtype)
    right = pd.Series(right_values, dtype=right_dtype)

    _assert_series_equal_both(
        left, right, check_dtype=False, check_exact=False, rtol=0, atol=0
    )


@pytest.mark.parametrize("dtype", ["int64", "Int64"])
def test_assert_series_equal_large_int_atol(dtype):
    # GH#66400 an explicitly passed atol must be honored above 2**53 too;
    #  GH#40719 covers the default, which never reaches the tolerance check
    val = 1450804465901089690
    ser = pd.Series([val], dtype=dtype)

    tm.assert_series_equal(
        ser, pd.Series([val - 76], dtype=dtype), check_exact=False, rtol=0, atol=100
    )

    msg = "Series are different"
    with pytest.raises(AssertionError, match=msg):
        tm.assert_series_equal(
            ser, pd.Series([val + 100], dtype=dtype), check_exact=False, rtol=0, atol=10
        )


@pytest.mark.parametrize(
    "left_values,right_values",
    [
        (
            pd.arrays.IntervalArray.from_tuples([(1.0, 2.0)]),
            pd.arrays.IntervalArray.from_tuples([(1.5, 2.0)]),
        ),
        (pd.to_datetime(["2020-01-01"]), pd.to_datetime(["2020-01-02"])),
        (pd.to_timedelta([1], unit="D"), pd.to_timedelta([2], unit="D")),
        (
            pd.period_range("2020-01-01", periods=1, freq="D"),
            pd.period_range("2020-01-02", periods=1, freq="D"),
        ),
        (pd.array(["a"], dtype="str"), pd.array(["b"], dtype="str")),
    ],
)
def test_assert_series_equal_tolerance_numeric_only(left_values, right_values):
    # GH#43913 rtol/atol are documented as numeric-only; non-numeric dtypes
    #  compare exactly no matter how large the tolerance
    left = pd.Series(left_values)
    right = pd.Series(right_values)

    with pytest.raises(AssertionError, match="are different"):
        tm.assert_series_equal(left, right, check_exact=False, rtol=10, atol=10)


def test_assert_series_equal_check_like_check_freq():
    # GH#51920 sorting a shuffled DatetimeIndex does not restore its freq, so
    #  the freq check is skipped with check_like=True
    idx = pd.date_range("2020-01-01", periods=3, freq="D")
    ser = pd.Series([1, 2, 3], index=idx)
    shuffled = ser.iloc[[2, 0, 1]]
    with tm.assert_produces_warning(None):
        tm.assert_series_equal(shuffled, ser, check_like=True)


def test_assert_series_equal_check_index_false_ignores_freq():
    # GH#51920 freq is an index attribute, so check_index=False skips it
    idx = pd.date_range("2020-01-01", periods=3, freq="D")
    left = pd.Series([1, 2, 3], index=idx)
    right = pd.Series([1, 2, 3], index=idx._with_freq(None))
    with tm.assert_produces_warning(None):
        tm.assert_series_equal(left, right, check_index=False)


def test_assert_series_equal_check_freq_multiindex_level():
    # GH#66761 a freq mismatch in a MultiIndex level was not checked before
    #  the check_freq deprecation, so it warns rather than raising
    dates = pd.date_range("2012-01-01", periods=3)
    left = pd.Series([1, 2, 3], index=pd.MultiIndex.from_arrays([dates, [1, 2, 3]]))
    right = pd.Series(
        [1, 2, 3],
        index=pd.MultiIndex.from_arrays([dates._with_freq(None), [1, 2, 3]]),
    )

    warn_msg = "will check the 'freq' attribute"
    with tm.assert_produces_warning(Pandas4Warning, match=warn_msg):
        tm.assert_series_equal(left, right)

    raise_msg = 'Attribute "freq" are different'
    with pytest.raises(AssertionError, match=raise_msg):
        tm.assert_series_equal(left, right, check_freq=True)

    with tm.assert_produces_warning(None):
        tm.assert_series_equal(left, right, check_freq=False)


def test_assert_series_equal_check_freq_categorical_values():
    # GH#66761 the freq of datetimelike Categorical categories was not checked
    #  before the check_freq deprecation, and check_freq has to reach it so the
    #  warning can be silenced
    dates = pd.date_range("2012-01-01", periods=3)
    left = pd.Series(pd.Categorical(dates, categories=dates))
    right = pd.Series(
        pd.Categorical(dates._with_freq(None), categories=dates._with_freq(None))
    )

    warn_msg = "will check the 'freq' attribute"
    with tm.assert_produces_warning(Pandas4Warning, match=warn_msg):
        tm.assert_series_equal(left, right)

    raise_msg = 'Attribute "freq" are different'
    with pytest.raises(AssertionError, match=raise_msg):
        tm.assert_series_equal(left, right, check_freq=True)

    with tm.assert_produces_warning(None):
        tm.assert_series_equal(left, right, check_freq=False)


def test_assert_series_equal_category_order_with_na():
    # GH#62008 NA has code -1, which must not be read as a positional indexer
    #  for the last category when the two sides order their categories
    #  differently
    values = ["B", None, "D"]
    left = pd.Series(pd.Categorical(values, categories=["B", "D"]))
    right = pd.Series(pd.Categorical(values, categories=["D", "B"]))

    tm.assert_series_equal(left, right, check_category_order=False)
