rspec-expectations 2.8.0 → 2.9.0.rc2

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 (68) hide show
  1. data/.document +5 -0
  2. data/.yardopts +3 -0
  3. data/Changelog.md +176 -0
  4. data/README.md +2 -13
  5. data/features/custom_matchers/access_running_example.feature +1 -1
  6. data/features/step_definitions/additional_cli_steps.rb +4 -4
  7. data/lib/rspec/expectations/fail_with.rb +3 -3
  8. data/lib/rspec/expectations/handler.rb +3 -5
  9. data/lib/rspec/expectations/version.rb +1 -1
  10. data/lib/rspec/matchers.rb +387 -21
  11. data/lib/rspec/matchers/built_in.rb +33 -0
  12. data/lib/rspec/matchers/built_in/base_matcher.rb +58 -0
  13. data/lib/rspec/matchers/built_in/be.rb +183 -0
  14. data/lib/rspec/matchers/built_in/be_instance_of.rb +13 -0
  15. data/lib/rspec/matchers/built_in/be_kind_of.rb +13 -0
  16. data/lib/rspec/matchers/built_in/be_within.rb +39 -0
  17. data/lib/rspec/matchers/built_in/change.rb +132 -0
  18. data/lib/rspec/matchers/built_in/cover.rb +22 -0
  19. data/lib/rspec/matchers/built_in/eq.rb +26 -0
  20. data/lib/rspec/matchers/built_in/eql.rb +25 -0
  21. data/lib/rspec/matchers/built_in/equal.rb +48 -0
  22. data/lib/rspec/matchers/built_in/exist.rb +28 -0
  23. data/lib/rspec/matchers/built_in/has.rb +47 -0
  24. data/lib/rspec/matchers/built_in/have.rb +107 -0
  25. data/lib/rspec/matchers/built_in/include.rb +52 -0
  26. data/lib/rspec/matchers/built_in/match.rb +13 -0
  27. data/lib/rspec/matchers/built_in/match_array.rb +52 -0
  28. data/lib/rspec/matchers/built_in/raise_error.rb +96 -0
  29. data/lib/rspec/matchers/built_in/respond_to.rb +73 -0
  30. data/lib/rspec/matchers/built_in/satisfy.rb +29 -0
  31. data/lib/rspec/matchers/built_in/throw_symbol.rb +93 -0
  32. data/lib/rspec/matchers/dsl.rb +1 -1
  33. data/lib/rspec/matchers/matcher.rb +263 -233
  34. data/lib/rspec/matchers/method_missing.rb +2 -2
  35. data/lib/rspec/matchers/operator_matcher.rb +19 -20
  36. data/spec/rspec/expectations/handler_spec.rb +1 -1
  37. data/spec/rspec/matchers/base_matcher_spec.rb +1 -2
  38. data/spec/rspec/matchers/change_spec.rb +3 -3
  39. data/spec/rspec/matchers/cover_spec.rb +46 -46
  40. data/spec/rspec/matchers/dsl_spec.rb +36 -3
  41. data/spec/rspec/matchers/have_spec.rb +2 -2
  42. data/spec/rspec/matchers/include_spec.rb +1 -1
  43. data/spec/rspec/matchers/matcher_spec.rb +319 -305
  44. data/spec/rspec/matchers/method_missing_spec.rb +1 -0
  45. data/spec/rspec/matchers/operator_matcher_spec.rb +2 -2
  46. data/spec/rspec/matchers/throw_symbol_spec.rb +103 -105
  47. metadata +93 -39
  48. data/lib/rspec/matchers/base_matcher.rb +0 -56
  49. data/lib/rspec/matchers/be.rb +0 -232
  50. data/lib/rspec/matchers/be_instance_of.rb +0 -24
  51. data/lib/rspec/matchers/be_kind_of.rb +0 -24
  52. data/lib/rspec/matchers/be_within.rb +0 -47
  53. data/lib/rspec/matchers/change.rb +0 -197
  54. data/lib/rspec/matchers/cover.rb +0 -36
  55. data/lib/rspec/matchers/eq.rb +0 -36
  56. data/lib/rspec/matchers/eql.rb +0 -35
  57. data/lib/rspec/matchers/equal.rb +0 -58
  58. data/lib/rspec/matchers/errors.rb +0 -5
  59. data/lib/rspec/matchers/exist.rb +0 -34
  60. data/lib/rspec/matchers/has.rb +0 -44
  61. data/lib/rspec/matchers/have.rb +0 -162
  62. data/lib/rspec/matchers/include.rb +0 -66
  63. data/lib/rspec/matchers/match.rb +0 -21
  64. data/lib/rspec/matchers/match_array.rb +0 -65
  65. data/lib/rspec/matchers/raise_error.rb +0 -116
  66. data/lib/rspec/matchers/respond_to.rb +0 -80
  67. data/lib/rspec/matchers/satisfy.rb +0 -46
  68. data/lib/rspec/matchers/throw_symbol.rb +0 -112
