millsb-twitter-auth 0.1.16

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 (40) hide show
  1. data/README.markdown +96 -0
  2. data/Rakefile +31 -0
  3. data/VERSION.yml +4 -0
  4. data/app/controllers/sessions_controller.rb +64 -0
  5. data/app/models/twitter_auth/basic_user.rb +63 -0
  6. data/app/models/twitter_auth/generic_user.rb +93 -0
  7. data/app/models/twitter_auth/oauth_user.rb +43 -0
  8. data/app/views/sessions/_login_form.html.erb +17 -0
  9. data/app/views/sessions/new.html.erb +5 -0
  10. data/config/routes.rb +6 -0
  11. data/generators/twitter_auth/USAGE +12 -0
  12. data/generators/twitter_auth/templates/migration.rb +48 -0
  13. data/generators/twitter_auth/templates/twitter_auth.yml +44 -0
  14. data/generators/twitter_auth/templates/user.rb +5 -0
  15. data/generators/twitter_auth/twitter_auth_generator.rb +34 -0
  16. data/lib/twitter_auth.rb +87 -0
  17. data/lib/twitter_auth/controller_extensions.rb +65 -0
  18. data/lib/twitter_auth/cryptify.rb +30 -0
  19. data/lib/twitter_auth/dispatcher/basic.rb +46 -0
  20. data/lib/twitter_auth/dispatcher/oauth.rb +26 -0
  21. data/lib/twitter_auth/dispatcher/shared.rb +40 -0
  22. data/rails/init.rb +8 -0
  23. data/spec/controllers/controller_extensions_spec.rb +162 -0
  24. data/spec/controllers/sessions_controller_spec.rb +221 -0
  25. data/spec/fixtures/config/twitter_auth.yml +17 -0
  26. data/spec/fixtures/factories.rb +18 -0
  27. data/spec/fixtures/fakeweb.rb +18 -0
  28. data/spec/fixtures/twitter.rb +5 -0
  29. data/spec/models/twitter_auth/basic_user_spec.rb +122 -0
  30. data/spec/models/twitter_auth/generic_user_spec.rb +142 -0
  31. data/spec/models/twitter_auth/oauth_user_spec.rb +94 -0
  32. data/spec/schema.rb +41 -0
  33. data/spec/spec.opts +1 -0
  34. data/spec/spec_helper.rb +51 -0
  35. data/spec/twitter_auth/cryptify_spec.rb +51 -0
  36. data/spec/twitter_auth/dispatcher/basic_spec.rb +83 -0
  37. data/spec/twitter_auth/dispatcher/oauth_spec.rb +72 -0
  38. data/spec/twitter_auth/dispatcher/shared_spec.rb +26 -0
  39. data/spec/twitter_auth_spec.rb +154 -0
  40. metadata +127 -0
