tzinfo 1.2.3 → 2.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (144) hide show
  1. checksums.yaml +5 -5
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/.yardopts +3 -0
  5. data/CHANGES.md +501 -372
  6. data/LICENSE +13 -13
  7. data/README.md +368 -113
  8. data/lib/tzinfo.rb +64 -29
  9. data/lib/tzinfo/country.rb +141 -129
  10. data/lib/tzinfo/country_timezone.rb +71 -101
  11. data/lib/tzinfo/data_source.rb +389 -144
  12. data/lib/tzinfo/data_sources.rb +8 -0
  13. data/lib/tzinfo/data_sources/constant_offset_data_timezone_info.rb +56 -0
  14. data/lib/tzinfo/data_sources/country_info.rb +42 -0
  15. data/lib/tzinfo/data_sources/data_timezone_info.rb +91 -0
  16. data/lib/tzinfo/data_sources/linked_timezone_info.rb +33 -0
  17. data/lib/tzinfo/data_sources/ruby_data_source.rb +143 -0
  18. data/lib/tzinfo/data_sources/timezone_info.rb +47 -0
  19. data/lib/tzinfo/data_sources/transitions_data_timezone_info.rb +214 -0
  20. data/lib/tzinfo/data_sources/zoneinfo_data_source.rb +575 -0
  21. data/lib/tzinfo/data_sources/zoneinfo_reader.rb +286 -0
  22. data/lib/tzinfo/data_timezone.rb +33 -47
  23. data/lib/tzinfo/datetime_with_offset.rb +153 -0
  24. data/lib/tzinfo/format1.rb +10 -0
  25. data/lib/tzinfo/format1/country_definer.rb +17 -0
  26. data/lib/tzinfo/format1/country_index_definition.rb +64 -0
  27. data/lib/tzinfo/format1/timezone_definer.rb +64 -0
  28. data/lib/tzinfo/format1/timezone_definition.rb +39 -0
  29. data/lib/tzinfo/format1/timezone_index_definition.rb +77 -0
  30. data/lib/tzinfo/format2.rb +10 -0
  31. data/lib/tzinfo/format2/country_definer.rb +68 -0
  32. data/lib/tzinfo/format2/country_index_definer.rb +68 -0
  33. data/lib/tzinfo/format2/country_index_definition.rb +46 -0
  34. data/lib/tzinfo/format2/timezone_definer.rb +94 -0
  35. data/lib/tzinfo/format2/timezone_definition.rb +73 -0
  36. data/lib/tzinfo/format2/timezone_index_definer.rb +45 -0
  37. data/lib/tzinfo/format2/timezone_index_definition.rb +55 -0
  38. data/lib/tzinfo/info_timezone.rb +26 -21
  39. data/lib/tzinfo/linked_timezone.rb +33 -52
  40. data/lib/tzinfo/offset_timezone_period.rb +42 -0
  41. data/lib/tzinfo/string_deduper.rb +118 -0
  42. data/lib/tzinfo/time_with_offset.rb +128 -0
  43. data/lib/tzinfo/timestamp.rb +548 -0
  44. data/lib/tzinfo/timestamp_with_offset.rb +85 -0
  45. data/lib/tzinfo/timezone.rb +989 -498
  46. data/lib/tzinfo/timezone_offset.rb +90 -57
  47. data/lib/tzinfo/timezone_period.rb +155 -197
  48. data/lib/tzinfo/timezone_proxy.rb +71 -74
  49. data/lib/tzinfo/timezone_transition.rb +77 -99
  50. data/lib/tzinfo/transitions_timezone_period.rb +63 -0
  51. data/lib/tzinfo/untaint_ext.rb +18 -0
  52. data/lib/tzinfo/version.rb +7 -0
  53. data/lib/tzinfo/with_offset.rb +61 -0
  54. metadata +63 -120
  55. metadata.gz.sig +0 -0
  56. data/Rakefile +0 -107
  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/ruby_core_support.rb +0 -146
  63. data/lib/tzinfo/ruby_country_info.rb +0 -70
  64. data/lib/tzinfo/ruby_data_source.rb +0 -136
  65. data/lib/tzinfo/time_or_datetime.rb +0 -333
  66. data/lib/tzinfo/timezone_definition.rb +0 -36
  67. data/lib/tzinfo/timezone_index_definition.rb +0 -54
  68. data/lib/tzinfo/timezone_info.rb +0 -30
  69. data/lib/tzinfo/timezone_transition_definition.rb +0 -101
  70. data/lib/tzinfo/transition_data_timezone_info.rb +0 -274
  71. data/lib/tzinfo/zoneinfo_country_info.rb +0 -35
  72. data/lib/tzinfo/zoneinfo_data_source.rb +0 -487
  73. data/lib/tzinfo/zoneinfo_timezone_info.rb +0 -294
  74. data/test/tc_country.rb +0 -236
  75. data/test/tc_country_index_definition.rb +0 -69
  76. data/test/tc_country_info.rb +0 -16
  77. data/test/tc_country_timezone.rb +0 -161
  78. data/test/tc_data_source.rb +0 -218
  79. data/test/tc_data_timezone.rb +0 -99
  80. data/test/tc_data_timezone_info.rb +0 -18
  81. data/test/tc_info_timezone.rb +0 -34
  82. data/test/tc_linked_timezone.rb +0 -155
  83. data/test/tc_linked_timezone_info.rb +0 -23
  84. data/test/tc_offset_rationals.rb +0 -23
  85. data/test/tc_ruby_core_support.rb +0 -168
  86. data/test/tc_ruby_country_info.rb +0 -80
  87. data/test/tc_ruby_data_source.rb +0 -143
  88. data/test/tc_time_or_datetime.rb +0 -639
  89. data/test/tc_timezone.rb +0 -1350
  90. data/test/tc_timezone_definition.rb +0 -113
  91. data/test/tc_timezone_index_definition.rb +0 -73
  92. data/test/tc_timezone_info.rb +0 -11
  93. data/test/tc_timezone_london.rb +0 -143
  94. data/test/tc_timezone_melbourne.rb +0 -142
  95. data/test/tc_timezone_new_york.rb +0 -142
  96. data/test/tc_timezone_offset.rb +0 -126
  97. data/test/tc_timezone_period.rb +0 -548
  98. data/test/tc_timezone_proxy.rb +0 -127
  99. data/test/tc_timezone_transition.rb +0 -352
  100. data/test/tc_timezone_transition_definition.rb +0 -284
  101. data/test/tc_timezone_utc.rb +0 -27
  102. data/test/tc_transition_data_timezone_info.rb +0 -423
  103. data/test/tc_zoneinfo_country_info.rb +0 -64
  104. data/test/tc_zoneinfo_data_source.rb +0 -1193
  105. data/test/tc_zoneinfo_timezone_info.rb +0 -1128
  106. data/test/test_utils.rb +0 -134
  107. data/test/ts_all.rb +0 -7
  108. data/test/ts_all_ruby.rb +0 -5
  109. data/test/ts_all_zoneinfo.rb +0 -7
  110. data/test/tzinfo-data/tzinfo/data.rb +0 -8
  111. data/test/tzinfo-data/tzinfo/data/definitions/America/Argentina/Buenos_Aires.rb +0 -89
  112. data/test/tzinfo-data/tzinfo/data/definitions/America/New_York.rb +0 -315
  113. data/test/tzinfo-data/tzinfo/data/definitions/Australia/Melbourne.rb +0 -218
  114. data/test/tzinfo-data/tzinfo/data/definitions/EST.rb +0 -19
  115. data/test/tzinfo-data/tzinfo/data/definitions/Etc/GMT__m__1.rb +0 -21
  116. data/test/tzinfo-data/tzinfo/data/definitions/Etc/GMT__p__1.rb +0 -21
  117. data/test/tzinfo-data/tzinfo/data/definitions/Etc/UTC.rb +0 -21
  118. data/test/tzinfo-data/tzinfo/data/definitions/Europe/Amsterdam.rb +0 -261
  119. data/test/tzinfo-data/tzinfo/data/definitions/Europe/Andorra.rb +0 -186
  120. data/test/tzinfo-data/tzinfo/data/definitions/Europe/London.rb +0 -321
  121. data/test/tzinfo-data/tzinfo/data/definitions/Europe/Paris.rb +0 -265
  122. data/test/tzinfo-data/tzinfo/data/definitions/Europe/Prague.rb +0 -220
  123. data/test/tzinfo-data/tzinfo/data/definitions/UTC.rb +0 -16
  124. data/test/tzinfo-data/tzinfo/data/indexes/countries.rb +0 -927
  125. data/test/tzinfo-data/tzinfo/data/indexes/timezones.rb +0 -596
  126. data/test/tzinfo-data/tzinfo/data/version.rb +0 -14
  127. data/test/zoneinfo/America/Argentina/Buenos_Aires +0 -0
  128. data/test/zoneinfo/America/New_York +0 -0
  129. data/test/zoneinfo/Australia/Melbourne +0 -0
  130. data/test/zoneinfo/EST +0 -0
  131. data/test/zoneinfo/Etc/UTC +0 -0
  132. data/test/zoneinfo/Europe/Amsterdam +0 -0
  133. data/test/zoneinfo/Europe/Andorra +0 -0
  134. data/test/zoneinfo/Europe/London +0 -0
  135. data/test/zoneinfo/Europe/Paris +0 -0
  136. data/test/zoneinfo/Europe/Prague +0 -0
  137. data/test/zoneinfo/Factory +0 -0
  138. data/test/zoneinfo/iso3166.tab +0 -275
  139. data/test/zoneinfo/posix/Europe/London +0 -0
  140. data/test/zoneinfo/posixrules +0 -0
  141. data/test/zoneinfo/right/Europe/London +0 -0
  142. data/test/zoneinfo/zone.tab +0 -439
  143. data/test/zoneinfo/zone1970.tab +0 -369
  144. data/tzinfo.gemspec +0 -21
