timecop 0.9.7 → 0.9.9

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 016ae208ea8ac5c5713b042c7ea1f030bd2d3ff312e95b349e3d31264fc0f0d4
4
- data.tar.gz: ed69f4b76ca2a02af2c10f4ad486140bbfefae3d1f3ac13f2d0e7a9176ba09d8
3
+ metadata.gz: 5ffc3899071434ff0ae8eb0a9e4a6ea4c2d8794547113c272bdc24a384d2eb45
4
+ data.tar.gz: e9333e4c2cf362558c432d7b954a724ff588e66c4dcce8d3af4a327dd6dcb894
5
5
  SHA512:
6
- metadata.gz: f47a6e763afa59b037e5e00250b63a623cf3e605135962ecca5bd7eba9e7e36db669c8c261dcefc52ee6c852f1a1507977d5266ad1c63bd007d1edc50414ea1e
7
- data.tar.gz: b4a3bff764722b9d1c95d0e7f01dbdad3953503d87e4587c02ad12c0fc5ebe47598177cafdd4d81b9dfaee6ef76447a2e15f5382403cad224fbe08221886fc90
6
+ metadata.gz: 692759ecf208cccb83f72d2cd2a3632d6fb6477e9ac1dbf1ca19d8c23a0b864093abdfdc1d51ee98078858dc2dd3eab50f1bd8b469cc84f0619c99bed242169f
7
+ data.tar.gz: 85fc3b65a8f415601a047d4189ff497a73f49d4d48647881a6579d82dc6f12ab9e6a088da0ca2b3c2a25693f220ce3c8f31b5f2847f6a5d4784c63ace77136ff
data/README.markdown CHANGED
@@ -5,7 +5,7 @@
5
5
 
6
6
  ## DESCRIPTION
7
7
 
8
- A gem providing "time travel" and "time freezing" capabilities, making it dead simple to test time-dependent code. It provides a unified method to mock `Time.now`, `Date.today`, and `DateTime.now` in a single call.
8
+ A gem providing "time travel" and "time freezing" capabilities, making it dead simple to test time-dependent code. It provides a unified method to mock `Time.now`, `Date.today`, `DateTime.now`, and `Process.clock_gettime` in a single call.
9
9
 
10
10
  ## INSTALL
11
11
 
@@ -58,14 +58,21 @@ class Date #:nodoc:
58
58
  Date.new(year, mon, d[:mday], start)
59
59
  elsif d[:yday]
60
60
  Date.new(year, 1, 1, start).next_day(d[:yday] - 1)
61
- elsif d[:cwyear] || d[:cweek] || d[:wnum1] || d[:wday] || d[:cwday]
62
- day_of_week_from_monday = if d[:wday]
63
- (d[:wday] + 6)%7 + 1
64
- else
65
- d[:cwday] || 1
66
- end
67
- week = d[:cweek] || d[:wnum1] || now.strftime('%W').to_i
68
- Date.commercial(year, week, day_of_week_from_monday, start)
61
+ elsif d[:cwyear] || d[:cweek] || d[:wnum0] || d[:wnum1] || d[:wday] || d[:cwday]
62
+ week = d[:cweek] || d[:wnum1] || d[:wnum0] || now.strftime('%W').to_i
63
+ if d[:wnum0] #Week of year where week starts on sunday
64
+ if d[:cwday] #monday based day of week
65
+ Date.strptime_without_mock_date("#{year} #{week} #{d[:cwday]}", '%Y %U %u', start)
66
+ else
67
+ Date.strptime_without_mock_date("#{year} #{week} #{d[:wday] || 0}", '%Y %U %w', start)
68
+ end
69
+ else #Week of year where week starts on monday
70
+ if d[:wday] #sunday based day of week
71
+ Date.strptime_without_mock_date("#{year} #{week} #{d[:wday]}", '%Y %W %w', start)
72
+ else
73
+ Date.strptime_without_mock_date("#{year} #{week} #{d[:cwday] || 1}", '%Y %W %u', start)
74
+ end
75
+ end
69
76
  elsif d[:seconds]
70
77
  Time.at(d[:seconds]).to_date
71
78
  else
@@ -136,8 +143,17 @@ class DateTime #:nodoc:
136
143
  DateTime.new(mocked_time_stack_item.year, date_hash[:mon], date_hash[:mday])
137
144
  when date_hash[:mday]
138
145
  DateTime.new(mocked_time_stack_item.year, mocked_time_stack_item.month, date_hash[:mday])
146
+ when date_hash[:wday] && date_hash[:hour] && date_hash[:min]
147
+ closest_date = Date.closest_wday(date_hash[:wday]).to_datetime
148
+
149
+ DateTime.new(
150
+ closest_date.year, closest_date.month, closest_date.day,
151
+ date_hash[:hour], date_hash[:min]
152
+ )
139
153
  when date_hash[:wday]
140
154
  Date.closest_wday(date_hash[:wday]).to_datetime
155
+ when date_hash[:hour] && date_hash[:min] && date_hash[:sec]
156
+ DateTime.new(mocked_time_stack_item.year, mocked_time_stack_item.month, mocked_time_stack_item.day, date_hash[:hour], date_hash[:min], date_hash[:sec])
141
157
  else
142
158
  parsed_date + mocked_time_stack_item.travel_offset_days
143
159
  end
@@ -151,3 +167,59 @@ class DateTime #:nodoc:
151
167
  end
152
168
  end
153
169
  end
