rspec-sleeping_king_studios 1.0.0.rc.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (35) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +22 -0
  3. data/README.md +323 -0
  4. data/lib/rspec/sleeping_king_studios.rb +5 -0
  5. data/lib/rspec/sleeping_king_studios/matchers.rb +5 -0
  6. data/lib/rspec/sleeping_king_studios/matchers/active_model.rb +5 -0
  7. data/lib/rspec/sleeping_king_studios/matchers/active_model/have_errors.rb +219 -0
  8. data/lib/rspec/sleeping_king_studios/matchers/active_model/have_errors/error_expectation.rb +60 -0
  9. data/lib/rspec/sleeping_king_studios/matchers/active_model/have_errors/message_expectation.rb +17 -0
  10. data/lib/rspec/sleeping_king_studios/matchers/active_model/have_errors/require.rb +7 -0
  11. data/lib/rspec/sleeping_king_studios/matchers/active_model/require.rb +8 -0
  12. data/lib/rspec/sleeping_king_studios/matchers/base_matcher.rb +43 -0
  13. data/lib/rspec/sleeping_king_studios/matchers/built_in.rb +5 -0
  14. data/lib/rspec/sleeping_king_studios/matchers/built_in/be_kind_of.rb +68 -0
  15. data/lib/rspec/sleeping_king_studios/matchers/built_in/include.rb +92 -0
  16. data/lib/rspec/sleeping_king_studios/matchers/built_in/require.rb +7 -0
  17. data/lib/rspec/sleeping_king_studios/matchers/built_in/respond_to.rb +187 -0
  18. data/lib/rspec/sleeping_king_studios/matchers/core.rb +5 -0
  19. data/lib/rspec/sleeping_king_studios/matchers/core/be_boolean.rb +41 -0
  20. data/lib/rspec/sleeping_king_studios/matchers/core/construct.rb +138 -0
  21. data/lib/rspec/sleeping_king_studios/matchers/core/have_property.rb +84 -0
  22. data/lib/rspec/sleeping_king_studios/matchers/core/have_reader.rb +76 -0
  23. data/lib/rspec/sleeping_king_studios/matchers/core/have_writer.rb +101 -0
  24. data/lib/rspec/sleeping_king_studios/matchers/core/require.rb +7 -0
  25. data/lib/rspec/sleeping_king_studios/matchers/meta.rb +5 -0
  26. data/lib/rspec/sleeping_king_studios/matchers/meta/fail_with_actual.rb +142 -0
  27. data/lib/rspec/sleeping_king_studios/matchers/meta/pass_with_actual.rb +96 -0
  28. data/lib/rspec/sleeping_king_studios/matchers/meta/require.rb +7 -0
  29. data/lib/rspec/sleeping_king_studios/matchers/require.rb +12 -0
  30. data/lib/rspec/sleeping_king_studios/matchers/shared/match_parameters.rb +69 -0
  31. data/lib/rspec/sleeping_king_studios/matchers/shared/require.rb +7 -0
  32. data/lib/rspec/sleeping_king_studios/mocks/custom_double.rb +13 -0
  33. data/lib/rspec/sleeping_king_studios/require.rb +7 -0
  34. data/lib/rspec/sleeping_king_studios/version.rb +7 -0
  35. metadata +151 -0