@@ -1,64 +0,0 @@
1
- require File.join(File.expand_path(File.dirname(__FILE__)), 'test_utils')
2
-
3
- include TZInfo
4
-
5
- class TCZoneinfoCountryInfo < Minitest::Test
6
-
7
- def test_code
8
- ci = ZoneinfoCountryInfo.new('ZZ', 'Zzz', []) {|c| }
9
- assert_equal('ZZ', ci.code)
10
- end
11
-
12
- def test_name
13
- ci = ZoneinfoCountryInfo.new('ZZ', 'Zzz', []) {|c| }
14
- assert_equal('Zzz', ci.name)
15
- end
16
-
17
- def test_zone_identifiers_empty
18
- ci = ZoneinfoCountryInfo.new('ZZ', 'Zzz', []) {|c| }
19
- assert(ci.zone_identifiers.empty?)
20
- assert(ci.zone_identifiers.frozen?)
21
- end
22
-
23
- def test_zone_identifiers
24
- zones = [
25
- CountryTimezone.new('ZZ/TimezoneB', Rational(1, 2), Rational(1, 2), 'Timezone B'),
26
- CountryTimezone.new('ZZ/TimezoneA', Rational(1, 4), Rational(1, 4), 'Timezone A'),
27
- CountryTimezone.new('ZZ/TimezoneC', Rational(-10, 3), Rational(-20, 7), 'C'),
28
- CountryTimezone.new('ZZ/TimezoneD', Rational(-10, 3), Rational(-20, 7))
29
- ]
30
-
31
- ci = ZoneinfoCountryInfo.new('ZZ', 'Zzz', zones)
32
-
33
- assert_equal(['ZZ/TimezoneB', 'ZZ/TimezoneA', 'ZZ/TimezoneC', 'ZZ/TimezoneD'], ci.zone_identifiers)
34
- assert(ci.zone_identifiers.frozen?)
35
- assert(!ci.zones.equal?(zones))
36
- assert(!zones.frozen?)
37
- end
38
-
39
- def test_zones_empty
40
- ci = ZoneinfoCountryInfo.new('ZZ', 'Zzz', [])
41
- assert(ci.zones.empty?)
42
- assert(ci.zones.frozen?)
43
- end
44
-
45
- def test_zones
46
- zones = [
47
- CountryTimezone.new('ZZ/TimezoneB', Rational(1, 2), Rational(1, 2), 'Timezone B'),
48
- CountryTimezone.new('ZZ/TimezoneA', Rational(1, 4), Rational(1, 4), 'Timezone A'),
49
- CountryTimezone.new('ZZ/TimezoneC', Rational(-10, 3), Rational(-20, 7), 'C'),
50
- CountryTimezone.new('ZZ/TimezoneD', Rational(-10, 3), Rational(-20, 7))
51
- ]
52
-
53
- ci = ZoneinfoCountryInfo.new('ZZ', 'Zzz', zones)
54
-
55
- assert_equal([CountryTimezone.new('ZZ/TimezoneB', Rational(1, 2), Rational(1, 2), 'Timezone B'),
56
- CountryTimezone.new('ZZ/TimezoneA', Rational(1, 4), Rational(1, 4), 'Timezone A'),
57
- CountryTimezone.new('ZZ/TimezoneC', Rational(-10, 3), Rational(-20, 7), 'C'),
58
- CountryTimezone.new('ZZ/TimezoneD', Rational(-10, 3), Rational(-20, 7))],
59
- ci.zones)
60
- assert(ci.zones.frozen?)
61
- assert(!ci.zones.equal?(zones))
62
- assert(!zones.frozen?)
63
- end
64
- end
@@ -1,1193 +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 = File.join(File.expand_path(File.dirname(__FILE__)), 'zoneinfo').untaint
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('../Definitions/Europe/London')
369
- end
370
- end
371
-
372
- def test_load_timezone_info_ignored_file
373
- assert_raises(InvalidTimezoneIdentifier) do
374
- @data_source.load_timezone_info('localtime')
375
- end
376
- end
377
-
378
- def test_load_timezone_info_ignored_plus_version_file
379
- # Mac OS X includes a file named +VERSION containing the tzdata version.
380
-
381
- Dir.mktmpdir('tzinfo_test') do |dir|
382
- FileUtils.touch(File.join(dir, 'zone.tab'))
383
- FileUtils.touch(File.join(dir, 'iso3166.tab'))
384
-
385
- File.open(File.join(dir, '+VERSION'), 'w') do |f|
386
- f.binmode
387
- f.write("2013a\n")
388
- end
389
-
390
- data_source = ZoneinfoDataSource.new(dir)
391
-
392
- assert_raises(InvalidTimezoneIdentifier) do
393
- data_source.load_timezone_info('+VERSION')
394
- end
395
- end
396
- end
397
-
398
- def test_load_timezone_info_ignored_timeconfig_symlink
399
- # Slackware includes a symlink named timeconfig that points at /usr/sbin/timeconfig.
400
-
401
- Dir.mktmpdir('tzinfo_test_target') do |target_dir|
402
- target_path = File.join(target_dir, 'timeconfig')
403
-
404
- File.open(target_path, 'w') do |f|
405
- f.write("#!/bin/sh\n")
406
- f.write("#\n")
407
- f.write('# timeconfig Slackware Linux timezone configuration utility.\n')
408
- end
409
-
410
- Dir.mktmpdir('tzinfo_test') do |dir|
411
- FileUtils.touch(File.join(dir, 'zone.tab'))
412
- FileUtils.touch(File.join(dir, 'iso3166.tab'))
413
- FileUtils.cp(File.join(@data_source.zoneinfo_dir, 'EST'), File.join(dir, 'EST'))
414
-
415
- symlink_path = File.join(dir, 'timeconfig')
416
- begin
417
- FileUtils.ln_s(target_path, symlink_path)
418
- rescue NotImplementedError, Errno::EACCES
419
- # Symlinks not supported on this platform, or permission denied
420
- # (administrative rights are required on Windows). Copy instead.
421
- FileUtils.cp(target_path, symlink_path)
422
- end
423
-
424
- data_source = ZoneinfoDataSource.new(dir)
425
-
426
- assert_raises(InvalidTimezoneIdentifier) do
427
- data_source.load_timezone_info('timeconfig')
428
- end
429
- end
430
- end
431
- end
432
-
433
- def test_load_timezone_info_nil
434
- assert_raises(InvalidTimezoneIdentifier) do
435
- @data_source.load_timezone_info(nil)
436
- end
437
- end
438
-
439
- def test_load_timezone_info_case
440
- assert_raises(InvalidTimezoneIdentifier) do
441
- @data_source.load_timezone_info('europe/london')
442
- end
443
- end
444
-
445
- def test_load_timezone_info_permission_denied
446
- Dir.mktmpdir('tzinfo_test') do |dir|
447
- FileUtils.touch(File.join(dir, 'zone.tab'))
448
- FileUtils.touch(File.join(dir, 'iso3166.tab'))
449
-
450
- file = File.join(dir, 'UTC')
451
- FileUtils.touch(file)
452
- FileUtils.chmod(0200, file)
453
-
454
- data_source = ZoneinfoDataSource.new(dir)
455
-
456
- assert_raises(InvalidTimezoneIdentifier) do
457
- data_source.load_timezone_info('UTC')
458
- end
459
- end
460
- end
461
-
462
- def test_load_timezone_info_directory
463
- Dir.mktmpdir('tzinfo_test') do |dir|
464
- FileUtils.touch(File.join(dir, 'zone.tab'))
465
- FileUtils.touch(File.join(dir, 'iso3166.tab'))
466
-
467
- subdir = File.join(dir, 'Subdir')
468
- FileUtils.mkdir(subdir)
469
-
470
- data_source = ZoneinfoDataSource.new(dir)
471
-
472
- assert_raises(InvalidTimezoneIdentifier) do
473
- data_source.load_timezone_info('Subdir')
474
- end
475
- end
476
- end
477
-
478
- def test_load_timezone_info_linked_absolute_outside
479
- Dir.mktmpdir('tzinfo_test') do |dir|
480
- Dir.mktmpdir('tzinfo_test') do |outside|
481
- outside_file = File.join(outside, 'EST')
482
- FileUtils.cp(File.join(@data_source.zoneinfo_dir, 'EST'), outside_file)
483
-
484
- FileUtils.touch(File.join(dir, 'zone.tab'))
485
- FileUtils.touch(File.join(dir, 'iso3166.tab'))
486
-
487
- file = File.join(dir, 'EST')
488
-
489
- begin
490
- FileUtils.ln_s(outside_file, file)
491
- rescue NotImplementedError, Errno::EACCES
492
- # Symlinks not supported on this platform, or permission denied
493
- # (administrative rights are required on Windows). Skip test.
494
- return
495
- end
496
-
497
- data_source = ZoneinfoDataSource.new(dir)
498
-
499
- info = data_source.load_timezone_info('EST')
500
- assert_kind_of(ZoneinfoTimezoneInfo, info)
501
- assert_equal('EST', info.identifier)
502
- end
503
- end
504
- end
505
-
506
- def test_load_timezone_info_linked_absolute_inside
507
- Dir.mktmpdir('tzinfo_test') do |dir|
508
- FileUtils.touch(File.join(dir, 'zone.tab'))
509
- FileUtils.touch(File.join(dir, 'iso3166.tab'))
510
-
511
- FileUtils.cp(File.join(@data_source.zoneinfo_dir, 'EST'), File.join(dir, 'EST'))
512
-
513
- link = File.join(dir, 'Link')
514
-
515
- begin
516
- FileUtils.ln_s(File.join(File.expand_path(dir), 'EST'), link)
517
- rescue NotImplementedError, Errno::EACCES
518
- # Symlinks not supported on this platform, or permission denied
519
- # (administrative rights are required on Windows). Skip test.
520
- return
521
- end
522
-
523
- data_source = ZoneinfoDataSource.new(dir)
524
-
525
- info = data_source.load_timezone_info('Link')
526
- assert_kind_of(ZoneinfoTimezoneInfo, info)
527
- assert_equal('Link', info.identifier)
528
- end
529
- end
530
-
531
- def test_load_timezone_info_linked_relative_outside
532
- Dir.mktmpdir('tzinfo_test') do |root|
533
- FileUtils.cp(File.join(@data_source.zoneinfo_dir, 'EST'), File.join(root, 'outside'))
534
-
535
- dir = File.join(root, 'zoneinfo')
536
- FileUtils.mkdir(dir)
537
-
538
- FileUtils.touch(File.join(dir, 'zone.tab'))
539
- FileUtils.touch(File.join(dir, 'iso3166.tab'))
540
-
541
- link = File.join(dir, 'Link')
542
-
543
- begin
544
- FileUtils.ln_s('../outside', link)
545
- rescue NotImplementedError, Errno::EACCES
546
- # Symlinks not supported on this platform, or permission denied
547
- # (administrative rights are required on Windows). Skip test.
548
- return
549
- end
550
-
551
- subdir = File.join(dir, 'Subdir')
552
- subdir_link = File.join(subdir, 'Link')
553
- FileUtils.mkdir(subdir)
554
- FileUtils.ln_s('../../outside', subdir_link)
555
-
556
- data_source = ZoneinfoDataSource.new(dir)
557
-
558
- info = data_source.load_timezone_info('Link')
559
- assert_kind_of(ZoneinfoTimezoneInfo, info)
560
- assert_equal('Link', info.identifier)
561
-
562
- info = data_source.load_timezone_info('Subdir/Link')
563
- assert_kind_of(ZoneinfoTimezoneInfo, info)
564
- assert_equal('Subdir/Link', info.identifier)
565
- end
566
- end
567
-
568
- def test_load_timezone_info_linked_relative_parent_inside
569
- Dir.mktmpdir('tzinfo_test') do |dir|
570
- FileUtils.touch(File.join(dir, 'zone.tab'))
571
- FileUtils.touch(File.join(dir, 'iso3166.tab'))
572
-
573
- FileUtils.cp(File.join(@data_source.zoneinfo_dir, 'EST'), File.join(dir, 'EST'))
574
-
575
- subdir = File.join(dir, 'Subdir')
576
- FileUtils.mkdir(subdir)
577
- FileUtils.cp(File.join(@data_source.zoneinfo_dir, 'EST'), File.join(subdir, 'EST'))
578
-
579
- subdir_link = File.join(subdir, 'Link')
580
- begin
581
- FileUtils.ln_s('../Subdir/EST', subdir_link)
582
- rescue NotImplementedError, Errno::EACCES
583
- # Symlinks not supported on this platform, or permission denied
584
- # (administrative rights are required on Windows). Skip test.
585
- return
586
- end
587
-
588
- subdir_link2 = File.join(subdir, 'Link2')
589
- FileUtils.ln_s('../EST', subdir_link2)
590
-
591
- subdir2 = File.join(dir, 'Subdir2')
592
- FileUtils.mkdir(subdir2)
593
- subdir2_link = File.join(subdir2, 'Link')
594
- FileUtils.ln_s('../Subdir/EST', subdir2_link)
595
-
596
- data_source = ZoneinfoDataSource.new(dir)
597
-
598
- info = data_source.load_timezone_info('Subdir/Link')
599
- assert_kind_of(ZoneinfoTimezoneInfo, info)
600
- assert_equal('Subdir/Link', info.identifier)
601
-
602
- info = data_source.load_timezone_info('Subdir/Link2')
603
- assert_kind_of(ZoneinfoTimezoneInfo, info)
604
- assert_equal('Subdir/Link2', info.identifier)
605
-
606
- info = data_source.load_timezone_info('Subdir2/Link')
607
- assert_kind_of(ZoneinfoTimezoneInfo, info)
608
- assert_equal('Subdir2/Link', info.identifier)
609
- end
610
- end
611
-
612
- def test_load_timezone_info_invalid_file
613
- Dir.mktmpdir('tzinfo_test') do |dir|
614
- FileUtils.touch(File.join(dir, 'zone.tab'))
615
- FileUtils.touch(File.join(dir, 'iso3166.tab'))
616
-
617
- File.open(File.join(dir, 'Zone'), 'wb') do |file|
618
- file.write('NotAValidTZifFile')
619
- end
620
-
621
- data_source = ZoneinfoDataSource.new(dir)
622
-
623
- assert_raises(InvalidTimezoneIdentifier) do
624
- data_source.load_timezone_info('Zone')
625
- end
626
- end
627
- end
628
-
629
- def test_load_timezone_info_invalid_file_2
630
- Dir.mktmpdir('tzinfo_test') do |dir|
631
- FileUtils.touch(File.join(dir, 'zone.tab'))
632
- FileUtils.touch(File.join(dir, 'iso3166.tab'))
633
-
634
- zone = File.join(dir, 'Zone')
635
-
636
- File.open(File.join(@data_source.zoneinfo_dir, 'EST')) do |src|
637
- # Change header to TZif1 (which is not a valid header).
638
- File.open(zone, 'wb') do |dest|
639
- dest.write('TZif1')
640
- src.pos = 5
641
- FileUtils.copy_stream(src, dest)
642
- end
643
- end
644
-
645
- data_source = ZoneinfoDataSource.new(dir)
646
-
647
- assert_raises(InvalidTimezoneIdentifier) do
648
- data_source.load_timezone_info('Zone')
649
- end
650
- end
651
- end
652
-
653
- def test_load_timezone_info_tainted
654
- safe_test do
655
- identifier = 'Europe/Amsterdam'.dup.taint
656
- assert(identifier.tainted?)
657
- info = @data_source.load_timezone_info(identifier)
658
- assert_equal('Europe/Amsterdam', info.identifier)
659
- assert(identifier.tainted?)
660
- end
661
- end
662
-
663
- def test_load_timezone_info_tainted_and_frozen
664
- safe_test do
665
- info = @data_source.load_timezone_info('Europe/Amsterdam'.dup.taint.freeze)
666
- assert_equal('Europe/Amsterdam', info.identifier)
667
- end
668
- end
669
-
670
- def test_load_timezone_info_tainted_zoneinfo_dir_safe_mode
671
- safe_test(:unavailable => :skip) do
672
- assert_raises(SecurityError) do
673
- ZoneinfoDataSource.new(@data_source.zoneinfo_dir.dup.taint)
674
- end
675
- end
676
- end
677
-
678
- def test_load_timezone_info_tainted_zoneinfo_dir
679
- data_source = ZoneinfoDataSource.new(@data_source.zoneinfo_dir.dup.taint)
680
- info = data_source.load_timezone_info('Europe/London')
681
- assert_kind_of(ZoneinfoTimezoneInfo, info)
682
- assert_equal('Europe/London', info.identifier)
683
- end
684
-
685
- def get_timezone_filenames(directory)
686
- entries = Dir.glob(File.join(directory, '**', '*'))
687
-
688
- entries = entries.select do |file|
689
- file.untaint
690
- File.file?(file)
691
- end
692
-
693
- entries = entries.collect {|file| file[directory.length + File::SEPARATOR.length, file.length - directory.length - File::SEPARATOR.length]}
694
-
695
- # Exclude right (with leapseconds) and posix (copy) directories; .tab files; localtime and posixrules files.
696
- entries = entries.select do |file|
697
- file !~ /\A(posix|right)\// &&
698
- file !~ /\.tab\z/ &&
699
- !%w(localtime posixrules).include?(file)
700
- end
701
-
702
- entries.sort
703
- end
704
-
705
- def test_timezone_identifiers
706
- expected = get_timezone_filenames(@data_source.zoneinfo_dir)
707
- all = @data_source.timezone_identifiers
708
- assert_kind_of(Array, all)
709
- assert_array_same_items(expected, all)
710
- assert_equal(true, all.frozen?)
711
- end
712
-
713
- def test_data_timezone_identifiers
714
- expected = get_timezone_filenames(@data_source.zoneinfo_dir)
715
- all_data = @data_source.data_timezone_identifiers
716
- assert_kind_of(Array, all_data)
717
- assert_array_same_items(expected, all_data)
718
- assert_equal(true, all_data.frozen?)
719
- end
720
-
721
- def test_linked_timezone_identifiers
722
- all_linked = @data_source.linked_timezone_identifiers
723
- assert_kind_of(Array, all_linked)
724
- assert_equal(true, all_linked.empty?)
725
- assert_equal(true, all_linked.frozen?)
726
- end
727
-
728
- def test_timezone_identifiers_safe_mode
729
- safe_test do
730
- expected = get_timezone_filenames(@data_source.zoneinfo_dir)
731
- all = @data_source.timezone_identifiers
732
- assert_kind_of(Array, all)
733
- assert_array_same_items(expected, all)
734
- assert_equal(true, all.frozen?)
735
- end
736
- end
737
-
738
- def test_timezone_identifiers_ignored_plus_version_file
739
- # Mac OS X includes a file named +VERSION containing the tzdata version.
740
-
741
- Dir.mktmpdir('tzinfo_test') do |dir|
742
- FileUtils.touch(File.join(dir, 'zone.tab'))
743
- FileUtils.touch(File.join(dir, 'iso3166.tab'))
744
- FileUtils.cp(File.join(@data_source.zoneinfo_dir, 'EST'), File.join(dir, 'EST'))
745
-
746
- File.open(File.join(dir, '+VERSION'), 'w') do |f|
747
- f.binmode
748
- f.write("2013a\n")
749
- end
750
-
751
- data_source = ZoneinfoDataSource.new(dir)
752
- assert_array_same_items(['EST'], data_source.timezone_identifiers)
753
- end
754
- end
755
-
756
- def test_timezone_identifiers_ignored_timeconfig_symlink
757
- # Slackware includes a symlink named timeconfig that points at /usr/sbin/timeconfig.
758
-
759
- Dir.mktmpdir('tzinfo_test_target') do |target_dir|
760
- target_path = File.join(target_dir, 'timeconfig')
761
-
762
- File.open(target_path, 'w') do |f|
763
- f.write("#!/bin/sh\n")
764
- f.write("#\n")
765
- f.write('# timeconfig Slackware Linux timezone configuration utility.\n')
766
- end
767
-
768
- Dir.mktmpdir('tzinfo_test') do |dir|
769
- FileUtils.touch(File.join(dir, 'zone.tab'))
770
- FileUtils.touch(File.join(dir, 'iso3166.tab'))
771
- FileUtils.cp(File.join(@data_source.zoneinfo_dir, 'EST'), File.join(dir, 'EST'))
772
-
773
- symlink_path = File.join(dir, 'timeconfig')
774
- begin
775
- FileUtils.ln_s(target_path, symlink_path)
776
- rescue NotImplementedError, Errno::EACCES
777
- # Symlinks not supported on this platform, or permission denied
778
- # (administrative rights are required on Windows). Copy instead.
779
- FileUtils.cp(target_path, symlink_path)
780
- end
781
-
782
- data_source = ZoneinfoDataSource.new(dir)
783
- assert_array_same_items(['EST'], data_source.timezone_identifiers)
784
- end
785
- end
786
- end
787
-
788
- def test_timezone_identifiers_ignored_src_directory
789
- # Solaris includes a src directory containing the source timezone data files
790
- # from the tzdata distribution. These should be ignored.
791
-
792
- Dir.mktmpdir('tzinfo_test') do |dir|
793
- FileUtils.touch(File.join(dir, 'zone.tab'))
794
- FileUtils.touch(File.join(dir, 'iso3166.tab'))
795
- FileUtils.cp(File.join(@data_source.zoneinfo_dir, 'EST'), File.join(dir, 'EST'))
796
-
797
- src_dir = File.join(dir, 'src')
798
- FileUtils.mkdir(src_dir)
799
-
800
- File.open(File.join(src_dir, 'europe'), 'w') do |f|
801
- f.binmode
802
- f.write("Zone\tEurope/London\t0:00\tEU\tGMT/BST\n")
803
- end
804
-
805
- data_source = ZoneinfoDataSource.new(dir)
806
- assert_array_same_items(['EST'], data_source.timezone_identifiers)
807
- end
808
- end
809
-
810
- def test_load_country_info
811
- info = @data_source.load_country_info('GB')
812
- assert_equal('GB', info.code)
813
- assert_equal('Britain (UK)', info.name)
814
- end
815
-
816
- def test_load_country_info_not_exist
817
- assert_raises(InvalidCountryCode) do
818
- @data_source.load_country_info('ZZ')
819
- end
820
- end
821
-
822
- def test_load_country_info_invalid
823
- assert_raises(InvalidCountryCode) do
824
- @data_source.load_country_info('../Countries/GB')
825
- end
826
- end
827
-
828
- def test_load_country_info_nil
829
- assert_raises(InvalidCountryCode) do
830
- @data_source.load_country_info(nil)
831
- end
832
- end
833
-
834
- def test_load_country_info_case
835
- assert_raises(InvalidCountryCode) do
836
- @data_source.load_country_info('gb')
837
- end
838
- end
839
-
840
- def test_load_country_info_tainted
841
- safe_test do
842
- code = 'NL'.dup.taint
843
- assert(code.tainted?)
844
- info = @data_source.load_country_info(code)
845
- assert_equal('NL', info.code)
846
- assert(code.tainted?)
847
- end
848
- end
849
-
850
- def test_load_country_info_tainted_and_frozen
851
- safe_test do
852
- info = @data_source.load_country_info('NL'.dup.taint.freeze)
853
- assert_equal('NL', info.code)
854
- end
855
- end
856
-
857
- def test_load_country_info_check_zones
858
- Dir.mktmpdir('tzinfo_test') do |dir|
859
- RubyCoreSupport.open_file(File.join(dir, 'iso3166.tab'), 'w', :external_encoding => 'UTF-8') do |iso3166|
860
- iso3166.puts('# iso3166.tab')
861
- iso3166.puts('')
862
- iso3166.puts("FC\tFake Country")
863
- iso3166.puts("OC\tOther Country")
864
- end
865
-
866
- RubyCoreSupport.open_file(File.join(dir, 'zone.tab'), 'w', :external_encoding => 'UTF-8') do |zone|
867
- zone.puts('# zone.tab')
868
- zone.puts('')
869
- zone.puts("FC\t+513030-0000731\tFake/One\tDescription of one")
870
- zone.puts("FC\t+353916+1394441\tFake/Two\tAnother description")
871
- zone.puts("FC\t-2332-04637\tFake/Three\tThis is Three")
872
- zone.puts("OC\t+5005+01426\tOther/One")
873
- end
874
-
875
- data_source = ZoneinfoDataSource.new(dir)
876
-
877
- info = data_source.load_country_info('FC')
878
- assert_equal('FC', info.code)
879
- assert_equal('Fake Country', info.name)
880
- assert_equal(['Fake/One', 'Fake/Two', 'Fake/Three'], info.zone_identifiers)
881
- assert_equal(true, info.zone_identifiers.frozen?)
882
- assert_equal([
883
- CountryTimezone.new('Fake/One', Rational(6181, 120), Rational(-451, 3600), 'Description of one'),
884
- CountryTimezone.new('Fake/Two', Rational(32089, 900), Rational(503081, 3600), 'Another description'),
885
- CountryTimezone.new('Fake/Three', Rational(-353, 15), Rational(-2797, 60), 'This is Three')], info.zones)
886
- assert_equal(true, info.zones.frozen?)
887
-
888
- info = data_source.load_country_info('OC')
889
- assert_equal('OC', info.code)
890
- assert_equal('Other Country', info.name)
891
- assert_equal(['Other/One'], info.zone_identifiers)
892
- assert_equal(true, info.zone_identifiers.frozen?)
893
- assert_equal([CountryTimezone.new('Other/One', Rational(601, 12), Rational(433, 30))], info.zones)
894
- assert_equal(true, info.zones.frozen?)
895
- end
896
- end
897
-
898
- def test_load_country_info_check_zones_zone1970
899
- Dir.mktmpdir('tzinfo_test') do |dir|
900
- RubyCoreSupport.open_file(File.join(dir, 'iso3166.tab'), 'w', :external_encoding => 'UTF-8') do |iso3166|
901
- iso3166.puts('# iso3166.tab')
902
- iso3166.puts('')
903
- iso3166.puts("AC\tAnother Country")
904
- iso3166.puts("FC\tFake Country")
905
- iso3166.puts("OC\tOther Country")
906
- end
907
-
908
- # zone.tab will be ignored.
909
- RubyCoreSupport.open_file(File.join(dir, 'zone.tab'), 'w', :external_encoding => 'UTF-8') do |zone|
910
- zone.puts('# zone.tab')
911
- zone.puts('')
912
- zone.puts("FC\t+513030-0000731\tFake/One\tDescription of one")
913
- zone.puts("FC\t+353916+1394441\tFake/Two\tAnother description")
914
- zone.puts("FC\t-2332-04637\tFake/Three\tThis is Three")
915
- zone.puts("OC\t+5005+01426\tOther/One")
916
- end
917
-
918
- # zone1970.tab will be used.
919
- RubyCoreSupport.open_file(File.join(dir, 'zone1970.tab'), 'w', :external_encoding => 'UTF-8') do |zone|
920
- zone.puts('# zone1970.tab')
921
- zone.puts('')
922
- zone.puts("AC,OC\t+0000+00000\tMiddle/Another/One\tAnother's One")
923
- zone.puts("FC\t+513030-0000731\tFake/One\tDescription of one")
924
- zone.puts("FC,OC\t+353916+1394441\tFake/Two\tAnother description")
925
- zone.puts("FC,OC\t-2332-04637\tFake/Three\tThis is Three")
926
- zone.puts("OC\t+5005+01426\tOther/One")
927
- zone.puts("OC\t+5015+11426\tOther/Two")
928
- end
929
-
930
- data_source = ZoneinfoDataSource.new(dir)
931
-
932
- info = data_source.load_country_info('AC')
933
- assert_equal('AC', info.code)
934
- assert_equal('Another Country', info.name)
935
- assert_equal(['Middle/Another/One'], info.zone_identifiers)
936
- assert_equal(true, info.zone_identifiers.frozen?)
937
- assert_equal([CountryTimezone.new('Middle/Another/One', Rational(0, 1), Rational(0, 1), "Another's One")], info.zones)
938
- assert_equal(true, info.zones.frozen?)
939
-
940
- info = data_source.load_country_info('FC')
941
- assert_equal('FC', info.code)
942
- assert_equal('Fake Country', info.name)
943
- assert_equal(['Fake/One', 'Fake/Two', 'Fake/Three'], info.zone_identifiers)
944
- assert_equal(true, info.zone_identifiers.frozen?)
945
- assert_equal([
946
- CountryTimezone.new('Fake/One', Rational(6181, 120), Rational(-451, 3600), 'Description of one'),
947
- CountryTimezone.new('Fake/Two', Rational(32089, 900), Rational(503081, 3600), 'Another description'),
948
- CountryTimezone.new('Fake/Three', Rational(-353, 15), Rational(-2797, 60), 'This is Three')], info.zones)
949
- assert_equal(true, info.zones.frozen?)
950
-
951
- # Testing the ordering of zones. A zone can either be primary (country
952
- # code is the first in the first column), or secondary (country code is
953
- # not the first). Should return all the primaries first in the order they
954
- # appeared in the file, followed by all the secondaries in the order they
955
- # appeared in file.
956
-
957
- info = data_source.load_country_info('OC')
958
- assert_equal('OC', info.code)
959
- assert_equal('Other Country', info.name)
960
- assert_equal(['Other/One', 'Other/Two', 'Middle/Another/One', 'Fake/Two', 'Fake/Three'], info.zone_identifiers)
961
- assert_equal(true, info.zone_identifiers.frozen?)
962
- assert_equal([
963
- CountryTimezone.new('Other/One', Rational(601, 12), Rational( 433, 30)),
964
- CountryTimezone.new('Other/Two', Rational(201, 4), Rational(3433, 30)),
965
- CountryTimezone.new('Middle/Another/One', Rational(0, 1), Rational(0, 1), "Another's One"),
966
- CountryTimezone.new('Fake/Two', Rational(32089, 900), Rational(503081, 3600), 'Another description'),
967
- CountryTimezone.new('Fake/Three', Rational(-353, 15), Rational(-2797, 60), 'This is Three')], info.zones)
968
- assert_equal(true, info.zones.frozen?)
969
- end
970
- end
971
-
972
- def test_load_country_info_check_zones_solaris_tab_files
973
- # Solaris uses 5 columns instead of the usual 4 in zone_sun.tab.
974
- # An extra column before the comment gives an optional linked/alternate
975
- # timezone identifier (or '-' if not set).
976
- #
977
- # Additionally, there is a section at the end of the file for timezones
978
- # covering regions. These are given lower-case "country" codes. The timezone
979
- # identifier column refers to a continent instead of an identifier. These
980
- # lines will be ignored by TZInfo.
981
-
982
- Dir.mktmpdir('tzinfo_test') do |dir|
983
- tab_dir = File.join(dir, 'tab')
984
- FileUtils.mkdir(tab_dir)
985
-
986
- RubyCoreSupport.open_file(File.join(tab_dir, 'country.tab'), 'w', :external_encoding => 'UTF-8') do |country|
987
- country.puts('# country.tab')
988
- country.puts('# Solaris')
989
- country.puts("FC\tFake Country")
990
- country.puts("OC\tOther Country")
991
- end
992
-
993
- RubyCoreSupport.open_file(File.join(tab_dir, 'zone_sun.tab'), 'w', :external_encoding => 'UTF-8') do |zone_sun|
994
- zone_sun.puts('# zone_sun.tab')
995
- zone_sun.puts('# Solaris')
996
- zone_sun.puts('# Countries')
997
- zone_sun.puts("FC\t+513030-0000731\tFake/One\t-\tDescription of one")
998
- zone_sun.puts("FC\t+353916+1394441\tFake/Two\tFake/Alias/Two\tAnother description")
999
- zone_sun.puts("FC\t-2332-04637\tFake/Three\tFake/Alias/Three\tThis is Three")
1000
- zone_sun.puts("OC\t+5005+01426\tOther/One\tOther/Linked/One")
1001
- zone_sun.puts("OC\t+5015+01436\tOther/Two\t-")
1002
- zone_sun.puts('# Regions')
1003
- zone_sun.puts("ee\t+0000+00000\tEurope/\tEET")
1004
- zone_sun.puts("me\t+0000+00000\tEurope/\tMET")
1005
- zone_sun.puts("we\t+0000+00000\tEurope/\tWET")
1006
- end
1007
-
1008
- data_source = ZoneinfoDataSource.new(dir)
1009
-
1010
- info = data_source.load_country_info('FC')
1011
- assert_equal('FC', info.code)
1012
- assert_equal('Fake Country', info.name)
1013
- assert_equal(['Fake/One', 'Fake/Two', 'Fake/Three'], info.zone_identifiers)
1014
- assert_equal(true, info.zone_identifiers.frozen?)
1015
- assert_equal([
1016
- CountryTimezone.new('Fake/One', Rational(6181, 120), Rational(-451, 3600), 'Description of one'),
1017
- CountryTimezone.new('Fake/Two', Rational(32089, 900), Rational(503081, 3600), 'Another description'),
1018
- CountryTimezone.new('Fake/Three', Rational(-353, 15), Rational(-2797, 60), 'This is Three')], info.zones)
1019
- assert_equal(true, info.zones.frozen?)
1020
-
1021
- info = data_source.load_country_info('OC')
1022
- assert_equal('OC', info.code)
1023
- assert_equal('Other Country', info.name)
1024
- assert_equal(['Other/One', 'Other/Two'], info.zone_identifiers)
1025
- assert_equal(true, info.zone_identifiers.frozen?)
1026
- assert_equal([
1027
- CountryTimezone.new('Other/One', Rational(601, 12), Rational(433, 30)),
1028
- CountryTimezone.new('Other/Two', Rational(201, 4), Rational(73, 5))], info.zones)
1029
- assert_equal(true, info.zones.frozen?)
1030
- end
1031
- end
1032
-
1033
- def test_load_country_info_check_zones_alternate_iso3166_file
1034
- Dir.mktmpdir('tzinfo_test') do |dir|
1035
- zoneinfo_dir = File.join(dir, 'zoneinfo')
1036
- tab_dir = File.join(dir, 'tab')
1037
- FileUtils.mkdir(zoneinfo_dir)
1038
- FileUtils.mkdir(tab_dir)
1039
-
1040
- tab_file = File.join(tab_dir, 'iso3166')
1041
- RubyCoreSupport.open_file(tab_file, 'w', :external_encoding => 'UTF-8') do |iso3166|
1042
- # Use the BSD 4 column format (alternate iso3166 is used on BSD).
1043
- iso3166.puts("FC\tFCC\t001\tFake Country")
1044
- iso3166.puts("OC\tOCC\t002\tOther Country")
1045
- end
1046
-
1047
- RubyCoreSupport.open_file(File.join(zoneinfo_dir, 'zone.tab'), 'w', :external_encoding => 'UTF-8') do |zone|
1048
- zone.puts("FC\t+513030-0000731\tFake/One\tDescription of one")
1049
- zone.puts("FC\t+353916+1394441\tFake/Two\tAnother description")
1050
- zone.puts("FC\t-2332-04637\tFake/Three\tThis is Three")
1051
- zone.puts("OC\t+5005+01426\tOther/One")
1052
- end
1053
-
1054
- data_source = ZoneinfoDataSource.new(zoneinfo_dir, tab_file)
1055
-
1056
- info = data_source.load_country_info('FC')
1057
- assert_equal('FC', info.code)
1058
- assert_equal('Fake Country', info.name)
1059
- assert_equal(['Fake/One', 'Fake/Two', 'Fake/Three'], info.zone_identifiers)
1060
- assert_equal(true, info.zone_identifiers.frozen?)
1061
- assert_equal([
1062
- CountryTimezone.new('Fake/One', Rational(6181, 120), Rational(-451, 3600), 'Description of one'),
1063
- CountryTimezone.new('Fake/Two', Rational(32089, 900), Rational(503081, 3600), 'Another description'),
1064
- CountryTimezone.new('Fake/Three', Rational(-353, 15), Rational(-2797, 60), 'This is Three')], info.zones)
1065
- assert_equal(true, info.zones.frozen?)
1066
-
1067
- info = data_source.load_country_info('OC')
1068
- assert_equal('OC', info.code)
1069
- assert_equal('Other Country', info.name)
1070
- assert_equal(['Other/One'], info.zone_identifiers)
1071
- assert_equal(true, info.zone_identifiers.frozen?)
1072
- assert_equal([CountryTimezone.new('Other/One', Rational(601, 12), Rational(433, 30))], info.zones)
1073
- assert_equal(true, info.zones.frozen?)
1074
- end
1075
- end
1076
-
1077
- def test_load_country_info_four_column_iso31611
1078
- # OpenBSD and FreeBSD use a 4 column iso3166.tab file that includes
1079
- # alpha-3 and numeric-3 codes in addition to the alpha-2 and name in the
1080
- # tz database version.
1081
-
1082
- Dir.mktmpdir('tzinfo_test') do |dir|
1083
- RubyCoreSupport.open_file(File.join(dir, 'iso3166.tab'), 'w', :external_encoding => 'UTF-8') do |iso3166|
1084
- iso3166.puts("FC\tFCC\t001\tFake Country")
1085
- iso3166.puts("OC\tOCC\t002\tOther Country")
1086
- end
1087
-
1088
- RubyCoreSupport.open_file(File.join(dir, 'zone.tab'), 'w', :external_encoding => 'UTF-8') do |zone|
1089
- zone.puts("FC\t+513030-0000731\tFake/One\tDescription of one")
1090
- zone.puts("OC\t+5005+01426\tOther/One")
1091
- end
1092
-
1093
- data_source = ZoneinfoDataSource.new(dir)
1094
-
1095
- info = data_source.load_country_info('FC')
1096
- assert_equal('FC', info.code)
1097
- assert_equal('Fake Country', info.name)
1098
-
1099
- info = data_source.load_country_info('OC')
1100
- assert_equal('OC', info.code)
1101
- assert_equal('Other Country', info.name)
1102
- end
1103
- end
1104
-
1105
- def test_load_country_info_utf8
1106
- # iso3166.tab is currently in ASCII (as of tzdata 2014f), but will be
1107
- # changed to UTF-8 in the future.
1108
-
1109
- # zone.tab is in ASCII, with no plans to change. Since ASCII is a subset of
1110
- # UTF-8, test that this is loaded in UTF-8 anyway.
1111
-
1112
- Dir.mktmpdir('tzinfo_test') do |dir|
1113
- RubyCoreSupport.open_file(File.join(dir, 'iso3166.tab'), 'w', :external_encoding => 'UTF-8') do |iso3166|
1114
- iso3166.puts("UT\tUnicode Test ✓")
1115
- end
1116
-
1117
- RubyCoreSupport.open_file(File.join(dir, 'zone.tab'), 'w', :external_encoding => 'UTF-8') do |zone|
1118
- zone.puts("UT\t+513030-0000731\tUnicode✓/One\tUnicode Description ✓")
1119
- end
1120
-
1121
- data_source = ZoneinfoDataSource.new(dir)
1122
-
1123
- info = data_source.load_country_info('UT')
1124
- assert_equal('UT', info.code)
1125
- assert_equal('Unicode Test ✓', info.name)
1126
- assert_equal(['Unicode✓/One'], info.zone_identifiers)
1127
- assert_equal([CountryTimezone.new('Unicode✓/One', Rational(6181, 120), Rational(-451, 3600), 'Unicode Description ✓')], info.zones)
1128
- end
1129
- end
1130
-
1131
- def test_load_country_info_utf8_zone1970
1132
- # iso3166.tab is currently in ASCII (as of tzdata 2014f), but will be
1133
- # changed to UTF-8 in the future.
1134
-
1135
- # zone1970.tab is in UTF-8.
1136
-
1137
- Dir.mktmpdir('tzinfo_test') do |dir|
1138
- RubyCoreSupport.open_file(File.join(dir, 'iso3166.tab'), 'w', :external_encoding => 'UTF-8') do |iso3166|
1139
- iso3166.puts("UT\tUnicode Test ✓")
1140
- end
1141
-
1142
- RubyCoreSupport.open_file(File.join(dir, 'zone1970.tab'), 'w', :external_encoding => 'UTF-8') do |zone|
1143
- zone.puts("UT\t+513030-0000731\tUnicode✓/One\tUnicode Description ✓")
1144
- end
1145
-
1146
- data_source = ZoneinfoDataSource.new(dir)
1147
-
1148
- info = data_source.load_country_info('UT')
1149
- assert_equal('UT', info.code)
1150
- assert_equal('Unicode Test ✓', info.name)
1151
- assert_equal(['Unicode✓/One'], info.zone_identifiers)
1152
- assert_equal([CountryTimezone.new('Unicode✓/One', Rational(6181, 120), Rational(-451, 3600), 'Unicode Description ✓')], info.zones)
1153
- end
1154
- end
1155
-
1156
- def test_country_codes
1157
- file_codes = []
1158
-
1159
- RubyCoreSupport.open_file(File.join(@data_source.zoneinfo_dir, 'iso3166.tab'), 'r', :external_encoding => 'UTF-8', :internal_encoding => 'UTF-8') do |file|
1160
- file.each_line do |line|
1161
- line.chomp!
1162
- file_codes << $1 if line =~ /\A([A-Z]{2})\t/
1163
- end
1164
- end
1165
-
1166
- codes = @data_source.country_codes
1167
- assert_array_same_items(file_codes, codes)
1168
- assert_equal(true, codes.frozen?)
1169
- end
1170
-
1171
- def test_country_codes_four_column_iso3166
1172
- # OpenBSD and FreeBSD use a 4 column iso3166.tab file that includes
1173
- # alpha-3 and numeric-3 codes in addition to the alpha-2 and name in the
1174
- # tz database version.
1175
-
1176
- Dir.mktmpdir('tzinfo_test') do |dir|
1177
- RubyCoreSupport.open_file(File.join(dir, 'iso3166.tab'), 'w', :external_encoding => 'UTF-8') do |iso3166|
1178
- iso3166.puts("FC\tFCC\t001\tFake Country")
1179
- iso3166.puts("OC\tOCC\t002\tOther Country")
1180
- end
1181
-
1182
- RubyCoreSupport.open_file(File.join(dir, 'zone.tab'), 'w', :external_encoding => 'UTF-8') do |zone|
1183
- zone.puts("FC\t+513030-0000731\tFake/One\tDescription of one")
1184
- zone.puts("OC\t+5005+01426\tOther/One")
1185
- end
1186
-
1187
- data_source = ZoneinfoDataSource.new(dir)
1188
-
1189
- codes = data_source.country_codes
1190
- assert_array_same_items(%w(FC OC), codes)
1191
- end
1192
- end
1193
- end