Skip to content

Commit

Permalink
Created some broken tests to highlight issue collective#333
Browse files Browse the repository at this point in the history
  • Loading branch information
tobixen committed Nov 17, 2021
1 parent 90c0593 commit a427643
Showing 1 changed file with 387 additions and 0 deletions.
387 changes: 387 additions & 0 deletions src/icalendar/tests/test_timezoned_new.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,387 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals

"""
Ref https://pytz-deprecation-shim.readthedocs.io/en/latest/migration.html and
other sources, the pytz library is on the way to becoming deprecated in favor
of zoneinfo. The good news is that zoneinfo is part of the standard "battery
included" libraries. The bad news is that it's not directly backwards
compatible with pytz.
"""

import unittest

import datetime
import dateutil.parser
import icalendar
import os
import pytz
try:
import zoneinfo
except:
try:
from backports import zoneinfo
except:
raise unittest.SkipTest("zoneinfo built-in library not supported in your python distribution")
utc = zoneinfo.ZoneInfo('UTC')

class TestNewTimezoned(unittest.TestCase):

def test_create_from_ical(self):
directory = os.path.dirname(__file__)
with open(os.path.join(directory, 'timezoned.ics'), 'rb') as fp:
data = fp.read()
cal = icalendar.Calendar.from_ical(data)

self.assertEqual(
cal['prodid'].to_ical(),
b"-//Plone.org//NONSGML plone.app.event//EN"
)

timezones = cal.walk('VTIMEZONE')
self.assertEqual(len(timezones), 1)

tz = timezones[0]
self.assertEqual(tz['tzid'].to_ical(), b"Europe/Vienna")

std = tz.walk('STANDARD')[0]
self.assertEqual(
std.decoded('TZOFFSETFROM'),
datetime.timedelta(0, 7200)
)

ev1 = cal.walk('VEVENT')[0]
self.assertEqual(
ev1.decoded('DTSTART'),
datetime.datetime(2012, 2, 13, 10, 0, 0, tzinfo=zoneinfo.ZoneInfo('Europe/Vienna'))
)
self.assertEqual(
ev1.decoded('DTSTAMP'),
datetime.datetime(2010, 10, 10, 9, 10, 10, tzinfo=utc)
)

def test_create_to_ical(self):
cal = icalendar.Calendar()

cal.add('prodid', "-//Plone.org//NONSGML plone.app.event//EN")
cal.add('version', "2.0")
cal.add('x-wr-calname', "test create calendar")
cal.add('x-wr-caldesc', "icalendar tests")
cal.add('x-wr-relcalid', "12345")
cal.add('x-wr-timezone', "Europe/Vienna")

tzc = icalendar.Timezone()
tzc.add('tzid', 'Europe/Vienna')
tzc.add('x-lic-location', 'Europe/Vienna')

tzs = icalendar.TimezoneStandard()
tzs.add('tzname', 'CET')
tzs.add('dtstart', datetime.datetime(1970, 10, 25, 3, 0, 0))
tzs.add('rrule', {'freq': 'yearly', 'bymonth': 10, 'byday': '-1su'})
tzs.add('TZOFFSETFROM', datetime.timedelta(hours=2))
tzs.add('TZOFFSETTO', datetime.timedelta(hours=1))

tzd = icalendar.TimezoneDaylight()
tzd.add('tzname', 'CEST')
tzd.add('dtstart', datetime.datetime(1970, 3, 29, 2, 0, 0))
tzs.add('rrule', {'freq': 'yearly', 'bymonth': 3, 'byday': '-1su'})
tzd.add('TZOFFSETFROM', datetime.timedelta(hours=1))
tzd.add('TZOFFSETTO', datetime.timedelta(hours=2))

tzc.add_component(tzs)
tzc.add_component(tzd)
cal.add_component(tzc)

