summaryrefslogtreecommitdiffstats
path: root/test/lib/spec/matchers/have.rb
diff options
context:
space:
mode:
Diffstat (limited to 'test/lib/spec/matchers/have.rb')
-rw-r--r--test/lib/spec/matchers/have.rb140
1 files changed, 140 insertions, 0 deletions
diff --git a/test/lib/spec/matchers/have.rb b/test/lib/spec/matchers/have.rb
new file mode 100644
index 000000000..81f9af3e3
--- /dev/null
+++ b/test/lib/spec/matchers/have.rb
@@ -0,0 +1,140 @@
+module Spec
+ module Matchers
+
+ class Have #:nodoc:
+ def initialize(expected, relativity=:exactly)
+ @expected = (expected == :no ? 0 : expected)
+ @relativity = relativity
+ end
+
+ def relativities
+ @relativities ||= {
+ :exactly => "",
+ :at_least => "at least ",
+ :at_most => "at most "
+ }
+ end
+
+ def method_missing(sym, *args, &block)
+ @collection_name = sym
+ @args = args
+ @block = block
+ self
+ end
+
+ def matches?(collection_owner)
+ if collection_owner.respond_to?(collection_name)
+ collection = collection_owner.send(collection_name, *@args, &@block)
+ elsif (collection_owner.respond_to?(:length) || collection_owner.respond_to?(:size))
+ collection = collection_owner
+ else
+ collection_owner.send(collection_name, *@args, &@block)
+ end
+ @actual = collection.length if collection.respond_to?(:length)
+ @actual = collection.size if collection.respond_to?(:size)
+ return @actual >= @expected if @relativity == :at_least
+ return @actual <= @expected if @relativity == :at_most
+ return @actual == @expected
+ end
+
+ def failure_message
+ "expected #{relative_expectation} #{collection_name}, got #{@actual}"
+ end
+
+ def negative_failure_message
+ if @relativity == :exactly
+ return "expected target not to have #{@expected} #{collection_name}, got #{@actual}"
+ elsif @relativity == :at_most
+ return <<-EOF
+Isn't life confusing enough?
+Instead of having to figure out the meaning of this:
+ should_not have_at_most(#{@expected}).#{collection_name}
+We recommend that you use this instead:
+ should have_at_least(#{@expected + 1}).#{collection_name}
+EOF
+ elsif @relativity == :at_least
+ return <<-EOF
+Isn't life confusing enough?
+Instead of having to figure out the meaning of this:
+ should_not have_at_least(#{@expected}).#{collection_name}
+We recommend that you use this instead:
+ should have_at_most(#{@expected - 1}).#{collection_name}
+EOF
+ end
+ end
+
+ def description
+ "have #{relative_expectation} #{collection_name}"
+ end
+
+ private
+ def collection_name
+ @collection_name
+ end
+
+ def relative_expectation
+ "#{relativities[@relativity]}#{@expected}"
+ end
+ end
+
+ # :call-seq:
+ # should have(number).named_collection__or__sugar
+ # should_not have(number).named_collection__or__sugar
+ #
+ # Passes if receiver is a collection with the submitted
+ # number of items OR if the receiver OWNS a collection
+ # with the submitted number of items.
+ #
+ # If the receiver OWNS the collection, you must use the name
+ # of the collection. So if a <tt>Team</tt> instance has a
+ # collection named <tt>#players</tt>, you must use that name
+ # to set the expectation.
+ #
+ # If the receiver IS the collection, you can use any name
+ # you like for <tt>named_collection</tt>. We'd recommend using
+ # either "elements", "members", or "items" as these are all
+ # standard ways of describing the things IN a collection.
+ #
+ # This also works for Strings, letting you set an expectation
+ # about its length
+ #
+ # == Examples
+ #
+ # # Passes if team.players.size == 11
+ # team.should have(11).players
+ #
+ # # Passes if [1,2,3].length == 3
+ # [1,2,3].should have(3).items #"items" is pure sugar
+ #
+ # # Passes if "this string".length == 11
+ # "this string".should have(11).characters #"characters" is pure sugar
+ def have(n)
+ Matchers::Have.new(n)
+ end
+ alias :have_exactly :have
+
+ # :call-seq:
+ # should have_at_least(number).items
+ #
+ # Exactly like have() with >=.
+ #
+ # == Warning
+ #
+ # +should_not+ +have_at_least+ is not supported
+ def have_at_least(n)
+ Matchers::Have.new(n, :at_least)
+ end
+
+ # :call-seq:
+ # should have_at_most(number).items
+ #
+ # Exactly like have() with <=.
+ #
+ # == Warning
+ #
+ # +should_not+ +have_at_most+ is not supported
+ def have_at_most(n)
+ Matchers::Have.new(n, :at_most)
+ end
+ end
+end \ No newline at end of file