lotus 0.0.12

Sign up to get free protection for your applications and to get access to all the features.
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