Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Implemented time =~ time matcher, which checks if times/dates are pre…

…tty much equal (difference less than 1 second)
  • Loading branch information...
commit d08fc7e7126a0e834a106539a042ddfe4dda7ff9 1 parent d427bac
@andriusch andriusch authored
View
26 features/built_in_matchers/operators.feature
@@ -219,3 +219,29 @@ Feature: operator matchers
the extra elements were: [3]
"""
+ Scenario: time operator matchers
+ Given a file named "time_operator_matchers_spec.rb" with:
+ """
+ describe Time.utc(2012, 8, 25, 10, 37, 42) do
+ it { should =~ subject + 0.999 }
+ it { should =~ subject - 0.999 }
+ it { should_not =~ subject + 1 }
+ it { should_not =~ subject - 1 }
+
+ # deliberate failures
+ it { should_not =~ subject + 0.999 }
+ it { should =~ subject + 1 }
+ end
+ """
+ When I run `rspec time_operator_matchers_spec.rb`
+ Then the output should contain "6 examples, 2 failures"
+ And the output should contain:
+ """
+ Failure/Error: it { should_not =~ subject + 0.999 }
+ expected 2012-08-25 10:37:42 UTC not to be same time as 2012-08-25 10:37:42 UTC but it was
+ """
+ And the output should contain:
+ """
+ Failure/Error: it { should =~ subject + 1 }
+ expected 2012-08-25 10:37:42 UTC to be same time as 2012-08-25 10:37:43 UTC but it wasn't
+ """
View
34 lib/rspec/matchers.rb
@@ -214,7 +214,7 @@ def be_nil
#
# Given true, false, or nil, will pass if actual value is true, false or
# nil (respectively). Given no args means the caller should satisfy an if
- # condition (to be or not to be).
+ # condition (to be or not to be).
#
# Predicates are any Ruby method that ends in a "?" and returns true or
# false. Given be_ followed by arbitrary_predicate (without the "?"),
@@ -246,7 +246,7 @@ def be_a(klass)
def be_an_instance_of(expected)
BuiltIn::BeAnInstanceOf.new(expected)
end
-
+
alias_method :be_instance_of, :be_an_instance_of
# Passes if actual.kind_of?(expected)
@@ -288,20 +288,20 @@ def be_within(delta)
# @example
#
# lambda {
- # team.add_player(player)
+ # team.add_player(player)
# }.should change(roster, :count)
#
# lambda {
- # team.add_player(player)
+ # team.add_player(player)
# }.should change(roster, :count).by(1)
#
# lambda {
- # team.add_player(player)
+ # team.add_player(player)
# }.should change(roster, :count).by_at_least(1)
#
# lambda {
# team.add_player(player)
- # }.should change(roster, :count).by_at_most(1)
+ # }.should change(roster, :count).by_at_most(1)
#
# string = "string"
# lambda {
@@ -311,7 +311,7 @@ def be_within(delta)
# lambda {
# person.happy_birthday
# }.should change(person, :birthday).from(32).to(33)
- #
+ #
# lambda {
# employee.develop_great_new_social_networking_app
# }.should change(employee, :title).from("Mail Clerk").to("CEO")
@@ -523,7 +523,7 @@ def raise_error(error=Exception, message=nil, &block)
# provided. Names can be Strings or Symbols.
#
# @example
- #
+ #
def respond_to(*names)
BuiltIn::RespondTo.new(*names)
end
@@ -685,5 +685,23 @@ def match_array(array)
end
OperatorMatcher.register(Array, '=~', BuiltIn::MatchArray)
+
+ # Passes if the actual time differs from expected time by less than 1 second. Works with time and date objects.
+ #
+ # @note This is also available using the `=~` operator
+ #
+ # @example
+ #
+ # expect(Time.now).to match_time(Time.now) # => would pass
+ # Time.now.should =~ Date.new(2012, 8, 25) # => would pass on 2012-08-25 00:00:00
+ # Time.now.should =~ Time.now - 2 # => would fail
+ def match_time(time)
+ BuiltIn::MatchTime.new(time)
+ end
+
+ OperatorMatcher.register(Time, '=~', BuiltIn::MatchTime) if defined?(Time)
+ OperatorMatcher.register(Date, '=~', BuiltIn::MatchTime) if defined?(Date)
+ OperatorMatcher.register(DateTime, '=~', BuiltIn::MatchTime) if defined?(DateTime)
+ OperatorMatcher.register(ActiveSupport::TimeWithZone, '=~', BuiltIn::MatchTime) if defined?(ActiveSupport::TimeWithZone)
end
end
View
1  lib/rspec/matchers/built_in.rb
@@ -22,6 +22,7 @@ module BuiltIn
autoload :Include, 'rspec/matchers/built_in/include'
autoload :Match, 'rspec/matchers/built_in/match'
autoload :MatchArray, 'rspec/matchers/built_in/match_array'
+ autoload :MatchTime, 'rspec/matchers/built_in/match_time'
autoload :RaiseError, 'rspec/matchers/built_in/raise_error'
autoload :RespondTo, 'rspec/matchers/built_in/respond_to'
autoload :StartWith, 'rspec/matchers/built_in/start_and_end_with'
View
30 lib/rspec/matchers/built_in/match_time.rb
@@ -0,0 +1,30 @@
+module RSpec
+ module Matchers
+ module BuiltIn
+ class MatchTime < BaseMatcher
+ def match(expected, actual)
+ (seconds_of(expected) - seconds_of(actual)).abs < 1
+ end
+
+ def failure_message_for_should
+ "expected #{actual} to be same time as #{expected} but it wasn't"
+ end
+
+ def failure_message_for_should_not
+ "expected #{actual} not to be same time as #{expected} but it was"
+ end
+
+ def description
+ "be same time as #{expected}"
+ end
+
+ private
+
+ def seconds_of(time)
+ time = time.to_time if time.respond_to?(:to_time)
+ time.to_f
+ end
+ end
+ end
+ end
+end
View
58 spec/rspec/matchers/match_time_spec.rb
@@ -0,0 +1,58 @@
+require 'spec_helper'
+
+describe "using match_time" do
+ it_behaves_like "an RSpec matcher", :valid_value => Time.mktime(2012, 8, 25), :invalid_value => Time.mktime(2012, 8, 26) do
+ let(:matcher) { match_time(Time.mktime(2012, 8, 25)) }
+ end
+end
+
+describe "time.should =~ other_time" do
+ let :time do
+ Time.now.to_date.to_time
+ end
+
+ let :date do
+ time.to_date
+ end
+
+ let :datetime do
+ time.to_datetime
+ end
+
+ it "passes if actual value differs from expected by less than 1 second" do
+ time.should =~ time + 0.999
+ end
+
+ it "fails if actual value is lower than expected by at least 1 second" do
+ expect {
+ time.should =~ time + 1
+ }.to fail_with("expected 2012-08-25 00:00:00 +0300 to be same time as 2012-08-25 00:00:01 +0300 but it wasn't")
+ end
+
+ it "fails if actual value is higher than expected by at least 1 second" do
+ expect {
+ time.should =~ time - 1
+ }.to fail_with("expected 2012-08-25 00:00:00 +0300 to be same time as 2012-08-24 23:59:59 +0300 but it wasn't")
+ end
+
+ it "can be called on Date objects" do
+ date.should =~ time - 0.999
+ end
+
+ it "can be called on DateTime objects" do
+ datetime.should =~ time - 0.999
+ end
+
+ it "can be compared to Date objects" do
+ time.should =~ date
+ end
+end
+
+describe "time.should_not =~ other_time" do
+ it "fails if actual value differs from expected by less than 1 second" do
+ time = Time.mktime(2012, 8, 25)
+ expect {
+ time.should_not =~ time + 0.999
+ }.to fail_with("expected 2012-08-25 00:00:00 +0300 not to be same time as 2012-08-25 00:00:00 +0300 but it was")
+ end
+end
Please sign in to comment.
Something went wrong with that request. Please try again.