timecop 0.0.99

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.
@@ -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
+