timecop 0.0.99

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,48 @@
1
+ === 0.2.1 / 2009-03-06
2
+ * API Changes
3
+
4
+ * Introduced a 5th style of arguments to be passed into #travel and #freeze. Now, if you pass in a single integer value,
5
+ it will be interpreted as a relative offset in seconds from the current Time.now. Previously this was interpreted as
6
+ only the year, similar to calling Time.local(2008) --> Jan. 1, 2008. This is no longer the case.
7
+
8
+ * Documentation
9
+
10
+ * Moved to Textile for the README.
11
+
12
+ * Added documentation for the new feature, and fixed a few typos.
13
+
14
+ === 0.2.0 / 2008-12-23
15
+
16
+ * API Changes
17
+
18
+ * Timecop#travel no longer freezes time. Rather, it computes the current offset between the new "now" and the real "now", and
19
+ returns times as if Time had continued to move forward
20
+
21
+ * Timecop#freeze now behaves exactly as the old Timecop#travel behaved. Unless you depended on the actual freezing of time
22
+ (which I think would be rare), you should be able to continue to use #travel without worry.
23
+
24
+ * Timecop#return is now exposed (previously Timecop#unset_all, but not well advertised). It will completely unmock time,
25
+ and will probably be rarely used outside of the actual implementation of this library.
26
+
27
+ * More Test Coverage
28
+
29
+ * Tests now explicitly cover the cases when the Date and DateTime objects are not loaded, and ensures proper functionality
30
+ in their absence and existence.
31
+
32
+ * Still haven't done regression testing against anything other than a few version of 1.8.6 (including REE). We should
33
+ probably try to get this tested on both 1.8.7 and 1.9.1.
34
+
35
+ * Documentation
36
+
37
+ * Fixed up a lot of the poorly-formatted rdoc syntax. The public API should now be properly published in the rdoc,
38
+ and the internals are omitted.
39
+
40
+ === 0.1.0 / 2008-11-09
41
+
42
+ * Initial Feature Set
43
+
44
+ * Temporarily (or permanently if you prefer) change the concept of Time.now, DateTime.now (if defined), and Date.today (if defined)
45
+ * Timecop#travel api allows an argument to be passed in as one of: 1) Time instance, 2) DateTime instance, 3) Date instance,
46
+ 4) individual arguments (year, month, day, hour, minute, second)
47
+ * Nested calls to Timecop#travel are supported -- each block will maintain it's interpretation of now.
48
+
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ (The MIT License)
2
+
3
+ Copyright (c) 2008
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ 'Software'), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
20
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
21
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
22
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,14 @@
1
+ History.txt
2
+ Manifest.txt
3
+ README.txt
4
+ Rakefile
5
+ lib/timecop.rb
6
+ lib/timecop/stack_item.rb
7
+ lib/timecop/time_extensions.rb
8
+ lib/timecop/timecop.rb
9
+ lib/timecop/version.rb
10
+ test/run_tests.sh
11
+ test/test_timecop.rb
12
+ test/test_timecop_internals.rb
13
+ test/test_timecop_without_date.rb
14
+ timecop.gemspec
@@ -0,0 +1,68 @@
1
+ h1. timecop
2
+
3
+ * http://github.com/jtrupiano/timecop
4
+
5
+ h2. DESCRIPTION
6
+
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 test time-dependent code.
8
+
9
+ h2. FEATURES
10
+
11
+ * Temporarily (or permanently if you prefer) change the concept of Time.now, DateTime.now, and Date.today
12
+ * Timecop api allows arguments to be passed into #freeze and #travel as one of the following:
13
+ # Time instance
14
+ # DateTime instance
15
+ # Date instance
16
+ # individual arguments (year, month, day, hour, minute, second)
17
+ # a single integer argument that is interpreted as an offset in seconds from Time.now
18
+
19
+ * Nested calls to Timecop#travel and Timecop#freeze are supported -- each block will maintain it's interpretation of now.
20
+
21
+ h2. SHORTCOMINGS
22
+
23
+ * 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.)
24
+
25
+ h2. SYNOPSIS
26
+
27
+ Run a time-sensitive test
28
+
29
+ <pre>
30
+ <code>
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
+ </code>
39
+ </pre>
40
+
41
+ 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)
42
+
43
+ in config/environments/test.rb
44
+
45
+ <pre>
46
+ <code>
47
+ config.after_initialize do
48
+ # Set Time.now to September 1, 2008 10:05:00 AM
49
+ t = Time.local(2008, 9, 1, 10, 5, 0)
50
+ Timecop.travel(t)
51
+ end
52
+ </code>
53
+ </pre>
54
+
55
+ h2. REQUIREMENTS
56
+
57
+ * None
58
+
59
+ h2. INSTALL
60
+
61
+ * sudo gem install timecop (latest stable version from rubyforge)
62
+ * sudo gem install jtrupiano-timecop (HEAD of the repo from github)
63
+
64
+ h2. REFERENCES
65
+
66
+ * "0.1.0 release":http://blog.smartlogicsolutions.com/2008/11/19/timecop-freeze-time-in-ruby-for-better-testing/
67
+ * "0.2.0 release":http://blog.smartlogicsolutions.com/2008/12/24/timecop-2-released-freeze-and-rebase-time-ruby/
68
+
@@ -0,0 +1,31 @@
1
+ require 'rake'
2
+ require 'rake/testtask'
3
+ require 'rake/rdoctask'
4
+
5
+ begin
6
+ require 'jeweler'
7
+ Jeweler::Tasks.new do |s|
8
+ s.name = "timecop"
9
+ s.rubyforge_project = 'johntrupiano' # if different than lowercase project name
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 test time-dependent code.)
11
+ s.summary = s.description # More details later??
12
+ s.email = "jtrupiano@gmail.com"
13
+ s.homepage = "http://github.com/jtrupiano/timecop"
14
+ s.authors = ["John Trupiano"]
15
+ s.files = FileList["[A-Z]*", "{bin,lib,test}/**/*"]
16
+ #s.add_dependency 'schacon-git'
17
+ end
18
+ rescue LoadError
19
+ puts "Jeweler, or one of its dependencies, is not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
20
+ end
21
+
22
+ # Override the test task and instruct them how to actually run the tests.
23
+ Rake.application.send(:eval, "@tasks.delete('test')")
24
+ desc "Does not execute tests. Manually run shell script ./run_tests.sh to execute tests."
25
+ task :test do
26
+ puts <<-MSG
27
+ In order to run the test suite, run: cd test && ./run_tests.sh
28
+ The tests need to be run with different libraries loaded, which rules out using Rake
29
+ to automate them.
30
+ MSG
31
+ end
@@ -0,0 +1,4 @@
1
+ ---
2
+ :major: 0
3
+ :minor: 0
4
+ :patch: 99
@@ -0,0 +1,3 @@
1
+ # place gem dependencies here...
2
+ #require 'timecop/timecop'
3
+ require File.join(File.dirname(__FILE__), 'timecop', 'timecop')
@@ -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
+
@@ -0,0 +1,96 @@
1
+ # 1. Extensions to the Time, Date, and DateTime objects
2
+ # 2. Allows us to "freeze" time in our Ruby applications.
3
+ # 3. This is very useful when your app's functionality is dependent on time (e.g.
4
+ # anything that might expire). This will allow us to alter the return value of
5
+ # Date.today, Time.now, and DateTime.now, such that our application code _never_ has to change.
6
+
7
+ class Time
8
+ class << self
9
+ # Time we might be behaving as
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
22
+
23
+ # Set new time to pretend we are.
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)
37
+ end
38
+
39
+ # Alias the original now
40
+ alias_method :now_without_mock_time, :now
41
+
42
+ # Define now_with_mock_time
43
+ def now_with_mock_time
44
+ mock_time || now_without_mock_time
45
+ end
46
+
47
+ # Alias now to now_with_mock_time
48
+ alias_method :now, :now_with_mock_time
49
+ end
50
+ end
51
+
52
+ if Object.const_defined?(:Date)
53
+ class Date
54
+ class << self
55
+ def mock_date
56
+ now = Time.mock_time
57
+ return nil if now.nil?
58
+ Date.new(now.year, now.month, now.day)
59
+ end
60
+
61
+ # Alias the original today
62
+ alias_method :today_without_mock_date, :today
63
+
64
+ # Define today_with_mock_date
65
+ def today_with_mock_date
66
+ mock_date || today_without_mock_date
67
+ end
68
+
69
+ # Alias today to today_with_mock_date
70
+ alias_method :today, :today_with_mock_date
71
+ end
72
+ end
73
+ end
74
+
75
+ if Object.const_defined?(:DateTime)
76
+ class DateTime
77
+ class << self
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)
82
+ end
83
+
84
+ # Alias the original now
85
+ alias_method :now_without_mock_time, :now
86
+
87
+ # Define now_with_mock_time
88
+ def now_with_mock_time
89
+ mock_time || now_without_mock_time
90
+ end
91
+
92
+ # Alias now to now_with_mock_time
93
+ alias_method :now, :now_with_mock_time
94
+ end
95
+ end
96
+ end
@@ -0,0 +1,198 @@
1
+ require 'singleton'
2
+ require File.join(File.dirname(__FILE__), 'time_extensions')
3
+ require File.join(File.dirname(__FILE__), 'stack_item')
4
+
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.
11
+ # anything that might expire). This will allow us to alter the return value of
12
+ # Date.today, Time.now, and DateTime.now, such that our application code _never_ has to change.
13
+ class Timecop
14
+ include Singleton
15
+
16
+ # Allows you to run a block of code and "fake" a time throughout the execution of that block.
17
+ # This is particularly useful for writing test methods where the passage of time is critical to the business
18
+ # logic being tested. For example:
19
+ #
20
+ # <code>
21
+ # joe = User.find(1)
22
+ # joe.purchase_home()
23
+ # assert !joe.mortgage_due?
24
+ # Timecop.freeze(2008, 10, 5) do
25
+ # assert joe.mortgage_due?
26
+ # end
27
+ # </code>
28
+ #
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)
34
+ #
35
+ # When a block is also passed, Time.now, DateTime.now and Date.today are all reset to their
36
+ # previous values. This allows us to nest multiple calls to Timecop.travel and have each block
37
+ # maintain it's concept of "now."
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.
56
+ def self.travel(*args, &block)
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
65
+
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)
82
+
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)
91
+
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
111
+ end
112
+ end
113
+
114
+ def unmock!
115
+ Time.unmock!
116
+ end
117
+
118
+ private
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)
157
+ arg = args.shift
158
+ if arg.is_a?(Time) || (Object.const_defined?(:DateTime) && arg.is_a?(DateTime))
159
+ year, month, day, hour, minute, second = arg.year, arg.month, arg.day, arg.hour, arg.min, arg.sec
160
+ elsif Object.const_defined?(:Date) && arg.is_a?(Date)
161
+ year, month, day, hour, minute, second = arg.year, arg.month, arg.day, 0, 0, 0
162
+ #puts "#{year}-#{month}-#{day} #{hour}:#{minute}:#{second}"
163
+ elsif args.empty? && arg.kind_of?(Integer)
164
+ t = Time.now + arg
165
+ year, month, day, hour, minute, second = t.year, t.month, t.day, t.hour, t.min, t.sec
166
+ else # we'll just assume it's a list of y/m/h/d/m/s
167
+ year = arg || 0
168
+ month = args.shift || 1
169
+ day = args.shift || 1
170
+ hour = args.shift || 0
171
+ minute = args.shift || 0
172
+ second = args.shift || 0
173
+ end
174
+ return year, month, day, hour, minute, second
175
+ end
176
+ end
177
+
178
+ #def with_dates(*dates, &block)
179
+ # dates.flatten.each do |date|
180
+ # begin
181
+ # DateTime.forced_now = case date
182
+ # when String: DateTime.parse(date)
183
+ # when Time: DateTime.parse(date.to_s)
184
+ # else
185
+ # date
186
+ # end
187
+ # Date.forced_today = Date.new(DateTime.forced_now.year,
188
+ #DateTime.forced_now.month, DateTime.forced_now.day)
189
+ # yield
190
+ # rescue Exception => e
191
+ # raise e
192
+ # ensure
193
+ # DateTime.forced_now = nil
194
+ # Date.forced_today = nil
195
+ # end
196
+ # end
197
+ #end
198
+
@@ -0,0 +1,20 @@
1
+ module Timecop
2
+ module Version #:nodoc:
3
+ # A method for comparing versions of required modules. It expects two
4
+ # arrays of integers as parameters, the first being the minimum version
5
+ # required, and the second being the actual version available. It returns
6
+ # true if the actual version is at least equal to the required version.
7
+ def self.check(required, actual) #:nodoc:
8
+ required = required.map { |v| "%06d" % v }.join(".")
9
+ actual = actual.map { |v| "%06d" % v }.join(".")
10
+ return actual >= required
11
+ end
12
+
13
+ MAJOR = 0
14
+ MINOR = 2
15
+ TINY = 0
16
+
17
+ STRING = [MAJOR, MINOR, TINY].join(".")
18
+ end
19
+ end
20
+
@@ -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!!!!!!!!!!!!")
@@ -0,0 +1,175 @@
1
+
2
+ require 'date'
3
+ require 'test/unit'
4
+ require File.join(File.dirname(__FILE__), '..', 'lib', 'timecop')
5
+
6
+ class TestTimecop < Test::Unit::TestCase
7
+
8
+ def setup
9
+
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?
20
+
21
+ t = Time.local(2008, 10, 10, 10, 10, 10)
22
+ assert_not_equal t, Time.now
23
+ Timecop.freeze(2008, 10, 10, 10, 10, 10) do
24
+ assert_equal t, Time.now
25
+ end
26
+ assert_not_equal t, Time.now
27
+ end
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_not_equal t, Time.now
40
+ end
41
+
42
+ def test_freeze_with_time_instance_works_as_expected
43
+ t = Time.local(2008, 10, 10, 10, 10, 10)
44
+ Timecop.freeze(t) do
45
+ assert_equal t, Time.now
46
+ assert_equal DateTime.new(2008, 10, 10, 10, 10, 10), DateTime.now
47
+ assert_equal Date.new(2008, 10, 10), Date.today
48
+ end
49
+ assert_not_equal t, Time.now
50
+ assert_not_equal DateTime.new(2008, 10, 10, 10, 10, 10), DateTime.now
51
+ assert_not_equal Date.new(2008, 10, 10), Date.today
52
+ end
53
+
54
+ def test_freeze_with_datetime_instance_works_as_expected
55
+ t = DateTime.new(2008, 10, 10, 10, 10, 10)
56
+ Timecop.freeze(t) do
57
+ assert_equal t, DateTime.now
58
+ assert_equal Time.local(2008, 10, 10, 10, 10, 10), Time.now
59
+ assert_equal Date.new(2008, 10, 10), Date.today
60
+ end
61
+ assert_not_equal t, DateTime.now
62
+ assert_not_equal Time.local(2008, 10, 10, 10, 10, 10), Time.now
63
+ assert_not_equal Date.new(2008, 10, 10), Date.today
64
+ end
65
+
66
+ def test_freeze_with_date_instance_works_as_expected
67
+ d = Date.new(2008, 10, 10)
68
+ Timecop.freeze(d) do
69
+ assert_equal d, Date.today
70
+ assert_equal Time.local(2008, 10, 10, 0, 0, 0), Time.now
71
+ assert_equal DateTime.new(2008, 10, 10, 0, 0, 0), DateTime.now
72
+ end
73
+ assert_not_equal d, Date.today
74
+ assert_not_equal Time.local(2008, 10, 10, 0, 0, 0), Time.now
75
+ assert_not_equal DateTime.new(2008, 10, 10, 0, 0, 0), DateTime.now
76
+ end
77
+
78
+ def test_freeze_with_integer_instance_works_as_expected
79
+ t = Time.local(2008, 10, 10, 10, 10, 10)
80
+ Timecop.freeze(t) do
81
+ assert_equal t, Time.now
82
+ assert_equal DateTime.new(2008, 10, 10, 10, 10, 10), DateTime.now
83
+ assert_equal Date.new(2008, 10, 10), Date.today
84
+ Timecop.freeze(10) do
85
+ assert_equal t + 10, Time.now
86
+ assert_equal Time.local(2008, 10, 10, 10, 10, 20), Time.now
87
+ assert_equal Date.new(2008, 10, 10), Date.today
88
+ end
89
+ end
90
+ assert_not_equal t, Time.now
91
+ assert_not_equal DateTime.new(2008, 10, 10, 10, 10, 10), DateTime.now
92
+ assert_not_equal Date.new(2008, 10, 10), Date.today
93
+ end
94
+
95
+ def test_exception_thrown_in_freeze_block_properly_resets_time
96
+ t = Time.local(2008, 10, 10, 10, 10, 10)
97
+ begin
98
+ Timecop.freeze(t) do
99
+ assert_equal t, Time.now
100
+ raise "blah exception"
101
+ end
102
+ rescue
103
+ assert_not_equal t, Time.now
104
+ assert_nil Time.send(:mock_time)
105
+ end
106
+ end
107
+
108
+ def test_freeze_freezes_time
109
+ t = Time.local(2008, 10, 10, 10, 10, 10)
110
+ now = Time.now
111
+ Timecop.freeze(t) do
112
+ #assert Time.now < now, "If we had failed to freeze, time would have proceeded, which is what appears to have happened."
113
+ new_t, new_d, new_dt = Time.now, Date.today, DateTime.now
114
+ assert_equal t, new_t, "Failed to freeze time." # 2 seconds
115
+ #sleep(10)
116
+ assert_equal new_t, Time.now
117
+ assert_equal new_d, Date.today
118
+ assert_equal new_dt, DateTime.now
119
+ end
120
+ end
121
+
122
+ def test_travel_keeps_time_moving
123
+ t = Time.local(2008, 10, 10, 10, 10, 10)
124
+ now = Time.now
125
+ Timecop.travel(t) do
126
+ #assert Time.now < now, "If we had failed to freeze, time would have proceeded, which is what appears to have happened."
127
+ assert Time.now - t < 2000, "Looks like we failed to actually travel time" # 2 seconds
128
+ new_t = Time.now
129
+ #sleep(10)
130
+ assert_not_equal new_t, Time.now
131
+ end
132
+ end
133
+
134
+ def test_recursive_rebasing_maintains_each_context
135
+ t = Time.local(2008, 10, 10, 10, 10, 10)
136
+ Timecop.travel(2008, 10, 10, 10, 10, 10) do
137
+ assert((t - Time.now).abs < 50, "Failed to travel time.")
138
+ t2 = Time.local(2008, 9, 9, 9, 9, 9)
139
+ Timecop.travel(2008, 9, 9, 9, 9, 9) do
140
+ assert((t2 - Time.now) < 50, "Failed to travel time.")
141
+ assert((t - Time.now) > 1000, "Failed to travel time.")
142
+ end
143
+ assert((t - Time.now).abs < 2000, "Failed to restore previously-traveled time.")
144
+ end
145
+ assert_nil Time.send(:mock_time)
146
+ end
147
+
148
+ def test_recursive_travel_then_freeze
149
+ t = Time.local(2008, 10, 10, 10, 10, 10)
150
+ Timecop.travel(2008, 10, 10, 10, 10, 10) do
151
+ assert((t - Time.now).abs < 50, "Failed to travel time.")
152
+ t2 = Time.local(2008, 9, 9, 9, 9, 9)
153
+ Timecop.freeze(2008, 9, 9, 9, 9, 9) do
154
+ assert_equal t2, Time.now
155
+ end
156
+ assert((t - Time.now).abs < 2000, "Failed to restore previously-traveled time.")
157
+ end
158
+ assert_nil Time.send(:mock_time)
159
+ end
160
+
161
+ def test_recursive_freeze_then_travel
162
+ t = Time.local(2008, 10, 10, 10, 10, 10)
163
+ Timecop.freeze(t) do
164
+ assert_equal t, Time.now
165
+ t2 = Time.local(2008, 9, 9, 9, 9, 9)
166
+ Timecop.travel(t2) do
167
+ assert((t2 - Time.now) < 50, "Failed to travel time.")
168
+ assert((t - Time.now) > 1000, "Failed to travel time.")
169
+ end
170
+ assert_equal t, Time.now
171
+ end
172
+ assert_nil Time.send(:mock_time)
173
+ end
174
+
175
+ end
@@ -0,0 +1,69 @@
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
+ # Due to the nature of this test (calling Time.now once in this test and
45
+ # once in #parse_travel_args), this test may fail when two subsequent calls
46
+ # to Time.now return a different second.
47
+ def test_parse_travel_args_with_integer
48
+ t = Time.now
49
+ y, m, d, h, min, s = t.year, t.month, t.day, t.hour, t.min, t.sec
50
+ ty, tm, td, th, tmin, ts = Timecop.instance().send(:parse_travel_args, 0)
51
+ assert_equal y, ty
52
+ assert_equal m, tm
53
+ assert_equal d, td
54
+ assert_equal h, th
55
+ assert_equal min, tmin
56
+ assert_equal s, ts
57
+ end
58
+
59
+ def test_parse_travel_args_with_individual_arguments
60
+ y, m, d, h, min, s = 2008, 10, 10, 10, 10, 10
61
+ ty, tm, td, th, tmin, ts = Timecop.instance().send(:parse_travel_args, y, m, d, h, min, s)
62
+ assert_equal y, ty
63
+ assert_equal m, tm
64
+ assert_equal d, td
65
+ assert_equal h, th
66
+ assert_equal min, tmin
67
+ assert_equal s, ts
68
+ end
69
+ end
@@ -0,0 +1,120 @@
1
+
2
+ require 'test/unit'
3
+ require File.join(File.dirname(__FILE__), '..', 'lib', 'timecop')
4
+
5
+ class TestTimecopWithouDate < Test::Unit::TestCase
6
+
7
+ def setup
8
+ assert !Object.const_defined?(:Date)
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?
20
+
21
+ t = Time.local(2008, 10, 10, 10, 10, 10)
22
+ assert_not_equal t, Time.now
23
+ Timecop.freeze(2008, 10, 10, 10, 10, 10) do
24
+ assert_equal t, Time.now
25
+ end
26
+ assert_not_equal t, Time.now
27
+ end
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
+
120
+ end
metadata ADDED
@@ -0,0 +1,70 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: timecop
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.99
5
+ platform: ruby
6
+ authors:
7
+ - John Trupiano
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-03-07 00:00:00 -05:00
13
+ default_executable:
14
+ dependencies: []
15
+
16
+ description: 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 test time-dependent code.
17
+ email: jtrupiano@gmail.com
18
+ executables: []
19
+
20
+ extensions: []
21
+
22
+ extra_rdoc_files:
23
+ - README.textile
24
+ - LICENSE
25
+ files:
26
+ - History.txt
27
+ - LICENSE
28
+ - Manifest.txt
29
+ - Rakefile
30
+ - README.textile
31
+ - VERSION.yml
32
+ - lib/timecop
33
+ - lib/timecop/stack_item.rb
34
+ - lib/timecop/time_extensions.rb
35
+ - lib/timecop/timecop.rb
36
+ - lib/timecop/version.rb
37
+ - lib/timecop.rb
38
+ - test/run_tests.sh
39
+ - test/test_timecop.rb
40
+ - test/test_timecop_internals.rb
41
+ - test/test_timecop_without_date.rb
42
+ has_rdoc: true
43
+ homepage: http://github.com/jtrupiano/timecop
44
+ post_install_message:
45
+ rdoc_options:
46
+ - --inline-source
47
+ - --charset=UTF-8
48
+ require_paths:
49
+ - lib
50
+ required_ruby_version: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: "0"
55
+ version:
56
+ required_rubygems_version: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ version: "0"
61
+ version:
62
+ requirements: []
63
+
64
+ rubyforge_project: johntrupiano
65
+ rubygems_version: 1.3.1
66
+ signing_key:
67
+ specification_version: 2
68
+ 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 test time-dependent code.
69
+ test_files: []
70
+