mumboe-vpim 0.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (69) hide show
  1. data/CHANGES +510 -0
  2. data/COPYING +58 -0
  3. data/README +185 -0
  4. data/lib/vpim/address.rb +219 -0
  5. data/lib/vpim/agent/atomize.rb +104 -0
  6. data/lib/vpim/agent/base.rb +73 -0
  7. data/lib/vpim/agent/calendars.rb +173 -0
  8. data/lib/vpim/agent/handler.rb +26 -0
  9. data/lib/vpim/agent/ics.rb +161 -0
  10. data/lib/vpim/attachment.rb +102 -0
  11. data/lib/vpim/date.rb +222 -0
  12. data/lib/vpim/dirinfo.rb +277 -0
  13. data/lib/vpim/duration.rb +119 -0
  14. data/lib/vpim/enumerator.rb +32 -0
  15. data/lib/vpim/field.rb +614 -0
  16. data/lib/vpim/icalendar.rb +384 -0
  17. data/lib/vpim/maker/vcard.rb +16 -0
  18. data/lib/vpim/property/base.rb +193 -0
  19. data/lib/vpim/property/common.rb +315 -0
  20. data/lib/vpim/property/location.rb +38 -0
  21. data/lib/vpim/property/priority.rb +43 -0
  22. data/lib/vpim/property/recurrence.rb +69 -0
  23. data/lib/vpim/property/resources.rb +24 -0
  24. data/lib/vpim/repo.rb +261 -0
  25. data/lib/vpim/rfc2425.rb +367 -0
  26. data/lib/vpim/rrule.rb +591 -0
  27. data/lib/vpim/time.rb +40 -0
  28. data/lib/vpim/vcard.rb +1456 -0
  29. data/lib/vpim/version.rb +18 -0
  30. data/lib/vpim/vevent.rb +187 -0
  31. data/lib/vpim/view.rb +90 -0
  32. data/lib/vpim/vjournal.rb +58 -0
  33. data/lib/vpim/vpim.rb +65 -0
  34. data/lib/vpim/vtodo.rb +103 -0
  35. data/lib/vpim.rb +13 -0
  36. data/samples/README.mutt +93 -0
  37. data/samples/ab-query.rb +57 -0
  38. data/samples/agent.ru +10 -0
  39. data/samples/cmd-itip.rb +156 -0
  40. data/samples/ex_cpvcard.rb +55 -0
  41. data/samples/ex_get_vcard_photo.rb +22 -0
  42. data/samples/ex_mkv21vcard.rb +34 -0
  43. data/samples/ex_mkvcard.rb +64 -0
  44. data/samples/ex_mkyourown.rb +29 -0
  45. data/samples/ics-dump.rb +210 -0
  46. data/samples/ics-to-rss.rb +84 -0
  47. data/samples/mutt-aliases-to-vcf.rb +45 -0
  48. data/samples/osx-wrappers.rb +86 -0
  49. data/samples/reminder.rb +209 -0
  50. data/samples/rrule.rb +71 -0
  51. data/samples/tabbed-file-to-vcf.rb +390 -0
  52. data/samples/vcf-dump.rb +86 -0
  53. data/samples/vcf-lines.rb +61 -0
  54. data/samples/vcf-to-ics.rb +22 -0
  55. data/samples/vcf-to-mutt.rb +121 -0
  56. data/test/test_agent_atomize.rb +84 -0
  57. data/test/test_agent_calendars.rb +128 -0
  58. data/test/test_agent_ics.rb +96 -0
  59. data/test/test_all.rb +17 -0
  60. data/test/test_date.rb +120 -0
  61. data/test/test_dur.rb +41 -0
  62. data/test/test_field.rb +156 -0
  63. data/test/test_ical.rb +437 -0
  64. data/test/test_misc.rb +13 -0
  65. data/test/test_repo.rb +129 -0
  66. data/test/test_rrule.rb +1030 -0
  67. data/test/test_vcard.rb +973 -0
  68. data/test/test_view.rb +79 -0
  69. metadata +140 -0
