twitter-auth-with-mongo-mapper 0.0.9

Sign up to get free protection for your applications and to get access to all the features.
Files changed (41) hide show
  1. data/CHANGELOG.markdown +11 -0
  2. data/README.markdown +5 -0
  3. data/Rakefile +31 -0
  4. data/VERSION.yml +4 -0
  5. data/app/controllers/sessions_controller.rb +81 -0
  6. data/app/models/twitter_auth/basic_user.rb +64 -0
  7. data/app/models/twitter_auth/generic_user.rb +135 -0
  8. data/app/models/twitter_auth/oauth_user.rb +50 -0
  9. data/app/views/sessions/_login_form.html.erb +17 -0
  10. data/app/views/sessions/new.html.erb +5 -0
  11. data/config/routes.rb +6 -0
  12. data/generators/twitter_auth/USAGE +12 -0
  13. data/generators/twitter_auth/templates/migration.rb +49 -0
  14. data/generators/twitter_auth/templates/twitter_auth.yml +47 -0
  15. data/generators/twitter_auth/templates/user.rb +5 -0
  16. data/generators/twitter_auth/twitter_auth_generator.rb +34 -0
  17. data/lib/twitter_auth.rb +100 -0
  18. data/lib/twitter_auth/controller_extensions.rb +82 -0
  19. data/lib/twitter_auth/cryptify.rb +31 -0
  20. data/lib/twitter_auth/dispatcher/basic.rb +46 -0
  21. data/lib/twitter_auth/dispatcher/oauth.rb +27 -0
  22. data/lib/twitter_auth/dispatcher/shared.rb +40 -0
  23. data/rails/init.rb +8 -0
  24. data/spec/controllers/controller_extensions_spec.rb +162 -0
  25. data/spec/controllers/sessions_controller_spec.rb +221 -0
  26. data/spec/fixtures/config/twitter_auth.yml +17 -0
  27. data/spec/fixtures/factories.rb +20 -0
  28. data/spec/fixtures/fakeweb.rb +18 -0
  29. data/spec/fixtures/twitter.rb +5 -0
  30. data/spec/models/twitter_auth/basic_user_spec.rb +138 -0
  31. data/spec/models/twitter_auth/generic_user_spec.rb +146 -0
  32. data/spec/models/twitter_auth/oauth_user_spec.rb +100 -0
  33. data/spec/schema.rb +42 -0
  34. data/spec/spec.opts +1 -0
  35. data/spec/spec_helper.rb +51 -0
  36. data/spec/twitter_auth/cryptify_spec.rb +51 -0
  37. data/spec/twitter_auth/dispatcher/basic_spec.rb +83 -0
  38. data/spec/twitter_auth/dispatcher/oauth_spec.rb +72 -0
  39. data/spec/twitter_auth/dispatcher/shared_spec.rb +26 -0
  40. data/spec/twitter_auth_spec.rb +160 -0
  41. metadata +151 -0
