lotus 0.0.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. data/.gitignore +6 -0
  2. data/.travis.yml +9 -0
  3. data/Gemfile +16 -0
  4. data/README.md +233 -0
  5. data/Rakefile +7 -0
  6. data/lib/lotus.rb +232 -0
  7. data/lib/lotus/activity.rb +134 -0
  8. data/lib/lotus/atom/account.rb +50 -0
  9. data/lib/lotus/atom/address.rb +56 -0
  10. data/lib/lotus/atom/author.rb +167 -0
  11. data/lib/lotus/atom/category.rb +41 -0
  12. data/lib/lotus/atom/entry.rb +159 -0
  13. data/lib/lotus/atom/feed.rb +174 -0
  14. data/lib/lotus/atom/generator.rb +40 -0
  15. data/lib/lotus/atom/link.rb +79 -0
  16. data/lib/lotus/atom/name.rb +57 -0
  17. data/lib/lotus/atom/organization.rb +62 -0
  18. data/lib/lotus/atom/portable_contacts.rb +117 -0
  19. data/lib/lotus/atom/source.rb +168 -0
  20. data/lib/lotus/atom/thread.rb +60 -0
  21. data/lib/lotus/author.rb +177 -0
  22. data/lib/lotus/category.rb +45 -0
  23. data/lib/lotus/crypto.rb +146 -0
  24. data/lib/lotus/feed.rb +190 -0
  25. data/lib/lotus/generator.rb +53 -0
  26. data/lib/lotus/identity.rb +59 -0
  27. data/lib/lotus/link.rb +56 -0
  28. data/lib/lotus/notification.rb +220 -0
  29. data/lib/lotus/publisher.rb +40 -0
  30. data/lib/lotus/subscription.rb +117 -0
  31. data/lib/lotus/version.rb +3 -0
  32. data/lotus.gemspec +27 -0
  33. data/spec/activity_spec.rb +84 -0
  34. data/spec/atom/feed_spec.rb +681 -0
  35. data/spec/author_spec.rb +150 -0
  36. data/spec/crypto_spec.rb +138 -0
  37. data/spec/feed_spec.rb +252 -0
  38. data/spec/helper.rb +8 -0
  39. data/spec/identity_spec.rb +67 -0
  40. data/spec/link_spec.rb +30 -0
  41. data/spec/notification_spec.rb +77 -0
  42. data/test/example_feed.atom +393 -0
  43. data/test/example_feed_empty_author.atom +336 -0
  44. data/test/example_feed_false_connected.atom +359 -0
  45. data/test/example_feed_link_without_href.atom +134 -0
  46. data/test/example_page.html +4 -0
  47. data/test/mime_type_bug_feed.atom +874 -0
  48. metadata +204 -0