170
+
171
+ if RUBY_VERSION >= '2.1.0'
172
+ module Process #:nodoc:
173
+ class << self
174
+ alias_method :clock_gettime_without_mock, :clock_gettime
175
+
176
+ def clock_gettime_mock_time(clock_id, unit = :float_second)
177
+ mock_time = case clock_id
178
+ when Process::CLOCK_MONOTONIC
179
+ mock_time_monotonic
180
+ when Process::CLOCK_REALTIME
181
+ mock_time_realtime
182
+ end
183
+
184
+ return clock_gettime_without_mock(clock_id, unit) unless mock_time
185
+
186
+ divisor = case unit
187
+ when :float_second
188
+ 1_000_000_000.0
189
+ when :second
190
+ 1_000_000_000
191
+ when :float_millisecond
192
+ 1_000_000.0
193
+ when :millisecond
194
+ 1_000_000
195
+ when :float_microsecond
196
+ 1000.0
197
+ when :microsecond
198
+ 1000
199
+ when :nanosecond
200
+ 1
201
+ end
202
+
203
+ (mock_time / divisor)
204
+ end
205
+
206
+ alias_method :clock_gettime, :clock_gettime_mock_time
207
+
208
+ private
209
+
210
+ def mock_time_monotonic
211
+ mocked_time_stack_item = Timecop.top_stack_item
212
+ mocked_time_stack_item.nil? ? nil : mocked_time_stack_item.monotonic
213
+ end
214
+
215
+ def mock_time_realtime
216
+ mocked_time_stack_item = Timecop.top_stack_item
217
+
218
+ return nil if mocked_time_stack_item.nil?
219
+
220
+ t = mocked_time_stack_item.time
221
+ t.to_i * 1_000_000_000 + t.nsec
222
+ end
223
+ end
224
+ end
225
+ end
@@ -9,6 +9,7 @@ class Timecop
9
9
  @travel_offset = @scaling_factor = nil
10
10
  @scaling_factor = args.shift if mock_type == :scale
11
11
  @mock_type = mock_type
12
+ @monotonic = parse_monotonic_time(*args) if RUBY_VERSION >= '2.1.0'
12
13
  @time = parse_time(*args)
13
14
  @time_was = Time.now_without_mock_time
14
15
  @travel_offset = compute_travel_offset
@@ -54,9 +55,29 @@ class Timecop
54
55
  @scaling_factor
55
56
  end
56
57
 
58
+ if RUBY_VERSION >= '2.1.0'
59
+ def monotonic
60
+ if travel_offset.nil?
61
+ @monotonic
62
+ elsif scaling_factor.nil?
63
+ current_monotonic + travel_offset * (10 ** 9)
64
+ else
65
+ (@monotonic + (current_monotonic - @monotonic) * scaling_factor).to_i
66
+ end
67
+ end
68
+
69
+ def current_monotonic
70
+ Process.clock_gettime_without_mock(Process::CLOCK_MONOTONIC, :nanosecond)
71
+ end
72
+
73
+ def current_monotonic_with_mock
74
+ Process.clock_gettime_mock_time(Process::CLOCK_MONOTONIC, :nanosecond)
75
+ end
76
+ end
77
+
57
78
  def time(time_klass = Time) #:nodoc:
58
79
  if @time.respond_to?(:in_time_zone)
59
- time = time_klass.at(@time.localtime)
80
+ time = time_klass.at(@time.dup.localtime)
60
81
  else
61
82
  time = time_klass.at(@time)
62
83
  end
@@ -97,6 +118,16 @@ class Timecop
97
118
  Rational(utc_offset, 24 * 60 * 60)
98
119
  end
99
120
 
121
+ def parse_monotonic_time(*args)
122
+ arg = args.shift
123
+ offset_in_nanoseconds = if args.empty? && (arg.kind_of?(Integer) || arg.kind_of?(Float))
124
+ arg * 1_000_000_000
125
+ else
126
+ 0
127
+ end
128
+ current_monotonic_with_mock + offset_in_nanoseconds
129
+ end
130
+
100
131
  def parse_time(*args)
101
132
  arg = args.shift
102
133
  if arg.is_a?(Time)
@@ -38,6 +38,12 @@ class Timecop
38
38
  # previous values after the block has finished executing. This allows us to nest multiple
39
39
  # calls to Timecop.travel and have each block maintain it's concept of "now."
40
40
  #
41
+ # The Process.clock_gettime call mocks both CLOCK::MONOTIC and CLOCK::REALTIME
42
+ #
43
+ # CLOCK::MONOTONIC works slightly differently than other clocks. This clock cannot move to a
44
+ # particular date/time. So the only option that changes this clock is #4 which will move the
45
+ # clock the requested offset. Otherwise the clock is frozen to the current tick.
46
+ #
41
47
  # * Note: Timecop.freeze will actually freeze time. This can cause unanticipated problems if
42
48
  # benchmark or other timing calls are executed, which implicitly expect Time to actually move
43
49
  # forward.
@@ -126,6 +132,16 @@ class Timecop
126
132
  !instance.stack.empty? && instance.stack.last.mock_type == :freeze
127
133
  end
128
134
 
135
+ # Returns whether or not Timecop is currently travelled
136
+ def travelled?
137
+ !instance.stack.empty? && instance.stack.last.mock_type == :travel
138
+ end
139
+
140
+ # Returns whether or not Timecop is currently scaled
141
+ def scaled?
142
+ !instance.stack.empty? && instance.stack.last.mock_type == :scale
143
+ end
144
+
129
145
  private
130
146
  def send_travel(mock_type, *args, &block)
131
147
  val = instance.travel(mock_type, *args, &block)
@@ -1,3 +1,3 @@
1
1
  class Timecop
2
- VERSION = "0.9.7"
2
+ VERSION = "0.9.9"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: timecop
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.7
4
+ version: 0.9.9
5
5
  platform: ruby
6
6
  authors:
7
7
  - Travis Jeffery
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2023-08-12 00:00:00.000000000 Z
12
+ date: 2024-06-01 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