event = icalendar.Event()
tz = zoneinfo.ZoneInfo("Europe/Vienna")
event.add(
'dtstart',
datetime.datetime(2012, 2, 13, 10, 00, 00, tzinfo=tz))
event.add(
'dtend',
datetime.datetime(2012, 2, 17, 18, 00, 00, tzinfo=tz))
event.add(
'dtstamp',
datetime.datetime(2010, 10, 10, 10, 10, 10, tzinfo=tz))
event.add(
'created',
datetime.datetime(2010, 10, 10, 10, 10, 10, tzinfo=tz))
event.add('uid', '123456')
event.add(
'last-modified',
datetime.datetime(2010, 10, 10, 10, 10, 10, tzinfo=tz))
event.add('summary', 'artsprint 2012')
# event.add('rrule', 'FREQ=YEARLY;INTERVAL=1;COUNT=10')
event.add('description', 'sprinting at the artsprint')
event.add('location', 'aka bild, wien')
event.add('categories', 'first subject')
event.add('categories', 'second subject')
event.add('attendee', 'häns')
event.add('attendee', 'franz')
event.add('attendee', 'sepp')
event.add('contact', 'Max Mustermann, 1010 Wien')
event.add('url', 'http://plone.org')
cal.add_component(event)

test_out = b'|'.join(cal.to_ical().splitlines())
test_out = test_out.decode('utf-8')

vtimezone_lines = "BEGIN:VTIMEZONE|TZID:Europe/Vienna|X-LIC-LOCATION:"
"Europe/Vienna|BEGIN:STANDARD|DTSTART;VALUE=DATE-TIME:19701025T03"
"0000|RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10|RRULE:FREQ=YEARLY;B"
"YDAY=-1SU;BYMONTH=3|TZNAME:CET|TZOFFSETFROM:+0200|TZOFFSETTO:+01"
"00|END:STANDARD|BEGIN:DAYLIGHT|DTSTART;VALUE=DATE-TIME:19700329T"
"020000|TZNAME:CEST|TZOFFSETFROM:+0100|TZOFFSETTO:+0200|END:DAYLI"
"GHT|END:VTIMEZONE"
self.assertTrue(vtimezone_lines in test_out)

test_str = "DTSTART;TZID=Europe/Vienna;VALUE=DATE-TIME:20120213T100000"
self.assertTrue(test_str in test_out)
self.assertTrue("ATTENDEE:sepp" in test_out)

# ical standard expects DTSTAMP and CREATED in UTC
self.assertTrue("DTSTAMP;VALUE=DATE-TIME:20101010T081010Z" in test_out)
self.assertTrue("CREATED;VALUE=DATE-TIME:20101010T081010Z" in test_out)

def test_tzinfo_dateutil(self):
# Test for issues #77, #63
# references: #73,7430b66862346fe3a6a100ab25e35a8711446717
date = dateutil.parser.parse('2012-08-30T22:41:00Z')
date2 = dateutil.parser.parse('2012-08-30T22:41:00 +02:00')
self.assertTrue(date.tzinfo.__module__.startswith('dateutil.tz'))
self.assertTrue(date2.tzinfo.__module__.startswith('dateutil.tz'))

# make sure, it's parsed properly and doesn't throw an error
self.assertTrue(icalendar.vDDDTypes(date).to_ical()
== b'20120830T224100Z')
self.assertTrue(icalendar.vDDDTypes(date2).to_ical()
== b'20120830T224100')


class TestTimezoneCreation(unittest.TestCase):

def test_create_america_new_york(self):
"""testing America/New_York, the most complex example from the
RFC"""

directory = os.path.dirname(__file__)
with open(os.path.join(directory, 'america_new_york.ics'), 'rb') as fp:
data = fp.read()
cal = icalendar.Calendar.from_ical(data)

tz = cal.walk('VEVENT')[0]['DTSTART'][0].dt.tzinfo
self.assertEqual(str(tz), 'custom_America/New_York')
pytz_new_york = pytz.timezone('America/New_York')

# for reasons (tm) the locally installed version of the time zone
# database isn't always complete, therefore we only compare some
# transition times
ny_transition_times = []
ny_transition_info = []
for num, date in enumerate(pytz_new_york._utc_transition_times):
if datetime.datetime(1967, 4, 30, 7, 0)\
<= date <= datetime.datetime(2037, 11, 1, 6, 0):
ny_transition_times.append(date)
ny_transition_info.append(pytz_new_york._transition_info[num])
self.assertEqual(tz._utc_transition_times[:142], ny_transition_times)
self.assertEqual(tz._transition_info[0:142], ny_transition_info)
self.assertIn(
(
datetime.timedelta(-1, 72000),
datetime.timedelta(0, 3600), 'EDT'
),
tz._tzinfos.keys()
)
self.assertIn(
(datetime.timedelta(-1, 68400), datetime.timedelta(0), 'EST'),
tz._tzinfos.keys()
)

def test_create_pacific_fiji(self):
"""testing Pacific/Fiji, another pretty complex example with more than
one RDATE property per subcomponent"""
self.maxDiff = None

