diff options
Diffstat (limited to 'test/lib/spec/matchers/have.rb')
-rw-r--r-- | test/lib/spec/matchers/have.rb | 140 |
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 |