devise 2.0.6 → 2.1.0.rc
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of devise might be problematic. Click here for more details.
- data/.travis.yml +0 -1
- data/CHANGELOG.rdoc +12 -6
- data/Gemfile.lock +3 -3
- data/README.md +9 -15
- data/app/controllers/devise_controller.rb +2 -3
- data/app/views/devise/_links.erb +3 -25
- data/app/views/devise/confirmations/new.html.erb +1 -1
- data/app/views/devise/passwords/edit.html.erb +1 -1
- data/app/views/devise/passwords/new.html.erb +1 -1
- data/app/views/devise/registrations/new.html.erb +1 -1
- data/app/views/devise/sessions/new.html.erb +1 -1
- data/app/views/devise/shared/_links.erb +25 -3
- data/app/views/devise/unlocks/new.html.erb +1 -1
- data/config/locales/en.yml +2 -2
- data/gemfiles/Gemfile.rails-3.1.x.lock +3 -3
- data/lib/devise.rb +1 -0
- data/lib/devise/controllers/helpers.rb +1 -1
- data/lib/devise/encryptors/base.rb +5 -1
- data/lib/devise/encryptors/bcrypt.rb +14 -0
- data/lib/devise/failure_app.rb +1 -0
- data/lib/devise/models.rb +32 -2
- data/lib/devise/models/authenticatable.rb +15 -10
- data/lib/devise/models/confirmable.rb +21 -1
- data/lib/devise/models/database_authenticatable.rb +11 -5
- data/lib/devise/models/encryptable.rb +17 -9
- data/lib/devise/models/lockable.rb +17 -1
- data/lib/devise/models/omniauthable.rb +4 -0
- data/lib/devise/models/recoverable.rb +4 -0
- data/lib/devise/models/registerable.rb +4 -0
- data/lib/devise/models/rememberable.rb +6 -2
- data/lib/devise/models/timeoutable.rb +4 -0
- data/lib/devise/models/token_authenticatable.rb +5 -0
- data/lib/devise/models/trackable.rb +4 -0
- data/lib/devise/models/validatable.rb +4 -0
- data/lib/devise/param_filter.rb +2 -1
- data/lib/devise/rails/routes.rb +3 -2
- data/lib/devise/strategies/authenticatable.rb +10 -4
- data/lib/devise/version.rb +1 -1
- data/lib/generators/devise/views_generator.rb +15 -6
- data/lib/generators/templates/devise.rb +1 -1
- data/lib/generators/templates/simple_form_for/confirmations/new.html.erb +1 -1
- data/lib/generators/templates/simple_form_for/passwords/edit.html.erb +1 -1
- data/lib/generators/templates/simple_form_for/passwords/new.html.erb +1 -1
- data/lib/generators/templates/simple_form_for/registrations/new.html.erb +1 -1
- data/lib/generators/templates/simple_form_for/sessions/new.html.erb +1 -1
- data/lib/generators/templates/simple_form_for/unlocks/new.html.erb +1 -1
- data/test/generators/views_generator_test.rb +1 -1
- data/test/integration/omniauthable_test.rb +2 -2
- data/test/integration/recoverable_test.rb +9 -0
- data/test/models/authenticatable_test.rb +3 -5
- data/test/models/confirmable_test.rb +26 -0
- data/test/models/database_authenticatable_test.rb +29 -7
- data/test/models/encryptable_test.rb +6 -0
- data/test/models/lockable_test.rb +34 -0
- data/test/models/omniauthable_test.rb +7 -0
- data/test/models/recoverable_test.rb +8 -1
- data/test/models/registerable_test.rb +7 -0
- data/test/models/rememberable_test.rb +8 -1
- data/test/models/timeoutable_test.rb +4 -0
- data/test/models/token_authenticatable_test.rb +6 -0
- data/test/models/trackable_test.rb +9 -1
- data/test/models/validatable_test.rb +5 -1
- data/test/models_test.rb +70 -0
- data/test/rails_app/config/routes.rb +4 -0
- data/test/routes_test.rb +4 -0
- data/test/support/assertions.rb +15 -0
- data/test/support/helpers.rb +21 -0
- metadata +19 -34
@@ -46,7 +46,7 @@ class ViewsGeneratorTest < Rails::Generators::TestCase
|
|
46
46
|
assert_file "app/views/#{scope}/registrations/new.html.erb"
|
47
47
|
assert_file "app/views/#{scope}/registrations/edit.html.erb"
|
48
48
|
assert_file "app/views/#{scope}/sessions/new.html.erb"
|
49
|
+
assert_file "app/views/#{scope}/shared/_links.erb"
|
49
50
|
assert_file "app/views/#{scope}/unlocks/new.html.erb"
|
50
|
-
assert_file "app/views/#{scope}/_links.erb"
|
51
51
|
end
|
52
52
|
end
|
@@ -118,7 +118,7 @@ class OmniauthableIntegrationTest < ActionController::IntegrationTest
|
|
118
118
|
OmniAuth.config.mock_auth[:facebook] = :access_denied
|
119
119
|
visit "/users/auth/facebook/callback?error=access_denied"
|
120
120
|
assert_current_url "/users/sign_in"
|
121
|
-
assert_contain 'Could not
|
121
|
+
assert_contain 'Could not authenticate you from Facebook because "Access denied".'
|
122
122
|
end
|
123
123
|
|
124
124
|
test "handles other exceptions from omniauth" do
|
@@ -128,6 +128,6 @@ class OmniauthableIntegrationTest < ActionController::IntegrationTest
|
|
128
128
|
click_link "Sign in with Facebook"
|
129
129
|
|
130
130
|
assert_current_url "/users/sign_in"
|
131
|
-
assert_contain 'Could not
|
131
|
+
assert_contain 'Could not authenticate you from Facebook because "Invalid credentials".'
|
132
132
|
end
|
133
133
|
end
|
@@ -195,6 +195,15 @@ class PasswordTest < ActionController::IntegrationTest
|
|
195
195
|
assert !warden.authenticated?(:user)
|
196
196
|
end
|
197
197
|
|
198
|
+
test 'sign in user automatically and confirm after changing its password if it\'s not confirmed' do
|
199
|
+
user = create_user(:confirm => false)
|
200
|
+
request_forgot_password
|
201
|
+
reset_password :reset_password_token => user.reload.reset_password_token
|
202
|
+
|
203
|
+
assert warden.authenticated?(:user)
|
204
|
+
assert user.reload.confirmed?
|
205
|
+
end
|
206
|
+
|
198
207
|
test 'reset password request with valid E-Mail in XML format should return valid response' do
|
199
208
|
create_user
|
200
209
|
post user_password_path(:format => 'xml'), :user => {:email => "user@test.com"}
|
@@ -1,9 +1,7 @@
|
|
1
1
|
require 'test_helper'
|
2
2
|
|
3
3
|
class AuthenticatableTest < ActiveSupport::TestCase
|
4
|
-
test '
|
5
|
-
|
6
|
-
assert_equal User.find_first_by_auth_conditions({ :email => "example@example.com" }), user
|
7
|
-
assert_equal User.find_first_by_auth_conditions({ :email => "example@example.com" }, :id => user.id + 1), nil
|
4
|
+
test 'required_fields should be an empty array' do
|
5
|
+
assert_equal Devise::Models::Validatable.required_fields(User), []
|
8
6
|
end
|
9
|
-
end
|
7
|
+
end
|
@@ -252,6 +252,15 @@ class ReconfirmableTest < ActiveSupport::TestCase
|
|
252
252
|
assert_not_nil admin.confirmation_token
|
253
253
|
end
|
254
254
|
|
255
|
+
test 'should not generate confirmation token if skipping reconfirmation after changing email' do
|
256
|
+
admin = create_admin
|
257
|
+
assert admin.confirm!
|
258
|
+
admin.skip_reconfirmation!
|
259
|
+
assert admin.update_attributes(:email => 'new_test@example.com')
|
260
|
+
assert_nil admin.confirmation_token
|
261
|
+
end
|
262
|
+
|
263
|
+
|
255
264
|
test 'should regenerate confirmation token after changing email' do
|
256
265
|
admin = create_admin
|
257
266
|
assert admin.confirm!
|
@@ -328,4 +337,21 @@ class ReconfirmableTest < ActiveSupport::TestCase
|
|
328
337
|
admin = Admin.find_by_unconfirmed_email_with_errors(:email => "new_test@email.com")
|
329
338
|
assert admin.persisted?
|
330
339
|
end
|
340
|
+
|
341
|
+
test 'required_fields should contain the fields that Devise uses' do
|
342
|
+
assert_same_content Devise::Models::Confirmable.required_fields(User), [
|
343
|
+
:confirmation_sent_at,
|
344
|
+
:confirmation_token,
|
345
|
+
:confirmed_at
|
346
|
+
]
|
347
|
+
end
|
348
|
+
|
349
|
+
test 'required_fields should also contain unconfirmable when reconfirmable_email is true' do
|
350
|
+
assert_same_content Devise::Models::Confirmable.required_fields(Admin), [
|
351
|
+
:confirmation_sent_at,
|
352
|
+
:confirmation_token,
|
353
|
+
:confirmed_at,
|
354
|
+
:unconfirmed_email
|
355
|
+
]
|
356
|
+
end
|
331
357
|
end
|
@@ -11,7 +11,7 @@ class DatabaseAuthenticatableTest < ActiveSupport::TestCase
|
|
11
11
|
user.save!
|
12
12
|
assert_equal email.downcase, user.email
|
13
13
|
end
|
14
|
-
|
14
|
+
|
15
15
|
test 'should remove whitespace from strip whitespace keys when saving' do
|
16
16
|
# strip_whitespace_keys is set to :email by default.
|
17
17
|
email = ' foo@bar.com '
|
@@ -23,9 +23,15 @@ class DatabaseAuthenticatableTest < ActiveSupport::TestCase
|
|
23
23
|
end
|
24
24
|
|
25
25
|
test "param filter should not convert booleans and integer to strings" do
|
26
|
-
conditions = {
|
26
|
+
conditions = { 'login' => 'foo@bar.com', "bool1" => true, "bool2" => false, "fixnum" => 123, "will_be_converted" => (1..10) }
|
27
|
+
conditions = Devise::ParamFilter.new([], []).filter(conditions)
|
28
|
+
assert_equal( { 'login' => 'foo@bar.com', "bool1" => true, "bool2" => false, "fixnum" => 123, "will_be_converted" => "1..10" }, conditions)
|
29
|
+
end
|
30
|
+
|
31
|
+
test "param filter should not convert regular expressions to strings" do
|
32
|
+
conditions = { "regexp" => /expression/ }
|
27
33
|
conditions = Devise::ParamFilter.new([], []).filter(conditions)
|
28
|
-
assert_equal( { "
|
34
|
+
assert_equal( { "regexp" => /expression/ }, conditions)
|
29
35
|
end
|
30
36
|
|
31
37
|
test 'should respond to password and password confirmation' do
|
@@ -86,14 +92,14 @@ class DatabaseAuthenticatableTest < ActiveSupport::TestCase
|
|
86
92
|
:password => 'pass321', :password_confirmation => 'pass321')
|
87
93
|
assert user.reload.valid_password?('pass321')
|
88
94
|
end
|
89
|
-
|
95
|
+
|
90
96
|
test 'should update password with valid current password and :as option' do
|
91
97
|
user = create_user
|
92
98
|
assert user.update_with_password(:current_password => '123456',
|
93
99
|
:password => 'pass321', :password_confirmation => 'pass321', :as => :admin)
|
94
100
|
assert user.reload.valid_password?('pass321')
|
95
101
|
end
|
96
|
-
|
102
|
+
|
97
103
|
test 'should add an error to current password when it is invalid' do
|
98
104
|
user = create_user
|
99
105
|
assert_not user.update_with_password(:current_password => 'other',
|
@@ -145,7 +151,7 @@ class DatabaseAuthenticatableTest < ActiveSupport::TestCase
|
|
145
151
|
user.update_without_password(:email => 'new@example.com')
|
146
152
|
assert_equal 'new@example.com', user.email
|
147
153
|
end
|
148
|
-
|
154
|
+
|
149
155
|
test 'should update the user without password with :as option' do
|
150
156
|
user = create_user
|
151
157
|
user.update_without_password(:email => 'new@example.com', :as => :admin)
|
@@ -164,4 +170,20 @@ class DatabaseAuthenticatableTest < ActiveSupport::TestCase
|
|
164
170
|
user = User.create(:email => "HEllO@example.com", :password => "123456")
|
165
171
|
assert !user.valid?
|
166
172
|
end
|
167
|
-
|
173
|
+
|
174
|
+
test 'required_fiels should be encryptable_password and the email field by default' do
|
175
|
+
assert_same_content Devise::Models::DatabaseAuthenticatable.required_fields(User), [
|
176
|
+
:email,
|
177
|
+
:encrypted_password
|
178
|
+
]
|
179
|
+
end
|
180
|
+
|
181
|
+
test 'required_fields should be encryptable_password and the login when the login is on authentication_keys' do
|
182
|
+
swap Devise, :authentication_keys => [:login] do
|
183
|
+
assert_same_content Devise::Models::DatabaseAuthenticatable.required_fields(User), [
|
184
|
+
:encrypted_password,
|
185
|
+
:login
|
186
|
+
]
|
187
|
+
end
|
188
|
+
end
|
189
|
+
end
|
@@ -64,4 +64,10 @@ class EncryptableTest < ActiveSupport::TestCase
|
|
64
64
|
admin.save
|
65
65
|
assert_not admin.valid_password?('123456')
|
66
66
|
end
|
67
|
+
|
68
|
+
test 'required_fields should contain the fields that Devise uses' do
|
69
|
+
assert_same_content Devise::Models::Encryptable.required_fields(User), [
|
70
|
+
:password_salt
|
71
|
+
]
|
72
|
+
end
|
67
73
|
end
|
@@ -235,4 +235,38 @@ class LockableTest < ActiveSupport::TestCase
|
|
235
235
|
assert_nil user.locked_at
|
236
236
|
end
|
237
237
|
end
|
238
|
+
|
239
|
+
test 'required_fields should contain the all the fields when all the strategies are enabled' do
|
240
|
+
swap Devise, :unlock_strategy => :both do
|
241
|
+
swap Devise, :lock_strategy => :failed_attempts do
|
242
|
+
assert_same_content Devise::Models::Lockable.required_fields(User), [
|
243
|
+
:failed_attempts,
|
244
|
+
:unlock_at,
|
245
|
+
:unlock_token
|
246
|
+
]
|
247
|
+
end
|
248
|
+
end
|
249
|
+
end
|
250
|
+
|
251
|
+
test 'required_fields should contain only failed_attempts and unlock_at when the strategies are time and failed_attempts are enabled' do
|
252
|
+
swap Devise, :unlock_strategy => :time do
|
253
|
+
swap Devise, :lock_strategy => :failed_attempts do
|
254
|
+
assert_same_content Devise::Models::Lockable.required_fields(User), [
|
255
|
+
:failed_attempts,
|
256
|
+
:unlock_at
|
257
|
+
]
|
258
|
+
end
|
259
|
+
end
|
260
|
+
end
|
261
|
+
|
262
|
+
test 'required_fields should contain only failed_attempts and unlock_token when the strategies are token and failed_attempts are enabled' do
|
263
|
+
swap Devise, :unlock_strategy => :email do
|
264
|
+
swap Devise, :lock_strategy => :failed_attempts do
|
265
|
+
assert_same_content Devise::Models::Lockable.required_fields(User), [
|
266
|
+
:failed_attempts,
|
267
|
+
:unlock_token
|
268
|
+
]
|
269
|
+
end
|
270
|
+
end
|
271
|
+
end
|
238
272
|
end
|
@@ -195,4 +195,11 @@ class RecoverableTest < ActiveSupport::TestCase
|
|
195
195
|
assert_equal "has expired, please request a new one", reset_password_user.errors[:reset_password_token].join
|
196
196
|
end
|
197
197
|
end
|
198
|
-
|
198
|
+
|
199
|
+
test 'required_fields should contain the fields that Devise uses' do
|
200
|
+
assert_same_content Devise::Models::Recoverable.required_fields(User), [
|
201
|
+
:reset_password_sent_at,
|
202
|
+
:reset_password_token
|
203
|
+
]
|
204
|
+
end
|
205
|
+
end
|
@@ -54,7 +54,7 @@ class RememberableTest < ActiveSupport::TestCase
|
|
54
54
|
resource.forget_me!
|
55
55
|
assert resource.remember_created_at.nil?
|
56
56
|
end
|
57
|
-
|
57
|
+
|
58
58
|
test 'forget_me should not try to update resource if it has been destroyed' do
|
59
59
|
resource = create_resource
|
60
60
|
resource.destroy
|
@@ -165,4 +165,11 @@ class RememberableTest < ActiveSupport::TestCase
|
|
165
165
|
assert_not_equal old, resource.remember_created_at
|
166
166
|
end
|
167
167
|
end
|
168
|
+
|
169
|
+
test 'should have the required_fiels array' do
|
170
|
+
assert_same_content Devise::Models::Rememberable.required_fields(User), [
|
171
|
+
:remember_created_at,
|
172
|
+
:remember_token
|
173
|
+
]
|
174
|
+
end
|
168
175
|
end
|
@@ -39,4 +39,8 @@ class TimeoutableTest < ActiveSupport::TestCase
|
|
39
39
|
assert user.timedout?(6.minutes.ago)
|
40
40
|
end
|
41
41
|
end
|
42
|
+
|
43
|
+
test 'required_fields should contain the fields that Devise uses' do
|
44
|
+
assert_same_content Devise::Models::Timeoutable.required_fields(User), []
|
45
|
+
end
|
42
46
|
end
|
@@ -46,4 +46,10 @@ class TokenAuthenticatableTest < ActiveSupport::TestCase
|
|
46
46
|
user = User.find_for_token_authentication(:auth_token => {'$ne' => user1.authentication_token})
|
47
47
|
assert_nil user
|
48
48
|
end
|
49
|
+
|
50
|
+
test 'required_fields should contain the fields that Devise uses' do
|
51
|
+
assert_same_content Devise::Models::TokenAuthenticatable.required_fields(User), [
|
52
|
+
:authentication_token
|
53
|
+
]
|
54
|
+
end
|
49
55
|
end
|
@@ -1,5 +1,13 @@
|
|
1
1
|
require 'test_helper'
|
2
2
|
|
3
3
|
class TrackableTest < ActiveSupport::TestCase
|
4
|
-
|
4
|
+
test 'required_fields should contain the fields that Devise uses' do
|
5
|
+
assert_same_content Devise::Models::Trackable.required_fields(User), [
|
6
|
+
:current_sign_in_at,
|
7
|
+
:current_sign_in_ip,
|
8
|
+
:last_sign_in_at,
|
9
|
+
:last_sign_in_ip,
|
10
|
+
:sign_in_count
|
11
|
+
]
|
12
|
+
end
|
5
13
|
end
|
@@ -105,9 +105,13 @@ class ValidatableTest < ActiveSupport::TestCase
|
|
105
105
|
assert_equal 'is too long (maximum is 128 characters)', user.errors[:password].join
|
106
106
|
end
|
107
107
|
|
108
|
-
test '
|
108
|
+
test 'should not be included in objects with invalid API' do
|
109
109
|
assert_raise RuntimeError do
|
110
110
|
Class.new.send :include, Devise::Models::Validatable
|
111
111
|
end
|
112
112
|
end
|
113
|
+
|
114
|
+
test 'required_fields should be an empty array' do
|
115
|
+
assert_equal Devise::Models::Validatable.required_fields(User), []
|
116
|
+
end
|
113
117
|
end
|
data/test/models_test.rb
CHANGED
@@ -107,3 +107,73 @@ class ActiveRecordTest < ActiveSupport::TestCase
|
|
107
107
|
Admin.create!
|
108
108
|
end
|
109
109
|
end
|
110
|
+
|
111
|
+
class CheckFieldsTest < ActiveSupport::TestCase
|
112
|
+
test 'checks if the class respond_to the required fields' do
|
113
|
+
Player = Class.new do
|
114
|
+
extend Devise::Models
|
115
|
+
|
116
|
+
def self.before_validation(instance)
|
117
|
+
end
|
118
|
+
|
119
|
+
devise :database_authenticatable
|
120
|
+
|
121
|
+
attr_accessor :encrypted_password, :email
|
122
|
+
end
|
123
|
+
|
124
|
+
assert_nothing_raised Devise::Models::MissingAttribute do
|
125
|
+
Devise::Models.check_fields!(Player)
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
test 'raises Devise::Models::MissingAtrribute and shows the missing attribute if the class doesn\'t respond_to one of the attributes' do
|
130
|
+
Clown = Class.new do
|
131
|
+
extend Devise::Models
|
132
|
+
|
133
|
+
def self.before_validation(instance)
|
134
|
+
end
|
135
|
+
|
136
|
+
devise :database_authenticatable
|
137
|
+
|
138
|
+
attr_accessor :encrypted_password
|
139
|
+
end
|
140
|
+
|
141
|
+
assert_raise_with_message Devise::Models::MissingAttribute, "The following attribute(s) is (are) missing on your model: email" do
|
142
|
+
Devise::Models.check_fields!(Clown)
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
test 'raises Devise::Models::MissingAtrribute with all the missing attributes if there is more than one' do
|
147
|
+
Magician = Class.new do
|
148
|
+
extend Devise::Models
|
149
|
+
|
150
|
+
def self.before_validation(instance)
|
151
|
+
end
|
152
|
+
|
153
|
+
devise :database_authenticatable
|
154
|
+
end
|
155
|
+
|
156
|
+
exception = assert_raise_with_message Devise::Models::MissingAttribute, "The following attribute(s) is (are) missing on your model: encrypted_password, email" do
|
157
|
+
Devise::Models.check_fields!(Magician)
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
test "doesn't raise a NoMethodError exception when the module doesn't have a required_field(klass) class method" do
|
162
|
+
driver = Class.new do
|
163
|
+
extend Devise::Models
|
164
|
+
|
165
|
+
def self.before_validation(instance)
|
166
|
+
end
|
167
|
+
|
168
|
+
attr_accessor :encrypted_password, :email
|
169
|
+
|
170
|
+
devise :database_authenticatable
|
171
|
+
end
|
172
|
+
|
173
|
+
swap_module_method_existence Devise::Models::DatabaseAuthenticatable, :required_fields do
|
174
|
+
assert_deprecated do
|
175
|
+
Devise::Models.check_fields!(driver)
|
176
|
+
end
|
177
|
+
end
|
178
|
+
end
|
179
|
+
end
|
@@ -58,6 +58,10 @@ Rails.application.routes.draw do
|
|
58
58
|
# Other routes for routing_test.rb
|
59
59
|
devise_for :reader, :class_name => "User", :only => :passwords
|
60
60
|
|
61
|
+
scope :host => "sub.example.com" do
|
62
|
+
devise_for :sub_admin, :class_name => "Admin"
|
63
|
+
end
|
64
|
+
|
61
65
|
namespace :publisher, :path_names => { :sign_in => "i_dont_care", :sign_out => "get_out" } do
|
62
66
|
devise_for :accounts, :class_name => "Admin", :path_names => { :sign_in => "get_in" }
|
63
67
|
end
|
data/test/routes_test.rb
CHANGED
@@ -128,6 +128,10 @@ class CustomizedRoutingTest < ActionController::TestCase
|
|
128
128
|
end
|
129
129
|
end
|
130
130
|
|
131
|
+
test 'subdomain admin' do
|
132
|
+
assert_recognizes({"host"=>"sub.example.com", :controller => 'devise/sessions', :action => 'new'}, {:host => "sub.example.com", :path => '/sub_admin/sign_in', :method => :get})
|
133
|
+
end
|
134
|
+
|
131
135
|
test 'does only map reader password' do
|
132
136
|
assert_raise ActionController::RoutingError do
|
133
137
|
assert_recognizes({:controller => 'devise/sessions', :action => 'new'}, 'reader/sessions/new')
|
data/test/support/assertions.rb
CHANGED
@@ -24,4 +24,19 @@ class ActiveSupport::TestCase
|
|
24
24
|
def assert_email_not_sent(&block)
|
25
25
|
assert_no_difference('ActionMailer::Base.deliveries.size') { yield }
|
26
26
|
end
|
27
|
+
|
28
|
+
def assert_same_content(result, expected)
|
29
|
+
assert expected.size == result.size, "the arrays doesn't have the same size"
|
30
|
+
expected.each do |element|
|
31
|
+
assert result.include?(element), "The array doesn't include '#{element}'."
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def assert_raise_with_message(exception_klass, message)
|
36
|
+
exception = assert_raise exception_klass do
|
37
|
+
yield
|
38
|
+
end
|
39
|
+
|
40
|
+
assert_equal exception.message, message, "The expected message was #{message} but your exception throwed #{exception.message}"
|
41
|
+
end
|
27
42
|
end
|