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.
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