view tests/unit/test_plugin_xep_0082.py @ 4180:b86912d3fd33

plugin IP: fix use of legacy URL + coroutine use: An https:/salut-a-toi.org URL was used to retrieve external IP, but it's not valid anymore, resulting in an exception. This feature is currently disabled. Also moved several methods from legacy inline callbacks to coroutines.
author Goffi <goffi@goffi.org>
date Sat, 09 Dec 2023 14:30:54 +0100
parents 4b842c1fb686
children f1d0cde61af7
line wrap: on
line source

#!/usr/bin/env python3

# Tests for Libervia's XMPP Date and Time Profile formatting and parsing plugin
# Copyright (C) 2022-2022 Tim Henkes (me@syndace.dev)

# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.

# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU Affero General Public License for more details.

# You should have received a copy of the GNU Affero General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

from datetime import date, datetime, time, timezone

import pytest
from libervia.backend.core import exceptions

from libervia.backend.plugins.plugin_xep_0082 import XEP_0082


__all__ = [  # pylint: disable=unused-variable
    "test_date_formatting",
    "test_date_parsing",
    "test_datetime_formatting",
    "test_datetime_parsing",
    "test_time_formatting",
    "test_time_parsing"
]


def test_date_formatting() -> None:  # pylint: disable=missing-function-docstring
    # The following tests don't check the output of format_date directly; instead, they
    # assume that parse_date rejects incorrect formatting.

    # The date version 0.1 of XEP-0082 was published
    value = date(2003, 4, 21)

    # Check that the parsed date equals the formatted date
    assert XEP_0082.parse_date(XEP_0082.format_date(value)) == value

    # Check that a date instance is returned when format_date is called without an
    # explicit input date
    assert isinstance(XEP_0082.parse_date(XEP_0082.format_date()), date)


def test_date_parsing() -> None:  # pylint: disable=missing-function-docstring
    # There isn't really a point in testing much more than this
    assert XEP_0082.parse_date("2003-04-21") == date(2003, 4, 21)


def test_datetime_formatting() -> None:  # pylint: disable=missing-function-docstring
    # The following tests don't check the output of format_datetime directly; instead,
    # they assume that parse_datetime rejects incorrect formatting.

    # A datetime in UTC
    value = datetime(1234, 5, 6, 7, 8, 9, 123456, timezone.utc)

    # Check that the parsed datetime equals the formatted datetime except for the
    # microseconds
    parsed = XEP_0082.parse_datetime(XEP_0082.format_datetime(value))
    assert parsed != value
    assert parsed.replace(microsecond=123456) == value

    # Check that the parsed datetime equals the formatted datetime including microseconds
    assert XEP_0082.parse_datetime(XEP_0082.format_datetime(value, True)) == value

    # A datetime in some other timezone, from the Python docs of the datetime module
    value = datetime.fromisoformat("2011-11-04T00:05:23+04:00")

    # Check that the parsed datetime equals the formatted datetime with or without
    # microseconds
    assert XEP_0082.parse_datetime(XEP_0082.format_datetime(value)) == value
    assert XEP_0082.parse_datetime(XEP_0082.format_datetime(value, True)) == value

    # Check that the datetime was converted to UTC while formatting
    assert XEP_0082.parse_datetime(XEP_0082.format_datetime(value)).tzinfo == timezone.utc

    # Check that a datetime instance is returned when format_datetime is called without an
    # explicit input
    # datetime
    assert isinstance(XEP_0082.parse_datetime(XEP_0082.format_datetime()), datetime)
    assert isinstance(XEP_0082.parse_datetime(XEP_0082.format_datetime(
        include_microsecond=True
    )), datetime)
    assert XEP_0082.parse_datetime(XEP_0082.format_datetime()).tzinfo == timezone.utc


