-
-
Notifications
You must be signed in to change notification settings - Fork 910
/
Copy pathhave_secure_password_matcher.rb
125 lines (108 loc) · 3.6 KB
/
have_secure_password_matcher.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
module Shoulda
module Matchers
module ActiveModel
# The `have_secure_password` matcher tests usage of the
# `has_secure_password` macro.
#
# #### Example
#
# class User
# include ActiveModel::Model
# include ActiveModel::SecurePassword
# attr_accessor :password
# attr_accessor :reset_password
#
# has_secure_password
# has_secure_password :reset_password
# end
#
# # RSpec
# RSpec.describe User, type: :model do
# it { should have_secure_password }
# it { should have_secure_password(:reset_password) }
# end
#
# # Minitest (Shoulda)
# class UserTest < ActiveSupport::TestCase
# should have_secure_password
# should have_secure_password(:reset_password)
# end
#
# @return [HaveSecurePasswordMatcher]
#
def have_secure_password(attr = :password)
HaveSecurePasswordMatcher.new(attr)
end
# @private
class HaveSecurePasswordMatcher
attr_reader :failure_message
CORRECT_PASSWORD = 'aBcDe12345'.freeze
INCORRECT_PASSWORD = 'password'.freeze
MESSAGES = {
authenticated_incorrect_password: 'expected %{subject} to not'\
' authenticate an incorrect %{attribute}',
did_not_authenticate_correct_password: 'expected %{subject} to'\
' authenticate the correct %{attribute}',
method_not_found: 'expected %{subject} to respond to %{methods}',
should_not_have_secure_password: 'expected %{subject} to'\
' not %{description}!',
}.freeze
def initialize(attribute)
@attribute = attribute.to_sym
end
def description
"have a secure password, defined on #{@attribute} attribute"
end
def matches?(subject)
@subject = subject
if failure = validate
key, params = failure
@failure_message =
MESSAGES[key] % { subject: subject.class }.merge(params)
end
failure.nil?
end
def failure_message_when_negated
MESSAGES[:should_not_have_secure_password] %
{ subject: @subject.class, description: description }
end
protected
attr_reader :subject
def validate
missing_methods = expected_methods.reject do |m|
subject.respond_to?(m)
end
if missing_methods.present?
[:method_not_found, { methods: missing_methods.to_sentence }]
else
subject.send("#{@attribute}=", CORRECT_PASSWORD)
subject.send("#{@attribute}_confirmation=", CORRECT_PASSWORD)
if not subject.send(authenticate_method, CORRECT_PASSWORD)
[:did_not_authenticate_correct_password,
{ attribute: @attribute },]
elsif subject.send(authenticate_method, INCORRECT_PASSWORD)
[:authenticated_incorrect_password, { attribute: @attribute }]
end
end
end
private
def expected_methods
@_expected_methods ||= %I[
#{authenticate_method}
#{@attribute}=
#{@attribute}_confirmation=
#{@attribute}_digest
#{@attribute}_digest=
]
end
def authenticate_method
if @attribute == :password
:authenticate
else
"authenticate_#{@attribute}".to_sym
end
end
end
end
end
end