@@ -0,0 +1,162 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper'
2
+
3
+ ActionController::Routing::Routes.draw do |map|
4
+ map.connect ':controller/:action/:id'
5
+ end
6
+
7
+ class TwitterAuthTestController < ApplicationController
8
+ before_filter :login_required, :only => [:login_required_action]
9
+
10
+ def login_required_action
11
+ render :text => "You are logged in!"
12
+ end
13
+
14
+ def fail_auth
15
+ authentication_failed('Auth FAIL.')
16
+ end
17
+
18
+ def pass_auth
19
+ if params[:message]
20
+ authentication_succeeded(params[:message])
21
+ else
22
+ authentication_succeeded
23
+ end
24
+ end
25
+
26
+ def access_denied_action
27
+ access_denied
28
+ end
29
+
30
+ def redirect_back_action
31
+ redirect_back_or_default(params[:to] || '/')
32
+ end
33
+
34
+ def logout_keeping_session_action
35
+ logout_keeping_session!
36
+ redirect_back_or_default('/')
37
+ end
38
+
39
+ def current_user_action
40
+ @user = current_user
41
+ render :nothing => true
42
+ end
43
+ end
44
+
45
+ describe TwitterAuthTestController do
46
+ before do
47
+ controller.stub!(:cookies).and_return({})
48
+ end
49
+
50
+ %w(authentication_failed authentication_succeeded current_user authorized? login_required access_denied store_location redirect_back_or_default logout_keeping_session!).each do |m|
51
+ it "should respond to the extension method '#{m}'" do
52
+ controller.should respond_to(m)
53
+ end
54
+ end
55
+
56
+ describe "#authentication_failed" do
57
+ it 'should set the flash[:error] to the message passed in' do
58
+ get :fail_auth
59
+ flash[:error].should == 'Auth FAIL.'
60
+ end
61
+
62
+ it 'should redirect to the root' do
63
+ get :fail_auth
64
+ should redirect_to('/')
65
+ end
66
+ end
67
+
68
+ describe "#authentication_succeeded" do
69
+ it 'should set the flash[:notice] to a default success message' do
70
+ get :pass_auth
71
+ flash[:notice].should == 'You have logged in successfully.'
72
+ end
73
+
74
+ it 'should be able ot receive a custom message' do
75
+ get :pass_auth, :message => 'Eat at Joes.'
76
+ flash[:notice].should == 'Eat at Joes.'
77
+ end
78
+ end
79
+
80
+ describe '#current_user' do
81
+ it 'should find the user based on the session user_id' do
82
+ user = Factory.create(:twitter_oauth_user)
83
+ request.session[:user_id] = user.id
84
+ get(:current_user_action)
85
+ assigns[:user].should == user
86
+ end
87
+
88
+ it 'should log the user in through a cookie' do
89
+ user = Factory(:twitter_oauth_user, :remember_token => 'abc', :remember_token_expires_at => (Time.now + 10.days))
90
+ controller.stub!(:cookies).and_return({:remember_token => 'abc'})
91
+ get :current_user_action
92
+ assigns[:user].should == user
93
+ end
94
+
95
+ it 'should return nil if there is no user matching that id' do
96
+ request.session[:user_id] = 2345
97
+ get :current_user_action
98
+ assigns[:user].should be_nil
99
+ end
100
+ end
101
+
102
+ describe "#authorized?" do
103
+ it 'should be true if there is a current_user' do
104
+ user = Factory.create(:twitter_oauth_user)
105
+ controller.stub!(:current_user).and_return(user)
106
+ controller.send(:authorized?).should be_true
107
+ end
108
+
109
+ it 'should be false if there is not current_user' do
110
+ controller.stub!(:current_user).and_return(nil)
111
+ controller.send(:authorized?).should be_false
112
+ end
113
+ end
114
+
115
+ describe '#access_denied' do
116
+ it 'should redirect to the login path' do
117
+ get :access_denied_action
118
+ should redirect_to(login_path)
119
+ end
120
+
121
+ it 'should store the location first' do
122
+ controller.should_receive(:store_location).once
123
+ get :access_denied_action
124
+ end
125
+ end
126
+
127
+ describe '#redirect_back_or_default' do
128
+ it 'should redirect if there is a session[:return_to]' do
129
+ request.session[:return_to] = '/'
130
+ get :redirect_back_action, :to => '/notroot'
131
+ should redirect_to('/')
132
+ end
133
+
134
+ it 'should redirect to the default provided otherwise' do
135
+ get :redirect_back_action, :to => '/someurl'
136
+ should redirect_to('/someurl')
137
+ end
138
+ end
139
+
140
+ describe 'logout_keeping_session!' do
141
+ before do
142
+ @user = Factory.create(:twitter_oauth_user)
143
+ request.session[:user_id] = @user.id
144
+ end
145
+
146
+ it 'should unset session[:user_id]' do
147
+ get :logout_keeping_session_action
148
+ request.session[:user_id].should be_nil
149
+ end
150
+
151
+ it 'should unset current_user' do
152
+ controller.send(:current_user).should == @user
153
+ get :logout_keeping_session_action
154
+ controller.send(:current_user).should be_nil
155
+ end
156
+
157
+ it 'should unset the cookie' do
158
+ controller.send(:cookies).should_receive(:delete).with(:remember_token)
159
+ get :logout_keeping_session_action
160
+ end
161
+ end
162
+ end
@@ -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)
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)
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,18 @@
1
+ require 'factory_girl'
2
+
3
+ Factory.define(:twitter_oauth_user, :class => User) do |u|
4
+ u.login 'twitterman'
5
+ u.access_token 'fakeaccesstoken'
6
+ u.access_secret 'fakeaccesstokensecret'
7
+
8
+ u.name 'Twitter Man'
9
+ u.description 'Saving the world for all Twitter kind.'
10
+ end
11
+
12
+ Factory.define(:twitter_basic_user, :class => User) do |u|
13
+ u.login 'twitterman'
14
+ u.password 'test'
15
+
16
+ u.name 'Twitter Man'
17
+ u.description 'Saving the world for all Twitter kind.'
18
+ 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\":20256865,\"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,122 @@
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)
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)
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\":20256865,\"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)
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({'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({'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({'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({'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({'screen_name' => 'dude', 'name' => "Lebowski"}, 'test')
103
+ user.login.should == 'dude'
104
+ user.name.should == 'Lebowski'
105
+ user.password.should == 'test'
106
+ end
107
+ end
108
+
109
+ describe '#twitter' do
110
+ before do
111
+ @user = Factory.create(:twitter_basic_user)
112
+ end
113
+
114
+ it 'should be an instance of TwitterAuth::Dispatcher::Basic' do
115
+ @user.twitter.class.should == TwitterAuth::Dispatcher::Basic
116
+ end
117
+
118
+ it 'should have the correct user set' do
119
+ @user.twitter.user.should == @user
120
+ end
121
+ end
122
+ end