timecop 0.3.5 → 0.5.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.rdoc +35 -0
- data/LICENSE +1 -1
- data/README.markdown +100 -0
- data/Rakefile +10 -37
- data/VERSION.yml +2 -2
- data/lib/timecop/time_extensions.rb +17 -4
- data/lib/timecop/time_stack_item.rb +43 -22
- data/lib/timecop/timecop.rb +99 -69
- data/test/run_tests.sh +3 -10
- data/test/test_helper.rb +5 -1
- data/test/{test_time_stack_item.rb → time_stack_item_test.rb} +50 -13
- data/test/{test_timecop.rb → timecop_test.rb} +161 -49
- data/test/{test_timecop_without_date.rb → timecop_without_date_test.rb} +3 -3
- metadata +18 -17
- data/README.rdoc +0 -68
- /data/test/{test_timecop_without_date_but_with_time.rb → timecop_without_date_but_with_time_test.rb} +0 -0
data/History.rdoc
CHANGED
|
@@ -1,3 +1,38 @@
|
|
|
1
|
+
=== 0.5.0 / 2012-09-12
|
|
2
|
+
|
|
3
|
+
* Maintenance
|
|
4
|
+
* Timecop#travel, Timecop#freeze blocks return nil or block value
|
|
5
|
+
|
|
6
|
+
=== 0.4.6 / 2012-09-05
|
|
7
|
+
|
|
8
|
+
* Maintenance
|
|
9
|
+
* Fix rounding support for Ruby < 1.9
|
|
10
|
+
|
|
11
|
+
=== 0.4.5 / 2012-08-09
|
|
12
|
+
|
|
13
|
+
* Maintenance
|
|
14
|
+
* Subclasses of Time/Date/DateTime now return proper instances
|
|
15
|
+
|
|
16
|
+
=== 0.4.4 / 2012-07-29
|
|
17
|
+
|
|
18
|
+
* Maintenance
|
|
19
|
+
* Can now configure Timecop to not use ActiveSupport by setting Timecop.active_support = false
|
|
20
|
+
|
|
21
|
+
=== 0.4.3 / 2012-07-27
|
|
22
|
+
|
|
23
|
+
* Maintenance
|
|
24
|
+
* Fix alias of Time#new/Time#now when Time#new given with args
|
|
25
|
+
|
|
26
|
+
=== 0.4.2 / 2012-07-27
|
|
27
|
+
|
|
28
|
+
* Maintenance
|
|
29
|
+
* Mock Time#new the same as Time#now since they're synonyms
|
|
30
|
+
* Set default arg in parsing to 2000
|
|
31
|
+
* Time.freeze defaults to Time#now
|
|
32
|
+
* Use Time#parse is available to parse Time's given as strings
|
|
33
|
+
* Add ActiveSupport Time.zone support
|
|
34
|
+
* Stop DateTime from losing precision after traveling
|
|
35
|
+
|
|
1
36
|
=== 0.3.5 / 2010-06-07
|
|
2
37
|
|
|
3
38
|
* Maintenance
|
data/LICENSE
CHANGED
data/README.markdown
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
# timecop
|
|
2
|
+
|
|
3
|
+
- Source[http://github.com/jtrupiano/timecop]
|
|
4
|
+
- Documentation[http://johntrupiano.rubyforge.org/timecop]
|
|
5
|
+
|
|
6
|
+
## DESCRIPTION
|
|
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.
|
|
9
|
+
|
|
10
|
+
## INSTALL
|
|
11
|
+
|
|
12
|
+
gem install timecop
|
|
13
|
+
|
|
14
|
+
## FEATURES
|
|
15
|
+
|
|
16
|
+
- Freeze time to a specific point.
|
|
17
|
+
- Travel back to a specific point in time, but allow time to continue moving forward from there.
|
|
18
|
+
- No dependencies, can be used with _any_ ruby project
|
|
19
|
+
- Timecop api allows arguments to be passed into #freeze and #travel as one of the following:
|
|
20
|
+
- Time instance
|
|
21
|
+
- DateTime instance
|
|
22
|
+
- Date instance
|
|
23
|
+
- individual arguments (year, month, day, hour, minute, second)
|
|
24
|
+
- a single integer argument that is interpreted as an offset in seconds from Time.now
|
|
25
|
+
- Nested calls to Timecop#travel and Timecop#freeze are supported -- each block will maintain its interpretation of now.
|
|
26
|
+
- Works with regular Ruby projects, and Ruby on Rails projects
|
|
27
|
+
|
|
28
|
+
## USAGE
|
|
29
|
+
|
|
30
|
+
Run a time-sensitive test
|
|
31
|
+
|
|
32
|
+
```ruby
|
|
33
|
+
joe = User.find(1)
|
|
34
|
+
joe.purchase_home()
|
|
35
|
+
assert !joe.mortgage_due?
|
|
36
|
+
# move ahead a month and assert that the mortgage is due
|
|
37
|
+
Timecop.freeze(Date.today + 30) do
|
|
38
|
+
assert joe.mortgage_due?
|
|
39
|
+
end
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Set the time for the test environment of a rails app -- this is particularly
|
|
43
|
+
helpful if your whole application is time-sensitive. It allows you to build
|
|
44
|
+
your test data at a single point in time, and to move in/out of that time as
|
|
45
|
+
appropriate (within your tests)
|
|
46
|
+
|
|
47
|
+
in config/environments/test.rb
|
|
48
|
+
|
|
49
|
+
```ruby
|
|
50
|
+
config.after_initialize do
|
|
51
|
+
# Set Time.now to September 1, 2008 10:05:00 AM (at this instant), but allow it to move forward
|
|
52
|
+
t = Time.local(2008, 9, 1, 10, 5, 0)
|
|
53
|
+
Timecop.travel(t)
|
|
54
|
+
end
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### The difference between Timecop.freeze and Timecop.travel
|
|
58
|
+
|
|
59
|
+
freeze is used to statically mock the concept of now. As your program executes,
|
|
60
|
+
Time.now will not change unless you make subsequent calls into the Timecop API.
|
|
61
|
+
travel, on the other hand, computes an offset between what we currently think
|
|
62
|
+
Time.now is (recall that we support nested traveling) and the time passed in.
|
|
63
|
+
It uses this offset to simulate the passage of time. To demonstrate, consider
|
|
64
|
+
the following code snippets:
|
|
65
|
+
|
|
66
|
+
```ruby
|
|
67
|
+
new_time = Time.local(2008, 9, 1, 12, 0, 0)
|
|
68
|
+
Timecop.freeze(new_time)
|
|
69
|
+
sleep(10)
|
|
70
|
+
new_time == Time.now # ==> true
|
|
71
|
+
|
|
72
|
+
Timecop.return # "turn off" Timecop
|
|
73
|
+
Timecop.travel(new_time)
|
|
74
|
+
sleep(10)
|
|
75
|
+
new_time == Time.now # ==> false
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
## REFERENCES
|
|
79
|
+
|
|
80
|
+
* {0.3.4 release}[http://blog.smartlogicsolutions.com/2009/12/07/timecop-0-3-4-released/]
|
|
81
|
+
* {0.3.0 release}[http://blog.smartlogicsolutions.com/2009/09/20/timecop-0-3-0-released/]
|
|
82
|
+
* {0.2.0 release}[http://blog.smartlogicsolutions.com/2008/12/24/timecop-2-released-freeze-and-rebase-time-ruby/]
|
|
83
|
+
* {0.1.0 release}[http://blog.smartlogicsolutions.com/2008/11/19/timecop-freeze-time-in-ruby-for-better-testing/]
|
|
84
|
+
|
|
85
|
+
## Contribute
|
|
86
|
+
|
|
87
|
+
timecop is maintained by [travisjeffery](http://github.com/travisjeffery), who
|
|
88
|
+
you can also hit up on [Twitter](http://twitter.com/travisjeffery).
|
|
89
|
+
|
|
90
|
+
Here's the most direct way to get your work merged into the project.
|
|
91
|
+
|
|
92
|
+
- Fork the project
|
|
93
|
+
- Clone down your fork
|
|
94
|
+
- Create a feature branch
|
|
95
|
+
- Hack away and add tests, not necessarily in that order
|
|
96
|
+
- Make sure everything still passes by running tests
|
|
97
|
+
- If necessary, rebase your commits into logical chunks without errors
|
|
98
|
+
- Push the branch up to your fork
|
|
99
|
+
- Send a pull request for your branch
|
|
100
|
+
|
data/Rakefile
CHANGED
|
@@ -1,42 +1,10 @@
|
|
|
1
|
-
require '
|
|
1
|
+
require 'bundler/setup'
|
|
2
|
+
require 'bundler/gem_tasks'
|
|
2
3
|
require 'rake/testtask'
|
|
3
|
-
require '
|
|
4
|
+
require 'rdoc/task'
|
|
4
5
|
|
|
5
|
-
|
|
6
|
+
$LOAD_PATH.unshift("lib")
|
|
6
7
|
|
|
7
|
-
begin
|
|
8
|
-
require 'jeweler'
|
|
9
|
-
Jeweler::Tasks.new do |s|
|
|
10
|
-
s.name = "timecop"
|
|
11
|
-
s.rubyforge_project = 'johntrupiano' # if different than lowercase project name
|
|
12
|
-
s.description = %q(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.)
|
|
13
|
-
s.summary = s.description # More details later??
|
|
14
|
-
s.email = "jtrupiano@gmail.com"
|
|
15
|
-
s.homepage = "http://github.com/jtrupiano/timecop"
|
|
16
|
-
s.authors = ["John Trupiano"]
|
|
17
|
-
s.files = FileList["[A-Z]*", "{bin,lib,test}/**/*"]
|
|
18
|
-
end
|
|
19
|
-
Jeweler::GemcutterTasks.new
|
|
20
|
-
Jeweler::RubyforgeTasks.new do |rubyforge|
|
|
21
|
-
rubyforge.doc_task = "rdoc"
|
|
22
|
-
rubyforge.remote_doc_path = "timecop"
|
|
23
|
-
end
|
|
24
|
-
rescue LoadError
|
|
25
|
-
puts "Jeweler, or one of its dependencies, is not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
|
|
26
|
-
end
|
|
27
|
-
|
|
28
|
-
# Override the test task and instruct them how to actually run the tests.
|
|
29
|
-
Rake.application.send(:eval, "@tasks.delete('test')")
|
|
30
|
-
desc "Does not execute tests. Manually run shell script ./run_tests.sh to execute tests."
|
|
31
|
-
task :test do
|
|
32
|
-
puts <<-MSG
|
|
33
|
-
In order to run the test suite, run: cd test && ./run_tests.sh
|
|
34
|
-
The tests need to be run with different libraries loaded, which rules out using Rake
|
|
35
|
-
to automate them.
|
|
36
|
-
MSG
|
|
37
|
-
end
|
|
38
|
-
|
|
39
|
-
require 'rake/rdoctask'
|
|
40
8
|
Rake::RDocTask.new do |rdoc|
|
|
41
9
|
if File.exist?('VERSION')
|
|
42
10
|
version = File.read('VERSION')
|
|
@@ -52,4 +20,9 @@ Rake::RDocTask.new do |rdoc|
|
|
|
52
20
|
rdoc.rdoc_files.include('lib/**/*.rb')
|
|
53
21
|
end
|
|
54
22
|
|
|
55
|
-
task :
|
|
23
|
+
task :test do
|
|
24
|
+
system "cd test && ./run_tests.sh"
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
desc 'Default: run tests'
|
|
28
|
+
task :default => [:test]
|
data/VERSION.yml
CHANGED
|
@@ -4,7 +4,7 @@ class Time #:nodoc:
|
|
|
4
4
|
# Time we are behaving as
|
|
5
5
|
def mock_time
|
|
6
6
|
mocked_time_stack_item = Timecop.top_stack_item
|
|
7
|
-
mocked_time_stack_item.nil? ? nil : mocked_time_stack_item.time
|
|
7
|
+
mocked_time_stack_item.nil? ? nil : mocked_time_stack_item.time(self)
|
|
8
8
|
end
|
|
9
9
|
|
|
10
10
|
# Alias the original now
|
|
@@ -17,6 +17,19 @@ class Time #:nodoc:
|
|
|
17
17
|
|
|
18
18
|
# Alias now to now_with_mock_time
|
|
19
19
|
alias_method :now, :now_with_mock_time
|
|
20
|
+
|
|
21
|
+
alias_method :new_without_mock_time, :new
|
|
22
|
+
|
|
23
|
+
def new_with_mock_time *args
|
|
24
|
+
begin
|
|
25
|
+
raise ArgumentError.new if args.size <= 0
|
|
26
|
+
new_without_mock_time *args
|
|
27
|
+
rescue ArgumentError
|
|
28
|
+
now
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
alias_method :new, :new_with_mock_time
|
|
20
33
|
end
|
|
21
34
|
end
|
|
22
35
|
|
|
@@ -26,7 +39,7 @@ if Object.const_defined?(:Date) && Date.respond_to?(:today)
|
|
|
26
39
|
# Date we are behaving as
|
|
27
40
|
def mock_date
|
|
28
41
|
mocked_time_stack_item = Timecop.top_stack_item
|
|
29
|
-
mocked_time_stack_item.nil? ? nil : mocked_time_stack_item.date
|
|
42
|
+
mocked_time_stack_item.nil? ? nil : mocked_time_stack_item.date(self)
|
|
30
43
|
end
|
|
31
44
|
|
|
32
45
|
# Alias the original today
|
|
@@ -49,7 +62,7 @@ if Object.const_defined?(:DateTime) && DateTime.respond_to?(:now)
|
|
|
49
62
|
# Time we are behaving as
|
|
50
63
|
def mock_time
|
|
51
64
|
mocked_time_stack_item = Timecop.top_stack_item
|
|
52
|
-
mocked_time_stack_item.nil? ? nil : mocked_time_stack_item.datetime
|
|
65
|
+
mocked_time_stack_item.nil? ? nil : mocked_time_stack_item.datetime(self)
|
|
53
66
|
end
|
|
54
67
|
|
|
55
68
|
# Fake alias :now_without_mock_time :now
|
|
@@ -69,4 +82,4 @@ if Object.const_defined?(:DateTime) && DateTime.respond_to?(:now)
|
|
|
69
82
|
alias_method :now, :now_with_mock_time
|
|
70
83
|
end
|
|
71
84
|
end
|
|
72
|
-
end
|
|
85
|
+
end
|
|
@@ -10,7 +10,7 @@ class Timecop
|
|
|
10
10
|
@mock_type = mock_type
|
|
11
11
|
@time = parse_time(*args)
|
|
12
12
|
@travel_offset = compute_travel_offset
|
|
13
|
-
@dst_adjustment = compute_dst_adjustment
|
|
13
|
+
@dst_adjustment = compute_dst_adjustment(@time)
|
|
14
14
|
end
|
|
15
15
|
|
|
16
16
|
def year
|
|
@@ -45,22 +45,29 @@ class Timecop
|
|
|
45
45
|
@travel_offset
|
|
46
46
|
end
|
|
47
47
|
|
|
48
|
-
def time #:nodoc:
|
|
48
|
+
def time(time_klass=Time) #:nodoc:
|
|
49
49
|
if travel_offset.nil?
|
|
50
|
-
@time.
|
|
50
|
+
time_klass.at( @time.to_f )
|
|
51
51
|
else
|
|
52
|
-
Time.now_without_mock_time + travel_offset
|
|
52
|
+
time_klass.at( ( Time.now_without_mock_time + travel_offset ).to_f )
|
|
53
53
|
end
|
|
54
54
|
end
|
|
55
55
|
|
|
56
|
-
def date
|
|
57
|
-
time.
|
|
56
|
+
def date(date_klass=Date)
|
|
57
|
+
date_klass.jd(time.__send__(:to_date).jd)
|
|
58
58
|
end
|
|
59
59
|
|
|
60
|
-
def datetime
|
|
60
|
+
def datetime(datetime_klass=DateTime)
|
|
61
61
|
# DateTime doesn't know about DST, so let's remove its presence
|
|
62
62
|
our_offset = utc_offset + dst_adjustment
|
|
63
|
-
|
|
63
|
+
if Float.method_defined?(:to_r)
|
|
64
|
+
fractions_of_a_second = time.to_f % 1
|
|
65
|
+
datetime_klass.new(year, month, day, hour, min, sec + fractions_of_a_second,
|
|
66
|
+
utc_offset_to_rational(our_offset))
|
|
67
|
+
else
|
|
68
|
+
our_offset = utc_offset + dst_adjustment
|
|
69
|
+
datetime_klass.new(year, month, day, hour, min, sec, utc_offset_to_rational(our_offset))
|
|
70
|
+
end
|
|
64
71
|
end
|
|
65
72
|
|
|
66
73
|
def dst_adjustment
|
|
@@ -77,28 +84,42 @@ class Timecop
|
|
|
77
84
|
end
|
|
78
85
|
|
|
79
86
|
def parse_time(*args)
|
|
87
|
+
time_klass = Time
|
|
88
|
+
time_klass = Time.zone if Time.respond_to? :zone
|
|
80
89
|
arg = args.shift
|
|
81
|
-
if arg.is_a?(Time)
|
|
82
|
-
arg.
|
|
90
|
+
if arg.is_a?(Time)
|
|
91
|
+
if Timecop.active_support != false && arg.respond_to?(:in_time_zone)
|
|
92
|
+
arg.in_time_zone
|
|
93
|
+
else
|
|
94
|
+
arg.getlocal
|
|
95
|
+
end
|
|
83
96
|
elsif Object.const_defined?(:DateTime) && arg.is_a?(DateTime)
|
|
84
|
-
|
|
85
|
-
|
|
97
|
+
expected_time = time_klass.local(arg.year, arg.month, arg.day, arg.hour, arg.min, arg.sec)
|
|
98
|
+
expected_time += expected_time.utc_offset - rational_to_utc_offset(arg.offset)
|
|
99
|
+
expected_time + compute_dst_adjustment(expected_time)
|
|
86
100
|
elsif Object.const_defined?(:Date) && arg.is_a?(Date)
|
|
87
|
-
|
|
101
|
+
time_klass.local(arg.year, arg.month, arg.day, 0, 0, 0)
|
|
88
102
|
elsif args.empty? && arg.kind_of?(Integer)
|
|
89
103
|
Time.now + arg
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
104
|
+
elsif arg.nil?
|
|
105
|
+
Time.now
|
|
106
|
+
else
|
|
107
|
+
if arg.is_a?(String) && Timecop.active_support != false && Time.respond_to?(:parse)
|
|
108
|
+
Time.parse(arg)
|
|
109
|
+
else
|
|
110
|
+
# we'll just assume it's a list of y/m/d/h/m/s
|
|
111
|
+
year = arg || 2000
|
|
112
|
+
month = args.shift || 1
|
|
113
|
+
day = args.shift || 1
|
|
114
|
+
hour = args.shift || 0
|
|
115
|
+
minute = args.shift || 0
|
|
116
|
+
second = args.shift || 0
|
|
117
|
+
time_klass.local(year, month, day, hour, minute, second)
|
|
118
|
+
end
|
|
98
119
|
end
|
|
99
120
|
end
|
|
100
121
|
|
|
101
|
-
def compute_dst_adjustment
|
|
122
|
+
def compute_dst_adjustment(time)
|
|
102
123
|
return 0 if !(time.dst? ^ Time.now.dst?)
|
|
103
124
|
return -1 * 60 * 60 if time.dst?
|
|
104
125
|
return 60 * 60
|
data/lib/timecop/timecop.rb
CHANGED
|
@@ -6,98 +6,128 @@ require 'timecop/time_stack_item'
|
|
|
6
6
|
# * Wrapper class for manipulating the extensions to the Time, Date, and DateTime objects
|
|
7
7
|
# * Allows us to "freeze" time in our Ruby applications.
|
|
8
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.
|
|
9
|
+
#
|
|
10
|
+
# This is very useful when your app's functionality is dependent on time (e.g.
|
|
11
11
|
# anything that might expire). This will allow us to alter the return value of
|
|
12
12
|
# Date.today, Time.now, and DateTime.now, such that our application code _never_ has to change.
|
|
13
13
|
class Timecop
|
|
14
14
|
include Singleton
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
15
|
+
|
|
16
|
+
class << self
|
|
17
|
+
attr_accessor :active_support
|
|
18
|
+
|
|
19
|
+
# Allows you to run a block of code and "fake" a time throughout the execution of that block.
|
|
20
|
+
# This is particularly useful for writing test methods where the passage of time is critical to the business
|
|
21
|
+
# logic being tested. For example:
|
|
22
|
+
#
|
|
23
|
+
# joe = User.find(1)
|
|
24
|
+
# joe.purchase_home()
|
|
25
|
+
# assert !joe.mortgage_due?
|
|
26
|
+
# Timecop.freeze(2008, 10, 5) do
|
|
27
|
+
# assert joe.mortgage_due?
|
|
28
|
+
# end
|
|
29
|
+
#
|
|
30
|
+
# freeze and travel will respond to several different arguments:
|
|
31
|
+
# 1. Timecop.freeze(time_inst)
|
|
32
|
+
# 2. Timecop.freeze(datetime_inst)
|
|
33
|
+
# 3. Timecop.freeze(date_inst)
|
|
34
|
+
# 4. Timecop.freeze(offset_in_seconds)
|
|
35
|
+
# 5. Timecop.freeze(year, month, day, hour=0, minute=0, second=0)
|
|
36
|
+
#
|
|
37
|
+
# When a block is also passed, Time.now, DateTime.now and Date.today are all reset to their
|
|
38
|
+
# previous values after the block has finished executing. This allows us to nest multiple
|
|
39
|
+
# calls to Timecop.travel and have each block maintain it's concept of "now."
|
|
40
|
+
#
|
|
41
|
+
# * Note: Timecop.freeze will actually freeze time. This can cause unanticipated problems if
|
|
42
|
+
# benchmark or other timing calls are executed, which implicitly expect Time to actually move
|
|
43
|
+
# forward.
|
|
44
|
+
#
|
|
45
|
+
# * Rails Users: Be especially careful when setting this in your development environment in a
|
|
46
|
+
# rails project. Generators will load your environment, including the migration generator,
|
|
47
|
+
# which will lead to files being generated with the timestamp set by the Timecop.freeze call
|
|
48
|
+
# in your dev environment
|
|
49
|
+
#
|
|
50
|
+
# Returns the value of the block or nil.
|
|
51
|
+
def freeze(*args, &block)
|
|
52
|
+
val = instance().send(:travel, :freeze, *args, &block)
|
|
53
|
+
|
|
54
|
+
block_given? ? val : nil
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
# Allows you to run a block of code and "fake" a time throughout the execution of that block.
|
|
58
|
+
# See Timecop#freeze for a sample of how to use (same exact usage syntax)
|
|
59
|
+
#
|
|
60
|
+
# * Note: Timecop.travel will not freeze time (as opposed to Timecop.freeze). This is a particularly
|
|
61
|
+
# good candidate for use in environment files in rails projects.
|
|
62
|
+
#
|
|
63
|
+
# Returns the value of the block or nil.
|
|
64
|
+
def travel(*args, &block)
|
|
65
|
+
val = instance().send(:travel, :travel, *args, &block)
|
|
66
|
+
|
|
67
|
+
block_given? ? val : nil
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def baseline
|
|
71
|
+
instance().send(:baseline)
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def baseline=(baseline)
|
|
75
|
+
instance().send(:baseline=, baseline)
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
# Reverts back to system's Time.now, Date.today and DateTime.now (if it exists).
|
|
79
|
+
def return
|
|
80
|
+
instance().send(:unmock!)
|
|
81
|
+
nil
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def return_to_baseline
|
|
85
|
+
instance().send(:return_to_baseline)
|
|
86
|
+
Time.now
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def top_stack_item #:nodoc:
|
|
90
|
+
instance().instance_variable_get(:@_stack).last
|
|
91
|
+
end
|
|
75
92
|
end
|
|
76
93
|
|
|
77
94
|
protected
|
|
78
|
-
|
|
95
|
+
|
|
96
|
+
def baseline=(baseline)
|
|
97
|
+
@baseline = baseline
|
|
98
|
+
@_stack << TimeStackItem.new(:travel, baseline)
|
|
99
|
+
end
|
|
100
|
+
|
|
79
101
|
def initialize #:nodoc:
|
|
80
102
|
@_stack = []
|
|
81
103
|
end
|
|
82
|
-
|
|
104
|
+
|
|
83
105
|
def travel(mock_type, *args, &block) #:nodoc:
|
|
84
106
|
stack_item = TimeStackItem.new(mock_type, *args)
|
|
85
|
-
|
|
107
|
+
|
|
86
108
|
# store this time traveling on our stack...
|
|
87
109
|
@_stack << stack_item
|
|
88
|
-
|
|
110
|
+
|
|
89
111
|
if block_given?
|
|
90
112
|
begin
|
|
91
|
-
yield
|
|
113
|
+
yield stack_item.time
|
|
92
114
|
ensure
|
|
93
115
|
# pull it off the stack...
|
|
94
116
|
@_stack.pop
|
|
95
117
|
end
|
|
96
118
|
end
|
|
97
119
|
end
|
|
98
|
-
|
|
120
|
+
|
|
99
121
|
def unmock! #:nodoc:
|
|
122
|
+
@baseline = nil
|
|
100
123
|
@_stack = []
|
|
101
124
|
end
|
|
102
|
-
|
|
125
|
+
|
|
126
|
+
def return_to_baseline
|
|
127
|
+
if @baseline
|
|
128
|
+
@_stack = [@_stack.shift]
|
|
129
|
+
else
|
|
130
|
+
unmock!
|
|
131
|
+
end
|
|
132
|
+
end
|
|
103
133
|
end
|
data/test/run_tests.sh
CHANGED
|
@@ -1,13 +1,6 @@
|
|
|
1
1
|
#!/bin/sh
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
ruby -I../lib
|
|
3
|
+
for f in *_test.rb; do
|
|
4
|
+
${RUBY:-ruby} -I../lib:. $f
|
|
5
|
+
done
|
|
5
6
|
|
|
6
|
-
echo "\033[1;81m Running test_timecop_without_date...\033[0m"
|
|
7
|
-
ruby -I../lib test_timecop_without_date.rb || (echo "FAILED!!!!!!!!!!!!")
|
|
8
|
-
|
|
9
|
-
echo "\033[1;81m Running test_timecop_without_date_but_with_time...\033[0m"
|
|
10
|
-
ruby -I../lib test_timecop_without_date_but_with_time.rb || (echo "FAILED!!!!!!!!!!!!")
|
|
11
|
-
|
|
12
|
-
echo "\033[1;81m Running test_timecop...\033[0m"
|
|
13
|
-
ruby -I../lib test_timecop.rb || (echo "FAILED!!!!!!!!!!!!")
|
data/test/test_helper.rb
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
|
+
require 'rubygems'
|
|
2
|
+
require 'bundler/setup'
|
|
1
3
|
require 'test/unit'
|
|
4
|
+
require 'mocha'
|
|
2
5
|
|
|
3
6
|
class Test::Unit::TestCase
|
|
7
|
+
|
|
4
8
|
private
|
|
5
9
|
# Tests to see that two times are within the given distance,
|
|
6
10
|
# in seconds, from each other.
|
|
@@ -43,4 +47,4 @@ class Test::Unit::TestCase
|
|
|
43
47
|
assert_equal dt1, dt2, "Failed for timezone: #{ENV['TZ']}: #{dt1.to_s} not equal to #{dt2.to_s}"
|
|
44
48
|
end
|
|
45
49
|
|
|
46
|
-
end
|
|
50
|
+
end
|
|
@@ -5,6 +5,7 @@ require File.join(File.dirname(__FILE__), '..', 'lib', 'timecop')
|
|
|
5
5
|
class TestTimeStackItem < Test::Unit::TestCase
|
|
6
6
|
|
|
7
7
|
def teardown
|
|
8
|
+
Timecop.active_support = nil
|
|
8
9
|
Timecop.return
|
|
9
10
|
end
|
|
10
11
|
|
|
@@ -19,6 +20,18 @@ class TestTimeStackItem < Test::Unit::TestCase
|
|
|
19
20
|
assert_equal min, stack_item.min
|
|
20
21
|
assert_equal s, stack_item.sec
|
|
21
22
|
end
|
|
23
|
+
|
|
24
|
+
def test_new_with_time_and_arguments
|
|
25
|
+
t = Time.new(2012, 7, 28, 20, 0)
|
|
26
|
+
y, m, d, h, min, s = t.year, t.month, t.day, t.hour, t.min, t.sec
|
|
27
|
+
stack_item = Timecop::TimeStackItem.new(:freeze, t)
|
|
28
|
+
assert_equal y, stack_item.year
|
|
29
|
+
assert_equal m, stack_item.month
|
|
30
|
+
assert_equal d, stack_item.day
|
|
31
|
+
assert_equal h, stack_item.hour
|
|
32
|
+
assert_equal min, stack_item.min
|
|
33
|
+
assert_equal s, stack_item.sec
|
|
34
|
+
end
|
|
22
35
|
|
|
23
36
|
def test_new_with_datetime_now
|
|
24
37
|
t = DateTime.now
|
|
@@ -97,8 +110,7 @@ class TestTimeStackItem < Test::Unit::TestCase
|
|
|
97
110
|
Timecop.freeze(DateTime.parse("2009-10-1 00:38:00 -0400"))
|
|
98
111
|
t = DateTime.parse("2009-10-11 00:00:00 -0400")
|
|
99
112
|
tsi = Timecop::TimeStackItem.new(:freeze, t)
|
|
100
|
-
|
|
101
|
-
assert tsi.time.dst?, "precondition"
|
|
113
|
+
return if !(Time.now.dst? && tsi.time.dst?)
|
|
102
114
|
assert_equal 0, tsi.send(:dst_adjustment)
|
|
103
115
|
end
|
|
104
116
|
|
|
@@ -106,8 +118,7 @@ class TestTimeStackItem < Test::Unit::TestCase
|
|
|
106
118
|
Timecop.freeze(DateTime.parse("2009-12-1 00:38:00 -0400"))
|
|
107
119
|
t = DateTime.parse("2009-12-11 00:00:00 -0400")
|
|
108
120
|
tsi = Timecop::TimeStackItem.new(:freeze, t)
|
|
109
|
-
|
|
110
|
-
assert !tsi.time.dst?, "precondition"
|
|
121
|
+
return if Time.now.dst? || tsi.time.dst?
|
|
111
122
|
assert_equal 0, tsi.send(:dst_adjustment)
|
|
112
123
|
end
|
|
113
124
|
|
|
@@ -115,8 +126,7 @@ class TestTimeStackItem < Test::Unit::TestCase
|
|
|
115
126
|
Timecop.freeze(DateTime.parse("2009-10-1 00:38:00 -0400"))
|
|
116
127
|
t = DateTime.parse("2009-12-11 00:00:00 -0400")
|
|
117
128
|
tsi = Timecop::TimeStackItem.new(:freeze, t)
|
|
118
|
-
|
|
119
|
-
assert !tsi.time.dst?, "precondition"
|
|
129
|
+
return if !Time.now.dst? || tsi.time.dst?
|
|
120
130
|
assert_equal 60 * 60, tsi.send(:dst_adjustment)
|
|
121
131
|
end
|
|
122
132
|
|
|
@@ -124,27 +134,24 @@ class TestTimeStackItem < Test::Unit::TestCase
|
|
|
124
134
|
Timecop.freeze(DateTime.parse("2009-12-1 00:38:00 -0400"))
|
|
125
135
|
t = DateTime.parse("2009-10-11 00:00:00 -0400")
|
|
126
136
|
tsi = Timecop::TimeStackItem.new(:freeze, t)
|
|
127
|
-
|
|
128
|
-
assert tsi.time.dst?, "precondition"
|
|
137
|
+
return if Time.now.dst? || !tsi.time.dst?
|
|
129
138
|
assert_equal -1 * 60 * 60, tsi.send(:dst_adjustment)
|
|
130
139
|
end
|
|
131
140
|
|
|
132
|
-
# Ensure
|
|
141
|
+
# Ensure DateTimes handle changing DST properly
|
|
133
142
|
def test_datetime_for_dst_to_non_dst
|
|
134
143
|
Timecop.freeze(DateTime.parse("2009-12-1 00:38:00 -0500"))
|
|
135
144
|
t = DateTime.parse("2009-10-11 00:00:00 -0400")
|
|
136
145
|
tsi = Timecop::TimeStackItem.new(:freeze, t)
|
|
137
146
|
assert_date_times_equal t, tsi.datetime
|
|
138
|
-
# verify Date also 'moves backward' an hour to change the day
|
|
139
|
-
assert_equal Date.new(2009, 10, 10), tsi.date
|
|
140
147
|
end
|
|
141
148
|
|
|
142
149
|
def test_datetime_for_non_dst_to_dst
|
|
143
150
|
Timecop.freeze(DateTime.parse("2009-10-11 00:00:00 -0400"))
|
|
144
151
|
t = DateTime.parse("2009-11-30 23:38:00 -0500")
|
|
145
152
|
tsi = Timecop::TimeStackItem.new(:freeze, t)
|
|
153
|
+
return if !tsi.time.dst?
|
|
146
154
|
assert_date_times_equal t, tsi.datetime
|
|
147
|
-
# verify Date also 'moves forward' an hour to change the day
|
|
148
155
|
assert_equal Date.new(2009, 12, 1), tsi.date
|
|
149
156
|
end
|
|
150
157
|
|
|
@@ -164,4 +171,34 @@ class TestTimeStackItem < Test::Unit::TestCase
|
|
|
164
171
|
tsi = Timecop::TimeStackItem.new(:freeze, t)
|
|
165
172
|
assert_equal nil, tsi.send(:travel_offset)
|
|
166
173
|
end
|
|
167
|
-
|
|
174
|
+
|
|
175
|
+
def test_parse_string_date_with_active_support
|
|
176
|
+
date = '2012-01-02'
|
|
177
|
+
Time.expects(:parse).with(date).returns(Time.local(2012, 01, 02))
|
|
178
|
+
Timecop.freeze(date)
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
def test_parse_only_string_with_active_support
|
|
182
|
+
Time.expects(:parse).never
|
|
183
|
+
Timecop.freeze(2011, 01, 02, hour=0, minute=0, second=0)
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
def test_parse_with_active_support_off
|
|
187
|
+
date = '2012-01-02'
|
|
188
|
+
Timecop.active_support = false
|
|
189
|
+
Time.expects(:parse).never
|
|
190
|
+
Timecop.freeze(date)
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
def test_uses_active_supports_in_time_zone
|
|
194
|
+
time = Time.now
|
|
195
|
+
Time.any_instance.expects(:in_time_zone).returns(time)
|
|
196
|
+
Timecop::TimeStackItem.new(:freeze, time)
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
def test_configured_off_active_support_in_time_zone_xxx
|
|
200
|
+
Timecop.active_support = false
|
|
201
|
+
Time.any_instance.expects(:in_time_zone).never
|
|
202
|
+
Timecop::TimeStackItem.new(:freeze, Time.now)
|
|
203
|
+
end
|
|
204
|
+
end
|
|
@@ -3,20 +3,20 @@ require 'test_helper'
|
|
|
3
3
|
require File.join(File.dirname(__FILE__), '..', 'lib', 'timecop')
|
|
4
4
|
|
|
5
5
|
class TestTimecop < Test::Unit::TestCase
|
|
6
|
-
|
|
6
|
+
|
|
7
7
|
def setup
|
|
8
|
-
|
|
8
|
+
|
|
9
9
|
end
|
|
10
|
-
|
|
10
|
+
|
|
11
11
|
# just in case...let's really make sure that Timecop is disabled between tests...
|
|
12
12
|
def teardown
|
|
13
13
|
Timecop.return
|
|
14
14
|
end
|
|
15
|
-
|
|
15
|
+
|
|
16
16
|
def test_freeze_changes_and_resets_time
|
|
17
17
|
# depending on how we're invoked (individually or via the rake test suite)
|
|
18
18
|
assert !Time.respond_to?(:zone) || Time.zone.nil?
|
|
19
|
-
|
|
19
|
+
|
|
20
20
|
t = Time.local(2008, 10, 10, 10, 10, 10)
|
|
21
21
|
assert_not_equal t, Time.now
|
|
22
22
|
Timecop.freeze(2008, 10, 10, 10, 10, 10) do
|
|
@@ -24,6 +24,12 @@ class TestTimecop < Test::Unit::TestCase
|
|
|
24
24
|
end
|
|
25
25
|
assert_not_equal t, Time.now
|
|
26
26
|
end
|
|
27
|
+
|
|
28
|
+
def test_freeze_yields_mocked_time
|
|
29
|
+
Timecop.freeze(2008, 10, 10, 10, 10, 10) do |frozen_time|
|
|
30
|
+
assert_equal frozen_time, Time.now
|
|
31
|
+
end
|
|
32
|
+
end
|
|
27
33
|
|
|
28
34
|
def test_freeze_then_return_unsets_mock_time
|
|
29
35
|
Timecop.freeze(1)
|
|
@@ -36,22 +42,66 @@ class TestTimecop < Test::Unit::TestCase
|
|
|
36
42
|
Timecop.return
|
|
37
43
|
assert_nil Time.send(:mock_time)
|
|
38
44
|
end
|
|
39
|
-
|
|
45
|
+
|
|
40
46
|
def test_freeze_with_block_unsets_mock_time
|
|
41
47
|
assert_nil Time.send(:mock_time), "test is invalid"
|
|
42
48
|
Timecop.freeze(1) do; end
|
|
43
49
|
assert_nil Time.send(:mock_time)
|
|
44
50
|
end
|
|
45
|
-
|
|
51
|
+
|
|
46
52
|
def test_travel_with_block_unsets_mock_time
|
|
47
53
|
assert_nil Time.send(:mock_time), "test is invalid"
|
|
48
54
|
Timecop.travel(1) do; end
|
|
49
55
|
assert_nil Time.send(:mock_time)
|
|
50
56
|
end
|
|
51
|
-
|
|
57
|
+
|
|
58
|
+
def test_travel_does_not_reduce_precision_of_datetime
|
|
59
|
+
# requires to_r on Float (>= 1.9)
|
|
60
|
+
if Float.method_defined?(:to_r)
|
|
61
|
+
Timecop.travel(1)
|
|
62
|
+
assert_not_equal DateTime.now, DateTime.now
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def test_freeze_in_time_subclass_returns_mocked_subclass
|
|
67
|
+
t = Time.local(2008, 10, 10, 10, 10, 10)
|
|
68
|
+
custom_timeklass = Class.new(Time) do
|
|
69
|
+
def custom_format_method() strftime('%F') end
|
|
70
|
+
end
|
|
71
|
+
Timecop.freeze(2008, 10, 10, 10, 10, 10) do
|
|
72
|
+
assert custom_timeklass.now.is_a? custom_timeklass
|
|
73
|
+
assert Time.now.eql? custom_timeklass.now
|
|
74
|
+
assert custom_timeklass.now.respond_to? :custom_format_method
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def test_freeze_in_date_subclass_returns_mocked_subclass
|
|
79
|
+
t = Time.local(2008, 10, 10, 10, 10, 10)
|
|
80
|
+
custom_dateklass = Class.new(Date) do
|
|
81
|
+
def custom_format_method() strftime('%F') end
|
|
82
|
+
end
|
|
83
|
+
Timecop.freeze(2008, 10, 10, 10, 10, 10) do
|
|
84
|
+
assert custom_dateklass.today.is_a? custom_dateklass
|
|
85
|
+
assert Date.today.eql? custom_dateklass.today
|
|
86
|
+
assert custom_dateklass.today.respond_to? :custom_format_method
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def test_freeze_in_datetime_subclass_returns_mocked_subclass
|
|
91
|
+
t = Time.local(2008, 10, 10, 10, 10, 10)
|
|
92
|
+
custom_datetimeklass = Class.new(DateTime) do
|
|
93
|
+
def custom_format_method() strftime('%F') end
|
|
94
|
+
end
|
|
95
|
+
Timecop.freeze(2008, 10, 10, 10, 10, 10) do
|
|
96
|
+
assert custom_datetimeklass.now.is_a? custom_datetimeklass
|
|
97
|
+
assert DateTime.now.eql? custom_datetimeklass.now
|
|
98
|
+
assert custom_datetimeklass.now.respond_to? :custom_format_method
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
|
|
52
102
|
def test_recursive_freeze
|
|
53
103
|
t = Time.local(2008, 10, 10, 10, 10, 10)
|
|
54
|
-
Timecop.freeze(2008, 10, 10, 10, 10, 10) do
|
|
104
|
+
Timecop.freeze(2008, 10, 10, 10, 10, 10) do
|
|
55
105
|
assert_equal t, Time.now
|
|
56
106
|
t2 = Time.local(2008, 9, 9, 9, 9, 9)
|
|
57
107
|
Timecop.freeze(2008, 9, 9, 9, 9, 9) do
|
|
@@ -61,10 +111,10 @@ class TestTimecop < Test::Unit::TestCase
|
|
|
61
111
|
end
|
|
62
112
|
assert_not_equal t, Time.now
|
|
63
113
|
end
|
|
64
|
-
|
|
114
|
+
|
|
65
115
|
def test_freeze_with_time_instance_works_as_expected
|
|
66
116
|
t = Time.local(2008, 10, 10, 10, 10, 10)
|
|
67
|
-
Timecop.freeze(t) do
|
|
117
|
+
Timecop.freeze(t) do
|
|
68
118
|
assert_equal t, Time.now
|
|
69
119
|
assert_date_times_equal DateTime.new(2008, 10, 10, 10, 10, 10, local_offset), DateTime.now
|
|
70
120
|
assert_equal Date.new(2008, 10, 10), Date.today
|
|
@@ -73,7 +123,7 @@ class TestTimecop < Test::Unit::TestCase
|
|
|
73
123
|
assert_not_equal DateTime.new(2008, 10, 10, 10, 10, 10, local_offset), DateTime.now
|
|
74
124
|
assert_not_equal Date.new(2008, 10, 10), Date.today
|
|
75
125
|
end
|
|
76
|
-
|
|
126
|
+
|
|
77
127
|
def test_freeze_with_datetime_on_specific_timezone_during_dst
|
|
78
128
|
each_timezone do
|
|
79
129
|
# Start from a time that is subject to DST
|
|
@@ -87,7 +137,7 @@ class TestTimecop < Test::Unit::TestCase
|
|
|
87
137
|
Timecop.return
|
|
88
138
|
end
|
|
89
139
|
end
|
|
90
|
-
|
|
140
|
+
|
|
91
141
|
def test_freeze_with_datetime_on_specific_timezone_not_during_dst
|
|
92
142
|
each_timezone do
|
|
93
143
|
# Start from a time that is not subject to DST
|
|
@@ -99,7 +149,7 @@ class TestTimecop < Test::Unit::TestCase
|
|
|
99
149
|
end
|
|
100
150
|
end
|
|
101
151
|
end
|
|
102
|
-
|
|
152
|
+
|
|
103
153
|
def test_freeze_with_datetime_from_a_non_dst_time_to_a_dst_time
|
|
104
154
|
each_timezone do
|
|
105
155
|
# Start from a time that is not subject to DST
|
|
@@ -109,7 +159,7 @@ class TestTimecop < Test::Unit::TestCase
|
|
|
109
159
|
Timecop.freeze(t) do
|
|
110
160
|
assert_date_times_equal t, DateTime.now
|
|
111
161
|
end
|
|
112
|
-
end
|
|
162
|
+
end
|
|
113
163
|
end
|
|
114
164
|
|
|
115
165
|
def test_freeze_with_datetime_from_a_dst_time_to_a_non_dst_time
|
|
@@ -121,9 +171,9 @@ class TestTimecop < Test::Unit::TestCase
|
|
|
121
171
|
Timecop.freeze(t) do
|
|
122
172
|
assert_date_times_equal t, DateTime.now
|
|
123
173
|
end
|
|
124
|
-
end
|
|
174
|
+
end
|
|
125
175
|
end
|
|
126
|
-
|
|
176
|
+
|
|
127
177
|
def test_freeze_with_date_instance_works_as_expected
|
|
128
178
|
d = Date.new(2008, 10, 10)
|
|
129
179
|
Timecop.freeze(d) do
|
|
@@ -133,9 +183,9 @@ class TestTimecop < Test::Unit::TestCase
|
|
|
133
183
|
end
|
|
134
184
|
assert_not_equal d, Date.today
|
|
135
185
|
assert_not_equal Time.local(2008, 10, 10, 0, 0, 0), Time.now
|
|
136
|
-
assert_not_equal DateTime.new(2008, 10, 10, 0, 0, 0, local_offset), DateTime.now
|
|
186
|
+
assert_not_equal DateTime.new(2008, 10, 10, 0, 0, 0, local_offset), DateTime.now
|
|
137
187
|
end
|
|
138
|
-
|
|
188
|
+
|
|
139
189
|
def test_freeze_with_integer_instance_works_as_expected
|
|
140
190
|
t = Time.local(2008, 10, 10, 10, 10, 10)
|
|
141
191
|
Timecop.freeze(t) do
|
|
@@ -165,7 +215,7 @@ class TestTimecop < Test::Unit::TestCase
|
|
|
165
215
|
assert_nil Time.send(:mock_time)
|
|
166
216
|
end
|
|
167
217
|
end
|
|
168
|
-
|
|
218
|
+
|
|
169
219
|
def test_freeze_freezes_time
|
|
170
220
|
t = Time.local(2008, 10, 10, 10, 10, 10)
|
|
171
221
|
now = Time.now
|
|
@@ -179,7 +229,7 @@ class TestTimecop < Test::Unit::TestCase
|
|
|
179
229
|
assert_equal new_dt, DateTime.now
|
|
180
230
|
end
|
|
181
231
|
end
|
|
182
|
-
|
|
232
|
+
|
|
183
233
|
def test_travel_keeps_time_moving
|
|
184
234
|
t = Time.local(2008, 10, 10, 10, 10, 10)
|
|
185
235
|
now = Time.now
|
|
@@ -190,7 +240,7 @@ class TestTimecop < Test::Unit::TestCase
|
|
|
190
240
|
assert_times_effectively_not_equal new_now, Time.now, 0.25, "Looks like time is not moving"
|
|
191
241
|
end
|
|
192
242
|
end
|
|
193
|
-
|
|
243
|
+
|
|
194
244
|
def test_mocked_date_time_now_is_local
|
|
195
245
|
each_timezone do
|
|
196
246
|
t = DateTime.parse("2009-10-11 00:38:00 +0200")
|
|
@@ -199,7 +249,7 @@ class TestTimecop < Test::Unit::TestCase
|
|
|
199
249
|
end
|
|
200
250
|
end
|
|
201
251
|
end
|
|
202
|
-
|
|
252
|
+
|
|
203
253
|
def test_freeze_with_utc_time
|
|
204
254
|
each_timezone do
|
|
205
255
|
t = Time.utc(2008, 10, 10, 10, 10, 10)
|
|
@@ -224,10 +274,10 @@ class TestTimecop < Test::Unit::TestCase
|
|
|
224
274
|
assert !Time.now.utc?, "Failed to thwart destructive methods."
|
|
225
275
|
end
|
|
226
276
|
end
|
|
227
|
-
|
|
277
|
+
|
|
228
278
|
def test_recursive_travel_maintains_each_context
|
|
229
279
|
t = Time.local(2008, 10, 10, 10, 10, 10)
|
|
230
|
-
Timecop.travel(2008, 10, 10, 10, 10, 10) do
|
|
280
|
+
Timecop.travel(2008, 10, 10, 10, 10, 10) do
|
|
231
281
|
assert((t - Time.now).abs < 50, "Failed to travel time.")
|
|
232
282
|
t2 = Time.local(2008, 9, 9, 9, 9, 9)
|
|
233
283
|
Timecop.travel(2008, 9, 9, 9, 9, 9) do
|
|
@@ -238,10 +288,18 @@ class TestTimecop < Test::Unit::TestCase
|
|
|
238
288
|
end
|
|
239
289
|
assert_nil Time.send(:mock_time)
|
|
240
290
|
end
|
|
291
|
+
|
|
292
|
+
def test_recursive_travel_yields_correct_time
|
|
293
|
+
Timecop.travel(2008, 10, 10, 10, 10, 10) do
|
|
294
|
+
Timecop.travel(2008, 9, 9, 9, 9, 9) do |inner_freeze|
|
|
295
|
+
assert_times_effectively_equal inner_freeze, Time.now, 1, "Failed to yield current time back to block"
|
|
296
|
+
end
|
|
297
|
+
end
|
|
298
|
+
end
|
|
241
299
|
|
|
242
300
|
def test_recursive_travel_then_freeze
|
|
243
301
|
t = Time.local(2008, 10, 10, 10, 10, 10)
|
|
244
|
-
Timecop.travel(2008, 10, 10, 10, 10, 10) do
|
|
302
|
+
Timecop.travel(2008, 10, 10, 10, 10, 10) do
|
|
245
303
|
assert((t - Time.now).abs < 50, "Failed to travel time.")
|
|
246
304
|
t2 = Time.local(2008, 9, 9, 9, 9, 9)
|
|
247
305
|
Timecop.freeze(2008, 9, 9, 9, 9, 9) do
|
|
@@ -251,10 +309,10 @@ class TestTimecop < Test::Unit::TestCase
|
|
|
251
309
|
end
|
|
252
310
|
assert_nil Time.send(:mock_time)
|
|
253
311
|
end
|
|
254
|
-
|
|
312
|
+
|
|
255
313
|
def test_recursive_freeze_then_travel
|
|
256
314
|
t = Time.local(2008, 10, 10, 10, 10, 10)
|
|
257
|
-
Timecop.freeze(t) do
|
|
315
|
+
Timecop.freeze(t) do
|
|
258
316
|
assert_equal t, Time.now
|
|
259
317
|
t2 = Time.local(2008, 9, 9, 9, 9, 9)
|
|
260
318
|
Timecop.travel(t2) do
|
|
@@ -263,32 +321,86 @@ class TestTimecop < Test::Unit::TestCase
|
|
|
263
321
|
end
|
|
264
322
|
assert_equal t, Time.now
|
|
265
323
|
end
|
|
266
|
-
assert_nil Time.send(:mock_time)
|
|
324
|
+
assert_nil Time.send(:mock_time)
|
|
267
325
|
end
|
|
268
|
-
|
|
269
|
-
def
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
assert Timecop.return.is_a?(Time)
|
|
326
|
+
|
|
327
|
+
def test_travel_time_returns_nil
|
|
328
|
+
t_future = Time.local(2030, 10, 10, 10, 10, 10)
|
|
329
|
+
assert_nil Timecop.travel(t_future)
|
|
273
330
|
end
|
|
274
|
-
|
|
275
|
-
def
|
|
331
|
+
|
|
332
|
+
def test_travel_time_with_block_returns_the_value_of_the_block
|
|
276
333
|
t_future = Time.local(2030, 10, 10, 10, 10, 10)
|
|
277
|
-
|
|
278
|
-
|
|
334
|
+
expected = :foo
|
|
335
|
+
actual = Timecop.travel(t_future) { expected }
|
|
336
|
+
|
|
337
|
+
assert_equal expected, actual
|
|
279
338
|
end
|
|
280
|
-
|
|
281
|
-
def
|
|
339
|
+
|
|
340
|
+
def test_freeze_time_returns_nil
|
|
282
341
|
t_future = Time.local(2030, 10, 10, 10, 10, 10)
|
|
283
|
-
|
|
284
|
-
assert times_effectively_equal(t_future, t_frozen)
|
|
342
|
+
assert_nil Timecop.freeze(t_future)
|
|
285
343
|
end
|
|
286
|
-
|
|
287
|
-
def
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
344
|
+
|
|
345
|
+
def test_freeze_time_with_block_returns_the_value_of_the_block
|
|
346
|
+
t_future = Time.local(2030, 10, 10, 10, 10, 10)
|
|
347
|
+
expected = :foo
|
|
348
|
+
actual = Timecop.freeze(t_future) { expected }
|
|
349
|
+
|
|
350
|
+
assert_equal expected, actual
|
|
351
|
+
end
|
|
352
|
+
|
|
353
|
+
def test_return_returns_nil
|
|
354
|
+
assert_nil Timecop.return
|
|
355
|
+
end
|
|
356
|
+
|
|
357
|
+
def test_freeze_without_params
|
|
358
|
+
Timecop.freeze 1 do
|
|
359
|
+
current_time = Time.now
|
|
360
|
+
Timecop.freeze do
|
|
361
|
+
assert_equal Time.now, current_time
|
|
362
|
+
end
|
|
363
|
+
end
|
|
364
|
+
end
|
|
365
|
+
|
|
366
|
+
def test_freeze_with_new_date
|
|
367
|
+
date = Date.new(2012, 6, 9)
|
|
368
|
+
Timecop.freeze(Date.new(2012, 6, 9)) do
|
|
369
|
+
assert_equal date, Time.now.__send__(:to_date)
|
|
370
|
+
end
|
|
292
371
|
end
|
|
293
372
|
|
|
294
|
-
|
|
373
|
+
def test_return_to_baseline_without_a_baseline_set_returns_to_current_time
|
|
374
|
+
time_before_travel = Time.now
|
|
375
|
+
Timecop.travel Time.now - 60
|
|
376
|
+
Timecop.return_to_baseline
|
|
377
|
+
assert times_effectively_equal(time_before_travel, Time.now)
|
|
378
|
+
end
|
|
379
|
+
|
|
380
|
+
def test_return_to_baseline_with_a_baseline_set_returns_to_baseline
|
|
381
|
+
baseline = Time.local(1945, 10, 10, 10, 10, 10)
|
|
382
|
+
Timecop.baseline = baseline
|
|
383
|
+
Timecop.travel Time.now - 60
|
|
384
|
+
time_now = Timecop.return_to_baseline
|
|
385
|
+
assert times_effectively_equal(baseline, time_now),
|
|
386
|
+
"expected to return to #{baseline}, but returned to #{time_now}"
|
|
387
|
+
end
|
|
388
|
+
|
|
389
|
+
def test_return_eliminates_baseline
|
|
390
|
+
time_before_travel = Time.now
|
|
391
|
+
Timecop.baseline = Time.local(1937, 9, 9, 9, 9, 9)
|
|
392
|
+
Timecop.return
|
|
393
|
+
assert times_effectively_equal(time_before_travel, Time.now)
|
|
394
|
+
|
|
395
|
+
Timecop.travel(Time.now - 100)
|
|
396
|
+
Timecop.return_to_baseline
|
|
397
|
+
assert times_effectively_equal(time_before_travel, Time.now)
|
|
398
|
+
end
|
|
399
|
+
|
|
400
|
+
def test_mock_time_new_same_as_now
|
|
401
|
+
date = Time.local(2011, 01, 02)
|
|
402
|
+
Timecop.freeze date
|
|
403
|
+
assert_equal date, Time.now
|
|
404
|
+
assert_equal date, Time.new
|
|
405
|
+
end
|
|
406
|
+
end
|
|
@@ -5,8 +5,8 @@ require File.join(File.dirname(__FILE__), '..', 'lib', 'timecop')
|
|
|
5
5
|
class TestTimecopWithoutDate < Test::Unit::TestCase
|
|
6
6
|
|
|
7
7
|
def setup
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
Object.send(:remove_const, :Date) if Object.const_defined?(:Date)
|
|
9
|
+
Object.send(:remove_const, :DateTime) if Object.const_defined?(:DateTime)
|
|
10
10
|
end
|
|
11
11
|
|
|
12
12
|
# just in case...let's really make sure that Timecop is disabled between tests...
|
|
@@ -116,4 +116,4 @@ class TestTimecopWithoutDate < Test::Unit::TestCase
|
|
|
116
116
|
assert_nil Time.send(:mock_time)
|
|
117
117
|
end
|
|
118
118
|
|
|
119
|
-
end
|
|
119
|
+
end
|
metadata
CHANGED
|
@@ -1,37 +1,38 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: timecop
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
hash:
|
|
5
|
-
prerelease:
|
|
4
|
+
hash: 11
|
|
5
|
+
prerelease:
|
|
6
6
|
segments:
|
|
7
7
|
- 0
|
|
8
|
-
- 3
|
|
9
8
|
- 5
|
|
10
|
-
|
|
9
|
+
- 0
|
|
10
|
+
version: 0.5.0
|
|
11
11
|
platform: ruby
|
|
12
12
|
authors:
|
|
13
|
+
- Travis Jeffery
|
|
13
14
|
- John Trupiano
|
|
14
15
|
autorequire:
|
|
15
16
|
bindir: bin
|
|
16
17
|
cert_chain: []
|
|
17
18
|
|
|
18
|
-
date:
|
|
19
|
+
date: 2012-09-05 00:00:00 -05:00
|
|
19
20
|
default_executable:
|
|
20
21
|
dependencies: []
|
|
21
22
|
|
|
22
23
|
description: 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.
|
|
23
|
-
email:
|
|
24
|
+
email: travisjeffery@gmail.com
|
|
24
25
|
executables: []
|
|
25
26
|
|
|
26
27
|
extensions: []
|
|
27
28
|
|
|
28
29
|
extra_rdoc_files:
|
|
29
30
|
- LICENSE
|
|
30
|
-
- README.
|
|
31
|
+
- README.markdown
|
|
31
32
|
files:
|
|
32
33
|
- History.rdoc
|
|
33
34
|
- LICENSE
|
|
34
|
-
- README.
|
|
35
|
+
- README.markdown
|
|
35
36
|
- Rakefile
|
|
36
37
|
- VERSION.yml
|
|
37
38
|
- lib/timecop.rb
|
|
@@ -40,10 +41,10 @@ files:
|
|
|
40
41
|
- lib/timecop/timecop.rb
|
|
41
42
|
- test/run_tests.sh
|
|
42
43
|
- test/test_helper.rb
|
|
43
|
-
- test/
|
|
44
|
-
- test/
|
|
45
|
-
- test/
|
|
46
|
-
- test/
|
|
44
|
+
- test/time_stack_item_test.rb
|
|
45
|
+
- test/timecop_test.rb
|
|
46
|
+
- test/timecop_without_date_test.rb
|
|
47
|
+
- test/timecop_without_date_but_with_time_test.rb
|
|
47
48
|
has_rdoc: true
|
|
48
49
|
homepage: http://github.com/jtrupiano/timecop
|
|
49
50
|
licenses: []
|
|
@@ -74,13 +75,13 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
74
75
|
requirements: []
|
|
75
76
|
|
|
76
77
|
rubyforge_project: johntrupiano
|
|
77
|
-
rubygems_version: 1.
|
|
78
|
+
rubygems_version: 1.6.2
|
|
78
79
|
signing_key:
|
|
79
80
|
specification_version: 3
|
|
80
81
|
summary: 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.
|
|
81
82
|
test_files:
|
|
82
83
|
- test/test_helper.rb
|
|
83
|
-
- test/
|
|
84
|
-
- test/
|
|
85
|
-
- test/
|
|
86
|
-
- test/
|
|
84
|
+
- test/time_stack_item_test.rb
|
|
85
|
+
- test/timecop_test.rb
|
|
86
|
+
- test/timecop_without_date_test.rb
|
|
87
|
+
- test/timecop_without_date_but_with_time_test.rb
|
data/README.rdoc
DELETED
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
= timecop
|
|
2
|
-
|
|
3
|
-
* Source[http://github.com/jtrupiano/timecop]
|
|
4
|
-
* Documentation[http://johntrupiano.rubyforge.org/timecop]
|
|
5
|
-
|
|
6
|
-
== DESCRIPTION
|
|
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.
|
|
9
|
-
|
|
10
|
-
== INSTALL
|
|
11
|
-
|
|
12
|
-
gem install timecop
|
|
13
|
-
|
|
14
|
-
== FEATURES
|
|
15
|
-
|
|
16
|
-
* Freeze time to a specific point.
|
|
17
|
-
* Travel back to a specific point in time, but allow time to continue moving forward from there.
|
|
18
|
-
* No dependencies, can be used with _any_ ruby project
|
|
19
|
-
* Timecop api allows arguments to be passed into #freeze and #travel as one of the following:
|
|
20
|
-
* Time instance
|
|
21
|
-
* DateTime instance
|
|
22
|
-
* Date instance
|
|
23
|
-
* individual arguments (year, month, day, hour, minute, second)
|
|
24
|
-
* a single integer argument that is interpreted as an offset in seconds from Time.now
|
|
25
|
-
* Nested calls to Timecop#travel and Timecop#freeze are supported -- each block will maintain its interpretation of now.
|
|
26
|
-
|
|
27
|
-
== USAGE
|
|
28
|
-
|
|
29
|
-
Run a time-sensitive test
|
|
30
|
-
|
|
31
|
-
joe = User.find(1)
|
|
32
|
-
joe.purchase_home()
|
|
33
|
-
assert !joe.mortgage_due?
|
|
34
|
-
# move ahead a month and assert that the mortgage is due
|
|
35
|
-
Timecop.freeze(Date.today + 30) do
|
|
36
|
-
assert joe.mortgage_due?
|
|
37
|
-
end
|
|
38
|
-
|
|
39
|
-
Set the time for the test environment of a rails app -- this is particularly helpful if your whole application is time-sensitive. It allows you to build your test data at a single point in time, and to move in/out of that time as appropriate (within your tests)
|
|
40
|
-
|
|
41
|
-
in config/environments/test.rb
|
|
42
|
-
|
|
43
|
-
config.after_initialize do
|
|
44
|
-
# Set Time.now to September 1, 2008 10:05:00 AM (at this instant), but allow it to move forward
|
|
45
|
-
t = Time.local(2008, 9, 1, 10, 5, 0)
|
|
46
|
-
Timecop.travel(t)
|
|
47
|
-
end
|
|
48
|
-
|
|
49
|
-
=== The difference between Timecop.freeze and Timecop.travel
|
|
50
|
-
|
|
51
|
-
#freeze is used to statically mock the concept of now. As your program executes, Time.now will not change unless you make subsequent calls into the Timecop API. #travel, on the other hand, computes an offset between what we currently think Time.now is (recall that we support nested traveling) and the time passed in. It uses this offset to simulate the passage of time. To demonstrate, consider the following code snippets:
|
|
52
|
-
|
|
53
|
-
new_time = Time.local(2008, 9, 1, 12, 0, 0)
|
|
54
|
-
Timecop.freeze(new_time)
|
|
55
|
-
sleep(10)
|
|
56
|
-
new_time == Time.now # ==> true
|
|
57
|
-
|
|
58
|
-
Timecop.return # "turn off" Timecop
|
|
59
|
-
Timecop.travel(new_time)
|
|
60
|
-
sleep(10)
|
|
61
|
-
new_time == Time.now # ==> false
|
|
62
|
-
|
|
63
|
-
== REFERENCES
|
|
64
|
-
|
|
65
|
-
* {0.3.4 release}[http://blog.smartlogicsolutions.com/2009/12/07/timecop-0-3-4-released/]
|
|
66
|
-
* {0.3.0 release}[http://blog.smartlogicsolutions.com/2009/09/20/timecop-0-3-0-released/]
|
|
67
|
-
* {0.2.0 release}[http://blog.smartlogicsolutions.com/2008/12/24/timecop-2-released-freeze-and-rebase-time-ruby/]
|
|
68
|
-
* {0.1.0 release}[http://blog.smartlogicsolutions.com/2008/11/19/timecop-freeze-time-in-ruby-for-better-testing/]
|
/data/test/{test_timecop_without_date_but_with_time.rb → timecop_without_date_but_with_time_test.rb}
RENAMED
|
File without changes
|