rspec-expectations 2.0.0.a1

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.
Files changed (55) hide show
  1. data/.document +5 -0
  2. data/.gitignore +5 -0
  3. data/License.txt +22 -0
  4. data/README.markdown +8 -0
  5. data/Rakefile +43 -0
  6. data/VERSION +1 -0
  7. data/VERSION.yml +5 -0
  8. data/lib/rspec/expectations.rb +36 -0
  9. data/lib/rspec/expectations/differs/default.rb +62 -0
  10. data/lib/rspec/expectations/differs/load-diff-lcs.rb +12 -0
  11. data/lib/rspec/expectations/errors.rb +12 -0
  12. data/lib/rspec/expectations/extensions.rb +1 -0
  13. data/lib/rspec/expectations/extensions/kernel.rb +52 -0
  14. data/lib/rspec/expectations/fail_with.rb +43 -0
  15. data/lib/rspec/expectations/handler.rb +50 -0
  16. data/lib/rspec/matchers.rb +195 -0
  17. data/lib/rspec/matchers/be.rb +210 -0
  18. data/lib/rspec/matchers/be_close.rb +32 -0
  19. data/lib/rspec/matchers/be_instance_of.rb +26 -0
  20. data/lib/rspec/matchers/be_kind_of.rb +26 -0
  21. data/lib/rspec/matchers/change.rb +151 -0
  22. data/lib/rspec/matchers/compatibility.rb +14 -0
  23. data/lib/rspec/matchers/dsl.rb +14 -0
  24. data/lib/rspec/matchers/eql.rb +42 -0
  25. data/lib/rspec/matchers/equal.rb +53 -0
  26. data/lib/rspec/matchers/errors.rb +5 -0
  27. data/lib/rspec/matchers/exist.rb +16 -0
  28. data/lib/rspec/matchers/extensions/instance_exec.rb +23 -0
  29. data/lib/rspec/matchers/generated_descriptions.rb +36 -0
  30. data/lib/rspec/matchers/has.rb +35 -0
  31. data/lib/rspec/matchers/have.rb +151 -0
  32. data/lib/rspec/matchers/include.rb +44 -0
  33. data/lib/rspec/matchers/match.rb +21 -0
  34. data/lib/rspec/matchers/match_array.rb +71 -0
  35. data/lib/rspec/matchers/matcher.rb +86 -0
  36. data/lib/rspec/matchers/method_missing.rb +9 -0
  37. data/lib/rspec/matchers/operator_matcher.rb +78 -0
  38. data/lib/rspec/matchers/pretty.rb +37 -0
  39. data/lib/rspec/matchers/raise_error.rb +129 -0
  40. data/lib/rspec/matchers/respond_to.rb +71 -0
  41. data/lib/rspec/matchers/satisfy.rb +47 -0
  42. data/lib/rspec/matchers/simple_matcher.rb +133 -0
  43. data/lib/rspec/matchers/throw_symbol.rb +104 -0
  44. data/lib/rspec/matchers/wrap_expectation.rb +55 -0
  45. data/rspec-expectations.gemspec +104 -0
  46. data/spec/rspec/expectations/differs/default_spec.rb +128 -0
  47. data/spec/rspec/expectations/extensions/kernel_spec.rb +45 -0
  48. data/spec/rspec/expectations/fail_with_spec.rb +88 -0
  49. data/spec/rspec/expectations/handler_spec.rb +206 -0
  50. data/spec/rspec/expectations/wrap_expectation_spec.rb +30 -0
  51. data/spec/spec.opts +6 -0
  52. data/spec/spec_helper.rb +31 -0
  53. data/spec/suite.rb +1 -0
  54. data/spec/support/macros.rb +29 -0
  55. metadata +135 -0
