tzinfo 1.2.4 → 1.2.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of tzinfo might be problematic. Click here for more details.

@@ -2,11 +2,29 @@ require File.join(File.expand_path(File.dirname(__FILE__)), 'test_utils')
2
2
 
3
3
  include TZInfo
4
4
 
5
+ using TaintExt if Module.const_defined?(:TaintExt)
6
+
5
7
  class TCRubyDataSource < Minitest::Test
6
8
  def setup
7
9
  @data_source = RubyDataSource.new
8
10
  end
9
11
 
12
+ def test_initialize_not_found
13
+ # A failure to load tzinfo/data in initialize will not cause an exception.
14
+ # Attempts to load data files will subsequently fail.
15
+ code = <<-EOF
16
+ begin
17
+ ds = TZInfo::RubyDataSource.new
18
+ puts 'Initialized'
19
+ ds.load_timezone_info('Europe/London')
20
+ rescue Exception => e
21
+ puts e.class
22
+ end
23
+ EOF
24
+
25
+ assert_sub_process_returns(['Initialized', 'TZInfo::InvalidTimezoneIdentifier'], code)
26
+ end
27
+
10
28
  def test_load_timezone_info_data
11
29
  info = @data_source.load_timezone_info('Europe/London')
12
30
  assert_kind_of(DataTimezoneInfo, info)
@@ -55,7 +73,9 @@ class TCRubyDataSource < Minitest::Test
55
73
  end
56
74
 
57
75
  def test_load_timezone_info_tainted
58
- safe_test do
76
+ skip_if_has_bug_14060
77
+
78
+ safe_test(:unavailable => :skip) do
59
79
  identifier = 'Europe/Amsterdam'.dup.taint
60
80
  assert(identifier.tainted?)
61
81
  info = @data_source.load_timezone_info(identifier)
@@ -65,6 +85,8 @@ class TCRubyDataSource < Minitest::Test
65
85
  end
66
86
 
67
87
  def test_load_timezone_info_tainted_and_frozen
88
+ skip_if_has_bug_14060
89
+
68
90
  safe_test do
69
91
  info = @data_source.load_timezone_info('Europe/Amsterdam'.dup.taint.freeze)
70
92
  assert_equal('Europe/Amsterdam', info.identifier)
@@ -119,7 +141,7 @@ class TCRubyDataSource < Minitest::Test
119
141
  end
120
142
 
121
143
  def test_load_country_info_tainted
122
- safe_test do
144
+ safe_test(:unavailable => :skip) do
123
145
  code = 'NL'.dup.taint
124
146
  assert(code.tainted?)
125
147
  info = @data_source.load_country_info(code)
@@ -4,6 +4,12 @@ require 'rational' unless defined?(Rational)
4
4
  include TZInfo
5
5
 
6
6
  class TCTimeOrDateTime < Minitest::Test
7
+ # Ruby 1.8.7 (built with GCC 8.3.0 on Ubuntu 19.04) fails to perform DateTime
8
+ # arithmetic operations correctly when sub-seconds are used. Detect this and
9
+ # disable the affected tests.
10
+ DATETIME_SUBSECOND_ARITHMETIC_IS_BROKEN = (DateTime.new(2019, 12, 22, 15, 0, Rational(1, 1000)) + Rational(1, 86400)).strftime('%Q') != '1577026801001'
11
+ puts "DateTime sub-second arithmetic is broken on this platform" if DATETIME_SUBSECOND_ARITHMETIC_IS_BROKEN
12
+
7
13
  def test_initialize_time
8
14
  assert_nothing_raised do
9
15
  TimeOrDateTime.new(Time.utc(2006, 3, 24, 15, 32, 3, 721000))
@@ -128,6 +134,11 @@ class TCTimeOrDateTime < Minitest::Test
128
134
  assert_equal(Time.utc(2006, 3, 24, 15, 32, 3, 721123),
129
135
  TimeOrDateTime.new(DateTime.new(2006, 3, 24, 15, 32, 3 + Rational(7211239, 10000000))).to_time)
130
136
  end
137
+
138
+ def test_to_time_after_freeze
139
+ assert_equal(Time.utc(2006, 3, 24, 15, 32, 3), TimeOrDateTime.new(DateTime.new(2006, 3, 24, 15, 32, 3)).freeze.to_time)
140
+ assert_equal(Time.utc(2006, 3, 24, 15, 32, 3), TimeOrDateTime.new(1143214323).freeze.to_time)
141
+ end
131
142
 
132
143
  def test_to_datetime
