symmetric-encryption 3.7.2 → 3.8.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,3 +1,3 @@
1
1
  module SymmetricEncryption #:nodoc
2
- VERSION = "3.7.2"
2
+ VERSION = '3.8.0'
3
3
  end
@@ -100,9 +100,9 @@ module SymmetricEncryption
100
100
  # end
101
101
  def self.open(filename_or_stream, options={}, &block)
102
102
  raise(ArgumentError, 'options must be a hash') unless options.respond_to?(:each_pair)
103
- mode = options.fetch(:mode, 'wb')
103
+ mode = options.fetch(:mode, 'wb')
104
104
  compress = options.fetch(:compress, false)
105
- ios = filename_or_stream.is_a?(String) ? ::File.open(filename_or_stream, mode) : filename_or_stream
105
+ ios = filename_or_stream.is_a?(String) ? ::File.open(filename_or_stream, mode) : filename_or_stream
106
106
 
107
107
  begin
108
108
  file = self.new(ios, options)
@@ -114,11 +114,11 @@ module SymmetricEncryption
114
114
  end
115
115
 
116
116
  # Encrypt data before writing to the supplied stream
117
- def initialize(ios,options={})
118
- @ios = ios
119
- header = options.fetch(:header, true)
120
- random_key = options.fetch(:random_key, true)
121
- random_iv = options.fetch(:random_iv, random_key)
117
+ def initialize(ios, options={})
118
+ @ios = ios
119
+ header = options.fetch(:header, true)
120
+ random_key = options.fetch(:random_key, true)
121
+ random_iv = options.fetch(:random_iv, random_key)
122
122
  raise(ArgumentError, 'When :random_key is true, :random_iv must also be true') if random_key && !random_iv
123
123
  # Compress is only used at this point for setting the flag in the header
124
124
  compress = options.fetch(:compress, false)
@@ -137,21 +137,21 @@ module SymmetricEncryption
137
137
  @stream_cipher.encrypt
138
138
 
139
139
  key = random_key ? @stream_cipher.random_key : cipher.send(:key)
140
- iv = random_iv ? @stream_cipher.random_iv : cipher.send(:iv)
140
+ iv = random_iv ? @stream_cipher.random_iv : cipher.send(:iv)
141
141
 
142
142
  @stream_cipher.key = key
143
- @stream_cipher.iv = iv if iv
143
+ @stream_cipher.iv = iv if iv
144
144
 
145
145
  # Write the Encryption header including the random iv, key, and cipher
146
146
  if header
147
147
  @ios.write(Cipher.build_header(
148
148
  cipher.version,
149
149
  compress,
150
- random_iv ? iv : nil,
150
+ random_iv ? iv : nil,
151
151
  random_key ? key : nil,
152
152
  cipher_name))
153
153
  end
154
- @size = 0
154
+ @size = 0
155
155
  @closed = false
156
156
  end
157
157
 
@@ -182,8 +182,8 @@ module SymmetricEncryption
182
182
  def write(data)
183
183
  return unless data
184
184
 
185
- bytes = data.to_s
186
- @size += bytes.size
185
+ bytes = data.to_s
186
+ @size += bytes.size
187
187
  partial = @stream_cipher.update(bytes)
188
188
  @ios.write(partial) if partial.length > 0
189
189
  data.length
@@ -1,9 +1,10 @@
1
1
  require_relative 'test_helper'
2
2
 
3
- ActiveRecord::Base.logger = SemanticLogger[ActiveRecord]
3
+ ActiveRecord::Base.logger = SemanticLogger[ActiveRecord]
4
4
  ActiveRecord::Base.configurations = YAML::load(ERB.new(IO.read('test/config/database.yml')).result)
5
5
  ActiveRecord::Base.establish_connection(:test)
6
6
 
7
+ #@formatter:off
7
8
  ActiveRecord::Schema.define version: 0 do
8
9
  create_table :users, force: true do |t|
9
10
  t.string :encrypted_bank_account_number
