timecop 0.1.0 → 0.2.1

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