rspec-expectations 2.8.0 → 2.9.0.rc2

Sign up to get free protection for your applications and to get access to all the features.
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