rspec-expectations 2.14.0 → 3.13.0

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 (155) hide show
  1. checksums.yaml +7 -0
  2. checksums.yaml.gz.sig +0 -0
  3. data/.document +1 -1
  4. data/.yardopts +1 -1
  5. data/Changelog.md +976 -25
  6. data/{License.txt → LICENSE.md} +5 -3
  7. data/README.md +162 -26
  8. data/lib/rspec/expectations/block_snippet_extractor.rb +253 -0
  9. data/lib/rspec/expectations/configuration.rb +230 -0
  10. data/lib/rspec/expectations/expectation_target.rb +127 -51
  11. data/lib/rspec/expectations/fail_with.rb +17 -57
  12. data/lib/rspec/expectations/failure_aggregator.rb +229 -0
  13. data/lib/rspec/expectations/handler.rb +146 -32
  14. data/lib/rspec/expectations/minitest_integration.rb +58 -0
  15. data/lib/rspec/expectations/syntax.rb +68 -100
  16. data/lib/rspec/expectations/version.rb +1 -1
  17. data/lib/rspec/expectations.rb +58 -23
  18. data/lib/rspec/matchers/aliased_matcher.rb +116 -0
  19. data/lib/rspec/matchers/built_in/all.rb +86 -0
  20. data/lib/rspec/matchers/built_in/base_matcher.rb +191 -20
  21. data/lib/rspec/matchers/built_in/be.rb +114 -114
  22. data/lib/rspec/matchers/built_in/be_between.rb +77 -0
  23. data/lib/rspec/matchers/built_in/be_instance_of.rb +15 -4
  24. data/lib/rspec/matchers/built_in/be_kind_of.rb +10 -1
  25. data/lib/rspec/matchers/built_in/be_within.rb +35 -18
  26. data/lib/rspec/matchers/built_in/change.rb +389 -80
  27. data/lib/rspec/matchers/built_in/compound.rb +290 -0
  28. data/lib/rspec/matchers/built_in/contain_exactly.rb +310 -0
  29. data/lib/rspec/matchers/built_in/count_expectation.rb +169 -0
  30. data/lib/rspec/matchers/built_in/cover.rb +3 -0
  31. data/lib/rspec/matchers/built_in/eq.rb +30 -8
  32. data/lib/rspec/matchers/built_in/eql.rb +23 -8
  33. data/lib/rspec/matchers/built_in/equal.rb +55 -22
  34. data/lib/rspec/matchers/built_in/exist.rb +74 -10
  35. data/lib/rspec/matchers/built_in/has.rb +141 -22
  36. data/lib/rspec/matchers/built_in/have_attributes.rb +114 -0
  37. data/lib/rspec/matchers/built_in/include.rb +184 -32
  38. data/lib/rspec/matchers/built_in/match.rb +95 -1
  39. data/lib/rspec/matchers/built_in/operators.rb +128 -0
  40. data/lib/rspec/matchers/built_in/output.rb +207 -0
  41. data/lib/rspec/matchers/built_in/raise_error.rb +192 -44
  42. data/lib/rspec/matchers/built_in/respond_to.rb +154 -28
  43. data/lib/rspec/matchers/built_in/satisfy.rb +39 -9
  44. data/lib/rspec/matchers/built_in/start_or_end_with.rb +94 -0
  45. data/lib/rspec/matchers/built_in/throw_symbol.rb +58 -14
  46. data/lib/rspec/matchers/built_in/yield.rb +240 -161
  47. data/lib/rspec/matchers/built_in.rb +47 -33
  48. data/lib/rspec/matchers/composable.rb +171 -0
  49. data/lib/rspec/matchers/dsl.rb +531 -10
  50. data/lib/rspec/matchers/english_phrasing.rb +58 -0
  51. data/lib/rspec/matchers/fail_matchers.rb +42 -0
  52. data/lib/rspec/matchers/generated_descriptions.rb +14 -8
  53. data/lib/rspec/matchers/matcher_delegator.rb +61 -0
  54. data/lib/rspec/matchers/matcher_protocol.rb +105 -0
  55. data/lib/rspec/matchers/multi_matcher_diff.rb +82 -0
  56. data/lib/rspec/matchers.rb +520 -173
  57. data.tar.gz.sig +0 -0
  58. metadata +141 -242
  59. metadata.gz.sig +2 -0
  60. data/features/README.md +0 -48
  61. data/features/Upgrade.md +0 -53
  62. data/features/built_in_matchers/README.md +0 -90
  63. data/features/built_in_matchers/be.feature +0 -175
  64. data/features/built_in_matchers/be_within.feature +0 -48
  65. data/features/built_in_matchers/cover.feature +0 -47
  66. data/features/built_in_matchers/end_with.feature +0 -48
  67. data/features/built_in_matchers/equality.feature +0 -139
  68. data/features/built_in_matchers/exist.feature +0 -45
  69. data/features/built_in_matchers/expect_change.feature +0 -59
  70. data/features/built_in_matchers/expect_error.feature +0 -144
  71. data/features/built_in_matchers/have.feature +0 -109
  72. data/features/built_in_matchers/include.feature +0 -174
  73. data/features/built_in_matchers/match.feature +0 -52
  74. data/features/built_in_matchers/operators.feature +0 -227
  75. data/features/built_in_matchers/predicates.feature +0 -137
  76. data/features/built_in_matchers/respond_to.feature +0 -84
  77. data/features/built_in_matchers/satisfy.feature +0 -33
  78. data/features/built_in_matchers/start_with.feature +0 -48
  79. data/features/built_in_matchers/throw_symbol.feature +0 -91
  80. data/features/built_in_matchers/types.feature +0 -116
  81. data/features/built_in_matchers/yield.feature +0 -161
  82. data/features/custom_matchers/access_running_example.feature +0 -53
  83. data/features/custom_matchers/define_diffable_matcher.feature +0 -27
  84. data/features/custom_matchers/define_matcher.feature +0 -368
  85. data/features/custom_matchers/define_matcher_outside_rspec.feature +0 -38
  86. data/features/custom_matchers/define_matcher_with_fluent_interface.feature +0 -24
  87. data/features/customized_message.feature +0 -22
  88. data/features/diffing.feature +0 -85
  89. data/features/implicit_docstrings.feature +0 -52
  90. data/features/step_definitions/additional_cli_steps.rb +0 -22
  91. data/features/support/env.rb +0 -14
  92. data/features/syntax_configuration.feature +0 -71
  93. data/features/test_frameworks/test_unit.feature +0 -44
  94. data/lib/rspec/expectations/deprecation.rb +0 -17
  95. data/lib/rspec/expectations/differ.rb +0 -133
  96. data/lib/rspec/expectations/errors.rb +0 -9
  97. data/lib/rspec/expectations/extensions/array.rb +0 -9
  98. data/lib/rspec/expectations/extensions/object.rb +0 -29
  99. data/lib/rspec/expectations/extensions.rb +0 -2
  100. data/lib/rspec/matchers/be_close.rb +0 -9
  101. data/lib/rspec/matchers/built_in/have.rb +0 -124
  102. data/lib/rspec/matchers/built_in/match_array.rb +0 -51
  103. data/lib/rspec/matchers/built_in/start_and_end_with.rb +0 -48
  104. data/lib/rspec/matchers/compatibility.rb +0 -14
  105. data/lib/rspec/matchers/configuration.rb +0 -108
  106. data/lib/rspec/matchers/extensions/instance_eval_with_args.rb +0 -39
  107. data/lib/rspec/matchers/matcher.rb +0 -300
  108. data/lib/rspec/matchers/method_missing.rb +0 -12
  109. data/lib/rspec/matchers/operator_matcher.rb +0 -109
  110. data/lib/rspec/matchers/pretty.rb +0 -70
  111. data/lib/rspec/matchers/test_unit_integration.rb +0 -11
  112. data/lib/rspec-expectations.rb +0 -1
  113. data/spec/rspec/expectations/differ_spec.rb +0 -192
  114. data/spec/rspec/expectations/expectation_target_spec.rb +0 -82
  115. data/spec/rspec/expectations/extensions/kernel_spec.rb +0 -67
  116. data/spec/rspec/expectations/fail_with_spec.rb +0 -114
  117. data/spec/rspec/expectations/handler_spec.rb +0 -227
  118. data/spec/rspec/expectations/syntax_spec.rb +0 -139
  119. data/spec/rspec/matchers/base_matcher_spec.rb +0 -62
  120. data/spec/rspec/matchers/be_close_spec.rb +0 -22
  121. data/spec/rspec/matchers/be_instance_of_spec.rb +0 -63
  122. data/spec/rspec/matchers/be_kind_of_spec.rb +0 -41
  123. data/spec/rspec/matchers/be_spec.rb +0 -516
  124. data/spec/rspec/matchers/be_within_spec.rb +0 -137
  125. data/spec/rspec/matchers/change_spec.rb +0 -553
  126. data/spec/rspec/matchers/configuration_spec.rb +0 -206
  127. data/spec/rspec/matchers/cover_spec.rb +0 -69
  128. data/spec/rspec/matchers/description_generation_spec.rb +0 -190
  129. data/spec/rspec/matchers/dsl_spec.rb +0 -57
  130. data/spec/rspec/matchers/eq_spec.rb +0 -60
  131. data/spec/rspec/matchers/eql_spec.rb +0 -41
  132. data/spec/rspec/matchers/equal_spec.rb +0 -78
  133. data/spec/rspec/matchers/exist_spec.rb +0 -124
  134. data/spec/rspec/matchers/has_spec.rb +0 -122
  135. data/spec/rspec/matchers/have_spec.rb +0 -455
  136. data/spec/rspec/matchers/include_matcher_integration_spec.rb +0 -30
  137. data/spec/rspec/matchers/include_spec.rb +0 -531
  138. data/spec/rspec/matchers/match_array_spec.rb +0 -194
  139. data/spec/rspec/matchers/match_spec.rb +0 -61
  140. data/spec/rspec/matchers/matcher_spec.rb +0 -471
  141. data/spec/rspec/matchers/matchers_spec.rb +0 -37
  142. data/spec/rspec/matchers/method_missing_spec.rb +0 -28
  143. data/spec/rspec/matchers/operator_matcher_spec.rb +0 -223
  144. data/spec/rspec/matchers/raise_error_spec.rb +0 -485
  145. data/spec/rspec/matchers/respond_to_spec.rb +0 -292
  146. data/spec/rspec/matchers/satisfy_spec.rb +0 -44
  147. data/spec/rspec/matchers/start_with_end_with_spec.rb +0 -186
  148. data/spec/rspec/matchers/throw_symbol_spec.rb +0 -116
  149. data/spec/rspec/matchers/yield_spec.rb +0 -514
  150. data/spec/spec_helper.rb +0 -54
  151. data/spec/support/classes.rb +0 -56
  152. data/spec/support/in_sub_process.rb +0 -38
  153. data/spec/support/matchers.rb +0 -22
  154. data/spec/support/ruby_version.rb +0 -10
  155. data/spec/support/shared_examples.rb +0 -13
