view tests/unit/test_plugin_xep_0082.py @ 3942:a92eef737703

plugin XEP-0373: download public keys if they are not found in local storage: public keys were only obtained from PEP notifications, however this wasn't working if the entity was not in our roster. Now if no public key is retrieved from local storage, the public key node is requested, and an error is raised if nothing is found. This allows the use of OX with entities which are not in roster. rel 380
author Goffi <goffi@goffi.org>
date Sat, 15 Oct 2022 20:38:33 +0200
parents cecf45416403
children 4b842c1fb686
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 sat.core import exceptions

from sat.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)