@@ -0,0 +1,221 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper'
2
+
3
+ describe SessionsController do
4
+ integrate_views
5
+
6
+ describe 'routes' do
7
+ it 'should route /session/new to SessionsController#new' do
8
+ params_from(:get, '/session/new').should == {:controller => 'sessions', :action => 'new'}
9
+ end
10
+
11
+ it 'should route /login to SessionsController#new' do
12
+ params_from(:get, '/login').should == {:controller => 'sessions', :action => 'new'}
13
+ end
14
+
15
+ it 'should route /logout to SessionsController#destroy' do
16
+ params_from(:get, '/logout').should == {:controller => 'sessions', :action => 'destroy'}
17
+ end
18
+
19
+ it 'should route DELETE /session to SessionsController#destroy' do
20
+ params_from(:delete, '/session').should == {:controller => 'sessions', :action => 'destroy'}
21
+ end
22
+
23
+ it 'should route /oauth_callback to SessionsController#oauth_callback' do
24
+ params_from(:get, '/oauth_callback').should == {:controller => 'sessions', :action => 'oauth_callback'}
25
+ end
26
+
27
+ it 'should route POST /session to SessionsController#create' do
28
+ params_from(:post, '/session').should == {:controller => 'sessions', :action => 'create'}
29
+ end
30
+ end
31
+
32
+ describe 'with OAuth strategy' do
33
+ before do
34
+ stub_oauth!
35
+ end
36
+
37
+ describe '#new' do
38
+ it 'should retrieve a request token' do
39
+ get :new
40
+ assigns[:request_token].token.should == 'faketoken'
41
+ assigns[:request_token].secret.should == 'faketokensecret'
42
+ end
43
+
44
+ it 'should set session variables for the request token' do
45
+ get :new
46
+ session[:request_token].should == 'faketoken'
47
+ session[:request_token_secret].should == 'faketokensecret'
48
+ end
49
+
50
+ it 'should redirect to the oauth authorization url' do
51
+ get :new
52
+ response.should redirect_to('https://twitter.com/oauth/authorize?oauth_token=faketoken')
53
+ end
54
+
55
+ it 'should redirect to the oauth_callback if one is specified' do
56
+ TwitterAuth.stub!(:oauth_callback).and_return('http://localhost:3000/development')
57
+ TwitterAuth.stub!(:oauth_callback?).and_return(true)
58
+
59
+ get :new
60
+ response.should redirect_to('https://twitter.com/oauth/authorize?oauth_token=faketoken&oauth_callback=' + CGI.escape(TwitterAuth.oauth_callback))
61
+ end
62
+ end
63
+
64
+ describe '#oauth_callback' do
65
+ describe 'with no session info' do
66
+ it 'should set the flash[:error]' do
67
+ get :oauth_callback, :oauth_token => 'faketoken'
68
+ flash[:error].should == 'No authentication information was found in the session. Please try again.'
69
+ end
70
+
71
+ it 'should redirect to "/" by default' do
72
+ get :oauth_callback, :oauth_token => 'faketoken'
73
+ response.should redirect_to('/')
74
+ end
75
+
76
+ it 'should call authentication_failed' do
77
+ controller.should_receive(:authentication_failed).any_number_of_times
78
+ get :oauth_callback, :oauth_token => 'faketoken'
79
+ end
80
+ end
81
+
82
+ describe 'with proper info' do
83
+ before do
84
+ @user = Factory.create(:twitter_oauth_user, :twitter_id => '123')
85
+ @time = Time.now
86
+ @remember_token = ActiveSupport::SecureRandom.hex(10)
87
+
88
+ Time.stub!(:now).and_return(@time)
89
+ ActiveSupport::SecureRandom.stub!(:hex).and_return(@remember_token)
90
+
91
+ request.session[:request_token] = 'faketoken'
92
+ request.session[:request_token_secret] = 'faketokensecret'
93
+ get :oauth_callback, :oauth_token => 'faketoken'
94
+ end
95
+
96
+ describe 'building the access token' do
97
+ it 'should rebuild the request token' do
98
+ correct_token = OAuth::RequestToken.new(TwitterAuth.consumer,'faketoken','faketokensecret')
99
+
100
+ %w(token secret).each do |att|
101
+ assigns[:request_token].send(att).should == correct_token.send(att)
102
+ end
103
+ end
104
+
105
+ it 'should exchange the request token for an access token' do
106
+ assigns[:access_token].should be_a(OAuth::AccessToken)
107
+ assigns[:access_token].token.should == 'fakeaccesstoken'
108
+ assigns[:access_token].secret.should == 'fakeaccesstokensecret'
109
+ end
110
+
111
+ it 'should wipe the request token after exchange' do
112
+ session[:request_token].should be_nil
113
+ session[:request_token_secret].should be_nil
114
+ end
115
+ end
116
+
117
+ describe 'identifying the user' do
118
+ it "should find the user" do
119
+ assigns[:user].should == @user
120
+ end
121
+
122
+ it "should assign the user id to the session" do
123
+ session[:user_id].should == @user.id
124
+ end
125
+
126
+ it "should call remember me" do
127
+ @user.reload
128
+ @user.remember_token.should == @remember_token
129
+ end
130
+
131
+ it "should set a cookie" do
132
+ cookies[:remember_token].should == @remember_token
133
+ end
134
+ end
135
+
136
+ describe "when OAuth doesn't work" do
137
+ before do
138
+ request.session[:request_token] = 'faketoken'
139
+ request.session[:request_token_secret] = 'faketokensecret'
140
+ @request_token = OAuth::RequestToken.new(TwitterAuth.consumer, session[:request_token], session[:request_token_secret])
141
+ OAuth::RequestToken.stub!(:new).and_return(@request_token)
142
+ end
143
+
144
+ it 'should call authentication_failed when it gets a 401 from OAuth' do
145
+ @request_token.stub!(:get_access_token).and_raise(Net::HTTPServerException.new('401 "Unauthorized"', '401 "Unauthorized"'))
146
+ controller.should_receive(:authentication_failed).with('This authentication request is no longer valid. Please try again.')
147
+ # the should raise_error is hacky because of the expectation
148
+ # stubbing the proper behavior :-(
149
+ lambda{get :oauth_callback, :oauth_token => 'faketoken'}.should raise_error(ActionView::MissingTemplate)
150
+ end
151
+
152
+ it 'should call authentication_failed when it gets a different HTTPServerException' do
153
+ @request_token.stub!(:get_access_token).and_raise(Net::HTTPServerException.new('404 "Not Found"', '404 "Not Found"'))
154
+ controller.should_receive(:authentication_failed).with('There was a problem trying to authenticate you. Please try again.')
155
+ lambda{get :oauth_callback, :oauth_token => 'faketoken'}.should raise_error(ActionView::MissingTemplate)
156
+ end
157
+ end
158
+ end
159
+ end
160
+ end
161
+
162
+ describe 'with Basic strategy' do
163
+ before do
164
+ stub_basic!
165
+ end
166
+
167
+ describe '#new' do
168
+ it 'should render the new action' do
169
+ get :new
170
+ response.should render_template('sessions/new')
171
+ end
172
+
173
+ it 'should render the login form' do
174
+ get :new
175
+ response.should have_tag('form[action=/session][id=login_form][method=post]')
176
+ end
177
+
178
+ describe '#create' do
179
+ before do
180
+ @user = Factory.create(:twitter_basic_user, :twitter_id => '123')
181
+ end
182
+
183
+ it 'should call logout_keeping_session! to remove session info' do
184
+ controller.should_receive(:logout_keeping_session!)
185
+ post :create
186
+ end
187
+
188
+ it 'should try to authenticate the user' do
189
+ User.should_receive(:authenticate)
190
+ post :create
191
+ end
192
+
193
+ it 'should call authentication_failed on authenticate failure' do
194
+ User.should_receive(:authenticate).and_return(nil)
195
+ post :create, :login => 'wrong', :password => 'false'
196
+ response.should redirect_to('/login')
197
+ end
198
+
199
+ it 'should call authentication_succeeded on authentication success' do
200
+ User.should_receive(:authenticate).and_return(@user)
201
+ post :create, :login => 'twitterman', :password => 'cool'
202
+ response.should redirect_to('/')
203
+ flash[:notice].should_not be_blank
204
+ end
205
+ end
206
+ end
207
+
208
+ end
209
+
210
+ describe '#destroy' do
211
+ it 'should call logout_keeping_session!' do
212
+ controller.should_receive(:logout_keeping_session!).once
213
+ get :destroy
214
+ end
215
+
216
+ it 'should redirect to the root' do
217
+ get :destroy
218
+ response.should redirect_to('/')
219
+ end
220
+ end
221
+ end
@@ -0,0 +1,17 @@
1
+ development:
2
+ strategy: oauth
3
+ base_url: "https://twitter.com"
4
+ oauth_consumer_key: devkey
5
+ oauth_consumer_secret: devsecret
6
+ oauth_callback: "http://localhost:3000"
7
+ test:
8
+ strategy: oauth
9
+ base_url: "https://twitter.com"
10
+ oauth_consumer_key: testkey
11
+ oauth_consumer_secret: testsecret
12
+ production:
13
+ strategy: oauth
14
+ base_url: "https://twitter.com"
15
+ oauth_consumer_key: prodkey
16
+ oauth_consumer_secret: prodsecret
17
+
@@ -0,0 +1,20 @@
1
+ require 'factory_girl'
2
+
3
+ Factory.define(:twitter_oauth_user, :class => User) do |u|
4
+ u.twitter_id { User.count + 1 }
5
+ u.login 'twitterman'
6
+ u.access_token 'fakeaccesstoken'
7
+ u.access_secret 'fakeaccesstokensecret'
8
+
9
+ u.name 'Twitter Man'
10
+ u.description 'Saving the world for all Twitter kind.'
11
+ end
12
+
13
+ Factory.define(:twitter_basic_user, :class => User) do |u|
14
+ u.twitter_id { User.count + 1 }
15
+ u.login 'twitterman'
16
+ u.password 'test'
17
+
18
+ u.name 'Twitter Man'
19
+ u.description 'Saving the world for all Twitter kind.'
20
+ end
@@ -0,0 +1,18 @@
1
+ # This is where we fake out all of the URLs that we
2
+ # will be calling as a part of this spec suite.
3
+ # You must have the 'fakeweb' gem in order to run
4
+ # the tests for TwitterAuth.
5
+ #
6
+ # gem install 'mbleigh-fakeweb'
7
+
8
+ require 'fake_web'
9
+
10
+ FakeWeb.allow_net_connect = false
11
+
12
+ FakeWeb.register_uri(:post, 'https://twitter.com:443/oauth/request_token', :string => 'oauth_token=faketoken&oauth_token_secret=faketokensecret')
13
+
14
+ FakeWeb.register_uri(:post, 'https://twitter.com:443/oauth/access_token', :string => 'oauth_token=fakeaccesstoken&oauth_token_secret=fakeaccesstokensecret')
15
+
16
+ FakeWeb.register_uri(:get, 'https://twitter.com:443/account/verify_credentials.json', :string => "{\"profile_image_url\":\"http:\\/\\/static.twitter.com\\/images\\/default_profile_normal.png\",\"description\":\"Saving the world for all Twitter kind.\",\"utc_offset\":null,\"favourites_count\":0,\"profile_sidebar_fill_color\":\"e0ff92\",\"screen_name\":\"twitterman\",\"statuses_count\":0,\"profile_background_tile\":false,\"profile_sidebar_border_color\":\"87bc44\",\"friends_count\":2,\"url\":null,\"name\":\"Twitter Man\",\"time_zone\":null,\"protected\":false,\"profile_background_image_url\":\"http:\\/\\/static.twitter.com\\/images\\/themes\\/theme1\\/bg.gif\",\"profile_background_color\":\"9ae4e8\",\"created_at\":\"Fri Feb 06 18:10:32 +0000 2009\",\"profile_text_color\":\"000000\",\"followers_count\":2,\"location\":null,\"id\":123,\"profile_link_color\":\"0000ff\"}")
17
+
18
+ #FakeWeb.register_uri(:get, 'https://twitter.com:443/)
@@ -0,0 +1,5 @@
1
+ require 'net/http'
2
+
3
+ TWITTER_JSON = {
4
+ :verify_credentials => "{\"profile_image_url\":\"http:\\/\\/static.twitter.com\\/images\\/default_profile_normal.png\",\"description\":\"Saving the world for all Twitter kind.\",\"utc_offset\":null,\"favourites_count\":0,\"profile_sidebar_fill_color\":\"e0ff92\",\"screen_name\":\"twitterman\",\"statuses_count\":0,\"profile_background_tile\":false,\"profile_sidebar_border_color\":\"87bc44\",\"friends_count\":2,\"url\":null,\"name\":\"Twitter Man\",\"time_zone\":null,\"protected\":false,\"profile_background_image_url\":\"http:\\/\\/static.twitter.com\\/images\\/themes\\/theme1\\/bg.gif\",\"profile_background_color\":\"9ae4e8\",\"created_at\":\"Fri Feb 06 18:10:32 +0000 2009\",\"profile_text_color\":\"000000\",\"followers_count\":2,\"location\":null,\"id\":20256865,\"profile_link_color\":\"0000ff\"}"
5
+ }
@@ -0,0 +1,138 @@
1
+ require File.dirname(__FILE__) + '/../../spec_helper'
2
+
3
+ describe TwitterAuth::BasicUser do
4
+ before do
5
+ stub_basic!
6
+ end
7
+
8
+ describe '#password=' do
9
+ before do
10
+ @user = Factory.build(:twitter_basic_user, :twitter_id => '123')
11
+ end
12
+
13
+ it 'should change the value of crypted_password' do
14
+ lambda{@user.password = 'newpass'}.should change(@user, :crypted_password)
15
+ end
16
+
17
+ it 'should change the value of salt' do
18
+ lambda{@user.password = 'newpass'}.should change(@user, :salt)
19
+ end
20
+
21
+ it 'should not store the plaintext password' do
22
+ @user.password = 'newpass'
23
+ @user.crypted_password.should_not == 'newpass'
24
+ end
25
+ end
26
+
27
+ describe '#password' do
28
+ before do
29
+ @user = Factory.build(:twitter_basic_user, :password => 'monkey')
30
+ end
31
+
32
+ it 'should return the password' do
33
+ @user.password.should == 'monkey'
34
+ end
35
+
36
+ it 'should not be a database attribute' do
37
+ @user['password'].should_not == 'monkey'
38
+ end
39
+ end
40
+
41
+ describe '.verify_credentials' do
42
+ before do
43
+ @user = Factory.create(:twitter_basic_user)
44
+ end
45
+
46
+ it 'should return a JSON hash of the user when successful' do
47
+ hash = User.verify_credentials('twitterman','test')
48
+ hash.should be_a(Hash)
49
+ hash['screen_name'].should == 'twitterman'
50
+ hash['name'].should == 'Twitter Man'
51
+ end
52
+
53
+ it 'should return false when a 401 unauthorized happens' do
54
+ FakeWeb.register_uri(:get, 'https://twitter.com:443/account/verify_credentials.json', :string => '401 "Unauthorized"', :status => ['401',' Unauthorized'])
55
+ User.verify_credentials('twitterman','wrong').should be_false
56
+ end
57
+ end
58
+
59
+ describe '.authenticate' do
60
+ before do
61
+ @user = Factory.create(:twitter_basic_user, :twitter_id => '123')
62
+ end
63
+
64
+ it 'should make a call to verify_credentials' do
65
+ User.should_receive(:verify_credentials).with('twitterman','test')
66
+ User.authenticate('twitterman','test')
67
+ end
68
+
69
+ it 'should return nil if verify_credentials returns false' do
70
+ User.stub!(:verify_credentials).and_return(false)
71
+ User.authenticate('twitterman','test').should be_nil
72
+ end
73
+
74
+ it 'should return the user if verify_credentials succeeds' do
75
+ User.stub!(:verify_credentials).and_return(JSON.parse("{\"profile_image_url\":\"http:\\/\\/static.twitter.com\\/images\\/default_profile_normal.png\",\"description\":\"Saving the world for all Twitter kind.\",\"utc_offset\":null,\"favourites_count\":0,\"profile_sidebar_fill_color\":\"e0ff92\",\"screen_name\":\"twitterman\",\"statuses_count\":0,\"profile_background_tile\":false,\"profile_sidebar_border_color\":\"87bc44\",\"friends_count\":2,\"url\":null,\"name\":\"Twitter Man\",\"time_zone\":null,\"protected\":false,\"profile_background_image_url\":\"http:\\/\\/static.twitter.com\\/images\\/themes\\/theme1\\/bg.gif\",\"profile_background_color\":\"9ae4e8\",\"created_at\":\"Fri Feb 06 18:10:32 +0000 2009\",\"profile_text_color\":\"000000\",\"followers_count\":2,\"location\":null,\"id\":123,\"profile_link_color\":\"0000ff\"}"))
76
+ User.authenticate('twitterman','test').should == @user
77
+ end
78
+ end
79
+
80
+ describe '.find_or_create_by_twitter_hash_and_password' do
81
+ before do
82
+ @user = Factory.create(:twitter_basic_user, :twitter_id => '123')
83
+ end
84
+
85
+ it 'should return the existing user if there is one' do
86
+ User.identify_or_create_from_twitter_hash_and_password({'id' => '123', 'screen_name' => 'twitterman'},'test').should == @user
87
+ end
88
+
89
+ it 'should update the attributes from the hash' do
90
+ User.identify_or_create_from_twitter_hash_and_password({'id' => 123, 'screen_name' => 'twitterman', 'name' => 'New Name'}, 'test').name.should == 'New Name'
91
+ end
92
+
93
+ it 'should update the password from the argument' do
94
+ User.identify_or_create_from_twitter_hash_and_password({'id' => '123', 'screen_name' => 'twitterman', 'name' => 'New Name'}, 'test2').password.should == 'test2'
95
+ end
96
+
97
+ it 'should create a user if one does not exist' do
98
+ lambda{User.identify_or_create_from_twitter_hash_and_password({'id' => 124, 'screen_name' => 'dude', 'name' => "Lebowski"}, 'test')}.should change(User, :count).by(1)
99
+ end
100
+
101
+ it 'should assign the attributes from the hash to a created user' do
102
+ user = User.identify_or_create_from_twitter_hash_and_password({'id' => 124, 'screen_name' => 'dude', 'name' => "Lebowski"}, 'test')
103
+ user.twitter_id.should == '124'
104
+ user.login.should == 'dude'
105
+ user.name.should == 'Lebowski'
106
+ user.password.should == 'test'
107
+ end
108
+ end
109
+
110
+ describe '#twitter' do
111
+ before do
112
+ @user = Factory.create(:twitter_basic_user, :twitter_id => '123')
113
+ end
114
+
115
+ it 'should be an instance of TwitterAuth::Dispatcher::Basic' do
116
+ @user.twitter.class.should == TwitterAuth::Dispatcher::Basic
117
+ end
118
+
119
+ it 'should have the correct user set' do
120
+ @user.twitter.user.should == @user
121
+ end
122
+ end
123
+
124
+ describe 'changing usernames' do
125
+ before do
126
+ @user = Factory.create(:twitter_basic_user, :twitter_id => '123')
127
+ end
128
+
129
+ it 'should not create a new record when a screen_name has changed' do
130
+ lambda{User.identify_or_create_from_twitter_hash_and_password({'id' => '123', 'screen_name' => 'dude'},'awesome')}.should_not change(User,:count)
131
+ end
132
+
133
+ it 'should update the record with the new screen name' do
134
+ User.identify_or_create_from_twitter_hash_and_password({'id' => '123', 'screen_name' => 'dude'},'awesome').should == @user.reload
135
+ @user.login.should == 'dude'
136
+ end
137
+ end
138
+ end
@@ -0,0 +1,146 @@
1
+ require File.dirname(__FILE__) + '/../../spec_helper'
2
+
3
+ describe TwitterAuth::GenericUser do
4
+ should_validate_presence_of :login, :twitter_id
5
+ should_validate_format_of :login, 'some_guy', 'awesome', 'cool_man'
6
+ should_not_validate_format_of :login, 'with-dashes', 'with.periods', 'with spaces'
7
+ should_validate_length_of :login, :in => 1..15
8
+
9
+ it 'should validate uniqueness of login' do
10
+ Factory.create(:twitter_oauth_user)
11
+ Factory.build(:twitter_oauth_user).should have_at_least(1).errors_on(:login)
12
+ end
13
+
14
+ it 'should validate uniqueness of remember_token' do
15
+ Factory.create(:twitter_oauth_user, :remember_token => 'abc')
16
+ Factory.build(:twitter_oauth_user, :remember_token => 'abc').should have_at_least(1).errors_on(:remember_token)
17
+ end
18
+
19
+ it 'should allow capital letters in the username' do
20
+ Factory.build(:twitter_oauth_user, :login => 'TwitterMan').should have(:no).errors_on(:login)
21
+ end
22
+
23
+ it 'should not allow the same login with different capitalization' do
24
+ Factory.create(:twitter_oauth_user, :login => 'twitterman')
25
+ Factory.build(:twitter_oauth_user, :login => 'TwitterMan').should have_at_least(1).errors_on(:login)
26
+ end
27
+
28
+ describe '.new_from_twitter_hash' do
29
+ it 'should raise an argument error if the hash does not have a screen_name attribute' do
30
+ lambda{User.new_from_twitter_hash({'id' => '123'})}.should raise_error(ArgumentError, 'Invalid hash: must include screen_name.')
31
+ end
32
+
33
+ it 'should raise an argument error if the hash does not have an id attribute' do
34
+ lambda{User.new_from_twitter_hash({'screen_name' => 'abc123'})}.should raise_error(ArgumentError, 'Invalid hash: must include id.')
35
+ end
36
+
37
+ it 'should return a user' do
38
+ User.new_from_twitter_hash({'id' => '123', 'screen_name' => 'twitterman'}).should be_a(User)
39
+ end
40
+
41
+ it 'should assign login to the screen_name' do
42
+ User.new_from_twitter_hash({'id' => '123', 'screen_name' => 'twitterman'}).login.should == 'twitterman'
43
+ end
44
+
45
+ it 'should assign twitter attributes that are provided' do
46
+ u = User.new_from_twitter_hash({'id' => '4566', 'screen_name' => 'twitterman', 'name' => 'Twitter Man', 'description' => 'Saving the world for all Tweet kind.'})
47
+ u.name.should == 'Twitter Man'
48
+ u.description.should == 'Saving the world for all Tweet kind.'
49
+ end
50
+ end
51
+
52
+ describe '#update_twitter_attributes' do
53
+ it 'should assign values to the user' do
54
+ user = Factory.create(:twitter_oauth_user, :name => "Dude", :description => "Awesome, man.")
55
+ user.update_twitter_attributes({'name' => 'Twitter Man', 'description' => 'Works.'})
56
+ user.reload
57
+ user.name.should == 'Twitter Man'
58
+ user.description.should == 'Works.'
59
+ end
60
+
61
+ it 'should not throw an error with extraneous info' do
62
+ user = Factory.create(:twitter_oauth_user, :name => "Dude", :description => "Awesome, man.")
63
+ lambda{user.update_twitter_attributes({'name' => 'Twitter Man', 'description' => 'Works.', 'whoopsy' => 'noworks.'})}.should_not raise_error
64
+ end
65
+ end
66
+
67
+ describe '#remember_me' do
68
+ before do
69
+ @user = Factory(:twitter_oauth_user)
70
+ end
71
+
72
+ it 'should check for the remember_token column' do
73
+ @user.should_receive(:respond_to?).with(:remember_token).and_return(false)
74
+ @user.remember_me
75
+ end
76
+
77
+ it 'should return nil if there is no remember_token column' do
78
+ @user.should_receive(:respond_to?).with(:remember_token).and_return(false)
79
+ @user.remember_me.should be_false
80
+ end
81
+
82
+ describe ' with proper columns' do
83
+ it 'should generate a secure random token' do
84
+ ActiveSupport::SecureRandom.should_receive(:hex).with(10).and_return('abcdef')
85
+ @user.remember_me
86
+ @user.remember_token.should == 'abcdef'
87
+ end
88
+
89
+ it 'should set the expiration to the current time plus the remember_for period' do
90
+ TwitterAuth.stub!(:remember_for).and_return(10)
91
+ time = Time.now
92
+ Time.stub!(:now).and_return(time)
93
+
94
+ @user.remember_me
95
+
96
+ @user.remember_token_expires_at.should == Time.now + 10.days
97
+ end
98
+
99
+ it 'should return a hash with a :value and :expires key' do
100
+ result = @user.remember_me
101
+ result.should be_a(Hash)
102
+ result.key?(:value).should be_true
103
+ result.key?(:expires).should be_true
104
+ end
105
+
106
+ it 'should return a hash with appropriate values' do
107
+ TwitterAuth.stub!(:remember_for).and_return(10)
108
+ time = Time.now
109
+ Time.stub!(:now).and_return(time)
110
+ ActiveSupport::SecureRandom.stub!(:hex).and_return('abcdef')
111
+
112
+ @user.remember_me.should == {:value => 'abcdef', :expires => (Time.now + 10.days)}
113
+ end
114
+ end
115
+ end
116
+
117
+ describe '#forget_me' do
118
+ it 'should reset remember_token and remember_token_expires_at' do
119
+ @user = Factory(:twitter_oauth_user, :remember_token => "abcdef", :remember_token_expires_at => Time.now + 10.days)
120
+ @user.forget_me
121
+ @user.reload
122
+ @user.remember_token.should be_nil
123
+ @user.remember_token_expires_at.should be_nil
124
+ end
125
+ end
126
+
127
+ describe '.from_remember_token' do
128
+ before do
129
+ @user = Factory(:twitter_oauth_user, :remember_token => 'abcdef', :remember_token_expires_at => (Time.now + 10.days))
130
+ end
131
+
132
+ it 'should find the user with the specified remember_token' do
133
+ User.from_remember_token('abcdef').should == @user
134
+ end
135
+
136
+ it 'should not find a user with an expired token' do
137
+ user2 = Factory(:twitter_oauth_user, :login => 'walker', :remember_token => 'ghijkl', :remember_token_expires_at => (Time.now - 10.days))
138
+ User.from_remember_token('ghijkl').should be_nil
139
+ end
140
+
141
+ it 'should not find a user with a nil token and an expiration' do
142
+ user = Factory(:twitter_oauth_user, :login => 'stranger', :remember_token => nil, :remember_token_expires_at => (Time.now + 10.days))
143
+ User.from_remember_token(nil).should be_nil
144
+ end
145
+ end
146
+ end