directory = os.path.dirname(__file__)
with open(os.path.join(directory, 'pacific_fiji.ics'), 'rb') as fp:
data = fp.read()
cal = icalendar.Calendar.from_ical(data)

tz = cal.walk('VEVENT')[0]['DTSTART'][0].dt.tzinfo
self.assertEqual(str(tz), 'custom_Pacific/Fiji')
self.assertEqual(tz._utc_transition_times,
[datetime.datetime(1915, 10, 25, 12, 4),
datetime.datetime(1998, 10, 31, 14, 0),
datetime.datetime(1999, 2, 27, 14, 0),
datetime.datetime(1999, 11, 6, 14, 0),
datetime.datetime(2000, 2, 26, 14, 0),
datetime.datetime(2009, 11, 28, 14, 0),
datetime.datetime(2010, 3, 27, 14, 0),
datetime.datetime(2010, 10, 23, 14, 0),
datetime.datetime(2011, 3, 5, 14, 0),
datetime.datetime(2011, 10, 22, 14, 0),
datetime.datetime(2012, 1, 21, 14, 0),
datetime.datetime(2012, 10, 20, 14, 0),
datetime.datetime(2013, 1, 19, 14, 0),
datetime.datetime(2013, 10, 26, 14, 0),
datetime.datetime(2014, 1, 18, 13, 0),
datetime.datetime(2014, 10, 25, 14, 0),
datetime.datetime(2015, 1, 17, 13, 0),
datetime.datetime(2015, 10, 24, 14, 0),
datetime.datetime(2016, 1, 23, 13, 0),
datetime.datetime(2016, 10, 22, 14, 0),
datetime.datetime(2017, 1, 21, 13, 0),
datetime.datetime(2017, 10, 21, 14, 0),
datetime.datetime(2018, 1, 20, 13, 0),
datetime.datetime(2018, 10, 20, 14, 0),
datetime.datetime(2019, 1, 19, 13, 0),
datetime.datetime(2019, 10, 26, 14, 0),
datetime.datetime(2020, 1, 18, 13, 0),
datetime.datetime(2020, 10, 24, 14, 0),
datetime.datetime(2021, 1, 23, 13, 0),
datetime.datetime(2021, 10, 23, 14, 0),
datetime.datetime(2022, 1, 22, 13, 0),
datetime.datetime(2022, 10, 22, 14, 0),
datetime.datetime(2023, 1, 21, 13, 0),
datetime.datetime(2023, 10, 21, 14, 0),
datetime.datetime(2024, 1, 20, 13, 0),
datetime.datetime(2024, 10, 26, 14, 0),
datetime.datetime(2025, 1, 18, 13, 0),
datetime.datetime(2025, 10, 25, 14, 0),
datetime.datetime(2026, 1, 17, 13, 0),
datetime.datetime(2026, 10, 24, 14, 0),
datetime.datetime(2027, 1, 23, 13, 0),
datetime.datetime(2027, 10, 23, 14, 0),
datetime.datetime(2028, 1, 22, 13, 0),
datetime.datetime(2028, 10, 21, 14, 0),
datetime.datetime(2029, 1, 20, 13, 0),
datetime.datetime(2029, 10, 20, 14, 0),
datetime.datetime(2030, 1, 19, 13, 0),
datetime.datetime(2030, 10, 26, 14, 0),
datetime.datetime(2031, 1, 18, 13, 0),
datetime.datetime(2031, 10, 25, 14, 0),
datetime.datetime(2032, 1, 17, 13, 0),
datetime.datetime(2032, 10, 23, 14, 0),
datetime.datetime(2033, 1, 22, 13, 0),
datetime.datetime(2033, 10, 22, 14, 0),
datetime.datetime(2034, 1, 21, 13, 0),
datetime.datetime(2034, 10, 21, 14, 0),
datetime.datetime(2035, 1, 20, 13, 0),
datetime.datetime(2035, 10, 20, 14, 0),
datetime.datetime(2036, 1, 19, 13, 0),
datetime.datetime(2036, 10, 25, 14, 0),
datetime.datetime(2037, 1, 17, 13, 0),
datetime.datetime(2037, 10, 24, 14, 0),
datetime.datetime(2038, 1, 23, 13, 0),
datetime.datetime(2038, 10, 23, 14, 0)]

)
self.assertEqual(
tz._transition_info,
[(
datetime.timedelta(0, 43200),
datetime.timedelta(0),
'custom_Pacific/Fiji_19151026T000000_+115544_+1200'
)] +
3 * [(
datetime.timedelta(0, 46800),
datetime.timedelta(0, 3600),
'custom_Pacific/Fiji_19981101T020000_+1200_+1300'
), (
datetime.timedelta(0, 43200),
datetime.timedelta(0),
'custom_Pacific/Fiji_19990228T030000_+1300_+1200')
] +
3 * [(
datetime.timedelta(0, 46800),
datetime.timedelta(0, 3600),
'custom_Pacific/Fiji_20101024T020000_+1200_+1300'
), (
datetime.timedelta(0, 43200),
datetime.timedelta(0),
'custom_Pacific/Fiji_19990228T030000_+1300_+1200'
)] +
25 * [(
datetime.timedelta(0, 46800),
datetime.timedelta(0, 3600),
'custom_Pacific/Fiji_20101024T020000_+1200_+1300'
), (
datetime.timedelta(0, 43200),
datetime.timedelta(0),
'custom_Pacific/Fiji_20140119T020000_+1300_+1200'
)] +
[(
datetime.timedelta(0, 46800),
datetime.timedelta(0, 3600),
'custom_Pacific/Fiji_20101024T020000_+1200_+1300'
)]
)

