ndr_support 3.1.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|