def test_datetime_parsing() -> None:  # pylint: disable=missing-function-docstring
    # Datetime of the first human steps on the Moon (UTC)
    value = datetime(1969, 7, 21, 2, 56, 15, tzinfo=timezone.utc)

    # With timezone 'Z', without a fraction of a second
    assert XEP_0082.parse_datetime("1969-07-21T02:56:15Z") == value

    # With timezone '+04:00', without a fraction of a second
    assert XEP_0082.parse_datetime("1969-07-21T06:56:15+04:00") == value

    # With timezone '-05:00', without a fraction of a second
    assert XEP_0082.parse_datetime("1969-07-20T21:56:15-05:00") == value

    # Without timezone, without a fraction of a second
    with pytest.raises(exceptions.ParsingError):
        XEP_0082.parse_datetime("1969-07-21T02:56:15")

    # With timezone 'Z', with a fraction of a second consisting of two digits
    assert XEP_0082.parse_datetime("1969-07-21T02:56:15.12Z") == \
        value.replace(microsecond=120000)

    # With timezone 'Z', with a fraction of a second consisting of nine digits
    assert XEP_0082.parse_datetime("1969-07-21T02:56:15.123456789Z") == \
        value.replace(microsecond=123456)

    # With timezone '+04:00', with a fraction of a second consisting of six digits
    assert XEP_0082.parse_datetime("1969-07-21T06:56:15.123456+04:00") == \
        value.replace(microsecond=123456)

    # With timezone '-05:00', with a fraction of a second consisting of zero digits
    assert XEP_0082.parse_datetime("1969-07-20T21:56:15.-05:00") == value

    # Without timezone, with a fraction of a second consisting of six digits
    with pytest.raises(exceptions.ParsingError):
        XEP_0082.parse_datetime("1969-07-21T02:56:15.123456")


def test_time_formatting() -> None:  # pylint: disable=missing-function-docstring
    # The following tests don't check the output of format_time directly; instead, they
    # assume that parse_time rejects incorrect formatting.

    # A time in UTC
    value = time(12, 34, 56, 789012, timezone.utc)

    # Check that the parsed time equals the formatted time except for the microseconds
    parsed = XEP_0082.parse_time(XEP_0082.format_time(value))
    assert parsed != value
    assert parsed.replace(microsecond=789012) == value

    # Check that the parsed time equals the formatted time including microseconds
    assert XEP_0082.parse_time(XEP_0082.format_time(value, True)) == value

    # A time in some other timezone, from the Python docs of the datetime module
    value = time.fromisoformat("04:23:01+04:00")

    # Check that the parsed time equals the formatted time with or without microseconds
    assert XEP_0082.parse_time(XEP_0082.format_time(value)) == value
    assert XEP_0082.parse_time(XEP_0082.format_time(value, True)) == value

    # Check that the time has retained its timezone
    assert XEP_0082.parse_time(XEP_0082.format_time(value)).tzinfo == value.tzinfo

    # A time without timezone information, from the Python docs of the datetime module
    value = time.fromisoformat("04:23:01")

    # Check that the parsed time doesn't have timezone information either
    assert XEP_0082.parse_time(XEP_0082.format_time(value)).tzinfo is None

    # Check that a time instance is returned when format_time is called without an
    # explicit input date
    assert isinstance(XEP_0082.parse_time(XEP_0082.format_time()), time)
    assert isinstance(XEP_0082.parse_time(XEP_0082.format_time(
        include_microsecond=True
    )), time)
    assert XEP_0082.parse_time(XEP_0082.format_time()).tzinfo == timezone.utc


def test_time_parsing() -> None:  # pylint: disable=missing-function-docstring
    # Time for tea
    value = time(16, 0, 0, tzinfo=timezone.utc)

    # With timezone 'Z', without a fraction of a second
    assert XEP_0082.parse_time("16:00:00Z") == value

    # With timezone '+04:00', without a fraction of a second
    assert XEP_0082.parse_time("20:00:00+04:00") == value

    # With timezone '-05:00', without a fraction of a second
    assert XEP_0082.parse_time("11:00:00-05:00") == value

    # Without a timezone, without a fraction of a second
    assert XEP_0082.parse_time("16:00:00") == value.replace(tzinfo=None)

    # With timezone 'Z', with a fraction of a second consisting of two digits
    assert XEP_0082.parse_time("16:00:00.12Z") == value.replace(microsecond=120000)

    # With timezone 'Z', with a fraction of a second consisting of nine digits
    assert XEP_0082.parse_time("16:00:00.123456789Z") == value.replace(microsecond=123456)

    # With timezone '+04:00', with a fraction of a second consisting of six digits
    assert XEP_0082.parse_time("20:00:00.123456+04:00") == \
        value.replace(microsecond=123456)

    # With timezone '-05:00', with a fraction of a second consisting of zero digits
    assert XEP_0082.parse_time("11:00:00.-05:00") == value

    # Without a timezone, with a fraction of a second consisting of six digits
    assert XEP_0082.parse_time("16:00:00.123456") == \
        value.replace(microsecond=123456, tzinfo=None)