@@ -27,6 +28,11 @@ ActiveRecord::Schema.define version: 0 do
27
28
  t.string :encrypted_text
28
29
  t.string :encrypted_number
29
30
  end
31
+
32
+ create_table :unique_users, force: true do |t|
33
+ t.string :encrypted_email
34
+ t.string :encrypted_username
35
+ end
30
36
  end
31
37
 
32
38
  class User < ActiveRecord::Base
@@ -52,13 +58,27 @@ class User < ActiveRecord::Base
52
58
  attr_encrypted :text, type: :string
53
59
  attr_encrypted :number, type: :integer
54
60
 
55
- validates :text, format: { with: /\A[a-zA-Z ]+\z/, message: "only allows letters" }, presence: true
61
+ validates :text, format: { with: /\A[a-zA-Z ]+\z/, message: 'only allows letters' }, presence: true
56
62
  validates :number, presence: true
57
63
  end
58
64
 
65
+ class UniqueUser < ActiveRecord::Base
66
+ attr_encrypted :email
67
+ attr_encrypted :username
68
+
69
+ validates_uniqueness_of :encrypted_email, allow_blank: true, if: :encrypted_email_changed?
70
+ validates_uniqueness_of :encrypted_username, allow_blank: true, if: :encrypted_username_changed?
71
+
72
+ validates :username,
73
+ length: {in: 3..20},
74
+ format: {with: /\A[\w\d\-[[:alnum:]]]+\z/},
75
+ allow_blank: true
76
+ end
77
+ #@formatter:on
78
+
59
79
  # Initialize the database connection
60
80
  config_file = File.join(File.dirname(__FILE__), 'config', 'database.yml')
61
- raise "database config not found. Create a config file at: test/config/database.yml" unless File.exists? config_file
81
+ raise 'database config not found. Create a config file at: test/config/database.yml' unless File.exists? config_file
62
82
 
63
83
  cfg = YAML.load(ERB.new(File.new(config_file).read).result)['test']
64
84
  raise("Environment 'test' not defined in test/config/database.yml") unless cfg
@@ -69,7 +89,7 @@ User.establish_connection(cfg)
69
89
  # Unit Test for attr_encrypted extensions in ActiveRecord
70
90
  #
71
91
  class ActiveRecordTest < Minitest::Test
72
- context 'ActiveRecord' do
92
+ describe 'ActiveRecord' do
73
93
  INTEGER_VALUE = 12
74
94
  FLOAT_VALUE = 88.12345
75
95
  DECIMAL_VALUE = BigDecimal.new("22.51")
@@ -77,19 +97,19 @@ class ActiveRecordTest < Minitest::Test
77
97
  TIME_VALUE = Time.new(2013, 01, 01, 22, 30, 00, "-04:00")
78
98
  DATE_VALUE = Date.new(1927, 04, 02)
79
99
 
80
- setup do
81
- @bank_account_number = "1234567890"
82
- @bank_account_number_encrypted = "QEVuQwIAL94ArJeFlJrZp6SYsvoOGA=="
100
+ before do
101
+ @bank_account_number = '1234567890'
102
+ @bank_account_number_encrypted = 'QEVuQwIAL94ArJeFlJrZp6SYsvoOGA=='
83
103
 
84
- @social_security_number = "987654321"
85
- @social_security_number_encrypted = "QEVuQwIAS+8X1NRrqdfEIQyFHVPuVA=="
104
+ @social_security_number = '987654321'
105
+ @social_security_number_encrypted = 'QEVuQwIAS+8X1NRrqdfEIQyFHVPuVA=='
86
106
 
87
- @string = "A string containing some data to be encrypted with a random initialization vector"
88
- @long_string = "A string containing some data to be encrypted with a random initialization vector and compressed since it takes up so much space in plain text form"
107
+ @string = 'A string containing some data to be encrypted with a random initialization vector'
108
+ @long_string = 'A string containing some data to be encrypted with a random initialization vector and compressed since it takes up so much space in plain text form'
89
109
 
