-
-
Notifications
You must be signed in to change notification settings - Fork 910
/
have_secure_password_matcher.rb
118 lines (102 loc) · 3.33 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
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}',
}.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
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