summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authorGuido Guenther <agx@sigxcpu.org>2006-09-09 17:15:23 +0200
committerGuido Guenther <agx@bogon.sigxcpu.org>2006-09-09 17:15:23 +0200
commit0f963fa4c3d05e0f8b297aeb20aa5d719f7ab31d (patch)
tree8a580ddfbfbab89549d8e086f175fd0284652421 /tests
Import upstream version 0.0.svn147
Diffstat (limited to 'tests')
-rw-r--r--tests/recurrence.ics30
-rw-r--r--tests/tests.py711
-rw-r--r--tests/utf8_test.ics39
3 files changed, 780 insertions, 0 deletions
diff --git a/tests/recurrence.ics b/tests/recurrence.ics
new file mode 100644
index 0000000..f592234
--- /dev/null
+++ b/tests/recurrence.ics
@@ -0,0 +1,30 @@
+BEGIN:VCALENDAR
+VERSION
+ :2.0
+PRODID
+ :-//Mozilla.org/NONSGML Mozilla Calendar V1.0//EN
+BEGIN:VEVENT
+CREATED
+ :20060327T214227Z
+LAST-MODIFIED
+ :20060313T080829Z
+DTSTAMP
+ :20060116T231602Z
+UID
+ :70922B3051D34A9E852570EC00022388
+SUMMARY
+ :Monthly - All Hands Meeting with Joe Smith
+STATUS
+ :CONFIRMED
+CLASS
+ :PUBLIC
+RRULE
+ :FREQ=MONTHLY;UNTIL=20061228;INTERVAL=1;BYDAY=4TH
+DTSTART
+ :20060126T230000Z
+DTEND
+ :20060127T000000Z
+DESCRIPTION
+ :Repeat Meeting: - Occurs every 4th Thursday of each month
+END:VEVENT
+END:VCALENDAR
diff --git a/tests/tests.py b/tests/tests.py
new file mode 100644
index 0000000..16ef0c2
--- /dev/null
+++ b/tests/tests.py
@@ -0,0 +1,711 @@
+"""Long or boring tests for vobjects."""
+
+# add source directory to front of sys path
+import sys, os
+basepath = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
+sys.path.insert( 0, os.path.join( basepath, 'src', 'vobject' ) )
+
+import base, icalendar, behavior, vcard, hcalendar
+import StringIO, re, dateutil.tz, datetime
+
+
+#------------------- Testing and running functions -----------------------------
+def _test():
+ import doctest, base, tests, icalendar, __init__, re
+ flags = doctest.NORMALIZE_WHITESPACE | doctest.REPORT_ONLY_FIRST_FAILURE
+ for mod in base, tests, icalendar, __init__, vcard:
+ doctest.testmod(mod, verbose=0, optionflags=flags)
+ try:
+ sys.path.pop()
+ sys.path.insert( 0, os.path.join( basepath, 'src' ) )
+ doctest.testfile('../README.txt', optionflags=flags)
+ except IOError: #allow this test to fail if we can't find README.txt
+ pass
+
+
+if __name__ == '__main__':
+ _test()
+
+
+testSilly="""
+sillyname:name
+profile:sillyprofile
+stuff:folded
+ line
+""" + "morestuff;asinine:this line is not folded, \
+but in practice probably ought to be, as it is exceptionally long, \
+and moreover demonstratively stupid"
+
+icaltest=r"""BEGIN:VCALENDAR
+CALSCALE:GREGORIAN
+X-WR-TIMEZONE;VALUE=TEXT:US/Pacific
+METHOD:PUBLISH
+PRODID:-//Apple Computer\, Inc//iCal 1.0//EN
+X-WR-CALNAME;VALUE=TEXT:Example
+VERSION:2.0
+BEGIN:VEVENT
+SEQUENCE:5
+DTSTART;TZID=US/Pacific:20021028T140000
+RRULE:FREQ=Weekly;COUNT=10
+DTSTAMP:20021028T011706Z
+SUMMARY:Coffee with Jason
+UID:EC9439B1-FF65-11D6-9973-003065F99D04
+DTEND;TZID=US/Pacific:20021028T150000
+BEGIN:VALARM
+TRIGGER;VALUE=DURATION:-P1D
+ACTION:DISPLAY
+DESCRIPTION:Event reminder\, with comma\nand line feed
+END:VALARM
+END:VEVENT
+BEGIN:VTIMEZONE
+X-LIC-LOCATION:Random location
+TZID:US/Pacific
+LAST-MODIFIED:19870101T000000Z
+BEGIN:STANDARD
+DTSTART:19671029T020000
+RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10
+TZOFFSETFROM:-0700
+TZOFFSETTO:-0800
+TZNAME:PST
+END:STANDARD
+BEGIN:DAYLIGHT
+DTSTART:19870405T020000
+RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=4
+TZOFFSETFROM:-0800
+TZOFFSETTO:-0700
+TZNAME:PDT
+END:DAYLIGHT
+END:VTIMEZONE
+END:VCALENDAR"""
+
+vcardtest = """BEGIN:VCARD
+VERSION:3.0
+FN:Daffy Duck Knudson (with Bugs Bunny and Mr. Pluto)
+N:Knudson;Daffy Duck (with Bugs Bunny and Mr. Pluto)
+NICKNAME:gnat and gnu and pluto
+BDAY;value=date:02-10;11-05;01-01
+TEL;type=HOME:+01-(0)2-765.43.21
+TEL;type=CELL:+01-(0)5-555.55.55
+ACCOUNT;type=HOME:010-1234567-05
+ADR;type=HOME:;;Haight Street 512;Novosibirsk;;80214;Gnuland
+TEL;type=HOME:+01-(0)2-876.54.32
+ORG:University of Novosibirsk, Department of Octopus
+ Parthenogenesis
+END:VCARD"""
+
+vcardWithGroups = r"""home.begin:vcard
+version:3.0
+source:ldap://cn=Meister%20Berger,o=Universitaet%20Goerlitz,c=DE
+name:Meister Berger
+fn:Meister Berger
+n:Berger;Meister
+bday;value=date:1963-09-21
+o:Universit=E6t G=F6rlitz
+title:Mayor
+title;language=de;value=text:Burgermeister
+note:The Mayor of the great city of
+ Goerlitz in the great country of Germany.
+email;internet:mb@goerlitz.de
+home.tel;type=fax,voice;type=msg:+49 3581 123456
+home.label:Hufenshlagel 1234\n
+ 02828 Goerlitz\n
+ Deutschland
+END:VCARD"""
+
+lowercaseComponentNames = r"""begin:vcard
+fn:Anders Bobo
+n:Bobo;Anders
+org:Bobo A/S;Vice President, Technical Support
+adr:Rockfeller Center;;Mekastreet;Bobocity;;2100;Myworld
+email;internet:bobo@example.com
+tel;work:+123455
+tel;fax:+123456
+tel;cell:+123457
+x-mozilla-html:FALSE
+url:http://www.example.com
+version:2.1
+end:vcard"""
+
+icalWeirdTrigger = r"""BEGIN:VCALENDAR
+CALSCALE:GREGORIAN
+X-WR-TIMEZONE;VALUE=TEXT:US/Pacific
+METHOD:PUBLISH
+PRODID:-//Apple Computer\, Inc//iCal 1.0//EN
+X-WR-CALNAME;VALUE=TEXT:Example
+VERSION:2.0
+BEGIN:VEVENT
+DTSTART:20021028T140000Z
+BEGIN:VALARM
+TRIGGER:20021028T120000Z
+ACTION:DISPLAY
+DESCRIPTION:This trigger is a date-time without a VALUE=DATE-TIME parameter
+END:VALARM
+END:VEVENT
+END:VCALENDAR"""
+
+badstream = r"""BEGIN:VCALENDAR
+CALSCALE:GREGORIAN
+X-WR-TIMEZONE;VALUE=TEXT:US/Pacific
+METHOD:PUBLISH
+PRODID:-//Apple Computer\, Inc//iCal 1.0//EN
+X-WR-CALNAME;VALUE=TEXT:Example
+VERSION:2.0
+BEGIN:VEVENT
+DTSTART:20021028T140000Z
+BEGIN:VALARM
+TRIGGER:a20021028120000
+ACTION:DISPLAY
+DESCRIPTION:This trigger has a nonsensical value
+END:VALARM
+END:VEVENT
+END:VCALENDAR"""
+
+timezones = r"""
+
+BEGIN:VTIMEZONE
+TZID:US/Pacific
+BEGIN:STANDARD
+DTSTART:19671029T020000
+RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10
+TZOFFSETFROM:-0700
+TZOFFSETTO:-0800
+TZNAME:PST
+END:STANDARD
+BEGIN:DAYLIGHT
+DTSTART:19870405T020000
+RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=4
+TZOFFSETFROM:-0800
+TZOFFSETTO:-0700
+TZNAME:PDT
+END:DAYLIGHT
+END:VTIMEZONE
+
+BEGIN:VTIMEZONE
+TZID:US/Eastern
+BEGIN:STANDARD
+DTSTART:19671029T020000
+RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10
+TZOFFSETFROM:-0400
+TZOFFSETTO:-0500
+TZNAME:EST
+END:STANDARD
+BEGIN:DAYLIGHT
+DTSTART:19870405T020000
+RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=4
+TZOFFSETFROM:-0500
+TZOFFSETTO:-0400
+TZNAME:EDT
+END:DAYLIGHT
+END:VTIMEZONE
+
+BEGIN:VTIMEZONE
+TZID:Santiago
+BEGIN:STANDARD
+DTSTART:19700314T000000
+TZOFFSETFROM:-0300
+TZOFFSETTO:-0400
+RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=2SA
+TZNAME:Pacific SA Standard Time
+END:STANDARD
+BEGIN:DAYLIGHT
+DTSTART:19701010T000000
+TZOFFSETFROM:-0400
+TZOFFSETTO:-0300
+RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=2SA
+TZNAME:Pacific SA Daylight Time
+END:DAYLIGHT
+END:VTIMEZONE
+
+BEGIN:VTIMEZONE
+TZID:W. Europe
+BEGIN:STANDARD
+DTSTART:19701025T030000
+TZOFFSETFROM:+0200
+TZOFFSETTO:+0100
+RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU
+TZNAME:W. Europe Standard Time
+END:STANDARD
+BEGIN:DAYLIGHT
+DTSTART:19700329T020000
+TZOFFSETFROM:+0100
+TZOFFSETTO:+0200
+RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU
+TZNAME:W. Europe Daylight Time
+END:DAYLIGHT
+END:VTIMEZONE
+
+BEGIN:VTIMEZONE
+TZID:US/Fictitious-Eastern
+LAST-MODIFIED:19870101T000000Z
+BEGIN:STANDARD
+DTSTART:19671029T020000
+RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10
+TZOFFSETFROM:-0400
+TZOFFSETTO:-0500
+TZNAME:EST
+END:STANDARD
+BEGIN:DAYLIGHT
+DTSTART:19870405T020000
+RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=4;UNTIL=20050403T070000Z
+TZOFFSETFROM:-0500
+TZOFFSETTO:-0400
+TZNAME:EDT
+END:DAYLIGHT
+END:VTIMEZONE
+
+BEGIN:VTIMEZONE
+TZID:America/Montreal
+LAST-MODIFIED:20051013T233643Z
+BEGIN:DAYLIGHT
+DTSTART:20050403T070000
+TZOFFSETTO:-0400
+TZOFFSETFROM:+0000
+TZNAME:EDT
+END:DAYLIGHT
+BEGIN:STANDARD
+DTSTART:20051030T020000
+TZOFFSETTO:-0500
+TZOFFSETFROM:-0400
+TZNAME:EST
+END:STANDARD
+END:VTIMEZONE
+
+"""
+
+__test__ = { "Test readOne" :
+ r"""
+ >>> silly = base.readOne(testSilly)
+ >>> silly
+ <SILLYPROFILE| [<MORESTUFF{}this line is not folded, but in practice probably ought to be, as it is exceptionally long, and moreover demonstratively stupid>, <SILLYNAME{}name>, <STUFF{}foldedline>]>
+ >>> silly.stuff
+ <STUFF{}foldedline>
+ >>> original = silly.serialize()
+ >>> f3 = StringIO.StringIO(original)
+ >>> silly2 = base.readOne(f3)
+ >>> silly2.serialize()==original
+ True
+ >>> s3 = StringIO.StringIO('cn:Babs Jensen\r\ncn:Barbara J Jensen\r\nsn:Jensen\r\nemail:babs@umich.edu\r\nphone:+1 313 747-4454\r\nx-id:1234567890\r\n')
+ >>> ex1 = base.readOne(s3)
+ >>> ex1
+ <*unnamed*| [<CN{}Babs Jensen>, <CN{}Barbara J Jensen>, <EMAIL{}babs@umich.edu>, <PHONE{}+1 313 747-4454>, <SN{}Jensen>, <X-ID{}1234567890>]>
+ >>> ex1.serialize()
+ u'CN:Babs Jensen\r\nCN:Barbara J Jensen\r\nEMAIL:babs@umich.edu\r\nPHONE:+1 313 747-4454\r\nSN:Jensen\r\nX-ID:1234567890\r\n'
+ """,
+
+ "Import icaltest" :
+ r"""
+ >>> c = base.readOne(icaltest, validate=True)
+ >>> c.vevent.valarm.trigger
+ <TRIGGER{}-1 day, 0:00:00>
+ >>> c.vevent.dtstart.value
+ datetime.datetime(2002, 10, 28, 14, 0, tzinfo=<tzicalvtz 'US/Pacific'>)
+ >>> c.vevent.dtend.value
+ datetime.datetime(2002, 10, 28, 15, 0, tzinfo=<tzicalvtz 'US/Pacific'>)
+ >>> c.vevent.dtstamp.value
+ datetime.datetime(2002, 10, 28, 1, 17, 6, tzinfo=tzutc())
+ >>> c.vevent.valarm.description.value
+ u'Event reminder, with comma\nand line feed'
+ >>> c.vevent.valarm.description.serialize()
+ u'DESCRIPTION:Event reminder\\, with comma\\nand line feed\r\n'
+ >>> vevent = c.vevent.transformFromNative()
+ >>> vevent.rrule
+ <RRULE{}FREQ=Weekly;COUNT=10>
+ """,
+
+ "Parsing tests" :
+ """
+ >>> parseRDate = icalendar.MultiDateBehavior.transformToNative
+ >>> icalendar.stringToTextValues('')
+ ['']
+ >>> icalendar.stringToTextValues('abcd,efgh')
+ ['abcd', 'efgh']
+ >>> icalendar.stringToPeriod("19970101T180000Z/19970102T070000Z")
+ (datetime.datetime(1997, 1, 1, 18, 0, tzinfo=tzutc()), datetime.timedelta(0, 46800))
+ >>> parseRDate(base.textLineToContentLine("RDATE;VALUE=DATE:19970304,19970504,19970704,19970904"))
+ <RDATE{'VALUE': ['DATE']}[datetime.date(1997, 3, 4), datetime.date(1997, 5, 4), datetime.date(1997, 7, 4), datetime.date(1997, 9, 4)]>
+ >>> parseRDate(base.textLineToContentLine("RDATE;VALUE=PERIOD:19960403T020000Z/19960403T040000Z,19960404T010000Z/PT3H"))
+ <RDATE{'VALUE': ['PERIOD']}[(datetime.datetime(1996, 4, 3, 2, 0, tzinfo=tzutc()), datetime.timedelta(0, 7200)), (datetime.datetime(1996, 4, 4, 1, 0, tzinfo=tzutc()), datetime.timedelta(0, 10800))]>
+ """,
+
+ "read failure" :
+ """
+ >>> vevent = base.readOne(badstream)
+ Traceback (most recent call last):
+ ...
+ ParseError: At line 11: TRIGGER with no VALUE not recognized as DURATION or as DATE-TIME
+ """,
+
+ "ical trigger workaround" :
+ """
+
+ >>> badical = base.readOne(icalWeirdTrigger)
+ >>> badical.vevent.valarm.description.value
+ u'This trigger is a date-time without a VALUE=DATE-TIME parameter'
+ >>> badical.vevent.valarm.trigger.value
+ datetime.datetime(2002, 10, 28, 12, 0, tzinfo=tzutc())
+ """,
+
+ "unicode test" :
+ r"""
+ >>> f = open(os.path.join(basepath, 'tests', 'utf8_test.ics'))
+ >>> vevent = base.readOne(f).vevent
+ >>> vevent.summary.value
+ u'The title \u3053\u3093\u306b\u3061\u306f\u30ad\u30c6\u30a3'
+ >>> summary = vevent.summary.value
+ """,
+
+ # make sure date valued UNTILs in rrules are in a reasonable timezone,
+ # and include that day (12/28 in this test)
+ "recurrence test" :
+ r"""
+ >>> f = file(os.path.join(basepath, 'tests', 'recurrence.ics'))
+ >>> cal = base.readOne(f)
+ >>> dates = list(cal.vevent.rruleset)
+ >>> dates[0]
+ datetime.datetime(2006, 1, 26, 23, 0, tzinfo=tzutc())
+ >>> dates[1]
+ datetime.datetime(2006, 2, 23, 23, 0, tzinfo=tzutc())
+ >>> dates[-1]
+ datetime.datetime(2006, 12, 28, 23, 0, tzinfo=tzutc())
+ """,
+
+
+ "regular expression test" :
+ """
+ >>> re.findall(base.patterns['name'], '12foo-bar:yay')
+ ['12foo-bar', 'yay']
+ >>> re.findall(base.patterns['safe_char'], 'a;b"*,cd')
+ ['a', 'b', '*', 'c', 'd']
+ >>> re.findall(base.patterns['qsafe_char'], 'a;b"*,cd')
+ ['a', ';', 'b', '*', ',', 'c', 'd']
+ >>> re.findall(base.patterns['param_value'], '"quoted";not-quoted;start"after-illegal-quote', re.VERBOSE)
+ ['"quoted"', '', 'not-quoted', '', 'start', '', 'after-illegal-quote', '']
+ >>> match = base.line_re.match('TEST;ALTREP="http://www.wiz.org":value:;"')
+ >>> match.group('value')
+ 'value:;"'
+ >>> match.group('name')
+ 'TEST'
+ >>> match.group('params')
+ ';ALTREP="http://www.wiz.org"'
+ """,
+
+ "VTIMEZONE creation test:" :
+
+ """
+ >>> f = StringIO.StringIO(timezones)
+ >>> tzs = dateutil.tz.tzical(f)
+ >>> tzs.get("US/Pacific")
+ <tzicalvtz 'US/Pacific'>
+ >>> icalendar.TimezoneComponent(_)
+ <VTIMEZONE | <TZID{}US/Pacific>>
+ >>> pacific = _
+ >>> print pacific.serialize()
+ BEGIN:VTIMEZONE
+ TZID:US/Pacific
+ BEGIN:STANDARD
+ DTSTART:20001029T020000
+ RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10
+ TZNAME:PST
+ TZOFFSETFROM:-0700
+ TZOFFSETTO:-0800
+ END:STANDARD
+ BEGIN:DAYLIGHT
+ DTSTART:20000402T020000
+ RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=4
+ TZNAME:PDT
+ TZOFFSETFROM:-0800
+ TZOFFSETTO:-0700
+ END:DAYLIGHT
+ END:VTIMEZONE
+ >>> (_)
+ <VTIMEZONE | <TZID{}US/Pacific>>
+ >>> santiago = icalendar.TimezoneComponent(tzs.get('Santiago'))
+ >>> ser = santiago.serialize()
+ >>> print ser
+ BEGIN:VTIMEZONE
+ TZID:Santiago
+ BEGIN:STANDARD
+ DTSTART:20000311T000000
+ RRULE:FREQ=YEARLY;BYDAY=2SA;BYMONTH=3
+ TZNAME:Pacific SA Standard Time
+ TZOFFSETFROM:-0300
+ TZOFFSETTO:-0400
+ END:STANDARD
+ BEGIN:DAYLIGHT
+ DTSTART:20001014T000000
+ RRULE:FREQ=YEARLY;BYDAY=2SA;BYMONTH=10
+ TZNAME:Pacific SA Daylight Time
+ TZOFFSETFROM:-0400
+ TZOFFSETTO:-0300
+ END:DAYLIGHT
+ END:VTIMEZONE
+ >>> roundtrip = dateutil.tz.tzical(StringIO.StringIO(str(ser))).get()
+ >>> for year in range(2001, 2010):
+ ... for month in (2, 9):
+ ... dt = datetime.datetime(year, month, 15, tzinfo = roundtrip)
+ ... if dt.replace(tzinfo=tzs.get('Santiago')) != dt:
+ ... print "Failed for:", dt
+ >>> fict = icalendar.TimezoneComponent(tzs.get('US/Fictitious-Eastern'))
+ >>> print fict.serialize()
+ BEGIN:VTIMEZONE
+ TZID:US/Fictitious-Eastern
+ BEGIN:STANDARD
+ DTSTART:20001029T020000
+ RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10
+ TZNAME:EST
+ TZOFFSETFROM:-0400
+ TZOFFSETTO:-0500
+ END:STANDARD
+ BEGIN:DAYLIGHT
+ DTSTART:20000402T020000
+ RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=4;UNTIL=20050403T070000Z
+ TZNAME:EDT
+ TZOFFSETFROM:-0500
+ TZOFFSETTO:-0400
+ END:DAYLIGHT
+ END:VTIMEZONE
+ """,
+
+ "Create iCalendar from scratch" :
+
+ """
+ >>> cal = base.newFromBehavior('vcalendar', '2.0')
+ >>> cal.add('vevent')
+ <VEVENT| []>
+ >>> cal.vevent.add('dtstart').value = datetime.datetime(2006, 5, 9)
+ >>> cal.vevent.add('description').value = "Test event"
+ >>> pacific = dateutil.tz.tzical(StringIO.StringIO(timezones)).get('US/Pacific')
+ >>> cal.vevent.add('created').value = datetime.datetime(2006, 1, 1, 10, tzinfo=pacific)
+ >>> cal.vevent.add('uid').value = "Not very random UID"
+ >>> print cal.serialize()
+ BEGIN:VCALENDAR
+ VERSION:2.0
+ PRODID:-//PYVOBJECT//NONSGML Version 1//EN
+ BEGIN:VEVENT
+ UID:Not very random UID
+ DTSTART:20060509T000000
+ CREATED:20060101T180000Z
+ DESCRIPTION:Test event
+ END:VEVENT
+ END:VCALENDAR
+ """,
+
+ "Serializing with timezones test" :
+
+ """
+ >>> from dateutil.rrule import rrule, rruleset, WEEKLY
+ >>> pacific = dateutil.tz.tzical(StringIO.StringIO(timezones)).get('US/Pacific')
+ >>> cal = base.Component('VCALENDAR')
+ >>> cal.setBehavior(icalendar.VCalendar2_0)
+ >>> ev = cal.add('vevent')
+ >>> ev.add('dtstart').value = datetime.datetime(2005, 10, 12, 9, tzinfo = pacific)
+ >>> set = rruleset()
+ >>> set.rrule(rrule(WEEKLY, interval=2, byweekday=[2,4], until=datetime.datetime(2005, 12, 15, 9)))
+ >>> set.exdate(datetime.datetime(2005, 10, 14, 9, tzinfo = pacific))
+ >>> ev.rruleset = set
+ >>> ev.add('uid').value = "uid could be generated but doctest complains"
+ >>> ev.add('duration').value = datetime.timedelta(hours=1)
+ >>> print cal.serialize()
+ BEGIN:VCALENDAR
+ VERSION:2.0
+ PRODID:-//PYVOBJECT//NONSGML Version 1//EN
+ BEGIN:VTIMEZONE
+ TZID:US/Pacific
+ BEGIN:STANDARD
+ DTSTART:20001029T020000
+ RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10
+ TZNAME:PST
+ TZOFFSETFROM:-0700
+ TZOFFSETTO:-0800
+ END:STANDARD
+ BEGIN:DAYLIGHT
+ DTSTART:20000402T020000
+ RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=4
+ TZNAME:PDT
+ TZOFFSETFROM:-0800
+ TZOFFSETTO:-0700
+ END:DAYLIGHT
+ END:VTIMEZONE
+ BEGIN:VEVENT
+ UID:uid could be generated but doctest complains
+ DTSTART;TZID=US/Pacific:20051012T090000
+ DURATION:PT1H
+ EXDATE;TZID=US/Pacific:20051014T090000
+ RRULE:FREQ=WEEKLY;BYDAY=WE,FR;INTERVAL=2;UNTIL=20051215T090000
+ END:VEVENT
+ END:VCALENDAR
+ >>> apple = dateutil.tz.tzical(StringIO.StringIO(timezones)).get('America/Montreal')
+ >>> ev.dtstart.value = datetime.datetime(2005, 10, 12, 9, tzinfo = apple)
+ >>> print cal.serialize()
+ BEGIN:VCALENDAR
+ VERSION:2.0
+ PRODID:-//PYVOBJECT//NONSGML Version 1//EN
+ BEGIN:VTIMEZONE
+ TZID:US/Pacific
+ BEGIN:STANDARD
+ DTSTART:20001029T020000
+ RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10
+ TZNAME:PST
+ TZOFFSETFROM:-0700
+ TZOFFSETTO:-0800
+ END:STANDARD
+ BEGIN:DAYLIGHT
+ DTSTART:20000402T020000
+ RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=4
+ TZNAME:PDT
+ TZOFFSETFROM:-0800
+ TZOFFSETTO:-0700
+ END:DAYLIGHT
+ END:VTIMEZONE
+ BEGIN:VTIMEZONE
+ TZID:America/Montreal
+ BEGIN:STANDARD
+ DTSTART:20000101T000000
+ RRULE:FREQ=YEARLY;BYMONTH=1;UNTIL=20040101T050000Z
+ TZNAME:EST
+ TZOFFSETFROM:-0500
+ TZOFFSETTO:-0500
+ END:STANDARD
+ BEGIN:STANDARD
+ DTSTART:20051030T020000
+ RRULE:FREQ=YEARLY;BYDAY=5SU;BYMONTH=10
+ TZNAME:EST
+ TZOFFSETFROM:-0400
+ TZOFFSETTO:-0500
+ END:STANDARD
+ BEGIN:DAYLIGHT
+ DTSTART:20050403T070000
+ RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=4;UNTIL=20050403T120000Z
+ TZNAME:EDT
+ TZOFFSETFROM:-0500
+ TZOFFSETTO:-0400
+ END:DAYLIGHT
+ END:VTIMEZONE
+ BEGIN:VEVENT
+ UID:uid could be generated but doctest complains
+ DTSTART;TZID=America/Montreal:20051012T090000
+ DURATION:PT1H
+ EXDATE;TZID=US/Pacific:20051014T090000
+ RRULE:FREQ=WEEKLY;BYDAY=WE,FR;INTERVAL=2;UNTIL=20051215T090000
+ END:VEVENT
+ END:VCALENDAR
+ """,
+
+ "Serializing iCalendar to hCalendar" :
+
+ """
+ >>> cal = base.newFromBehavior('hcalendar')
+ >>> cal.behavior
+ <class 'hcalendar.HCalendar'>
+ >>> pacific = dateutil.tz.tzical(StringIO.StringIO(timezones)).get('US/Pacific')
+ >>> cal.add('vevent')
+ <VEVENT| []>
+ >>> cal.vevent.add('summary').value = "this is a note"
+ >>> cal.vevent.add('url').value = "http://microformats.org/code/hcalendar/creator"
+ >>> cal.vevent.add('dtstart').value = datetime.date(2006,2,27)
+ >>> cal.vevent.add('location').value = "a place"
+ >>> cal.vevent.add('dtend').value = datetime.date(2006,2,27) + datetime.timedelta(days = 2)
+ >>> event2 = cal.add('vevent')
+ >>> event2.add('summary').value = "Another one"
+ >>> event2.add('description').value = "The greatest thing ever!"
+ >>> event2.add('dtstart').value = datetime.datetime(1998, 12, 17, 16, 42, tzinfo = pacific)
+ >>> event2.add('location').value = "somewhere else"
+ >>> event2.add('dtend').value = event2.dtstart.value + datetime.timedelta(days = 6)
+ >>> hcal = cal.serialize()
+ >>> print hcal
+ <span class="vevent">
+ <a class="url" href="http://microformats.org/code/hcalendar/creator">
+ <span class="summary">this is a note</span>:
+ <abbr class="dtstart", title="20060227">Monday, February 27</abbr>
+ - <abbr class="dtend", title="20060301">Tuesday, February 28</abbr>
+ at <span class="location">a place</span>
+ </a>
+ </span>
+ <span class="vevent">
+ <span class="summary">Another one</span>:
+ <abbr class="dtstart", title="19981217T164200-0800">Thursday, December 17, 16:42</abbr>
+ - <abbr class="dtend", title="19981223T164200-0800">Wednesday, December 23, 16:42</abbr>
+ at <span class="location">somewhere else</span>
+ <div class="description">The greatest thing ever!</div>
+ </span>
+ """,
+
+ "Generate UIDs automatically test:" :
+
+ """
+ >>> cal = base.newFromBehavior('vcalendar')
+ >>> cal.add('vevent').add('dtstart').value = datetime.datetime(2006,2,2,10)
+ >>> ser = cal.serialize()
+ >>> len(cal.vevent.uid_list)
+ 1
+ """,
+
+ "VCARD 3.0 parse test:" :
+
+ r"""
+ >>> card = base.readOne(vcardtest)
+ >>> card.adr.value
+ <Address: Haight Street 512\nNovosibirsk, 80214\nGnuland>
+ >>> print card.adr.value
+ Haight Street 512
+ Novosibirsk, 80214
+ Gnuland
+ >>> card.org.value
+ u'University of Novosibirsk, Department of Octopus Parthenogenesis'
+ >>> print card.serialize()
+ BEGIN:VCARD
+ VERSION:3.0
+ ACCOUNT;TYPE=HOME:010-1234567-05
+ ADR;TYPE=HOME:;;Haight Street 512;Novosibirsk;;80214;Gnuland
+ BDAY;VALUE=date:02-10;11-05;01-01
+ FN:Daffy Duck Knudson (with Bugs Bunny and Mr. Pluto)
+ N:Knudson;Daffy Duck (with Bugs Bunny and Mr. Pluto);;;
+ NICKNAME:gnat and gnu and pluto
+ ORG:University of Novosibirsk, Department of Octopus Parthenogenesis
+ TEL;TYPE=HOME:+01-(0)2-765.43.21
+ TEL;TYPE=CELL:+01-(0)5-555.55.55
+ TEL;TYPE=HOME:+01-(0)2-876.54.32
+ END:VCARD
+ """,
+
+ "Multi-text serialization test:" :
+
+ """
+ >>> category = base.newFromBehavior('categories')
+ >>> category.value = ['Random category']
+ >>> print category.serialize().strip()
+ CATEGORIES:Random category
+ >>> category.value.append('Other category')
+ >>> print category.serialize().strip()
+ CATEGORIES:Random category,Other category
+ """,
+
+ "vCard groups test:" :
+
+ """
+ >>> card = base.readOne(vcardWithGroups)
+ >>> card.group
+ u'home'
+ >>> card.tel.group
+ u'home'
+ >>> card.group = card.tel.group = 'new'
+ >>> card.tel.serialize().strip()
+ u'new.TEL;TYPE=fax,voice,msg:+49 3581 123456'
+ >>> card.serialize().splitlines()[0]
+ u'new.BEGIN:VCARD'
+ >>> dtstart = base.newFromBehavior('dtstart')
+ >>> dtstart.group = "badgroup"
+ >>> dtstart.serialize()
+ Traceback (most recent call last):
+ ...
+ VObjectError: "<DTSTART{}> has a group, but this object doesn't support groups"
+ """,
+
+ "Lowercase components test:" :
+
+ """
+ >>> card = base.readOne(lowercaseComponentNames)
+ >>> card.version
+ <VERSION{}2.1>
+ """
+ }
diff --git a/tests/utf8_test.ics b/tests/utf8_test.ics
new file mode 100644
index 0000000..fbb9ada
--- /dev/null
+++ b/tests/utf8_test.ics
@@ -0,0 +1,39 @@
+BEGIN:VCALENDAR
+METHOD:PUBLISH
+CALSCALE:GREGORIAN
+PRODID:-//EVDB//www.evdb.com//EN
+VERSION:2.0
+X-WR-CALNAME:EVDB Event Feed
+BEGIN:VEVENT
+DTSTART:20060922T000100Z
+DTEND:20060922T050100Z
+DTSTAMP:20050914T163414Z
+SUMMARY:The title こんにちはキティ
+DESCRIPTION:hello\nHere is a description\n\n\nこんにちはキティ
+ \n\n\n\nZwei Java-schwere Entwicklerpositionen und irgendeine Art sond
+ erbar-klingende Netzsichtbarmachungöffnung\, an einer interessanten F
+ irma im Gebäude\, in dem ich angerufenen Semantic Research bearbeite.
+ 1. Zauberer Des Semantica Software Engineer 2. Älterer Semantica Sof
+ tware-Englisch-3. Graph/Semantica Netz-Visualization/Navigation Sie ei
+ ngestufte Software-Entwicklung für die Regierung. Die Firma ist stark
+ und die Projekte sind sehr kühl und schließen irgendeinen Spielraum
+ ein. Wenn ich Ihnen irgendwie mehr erkläre\, muß ich Sie töten. Ps
+ . Tat schnell -- jemand ist\, wenn es hier interviewt\, wie ich dieses
+ schreibe. Er schaut intelligent (er trägt Kleidhosen) Semantica Soft
+ ware Engineer FIRMA: Semantische Forschung\, Inc. REPORTS ZU: Vizeprä
+ sident\, Produkt-Entwicklung POSITION: San Diego (Pint Loma) WEB SITE:
+ www.semanticresearch.com email: dorie@semanticresearch.com FIRMA-HINT
+ ERGRUND Semantische Forschung ist der führende Versorger der semantis
+ cher Netzwerkanschluß gegründeten nicht linearen Wissen Darstellung
+ Werkzeuge. Die Firma stellt diese Werkzeuge zum Intel\, zur reg.\, zum
+ EDU und zu den kommerziellen Märkten zur Verfügung. BRINGEN SIE ZUS
+ AMMENFASSUNG IN POSITION Semantische Forschung\, Inc. basiert in San D
+ iego\, Ca im alten realen Weltsan Diego Haus...\, das wir den Weltbest
+ en Platz haben zum zu arbeiten. Wir suchen nach Superstarentwicklern\,
+ um uns in der fortfahrenden Entwicklung unserer Semantica Produktseri
+ e zu unterstützen.
+LOCATION:こんにちはキティ
+SEQUENCE:0
+UID:E0-001-000276068-2
+END:VEVENT
+END:VCALENDAR \ No newline at end of file