timecop 0.1.0 → 0.2.0
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.
- data/History.txt +26 -0
- data/Manifest.txt +4 -0
- data/README.txt +10 -6
- data/Rakefile +10 -0
- data/lib/timecop/stack_item.rb +11 -0
- data/lib/timecop/time_extensions.rb +37 -19
- data/lib/timecop/timecop.rb +128 -54
- data/lib/timecop/version.rb +1 -1
- data/test/run_tests.sh +10 -0
- data/test/test_timecop.rb +74 -54
- data/test/test_timecop_internals.rb +54 -0
- data/test/test_timecop_without_date.rb +105 -6
- data/timecop.gemspec +4 -4
- metadata +7 -3
- data/test/test_timecop_with_rails.rb +0 -22
data/History.txt
CHANGED
@@ -1,3 +1,29 @@
|
|
1
|
+
=== 0.2.0 / 2008-12-23
|
2
|
+
|
3
|
+
* API Changes
|
4
|
+
|
5
|
+
* Timecop#travel no longer freezes time. Rather, it computes the current offset between the new "now" and the real "now", and
|
6
|
+
returns times as if Time had continued to move forward
|
7
|
+
|
8
|
+
* Timecop#freeze now behaves exactly as the old Timecop#travel behaved. Unless you depended on the actual freezing of time
|
9
|
+
(which I think would be rare), you should be able to continue to use #travel without worry.
|
10
|
+
|
11
|
+
* Timecop#return is now exposed (previously Timecop#unset_all, but not well advertised). It will completely unmock time,
|
12
|
+
and will probably be rarely used outside of the actual implementation of this library.
|
13
|
+
|
14
|
+
* More Test Coverage
|
15
|
+
|
16
|
+
* Tests now explicitly cover the cases when the Date and DateTime objects are not loaded, and ensures proper functionality
|
17
|
+
in their absence and existence.
|
18
|
+
|
19
|
+
* Still haven't done regression testing against anything other than a few version of 1.8.6 (including REE). We should
|
20
|
+
probably try to get this tested on both 1.8.7 and 1.9.1.
|
21
|
+
|
22
|
+
* Documentation
|
23
|
+
|
24
|
+
* Fixed up a lot of the poorly-formatted rdoc syntax. The public API should now be properly published in the rdoc,
|
25
|
+
and the internals are omitted.
|
26
|
+
|
1
27
|
=== 0.1.0 / 2008-11-09
|
2
28
|
|
3
29
|
* Initial Feature Set
|
data/Manifest.txt
CHANGED
@@ -3,8 +3,12 @@ Manifest.txt
|
|
3
3
|
README.txt
|
4
4
|
Rakefile
|
5
5
|
lib/timecop.rb
|
6
|
+
lib/timecop/stack_item.rb
|
6
7
|
lib/timecop/time_extensions.rb
|
7
8
|
lib/timecop/timecop.rb
|
8
9
|
lib/timecop/version.rb
|
10
|
+
test/run_tests.sh
|
9
11
|
test/test_timecop.rb
|
12
|
+
test/test_timecop_internals.rb
|
13
|
+
test/test_timecop_without_date.rb
|
10
14
|
timecop.gemspec
|
data/README.txt
CHANGED
@@ -4,14 +4,18 @@
|
|
4
4
|
|
5
5
|
== DESCRIPTION:
|
6
6
|
|
7
|
-
A gem providing simple ways to
|
7
|
+
A gem providing simple ways to mock Time.now, Date.today, and DateTime.now. It provides "time travel" and "time freezing" capabilities, making it dead simple to write test time-dependent code.
|
8
8
|
|
9
|
-
== FEATURES
|
9
|
+
== FEATURES:
|
10
10
|
|
11
|
-
* Temporarily (or permanently if you prefer) change the concept of Time.now, DateTime.now
|
12
|
-
* Timecop
|
11
|
+
* Temporarily (or permanently if you prefer) change the concept of Time.now, DateTime.now, and Date.today
|
12
|
+
* Timecop api allows an arguments to be passed into #freeze and #travel as one of: 1) Time instance, 2) DateTime instance, 3) Date instance,
|
13
13
|
4) individual arguments (year, month, day, hour, minute, second)
|
14
|
-
* Nested calls to Timecop#travel are supported -- each block will maintain it's interpretation of now.
|
14
|
+
* Nested calls to Timecop#travel and Timecop#freeze are supported -- each block will maintain it's interpretation of now.
|
15
|
+
|
16
|
+
== SHORTCOMINGS:
|
17
|
+
|
18
|
+
* Only fully tested on the 1.8.6 Ruby implementations. 1.8.7 and 1.9.1 should be tested, as well as other flavors (jruby, etc.)
|
15
19
|
|
16
20
|
== SYNOPSIS:
|
17
21
|
|
@@ -21,7 +25,7 @@ A gem providing simple ways to (temporarily) override Time.now, Date.today, and
|
|
21
25
|
joe.purchase_home()
|
22
26
|
assert !joe.mortgage_due?
|
23
27
|
# move ahead a month and assert that the mortgage is due
|
24
|
-
Timecop.
|
28
|
+
Timecop.freeze(Date.today + 30) do
|
25
29
|
assert joe.mortgage_due?
|
26
30
|
end
|
27
31
|
</code>
|
data/Rakefile
CHANGED
@@ -31,3 +31,13 @@ end
|
|
31
31
|
|
32
32
|
# vim: syntax=Ruby
|
33
33
|
|
34
|
+
# Override the test task and instruct them how to actually run the tests.
|
35
|
+
Rake.application.send(:eval, "@tasks.delete('test')")
|
36
|
+
desc "Does not execute tests. Manually run shell script ./run_tests.sh to execute tests."
|
37
|
+
task :test do
|
38
|
+
puts <<-MSG
|
39
|
+
In order to run the test suite, run: cd test && ./run_tests.sh
|
40
|
+
The tests need to be run with different libraries loaded, which rules out using Rake
|
41
|
+
to automate them.
|
42
|
+
MSG
|
43
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
|
2
|
+
# Simply a data class for carrying around "time movement" objects. Makes it easy to keep track of the time
|
3
|
+
# movements on a simple stack.
|
4
|
+
class StackItem
|
5
|
+
|
6
|
+
attr_reader :mock_type, :year, :month, :day, :hour, :minute, :second
|
7
|
+
def initialize(mock_type, year, month, day, hour, minute, second)
|
8
|
+
@mock_type, @year, @month, @day, @hour, @minute, @second = mock_type, year, month, day, hour, minute, second
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
@@ -7,11 +7,33 @@
|
|
7
7
|
class Time
|
8
8
|
class << self
|
9
9
|
# Time we might be behaving as
|
10
|
-
attr_reader :mock_time
|
10
|
+
#attr_reader :mock_time
|
11
|
+
|
12
|
+
@@mock_offset = nil
|
13
|
+
@@mock_time = nil
|
14
|
+
|
15
|
+
def mock_time
|
16
|
+
if !@@mock_offset.nil?
|
17
|
+
now_without_mock_time - @@mock_offset
|
18
|
+
else
|
19
|
+
@@mock_time
|
20
|
+
end
|
21
|
+
end
|
11
22
|
|
12
23
|
# Set new time to pretend we are.
|
13
|
-
def
|
14
|
-
|
24
|
+
def freeze_time(new_now)
|
25
|
+
@@mock_time = new_now
|
26
|
+
@@mock_offset = nil
|
27
|
+
end
|
28
|
+
|
29
|
+
def move_time(new_now)
|
30
|
+
@@mock_offset = new_now.nil? ? nil : (now_without_mock_time - new_now)
|
31
|
+
@@mock_time = nil
|
32
|
+
end
|
33
|
+
|
34
|
+
# Restores Time to system clock
|
35
|
+
def unmock!
|
36
|
+
move_time(nil)
|
15
37
|
end
|
16
38
|
|
17
39
|
# Alias the original now
|
@@ -30,14 +52,12 @@ end
|
|
30
52
|
if Object.const_defined?(:Date)
|
31
53
|
class Date
|
32
54
|
class << self
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
def mock_date=(new_date)
|
38
|
-
@mock_date = new_date
|
55
|
+
def mock_date
|
56
|
+
now = Time.mock_time
|
57
|
+
return nil if now.nil?
|
58
|
+
Date.new(now.year, now.month, now.day)
|
39
59
|
end
|
40
|
-
|
60
|
+
|
41
61
|
# Alias the original today
|
42
62
|
alias_method :today_without_mock_date, :today
|
43
63
|
|
@@ -55,22 +75,20 @@ end
|
|
55
75
|
if Object.const_defined?(:DateTime)
|
56
76
|
class DateTime
|
57
77
|
class << self
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
def mock_time=(new_now)
|
63
|
-
@mock_time = new_now
|
78
|
+
def mock_time
|
79
|
+
t_now = Time.mock_time
|
80
|
+
return nil if t_now.nil?
|
81
|
+
DateTime.new(t_now.year, t_now.month, t_now.day, t_now.hour, t_now.min, t_now.sec)
|
64
82
|
end
|
65
|
-
|
83
|
+
|
66
84
|
# Alias the original now
|
67
85
|
alias_method :now_without_mock_time, :now
|
68
|
-
|
86
|
+
|
69
87
|
# Define now_with_mock_time
|
70
88
|
def now_with_mock_time
|
71
89
|
mock_time || now_without_mock_time
|
72
90
|
end
|
73
|
-
|
91
|
+
|
74
92
|
# Alias now to now_with_mock_time
|
75
93
|
alias_method :now, :now_with_mock_time
|
76
94
|
end
|
data/lib/timecop/timecop.rb
CHANGED
@@ -1,39 +1,17 @@
|
|
1
|
+
require 'singleton'
|
1
2
|
require File.join(File.dirname(__FILE__), 'time_extensions')
|
3
|
+
require File.join(File.dirname(__FILE__), 'stack_item')
|
2
4
|
|
3
|
-
#
|
4
|
-
#
|
5
|
-
#
|
5
|
+
# Timecop
|
6
|
+
# * Wrapper class for manipulating the extensions to the Time, Date, and DateTime objects
|
7
|
+
# * Allows us to "freeze" time in our Ruby applications.
|
8
|
+
# * Optionally allows time travel to simulate a running clock, such time is not technically frozen.
|
9
|
+
#
|
10
|
+
# This is very useful when your app's functionality is dependent on time (e.g.
|
6
11
|
# anything that might expire). This will allow us to alter the return value of
|
7
12
|
# Date.today, Time.now, and DateTime.now, such that our application code _never_ has to change.
|
8
13
|
class Timecop
|
9
|
-
|
10
|
-
# Re-bases Time.now, Date.today and DateTime.now (if it exists) to use the time passed in.
|
11
|
-
# When using this method directly, it is up to the developer to call unset_all to return us
|
12
|
-
# to sanity.
|
13
|
-
#
|
14
|
-
# * If being consumed in a rails app, Time.zone.local will be used to instantiate the time.
|
15
|
-
# Otherwise, Time.local will be used.
|
16
|
-
def self.set_all(year, month, day, hour=0, minute=0, second=0)
|
17
|
-
if Time.respond_to?(:zone) && !Time.zone.nil?
|
18
|
-
# ActiveSupport loaded
|
19
|
-
time = Time.zone.local(year, month, day, hour, minute, second)
|
20
|
-
else
|
21
|
-
# ActiveSupport not loaded
|
22
|
-
time = Time.local(year, month, day, hour, minute, second)
|
23
|
-
end
|
24
|
-
|
25
|
-
Time.mock_time = time
|
26
|
-
Date.mock_date = Date.new(time.year, time.month, time.day) if Object.const_defined?(:Date)
|
27
|
-
DateTime.mock_time = DateTime.new(time.year, time.month, time.day, time.hour, time.min, time.sec) if Object.const_defined?(:DateTime)
|
28
|
-
end
|
29
|
-
|
30
|
-
# Reverts back to system's Time.now, Date.today and DateTime.now (if it exists). If set_all
|
31
|
-
# was never called in the first place, this method will have no effect.
|
32
|
-
def self.unset_all
|
33
|
-
Date.mock_date = nil
|
34
|
-
DateTime.mock_time = nil if Object.const_defined?(:Date)
|
35
|
-
Time.mock_time = nil if Object.const_defined?(:DateTime)
|
36
|
-
end
|
14
|
+
include Singleton
|
37
15
|
|
38
16
|
# Allows you to run a block of code and "fake" a time throughout the execution of that block.
|
39
17
|
# This is particularly useful for writing test methods where the passage of time is critical to the business
|
@@ -43,49 +21,145 @@ class Timecop
|
|
43
21
|
# joe = User.find(1)
|
44
22
|
# joe.purchase_home()
|
45
23
|
# assert !joe.mortgage_due?
|
46
|
-
# Timecop.
|
24
|
+
# Timecop.freeze(2008, 10, 5) do
|
47
25
|
# assert joe.mortgage_due?
|
48
26
|
# end
|
49
27
|
# </code>
|
50
28
|
#
|
51
|
-
# travel will respond to several different arguments:
|
52
|
-
# 1. Timecop.
|
53
|
-
# 2. Timecop.
|
54
|
-
# 3. Timecop.
|
55
|
-
# 4. Timecop.
|
29
|
+
# freeze and travel will respond to several different arguments:
|
30
|
+
# 1. Timecop.freeze(time_inst)
|
31
|
+
# 2. Timecop.freeze(datetime_inst)
|
32
|
+
# 3. Timecop.freeze(date_inst)
|
33
|
+
# 4. Timecop.freeze(year, month, day, hour=0, minute=0, second=0)
|
56
34
|
#
|
57
|
-
# When a block is also passed,
|
35
|
+
# When a block is also passed, Time.now, DateTime.now and Date.today are all reset to their
|
58
36
|
# previous values. This allows us to nest multiple calls to Timecop.travel and have each block
|
59
37
|
# maintain it's concept of "now."
|
60
|
-
#
|
38
|
+
#
|
39
|
+
# * Note: Timecop.freeze will actually freeze time. This can cause unanticipated problems if
|
40
|
+
# benchmark or other timing calls are executed, which implicitly expect Time to actually move
|
41
|
+
# forward.
|
42
|
+
#
|
43
|
+
# * Rails Users: Be especially careful when setting this in your development environment in a
|
44
|
+
# rails project. Generators will load your environment, including the migration generator,
|
45
|
+
# which will lead to files being generated with the timestamp set by the Timecop.freeze call
|
46
|
+
# in your dev environment
|
47
|
+
def self.freeze(*args, &block)
|
48
|
+
instance().send(:travel, :freeze, *args, &block)
|
49
|
+
end
|
50
|
+
|
51
|
+
# Allows you to run a block of code and "fake" a time throughout the execution of that block.
|
52
|
+
# See Timecop#freeze for a sample of how to use (same exact usage syntax)
|
53
|
+
#
|
54
|
+
# * Note: Timecop.travel will not freeze time (as opposed to Timecop.freeze). This is a particularly
|
55
|
+
# good candidate for use in environment files in rails projects.
|
61
56
|
def self.travel(*args, &block)
|
62
|
-
|
57
|
+
instance().send(:travel, :move, *args, &block)
|
58
|
+
end
|
59
|
+
|
60
|
+
# Reverts back to system's Time.now, Date.today and DateTime.now (if it exists). If freeze_all or rebase_all
|
61
|
+
# was never called in the first place, this method will have no effect.
|
62
|
+
def self.return
|
63
|
+
instance().send(:unmock!)
|
64
|
+
end
|
63
65
|
|
64
|
-
|
65
|
-
|
66
|
-
|
66
|
+
# [Deprecated]: See Timecop#return instead.
|
67
|
+
def self.unset_all
|
68
|
+
$stderr.puts "Timecop#unset_all is deprecated. Please use Timecop#return instead."
|
69
|
+
$stderr.flush
|
70
|
+
self.return
|
71
|
+
end
|
72
|
+
|
73
|
+
protected
|
74
|
+
|
75
|
+
def initialize
|
76
|
+
@_stack = []
|
77
|
+
end
|
78
|
+
|
79
|
+
def travel(mock_type, *args, &block)
|
80
|
+
# parse the arguments, build our base time units
|
81
|
+
year, month, day, hour, minute, second = parse_travel_args(*args)
|
67
82
|
|
68
|
-
|
83
|
+
# perform our action
|
84
|
+
if mock_type == :freeze
|
85
|
+
freeze_all(year, month, day, hour, minute, second)
|
86
|
+
else
|
87
|
+
move_all(year, month, day, hour, minute, second)
|
88
|
+
end
|
89
|
+
# store this time traveling on our stack...
|
90
|
+
@_stack << StackItem.new(mock_type, year, month, day, hour, minute, second)
|
69
91
|
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
92
|
+
if block_given?
|
93
|
+
begin
|
94
|
+
yield
|
95
|
+
ensure
|
96
|
+
# pull it off the stack...
|
97
|
+
stack_item = @_stack.pop
|
98
|
+
if @_stack.size == 0
|
99
|
+
# completely unmock if there's nothing to revert back to
|
100
|
+
unmock!
|
101
|
+
else
|
102
|
+
# or reinstantiate the new the top of the stack (could be a :freeze or a :move)
|
103
|
+
new_top = @_stack.last
|
104
|
+
if new_top.mock_type == :freeze
|
105
|
+
freeze_all(new_top.year, new_top.month, new_top.day, new_top.hour, new_top.minute, new_top.second)
|
106
|
+
else
|
107
|
+
move_all(new_top.year, new_top.month, new_top.day, new_top.hour, new_top.minute, new_top.second)
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
77
111
|
end
|
78
112
|
end
|
79
|
-
|
113
|
+
|
114
|
+
def unmock!
|
115
|
+
Time.unmock!
|
116
|
+
end
|
80
117
|
|
81
118
|
private
|
82
|
-
|
119
|
+
|
120
|
+
# Re-bases Time.now, Date.today and DateTime.now (if it exists) to use the time passed in.
|
121
|
+
# When using this method directly, it is up to the developer to call unset_all to return us
|
122
|
+
# to sanity.
|
123
|
+
#
|
124
|
+
# * If being consumed in a rails app, Time.zone.local will be used to instantiate the time.
|
125
|
+
# Otherwise, Time.local will be used.
|
126
|
+
def freeze_all(year, month, day, hour=0, minute=0, second=0)
|
127
|
+
if Time.respond_to?(:zone) && !Time.zone.nil?
|
128
|
+
# ActiveSupport loaded
|
129
|
+
time = Time.zone.local(year, month, day, hour, minute, second)
|
130
|
+
else
|
131
|
+
# ActiveSupport not loaded
|
132
|
+
time = Time.local(year, month, day, hour, minute, second)
|
133
|
+
end
|
134
|
+
|
135
|
+
Time.freeze_time(time)
|
136
|
+
end
|
137
|
+
|
138
|
+
# Re-bases Time.now, Date.today and DateTime.now to use the time passed in and to continue moving time
|
139
|
+
# forward. When using this method directly, it is up to the developer to call return to return us to
|
140
|
+
# sanity.
|
141
|
+
#
|
142
|
+
# * If being consumed in a rails app, Time.zone.local will be used to instantiate the time.
|
143
|
+
# Otherwise, Time.local will be used.
|
144
|
+
def move_all(year, month, day, hour=0, minute=0, second=0)
|
145
|
+
if Time.respond_to?(:zone) && !Time.zone.nil?
|
146
|
+
# ActiveSupport loaded
|
147
|
+
time = Time.zone.local(year, month, day, hour, minute, second)
|
148
|
+
else
|
149
|
+
# ActiveSupport not loaded
|
150
|
+
time = Time.local(year, month, day, hour, minute, second)
|
151
|
+
end
|
152
|
+
|
153
|
+
Time.move_time(time)
|
154
|
+
end
|
155
|
+
|
156
|
+
def parse_travel_args(*args)
|
83
157
|
arg = args.shift
|
84
158
|
if arg.is_a?(Time) || (Object.const_defined?(:DateTime) && arg.is_a?(DateTime))
|
85
159
|
year, month, day, hour, minute, second = arg.year, arg.month, arg.day, arg.hour, arg.min, arg.sec
|
86
160
|
elsif Object.const_defined?(:Date) && arg.is_a?(Date)
|
87
161
|
year, month, day, hour, minute, second = arg.year, arg.month, arg.day, 0, 0, 0
|
88
|
-
puts "#{year}-#{month}-#{day} #{hour}:#{minute}:#{second}"
|
162
|
+
#puts "#{year}-#{month}-#{day} #{hour}:#{minute}:#{second}"
|
89
163
|
else # we'll just assume it's a list of y/m/h/d/m/s
|
90
164
|
year = arg || 0
|
91
165
|
month = args.shift || 1
|
data/lib/timecop/version.rb
CHANGED
data/test/run_tests.sh
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
#!/bin/sh
|
2
|
+
|
3
|
+
echo "\033[1;81m Running test_timecop_internals...\033[0m"
|
4
|
+
ruby test_timecop_internals.rb || (echo "FAILED!!!!!!!!!!!!")
|
5
|
+
|
6
|
+
echo "\033[1;81m Running test_timecop_without_date...\033[0m"
|
7
|
+
ruby test_timecop_without_date.rb || (echo "FAILED!!!!!!!!!!!!")
|
8
|
+
|
9
|
+
echo "\033[1;81m Running test_timecop...\033[0m"
|
10
|
+
ruby test_timecop.rb || (echo "FAILED!!!!!!!!!!!!")
|
data/test/test_timecop.rb
CHANGED
@@ -11,37 +11,37 @@ class TestTimecop < Test::Unit::TestCase
|
|
11
11
|
|
12
12
|
# just in case...let's really make sure that Timecop is disabled between tests...
|
13
13
|
def teardown
|
14
|
-
Timecop.
|
14
|
+
Timecop.return
|
15
15
|
end
|
16
16
|
|
17
|
-
def
|
17
|
+
def test_freeze_changes_and_resets_time
|
18
18
|
# depending on how we're invoked (individually or via the rake test suite)
|
19
19
|
assert !Time.respond_to?(:zone) || Time.zone.nil?
|
20
20
|
|
21
21
|
t = Time.local(2008, 10, 10, 10, 10, 10)
|
22
22
|
assert_not_equal t, Time.now
|
23
|
-
Timecop.
|
23
|
+
Timecop.freeze(2008, 10, 10, 10, 10, 10) do
|
24
24
|
assert_equal t, Time.now
|
25
25
|
end
|
26
26
|
assert_not_equal t, Time.now
|
27
27
|
end
|
28
28
|
|
29
|
-
def
|
29
|
+
def test_recursive_freeze
|
30
30
|
t = Time.local(2008, 10, 10, 10, 10, 10)
|
31
|
-
Timecop.
|
31
|
+
Timecop.freeze(2008, 10, 10, 10, 10, 10) do
|
32
32
|
assert_equal t, Time.now
|
33
33
|
t2 = Time.local(2008, 9, 9, 9, 9, 9)
|
34
|
-
Timecop.
|
34
|
+
Timecop.freeze(2008, 9, 9, 9, 9, 9) do
|
35
35
|
assert_equal t2, Time.now
|
36
36
|
end
|
37
37
|
assert_equal t, Time.now
|
38
38
|
end
|
39
|
-
|
39
|
+
assert_not_equal t, Time.now
|
40
40
|
end
|
41
41
|
|
42
|
-
def
|
42
|
+
def test_freeze_with_time_instance_works_as_expected
|
43
43
|
t = Time.local(2008, 10, 10, 10, 10, 10)
|
44
|
-
Timecop.
|
44
|
+
Timecop.freeze(t) do
|
45
45
|
assert_equal t, Time.now
|
46
46
|
assert_equal DateTime.new(2008, 10, 10, 10, 10, 10), DateTime.now
|
47
47
|
assert_equal Date.new(2008, 10, 10), Date.today
|
@@ -51,9 +51,9 @@ class TestTimecop < Test::Unit::TestCase
|
|
51
51
|
assert_not_equal Date.new(2008, 10, 10), Date.today
|
52
52
|
end
|
53
53
|
|
54
|
-
def
|
54
|
+
def test_freeze_with_datetime_instance_works_as_expected
|
55
55
|
t = DateTime.new(2008, 10, 10, 10, 10, 10)
|
56
|
-
Timecop.
|
56
|
+
Timecop.freeze(t) do
|
57
57
|
assert_equal t, DateTime.now
|
58
58
|
assert_equal Time.local(2008, 10, 10, 10, 10, 10), Time.now
|
59
59
|
assert_equal Date.new(2008, 10, 10), Date.today
|
@@ -63,9 +63,9 @@ class TestTimecop < Test::Unit::TestCase
|
|
63
63
|
assert_not_equal Date.new(2008, 10, 10), Date.today
|
64
64
|
end
|
65
65
|
|
66
|
-
def
|
66
|
+
def test_freeze_with_date_instance_works_as_expected
|
67
67
|
d = Date.new(2008, 10, 10)
|
68
|
-
Timecop.
|
68
|
+
Timecop.freeze(d) do
|
69
69
|
assert_equal d, Date.today
|
70
70
|
assert_equal Time.local(2008, 10, 10, 0, 0, 0), Time.now
|
71
71
|
assert_equal DateTime.new(2008, 10, 10, 0, 0, 0), DateTime.now
|
@@ -75,10 +75,10 @@ class TestTimecop < Test::Unit::TestCase
|
|
75
75
|
assert_not_equal DateTime.new(2008, 10, 10, 0, 0, 0), DateTime.now
|
76
76
|
end
|
77
77
|
|
78
|
-
def
|
78
|
+
def test_exception_thrown_in_freeze_block_properly_resets_time
|
79
79
|
t = Time.local(2008, 10, 10, 10, 10, 10)
|
80
80
|
begin
|
81
|
-
Timecop.
|
81
|
+
Timecop.freeze(t) do
|
82
82
|
assert_equal t, Time.now
|
83
83
|
raise "blah exception"
|
84
84
|
end
|
@@ -88,51 +88,71 @@ class TestTimecop < Test::Unit::TestCase
|
|
88
88
|
end
|
89
89
|
end
|
90
90
|
|
91
|
+
def test_freeze_freezes_time
|
92
|
+
t = Time.local(2008, 10, 10, 10, 10, 10)
|
93
|
+
now = Time.now
|
94
|
+
Timecop.freeze(t) do
|
95
|
+
#assert Time.now < now, "If we had failed to freeze, time would have proceeded, which is what appears to have happened."
|
96
|
+
new_t, new_d, new_dt = Time.now, Date.today, DateTime.now
|
97
|
+
assert_equal t, new_t, "Failed to freeze time." # 2 seconds
|
98
|
+
#sleep(10)
|
99
|
+
assert_equal new_t, Time.now
|
100
|
+
assert_equal new_d, Date.today
|
101
|
+
assert_equal new_dt, DateTime.now
|
102
|
+
end
|
103
|
+
end
|
91
104
|
|
92
|
-
def
|
93
|
-
t = Time.
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
105
|
+
def test_travel_keeps_time_moving
|
106
|
+
t = Time.local(2008, 10, 10, 10, 10, 10)
|
107
|
+
now = Time.now
|
108
|
+
Timecop.travel(t) do
|
109
|
+
#assert Time.now < now, "If we had failed to freeze, time would have proceeded, which is what appears to have happened."
|
110
|
+
assert Time.now - t < 2000, "Looks like we failed to actually travel time" # 2 seconds
|
111
|
+
new_t = Time.now
|
112
|
+
#sleep(10)
|
113
|
+
assert_not_equal new_t, Time.now
|
114
|
+
end
|
102
115
|
end
|
103
116
|
|
104
|
-
def
|
105
|
-
t =
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
117
|
+
def test_recursive_rebasing_maintains_each_context
|
118
|
+
t = Time.local(2008, 10, 10, 10, 10, 10)
|
119
|
+
Timecop.travel(2008, 10, 10, 10, 10, 10) do
|
120
|
+
assert((t - Time.now).abs < 50, "Failed to travel time.")
|
121
|
+
t2 = Time.local(2008, 9, 9, 9, 9, 9)
|
122
|
+
Timecop.travel(2008, 9, 9, 9, 9, 9) do
|
123
|
+
assert((t2 - Time.now) < 50, "Failed to travel time.")
|
124
|
+
assert((t - Time.now) > 1000, "Failed to travel time.")
|
125
|
+
end
|
126
|
+
assert((t - Time.now).abs < 2000, "Failed to restore previously-traveled time.")
|
127
|
+
end
|
128
|
+
assert_nil Time.send(:mock_time)
|
114
129
|
end
|
115
130
|
|
116
|
-
def
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
131
|
+
def test_recursive_travel_then_freeze
|
132
|
+
t = Time.local(2008, 10, 10, 10, 10, 10)
|
133
|
+
Timecop.travel(2008, 10, 10, 10, 10, 10) do
|
134
|
+
assert((t - Time.now).abs < 50, "Failed to travel time.")
|
135
|
+
t2 = Time.local(2008, 9, 9, 9, 9, 9)
|
136
|
+
Timecop.freeze(2008, 9, 9, 9, 9, 9) do
|
137
|
+
assert_equal t2, Time.now
|
138
|
+
end
|
139
|
+
assert((t - Time.now).abs < 2000, "Failed to restore previously-traveled time.")
|
140
|
+
end
|
141
|
+
assert_nil Time.send(:mock_time)
|
126
142
|
end
|
127
143
|
|
128
|
-
def
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
144
|
+
def test_recursive_freeze_then_travel
|
145
|
+
t = Time.local(2008, 10, 10, 10, 10, 10)
|
146
|
+
Timecop.freeze(t) do
|
147
|
+
assert_equal t, Time.now
|
148
|
+
t2 = Time.local(2008, 9, 9, 9, 9, 9)
|
149
|
+
Timecop.travel(t2) do
|
150
|
+
assert((t2 - Time.now) < 50, "Failed to travel time.")
|
151
|
+
assert((t - Time.now) > 1000, "Failed to travel time.")
|
152
|
+
end
|
153
|
+
assert_equal t, Time.now
|
154
|
+
end
|
155
|
+
assert_nil Time.send(:mock_time)
|
137
156
|
end
|
157
|
+
|
138
158
|
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
|
2
|
+
require 'date'
|
3
|
+
require 'test/unit'
|
4
|
+
require File.join(File.dirname(__FILE__), '..', 'lib', 'timecop')
|
5
|
+
|
6
|
+
class TestTimecopInternals < Test::Unit::TestCase
|
7
|
+
|
8
|
+
def test_parse_travel_args_with_time
|
9
|
+
t = Time.now
|
10
|
+
y, m, d, h, min, s = t.year, t.month, t.day, t.hour, t.min, t.sec
|
11
|
+
ty, tm, td, th, tmin, ts = Timecop.instance().send(:parse_travel_args, t)
|
12
|
+
assert_equal y, ty
|
13
|
+
assert_equal m, tm
|
14
|
+
assert_equal d, td
|
15
|
+
assert_equal h, th
|
16
|
+
assert_equal min, tmin
|
17
|
+
assert_equal s, ts
|
18
|
+
end
|
19
|
+
|
20
|
+
def test_parse_travel_args_with_datetime
|
21
|
+
t = DateTime.now
|
22
|
+
y, m, d, h, min, s = t.year, t.month, t.day, t.hour, t.min, t.sec
|
23
|
+
ty, tm, td, th, tmin, ts = Timecop.instance().send(:parse_travel_args, t)
|
24
|
+
assert_equal y, ty
|
25
|
+
assert_equal m, tm
|
26
|
+
assert_equal d, td
|
27
|
+
assert_equal h, th
|
28
|
+
assert_equal min, tmin
|
29
|
+
assert_equal s, ts
|
30
|
+
end
|
31
|
+
|
32
|
+
def test_parse_travel_args_with_date
|
33
|
+
date = Date.today
|
34
|
+
y, m, d, h, min, s = date.year, date.month, date.day, 0, 0, 0
|
35
|
+
ty, tm, td, th, tmin, ts = Timecop.instance().send(:parse_travel_args, date)
|
36
|
+
assert_equal y, ty
|
37
|
+
assert_equal m, tm
|
38
|
+
assert_equal d, td
|
39
|
+
assert_equal h, th
|
40
|
+
assert_equal min, tmin
|
41
|
+
assert_equal s, ts
|
42
|
+
end
|
43
|
+
|
44
|
+
def test_parse_travel_args_with_individual_arguments
|
45
|
+
y, m, d, h, min, s = 2008, 10, 10, 10, 10, 10
|
46
|
+
ty, tm, td, th, tmin, ts = Timecop.instance().send(:parse_travel_args, y, m, d, h, min, s)
|
47
|
+
assert_equal y, ty
|
48
|
+
assert_equal m, tm
|
49
|
+
assert_equal d, td
|
50
|
+
assert_equal h, th
|
51
|
+
assert_equal min, tmin
|
52
|
+
assert_equal s, ts
|
53
|
+
end
|
54
|
+
end
|
@@ -2,20 +2,119 @@
|
|
2
2
|
require 'test/unit'
|
3
3
|
require File.join(File.dirname(__FILE__), '..', 'lib', 'timecop')
|
4
4
|
|
5
|
-
class
|
5
|
+
class TestTimecopWithouDate < Test::Unit::TestCase
|
6
6
|
|
7
|
-
def
|
8
|
-
|
9
|
-
assert Object.const_defined?(:Time)
|
10
|
-
#assert !Object.const_defined?(:Date)
|
7
|
+
def setup
|
8
|
+
assert !Object.const_defined?(:Date)
|
11
9
|
assert !Object.const_defined?(:DateTime)
|
10
|
+
end
|
11
|
+
|
12
|
+
# just in case...let's really make sure that Timecop is disabled between tests...
|
13
|
+
def teardown
|
14
|
+
Timecop.return
|
15
|
+
end
|
16
|
+
|
17
|
+
def test_freeze_changes_and_resets_time
|
18
|
+
# depending on how we're invoked (individually or via the rake test suite)
|
19
|
+
assert !Time.respond_to?(:zone) || Time.zone.nil?
|
12
20
|
|
13
21
|
t = Time.local(2008, 10, 10, 10, 10, 10)
|
14
22
|
assert_not_equal t, Time.now
|
15
|
-
Timecop.
|
23
|
+
Timecop.freeze(2008, 10, 10, 10, 10, 10) do
|
16
24
|
assert_equal t, Time.now
|
17
25
|
end
|
18
26
|
assert_not_equal t, Time.now
|
19
27
|
end
|
20
28
|
|
29
|
+
def test_recursive_freeze
|
30
|
+
t = Time.local(2008, 10, 10, 10, 10, 10)
|
31
|
+
Timecop.freeze(2008, 10, 10, 10, 10, 10) do
|
32
|
+
assert_equal t, Time.now
|
33
|
+
t2 = Time.local(2008, 9, 9, 9, 9, 9)
|
34
|
+
Timecop.freeze(2008, 9, 9, 9, 9, 9) do
|
35
|
+
assert_equal t2, Time.now
|
36
|
+
end
|
37
|
+
assert_equal t, Time.now
|
38
|
+
end
|
39
|
+
assert_nil Time.send(:mock_time)
|
40
|
+
end
|
41
|
+
|
42
|
+
def test_exception_thrown_in_freeze_block_properly_resets_time
|
43
|
+
t = Time.local(2008, 10, 10, 10, 10, 10)
|
44
|
+
begin
|
45
|
+
Timecop.freeze(t) do
|
46
|
+
assert_equal t, Time.now
|
47
|
+
raise "blah exception"
|
48
|
+
end
|
49
|
+
rescue
|
50
|
+
assert_not_equal t, Time.now
|
51
|
+
assert_nil Time.send(:mock_time)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def test_freeze_freezes_time
|
56
|
+
t = Time.local(2008, 10, 10, 10, 10, 10)
|
57
|
+
now = Time.now
|
58
|
+
Timecop.freeze(t) do
|
59
|
+
#assert Time.now < now, "If we had failed to freeze, time would have proceeded, which is what appears to have happened."
|
60
|
+
new_t = Time.now
|
61
|
+
assert_equal t, new_t, "Failed to change move time." # 2 seconds
|
62
|
+
#sleep(10)
|
63
|
+
assert_equal new_t, Time.now
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def test_travel_keeps_time_moving
|
68
|
+
t = Time.local(2008, 10, 10, 10, 10, 10)
|
69
|
+
now = Time.now
|
70
|
+
Timecop.travel(t) do
|
71
|
+
#assert Time.now < now, "If we had failed to freeze, time would have proceeded, which is what appears to have happened."
|
72
|
+
assert Time.now - t < 2000, "Looks like we failed to actually travel time" # 2 seconds
|
73
|
+
new_t = Time.now
|
74
|
+
#sleep(10)
|
75
|
+
assert_not_equal new_t, Time.now
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def test_recursive_rebasing_maintains_each_context
|
80
|
+
t = Time.local(2008, 10, 10, 10, 10, 10)
|
81
|
+
Timecop.travel(2008, 10, 10, 10, 10, 10) do
|
82
|
+
assert((t - Time.now).abs < 50, "Failed to travel time.")
|
83
|
+
t2 = Time.local(2008, 9, 9, 9, 9, 9)
|
84
|
+
Timecop.travel(2008, 9, 9, 9, 9, 9) do
|
85
|
+
assert((t2 - Time.now) < 50, "Failed to travel time.")
|
86
|
+
assert((t - Time.now) > 1000, "Failed to travel time.")
|
87
|
+
end
|
88
|
+
assert((t - Time.now).abs < 2000, "Failed to restore previously-traveled time.")
|
89
|
+
end
|
90
|
+
assert_nil Time.send(:mock_time)
|
91
|
+
end
|
92
|
+
|
93
|
+
def test_recursive_travel_then_freeze
|
94
|
+
t = Time.local(2008, 10, 10, 10, 10, 10)
|
95
|
+
Timecop.travel(2008, 10, 10, 10, 10, 10) do
|
96
|
+
assert((t - Time.now).abs < 50, "Failed to travel time.")
|
97
|
+
t2 = Time.local(2008, 9, 9, 9, 9, 9)
|
98
|
+
Timecop.freeze(2008, 9, 9, 9, 9, 9) do
|
99
|
+
assert_equal t2, Time.now
|
100
|
+
end
|
101
|
+
assert((t - Time.now).abs < 2000, "Failed to restore previously-traveled time.")
|
102
|
+
end
|
103
|
+
assert_nil Time.send(:mock_time)
|
104
|
+
end
|
105
|
+
|
106
|
+
def test_recursive_freeze_then_travel
|
107
|
+
t = Time.local(2008, 10, 10, 10, 10, 10)
|
108
|
+
Timecop.freeze(t) do
|
109
|
+
assert_equal t, Time.now
|
110
|
+
t2 = Time.local(2008, 9, 9, 9, 9, 9)
|
111
|
+
Timecop.travel(t2) do
|
112
|
+
assert((t2 - Time.now) < 50, "Failed to travel time.")
|
113
|
+
assert((t - Time.now) > 1000, "Failed to travel time.")
|
114
|
+
end
|
115
|
+
assert_equal t, Time.now
|
116
|
+
end
|
117
|
+
assert_nil Time.send(:mock_time)
|
118
|
+
end
|
119
|
+
|
21
120
|
end
|
data/timecop.gemspec
CHANGED
@@ -2,15 +2,15 @@
|
|
2
2
|
|
3
3
|
Gem::Specification.new do |s|
|
4
4
|
s.name = %q{timecop}
|
5
|
-
s.version = "0.
|
5
|
+
s.version = "0.2.0"
|
6
6
|
|
7
7
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
8
8
|
s.authors = ["John Trupiano"]
|
9
|
-
s.date = %q{2008-
|
9
|
+
s.date = %q{2008-12-23}
|
10
10
|
s.description = %q{A gem providing simple ways to temporarily override Time.now, Date.today, and DateTime.now. It provides "time travel" capabilities, making it dead simple to write test time-dependent code.}
|
11
11
|
s.email = %q{jtrupiano@gmail.com}
|
12
12
|
s.extra_rdoc_files = ["History.txt", "Manifest.txt", "README.txt"]
|
13
|
-
s.files = ["History.txt", "Manifest.txt", "README.txt", "Rakefile", "lib/timecop.rb", "lib/timecop/time_extensions.rb", "lib/timecop/timecop.rb", "lib/timecop/version.rb", "test/
|
13
|
+
s.files = ["History.txt", "Manifest.txt", "README.txt", "Rakefile", "lib/timecop.rb", "lib/timecop/stack_item.rb", "lib/timecop/time_extensions.rb", "lib/timecop/timecop.rb", "lib/timecop/version.rb", "test/run_tests.sh", "test/test_timecop.rb", "test/test_timecop_internals.rb", "test/test_timecop_without_date.rb", "timecop.gemspec"]
|
14
14
|
s.has_rdoc = true
|
15
15
|
s.homepage = %q{http://github.com/jtrupiano/timecop}
|
16
16
|
s.rdoc_options = ["--main", "README.txt"]
|
@@ -18,7 +18,7 @@ Gem::Specification.new do |s|
|
|
18
18
|
s.rubyforge_project = %q{johntrupiano}
|
19
19
|
s.rubygems_version = %q{1.3.1}
|
20
20
|
s.summary = %q{A gem providing simple ways to temporarily override Time.now, Date.today, and DateTime.now. It provides "time travel" capabilities, making it dead simple to write test time-dependent code.}
|
21
|
-
s.test_files = ["test/test_timecop.rb", "test/
|
21
|
+
s.test_files = ["test/test_timecop.rb", "test/test_timecop_internals.rb", "test/test_timecop_without_date.rb"]
|
22
22
|
|
23
23
|
if s.respond_to? :specification_version then
|
24
24
|
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
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.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- John Trupiano
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2008-
|
12
|
+
date: 2008-12-24 00:00:00 -05:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -38,10 +38,14 @@ files:
|
|
38
38
|
- README.txt
|
39
39
|
- Rakefile
|
40
40
|
- lib/timecop.rb
|
41
|
+
- lib/timecop/stack_item.rb
|
41
42
|
- lib/timecop/time_extensions.rb
|
42
43
|
- lib/timecop/timecop.rb
|
43
44
|
- lib/timecop/version.rb
|
45
|
+
- test/run_tests.sh
|
44
46
|
- test/test_timecop.rb
|
47
|
+
- test/test_timecop_internals.rb
|
48
|
+
- test/test_timecop_without_date.rb
|
45
49
|
- timecop.gemspec
|
46
50
|
has_rdoc: true
|
47
51
|
homepage: http://github.com/jtrupiano/timecop
|
@@ -72,5 +76,5 @@ specification_version: 2
|
|
72
76
|
summary: A gem providing simple ways to temporarily override Time.now, Date.today, and DateTime.now. It provides "time travel" capabilities, making it dead simple to write test time-dependent code.
|
73
77
|
test_files:
|
74
78
|
- test/test_timecop.rb
|
75
|
-
- test/
|
79
|
+
- test/test_timecop_internals.rb
|
76
80
|
- test/test_timecop_without_date.rb
|
@@ -1,22 +0,0 @@
|
|
1
|
-
|
2
|
-
require 'test/unit'
|
3
|
-
|
4
|
-
require 'rubygems'
|
5
|
-
gem "activesupport", ">= 2.1.0"
|
6
|
-
require 'activesupport'
|
7
|
-
|
8
|
-
require File.join(File.dirname(__FILE__), '..', 'lib', 'timecop')
|
9
|
-
|
10
|
-
class TestTimecopWithRails < Test::Unit::TestCase
|
11
|
-
|
12
|
-
def test_travel_changes_and_resets_time
|
13
|
-
Time.zone = 'Eastern Time (US & Canada)'
|
14
|
-
t = Time.zone.local(2008, 10, 10, 10, 10, 10)
|
15
|
-
assert_not_equal t, Time.now
|
16
|
-
Timecop.travel(2008, 10, 10, 10, 10, 10) do
|
17
|
-
assert_equal t, Time.now
|
18
|
-
end
|
19
|
-
assert_not_equal t, Time.now
|
20
|
-
end
|
21
|
-
|
22
|
-
end
|