90
110
  @name = 'Joe Bloggs'
91
111
 
92
- @h = { a: 'A', b: 'B' }
112
+ @h = {a: 'A', b: 'B'}
93
113
 
94
114
  @user = User.new(
95
115
  # Encrypted Attribute
@@ -113,7 +133,7 @@ class ActiveRecordTest < Minitest::Test
113
133
  )
114
134
  end
115
135
 
116
- should 'have encrypted methods' do
136
+ it 'have encrypted methods' do
117
137
  assert_equal true, @user.respond_to?(:encrypted_bank_account_number)
118
138
  assert_equal true, @user.respond_to?(:bank_account_number)
119
139
  assert_equal true, @user.respond_to?(:encrypted_social_security_number)
@@ -121,19 +141,21 @@ class ActiveRecordTest < Minitest::Test
121
141
  assert_equal true, @user.respond_to?(:data_yaml)
122
142
  assert_equal true, @user.respond_to?(:data_json)
123
143
  assert_equal false, @user.respond_to?(:encrypted_name)
144
+ assert_equal true, @user.respond_to?(:encrypted_bank_account_number_changed?)
145
+ assert_equal true, @user.respond_to?(:bank_account_number_changed?)
124
146
  end
125
147
 
126
- should 'have unencrypted values' do
148
+ it 'have unencrypted values' do
127
149
  assert_equal @bank_account_number, @user.bank_account_number
128
150
  assert_equal @social_security_number, @user.social_security_number
129
151
  end
130
152
 
131
- should 'have encrypted values' do
153
+ it 'have encrypted values' do
132
154
  assert_equal @bank_account_number_encrypted, @user.encrypted_bank_account_number
133
155
  assert_equal @social_security_number_encrypted, @user.encrypted_social_security_number
134
156
  end
135
157
 
136
- should 'support same iv' do
158
+ it 'support same iv' do
137
159
  @user.social_security_number = @social_security_number
138
160
  assert first_value = @user.social_security_number
139
161
  # Assign the same value
@@ -141,7 +163,7 @@ class ActiveRecordTest < Minitest::Test
141
163
  assert_equal first_value, @user.social_security_number
142
164
  end
143
165
 
144
- should 'support a random iv' do
166
+ it 'support a random iv' do
145
167
  @user.string = @string
146
168
  assert first_value = @user.encrypted_string
147
169
  # Assign the same value
@@ -149,21 +171,21 @@ class ActiveRecordTest < Minitest::Test
149
171
  assert_equal true, first_value != @user.encrypted_string
150
172
  end
151
173
 
152
- should 'support a random iv and compress' do
153
- @user.string = @long_string
174
+ it 'support a random iv and compress' do
175
+ @user.string = @long_string
154
176
  @user.long_string = @long_string
155
177
 
156
178
  assert_equal true, (@user.encrypted_long_string.length.to_f / @user.encrypted_string.length) < 0.8
157
179
  end
158
180
 
159
- should 'encrypt' do
160
- user = User.new
181
+ it 'encrypt' do
182
+ user = User.new
161
183
  user.bank_account_number = @bank_account_number
162
184
  assert_equal @bank_account_number, user.bank_account_number
163
185
  assert_equal @bank_account_number_encrypted, user.encrypted_bank_account_number
164
186
  end
165
187
 
166
- should 'allow lookups using unencrypted or encrypted column name' do
188
+ it 'allow lookups using unencrypted or encrypted column name' do
167
189
  if ActiveRecord::VERSION::STRING.to_f < 4.1
168
190
  @user.save!
169
191
 
@@ -175,19 +197,19 @@ class ActiveRecordTest < Minitest::Test
175
197
  end
176
198
  end
177
199
 
178
- should 'all paths should lead to the same result' do
200
+ it 'all paths it lead to the same result' do
179
201
  assert_equal @bank_account_number_encrypted, (@user.encrypted_social_security_number = @bank_account_number_encrypted)