@@ -0,0 +1,60 @@
1
+ # lib/rspec/sleeping_king_studios/matchers/active_model/have_errors/error_expectation.rb
2
+
3
+ require 'rspec/sleeping_king_studios/matchers/base_matcher'
4
+ require 'rspec/sleeping_king_studios/matchers/active_model/have_errors/message_expectation'
5
+
6
+ module RSpec::SleepingKingStudios::Matchers::ActiveModel::HaveErrors
7
+ # Stores an expectation of receiving an error for a specified attribute, as
8
+ # well as zero or more message expectations.
9
+ #
10
+ # @since 1.0.0
11
+ #
12
+ # @see MessageExpectation
13
+ class ErrorExpectation < Struct.new :attribute, :expected, :received
14
+ # Extra instance methods for the :messages array.
15
+ #
16
+ # @private
17
+ module MessagesMethods
18
+ # @return [Array<MessageExpectation>] messages that are expected
19
+ def expected
20
+ select { |message| message.expected }
21
+ end # method expected
22
+
23
+ # @return [Array<MessageExpectation>] messages that are expected but have
24
+ # not been received
25
+ def missing
26
+ select { |message| message.expected && !message.received }
27
+ end # method missing
28
+
29
+ # @return [Array<MessageExpectation>] messages that have been received
30
+ def received
31
+ select { |message| message.received }
32
+ end # method received
33
+ end # module
34
+
35
+ # @param [String, Symbol] attribute the attribute for which an error is
36
+ # expected to be or has been received
37
+ # @param [Boolean] expected whether an error is expected for the specified
38
+ # attribute
39
+ # @param [Boolean] received whether an error has been received for the
40
+ # specified attribute
41
+ def initialize attribute, expected = true, received = false
42
+ super attribute.intern, expected, received
43
+
44
+ @messages = []
45
+ class << @messages
46
+ include MessagesMethods
47
+ end # eigenclass
48
+ end # constructor
49
+
50
+ # The message expectations for the specified attribute. The returned array
51
+ # supports several additional methods: #expected, #missing, and #received.
52
+ #
53
+ # @return [Array<MessageExpectation>]
54
+ #
55
+ # @see MessagesMethods#expected
56
+ # @see MessagesMethods#missing
57
+ # @see MessagesMethods#received
58
+ attr_reader :messages
59
+ end # class
60
+ end # module
@@ -0,0 +1,17 @@
1
+ # lib/rspec/sleeping_king_studios/matchers/active_model/have_errors/message_expectation.rb
2
+
3
+ require 'rspec/sleeping_king_studios/matchers/base_matcher'
4
+ require 'rspec/sleeping_king_studios/matchers/active_model/have_errors/require'
5
+
6
+ module RSpec::SleepingKingStudios::Matchers::ActiveModel::HaveErrors
7
+ # Stores an expectation of receiving a specified error message.
8
+ class MessageExpectation < Struct.new :message, :expected, :received
9
+ # @param [String] message the message which is expected to be or has been
10
+ # received
11
+ # @param [Boolean] expected whether the message is expected
12
+ # @param [Boolean] received whether the message has been received
13
+ def initialize message, expected = true, received = false
14
+ super message, expected, received
15
+ end # constructor
16
+ end # class
17
+ end # module
@@ -0,0 +1,7 @@
1
+ # spec/rspec/sleeping_king_studios/matchers/active_model/have_errors/require.rb
2
+
3
+ require 'rspec/sleeping_king_studios/matchers/active_model/require'
4
+
5
+ module RSpec::SleepingKingStudios::Matchers::ActiveModel
6
+ module HaveErrors; end
7
+ end # module
@@ -0,0 +1,8 @@
1
+ # lib/rspec/sleeping_king_studios/matchers/active_model/require.rb
2
+
3
+ require 'rspec/sleeping_king_studios/matchers/require'
4
+
5
+ module RSpec::SleepingKingStudios::Matchers
6
+ # Matchers for ActiveModel object validation testing.
7
+ module ActiveModel; end
8
+ end # module
@@ -0,0 +1,43 @@
1
+ # lib/rspec/sleeping_king_studios/matchers/base_matcher.rb
2
+
3
+ require 'rspec/sleeping_king_studios/matchers/require'
4
+
5
+ module RSpec::SleepingKingStudios::Matchers
6
+ # Minimal implementation of the RSpec matcher interface.
7
+ #
8
+ # @since 1.0.0
9
+ class BaseMatcher
10
+ def initialize *args
11
+ end # constructor
12
+
13
+ # A short string that describes the purpose of the matcher.
14
+ #
15
+ # @return [String] the matcher description
16
+ def description
17
+ "match"
18
+ end # method description
19
+
20
+ # Tests the actual object to see if it matches the defined condition(s).
21
+ # Invoked by RSpec expectations.
22
+ #
23
+ # @param [Object] actual the object to test against the matcher
24
+ #
25
+ # @return [Boolean] true if the object matches, otherwise false
26
+ def matches? actual
27
+ @actual = actual
28
+ true
29
+ end # method matches?
30
+
31
+ # Message for when the object does not match, but was expected to. Make
32
+ # sure to always call #matches? first to set up the matcher state.
33
+ def failure_message_for_should
34
+ "expected #{@actual.inspect} to #{description}"
35
+ end # method failure_message_for_should
36
+
37
+ # Message for when the object matches, but was expected not to. Make sure
38
+ # to always call #matches? first to set up the matcher state.
39
+ def failure_message_for_should_not
40
+ "expected #{@actual.inspect} not to #{description}"
41
+ end # method failure_message_for_should_not
42
+ end # class
43
+ end # module
@@ -0,0 +1,5 @@
1
+ # lib/rspec/sleeping_king_studios/matchers/built_in.rb
2
+
3
+ Dir[File.join File.dirname(__FILE__), 'built_in', '*.rb'].each do |file|
4
+ require file
5
+ end # end each
@@ -0,0 +1,68 @@
1
+ # lib/rspec/sleeping_king_studios/matchers/built_in/be_kind_of.rb
2
+
3
+ require 'rspec/sleeping_king_studios/matchers/built_in/require'
4
+
5
+ module RSpec::SleepingKingStudios::Matchers::BuiltIn
6
+ class BeAKindOfMatcher < RSpec::Matchers::BuiltIn::BeAKindOf
7
+ # Checks if the object matches one of the specified types. Allows an
8
+ # expected value of nil as a shortcut for expecting an instance of
9
+ # NilClass.
10
+ #
11
+ # @param [Module, nil, Array<Module, nil>] expected the type or types to
12
+ # check the object against
13
+ # @param [Object] actual the object to check
14
+ #
15
+ # @return [Boolean] true if the object matches one of the specified types,
16
+ # otherwise false
17
+ def match expected, actual
18
+ match_type? expected
19
+ end # method match
20
+
21
+ # @see BaseMatcher#failure_message_for_should
22
+ def failure_message_for_should
23
+ "expected #{@actual.inspect} to be #{type_string}"
24
+ end # method failure_message_for_should
25
+
26
+ # @see BaseMatcher#failure_message_for_should_not
27
+ def failure_message_for_should_not
28
+ "expected #{@actual.inspect} not to be #{type_string}"
29
+ end # method failure_message_for_should_not
30
+
31
+ private
32
+
33
+ def match_type? expected
34
+ case
35
+ when expected.nil?
36
+ @actual.nil?
37
+ when expected.is_a?(Enumerable)
38
+ expected.reduce(false) { |memo, obj| memo || match_type?(obj) }
39
+ else
40
+ @actual.kind_of? expected
41
+ end # case
42
+ end # method match_type?
43
+
44
+ def type_string
45
+ case
46
+ when @expected.nil?
47
+ @expected.inspect
48
+ when @expected.is_a?(Enumerable) && 1 < @expected.count
49
+ if 2 == expected.count
50
+ "a #{expected.first.inspect} or #{expected.last.inspect}"
51
+ else
52
+ "a #{expected[0..-2].map(&:inspect).join(", ")}, or #{expected.last.inspect}"
53
+ end # if-else
54
+ else
55
+ "a #{expected}"
56
+ end # case
57
+ end # method type_string
58
+ end # class
59
+ end # module
60
+
61
+ module RSpec::SleepingKingStudios::Matchers
62
+ # @see RSpec::SleepingKingStudios::Matchers::BuiltIn::BeAKindOfMatcher#match
63
+ def be_kind_of expected
64
+ RSpec::SleepingKingStudios::Matchers::BuiltIn::BeAKindOfMatcher.new expected
65
+ end # method be_kind_of
66
+
67
+ alias_method :be_a, :be_kind_of
68
+ end # module
@@ -0,0 +1,92 @@
1
+ # lib/rspec/sleeping_king_studios/matchers/built_in/be_kind_of.rb
2
+
3
+ require 'rspec/sleeping_king_studios/matchers/built_in/require'
4
+
5
+ module RSpec::SleepingKingStudios::Matchers::BuiltIn
6
+ class IncludeMatcher < RSpec::Matchers::BuiltIn::Include
7
+ # @param [Array<Hash, Proc, Object>] expected the items expected to be
8
+ # matched by the actual object
9
+ #
10
+ # @yield if a block is provided, the block is converted to a proc and
11
+ # appended to the item expectations
12
+ # @yieldparam [Object] item an item from the actual object; yield(item)
13
+ # should return true if and only if the item matches the desired
14
+ # predicate
15
+ def initialize *expected, &block
16
+ expected << block if block_given?
17
+ super *expected
18
+ end # constructor
19
+
20
+ # Checks if the object includes the specified objects. Proc expectations
21
+ # are evaluated by passing each item to proc#call.
22
+ #
23
+ # @param [Object] actual the object to check
24
+ #
25
+ # @return [Boolean] true if for each item expectation, the object contains
26
+ # an item matching that expectation; otherwise false
27
+ def matches? actual
28
+ super
29
+ end # method matches?
30
+
31
+ # @private
32
+ def name
33
+ "include"
34
+ end # method name
35
+
36
+ # @private
37
+ def to_word item
38
+ case
39
+ when is_matcher_with_description?(item)
40
+ item.description
41
+ when Proc === item
42
+ "matching block"
43
+ else
44
+ item.inspect
45
+ end # case
46
+ end # method to_word
47
+
48
+ # @see BaseMatcher#failure_message_for_should
49
+ def failure_message_for_should
50
+ return "expected #{@actual.inspect} to respond to :include?" if false === @includes
51
+
52
+ super
53
+ end # method failure_message_for_should
54
+
55
+ # @see BaseMatcher#failure_message_for_should_not
56
+ def failure_message_for_should_not
57
+ super
58
+ end # method
59
+
60
+ private
61
+
62
+ def perform_match predicate, hash_predicate, actuals, expecteds
63
+ expecteds.__send__(predicate) do |expected|
64
+ if comparing_proc? actuals, expected
65
+ !!actuals.detect { |actual| expected.call(actual) }
66
+ elsif comparing_hash_values?(actuals, expected)
67
+ expected.__send__(hash_predicate) { |k,v|
68
+ actuals.has_key?(k) && actuals[k] == v
69
+ }
70
+ elsif comparing_hash_keys?(actuals, expected)
71
+ actuals.has_key?(expected)
72
+ elsif comparing_with_matcher?(actual, expected)
73
+ actual.any? { |value| expected.matches?(value) }
74
+ else
75
+ @includes = actuals.respond_to?(:include?)
76
+ @includes && actuals.include?(expected)
77
+ end # if-elsif-end
78
+ end # send
79
+ end # method perform_match
80
+
81
+ def comparing_proc? actual, expected
82
+ expected.is_a?(Proc)
83
+ end # method comparing_proc?
84
+ end # class
85
+ end # module
86
+
87
+ module RSpec::SleepingKingStudios::Matchers
88
+ # @see RSpec::SleepingKingStudios::Matchers::BuiltIn::IncludeMatcher#matches?
89
+ def include *expected, &block
90
+ RSpec::SleepingKingStudios::Matchers::BuiltIn::IncludeMatcher.new *expected, &block
91
+ end # method include
92
+ end # module
@@ -0,0 +1,7 @@
1
+ # lib/rspec/sleeping_king_studios/matchers/built_in/require.rb
2
+
3
+ require 'rspec/sleeping_king_studios/matchers/require'
4
+
5
+ module RSpec::SleepingKingStudios::Matchers
6
+ module BuiltIn; end
7
+ end # module
@@ -0,0 +1,187 @@
1
+ # lib/rspec/sleeping_king_studios/matchers/built_in/respond_to.rb
2
+
3
+ require 'rspec/sleeping_king_studios/matchers/base_matcher'
4
+ require 'rspec/sleeping_king_studios/matchers/built_in/require'
5
+ require 'rspec/sleeping_king_studios/matchers/shared/match_parameters'
6
+
7
+ module RSpec::SleepingKingStudios::Matchers::BuiltIn
8
+ class RespondToMatcher < RSpec::Matchers::BuiltIn::RespondTo
9
+ include RSpec::SleepingKingStudios::Matchers::Shared::MatchParameters
10
+
11
+ # Checks if the object responds to the specified message. If so, checks the
12
+ # parameters against the expected parameters, if any.
13
+ #
14
+ # @param [Object] actual the object to check
15
+ #
16
+ # @return [Boolean] true if the object responds to the message and accepts
17
+ # the specified parameters; otherwise false
18
+ def matches? actual
19
+ super
20
+ end # method matches?
21
+
22
+ # Adds a parameter count expectation and/or one or more keyword
23
+ # expectations (Ruby 2.0 only).
24
+ #
25
+ # @param [Integer, Range, nil] count the number of expected parameters; can
26
+ # be an integer, a range, or nil (parameter count is ignored)
27
+ # @param [Array<String, Symbol>] keywords list of keyword arguments
28
+ # accepted by the method
29
+ #
30
+ # @return [RespondToMatcher] self
31
+ def with count = nil, *keywords
32
+ @expected_arity = count unless count.nil?
33
+ @expected_keywords = keywords
34
+ self
35
+ end # method with
36
+
37
+ # Adds a block expectation. The actual object will only match a block
38
+ # expectation if it expects a parameter of the form &block.
39
+ #
40
+ # @return [RespondToMatcher] self
41
+ def a_block
42
+ @expected_block = true
43
+ self
44
+ end # method a_block
45
+
46
+ # Convenience method for more fluent specs. Does nothing and returns self.
47
+ #
48
+ # @return [RespondToMatcher] self
49
+ def arguments
50
+ self
51
+ end # method arguments
52
+
53
+ # Convenience method for more fluent specs. Does nothing and returns self.
54
+ #
55
+ # @return [RespondToMatcher] self
56
+ def and
57
+ self
58
+ end # method arguments
59
+
60
+ # @see BaseMatcher#failure_message_for_should
61
+ def failure_message_for_should
62
+ messages = []
63
+ @failing_method_names ||= []
64
+ @failing_method_names.map do |method|
65
+ message = "expected #{@actual.inspect} to respond to #{method.inspect}"
66
+ if @actual.respond_to?(method)
67
+ message << " with arguments:\n#{format_errors_for_method method}"
68
+ end # if-else
69
+ messages << message
70
+ end # method
71
+ messages.join "\n"
72
+ end # method failure_message_for_should
73
+
74
+ # @see BaseMatcher#failure_message_for_should_not
75
+ def failure_message_for_should_not
76
+ @failing_method_names ||= []
77
+ methods, messages = @names - @failing_method_names, []
78
+
79
+ @names.map do |method|
80
+ message = "expected #{@actual.inspect} not to respond to #{method.inspect}"
81
+ unless (formatted = format_expected_arguments).empty?
82
+ message << " with #{formatted}"
83
+ end # unless
84
+ messages << message
85
+ end # method
86
+ messages.join "\n"
87
+ end # method failure_message_for_should_not
88
+
89
+ private
90
+
91
+ def find_failing_method_names actual, filter_method
92
+ @actual = actual
93
+ @failing_method_reasons = {}
94
+ @failing_method_names = @names.__send__(filter_method) do |name|
95
+ @actual.respond_to?(name) &&
96
+ matches_arity?(actual, name) &&
97
+ matches_keywords?(actual, name) &&
98
+ matches_block?(actual, name)
99
+ end # send
100
+ end # method find_failing_method_names
101
+
102
+ def matches_arity? actual, name
103
+ return true unless @expected_arity
104
+
105
+ if result = check_method_arity(actual.method(name), @expected_arity)
106
+ (@failing_method_reasons[name] ||= {}).update result
107
+ return false
108
+ end # if
109
+
110
+ true
111
+ end # method matches_arity?
112
+
113
+ def matches_keywords? actual, name
114
+ return true unless @expected_keywords
115
+
116
+ if result = check_method_keywords(actual.method(name), @expected_keywords)
117
+ (@failing_method_reasons[name] ||= {}).update result
118
+ return false
119
+ end # if
120
+
121
+ true
122
+ end # method matches_keywords?
123
+
124
+ def matches_block? actual, name
125
+ return true unless @expected_block
126
+
127
+ if result = check_method_block(@actual.method(name))
128
+ (@failing_method_reasons[name] ||= {}).update result
129
+ return false
130
+ end # if
131
+
132
+ true
133
+ end # method matches_block?
134
+
135
+ def format_expected_arguments
136
+ messages = []
137
+
138
+ if !@expected_arity.nil?
139
+ messages << "#{@expected_arity.inspect} argument#{1 == @expected_arity ? "" : "s"}"
140
+ end # if
141
+
142
+ if !(@expected_keywords.nil? || @expected_keywords.empty?)
143
+ messages << "keywords #{@expected_keywords.map(&:inspect).join(", ")}"
144
+ end # if
145
+
146
+ if @expected_block
147
+ messages << "a block"
148
+ end # if
149
+
150
+ case messages.count
151
+ when 0..1
152
+ messages.join(", ")
153
+ when 2
154
+ "#{messages[0]} and #{messages[1]}"
155
+ else
156
+ "#{messages[1..-1].join(", ")}, and #{messages[0]}"
157
+ end # case
158
+ end # method format_expected_arguments
159
+
160
+ def format_errors_for_method method
161
+ reasons, messages = @failing_method_reasons[method], []
162
+
163
+ if hsh = reasons.fetch(:not_enough_args, false)
164
+ messages << " expected at least #{hsh[:count]} arguments, but received #{hsh[:arity]}"
165
+ elsif hsh = reasons.fetch(:too_many_args, false)
166
+ messages << " expected at most #{hsh[:count]} arguments, but received #{hsh[:arity]}"
167
+ end # if-elsif
168
+
169
+ if ary = reasons.fetch(:unexpected_keywords, false)
170
+ messages << " unexpected keywords #{ary.map(&:inspect).join(", ")}"
171
+ end # if
172
+
173
+ if reasons.fetch(:expected_block, false)
174
+ messages << " unexpected block"
175
+ end # if
176
+
177
+ messages.join "\n"
178
+ end # method format_errors_for_method
179
+ end # class
180
+ end # module
181
+
182
+ module RSpec::SleepingKingStudios::Matchers
183
+ # @see RSpec::SleepingKingStudios::Matchers::BuiltIn::RespondToMatcher#matches?
184
+ def respond_to expected
185
+ RSpec::SleepingKingStudios::Matchers::BuiltIn::RespondToMatcher.new expected
186
+ end # method respond_to
187
+ end # module