@@ -0,0 +1,22 @@
1
+ module RSpec
2
+ module Matchers
3
+ module BuiltIn
4
+ class Cover
5
+ include BaseMatcher
6
+
7
+ def initialize(*expected)
8
+ super(expected)
9
+ end
10
+
11
+ def matches?(range)
12
+ expected.all? {|e| super(range).cover?(e)}
13
+ end
14
+
15
+ def does_not_match?(range)
16
+ @actual = range
17
+ expected.none? {|e| range.cover?(e)}
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,26 @@
1
+ module RSpec
2
+ module Matchers
3
+ module BuiltIn
4
+ class Eq
5
+ include BaseMatcher
6
+
7
+ def matches?(actual)
8
+ super(actual) == expected
9
+ end
10
+
11
+ def failure_message_for_should
12
+ "\nexpected: #{expected.inspect}\n got: #{actual.inspect}\n\n(compared using ==)\n"
13
+ end
14
+
15
+ def failure_message_for_should_not
16
+ "\nexpected: value != #{expected.inspect}\n got: #{actual.inspect}\n\n(compared using ==)\n"
17
+ end
18
+
19
+ def diffable?
20
+ true
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
26
+
@@ -0,0 +1,25 @@
1
+ module RSpec
2
+ module Matchers
3
+ module BuiltIn
4
+ class Eql
5
+ include BaseMatcher
6
+
7
+ def matches?(actual)
8
+ super(actual).eql?(expected)
9
+ end
10
+
11
+ def failure_message_for_should
12
+ "\nexpected: #{expected.inspect}\n got: #{actual.inspect}\n\n(compared using eql?)\n"
13
+ end
14
+
15
+ def failure_message_for_should_not
16
+ "\nexpected: value != #{expected.inspect}\n got: #{actual.inspect}\n\n(compared using eql?)\n"
17
+ end
18
+
19
+ def diffable?
20
+ true
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,48 @@
1
+ module RSpec
2
+ module Matchers
3
+ module BuiltIn
4
+ class Equal
5
+ include BaseMatcher
6
+
7
+ def matches?(actual)
8
+ super(actual).equal?(expected)
9
+ end
10
+
11
+ def failure_message_for_should
12
+ return <<-MESSAGE
13
+
14
+ expected #{inspect_object(expected)}
15
+ got #{inspect_object(actual)}
16
+
17
+ Compared using equal?, which compares object identity,
18
+ but expected and actual are not the same object. Use
19
+ 'actual.should == expected' if you don't care about
20
+ object identity in this example.
21
+
22
+ MESSAGE
23
+ end
24
+
25
+ def failure_message_for_should_not
26
+ return <<-MESSAGE
27
+
28
+ expected not #{inspect_object(actual)}
29
+ got #{inspect_object(expected)}
30
+
31
+ Compared using equal?, which compares object identity.
32
+
33
+ MESSAGE
34
+ end
35
+
36
+ def diffable?
37
+ true
38
+ end
39
+
40
+ private
41
+
42
+ def inspect_object(o)
43
+ "#<#{o.class}:#{o.object_id}> => #{o.inspect}"
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,28 @@
1
+ module RSpec
2
+ module Matchers
3
+ module BuiltIn
4
+ class Exist
5
+ include BaseMatcher
6
+
7
+ def initialize(*args)
8
+ super(args)
9
+ end
10
+
11
+ def matches?(actual)
12
+ super(actual)
13
+ predicates = [:exist?, :exists?].select { |p| actual.respond_to?(p) }
14
+ existance_values = predicates.map { |p| actual.send(p, *expected) }
15
+ uniq_truthy_values = existance_values.map { |v| !!v }.uniq
16
+
17
+ case uniq_truthy_values.size
18
+ when 0; raise NoMethodError.new("#{actual.inspect} does not respond to either #exist? or #exists?")
19
+ when 1; existance_values.first
20
+ else raise "#exist? and #exists? returned different values:\n\n" +
21
+ " exist?: #{existance_values.first}\n" +
22
+ "exists?: #{existance_values.last}"
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,47 @@
1
+ module RSpec
2
+ module Matchers
3
+ module BuiltIn
4
+ class Has
5
+ def initialize(expected, *args)
6
+ @expected, @args = expected, args
7
+ end
8
+
9
+ def matches?(actual)
10
+ actual.__send__(predicate(@expected), *@args)
11
+ end
12
+
13
+ def failure_message_for_should
14
+ "expected ##{predicate(@expected)}#{failure_message_args_description} to return true, got false"
15
+ end
16
+
17
+ def failure_message_for_should_not
18
+ "expected ##{predicate(@expected)}#{failure_message_args_description} to return false, got true"
19
+ end
20
+
21
+ def description
22
+ [method_description(@expected), args_description].compact.join(' ')
23
+ end
24
+
25
+ private
26
+
27
+ def predicate(sym)
28
+ "#{sym.to_s.sub("have_","has_")}?".to_sym
29
+ end
30
+
31
+ def method_description(method)
32
+ method.to_s.gsub('_', ' ')
33
+ end
34
+
35
+ def args_description
36
+ return nil if @args.empty?
37
+ @args.map { |arg| arg.inspect }.join(', ')
38
+ end
39
+
40
+ def failure_message_args_description
41
+ desc = args_description
42
+ "(#{desc})" if desc
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,107 @@
1
+ module RSpec
2
+ module Matchers
3
+ module BuiltIn
4
+ class Have
5
+ def initialize(expected, relativity=:exactly)
6
+ @expected = case expected
7
+ when :no then 0
8
+ when String then expected.to_i
9
+ else expected
10
+ end
11
+ @relativity = relativity
12
+ @actual = @collection_name = @plural_collection_name = nil
13
+ end
14
+
15
+ def relativities
16
+ @relativities ||= {
17
+ :exactly => "",
18
+ :at_least => "at least ",
19
+ :at_most => "at most "
20
+ }
21
+ end
22
+
23
+ def matches?(collection_or_owner)
24
+ collection = determine_collection(collection_or_owner)
25
+ query_method = determine_query_method(collection)
26
+ raise not_a_collection unless query_method
27
+ @actual = collection.send(query_method)
28
+ case @relativity
29
+ when :at_least then @actual >= @expected
30
+ when :at_most then @actual <= @expected
31
+ else @actual == @expected
32
+ end
33
+ end
34
+
35
+ def determine_collection(collection_or_owner)
36
+ if collection_or_owner.respond_to?(@collection_name)
37
+ collection_or_owner.send(@collection_name, *@args, &@block)
38
+ elsif (@plural_collection_name && collection_or_owner.respond_to?(@plural_collection_name))
39
+ collection_or_owner.send(@plural_collection_name, *@args, &@block)
40
+ elsif determine_query_method(collection_or_owner)
41
+ collection_or_owner
42
+ else
43
+ collection_or_owner.send(@collection_name, *@args, &@block)
44
+ end
45
+ end
46
+
47
+ def determine_query_method(collection)
48
+ [:size, :length, :count].detect {|m| collection.respond_to?(m)}
49
+ end
50
+
51
+ def not_a_collection
52
+ "expected #{@collection_name} to be a collection but it does not respond to #length, #size or #count"
53
+ end
54
+
55
+ def failure_message_for_should
56
+ "expected #{relative_expectation} #{@collection_name}, got #{@actual}"
57
+ end
58
+
59
+ def failure_message_for_should_not
60
+ if @relativity == :exactly
61
+ return "expected target not to have #{@expected} #{@collection_name}, got #{@actual}"
62
+ elsif @relativity == :at_most
63
+ return <<-EOF
64
+ Isn't life confusing enough?
65
+ Instead of having to figure out the meaning of this:
66
+ should_not have_at_most(#{@expected}).#{@collection_name}
67
+ We recommend that you use this instead:
68
+ should have_at_least(#{@expected + 1}).#{@collection_name}
69
+ EOF
70
+ elsif @relativity == :at_least
71
+ return <<-EOF
72
+ Isn't life confusing enough?
73
+ Instead of having to figure out the meaning of this:
74
+ should_not have_at_least(#{@expected}).#{@collection_name}
75
+ We recommend that you use this instead:
76
+ should have_at_most(#{@expected - 1}).#{@collection_name}
77
+ EOF
78
+ end
79
+ end
80
+
81
+ def description
82
+ "have #{relative_expectation} #{@collection_name}"
83
+ end
84
+
85
+ def respond_to?(m)
86
+ @expected.respond_to?(m) || super
87
+ end
88
+
89
+ private
90
+
91
+ def method_missing(method, *args, &block)
92
+ @collection_name = method
93
+ if inflector = (defined?(ActiveSupport::Inflector) && ActiveSupport::Inflector.respond_to?(:pluralize) ? ActiveSupport::Inflector : (defined?(Inflector) ? Inflector : nil))
94
+ @plural_collection_name = inflector.pluralize(method.to_s)
95
+ end
96
+ @args = args
97
+ @block = block
98
+ self
99
+ end
100
+
101
+ def relative_expectation
102
+ "#{relativities[@relativity]}#{@expected}"
103
+ end
104
+ end
105
+ end
106
+ end
107
+ end
@@ -0,0 +1,52 @@
1
+ module RSpec
2
+ module Matchers
3
+ module BuiltIn
4
+ class Include
5
+ include BaseMatcher
6
+
7
+ def initialize(*expected)
8
+ super(expected)
9
+ end
10
+
11
+ def matches?(actual)
12
+ perform_match(:all?, :all?, super(actual), expected)
13
+ end
14
+
15
+ def does_not_match?(actual)
16
+ @actual = actual
17
+ perform_match(:none?, :any?, actual, expected)
18
+ end
19
+
20
+ def description
21
+ "include#{expected_to_sentence}"
22
+ end
23
+
24
+ def diffable?
25
+ true
26
+ end
27
+
28
+ private
29
+
30
+ def perform_match(predicate, hash_predicate, actuals, expecteds)
31
+ expecteds.send(predicate) do |expected|
32
+ if comparing_hash_values?(actuals, expected)
33
+ expected.send(hash_predicate) {|k,v| actuals[k] == v}
34
+ elsif comparing_hash_keys?(actuals, expected)
35
+ actuals.has_key?(expected)
36
+ else
37
+ actuals.include?(expected)
38
+ end
39
+ end
40
+ end
41
+
42
+ def comparing_hash_keys?(actual, expected)
43
+ actual.is_a?(Hash) && !expected.is_a?(Hash)
44
+ end
45
+
46
+ def comparing_hash_values?(actual, expected)
47
+ actual.is_a?(Hash) && expected.is_a?(Hash)
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,13 @@
1
+ module RSpec
2
+ module Matchers
3
+ module BuiltIn
4
+ class Match
5
+ include BaseMatcher
6
+
7
+ def matches?(actual)
8
+ super(actual).match(expected)
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,52 @@
1
+ module RSpec
2
+ module Matchers
3
+ module BuiltIn
4
+ class MatchArray
5
+ include RSpec::Matchers::Pretty
6
+
7
+ def initialize(expected)
8
+ @expected = expected
9
+ end
10
+
11
+ def matches?(actual)
12
+ @actual = actual
13
+ @extra_items = difference_between_arrays(@actual, @expected)
14
+ @missing_items = difference_between_arrays(@expected, @actual)
15
+ @extra_items.empty? & @missing_items.empty?
16
+ end
17
+
18
+ def failure_message_for_should
19
+ message = "expected collection contained: #{safe_sort(@expected).inspect}\n"
20
+ message += "actual collection contained: #{safe_sort(@actual).inspect}\n"
21
+ message += "the missing elements were: #{safe_sort(@missing_items).inspect}\n" unless @missing_items.empty?
22
+ message += "the extra elements were: #{safe_sort(@extra_items).inspect}\n" unless @extra_items.empty?
23
+ message
24
+ end
25
+
26
+ def failure_message_for_should_not
27
+ "Matcher does not support should_not"
28
+ end
29
+
30
+ def description
31
+ "contain exactly #{_pretty_print(@expected)}"
32
+ end
33
+
34
+ private
35
+
36
+ def safe_sort(array)
37
+ array.sort rescue array
38
+ end
39
+
40
+ def difference_between_arrays(array_1, array_2)
41
+ difference = array_1.dup
42
+ array_2.each do |element|
43
+ if index = difference.index(element)
44
+ difference.delete_at(index)
45
+ end
46
+ end
47
+ difference
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,96 @@
1
+ module RSpec
2
+ module Matchers
3
+ module BuiltIn
4
+ class RaiseError
5
+ def initialize(expected_error_or_message=Exception, expected_message=nil, &block)
6
+ @block = block
7
+ @actual_error = nil
8
+ case expected_error_or_message
9
+ when String, Regexp
10
+ @expected_error, @expected_message = Exception, expected_error_or_message
11
+ else
12
+ @expected_error, @expected_message = expected_error_or_message, expected_message
13
+ end
14
+ end
15
+
16
+ def matches?(given_proc)
17
+ @raised_expected_error = false
18
+ @with_expected_message = false
19
+ @eval_block = false
20
+ @eval_block_passed = false
21
+ begin
22
+ given_proc.call
23
+ rescue @expected_error => @actual_error
24
+ @raised_expected_error = true
25
+ @with_expected_message = verify_message
26
+ rescue Exception => @actual_error
27
+ # This clause should be empty, but rcov will not report it as covered
28
+ # unless something (anything) is executed within the clause
29
+ "http://eigenclass.org/hiki.rb?rcov-0.8.0"
30
+ end
31
+
32
+ unless negative_expectation?
33
+ eval_block if @raised_expected_error && @with_expected_message && @block
34
+ end
35
+ ensure
36
+ return (@raised_expected_error & @with_expected_message) ? (@eval_block ? @eval_block_passed : true) : false
37
+ end
38
+
39
+ def eval_block
40
+ @eval_block = true
41
+ begin
42
+ @block[@actual_error]
43
+ @eval_block_passed = true
44
+ rescue Exception => err
45
+ @actual_error = err
46
+ end
47
+ end
48
+
49
+ def verify_message
50
+ case @expected_message
51
+ when nil
52
+ true
53
+ when Regexp
54
+ @expected_message =~ @actual_error.message
55
+ else
56
+ @expected_message == @actual_error.message
57
+ end
58
+ end
59
+
60
+ def failure_message_for_should
61
+ @eval_block ? @actual_error.message : "expected #{expected_error}#{given_error}"
62
+ end
63
+
64
+ def failure_message_for_should_not
65
+ "expected no #{expected_error}#{given_error}"
66
+ end
67
+
68
+ def description
69
+ "raise #{expected_error}"
70
+ end
71
+
72
+ private
73
+
74
+ def expected_error
75
+ case @expected_message
76
+ when nil
77
+ @expected_error
78
+ when Regexp
79
+ "#{@expected_error} with message matching #{@expected_message.inspect}"
80
+ else
81
+ "#{@expected_error} with #{@expected_message.inspect}"
82
+ end
83
+ end
84
+
85
+ def given_error
86
+ @actual_error.nil? ? " but nothing was raised" : ", got #{@actual_error.inspect}"
87
+ end
88
+
89
+ def negative_expectation?
90
+ # YES - I'm a bad person... help me find a better way - ryand
91
+ caller.first(3).find { |s| s =~ /should_not/ }
92
+ end
93
+ end
94
+ end
95
+ end
96
+ end