133
144
  assert_equal(DateTime.new(2006, 3, 24, 15, 32, 3),
@@ -157,6 +168,11 @@ class TCTimeOrDateTime < Minitest::Test
157
168
  assert_equal(DateTime.new(2006, 3, 24, 15, 32, 3 + Rational(721123, 1000000)),
158
169
  TimeOrDateTime.new(Time.utc(2006, 3, 24, 15, 32, 3, 721123 + Rational(9, 10))).to_datetime)
159
170
  end
171
+
172
+ def test_to_datetime_after_freeze
173
+ assert_equal(DateTime.new(2006, 3, 24, 15, 32, 3), TimeOrDateTime.new(Time.utc(2006, 3, 24, 15, 32, 3)).freeze.to_datetime)
174
+ assert_equal(DateTime.new(2006, 3, 24, 15, 32, 3), TimeOrDateTime.new(1143214323).freeze.to_datetime)
175
+ end
160
176
 
161
177
  def test_to_i
162
178
  assert_equal(1143214323,
@@ -172,6 +188,11 @@ class TCTimeOrDateTime < Minitest::Test
172
188
  assert_equal(1143214323,
173
189
  TimeOrDateTime.new('1143214323').to_i)
174
190
  end
191
+
192
+ def test_to_i_after_freeze
193
+ assert_equal(1143214323, TimeOrDateTime.new(Time.utc(2006, 3, 24, 15, 32, 3)).freeze.to_i)
194
+ assert_equal(1143214323, TimeOrDateTime.new(DateTime.new(2006, 3, 24, 15, 32, 3)).freeze.to_i)
195
+ end
175
196
 
176
197
  def test_to_orig
177
198
  assert_equal(Time.utc(2006, 3, 24, 15, 32, 3),
@@ -485,12 +506,12 @@ class TCTimeOrDateTime < Minitest::Test
485
506
  assert_equal(Time.utc(2006, 3, 24, 15, 32, 4), (TimeOrDateTime.new(Time.utc(2006, 3, 24, 15, 32, 3)) + 1).to_orig)
486
507
  assert_equal(Time.utc(2006, 3, 24, 15, 32, 4, 721000), (TimeOrDateTime.new(Time.utc(2006, 3, 24, 15, 32, 3, 721000)) + 1).to_orig)
487
508
  assert_equal(DateTime.new(2006, 3, 24, 15, 32, 4), (TimeOrDateTime.new(DateTime.new(2006, 3, 24, 15, 32, 3)) + 1).to_orig)
488
- assert_equal(DateTime.new(2006, 3, 24, 15, 32, 4 + Rational(721, 1000)), (TimeOrDateTime.new(DateTime.new(2006, 3, 24, 15, 32, 3 + Rational(721, 1000))) + 1).to_orig)
509
+ assert_equal(DateTime.new(2006, 3, 24, 15, 32, 4 + Rational(721, 1000)), (TimeOrDateTime.new(DateTime.new(2006, 3, 24, 15, 32, 3 + Rational(721, 1000))) + 1).to_orig) unless DATETIME_SUBSECOND_ARITHMETIC_IS_BROKEN
489
510
  assert_equal(1143214324, (TimeOrDateTime.new(1143214323) + 1).to_orig)
490
511
  assert_equal(Time.utc(2006, 3, 24, 15, 32, 2), (TimeOrDateTime.new(Time.utc(2006, 3, 24, 15, 32, 3)) + (-1)).to_orig)
491
512
  assert_equal(Time.utc(2006, 3, 24, 15, 32, 2, 721000), (TimeOrDateTime.new(Time.utc(2006, 3, 24, 15, 32, 3, 721000)) + (-1)).to_orig)
492
513
  assert_equal(DateTime.new(2006, 3, 24, 15, 32, 2), (TimeOrDateTime.new(DateTime.new(2006, 3, 24, 15, 32, 3)) + (-1)).to_orig)
493
- assert_equal(DateTime.new(2006, 3, 24, 15, 32, 2 + Rational(721, 1000)), (TimeOrDateTime.new(DateTime.new(2006, 3, 24, 15, 32, 3 + Rational(721, 1000))) + (-1)).to_orig)
514
+ assert_equal(DateTime.new(2006, 3, 24, 15, 32, 2 + Rational(721, 1000)), (TimeOrDateTime.new(DateTime.new(2006, 3, 24, 15, 32, 3 + Rational(721, 1000))) + (-1)).to_orig) unless DATETIME_SUBSECOND_ARITHMETIC_IS_BROKEN
494
515
  assert_equal(1143214322, (TimeOrDateTime.new(1143214323) + (-1)).to_orig)
495
516
  end
496
517
 
@@ -503,12 +524,12 @@ class TCTimeOrDateTime < Minitest::Test
503
524
  assert_equal(Time.utc(2006, 3, 24, 15, 32, 2), (TimeOrDateTime.new(Time.utc(2006, 3, 24, 15, 32, 3)) - 1).to_orig)
504
525
  assert_equal(Time.utc(2006, 3, 24, 15, 32, 2, 721000), (TimeOrDateTime.new(Time.utc(2006, 3, 24, 15, 32, 3, 721000)) - 1).to_orig)
505
526
  assert_equal(DateTime.new(2006, 3, 24, 15, 32, 2), (TimeOrDateTime.new(DateTime.new(2006, 3, 24, 15, 32, 3)) - 1).to_orig)
506
- assert_equal(DateTime.new(2006, 3, 24, 15, 32, 2 + Rational(721, 1000)), (TimeOrDateTime.new(DateTime.new(2006, 3, 24, 15, 32, 3 + Rational(721, 1000))) - 1).to_orig)
527
+ assert_equal(DateTime.new(2006, 3, 24, 15, 32, 2 + Rational(721, 1000)), (TimeOrDateTime.new(DateTime.new(2006, 3, 24, 15, 32, 3 + Rational(721, 1000))) - 1).to_orig) unless DATETIME_SUBSECOND_ARITHMETIC_IS_BROKEN
507
528
  assert_equal(1143214322, (TimeOrDateTime.new(1143214323) - 1).to_orig)
508
529
  assert_equal(Time.utc(2006, 3, 24, 15, 32, 4), (TimeOrDateTime.new(Time.utc(2006, 3, 24, 15, 32, 3)) - (-1)).to_orig)
509
530
  assert_equal(Time.utc(2006, 3, 24, 15, 32, 4, 721000), (TimeOrDateTime.new(Time.utc(2006, 3, 24, 15, 32, 3, 721000)) - (-1)).to_orig)
510
531
  assert_equal(DateTime.new(2006, 3, 24, 15, 32, 4), (TimeOrDateTime.new(DateTime.new(2006, 3, 24, 15, 32, 3)) - (-1)).to_orig)
511
- assert_equal(DateTime.new(2006, 3, 24, 15, 32, 4 + Rational(721, 1000)), (TimeOrDateTime.new(DateTime.new(2006, 3, 24, 15, 32, 3 + Rational(721, 1000))) - (-1)).to_orig)
532
+ assert_equal(DateTime.new(2006, 3, 24, 15, 32, 4 + Rational(721, 1000)), (TimeOrDateTime.new(DateTime.new(2006, 3, 24, 15, 32, 3 + Rational(721, 1000))) - (-1)).to_orig) unless DATETIME_SUBSECOND_ARITHMETIC_IS_BROKEN
512
533
  assert_equal(1143214324, (TimeOrDateTime.new(1143214323) - (-1)).to_orig)
513
534
  end
514
535
 
@@ -521,12 +542,12 @@ class TCTimeOrDateTime < Minitest::Test
521
542
  assert_equal(Time.utc(2006, 3, 24, 15, 32, 4), TimeOrDateTime.new(Time.utc(2006, 3, 24, 15, 32, 3)).add_with_convert(1).to_orig)
522
543
  assert_equal(Time.utc(2006, 3, 24, 15, 32, 4, 721000), TimeOrDateTime.new(Time.utc(2006, 3, 24, 15, 32, 3, 721000)).add_with_convert(1).to_orig)
523
544
  assert_equal(DateTime.new(2006, 3, 24, 15, 32, 4), TimeOrDateTime.new(DateTime.new(2006, 3, 24, 15, 32, 3)).add_with_convert(1).to_orig)
524
- assert_equal(DateTime.new(2006, 3, 24, 15, 32, 4 + Rational(721, 1000)), TimeOrDateTime.new(DateTime.new(2006, 3, 24, 15, 32, 3 + Rational(721, 1000))).add_with_convert(1).to_orig)
545
+ assert_equal(DateTime.new(2006, 3, 24, 15, 32, 4 + Rational(721, 1000)), TimeOrDateTime.new(DateTime.new(2006, 3, 24, 15, 32, 3 + Rational(721, 1000))).add_with_convert(1).to_orig) unless DATETIME_SUBSECOND_ARITHMETIC_IS_BROKEN
525
546
  assert_equal(1143214324, TimeOrDateTime.new(1143214323).add_with_convert(1).to_orig)
526
547
  assert_equal(Time.utc(2006, 3, 24, 15, 32, 2), TimeOrDateTime.new(Time.utc(2006, 3, 24, 15, 32, 3)).add_with_convert(-1).to_orig)
527
548
  assert_equal(Time.utc(2006, 3, 24, 15, 32, 2, 721000), TimeOrDateTime.new(Time.utc(2006, 3, 24, 15, 32, 3, 721000)).add_with_convert(-1).to_orig)
528
549
  assert_equal(DateTime.new(2006, 3, 24, 15, 32, 2), TimeOrDateTime.new(DateTime.new(2006, 3, 24, 15, 32, 3)).add_with_convert(-1).to_orig)
529
- assert_equal(DateTime.new(2006, 3, 24, 15, 32, 2 + Rational(721, 1000)), TimeOrDateTime.new(DateTime.new(2006, 3, 24, 15, 32, 3 + Rational(721, 1000))).add_with_convert(-1).to_orig)
550
+ assert_equal(DateTime.new(2006, 3, 24, 15, 32, 2 + Rational(721, 1000)), TimeOrDateTime.new(DateTime.new(2006, 3, 24, 15, 32, 3 + Rational(721, 1000))).add_with_convert(-1).to_orig) unless DATETIME_SUBSECOND_ARITHMETIC_IS_BROKEN
530
551
  assert_equal(1143214322, TimeOrDateTime.new(1143214323).add_with_convert(-1).to_orig)
531
552
 
532
553
  if RubyCoreSupport.time_supports_negative
data/test/tc_timezone.rb CHANGED
@@ -2,6 +2,8 @@ require File.join(File.expand_path(File.dirname(__FILE__)), 'test_utils')
2
2
 
3
3
  include TZInfo
4
4
 
5
+ using TaintExt if Module.const_defined?(:TaintExt)
6
+
5
7
  class TCTimezone < Minitest::Test
6
8
 
7
9
  class BlockCalled < StandardError
@@ -242,7 +244,7 @@ class TCTimezone < Minitest::Test
242
244
  def test_get_tainted_loaded
243
245
  Timezone.get('Europe/Andorra')
244
246
 
245
- safe_test do
247
+ safe_test(:unavailable => :skip) do
246
248
  identifier = 'Europe/Andorra'.dup.taint
247
249
  assert(identifier.tainted?)
248
250
  tz = Timezone.get(identifier)
@@ -261,7 +263,9 @@ class TCTimezone < Minitest::Test
261
263
  end
262
264
 
263
265
  def test_get_tainted_not_previously_loaded
264
- safe_test do
266
+ skip_if_has_bug_14060
267
+
268
+ safe_test(:unavailable => :skip) do
265
269
  identifier = 'Europe/Andorra'.dup.taint
266
270
  assert(identifier.tainted?)
267
271
  tz = Timezone.get(identifier)
@@ -271,6 +275,8 @@ class TCTimezone < Minitest::Test
271
275
  end
272
276
 
273
277
  def test_get_tainted_and_frozen_not_previously_loaded
278
+ skip_if_has_bug_14060
279
+
274
280
  safe_test do
275
281
  tz = Timezone.get('Europe/Amsterdam'.dup.taint.freeze)
276
282
  assert_equal('Europe/Amsterdam', tz.identifier)
@@ -1260,6 +1266,7 @@ class TCTimezone < Minitest::Test
1260
1266
  assert_equal('BST BST', tz.strftime('%Z %Z', dt))
1261
1267
  assert_equal('BST %Z %BST %%Z %%BST', tz.strftime('%Z %%Z %%%Z %%%%Z %%%%%Z', dt))
1262
1268
  assert_equal('+0100 +01:00 +01:00:00 +01 %::::z', tz.strftime('%z %:z %::z %:::z %::::z', dt))
1269
+ assert_equal('1153001522 %s %1153001522', tz.strftime('%s %%s %%%s', dt))
1263
1270
  end
1264
1271
 
1265
1272
  def test_strftime_time
@@ -1271,6 +1278,7 @@ class TCTimezone < Minitest::Test
1271
1278
  assert_equal('BST BST', tz.strftime('%Z %Z', t))
1272
1279
  assert_equal('BST %Z %BST %%Z %%BST', tz.strftime('%Z %%Z %%%Z %%%%Z %%%%%Z', t))
1273
1280
  assert_equal('+0100 +01:00 +01:00:00 +01 %::::z', tz.strftime('%z %:z %::z %:::z %::::z', t))
1281
+ assert_equal('1153001522 %s %1153001522', tz.strftime('%s %%s %%%s', t))
1274
1282
  end
1275
1283
 
1276
1284
  def test_strftime_int
@@ -1282,6 +1290,7 @@ class TCTimezone < Minitest::Test
1282
1290
  assert_equal('BST BST', tz.strftime('%Z %Z', i))
1283
1291
  assert_equal('BST %Z %BST %%Z %%BST', tz.strftime('%Z %%Z %%%Z %%%%Z %%%%%Z', i))
1284
1292
  assert_equal('+0100 +01:00 +01:00:00 +01 %::::z', tz.strftime('%z %:z %::z %:::z %::::z', i))
1293
+ assert_equal('1153001522 %s %1153001522', tz.strftime('%s %%s %%%s', i))
1285
1294
  end
1286
1295
 
1287
1296
  def test_get_missing_data_source
@@ -149,6 +149,13 @@ class TCTimezonePeriod < Minitest::Test
149
149
  assert_nil(p.local_end)
150
150
  assert_nil(p.local_end_time)
151
151
  end
152
+
153
+ def test_utc_total_offset_rational_after_freeze
154
+ o = TimezoneOffset.new(3600, 0, :TEST)
155
+ p = TimezonePeriod.new(nil, nil, o)
156
+ p.freeze
157
+ assert_equal(Rational(1, 24), p.utc_total_offset_rational)
158
+ end
152
159
 
153
160
  def test_dst
154
161
  p1 = TimezonePeriod.new(nil, nil, TimezoneOffset.new(-14400, 3600, :TEST))
@@ -88,6 +88,15 @@ class TCTimezoneProxy < Minitest::Test
88
88
  assert_same(Timezone.get('UTC'), proxy.canonical_zone)
89
89
  end
90
90
  end
91
+
92
+ def test_after_freeze
93
+ proxy = TimezoneProxy.new('Europe/London')
94
+ real = Timezone.get('Europe/London')
95
+ t = Time.utc(2017, 6, 1)
96
+ proxy.freeze
97
+ assert_equal('Europe/London', proxy.identifier)
98
+ assert_equal(real.utc_to_local(t), proxy.utc_to_local(t))
99
+ end
91
100
 
92
101
  def test_equals
93
102
  assert_equal(true, TimezoneProxy.new('Europe/London') == TimezoneProxy.new('Europe/London'))
@@ -68,6 +68,13 @@ class TCTimezoneTransition < Minitest::Test
68
68
  assert(TimeOrDateTime.new(DateTime.new(2006, 5, 30, 1, 31, 20)).eql?(t2.local_end_at))
69
69
  assert(TimeOrDateTime.new(Time.utc(2006, 5, 30, 1, 31, 20)).eql?(t3.local_end_at))
70
70
  end
71
+
72
+ def test_local_end_at_after_freeze
73
+ t = TestTimezoneTransition.new(TimezoneOffset.new(3600, 3600, :TDT),
74
+ TimezoneOffset.new(3600, 0, :TST), 1148949080)
75
+ t.freeze
76
+ assert(TimeOrDateTime.new(1148952680).eql?(t.local_end_at))
77
+ end
71
78
 
72
79
  def test_local_end
73
80
  t1 = TestTimezoneTransition.new(TimezoneOffset.new(3600, 3600, :TDT),
@@ -107,6 +114,13 @@ class TCTimezoneTransition < Minitest::Test
107
114
  assert(TimeOrDateTime.new(DateTime.new(2006, 5, 30, 2, 31, 20)).eql?(t2.local_start_at))
108
115
  assert(TimeOrDateTime.new(Time.utc(2006, 5, 30, 2, 31, 20)).eql?(t3.local_start_at))
109
116
  end
117
+
118
+ def test_local_start_at_after_freeze
119
+ t = TestTimezoneTransition.new(TimezoneOffset.new(3600, 3600, :TDT),
120
+ TimezoneOffset.new(3600, 0, :TST), 1148949080)
121
+ t.freeze
122
+ assert(TimeOrDateTime.new(1148956280).eql?(t.local_start_at))
123
+ end
110
124
 
111
125
  def test_local_start
112
126
  t1 = TestTimezoneTransition.new(TimezoneOffset.new(3600, 3600, :TDT),
@@ -70,6 +70,17 @@ class TCTimezoneTransitionDefinition < Minitest::Test
70
70
  assert(TimeOrDateTime.new(DateTime.new(2038, 1, 19, 3, 14, 8)).eql?(t.at))
71
71
  end
72
72
  end
73
+
74
+ def test_at_after_freeze
75
+ t1 = TimezoneTransitionDefinition.new(TimezoneOffset.new(3600, 3600, :TDT),
76
+ TimezoneOffset.new(3600, 0, :TST), 1148949080)
77
+ t2 = TimezoneTransitionDefinition.new(TimezoneOffset.new(3600, 3600, :TDT),
78
+ TimezoneOffset.new(3600, 0, :TST), 5300392727, 2160)
79
+ t1.freeze
80
+ t2.freeze
81
+ assert(TimeOrDateTime.new(1148949080).eql?(t1.at))
82
+ assert(TimeOrDateTime.new(DateTime.new(2006, 5, 30, 0, 31, 20)).eql?(t2.at))
83
+ end
73
84
 
74
85
  def test_eql_timestamp
75
86
  t1 = TimezoneTransitionDefinition.new(TimezoneOffset.new(3600, 3600, :TDT),
@@ -359,7 +359,17 @@ class TCTransitionDataTimezoneInfo < Minitest::Test
359
359
  assert_equal([t1,t2,t3,t4,t5], dti.transitions_up_to(DateTime.new(2011,10,1,1,0,Rational(DATETIME_RESOLUTION,1000000))))
360
360
  assert_equal([t1,t2,t3,t4,t5], dti.transitions_up_to(DateTime.new(2011,10,1,1,0,1), DateTime.new(2010,4,1,1,0,0)))
361
361
  assert_equal([t2,t3,t4,t5], dti.transitions_up_to(DateTime.new(2011,10,1,1,0,1), DateTime.new(2010,4,1,1,0,1)))
362
- assert_equal([t2,t3,t4,t5], dti.transitions_up_to(DateTime.new(2011,10,1,1,0,1), DateTime.new(2010,4,1,1,0,Rational(DATETIME_RESOLUTION,1000000))))
362
+
363
+ # Ruby 1.8.7 (built with GCC 8.3.0 on Ubuntu 19.04) fails to perform
364
+ # DateTime comparisons correctly when sub-seconds are used.
365
+ to = DateTime.new(2011,10,1,1,0,1)
366
+ from = DateTime.new(2010,4,1,1,0,Rational(DATETIME_RESOLUTION,1000000))
367
+ if to > from
368
+ assert_equal([t2,t3,t4,t5], dti.transitions_up_to(to, from))
369
+ else
370
+ puts "This platform does not consider the DateTime #{to.strftime('%Y-%m-%d %H:%m:%S.%N')} to be later than the DateTime #{from.strftime('%Y-%m-%d %H:%m:%S.%N')}"
371
+ end
372
+
363
373
  assert_equal([t5], dti.transitions_up_to(DateTime.new(2015,1,1,0,0,0), DateTime.new(2011,10,1,1,0,0)))
364
374
  assert_equal([], dti.transitions_up_to(DateTime.new(2015,1,1,0,0,0), DateTime.new(2011,10,1,1,0,1)))
365
375
  end
@@ -35,6 +35,20 @@ class TCZoneinfoCountryInfo < Minitest::Test
35
35
  assert(!ci.zones.equal?(zones))
36
36
  assert(!zones.frozen?)
37
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
38
52
 
39
53
  def test_zones_empty
40
54
  ci = ZoneinfoCountryInfo.new('ZZ', 'Zzz', [])
@@ -7,6 +7,15 @@ require 'tmpdir'
7
7
 
8
8
  include TZInfo
9
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
+
10
19
  class TCZoneinfoDataSource < Minitest::Test
11
20
  ZONEINFO_DIR = File.join(File.expand_path(File.dirname(__FILE__)), 'zoneinfo').untaint
12
21
 
@@ -653,7 +662,7 @@ class TCZoneinfoDataSource < Minitest::Test
653
662
  end
654
663
 
655
664
  def test_load_timezone_info_tainted
656
- safe_test do
665
+ safe_test(:unavailable => :skip) do
657
666
  identifier = 'Europe/Amsterdam'.dup.taint
658
667
  assert(identifier.tainted?)
659
668
  info = @data_source.load_timezone_info(identifier)
@@ -840,7 +849,7 @@ class TCZoneinfoDataSource < Minitest::Test
840
849
  end
841
850
 
842
851
  def test_load_country_info_tainted
843
- safe_test do
852
+ safe_test(:unavailable => :skip) do
844
853
  code = 'NL'.dup.taint
845
854
  assert(code.tainted?)
846
855
  info = @data_source.load_country_info(code)
@@ -5,6 +5,8 @@ require 'tempfile'
5
5
 
6
6
  include TZInfo
7
7
 
8
+ using RubyCoreSupport::UntaintExt if RubyCoreSupport.const_defined?(:UntaintExt)
9
+
8
10
  class TCZoneinfoTimezoneInfo < Minitest::Test
9
11
 
10
12
  begin
@@ -1070,6 +1072,110 @@ class TCZoneinfoTimezoneInfo < Minitest::Test
1070
1072
  assert_period(:XST1, 3600, 0, false, Time.utc(2000, 4, 1), nil, info)
1071
1073
  end
1072
1074
  end
1075
+
1076
+ def test_read_offset_negative_std_offset_dst
1077
+ # The zoneinfo files don't include the offset from standard time, so this
1078
+ # has to be derived by looking at changes in the total UTC offset.
1079
+
1080
+ offsets = [
1081
+ {:gmtoff => -100, :isdst => false, :abbrev => 'LMT'},
1082
+ {:gmtoff => 3600, :isdst => false, :abbrev => 'XST'},
1083
+ {:gmtoff => 0, :isdst => true, :abbrev => 'XWT'}]
1084
+
1085
+ transitions = [
1086
+ {:at => Time.utc(2000, 1, 1), :offset_index => 1},
1087
+ {:at => Time.utc(2000, 2, 1), :offset_index => 2},
1088
+ {:at => Time.utc(2000, 3, 1), :offset_index => 1},
1089
+ {:at => Time.utc(2000, 4, 1), :offset_index => 2},
1090
+ {:at => Time.utc(2000, 5, 1), :offset_index => 1}]
1091
+
1092
+ tzif_test(offsets, transitions) do |path, format|
1093
+ info = ZoneinfoTimezoneInfo.new('Zone/NegativeStdOffsetDst', path)
1094
+ assert_equal('Zone/NegativeStdOffsetDst', info.identifier)
1095
+
1096
+ assert_period(:LMT, -100, 0, false, nil, Time.utc(2000, 1, 1), info)
1097
+ assert_period(:XST, 3600, 0, false, Time.utc(2000, 1, 1), Time.utc(2000, 2, 1), info)
1098
+ assert_period(:XWT, 3600, -3600, true, Time.utc(2000, 2, 1), Time.utc(2000, 3, 1), info)
1099
+ assert_period(:XST, 3600, 0, false, Time.utc(2000, 3, 1), Time.utc(2000, 4, 1), info)
1100
+ assert_period(:XWT, 3600, -3600, true, Time.utc(2000, 4, 1), Time.utc(2000, 5, 1), info)
1101
+ assert_period(:XST, 3600, 0, false, Time.utc(2000, 5, 1), nil, info)
1102
+ end
1103
+ end
1104
+
1105
+ def test_read_offset_negative_std_offset_dst_initial_dst
1106
+ # The zoneinfo files don't include the offset from standard time, so this
1107
+ # has to be derived by looking at changes in the total UTC offset.
1108
+
1109
+ offsets = [
1110
+ {:gmtoff => -100, :isdst => false, :abbrev => 'LMT'},
1111
+ {:gmtoff => 0, :isdst => true, :abbrev => 'XWT'},
1112
+ {:gmtoff => 3600, :isdst => false, :abbrev => 'XST'}]
1113
+
1114
+ transitions = [
1115
+ {:at => Time.utc(2000, 1, 1), :offset_index => 1},
1116
+ {:at => Time.utc(2000, 2, 1), :offset_index => 2},
1117
+ {:at => Time.utc(2000, 3, 1), :offset_index => 1},
1118
+ {:at => Time.utc(2000, 4, 1), :offset_index => 2},
1119
+ {:at => Time.utc(2000, 5, 1), :offset_index => 1}]
1120
+
1121
+ tzif_test(offsets, transitions) do |path, format|
1122
+ info = ZoneinfoTimezoneInfo.new('Zone/NegativeStdOffsetDstInitialDst', path)
1123
+ assert_equal('Zone/NegativeStdOffsetDstInitialDst', info.identifier)
1124
+
1125
+ assert_period(:LMT, -100, 0, false, nil, Time.utc(2000, 1, 1), info)
1126
+ assert_period(:XWT, 3600, -3600, true, Time.utc(2000, 1, 1), Time.utc(2000, 2, 1), info)
1127
+ assert_period(:XST, 3600, 0, false, Time.utc(2000, 2, 1), Time.utc(2000, 3, 1), info)
1128
+ assert_period(:XWT, 3600, -3600, true, Time.utc(2000, 3, 1), Time.utc(2000, 4, 1), info)
1129
+ assert_period(:XST, 3600, 0, false, Time.utc(2000, 4, 1), Time.utc(2000, 5, 1), info)
1130
+ assert_period(:XWT, 3600, -3600, true, Time.utc(2000, 5, 1), nil, info)
1131
+ end
1132
+ end
1133
+
1134
+ def test_read_offset_prefer_base_offset_moves_to_dst_not_hour
1135
+ offsets = [
1136
+ {:gmtoff => -100, :isdst => false, :abbrev => 'LMT'},
1137
+ {:gmtoff => 0, :isdst => false, :abbrev => 'XST'},
1138
+ {:gmtoff => 1800, :isdst => true, :abbrev => 'XDT'},
1139
+ {:gmtoff => 1800, :isdst => false, :abbrev => 'XST'}]
1140
+
1141
+ transitions = [
1142
+ {:at => Time.utc(2000, 1, 1), :offset_index => 1},
1143
+ {:at => Time.utc(2000, 2, 1), :offset_index => 2},
1144
+ {:at => Time.utc(2000, 3, 1), :offset_index => 3}]
1145
+
1146
+ tzif_test(offsets, transitions) do |path, format|
1147
+ info = ZoneinfoTimezoneInfo.new('Zone/BaseOffsetMovesToDstNotHour', path)
1148
+ assert_equal('Zone/BaseOffsetMovesToDstNotHour', info.identifier)
1149
+
1150
+ assert_period(:LMT, -100, 0, false, nil, Time.utc(2000, 1, 1), info)
1151
+ assert_period(:XST, 0, 0, false, Time.utc(2000, 1, 1), Time.utc(2000, 2, 1), info)
1152
+ assert_period(:XDT, 0, 1800, true, Time.utc(2000, 2, 1), Time.utc(2000, 3, 1), info)
1153
+ assert_period(:XST, 1800, 0, false, Time.utc(2000, 3, 1), nil, info)
1154
+ end
1155
+ end
1156
+
1157
+ def test_read_offset_prefer_base_offset_moves_from_dst_not_hour
1158
+ offsets = [
1159
+ {:gmtoff => -100, :isdst => false, :abbrev => 'LMT'},
1160
+ {:gmtoff => 1800, :isdst => false, :abbrev => 'XST'},
1161
+ {:gmtoff => 1800, :isdst => true, :abbrev => 'XDT'},
1162
+ {:gmtoff => 0, :isdst => false, :abbrev => 'XST'}]
1163
+
1164
+ transitions = [
1165
+ {:at => Time.utc(2000, 1, 1), :offset_index => 1},
1166
+ {:at => Time.utc(2000, 2, 1), :offset_index => 2},
1167
+ {:at => Time.utc(2000, 3, 1), :offset_index => 3}]
1168
+
1169
+ tzif_test(offsets, transitions) do |path, format|
1170
+ info = ZoneinfoTimezoneInfo.new('Zone/BaseOffsetMovesFromDstNotHour', path)
1171
+ assert_equal('Zone/BaseOffsetMovesFromDstNotHour', info.identifier)
1172
+
1173
+ assert_period(:LMT, -100, 0, false, nil, Time.utc(2000, 1, 1), info)
1174
+ assert_period(:XST, 1800, 0, false, Time.utc(2000, 1, 1), Time.utc(2000, 2, 1), info)
1175
+ assert_period(:XDT, 0, 1800, true, Time.utc(2000, 2, 1), Time.utc(2000, 3, 1), info)
1176
+ assert_period(:XST, 0, 0, false, Time.utc(2000, 3, 1), nil, info)
1177
+ end
1178
+ end
1073
1179
 
1074
1180
  def test_load_in_safe_mode
1075
1181
  offsets = [{:gmtoff => -12094, :isdst => false, :abbrev => 'LT'}]
data/test/test_utils.rb CHANGED
@@ -1,4 +1,6 @@
1
- TESTS_DIR = File.expand_path(File.dirname(__FILE__)).untaint
1
+ tests_dir = File.expand_path(File.dirname(__FILE__))
2
+ tests_dir.untaint if RUBY_VERSION < '2.7'
3
+ TESTS_DIR = tests_dir
2
4
  TZINFO_LIB_DIR = File.expand_path(File.join(TESTS_DIR, '..', 'lib'))
3
5
  TZINFO_TEST_DATA_DIR = File.join(TESTS_DIR, 'tzinfo-data')
4
6
  TZINFO_TEST_ZONEINFO_DIR = File.join(TESTS_DIR, 'zoneinfo')
@@ -55,18 +57,57 @@ module Kernel
55
57
  end
56
58
 
57
59
  def safe_test(options = {})
58
- # JRuby and Rubinus don't support SAFE levels.
59
- available = !(defined?(RUBY_ENGINE) && %w(jruby rbx).include?(RUBY_ENGINE))
60
+ # Ruby >= 2.7, JRuby and Rubinus don't support SAFE levels.
61
+ available = RUBY_VERSION < '2.7' && !(defined?(RUBY_ENGINE) && %w(jruby rbx).include?(RUBY_ENGINE))
60
62
 
61
63
  if available || options[:unavailable] != :skip
62
64
  thread = Thread.new do
63
- $SAFE = options[:level] || 1 if available
64
- yield
65
+ orig_diff = Minitest::Assertions.diff
66
+
67
+ if available
68
+ orig_safe = $SAFE
69
+ $SAFE = options[:level] || 1
70
+ end
71
+ begin
72
+ # Disable the use of external diff tools during safe mode tests (since
73
+ # safe mode will prevent their use). The initial value is retrieved
74
+ # before activating safe mode because the first time
75
+ # Minitest::Assertions.diff is called, it will attempt to find a diff
76
+ # tool. Finding the diff tool will also fail in safe mode.
77
+ Minitest::Assertions.diff = nil
78
+ begin
79
+ yield
80
+ ensure
81
+ Minitest::Assertions.diff = orig_diff
82
+ end
83
+ ensure
84
+ if available
85
+ # On Ruby < 2.6, setting $SAFE affects only the current thread
86
+ # and the $SAFE level cannot be downgraded. Catch and ignore the
87
+ # SecurityError.
88
+ # On Ruby >= 2.6, setting $SAFE is global, and the $SAFE level
89
+ # can be downgraded. Restore $SAFE back to the original level.
90
+ begin
91
+ $SAFE = orig_safe
92
+ rescue SecurityError
93
+ end
94
+ end
95
+ end
65
96
  end
66
97
 
67
98
  thread.join
68
99
  end
69
100
  end
101
+
102
+ def skip_if_has_bug_14060
103
+ # On Ruby 2.4.4 in safe mode, require will fail with a SecurityError for
104
+ # any file that has not previously been loaded, regardless of whether the
105
+ # file name is tainted.
106
+ # See https://bugs.ruby-lang.org/issues/14060#note-5.
107
+ if defined?(RUBY_ENGINE) && RUBY_ENGINE == 'ruby' && RUBY_VERSION == '2.4.4'
108
+ skip('Skipping test due to Ruby 2.4.4 being affected by Bug 14060 (see https://bugs.ruby-lang.org/issues/14060#note-5)')
109
+ end
110
+ end
70
111
 
71
112
  def assert_array_same_items(expected, actual, msg = nil)
72
113
  full_message = message(msg, '') { diff(expected, actual) }
@@ -123,6 +164,19 @@ module Kernel
123
164
  end
124
165
 
125
166
 
167
+ # Object#taint is a deprecated no-op in Ruby 2.7 and outputs a warning. It will
168
+ # be removed in 3.0. Silence the warning or supply a replacement.
169
+ if TZInfo::RubyCoreSupport.const_defined?(:UntaintExt)
170
+ module TaintExt
171
+ refine Object do
172
+ def taint
173
+ self
174
+ end
175
+ end
176
+ end
177
+ end
178
+
179
+
126
180
  # JRuby 1.7.5 to 1.7.9 consider DateTime instances that differ by less than
127
181
  # 1 millisecond to be equivalent (https://github.com/jruby/jruby/issues/1311).
128
182
  #
@@ -2,6 +2,8 @@ require File.join(File.expand_path(File.dirname(__FILE__)), 'test_utils.rb')
2
2
 
3
3
  # Use a zoneinfo directory containing files needed by the tests.
4
4
  # The symlinks in this directory are set up in test_utils.rb.
5
- TZInfo::DataSource.set(:zoneinfo, File.join(File.expand_path(File.dirname(__FILE__)), 'zoneinfo').untaint)
5
+ zoneinfo_path = File.join(File.expand_path(File.dirname(__FILE__)), 'zoneinfo')
6
+ zoneinfo_path.untaint if RUBY_VERSION < '2.7'
7
+ TZInfo::DataSource.set(:zoneinfo, zoneinfo_path)
6
8
 
7
9
  require File.join(File.expand_path(File.dirname(__FILE__)), 'ts_all.rb')
data/tzinfo.gemspec CHANGED
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = 'tzinfo'
3
- s.version = '1.2.4'
3
+ s.version = '1.2.6'
4
4
  s.summary = 'Daylight savings aware timezone library'
5
5
  s.description = 'TZInfo provides daylight savings aware transformations between times in different time zones.'
6
6
  s.author = 'Philip Ross'
data.tar.gz.sig CHANGED
Binary file