attr_encrypted-magicless 1.3.42

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,339 @@
1
+ # encoding: UTF-8
2
+ require File.expand_path('../test_helper', __FILE__)
3
+
4
+ class SillyEncryptor
5
+ def self.silly_encrypt(options)
6
+ (options[:value] + options[:some_arg]).reverse
7
+ end
8
+
9
+ def self.silly_decrypt(options)
10
+ options[:value].reverse.gsub(/#{options[:some_arg]}$/, '')
11
+ end
12
+ end
13
+
14
+ class User
15
+ include AttrEncrypted
16
+
17
+ self.attr_encrypted_options[:key] = Proc.new { |user| SECRET_KEY } # default key
18
+ self.attr_encrypted_options[:mode] = :per_attribute_iv_and_salt
19
+
20
+ attr_encrypted :email, :without_encoding, :key => SECRET_KEY
21
+ attr_encrypted :password, :prefix => 'crypted_', :suffix => '_test'
22
+ attr_encrypted :ssn, :key => :secret_key, :attribute => 'ssn_encrypted'
23
+ attr_encrypted :credit_card, :encryptor => SillyEncryptor, :encrypt_method => :silly_encrypt, :decrypt_method => :silly_decrypt, :some_arg => 'test'
24
+ attr_encrypted :with_encoding, :key => SECRET_KEY, :encode => true
25
+ attr_encrypted :with_custom_encoding, :key => SECRET_KEY, :encode => 'm'
26
+ attr_encrypted :with_marshaling, :key => SECRET_KEY, :marshal => true
27
+ attr_encrypted :with_true_if, :key => SECRET_KEY, :if => true
28
+ attr_encrypted :with_false_if, :key => SECRET_KEY, :if => false
29
+ attr_encrypted :with_true_unless, :key => SECRET_KEY, :unless => true
30
+ attr_encrypted :with_false_unless, :key => SECRET_KEY, :unless => false
31
+ attr_encrypted :with_if_changed, :key => SECRET_KEY, :if => :should_encrypt
32
+
33
+ attr_encryptor :aliased, :key => SECRET_KEY
34
+
35
+ attr_accessor :salt
36
+ attr_accessor :should_encrypt
37
+
38
+ def initialize
39
+ self.salt = Time.now.to_i.to_s
40
+ self.should_encrypt = true
41
+ end
42
+
43
+ def secret_key
44
+ SECRET_KEY
45
+ end
46
+ end
47
+
48
+ class Admin < User
49
+ attr_encrypted :testing
50
+ end
51
+
52
+ class SomeOtherClass
53
+ include AttrEncrypted
54
+
55
+ def self.call(object)
56
+ object.class
57
+ end
58
+ end
59
+
60
+ class CryptedObject
61
+ include AttrEncrypted
62
+ end
63
+
64
+ class AttrEncryptedTest < Minitest::Test
65
+
66
+ def test_should_store_email_in_encrypted_attributes
67
+ assert User.encrypted_attributes.include?(:email)
68
+ end
69
+
70
+ def test_should_not_store_salt_in_encrypted_attributes
71
+ assert !User.encrypted_attributes.include?(:salt)
72
+ end
73
+
74
+ def test_attr_encrypted_should_return_true_for_email
75
+ assert User.attr_encrypted?('email')
76
+ end
77
+
78
+ def test_attr_encrypted_should_not_use_the_same_attribute_name_for_two_attributes_in_the_same_line
79
+ refute_equal User.encrypted_attributes[:email][:attribute], User.encrypted_attributes[:without_encoding][:attribute]
80
+ end
81
+
82
+ def test_attr_encrypted_should_return_false_for_salt
83
+ assert !User.attr_encrypted?('salt')
84
+ end
85
+
86
+ def test_should_generate_an_encrypted_attribute
87
+ assert User.new.respond_to?(:encrypted_email)
88
+ end
89
+
90
+ def test_should_generate_an_encrypted_attribute_with_a_prefix_and_suffix
91
+ assert User.new.respond_to?(:crypted_password_test)
92
+ end
93
+
94
+ def test_should_generate_an_encrypted_attribute_with_the_attribute_option
95
+ assert User.new.respond_to?(:ssn_encrypted)
96
+ end
97
+
98
+ def test_should_not_encrypt_nil_value
99
+ assert_nil User.encrypt_email(nil)
100
+ end
101
+
102
+ def test_should_not_encrypt_empty_string
103
+ assert_equal '', User.encrypt_email('')
104
+ end
105
+
106
+ def test_should_encrypt_email
107
+ refute_nil User.encrypt_email('test@example.com')
108
+ refute_equal 'test@example.com', User.encrypt_email('test@example.com')
109
+ end
110
+
111
+ def test_should_encrypt_email_when_modifying_the_attr_writer
112
+ @user = User.new
113
+ assert_nil @user.encrypted_email
114
+ @user.email = 'test@example.com'
115
+ refute_nil @user.encrypted_email
116
+ assert_equal User.encrypt_email('test@example.com'), @user.encrypted_email
117
+ end
118
+
119
+ def test_should_not_decrypt_nil_value
120
+ assert_nil User.decrypt_email(nil)
121
+ end
122
+
123
+ def test_should_not_decrypt_empty_string
124
+ assert_equal '', User.decrypt_email('')
125
+ end
126
+
127
+ def test_should_decrypt_email
128
+ encrypted_email = User.encrypt_email('test@example.com')
129
+ refute_equal 'test@test.com', encrypted_email
130
+ assert_equal 'test@example.com', User.decrypt_email(encrypted_email)
131
+ end
132
+
133
+ def test_should_decrypt_email_when_reading
134
+ @user = User.new
135
+ assert_nil @user.email
136
+ @user.encrypted_email = User.encrypt_email('test@example.com')
137
+ assert_equal 'test@example.com', @user.email
138
+ end
139
+
140
+ def test_should_encrypt_with_encoding
141
+ assert_equal User.encrypt_with_encoding('test'), [User.encrypt_without_encoding('test')].pack('m')
142
+ end
143
+
144
+ def test_should_decrypt_with_encoding
145
+ encrypted = User.encrypt_with_encoding('test')
146
+ assert_equal 'test', User.decrypt_with_encoding(encrypted)
147
+ assert_equal User.decrypt_with_encoding(encrypted), User.decrypt_without_encoding(encrypted.unpack('m').first)
148
+ end
149
+
150
+ def test_should_encrypt_with_custom_encoding
151
+ assert_equal User.encrypt_with_encoding('test'), [User.encrypt_without_encoding('test')].pack('m')
152
+ end
153
+
154
+ def test_should_decrypt_with_custom_encoding
155
+ encrypted = User.encrypt_with_encoding('test')
156
+ assert_equal 'test', User.decrypt_with_encoding(encrypted)
157
+ assert_equal User.decrypt_with_encoding(encrypted), User.decrypt_without_encoding(encrypted.unpack('m').first)
158
+ end
159
+
160
+ def test_should_encrypt_with_marshaling
161
+ @user = User.new
162
+ @user.with_marshaling = [1, 2, 3]
163
+ refute_nil @user.encrypted_with_marshaling
164
+ end
165
+
166
+ def test_should_use_custom_encryptor_and_crypt_method_names_and_arguments
167
+ assert_equal SillyEncryptor.silly_encrypt(:value => 'testing', :some_arg => 'test'), User.encrypt_credit_card('testing')
168
+ end
169
+
170
+ def test_should_evaluate_a_key_passed_as_a_symbol
171
+ @user = User.new
172
+ assert_nil @user.ssn_encrypted
173
+ @user.ssn = 'testing'
174
+ refute_nil @user.ssn_encrypted
175
+ encrypted = Encryptor.encrypt(:value => 'testing', :key => SECRET_KEY, :iv => @user.ssn_encrypted_iv.unpack("m").first, :salt => @user.ssn_encrypted_salt )
176
+ assert_equal encrypted, @user.ssn_encrypted
177
+ end
178
+
179
+ def test_should_evaluate_a_key_passed_as_a_proc
180
+ @user = User.new
181
+ assert_nil @user.crypted_password_test
182
+ @user.password = 'testing'
183
+ refute_nil @user.crypted_password_test
184
+ encrypted = Encryptor.encrypt(:value => 'testing', :key => SECRET_KEY, :iv => @user.crypted_password_test_iv.unpack("m").first, :salt => @user.crypted_password_test_salt)
185
+ assert_equal encrypted, @user.crypted_password_test
186
+ end
187
+
188
+ def test_should_use_options_found_in_the_attr_encrypted_options_attribute
189
+ @user = User.new
190
+ assert_nil @user.crypted_password_test
191
+ @user.password = 'testing'
192
+ refute_nil @user.crypted_password_test
193
+ encrypted = Encryptor.encrypt(:value => 'testing', :key => SECRET_KEY, :iv => @user.crypted_password_test_iv.unpack("m").first, :salt => @user.crypted_password_test_salt)
194
+ assert_equal encrypted, @user.crypted_password_test
195
+ end
196
+
197
+ def test_should_inherit_encrypted_attributes
198
+ assert_equal [User.encrypted_attributes.keys, :testing].flatten.collect { |key| key.to_s }.sort, Admin.encrypted_attributes.keys.collect { |key| key.to_s }.sort
199
+ end
200
+
201
+ def test_should_inherit_attr_encrypted_options
202
+ assert !User.attr_encrypted_options.empty?
203
+ assert_equal User.attr_encrypted_options, Admin.attr_encrypted_options
204
+ end
205
+
206
+ def test_should_not_inherit_unrelated_attributes
207
+ assert SomeOtherClass.attr_encrypted_options.empty?
208
+ assert SomeOtherClass.encrypted_attributes.empty?
209
+ end
210
+
211
+ def test_should_evaluate_a_symbol_option
212
+ assert_equal CryptedObject, CryptedObject.new.send(:evaluate_attr_encrypted_option, :class)
213
+ end
214
+
215
+ def test_should_evaluate_a_proc_option
216
+ assert_equal CryptedObject, CryptedObject.new.send(:evaluate_attr_encrypted_option, proc { |object| object.class })
217
+ end
218
+
219
+ def test_should_evaluate_a_lambda_option
220
+ assert_equal CryptedObject, CryptedObject.new.send(:evaluate_attr_encrypted_option, lambda { |object| object.class })
221
+ end
222
+
223
+ def test_should_evaluate_a_method_option
224
+ assert_equal CryptedObject, CryptedObject.new.send(:evaluate_attr_encrypted_option, SomeOtherClass.method(:call))
225
+ end
226
+
227
+ def test_should_return_a_string_option
228
+ assert_equal 'CryptedObject', CryptedObject.new.send(:evaluate_attr_encrypted_option, 'CryptedObject')
229
+ end
230
+
231
+ def test_should_encrypt_with_true_if
232
+ @user = User.new
233
+ assert_nil @user.encrypted_with_true_if
234
+ @user.with_true_if = 'testing'
235
+ refute_nil @user.encrypted_with_true_if
236
+ encrypted = Encryptor.encrypt(:value => 'testing', :key => SECRET_KEY, :iv => @user.encrypted_with_true_if_iv.unpack("m").first, :salt => @user.encrypted_with_true_if_salt)
237
+ assert_equal encrypted, @user.encrypted_with_true_if
238
+ end
239
+
240
+ def test_should_not_encrypt_with_false_if
241
+ @user = User.new
242
+ assert_nil @user.encrypted_with_false_if
243
+ @user.with_false_if = 'testing'
244
+ refute_nil @user.encrypted_with_false_if
245
+ assert_equal 'testing', @user.encrypted_with_false_if
246
+ end
247
+
248
+ def test_should_encrypt_with_false_unless
249
+ @user = User.new
250
+ assert_nil @user.encrypted_with_false_unless
251
+ @user.with_false_unless = 'testing'
252
+ refute_nil @user.encrypted_with_false_unless
253
+ encrypted = Encryptor.encrypt(:value => 'testing', :key => SECRET_KEY, :iv => @user.encrypted_with_false_unless_iv.unpack("m").first, :salt => @user.encrypted_with_false_unless_salt)
254
+ assert_equal encrypted, @user.encrypted_with_false_unless
255
+ end
256
+
257
+ def test_should_not_encrypt_with_true_unless
258
+ @user = User.new
259
+ assert_nil @user.encrypted_with_true_unless
260
+ @user.with_true_unless = 'testing'
261
+ refute_nil @user.encrypted_with_true_unless
262
+ assert_equal 'testing', @user.encrypted_with_true_unless
263
+ end
264
+
265
+ def test_should_work_with_aliased_attr_encryptor
266
+ assert User.encrypted_attributes.include?(:aliased)
267
+ end
268
+
269
+ def test_should_always_reset_options
270
+ @user = User.new
271
+ @user.with_if_changed = "encrypt_stuff"
272
+ @user.stubs(:instance_variable_get).returns(nil)
273
+ @user.stubs(:instance_variable_set).raises("BadStuff")
274
+ assert_raises RuntimeError do
275
+ @user.with_if_changed
276
+ end
277
+
278
+ @user = User.new
279
+ @user.should_encrypt = false
280
+ @user.with_if_changed = "not_encrypted_stuff"
281
+ assert_equal "not_encrypted_stuff", @user.with_if_changed
282
+ assert_equal "not_encrypted_stuff", @user.encrypted_with_if_changed
283
+ end
284
+
285
+ def test_should_cast_values_as_strings_before_encrypting
286
+ string_encrypted_email = User.encrypt_email('3')
287
+ assert_equal string_encrypted_email, User.encrypt_email(3)
288
+ assert_equal '3', User.decrypt_email(string_encrypted_email)
289
+ end
290
+
291
+ def test_should_create_query_accessor
292
+ @user = User.new
293
+ assert !@user.email?
294
+ @user.email = ''
295
+ assert !@user.email?
296
+ @user.email = 'test@example.com'
297
+ assert @user.email?
298
+ end
299
+
300
+ def test_should_vary_iv_per_attribute
301
+ @user = User.new
302
+ @user.email = 'email@example.com'
303
+ @user.password = 'p455w0rd'
304
+ refute_equal @user.encrypted_email_iv, @user.crypted_password_test_iv
305
+ end
306
+
307
+ def test_should_vary_iv_per_instance
308
+ @user1 = User.new
309
+ @user1.email = 'email@example.com'
310
+ @user2 = User.new
311
+ @user2.email = 'email@example.com'
312
+ refute_equal @user1.encrypted_email_iv, @user2.encrypted_email_iv
313
+ end
314
+
315
+ def test_should_vary_salt_per_attribute
316
+ @user = User.new
317
+ @user.email = 'email@example.com'
318
+ @user.password = 'p455w0rd'
319
+ refute_equal @user.encrypted_email_salt, @user.crypted_password_test_salt
320
+ end
321
+
322
+ def test_should_vary_salt_per_instance
323
+ @user1 = User.new
324
+ @user1.email = 'email@example.com'
325
+ @user2 = User.new
326
+ @user2.email = 'email@example.com'
327
+ refute_equal @user1.encrypted_email_salt, @user2.encrypted_email_salt
328
+ end
329
+
330
+ def test_should_decrypt_second_record
331
+ @user1 = User.new
332
+ @user1.email = 'test@example.com'
333
+
334
+ @user2 = User.new
335
+ @user2.email = 'test@example.com'
336
+
337
+ assert_equal 'test@example.com', @user1.decrypt(:email, @user1.encrypted_email)
338
+ end
339
+ end
@@ -0,0 +1,106 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.expand_path('../test_helper', __FILE__)
3
+
4
+ # Test to ensure that existing representations in database do not break on
5
+ # migrating to new versions of this gem. This ensures that future versions of
6
+ # this gem will retain backwards compatibility with data generated by earlier
7
+ # versions.
8
+ class CompatibilityTest < Minitest::Test
9
+ class NonmarshallingPet < ActiveRecord::Base
10
+ PET_NICKNAME_SALT = Digest::SHA256.hexdigest('my-really-really-secret-pet-nickname-salt')
11
+ PET_NICKNAME_KEY = 'my-really-really-secret-pet-nickname-key'
12
+ PET_BIRTHDATE_SALT = Digest::SHA256.hexdigest('my-really-really-secret-pet-birthdate-salt')
13
+ PET_BIRTHDATE_KEY = 'my-really-really-secret-pet-birthdate-key'
14
+
15
+ self.attr_encrypted_options[:mode] = :per_attribute_iv_and_salt
16
+
17
+ attr_encrypted :nickname,
18
+ :key => proc { Encryptor.encrypt(:value => PET_NICKNAME_SALT, :key => PET_NICKNAME_KEY) }
19
+ attr_encrypted :birthdate,
20
+ :key => proc { Encryptor.encrypt(:value => PET_BIRTHDATE_SALT, :key => PET_BIRTHDATE_KEY) }
21
+ end
22
+
23
+ class MarshallingPet < ActiveRecord::Base
24
+ PET_NICKNAME_SALT = Digest::SHA256.hexdigest('my-really-really-secret-pet-nickname-salt')
25
+ PET_NICKNAME_KEY = 'my-really-really-secret-pet-nickname-key'
26
+ PET_BIRTHDATE_SALT = Digest::SHA256.hexdigest('my-really-really-secret-pet-birthdate-salt')
27
+ PET_BIRTHDATE_KEY = 'my-really-really-secret-pet-birthdate-key'
28
+
29
+ self.attr_encrypted_options[:mode] = :per_attribute_iv_and_salt
30
+
31
+ attr_encrypted :nickname,
32
+ :key => proc { Encryptor.encrypt(:value => PET_NICKNAME_SALT, :key => PET_NICKNAME_KEY) },
33
+ :marshal => true
34
+ attr_encrypted :birthdate,
35
+ :key => proc { Encryptor.encrypt(:value => PET_BIRTHDATE_SALT, :key => PET_BIRTHDATE_KEY) },
36
+ :marshal => true
37
+ end
38
+
39
+ def setup
40
+ ActiveRecord::Base.connection.tables.each { |table| ActiveRecord::Base.connection.drop_table(table) }
41
+ create_tables
42
+ end
43
+
44
+ def test_nonmarshalling_backwards_compatibility
45
+ pet = NonmarshallingPet.create!(
46
+ :name => 'Fido',
47
+ :encrypted_nickname => 'E4lJTxFG/EfkfPg5MpnriQ==',
48
+ :encrypted_nickname_iv => 'z4Q8deE4h7f6S8NNZcbPNg==',
49
+ :encrypted_nickname_salt => 'adcd833001a873db',
50
+ :encrypted_birthdate => '6uKEAiFVdJw+N5El+U6Gow==',
51
+ :encrypted_birthdate_iv => 'zxtc1XPssL4s2HwA69nORQ==',
52
+ :encrypted_birthdate_salt => '4f879270045eaad7'
53
+ )
54
+
55
+ assert_equal 'Fido', pet.name
56
+ assert_equal 'Fido the Dog', pet.nickname
57
+ assert_equal '2011-07-09', pet.birthdate
58
+ end
59
+
60
+ def test_marshalling_backwards_compatibility
61
+ pet = MarshallingPet.create!(
62
+ :name => 'Fido',
63
+ :encrypted_nickname => 'EsQScJYkPw80vVGvKWkE37Px99HHpXPFjoEPTNa4rbs=',
64
+ :encrypted_nickname_iv => 'fNq1OZcGvty4KfcvGTcFSw==',
65
+ :encrypted_nickname_salt => '733b459b7d34c217',
66
+ :encrypted_birthdate => '+VUlKQGfNWkOgCwI4hv+3qlGIwh9h6cJ/ranJlaxvU+xxQdL3H3cOzTcI2rkYkdR',
67
+ :encrypted_birthdate_iv => 'Ka+zF/SwEYZKwVa24lvFfA==',
68
+ :encrypted_birthdate_salt => 'd5e892d5bbd81566'
69
+ )
70
+
71
+ assert_equal 'Fido', pet.name
72
+ assert_equal 'Mummy\'s little helper', pet.nickname
73
+
74
+ assert_equal Date.new(2011, 7, 9), pet.birthdate
75
+ end
76
+
77
+ private
78
+
79
+ def create_tables
80
+ silence_stream(STDOUT) do
81
+ ActiveRecord::Schema.define(:version => 1) do
82
+ create_table :nonmarshalling_pets do |t|
83
+ t.string :name
84
+ t.string :encrypted_nickname
85
+ t.string :encrypted_nickname_iv
86
+ t.string :encrypted_nickname_salt
87
+ t.string :encrypted_birthdate
88
+ t.string :encrypted_birthdate_iv
89
+ t.string :encrypted_birthdate_salt
90
+ end
91
+ create_table :marshalling_pets do |t|
92
+ t.string :name
93
+ t.string :encrypted_nickname
94
+ t.string :encrypted_nickname_iv
95
+ t.string :encrypted_nickname_salt
96
+ t.string :encrypted_birthdate
97
+ t.string :encrypted_birthdate_iv
98
+ t.string :encrypted_birthdate_salt
99
+ end
100
+ end
101
+ end
102
+ end
103
+ end
104
+
105
+ ActiveRecord::Base.establish_connection :adapter => 'sqlite3', :database => ':memory:'
106
+
@@ -0,0 +1,94 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.expand_path('../test_helper', __FILE__)
3
+
4
+ ActiveRecord::Base.establish_connection :adapter => 'sqlite3', :database => ':memory:'
5
+
6
+ def create_people_table
7
+ silence_stream(STDOUT) do
8
+ ActiveRecord::Schema.define(:version => 1) do
9
+ create_table :legacy_people do |t|
10
+ t.string :encrypted_email
11
+ t.string :password
12
+ t.string :encrypted_credentials
13
+ t.string :salt
14
+ end
15
+ end
16
+ end
17
+ end
18
+
19
+ # The table needs to exist before defining the class
20
+ create_people_table
21
+
22
+ ActiveRecord::MissingAttributeError = ActiveModel::MissingAttributeError unless defined?(ActiveRecord::MissingAttributeError)
23
+
24
+ class LegacyPerson < ActiveRecord::Base
25
+ attr_encrypted :email, :key => 'a secret key'
26
+ attr_encrypted :credentials, :key => Proc.new { |user| Encryptor.encrypt(:value => user.salt, :key => 'some private key') }, :marshal => true
27
+
28
+ ActiveSupport::Deprecation.silenced = true
29
+ def after_initialize; end
30
+ ActiveSupport::Deprecation.silenced = false
31
+
32
+ after_initialize :initialize_salt_and_credentials
33
+
34
+ protected
35
+
36
+ def initialize_salt_and_credentials
37
+ self.salt ||= Digest::SHA256.hexdigest((Time.now.to_i * rand(5)).to_s)
38
+ self.credentials ||= { :username => 'example', :password => 'test' }
39
+ rescue ActiveRecord::MissingAttributeError
40
+ end
41
+ end
42
+
43
+ class LegacyPersonWithValidation < LegacyPerson
44
+ validates_presence_of :email
45
+ validates_uniqueness_of :encrypted_email
46
+ end
47
+
48
+ class LegacyActiveRecordTest < Minitest::Test
49
+
50
+ def setup
51
+ ActiveRecord::Base.connection.tables.each { |table| ActiveRecord::Base.connection.drop_table(table) }
52
+ create_people_table
53
+ end
54
+
55
+ def test_should_decrypt_with_correct_encoding
56
+ if defined?(Encoding)
57
+ @person = LegacyPerson.create :email => 'test@example.com'
58
+ assert_equal 'UTF-8', LegacyPerson.first.email.encoding.name
59
+ end
60
+ end
61
+
62
+ def test_should_encrypt_email
63
+ @person = LegacyPerson.create :email => 'test@example.com'
64
+ refute_nil @person.encrypted_email
65
+ refute_equal @person.email, @person.encrypted_email
66
+ assert_equal @person.email, LegacyPerson.first.email
67
+ end
68
+
69
+ def test_should_marshal_and_encrypt_credentials
70
+ @person = LegacyPerson.create
71
+ refute_nil @person.encrypted_credentials
72
+ refute_equal @person.credentials, @person.encrypted_credentials
73
+ assert_equal @person.credentials, LegacyPerson.first.credentials
74
+ end
75
+
76
+ def test_should_encode_by_default
77
+ assert LegacyPerson.attr_encrypted_options[:encode]
78
+ end
79
+
80
+ def test_should_validate_presence_of_email
81
+ @person = LegacyPersonWithValidation.new
82
+ assert !@person.valid?
83
+ assert !@person.errors[:email].empty? || @person.errors.on(:email)
84
+ end
85
+
86
+ def test_should_validate_uniqueness_of_email
87
+ @person = LegacyPersonWithValidation.new :email => 'test@example.com'
88
+ assert @person.save
89
+ @person2 = LegacyPersonWithValidation.new :email => @person.email
90
+ assert !@person2.valid?
91
+ assert !@person2.errors[:encrypted_email].empty? || @person2.errors.on(:encrypted_email)
92
+ end
93
+
94
+ end