@@ -0,0 +1,973 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'vpim/vcard'
4
+ require 'test/unit'
5
+ require 'date'
6
+
7
+ require 'pp'
8
+
9
+ include Vpim
10
+
11
+ # Test equivalence where whitespace is compressed.
12
+ def assert_equal_nospace(expected, got)
13
+ expected = expected.gsub(/\s+/,'')
14
+ got = expected.gsub(/\s+/,'')
15
+ assert_equal(expected, got)
16
+ end
17
+
18
+
19
+ # Test cases: multiple occurrences of type
20
+ =begin
21
+ begin:VCARD
22
+ version:2.1
23
+ v;x1=a;x2=,a;x3=a,;x4=a,,a;x5=,a,:
24
+ source:ldap://cn=bjorn%20Jensen, o=university%20of%20Michigan, c=US
25
+ fn:Bj=F8rn
26
+ Jensen
27
+ other.name:Jensen;Bj=F8rn
28
+ some.other.value:1.2.3
29
+ some.other.value:some.other
30
+ some.other.value:some.other.value
31
+ v;p-1=;p-2=,,;p-3=a;p-4=a b,"v;p-1=;p-2=,,;p-3=a;p-4=a":v-value
32
+ email;type=internet:
33
+ bjorn@umich.edu
34
+ tel;type=work,voice,msg:+1 313 747-4454
35
+ tel:+...
36
+ key;type=x509;encoding=B:dGhpcyBjb3VsZCBiZSAKbXkgY2VydGlmaWNhdGUK
37
+ end:vcard
38
+ =end
39
+
40
+ class TestVcard < Test::Unit::TestCase
41
+
42
+ # RFC2425 - 8.1. Example 1
43
+ # Note that this is NOT a valid vCard, it lacks BEGIN/END.
44
+ EX1 =<<'EOF'
45
+ cn:
46
+ cn:Babs Jensen
47
+ cn:Barbara J Jensen
48
+ sn:Jensen
49
+ email:babs@umich.edu
50
+ phone:+1 313 747-4454
51
+ x-id:1234567890
52
+ EOF
53
+ def test_ex1
54
+ card = nil
55
+ ex1 = EX1
56
+ assert_nothing_thrown { card = Vpim::DirectoryInfo.decode(ex1) }
57
+ assert_equal_nospace(EX1, card.to_s)
58
+
59
+ assert_equal("Babs Jensen", card["cn"])
60
+ assert_equal("Jensen", card["sn"])
61
+
62
+ assert_equal("babs@umich.edu", card[ "email" ])
63
+
64
+ assert_equal("+1 313 747-4454", card[ "PhOnE" ])
65
+ assert_equal("1234567890", card[ "x-id" ])
66
+ assert_equal([], card.groups)
67
+ end
68
+
69
+ # RFC2425 - 8.2. Example 2
70
+ EX2 = <<-END
71
+ begin:VCARD
72
+ source:ldap://cn=bjorn%20Jensen, o=university%20of%20Michigan, c=US
73
+ name:Bjorn Jensen
74
+ fn:Bj=F8rn Jensen
75
+ n:Jensen;Bj=F8rn
76
+ email;type=internet:bjorn@umich.edu
77
+ tel;type=work,voice,msg:+1 313 747-4454
78
+ key;type=x509;encoding=B:dGhpcyBjb3VsZCBiZSAKbXkgY2VydGlmaWNhdGUK
79
+ end:VCARD
80
+ END
81
+
82
+ def test_ex2
83
+ card = nil
84
+ ex2 = EX2
85
+ assert_nothing_thrown { card = Vpim::Vcard.decode(ex2).first }
86
+ assert_equal(EX2, card.encode(0))
87
+ assert_raises(InvalidEncodingError) { card.version }
88
+
89
+ assert_equal("Bj=F8rn Jensen", card.name.fullname)
90
+ assert_equal("Jensen", card.name.family)
91
+ assert_equal("Bj=F8rn", card.name.given)
92
+ assert_equal("", card.name.prefix)
93
+
94
+ assert_equal("Bj=F8rn Jensen", card[ "fn" ])
95
+ assert_equal("+1 313 747-4454", card[ "tEL" ])
96
+
97
+ assert_equal(nil, card[ "not-a-field" ])
98
+ assert_equal([], card.groups)
99
+
100
+ assert_equal(nil, card.enum_by_name("n").entries[0].param("encoding"))
101
+
102
+ assert_equal(["internet"], card.enum_by_name("Email").entries.first.param("Type"))
103
+ assert_equal(nil, card.enum_by_name("Email").entries[0].param("foo"))
104
+
105
+ assert_equal(["B"], card.enum_by_name("kEy").to_a.first.param("encoding"))
106
+ assert_equal("B", card.enum_by_name("kEy").entries[0].encoding)
107
+
108
+ assert_equal(["work", "voice", "msg"], card.enum_by_name("tel").entries[0].param("Type"))
109
+
110
+ assert_equal([card.fields[6]], card.enum_by_name("tel").entries)
111
+
112
+ assert_equal([card.fields[6]], card.enum_by_name("tel").to_a)
113
+
114
+ assert_equal(nil, card.enum_by_name("tel").entries.first.encoding)
115
+
116
+ assert_equal("B", card.enum_by_name("key").entries.first.encoding)
117
+
118
+ assert_equal("dGhpcyBjb3VsZCBiZSAKbXkgY2VydGlmaWNhdGUK", card.enum_by_name("key").entries.first.value_raw)
119
+
120
+ assert_equal("this could be \nmy certificate\n", card.enum_by_name("key").entries.first.value)
121
+
122
+ card.lines
123
+ end
124
+
125
+ =begin
126
+ EX3 = <<-END
127
+ begin:vcard
128
+ source:ldap://cn=Meister%20Berger,o=Universitaet%20Goerlitz,c=DE
129
+ name:Meister Berger
130
+ fn:Meister Berger
131
+ n:Berger;Meister
132
+ bday;value=date:1963-09-21
133
+ o:Universit=E6t G=F6rlitz
134
+ title:Mayor
135
+ title;language=de;value=text:Burgermeister
136
+ note:The Mayor of the great city of
137
+ Goerlitz in the great country of Germany.
138
+ email;internet:mb@goerlitz.de
139
+ home.tel;type=fax,voice,msg:+49 3581 123456
140
+ home.label:Hufenshlagel 1234\n
141
+ 02828 Goerlitz\n
142
+ Deutschland
143
+ key;type=X509;encoding=b:MIICajCCAdOgAwIBAgICBEUwDQYJKoZIhvcNAQEEBQ
144
+ AwdzELMAkGA1UEBhMCVVMxLDAqBgNVBAoTI05ldHNjYXBlIENvbW11bmljYXRpb25zI
145
+ ENvcnBvcmF0aW9uMRwwGgYDVQQLExNJbmZvcm1hdGlvbiBTeXN0ZW1zMRwwGgYDVQQD
146
+ ExNyb290Y2EubmV0c2NhcGUuY29tMB4XDTk3MDYwNjE5NDc1OVoXDTk3MTIwMzE5NDc
147
+ 1OVowgYkxCzAJBgNVBAYTAlVTMSYwJAYDVQQKEx1OZXRzY2FwZSBDb21tdW5pY2F0aW
148
+ 9ucyBDb3JwLjEYMBYGA1UEAxMPVGltb3RoeSBBIEhvd2VzMSEwHwYJKoZIhvcNAQkBF
149
+ hJob3dlc0BuZXRzY2FwZS5jb20xFTATBgoJkiaJk/IsZAEBEwVob3dlczBcMA0GCSqG
150
+ SIb3DQEBAQUAA0sAMEgCQQC0JZf6wkg8pLMXHHCUvMfL5H6zjSk4vTTXZpYyrdN2dXc
151
+ oX49LKiOmgeJSzoiFKHtLOIboyludF90CgqcxtwKnAgMBAAGjNjA0MBEGCWCGSAGG+E
152
+ IBAQQEAwIAoDAfBgNVHSMEGDAWgBT84FToB/GV3jr3mcau+hUMbsQukjANBgkqhkiG9
153
+ w0BAQQFAAOBgQBexv7o7mi3PLXadkmNP9LcIPmx93HGp0Kgyx1jIVMyNgsemeAwBM+M
154
+ SlhMfcpbTrONwNjZYW8vJDSoi//yrZlVt9bJbs7MNYZVsyF1unsqaln4/vy6Uawfg8V
155
+ UMk1U7jt8LYpo4YULU7UZHPYVUaSgVttImOHZIKi4hlPXBOhcUQ==
156
+ end:vcard
157
+ END
158
+ assert_equal(
159
+ ["other", "some.other"],
160
+ card.groups_all
161
+ )
162
+ #a = []
163
+ #card.enum_by_group("some.other").each { |field| a << field }
164
+ #assert_equal(card.fields.indexes(6, 7, 8), a)
165
+ #assert_equal(card.fields.indexes(6, 7, 8), card.fields_by_group("some.other"))
166
+ =end
167
+
168
+ # This is my vCard exported from OS X's AddressBook.app.
169
+ EX_APPLE1 =<<'EOF'
170
+ BEGIN:VCARD
171
+ VERSION:3.0
172
+ N:Roberts;Sam;;;
173
+ FN:Roberts Sam
174
+ EMAIL;type=HOME;type=pref:sroberts@uniserve.com
175
+ TEL;type=WORK;type=pref:905-501-3781
176
+ TEL;type=FAX:905-907-4230
177
+ TEL;type=HOME:416 535 5341
178
+ ADR;type=HOME;type=pref:;;376 Westmoreland Ave.;Toronto;ON;M6H 3
179
+ A6;Canada
180
+ NOTE:CATEGORIES: Amis/Famille
181
+ BDAY;value=date:1970-07-14
182
+ END:VCARD
183
+ EOF
184
+ def test_ex_apple1
185
+ card = nil
186
+ assert_nothing_thrown { card = Vpim::Vcard.decode(EX_APPLE1).first }
187
+
188
+ assert_equal("Roberts Sam", card.name.fullname)
189
+ assert_equal("Roberts", card.name.family)
190
+ assert_equal("Sam", card.name.given)
191
+ assert_equal("", card.name.prefix)
192
+ assert_equal("", card.name.suffix)
193
+
194
+ assert_equal(EX_APPLE1, card.to_s(64))
195
+
196
+ check_ex_apple1(card)
197
+ end
198
+
199
+ NICKNAME0=<<'EOF'
200
+ begin:vcard
201
+ end:vcard
202
+ EOF
203
+ NICKNAME1=<<'EOF'
204
+ begin:vcard
205
+ nickname:
206
+ end:vcard
207
+ EOF
208
+ NICKNAME2=<<'EOF'
209
+ begin:vcard
210
+ nickname:
211
+ end:vcard
212
+ EOF
213
+ NICKNAME3=<<'EOF'
214
+ begin:vcard
215
+ nickname: Big Joey
216
+ end:vcard
217
+ EOF
218
+ NICKNAME4=<<'EOF'
219
+ begin:vcard
220
+ nickname:
221
+ nickname: Big Joey
222
+ end:vcard
223
+ EOF
224
+ NICKNAME5=<<'EOF'
225
+ begin:vcard
226
+ nickname:
227
+ nickname: Big Joey
228
+ nickname:Bob
229
+ end:vcard
230
+ EOF
231
+ def test_nickname
232
+ assert_equal(nil, Vpim::Vcard.decode(NICKNAME0).first.nickname)
233
+ assert_equal(nil, Vpim::Vcard.decode(NICKNAME1).first.nickname)
234
+ assert_equal(nil, Vpim::Vcard.decode(NICKNAME2).first.nickname)
235
+ assert_equal('Big Joey', Vpim::Vcard.decode(NICKNAME3).first.nickname)
236
+ assert_equal('Big Joey', Vpim::Vcard.decode(NICKNAME4).first['nickname'])
237
+ assert_equal(['Big Joey', 'Bob'], Vpim::Vcard.decode(NICKNAME5).first.nicknames)
238
+ end
239
+
240
+
241
+ def check_ex_apple1(card)
242
+ assert_equal("3.0", card[ "version" ])
243
+ assert_equal(30, card.version)
244
+
245
+ assert_equal("sroberts@uniserve.com", card[ "email" ])
246
+ assert_equal(["HOME", "pref"], card.enum_by_name("email").entries.first.param("type"))
247
+ assert_equal(nil, card.enum_by_name("email").entries.first.group)
248
+
249
+ assert_equal(["WORK","pref"], card.enum_by_name("tel").entries[0].param("type"))
250
+ assert_equal(["FAX"], card.enum_by_name("tel").entries[1].param("type"))
251
+ assert_equal(["HOME"], card.enum_by_name("tel").entries[2].param("type"))
252
+
253
+ assert_equal(nil, card.enum_by_name("bday").entries[0].param("type"))
254
+ assert_equal(["date"], card.enum_by_name("bday").entries[0].param("value"))
255
+
256
+ assert_equal( 1970, card.enum_by_name("bday").entries[0].to_time[0].year)
257
+ assert_equal( 7, card.enum_by_name("bday").entries[0].to_time[0].month)
258
+ assert_equal( 14, card.enum_by_name("bday").entries[0].to_time[0].day)
259
+
260
+ assert_equal("CATEGORIES: Amis/Famille", card[ "note" ])
261
+ end
262
+
263
+ # Test data for Vpim.expand
264
+ EX_EXPAND =<<'EOF'
265
+ BEGIN:a
266
+ a1:
267
+ BEGIN:b
268
+ BEGIN:c
269
+ c1:
270
+ c2:
271
+ END:c
272
+ V1:
273
+ V2:
274
+ END:b
275
+ a2:
276
+ END:a
277
+ EOF
278
+ def test_expand
279
+ src = Vpim.decode(EX_EXPAND)
280
+ dst = Vpim.expand(src)
281
+
282
+ assert_equal('a', dst[0][0].value)
283
+ assert_equal('A1', dst[0][1].name)
284
+ assert_equal('b', dst[0][2][0].value)
285
+ assert_equal('c', dst[0][2][1][0].value)
286
+ assert_equal('C1', dst[0][2][1][1].name)
287
+ assert_equal('C2', dst[0][2][1][2].name)
288
+ assert_equal('c', dst[0][2][1][3].value)
289
+
290
+ cards = Vpim::Vcard.decode(EX_APPLE1)
291
+
292
+ assert_equal(1, cards.length)
293
+
294
+ check_ex_apple1(cards[0])
295
+ end
296
+
297
+ # An iCalendar for Vpim.expand
298
+ EX_ICAL_1 =<<'EOF'
299
+ BEGIN:VCALENDAR
300
+ CALSCALE:GREGORIAN
301
+ X-WR-TIMEZONE;VALUE=TEXT:Canada/Eastern
302
+ METHOD:PUBLISH
303
+ PRODID:-//Apple Computer\, Inc//iCal 1.0//EN
304
+ X-WR-RELCALID;VALUE=TEXT:18E75B8C-5722-11D7-AB0B-000393AD088C
305
+ X-WR-CALNAME;VALUE=TEXT:Events
306
+ VERSION:2.0
307
+ BEGIN:VEVENT
308
+ SEQUENCE:14
309
+ UID:18E74C28-5722-11D7-AB0B-000393AD088C
310
+ DTSTAMP:20030301T171521Z
311
+ SUMMARY:Bob Log III
312
+ DTSTART;TZID=Canada/Eastern:20030328T200000
313
+ DTEND;TZID=Canada/Eastern:20030328T230000
314
+ DESCRIPTION:Healey's\n\nLook up exact time.\n
315
+ BEGIN:VALARM
316
+ TRIGGER;VALUE=DURATION:-P2D
317
+ ACTION:DISPLAY
318
+ DESCRIPTION:Event reminder
319
+ END:VALARM
320
+ BEGIN:VALARM
321
+ ATTENDEE:mailto:sroberts@uniserve.com
322
+ TRIGGER;VALUE=DURATION:-P1D
323
+ ACTION:EMAIL
324
+ SUMMARY:Alarm notification
325
+ DESCRIPTION:This is an event reminder
326
+ END:VALARM
327
+ END:VEVENT
328
+ BEGIN:VEVENT
329
+ SEQUENCE:1
330
+ DTSTAMP:20030312T043534Z
331
+ SUMMARY:Small Potatoes 10\nFriday\, March 14th\, 8:00 p.m.\n361 Danforth
332
+ Avenue (at Hampton -- Chester subway)\nInfo:  (416) 480-2802 or (416)
333
+ 323-1715\n
334
+ UID:18E750A8-5722-11D7-AB0B-000393AD088C
335
+ DTSTART;TZID=Canada/Eastern:20030315T000000
336
+ DURATION:PT1H
337
+ BEGIN:VALARM
338
+ ATTENDEE:mailto:sroberts@uniserve.com
339
+ TRIGGER;VALUE=DURATION:-P1D
340
+ ACTION:EMAIL
341
+ SUMMARY:Alarm notification
342
+ DESCRIPTION:This is an event reminder
343
+ END:VALARM
344
+ END:VEVENT
345
+ END:VCALENDAR
346
+ EOF
347
+ def test_ical_1
348
+ src = nil
349
+ dst = nil
350
+ assert_nothing_thrown {
351
+ src = Vpim.decode(EX_ICAL_1)
352
+ dst = Vpim.expand(src)
353
+ }
354
+
355
+ #p dst
356
+ end
357
+
358
+ # Constructed data.
359
+ TST1 =<<'EOF'
360
+ BEGIN:vCard
361
+ DESCRIPTION:Healey's\n\nLook up exact time.\n
362
+ email;type=work:work@example.com
363
+ email;type=internet,home;type=pref:home@example.com
364
+ fax;type=foo,pref;bar:fax
365
+ name:firstname
366
+ name:secondname
367
+ time;value=time:
368
+ END:vCARD
369
+ EOF
370
+ def _test_cons # FIXME
371
+ card = nil
372
+ assert_nothing_thrown { card = Vpim::Vcard.decode(TST1).first }
373
+ assert_equal(TST1, card.to_s)
374
+ assert_equal('Healey\'s\n\nLook up exact time.\n', card[ "description" ])
375
+
376
+ # Test the [] API
377
+ assert_equal(nil, card[ "not-a-field" ])
378
+
379
+ assert_equal('firstname', card[ "name" ])
380
+
381
+ assert_equal('home@example.com', card[ "email" ])
382
+ assert_equal('home@example.com', card[ "email", "pref" ])
383
+ assert_equal('home@example.com', card[ "email", "internet" ])
384
+ assert_equal('work@example.com', card[ "email", "work" ])
385
+
386
+
387
+ # Test the merging of vCard 2.1 type fields.
388
+ #p card
389
+ #p card.enum_by_name('fax').entries[0].each_param { |p,v| puts "#{p} = #{v}\n" }
390
+
391
+ assert_equal('fax', card[ "fax" ])
392
+ assert_equal('fax', card[ "fax", 'bar' ])
393
+ end
394
+
395
+ =begin
396
+ def test_bad
397
+ # FIXME: this should THROW, it's badly encoded!
398
+ assert_nothing_thrown {
399
+ Vpim::Vcard.decode(
400
+ "BEGIN:VCARD\nVERSION:3.0\nKEYencoding=b:this could be \nmy certificate\n\nEND:VCARD\n"
401
+ )
402
+ }
403
+ end
404
+ =end
405
+
406
+ def test_create
407
+ card = Vpim::Vcard.create
408
+
409
+ key = Vpim::DirectoryInfo.decode("key;type=x509;encoding=B:dGhpcyBjb3VsZCBiZSAKbXkgY2VydGlmaWNhdGUK\n")['key']
410
+
411
+ card << Vpim::DirectoryInfo::Field.create('key', key, 'encoding' => :b64)
412
+
413
+ assert_equal(key, card['key'])
414
+
415
+ #p card.to_s
416
+ end
417
+
418
+ def test_values
419
+
420
+ # date
421
+ assert_equal([2002, 4, 22], Vpim.decode_date(" 20020422 "))
422
+ assert_equal([2002, 4, 22], Vpim.decode_date(" 2002-04-22 "))
423
+ assert_equal([2002, 4, 22], Vpim.decode_date(" 2002-04-22 \n"))
424
+
425
+ assert_equal([[2002, 4, 22]],
426
+ Vpim.decode_date_list(" 2002-04-22 "))
427
+
428
+ assert_equal([[2002, 4, 22],[2002, 4, 22]],
429
+ Vpim.decode_date_list(" 2002-04-22, 2002-04-22,"))
430
+
431
+ assert_equal([[2002, 4, 22],[2002, 4, 22]],
432
+ Vpim.decode_date_list(" 2002-04-22,,, , ,2002-04-22, , \n"))
433
+
434
+ assert_equal([],
435
+ Vpim.decode_date_list(" , , "))
436
+
437
+ # time
438
+ assert_equal(
439
+ [4, 53, 22, 0, nil],
440
+ Vpim.decode_time(" 04:53:22 \n")
441
+ )
442
+ assert_equal(
443
+ [4, 53, 22, 0.10, nil],
444
+ Vpim.decode_time(" 04:53:22.10 \n")
445
+ )
446
+ assert_equal(
447
+ [4, 53, 22, 0.10, "Z"],
448
+ Vpim.decode_time(" 04:53:22.10Z \n")
449
+ )
450
+ assert_equal(
451
+ [4, 53, 22, 0, "Z"],
452
+ Vpim.decode_time(" 045322Z \n")
453
+ )
454
+ assert_equal(
455
+ [4, 53, 22, 0, "+0530"],
456
+ Vpim.decode_time(" 04:5322+0530 \n")
457
+ )
458
+ assert_equal(
459
+ [4, 53, 22, 0.10, "Z"],
460
+ Vpim.decode_time(" 045322.10Z \n")
461
+ )
462
+
463
+ # date-time
464
+ assert_equal(
465
+ [2002, 4, 22, 4, 53, 22, 0, nil],
466
+ Vpim.decode_date_time("20020422T04:53:22 \n")
467
+ )
468
+ assert_equal(
469
+ [2002, 4, 22, 4, 53, 22, 0.10, nil],
470
+ Vpim.decode_date_time(" 2002-04-22T04:53:22.10 \n")
471
+ )
472
+ assert_equal(
473
+ [2002, 4, 22, 4, 53, 22, 0.10, "Z"],
474
+ Vpim.decode_date_time(" 20020422T04:53:22.10Z \n")
475
+ )
476
+ assert_equal(
477
+ [2002, 4, 22, 4, 53, 22, 0, "Z"],
478
+ Vpim.decode_date_time(" 20020422T045322Z \n")
479
+ )
480
+ assert_equal(
481
+ [2002, 4, 22, 4, 53, 22, 0, "+0530"],
482
+ Vpim.decode_date_time(" 20020422T04:5322+0530 \n")
483
+ )
484
+ assert_equal(
485
+ [2002, 4, 22, 4, 53, 22, 0.10, "Z"],
486
+ Vpim.decode_date_time(" 20020422T045322.10Z \n")
487
+ )
488
+ assert_equal(
489
+ [2003, 3, 25, 3, 20, 35, 0, "Z"],
490
+ Vpim.decode_date_time("20030325T032035Z")
491
+ )
492
+
493
+ # text
494
+ assert_equal(
495
+ "aa,\n\n,\\,\\a;;b",
496
+ Vpim.decode_text('aa,\\n\\n,\\\\\,\\\\a\;\;b')
497
+ )
498
+ assert_equal(
499
+ ['', "1\n2,3", "bbb", '', "zz", ''],
500
+ Vpim.decode_text_list(',1\\n2\\,3,bbb,,zz,')
501
+ )
502
+ end
503
+
504
+ EX_ENCODE_1 =<<'EOF'
505
+ BEGIN:VCARD
506
+ VERSION:3.0
507
+ N:Roberts;Sam;;;
508
+ FN:Roberts Sam
509
+ EMAIL;type=HOME;type=pref:sroberts@uniserve.com
510
+ TEL;type=HOME:416 535 5341
511
+ ADR;type=HOME;type=pref:;;376 Westmoreland Ave.;Toronto;ON;M6H 3A6;Canada
512
+ NOTE:CATEGORIES: Amis/Famille
513
+ BDAY;value=date:1970-07-14
514
+ END:VCARD
515
+ EOF
516
+
517
+ def test_create_1
518
+ card = Vpim::Vcard.create
519
+
520
+ card << DirectoryInfo::Field.create('n', 'Roberts;Sam;;;')
521
+ card << DirectoryInfo::Field.create('fn', 'Roberts Sam')
522
+ card << DirectoryInfo::Field.create('email', 'sroberts@uniserve.com', 'type' => ['home', 'pref'])
523
+ card << DirectoryInfo::Field.create('tel', '416 535 5341', 'type' => 'home')
524
+ # TODO - allow the value to be an array, in which case it will be
525
+ # concatentated with ';'
526
+ card << DirectoryInfo::Field.create('adr', ';;376 Westmoreland Ave.;Toronto;ON;M6H 3A6;Canada', 'type' => ['home', 'pref'])
527
+ # TODO - allow the date to be a Date, and for value to be set correctly
528
+ card << DirectoryInfo::Field.create('bday', Date.new(1970, 7, 14), 'value' => 'date')
529
+
530
+ # puts card.to_s
531
+ end
532
+
533
+ EX_BDAYS = <<'EOF'
534
+ BEGIN:VCARD
535
+ BDAY;value=date:206-12-15
536
+ END:VCARD
537
+ BEGIN:VCARD
538
+ BDAY;value=date:2003-12-09
539
+ END:VCARD
540
+ BEGIN:VCARD
541
+ END:VCARD
542
+ EOF
543
+
544
+ def test_birthday
545
+ cards = Vpim::Vcard.decode(EX_BDAYS)
546
+
547
+ expected = [
548
+ Date.new(Time.now.year, 12, 15),
549
+ Date.new(2003, 12, 9),
550
+ nil
551
+ ]
552
+
553
+ expected.each_with_index do | d, i|
554
+ #pp d
555
+ #pp i
556
+ #pp cards[i]
557
+ #pp cards[i].birthday.to_s
558
+ #pp cards[i].birthday.class
559
+ assert_equal(d, cards[i].birthday)
560
+ end
561
+
562
+ end
563
+
564
+ EX_ATTACH=<<'---'
565
+ BEGIN:VCARD
566
+ VERSION:3.0
567
+ N:Middle Family;Ny_full
568
+ PHOTO:val\nue
569
+ PHOTO;encoding=8bit:val\nue
570
+ PHOTO;encoding=8bit:val\nue
571
+ PHOTO;encoding=8bit;type=atype:val\nue
572
+ PHOTO;value=binary;encoding=8bit:val\nue
573
+ PHOTO;value=binary;encoding=8bit:val\nue
574
+ PHOTO;value=binary;encoding=8bit;type=atype:val\nue
575
+ PHOTO;value=text;encoding=8bit:val\nue
576
+ PHOTO;value=text;encoding=8bit:val\nue
577
+ PHOTO;value=text;encoding=8bit;type=atype:val\nue
578
+ PHOTO;value=uri:my://
579
+ PHOTO;value=uri;type=atype:my://
580
+ END:VCARD
581
+ ---
582
+ def test_attach
583
+ card = Vpim::Vcard.decode(EX_ATTACH).first
584
+ card.lines # FIXME - assert values are as expected
585
+ end
586
+
587
+ EX_21=<<'---'
588
+ BEGIN:VCARD
589
+ VERSION:2.1
590
+ X-EVOLUTION-FILE-AS:AAA Our Fax
591
+ FN:AAA Our Fax
592
+ N:AAA Our Fax
593
+ ADR;WORK;PREF:
594
+ LABEL;WORK;PREF:
595
+ TEL;WORK;FAX:925 833-7660
596
+ TEL;HOME;FAX:925 833-7660
597
+ TEL;VOICE:1
598
+ TEL;FAX:2
599
+ EMAIL;INTERNET:e@c
600
+ TITLE:
601
+ NOTE:
602
+ UID:pas-id-3F93E22900000001
603
+ END:VCARD
604
+ ---
605
+ def test_v21_modification
606
+ card0 = Vpim::Vcard.decode(EX_21).first
607
+ card1 = Vpim::Vcard::Maker.make2(card0) do |maker|
608
+ maker.nickname = 'nickname'
609
+ end
610
+ card2 = Vpim::Vcard.decode(card1.encode).first
611
+
612
+ assert_equal(card0.version, card1.version)
613
+ assert_equal(card0.version, card2.version)
614
+ end
615
+
616
+ def test_v21_versioned_copy
617
+ card0 = Vpim::Vcard.decode(EX_21).first
618
+ card1 = Vpim::Vcard::Maker.make2(Vpim::DirectoryInfo.create([], 'VCARD')) do |maker|
619
+ maker.copy card0
620
+ end
621
+ card2 = Vpim::Vcard.decode(card1.encode).first
622
+
623
+ assert_equal(card0.version, card2.version)
624
+ end
625
+
626
+ def test_v21_strip_version
627
+ card0 = Vpim::Vcard.decode(EX_21).first
628
+
629
+ card0.delete card0.field('VERSION')
630
+ card0.delete card0.field('TEL')
631
+ card0.delete card0.field('TEL')
632
+ card0.delete card0.field('TEL')
633
+ card0.delete card0.field('TEL')
634
+
635
+ assert_raises(ArgumentError) do
636
+ card0.delete card0.field('END')
637
+ end
638
+ assert_raises(ArgumentError) do
639
+ card0.delete card0.field('BEGIN')
640
+ end
641
+
642
+ card1 = Vpim::Vcard::Maker.make2(Vpim::DirectoryInfo.create([], 'VCARD')) do |maker|
643
+ maker.copy card0
644
+ end
645
+ card2 = Vpim::Vcard.decode(card1.encode).first
646
+
647
+ assert_equal(30, card2.version)
648
+ assert_equal(nil, card2.field('TEL'))
649
+ end
650
+
651
+
652
+ EX_21_CASE0=<<'---'
653
+ BEGIN:VCARD
654
+ VERSION:2.1
655
+ N:Middle Family;Ny_full
656
+ TEL;PREF;HOME;VOICE:0123456789
657
+ TEL;FAX:0123456789
658
+ TEL;CELL;VOICE:0123456789
659
+ TEL;HOME;VOICE:0123456789
660
+ TEL;WORK;VOICE:0123456789
661
+ EMAIL:email@email.com
662
+ EMAIL:work@work.com
663
+ URL:www.email.com
664
+ URL:www.work.com
665
+ LABEL;CHARSET=ISO-8859-1;ENCODING=QUOTED-PRINTABLE:Box 1234=0AWorkv=E4gen =
666
+ 2=0AWorkv=E4gen 1=0AUme=E5=0AV=E4sterbotten=0A12345=0AS
667
+ END:VCARD
668
+ ---
669
+ def test_v21_case0
670
+ card = Vpim::Vcard.decode(EX_21_CASE0).first
671
+ # pp card.field('LABEL').value_raw
672
+ # pp card.field('LABEL').value
673
+ end
674
+
675
+ def test_modify_name
676
+ card = Vcard.decode("begin:vcard\nend:vcard\n").first
677
+
678
+ assert_raises(InvalidEncodingError) do
679
+ card.name
680
+ end
681
+
682
+ assert_raises(Unencodeable) do
683
+ Vcard::Maker.make2(card) {}
684
+ end
685
+
686
+ card.make do |m|
687
+ m.name {}
688
+ end
689
+
690
+ assert_equal('', card.name.given)
691
+ assert_equal('', card.name.fullname)
692
+
693
+ assert_raises(TypeError) do
694
+ card.name.given = 'given'
695
+ end
696
+
697
+ card.make do |m|
698
+ m.name do |n|
699
+ n.given = 'given'
700
+ end
701
+ end
702
+
703
+ assert_equal('given', card.name.given)
704
+ assert_equal('given', card.name.fullname)
705
+ assert_equal('' , card.name.family)
706
+
707
+ card.make do |m|
708
+ m.name do |n|
709
+ n.family = n.given
710
+ n.prefix = ' Ser '
711
+ n.fullname = 'well given'
712
+ end
713
+ end
714
+
715
+ assert_equal('given', card.name.given)
716
+ assert_equal('given', card.name.family)
717
+ assert_equal('Ser given given', card.name.formatted)
718
+ assert_equal('well given', card.name.fullname)
719
+ end
720
+
721
+ def test_add_note
722
+ note = "hi\' \ \"\",,;; \n \n field"
723
+
724
+ card = Vpim::Vcard::Maker.make2 do |m|
725
+ m.add_note(note)
726
+ m.name {}
727
+ end
728
+
729
+ assert_equal(note, card.note)
730
+ end
731
+
732
+ def test_empty_tel
733
+ cin = <<___
734
+ BEGIN:VCARD
735
+ TEL;HOME;FAX:
736
+ END:VCARD
737
+ ___
738
+
739
+ card = Vpim::Vcard.decode(cin).first
740
+ assert_equal(card.telephone, nil)
741
+ assert_equal(card.telephone('HOME'), nil)
742
+ assert_equal([], card.telephones)
743
+
744
+ end
745
+
746
+ def test_slash_in_field_name
747
+ cin = <<___
748
+ BEGIN:VCARD
749
+ X-messaging/xmpp-All:some@jabber.id
750
+ END:VCARD
751
+ ___
752
+
753
+ card = Vpim::Vcard.decode(cin).first
754
+ assert_equal(card.value("X-messaging/xmpp-All"), "some@jabber.id")
755
+ assert_equal(card["X-messaging/xmpp-All"], "some@jabber.id")
756
+ end
757
+
758
+ def test_url_decode
759
+ cin=<<'---'
760
+ BEGIN:VCARD
761
+ URL:www.email.com
762
+ URL:www.work.com
763
+ END:VCARD
764
+ ---
765
+ card = Vpim::Vcard.decode(cin).first
766
+
767
+ assert_equal("www.email.com", card.url.uri)
768
+ assert_equal("www.email.com", card.url.uri.to_s)
769
+ assert_equal("www.email.com", card.urls.first.uri)
770
+ assert_equal("www.work.com", card.urls.last.uri)
771
+ end
772
+
773
+ def test_bday_decode
774
+ cin=<<'---'
775
+ BEGIN:VCARD
776
+ BDAY:1970-07-14
777
+ END:VCARD
778
+ ---
779
+ card = Vpim::Vcard.decode(cin).first
780
+
781
+ card.birthday
782
+
783
+ assert_equal(Date.new(1970, 7, 14), card.birthday)
784
+ assert_equal(1, card.values("bday").size)
785
+
786
+ # Nobody should have multiple bdays, I hope, but its allowed syntactically,
787
+ # so test it, along with some variant forms of BDAY
788
+ cin=<<'---'
789
+ BEGIN:VCARD
790
+ BDAY:1970-07-14
791
+ BDAY:70-7-14
792
+ BDAY:1970-07-15T03:45:12
793
+ BDAY:1970-07-15T03:45:12Z
794
+ END:VCARD
795
+ ---
796
+ card = Vpim::Vcard.decode(cin).first
797
+
798
+ assert_equal(Date.new(1970, 7, 14), card.birthday)
799
+ assert_equal(4, card.values("bday").size)
800
+ assert_equal(Date.new(1970, 7, 14), card.values("bday").first)
801
+ assert_equal(Date.new(Time.now.year, 7, 14), card.values("bday")[1])
802
+ assert_equal(DateTime.new(1970, 7, 15, 3, 45, 12).to_s, card.values("bday")[2].to_s)
803
+ assert_equal(DateTime.new(1970, 7, 15, 3, 45, 12).to_s, card.values("bday").last.to_s)
804
+ end
805
+
806
+ def utf_name_test(c)
807
+
808
+ begin
809
+ card = Vpim::Vcard.decode(c).first
810
+ assert_equal("name", card.name.family)
811
+ rescue
812
+ $!.message << " #{c.inspect}"
813
+ raise
814
+ end
815
+ end
816
+
817
+ def be(s)
818
+ s.unpack('U*').pack('n*')
819
+ end
820
+ def le(s)
821
+ s.unpack('U*').pack('v*')
822
+ end
823
+
824
+ def test_utf_heuristics
825
+ bom = "\xEF\xBB\xBF"
826
+ dat = "BEGIN:VCARD\nN:name\nEND:VCARD\n"
827
+ utf_name_test(bom+dat)
828
+ utf_name_test(bom+dat.downcase)
829
+ utf_name_test(dat)
830
+ utf_name_test(dat.downcase)
831
+
832
+ utf_name_test(be(bom+dat))
833
+ utf_name_test(be(bom+dat.downcase))
834
+ utf_name_test(be(dat))
835
+ utf_name_test(be(dat.downcase))
836
+
837
+ utf_name_test(le(bom+dat))
838
+ utf_name_test(le(bom+dat.downcase))
839
+ utf_name_test(le(dat))
840
+ utf_name_test(le(dat.downcase))
841
+ end
842
+
843
+ # Broken output from Highrise. Report to support@highrisehq.com
844
+ def test_highrises_invalid_google_talk_field
845
+ c = <<'__'
846
+ BEGIN:VCARD
847
+ VERSION:3.0
848
+ REV:20080409T095515Z
849
+ X-YAHOO;TYPE=HOME:yahoo.john
850
+ X-GOOGLE TALK;TYPE=WORK:gtalk.john
851
+ X-SAMETIME;TYPE=WORK:sametime.john
852
+ X-SKYPE;TYPE=WORK:skype.john
853
+ X-MSN;TYPE=WORK:msn.john
854
+ X-JABBER;TYPE=WORK:jabber.john
855
+ N:Doe;John;;;
856
+ ADR;TYPE=WORK:;;456 Grandview Building\, Wide Street;San Diego;CA;90204;
857
+ United States
858
+ ADR;TYPE=HOME:;;123 Sweet Home\, Narrow Street;New York;NY;91102;United
859
+ States
860
+ URL;TYPE=OTHER:http\://www.homepage.com
861
+ URL;TYPE=HOME:http\://www.home.com
862
+ URL;TYPE=WORK:http\://www.work.com
863
+ URL;TYPE=OTHER:http\://www.other.com
864
+ URL;TYPE=OTHER:http\://www.custom.com
865
+ ORG:John Doe & Partners Limited;;
866
+ TEL;TYPE=WORK:11111111
867
+ TEL;TYPE=CELL:22222222
868
+ TEL;TYPE=HOME:33333333
869
+ TEL;TYPE=OTHER:44444444
870
+ TEL;TYPE=FAX:55555555
871
+ TEL;TYPE=FAX:66666666
872
+ TEL;TYPE=PAGER:77777777
873
+ TEL;TYPE=OTHER:88888888
874
+ TEL;TYPE=OTHER:99999999
875
+ UID:cc548e11-569e-3bf5-a9aa-722de4571f4a
876
+ X-ICQ;TYPE=HOME:icq.john
877
+ EMAIL;TYPE=WORK,INTERNET:john.doe@work.com
878
+ EMAIL;TYPE=HOME,INTERNET:john.doe@home.com
879
+ EMAIL;TYPE=OTHER,INTERNET:john.doe@other.com
880
+ EMAIL;TYPE=OTHER,INTERNET:john.doe@custom.com
881
+ TITLE:Sales Manager
882
+ X-OTHER;TYPE=WORK:other.john
883
+ X-AIM;TYPE=WORK:aim.john
884
+ X-QQ;TYPE=WORK:qq.john
885
+ FN:John Doe
886
+ END:VCARD
887
+ __
888
+
889
+ card = Vpim::Vcard.decode(c).first
890
+ assert_equal("Doe", card.name.family)
891
+ assert_equal("456 Grandview Building, Wide Street", card.address('work').street)
892
+ assert_equal("123 Sweet Home, Narrow Street", card.address('home').street)
893
+ assert_equal("John Doe & Partners Limited", card.org.first)
894
+ assert_equal("gtalk.john", card.value("x-google talk"))
895
+ assert_equal("http\\://www.homepage.com", card.url.uri)
896
+
897
+ end
898
+
899
+ def _test_gmail_vcard_export
900
+ # GOOGLE BUG - Whitespace before the LABEL field values is a broken
901
+ # line continuation.
902
+ # GOOGLE BUG - vCards are being exported with embedded "=" in them, so
903
+ # become unparseable.
904
+ c = <<'__'
905
+ BEGIN:VCARD
906
+ VERSION:3.0
907
+ FN:Stepcase TestUser
908
+ N:TestUser;Stepcase;;;
909
+ EMAIL;TYPE=INTERNET:testuser@stepcase.com
910
+ X-GTALK:gtalk.step
911
+ X-AIM:aim.step
912
+ X-YAHOO:yahoo.step
913
+ X-MSN:msn.step
914
+ X-ICQ:icq.step
915
+ X-JABBER:jabber.step
916
+ TEL;TYPE=FAX:44444444
917
+ TEL;TYPE=PAGER:66666666
918
+ TEL;TYPE=HOME:22222222
919
+ TEL;TYPE=CELL:11111111
920
+ TEL;TYPE=FAX:55555555
921
+ TEL;TYPE=WORK:33333333
922
+ LABEL;TYPE=HOME;ENCODING=QUOTED-PRINTABLE:123 Home, Home Street=0D=0A=
923
+ Kowloon, N/A=0D=0A=
924
+ Hong Kong
925
+ LABEL;TYPE=HOME;ENCODING=QUOTED-PRINTABLE:321 Office, Work Road=0D=0A=
926
+ Tsuen Wan NT=0D=0A=
927
+ Hong Kong
928
+ TITLE:CTO
929
+ ORG:Stepcase.com
930
+ NOTE:Stepcase test user is a robot.
931
+ END:VCARD
932
+ __
933
+ card = Vpim::Vcard.decode(c).first
934
+ assert_equal("123 Home, Home Street\r\n Kowloon, N/A\r\n Hong Kong", card.value("label"))
935
+ end
936
+
937
+ def test_title
938
+ title = "She Who Must Be Obeyed"
939
+ card = Vpim::Vcard::Maker.make2 do |m|
940
+ m.name do |n|
941
+ n.given = "Hilda"
942
+ n.family = "Rumpole"
943
+ end
944
+ m.title = title
945
+ end
946
+ assert_equal(title, card.title)
947
+ card = Vpim::Vcard.decode(card.encode).first
948
+ assert_equal(title, card.title)
949
+ end
950
+
951
+ def _test_org(*org)
952
+ card = Vpim::Vcard::Maker.make2 do |m|
953
+ m.name do |n|
954
+ n.given = "Hilda"
955
+ n.family = "Rumpole"
956
+ end
957
+ m.org = org
958
+ end
959
+ assert_equal(org, card.org)
960
+ card = Vpim::Vcard.decode(card.encode).first
961
+ assert_equal(org, card.org)
962
+ end
963
+
964
+ def test_org_single
965
+ _test_org("Megamix Corp.")
966
+ end
967
+
968
+ def test_org_multiple
969
+ _test_org("Megamix Corp.", "Marketing")
970
+ end
971
+
972
+ end
973
+