vpim 0.597 → 0.602

Sign up to get free protection for your applications and to get access to all the features.
data/test/test_date.rb ADDED
@@ -0,0 +1,120 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'vpim/date'
4
+ require 'vpim/time'
5
+ require 'test/unit'
6
+
7
+ class TestVpimDate < Test::Unit::TestCase
8
+
9
+ def test_to_time
10
+ # Need to test with DateTime, but I don't have that with ruby 1.6.
11
+ assert_equal(Time.at(0), Date.new(1970, 1, 1).to_time)
12
+ assert_equal(Time.at(24 * 60 * 60), Date.new(1970, 1, 2).to_time)
13
+ end
14
+
15
+ def test_date_weekstart
16
+ assert_equal(Date.weekstart(2004, 01, 12, 'tu').to_s, Date.new(2004, 01, 6).to_s)
17
+ assert_equal(Date.weekstart(2004, 01, 12, 'we').to_s, Date.new(2004, 01, 7).to_s)
18
+ assert_equal(Date.weekstart(2004, 01, 12, 'th').to_s, Date.new(2004, 01, 8).to_s)
19
+ assert_equal(Date.weekstart(2004, 01, 12, 'fr').to_s, Date.new(2004, 01, 9).to_s)
20
+ assert_equal(Date.weekstart(2004, 01, 12, 'sa').to_s, Date.new(2004, 01, 10).to_s)
21
+ assert_equal(Date.weekstart(2004, 01, 12, 'su').to_s, Date.new(2004, 01, 11).to_s)
22
+ assert_equal(Date.weekstart(2004, 01, 12, 'mo').to_s, Date.new(2004, 01, 12).to_s)
23
+ end
24
+
25
+ def do_bywday(args, expect)
26
+ # Rewrite 'string' weekday specifications.
27
+ args = [ args[0], args[1], Date.str2wday(args[2]), args[3] ]
28
+ date = Date.bywday(*args)
29
+ dates = DateGen.bywday(*args)
30
+ need = Date.new(*expect)
31
+
32
+ assert_equal(date, need)
33
+
34
+ # Date.bywday always produces a single date, so should the generator, in
35
+ # this case.
36
+ assert_equal(dates[0], need)
37
+ end
38
+
39
+ def test_bywday
40
+
41
+ # 2004
42
+ #
43
+ # January February March
44
+ # S M Tu W Th F S S M Tu W Th F S S M Tu W Th F S
45
+ # 1 2 3 1 2 3 4 5 6 7 1 2 3 4 5 6
46
+ # 4 5 6 7 8 9 10 8 9 10 11 12 13 14 7 8 9 10 11 12 13
47
+ # 11 12 13 14 15 16 17 15 16 17 18 19 20 21 14 15 16 17 18 19 20
48
+ # 18 19 20 21 22 23 24 22 23 24 25 26 27 28 21 22 23 24 25 26 27
49
+ # 25 26 27 28 29 30 31 29 28 29 30 31
50
+ #
51
+ do_bywday([2004, 1, 4, 1], [2004, 1, 1])
52
+ do_bywday([2004, 1, 4, 2], [2004, 1, 8])
53
+ do_bywday([2004, 1, 4, -1], [2004, 1, 29])
54
+ do_bywday([2004, 1, 4, -2], [2004, 1, 22])
55
+ do_bywday([2004, 1, 4, -5], [2004, 1, 1])
56
+ do_bywday([2004,nil, 4, 1], [2004, 1, 1])
57
+ do_bywday([2004,nil, 4, 2], [2004, 1, 8])
58
+ do_bywday([2004,-12, 4, 1], [2004, 1, 1])
59
+ do_bywday([2004,-12, 4, 2], [2004, 1, 8])
60
+ do_bywday([2004,-12, 4, -1], [2004, 1, 29])
61
+ do_bywday([2004,-12, 4, -2], [2004, 1, 22])
62
+ do_bywday([2004,-12, 4, -5], [2004, 1, 1])
63
+
64
+ do_bywday([2004, 1, "th", 1], [2004, 1, 1])
65
+ do_bywday([2004, 1, "th", 2], [2004, 1, 8])
66
+ do_bywday([2004, 1, "th", -1], [2004, 1, 29])
67
+ do_bywday([2004, 1, "th", -2], [2004, 1, 22])
68
+ do_bywday([2004, 1, "th", -5], [2004, 1, 1])
69
+ do_bywday([2004,nil, "th", 1], [2004, 1, 1])
70
+ do_bywday([2004,nil, "th", 2], [2004, 1, 8])
71
+ do_bywday([2004,-12, "th", 1], [2004, 1, 1])
72
+ do_bywday([2004,-12, "th", 2], [2004, 1, 8])
73
+ do_bywday([2004,-12, "th", -1], [2004, 1, 29])
74
+ do_bywday([2004,-12, "th", -2], [2004, 1, 22])
75
+ do_bywday([2004,-12, "th", -5], [2004, 1, 1])
76
+
77
+ # October November December
78
+ # S M Tu W Th F S S M Tu W Th F S S M Tu W Th F S
79
+ # 1 2 1 2 3 4 5 6 1 2 3 4
80
+ # 3 4 5 6 7 8 9 7 8 9 10 11 12 13 5 6 7 8 9 10 11
81
+ # 10 11 12 13 14 15 16 14 15 16 17 18 19 20 12 13 14 15 16 17 18
82
+ # 17 18 19 20 21 22 23 21 22 23 24 25 26 27 19 20 21 22 23 24 25
83
+ # 24 25 26 27 28 29 30 28 29 30 26 27 28 29 30 31
84
+ # 31
85
+
86
+ do_bywday([2004, -1, 4, 1], [2004, 12, 2])
87
+ do_bywday([2004, -1, 4, -1], [2004, 12, 30])
88
+ do_bywday([2004, -1, 4, -2], [2004, 12, 23])
89
+ do_bywday([2004, -1, 4, -5], [2004, 12, 2])
90
+ do_bywday([2004,nil, 4, -1], [2004, 12, 30])
91
+ do_bywday([2004,nil, 4, -2], [2004, 12, 23])
92
+ do_bywday([2004,nil, 4, -5], [2004, 12, 2])
93
+ do_bywday([2004,nil, 4, -7], [2004, 11, 18])
94
+
95
+ end
96
+
97
+ def do_gen(args)
98
+ assert_nothing_thrown do
99
+ dates = DateGen.bywday(*args)
100
+ dates.each do |d|
101
+ assert_equal(args[0], d.year)
102
+ if(args[1])
103
+ mon = args[1]
104
+ if mon < 0
105
+ mon = 13 + args[1]
106
+ end
107
+ assert_equal(mon, d.mon)
108
+ end
109
+ assert_equal(args[2], d.wday)
110
+ end
111
+ end
112
+ end
113
+
114
+ def test_gen
115
+ do_gen([2004, 12, 1])
116
+ do_gen([2004, -1, 1])
117
+ do_gen([2004, nil, 1])
118
+ end
119
+ end
120
+
data/test/test_dur.rb ADDED
@@ -0,0 +1,41 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'vpim/duration'
4
+ require 'test/unit'
5
+
6
+ include Vpim
7
+
8
+ class TestVpimDate < Test::Unit::TestCase
9
+
10
+ def duration(d0, h0, m0, s0)
11
+ # 3 hours, 2 mins, 39 secs
12
+ d = Duration.secs(d0 * 24 * 60 * 60 + h0 * 60 * 60 + m0 * 60 + s0)
13
+
14
+ assert_equal(d.secs, d0 * 24 * 60 * 60 + h0 * 60 * 60 + m0 * 60 + s0)
15
+ assert_equal(d.mins, d0 * 24 * 60 + h0 * 60 + m0)
16
+ assert_equal(d.hours, d0 * 24 + h0)
17
+ assert_equal(d.days, d0)
18
+ assert_equal(d.by_hours, [d0*24 + h0, m0, s0])
19
+ assert_equal(d.by_days, [d0, h0, m0, s0])
20
+
21
+ h, m, s = d.by_hours
22
+
23
+ assert_equal(h, h0 + d0*24)
24
+ assert_equal(m, m0)
25
+ assert_equal(s, s0)
26
+
27
+ d, h, m, s = d.by_days
28
+
29
+ assert_equal(d, d0)
30
+ assert_equal(h, h0)
31
+ assert_equal(m, m0)
32
+ assert_equal(s, s0)
33
+ end
34
+
35
+ def test_1
36
+ duration(0, 3, 2, 39)
37
+ duration(5, 23, 39, 1)
38
+ end
39
+
40
+ end
41
+
@@ -0,0 +1,156 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'test/unit'
4
+ require 'pp'
5
+ require 'vpim/field'
6
+
7
+ Field=Vpim::DirectoryInfo::Field
8
+
9
+ class TestField < Test::Unit::TestCase
10
+
11
+ def test_encode_decode_text()
12
+ enc_in = "+\\\\+\\n+\\N+\\,+\\;+\\a+\\b+\\c+"
13
+ dec = Vpim.decode_text(enc_in)
14
+ #puts("<#{enc_in}> => <#{dec}>")
15
+ assert_equal("+\\+\n+\n+,+;+a+b+c+", dec)
16
+ enc_out = Vpim.encode_text(dec)
17
+ should_be = "+\\\\+\\n+\\n+\\,+\\;+a+b+c+"
18
+ # Note a, b, and c are allowed to be escaped, but shouldn't be and
19
+ # aren't in output
20
+ #puts("<#{dec}> => <#{enc_out}>")
21
+ assert_equal(should_be, enc_out)
22
+
23
+ end
24
+
25
+ def test_field4
26
+ line = 't;e=a,b: 4 '
27
+ part = Field.decode0(line)
28
+ assert_equal("4", part[ 3 ])
29
+ end
30
+
31
+ def test_field3
32
+ line = 't;e=a,b:4'
33
+ part = Field.decode0(line)
34
+ assert_equal("4", part[ 3 ])
35
+ assert_equal( {'E' => [ 'a','b' ] }, part[ 2 ])
36
+ end
37
+
38
+ def test_field2
39
+ line = 'tel;type=work,voice,msg:+1 313 747-4454'
40
+ part = Field.decode0(line)
41
+ assert_equal("+1 313 747-4454", part[ 3 ])
42
+ assert_equal( {'TYPE' => [ 'work','voice','msg' ] }, part[ 2 ])
43
+ end
44
+
45
+ def test_field1
46
+ line = 'ORGANIZER;CN="xxxx, xxxx [SC100:370:EXCH]":MAILTO:xxxx@americasm01.nt.com'
47
+ parts = Field.decode0(line)
48
+
49
+ assert_equal(nil, parts[0])
50
+ assert_equal('ORGANIZER', parts[1])
51
+ assert_equal({ 'CN' => [ "xxxx, xxxx [SC100:370:EXCH]" ] }, parts[2])
52
+ assert_equal('MAILTO:xxxx@americasm01.nt.com', parts[3])
53
+ end
54
+
55
+ =begin this can not be done :-(
56
+ def test_case_equiv
57
+ line = 'ORGANIZER;CN="xxxx, xxxx [SC100:370:EXCH]":MAILTO:xxxx@americasm01.nt.com'
58
+ field = Field.decode(line)
59
+ assert_equal(true, field.name?('organIZER'))
60
+ assert_equal(true, field === 'organIZER')
61
+
62
+ b = nil
63
+ case field
64
+ when 'organIZER'
65
+ b = true
66
+ end
67
+
68
+ assert_equal(true, b)
69
+ end
70
+ =end
71
+
72
+ def test_field0
73
+ assert_equal('name:', line = Field.encode0(nil, 'name'))
74
+ assert_equal([ nil, 'NAME', {}, ''], Field.decode0(line))
75
+
76
+ assert_equal('name:value', line = Field.encode0(nil, 'name', {}, 'value'))
77
+ assert_equal([ nil, 'NAME', {}, 'value'], Field.decode0(line))
78
+
79
+ assert_equal('name;encoding=B:dmFsdWU=', line = Field.encode0(nil, 'name', { 'encoding'=>:b64 }, 'value'))
80
+ assert_equal([ nil, 'NAME', { 'ENCODING'=>['B']}, ['value'].pack('m').chomp ], Field.decode0(line))
81
+
82
+ assert_equal('group.name:value', line = Field.encode0('group', 'name', {}, 'value'))
83
+ assert_equal([ 'GROUP', 'NAME', {}, 'value'], Field.decode0(line))
84
+ end
85
+
86
+ def tEst_invalid_fields
87
+ [
88
+ 'g.:',
89
+ ':v',
90
+ ].each do |line|
91
+ assert_raises(Vpim::InvalidEncodingError) { Field.decode0(line) }
92
+ end
93
+ end
94
+
95
+ def test_date_encode
96
+ assert_equal("DTSTART:20040101\n", Field.create('DTSTART', Date.new(2004, 1, 1) ).to_s)
97
+ assert_equal("DTSTART:20040101\n", Field.create('DTSTART', [Date.new(2004, 1, 1)]).to_s)
98
+ end
99
+
100
+ def test_field_modify
101
+ f = Field.create('name')
102
+
103
+ assert_equal('', f.value)
104
+ f.value = ''
105
+ assert_equal('', f.value)
106
+ f.value = 'z'
107
+ assert_equal('z', f.value)
108
+
109
+ f.group = 'z.b'
110
+ assert_equal('Z.B', f.group)
111
+ assert_equal("z.b.NAME:z\n", f.encode)
112
+
113
+ assert_raises(TypeError) { f.value = :group }
114
+
115
+ assert_equal('Z.B', f.group)
116
+
117
+ assert_equal("z.b.NAME:z\n", f.encode)
118
+
119
+ assert_raises(TypeError) { f.group = :group }
120
+
121
+ assert_equal("z.b.NAME:z\n", f.encode)
122
+ assert_equal('Z.B', f.group)
123
+
124
+ f['p0'] = "hi julie"
125
+
126
+ assert_equal("Z.B.NAME;P0=hi julie:z\n", f.encode)
127
+ assert_equal(['hi julie'], f.param('p0'))
128
+ assert_equal(['hi julie'], f['p0'])
129
+ assert_equal('NAME', f.name)
130
+ assert_equal('Z.B', f.group)
131
+
132
+ # FAIL assert_raises(ArgumentError) { f.group = 'z.b:' }
133
+
134
+ assert_equal('Z.B', f.group)
135
+
136
+ f.value = 'some text'
137
+
138
+ assert_equal('some text', f.value)
139
+ assert_equal('some text', f.value_raw)
140
+
141
+ f['encoding'] = :b64
142
+
143
+ assert_equal('some text', f.value)
144
+ assert_equal([ 'some text' ].pack('m*').chomp, f.value_raw)
145
+ end
146
+
147
+ def test_field_wrapping
148
+ assert_equal("0:x\n", Vpim::DirectoryInfo::Field.create('0', 'x' * 1).encode(4))
149
+ assert_equal("0:xx\n", Vpim::DirectoryInfo::Field.create('0', 'x' * 2).encode(4))
150
+ assert_equal("0:xx\n x\n", Vpim::DirectoryInfo::Field.create('0', 'x' * 3).encode(4))
151
+ assert_equal("0:xx\n xx\n", Vpim::DirectoryInfo::Field.create('0', 'x' * 4).encode(4))
152
+ assert_equal("0:xx\n xxxx\n", Vpim::DirectoryInfo::Field.create('0', 'x' * 6).encode(4))
153
+ assert_equal("0:xx\n xxxx\n x\n", Vpim::DirectoryInfo::Field.create('0', 'x' * 7).encode(4))
154
+ end
155
+ end
156
+
data/test/test_ical.rb ADDED
@@ -0,0 +1,201 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'vpim/icalendar'
4
+ require 'test/unit'
5
+
6
+ include Vpim
7
+
8
+ Req_1 =<<___
9
+ BEGIN:VCALENDAR
10
+ METHOD:REQUEST
11
+ PRODID:-//Lotus Development Corporation//NONSGML Notes 6.0//EN
12
+ VERSION:2.0
13
+ X-LOTUS-CHARSET:UTF-8
14
+ BEGIN:VTIMEZONE
15
+ TZID:Pacific
16
+ BEGIN:STANDARD
17
+ DTSTART:19501029T020000
18
+ TZOFFSETFROM:-0700
19
+ TZOFFSETTO:-0800
20
+ RRULE:FREQ=YEARLY;BYMINUTE=0;BYHOUR=2;BYDAY=-1SU;BYMONTH=10
21
+ END:STANDARD
22
+ BEGIN:DAYLIGHT
23
+ DTSTART:19500402T020000
24
+ TZOFFSETFROM:-0800
25
+ TZOFFSETTO:-0700
26
+ RRULE:FREQ=YEARLY;BYMINUTE=0;BYHOUR=2;BYDAY=1SU;BYMONTH=4
27
+ END:DAYLIGHT
28
+ END:VTIMEZONE
29
+ BEGIN:VEVENT
30
+ ATTENDEE;ROLE=CHAIR;PARTSTAT=ACCEPTED;CN="Gary Pope/Certicom"
31
+ ;RSVP=FALSE:mailto:gpope@certicom.com
32
+ ATTENDEE;ROLE=REQ-PARTICIPANT;PARTSTAT=NEEDS-ACTION
33
+ ;CN="Mike Harvey/Certicom";RSVP=TRUE:mailto:MHarvey@certicom.com
34
+ ATTENDEE;ROLE=REQ-PARTICIPANT;PARTSTAT=NEEDS-ACTION;RSVP=TRUE
35
+ :mailto:rgallant@emilpost.certicom.com
36
+ ATTENDEE;ROLE=REQ-PARTICIPANT;PARTSTAT=NEEDS-ACTION
37
+ ;CN="Sam Roberts/Certicom";RSVP=TRUE:mailto:SRoberts@certicom.com
38
+ ATTENDEE;ROLE=REQ-PARTICIPANT;PARTSTAT=NEEDS-ACTION
39
+ ;CN="Tony Walters/Certicom";RSVP=TRUE:mailto:TWalters@certicom.com
40
+ CLASS:PUBLIC
41
+ DTEND;TZID="Pacific":20040415T130000
42
+ DTSTAMP:20040319T205045Z
43
+ DTSTART;TZID="Pacific":20040415T120000
44
+ ORGANIZER;CN="Gary Pope/Certicom":mailto:gpope@certicom.com
45
+ SEQUENCE:0
46
+ SUMMARY:hjold intyel
47
+ TRANSP:OPAQUE
48
+ UID:3E19204063C93D2388256E5C006BF8D9-Lotus_Notes_Generated
49
+ X-LOTUS-BROADCAST:FALSE
50
+ X-LOTUS-CHILD_UID:3E19204063C93D2388256E5C006BF8D9
51
+ X-LOTUS-NOTESVERSION:2
52
+ X-LOTUS-NOTICETYPE:I
53
+ X-LOTUS-UPDATE-SEQ:1
54
+ X-LOTUS-UPDATE-WISL:$S:1;$L:1;$B:1;$R:1;$E:1
55
+ END:VEVENT
56
+ END:VCALENDAR
57
+ ___
58
+
59
+ Rep_1 =<<___
60
+ BEGIN:VCALENDAR
61
+ CALSCALE:GREGORIAN
62
+ PRODID:-//Apple Computer\, Inc//iCal 1.5//EN
63
+ VERSION:2.0
64
+ METHOD:REPLY
65
+ BEGIN:VEVENT
66
+ ATTENDEE;CN="Sam Roberts/Certicom";PARTSTAT=ACCEPTED;ROLE=REQ-PARTICIPAN
67
+ T;RSVP=TRUE:mailto:SRoberts@certicom.com
68
+ CLASS:PUBLIC
69
+ DTEND;TZID=Pacific:20040415T130000
70
+ DTSTAMP:20040319T205045Z
71
+ DTSTART;TZID=Pacific:20040415T120000
72
+ ORGANIZER;CN="Gary Pope/Certicom":mailto:gpope@certicom.com
73
+ SEQUENCE:0
74
+ SUMMARY:hjold intyel
75
+ TRANSP:OPAQUE
76
+ UID:3E19204063C93D2388256E5C006BF8D9-Lotus_Notes_Generated
77
+ X-LOTUS-BROADCAST:FALSE
78
+ X-LOTUS-CHILDUID:3E19204063C93D2388256E5C006BF8D9
79
+ X-LOTUS-NOTESVERSION:2
80
+ X-LOTUS-NOTICETYPE:I
81
+ X-LOTUS-UPDATE-SEQ:1
82
+ X-LOTUS-UPDATE-WISL:$S:1\;$L:1\;$B:1\;$R:1\;$E:1
83
+ END:VEVENT
84
+ END:VCALENDAR
85
+ ___
86
+
87
+ class TestIcal < Test::Unit::TestCase
88
+
89
+ # Reported by Kyle Maxwell
90
+ def test_serialize_todo
91
+ icstodo =<<___
92
+ BEGIN:VCALENDAR
93
+ VERSION:2.0
94
+ BEGIN:VTODO
95
+ END:VTODO
96
+ END:VCALENDAR
97
+ ___
98
+
99
+ cal = Icalendar.decode(icstodo)
100
+ assert_equal(icstodo, cal.to_s)
101
+ end
102
+
103
+ def test_1
104
+ req = Icalendar.decode(Req_1).first
105
+
106
+ req.components { }
107
+ req.components(Icalendar::Vevent) { }
108
+ req.components(Icalendar::Vjournal) { }
109
+ assert_equal(1, req.components.size)
110
+ assert_equal(1, req.components(Icalendar::Vevent).size)
111
+ assert_equal(0, req.components(Icalendar::Vjournal).size)
112
+
113
+ assert_equal(req.protocol, 'REQUEST')
114
+
115
+ event = req.events.first
116
+
117
+ assert(event)
118
+
119
+ assert( event.attendee?('mailto:sroberts@certicom.com'))
120
+ assert(!event.attendee?('mailto:sroberts@uniserve.com'))
121
+
122
+ me = event.attendees('mailto:sroberts@certicom.com').first
123
+
124
+ assert(me)
125
+ assert(me == 'mailto:sroberts@certicom.com')
126
+
127
+ reply = Icalendar.create_reply
128
+
129
+ reply.push(event.accept(me))
130
+
131
+ # puts "Reply=>"
132
+ # puts reply.to_s
133
+ end
134
+
135
+ def test_hal1
136
+ # Hal was encoding raw strings, here's how to do it with the API.
137
+
138
+ cal = Icalendar.create
139
+
140
+ start = Time.now
141
+
142
+ event = Icalendar::Vevent.create(start,
143
+ 'DTEND' => start + 60 * 60,
144
+ 'SUMMARY' => "this is an event",
145
+ 'RRULE' => 'freq=monthly;byday=2fr,4fr;count=5'
146
+ )
147
+
148
+ cal.push event
149
+
150
+ #puts cal.encode
151
+ end
152
+
153
+ # FIXME - test bad durations, like 'PT1D'
154
+
155
+ def test_duration
156
+ event = Icalendar::Vevent.create(Date.new(2000, 1, 21))
157
+ assert_equal(nil, event.duration)
158
+ assert_equal(nil, event.dtend)
159
+
160
+ event = Icalendar::Vevent.create(Date.new(2000, 1, 21),
161
+ 'DURATION' => 'PT1H')
162
+ assert_equal(Time.gm(2000, 1, 21, 1), event.dtend)
163
+
164
+ event = Icalendar::Vevent.create(Date.new(2000, 1, 21),
165
+ 'DTEND' => Date.new(2000, 1, 22))
166
+ assert_equal(24*60*60, event.duration)
167
+ end
168
+
169
+ def test_decode_duration_four_weeks
170
+ assert_equal 4*7*86400, Icalendar.decode_duration('P4W')
171
+ end
172
+
173
+ def test_decode_duration_negative_two_weeks
174
+ assert_equal(-2*7*86400, Icalendar.decode_duration('-P2W'))
175
+ end
176
+
177
+ def test_decode_duration_five_days
178
+ assert_equal 5*86400, Icalendar.decode_duration('P5D')
179
+ end
180
+
181
+ def test_decode_duration_one_hour
182
+ assert_equal 3600, Icalendar.decode_duration('PT1H')
183
+ end
184
+
185
+ def test_decode_duration_five_minutes
186
+ assert_equal 5*60, Icalendar.decode_duration('PT5M')
187
+ end
188
+
189
+ def test_decode_duration_ten_seconds
190
+ assert_equal 10, Icalendar.decode_duration('PT10S')
191
+ end
192
+
193
+ def test_decode_duration_with_leading_plus
194
+ assert_equal 10, Icalendar.decode_duration('+PT10S')
195
+ end
196
+
197
+ def test_decode_duration_with_composite_duration
198
+ assert_equal((15*86400+5*3600+20), Icalendar.decode_duration('P15DT5H0M20S'))
199
+ end
200
+ end
201
+