tzinfo 1.2.11 → 2.0.0

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