powerhome-attr_encrypted 1.0.1

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.
Files changed (38) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +6 -0
  3. data/.travis.yml +67 -0
  4. data/CHANGELOG.md +98 -0
  5. data/Gemfile +3 -0
  6. data/MIT-LICENSE +20 -0
  7. data/README.md +465 -0
  8. data/Rakefile +25 -0
  9. data/attr_encrypted.gemspec +63 -0
  10. data/certs/saghaulor.pem +21 -0
  11. data/checksum/attr_encrypted-3.0.0.gem.sha256 +1 -0
  12. data/checksum/attr_encrypted-3.0.0.gem.sha512 +1 -0
  13. data/checksum/attr_encrypted-3.0.1.gem.sha256 +1 -0
  14. data/checksum/attr_encrypted-3.0.1.gem.sha512 +1 -0
  15. data/checksum/attr_encrypted-3.0.2.gem.sha256 +1 -0
  16. data/checksum/attr_encrypted-3.0.2.gem.sha512 +1 -0
  17. data/checksum/attr_encrypted-3.0.3.gem.sha256 +1 -0
  18. data/checksum/attr_encrypted-3.0.3.gem.sha512 +1 -0
  19. data/checksum/attr_encrypted-3.1.0.gem.sha256 +1 -0
  20. data/checksum/attr_encrypted-3.1.0.gem.sha512 +1 -0
  21. data/lib/attr_encrypted.rb +473 -0
  22. data/lib/attr_encrypted/adapters/active_record.rb +157 -0
  23. data/lib/attr_encrypted/adapters/data_mapper.rb +24 -0
  24. data/lib/attr_encrypted/adapters/sequel.rb +16 -0
  25. data/lib/attr_encrypted/version.rb +19 -0
  26. data/test/active_record_test.rb +365 -0
  27. data/test/attr_encrypted_test.rb +490 -0
  28. data/test/compatibility_test.rb +109 -0
  29. data/test/data_mapper_test.rb +59 -0
  30. data/test/legacy_active_record_test.rb +120 -0
  31. data/test/legacy_attr_encrypted_test.rb +300 -0
  32. data/test/legacy_compatibility_test.rb +95 -0
  33. data/test/legacy_data_mapper_test.rb +57 -0
  34. data/test/legacy_sequel_test.rb +54 -0
  35. data/test/run.sh +12 -0
  36. data/test/sequel_test.rb +55 -0
  37. data/test/test_helper.rb +61 -0
  38. metadata +294 -0
