tzinfo 1.2.11 → 2.0.0

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 (151) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/.yardopts +3 -0
  4. data/CHANGES.md +469 -431
  5. data/LICENSE +13 -13
  6. data/README.md +368 -114
  7. data/lib/tzinfo/country.rb +131 -129
  8. data/lib/tzinfo/country_timezone.rb +70 -112
  9. data/lib/tzinfo/data_source.rb +389 -144
  10. data/lib/tzinfo/data_sources/constant_offset_data_timezone_info.rb +56 -0
  11. data/lib/tzinfo/data_sources/country_info.rb +42 -0
  12. data/lib/tzinfo/data_sources/data_timezone_info.rb +91 -0
  13. data/lib/tzinfo/data_sources/linked_timezone_info.rb +33 -0
  14. data/lib/tzinfo/data_sources/ruby_data_source.rb +141 -0
  15. data/lib/tzinfo/data_sources/timezone_info.rb +47 -0
  16. data/lib/tzinfo/data_sources/transitions_data_timezone_info.rb +214 -0
  17. data/lib/tzinfo/data_sources/zoneinfo_data_source.rb +573 -0
  18. data/lib/tzinfo/data_sources/zoneinfo_reader.rb +284 -0
  19. data/lib/tzinfo/data_sources.rb +8 -0
  20. data/lib/tzinfo/data_timezone.rb +33 -47
  21. data/lib/tzinfo/datetime_with_offset.rb +153 -0
  22. data/lib/tzinfo/format1/country_definer.rb +17 -0
  23. data/lib/tzinfo/format1/country_index_definition.rb +64 -0
  24. data/lib/tzinfo/format1/timezone_definer.rb +64 -0
  25. data/lib/tzinfo/format1/timezone_definition.rb +39 -0
  26. data/lib/tzinfo/format1/timezone_index_definition.rb +77 -0
  27. data/lib/tzinfo/format1.rb +10 -0
  28. data/lib/tzinfo/format2/country_definer.rb +68 -0
  29. data/lib/tzinfo/format2/country_index_definer.rb +68 -0
  30. data/lib/tzinfo/format2/country_index_definition.rb +46 -0
  31. data/lib/tzinfo/format2/timezone_definer.rb +94 -0
  32. data/lib/tzinfo/format2/timezone_definition.rb +73 -0
  33. data/lib/tzinfo/format2/timezone_index_definer.rb +45 -0
  34. data/lib/tzinfo/format2/timezone_index_definition.rb +55 -0
  35. data/lib/tzinfo/format2.rb +10 -0
  36. data/lib/tzinfo/info_timezone.rb +26 -21
  37. data/lib/tzinfo/linked_timezone.rb +33 -52
  38. data/lib/tzinfo/offset_timezone_period.rb +42 -0
  39. data/lib/tzinfo/string_deduper.rb +118 -0
  40. data/lib/tzinfo/time_with_offset.rb +128 -0
  41. data/lib/tzinfo/timestamp.rb +548 -0
  42. data/lib/tzinfo/timestamp_with_offset.rb +85 -0
  43. data/lib/tzinfo/timezone.rb +979 -502
  44. data/lib/tzinfo/timezone_offset.rb +84 -74
  45. data/lib/tzinfo/timezone_period.rb +151 -217
  46. data/lib/tzinfo/timezone_proxy.rb +70 -79
  47. data/lib/tzinfo/timezone_transition.rb +77 -109
  48. data/lib/tzinfo/transitions_timezone_period.rb +63 -0
  49. data/lib/tzinfo/version.rb +7 -0
  50. data/lib/tzinfo/with_offset.rb +61 -0
  51. data/lib/tzinfo.rb +60 -40
  52. data.tar.gz.sig +0 -0
  53. metadata +51 -115
  54. metadata.gz.sig +2 -3
  55. data/Rakefile +0 -107
  56. data/lib/tzinfo/annual_rules.rb +0 -51
  57. data/lib/tzinfo/country_index_definition.rb +0 -31
  58. data/lib/tzinfo/country_info.rb +0 -42
  59. data/lib/tzinfo/data_timezone_info.rb +0 -55
  60. data/lib/tzinfo/linked_timezone_info.rb +0 -26
  61. data/lib/tzinfo/offset_rationals.rb +0 -77
  62. data/lib/tzinfo/posix_time_zone_parser.rb +0 -136
  63. data/lib/tzinfo/ruby_core_support.rb +0 -176
  64. data/lib/tzinfo/ruby_country_info.rb +0 -74
  65. data/lib/tzinfo/ruby_data_source.rb +0 -136
  66. data/lib/tzinfo/time_or_datetime.rb +0 -351
  67. data/lib/tzinfo/timezone_definition.rb +0 -36
  68. data/lib/tzinfo/timezone_index_definition.rb +0 -54
  69. data/lib/tzinfo/timezone_info.rb +0 -30
  70. data/lib/tzinfo/timezone_transition_definition.rb +0 -104
  71. data/lib/tzinfo/transition_data_timezone_info.rb +0 -274
  72. data/lib/tzinfo/transition_rule.rb +0 -325
  73. data/lib/tzinfo/zoneinfo_country_info.rb +0 -37
  74. data/lib/tzinfo/zoneinfo_data_source.rb +0 -504
  75. data/lib/tzinfo/zoneinfo_timezone_info.rb +0 -516
  76. data/test/assets/payload.rb +0 -1
  77. data/test/tc_annual_rules.rb +0 -95
  78. data/test/tc_country.rb +0 -240
  79. data/test/tc_country_index_definition.rb +0 -69
  80. data/test/tc_country_info.rb +0 -16
  81. data/test/tc_country_timezone.rb +0 -173
  82. data/test/tc_data_source.rb +0 -218
  83. data/test/tc_data_timezone.rb +0 -99
  84. data/test/tc_data_timezone_info.rb +0 -18
  85. data/test/tc_info_timezone.rb +0 -34
  86. data/test/tc_linked_timezone.rb +0 -155
  87. data/test/tc_linked_timezone_info.rb +0 -23
  88. data/test/tc_offset_rationals.rb +0 -23
  89. data/test/tc_posix_time_zone_parser.rb +0 -261
  90. data/test/tc_ruby_core_support.rb +0 -168
  91. data/test/tc_ruby_country_info.rb +0 -110
  92. data/test/tc_ruby_data_source.rb +0 -175
  93. data/test/tc_time_or_datetime.rb +0 -674
  94. data/test/tc_timezone.rb +0 -1361
  95. data/test/tc_timezone_definition.rb +0 -113
  96. data/test/tc_timezone_index_definition.rb +0 -73
  97. data/test/tc_timezone_info.rb +0 -11
  98. data/test/tc_timezone_london.rb +0 -143
  99. data/test/tc_timezone_melbourne.rb +0 -142
  100. data/test/tc_timezone_new_york.rb +0 -142
  101. data/test/tc_timezone_offset.rb +0 -126
  102. data/test/tc_timezone_period.rb +0 -555
  103. data/test/tc_timezone_proxy.rb +0 -136
  104. data/test/tc_timezone_transition.rb +0 -366
  105. data/test/tc_timezone_transition_definition.rb +0 -295
  106. data/test/tc_timezone_utc.rb +0 -27
  107. data/test/tc_transition_data_timezone_info.rb +0 -433
  108. data/test/tc_transition_rule.rb +0 -663
  109. data/test/tc_zoneinfo_country_info.rb +0 -78
  110. data/test/tc_zoneinfo_data_source.rb +0 -1226
  111. data/test/tc_zoneinfo_timezone_info.rb +0 -2149
  112. data/test/test_utils.rb +0 -214
  113. data/test/ts_all.rb +0 -7
  114. data/test/ts_all_ruby.rb +0 -5
  115. data/test/ts_all_zoneinfo.rb +0 -9
  116. data/test/tzinfo-data/tzinfo/data/definitions/America/Argentina/Buenos_Aires.rb +0 -89
  117. data/test/tzinfo-data/tzinfo/data/definitions/America/New_York.rb +0 -327
  118. data/test/tzinfo-data/tzinfo/data/definitions/Australia/Melbourne.rb +0 -230
  119. data/test/tzinfo-data/tzinfo/data/definitions/EST.rb +0 -19
  120. data/test/tzinfo-data/tzinfo/data/definitions/Etc/GMT__m__1.rb +0 -21
  121. data/test/tzinfo-data/tzinfo/data/definitions/Etc/GMT__p__1.rb +0 -21
  122. data/test/tzinfo-data/tzinfo/data/definitions/Etc/UTC.rb +0 -21
  123. data/test/tzinfo-data/tzinfo/data/definitions/Europe/Amsterdam.rb +0 -273
  124. data/test/tzinfo-data/tzinfo/data/definitions/Europe/Andorra.rb +0 -198
  125. data/test/tzinfo-data/tzinfo/data/definitions/Europe/London.rb +0 -333
  126. data/test/tzinfo-data/tzinfo/data/definitions/Europe/Paris.rb +0 -277
  127. data/test/tzinfo-data/tzinfo/data/definitions/Europe/Prague.rb +0 -235
  128. data/test/tzinfo-data/tzinfo/data/definitions/UTC.rb +0 -16
  129. data/test/tzinfo-data/tzinfo/data/indexes/countries.rb +0 -940
  130. data/test/tzinfo-data/tzinfo/data/indexes/timezones.rb +0 -609
  131. data/test/tzinfo-data/tzinfo/data/version.rb +0 -20
  132. data/test/tzinfo-data/tzinfo/data.rb +0 -8
  133. data/test/zoneinfo/America/Argentina/Buenos_Aires +0 -0
  134. data/test/zoneinfo/America/New_York +0 -0
  135. data/test/zoneinfo/Australia/Melbourne +0 -0
  136. data/test/zoneinfo/EST +0 -0
  137. data/test/zoneinfo/Etc/UTC +0 -0
  138. data/test/zoneinfo/Europe/Amsterdam +0 -0
  139. data/test/zoneinfo/Europe/Andorra +0 -0
  140. data/test/zoneinfo/Europe/London +0 -0
  141. data/test/zoneinfo/Europe/Paris +0 -0
  142. data/test/zoneinfo/Europe/Prague +0 -0
  143. data/test/zoneinfo/Factory +0 -0
  144. data/test/zoneinfo/iso3166.tab +0 -274
  145. data/test/zoneinfo/leapseconds +0 -78
  146. data/test/zoneinfo/posix/Europe/London +0 -0
  147. data/test/zoneinfo/posixrules +0 -0
  148. data/test/zoneinfo/right/Europe/London +0 -0
  149. data/test/zoneinfo/zone.tab +0 -452
  150. data/test/zoneinfo/zone1970.tab +0 -384
  151. data/tzinfo.gemspec +0 -21