self.assertIn(
(
datetime.timedelta(0, 46800),
datetime.timedelta(0, 3600),
'custom_Pacific/Fiji_19981101T020000_+1200_+1300'
),
tz._tzinfos.keys()
)
self.assertIn(
(
datetime.timedelta(0, 43200),
datetime.timedelta(0),
'custom_Pacific/Fiji_19990228T030000_+1300_+1200'
),
tz._tzinfos.keys()
)

def test_same_start_date(self):
"""testing if we can handle VTIMEZONEs whose different components
have the same start DTIMEs."""
directory = os.path.dirname(__file__)
with open(os.path.join(directory, 'timezone_same_start.ics'), 'rb') as fp:
data = fp.read()
cal = icalendar.Calendar.from_ical(data)
d = cal.subcomponents[1]['DTSTART'].dt
self.assertEqual(d.strftime('%c'), 'Fri Feb 24 12:00:00 2017')

def test_same_start_date_and_offset(self):
"""testing if we can handle VTIMEZONEs whose different components
have the same DTSTARTs, TZOFFSETFROM, and TZOFFSETTO."""
directory = os.path.dirname(__file__)
with open(os.path.join(directory, 'timezone_same_start_and_offset.ics'), 'rb') as fp:
data = fp.read()
cal = icalendar.Calendar.from_ical(data)
d = cal.subcomponents[1]['DTSTART'].dt
self.assertEqual(d.strftime('%c'), 'Fri Feb 24 12:00:00 2017')

def test_rdate(self):
"""testing if we can handle VTIMEZONEs who only have an RDATE, not RRULE
"""
directory = os.path.dirname(__file__)
with open(os.path.join(directory, 'timezone_rdate.ics'), 'rb') as fp:
data = fp.read()
cal = icalendar.Calendar.from_ical(data)
vevent = cal.walk('VEVENT')[0]
tz = vevent['DTSTART'].dt.tzinfo
self.assertEqual(str(tz), 'posix/Europe/Vaduz')
self.assertEqual(
tz._utc_transition_times[:6],
[
datetime.datetime(1901, 12, 13, 20, 45, 38),
datetime.datetime(1941, 5, 5, 0, 0, 0),
datetime.datetime(1941, 10, 6, 0, 0, 0),
datetime.datetime(1942, 5, 4, 0, 0, 0),
datetime.datetime(1942, 10, 5, 0, 0, 0),
datetime.datetime(1981, 3, 29, 1, 0),
])
self.assertEqual(
tz._transition_info[:6],
[
(datetime.timedelta(0, 3600), datetime.timedelta(0), 'CET'),
(datetime.timedelta(0, 7200), datetime.timedelta(0, 3600), 'CEST'),
(datetime.timedelta(0, 3600), datetime.timedelta(0), 'CET'),
(datetime.timedelta(0, 7200), datetime.timedelta(0, 3600), 'CEST'),
(datetime.timedelta(0, 3600), datetime.timedelta(0), 'CET'),
(datetime.timedelta(0, 7200), datetime.timedelta(0, 3600), 'CEST'),
]
)

0 comments on commit a427643

Please sign in to comment.