@@ -0,0 +1,171 @@
1
+ RSpec::Support.require_rspec_support "fuzzy_matcher"
2
+
3
+ module RSpec
4
+ module Matchers
5
+ # Mixin designed to support the composable matcher features
6
+ # of RSpec 3+. Mix it into your custom matcher classes to
7
+ # allow them to be used in a composable fashion.
8
+ #
9
+ # @api public
10
+ module Composable
11
+ # Creates a compound `and` expectation. The matcher will
12
+ # only pass if both sub-matchers pass.
13
+ # This can be chained together to form an arbitrarily long
14
+ # chain of matchers.
15
+ #
16
+ # @example
17
+ # expect(alphabet).to start_with("a").and end_with("z")
18
+ # expect(alphabet).to start_with("a") & end_with("z")
19
+ #
20
+ # @note The negative form (`expect(...).not_to matcher.and other`)
21
+ # is not supported at this time.
22
+ def and(matcher)
23
+ BuiltIn::Compound::And.new self, matcher
24
+ end
25
+ alias & and
26
+
27
+ # Creates a compound `or` expectation. The matcher will
28
+ # pass if either sub-matcher passes.
29
+ # This can be chained together to form an arbitrarily long
30
+ # chain of matchers.
31
+ #
32
+ # @example
33
+ # expect(stoplight.color).to eq("red").or eq("green").or eq("yellow")
34
+ # expect(stoplight.color).to eq("red") | eq("green") | eq("yellow")
35
+ #
36
+ # @note The negative form (`expect(...).not_to matcher.or other`)
37
+ # is not supported at this time.
38
+ def or(matcher)
39
+ BuiltIn::Compound::Or.new self, matcher
40
+ end
41
+ alias | or
42
+
43
+ # Delegates to `#matches?`. Allows matchers to be used in composable
44
+ # fashion and also supports using matchers in case statements.
45
+ def ===(value)
46
+ matches?(value)
47
+ end
48
+
49
+ private
50
+
51
+ # This provides a generic way to fuzzy-match an expected value against
52
+ # an actual value. It understands nested data structures (e.g. hashes
53
+ # and arrays) and is able to match against a matcher being used as
54
+ # the expected value or within the expected value at any level of
55
+ # nesting.
56
+ #
57
+ # Within a custom matcher you are encouraged to use this whenever your
58
+ # matcher needs to match two values, unless it needs more precise semantics.
59
+ # For example, the `eq` matcher _does not_ use this as it is meant to
60
+ # use `==` (and only `==`) for matching.
61
+ #
62
+ # @param expected [Object] what is expected
63
+ # @param actual [Object] the actual value
64
+ #
65
+ # @!visibility public
66
+ def values_match?(expected, actual)
67
+ expected = with_matchers_cloned(expected)
68
+ Support::FuzzyMatcher.values_match?(expected, actual)
69
+ end
70
+
71
+ # Returns the description of the given object in a way that is
72
+ # aware of composed matchers. If the object is a matcher with
73
+ # a `description` method, returns the description; otherwise
74
+ # returns `object.inspect`.
75
+ #
76
+ # You are encouraged to use this in your custom matcher's
77
+ # `description`, `failure_message` or
78
+ # `failure_message_when_negated` implementation if you are
79
+ # supporting matcher arguments.
80
+ #
81
+ # @!visibility public
82
+ def description_of(object)
83
+ RSpec::Support::ObjectFormatter.format(object)
84
+ end
85
+
86
+ # Transforms the given data structure (typically a hash or array)
87
+ # into a new data structure that, when `#inspect` is called on it,
88
+ # will provide descriptions of any contained matchers rather than
89
+ # the normal `#inspect` output.
90
+ #
91
+ # You are encouraged to use this in your custom matcher's
92
+ # `description`, `failure_message` or
93
+ # `failure_message_when_negated` implementation if you are
94
+ # supporting any arguments which may be a data structure
95
+ # containing matchers.
96
+ #
97
+ # @!visibility public
98
+ def surface_descriptions_in(item)
99
+ if Matchers.is_a_describable_matcher?(item)
100
+ DescribableItem.new(item)
101
+ elsif Hash === item
102
+ Hash[surface_descriptions_in(item.to_a)]
103
+ elsif Struct === item || unreadable_io?(item)
104
+ RSpec::Support::ObjectFormatter.format(item)
105
+ elsif should_enumerate?(item)
106
+ item.map { |subitem| surface_descriptions_in(subitem) }
107
+ else
108
+ item
109
+ end
110
+ end
111
+
112
+ # @private
113
+ # Historically, a single matcher instance was only checked
114
+ # against a single value. Given that the matcher was only
115
+ # used once, it's been common to memoize some intermediate
116
+ # calculation that is derived from the `actual` value in
117
+ # order to reuse that intermediate result in the failure
118
+ # message.
119
+ #
120
+ # This can cause a problem when using such a matcher as an
121
+ # argument to another matcher in a composed matcher expression,
122
+ # since the matcher instance may be checked against multiple
123
+ # values and produce invalid results due to the memoization.
124
+ #
125
+ # To deal with this, we clone any matchers in `expected` via
126
+ # this method when using `values_match?`, so that any memoization
127
+ # does not "leak" between checks.
128
+ def with_matchers_cloned(object)
129
+ if Matchers.is_a_matcher?(object)
130
+ object.clone
131
+ elsif Hash === object
132
+ Hash[with_matchers_cloned(object.to_a)]
133
+ elsif should_enumerate?(object)
134
+ object.map { |subobject| with_matchers_cloned(subobject) }
135
+ else
136
+ object
137
+ end
138
+ end
139
+
140
+ # @api private
141
+ # We should enumerate arrays as long as they are not recursive.
142
+ def should_enumerate?(item)
143
+ Array === item && item.none? { |subitem| subitem.equal?(item) }
144
+ end
145
+
146
+ # @api private
147
+ def unreadable_io?(object)
148
+ return false unless IO === object
149
+ object.each {} # STDOUT is enumerable but raises an error
150
+ false
151
+ rescue IOError
152
+ true
153
+ end
154
+ module_function :surface_descriptions_in, :should_enumerate?, :unreadable_io?
155
+
156
+ # Wraps an item in order to surface its `description` via `inspect`.
157
+ # @api private
158
+ DescribableItem = Struct.new(:item) do
159
+ # Inspectable version of the item description
160
+ def inspect
161
+ "(#{item.description})"
162
+ end
163
+
164
+ # A pretty printed version of the item description.
165
+ def pretty_print(pp)
166
+ pp.text "(#{item.description})"
167
+ end
168
+ end
169
+ end
170
+ end
171
+ end