remarkable_devise 1.0.0.alpha3 → 1.0.0
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.
- data/README.markdown +70 -7
- data/lib/remarkable/devise/matchers/base_matcher.rb +17 -0
- data/lib/remarkable/devise/matchers/be_a_confirmable_matcher.rb +7 -3
- data/lib/remarkable/devise/matchers/be_a_database_authenticatable_matcher.rb +11 -4
- data/lib/remarkable/devise/matchers/be_a_lockable_matcher.rb +34 -0
- data/lib/remarkable/devise/matchers/be_a_registerable_matcher.rb +19 -0
- data/lib/remarkable/devise/matchers/be_a_rememberable_matcher.rb +7 -3
- data/lib/remarkable/devise/matchers/be_a_timeoutable_matcher.rb +23 -0
- data/lib/remarkable/devise/matchers/be_a_token_authenticatable_matcher.rb +7 -3
- data/lib/remarkable/devise/matchers/be_a_validatable_matcher.rb +7 -3
- data/lib/remarkable/devise/matchers/be_an_authenticatable_matcher.rb +19 -0
- data/lib/remarkable/devise/version.rb +1 -1
- data/locale/en.yml +70 -0
- data/remarkable_devise.gemspec +1 -1
- data/spec/example_models.rb +10 -2
- data/spec/examples/user_spec.rb +24 -0
- data/spec/matchers/be_a_confirmable_spec.rb +32 -4
- data/spec/matchers/be_a_database_authenticatable_spec.rb +55 -5
- data/spec/matchers/be_a_lockable_spec.rb +274 -0
- data/spec/matchers/be_a_registerable_spec.rb +27 -0
- data/spec/matchers/be_a_rememberable_spec.rb +81 -1
- data/spec/matchers/be_a_timeoutable_spec.rb +59 -0
- data/spec/matchers/be_a_token_authenticatable_spec.rb +33 -1
- data/spec/matchers/be_a_validatable_spec.rb +58 -5
- data/spec/matchers_spec.rb +23 -5
- data/spec/shared_examples.rb +122 -0
- data/spec/spec_helper.rb +13 -4
- metadata +23 -12
data/remarkable_devise.gemspec
CHANGED
@@ -21,7 +21,7 @@ Gem::Specification.new do |s|
|
|
21
21
|
s.add_runtime_dependency(%q<rspec>, [">=2.1.0"])
|
22
22
|
s.add_runtime_dependency(%q<rails>, [">=3.0.1"])
|
23
23
|
s.add_runtime_dependency(%q<activerecord>, [">=3.0.1"])
|
24
|
-
s.add_runtime_dependency(%q<remarkable_activerecord>, ["4.0.0.alpha4"])
|
24
|
+
s.add_runtime_dependency(%q<remarkable_activerecord>, [">=4.0.0.alpha4"])
|
25
25
|
s.add_runtime_dependency(%q<devise>, [">=1.1.3"])
|
26
26
|
|
27
27
|
s.add_development_dependency "mocha"
|
data/spec/example_models.rb
CHANGED
@@ -1,6 +1,14 @@
|
|
1
1
|
class User < ActiveRecord::Base
|
2
|
-
devise :database_authenticatable, :
|
3
|
-
|
2
|
+
devise :database_authenticatable, :stretches => 15, :encryptor => :clearance_sha1, :authentication_keys => [:email, :login], :params_authenticatable => false
|
3
|
+
devise :confirmable, :confirm_within => 2.days
|
4
|
+
devise :recoverable
|
5
|
+
devise :rememberable, :remember_for => 2.weeks, :extend_remember_period => true, :cookie_domain => 'foo'
|
6
|
+
devise :trackable
|
7
|
+
devise :validatable, :password_length => 8..20, :email_regexp => /^([\w\.%\+\-]+)@([\w\-]+\.)+([\w]{2,})$/i
|
8
|
+
devise :token_authenticatable, :token_authentication_key => :auth_token
|
9
|
+
devise :timeoutable, :timeout_in => 15.minutes
|
10
|
+
devise :lockable, :maximum_attempts => 10, :lock_strategy => :none, :unlock_strategy => :time, :unlock_in => 5.hours
|
11
|
+
devise :registerable
|
4
12
|
end
|
5
13
|
|
6
14
|
class FooUser < ActiveRecord::Base
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe User do
|
4
|
+
before do
|
5
|
+
User.stubs(:column_names).returns(%w{email encrypted_password password_salt confirmation_token confirmed_at confirmation_sent_at remember_token remember_created_at locked_at authentication_token sign_in_count current_sign_in_at last_sign_in_at current_sign_in_ip last_sign_in_ip reset_password_token failed_attempts unlock_token})
|
6
|
+
end
|
7
|
+
|
8
|
+
it { should be_a_confirmable(:confirm_within => 2.days) }
|
9
|
+
it { should be_a_rememberable(:remember_for => 2.weeks) }
|
10
|
+
it { should be_a_validatable(:password_length => 8..20) }
|
11
|
+
it { should be_a_timeoutable(:timeout_in => 15.minutes) }
|
12
|
+
it { should be_a_lockable(:lock_strategy => :failed_attempts, :unlock_strategy => :both) }
|
13
|
+
it { should be_a_token_authenticatable }
|
14
|
+
it { should be_a_trackable }
|
15
|
+
it { should be_a_registerable }
|
16
|
+
it { should be_a_recoverable }
|
17
|
+
|
18
|
+
should_be_a_database_authenticatable do |o|
|
19
|
+
o.stretches = 15
|
20
|
+
o.encryptor = :clearance_sha1
|
21
|
+
o.params_authenticatable = false
|
22
|
+
o.authentication_keys = [:email, :login]
|
23
|
+
end
|
24
|
+
end
|
@@ -17,6 +17,18 @@ describe Remarkable::Devise::Matchers::BeAConfirmableMatcher do
|
|
17
17
|
end
|
18
18
|
end
|
19
19
|
|
20
|
+
context "options validation" do
|
21
|
+
describe :confirm_within do
|
22
|
+
it "should validate that model has proper :confirm_within" do
|
23
|
+
subject.class.new(:confirm_within => 2.days).matches?(User).should be_true
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should validate that model hasn't proper :confirm_within" do
|
27
|
+
subject.class.new(:confirm_within => 3.days).matches?(User).should be_false
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
20
32
|
context "columns validation" do
|
21
33
|
context "confirmation_token column" do
|
22
34
|
before do
|
@@ -71,11 +83,18 @@ describe Remarkable::Devise::Matchers::BeAConfirmableMatcher do
|
|
71
83
|
end
|
72
84
|
|
73
85
|
describe "description" do
|
74
|
-
|
75
|
-
|
86
|
+
context "when matching without options" do
|
87
|
+
specify { subject.description.should eql('be a confirmable') }
|
88
|
+
end
|
89
|
+
|
90
|
+
context "when matching with :confirm_within" do
|
91
|
+
before do
|
92
|
+
@matcher = subject.class.new(:confirm_within => 5.days)
|
93
|
+
@matcher.matches?(User)
|
94
|
+
end
|
95
|
+
|
96
|
+
specify { @matcher.description.should eql("be a confirmable within 5 days") }
|
76
97
|
end
|
77
|
-
|
78
|
-
specify { @msg.should eql('be a confirmable') }
|
79
98
|
end
|
80
99
|
|
81
100
|
context "expectation message" do
|
@@ -121,5 +140,14 @@ describe Remarkable::Devise::Matchers::BeAConfirmableMatcher do
|
|
121
140
|
|
122
141
|
specify { @msg.should match('to have confirmation_sent_at column') }
|
123
142
|
end
|
143
|
+
|
144
|
+
context "when :confirm_within doesn't match" do
|
145
|
+
before do
|
146
|
+
@matcher = subject.class.new(:confirm_within => 3.days)
|
147
|
+
@matcher.matches?(User)
|
148
|
+
end
|
149
|
+
|
150
|
+
specify { @matcher.failure_message_for_should.should match("User to be a confirmable with options (.+), got (.+)")}
|
151
|
+
end
|
124
152
|
end
|
125
153
|
end
|
@@ -1,6 +1,8 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe Remarkable::Devise::Matchers::BeADatabaseAuthenticatableMatcher do
|
4
|
+
it_should_behave_like "any Devise authentication model"
|
5
|
+
|
4
6
|
before do
|
5
7
|
@valid_columns = ['email', 'encrypted_password', 'password_salt']
|
6
8
|
|
@@ -13,7 +15,29 @@ describe Remarkable::Devise::Matchers::BeADatabaseAuthenticatableMatcher do
|
|
13
15
|
end
|
14
16
|
|
15
17
|
it "should validate that model has no :database_authenticatable model" do
|
16
|
-
|
18
|
+
subject.matches?(FooUser).should be_false
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
context "options validation" do
|
23
|
+
describe :stretches do
|
24
|
+
it "should validate that a model has proper :stratches" do
|
25
|
+
subject.class.new(:stretches => 15).matches?(User).should be_true
|
26
|
+
end
|
27
|
+
|
28
|
+
it "should validate that a model hasn't proper :stratches" do
|
29
|
+
subject.class.new(:stretches => 10).matches?(User).should be_false
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
describe :encryptor do
|
34
|
+
it "should validate that a model has proper :encryptor" do
|
35
|
+
subject.class.new(:encryptor => :clearance_sha1).matches?(User).should be_true
|
36
|
+
end
|
37
|
+
|
38
|
+
it "should validate that a model hasn't proper :encryptor" do
|
39
|
+
subject.class.new(:encryptor => :bcrypt).matches?(User).should be_false
|
40
|
+
end
|
17
41
|
end
|
18
42
|
end
|
19
43
|
|
@@ -71,16 +95,33 @@ describe Remarkable::Devise::Matchers::BeADatabaseAuthenticatableMatcher do
|
|
71
95
|
end
|
72
96
|
|
73
97
|
describe "description" do
|
74
|
-
|
75
|
-
|
98
|
+
context "when matching without options" do
|
99
|
+
specify { subject.description.should eql('be a database authenticatable') }
|
100
|
+
end
|
101
|
+
|
102
|
+
context "when matching with :stretches option" do
|
103
|
+
before do
|
104
|
+
@matcher = subject.class.new(:stretches => 15)
|
105
|
+
@matcher.matches?(User)
|
106
|
+
end
|
107
|
+
|
108
|
+
specify { @matcher.description.should eql("be a database authenticatable with password stretches 15") }
|
109
|
+
end
|
110
|
+
|
111
|
+
context "when matching with :encryptor option" do
|
112
|
+
before do
|
113
|
+
@matcher = subject.class.new(:encryptor => :bcrypt)
|
114
|
+
@matcher.matches?(User)
|
115
|
+
end
|
116
|
+
|
117
|
+
specify { @matcher.description.should eql("be a database authenticatable with :bcrypt password encryptor") }
|
76
118
|
end
|
77
|
-
|
78
|
-
specify { @msg.should eql('be a database authenticatable') }
|
79
119
|
end
|
80
120
|
|
81
121
|
context "expectation message" do
|
82
122
|
context "when Devise::Models::DatabaseAuthenticatable not included" do
|
83
123
|
before do
|
124
|
+
subject.stubs(:has_authenticatable_module_included?).returns(true)
|
84
125
|
subject.matches?(FooUser)
|
85
126
|
|
86
127
|
@msg = subject.failure_message_for_should
|
@@ -121,5 +162,14 @@ describe Remarkable::Devise::Matchers::BeADatabaseAuthenticatableMatcher do
|
|
121
162
|
|
122
163
|
specify { @msg.should match('to have password_salt column') }
|
123
164
|
end
|
165
|
+
|
166
|
+
context "when options doesn't match" do
|
167
|
+
before do
|
168
|
+
@matcher = subject.class.new(:stretches => 10)
|
169
|
+
@matcher.matches?(User)
|
170
|
+
end
|
171
|
+
|
172
|
+
specify { @matcher.failure_message_for_should.should match('User to be a database authenticatable with options (.+), got (.+)') }
|
173
|
+
end
|
124
174
|
end
|
125
175
|
end
|
@@ -0,0 +1,274 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Remarkable::Devise::Matchers::BeALockableMatcher do
|
4
|
+
before do
|
5
|
+
@valid_columns = %w{failed_attempts unlock_token locked_at}
|
6
|
+
|
7
|
+
User.stubs(:column_names).returns(@valid_columns)
|
8
|
+
end
|
9
|
+
|
10
|
+
describe "validation of Devise::Models::Lockable module inclusion" do
|
11
|
+
before do
|
12
|
+
User.stubs(:lock_strategy).returns(:none)
|
13
|
+
User.stubs(:unlock_strategy).returns(:none)
|
14
|
+
User.stubs(:has_column?).returns(true)
|
15
|
+
end
|
16
|
+
|
17
|
+
it "should validate that a model has Devise::Models::Lockable module included" do
|
18
|
+
subject.matches?(User).should be_true
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should validate that a model hasn't Devise::Models::Lockable module included" do
|
22
|
+
subject.matches?(FooUser).should be_false
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
describe "columns validation" do
|
27
|
+
before do
|
28
|
+
subject.stubs(:included?).returns(true)
|
29
|
+
end
|
30
|
+
|
31
|
+
context "when :lock_strategy is :failed_attempts" do
|
32
|
+
before do
|
33
|
+
User.stubs(:lock_strategy).returns(:failed_attempts)
|
34
|
+
end
|
35
|
+
|
36
|
+
it "should validate that a model has :failed_attempts column" do
|
37
|
+
subject.matches?(User).should be_true
|
38
|
+
end
|
39
|
+
|
40
|
+
it "should validate that a model hasn't :faild_attempts column" do
|
41
|
+
User.stubs(:column_names).returns(@valid_columns - ['failed_attempts'])
|
42
|
+
|
43
|
+
subject.matches?(User).should be_false
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
context "when :lock_strategy is :none" do
|
48
|
+
before do
|
49
|
+
User.stubs(:lock_strategy).returns(:none)
|
50
|
+
end
|
51
|
+
|
52
|
+
context "when a model has :failed_attempts column" do
|
53
|
+
it "should match" do
|
54
|
+
subject.matches?(User).should be_true
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
context "when a model hasn't :failed_attempts column" do
|
59
|
+
before do
|
60
|
+
User.stubs(:column_names).returns(@valid_columns - ['failed_attempts'])
|
61
|
+
end
|
62
|
+
|
63
|
+
it "should match" do
|
64
|
+
subject.matches?(User).should be_true
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
context "when :unlock_strategy is :time" do
|
70
|
+
before do
|
71
|
+
User.stubs(:unlock_strategy).returns(:time)
|
72
|
+
end
|
73
|
+
|
74
|
+
it_should_behave_like "lockable matcher for unlock_strategy without unlock_token column needed"
|
75
|
+
end
|
76
|
+
|
77
|
+
context "when :unlock_strategy is :email" do
|
78
|
+
before do
|
79
|
+
User.stubs(:unlock_strategy).returns(:email)
|
80
|
+
end
|
81
|
+
|
82
|
+
it_should_behave_like "lockable matcher for unlock_strategy with unlock_token column needed"
|
83
|
+
end
|
84
|
+
|
85
|
+
context "when :unlock_strategy is :both" do
|
86
|
+
before do
|
87
|
+
User.stubs(:unlock_strategy).returns(:both)
|
88
|
+
end
|
89
|
+
|
90
|
+
it_should_behave_like "lockable matcher for unlock_strategy with unlock_token column needed"
|
91
|
+
end
|
92
|
+
|
93
|
+
context "when :unlock_strategy is :none" do
|
94
|
+
before do
|
95
|
+
User.stubs(:unlock_strategy).returns(:none)
|
96
|
+
end
|
97
|
+
|
98
|
+
it_should_behave_like "lockable matcher for unlock_strategy without unlock_token column needed"
|
99
|
+
end
|
100
|
+
|
101
|
+
describe :locked_at do
|
102
|
+
context "when a model has locked_at column" do
|
103
|
+
it "should match" do
|
104
|
+
subject.matches?(User).should be_true
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
context "when a model has no locked_at column" do
|
109
|
+
before do
|
110
|
+
User.stubs(:column_names).returns(@valid_columns - ['locked_at'])
|
111
|
+
end
|
112
|
+
|
113
|
+
it "should not match" do
|
114
|
+
subject.matches?(User).should be_false
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
describe "matching with options" do
|
121
|
+
describe :maximum_attempts do
|
122
|
+
context "when a model has expected :maximum_attepmts value" do
|
123
|
+
it "should match" do
|
124
|
+
subject.class.new(:maximum_attempts => 10).matches?(User).should be_true
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
context "when a model hasn't expected :maximum_attempts value" do
|
129
|
+
it "should not match" do
|
130
|
+
subject.class.new(:maximum_attempts => 25).matches?(User).should be_false
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
describe :lock_strategy do
|
136
|
+
context "when a model has expected :lock_strategy value" do
|
137
|
+
it "should match" do
|
138
|
+
subject.class.new(:lock_strategy => :none).matches?(User).should be_true
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
context "when a model hasn't expected :lock_strategy value" do
|
143
|
+
it "should not match" do
|
144
|
+
subject.class.new(:lock_strategy => :failed_attempts).matches?(User).should be_false
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
describe :unlock_strategy do
|
150
|
+
context "when a model has expected :unlock_strategy value" do
|
151
|
+
it "should match" do
|
152
|
+
subject.class.new(:unlock_strategy => :time).matches?(User).should be_true
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
context "when a model hasn't expected :unlock_strategy value" do
|
157
|
+
it "should not match" do
|
158
|
+
subject.class.new(:unlock_strategy => :both).matches?(User).should be_false
|
159
|
+
end
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
describe :unlock_in do
|
164
|
+
context "when a model has expected :unlock_in value" do
|
165
|
+
it "should match" do
|
166
|
+
subject.class.new(:unlock_in => 5.hours).matches?(User).should be_true
|
167
|
+
end
|
168
|
+
|
169
|
+
end
|
170
|
+
|
171
|
+
context "when a model hasn't expected :unlock_in value" do
|
172
|
+
it "should not match" do
|
173
|
+
subject.class.new(:unlock_in => 1.hour).matches?(User).should be_false
|
174
|
+
end
|
175
|
+
end
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
describe "description" do
|
180
|
+
context "when matching without options" do
|
181
|
+
specify { subject.description.should eql('be a lockable') }
|
182
|
+
end
|
183
|
+
|
184
|
+
context "when matching with :maximum_attempts option" do
|
185
|
+
before do
|
186
|
+
@matcher = subject.class.new(:maximum_attempts => 10)
|
187
|
+
@matcher.matches?(User)
|
188
|
+
end
|
189
|
+
|
190
|
+
specify { @matcher.description.should eql("be a lockable with 10 maximum attempts") }
|
191
|
+
end
|
192
|
+
|
193
|
+
context "when matching with :lock_strategy option" do
|
194
|
+
before do
|
195
|
+
@matcher = subject.class.new(:lock_strategy => :time)
|
196
|
+
@matcher.matches?(User)
|
197
|
+
end
|
198
|
+
|
199
|
+
specify { @matcher.description.should eql("be a lockable with :time lock strategy") }
|
200
|
+
end
|
201
|
+
|
202
|
+
context "when matching with :unlock_strategy option" do
|
203
|
+
before do
|
204
|
+
@matcher = subject.class.new(:unlock_strategy => :both)
|
205
|
+
@matcher.matches?(User)
|
206
|
+
end
|
207
|
+
|
208
|
+
specify { @matcher.description.should eql("be a lockable with :both unlock strategy") }
|
209
|
+
end
|
210
|
+
|
211
|
+
context "when matching with :unlock_in option" do
|
212
|
+
before do
|
213
|
+
@matcher = subject.class.new(:unlock_in => 5.minutes)
|
214
|
+
@matcher.matches?(User)
|
215
|
+
end
|
216
|
+
|
217
|
+
specify { @matcher.description.should eql("be a lockable with unlock in 300 seconds") }
|
218
|
+
end
|
219
|
+
end
|
220
|
+
|
221
|
+
describe "failure message" do
|
222
|
+
before do
|
223
|
+
User.lock_strategy = :failed_attempts
|
224
|
+
User.unlock_strategy = :both
|
225
|
+
end
|
226
|
+
|
227
|
+
context "when module Devise::Models::Lockable is not included" do
|
228
|
+
before do
|
229
|
+
subject.matches?(FooUser)
|
230
|
+
end
|
231
|
+
|
232
|
+
specify { subject.failure_message_for_should.should match("Foo user to have Devise :lockable model") }
|
233
|
+
end
|
234
|
+
|
235
|
+
context "when model doesn't have :failed_attempts column" do
|
236
|
+
before do
|
237
|
+
User.stubs(:column_names).returns(@valid_columns - ['failed_attempts'])
|
238
|
+
|
239
|
+
subject.matches?(User)
|
240
|
+
end
|
241
|
+
|
242
|
+
specify { subject.failure_message_for_should.should match("User to have failed_attempts column") }
|
243
|
+
end
|
244
|
+
|
245
|
+
context "when model doesn't have :unlock_token column" do
|
246
|
+
before do
|
247
|
+
User.stubs(:column_names).returns(@valid_columns - ['unlock_token'])
|
248
|
+
|
249
|
+
subject.matches?(User)
|
250
|
+
end
|
251
|
+
|
252
|
+
specify { subject.failure_message_for_should.should match("User to have unlock_token column") }
|
253
|
+
end
|
254
|
+
|
255
|
+
context "when model doesn't have :locked_at column" do
|
256
|
+
before do
|
257
|
+
User.stubs(:column_names).returns(@valid_columns - ['locked_at'])
|
258
|
+
|
259
|
+
subject.matches?(User)
|
260
|
+
end
|
261
|
+
|
262
|
+
specify { subject.failure_message_for_should.should match("User to have locked_at column") }
|
263
|
+
end
|
264
|
+
|
265
|
+
context "when options doesn't match" do
|
266
|
+
before do
|
267
|
+
@matcher = subject.class.new(:maximum_attempts => 15)
|
268
|
+
@matcher.matches?(User)
|
269
|
+
end
|
270
|
+
|
271
|
+
specify { @matcher.failure_message_for_should.should match("User to be a lockable with options (.+), got (.+)") }
|
272
|
+
end
|
273
|
+
end
|
274
|
+
end
|