ndr_support 3.1.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.
- checksums.yaml +15 -0
- data/.gitignore +14 -0
- data/.rubocop.yml +27 -0
- data/.ruby-version +1 -0
- data/.travis.yml +22 -0
- data/CODE_OF_CONDUCT.md +13 -0
- data/Gemfile +4 -0
- data/Guardfile +16 -0
- data/LICENSE.txt +21 -0
- data/README.md +91 -0
- data/Rakefile +12 -0
- data/code_safety.yml +258 -0
- data/gemfiles/Gemfile.rails32 +6 -0
- data/gemfiles/Gemfile.rails32.lock +108 -0
- data/gemfiles/Gemfile.rails41 +6 -0
- data/gemfiles/Gemfile.rails41.lock +111 -0
- data/gemfiles/Gemfile.rails42 +6 -0
- data/gemfiles/Gemfile.rails42.lock +111 -0
- data/lib/ndr_support.rb +21 -0
- data/lib/ndr_support/array.rb +52 -0
- data/lib/ndr_support/concerns/working_days.rb +94 -0
- data/lib/ndr_support/date_and_time_extensions.rb +103 -0
- data/lib/ndr_support/daterange.rb +196 -0
- data/lib/ndr_support/fixnum/calculations.rb +15 -0
- data/lib/ndr_support/fixnum/julian_date_conversions.rb +14 -0
- data/lib/ndr_support/hash.rb +52 -0
- data/lib/ndr_support/integer.rb +12 -0
- data/lib/ndr_support/nil.rb +38 -0
- data/lib/ndr_support/ourdate.rb +97 -0
- data/lib/ndr_support/ourtime.rb +51 -0
- data/lib/ndr_support/regexp_range.rb +65 -0
- data/lib/ndr_support/safe_file.rb +185 -0
- data/lib/ndr_support/safe_path.rb +268 -0
- data/lib/ndr_support/string/cleaning.rb +136 -0
- data/lib/ndr_support/string/conversions.rb +137 -0
- data/lib/ndr_support/tasks.rb +1 -0
- data/lib/ndr_support/time/conversions.rb +13 -0
- data/lib/ndr_support/utf8_encoding.rb +72 -0
- data/lib/ndr_support/utf8_encoding/control_characters.rb +53 -0
- data/lib/ndr_support/utf8_encoding/force_binary.rb +44 -0
- data/lib/ndr_support/utf8_encoding/object_support.rb +31 -0
- data/lib/ndr_support/version.rb +5 -0
- data/lib/ndr_support/yaml/serialization_migration.rb +65 -0
- data/lib/tasks/audit_code.rake +423 -0
- data/ndr_support.gemspec +39 -0
- data/test/array_test.rb +20 -0
- data/test/concerns/working_days_test.rb +122 -0
- data/test/daterange_test.rb +194 -0
- data/test/fixnum/calculations_test.rb +28 -0
- data/test/hash_test.rb +84 -0
- data/test/integer_test.rb +14 -0
- data/test/nil_test.rb +40 -0
- data/test/ourdate_test.rb +27 -0
- data/test/ourtime_test.rb +27 -0
- data/test/regexp_range_test.rb +135 -0
- data/test/resources/filesystem_paths.yml +37 -0
- data/test/safe_file_test.rb +597 -0
- data/test/safe_path_test.rb +168 -0
- data/test/string/cleaning_test.rb +176 -0
- data/test/string/conversions_test.rb +353 -0
- data/test/test_helper.rb +41 -0
- data/test/time/conversions_test.rb +15 -0
- data/test/utf8_encoding/control_characters_test.rb +84 -0
- data/test/utf8_encoding/force_binary_test.rb +64 -0
- data/test/utf8_encoding_test.rb +170 -0
- data/test/yaml/serialization_test.rb +145 -0
- metadata +295 -0
@@ -0,0 +1,168 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
# Switch on the patientlimiter as though in external environment
|
4
|
+
|
5
|
+
class SafePathTest < Minitest::Test
|
6
|
+
def setup
|
7
|
+
@sp = SafePath.new('dbs_outbox').join!('/usr/lib')
|
8
|
+
end
|
9
|
+
|
10
|
+
def test_reconfiguring_exception
|
11
|
+
# We need SafePath to be well-configured for testing already:
|
12
|
+
SafePath.fs_paths # force configuration
|
13
|
+
assert_raises(SecurityError) { SafePath.configure! 'dodgy_config.yml' }
|
14
|
+
end
|
15
|
+
|
16
|
+
test 'path passed to the constructor is always relative to the root of the path space' do
|
17
|
+
assert_equal @sp.to_s, '/mounts/ron/dbs_outbox/usr/lib'
|
18
|
+
end
|
19
|
+
|
20
|
+
test 'permissions are combination of w or r or x' do
|
21
|
+
assert_equal Array, @sp.permissions.class
|
22
|
+
assert_equal %w(r w x), @sp.permissions
|
23
|
+
|
24
|
+
@sp.permissions = 'r'
|
25
|
+
assert_equal ['r'], @sp.permissions
|
26
|
+
|
27
|
+
# The assignment of the permissions preserves the order, although this is not
|
28
|
+
# necessary.
|
29
|
+
@sp.permissions = %w(w r)
|
30
|
+
assert_equal %w(w r), @sp.permissions
|
31
|
+
|
32
|
+
# The class shouldn't keep duplicates and should flattent the arrays
|
33
|
+
@sp.permissions = ['w', 'r', 'x', 'w', 'r', %w(x r)]
|
34
|
+
assert_equal %w(w r x), @sp.permissions
|
35
|
+
end
|
36
|
+
|
37
|
+
test 'safe path raises exception if parmission different from rwx is passed' do
|
38
|
+
@sp.permissions = 'w'
|
39
|
+
assert_raises ArgumentError do
|
40
|
+
@sp.permissions = %w(r w potato)
|
41
|
+
end
|
42
|
+
|
43
|
+
# The class sould keep it's old permissions in case of raised exception
|
44
|
+
assert_equal ['w'], @sp.permissions
|
45
|
+
end
|
46
|
+
|
47
|
+
test 'safe path should remember the pathspace' do
|
48
|
+
assert_equal 'dbs_outbox', @sp.path_space
|
49
|
+
end
|
50
|
+
|
51
|
+
test 'safe path should remember root and return another instance of safe path rather than string' do
|
52
|
+
@sp.permissions = %w(w x)
|
53
|
+
root = @sp.root
|
54
|
+
assert_equal SafePath, @sp.root.class
|
55
|
+
assert_equal '/mounts/ron/dbs_outbox', root.to_s
|
56
|
+
|
57
|
+
assert_equal @sp.permissions, root.permissions
|
58
|
+
assert_equal @sp.path_space, root.path_space
|
59
|
+
end
|
60
|
+
|
61
|
+
test 'safe path should raise exception if unsafe path passed to constructor' do
|
62
|
+
assert_raises SecurityError do
|
63
|
+
SafePath.new('dbs_outbox').join!('../../../evil_path')
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
test 'safe path should raise expecption if incorrect path is assigned' do
|
68
|
+
assert_raises SecurityError do
|
69
|
+
@sp.path = '/etc/passwd'
|
70
|
+
end
|
71
|
+
|
72
|
+
assert_raises SecurityError do
|
73
|
+
@sp.path = '/mounts/ron/dbs_outbox/../../../evil_path'
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
test 'join should return SafePath' do
|
78
|
+
assert_equal SafePath, @sp.join('/test').class
|
79
|
+
end
|
80
|
+
|
81
|
+
test 'join sould raise exception if insecure path constructed' do
|
82
|
+
assert_raises SecurityError do
|
83
|
+
@sp.join('../../../evil_path')
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
test 'join should create new object' do
|
88
|
+
refute_equal @sp.object_id, @sp.join('test').object_id
|
89
|
+
end
|
90
|
+
|
91
|
+
test 'join! should return SafePath' do
|
92
|
+
assert_equal SafePath, @sp.join!('/test').class
|
93
|
+
end
|
94
|
+
|
95
|
+
test 'join! sould raise exception if insecure path constructed' do
|
96
|
+
path = @sp.to_s
|
97
|
+
|
98
|
+
assert_raises SecurityError do
|
99
|
+
@sp.join!('/../../../evil_path')
|
100
|
+
end
|
101
|
+
|
102
|
+
# if join is unsuccessful then it shouldn't alter the path
|
103
|
+
assert_equal path, @sp.to_s
|
104
|
+
end
|
105
|
+
|
106
|
+
test 'join! should work in-place' do
|
107
|
+
assert_equal @sp.object_id, @sp.join!('test').object_id
|
108
|
+
end
|
109
|
+
|
110
|
+
test '+ should return SafePath' do
|
111
|
+
assert_equal SafePath, (@sp + '/test').class
|
112
|
+
end
|
113
|
+
|
114
|
+
test '+ sould raise exception if insecure path constructed' do
|
115
|
+
assert_raises SecurityError do
|
116
|
+
@sp + '../../../evil_path'
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
test '+ should create new object' do
|
121
|
+
refute_equal @sp.object_id, (@sp + 'test').object_id
|
122
|
+
end
|
123
|
+
|
124
|
+
test "constructor should raise exception if the path space doesn't exist" do
|
125
|
+
assert_raises ArgumentError do
|
126
|
+
SafePath.new('potato_space')
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
test 'constructor should raise exception if path space is broken' do
|
131
|
+
assert_raises ArgumentError do
|
132
|
+
SafePath.new('broken_space')
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
test 'should reject root paths that are not subpath of the root specified in the yaml file' do
|
137
|
+
assert_raises SecurityError do
|
138
|
+
SafePath.new('dbs_outbox', '../../evil_path')
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
test 'should accept root paths that are subpath of the root specified in the yaml file' do
|
143
|
+
assert_equal '/mounts/ron/dbs_outbox/nice_path/path',
|
144
|
+
SafePath.new('dbs_outbox', 'nice_path/path').root.to_s
|
145
|
+
end
|
146
|
+
|
147
|
+
test 'should restrict the access only to the subpath specified in the contructor rather than the root in the yaml file' do
|
148
|
+
assert_raises SecurityError do
|
149
|
+
SafePath.new('dbs_outbox', 'nice_path/path').join!('../evil_path_under_the_root')
|
150
|
+
end
|
151
|
+
|
152
|
+
assert_raises SecurityError do
|
153
|
+
sp = SafePath.new('dbs_outbox', 'nice_path/path')
|
154
|
+
sp.path = '/mounts/ron/dbs_outbox/evil_path'
|
155
|
+
end
|
156
|
+
|
157
|
+
assert_raises SecurityError do
|
158
|
+
SafePath.new('dbs_outbox', 'nice_path/path').join('../../evil_path')
|
159
|
+
end
|
160
|
+
|
161
|
+
assert_raises SecurityError do
|
162
|
+
SafePath.new('dbs_outbox', 'nice_path/path') + '../../evil_path'
|
163
|
+
end
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
# TODO:
|
168
|
+
# Alternative .
|
@@ -0,0 +1,176 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class String::CleaningTest < Minitest::Test
|
4
|
+
# squash
|
5
|
+
|
6
|
+
test 'postcodeize' do
|
7
|
+
assert_equal 'CB22 3AD', 'CB223AD'.postcodeize
|
8
|
+
assert_equal 'CB2 2QQ', 'CB22QQ'.postcodeize
|
9
|
+
assert_equal 'CB2 2QQ', 'CB22QQ '.postcodeize
|
10
|
+
assert_equal 'CB2 2QQ', 'C B 22QQ '.postcodeize
|
11
|
+
assert_equal 'CB22QQ', 'CB2 2QQ'.postcodeize(:compact)
|
12
|
+
assert_equal 'CB2 2QQ', 'CB22QQ '.postcodeize(:db)
|
13
|
+
assert_equal 'CB2A2QQ', 'CB2A 2QQ '.postcodeize(:db)
|
14
|
+
assert_equal '', ''.postcodeize
|
15
|
+
assert_equal 'CB2 2QQ', 'cb22qq'.postcodeize(:db)
|
16
|
+
# Database storage format for all major UK postcode formats:
|
17
|
+
assert_equal 'A9 9AA', 'A9 9AA'.postcodeize(:db)
|
18
|
+
assert_equal 'A99 9AA', 'A99 9AA'.postcodeize(:db)
|
19
|
+
assert_equal 'A9A 9AA', 'A9A 9AA'.postcodeize(:db)
|
20
|
+
assert_equal 'AA9 9AA', 'AA9 9AA'.postcodeize(:db)
|
21
|
+
assert_equal 'AA999AA', 'AA99 9AA'.postcodeize(:db)
|
22
|
+
assert_equal 'AA9A9AA', 'AA9A 9AA'.postcodeize(:db)
|
23
|
+
# Examples of legacy postcodes, that should be unchanged
|
24
|
+
assert_equal 'IP222', 'IP222'.postcodeize(:db)
|
25
|
+
assert_equal 'IP222E', 'IP222E'.postcodeize(:db)
|
26
|
+
assert_equal 'HANTS', 'HANTS'.postcodeize(:db)
|
27
|
+
end
|
28
|
+
|
29
|
+
test 'xml_unsafe?' do
|
30
|
+
without_control = 'hello world!'
|
31
|
+
refute without_control.xml_unsafe?
|
32
|
+
|
33
|
+
with_safe_control = "increase: 100\045"
|
34
|
+
refute with_safe_control.xml_unsafe?
|
35
|
+
|
36
|
+
with_unsafe_control = "Lorem \000Ipsum\000"
|
37
|
+
assert with_unsafe_control.xml_unsafe?
|
38
|
+
end
|
39
|
+
|
40
|
+
test 'strip_xml_unsafe_characters' do
|
41
|
+
without_control = 'hello world!'
|
42
|
+
assert_equal without_control, without_control.strip_xml_unsafe_characters
|
43
|
+
|
44
|
+
with_safe_control = "increase: 100\045"
|
45
|
+
assert_equal 'increase: 100%', with_safe_control.strip_xml_unsafe_characters
|
46
|
+
|
47
|
+
with_unsafe_control = "Lorem \000Ipsum\000"
|
48
|
+
assert_equal 'Lorem Ipsum', with_unsafe_control.strip_xml_unsafe_characters
|
49
|
+
end
|
50
|
+
|
51
|
+
test 'clean xmlsafe' do
|
52
|
+
without_control = 'hello world!'
|
53
|
+
assert_equal without_control, without_control.clean(:xmlsafe)
|
54
|
+
|
55
|
+
with_safe_control = "increase: 100\045"
|
56
|
+
assert_equal 'increase: 100%', with_safe_control.clean(:xmlsafe)
|
57
|
+
|
58
|
+
with_unsafe_control = "Lorem \007Ipsum\006"
|
59
|
+
assert_equal 'Lorem Ipsum', with_unsafe_control.clean(:xmlsafe)
|
60
|
+
end
|
61
|
+
|
62
|
+
test 'clean make_xml_safe' do
|
63
|
+
without_control = 'hello world!'
|
64
|
+
assert_equal without_control, without_control.clean(:make_xml_safe)
|
65
|
+
|
66
|
+
with_safe_control = "increase: 100\045"
|
67
|
+
assert_equal 'increase: 100%', with_safe_control.clean(:make_xml_safe)
|
68
|
+
|
69
|
+
with_unsafe_control = "Lorem \000Ipsum\000"
|
70
|
+
assert_equal 'Lorem Ipsum', with_unsafe_control.clean(:make_xml_safe)
|
71
|
+
end
|
72
|
+
|
73
|
+
test 'clean nhsnumber' do
|
74
|
+
assert_equal '1234567890', '123 456 7890'.clean(:nhsnumber)
|
75
|
+
assert_equal '1234567890', ' 123-456-7890123'.clean(:nhsnumber)
|
76
|
+
assert_equal '', 'unknown'.clean(:nhsnumber)
|
77
|
+
assert_equal '', ''.clean(:nhsnumber)
|
78
|
+
end
|
79
|
+
|
80
|
+
test 'clean postcode' do
|
81
|
+
assert_equal 'CB4 3ND', 'cb4 3ND '.clean(:postcode)
|
82
|
+
assert_equal 'CB223AD', ' CB22 3AD'.clean(:postcode)
|
83
|
+
assert_equal '', ''.clean(:postcode)
|
84
|
+
end
|
85
|
+
|
86
|
+
test 'clean lpi' do
|
87
|
+
# self.upcase.delete('^0-9A-Z')
|
88
|
+
assert_equal '007', '007?!?'.clean(:lpi)
|
89
|
+
assert_equal 'A0000001', 'a0000001'.clean(:lpi)
|
90
|
+
assert_equal 'UNKNOWN', 'UNKNOWN'.clean(:lpi)
|
91
|
+
assert_equal '', ''.clean(:lpi)
|
92
|
+
end
|
93
|
+
|
94
|
+
test 'clean sex' do
|
95
|
+
assert_equal '1', 'male'.clean(:sex)
|
96
|
+
assert_equal '1', '1'.clean(:sex)
|
97
|
+
assert_equal '2', 'F'.clean(:sex)
|
98
|
+
assert_equal '2', '2'.clean(:sex)
|
99
|
+
assert_equal '0', ''.clean(:sex)
|
100
|
+
assert_equal '0', 'unknown'.clean(:sex)
|
101
|
+
end
|
102
|
+
|
103
|
+
test 'clean sex_c' do
|
104
|
+
assert_equal 'M', 'male'.clean(:sex_c)
|
105
|
+
assert_equal 'M', '1'.clean(:sex_c)
|
106
|
+
assert_equal 'F', 'F'.clean(:sex_c)
|
107
|
+
assert_equal 'F', '2'.clean(:sex_c)
|
108
|
+
assert_equal '', ''.clean(:sex_c)
|
109
|
+
assert_equal '', 'unknown'.clean(:sex_c)
|
110
|
+
end
|
111
|
+
|
112
|
+
test 'clean name' do
|
113
|
+
assert_equal 'MAKE A NAME', ' Make A. Name '.clean(:name)
|
114
|
+
assert_equal 'PUNCTUATE A NAME', 'PUNCTUATE,A;NAME'.clean(:name)
|
115
|
+
assert_equal 'SPREAD A NAME', 'spread a name'.clean(:name)
|
116
|
+
assert_equal "O'NAME", 'O`NAME'.clean(:name)
|
117
|
+
assert_equal "JOHN MIDDLE O'NAME", 'John, Middle. O`NAME'.clean(:name)
|
118
|
+
assert_equal '', ''.clean(:name)
|
119
|
+
end
|
120
|
+
|
121
|
+
test 'clean ethniccategory' do
|
122
|
+
assert_equal 'M', '1'.clean(:ethniccategory)
|
123
|
+
assert_equal 'X', '99'.clean(:ethniccategory)
|
124
|
+
assert_equal 'A', 'A'.clean(:ethniccategory)
|
125
|
+
assert_equal 'INVALID', 'InValid'.clean(:ethniccategory)
|
126
|
+
assert_equal '', ''.clean(:ethniccategory)
|
127
|
+
end
|
128
|
+
|
129
|
+
test 'clean code' do
|
130
|
+
assert_equal 'a123 B456', ' a12.3,,B45.6;'.clean(:code)
|
131
|
+
assert_equal 'A123 B456', 'A12.3 B.456'.clean(:code)
|
132
|
+
assert_equal 'UNKNOWN', 'UNKNOWN'.clean(:code)
|
133
|
+
assert_equal '', ''.clean(:code)
|
134
|
+
end
|
135
|
+
|
136
|
+
test 'clean code_icd' do
|
137
|
+
# TODO
|
138
|
+
end
|
139
|
+
|
140
|
+
test 'clean code_opcs' do
|
141
|
+
assert_equal 'B274 Z943', ' b27.4,Z94.3;'.clean(:code_opcs)
|
142
|
+
assert_equal 'B274 Z943', 'B27.4 Z94.3'.clean(:code_opcs)
|
143
|
+
assert_equal 'CZ001', 'CZ001'.clean(:code_opcs)
|
144
|
+
assert_equal 'B274 CZ002', 'B27.4 cz00.2'.clean(:code_opcs)
|
145
|
+
assert_equal '', 'CZ003'.clean(:code_opcs)
|
146
|
+
assert_equal '', 'UNKNOWN'.clean(:code_opcs)
|
147
|
+
assert_equal '', ''.clean(:code_opcs)
|
148
|
+
end
|
149
|
+
|
150
|
+
test 'clean hospitalnumber' do
|
151
|
+
assert_equal 'a0000001', 'a0000001'.clean(:hospitalnumber)
|
152
|
+
assert_equal 'A0000001', 'A0000001B'.clean(:hospitalnumber)
|
153
|
+
assert_equal 'UNKNOW', 'UNKNOWN'.clean(:hospitalnumber)
|
154
|
+
assert_equal '', ''.clean(:hospitalnumber)
|
155
|
+
end
|
156
|
+
|
157
|
+
test 'clean tnmcategory' do
|
158
|
+
assert_equal '', ''.clean(:tnmcategory)
|
159
|
+
assert_equal 'X', 'X'.clean(:tnmcategory)
|
160
|
+
assert_equal 'X', 'x'.clean(:tnmcategory)
|
161
|
+
assert_equal '1a', '1A'.clean(:tnmcategory)
|
162
|
+
assert_equal '1a', '1a'.clean(:tnmcategory)
|
163
|
+
assert_equal '1a', 'T1A'.clean(:tnmcategory)
|
164
|
+
assert_equal '1a', 't1a'.clean(:tnmcategory)
|
165
|
+
assert_equal 'X', 'TX'.clean(:tnmcategory)
|
166
|
+
assert_equal 'X', 'tx'.clean(:tnmcategory)
|
167
|
+
assert_equal 'X', 'Tx'.clean(:tnmcategory)
|
168
|
+
assert_equal 'X', 'tX'.clean(:tnmcategory)
|
169
|
+
end
|
170
|
+
|
171
|
+
test 'clean fallback' do
|
172
|
+
assert_equal 'UN KNOWN', 'UN ?KNOWN'.clean(:somethingorother)
|
173
|
+
assert_equal 'UNKNOWN', 'UNKNOWN'.clean(:somethingorother)
|
174
|
+
assert_equal '', ''.clean(:somethingorother)
|
175
|
+
end
|
176
|
+
end
|
@@ -0,0 +1,353 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class String::ConversionsTest < Minitest::Test
|
4
|
+
test 'soundex' do
|
5
|
+
assert_equal 'C460', 'colour'.soundex
|
6
|
+
assert_equal 'color'.soundex, 'colour'.soundex
|
7
|
+
assert 'color'.sounds_like('colour')
|
8
|
+
end
|
9
|
+
|
10
|
+
test 'date1' do
|
11
|
+
assert_equal '01.01.2000', '2000'.date1.to_s
|
12
|
+
end
|
13
|
+
|
14
|
+
test 'date2' do
|
15
|
+
assert_equal '31.12.2000', '2000'.date2.to_s
|
16
|
+
end
|
17
|
+
|
18
|
+
test 'thedate' do
|
19
|
+
# Treating a String like Ourdate
|
20
|
+
d = '01.03.2000'.thedate
|
21
|
+
assert_kind_of Date, d
|
22
|
+
assert_equal '01.03.2000', d.to_s
|
23
|
+
|
24
|
+
assert_equal '03.04.2000', '03042000'.thedate.to_s
|
25
|
+
assert_nil '01!02'.thedate, 'Expected illegal date format'
|
26
|
+
assert_nil '2000'.thedate, 'Date ranges are illegal as single dates'
|
27
|
+
end
|
28
|
+
|
29
|
+
test 'thetime' do
|
30
|
+
# Treating a local-format String like Ourtime (without seconds)
|
31
|
+
t = '01.02.1993 04:05'.thetime
|
32
|
+
assert_kind_of Time, t
|
33
|
+
assert_equal '1993-02-01 04:05:00', t.strftime('%Y-%m-%d %H:%M:%S')
|
34
|
+
end
|
35
|
+
|
36
|
+
test 'surname_and_initials' do
|
37
|
+
assert_equal 'Smith JD', 'SMITH JD'.surname_and_initials
|
38
|
+
assert_equal 'Pencheon JM', 'PENCHEON JM'.surname_and_initials
|
39
|
+
end
|
40
|
+
|
41
|
+
test 'surnameize' do
|
42
|
+
assert_equal 'Smith', 'SMITH'.surnameize
|
43
|
+
assert_equal 'McKinnon', 'MCKINNON'.surnameize
|
44
|
+
assert_equal 'O\'Neil', 'o\'neil'.surnameize
|
45
|
+
assert_equal 'X', 'X'.surnameize
|
46
|
+
assert_equal '', ''.surnameize
|
47
|
+
end
|
48
|
+
|
49
|
+
test 'nhs_numberize' do
|
50
|
+
assert_equal '123 456 7890', '1234567890'.nhs_numberize
|
51
|
+
assert_equal '012 345 6789', '0123456789'.nhs_numberize
|
52
|
+
assert_equal '012345678', '012345678'.nhs_numberize
|
53
|
+
assert_equal '', ''.nhs_numberize
|
54
|
+
end
|
55
|
+
|
56
|
+
test 'should parse dates correctly' do
|
57
|
+
assert_ymd [2001, 3, 2], '02.03.2001'.to_date
|
58
|
+
assert_ymd [2001, 3, 2], '02/03/2001'.to_date
|
59
|
+
assert_ymd [2010, 7, 11], '2010-07-11'.to_date
|
60
|
+
|
61
|
+
assert_ymd [2001, 2, 3], '2001/02/03'.to_date('yyyy/mm/dd')
|
62
|
+
assert_ymd [2001, 2, 3], '2001/03/02'.to_date('yyyy/dd/mm')
|
63
|
+
assert_ymd [2001, 2, 3], '2001-02-03'.to_date('yyyy-mm-dd')
|
64
|
+
assert_ymd [2001, 2, 3], '03/02/2001'.to_date('dd/mm/yyyy')
|
65
|
+
assert_ymd [2001, 2, 3], '02/03/2001'.to_date('mm/dd/yyyy')
|
66
|
+
|
67
|
+
assert_ymd [2001, 2, 3], '03-02-2001'.to_date('dd-mm-yyyy')
|
68
|
+
assert_ymd [1976, 9, 23], '23-09-1976'.to_date('dd-mm-yyyy')
|
69
|
+
|
70
|
+
assert_ymd [2001, 2, 3], '20010203'.to_date
|
71
|
+
|
72
|
+
assert_ymd [1954, 2, 3], '03/02/54'.to_date
|
73
|
+
assert_ymd [2014, 2, 3], '03/02/14'.to_date
|
74
|
+
assert_ymd [2014, 2, 3], '03/FEB/14'.to_date
|
75
|
+
|
76
|
+
assert_ymd [2014, 2, 3], '03-02-2014 00:00:00'.to_date
|
77
|
+
assert_ymd [2014, 2, 3], '2014-02-03 00:00:00'.to_date
|
78
|
+
assert_ymd [2014, 3, 2], '2014/03/02 13:02:01'.to_date
|
79
|
+
end
|
80
|
+
|
81
|
+
test 'ParseDate should behave consistently' do
|
82
|
+
# We use ParseDate (and thus Date._parse) for
|
83
|
+
# converting strings to dates. Its behaviour
|
84
|
+
# has been known to change...
|
85
|
+
#
|
86
|
+
# Using '.' as a separator rather than '/' appears
|
87
|
+
# to be more reliable across Ruby versions, and
|
88
|
+
# as that is what we use internally, that is all
|
89
|
+
# that we need to test here:
|
90
|
+
|
91
|
+
# Behaves as you might hope:
|
92
|
+
assert_ymd_parsed [2001, 2, 3], ParseDate.parsedate('20010203')
|
93
|
+
assert_ymd_parsed [2001, 2, 3], ParseDate.parsedate('03.02.2001')
|
94
|
+
|
95
|
+
# Doesn't behave as you might hope, but reliably gets day and year mixed:
|
96
|
+
assert_ymd_parsed [3, 2, 14], ParseDate.parsedate('03.02.14')
|
97
|
+
assert_ymd_parsed [3, 2, 54], ParseDate.parsedate('03.02.54')
|
98
|
+
assert_ymd_parsed [3, 11, 4], ParseDate.parsedate('03.11.04')
|
99
|
+
|
100
|
+
# Doesn't behave as you might hope, but reliably gets month and year mixed:
|
101
|
+
assert_ymd_parsed [14, 2, 3], ParseDate.parsedate('03.FEB.14')
|
102
|
+
assert_ymd_parsed [54, 2, 3], ParseDate.parsedate('03.FEB.54')
|
103
|
+
assert_ymd_parsed [4, 2, 3], ParseDate.parsedate('03.FEB.04')
|
104
|
+
end
|
105
|
+
|
106
|
+
test 'should calculate date differences / ages correctly' do
|
107
|
+
[['03.02.1976', '11.11.2011', 35],
|
108
|
+
['29.02.1976', '28.02.2011', 35],
|
109
|
+
['28.02.1976', '28.02.2011', 35],
|
110
|
+
['28.02.1976', '27.02.2011', 34],
|
111
|
+
['01.03.1976', '28.02.2011', 34]
|
112
|
+
].each do |date1, date2, expected_diff|
|
113
|
+
date1 = date1.to_date if date1.is_a?(String)
|
114
|
+
date2 = date2.to_date if date2.is_a?(String)
|
115
|
+
assert_equal(expected_diff,
|
116
|
+
Ourdate.date_difference_in_years(date2, date1),
|
117
|
+
"Expected difference between #{date2} and #{date1} to be #{expected_diff} years"
|
118
|
+
)
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
# to_date(pattern = nil)
|
123
|
+
test 'dd/mm/yyyy string to_date' do
|
124
|
+
# pre_epoch
|
125
|
+
assert_equal Ourdate.build_datetime(1945, 02, 13), '13/02/1945'.to_date('dd/mm/yyyy')
|
126
|
+
assert_equal Ourdate.build_datetime(1945, 05, 03), '03/05/1945'.to_date('dd/mm/yyyy')
|
127
|
+
# post epoch
|
128
|
+
assert_equal Ourdate.build_datetime(1998, 02, 13), '13/02/1998'.to_date('dd/mm/yyyy')
|
129
|
+
assert_equal Ourdate.build_datetime(1998, 05, 03), '03/05/1998'.to_date('dd/mm/yyyy')
|
130
|
+
|
131
|
+
# reverse pre_epoch
|
132
|
+
assert_equal Ourdate.build_datetime(1945, 02, 13), '13/02/1945'.to_date('yyyy/mm/dd')
|
133
|
+
assert_equal Ourdate.build_datetime(1945, 05, 03), '03/05/1945'.to_date('yyyy/mm/dd')
|
134
|
+
# reverse post epoch
|
135
|
+
assert_equal Ourdate.build_datetime(1998, 02, 13), '13/02/1998'.to_date('yyyy/mm/dd')
|
136
|
+
assert_equal Ourdate.build_datetime(1998, 05, 03), '03/05/1998'.to_date('yyyy/mm/dd')
|
137
|
+
end
|
138
|
+
|
139
|
+
test 'yyyy/mm/dd string to_date' do
|
140
|
+
# pre_epoch
|
141
|
+
assert_equal Ourdate.build_datetime(1945, 02, 13), '1945/02/13'.to_date('yyyy/mm/dd')
|
142
|
+
assert_equal Ourdate.build_datetime(1945, 05, 03), '1945/05/03'.to_date('yyyy/mm/dd')
|
143
|
+
# post epoch
|
144
|
+
assert_equal Ourdate.build_datetime(1998, 02, 13), '1998/02/13'.to_date('yyyy/mm/dd')
|
145
|
+
assert_equal Ourdate.build_datetime(1998, 05, 03), '1998/05/03'.to_date('yyyy/mm/dd')
|
146
|
+
|
147
|
+
# reverse pre_epoch
|
148
|
+
assert_equal Ourdate.build_datetime(1945, 02, 13), '1945/02/13'.to_date('dd/mm/yyyy')
|
149
|
+
assert_equal Ourdate.build_datetime(1945, 05, 03), '1945/05/03'.to_date('dd/mm/yyyy')
|
150
|
+
# reverse post epoch
|
151
|
+
assert_equal Ourdate.build_datetime(1998, 02, 13), '1998/02/13'.to_date('dd/mm/yyyy')
|
152
|
+
assert_equal Ourdate.build_datetime(1998, 05, 03), '1998/05/03'.to_date('dd/mm/yyyy')
|
153
|
+
end
|
154
|
+
|
155
|
+
test 'yyyymmdd string to_date' do
|
156
|
+
# pre_epoch
|
157
|
+
assert_equal Ourdate.build_datetime(1945, 02, 13), '19450213'.to_date('yyyymmdd')
|
158
|
+
assert_equal Ourdate.build_datetime(1945, 05, 03), '19450503'.to_date('yyyymmdd')
|
159
|
+
# post epoch
|
160
|
+
assert_equal Ourdate.build_datetime(1998, 02, 13), '19980213'.to_date('yyyymmdd')
|
161
|
+
assert_equal Ourdate.build_datetime(1998, 05, 03), '19980503'.to_date('yyyymmdd')
|
162
|
+
|
163
|
+
# long pre_epoch
|
164
|
+
assert_equal Ourdate.build_datetime(1945, 02, 13), '19450213SOMETHING'.to_date('yyyymmdd')
|
165
|
+
assert_equal Ourdate.build_datetime(1945, 05, 03), '19450503SOMETHING'.to_date('yyyymmdd')
|
166
|
+
# long post epoch
|
167
|
+
assert_equal Ourdate.build_datetime(1998, 02, 13), '19980213SOMETHING'.to_date('yyyymmdd')
|
168
|
+
assert_equal Ourdate.build_datetime(1998, 05, 03), '19980503SOMETHING'.to_date('yyyymmdd')
|
169
|
+
|
170
|
+
# ONS wildcard date formats
|
171
|
+
# (cannot convert to a Date, but need to parse into EBaseRecord date fields)
|
172
|
+
assert_equal nil, '19450000'.to_date('yyyymmdd')
|
173
|
+
assert_equal nil, '19450300'.to_date('yyyymmdd')
|
174
|
+
assert_equal nil, '19450013'.to_date('yyyymmdd')
|
175
|
+
|
176
|
+
# parse our own date format correctly, regardless of format specification
|
177
|
+
assert_equal Ourdate.build_datetime(1998, 02, 13), '13.02.1998'.to_date('yyyymmdd')
|
178
|
+
assert_equal Ourdate.build_datetime(1998, 05, 03), '03.05.1998'.to_date('yyyymmdd')
|
179
|
+
end
|
180
|
+
|
181
|
+
test 'ddmmyyyy string to_date' do
|
182
|
+
# pre_epoch
|
183
|
+
assert_equal Ourdate.build_datetime(1945, 02, 13), '13021945'.to_date('ddmmyyyy')
|
184
|
+
assert_equal Ourdate.build_datetime(1945, 05, 03), '03051945'.to_date('ddmmyyyy')
|
185
|
+
# post epoch
|
186
|
+
assert_equal Ourdate.build_datetime(1998, 02, 13), '13021998'.to_date('ddmmyyyy')
|
187
|
+
assert_equal Ourdate.build_datetime(1998, 05, 03), '03051998'.to_date('ddmmyyyy')
|
188
|
+
|
189
|
+
# long pre_epoch
|
190
|
+
assert_equal Ourdate.build_datetime(1945, 02, 13), '13021945SOMETHING'.to_date('ddmmyyyy')
|
191
|
+
assert_equal Ourdate.build_datetime(1945, 05, 03), '03051945SOMETHING'.to_date('ddmmyyyy')
|
192
|
+
# long post epoch
|
193
|
+
assert_equal Ourdate.build_datetime(1998, 02, 13), '13021998SOMETHING'.to_date('ddmmyyyy')
|
194
|
+
assert_equal Ourdate.build_datetime(1998, 05, 03), '03051998SOMETHING'.to_date('ddmmyyyy')
|
195
|
+
end
|
196
|
+
|
197
|
+
test 'mm/dd/yyyy string to_date' do
|
198
|
+
# This is currently unsupported, but will be tested if implemented
|
199
|
+
begin
|
200
|
+
# pre_epoch
|
201
|
+
assert_equal Ourdate.build_datetime(1945, 02, 13), '02/13/1945'.to_date('mm/dd/yyyy')
|
202
|
+
assert_equal Ourdate.build_datetime(1945, 05, 03), '05/03/1945'.to_date('mm/dd/yyyy')
|
203
|
+
# post epoch
|
204
|
+
assert_equal Ourdate.build_datetime(1998, 02, 13), '02/13/1998'.to_date('mm/dd/yyyy')
|
205
|
+
assert_equal Ourdate.build_datetime(1998, 05, 03), '05/03/1998'.to_date('mm/dd/yyyy')
|
206
|
+
rescue RuntimeError => e
|
207
|
+
raise e unless e.message == 'Unsupported date format'
|
208
|
+
end
|
209
|
+
end
|
210
|
+
|
211
|
+
test 'yyyy-mm-dd string to_date' do
|
212
|
+
# pre_epoch
|
213
|
+
assert_equal Ourdate.build_datetime(1945, 02, 13), '1945-02-13'.to_date('yyyy-mm-dd')
|
214
|
+
assert_equal Ourdate.build_datetime(1945, 05, 03), '1945-05-03'.to_date('yyyy-mm-dd')
|
215
|
+
# post epoch
|
216
|
+
assert_equal Ourdate.build_datetime(1998, 02, 13), '1998-02-13'.to_date('yyyy-mm-dd')
|
217
|
+
assert_equal Ourdate.build_datetime(1998, 05, 03), '1998-05-03'.to_date('yyyy-mm-dd')
|
218
|
+
end
|
219
|
+
|
220
|
+
test 'dd-mm-yyyy string to_date' do
|
221
|
+
# pre_epoch
|
222
|
+
assert_equal Ourdate.build_datetime(1945, 02, 13), '13-02-1945'.to_date('dd-mm-yyyy')
|
223
|
+
assert_equal Ourdate.build_datetime(1945, 05, 03), '03-05-1945'.to_date('dd-mm-yyyy')
|
224
|
+
# post epoch
|
225
|
+
assert_equal Ourdate.build_datetime(1998, 02, 13), '13-02-1998'.to_date('dd-mm-yyyy')
|
226
|
+
assert_equal Ourdate.build_datetime(1998, 05, 03), '03-05-1998'.to_date('dd-mm-yyyy')
|
227
|
+
end
|
228
|
+
|
229
|
+
test '%Y-%m-%d string to_date' do
|
230
|
+
# pre_epoch
|
231
|
+
assert_equal Ourdate.build_datetime(1945, 02, 13), '1945-02-13'.to_date('%Y-%m-%d')
|
232
|
+
assert_equal Ourdate.build_datetime(1945, 05, 03), '1945-05-03'.to_date('%Y-%m-%d')
|
233
|
+
# post epoch
|
234
|
+
assert_equal Ourdate.build_datetime(1998, 02, 13), '1998-02-13'.to_date('%Y-%m-%d')
|
235
|
+
assert_equal Ourdate.build_datetime(1998, 05, 03), '1998-05-03'.to_date('%Y-%m-%d')
|
236
|
+
|
237
|
+
assert ''.to_date('%Y-%m-%d').blank?
|
238
|
+
assert ' '.to_date('%Y-%m-%d').blank?
|
239
|
+
end
|
240
|
+
|
241
|
+
test '%d-%m-%Y string to_date' do
|
242
|
+
# pre_epoch
|
243
|
+
assert_equal Ourdate.build_datetime(1945, 02, 13), '13-02-1945'.to_date('%d-%m-%Y')
|
244
|
+
assert_equal Ourdate.build_datetime(1945, 05, 03), '03-05-1945'.to_date('%d-%m-%Y')
|
245
|
+
# post epoch
|
246
|
+
assert_equal Ourdate.build_datetime(1998, 02, 13), '13-02-1998'.to_date('%d-%m-%Y')
|
247
|
+
assert_equal Ourdate.build_datetime(1998, 05, 03), '03-05-1998'.to_date('%d-%m-%Y')
|
248
|
+
end
|
249
|
+
|
250
|
+
test '%Y %b %d string to_date' do
|
251
|
+
# pre_epoch
|
252
|
+
assert_equal Ourdate.build_datetime(1945, 02, 13), '1945 Feb 13'.to_date('%Y %b %d')
|
253
|
+
assert_equal Ourdate.build_datetime(1945, 05, 03), '1945 May 03'.to_date('%Y %b %d')
|
254
|
+
# post epoch
|
255
|
+
assert_equal Ourdate.build_datetime(1998, 02, 13), '1998 Feb 13'.to_date('%Y %b %d')
|
256
|
+
assert_equal Ourdate.build_datetime(1998, 05, 03), '1998 May 03'.to_date('%Y %b %d')
|
257
|
+
end
|
258
|
+
|
259
|
+
test 'inferred yyyy-mm-dd string to_date' do
|
260
|
+
# pattern pre_epoch
|
261
|
+
assert_equal Ourdate.build_datetime(1945, 02, 13), '1945-02-13'.to_date
|
262
|
+
assert_equal Ourdate.build_datetime(1945, 05, 03), '1945-05-03 00:00:00'.to_date
|
263
|
+
# pattern post epoch
|
264
|
+
assert_equal Ourdate.build_datetime(1998, 02, 13), '1998-02-13 00:00:00'.to_date
|
265
|
+
assert_equal Ourdate.build_datetime(1998, 05, 03), '1998-05-03'.to_date
|
266
|
+
end
|
267
|
+
|
268
|
+
test 'inferred dd-mm-yyyy string to_date' do
|
269
|
+
# pre_epoch
|
270
|
+
assert_equal Ourdate.build_datetime(1945, 02, 13), '13-02-1945'.to_date
|
271
|
+
assert_equal Ourdate.build_datetime(1945, 05, 03), '03-05-1945 00:00:00'.to_date
|
272
|
+
# post epoch
|
273
|
+
assert_equal Ourdate.build_datetime(1998, 02, 13), '13-02-1998 00:00:00'.to_date
|
274
|
+
assert_equal Ourdate.build_datetime(1998, 05, 03), '03-05-1998'.to_date
|
275
|
+
end
|
276
|
+
|
277
|
+
test 'inferred dd.mm.yyyy string to_date' do
|
278
|
+
# pre_epoch
|
279
|
+
assert_equal Ourdate.build_datetime(1945, 02, 13), '13.02.1945'.to_date
|
280
|
+
assert_equal Ourdate.build_datetime(1945, 05, 03), '3.5.1945'.to_date
|
281
|
+
# post epoch
|
282
|
+
assert_equal Ourdate.build_datetime(1998, 02, 13), '13.2.1998'.to_date
|
283
|
+
assert_equal Ourdate.build_datetime(1998, 05, 03), '03.05.1998'.to_date
|
284
|
+
end
|
285
|
+
|
286
|
+
test 'inferred yyyymmdd string to_date' do
|
287
|
+
# pre_epoch
|
288
|
+
assert_equal Ourdate.build_datetime(1945, 02, 13), '19450213'.to_date
|
289
|
+
assert_equal Ourdate.build_datetime(1945, 05, 03), '19450503'.to_date
|
290
|
+
# post epoch
|
291
|
+
assert_equal Ourdate.build_datetime(2008, 02, 13), '20080213'.to_date
|
292
|
+
assert_equal Ourdate.build_datetime(2008, 05, 03), '20080503'.to_date
|
293
|
+
end
|
294
|
+
|
295
|
+
test 'inferred dd/mm/yy string to_date' do
|
296
|
+
# pre_epoch
|
297
|
+
assert_equal Ourdate.build_datetime(1945, 02, 13), '13/02/45'.to_date
|
298
|
+
assert_equal Ourdate.build_datetime(1945, 05, 03), '03/05/45'.to_date
|
299
|
+
# post epoch
|
300
|
+
assert_equal Ourdate.build_datetime(2008, 02, 13), '13/02/08'.to_date
|
301
|
+
assert_equal Ourdate.build_datetime(2008, 05, 03), '03/05/08'.to_date
|
302
|
+
end
|
303
|
+
|
304
|
+
test 'inferred dd/mmm/yy string to_date' do
|
305
|
+
# pre_epoch
|
306
|
+
assert_equal Ourdate.build_datetime(1945, 02, 13), '13/FEB/45'.to_date
|
307
|
+
assert_equal Ourdate.build_datetime(1945, 06, 03), '03/JUN/45'.to_date
|
308
|
+
# post epoch
|
309
|
+
assert_equal Ourdate.build_datetime(2008, 02, 13), '13/FEB/08'.to_date
|
310
|
+
assert_equal Ourdate.build_datetime(2008, 06, 03), '03/JUN/08'.to_date
|
311
|
+
end
|
312
|
+
|
313
|
+
test 'inferred dd/mm/yyyy string to_date' do
|
314
|
+
# pre_epoch
|
315
|
+
assert_equal Ourdate.build_datetime(1945, 02, 13), '13/02/1945'.to_date
|
316
|
+
assert_equal Ourdate.build_datetime(1945, 05, 03), '03/05/1945'.to_date
|
317
|
+
# post epoch
|
318
|
+
assert_equal Ourdate.build_datetime(2008, 02, 13), '13/02/2008'.to_date
|
319
|
+
assert_equal Ourdate.build_datetime(2008, 05, 03), '03/05/2008'.to_date
|
320
|
+
end
|
321
|
+
|
322
|
+
test 'inferred dd/mm/yyyy hh:mm string to_date' do
|
323
|
+
# pre_epoch
|
324
|
+
assert_equal Ourdate.build_datetime(1945, 02, 13), '13/02/1945 13:38'.to_date
|
325
|
+
assert_equal Ourdate.build_datetime(1945, 05, 03), '03/05/1945 13:38'.to_date
|
326
|
+
# post epoch
|
327
|
+
assert_equal Ourdate.build_datetime(2008, 02, 13), '13/02/2008 13:38'.to_date
|
328
|
+
assert_equal Ourdate.build_datetime(2008, 05, 03), '03/05/2008 13:38'.to_date
|
329
|
+
end
|
330
|
+
|
331
|
+
test 'to_boolean' do
|
332
|
+
assert_equal true, 'true'.to_boolean
|
333
|
+
assert_equal true, 'yes'.to_boolean
|
334
|
+
assert_equal true, '1'.to_boolean
|
335
|
+
assert_equal false, 'false'.to_boolean
|
336
|
+
assert_equal false, 'no'.to_boolean
|
337
|
+
assert_equal false, '0'.to_boolean
|
338
|
+
assert_raises ArgumentError do
|
339
|
+
'meaningless'.to_boolean
|
340
|
+
end
|
341
|
+
end
|
342
|
+
|
343
|
+
def assert_ymd(ymd, date)
|
344
|
+
assert_equal ymd.first, date.year, 'years were not equal'
|
345
|
+
assert_equal ymd.second, date.month, 'months were not equal'
|
346
|
+
assert_equal ymd.third, date.day, 'days were not equal'
|
347
|
+
end
|
348
|
+
|
349
|
+
def assert_ymd_parsed(ymd, parse_results)
|
350
|
+
y, m, d, *_ = parse_results
|
351
|
+
assert_equal ymd, [y, m, d]
|
352
|
+
end
|
353
|
+
end
|