@@ -0,0 +1,3 @@
1
+ module Lotus
2
+ VERSION = "0.0.12"
3
+ end
@@ -0,0 +1,27 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "lotus/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "lotus"
7
+ s.version = Lotus::VERSION
8
+ s.platform = Gem::Platform::RUBY
9
+ s.authors = ['Hackers of the Severed Hand']
10
+ s.email = ['hotsh@xomb.org']
11
+ s.homepage = "http://github.com/hotsh/lotus"
12
+ s.summary = %q{Generalized federated system backend for social networks with ActivityStreams/OStatus/pump.io.}
13
+ s.description = %q{This gem allows easier implementation and utilization of distributed, federated social networks.}
14
+
15
+ s.add_dependency "ratom", "~> 0.7.2"
16
+ s.add_dependency "ruby-hmac"
17
+ s.add_dependency "rsa"
18
+ s.add_dependency "nokogiri"
19
+
20
+ s.add_development_dependency "rspec", "~> 2.10.0"
21
+ s.add_development_dependency "rake", "~> 0.9.2"
22
+
23
+ s.files = `git ls-files`.split("\n")
24
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
25
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
26
+ s.require_paths = ["lib"]
27
+ end
@@ -0,0 +1,84 @@
1
+ require_relative 'helper'
2
+ require_relative '../lib/lotus/activity.rb'
3
+
4
+ describe Lotus::Activity do
5
+ describe "#initialize" do
6
+ it "should store an object" do
7
+ Lotus::Activity.new(:object => "object").object.must_equal "object"
8
+ end
9
+
10
+ it "should store an type" do
11
+ Lotus::Activity.new(:type => :audio).type.must_equal :audio
12
+ end
13
+
14
+ it "should store a verb" do
15
+ Lotus::Activity.new(:verb => :follow).verb.must_equal :follow
16
+ end
17
+
18
+ it "should store a target" do
19
+ Lotus::Activity.new(:target => "target").target.must_equal "target"
20
+ end
21
+
22
+ it "should store a title" do
23
+ Lotus::Activity.new(:title => "My Title").title.must_equal "My Title"
24
+ end
25
+
26
+ it "should store an actor" do
27
+ actor = mock('author')
28
+ Lotus::Activity.new(:actor => actor).actor.must_equal actor
29
+ end
30
+
31
+ it "should store content" do
32
+ Lotus::Activity.new(:content => "Hello").content.must_equal "Hello"
33
+ end
34
+
35
+ it "should store the content type" do
36
+ Lotus::Activity.new(:content_type => "txt").content_type.must_equal "txt"
37
+ end
38
+
39
+ it "should store the published date" do
40
+ time = mock('date')
41
+ Lotus::Activity.new(:published => time).published.must_equal time
42
+ end
43
+
44
+ it "should store the updated date" do
45
+ time = mock('date')
46
+ Lotus::Activity.new(:updated => time).updated.must_equal time
47
+ end
48
+
49
+ it "should store a source feed" do
50
+ feed = mock('feed')
51
+ Lotus::Activity.new(:source => feed).source.must_equal feed
52
+ end
53
+
54
+ it "should store a url" do
55
+ Lotus::Activity.new(:url => "url").url.must_equal "url"
56
+ end
57
+
58
+ it "should store an id" do
59
+ Lotus::Activity.new(:id => "id").id.must_equal "id"
60
+ end
61
+
62
+ it "should store an array of threads" do
63
+ thread = mock('entry')
64
+ Lotus::Activity.new(:in_reply_to => [thread]).in_reply_to.must_equal [thread]
65
+ end
66
+
67
+ it "should store an array of threads when only given one entry" do
68
+ thread = mock('entry')
69
+ Lotus::Activity.new(:in_reply_to => thread).in_reply_to.must_equal [thread]
70
+ end
71
+
72
+ it "should store an empty array of threads by default" do
73
+ Lotus::Activity.new.in_reply_to.must_equal []
74
+ end
75
+
76
+ it "should default the content to '' if not given" do
77
+ Lotus::Activity.new.content.must_equal ''
78
+ end
79
+
80
+ it "should default the title to 'Untitled' if not given" do
81
+ Lotus::Activity.new.title.must_equal "Untitled"
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,681 @@
1
+ require_relative '../helper'
2
+ require_relative '../../lib/lotus/feed.rb'
3
+ require_relative '../../lib/lotus/atom/feed.rb'
4
+
5
+ # Sanity checks on atom generation because I don't trust ratom completely.
6
+ #
7
+ # Since I can't be completely sure how to test the implementations since they
8
+ # are patchy inheritance, I'll just do big acceptance tests and overtest.
9
+ # Somehow, these are still really fast.
10
+ describe Lotus::Atom do
11
+ before do
12
+ author = Lotus::Author.new(:uri => "http://example.com/users/1",
13
+ :email => "user@example.com",
14
+ :name => "wilkie",
15
+ :id => "1",
16
+ :nickname => "wilkie",
17
+ :extended_name => {:formatted => "Dave Wilkinson",
18
+ :family_name => "Wilkinson",
19
+ :given_name => "Dave",
20
+ :middle_name => "William",
21
+ :honorific_prefix => "Mr.",
22
+ :honorific_suffix => "II"},
23
+ :address => {:formatted => "123 Cherry Lane\nFoobar, PA, USA\n15206",
24
+ :street_address => "123 Cherry Lane",
25
+ :locality => "Foobar",
26
+ :region => "PA",
27
+ :postal_code => "15206",
28
+ :country => "USA"},
29
+ :organization => {:name => "Hackers of the Severed Hand",
30
+ :department => "Making Shit",
31
+ :title => "Founder",
32
+ :type => "open source",
33
+ :start_date => Date.today,
34
+ :end_date => Date.today,
35
+ :location => "everywhere",
36
+ :description => "I make ostatus work"},
37
+ :account => {:domain => "example.com",
38
+ :username => "wilkie",
39
+ :userid => "1"},
40
+ :gender => "androgynous",
41
+ :note => "cool dude",
42
+ :display_name => "Dave Wilkinson",
43
+ :preferred_username => "wilkie",
44
+ :updated => Time.now,
45
+ :published => Time.now,
46
+ :birthday => Date.today,
47
+ :anniversary => Date.today)
48
+
49
+ source_feed = Lotus::Feed.new(:title => "moo",
50
+ :authors => [author],
51
+ :rights => "CC")
52
+
53
+ reply_to = Lotus::Activity.new(:title => "My First Entry",
54
+ :type => :note,
55
+ :actor => author,
56
+ :content => "Hello",
57
+ :content_type => "html",
58
+ :id => "54321",
59
+ :url => "http://example.com/entries/1",
60
+ :published => Time.now,
61
+ :updated => Time.now)
62
+
63
+ entry = Lotus::Activity.new(:title => "My Entry",
64
+ :actor => author,
65
+ :type => :note,
66
+ :content => "Hello",
67
+ :content_type => "html",
68
+ :source => source_feed,
69
+ :id => "54321",
70
+ :url => "http://example.com/entries/1",
71
+ :published => Time.now,
72
+ :in_reply_to => reply_to,
73
+ :updated => Time.now)
74
+
75
+ @master = Lotus::Feed.new(:title => "My Feed",
76
+ :title_type => "html",
77
+ :subtitle => "Subtitle",
78
+ :subtitle_type => "html",
79
+ :url => "http://example.com/feeds/1",
80
+ :rights => "CC0",
81
+ :icon => "http://example.com/icon.png",
82
+ :logo => "http://example.com/logo.png",
83
+ :hubs => ["http://hub.example.com",
84
+ "http://hub2.example.com"],
85
+ :published => Time.now,
86
+ :updated => Time.now,
87
+ :authors => [author],
88
+ :entries => [entry],
89
+ :id => "12345")
90
+ end
91
+
92
+ it "should be able to reform canonical structure using Atom" do
93
+ xml = Lotus::Atom::Feed.from_canonical(@master).to_xml
94
+ new_feed = Lotus::Atom::Feed.new(XML::Reader.string(xml)).to_canonical
95
+
96
+ old_hash = @master.to_hash
97
+ new_hash = new_feed.to_hash
98
+
99
+ old_hash[:authors] = old_hash[:authors].map(&:to_hash)
100
+ new_hash[:authors] = new_hash[:authors].map(&:to_hash)
101
+
102
+ old_hash[:entries] = old_hash[:entries].map(&:to_hash)
103
+ new_hash[:entries] = new_hash[:entries].map(&:to_hash)
104
+
105
+ old_hash[:entries][0][:in_reply_to] = []
106
+ new_hash[:entries][0][:in_reply_to] = []
107
+
108
+ old_hash[:entries][0][:actor] = old_hash[:entries][0][:actor].to_hash
109
+ new_hash[:entries][0][:actor] = new_hash[:entries][0][:actor].to_hash
110
+
111
+ old_hash[:entries][0][:source] = old_hash[:entries][0][:source].to_hash
112
+ new_hash[:entries][0][:source] = new_hash[:entries][0][:source].to_hash
113
+
114
+ old_hash[:entries][0][:source][:authors] = old_hash[:entries][0][:source][:authors].map(&:to_hash)
115
+ new_hash[:entries][0][:source][:authors] = new_hash[:entries][0][:source][:authors].map(&:to_hash)
116
+
117
+ # Flatten all keys to their to_s
118
+ # We want to compare the to_s for all keys
119
+ def flatten_keys!(hash)
120
+ hash.keys.each do |k|
121
+ if hash[k].is_a? Array
122
+ # Go inside arrays (doesn't handle arrays of arrays)
123
+ hash[k].map! do |e|
124
+ if e.is_a? Hash
125
+ flatten_keys! e
126
+ e
127
+ else
128
+ e.to_s
129
+ end
130
+ end
131
+ elsif hash[k].is_a? Hash
132
+ # Go inside hashes
133
+ flatten_keys!(hash[k])
134
+ elsif hash[k].is_a? Time
135
+ # Ensure all Time classes become DateTimes for comparison
136
+ hash[k] = hash[k].to_datetime.to_s
137
+ else
138
+ # Ensure all fields become Strings
139
+ hash[k] = hash[k].to_s
140
+ end
141
+ end
142
+ end
143
+
144
+ flatten_keys!(old_hash)
145
+ flatten_keys!(new_hash)
146
+
147
+ old_hash.must_equal new_hash
148
+ end
149
+
150
+ describe "<xml>" do
151
+ before do
152
+ @xml_str = Lotus::Atom::Feed.from_canonical(@master).to_xml
153
+ @xml = XML::Parser.string(@xml_str).parse
154
+ end
155
+
156
+ it "should publish a version of 1.0" do
157
+ @xml_str.must_match /^<\?xml[^>]*\sversion="1\.0"/
158
+ end
159
+
160
+ it "should encode in utf-8" do
161
+ @xml_str.must_match /^<\?xml[^>]*\sencoding="UTF-8"/
162
+ end
163
+
164
+ describe "<feed>" do
165
+ before do
166
+ @feed = @xml.root
167
+ end
168
+
169
+ it "should contain the Atom namespace" do
170
+ @feed.namespaces.find_by_href("http://www.w3.org/2005/Atom").to_s
171
+ .must_equal "http://www.w3.org/2005/Atom"
172
+ end
173
+
174
+ it "should contain the PortableContacts namespace" do
175
+ @feed.namespaces.find_by_prefix('poco').to_s
176
+ .must_equal "poco:http://portablecontacts.net/spec/1.0"
177
+ end
178
+
179
+ it "should contain the ActivityStreams namespace" do
180
+ @feed.namespaces.find_by_prefix('activity').to_s
181
+ .must_equal "activity:http://activitystrea.ms/spec/1.0/"
182
+ end
183
+
184
+ describe "<id>" do
185
+ it "should contain the id from Lotus::Feed" do
186
+ @feed.find_first('xmlns:id', 'xmlns:http://www.w3.org/2005/Atom')
187
+ .content.must_equal @master.id
188
+ end
189
+ end
190
+
191
+ describe "<rights>" do
192
+ it "should contain the rights from Lotus::Feed" do
193
+ @feed.find_first('xmlns:rights', 'xmlns:http://www.w3.org/2005/Atom')
194
+ .content.must_equal @master.rights
195
+ end
196
+ end
197
+
198
+ describe "<logo>" do
199
+ it "should contain the logo from Lotus::Feed" do
200
+ @feed.find_first('xmlns:logo', 'xmlns:http://www.w3.org/2005/Atom')
201
+ .content.must_equal @master.logo
202
+ end
203
+ end
204
+
205
+ describe "<icon>" do
206
+ it "should contain the icon from Lotus::Feed" do
207
+ @feed.find_first('xmlns:icon', 'xmlns:http://www.w3.org/2005/Atom')
208
+ .content.must_equal @master.icon
209
+ end
210
+ end
211
+
212
+ describe "<published>" do
213
+ it "should contain the time in the published field in Lotus::Feed" do
214
+ time = @feed.find_first('xmlns:published',
215
+ 'xmlns:http://www.w3.org/2005/Atom').content
216
+ DateTime::rfc3339(time).to_s.must_equal @master.published.to_datetime.to_s
217
+ end
218
+ end
219
+
220
+ describe "<updated>" do
221
+ it "should contain the time in the updated field in Lotus::Feed" do
222
+ time = @feed.find_first('xmlns:updated',
223
+ 'xmlns:http://www.w3.org/2005/Atom').content
224
+ DateTime::rfc3339(time).to_s.must_equal @master.updated.to_datetime.to_s
225
+ end
226
+ end
227
+
228
+ describe "<link>" do
229
+ it "should contain a link for the hub" do
230
+ @feed.find_first('xmlns:link[@rel="hub"]',
231
+ 'xmlns:http://www.w3.org/2005/Atom').attributes
232
+ .get_attribute('href').value.must_equal(@master.hubs.first)
233
+ end
234
+
235
+ it "should allow a second link for the hub" do
236
+ @feed.find('xmlns:link[@rel="hub"]',
237
+ 'xmlns:http://www.w3.org/2005/Atom')[1].attributes
238
+ .get_attribute('href').value.must_equal(@master.hubs[1])
239
+ end
240
+
241
+ it "should contain a link for self" do
242
+ @feed.find_first('xmlns:link[@rel="self"]',
243
+ 'xmlns:http://www.w3.org/2005/Atom').attributes
244
+ .get_attribute('href').value.must_equal(@master.url)
245
+ end
246
+ end
247
+
248
+ describe "<title>" do
249
+ before do
250
+ @title = @feed.find_first('xmlns:title', 'xmlns:http://www.w3.org/2005/Atom')
251
+ end
252
+
253
+ it "should contain the title from Lotus::Feed" do
254
+ @title.content.must_equal @master.title
255
+ end
256
+
257
+ it "should contain the type attribute from Lotus::Feed" do
258
+ @title.attributes.get_attribute('type').value.must_equal @master.title_type
259
+ end
260
+ end
261
+
262
+ describe "<subtitle>" do
263
+ before do
264
+ @subtitle = @feed.find_first('xmlns:subtitle', 'xmlns:http://www.w3.org/2005/Atom')
265
+ end
266
+
267
+ it "should contain the subtitle from Lotus::Feed" do
268
+ @subtitle.content.must_equal @master.subtitle
269
+ end
270
+
271
+ it "should contain the type attribute from Lotus::Feed" do
272
+ @subtitle.attributes.get_attribute('type').value.must_equal @master.subtitle_type
273
+ end
274
+ end
275
+
276
+ describe "<author>" do
277
+ before do
278
+ @author = @feed.find_first('xmlns:author', 'xmlns:http://www.w3.org/2005/Atom')
279
+ end
280
+
281
+ describe "<activity:object-type>" do
282
+ it "should identify this tag as a person object" do
283
+ @author.find_first('activity:object-type').content
284
+ .must_equal "http://activitystrea.ms/schema/1.0/person"
285
+ end
286
+ end
287
+
288
+ describe "<email>" do
289
+ it "should list the author's email" do
290
+ @author.find_first('xmlns:email',
291
+ 'xmlns:http://www.w3.org/2005/Atom').content.must_equal @master.authors.first.email
292
+ end
293
+ end
294
+
295
+ describe "<uri>" do
296
+ it "should list the author's uri" do
297
+ @author.find_first('xmlns:uri',
298
+ 'xmlns:http://www.w3.org/2005/Atom').content.must_equal @master.authors.first.uri
299
+ end
300
+ end
301
+
302
+ describe "<name>" do
303
+ it "should list the author's name" do
304
+ @author.find_first('xmlns:name',
305
+ 'xmlns:http://www.w3.org/2005/Atom').content.must_equal @master.authors.first.name
306
+ end
307
+ end
308
+
309
+ describe "<poco:id>" do
310
+ it "should list the author's portable contact id" do
311
+ @author.find_first('poco:id',
312
+ 'http://portablecontacts.net/spec/1.0').content.must_equal @master.authors.first.id
313
+ end
314
+ end
315
+
316
+ describe "<poco:name>" do
317
+ before do
318
+ @poco_name = @author.find_first('poco:name',
319
+ 'http://portablecontacts.net/spec/1.0')
320
+ end
321
+
322
+ describe "<formatted>" do
323
+ it "should list the author's portable contact formatted name" do
324
+ @poco_name.find_first('xmlns:formatted',
325
+ 'xmlns:http://www.w3.org/2005/Atom')
326
+ .content.must_equal @master.authors.first.extended_name[:formatted]
327
+ end
328
+ end
329
+
330
+ describe "<familyName>" do
331
+ it "should list the author's portable contact family name" do
332
+ @poco_name.find_first('xmlns:familyName',
333
+ 'xmlns:http://www.w3.org/2005/Atom')
334
+ .content.must_equal @master.authors.first.extended_name[:family_name]
335
+ end
336
+ end
337
+
338
+ describe "<givenName>" do
339
+ it "should list the author's portable contact given name" do
340
+ @poco_name.find_first('xmlns:givenName',
341
+ 'xmlns:http://www.w3.org/2005/Atom')
342
+ .content.must_equal @master.authors.first.extended_name[:given_name]
343
+ end
344
+ end
345
+
346
+ describe "<middleName>" do
347
+ it "should list the author's portable contact middle name" do
348
+ @poco_name.find_first('xmlns:middleName',
349
+ 'xmlns:http://www.w3.org/2005/Atom')
350
+ .content.must_equal @master.authors.first.extended_name[:middle_name]
351
+ end
352
+ end
353
+
354
+ describe "<honorificPrefix>" do
355
+ it "should list the author's portable contact honorific prefix" do
356
+ @poco_name.find_first('xmlns:honorificPrefix',
357
+ 'xmlns:http://www.w3.org/2005/Atom')
358
+ .content.must_equal @master.authors.first.extended_name[:honorific_prefix]
359
+ end
360
+ end
361
+
362
+ describe "<honorificSuffix>" do
363
+ it "should list the author's portable contact honorific suffix" do
364
+ @poco_name.find_first('xmlns:honorificSuffix',
365
+ 'xmlns:http://www.w3.org/2005/Atom')
366
+ .content.must_equal @master.authors.first.extended_name[:honorific_suffix]
367
+ end
368
+ end
369
+ end
370
+
371
+ describe "<poco:organization>" do
372
+ before do
373
+ @poco_org = @author.find_first('poco:organization',
374
+ 'http://portablecontacts.net/spec/1.0')
375
+ end
376
+
377
+ describe "<name>" do
378
+ it "should list the author's portable contact organization name" do
379
+ @poco_org.find_first('xmlns:name',
380
+ 'xmlns:http://www.w3.org/2005/Atom')
381
+ .content.must_equal @master.authors.first.organization[:name]
382
+ end
383
+ end
384
+
385
+ describe "<department>" do
386
+ it "should list the author's portable contact organization department" do
387
+ @poco_org.find_first('xmlns:department',
388
+ 'xmlns:http://www.w3.org/2005/Atom')
389
+ .content.must_equal @master.authors.first.organization[:department]
390
+ end
391
+ end
392
+
393
+ describe "<title>" do
394
+ it "should list the author's portable contact organization title" do
395
+ @poco_org.find_first('xmlns:title',
396
+ 'xmlns:http://www.w3.org/2005/Atom')
397
+ .content.must_equal @master.authors.first.organization[:title]
398
+ end
399
+ end
400
+
401
+ describe "<type>" do
402
+ it "should list the author's portable contact organization type" do
403
+ @poco_org.find_first('xmlns:type',
404
+ 'xmlns:http://www.w3.org/2005/Atom')
405
+ .content.must_equal @master.authors.first.organization[:type]
406
+ end
407
+ end
408
+
409
+ describe "<startDate>" do
410
+ it "should list the author's portable contact organization startDate" do
411
+ time = @poco_org.find_first('xmlns:startDate',
412
+ 'xmlns:http://www.w3.org/2005/Atom').content
413
+ DateTime::parse(time).to_s
414
+ .must_equal @master.authors.first.organization[:start_date].to_datetime.to_s
415
+ end
416
+ end
417
+
418
+ describe "<endDate>" do
419
+ it "should list the author's portable contact organization endDate" do
420
+ time = @poco_org.find_first('xmlns:endDate',
421
+ 'xmlns:http://www.w3.org/2005/Atom').content
422
+ DateTime::parse(time).to_s
423
+ .must_equal @master.authors.first.organization[:end_date].to_datetime.to_s
424
+ end
425
+ end
426
+
427
+ describe "<location>" do
428
+ it "should list the author's portable contact organization location" do
429
+ @poco_org.find_first('xmlns:location',
430
+ 'xmlns:http://www.w3.org/2005/Atom')
431
+ .content.must_equal @master.authors.first.organization[:location]
432
+ end
433
+ end
434
+
435
+ describe "<description>" do
436
+ it "should list the author's portable contact organization description" do
437
+ @poco_org.find_first('xmlns:description',
438
+ 'xmlns:http://www.w3.org/2005/Atom')
439
+ .content.must_equal @master.authors.first.organization[:description]
440
+ end
441
+ end
442
+ end
443
+
444
+ describe "<poco:address>" do
445
+ before do
446
+ @poco_address = @author.find_first('poco:address',
447
+ 'http://portablecontacts.net/spec/1.0')
448
+ end
449
+
450
+ describe "<formatted>" do
451
+ it "should list the author's portable contact formatted address" do
452
+ @poco_address.find_first('xmlns:formatted',
453
+ 'xmlns:http://www.w3.org/2005/Atom')
454
+ .content.must_equal @master.authors.first.address[:formatted]
455
+ end
456
+ end
457
+
458
+ describe "<streetAddress>" do
459
+ it "should list the author's portable contact address streetAddress" do
460
+ @poco_address.find_first('xmlns:streetAddress',
461
+ 'xmlns:http://www.w3.org/2005/Atom')
462
+ .content.must_equal @master.authors.first.address[:street_address]
463
+ end
464
+ end
465
+
466
+ describe "<locality>" do
467
+ it "should list the author's portable contact address locality" do
468
+ @poco_address.find_first('xmlns:locality',
469
+ 'xmlns:http://www.w3.org/2005/Atom')
470
+ .content.must_equal @master.authors.first.address[:locality]
471
+ end
472
+ end
473
+
474
+ describe "<region>" do
475
+ it "should list the author's portable contact address region" do
476
+ @poco_address.find_first('xmlns:region',
477
+ 'xmlns:http://www.w3.org/2005/Atom')
478
+ .content.must_equal @master.authors.first.address[:region]
479
+ end
480
+ end
481
+
482
+ describe "<postalCode>" do
483
+ it "should list the author's portable contact address postalCode" do
484
+ @poco_address.find_first('xmlns:postalCode',
485
+ 'xmlns:http://www.w3.org/2005/Atom')
486
+ .content.must_equal @master.authors.first.address[:postal_code]
487
+ end
488
+ end
489
+
490
+ describe "<country>" do
491
+ it "should list the author's portable contact address country" do
492
+ @poco_address.find_first('xmlns:country',
493
+ 'xmlns:http://www.w3.org/2005/Atom')
494
+ .content.must_equal @master.authors.first.address[:country]
495
+ end
496
+ end
497
+ end
498
+
499
+ describe "<poco:account>" do
500
+ before do
501
+ @poco_account = @author.find_first('poco:account',
502
+ 'http://portablecontacts.net/spec/1.0')
503
+ end
504
+
505
+ describe "<domain>" do
506
+ it "should list the author's portable contact account domain" do
507
+ @poco_account.find_first('xmlns:domain',
508
+ 'xmlns:http://www.w3.org/2005/Atom')
509
+ .content.must_equal @master.authors.first.account[:domain]
510
+ end
511
+ end
512
+
513
+ describe "<username>" do
514
+ it "should list the author's portable contact account username" do
515
+ @poco_account.find_first('xmlns:username',
516
+ 'xmlns:http://www.w3.org/2005/Atom')
517
+ .content.must_equal @master.authors.first.account[:username]
518
+ end
519
+ end
520
+
521
+ describe "<userid>" do
522
+ it "should list the author's portable contact account userid" do
523
+ @poco_account.find_first('xmlns:userid',
524
+ 'xmlns:http://www.w3.org/2005/Atom')
525
+ .content.must_equal @master.authors.first.account[:userid]
526
+ end
527
+ end
528
+ end
529
+
530
+ describe "<poco:displayName>" do
531
+ it "should list the author's portable contact display name" do
532
+ @author.find_first('poco:displayName',
533
+ 'http://portablecontacts.net/spec/1.0')
534
+ .content.must_equal @master.authors.first.display_name
535
+ end
536
+ end
537
+
538
+ describe "<poco:nickname>" do
539
+ it "should list the author's portable contact nickname" do
540
+ @author.find_first('poco:nickname',
541
+ 'http://portablecontacts.net/spec/1.0')
542
+ .content.must_equal @master.authors.first.nickname
543
+ end
544
+ end
545
+
546
+ describe "<poco:gender>" do
547
+ it "should list the author's portable contact gender" do
548
+ @author.find_first('poco:gender',
549
+ 'http://portablecontacts.net/spec/1.0')
550
+ .content.must_equal @master.authors.first.gender
551
+ end
552
+ end
553
+
554
+ describe "<poco:note>" do
555
+ it "should list the author's portable contact note" do
556
+ @author.find_first('poco:note',
557
+ 'http://portablecontacts.net/spec/1.0')
558
+ .content.must_equal @master.authors.first.note
559
+ end
560
+ end
561
+
562
+ describe "<poco:preferredUsername>" do
563
+ it "should list the author's portable contact preferred username" do
564
+ @author.find_first('poco:preferredUsername',
565
+ 'http://portablecontacts.net/spec/1.0')
566
+ .content.must_equal @master.authors.first.preferred_username
567
+ end
568
+ end
569
+
570
+ describe "<poco:birthday>" do
571
+ it "should list the author's portable contact birthday" do
572
+ time = @author.find_first('poco:birthday',
573
+ 'http://portablecontacts.net/spec/1.0').content
574
+ DateTime::parse(time).to_s.must_equal @master.authors.first
575
+ .birthday.to_datetime.to_s
576
+ end
577
+ end
578
+
579
+ describe "<poco:anniversary>" do
580
+ it "should list the author's portable contact anniversary" do
581
+ time = @author.find_first('poco:anniversary',
582
+ 'http://portablecontacts.net/spec/1.0').content
583
+ DateTime::parse(time).to_s.must_equal @master.authors.first
584
+ .anniversary.to_datetime.to_s
585
+ end
586
+ end
587
+
588
+ describe "<poco:published>" do
589
+ it "should list the author's portable contact published date" do
590
+ time = @author.find_first('poco:published',
591
+ 'http://portablecontacts.net/spec/1.0').content
592
+ DateTime::parse(time).to_s.must_equal @master.authors.first
593
+ .published.to_datetime.to_s
594
+ end
595
+ end
596
+
597
+ describe "<poco:updated>" do
598
+ it "should list the author's portable contact updated date" do
599
+ time = @author.find_first('poco:updated',
600
+ 'http://portablecontacts.net/spec/1.0').content
601
+ DateTime::parse(time).to_s.must_equal @master.authors.first
602
+ .updated.to_datetime.to_s
603
+ end
604
+ end
605
+ end
606
+
607
+ describe "<entry>" do
608
+ before do
609
+ @entry = @feed.find_first('xmlns:entry', 'xmlns:http://www.w3.org/2005/Atom')
610
+ end
611
+
612
+ it "should have the thread namespace" do
613
+ @entry.namespaces.find_by_prefix('thr').to_s
614
+ .must_equal "thr:http://purl.org/syndication/thread/1.0"
615
+ end
616
+
617
+ it "should have the activity streams namespace" do
618
+ @entry.namespaces.find_by_prefix('activity').to_s
619
+ .must_equal "activity:http://activitystrea.ms/spec/1.0/"
620
+ end
621
+
622
+ describe "<title>" do
623
+ it "should contain the entry title" do
624
+ @entry.find_first('xmlns:title', 'xmlns:http://www.w3.org/2005/Atom')
625
+ .content.must_equal @master.entries.first.title
626
+ end
627
+ end
628
+
629
+ describe "<id>" do
630
+ it "should contain the entry id" do
631
+ @entry.find_first('xmlns:id', 'xmlns:http://www.w3.org/2005/Atom')
632
+ .content.must_equal @master.entries.first.id
633
+ end
634
+ end
635
+
636
+ describe "<link>" do
637
+ it "should contain a link for self" do
638
+ @entry.find_first('xmlns:link[@rel="self"]',
639
+ 'xmlns:http://www.w3.org/2005/Atom').attributes
640
+ .get_attribute('href').value.must_equal(@master.entries.first.url)
641
+ end
642
+ end
643
+
644
+ describe "<updated>" do
645
+ it "should contain the entry updated date" do
646
+ time = @entry.find_first('xmlns:updated',
647
+ 'xmlns:http://www.w3.org/2005/Atom').content
648
+ DateTime.parse(time).to_s.must_equal @master.entries.first.updated.to_datetime.to_s
649
+ end
650
+ end
651
+
652
+ describe "<published>" do
653
+ it "should contain the entry published date" do
654
+ time = @entry.find_first('xmlns:published',
655
+ 'xmlns:http://www.w3.org/2005/Atom').content
656
+ DateTime.parse(time).to_s.must_equal @master.entries.first.published.to_datetime.to_s
657
+ end
658
+ end
659
+
660
+ describe "<activity:object-type>" do
661
+ it "should reflect the activity for this entry" do
662
+ @entry.find_first('activity:object-type').content
663
+ .must_equal "http://activitystrea.ms/schema/1.0/note"
664
+ end
665
+ end
666
+
667
+ describe "<content>" do
668
+ it "should contain the entry content" do
669
+ @entry.find_first('xmlns:content', 'xmlns:http://www.w3.org/2005/Atom')
670
+ .content.must_equal @master.entries.first.content
671
+ end
672
+
673
+ it "should have the corresponding type attribute" do
674
+ @entry.find_first('xmlns:content', 'xmlns:http://www.w3.org/2005/Atom')
675
+ .attributes.get_attribute('type').value.must_equal @master.entries.first.content_type
676
+ end
677
+ end
678
+ end
679
+ end
680
+ end
681
+ end