@@ -0,0 +1,14 @@
1
+ Rspec::Matchers.constants.each do |c|
2
+ if Class === (klass = Rspec::Matchers.const_get(c))
3
+ if klass.public_instance_methods.any? {|m| ['failure_message_for_should',:failure_message_for_should].include?(m)}
4
+ klass.class_eval do
5
+ alias_method :failure_message, :failure_message_for_should
6
+ end
7
+ end
8
+ if klass.public_instance_methods.any? {|m| ['failure_message_for_should_not',:failure_message_for_should_not].include?(m)}
9
+ klass.class_eval do
10
+ alias_method :negative_failure_message, :failure_message_for_should_not
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,14 @@
1
+ module Rspec
2
+ module Matchers
3
+ module DSL
4
+ # See Rspec::Matchers
5
+ def define(name, &declarations)
6
+ define_method name do |*expected|
7
+ Rspec::Matchers::Matcher.new name, *expected, &declarations
8
+ end
9
+ end
10
+ end
11
+ end
12
+ end
13
+
14
+ Rspec::Matchers.extend Rspec::Matchers::DSL
@@ -0,0 +1,42 @@
1
+ module Rspec
2
+ module Matchers
3
+ # :call-seq:
4
+ # should eql(expected)
5
+ # should_not eql(expected)
6
+ #
7
+ # Passes if actual and expected are of equal value, but not necessarily the same object.
8
+ #
9
+ # See http://www.ruby-doc.org/core/classes/Object.html#M001057 for more information about equality in Ruby.
10
+ #
11
+ # == Examples
12
+ #
13
+ # 5.should eql(5)
14
+ # 5.should_not eql(3)
15
+ def eql(expected)
16
+ Matcher.new :eql, expected do |_expected_|
17
+ match do |actual|
18
+ actual.eql?(_expected_)
19
+ end
20
+
21
+ failure_message_for_should do |actual|
22
+ <<-MESSAGE
23
+
24
+ expected #{_expected_.inspect}
25
+ got #{actual.inspect}
26
+
27
+ (compared using eql?)
28
+ MESSAGE
29
+ end
30
+
31
+ failure_message_for_should_not do |actual|
32
+ <<-MESSAGE
33
+
34
+ expected #{actual.inspect} not to equal #{_expected_.inspect}
35
+
36
+ (compared using eql?)
37
+ MESSAGE
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,53 @@
1
+ module Rspec
2
+ module Matchers
3
+
4
+ # :call-seq:
5
+ # should equal(expected)
6
+ # should_not equal(expected)
7
+ #
8
+ # Passes if actual and expected are the same object (object identity).
9
+ #
10
+ # See http://www.ruby-doc.org/core/classes/Object.html#M001057 for more information about equality in Ruby.
11
+ #
12
+ # == Examples
13
+ #
14
+ # 5.should equal(5) #Fixnums are equal
15
+ # "5".should_not equal("5") #Strings that look the same are not the same object
16
+ def equal(expected)
17
+ Matcher.new :equal, expected do |_expected_|
18
+ match do |actual|
19
+ actual.equal?(_expected_)
20
+ end
21
+
22
+ def inspect_object(o)
23
+ "#<#{o.class}:#{o.object_id}> => #{o.inspect}"
24
+ end
25
+
26
+ failure_message_for_should do |actual|
27
+ <<-MESSAGE
28
+
29
+ expected #{inspect_object(_expected_)}
30
+ got #{inspect_object(actual)}
31
+
32
+ Compared using equal?, which compares object identity,
33
+ but expected and actual are not the same object. Use
34
+ 'actual.should == expected' if you don't care about
35
+ object identity in this example.
36
+
37
+ MESSAGE
38
+ end
39
+
40
+ failure_message_for_should_not do |actual|
41
+ <<-MESSAGE
42
+
43
+ expected not #{inspect_object(actual)}
44
+ got #{inspect_object(_expected_)}
45
+
46
+ Compared using equal?, which compares object identity.
47
+
48
+ MESSAGE
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,5 @@
1
+ module Rspec
2
+ module Matchers
3
+ class MatcherError < StandardError; end
4
+ end
5
+ end
@@ -0,0 +1,16 @@
1
+ module Rspec
2
+ module Matchers
3
+ # :call-seq:
4
+ # should exist
5
+ # should_not exist
6
+ #
7
+ # Passes if actual.exist?
8
+ def exist
9
+ Matcher.new :exist do
10
+ match do |actual|
11
+ actual.exist?
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,23 @@
1
+ unless respond_to?(:instance_exec)
2
+ # based on Bounded Spec InstanceExec (Mauricio Fernandez)
3
+ # http://eigenclass.org/hiki/bounded+space+instance_exec
4
+ class Object
5
+ module InstanceExecHelper; end
6
+ include InstanceExecHelper
7
+ def instance_exec(*args, &block)
8
+ begin
9
+ orig_critical, Thread.critical = Thread.critical, true
10
+ n = 0
11
+ n += 1 while respond_to?(method_name="__instance_exec#{n}")
12
+ InstanceExecHelper.module_eval{ define_method(method_name, &block) }
13
+ ensure
14
+ Thread.critical = orig_critical
15
+ end
16
+ begin
17
+ return send(method_name, *args)
18
+ ensure
19
+ InstanceExecHelper.module_eval{ remove_method(method_name) } rescue nil
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,36 @@
1
+ module Rspec
2
+ module Matchers
3
+ class << self
4
+ attr_accessor :last_matcher, :last_should # :nodoc:
5
+ end
6
+
7
+ def self.clear_generated_description
8
+ self.last_matcher = nil
9
+ self.last_should = nil
10
+ end
11
+
12
+ def self.generated_description
13
+ return nil if last_should.nil?
14
+ "#{last_should.to_s.gsub('_',' ')} #{last_description}"
15
+ end
16
+
17
+ private
18
+
19
+ def self.last_description
20
+ last_matcher.respond_to?(:description) ? last_matcher.description : <<-MESSAGE
21
+ When you call a matcher in an example without a String, like this:
22
+
23
+ specify { object.should matcher }
24
+
25
+ or this:
26
+
27
+ it { should matcher }
28
+
29
+ RSpec expects the matcher to have a #description method. You should either
30
+ add a String to the example this matcher is being used in, or give it a
31
+ description method. Then you won't have to suffer this lengthy warning again.
32
+ MESSAGE
33
+ end
34
+ end
35
+ end
36
+
@@ -0,0 +1,35 @@
1
+ module Rspec
2
+ module Matchers
3
+
4
+ class Has
5
+
6
+ def initialize(expected, *args)
7
+ @expected, @args = expected, args
8
+ end
9
+
10
+ def matches?(actual)
11
+ actual.__send__(predicate(@expected), *@args)
12
+ end
13
+
14
+ def failure_message_for_should
15
+ "expected ##{predicate(@expected)}(#{@args[0].inspect}) to return true, got false"
16
+ end
17
+
18
+ def failure_message_for_should_not
19
+ "expected ##{predicate(@expected)}(#{@args[0].inspect}) to return false, got true"
20
+ end
21
+
22
+ def description
23
+ "have key #{@args[0].inspect}"
24
+ end
25
+
26
+ private
27
+
28
+ def predicate(sym)
29
+ "#{sym.to_s.sub("have_","has_")}?".to_sym
30
+ end
31
+
32
+ end
33
+
34
+ end
35
+ end
@@ -0,0 +1,151 @@
1
+ module Rspec
2
+ module Matchers
3
+ class Have #:nodoc:
4
+ def initialize(expected, relativity=:exactly)
5
+ @expected = (expected == :no ? 0 : expected)
6
+ @relativity = relativity
7
+ @actual = nil
8
+ end
9
+
10
+ def relativities
11
+ @relativities ||= {
12
+ :exactly => "",
13
+ :at_least => "at least ",
14
+ :at_most => "at most "
15
+ }
16
+ end
17
+
18
+ def matches?(collection_owner)
19
+ if collection_owner.respond_to?(@collection_name)
20
+ collection = collection_owner.__send__(@collection_name, *@args, &@block)
21
+ elsif (@plural_collection_name && collection_owner.respond_to?(@plural_collection_name))
22
+ collection = collection_owner.__send__(@plural_collection_name, *@args, &@block)
23
+ elsif (collection_owner.respond_to?(:length) || collection_owner.respond_to?(:size))
24
+ collection = collection_owner
25
+ else
26
+ collection_owner.__send__(@collection_name, *@args, &@block)
27
+ end
28
+ @actual = collection.size if collection.respond_to?(:size)
29
+ @actual = collection.length if collection.respond_to?(:length)
30
+ raise not_a_collection if @actual.nil?
31
+ return @actual >= @expected if @relativity == :at_least
32
+ return @actual <= @expected if @relativity == :at_most
33
+ return @actual == @expected
34
+ end
35
+
36
+ def not_a_collection
37
+ "expected #{@collection_name} to be a collection but it does not respond to #length or #size"
38
+ end
39
+
40
+ def failure_message_for_should
41
+ "expected #{relative_expectation} #{@collection_name}, got #{@actual}"
42
+ end
43
+
44
+ def failure_message_for_should_not
45
+ if @relativity == :exactly
46
+ return "expected target not to have #{@expected} #{@collection_name}, got #{@actual}"
47
+ elsif @relativity == :at_most
48
+ return <<-EOF
49
+ Isn't life confusing enough?
50
+ Instead of having to figure out the meaning of this:
51
+ should_not have_at_most(#{@expected}).#{@collection_name}
52
+ We recommend that you use this instead:
53
+ should have_at_least(#{@expected + 1}).#{@collection_name}
54
+ EOF
55
+ elsif @relativity == :at_least
56
+ return <<-EOF
57
+ Isn't life confusing enough?
58
+ Instead of having to figure out the meaning of this:
59
+ should_not have_at_least(#{@expected}).#{@collection_name}
60
+ We recommend that you use this instead:
61
+ should have_at_most(#{@expected - 1}).#{@collection_name}
62
+ EOF
63
+ end
64
+ end
65
+
66
+ def description
67
+ "have #{relative_expectation} #{@collection_name}"
68
+ end
69
+
70
+ def respond_to?(sym)
71
+ @expected.respond_to?(sym) || super
72
+ end
73
+
74
+ private
75
+
76
+ def method_missing(sym, *args, &block)
77
+ @collection_name = sym
78
+ if inflector = (defined?(ActiveSupport::Inflector) ? ActiveSupport::Inflector : (defined?(Inflector) ? Inflector : nil))
79
+ @plural_collection_name = inflector.pluralize(sym.to_s)
80
+ end
81
+ @args = args
82
+ @block = block
83
+ self
84
+ end
85
+
86
+ def relative_expectation
87
+ "#{relativities[@relativity]}#{@expected}"
88
+ end
89
+ end
90
+
91
+ # :call-seq:
92
+ # should have(number).named_collection__or__sugar
93
+ # should_not have(number).named_collection__or__sugar
94
+ #
95
+ # Passes if receiver is a collection with the submitted
96
+ # number of items OR if the receiver OWNS a collection
97
+ # with the submitted number of items.
98
+ #
99
+ # If the receiver OWNS the collection, you must use the name
100
+ # of the collection. So if a <tt>Team</tt> instance has a
101
+ # collection named <tt>#players</tt>, you must use that name
102
+ # to set the expectation.
103
+ #
104
+ # If the receiver IS the collection, you can use any name
105
+ # you like for <tt>named_collection</tt>. We'd recommend using
106
+ # either "elements", "members", or "items" as these are all
107
+ # standard ways of describing the things IN a collection.
108
+ #
109
+ # This also works for Strings, letting you set an expectation
110
+ # about its length
111
+ #
112
+ # == Examples
113
+ #
114
+ # # Passes if team.players.size == 11
115
+ # team.should have(11).players
116
+ #
117
+ # # Passes if [1,2,3].length == 3
118
+ # [1,2,3].should have(3).items #"items" is pure sugar
119
+ #
120
+ # # Passes if "this string".length == 11
121
+ # "this string".should have(11).characters #"characters" is pure sugar
122
+ def have(n)
123
+ Matchers::Have.new(n)
124
+ end
125
+ alias :have_exactly :have
126
+
127
+ # :call-seq:
128
+ # should have_at_least(number).items
129
+ #
130
+ # Exactly like have() with >=.
131
+ #
132
+ # == Warning
133
+ #
134
+ # +should_not+ +have_at_least+ is not supported
135
+ def have_at_least(n)
136
+ Matchers::Have.new(n, :at_least)
137
+ end
138
+
139
+ # :call-seq:
140
+ # should have_at_most(number).items
141
+ #
142
+ # Exactly like have() with <=.
143
+ #
144
+ # == Warning
145
+ #
146
+ # +should_not+ +have_at_most+ is not supported
147
+ def have_at_most(n)
148
+ Matchers::Have.new(n, :at_most)
149
+ end
150
+ end
151
+ end
@@ -0,0 +1,44 @@
1
+ module Rspec
2
+ module Matchers
3
+ # :call-seq:
4
+ # should include(expected)
5
+ # should_not include(expected)
6
+ #
7
+ # Passes if actual includes expected. This works for
8
+ # collections and Strings. You can also pass in multiple args
9
+ # and it will only pass if all args are found in collection.
10
+ #
11
+ # == Examples
12
+ #
13
+ # [1,2,3].should include(3)
14
+ # [1,2,3].should include(2,3) #would pass
15
+ # [1,2,3].should include(2,3,4) #would fail
16
+ # [1,2,3].should_not include(4)
17
+ # "spread".should include("read")
18
+ # "spread".should_not include("red")
19
+ def include(*expected)
20
+ Matcher.new :include, *expected do |*_expected_|
21
+ match do |actual|
22
+ helper(actual, *_expected_)
23
+ end
24
+
25
+ def helper(actual, *_expected_)
26
+ _expected_.each do |expected|
27
+ if actual.is_a?(Hash)
28
+ if expected.is_a?(Hash)
29
+ expected.each_pair do |k,v|
30
+ return false unless actual[k] == v
31
+ end
32
+ else
33
+ return false unless actual.has_key?(expected)
34
+ end
35
+ else
36
+ return false unless actual.include?(expected)
37
+ end
38
+ end
39
+ true
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end