@@ -0,0 +1,490 @@
1
+ # frozen_string_literal: true
2
+
3
+ # encoding: UTF-8
4
+ require_relative 'test_helper'
5
+
6
+ class SillyEncryptor
7
+ def self.silly_encrypt(options)
8
+ (options[:value] + options[:some_arg]).reverse
9
+ end
10
+
11
+ def self.silly_decrypt(options)
12
+ options[:value].reverse.gsub(/#{options[:some_arg]}$/, '')
13
+ end
14
+ end
15
+
16
+ class User
17
+ extend AttrEncrypted
18
+ self.attr_encrypted_options[:key] = Proc.new { |user| SECRET_KEY } # default key
19
+ self.attr_encrypted_options[:mode] = :per_attribute_iv_and_salt
20
+
21
+ attr_encrypted :email, :without_encoding, :key => SECRET_KEY
22
+ attr_encrypted :password, :prefix => 'crypted_', :suffix => '_test'
23
+ attr_encrypted :ssn, :key => :secret_key, :attribute => 'ssn_encrypted'
24
+ attr_encrypted :credit_card, :encryptor => SillyEncryptor, :encrypt_method => :silly_encrypt, :decrypt_method => :silly_decrypt, :some_arg => 'test'
25
+ attr_encrypted :with_encoding, :key => SECRET_KEY, :encode => true
26
+ attr_encrypted :with_custom_encoding, :key => SECRET_KEY, :encode => 'm'
27
+ attr_encrypted :with_marshaling, :key => SECRET_KEY, :marshal => true
28
+ attr_encrypted :with_true_if, :key => SECRET_KEY, :if => true, mode: :per_attribute_iv_and_salt
29
+ attr_encrypted :with_false_if, :key => SECRET_KEY, :if => false, mode: :per_attribute_iv_and_salt
30
+ attr_encrypted :with_true_unless, :key => SECRET_KEY, :unless => true, mode: :per_attribute_iv_and_salt
31
+ attr_encrypted :with_false_unless, :key => SECRET_KEY, :unless => false, mode: :per_attribute_iv_and_salt
32
+ attr_encrypted :with_if_changed, :key => SECRET_KEY, :if => :should_encrypt
33
+ attr_encrypted :with_allow_empty_value, key: SECRET_KEY, allow_empty_value: true, marshal: true
34
+
35
+ attr_encryptor :aliased, :key => SECRET_KEY
36
+
37
+ attr_accessor :salt
38
+ attr_accessor :should_encrypt
39
+
40
+ def initialize(email: nil)
41
+ self.email = email
42
+ self.salt = Time.now.to_i.to_s
43
+ self.should_encrypt = true
44
+ end
45
+
46
+ private
47
+ def secret_key
48
+ SECRET_KEY
49
+ end
50
+ end
51
+
52
+ class Admin < User
53
+ attr_encrypted :testing
54
+ end
55
+
56
+ class SomeOtherClass
57
+ extend AttrEncrypted
58
+ def self.call(object)
59
+ object.class
60
+ end
61
+ end
62
+
63
+ class YetAnotherClass
64
+ extend AttrEncrypted
65
+ self.attr_encrypted_options[:encode_iv] = false
66
+
67
+ attr_encrypted :email, :key => SECRET_KEY
68
+ attr_encrypted :phone_number, :key => SECRET_KEY, mode: Proc.new { |thing| thing.mode }, encode_iv: Proc.new { |thing| thing.encode_iv }, encode_salt: Proc.new { |thing| thing.encode_salt }
69
+
70
+ def initialize(email: nil, encode_iv: 'm', encode_salt: 'm', mode: :per_attribute_iv_and_salt)
71
+ self.email = email
72
+ @encode_iv = encode_iv
73
+ @encode_salt = encode_salt
74
+ @mode = mode
75
+ end
76
+
77
+ attr_reader :encode_iv, :encode_salt, :mode
78
+ end
79
+
80
+ class AttrEncryptedTest < Minitest::Test
81
+ def setup
82
+ @iv = SecureRandom.random_bytes(12)
83
+ end
84
+
85
+ def test_should_store_email_in_encrypted_attributes
86
+ assert User.encrypted_attributes.include?(:email)
87
+ end
88
+
89
+ def test_should_not_store_salt_in_encrypted_attributes
90
+ refute User.encrypted_attributes.include?(:salt)
91
+ end
92
+
93
+ def test_attr_encrypted_should_return_true_for_email
94
+ assert User.attr_encrypted?('email')
95
+ end
96
+
97
+ def test_attr_encrypted_should_not_use_the_same_attribute_name_for_two_attributes_in_the_same_line
98
+ refute_equal User.encrypted_attributes[:email][:attribute], User.encrypted_attributes[:without_encoding][:attribute]
99
+ end
100
+
101
+ def test_attr_encrypted_should_return_false_for_salt
102
+ assert !User.attr_encrypted?('salt')
103
+ end
104
+
105
+ def test_should_generate_an_encrypted_attribute
106
+ assert User.new.respond_to?(:encrypted_email)
107
+ end
108
+
109
+ def test_should_generate_an_encrypted_attribute_with_a_prefix_and_suffix
110
+ assert User.new.respond_to?(:crypted_password_test)
111
+ end
112
+
113
+ def test_should_generate_an_encrypted_attribute_with_the_attribute_option
114
+ assert User.new.respond_to?(:ssn_encrypted)
115
+ end
116
+
117
+ def test_should_not_encrypt_nil_value
118
+ assert_nil User.encrypt_email(nil, iv: @iv)
119
+ end
120
+
121
+ def test_should_not_encrypt_empty_string_by_default
122
+ assert_equal '', User.encrypt_email('', iv: @iv)
123
+ end
124
+
125
+ def test_should_encrypt_email
126
+ refute_nil User.encrypt_email('test@example.com', iv: @iv)
127
+ refute_equal 'test@example.com', User.encrypt_email('test@example.com', iv: @iv)
128
+ end
129
+
130
+ def test_should_encrypt_email_when_modifying_the_attr_writer
131
+ @user = User.new
132
+ assert_nil @user.encrypted_email
133
+ @user.email = 'test@example.com'
134
+ refute_nil @user.encrypted_email
135
+ iv = @user.encrypted_email_iv.unpack('m').first
136
+ salt = @user.encrypted_email_salt[1..-1].unpack('m').first
137
+ assert_equal User.encrypt_email('test@example.com', iv: iv, salt: salt), @user.encrypted_email
138
+ end
139
+
140
+ def test_should_not_decrypt_nil_value
141
+ assert_nil User.decrypt_email(nil, iv: @iv)
142
+ end
143
+
144
+ def test_should_not_decrypt_empty_string
145
+ assert_equal '', User.decrypt_email('', iv: @iv)
146
+ end
147
+
148
+ def test_should_decrypt_email
149
+ encrypted_email = User.encrypt_email('test@example.com', iv: @iv)
150
+ refute_equal 'test@test.com', encrypted_email
151
+ assert_equal 'test@example.com', User.decrypt_email(encrypted_email, iv: @iv)
152
+ end
153
+
154
+ def test_should_decrypt_email_when_reading
155
+ @user = User.new
156
+ assert_nil @user.email
157
+ options = @user.encrypted_attributes[:email]
158
+ iv = @user.send(:generate_iv, options[:algorithm])
159
+ encoded_iv = [iv].pack(options[:encode_iv])
160
+ salt = SecureRandom.random_bytes
161
+ encoded_salt = @user.send(:prefix_and_encode_salt, salt, options[:encode_salt])
162
+ @user.encrypted_email = User.encrypt_email('test@example.com', iv: iv, salt: salt)
163
+ @user.encrypted_email_iv = encoded_iv
164
+ @user.encrypted_email_salt = encoded_salt
165
+ assert_equal 'test@example.com', @user.email
166
+ end
167
+
168
+ def test_should_encrypt_with_encoding
169
+ assert_equal User.encrypt_with_encoding('test', iv: @iv), [User.encrypt_without_encoding('test', iv: @iv)].pack('m')
170
+ end
171
+
172
+ def test_should_decrypt_with_encoding
173
+ encrypted = User.encrypt_with_encoding('test', iv: @iv)
174
+ assert_equal 'test', User.decrypt_with_encoding(encrypted, iv: @iv)
175
+ assert_equal User.decrypt_with_encoding(encrypted, iv: @iv), User.decrypt_without_encoding(encrypted.unpack('m').first, iv: @iv)
176
+ end
177
+
178
+ def test_should_encrypt_with_custom_encoding
179
+ assert_equal User.encrypt_with_encoding('test', iv: @iv), [User.encrypt_without_encoding('test', iv: @iv)].pack('m')
180
+ end
181
+
182
+ def test_should_decrypt_with_custom_encoding
183
+ encrypted = User.encrypt_with_encoding('test', iv: @iv)
184
+ assert_equal 'test', User.decrypt_with_encoding(encrypted, iv: @iv)
185
+ assert_equal User.decrypt_with_encoding(encrypted, iv: @iv), User.decrypt_without_encoding(encrypted.unpack('m').first, iv: @iv)
186
+ end
187
+
188
+ def test_should_encrypt_with_marshaling
189
+ @user = User.new
190
+ @user.with_marshaling = [1, 2, 3]
191
+ refute_nil @user.encrypted_with_marshaling
192
+ end
193
+
194
+ def test_should_use_custom_encryptor_and_crypt_method_names_and_arguments
195
+ assert_equal SillyEncryptor.silly_encrypt(:value => 'testing', :some_arg => 'test'), User.encrypt_credit_card('testing')
196
+ end
197
+
198
+ def test_should_evaluate_a_key_passed_as_a_symbol
199
+ @user = User.new
200
+ assert_nil @user.ssn_encrypted
201
+ @user.ssn = 'testing'
202
+ refute_nil @user.ssn_encrypted
203
+ encrypted = Encryptor.encrypt(:value => 'testing', :key => SECRET_KEY, :iv => @user.ssn_encrypted_iv.unpack("m").first, :salt => @user.ssn_encrypted_salt.unpack("m").first )
204
+ assert_equal encrypted, @user.ssn_encrypted
205
+ end
206
+
207
+ def test_should_evaluate_a_key_passed_as_a_proc
208
+ @user = User.new
209
+ assert_nil @user.crypted_password_test
210
+ @user.password = 'testing'
211
+ refute_nil @user.crypted_password_test
212
+ encrypted = Encryptor.encrypt(:value => 'testing', :key => SECRET_KEY, :iv => @user.crypted_password_test_iv.unpack("m").first, :salt => @user.crypted_password_test_salt.unpack("m").first)
213
+ assert_equal encrypted, @user.crypted_password_test
214
+ end
215
+
216
+ def test_should_use_options_found_in_the_attr_encrypted_options_attribute
217
+ @user = User.new
218
+ assert_nil @user.crypted_password_test
219
+ @user.password = 'testing'
220
+ refute_nil @user.crypted_password_test
221
+ encrypted = Encryptor.encrypt(:value => 'testing', :key => SECRET_KEY, :iv => @user.crypted_password_test_iv.unpack("m").first, :salt => @user.crypted_password_test_salt.unpack("m").first)
222
+ assert_equal encrypted, @user.crypted_password_test
223
+ end
224
+
225
+ def test_should_inherit_encrypted_attributes
226
+ assert_equal [User.encrypted_attributes.keys, :testing].flatten.collect { |key| key.to_s }.sort, Admin.encrypted_attributes.keys.collect { |key| key.to_s }.sort
227
+ end
228
+
229
+ def test_should_inherit_attr_encrypted_options
230
+ assert !User.attr_encrypted_options.empty?
231
+ assert_equal User.attr_encrypted_options, Admin.attr_encrypted_options
232
+ end
233
+
234
+ def test_should_not_inherit_unrelated_attributes
235
+ assert SomeOtherClass.attr_encrypted_options.empty?
236
+ assert SomeOtherClass.encrypted_attributes.empty?
237
+ end
238
+
239
+ def test_should_evaluate_a_symbol_option
240
+ assert_equal SomeOtherClass, SomeOtherClass.new.send(:evaluate_attr_encrypted_option, :class)
241
+ end
242
+
243
+ def test_should_evaluate_a_proc_option
244
+ assert_equal SomeOtherClass, SomeOtherClass.new.send(:evaluate_attr_encrypted_option, proc { |object| object.class })
245
+ end
246
+
247
+ def test_should_evaluate_a_lambda_option
248
+ assert_equal SomeOtherClass, SomeOtherClass.new.send(:evaluate_attr_encrypted_option, lambda { |object| object.class })
249
+ end
250
+
251
+ def test_should_evaluate_a_method_option
252
+ assert_equal SomeOtherClass, SomeOtherClass.new.send(:evaluate_attr_encrypted_option, SomeOtherClass.method(:call))
253
+ end
254
+
255
+ def test_should_return_a_string_option
256
+ class_string = 'SomeOtherClass'
257
+ assert_equal class_string, SomeOtherClass.new.send(:evaluate_attr_encrypted_option, class_string)
258
+ end
259
+
260
+ def test_should_encrypt_with_true_if
261
+ @user = User.new
262
+ assert_nil @user.encrypted_with_true_if
263
+ @user.with_true_if = 'testing'
264
+ refute_nil @user.encrypted_with_true_if
265
+ 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.unpack("m").first)
266
+ assert_equal encrypted, @user.encrypted_with_true_if
267
+ end
268
+
269
+ def test_should_not_encrypt_with_false_if
270
+ @user = User.new
271
+ assert_nil @user.encrypted_with_false_if
272
+ @user.with_false_if = 'testing'
273
+ refute_nil @user.encrypted_with_false_if
274
+ assert_equal 'testing', @user.encrypted_with_false_if
275
+ end
276
+
277
+ def test_should_encrypt_with_false_unless
278
+ @user = User.new
279
+ assert_nil @user.encrypted_with_false_unless
280
+ @user.with_false_unless = 'testing'
281
+ refute_nil @user.encrypted_with_false_unless
282
+ 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.unpack("m").first)
283
+ assert_equal encrypted, @user.encrypted_with_false_unless
284
+ end
285
+
286
+ def test_should_not_encrypt_with_true_unless
287
+ @user = User.new
288
+ assert_nil @user.encrypted_with_true_unless
289
+ @user.with_true_unless = 'testing'
290
+ refute_nil @user.encrypted_with_true_unless
291
+ assert_equal 'testing', @user.encrypted_with_true_unless
292
+ end
293
+
294
+ def test_should_encrypt_empty_with_truthy_allow_empty_value_option
295
+ @user = User.new
296
+ assert_nil @user.encrypted_with_allow_empty_value
297
+ @user.with_allow_empty_value = ''
298
+ refute_nil @user.encrypted_with_allow_empty_value
299
+ assert_equal '', @user.with_allow_empty_value
300
+ @user = User.new
301
+ @user.with_allow_empty_value = nil
302
+ refute_nil @user.encrypted_with_allow_empty_value
303
+ assert_nil @user.with_allow_empty_value
304
+ end
305
+
306
+ def test_should_work_with_aliased_attr_encryptor
307
+ assert User.encrypted_attributes.include?(:aliased)
308
+ end
309
+
310
+ def test_should_always_reset_options
311
+ @user = User.new
312
+ @user.with_if_changed = "encrypt_stuff"
313
+
314
+ @user = User.new
315
+ @user.should_encrypt = false
316
+ @user.with_if_changed = "not_encrypted_stuff"
317
+ assert_equal "not_encrypted_stuff", @user.with_if_changed
318
+ assert_equal "not_encrypted_stuff", @user.encrypted_with_if_changed
319
+ end
320
+
321
+ def test_should_cast_values_as_strings_before_encrypting
322
+ string_encrypted_email = User.encrypt_email('3', iv: @iv)
323
+ assert_equal string_encrypted_email, User.encrypt_email(3, iv: @iv)
324
+ assert_equal '3', User.decrypt_email(string_encrypted_email, iv: @iv)
325
+ end
326
+
327
+ def test_should_create_query_accessor
328
+ @user = User.new
329
+ assert !@user.email?
330
+ @user.email = ''
331
+ assert !@user.email?
332
+ @user.email = 'test@example.com'
333
+ assert @user.email?
334
+ end
335
+
336
+ def test_should_vary_iv_per_attribute
337
+ @user = User.new
338
+ @user.email = 'email@example.com'
339
+ @user.password = 'p455w0rd'
340
+ refute_equal @user.encrypted_email_iv, @user.crypted_password_test_iv
341
+ end
342
+
343
+ def test_should_generate_iv_per_attribute_by_default
344
+ thing = YetAnotherClass.new(email: 'thing@thing.com')
345
+ refute_nil thing.encrypted_email_iv
346
+ end
347
+
348
+ def test_should_vary_iv_per_instance
349
+ @user1 = User.new
350
+ @user1.email = 'email@example.com'
351
+ @user2 = User.new
352
+ @user2.email = 'email@example.com'
353
+ refute_equal @user1.encrypted_email_iv, @user2.encrypted_email_iv
354
+ refute_equal @user1.encrypted_email, @user2.encrypted_email
355
+ end
356
+
357
+ def test_should_vary_salt_per_attribute
358
+ @user = User.new
359
+ @user.email = 'email@example.com'
360
+ @user.password = 'p455w0rd'
361
+ refute_equal @user.encrypted_email_salt, @user.crypted_password_test_salt
362
+ end
363
+
364
+ def test_should_vary_salt_per_instance
365
+ @user1 = User.new
366
+ @user1.email = 'email@example.com'
367
+ @user2 = User.new
368
+ @user2.email = 'email@example.com'
369
+ refute_equal @user1.encrypted_email_salt, @user2.encrypted_email_salt
370
+ end
371
+
372
+ def test_should_not_generate_salt_per_attribute_by_default
373
+ thing = YetAnotherClass.new(email: 'thing@thing.com')
374
+ assert_nil thing.encrypted_email_salt
375
+ end
376
+
377
+ def test_should_decrypt_second_record
378
+ @user1 = User.new
379
+ @user1.email = 'test@example.com'
380
+
381
+ @user2 = User.new
382
+ @user2.email = 'test@example.com'
383
+
384
+ assert_equal 'test@example.com', @user1.decrypt(:email, @user1.encrypted_email)
385
+ end
386
+
387
+ def test_should_specify_the_default_algorithm
388
+ assert YetAnotherClass.encrypted_attributes[:email][:algorithm]
389
+ assert_equal YetAnotherClass.encrypted_attributes[:email][:algorithm], 'aes-256-gcm'
390
+ end
391
+
392
+ def test_should_not_encode_iv_when_encode_iv_is_false
393
+ email = 'thing@thing.com'
394
+ thing = YetAnotherClass.new(email: email)
395
+ refute thing.encrypted_email_iv =~ base64_encoding_regex
396
+ assert_equal thing.email, email
397
+ end
398
+
399
+ def test_should_base64_encode_iv_by_default
400
+ phone_number = '555-555-5555'
401
+ thing = YetAnotherClass.new
402
+ thing.phone_number = phone_number
403
+ assert thing.encrypted_phone_number_iv =~ base64_encoding_regex
404
+ assert_equal thing.phone_number, phone_number
405
+ end
406
+
407
+ def test_should_generate_unique_iv_for_every_encrypt_operation
408
+ user = User.new
409
+ user.email = 'initial_value@test.com'
410
+ original_iv = user.encrypted_email_iv
411
+ user.email = 'revised_value@test.com'
412
+ refute_equal original_iv, user.encrypted_email_iv
413
+ end
414
+
415
+ def test_should_not_generate_iv_for_attribute_when_if_option_is_false
416
+ user = User.new
417
+ user.with_false_if = 'derp'
418
+ assert_nil user.encrypted_with_false_if_iv
419
+ end
420
+
421
+ def test_should_generate_iv_for_attribute_when_if_option_is_true
422
+ user = User.new
423
+ user.with_true_if = 'derp'
424
+ refute_nil user.encrypted_with_true_if_iv
425
+
426
+ user.with_true_if = Object.new
427
+ refute_nil user.encrypted_with_true_if_iv
428
+ end
429
+
430
+ def test_should_not_generate_salt_for_attribute_when_if_option_is_false
431
+ user = User.new
432
+ user.with_false_if = 'derp'
433
+ assert_nil user.encrypted_with_false_if_salt
434
+ end
435
+
436
+ def test_should_generate_salt_for_attribute_when_if_option_is_true
437
+ user = User.new
438
+ user.with_true_if = 'derp'
439
+ refute_nil user.encrypted_with_true_if_salt
440
+ end
441
+
442
+ def test_should_generate_iv_for_attribute_when_unless_option_is_false
443
+ user = User.new
444
+ user.with_false_unless = 'derp'
445
+ refute_nil user.encrypted_with_false_unless_iv
446
+ end
447
+
448
+ def test_should_not_generate_iv_for_attribute_when_unless_option_is_true
449
+ user = User.new
450
+ user.with_true_unless = 'derp'
451
+ assert_nil user.encrypted_with_true_unless_iv
452
+ end
453
+
454
+ def test_should_generate_salt_for_attribute_when_unless_option_is_false
455
+ user = User.new
456
+ user.with_false_unless = 'derp'
457
+ refute_nil user.encrypted_with_false_unless_salt
458
+ end
459
+
460
+ def test_should_not_generate_salt_for_attribute_when_unless_option_is_true
461
+ user = User.new
462
+ user.with_true_unless = 'derp'
463
+ assert_nil user.encrypted_with_true_unless_salt
464
+ end
465
+
466
+ def test_should_not_by_default_generate_iv_when_attribute_is_empty
467
+ user = User.new
468
+ user.with_true_if = nil
469
+ assert_nil user.encrypted_with_true_if_iv
470
+ end
471
+
472
+ def test_encrypted_attributes_state_is_not_shared
473
+ user = User.new
474
+ user.ssn = '123456789'
475
+
476
+ another_user = User.new
477
+
478
+ assert_equal :encrypting, user.encrypted_attributes[:ssn][:operation]
479
+ assert_nil another_user.encrypted_attributes[:ssn][:operation]
480
+ end
481
+
482
+ def test_should_not_by_default_generate_key_when_attribute_is_empty
483
+ user = User.new
484
+ calls = 0
485
+ user.stub(:secret_key, lambda { calls += 1; SECRET_KEY }) do
486
+ user.ssn
487
+ end
488
+ assert_equal 0, calls
489
+ end
490
+ end