180
202
  assert_equal @bank_account_number, @user.social_security_number
181
203
  assert_equal @bank_account_number_encrypted, @user.encrypted_social_security_number
182
204
  end
183
205
 
184
- should 'all paths should lead to the same result 2' do
206
+ it 'all paths it lead to the same result 2' do
185
207
  assert_equal @bank_account_number, (@user.social_security_number = @bank_account_number)
186
208
  assert_equal @bank_account_number_encrypted, @user.encrypted_social_security_number
187
209
  assert_equal @bank_account_number, @user.social_security_number
188
210
  end
189
211
 
190
- should 'all paths should lead to the same result, check uninitialized' do
212
+ it 'all paths it lead to the same result, check uninitialized' do
191
213
  user = User.new
192
214
  assert_equal nil, user.social_security_number
193
215
  assert_equal @bank_account_number, (user.social_security_number = @bank_account_number)
@@ -199,7 +221,7 @@ class ActiveRecordTest < Minitest::Test
199
221
  assert_equal nil, user.encrypted_social_security_number
200
222
  end
201
223
 
202
- should 'allow unencrypted values to be passed to the constructor' do
224
+ it 'allow unencrypted values to be passed to the constructor' do
203
225
  user = User.new(bank_account_number: @bank_account_number, social_security_number: @social_security_number)
204
226
  assert_equal @bank_account_number, user.bank_account_number
205
227
  assert_equal @social_security_number, user.social_security_number
@@ -207,31 +229,31 @@ class ActiveRecordTest < Minitest::Test
207
229
  assert_equal @social_security_number_encrypted, user.encrypted_social_security_number
208
230
  end
209
231
 
210
- should 'return encrypted attributes for the class' do
232
+ it 'return encrypted attributes for the class' do
211
233
  expect = {social_security_number: :encrypted_social_security_number, bank_account_number: :encrypted_bank_account_number}
212
234
  result = User.encrypted_attributes
213
- expect.each_pair {|k,v| assert_equal expect[k], result[k]}
235
+ expect.each_pair { |k, v| assert_equal expect[k], result[k] }
214
236
  end
215
237
 
216
- should 'return encrypted keys for the class' do
238
+ it 'return encrypted keys for the class' do
217
239
  expect = [:social_security_number, :bank_account_number]
218
240
  result = User.encrypted_keys
219
- expect.each {|val| assert_equal true, result.include?(val)}
241
+ expect.each { |val| assert_equal true, result.include?(val) }
220
242
 
221
243
  # Also check encrypted_attribute?
222
- expect.each {|val| assert_equal true, User.encrypted_attribute?(val)}
244
+ expect.each { |val| assert_equal true, User.encrypted_attribute?(val) }
223
245
  end
224
246
 
225
- should 'return encrypted columns for the class' do
247
+ it 'return encrypted columns for the class' do
226
248
  expect = [:encrypted_social_security_number, :encrypted_bank_account_number]
227
249
  result = User.encrypted_columns
228
- expect.each {|val| assert_equal true, result.include?(val)}
250
+ expect.each { |val| assert_equal true, result.include?(val) }
229
251
 
230
252
  # Also check encrypted_column?
231
- expect.each {|val| assert_equal true, User.encrypted_column?(val)}
253
+ expect.each { |val| assert_equal true, User.encrypted_column?(val) }
232
254
  end
233
255
 
234
- should 'validate encrypted data' do
256
+ it 'validate encrypted data' do
235
257
  assert_equal true, @user.valid?
236
258
  @user.encrypted_bank_account_number = '123'
237
259
  assert_equal false, @user.valid?
@@ -242,7 +264,7 @@ class ActiveRecordTest < Minitest::Test
242
264
  assert_equal true, @user.valid?
243
265
  end
244
266
 
245
- should 'validate un-encrypted string data' do
267
+ it 'validate un-encrypted string data' do
246
268
  assert_equal true, @user.valid?
