timecop 0.8.0 → 0.9.8

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.
@@ -1,5 +1,4 @@
1
1
  require 'singleton'
2
- require File.join(File.dirname(__FILE__), "time_extensions")
3
2
  require File.join(File.dirname(__FILE__), "time_stack_item")
4
3
 
5
4
  # Timecop
@@ -14,6 +13,8 @@ class Timecop
14
13
  include Singleton
15
14
 
16
15
  class << self
16
+ private :instance
17
+
17
18
  # Allows you to run a block of code and "fake" a time throughout the execution of that block.
18
19
  # This is particularly useful for writing test methods where the passage of time is critical to the business
19
20
  # logic being tested. For example:
@@ -75,11 +76,11 @@ class Timecop
75
76
  end
76
77
 
77
78
  def baseline
78
- instance.send(:baseline)
79
+ instance.baseline
79
80
  end
80
81
 
81
82
  def baseline=(baseline)
82
- instance.send(:baseline=, baseline)
83
+ instance.baseline = baseline
83
84
  end
84
85
 
85
86
  # Reverts back to system's Time.now, Date.today and DateTime.now (if it exists) permamently when
@@ -87,20 +88,21 @@ class Timecop
87
88
  # the given block.
88
89
  def return(&block)
89
90
  if block_given?
90
- instance.send(:return, &block)
91
+ instance.return(&block)
91
92
  else
92
- instance.send(:unmock!)
93
+ instance.unmock!
93
94
  nil
94
95
  end
95
96
  end
97
+ alias :unfreeze :return
96
98
 
97
99
  def return_to_baseline
98
- instance.send(:return_to_baseline)
100
+ instance.return_to_baseline
99
101
  Time.now
100
102
  end
101
103
 
102
104
  def top_stack_item #:nodoc:
103
- instance.instance_variable_get(:@_stack).last
105
+ instance.stack.last
104
106
  end
105
107
 
106
108
  def safe_mode=(safe)
@@ -111,64 +113,117 @@ class Timecop
111
113
  @safe_mode ||= false
112
114
  end
113
115
 
114
- # Returns whether or not Timecop is currently frozen/travelled
116
+ def thread_safe=(t)
117
+ instance.thread_safe = t
118
+ end
119
+
120
+ def thread_safe
121
+ instance.thread_safe
122
+ end
123
+
124
+ # Returns whether or not Timecop is currently frozen
115
125
  def frozen?
116
- !instance.instance_variable_get(:@_stack).empty?
126
+ !instance.stack.empty? && instance.stack.last.mock_type == :freeze
117
127
  end
118
128
 
119
129
  private
120
130
  def send_travel(mock_type, *args, &block)
121
- val = instance.send(:travel, mock_type, *args, &block)
131
+ val = instance.travel(mock_type, *args, &block)
122
132
  block_given? ? val : Time.now
123
133
  end
124
134
  end
125
135
 
126
- private
136
+ def baseline=(b)
137
+ set_baseline(b)
138
+ stack << TimeStackItem.new(:travel, b)
139
+ end
140
+
141
+ def baseline
142
+ if @thread_safe
143
+ Thread.current[:timecop_baseline]
144
+ else
145
+ @baseline
146
+ end
147
+ end
127
148
 
128
- def baseline=(baseline)
129
- @baseline = baseline
130
- @_stack << TimeStackItem.new(:travel, baseline)
149
+ def set_baseline(b)
150
+ if @thread_safe
151
+ Thread.current[:timecop_baseline] = b
152
+ else
153
+ @baseline = b
154
+ end
155
+ end
156
+
157
+ def stack
158
+ if @thread_safe
159
+ Thread.current[:timecop_stack] ||= []
160
+ Thread.current[:timecop_stack]
161
+ else
162
+ @stack
163
+ end
164
+ end
165
+
166
+ def set_stack(s)
167
+ if @thread_safe
168
+ Thread.current[:timecop_stack] = s
169
+ else
170
+ @stack = s
171
+ end
131
172
  end
132
173
 