@@ -1,1226 +0,0 @@
1
- # encoding: UTF-8
2
-
3
- require File.join(File.expand_path(File.dirname(__FILE__)), 'test_utils')
4
- require 'fileutils'
5
- require 'pathname'
6
- require 'tmpdir'
7
-
8
- include TZInfo
9
-
10
- class TCZoneinfoDataSource < Minitest::Test
11
- ZONEINFO_DIR = RubyCoreSupport.untaint(File.join(File.expand_path(File.dirname(__FILE__)), 'zoneinfo'))
12
-
13
- def setup
14
- @orig_search_path = ZoneinfoDataSource.search_path.clone
15
- @orig_alternate_iso3166_tab_search_path = ZoneinfoDataSource.alternate_iso3166_tab_search_path.clone
16
- @orig_pwd = FileUtils.pwd
17
-
18
- # A zoneinfo directory containing files needed by the tests.
19
- # The symlinks in this directory are set up in test_utils.rb.
20
- @data_source = ZoneinfoDataSource.new(ZONEINFO_DIR)
21
- end
22
-
23
- def teardown
24
- ZoneinfoDataSource.search_path = @orig_search_path
25
- ZoneinfoDataSource.alternate_iso3166_tab_search_path = @orig_alternate_iso3166_tab_search_path
26
- FileUtils.chdir(@orig_pwd)
27
- end
28
-
29
- def test_default_search_path
30
- assert_equal(['/usr/share/zoneinfo', '/usr/share/lib/zoneinfo', '/etc/zoneinfo'], ZoneinfoDataSource.search_path)
31
- assert_equal(false, ZoneinfoDataSource.search_path.frozen?)
32
- end
33
-
34
- def test_set_search_path_default
35
- ZoneinfoDataSource.search_path = ['/tmp/zoneinfo1', '/tmp/zoneinfo2']
36
- assert_equal(['/tmp/zoneinfo1', '/tmp/zoneinfo2'], ZoneinfoDataSource.search_path)
37
-
38
- ZoneinfoDataSource.search_path = nil
39
- assert_equal(['/usr/share/zoneinfo', '/usr/share/lib/zoneinfo', '/etc/zoneinfo'], ZoneinfoDataSource.search_path)
40
- assert_equal(false, ZoneinfoDataSource.search_path.frozen?)
41
- end
42
-
43
- def test_set_search_path_array
44
- path = ['/tmp/zoneinfo1', '/tmp/zoneinfo2']
45
- ZoneinfoDataSource.search_path = path
46
- assert_equal(['/tmp/zoneinfo1', '/tmp/zoneinfo2'], ZoneinfoDataSource.search_path)
47
- refute_same(path, ZoneinfoDataSource.search_path)
48
- end
49
-
50
- def test_set_search_path_array_to_s
51
- ZoneinfoDataSource.search_path = [Pathname.new('/tmp/zoneinfo3')]
52
- assert_equal(['/tmp/zoneinfo3'], ZoneinfoDataSource.search_path)
53
- end
54
-
55
- def test_set_search_path_string
56
- ZoneinfoDataSource.search_path = ['/tmp/zoneinfo4', '/tmp/zoneinfo5'].join(File::PATH_SEPARATOR)
57
- assert_equal(['/tmp/zoneinfo4', '/tmp/zoneinfo5'], ZoneinfoDataSource.search_path)
58
- end
59
-
60
- def test_default_alternate_iso3166_tab_search_path
61
- assert_equal(['/usr/share/misc/iso3166.tab', '/usr/share/misc/iso3166'], ZoneinfoDataSource.alternate_iso3166_tab_search_path)
62
- assert_equal(false, ZoneinfoDataSource.alternate_iso3166_tab_search_path.frozen?)
63
- end
64
-
65
- def test_set_alternate_iso3166_tab_search_path_default
66
- ZoneinfoDataSource.alternate_iso3166_tab_search_path = ['/tmp/iso3166.tab', '/tmp/iso3166']
67
- assert_equal(['/tmp/iso3166.tab', '/tmp/iso3166'], ZoneinfoDataSource.alternate_iso3166_tab_search_path)
68
-
69
- ZoneinfoDataSource.alternate_iso3166_tab_search_path = nil
70
- assert_equal(['/usr/share/misc/iso3166.tab', '/usr/share/misc/iso3166'], ZoneinfoDataSource.alternate_iso3166_tab_search_path)
71
- assert_equal(false, ZoneinfoDataSource.alternate_iso3166_tab_search_path.frozen?)
72
- end
73
-
74
- def test_set_alternate_iso3166_tab_search_path_array
75
- path = ['/tmp/iso3166.tab', '/tmp/iso3166']
76
- ZoneinfoDataSource.alternate_iso3166_tab_search_path = path
77
- assert_equal(['/tmp/iso3166.tab', '/tmp/iso3166'], ZoneinfoDataSource.alternate_iso3166_tab_search_path)
78
- refute_same(path, ZoneinfoDataSource.alternate_iso3166_tab_search_path)
79
- end
80
-
81
- def test_set_alternate_iso3166_tab_search_path_array_to_s
82
- ZoneinfoDataSource.alternate_iso3166_tab_search_path = [Pathname.new('/tmp/iso3166.tab')]
83
- assert_equal(['/tmp/iso3166.tab'], ZoneinfoDataSource.alternate_iso3166_tab_search_path)
84
- end
85
-
86
- def test_set_alternate_iso3166_tab_search_path_string
87
- ZoneinfoDataSource.alternate_iso3166_tab_search_path = ['/tmp/iso3166.tab', '/tmp/iso3166'].join(File::PATH_SEPARATOR)
88
- assert_equal(['/tmp/iso3166.tab', '/tmp/iso3166'], ZoneinfoDataSource.alternate_iso3166_tab_search_path)
89
- end
90
-
91
- def test_new_search
92
- Dir.mktmpdir('tzinfo_test_dir1') do |dir1|
93
- Dir.mktmpdir('tzinfo_test_dir2') do |dir2|
94
- Dir.mktmpdir('tzinfo_test_dir3') do |dir3|
95
- Dir.mktmpdir('tzinfo_test_dir4') do |dir4|
96
- file = File.join(dir1, 'file')
97
- FileUtils.touch(File.join(dir2, 'zone.tab'))
98
- FileUtils.touch(File.join(dir3, 'iso3166.tab'))
99
- FileUtils.touch(File.join(dir4, 'zone.tab'))
100
- FileUtils.touch(File.join(dir4, 'iso3166.tab'))
101
-
102
- ZoneinfoDataSource.search_path = [file, dir2, dir3, dir4]
103
- ZoneinfoDataSource.alternate_iso3166_tab_search_path = []
104
-
105
- data_source = ZoneinfoDataSource.new
106
- assert_equal(dir4, data_source.zoneinfo_dir)
107
- end
108
- end
109
- end
110
- end
111
- end
112
-
113
- def test_new_search_zone1970
114
- Dir.mktmpdir('tzinfo_test_dir1') do |dir1|
115
- Dir.mktmpdir('tzinfo_test_dir2') do |dir2|
116
- Dir.mktmpdir('tzinfo_test_dir3') do |dir3|
117
- Dir.mktmpdir('tzinfo_test_dir4') do |dir4|
118
- file = File.join(dir1, 'file')
119
- FileUtils.touch(File.join(dir2, 'zone1970.tab'))
120
- FileUtils.touch(File.join(dir3, 'iso3166.tab'))
121
- FileUtils.touch(File.join(dir4, 'zone1970.tab'))
122
- FileUtils.touch(File.join(dir4, 'iso3166.tab'))
123
-
124
- ZoneinfoDataSource.search_path = [file, dir2, dir3, dir4]
125
- ZoneinfoDataSource.alternate_iso3166_tab_search_path = []
126
-
127
- data_source = ZoneinfoDataSource.new
128
- assert_equal(dir4, data_source.zoneinfo_dir)
129
- end
130
- end
131
- end
132
- end
133
- end
134
-
135
- def test_new_search_solaris_tab_files
136
- # Solaris names the tab files 'tab/country.tab' (iso3166.tab) and
137
- # 'tab/zone_sun.tab' (zone.tab).
138
-
139
- Dir.mktmpdir('tzinfo_test_dir') do |dir|
140
- tab = File.join(dir, 'tab')
141
- FileUtils.mkdir(tab)
142
- FileUtils.touch(File.join(tab, 'country.tab'))
143
- FileUtils.touch(File.join(tab, 'zone_sun.tab'))
144
-
145
- ZoneinfoDataSource.search_path = [dir]
146
- ZoneinfoDataSource.alternate_iso3166_tab_search_path = []
147
-
148
- data_source = ZoneinfoDataSource.new
149
- assert_equal(dir, data_source.zoneinfo_dir)
150
- end
151
- end
152
-
153
- def test_new_search_alternate_iso3166_path
154
- Dir.mktmpdir('tzinfo_test_dir_zoneinfo') do |zoneinfo_dir|
155
- Dir.mktmpdir('tzinfo_test_dir_tab') do |tab_dir|
156
- FileUtils.touch(File.join(zoneinfo_dir, 'zone.tab'))
157
-
158
- tab_file = File.join(tab_dir, 'iso3166')
159
-
160
- ZoneinfoDataSource.search_path = [zoneinfo_dir]
161
- ZoneinfoDataSource.alternate_iso3166_tab_search_path = [tab_file]
162
-
163
- assert_raises(ZoneinfoDirectoryNotFound) do
164
- ZoneinfoDataSource.new
165
- end
166
-
167
- FileUtils.touch(tab_file)
168
-
169
- data_source = ZoneinfoDataSource.new
170
- assert_equal(zoneinfo_dir, data_source.zoneinfo_dir)
171
- end
172
- end
173
- end
174
-
175
- def test_new_search_not_found
176
- Dir.mktmpdir('tzinfo_test_dir1') do |dir1|
177
- Dir.mktmpdir('tzinfo_test_dir2') do |dir2|
178
- Dir.mktmpdir('tzinfo_test_dir3') do |dir3|
179
- Dir.mktmpdir('tzinfo_test_dir4') do |dir4|
180
- Dir.mktmpdir('tzinfo_test_dir5') do |dir5|
181
- file = File.join(dir1, 'file')
182
- FileUtils.touch(file)
183
- FileUtils.touch(File.join(dir2, 'zone.tab'))
184
- FileUtils.touch(File.join(dir3, 'zone1970.tab'))
185
- FileUtils.touch(File.join(dir4, 'iso3166.tab'))
186
-
187
- ZoneinfoDataSource.search_path = [file, dir2, dir3, dir4, dir5]
188
- ZoneinfoDataSource.alternate_iso3166_tab_search_path = []
189
-
190
- assert_raises(ZoneinfoDirectoryNotFound) do
191
- ZoneinfoDataSource.new
192
- end
193
- end
194
- end
195
- end
196
- end
197
- end
198
- end
199
-
200
- def test_new_search_relative
201
- Dir.mktmpdir('tzinfo_test') do |dir|
202
- FileUtils.touch(File.join(dir, 'zone.tab'))
203
- FileUtils.touch(File.join(dir, 'iso3166.tab'))
204
-
205
- FileUtils.chdir(dir)
206
-
207
- ZoneinfoDataSource.search_path = ['.']
208
- ZoneinfoDataSource.alternate_iso3166_tab_search_path = []
209
- data_source = ZoneinfoDataSource.new
210
- assert_equal(Pathname.new(dir).realpath.to_s, data_source.zoneinfo_dir)
211
-
212
- # Change out of the directory to allow it to be deleted on Windows.
213
- FileUtils.chdir(@orig_pwd)
214
- end
215
- end
216
-
217
- def test_new_dir
218
- Dir.mktmpdir('tzinfo_test') do |dir|
219
- FileUtils.touch(File.join(dir, 'zone.tab'))
220
- FileUtils.touch(File.join(dir, 'iso3166.tab'))
221
-
222
- data_source = ZoneinfoDataSource.new(dir)
223
- assert_equal(dir, data_source.zoneinfo_dir)
224
- end
225
- end
226
-
227
- def test_new_dir_zone1970
228
- Dir.mktmpdir('tzinfo_test') do |dir|
229
- FileUtils.touch(File.join(dir, 'zone1970.tab'))
230
- FileUtils.touch(File.join(dir, 'iso3166.tab'))
231
-
232
- data_source = ZoneinfoDataSource.new(dir)
233
- assert_equal(dir, data_source.zoneinfo_dir)
234
- end
235
- end
236
-
237
- def test_new_dir_solaris_tab_files
238
- # Solaris names the tab files 'tab/country.tab' (iso3166.tab) and
239
- # 'tab/zone_sun.tab' (zone.tab).
240
-
241
- Dir.mktmpdir('tzinfo_test') do |dir|
242
- tab = File.join(dir, 'tab')
243
- FileUtils.mkdir(tab)
244
- FileUtils.touch(File.join(tab, 'country.tab'))
245
- FileUtils.touch(File.join(tab, 'zone_sun.tab'))
246
-
247
- data_source = ZoneinfoDataSource.new(dir)
248
- assert_equal(dir, data_source.zoneinfo_dir)
249
- end
250
- end
251
-
252
- def test_new_dir_alternate_iso3166_path
253
- Dir.mktmpdir('tzinfo_test_dir_zoneinfo') do |zoneinfo_dir|
254
- Dir.mktmpdir('tzinfo_test_dir_tab') do |tab_dir|
255
- FileUtils.touch(File.join(zoneinfo_dir, 'zone.tab'))
256
-
257
- tab_file = File.join(tab_dir, 'iso3166')
258
- FileUtils.touch(tab_file)
259
-
260
- ZoneinfoDataSource.alternate_iso3166_tab_search_path = [tab_file]
261
-
262
- assert_raises(InvalidZoneinfoDirectory) do
263
- # The alternate_iso3166_tab_search_path should not be used. This should raise
264
- # an exception.
265
- ZoneinfoDataSource.new(zoneinfo_dir)
266
- end
267
-
268
- data_source = ZoneinfoDataSource.new(zoneinfo_dir, tab_file)
269
- assert_equal(zoneinfo_dir, data_source.zoneinfo_dir)
270
- end
271
- end
272
- end
273
-
274
- def test_new_dir_invalid
275
- Dir.mktmpdir('tzinfo_test') do |dir|
276
- assert_raises(InvalidZoneinfoDirectory) do
277
- ZoneinfoDataSource.new(dir)
278
- end
279
- end
280
- end
281
-
282
- def test_new_dir_invalid_alternate_iso3166_path
283
- Dir.mktmpdir('tzinfo_test_dir_zoneinfo') do |zoneinfo_dir|
284
- Dir.mktmpdir('tzinfo_test_dir_tab') do |tab_dir|
285
- FileUtils.touch(File.join(zoneinfo_dir, 'zone.tab'))
286
-
287
- assert_raises(InvalidZoneinfoDirectory) do
288
- ZoneinfoDataSource.new(zoneinfo_dir, File.join(tab_dir, 'iso3166'))
289
- end
290
- end
291
- end
292
- end
293
-
294
- def test_new_dir_invalid_alternate_iso3166_path_overrides_valid
295
- Dir.mktmpdir('tzinfo_test_dir_zoneinfo') do |zoneinfo_dir|
296
- Dir.mktmpdir('tzinfo_test_dir_tab') do |tab_dir|
297
- FileUtils.touch(File.join(zoneinfo_dir, 'iso3166.tab'))
298
- FileUtils.touch(File.join(zoneinfo_dir, 'zone.tab'))
299
-
300
- assert_raises(InvalidZoneinfoDirectory) do
301
- ZoneinfoDataSource.new(zoneinfo_dir, File.join(tab_dir, 'iso3166'))
302
- end
303
- end
304
- end
305
- end
306
-
307
- def test_new_file
308
- Dir.mktmpdir('tzinfo_test') do |dir|
309
- file = File.join(dir, 'file')
310
- FileUtils.touch(file)
311
-
312
- assert_raises(InvalidZoneinfoDirectory) do
313
- ZoneinfoDataSource.new(file)
314
- end
315
- end
316
- end
317
-
318
- def test_new_dir_relative
319
- Dir.mktmpdir('tzinfo_test') do |dir|
320
- FileUtils.touch(File.join(dir, 'zone.tab'))
321
- FileUtils.touch(File.join(dir, 'iso3166.tab'))
322
-
323
- FileUtils.chdir(dir)
324
-
325
- data_source = ZoneinfoDataSource.new('.')
326
- assert_equal(Pathname.new(dir).realpath.to_s, data_source.zoneinfo_dir)
327
-
328
- # Change out of the directory to allow it to be deleted on Windows.
329
- FileUtils.chdir(@orig_pwd)
330
- end
331
- end
332
-
333
- def test_zoneinfo_dir
334
- Dir.mktmpdir('tzinfo_test') do |dir|
335
- FileUtils.touch(File.join(dir, 'zone.tab'))
336
- FileUtils.touch(File.join(dir, 'iso3166.tab'))
337
-
338
- data_source = ZoneinfoDataSource.new(dir)
339
- assert_equal(dir, data_source.zoneinfo_dir)
340
- assert_equal(true, data_source.zoneinfo_dir.frozen?)
341
- end
342
- end
343
-
344
- def test_load_timezone_info_data
345
- info = @data_source.load_timezone_info('Europe/London')
346
- assert_kind_of(ZoneinfoTimezoneInfo, info)
347
- assert_equal('Europe/London', info.identifier)
348
- end
349
-
350
- def test_load_timezone_info_linked
351
- info = @data_source.load_timezone_info('UTC')
352
-
353
- # On platforms that don't support symlinks, 'UTC' will be created as a copy.
354
- # Either way, a ZoneinfoTimezoneInfo should be returned.
355
-
356
- assert_kind_of(ZoneinfoTimezoneInfo, info)
357
- assert_equal('UTC', info.identifier)
358
- end
359
-
360
- def test_load_timezone_info_does_not_exist
361
- assert_raises(InvalidTimezoneIdentifier) do
362
- @data_source.load_timezone_info('Nowhere/Special')
363
- end
364
- end
365
-
366
- def test_load_timezone_info_invalid
367
- assert_raises(InvalidTimezoneIdentifier) do
368
- @data_source.load_timezone_info('../zoneinfo/Europe/London')
369
- end
370
- end
371
-
372
- %w(leapseconds localtime).each do |file_name|
373
- define_method("test_load_timezone_info_ignored_#{file_name}_file") do
374
- assert_raises(InvalidTimezoneIdentifier) do
375
- @data_source.load_timezone_info(file_name)
376
- end
377
- end
378
- end
379
-
380
- def test_load_timezone_info_ignored_plus_version_file
381
- # Mac OS X includes a file named +VERSION containing the tzdata version.
382
-
383
- Dir.mktmpdir('tzinfo_test') do |dir|
384
- FileUtils.touch(File.join(dir, 'zone.tab'))
385
- FileUtils.touch(File.join(dir, 'iso3166.tab'))
386
-
387
- File.open(File.join(dir, '+VERSION'), 'w') do |f|
388
- f.binmode
389
- f.write("2013a\n")
390
- end
391
-
392
- data_source = ZoneinfoDataSource.new(dir)
393
-
394
- assert_raises(InvalidTimezoneIdentifier) do
395
- data_source.load_timezone_info('+VERSION')
396
- end
397
- end
398
- end
399
-
400
- def test_load_timezone_info_ignored_timeconfig_symlink
401
- # Slackware includes a symlink named timeconfig that points at /usr/sbin/timeconfig.
402
-
403
- Dir.mktmpdir('tzinfo_test_target') do |target_dir|
404
- target_path = File.join(target_dir, 'timeconfig')
405
-
406
- File.open(target_path, 'w') do |f|
407
- f.write("#!/bin/sh\n")
408
- f.write("#\n")
409
- f.write('# timeconfig Slackware Linux timezone configuration utility.\n')
410
- end
411
-
412
- Dir.mktmpdir('tzinfo_test') do |dir|
413
- FileUtils.touch(File.join(dir, 'zone.tab'))
414
- FileUtils.touch(File.join(dir, 'iso3166.tab'))
415
- FileUtils.cp(File.join(@data_source.zoneinfo_dir, 'EST'), File.join(dir, 'EST'))
416
-
417
- symlink_path = File.join(dir, 'timeconfig')
418
- begin
419
- FileUtils.ln_s(target_path, symlink_path)
420
- rescue NotImplementedError, Errno::EACCES
421
- # Symlinks not supported on this platform, or permission denied
422
- # (administrative rights are required on Windows). Copy instead.
423
- FileUtils.cp(target_path, symlink_path)
424
- end
425
-
426
- data_source = ZoneinfoDataSource.new(dir)
427
-
428
- assert_raises(InvalidTimezoneIdentifier) do
429
- data_source.load_timezone_info('timeconfig')
430
- end
431
- end
432
- end
433
- end
434
-
435
- def test_load_timezone_info_nil
436
- assert_raises(InvalidTimezoneIdentifier) do
437
- @data_source.load_timezone_info(nil)
438
- end
439
- end
440
-
441
- def test_load_timezone_info_case
442
- assert_raises(InvalidTimezoneIdentifier) do
443
- @data_source.load_timezone_info('europe/london')
444
- end
445
- end
446
-
447
- def test_load_timezone_info_permission_denied
448
- Dir.mktmpdir('tzinfo_test') do |dir|
449
- FileUtils.touch(File.join(dir, 'zone.tab'))
450
- FileUtils.touch(File.join(dir, 'iso3166.tab'))
451
-
452
- file = File.join(dir, 'UTC')
453
- FileUtils.touch(file)
454
- FileUtils.chmod(0200, file)
455
-
456
- data_source = ZoneinfoDataSource.new(dir)
457
-
458
- assert_raises(InvalidTimezoneIdentifier) do
459
- data_source.load_timezone_info('UTC')
460
- end
461
- end
462
- end
463
-
464
- def test_load_timezone_info_directory
465
- Dir.mktmpdir('tzinfo_test') do |dir|
466
- FileUtils.touch(File.join(dir, 'zone.tab'))
467
- FileUtils.touch(File.join(dir, 'iso3166.tab'))
468
-
469
- subdir = File.join(dir, 'Subdir')
470
- FileUtils.mkdir(subdir)
471
-
472
- data_source = ZoneinfoDataSource.new(dir)
473
-
474
- assert_raises(InvalidTimezoneIdentifier) do
475
- data_source.load_timezone_info('Subdir')
476
- end
477
- end
478
- end
479
-
480
- def test_load_timezone_info_linked_absolute_outside
481
- Dir.mktmpdir('tzinfo_test') do |dir|
482
- Dir.mktmpdir('tzinfo_test') do |outside|
483
- outside_file = File.join(outside, 'EST')
484
- FileUtils.cp(File.join(@data_source.zoneinfo_dir, 'EST'), outside_file)
485
-
486
- FileUtils.touch(File.join(dir, 'zone.tab'))
487
- FileUtils.touch(File.join(dir, 'iso3166.tab'))
488
-
489
- file = File.join(dir, 'EST')
490
-
491
- begin
492
- FileUtils.ln_s(outside_file, file)
493
- rescue NotImplementedError, Errno::EACCES
494
- # Symlinks not supported on this platform, or permission denied
495
- # (administrative rights are required on Windows). Skip test.
496
- return
497
- end
498
-
499
- data_source = ZoneinfoDataSource.new(dir)
500
-
501
- info = data_source.load_timezone_info('EST')
502
- assert_kind_of(ZoneinfoTimezoneInfo, info)
503
- assert_equal('EST', info.identifier)
504
- end
505
- end
506
- end
507
-
508
- def test_load_timezone_info_linked_absolute_inside
509
- Dir.mktmpdir('tzinfo_test') do |dir|
510
- FileUtils.touch(File.join(dir, 'zone.tab'))
511
- FileUtils.touch(File.join(dir, 'iso3166.tab'))
512
-
513
- FileUtils.cp(File.join(@data_source.zoneinfo_dir, 'EST'), File.join(dir, 'EST'))
514
-
515
- link = File.join(dir, 'Link')
516
-
517
- begin
518
- FileUtils.ln_s(File.join(File.expand_path(dir), 'EST'), link)
519
- rescue NotImplementedError, Errno::EACCES
520
- # Symlinks not supported on this platform, or permission denied
521
- # (administrative rights are required on Windows). Skip test.
522
- return
523
- end
524
-
525
- data_source = ZoneinfoDataSource.new(dir)
526
-
527
- info = data_source.load_timezone_info('Link')
528
- assert_kind_of(ZoneinfoTimezoneInfo, info)
529
- assert_equal('Link', info.identifier)
530
- end
531
- end
532
-
533
- def test_load_timezone_info_linked_relative_outside
534
- Dir.mktmpdir('tzinfo_test') do |root|
535
- FileUtils.cp(File.join(@data_source.zoneinfo_dir, 'EST'), File.join(root, 'outside'))
536
-
537
- dir = File.join(root, 'zoneinfo')
538
- FileUtils.mkdir(dir)
539
-
540
- FileUtils.touch(File.join(dir, 'zone.tab'))
541
- FileUtils.touch(File.join(dir, 'iso3166.tab'))
542
-
543
- link = File.join(dir, 'Link')
544
-
545
- begin
546
- FileUtils.ln_s('../outside', link)
547
- rescue NotImplementedError, Errno::EACCES
548
- # Symlinks not supported on this platform, or permission denied
549
- # (administrative rights are required on Windows). Skip test.
550
- return
551
- end
552
-
553
- subdir = File.join(dir, 'Subdir')
554
- subdir_link = File.join(subdir, 'Link')
555
- FileUtils.mkdir(subdir)
556
- FileUtils.ln_s('../../outside', subdir_link)
557
-
558
- data_source = ZoneinfoDataSource.new(dir)
559
-
560
- info = data_source.load_timezone_info('Link')
561
- assert_kind_of(ZoneinfoTimezoneInfo, info)
562
- assert_equal('Link', info.identifier)
563
-
564
- info = data_source.load_timezone_info('Subdir/Link')
565
- assert_kind_of(ZoneinfoTimezoneInfo, info)
566
- assert_equal('Subdir/Link', info.identifier)
567
- end
568
- end
569
-
570
- def test_load_timezone_info_linked_relative_parent_inside
571
- Dir.mktmpdir('tzinfo_test') do |dir|
572
- FileUtils.touch(File.join(dir, 'zone.tab'))
573
- FileUtils.touch(File.join(dir, 'iso3166.tab'))
574
-
575
- FileUtils.cp(File.join(@data_source.zoneinfo_dir, 'EST'), File.join(dir, 'EST'))
576
-
577
- subdir = File.join(dir, 'Subdir')
578
- FileUtils.mkdir(subdir)
579
- FileUtils.cp(File.join(@data_source.zoneinfo_dir, 'EST'), File.join(subdir, 'EST'))
580
-
581
- subdir_link = File.join(subdir, 'Link')
582
- begin
583
- FileUtils.ln_s('../Subdir/EST', subdir_link)
584
- rescue NotImplementedError, Errno::EACCES
585
- # Symlinks not supported on this platform, or permission denied
586
- # (administrative rights are required on Windows). Skip test.
587
- return
588
- end
589
-
590
- subdir_link2 = File.join(subdir, 'Link2')
591
- FileUtils.ln_s('../EST', subdir_link2)
592
-
593
- subdir2 = File.join(dir, 'Subdir2')
594
- FileUtils.mkdir(subdir2)
595
- subdir2_link = File.join(subdir2, 'Link')
596
- FileUtils.ln_s('../Subdir/EST', subdir2_link)
597
-
598
- data_source = ZoneinfoDataSource.new(dir)
599
-
600
- info = data_source.load_timezone_info('Subdir/Link')
601
- assert_kind_of(ZoneinfoTimezoneInfo, info)
602
- assert_equal('Subdir/Link', info.identifier)
603
-
604
- info = data_source.load_timezone_info('Subdir/Link2')
605
- assert_kind_of(ZoneinfoTimezoneInfo, info)
606
- assert_equal('Subdir/Link2', info.identifier)
607
-
608
- info = data_source.load_timezone_info('Subdir2/Link')
609
- assert_kind_of(ZoneinfoTimezoneInfo, info)
610
- assert_equal('Subdir2/Link', info.identifier)
611
- end
612
- end
613
-
614
- def test_load_timezone_info_invalid_file
615
- Dir.mktmpdir('tzinfo_test') do |dir|
616
- FileUtils.touch(File.join(dir, 'zone.tab'))
617
- FileUtils.touch(File.join(dir, 'iso3166.tab'))
618
-
619
- File.open(File.join(dir, 'Zone'), 'wb') do |file|
620
- file.write('NotAValidTZifFile')
621
- end
622
-
623
- data_source = ZoneinfoDataSource.new(dir)
624
-
625
- assert_raises(InvalidTimezoneIdentifier) do
626
- data_source.load_timezone_info('Zone')
627
- end
628
- end
629
- end
630
-
631
- def test_load_timezone_info_invalid_file_2
632
- Dir.mktmpdir('tzinfo_test') do |dir|
633
- FileUtils.touch(File.join(dir, 'zone.tab'))
634
- FileUtils.touch(File.join(dir, 'iso3166.tab'))
635
-
636
- zone = File.join(dir, 'Zone')
637
-
638
- File.open(File.join(@data_source.zoneinfo_dir, 'EST')) do |src|
639
- # Change header to TZif1 (which is not a valid header).
640
- File.open(zone, 'wb') do |dest|
641
- dest.write('TZif1')
642
- src.pos = 5
643
- FileUtils.copy_stream(src, dest)
644
- end
645
- end
646
-
647
- data_source = ZoneinfoDataSource.new(dir)
648
-
649
- assert_raises(InvalidTimezoneIdentifier) do
650
- data_source.load_timezone_info('Zone')
651
- end
652
- end
653
- end
654
-
655
- def test_load_timezone_info_tainted
656
- skip_if_taint_is_undefined_or_no_op
657
-
658
- safe_test(:unavailable => :skip) do
659
- identifier = 'Europe/Amsterdam'.dup.taint
660
- assert(identifier.tainted?)
661
- info = @data_source.load_timezone_info(identifier)
662
- assert_equal('Europe/Amsterdam', info.identifier)
663
- assert(identifier.tainted?)
664
- end
665
- end
666
-
667
- def test_load_timezone_info_tainted_and_frozen
668
- skip_if_taint_is_undefined_or_no_op
669
-
670
- safe_test do
671
- info = @data_source.load_timezone_info('Europe/Amsterdam'.dup.taint.freeze)
672
- assert_equal('Europe/Amsterdam', info.identifier)
673
- end
674
- end
675
-
676
- def test_load_timezone_info_tainted_zoneinfo_dir_safe_mode
677
- skip_if_taint_is_undefined_or_no_op
678
-
679
- safe_test(:unavailable => :skip) do
680
- assert_raises(SecurityError) do
681
- ZoneinfoDataSource.new(@data_source.zoneinfo_dir.dup.taint)
682
- end
683
- end
684
- end
685
-
686
- def test_load_timezone_info_tainted_zoneinfo_dir
687
- skip_if_taint_is_undefined_or_no_op
688
-
689
- data_source = ZoneinfoDataSource.new(@data_source.zoneinfo_dir.dup.taint)
690
- info = data_source.load_timezone_info('Europe/London')
691
- assert_kind_of(ZoneinfoTimezoneInfo, info)
692
- assert_equal('Europe/London', info.identifier)
693
- end
694
-
695
- def get_timezone_filenames(directory)
696
- entries = Dir.glob(File.join(directory, '**', '*'))
697
-
698
- entries = entries.select do |file|
699
- RubyCoreSupport.untaint(file)
700
- File.file?(file)
701
- end
702
-
703
- entries = entries.collect {|file| file[directory.length + File::SEPARATOR.length, file.length - directory.length - File::SEPARATOR.length]}
704
-
705
- # Exclude right (with leapseconds) and posix (copy) directories; .tab files; leapseconds, localtime and posixrules files.
706
- entries = entries.select do |file|
707
- file !~ /\A(posix|right)\// &&
708
- file !~ /\.tab\z/ &&
709
- !%w(leapseconds localtime posixrules).include?(file)
710
- end
711
-
712
- entries.sort
713
- end
714
-
715
- def test_timezone_identifiers
716
- expected = get_timezone_filenames(@data_source.zoneinfo_dir)
717
- all = @data_source.timezone_identifiers
718
- assert_kind_of(Array, all)
719
- assert_array_same_items(expected, all)
720
- assert_equal(true, all.frozen?)
721
- end
722
-
723
- def test_data_timezone_identifiers
724
- expected = get_timezone_filenames(@data_source.zoneinfo_dir)
725
- all_data = @data_source.data_timezone_identifiers
726
- assert_kind_of(Array, all_data)
727
- assert_array_same_items(expected, all_data)
728
- assert_equal(true, all_data.frozen?)
729
- end
730
-
731
- def test_linked_timezone_identifiers
732
- all_linked = @data_source.linked_timezone_identifiers
733
- assert_kind_of(Array, all_linked)
734
- assert_equal(true, all_linked.empty?)
735
- assert_equal(true, all_linked.frozen?)
736
- end
737
-
738
- def test_timezone_identifiers_safe_mode
739
- safe_test do
740
- expected = get_timezone_filenames(@data_source.zoneinfo_dir)
741
- all = @data_source.timezone_identifiers
742
- assert_kind_of(Array, all)
743
- assert_array_same_items(expected, all)
744
- assert_equal(true, all.frozen?)
745
- end
746
- end
747
-
748
- def test_timezone_identifiers_ignored_plus_version_file
749
- # Mac OS X includes a file named +VERSION containing the tzdata version.
750
-
751
- Dir.mktmpdir('tzinfo_test') do |dir|
752
- FileUtils.touch(File.join(dir, 'zone.tab'))
753
- FileUtils.touch(File.join(dir, 'iso3166.tab'))
754
- FileUtils.cp(File.join(@data_source.zoneinfo_dir, 'EST'), File.join(dir, 'EST'))
755
-
756
- File.open(File.join(dir, '+VERSION'), 'w') do |f|
757
- f.binmode
758
- f.write("2013a\n")
759
- end
760
-
761
- data_source = ZoneinfoDataSource.new(dir)
762
- assert_array_same_items(['EST'], data_source.timezone_identifiers)
763
- end
764
- end
765
-
766
- def test_timezone_identifiers_ignored_timeconfig_symlink
767
- # Slackware includes a symlink named timeconfig that points at /usr/sbin/timeconfig.
768
-
769
- Dir.mktmpdir('tzinfo_test_target') do |target_dir|
770
- target_path = File.join(target_dir, 'timeconfig')
771
-
772
- File.open(target_path, 'w') do |f|
773
- f.write("#!/bin/sh\n")
774
- f.write("#\n")
775
- f.write('# timeconfig Slackware Linux timezone configuration utility.\n')
776
- end
777
-
778
- Dir.mktmpdir('tzinfo_test') do |dir|
779
- FileUtils.touch(File.join(dir, 'zone.tab'))
780
- FileUtils.touch(File.join(dir, 'iso3166.tab'))
781
- FileUtils.cp(File.join(@data_source.zoneinfo_dir, 'EST'), File.join(dir, 'EST'))
782
-
783
- symlink_path = File.join(dir, 'timeconfig')
784
- begin
785
- FileUtils.ln_s(target_path, symlink_path)
786
- rescue NotImplementedError, Errno::EACCES
787
- # Symlinks not supported on this platform, or permission denied
788
- # (administrative rights are required on Windows). Copy instead.
789
- FileUtils.cp(target_path, symlink_path)
790
- end
791
-
792
- data_source = ZoneinfoDataSource.new(dir)
793
- assert_array_same_items(['EST'], data_source.timezone_identifiers)
794
- end
795
- end
796
- end
797
-
798
- def test_timezone_identifiers_ignored_src_directory
799
- # Solaris includes a src directory containing the source timezone data files
800
- # from the tzdata distribution. These should be ignored.
801
-
802
- Dir.mktmpdir('tzinfo_test') do |dir|
803
- FileUtils.touch(File.join(dir, 'zone.tab'))
804
- FileUtils.touch(File.join(dir, 'iso3166.tab'))
805
- FileUtils.cp(File.join(@data_source.zoneinfo_dir, 'EST'), File.join(dir, 'EST'))
806
-
807
- src_dir = File.join(dir, 'src')
808
- FileUtils.mkdir(src_dir)
809
-
810
- File.open(File.join(src_dir, 'europe'), 'w') do |f|
811
- f.binmode
812
- f.write("Zone\tEurope/London\t0:00\tEU\tGMT/BST\n")
813
- end
814
-
815
- data_source = ZoneinfoDataSource.new(dir)
816
- assert_array_same_items(['EST'], data_source.timezone_identifiers)
817
- end
818
- end
819
-
820
- def test_timezone_identifiers_ignored_security_file
821
- # The Arch linux tzdata package includes a file named SECURITY giving
822
- # instructions for reporting security-related bugs.
823
-
824
- Dir.mktmpdir('tzinfo_test') do |dir|
825
- FileUtils.touch(File.join(dir, 'zone.tab'))
826
- FileUtils.touch(File.join(dir, 'iso3166.tab'))
827
- FileUtils.cp(File.join(@data_source.zoneinfo_dir, 'EST'), File.join(dir, 'EST'))
828
-
829
- File.open(File.join(dir, 'SECURITY'), 'w') do |f|
830
- f.binmode
831
- f.write("Please report any sensitive security-related bugs...\n")
832
- end
833
-
834
- data_source = ZoneinfoDataSource.new(dir)
835
- assert_equal(['EST'], data_source.timezone_identifiers)
836
- end
837
- end
838
-
839
- def test_load_country_info
840
- info = @data_source.load_country_info('GB')
841
- assert_equal('GB', info.code)
842
- assert_equal('Britain (UK)', info.name)
843
- end
844
-
845
- def test_load_country_info_not_exist
846
- assert_raises(InvalidCountryCode) do
847
- @data_source.load_country_info('ZZ')
848
- end
849
- end
850
-
851
- def test_load_country_info_invalid
852
- assert_raises(InvalidCountryCode) do
853
- @data_source.load_country_info('../Countries/GB')
854
- end
855
- end
856
-
857
- def test_load_country_info_nil
858
- assert_raises(InvalidCountryCode) do
859
- @data_source.load_country_info(nil)
860
- end
861
- end
862
-
863
- def test_load_country_info_case
864
- assert_raises(InvalidCountryCode) do
865
- @data_source.load_country_info('gb')
866
- end
867
- end
868
-
869
- def test_load_country_info_tainted
870
- skip_if_taint_is_undefined_or_no_op
871
-
872
- safe_test(:unavailable => :skip) do
873
- code = 'NL'.dup.taint
874
- assert(code.tainted?)
875
- info = @data_source.load_country_info(code)
876
- assert_equal('NL', info.code)
877
- assert(code.tainted?)
878
- end
879
- end
880
-
881
- def test_load_country_info_tainted_and_frozen
882
- skip_if_taint_is_undefined_or_no_op
883
-
884
- safe_test do
885
- info = @data_source.load_country_info('NL'.dup.taint.freeze)
886
- assert_equal('NL', info.code)
887
- end
888
- end
889
-
890
- def test_load_country_info_check_zones
891
- Dir.mktmpdir('tzinfo_test') do |dir|
892
- RubyCoreSupport.open_file(File.join(dir, 'iso3166.tab'), 'w', :external_encoding => 'UTF-8') do |iso3166|
893
- iso3166.puts('# iso3166.tab')
894
- iso3166.puts('')
895
- iso3166.puts("FC\tFake Country")
896
- iso3166.puts("OC\tOther Country")
897
- end
898
-
899
- RubyCoreSupport.open_file(File.join(dir, 'zone.tab'), 'w', :external_encoding => 'UTF-8') do |zone|
900
- zone.puts('# zone.tab')
901
- zone.puts('')
902
- zone.puts("FC\t+513030-0000731\tFake/One\tDescription of one")
903
- zone.puts("FC\t+353916+1394441\tFake/Two\tAnother description")
904
- zone.puts("FC\t-2332-04637\tFake/Three\tThis is Three")
905
- zone.puts("OC\t+5005+01426\tOther/One")
906
- end
907
-
908
- data_source = ZoneinfoDataSource.new(dir)
909
-
910
- info = data_source.load_country_info('FC')
911
- assert_equal('FC', info.code)
912
- assert_equal('Fake Country', info.name)
913
- assert_equal(['Fake/One', 'Fake/Two', 'Fake/Three'], info.zone_identifiers)
914
- assert_equal(true, info.zone_identifiers.frozen?)
915
- assert_equal([
916
- CountryTimezone.new('Fake/One', Rational(6181, 120), Rational(-451, 3600), 'Description of one'),
917
- CountryTimezone.new('Fake/Two', Rational(32089, 900), Rational(503081, 3600), 'Another description'),
918
- CountryTimezone.new('Fake/Three', Rational(-353, 15), Rational(-2797, 60), 'This is Three')], info.zones)
919
- assert_equal(true, info.zones.frozen?)
920
-
921
- info = data_source.load_country_info('OC')
922
- assert_equal('OC', info.code)
923
- assert_equal('Other Country', info.name)
924
- assert_equal(['Other/One'], info.zone_identifiers)
925
- assert_equal(true, info.zone_identifiers.frozen?)
926
- assert_equal([CountryTimezone.new('Other/One', Rational(601, 12), Rational(433, 30))], info.zones)
927
- assert_equal(true, info.zones.frozen?)
928
- end
929
- end
930
-
931
- def test_load_country_info_check_zones_zone1970
932
- Dir.mktmpdir('tzinfo_test') do |dir|
933
- RubyCoreSupport.open_file(File.join(dir, 'iso3166.tab'), 'w', :external_encoding => 'UTF-8') do |iso3166|
934
- iso3166.puts('# iso3166.tab')
935
- iso3166.puts('')
936
- iso3166.puts("AC\tAnother Country")
937
- iso3166.puts("FC\tFake Country")
938
- iso3166.puts("OC\tOther Country")
939
- end
940
-
941
- # zone.tab will be ignored.
942
- RubyCoreSupport.open_file(File.join(dir, 'zone.tab'), 'w', :external_encoding => 'UTF-8') do |zone|
943
- zone.puts('# zone.tab')
944
- zone.puts('')
945
- zone.puts("FC\t+513030-0000731\tFake/One\tDescription of one")
946
- zone.puts("FC\t+353916+1394441\tFake/Two\tAnother description")
947
- zone.puts("FC\t-2332-04637\tFake/Three\tThis is Three")
948
- zone.puts("OC\t+5005+01426\tOther/One")
949
- end
950
-
951
- # zone1970.tab will be used.
952
- RubyCoreSupport.open_file(File.join(dir, 'zone1970.tab'), 'w', :external_encoding => 'UTF-8') do |zone|
953
- zone.puts('# zone1970.tab')
954
- zone.puts('')
955
- zone.puts("AC,OC\t+0000+00000\tMiddle/Another/One\tAnother's One")
956
- zone.puts("FC\t+513030-0000731\tFake/One\tDescription of one")
957
- zone.puts("FC,OC\t+353916+1394441\tFake/Two\tAnother description")
958
- zone.puts("FC,OC\t-2332-04637\tFake/Three\tThis is Three")
959
- zone.puts("OC\t+5005+01426\tOther/One")
960
- zone.puts("OC\t+5015+11426\tOther/Two")
961
- end
962
-
963
- data_source = ZoneinfoDataSource.new(dir)
964
-
965
- info = data_source.load_country_info('AC')
966
- assert_equal('AC', info.code)
967
- assert_equal('Another Country', info.name)
968
- assert_equal(['Middle/Another/One'], info.zone_identifiers)
969
- assert_equal(true, info.zone_identifiers.frozen?)
970
- assert_equal([CountryTimezone.new('Middle/Another/One', Rational(0, 1), Rational(0, 1), "Another's One")], info.zones)
971
- assert_equal(true, info.zones.frozen?)
972
-
973
- info = data_source.load_country_info('FC')
974
- assert_equal('FC', info.code)
975
- assert_equal('Fake Country', info.name)
976
- assert_equal(['Fake/One', 'Fake/Two', 'Fake/Three'], info.zone_identifiers)
977
- assert_equal(true, info.zone_identifiers.frozen?)
978
- assert_equal([
979
- CountryTimezone.new('Fake/One', Rational(6181, 120), Rational(-451, 3600), 'Description of one'),
980
- CountryTimezone.new('Fake/Two', Rational(32089, 900), Rational(503081, 3600), 'Another description'),
981
- CountryTimezone.new('Fake/Three', Rational(-353, 15), Rational(-2797, 60), 'This is Three')], info.zones)
982
- assert_equal(true, info.zones.frozen?)
983
-
984
- # Testing the ordering of zones. A zone can either be primary (country
985
- # code is the first in the first column), or secondary (country code is
986
- # not the first). Should return all the primaries first in the order they
987
- # appeared in the file, followed by all the secondaries in the order they
988
- # appeared in file.
989
-
990
- info = data_source.load_country_info('OC')
991
- assert_equal('OC', info.code)
992
- assert_equal('Other Country', info.name)
993
- assert_equal(['Other/One', 'Other/Two', 'Middle/Another/One', 'Fake/Two', 'Fake/Three'], info.zone_identifiers)
994
- assert_equal(true, info.zone_identifiers.frozen?)
995
- assert_equal([
996
- CountryTimezone.new('Other/One', Rational(601, 12), Rational( 433, 30)),
997
- CountryTimezone.new('Other/Two', Rational(201, 4), Rational(3433, 30)),
998
- CountryTimezone.new('Middle/Another/One', Rational(0, 1), Rational(0, 1), "Another's One"),
999
- CountryTimezone.new('Fake/Two', Rational(32089, 900), Rational(503081, 3600), 'Another description'),
1000
- CountryTimezone.new('Fake/Three', Rational(-353, 15), Rational(-2797, 60), 'This is Three')], info.zones)
1001
- assert_equal(true, info.zones.frozen?)
1002
- end
1003
- end
1004
-
1005
- def test_load_country_info_check_zones_solaris_tab_files
1006
- # Solaris uses 5 columns instead of the usual 4 in zone_sun.tab.
1007
- # An extra column before the comment gives an optional linked/alternate
1008
- # timezone identifier (or '-' if not set).
1009
- #
1010
- # Additionally, there is a section at the end of the file for timezones
1011
- # covering regions. These are given lower-case "country" codes. The timezone
1012
- # identifier column refers to a continent instead of an identifier. These
1013
- # lines will be ignored by TZInfo.
1014
-
1015
- Dir.mktmpdir('tzinfo_test') do |dir|
1016
- tab_dir = File.join(dir, 'tab')
1017
- FileUtils.mkdir(tab_dir)
1018
-
1019
- RubyCoreSupport.open_file(File.join(tab_dir, 'country.tab'), 'w', :external_encoding => 'UTF-8') do |country|
1020
- country.puts('# country.tab')
1021
- country.puts('# Solaris')
1022
- country.puts("FC\tFake Country")
1023
- country.puts("OC\tOther Country")
1024
- end
1025
-
1026
- RubyCoreSupport.open_file(File.join(tab_dir, 'zone_sun.tab'), 'w', :external_encoding => 'UTF-8') do |zone_sun|
1027
- zone_sun.puts('# zone_sun.tab')
1028
- zone_sun.puts('# Solaris')
1029
- zone_sun.puts('# Countries')
1030
- zone_sun.puts("FC\t+513030-0000731\tFake/One\t-\tDescription of one")
1031
- zone_sun.puts("FC\t+353916+1394441\tFake/Two\tFake/Alias/Two\tAnother description")
1032
- zone_sun.puts("FC\t-2332-04637\tFake/Three\tFake/Alias/Three\tThis is Three")
1033
- zone_sun.puts("OC\t+5005+01426\tOther/One\tOther/Linked/One")
1034
- zone_sun.puts("OC\t+5015+01436\tOther/Two\t-")
1035
- zone_sun.puts('# Regions')
1036
- zone_sun.puts("ee\t+0000+00000\tEurope/\tEET")
1037
- zone_sun.puts("me\t+0000+00000\tEurope/\tMET")
1038
- zone_sun.puts("we\t+0000+00000\tEurope/\tWET")
1039
- end
1040
-
1041
- data_source = ZoneinfoDataSource.new(dir)
1042
-
1043
- info = data_source.load_country_info('FC')
1044
- assert_equal('FC', info.code)
1045
- assert_equal('Fake Country', info.name)
1046
- assert_equal(['Fake/One', 'Fake/Two', 'Fake/Three'], info.zone_identifiers)
1047
- assert_equal(true, info.zone_identifiers.frozen?)
1048
- assert_equal([
1049
- CountryTimezone.new('Fake/One', Rational(6181, 120), Rational(-451, 3600), 'Description of one'),
1050
- CountryTimezone.new('Fake/Two', Rational(32089, 900), Rational(503081, 3600), 'Another description'),
1051
- CountryTimezone.new('Fake/Three', Rational(-353, 15), Rational(-2797, 60), 'This is Three')], info.zones)
1052
- assert_equal(true, info.zones.frozen?)
1053
-
1054
- info = data_source.load_country_info('OC')
1055
- assert_equal('OC', info.code)
1056
- assert_equal('Other Country', info.name)
1057
- assert_equal(['Other/One', 'Other/Two'], info.zone_identifiers)
1058
- assert_equal(true, info.zone_identifiers.frozen?)
1059
- assert_equal([
1060
- CountryTimezone.new('Other/One', Rational(601, 12), Rational(433, 30)),
1061
- CountryTimezone.new('Other/Two', Rational(201, 4), Rational(73, 5))], info.zones)
1062
- assert_equal(true, info.zones.frozen?)
1063
- end
1064
- end
1065
-
1066
- def test_load_country_info_check_zones_alternate_iso3166_file
1067
- Dir.mktmpdir('tzinfo_test') do |dir|
1068
- zoneinfo_dir = File.join(dir, 'zoneinfo')
1069
- tab_dir = File.join(dir, 'tab')
1070
- FileUtils.mkdir(zoneinfo_dir)
1071
- FileUtils.mkdir(tab_dir)
1072
-
1073
- tab_file = File.join(tab_dir, 'iso3166')
1074
- RubyCoreSupport.open_file(tab_file, 'w', :external_encoding => 'UTF-8') do |iso3166|
1075
- # Use the BSD 4 column format (alternate iso3166 is used on BSD).
1076
- iso3166.puts("FC\tFCC\t001\tFake Country")
1077
- iso3166.puts("OC\tOCC\t002\tOther Country")
1078
- end
1079
-
1080
- RubyCoreSupport.open_file(File.join(zoneinfo_dir, 'zone.tab'), 'w', :external_encoding => 'UTF-8') do |zone|
1081
- zone.puts("FC\t+513030-0000731\tFake/One\tDescription of one")
1082
- zone.puts("FC\t+353916+1394441\tFake/Two\tAnother description")
1083
- zone.puts("FC\t-2332-04637\tFake/Three\tThis is Three")
1084
- zone.puts("OC\t+5005+01426\tOther/One")
1085
- end
1086
-
1087
- data_source = ZoneinfoDataSource.new(zoneinfo_dir, tab_file)
1088
-
1089
- info = data_source.load_country_info('FC')
1090
- assert_equal('FC', info.code)
1091
- assert_equal('Fake Country', info.name)
1092
- assert_equal(['Fake/One', 'Fake/Two', 'Fake/Three'], info.zone_identifiers)
1093
- assert_equal(true, info.zone_identifiers.frozen?)
1094
- assert_equal([
1095
- CountryTimezone.new('Fake/One', Rational(6181, 120), Rational(-451, 3600), 'Description of one'),
1096
- CountryTimezone.new('Fake/Two', Rational(32089, 900), Rational(503081, 3600), 'Another description'),
1097
- CountryTimezone.new('Fake/Three', Rational(-353, 15), Rational(-2797, 60), 'This is Three')], info.zones)
1098
- assert_equal(true, info.zones.frozen?)
1099
-
1100
- info = data_source.load_country_info('OC')
1101
- assert_equal('OC', info.code)
1102
- assert_equal('Other Country', info.name)
1103
- assert_equal(['Other/One'], info.zone_identifiers)
1104
- assert_equal(true, info.zone_identifiers.frozen?)
1105
- assert_equal([CountryTimezone.new('Other/One', Rational(601, 12), Rational(433, 30))], info.zones)
1106
- assert_equal(true, info.zones.frozen?)
1107
- end
1108
- end
1109
-
1110
- def test_load_country_info_four_column_iso31611
1111
- # OpenBSD and FreeBSD use a 4 column iso3166.tab file that includes
1112
- # alpha-3 and numeric-3 codes in addition to the alpha-2 and name in the
1113
- # tz database version.
1114
-
1115
- Dir.mktmpdir('tzinfo_test') do |dir|
1116
- RubyCoreSupport.open_file(File.join(dir, 'iso3166.tab'), 'w', :external_encoding => 'UTF-8') do |iso3166|
1117
- iso3166.puts("FC\tFCC\t001\tFake Country")
1118
- iso3166.puts("OC\tOCC\t002\tOther Country")
1119
- end
1120
-
1121
- RubyCoreSupport.open_file(File.join(dir, 'zone.tab'), 'w', :external_encoding => 'UTF-8') do |zone|
1122
- zone.puts("FC\t+513030-0000731\tFake/One\tDescription of one")
1123
- zone.puts("OC\t+5005+01426\tOther/One")
1124
- end
1125
-
1126
- data_source = ZoneinfoDataSource.new(dir)
1127
-
1128
- info = data_source.load_country_info('FC')
1129
- assert_equal('FC', info.code)
1130
- assert_equal('Fake Country', info.name)
1131
-
1132
- info = data_source.load_country_info('OC')
1133
- assert_equal('OC', info.code)
1134
- assert_equal('Other Country', info.name)
1135
- end
1136
- end
1137
-
1138
- def test_load_country_info_utf8
1139
- # iso3166.tab is currently in ASCII (as of tzdata 2014f), but will be
1140
- # changed to UTF-8 in the future.
1141
-
1142
- # zone.tab is in ASCII, with no plans to change. Since ASCII is a subset of
1143
- # UTF-8, test that this is loaded in UTF-8 anyway.
1144
-
1145
- Dir.mktmpdir('tzinfo_test') do |dir|
1146
- RubyCoreSupport.open_file(File.join(dir, 'iso3166.tab'), 'w', :external_encoding => 'UTF-8') do |iso3166|
1147
- iso3166.puts("UT\tUnicode Test ✓")
1148
- end
1149
-
1150
- RubyCoreSupport.open_file(File.join(dir, 'zone.tab'), 'w', :external_encoding => 'UTF-8') do |zone|
1151
- zone.puts("UT\t+513030-0000731\tUnicode✓/One\tUnicode Description ✓")
1152
- end
1153
-
1154
- data_source = ZoneinfoDataSource.new(dir)
1155
-
1156
- info = data_source.load_country_info('UT')
1157
- assert_equal('UT', info.code)
1158
- assert_equal('Unicode Test ✓', info.name)
1159
- assert_equal(['Unicode✓/One'], info.zone_identifiers)
1160
- assert_equal([CountryTimezone.new('Unicode✓/One', Rational(6181, 120), Rational(-451, 3600), 'Unicode Description ✓')], info.zones)
1161
- end
1162
- end
1163
-
1164
- def test_load_country_info_utf8_zone1970
1165
- # iso3166.tab is currently in ASCII (as of tzdata 2014f), but will be
1166
- # changed to UTF-8 in the future.
1167
-
1168
- # zone1970.tab is in UTF-8.
1169
-
1170
- Dir.mktmpdir('tzinfo_test') do |dir|
1171
- RubyCoreSupport.open_file(File.join(dir, 'iso3166.tab'), 'w', :external_encoding => 'UTF-8') do |iso3166|
1172
- iso3166.puts("UT\tUnicode Test ✓")
1173
- end
1174
-
1175
- RubyCoreSupport.open_file(File.join(dir, 'zone1970.tab'), 'w', :external_encoding => 'UTF-8') do |zone|
1176
- zone.puts("UT\t+513030-0000731\tUnicode✓/One\tUnicode Description ✓")
1177
- end
1178
-
1179
- data_source = ZoneinfoDataSource.new(dir)
1180
-
1181
- info = data_source.load_country_info('UT')
1182
- assert_equal('UT', info.code)
1183
- assert_equal('Unicode Test ✓', info.name)
1184
- assert_equal(['Unicode✓/One'], info.zone_identifiers)
1185
- assert_equal([CountryTimezone.new('Unicode✓/One', Rational(6181, 120), Rational(-451, 3600), 'Unicode Description ✓')], info.zones)
1186
- end
1187
- end
1188
-
1189
- def test_country_codes
1190
- file_codes = []
1191
-
1192
- RubyCoreSupport.open_file(File.join(@data_source.zoneinfo_dir, 'iso3166.tab'), 'r', :external_encoding => 'UTF-8', :internal_encoding => 'UTF-8') do |file|
1193
- file.each_line do |line|
1194
- line.chomp!
1195
- file_codes << $1 if line =~ /\A([A-Z]{2})\t/
1196
- end
1197
- end
1198
-
1199
- codes = @data_source.country_codes
1200
- assert_array_same_items(file_codes, codes)
1201
- assert_equal(true, codes.frozen?)
1202
- end
1203
-
1204
- def test_country_codes_four_column_iso3166
1205
- # OpenBSD and FreeBSD use a 4 column iso3166.tab file that includes
1206
- # alpha-3 and numeric-3 codes in addition to the alpha-2 and name in the
1207
- # tz database version.
1208
-
1209
- Dir.mktmpdir('tzinfo_test') do |dir|
1210
- RubyCoreSupport.open_file(File.join(dir, 'iso3166.tab'), 'w', :external_encoding => 'UTF-8') do |iso3166|
1211
- iso3166.puts("FC\tFCC\t001\tFake Country")
1212
- iso3166.puts("OC\tOCC\t002\tOther Country")
1213
- end
1214
-
1215
- RubyCoreSupport.open_file(File.join(dir, 'zone.tab'), 'w', :external_encoding => 'UTF-8') do |zone|
1216
- zone.puts("FC\t+513030-0000731\tFake/One\tDescription of one")
1217
- zone.puts("OC\t+5005+01426\tOther/One")
1218
- end
1219
-
1220
- data_source = ZoneinfoDataSource.new(dir)
1221
-
1222
- codes = data_source.country_codes
1223
- assert_array_same_items(%w(FC OC), codes)
1224
- end
1225
- end
1226
- end