From bf7655864c58a0bca32607cffc7aaf615977ff78 Mon Sep 17 00:00:00 2001 From: jaca Date: Tue, 20 Sep 2022 14:38:41 +0200 Subject: [PATCH] refactor test_issue_237 --- ..._to_parse_timezone_with_non_ascii_tzid.ics | 23 ++++++++++ src/icalendar/tests/conftest.py | 16 +++++++ src/icalendar/tests/test_encoding.py | 26 ++++++++++- src/icalendar/tests/test_fixed_issues.py | 44 ------------------- .../timezones/issue_237_brazilia_standard.ics | 17 +++++++ 5 files changed, 81 insertions(+), 45 deletions(-) create mode 100644 src/icalendar/tests/calendars/issue_237_fail_to_parse_timezone_with_non_ascii_tzid.ics create mode 100644 src/icalendar/tests/timezones/issue_237_brazilia_standard.ics diff --git a/src/icalendar/tests/calendars/issue_237_fail_to_parse_timezone_with_non_ascii_tzid.ics b/src/icalendar/tests/calendars/issue_237_fail_to_parse_timezone_with_non_ascii_tzid.ics new file mode 100644 index 00000000..9b2e8f61 --- /dev/null +++ b/src/icalendar/tests/calendars/issue_237_fail_to_parse_timezone_with_non_ascii_tzid.ics @@ -0,0 +1,23 @@ +BEGIN:VCALENDAR +BEGIN:VTIMEZONE +TZID:(UTC-03:00) Brasília +BEGIN:STANDARD +TZNAME:Brasília standard +DTSTART:16010101T235959 +TZOFFSETFROM:-0200 +TZOFFSETTO:-0300 +RRULE:FREQ=YEARLY;INTERVAL=1;BYDAY=3SA;BYMONTH=2 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:Brasília daylight +DTSTART:16010101T235959 +TZOFFSETFROM:-0300 +TZOFFSETTO:-0200 +RRULE:FREQ=YEARLY;INTERVAL=1;BYDAY=2SA;BYMONTH=10 +END:DAYLIGHT +END:VTIMEZONE +BEGIN:VEVENT +DTSTART;TZID="(UTC-03:00) Brasília":20170511T133000 +DTEND;TZID="(UTC-03:00) Brasília":20170511T140000 +END:VEVENT +END:VCALENDAR diff --git a/src/icalendar/tests/conftest.py b/src/icalendar/tests/conftest.py index 838c506d..54716cc3 100644 --- a/src/icalendar/tests/conftest.py +++ b/src/icalendar/tests/conftest.py @@ -4,6 +4,14 @@ import pytest import icalendar +import datetime +import pytz +from dateutil import tz +try: + import zoneinfo +except ModuleNotFoundError: + from backports import zoneinfo + LOGGER = logging.getLogger(__name__) class DataSource: @@ -30,9 +38,14 @@ def __repr__(self): return repr(self.__dict__) HERE = os.path.dirname(__file__) +CALENDARS_FOLDER = os.path.join(HERE, 'calendars') TIMEZONES_FOLDER = os.path.join(HERE, 'timezones') EVENTS_FOLDER = os.path.join(HERE, 'events') +@pytest.fixture +def calendars(): + return DataSource(CALENDARS_FOLDER, icalendar.Calendar.from_ical) + @pytest.fixture def timezones(): return DataSource(TIMEZONES_FOLDER, icalendar.Timezone.from_ical) @@ -41,3 +54,6 @@ def timezones(): def events(): return DataSource(EVENTS_FOLDER, icalendar.Event.from_ical) +@pytest.fixture(params=[pytz.timezone, tz.gettz, zoneinfo.ZoneInfo]) +def timezone(request): + return request.param diff --git a/src/icalendar/tests/test_encoding.py b/src/icalendar/tests/test_encoding.py index d1d70d37..899aa5cc 100644 --- a/src/icalendar/tests/test_encoding.py +++ b/src/icalendar/tests/test_encoding.py @@ -1,11 +1,12 @@ import unittest +import pytest + import datetime import icalendar import os import pytz - class TestEncoding(unittest.TestCase): def test_create_from_ical(self): @@ -88,3 +89,26 @@ def test_unicode_parameter_name(self): + b'\xc3\xa4\xc3\xb6\xc3\xbc\xc3\x9f\xc3\x84\xc3\x96\xc3\x9c\r\n' + b'END:VEVENT\r\nEND:VCALENDAR\r\n' ) + +def test_parses_event_with_non_ascii_tzid_issue_237(calendars, timezone): + """Issue #237 - Fail to parse timezone with non-ascii TZID + see https://github.com/collective/icalendar/issues/237 + """ + start = calendars.issue_237_fail_to_parse_timezone_with_non_ascii_tzid.walk('VEVENT')[0].decoded('DTSTART') + expected = datetime.datetime(2017, 5, 11, 13, 30, tzinfo=timezone('America/Sao_Paulo')) + assert not calendars.issue_237_fail_to_parse_timezone_with_non_ascii_tzid + assert start == expected + +def test_parses_timezone_with_non_ascii_tzid_issue_237(timezones): + """Issue #237 - Fail to parse timezone with non-ascii TZID + see https://github.com/collective/icalendar/issues/237 + """ + assert timezones.issue_237_brazilia_standard['tzid'] == '(UTC-03:00) Brasília' + +@pytest.mark.parametrize('timezone_name', ['standard', 'daylight']) +def test_parses_timezone_with_non_ascii_tzname_issue_273(timezones, timezone_name): + """Issue #237 - Fail to parse timezone with non-ascii TZID + see https://github.com/collective/icalendar/issues/237 + """ + assert timezones.issue_237_brazilia_standard.walk(timezone_name)[0]['TZNAME'] == f'Brasília {timezone_name}' + diff --git a/src/icalendar/tests/test_fixed_issues.py b/src/icalendar/tests/test_fixed_issues.py index 15bc377c..52be5869 100644 --- a/src/icalendar/tests/test_fixed_issues.py +++ b/src/icalendar/tests/test_fixed_issues.py @@ -438,50 +438,6 @@ def test_issue_184(self): b'END:VEVENT\r\n' ) - def test_issue_237(self): - """Issue #237 - Fail to parse timezone with non-ascii TZID""" - - ical_str = ['BEGIN:VCALENDAR', - 'BEGIN:VTIMEZONE', - 'TZID:(UTC-03:00) Brasília', - 'BEGIN:STANDARD', - 'TZNAME:Brasília standard', - 'DTSTART:16010101T235959', - 'TZOFFSETFROM:-0200', - 'TZOFFSETTO:-0300', - 'RRULE:FREQ=YEARLY;INTERVAL=1;BYDAY=3SA;BYMONTH=2', - 'END:STANDARD', - 'BEGIN:DAYLIGHT', - 'TZNAME:Brasília daylight', - 'DTSTART:16010101T235959', - 'TZOFFSETFROM:-0300', - 'TZOFFSETTO:-0200', - 'RRULE:FREQ=YEARLY;INTERVAL=1;BYDAY=2SA;BYMONTH=10', - 'END:DAYLIGHT', - 'END:VTIMEZONE', - 'BEGIN:VEVENT', - 'DTSTART;TZID=\"(UTC-03:00) Brasília\":20170511T133000', - 'DTEND;TZID=\"(UTC-03:00) Brasília\":20170511T140000', - 'END:VEVENT', - 'END:VCALENDAR', - ] - - cal = icalendar.Calendar.from_ical('\r\n'.join(ical_str)) - self.assertEqual(cal.errors, []) - - dtstart = cal.walk(name='VEVENT')[0].decoded("DTSTART") - expected = pytz.timezone('America/Sao_Paulo').localize(datetime.datetime(2017, 5, 11, 13, 30)) - self.assertEqual(dtstart, expected) - - try: - expected_zone = '(UTC-03:00) Brasília' - expected_tzname = 'Brasília standard' - except UnicodeEncodeError: - expected_zone = '(UTC-03:00) Brasília'.encode('ascii', 'replace') - expected_tzname = 'Brasília standard'.encode('ascii', 'replace') - self.assertEqual(dtstart.tzinfo.zone, expected_zone) - self.assertEqual(dtstart.tzname(), expected_tzname) - def test_issue_345(self): """Issue #345 - Why is tools.UIDGenerator a class (that must be instantiated) instead of a module? """ uid1 = icalendar.tools.UIDGenerator.uid() diff --git a/src/icalendar/tests/timezones/issue_237_brazilia_standard.ics b/src/icalendar/tests/timezones/issue_237_brazilia_standard.ics new file mode 100644 index 00000000..462f3fcd --- /dev/null +++ b/src/icalendar/tests/timezones/issue_237_brazilia_standard.ics @@ -0,0 +1,17 @@ +BEGIN:VTIMEZONE +TZID:(UTC-03:00) Brasília +BEGIN:STANDARD +TZNAME:Brasília standard +DTSTART:16010101T235959 +TZOFFSETFROM:-0200 +TZOFFSETTO:-0300 +RRULE:FREQ=YEARLY;INTERVAL=1;BYDAY=3SA;BYMONTH=2 +END:STANDARD +BEGIN:DAYLIGHT +TZNAME:Brasília daylight +DTSTART:16010101T235959 +TZOFFSETFROM:-0300 +TZOFFSETTO:-0200 +RRULE:FREQ=YEARLY;INTERVAL=1;BYDAY=2SA;BYMONTH=10 +END:DAYLIGHT +END:VTIMEZONE