247
269
  @user.text = '123'
248
270
  assert_equal false, @user.valid?
@@ -255,7 +277,7 @@ class ActiveRecordTest < Minitest::Test
255
277
  assert_equal ["only allows letters", "can't be blank"], @user.errors[:text]
256
278
  end
257
279
 
258
- should 'validate un-encrypted integer data with coercion' do
280
+ it 'validate un-encrypted integer data with coercion' do
259
281
  assert_equal true, @user.valid?
260
282
  @user.number = '123'
261
283
  assert_equal true, @user.valid?
@@ -272,22 +294,22 @@ class ActiveRecordTest < Minitest::Test
272
294
  assert_equal ["can't be blank"], @user.errors[:number]
273
295
  end
274
296
 
275
- context "with saved user" do
276
- setup do
297
+ describe "with saved user" do
298
+ before do
277
299
  @user.save!
278
300
  end
279
301
 
280
- teardown do
302
+ after do
281
303
  @user.destroy
282
304
  end
283
305
 
284
- should "return correct data type before save" do
306
+ it "return correct data type before save" do
285
307
  u = User.new(integer_value: "5")
286
308
  assert_equal 5, u.integer_value
287
309
  assert u.integer_value.kind_of?(Integer)
288
310
  end
289
311
 
290
- should "handle gsub! for non-encrypted_field" do
312
+ it "handle gsub! for non-encrypted_field" do
291
313
  @user.name.gsub!('a', 'v')
292
314
  new_name = @name.gsub('a', 'v')
293
315
  assert_equal new_name, @user.name
@@ -295,15 +317,15 @@ class ActiveRecordTest < Minitest::Test
295
317
  assert_equal new_name, @user.name
296
318
  end
297
319
 
298
- should "prevent gsub! on non-encrypted value of encrypted_field" do
320
+ it "prevent gsub! on non-encrypted value of encrypted_field" do
299
321
  # can't modify frozen String
300
322
  assert_raises RuntimeError do
301
323
  @user.bank_account_number.gsub!('5', '4')
302
324
  end
303
325
  end
304
326
 
305
- should "revert changes on reload" do
306
- new_bank_account_number = '444444444'
327
+ it "revert changes on reload" do
328
+ new_bank_account_number = '444444444'
307
329
  @user.bank_account_number = new_bank_account_number
308
330
  assert_equal new_bank_account_number, @user.bank_account_number
309
331
 
@@ -313,9 +335,9 @@ class ActiveRecordTest < Minitest::Test
313
335
  assert_equal @bank_account_number, @user.bank_account_number
314
336
  end
315
337
 
316
- should "revert changes to encrypted field on reload" do
317
- new_bank_account_number = '111111111'
318
- new_encrypted_bank_account_number = SymmetricEncryption.encrypt(new_bank_account_number)
338
+ it "revert changes to encrypted field on reload" do
339
+ new_bank_account_number = '111111111'
340
+ new_encrypted_bank_account_number = SymmetricEncryption.encrypt(new_bank_account_number)
319
341
  @user.encrypted_bank_account_number = new_encrypted_bank_account_number
320
342
  assert_equal new_encrypted_bank_account_number, @user.encrypted_bank_account_number
321
343
  assert_equal new_bank_account_number, @user.bank_account_number
@@ -326,12 +348,13 @@ class ActiveRecordTest < Minitest::Test
326
348
  assert_equal @bank_account_number, @user.bank_account_number
327
349
  end
328
350
 
329
- context "data types" do
330
- setup do
351
+ describe "data types" do
352
+ before do
331
353
  @user_clone = User.find(@user.id)
332
354
  end
333
355
 
