aurelian-contacts 0.3.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,69 @@
1
+ require 'spec_helper'
2
+ require 'contacts'
3
+
4
+ describe Contacts::Contact do
5
+ describe 'instance' do
6
+ before do
7
+ @contact = Contacts::Contact.new('max@example.com', 'Max Power', 'maxpower', "Max", "Power")
8
+ end
9
+
10
+ it "should have email" do
11
+ @contact.email.should == 'max@example.com'
12
+ end
13
+
14
+ it "should have name" do
15
+ @contact.name.should == 'Max Power'
16
+ end
17
+
18
+ it "should support a service id" do
19
+ @contact.service_id = 'service identifier'
20
+ @contact.service_id.should == 'service identifier'
21
+ end
22
+
23
+ it "should support multiple emails" do
24
+ @contact.emails << 'maxpower@example.com'
25
+ @contact.email.should == 'max@example.com'
26
+ @contact.emails.should == ['max@example.com', 'maxpower@example.com']
27
+ end
28
+
29
+ it "should support multiple ims" do
30
+ @contact.ims << {'value' => 'max', 'type' => 'skype'}
31
+ @contact.ims.should == [{'value' => 'max', 'type' => 'skype'}]
32
+ end
33
+
34
+ it "should support multiple phones" do
35
+ @contact.phones << {'value' => '111 111 1111', 'type' => 'home'}
36
+ @contact.phones.should == [{'value' => '111 111 1111', 'type' => 'home'}]
37
+ end
38
+
39
+ it "should support multiple addresses" do
40
+ @contact.addresses << {'formatted' => '111 SW 1st Street, New York, NY'}
41
+ @contact.addresses.should == [{'formatted' => '111 SW 1st Street, New York, NY'}]
42
+ end
43
+
44
+ it "should have username" do
45
+ @contact.username.should == 'maxpower'
46
+ end
47
+
48
+ it "should have firstname" do
49
+ @contact.firstname.should == 'Max'
50
+ end
51
+
52
+ it "should have lastname" do
53
+ @contact.lastname.should == 'Power'
54
+ end
55
+ end
56
+
57
+ describe '#inspect' do
58
+ it "should be nice" do
59
+ @contact = Contacts::Contact.new('max@example.com', 'Max Power', 'maxpower')
60
+ @contact.inspect.should == '#<Contacts::Contact "Max Power" (max@example.com)>'
61
+ end
62
+
63
+ it "should be nice without email" do
64
+ @contact = Contacts::Contact.new(nil, 'Max Power', 'maxpower')
65
+ @contact.inspect.should == '#<Contacts::Contact "Max Power">'
66
+ end
67
+ end
68
+
69
+ end
@@ -0,0 +1,68 @@
1
+ require 'contacts/google'
2
+
3
+ describe Contacts::Google, '.authentication_url' do
4
+
5
+ after :each do
6
+ FakeWeb.clean_registry
7
+ end
8
+
9
+ it 'generates a URL for target with default parameters' do
10
+ uri = parse_authentication_url('http://example.com/invite')
11
+
12
+ uri.host.should == 'www.google.com'
13
+ uri.scheme.should == 'https'
14
+ uri.query.split('&').sort.should == [
15
+ 'next=http%3A%2F%2Fexample.com%2Finvite',
16
+ 'scope=http%3A%2F%2Fwww.google.com%2Fm8%2Ffeeds%2Fcontacts%2F',
17
+ 'secure=0',
18
+ 'session=0'
19
+ ]
20
+ end
21
+
22
+ it 'should handle boolean parameters' do
23
+ pairs = parse_authentication_url(nil, :secure => true, :session => true).query.split('&')
24
+
25
+ pairs.should include('secure=1')
26
+ pairs.should include('session=1')
27
+ end
28
+
29
+ it 'skips parameters that have nil value' do
30
+ query = parse_authentication_url(nil, :secure => nil).query
31
+ query.should_not include('next')
32
+ query.should_not include('secure')
33
+ end
34
+
35
+ it 'should be able to exchange one-time for session token' do
36
+ FakeWeb::register_uri(:get, 'https://www.google.com/accounts/AuthSubSessionToken',
37
+ :body => "Token=G25aZ-v_8B\nExpiration=20061004T123456Z",
38
+ :verify => lambda { |req|
39
+ req['Authorization'].should == %(AuthSub token="dummytoken")
40
+ }
41
+ )
42
+
43
+ Contacts::Google.session_token('dummytoken').should == 'G25aZ-v_8B'
44
+ end
45
+
46
+ it "should support client login" do
47
+ FakeWeb::register_uri(:post, 'https://www.google.com/accounts/ClientLogin',
48
+ :method => 'POST',
49
+ :query => {
50
+ 'accountType' => 'GOOGLE', 'service' => 'cp', 'source' => 'Contacts-Ruby',
51
+ 'Email' => 'mislav@example.com', 'Passwd' => 'dummyPassword'
52
+ },
53
+ :body => "SID=klw4pHhL_ry4jl6\nLSID=Ij6k-7Ypnc1sxm\nAuth=EuoqMSjN5uo-3B"
54
+ )
55
+
56
+ Contacts::Google.client_login('mislav@example.com', 'dummyPassword').should == 'EuoqMSjN5uo-3B'
57
+ end
58
+
59
+ it "should support token authentication after client login" do
60
+ @gmail = Contacts::Google.new('dummytoken', 'default', true)
61
+ @gmail.headers['Authorization'].should == 'GoogleLogin auth="dummytoken"'
62
+ end
63
+
64
+ def parse_authentication_url(*args)
65
+ URI.parse Contacts::Google.authentication_url(*args)
66
+ end
67
+
68
+ end
@@ -0,0 +1,197 @@
1
+ require 'contacts/google'
2
+
3
+ describe Contacts::Google do
4
+
5
+ before :each do
6
+ @gmail = create
7
+ end
8
+
9
+ def create
10
+ Contacts::Google.new('dummytoken')
11
+ end
12
+
13
+ after :each do
14
+ FakeWeb.clean_registry
15
+ end
16
+
17
+ describe 'fetches contacts feed via HTTP GET' do
18
+ it 'with defaults' do
19
+ FakeWeb::register_uri(:get, 'www.google.com/m8/feeds/contacts/default/thin',
20
+ :body => 'thin results',
21
+ :verify => lambda { |req|
22
+ req['Authorization'].should == %(AuthSub token="dummytoken")
23
+ req['Accept-Encoding'].should == 'gzip'
24
+ req['User-Agent'].should == "Ruby Contacts v#{Contacts::VERSION::STRING} (gzip)"
25
+ }
26
+ )
27
+
28
+ response = @gmail.get({})
29
+ response.body.should == 'thin results'
30
+ end
31
+
32
+ it 'with explicit user ID and full projection' do
33
+ @gmail = Contacts::Google.new('dummytoken', 'person@example.com')
34
+ @gmail.projection = 'full'
35
+
36
+ FakeWeb::register_uri(:get, 'www.google.com/m8/feeds/contacts/person%40example.com/full',
37
+ :body => 'full results'
38
+ )
39
+
40
+ response = @gmail.get({})
41
+ response.body.should == 'full results'
42
+ end
43
+ end
44
+
45
+ it 'handles a normal response body' do
46
+ response = mock('HTTP response')
47
+ @gmail.expects(:get).returns(response)
48
+
49
+ response.expects(:'[]').with('Content-Encoding').returns(nil)
50
+ response.expects(:body).returns('<feed/>')
51
+
52
+ @gmail.expects(:parse_contacts).with('<feed/>')
53
+ @gmail.contacts
54
+ end
55
+
56
+ it 'handles gzipped response' do
57
+ response = mock('HTTP response')
58
+ @gmail.expects(:get).returns(response)
59
+
60
+ gzipped = StringIO.new
61
+ gzwriter = Zlib::GzipWriter.new gzipped
62
+ gzwriter.write(('a'..'z').to_a.join)
63
+ gzwriter.close
64
+
65
+ response.expects(:'[]').with('Content-Encoding').returns('gzip')
66
+ response.expects(:body).returns gzipped.string
67
+
68
+ @gmail.expects(:parse_contacts).with('abcdefghijklmnopqrstuvwxyz')
69
+ @gmail.contacts
70
+ end
71
+
72
+ it 'raises a fetching error when something goes awry' do
73
+ FakeWeb::register_uri(:get, 'www.google.com/m8/feeds/contacts/default/thin',
74
+ :status => [404, 'YOU FAIL']
75
+ )
76
+
77
+ lambda {
78
+ @gmail.get({})
79
+ }.should raise_error(Net::HTTPServerException)
80
+ end
81
+
82
+ it 'parses the resulting feed into name/email pairs' do
83
+ @gmail.stubs(:get)
84
+ @gmail.expects(:response_body).returns(sample_xml('google-single'))
85
+
86
+ found = @gmail.contacts
87
+ found.size.should == 1
88
+ contact = found.first
89
+ contact.name.should == 'Fitzgerald'
90
+ contact.emails.should == [{'primary' => 'true', 'type' => 'home', 'value' => 'fubar@gmail.com'}]
91
+ end
92
+
93
+ it 'parses a complex feed into name/email pairs' do
94
+ @gmail.stubs(:get)
95
+ @gmail.expects(:response_body).returns(sample_xml('google-many'))
96
+
97
+ found = @gmail.contacts
98
+ found.size.should == 4
99
+ found[0].name.should == 'Elizabeth Bennet'
100
+ found[0].emails.should == [{'primary' => 'true', 'type' => 'work', 'value' => 'liz@gmail.com'}, {'primary' => 'false', 'type' => 'home', 'value' => 'liz@example.org'}]
101
+ found[1].name.should == 'Poor Jack'
102
+ found[1].emails.should == []
103
+ found[2].name.should == 'William Paginate'
104
+ found[2].emails.should == [{'primary' => 'false', 'type' => 'other', 'value' => 'will_paginate@googlegroups.com'}]
105
+ found[3].name.should be_nil
106
+ found[3].emails.should == [{'primary' => 'false', 'type' => 'other', 'value' => 'anonymous@example.com'}]
107
+ end
108
+
109
+ it 'makes modification time available after parsing' do
110
+ @gmail.updated_at.should be_nil
111
+ @gmail.stubs(:get)
112
+ @gmail.expects(:response_body).returns(sample_xml('google-single'))
113
+
114
+ @gmail.contacts
115
+ u = @gmail.updated_at
116
+ u.year.should == 2008
117
+ u.day.should == 5
118
+ @gmail.updated_at_string.should == '2008-03-05T12:36:38.836Z'
119
+ end
120
+
121
+ describe 'GET query parameter handling' do
122
+
123
+ before :each do
124
+ @gmail = create
125
+ @gmail.stubs(:response_body)
126
+ @gmail.stubs(:parse_contacts)
127
+ end
128
+
129
+ it 'abstracts ugly parameters behind nicer ones' do
130
+ expect_params 'max-results' => '25',
131
+ 'orderby' => 'lastmodified',
132
+ 'sortorder' => 'ascending',
133
+ 'start-index' => '11',
134
+ 'updated-min' => 'datetime'
135
+
136
+ @gmail.contacts :limit => 25,
137
+ :offset => 10,
138
+ :order => 'lastmodified',
139
+ :descending => false,
140
+ :updated_after => 'datetime'
141
+ end
142
+
143
+ it 'should have implicit :descending with :order' do
144
+ expect_params 'orderby' => 'lastmodified',
145
+ 'sortorder' => 'descending',
146
+ 'max-results' => '200'
147
+
148
+ @gmail.contacts :order => 'lastmodified'
149
+ end
150
+
151
+ it 'should have default :limit of 200' do
152
+ expect_params 'max-results' => '200'
153
+ @gmail.contacts
154
+ end
155
+
156
+ it 'should skip nil values in parameters' do
157
+ expect_params 'start-index' => '1'
158
+ @gmail.contacts :limit => nil, :offset => 0
159
+ end
160
+
161
+ def expect_params(params)
162
+ query_string = Contacts::Google.query_string(params)
163
+ FakeWeb::register_uri(:get, "www.google.com/m8/feeds/contacts/default/thin?#{query_string}", {})
164
+ end
165
+
166
+ end
167
+
168
+ describe 'Retrieving all contacts (in chunks)' do
169
+
170
+ before :each do
171
+ @gmail = create
172
+ end
173
+
174
+ it 'should make only one API call when no more is needed' do
175
+ @gmail.expects(:contacts).with(instance_of(Hash)).once.returns((0..8).to_a)
176
+
177
+ @gmail.all_contacts({}, 10).should == (0..8).to_a
178
+ end
179
+
180
+ it 'should make multiple calls to :contacts when needed' do
181
+ @gmail.expects(:contacts).with(has_entries(:offset => 0 , :limit => 10)).returns(( 0..9 ).to_a)
182
+ @gmail.expects(:contacts).with(has_entries(:offset => 10, :limit => 10)).returns((10..19).to_a)
183
+ @gmail.expects(:contacts).with(has_entries(:offset => 20, :limit => 10)).returns((20..24).to_a)
184
+
185
+ @gmail.all_contacts({}, 10).should == (0..24).to_a
186
+ end
187
+
188
+ it 'should make one extra API call when not sure whether there are more contacts' do
189
+ @gmail.expects(:contacts).with(has_entries(:offset => 0 , :limit => 10)).returns((0..9).to_a)
190
+ @gmail.expects(:contacts).with(has_entries(:offset => 10, :limit => 10)).returns([])
191
+
192
+ @gmail.all_contacts({}, 10).should == (0..9).to_a
193
+ end
194
+
195
+ end
196
+
197
+ end
@@ -0,0 +1,91 @@
1
+ require 'rubygems'
2
+ require 'spec'
3
+ require 'mocha'
4
+ require 'cgi'
5
+
6
+ begin
7
+ require 'fake_web'
8
+ rescue LoadError
9
+ puts "~> spec_helper: Could not load fakeweb gem."
10
+ puts "~> spec_helper: Please install it with `gem install fakeweb'."
11
+ exit -1
12
+ end
13
+
14
+ $LOAD_PATH<< File.join(File.dirname(__FILE__), '..', 'lib')
15
+
16
+ FakeWeb.allow_net_connect = false
17
+
18
+ module SampleFeeds
19
+ FEED_DIR = File.dirname(__FILE__) + '/feeds/'
20
+
21
+ def sample_xml(name)
22
+ File.read "#{FEED_DIR}#{name}.xml"
23
+ end
24
+ end
25
+
26
+ module HttpMocks
27
+ def mock_response(type = :success)
28
+ klass = case type
29
+ when :success then Net::HTTPSuccess
30
+ when :redirect then Net::HTTPRedirection
31
+ when :fail then Net::HTTPClientError
32
+ else type
33
+ end
34
+
35
+ klass.new(nil, nil, nil)
36
+ end
37
+
38
+ def mock_connection(ssl = true)
39
+ connection = mock('HTTP connection')
40
+ connection.stubs(:start)
41
+ connection.stubs(:finish)
42
+ if ssl
43
+ connection.expects(:use_ssl=).with(true)
44
+ connection.expects(:verify_mode=).with(OpenSSL::SSL::VERIFY_NONE)
45
+ end
46
+ connection
47
+ end
48
+ end
49
+
50
+ Spec::Runner.configure do |config|
51
+ config.include SampleFeeds, HttpMocks
52
+ # config.predicate_matchers[:swim] = :can_swim?
53
+
54
+ config.mock_with :mocha
55
+ end
56
+
57
+ module Mocha
58
+ module ParameterMatchers
59
+ def query_string(entries, partial = false)
60
+ QueryStringMatcher.new(entries, partial)
61
+ end
62
+ end
63
+ end
64
+
65
+ class QueryStringMatcher < Mocha::ParameterMatchers::Base
66
+
67
+ def initialize(entries, partial)
68
+ @entries = entries
69
+ @partial = partial
70
+ end
71
+
72
+ def matches?(available_parameters)
73
+ string = available_parameters.shift.split('?').last
74
+ broken = string.split('&').map { |pair| pair.split('=').map { |value| CGI.unescape(value) } }
75
+ hash = Hash[*broken.flatten]
76
+
77
+ if @partial
78
+ has_entry_matchers = @entries.map do |key, value|
79
+ Mocha::ParameterMatchers::HasEntry.new(key, value)
80
+ end
81
+ Mocha::ParameterMatchers::AllOf.new(*has_entry_matchers).matches?([hash])
82
+ else
83
+ @entries == hash
84
+ end
85
+ end
86
+
87
+ def mocha_inspect
88
+ "query_string(#{@entries.mocha_inspect})"
89
+ end
90
+
91
+ end
@@ -0,0 +1,41 @@
1
+ require 'contacts/windows_live'
2
+
3
+ describe Contacts::WindowsLive do
4
+
5
+ before(:each) do
6
+ @path = Dir.getwd + '/spec/feeds/'
7
+ @wl = Contacts::WindowsLive.new(@path + 'contacts.yml')
8
+ end
9
+
10
+ it 'parse the XML contacts document' do
11
+ contacts = Contacts::WindowsLive.parse_xml(contacts_xml)
12
+ contacts.size.should == 2
13
+ contacts[0].service_id == "abc"
14
+ contacts[0].name.should == "Mia Pia"
15
+ contacts[0].firstname.should == "Mia"
16
+ contacts[0].lastname.should == "Pia"
17
+ contacts[0].emails.should include("mia@hotmail.com", "othermia@yahoo.com")
18
+ contacts[0].phones.should include({"value"=>"(123) 123 1234", "type"=>"home"}, {"value"=>"(321) 555 1234", "type"=>"other"})
19
+ contacts[0].addresses.should include({"region"=>"CA", "country"=>"USA", "postalCode"=>"92123", "streetAddress"=>"123 Green St", "type"=>"home", "locality"=>"Middleville", "formatted"=>"123 Green St, Middleville, CA, 92123, USA"})
20
+
21
+ contacts[0].service_id == "def"
22
+ contacts[1].name.should == ""
23
+ contacts[1].firstname.should == nil
24
+ contacts[1].lastname.should == nil
25
+ contacts[1].emails.should include("marcus@hotmail.com")
26
+ contacts[1].phones.should be_empty
27
+ contacts[1].addresses.should be_empty
28
+ end
29
+
30
+ it 'should can be initialized by a YAML file' do
31
+ wll = @wl.instance_variable_get('@wll')
32
+
33
+ wll.appid.should == 'your_app_id'
34
+ wll.securityalgorithm.should == 'wsignin1.0'
35
+ wll.returnurl.should == 'http://yourserver.com/your_return_url'
36
+ end
37
+
38
+ def contacts_xml
39
+ File.open(@path + 'wl_full_contacts.xml', 'r+').read
40
+ end
41
+ end