133
174
  def initialize #:nodoc:
134
- @_stack = []
175
+ @stack = []
176
+ @safe = nil
177
+ @thread_safe = false
178
+ end
179
+
180
+ def thread_safe=(t)
181
+ initialize
182
+ @thread_safe = t
183
+ end
184
+
185
+ def thread_safe
186
+ @thread_safe
135
187
  end
136
188
 
137
189
  def travel(mock_type, *args, &block) #:nodoc:
138
- raise SafeModeException if Timecop.safe_mode? && !block_given?
190
+ raise SafeModeException if Timecop.safe_mode? && !block_given? && !@safe
139
191
 
140
192
  stack_item = TimeStackItem.new(mock_type, *args)
141
193
 
142
- stack_backup = @_stack.dup
143
- @_stack << stack_item
194
+ stack_backup = stack.dup
195
+ stack << stack_item
144
196
 
145
197
  if block_given?
198
+ safe_backup = @safe
199
+ @safe = true
146
200
  begin
147
201
  yield stack_item.time
148
202
  ensure
149
- @_stack.replace stack_backup
203
+ stack.replace stack_backup
204
+ @safe = safe_backup
150
205
  end
151
206
  end
152
207
  end
153
208
 
154
209
  def return(&block)
155
- current_stack = @_stack
156
- current_baseline = @baseline
210
+ current_stack = stack
211
+ current_baseline = baseline
157
212
  unmock!
158
213
  yield
159
214
  ensure
160
- @_stack = current_stack
161
- @baseline = current_baseline
215
+ set_stack current_stack
216
+ set_baseline current_baseline
162
217
  end
163
218
 
164
219
  def unmock! #:nodoc:
165
- @baseline = nil
166
- @_stack = []
220
+ set_baseline nil
221
+ set_stack []
167
222
  end
168
223
 
169
224
  def return_to_baseline
170
- if @baseline
171
- @_stack = [@_stack.shift]
225
+ if baseline
226
+ set_stack [stack.shift]
172
227
  else
173
228
  unmock!
174
229
  end
@@ -180,3 +235,6 @@ class Timecop
180
235
  end
181
236
  end
182
237
  end
238
+
239
+ # This must be done after TimeCop is available
240
+ require File.join(File.dirname(__FILE__), "time_extensions")
@@ -1,3 +1,3 @@
1
1
  class Timecop
2
- VERSION = "0.8.0"
2
+ VERSION = "0.9.8"
3
3
  end
metadata CHANGED
@@ -1,15 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: timecop
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.0
4
+ version: 0.9.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - Travis Jeffery
8
8
  - John Trupiano
9
- autorequire:
9
+ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2015-07-28 00:00:00.000000000 Z
12
+ date: 2023-08-14 00:00:00.000000000 Z
13
13
  dependencies: []
14
14
  description: A gem providing "time travel" and "time freezing" capabilities, making
15
15
  it dead simple to test time-dependent code. It provides a unified method to mock
@@ -27,44 +27,32 @@ files:
27
27
  - lib/timecop.rb
28
28
  - lib/timecop/time_extensions.rb
29
29
  - lib/timecop/time_stack_item.rb
30
- - lib/timecop/version.rb
31
30
  - lib/timecop/timecop.rb
32
- - test/run_tests.sh
33
- - test/test_helper.rb
34
- - test/time_stack_item_test.rb
35
- - test/timecop_test.rb
36
- - test/timecop_without_date_test.rb
37
- - test/timecop_without_date_but_with_time_test.rb
31
+ - lib/timecop/version.rb
38
32
  homepage: https://github.com/travisjeffery/timecop
39
33
  licenses:
40
34
  - MIT
41
35
  metadata: {}
42
- post_install_message:
36
+ post_install_message:
43
37
  rdoc_options:
44
- - --charset=UTF-8
38
+ - "--charset=UTF-8"
45
39
  require_paths:
46
40
  - lib
47
41
  required_ruby_version: !ruby/object:Gem::Requirement
48
42
  requirements:
49
- - - '>='
43
+ - - ">="
50
44
  - !ruby/object:Gem::Version
51
45
  version: 1.9.2
52
46
  required_rubygems_version: !ruby/object:Gem::Requirement
53
47
  requirements:
54
- - - '>='
48
+ - - ">="
55
49
  - !ruby/object:Gem::Version
56
50
  version: '0'
57
51
  requirements: []
58
- rubyforge_project: timecop
59
- rubygems_version: 2.0.14
60
- signing_key:
61
- specification_version: 3
52
+ rubygems_version: 3.2.15
53
+ signing_key:
54
+ specification_version: 4
62
55
  summary: A gem providing "time travel" and "time freezing" capabilities, making it
63
56
  dead simple to test time-dependent code. It provides a unified method to mock Time.now,
64
57
  Date.today, and DateTime.now in a single call.
65
- test_files:
66
- - test/test_helper.rb
67
- - test/time_stack_item_test.rb
68
- - test/timecop_test.rb
69
- - test/timecop_without_date_test.rb
70
- - test/timecop_without_date_but_with_time_test.rb
58
+ test_files: []
data/test/run_tests.sh DELETED
@@ -1,10 +0,0 @@
1
- #!/bin/sh
2
-
3
- FAILEDCASES=0
4
- for f in *_test.rb; do
5
- if ! ${RUBY:-ruby} -I../lib:. $f; then
6
- FAILEDCASES=`expr "$FAILEDCASES" + 1`
7
- fi
8
- done
9
- echo "$FAILEDCASES test cases had failures"
10
- exit $FAILEDCASES
data/test/test_helper.rb DELETED
@@ -1,58 +0,0 @@
1
- require 'rubygems'
2
- require 'bundler/setup'
3
- require 'minitest/autorun'
4
-
5
- $VERBOSE = true # enable ruby warnings
6
-
7
- begin
8
- require 'mocha/setup'
9
- rescue LoadError
10
- require 'mocha'
11
- end
12
-
13
- class Minitest::Unit::TestCase
14
- private
15
- # Tests to see that two times are within the given distance,
16
- # in seconds, from each other.
17
- def times_effectively_equal(time1, time2, seconds_interval = 1)
18
- (time1 - time2).abs <= seconds_interval
19
- end
20
-
21
- def assert_times_effectively_equal(time1, time2, seconds_interval = 1, msg = nil)
22
- assert times_effectively_equal(time1, time2, seconds_interval), "#{msg}: time1 = #{time1.to_s}, time2 = #{time2.to_s}"
23
- end
24
-
25
- def assert_times_effectively_not_equal(time1, time2, seconds_interval = 1, msg = nil)
26
- assert !times_effectively_equal(time1, time2, seconds_interval), "#{msg}: time1 = #{time1.to_s}, time2 = #{time2.to_s}"
27
- end
28
-
29
- # Gets the local offset (supplied by ENV['TZ'] or your computer's clock)
30
- # At the given timestamp, or Time.now if not time is given.
31
- def local_offset(time = Time.now)
32
- Time.at(time.to_i).to_datetime.offset
33
- end
34
-
35
- TIMEZONES = ["Europe/Paris", "UTC", "America/Chicago"]
36
-
37
- def each_timezone
38
- old_tz = ENV["TZ"]
39
-
40
- begin
41
- TIMEZONES.each do |timezone|
42
- ENV["TZ"] = timezone
43
- yield
44
- end
45
- ensure
46
- ENV["TZ"] = old_tz
47
- end
48
- end
49
-
50
- def a_time_stack_item
51
- Timecop::TimeStackItem.new(:freeze, 2008, 1, 1, 0, 0, 0)
52
- end
53
-
54
- def assert_date_times_equal(dt1, dt2)
55
- assert_in_delta dt1.to_time.to_f, dt2.to_time.to_f, 0.01, "Failed for timezone: #{ENV['TZ']}: #{dt1.to_s} not equal to #{dt2.to_s}"
56
- end
57
-
58
- end
@@ -1,277 +0,0 @@
1
- require 'date'
2
- require File.join(File.dirname(__FILE__), "test_helper")
3
- require File.join(File.dirname(__FILE__), '..', 'lib', 'timecop')
4
-
5
- require 'active_support/all'
6
-
7
- class TestTimeStackItem < Minitest::Unit::TestCase
8
- def teardown
9
- Timecop.return
10
- Time.zone = nil
11
- end
12
-
13
- def test_new_with_time
14
- t = Time.now
15
- y, m, d, h, min, s = t.year, t.month, t.day, t.hour, t.min, t.sec
16
- stack_item = Timecop::TimeStackItem.new(:freeze, t)
17
-
18
- assert_equal y, stack_item.year
19
- assert_equal m, stack_item.month
20
- assert_equal d, stack_item.day
21
- assert_equal h, stack_item.hour
22
- assert_equal min, stack_item.min
23
- assert_equal s, stack_item.sec
24
- end
25
-
26
- def test_new_with_time_and_arguments
27
- t = Time.new(2012, 7, 28, 20, 0)
28
- y, m, d, h, min, s = t.year, t.month, t.day, t.hour, t.min, t.sec
29
- stack_item = Timecop::TimeStackItem.new(:freeze, t)
30
-
31
- assert_equal y, stack_item.year
32
- assert_equal m, stack_item.month
33
- assert_equal d, stack_item.day
34
- assert_equal h, stack_item.hour
35
- assert_equal min, stack_item.min
36
- assert_equal s, stack_item.sec
37
- end
38
-
39
- def test_new_with_datetime_now
40
- t = DateTime.now
41
- y, m, d, h, min, s = t.year, t.month, t.day, t.hour, t.min, t.sec
42
- stack_item = Timecop::TimeStackItem.new(:freeze, t)
43
-
44
- assert_equal y, stack_item.year
45
- assert_equal m, stack_item.month
46
- assert_equal d, stack_item.day
47
- assert_equal h, stack_item.hour
48
- assert_equal min, stack_item.min
49
- assert_equal s, stack_item.sec
50
- end
51
-
52
- def test_new_with_datetime_in_different_timezone
53
- each_timezone do
54
- t = DateTime.parse("2009-10-11 00:38:00 +0200")
55
- stack_item = Timecop::TimeStackItem.new(:freeze, t)
56
-
57
- assert_date_times_equal(t, stack_item.datetime)
58
- end
59
- end
60
-
61
- def test_new_with_date
62
- date = Date.today
63
- y, m, d, h, min, s = date.year, date.month, date.day, 0, 0, 0
64
- stack_item = Timecop::TimeStackItem.new(:freeze, date)
65
-
66
- assert_equal y, stack_item.year
67
- assert_equal m, stack_item.month
68
- assert_equal d, stack_item.day
69
- assert_equal h, stack_item.hour
70
- assert_equal min, stack_item.min
71
- assert_equal s, stack_item.sec
72
- end
73
-
74
- # Due to the nature of this test (calling Time.now once in this test and
75
- # once in #new), this test may fail when two subsequent calls
76
- # to Time.now return a different second.
77
- def test_new_with_integer
78
- t = Time.now
79
- y, m, d, h, min, s = t.year, t.month, t.day, t.hour, t.min, t.sec
80
- stack_item = Timecop::TimeStackItem.new(:freeze, 0)
81
-
82
- assert_equal y, stack_item.year
83
- assert_equal m, stack_item.month
84
- assert_equal d, stack_item.day
85
- assert_equal h, stack_item.hour
86
- assert_equal min, stack_item.min
87
- assert_equal s, stack_item.sec
88
- end
89
-
90
- def test_new_with_individual_arguments
91
- y, m, d, h, min, s = 2008, 10, 10, 10, 10, 10
92
- stack_item = Timecop::TimeStackItem.new(:freeze, y, m, d, h, min, s)
93
-
94
- assert_equal y, stack_item.year
95
- assert_equal m, stack_item.month
96
- assert_equal d, stack_item.day
97
- assert_equal h, stack_item.hour
98
- assert_equal min, stack_item.min
99
- assert_equal s, stack_item.sec
100
- end
101
-
102
- def test_rational_to_utc_offset
103
- assert_equal -14400, a_time_stack_item.send(:rational_to_utc_offset, Rational(-1, 6))
104
- assert_equal -18000, a_time_stack_item.send(:rational_to_utc_offset, Rational(-5, 24))
105
- assert_equal 0, a_time_stack_item.send(:rational_to_utc_offset, Rational(0, 1))
106
- assert_equal 3600, a_time_stack_item.send(:rational_to_utc_offset, Rational(1, 24))
107
- end
108
-
109
- def test_utc_offset_to_rational
110
- assert_equal Rational(-1, 6), a_time_stack_item.send(:utc_offset_to_rational, -14400)
111
- assert_equal Rational(-5, 24), a_time_stack_item.send(:utc_offset_to_rational, -18000)
112
- assert_equal Rational(0, 1), a_time_stack_item.send(:utc_offset_to_rational, 0)
113
- assert_equal Rational(1, 24), a_time_stack_item.send(:utc_offset_to_rational, 3600)
114
- end
115
-
116
- def test_datetime_in_presence_of_activesupport_timezone
117
- skip('requires ActiveSupport') unless Time.respond_to? :zone
118
- backed_up_zone, backed_up_tzvar = Time.zone, ENV['TZ']
119
-
120
- Time.zone = ENV['TZ'] = 'America/Los_Angeles'
121
- t = DateTime.new(2001, 2, 28, 23, 59, 59.5)
122
- tsi = Timecop::TimeStackItem.new(:freeze, t)
123
-
124
- assert_date_times_equal t, tsi.datetime
125
- ensure
126
- Time.zone, ENV['TZ'] = backed_up_zone, backed_up_tzvar
127
- end
128
-
129
- # Ensure DateTimes handle changing DST properly
130
- def test_datetime_for_dst_to_non_dst
131
- Timecop.freeze(DateTime.parse("2009-12-1 00:38:00 -0500"))
132
- t = DateTime.parse("2009-10-11 00:00:00 -0400")
133
- tsi = Timecop::TimeStackItem.new(:freeze, t)
134
-
135
- assert_date_times_equal t, tsi.datetime
136
- end
137
-
138
- # Ensure DateTimes handle changing DST properly when changing from DateTime to Time
139
- def test_datetime_for_dst_to_time_for_non_dst
140
- Timecop.freeze(DateTime.parse("2009-12-1 00:38:00 -0500"))
141
- t = DateTime.parse("2009-10-11 00:00:00 -0400")
142
- tsi = Timecop::TimeStackItem.new(:freeze, t)
143
-
144
- assert_date_times_equal t.to_time, tsi.time
145
- end
146
-
147
- def test_datetime_for_non_dst_to_dst
148
- Timecop.freeze(DateTime.parse("2009-10-11 00:00:00 -0400"))
149
- t = DateTime.parse("2009-11-30 23:38:00 -0500")
150
- tsi = Timecop::TimeStackItem.new(:freeze, t)
151
- return if !tsi.time.dst?
152
-
153
- assert_date_times_equal t, tsi.datetime
154
- assert_equal Date.new(2009, 12, 1), tsi.date
155
- end
156
-
157
- def test_set_travel_offset_for_travel
158
- t_now = Time.now
159
- t = Time.local(2009, 10, 1, 0, 0, 30)
160
- expected_offset = t - t_now
161
- tsi = Timecop::TimeStackItem.new(:travel, t)
162
-
163
- assert_times_effectively_equal expected_offset, tsi.send(:travel_offset), 1, "Offset not calculated correctly"
164
- end
165
-
166
- def test_set_travel_offset_for_freeze
167
- Timecop.freeze(2009, 10, 1, 0, 0, 0)
168
- t = Time.local(2009, 10, 1, 0, 0, 30)
169
- tsi = Timecop::TimeStackItem.new(:freeze, t)
170
-
171
- assert_equal nil, tsi.send(:travel_offset)
172
- end
173
-
174
- def test_timezones
175
- Time.zone = "Europe/Zurich"
176
- time = Time.zone.parse("2012-12-27T12:12:12+08:00")
177
- Timecop.freeze(time) do |frozen_time|
178
- assert_equal time, frozen_time
179
- end
180
- end
181
-
182
- def test_timezones_apply_dates
183
- Time.zone = "Central Time (US & Canada)"
184
- time = Time.zone.local(2013,1,3)
185
-
186
- Timecop.freeze(time) do
187
- assert_equal time.to_date, Time.now.to_date
188
- end
189
- end
190
-
191
- def test_set_scaling_factor_for_scale
192
- t_now = Time.now
193
- t = Time.local(2009, 10, 1, 0, 0, 30)
194
- expected_offset = t - t_now
195
- tsi = Timecop::TimeStackItem.new(:scale, 4, t)
196
-
197
- assert_times_effectively_equal expected_offset, tsi.send(:travel_offset), 1, "Offset not calculated correctly"
198
- assert_equal tsi.send(:scaling_factor), 4, "Scaling factor not set"
199
- end
200
-
201
- def test_parse_only_string_with_active_support
202
- Time.expects(:parse).never
203
- Timecop.freeze(2011, 01, 02, hour=0, minute=0, second=0)
204
- end
205
-
206
- def test_parse_date
207
- Timecop.freeze(Date.new(2012, 6, 9))
208
- end
209
-
210
- def test_time_zone_returns_nil
211
- Time.zone = nil
212
- Timecop.freeze
213
- end
214
-
215
- def test_nsecs_are_set
216
- time = Time.now
217
- Timecop.freeze time
218
- assert_equal time, Time.now
219
- assert_equal time.nsec, Time.now.nsec if (Time.now.respond_to?(:nsec))
220
- end
221
-
222
- def test_time_with_different_timezone_keeps_nsec
223
- Time.zone = "Tokyo"
224
- t = Time.now
225
- Timecop.freeze(t) do
226
- assert_equal t, Time.now
227
- assert_equal t.nsec, Time.now.nsec if (Time.now.respond_to?(:nsec))
228
- end
229
- end
230
-
231
- def test_time_now_always_returns_local_time
232
- Time.zone = "Tokyo"
233
- t = Time.utc(2000, 1, 1)
234
- Timecop.freeze(t) do
235
- assert_equal t.getlocal.zone, Time.now.zone
236
- end
237
- end
238
-
239
- def test_time_zone_now_returns_time_in_that_zone
240
- Time.zone = "Hawaii"
241
- t = Time.utc(2000, 1, 1)
242
- Timecop.freeze(t) do
243
- assert_equal t, Time.zone.now
244
- assert_equal 'HST', Time.zone.now.zone
245
- end
246
- end
247
-
248
- def test_freezing_a_time_leaves_timezone_intact
249
- Time.zone = "Tokyo"
250
- t = Time.now
251
- t_dup = t.dup
252
- Timecop.freeze(t) {}
253
- assert_equal t_dup.zone, t.zone
254
- end
255
-
256
- def test_freezing_a_time_with_zone_returns_proper_zones
257
- Time.zone = "Hawaii"
258
- t = ActiveSupport::TimeWithZone.new(Time.utc(2000, 1, 1), ActiveSupport::TimeZone['Tokyo'])
259
- Timecop.freeze(t) do
260
- local_now = Time.now
261
- assert_equal t, local_now
262
- assert_equal t.getlocal.zone, local_now.zone
263
-
264
- zoned_now = Time.zone.now
265
- assert_equal t, zoned_now
266
- assert_equal 'HST', zoned_now.zone
267
- end
268
- end
269
-
270
- def test_datetime_timezones
271
- dt = DateTime.new(2011,1,3,15,25,0,"-6")
272
- Timecop.freeze(dt) do
273
- now = DateTime.now
274
- assert_equal dt, now, "#{dt.to_f}, #{now.to_f}"
275
- end
276
- end
277
- end