rspec-sleeping_king_studios 1.0.0.rc.2

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 (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