ndr_support 3.1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (67) hide show
  1. checksums.yaml +15 -0
  2. data/.gitignore +14 -0
  3. data/.rubocop.yml +27 -0
  4. data/.ruby-version +1 -0
  5. data/.travis.yml +22 -0
  6. data/CODE_OF_CONDUCT.md +13 -0
  7. data/Gemfile +4 -0
  8. data/Guardfile +16 -0
  9. data/LICENSE.txt +21 -0
  10. data/README.md +91 -0
  11. data/Rakefile +12 -0
  12. data/code_safety.yml +258 -0
  13. data/gemfiles/Gemfile.rails32 +6 -0
  14. data/gemfiles/Gemfile.rails32.lock +108 -0
  15. data/gemfiles/Gemfile.rails41 +6 -0
  16. data/gemfiles/Gemfile.rails41.lock +111 -0
  17. data/gemfiles/Gemfile.rails42 +6 -0
  18. data/gemfiles/Gemfile.rails42.lock +111 -0
  19. data/lib/ndr_support.rb +21 -0
  20. data/lib/ndr_support/array.rb +52 -0
  21. data/lib/ndr_support/concerns/working_days.rb +94 -0
  22. data/lib/ndr_support/date_and_time_extensions.rb +103 -0
  23. data/lib/ndr_support/daterange.rb +196 -0
  24. data/lib/ndr_support/fixnum/calculations.rb +15 -0
  25. data/lib/ndr_support/fixnum/julian_date_conversions.rb +14 -0
  26. data/lib/ndr_support/hash.rb +52 -0
  27. data/lib/ndr_support/integer.rb +12 -0
  28. data/lib/ndr_support/nil.rb +38 -0
  29. data/lib/ndr_support/ourdate.rb +97 -0
  30. data/lib/ndr_support/ourtime.rb +51 -0
  31. data/lib/ndr_support/regexp_range.rb +65 -0
  32. data/lib/ndr_support/safe_file.rb +185 -0
  33. data/lib/ndr_support/safe_path.rb +268 -0
  34. data/lib/ndr_support/string/cleaning.rb +136 -0
  35. data/lib/ndr_support/string/conversions.rb +137 -0
  36. data/lib/ndr_support/tasks.rb +1 -0
  37. data/lib/ndr_support/time/conversions.rb +13 -0
  38. data/lib/ndr_support/utf8_encoding.rb +72 -0
  39. data/lib/ndr_support/utf8_encoding/control_characters.rb +53 -0
  40. data/lib/ndr_support/utf8_encoding/force_binary.rb +44 -0
  41. data/lib/ndr_support/utf8_encoding/object_support.rb +31 -0
  42. data/lib/ndr_support/version.rb +5 -0
  43. data/lib/ndr_support/yaml/serialization_migration.rb +65 -0
  44. data/lib/tasks/audit_code.rake +423 -0
  45. data/ndr_support.gemspec +39 -0
  46. data/test/array_test.rb +20 -0
  47. data/test/concerns/working_days_test.rb +122 -0
  48. data/test/daterange_test.rb +194 -0
  49. data/test/fixnum/calculations_test.rb +28 -0
  50. data/test/hash_test.rb +84 -0
  51. data/test/integer_test.rb +14 -0
  52. data/test/nil_test.rb +40 -0
  53. data/test/ourdate_test.rb +27 -0
  54. data/test/ourtime_test.rb +27 -0
  55. data/test/regexp_range_test.rb +135 -0
  56. data/test/resources/filesystem_paths.yml +37 -0
  57. data/test/safe_file_test.rb +597 -0
  58. data/test/safe_path_test.rb +168 -0
  59. data/test/string/cleaning_test.rb +176 -0
  60. data/test/string/conversions_test.rb +353 -0
  61. data/test/test_helper.rb +41 -0
  62. data/test/time/conversions_test.rb +15 -0
  63. data/test/utf8_encoding/control_characters_test.rb +84 -0
  64. data/test/utf8_encoding/force_binary_test.rb +64 -0
  65. data/test/utf8_encoding_test.rb +170 -0
  66. data/test/yaml/serialization_test.rb +145 -0
  67. 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