symmetric-encryption 3.8.2 → 3.8.3
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.
- checksums.yaml +4 -4
- data/README.md +10 -9
- data/lib/symmetric_encryption/cipher.rb +2 -2
- data/lib/symmetric_encryption/coerce.rb +18 -1
- data/lib/symmetric_encryption/extensions/active_record/base.rb +1 -1
- data/lib/symmetric_encryption/extensions/mongo_mapper/plugins/encrypted_key.rb +7 -7
- data/lib/symmetric_encryption/extensions/mongoid/encrypted.rb +7 -7
- data/lib/symmetric_encryption/generator.rb +3 -3
- data/lib/symmetric_encryption/version.rb +1 -1
- data/lib/symmetric_encryption/writer.rb +2 -2
- data/test/active_record_test.rb +82 -74
- data/test/cipher_test.rb +26 -26
- data/test/config/mongoid_v5.yml +9 -0
- data/test/mongo_mapper_test.rb +88 -88
- data/test/mongoid_test.rb +98 -90
- data/test/reader_test.rb +17 -18
- data/test/symmetric_encryption_test.rb +62 -62
- data/test/test_db.sqlite3 +0 -0
- data/test/test_helper.rb +8 -2
- data/test/writer_test.rb +4 -4
- metadata +6 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 788a470ed0ed501adc827789838ad6460fa6070b
|
4
|
+
data.tar.gz: ba3c6a6865c5127fa409271e477ab2caee65c1a6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 525c6df5648bbf5af0432eaab63a235e0ac0fbf3a9a503576e3cf89d11a8d074820aeea9017067afcce950d37f9902f3b39620e81c3239f615488316be57ff19
|
7
|
+
data.tar.gz: ac5ae0631681185ac0c2bbdfdb0fce0b61a803ddaa1410bc19cb77a98be7b1b37a9ef7417b047781c38c69ae6b75369085d654578767143e1d7b7143821ce251
|
data/README.md
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
#
|
1
|
+
# Symmetric Encryption
|
2
2
|
   
