tzinfo 1.2.6 → 2.0.2

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