Permalink
Browse files

First time with rspec and cukes specs on green

  • Loading branch information...
hugobarauna committed Jul 21, 2013
1 parent 266ff41 commit f2863caaf83907a271985101782baba6defe0a32
View
@@ -0,0 +1,18 @@
+*.sw?
+.DS_Store
+coverage*
+rdoc
+pkg
+doc
+tmp
+rerun.txt
+Gemfile.lock
+.bundle
+*.rbc
+.yardoc
+bin
+.rbx
+Gemfile-custom
+bundle
+.rspec-local
+Guardfile
View
2 .rspec
@@ -0,0 +1,2 @@
+--format documentation
+--color
View
@@ -11,3 +11,5 @@ gemspec
gem lib, :git => "git://github.com/rspec/#{lib}.git"
end
end
+
+eval File.read('Gemfile-custom') if File.exist?('Gemfile-custom')
View
@@ -0,0 +1,113 @@
+Feature: have(n).items matcher
+
+ RSpec provides several matchers that make it easy to set expectations about the
+ size of a collection. There are three basic forms:
+
+ ```ruby
+ collection.should have(x).items
+ collection.should have_at_least(x).items
+ collection.should have_at_most(x).items
+ ```
+
+ In addition, #have_exactly is provided as an alias to #have.
+
+ These work on any collection-like object--the object just needs to respond to #size
+ or #length (or both). When the matcher is called directly on a collection object,
+ the #items call is pure syntactic sugar. You can use anything you want here. These
+ are equivalent:
+
+ ```ruby
+ collection.should have(x).items
+ collection.should have(x).things
+ ```
+
+ You can also use this matcher on a non-collection object that returns a collection
+ from one of its methods. For example, Dir#entries returns an array, so you could
+ set an expectation using the following:
+
+ ```ruby
+ Dir.new("my/directory").should have(7).entries
+ ```
+
+ Scenario: have(x).items on a collection
+ Given a file named "have_items_spec.rb" with:
+ """ruby
+ require 'rspec/collection_matchers'
+
+ describe [1, 2, 3] do
+ it { should have(3).items }
+ it { should_not have(2).items }
+ it { should_not have(4).items }
+
+ it { should have_exactly(3).items }
+ it { should_not have_exactly(2).items }
+ it { should_not have_exactly(4).items }
+
+ it { should have_at_least(2).items }
+ it { should have_at_most(4).items }
+
+ # deliberate failures
+ it { should_not have(3).items }
+ it { should have(2).items }
+ it { should have(4).items }
+
+ it { should_not have_exactly(3).items }
+ it { should have_exactly(2).items }
+ it { should have_exactly(4).items }
+
+ it { should have_at_least(4).items }
+ it { should have_at_most(2).items }
+ end
+ """
+ When I run `rspec have_items_spec.rb`
+ Then the output should contain "16 examples, 8 failures"
+ And the output should contain "expected target not to have 3 items, got 3"
+ And the output should contain "expected 2 items, got 3"
+ And the output should contain "expected 4 items, got 3"
+ And the output should contain "expected at least 4 items, got 3"
+ And the output should contain "expected at most 2 items, got 3"
+
+ Scenario: have(x).words on a String when String#words is defined
+ Given a file named "have_words_spec.rb" with:
+ """ruby
+ require 'rspec/collection_matchers'
+
+ class String
+ def words
+ split(' ')
+ end
+ end
+
+ describe "a sentence with some words" do
+ it { should have(5).words }
+ it { should_not have(4).words }
+ it { should_not have(6).words }
+
+ it { should have_exactly(5).words }
+ it { should_not have_exactly(4).words }
+ it { should_not have_exactly(6).words }
+
+ it { should have_at_least(4).words }
+ it { should have_at_most(6).words }
+
+ # deliberate failures
+ it { should_not have(5).words }
+ it { should have(4).words }
+ it { should have(6).words }
+
+ it { should_not have_exactly(5).words }
+ it { should have_exactly(4).words }
+ it { should have_exactly(6).words }
+
+ it { should have_at_least(6).words }
+ it { should have_at_most(4).words }
+ end
+ """
+ When I run `rspec have_words_spec.rb`
+ Then the output should contain "16 examples, 8 failures"
+ And the output should contain "expected target not to have 5 words, got 5"
+ And the output should contain "expected 4 words, got 5"
+ And the output should contain "expected 6 words, got 5"
+ And the output should contain "expected at least 6 words, got 5"
+ And the output should contain "expected at most 4 words, got 5"
+
View
@@ -0,0 +1 @@
+require 'aruba/cucumber'
@@ -1,7 +1,3 @@
-require "rspec/collection_matchers/version"
-
-module Rspec
- module CollectionMatchers
- # Your code goes here...
- end
-end
+require 'rspec/collection_matchers/version'
+require 'rspec/collection_matchers/dsl'
+require 'rspec/collection_matchers/have'
@@ -0,0 +1,65 @@
+module RSpec
+ module CollectionMatchers
+ module Dsl
+ # 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 `Team` instance has a collection named `#players`,
+ # you must use that name to set the expectation.
+ #
+ # If the receiver IS the collection, you can use any name you like for
+ # `named_collection`. 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 expectations about their
+ # lengths.
+ #
+ # @example
+ #
+ # # Passes if team.players.size == 11
+ # expect(team).to have(11).players
+ #
+ # # Passes if [1,2,3].length == 3
+ # expect([1,2,3]).to have(3).items #"items" is pure sugar
+ #
+ # # Passes if ['a', 'b', 'c'].count == 3
+ # expect([1,2,3]).to have(3).items #"items" is pure sugar
+ #
+ # # Passes if "this string".length == 11
+ # expect("this string").to have(11).characters #"characters" is pure sugar
+ def have(n)
+ RSpec::CollectionMatchers::Have.new(n)
+ end
+ alias :have_exactly :have
+
+ # Exactly like have() with >=.
+ #
+ # @example
+ # expect("this").to have_at_least(3).letters
+ #
+ # ### Warning:
+ #
+ # `expect(..).not_to have_at_least` is not supported
+ def have_at_least(n)
+ RSpec::CollectionMatchers::Have.new(n, :at_least)
+ end
+
+ # Exactly like have() with <=.
+ #
+ # @example
+ # expect("this").to have_at_most(4).letters
+ #
+ # ### Warning:
+ #
+ # `expect(..).not_to have_at_most` is not supported
+ def have_at_most(n)
+ RSpec::CollectionMatchers::Have.new(n, :at_most)
+ end
+
+ end
+ end
+end
+
+RSpec::Matchers.send(:include, RSpec::CollectionMatchers::Dsl)
@@ -0,0 +1,122 @@
+module RSpec
+ module CollectionMatchers
+ class Have
+ QUERY_METHODS = [:size, :length, :count].freeze
+
+ def initialize(expected, relativity=:exactly)
+ @expected = case expected
+ when :no then 0
+ when String then expected.to_i
+ else expected
+ end
+ @relativity = relativity
+ @actual = @collection_name = @plural_collection_name = nil
+ end
+
+ def relativities
+ @relativities ||= {
+ :exactly => "",
+ :at_least => "at least ",
+ :at_most => "at most "
+ }
+ end
+
+ def matches?(collection_or_owner)
+ collection = determine_collection(collection_or_owner)
+ case collection
+ when enumerator_class
+ for query_method in QUERY_METHODS
+ next unless collection.respond_to?(query_method)
+ @actual = collection.__send__(query_method)
+ break unless @actual.nil?
+ end
+ raise not_a_collection if @actual.nil?
+ else
+ query_method = determine_query_method(collection)
+ raise not_a_collection unless query_method
+ @actual = collection.__send__(query_method)
+ end
+ case @relativity
+ when :at_least then @actual >= @expected
+ when :at_most then @actual <= @expected
+ else @actual == @expected
+ end
+ end
+ alias == matches?
+
+ def determine_collection(collection_or_owner)
+ if collection_or_owner.respond_to?(@collection_name)
+ collection_or_owner.__send__(@collection_name, *@args, &@block)
+ elsif (@plural_collection_name && collection_or_owner.respond_to?(@plural_collection_name))
+ collection_or_owner.__send__(@plural_collection_name, *@args, &@block)
+ elsif determine_query_method(collection_or_owner)
+ collection_or_owner
+ else
+ collection_or_owner.__send__(@collection_name, *@args, &@block)
+ end
+ end
+
+ def determine_query_method(collection)
+ QUERY_METHODS.detect {|m| collection.respond_to?(m)}
+ end
+
+ def not_a_collection
+ "expected #{@collection_name} to be a collection but it does not respond to #length, #size or #count"
+ end
+
+ def failure_message_for_should
+ "expected #{relative_expectation} #{@collection_name}, got #{@actual}"
+ end
+
+ def failure_message_for_should_not
+ 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:
+ #{Expectations::Syntax.negative_expression("actual", "have_at_most(#{@expected}).#{@collection_name}")}
+We recommend that you use this instead:
+ #{Expectations::Syntax.positive_expression("actual", "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:
+ #{Expectations::Syntax.negative_expression("actual", "have_at_least(#{@expected}).#{@collection_name}")}
+We recommend that you use this instead:
+ #{Expectations::Syntax.positive_expression("actual", "have_at_most(#{@expected - 1}).#{@collection_name}")}
+EOF
+ end
+ end
+
+ def description
+ "have #{relative_expectation} #{@collection_name}"
+ end
+
+ def respond_to?(m)
+ @expected.respond_to?(m) || super
+ end
+
+ private
+
+ def method_missing(method, *args, &block)
+ @collection_name = method
+ if inflector = (defined?(ActiveSupport::Inflector) && ActiveSupport::Inflector.respond_to?(:pluralize) ? ActiveSupport::Inflector : (defined?(Inflector) ? Inflector : nil))
+ @plural_collection_name = inflector.pluralize(method.to_s)
+ end
+ @args = args
+ @block = block
+ self
+ end
+
+ def relative_expectation
+ "#{relativities[@relativity]}#{@expected}"
+ end
+
+ def enumerator_class
+ RUBY_VERSION < '1.9' ? Enumerable::Enumerator : Enumerator
+ end
+ end
+ end
+end
@@ -1,4 +1,4 @@
-module Rspec
+module RSpec
module CollectionMatchers
VERSION = "0.0.1"
end
@@ -5,11 +5,11 @@ require 'rspec/collection_matchers/version'
Gem::Specification.new do |spec|
spec.name = "rspec-collection_matchers"
- spec.version = Rspec::CollectionMatchers::VERSION
+ spec.version = RSpec::CollectionMatchers::VERSION
spec.authors = ["Hugo Baraúna"]
spec.email = ["hugo.barauna@plataformatec.com.br"]
- spec.description = %q{TODO: Write a gem description}
- spec.summary = %q{TODO: Write a gem summary}
+ spec.summary = "rspec-collection_matchers-#{RSpec::CollectionMatchers::VERSION}"
+ spec.description = "rspec have(n).items matchers"
spec.homepage = ""
spec.license = "MIT"
@@ -20,7 +20,9 @@ Gem::Specification.new do |spec|
spec.add_runtime_dependency "rspec-expectations", ">= 2.14.0"
- spec.add_development_dependency "bundler", "~> 1.3"
- spec.add_development_dependency "rake"
- spec.add_development_dependency "rspec-core"
+ spec.add_development_dependency "bundler", "~> 1.3"
+ spec.add_development_dependency "rake", "~> 10.0.0"
+ spec.add_development_dependency "rspec-core", ">= 2.14.0"
+ spec.add_development_dependency "cucumber", "~> 1.1.9"
+ spec.add_development_dependency "aruba", "~> 0.5"
end
Oops, something went wrong.

0 comments on commit f2863ca

Please sign in to comment.