|
3
3
|
|
4
4
|
* http://github.com/rocketjob/symmetric-encryption
|
@@ -19,21 +19,22 @@ expose all the encryption algorithms supported by OpenSSL.
|
|
19
19
|
|
20
20
|
## Documentation
|
21
21
|
|
22
|
-
For complete documentation see: http://rocketjob.github.io/symmetric-encryption/
|
23
|
-
|
24
|
-
## Documentation
|
25
|
-
|
26
22
|
[Symmetric Encryption Guide](http://rocketjob.github.io/symmetric-encryption)
|
27
23
|
|
28
24
|
[Reference Documentation](http://www.rubydoc.info/gems/symmetric-encryption/)
|
29
25
|
|
26
|
+
## Rocket Job
|
27
|
+
|
28
|
+
Checkout the sister project [Rocket Job](http://rocketjob.io): Ruby's missing batch system.
|
29
|
+
|
30
|
+
Fully supports Symmetric Encryption to encrypt data in flight and at rest while running jobs in the background.
|
31
|
+
|
30
32
|
## Supports
|
31
33
|
|
32
|
-
Symmetric Encryption works with the following Ruby
|
34
|
+
Symmetric Encryption works with the following Ruby VMs:
|
33
35
|
|
34
|
-
|
35
|
-
|
36
|
-
* Rubinius 2.5, or greater
|
36
|
+
- Ruby 2.1, 2.2, 2.3, and above
|
37
|
+
- JRuby 1.7.23, 9.0.5 and above
|
37
38
|
|
38
39
|
## Upgrading to SymmetricEncryption V3
|
39
40
|
|
@@ -383,7 +383,7 @@ module SymmetricEncryption
|
|
383
383
|
end
|
384
384
|
if include_key
|
385
385
|
len = buffer.slice!(0..1).unpack('v').first
|
386
|
-
key = decryption_cipher.binary_decrypt(buffer.slice!(0..len-1),
|
386
|
+
key = decryption_cipher.binary_decrypt(buffer.slice!(0..len-1), false)
|
387
387
|
end
|
388
388
|
if include_cipher
|
389
389
|
len = buffer.slice!(0..1).unpack('v').first
|
@@ -476,7 +476,7 @@ module SymmetricEncryption
|
|
476
476
|
self.class.build_header(version, compress, random_iv ? iv : nil, nil, nil) +
|
477
477
|
openssl_cipher.update(compress ? Zlib::Deflate.deflate(string) : string)
|
478
478
|
else
|
479
|
-
openssl_cipher.iv = @iv if @iv
|
479
|
+
openssl_cipher.iv = @iv if defined?(@iv) && @iv
|
480
480
|
openssl_cipher.update(string)
|
481
481
|
end
|
482
482
|
result << openssl_cipher.final
|
@@ -14,7 +14,7 @@ module SymmetricEncryption
|
|
14
14
|
# Coerce given value into given type
|
15
15
|
# Does not coerce json or yaml values
|
16
16
|
def self.coerce(value, type, from_type=nil)
|
17
|
-
return if
|
17
|
+
return if blank?(value)
|
18
18
|
|
19
19
|
from_type ||= value.class
|
20
20
|
case type
|
@@ -71,5 +71,22 @@ module SymmetricEncryption
|
|
71
71
|
TYPE_MAP[symbol]
|
72
72
|
end
|
73
73
|
end
|
74
|
+
|
75
|
+
private
|
76
|
+
|
77
|
+
BLANK_RE = /\A[[:space:]]*\z/
|
78
|
+
|
79
|
+
# Returns [true|false] whether the supplied value is blank?
|
80
|
+
def self.blank?(value)
|
81
|
+
return true if value.nil?
|
82
|
+
if value.is_a?(String)
|
83
|
+
return true if value.empty?
|
84
|
+
# When Binary data is supplied that cannot convert to UTF-8 it is clearly not blank
|
85
|
+
return false unless value.dup.force_encoding(SymmetricEncryption::UTF8_ENCODING).valid_encoding?
|
86
|
+
(value =~ BLANK_RE) == 0
|
87
|
+
else
|
88
|
+
false
|
89
|
+
end
|
90
|
+
end
|
74
91
|
end
|
75
92
|
end
|
@@ -49,10 +49,10 @@ module MongoMapper
|
|
49
49
|
#
|
50
50
|
# The above document results in the following document in the Mongo collection 'persons':
|
51
51
|
# {
|
52
|
-
#
|
53
|
-
#
|
54
|
-
#
|
55
|
-
#
|
52
|
+
# 'name' : 'Joe',
|
53
|
+
# 'encrypted_social_security_number' : '...',
|
54
|
+
# 'age' : 21
|
55
|
+
# 'encrypted_life_history' : '...',
|
56
56
|
# }
|
57
57
|
#
|
58
58
|
# Symmetric Encryption creates the getters and setters to be able to work with the field
|
@@ -67,12 +67,12 @@ module MongoMapper
|
|
67
67
|
# puts "Decrypted Social Security Number is: #{SymmetricEncryption.decrypt(person.encrypted_social_security_number)}"
|
68
68
|
#
|
69
69
|
# # Sets the encrypted_social_security_number to encrypted version
|
70
|
-
# person.social_security_number =
|
70
|
+
# person.social_security_number = '123456789'
|
71
71
|
#
|
72
72
|
# # Or, is equivalent to:
|
73
|
-
# person.encrypted_social_security_number = SymmetricEncryption.encrypt(
|
73
|
+
# person.encrypted_social_security_number = SymmetricEncryption.encrypt('123456789')
|
74
74
|
#
|
75
|
-
# Note: Only
|
75
|
+
# Note: Only 'String' types are currently supported for encryption
|
76
76
|
#
|
77
77
|
# Note: Unlike attr_encrypted finders must use the encrypted field name
|
78
78
|
# Invalid Example, does not work:
|
@@ -30,10 +30,10 @@
|
|
30
30
|
#
|
31
31
|
# The above document results in the following document in the Mongo collection 'persons':
|
32
32
|
# {
|
33
|
-
#
|
34
|
-
#
|
35
|
-
#
|
36
|
-
#
|
33
|
+
# 'name' : 'Joe',
|
34
|
+
# 'encrypted_social_security_number' : '...',
|
35
|
+
# 'age' : 21
|
36
|
+
# 'encrypted_life_history' : '...',
|
37
37
|
# }
|
38
38
|
#
|
39
39
|
# Symmetric Encryption creates the getters and setters to be able to work with the field
|
@@ -48,12 +48,12 @@
|
|
48
48
|
# puts "Decrypted Social Security Number is: #{SymmetricEncryption.decrypt(person.encrypted_social_security_number)}"
|
49
49
|
#
|
50
50
|
# # Sets the encrypted_social_security_number to encrypted version
|
51
|
-
# person.social_security_number =
|
51
|
+
# person.social_security_number = '123456789'
|
52
52
|
#
|
53
53
|
# # Or, is equivalent to:
|
54
|
-
# person.encrypted_social_security_number = SymmetricEncryption.encrypt(
|
54
|
+
# person.encrypted_social_security_number = SymmetricEncryption.encrypt('123456789')
|
55
55
|
#
|
56
|
-
# Note: Only
|
56
|
+
# Note: Only 'String' types are currently supported for encryption
|
57
57
|
#
|
58
58
|
# Note: Unlike attr_encrypted finders must use the encrypted field name
|
59
59
|
# Invalid Example, does not work:
|
@@ -25,7 +25,7 @@ module SymmetricEncryption
|
|
25
25
|
# Freeze the decrypted field value so that it is not modified directly
|
26
26
|
def #{decrypted_name}=(value)
|
27
27
|
v = SymmetricEncryption::Coerce.coerce(value, :#{type})
|
28
|
-
self.#{encrypted_name} = @stored_#{encrypted_name} = ::SymmetricEncryption.encrypt(v
|
28
|
+
self.#{encrypted_name} = @stored_#{encrypted_name} = ::SymmetricEncryption.encrypt(v, #{random_iv}, #{compress}, :#{type})
|
29
29
|
@#{decrypted_name} = v.freeze
|
30
30
|
end
|
31
31
|
|
@@ -33,8 +33,8 @@ module SymmetricEncryption
|
|
33
33
|
# The decrypted value is cached and is only decrypted if the encrypted value has changed
|
34
34
|
# If this method is not called, then the encrypted value is never decrypted
|
35
35
|
def #{decrypted_name}
|
36
|
-
if @stored_#{encrypted_name} != self.#{encrypted_name}
|
37
|
-
@#{decrypted_name} = ::SymmetricEncryption.decrypt(self.#{encrypted_name},
|
36
|
+
if !defined?(@stored_#{encrypted_name}) || (@stored_#{encrypted_name} != self.#{encrypted_name})
|
37
|
+
@#{decrypted_name} = ::SymmetricEncryption.decrypt(self.#{encrypted_name}, nil, :#{type}).freeze
|
38
38
|
@stored_#{encrypted_name} = self.#{encrypted_name}
|
39
39
|
end
|
40
40
|
@#{decrypted_name}
|
@@ -79,7 +79,7 @@ module SymmetricEncryption
|
|
79
79
|
# # Example: Encrypt and write data to a file
|
80
80
|
# SymmetricEncryption::Writer.open('test_file') do |file|
|
81
81
|
# file.write "Hello World\n"
|
82
|
-
# file.write
|
82
|
+
# file.write 'Keep this secret'
|
83
83
|
# end
|
84
84
|
#
|
85
85
|
# # Example: Compress, Encrypt and write data to a file
|
@@ -193,7 +193,7 @@ module SymmetricEncryption
|
|
193
193
|
# Returns self
|
194
194
|
#
|
195
195
|
# Example:
|
196
|
-
# file << "Hello.\n" <<
|
196
|
+
# file << "Hello.\n" << 'This is Jack'
|
197
197
|
def <<(data)
|
198
198
|
write(data)
|
199
199
|
self
|
data/test/active_record_test.rb
CHANGED
@@ -9,8 +9,9 @@ ActiveRecord::Schema.define version: 0 do
|
|
9
9
|
create_table :users, force: true do |t|
|
10
10
|
t.string :encrypted_bank_account_number
|
11
11
|
t.string :encrypted_social_security_number
|
12
|
-
t.string :
|
13
|
-
t.text :
|
12
|
+
t.string :encrypted_string_value
|
13
|
+
t.text :encrypted_long_string_value
|
14
|
+
t.text :encrypted_binary_string_value
|
14
15
|
t.text :encrypted_data_yaml
|
15
16
|
t.text :encrypted_data_json
|
16
17
|
t.string :name
|
@@ -38,10 +39,11 @@ end
|
|
38
39
|
class User < ActiveRecord::Base
|
39
40
|
attr_encrypted :bank_account_number
|
40
41
|
attr_encrypted :social_security_number
|
41
|
-
attr_encrypted :
|
42
|
-
attr_encrypted :
|
43
|
-
attr_encrypted :
|
44
|
-
attr_encrypted :
|
42
|
+
attr_encrypted :string_value, random_iv: true
|
43
|
+
attr_encrypted :long_string_value, random_iv: true, compress: true
|
44
|
+
attr_encrypted :binary_string_value, random_iv: true, compress: true
|
45
|
+
attr_encrypted :data_yaml, random_iv: true, compress: true, type: :yaml
|
46
|
+
attr_encrypted :data_json, random_iv: true, compress: true, type: :json
|
45
47
|
|
46
48
|
attr_encrypted :integer_value, type: :integer
|
47
49
|
attr_encrypted :float_value, type: :float
|
@@ -71,14 +73,14 @@ class UniqueUser < ActiveRecord::Base
|
|
71
73
|
|
72
74
|
validates :username,
|
73
75
|
length: {in: 3..20},
|
74
|
-
format: {with: /\A[\w
|
76
|
+
format: {with: /\A[\w\-]+\z/},
|
75
77
|
allow_blank: true
|
76
78
|
end
|
77
79
|
#@formatter:on
|
78
80
|
|
79
81
|
# Initialize the database connection
|
80
82
|
config_file = File.join(File.dirname(__FILE__), 'config', 'database.yml')
|
81
|
-
raise 'database config not found. Create a config file at: test/config/database.yml' unless File.
|
83
|
+
raise 'database config not found. Create a config file at: test/config/database.yml' unless File.exist? config_file
|
82
84
|
|
83
85
|
cfg = YAML.load(ERB.new(File.new(config_file).read).result)['test']
|
84
86
|
raise("Environment 'test' not defined in test/config/database.yml") unless cfg
|
@@ -90,12 +92,15 @@ User.establish_connection(cfg)
|
|
90
92
|
#
|
91
93
|
class ActiveRecordTest < Minitest::Test
|
92
94
|
describe 'ActiveRecord' do
|
93
|
-
INTEGER_VALUE
|
94
|
-
FLOAT_VALUE
|
95
|
-
DECIMAL_VALUE
|
96
|
-
DATETIME_VALUE
|
97
|
-
TIME_VALUE
|
98
|
-
DATE_VALUE
|
95
|
+
INTEGER_VALUE = 12
|
96
|
+
FLOAT_VALUE = 88.12345
|
97
|
+
DECIMAL_VALUE = BigDecimal.new('22.51')
|
98
|
+
DATETIME_VALUE = DateTime.new(2001, 11, 26, 20, 55, 54, "-5")
|
99
|
+
TIME_VALUE = Time.new(2013, 01, 01, 22, 30, 00, "-04:00")
|
100
|
+
DATE_VALUE = Date.new(1927, 04, 02)
|
101
|
+
STRING_VALUE = 'A string containing some data to be encrypted with a random initialization vector'
|
102
|
+
LONG_STRING_VALUE = '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'
|
103
|
+
BINARY_STRING_VALUE = "Non-UTF8 Binary \x92 string".force_encoding('BINARY')
|
99
104
|
|
100
105
|
before do
|
101
106
|
@bank_account_number = '1234567890'
|
@@ -104,9 +109,6 @@ class ActiveRecordTest < Minitest::Test
|
|
104
109
|
@social_security_number = '987654321'
|
105
110
|
@social_security_number_encrypted = 'QEVuQwIAS+8X1NRrqdfEIQyFHVPuVA=='
|
106
111
|
|
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'
|
109
|
-
|
110
112
|
@name = 'Joe Bloggs'
|
111
113
|
|
112
114
|
@h = {a: 'A', b: 'B'}
|
@@ -118,6 +120,9 @@ class ActiveRecordTest < Minitest::Test
|
|
118
120
|
social_security_number: @social_security_number,
|
119
121
|
name: @name,
|
120
122
|
# data type specific fields
|
123
|
+
string_value: STRING_VALUE,
|
124
|
+
long_string_value: LONG_STRING_VALUE,
|
125
|
+
binary_string_value: BINARY_STRING_VALUE,
|
121
126
|
integer_value: INTEGER_VALUE,
|
122
127
|
float_value: FLOAT_VALUE,
|
123
128
|
decimal_value: DECIMAL_VALUE,
|
@@ -164,18 +169,18 @@ class ActiveRecordTest < Minitest::Test
|
|
164
169
|
end
|
165
170
|
|
166
171
|
it 'support a random iv' do
|
167
|
-
@user.
|
168
|
-
assert first_value = @user.
|
172
|
+
@user.string_value = STRING_VALUE
|
173
|
+
assert first_value = @user.encrypted_string_value
|
169
174
|
# Assign the same value
|
170
|
-
@user.
|
171
|
-
|
175
|
+
@user.string_value = STRING_VALUE.dup
|
176
|
+
assert first_value != @user.encrypted_string_value
|
172
177
|
end
|
173
178
|
|
174
179
|
it 'support a random iv and compress' do
|
175
|
-
@user.
|
176
|
-
@user.
|
180
|
+
@user.string_value = STRING_VALUE
|
181
|
+
@user.long_string_value = STRING_VALUE
|
177
182
|
|
178
|
-
|
183
|
+
refute_equal @user.encrypted_long_string_value, @user.encrypted_string_value
|
179
184
|
end
|
180
185
|
|
181
186
|
it 'encrypt' do
|
@@ -238,51 +243,51 @@ class ActiveRecordTest < Minitest::Test
|
|
238
243
|
it 'return encrypted keys for the class' do
|
239
244
|
expect = [:social_security_number, :bank_account_number]
|
240
245
|
result = User.encrypted_keys
|
241
|
-
expect.each { |val|
|
246
|
+
expect.each { |val| assert result.include?(val) }
|
242
247
|
|
243
248
|
# Also check encrypted_attribute?
|
244
|
-
expect.each { |val|
|
249
|
+
expect.each { |val| assert User.encrypted_attribute?(val) }
|
245
250
|
end
|
246
251
|
|
247
252
|
it 'return encrypted columns for the class' do
|
248
253
|
expect = [:encrypted_social_security_number, :encrypted_bank_account_number]
|
249
254
|
result = User.encrypted_columns
|
250
|
-
expect.each { |val|
|
255
|
+
expect.each { |val| assert result.include?(val) }
|
251
256
|
|
252
257
|
# Also check encrypted_column?
|
253
|
-
expect.each { |val|
|
258
|
+
expect.each { |val| assert User.encrypted_column?(val) }
|
254
259
|
end
|
255
260
|
|
256
261
|
it 'validate encrypted data' do
|
257
|
-
|
262
|
+
assert @user.valid?
|
258
263
|
@user.encrypted_bank_account_number = '123'
|
259
264
|
assert_equal false, @user.valid?
|
260
|
-
assert_equal [
|
265
|
+
assert_equal ['must be a value encrypted using SymmetricEncryption.encrypt'], @user.errors[:encrypted_bank_account_number]
|
261
266
|
@user.encrypted_bank_account_number = SymmetricEncryption.encrypt('123')
|
262
|
-
|
267
|
+
assert @user.valid?
|
263
268
|
@user.bank_account_number = '123'
|
264
|
-
|
269
|
+
assert @user.valid?
|
265
270
|
end
|
266
271
|
|
267
272
|
it 'validate un-encrypted string data' do
|
268
|
-
|
273
|
+
assert @user.valid?
|
269
274
|
@user.text = '123'
|
270
275
|
assert_equal false, @user.valid?
|
271
|
-
assert_equal [
|
276
|
+
assert_equal ['only allows letters'], @user.errors[:text]
|
272
277
|
@user.text = nil
|
273
278
|
assert_equal false, @user.valid?
|
274
|
-
assert_equal [
|
279
|
+
assert_equal ['only allows letters', "can't be blank"], @user.errors[:text]
|
275
280
|
@user.text = ''
|
276
281
|
assert_equal false, @user.valid?
|
277
|
-
assert_equal [
|
282
|
+
assert_equal ['only allows letters', "can't be blank"], @user.errors[:text]
|
278
283
|
end
|
279
284
|
|
280
285
|
it 'validate un-encrypted integer data with coercion' do
|
281
|
-
|
286
|
+
assert @user.valid?
|
282
287
|
@user.number = '123'
|
283
|
-
|
288
|
+
assert @user.valid?
|
284
289
|
assert_equal 123, @user.number
|
285
|
-
|
290
|
+
assert @user.valid?
|
286
291
|
@user.number = ''
|
287
292
|
assert_equal false, @user.valid?
|
288
293
|
assert_equal nil, @user.number
|
@@ -294,22 +299,22 @@ class ActiveRecordTest < Minitest::Test
|
|
294
299
|
assert_equal ["can't be blank"], @user.errors[:number]
|
295
300
|
end
|
296
301
|
|
297
|
-
describe
|
302
|
+
describe 'with saved user' do
|
298
303
|
before do
|
299
304
|
@user.save!
|
300
305
|
end
|
301
306
|
|
302
307
|
after do
|
303
|
-
@user.destroy
|
308
|
+
@user.destroy if @user
|
304
309
|
end
|
305
310
|
|
306
|
-
it
|
307
|
-
u = User.new(integer_value:
|
311
|
+
it 'return correct data type before save' do
|
312
|
+
u = User.new(integer_value: '5')
|
308
313
|
assert_equal 5, u.integer_value
|
309
314
|
assert u.integer_value.kind_of?(Integer)
|
310
315
|
end
|
311
316
|
|
312
|
-
it
|
317
|
+
it 'handle gsub! for non-encrypted_field' do
|
313
318
|
@user.name.gsub!('a', 'v')
|
314
319
|
new_name = @name.gsub('a', 'v')
|
315
320
|
assert_equal new_name, @user.name
|
@@ -324,7 +329,7 @@ class ActiveRecordTest < Minitest::Test
|
|
324
329
|
end
|
325
330
|
end
|
326
331
|
|
327
|
-
it
|
332
|
+
it 'revert changes on reload' do
|
328
333
|
new_bank_account_number = '444444444'
|
329
334
|
@user.bank_account_number = new_bank_account_number
|
330
335
|
assert_equal new_bank_account_number, @user.bank_account_number
|
@@ -335,7 +340,7 @@ class ActiveRecordTest < Minitest::Test
|
|
335
340
|
assert_equal @bank_account_number, @user.bank_account_number
|
336
341
|
end
|
337
342
|
|
338
|
-
it
|
343
|
+
it 'revert changes to encrypted field on reload' do
|
339
344
|
new_bank_account_number = '111111111'
|
340
345
|
new_encrypted_bank_account_number = SymmetricEncryption.encrypt(new_bank_account_number)
|
341
346
|
@user.encrypted_bank_account_number = new_encrypted_bank_account_number
|
@@ -348,21 +353,24 @@ class ActiveRecordTest < Minitest::Test
|
|
348
353
|
assert_equal @bank_account_number, @user.bank_account_number
|
349
354
|
end
|
350
355
|
|
351
|
-
describe
|
356
|
+
describe 'data types' do
|
352
357
|
before do
|
353
358
|
@user_clone = User.find(@user.id)
|
354
359
|
end
|
355
360
|
|
356
361
|
[
|
357
362
|
#@formatter:off
|
358
|
-
{
|
359
|
-
{
|
360
|
-
{
|
361
|
-
{
|
362
|
-
{
|
363
|
-
{
|
364
|
-
{
|
365
|
-
{
|
363
|
+
{attribute: :integer_value, klass: Integer, value: INTEGER_VALUE, new_value: 98},
|
364
|
+
{attribute: :float_value, klass: Float, value: FLOAT_VALUE, new_value: 45.4321},
|
365
|
+
{attribute: :decimal_value, klass: BigDecimal, value: DECIMAL_VALUE, new_value: BigDecimal.new('99.95'), coercible: '22.51'},
|
366
|
+
{attribute: :datetime_value, klass: DateTime, value: DATETIME_VALUE, new_value: DateTime.new(1998, 10, 21, 8, 33, 28, '+5'), coercible: DATETIME_VALUE.to_time},
|
367
|
+
{attribute: :time_value, klass: Time, value: TIME_VALUE, new_value: Time.new(2000, 01, 01, 22, 30, 00, "-04:00")},
|
368
|
+
{attribute: :date_value, klass: Date, value: DATE_VALUE, new_value: Date.new(2027, 04, 02), coercible: DATE_VALUE.to_time},
|
369
|
+
{attribute: :true_value, klass: TrueClass, value: true, new_value: false},
|
370
|
+
{attribute: :false_value, klass: FalseClass, value: false, new_value: true},
|
371
|
+
{attribute: :string_value, klass: String, value: STRING_VALUE, new_value: 'Hello World'},
|
372
|
+
{attribute: :long_string_value, klass: String, value: LONG_STRING_VALUE, new_value: 'A Really long Hello World'},
|
373
|
+
{attribute: :binary_string_value, klass: String, value: BINARY_STRING_VALUE, new_value: "A new Non-UTF8 Binary \x92 string".force_encoding('BINARY')},
|
366
374
|
#@formatter:on
|
367
375
|
].each do |value_test|
|
368
376
|
describe "#{value_test[:klass]} values" do
|
@@ -374,18 +382,18 @@ class ActiveRecordTest < Minitest::Test
|
|
374
382
|
@new_value = value_test[:new_value]
|
375
383
|
end
|
376
384
|
|
377
|
-
it
|
378
|
-
assert_equal @value, @user_clone.send(@attribute)
|
385
|
+
it 'return correct data type' do
|
386
|
+
assert_equal @value, @user_clone.send(@attribute), @user_clone.attributes.ai
|
379
387
|
assert @user.clone.send(@attribute).kind_of?(@klass)
|
380
388
|
end
|
381
389
|
|
382
|
-
it
|
390
|
+
it 'coerce data type before save' do
|
383
391
|
u = User.new(@attribute => @value)
|
384
392
|
assert_equal @value, u.send(@attribute)
|
385
393
|
assert u.send(@attribute).kind_of?(@klass), "Value supposed to be coerced into #{@klass}, but is #{u.send(@attribute).class.name}"
|
386
394
|
end
|
387
395
|
|
388
|
-
it
|
396
|
+
it 'permit replacing value with nil' do
|
389
397
|
@user_clone.send("#{@attribute}=".to_sym, nil)
|
390
398
|
@user_clone.save!
|
391
399
|
|
@@ -394,7 +402,7 @@ class ActiveRecordTest < Minitest::Test
|
|
394
402
|
assert_nil @user.send("encrypted_#{@attribute}".to_sym)
|
395
403
|
end
|
396
404
|
|
397
|
-
it
|
405
|
+
it 'permit replacing value with an empty string' do
|
398
406
|
@user_clone.send("#{@attribute}=".to_sym, '')
|
399
407
|
@user_clone.save!
|
400
408
|
|
@@ -403,7 +411,7 @@ class ActiveRecordTest < Minitest::Test
|
|
403
411
|
assert_nil @user.send("encrypted_#{@attribute}".to_sym)
|
404
412
|
end
|
405
413
|
|
406
|
-
it
|
414
|
+
it 'permit replacing value with a blank string' do
|
407
415
|
@user_clone.send("#{@attribute}=".to_sym, ' ')
|
408
416
|
@user_clone.save!
|
409
417
|
|
@@ -412,7 +420,7 @@ class ActiveRecordTest < Minitest::Test
|
|
412
420
|
assert_nil @user.send("encrypted_#{@attribute}".to_sym)
|
413
421
|
end
|
414
422
|
|
415
|
-
it
|
423
|
+
it 'permit replacing value' do
|
416
424
|
@user_clone.send("#{@attribute}=".to_sym, @new_value)
|
417
425
|
@user_clone.save!
|
418
426
|
|
@@ -422,7 +430,7 @@ class ActiveRecordTest < Minitest::Test
|
|
422
430
|
end
|
423
431
|
end
|
424
432
|
|
425
|
-
describe
|
433
|
+
describe 'JSON Serialization' do
|
426
434
|
before do
|
427
435
|
# JSON Does not support symbols, so they will come back as strings
|
428
436
|
# Convert symbols to string in the test
|
@@ -432,18 +440,18 @@ class ActiveRecordTest < Minitest::Test
|
|
432
440
|
end
|
433
441
|
end
|
434
442
|
|
435
|
-
it
|
443
|
+
it 'return correct data type' do
|
436
444
|
assert_equal @h, @user_clone.data_json
|
437
445
|
assert @user.clone.data_json.kind_of?(Hash)
|
438
446
|
end
|
439
447
|
|
440
|
-
it
|
448
|
+
it 'not coerce data type (leaves as hash) before save' do
|
441
449
|
u = User.new(data_json: @h)
|
442
450
|
assert_equal @h, u.data_json
|
443
451
|
assert u.data_json.kind_of?(Hash)
|
444
452
|
end
|
445
453
|
|
446
|
-
it
|
454
|
+
it 'permit replacing value with nil' do
|
447
455
|
@user_clone.data_json = nil
|
448
456
|
@user_clone.save!
|
449
457
|
|
@@ -452,7 +460,7 @@ class ActiveRecordTest < Minitest::Test
|
|
452
460
|
assert_nil @user.encrypted_data_json
|
453
461
|
end
|
454
462
|
|
455
|
-
it
|
463
|
+
it 'permit replacing value' do
|
456
464
|
new_value = @h.clone
|
457
465
|
new_value['c'] = 'C'
|
458
466
|
@user_clone.data_json = new_value
|
@@ -463,19 +471,19 @@ class ActiveRecordTest < Minitest::Test
|
|
463
471
|
end
|
464
472
|
end
|
465
473
|
|
466
|
-
describe
|
467
|
-
it
|
474
|
+
describe 'YAML Serialization' do
|
475
|
+
it 'return correct data type' do
|
468
476
|
assert_equal @h, @user_clone.data_yaml
|
469
477
|
assert @user.clone.data_yaml.kind_of?(Hash)
|
470
478
|
end
|
471
479
|
|
472
|
-
it
|
480
|
+
it 'not coerce data type (leaves as hash) before save' do
|
473
481
|
u = User.new(data_yaml: @h)
|
474
482
|
assert_equal @h, u.data_yaml
|
475
483
|
assert u.data_yaml.kind_of?(Hash)
|
476
484
|
end
|
477
485
|
|
478
|
-
it
|
486
|
+
it 'permit replacing value with nil' do
|
479
487
|
@user_clone.data_yaml = nil
|
480
488
|
@user_clone.save!
|
481
489
|
|
@@ -484,7 +492,7 @@ class ActiveRecordTest < Minitest::Test
|
|
484
492
|
assert_nil @user.encrypted_data_yaml
|
485
493
|
end
|
486
494
|
|
487
|
-
it
|
495
|
+
it 'permit replacing value' do
|
488
496
|
new_value = @h.clone
|
489
497
|
new_value[:c] = 'C'
|
490
498
|
@user_clone.data_yaml = new_value
|
@@ -504,8 +512,8 @@ class ActiveRecordTest < Minitest::Test
|
|
504
512
|
|
505
513
|
it 'return true if it was changed' do
|
506
514
|
@user.bank_account_number = '15424623'
|
507
|
-
|
508
|
-
|
515
|
+
assert @user.encrypted_bank_account_number_changed?
|
516
|
+
assert @user.bank_account_number_changed?
|
509
517
|
end
|
510
518
|
end
|
511
519
|
end
|