334
356
  [
357
+ #@formatter:off
335
358
  { attribute: :integer_value, klass: Integer, value: INTEGER_VALUE, new_value: 98 },
336
359
  { attribute: :float_value, klass: Float, value: FLOAT_VALUE, new_value: 45.4321 },
337
360
  { attribute: :decimal_value, klass: BigDecimal, value: DECIMAL_VALUE, new_value: BigDecimal.new("99.95"), coercible: "22.51"},
@@ -340,9 +363,10 @@ class ActiveRecordTest < Minitest::Test
340
363
  { attribute: :date_value, klass: Date, value: DATE_VALUE, new_value: Date.new(2027, 04, 02), coercible: DATE_VALUE.to_time },
341
364
  { attribute: :true_value, klass: TrueClass, value: true, new_value: false },
342
365
  { attribute: :false_value, klass: FalseClass, value: false, new_value: true },
366
+ #@formatter:on
343
367
  ].each do |value_test|
344
- context "#{value_test[:klass]} values" do
345
- setup do
368
+ describe "#{value_test[:klass]} values" do
369
+ before do
346
370
  @attribute = value_test[:attribute]
347
371
  @klass = value_test[:klass]
348
372
  @value = value_test[:value]
@@ -350,18 +374,18 @@ class ActiveRecordTest < Minitest::Test
350
374
  @new_value = value_test[:new_value]
351
375
  end
352
376
 
353
- should "return correct data type" do
377
+ it "return correct data type" do
354
378
  assert_equal @value, @user_clone.send(@attribute)
355
379
  assert @user.clone.send(@attribute).kind_of?(@klass)
356
380
  end
357
381
 
358
- should "coerce data type before save" do
382
+ it "coerce data type before save" do
359
383
  u = User.new(@attribute => @value)
360
384
  assert_equal @value, u.send(@attribute)
361
385
  assert u.send(@attribute).kind_of?(@klass), "Value supposed to be coerced into #{@klass}, but is #{u.send(@attribute).class.name}"
362
386
  end
363
387
 
364
- should "permit replacing value with nil" do
388
+ it "permit replacing value with nil" do
365
389
  @user_clone.send("#{@attribute}=".to_sym, nil)
366
390
  @user_clone.save!
367
391
 
@@ -370,7 +394,7 @@ class ActiveRecordTest < Minitest::Test
370
394
  assert_nil @user.send("encrypted_#{@attribute}".to_sym)
371
395
  end
372
396
 
373
- should "permit replacing value with an empty string" do
397
+ it "permit replacing value with an empty string" do
374
398
  @user_clone.send("#{@attribute}=".to_sym, '')
375
399
  @user_clone.save!
376
400
 
@@ -379,7 +403,7 @@ class ActiveRecordTest < Minitest::Test
379
403
  assert_nil @user.send("encrypted_#{@attribute}".to_sym)
380
404
  end
381
405
 
382
- should "permit replacing value with a blank string" do
406
+ it "permit replacing value with a blank string" do
383
407
  @user_clone.send("#{@attribute}=".to_sym, ' ')
384
408
  @user_clone.save!
385
409
 
@@ -388,7 +412,7 @@ class ActiveRecordTest < Minitest::Test
388
412
  assert_nil @user.send("encrypted_#{@attribute}".to_sym)
389
413
  end
390
414
 
391
- should "permit replacing value" do
415
+ it "permit replacing value" do
392
416
  @user_clone.send("#{@attribute}=".to_sym, @new_value)
393
417
  @user_clone.save!
394
418
 
@@ -398,8 +422,8 @@ class ActiveRecordTest < Minitest::Test
398
422
  end
399
423
  end
400
424
 
401
- context "JSON Serialization" do
402
- setup do
425
+ describe "JSON Serialization" do
426
+ before do
403
427
  # JSON Does not support symbols, so they will come back as strings
404
428
  # Convert symbols to string in the test
405
429
  @h.keys.each do |k|
@@ -408,18 +432,18 @@ class ActiveRecordTest < Minitest::Test
408
432
  end
409
433
  end
410
434
 
411
- should "return correct data type" do
435
+ it "return correct data type" do
412
436
  assert_equal @h, @user_clone.data_json
413
437
  assert @user.clone.data_json.kind_of?(Hash)
