twitter-auth-with-mongo-mapper 0.0.9

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 (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