414
438
  end
415
439
 
416
- should "not coerce data type (leaves as hash) before save" do
440
+ it "not coerce data type (leaves as hash) before save" do
417
441
  u = User.new(data_json: @h)
418
442
  assert_equal @h, u.data_json
419
443
  assert u.data_json.kind_of?(Hash)
420
444
  end
421
445
 
422
- should "permit replacing value with nil" do
446
+ it "permit replacing value with nil" do
423
447
  @user_clone.data_json = nil
424
448
  @user_clone.save!
425
449
 
@@ -428,9 +452,9 @@ class ActiveRecordTest < Minitest::Test
428
452
  assert_nil @user.encrypted_data_json
429
453
  end
430
454
 
431
- should "permit replacing value" do
432
- new_value = @h.clone
433
- new_value['c'] = 'C'
455
+ it "permit replacing value" do
456
+ new_value = @h.clone
457
+ new_value['c'] = 'C'
434
458
  @user_clone.data_json = new_value
435
459
  @user_clone.save!
436
460
 
@@ -439,19 +463,19 @@ class ActiveRecordTest < Minitest::Test
439
463
  end
440
464
  end
441
465
 
442
- context "YAML Serialization" do
443
- should "return correct data type" do
466
+ describe "YAML Serialization" do
467
+ it "return correct data type" do
444
468
  assert_equal @h, @user_clone.data_yaml
445
469
  assert @user.clone.data_yaml.kind_of?(Hash)
446
470
  end
447
471
 
448
- should "not coerce data type (leaves as hash) before save" do
472
+ it "not coerce data type (leaves as hash) before save" do
449
473
  u = User.new(data_yaml: @h)
450
474
  assert_equal @h, u.data_yaml
451
475
  assert u.data_yaml.kind_of?(Hash)
452
476
  end
453
477
 
454
- should "permit replacing value with nil" do
478
+ it "permit replacing value with nil" do
455
479
  @user_clone.data_yaml = nil
456
480
  @user_clone.save!
457
481
 
@@ -460,9 +484,9 @@ class ActiveRecordTest < Minitest::Test
460
484
  assert_nil @user.encrypted_data_yaml
461
485
  end
462
486
 
463
- should "permit replacing value" do
464
- new_value = @h.clone
465
- new_value[:c] = 'C'
487
+ it "permit replacing value" do
488
+ new_value = @h.clone
489
+ new_value[:c] = 'C'
466
490
  @user_clone.data_yaml = new_value
467
491
  @user_clone.save!
468
492
 
@@ -470,8 +494,37 @@ class ActiveRecordTest < Minitest::Test
470
494
  assert_equal new_value, @user.data_yaml
471
495
  end
472
496
  end
497
+ end
473
498
 
499
+ describe 'changed?' do
500
+ it 'return false if it was not changed' do
501
+ assert_equal false, @user.encrypted_bank_account_number_changed?
502
+ assert_equal false, @user.bank_account_number_changed?
503
+ end
504
+
505
+ it 'return true if it was changed' do
506
+ @user.bank_account_number = '15424623'
507
+ assert_equal true, @user.encrypted_bank_account_number_changed?
508
+ assert_equal true, @user.bank_account_number_changed?
509
+ end
510
+ end
511
+ end
512
+
513
+ describe 'uniqueness' do
514
+ before do
515
+ UniqueUser.destroy_all
516
+ @email = 'whatever@not-unique.com'
517
+ @username = 'gibby007'
518
+ @user = UniqueUser.create!(email: @email)
519
+ @email_user = UniqueUser.create!(username: @username)
520
+ end
521
+
522
+ it 'does not allow duplicate values' do
523
+ duplicate = UniqueUser.new(email: @email)
524
+ assert_equal false, duplicate.valid?
525
+ assert_equal 'has already been taken', duplicate.errors.messages[:encrypted_email].first
474
526
  end
475
527
  end
528
+
476
529
  end
477
530
  end