rspec-expectations 3.11.0 → 3.13.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (34) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/Changelog.md +90 -5
  4. data/README.md +10 -4
  5. data/lib/rspec/expectations/block_snippet_extractor.rb +2 -0
  6. data/lib/rspec/expectations/configuration.rb +5 -0
  7. data/lib/rspec/expectations/fail_with.rb +1 -1
  8. data/lib/rspec/expectations/failure_aggregator.rb +24 -0
  9. data/lib/rspec/expectations/handler.rb +4 -5
  10. data/lib/rspec/expectations/version.rb +1 -1
  11. data/lib/rspec/matchers/aliased_matcher.rb +3 -3
  12. data/lib/rspec/matchers/built_in/base_matcher.rb +45 -18
  13. data/lib/rspec/matchers/built_in/change.rb +2 -0
  14. data/lib/rspec/matchers/built_in/compound.rb +7 -4
  15. data/lib/rspec/matchers/built_in/contain_exactly.rb +12 -2
  16. data/lib/rspec/matchers/built_in/count_expectation.rb +3 -1
  17. data/lib/rspec/matchers/built_in/eq.rb +5 -1
  18. data/lib/rspec/matchers/built_in/eql.rb +5 -1
  19. data/lib/rspec/matchers/built_in/exist.rb +1 -1
  20. data/lib/rspec/matchers/built_in/has.rb +29 -2
  21. data/lib/rspec/matchers/built_in/include.rb +14 -2
  22. data/lib/rspec/matchers/built_in/match.rb +2 -0
  23. data/lib/rspec/matchers/built_in/raise_error.rb +11 -7
  24. data/lib/rspec/matchers/built_in/satisfy.rb +2 -0
  25. data/lib/rspec/matchers/built_in/throw_symbol.rb +4 -4
  26. data/lib/rspec/matchers/composable.rb +1 -1
  27. data/lib/rspec/matchers/dsl.rb +10 -9
  28. data/lib/rspec/matchers/english_phrasing.rb +2 -0
  29. data/lib/rspec/matchers/matcher_delegator.rb +27 -1
  30. data/lib/rspec/matchers/{expecteds_for_multiple_diffs.rb → multi_matcher_diff.rb} +16 -16
  31. data/lib/rspec/matchers.rb +10 -5
  32. data.tar.gz.sig +0 -0
  33. metadata +8 -8
  34. metadata.gz.sig +0 -0
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e651e80dd869915779a72a9ea43b38d20327f3dbfaf94a4851eff7974d1f3d0a
4
- data.tar.gz: e1788055c911b97cbad1b3747fe9b9be005a999e2e97e6c361df4c91fa4fda25
3
+ metadata.gz: 2326091f61f5fccf3b86b2275c850340614475381f32a9f22417cb9f59b80ab3
4
+ data.tar.gz: 7602b8b98d0dc9fecc754156a01686a131fedd6d43fe1b8ce8f689f0fba3b469
5
5
  SHA512:
6
- metadata.gz: ec1b6b68b80fddae764dbf88312817c35c1e76228c29748e2b89d8d9a69d95384aa4fe9daf7b8a650dd307dd32aca13bae590d8960f0989beea67c54f7f6d7d5
7
- data.tar.gz: 7a8a129e74ccec6299ab3af1c728cab2754a1cc98911507704c3f52a01c33b321250bfe715deef835b61963e22c66ec878500d10c6fea93d4fda7cc39b101676
6
+ metadata.gz: 21d9a95f4e9cb3fa1b7fb99419861bc90a39ee33b4fa183a1018ab351d830168bd93fb02e00452344e1c8d9824bc3d0543b988e42288396c8a3091b9fc5d6f9c
7
+ data.tar.gz: ec4864365250340370d370af68dee725f3d018e414e57506d21d173e9d0a69a9df258f7d7a11e8f2ff583f4060348a76bb3251aa09a29add0ddee6fb2b0d4192
checksums.yaml.gz.sig CHANGED
Binary file
data/Changelog.md CHANGED
@@ -1,5 +1,92 @@
1
1
  ### Development
2
- [Full Changelog](http://github.com/rspec/rspec-expectations/compare/v3.11.0...3-11-maintenance)
2
+ [Full Changelog](http://github.com/rspec/rspec-expectations/compare/v3.13.3...3-13-maintenance)
3
+
4
+ ### 3.13.3 / 2024-09-07
5
+ [Full Changelog](http://github.com/rspec/rspec-expectations/compare/v3.13.2...v3.13.3)
6
+
7
+ Bug Fixes:
8
+
9
+ * Fix passing a regular expression to the `include` matcher without a count constraint.
10
+ (Jon Rowe, #1485)
11
+
12
+ ### 3.13.2 / 2024-08-20
13
+ [Full Changelog](http://github.com/rspec/rspec-expectations/compare/v3.13.1...v3.13.2)
14
+
15
+ Bug Fixes:
16
+
17
+ * When using null object doubles, prevent typos triggering dynamic matchers.
18
+ (Eric Mueller, #1455)
19
+ * Use `RSpec.warning` for an expectation warning rather than `Kernel.warn`. (Jon Rowe, #1472)
20
+ * Prevent mismatched use of block and value matchers in compound expectations. (Phil Pirozhkov, #1476)
21
+ * Raise an error when passing no arguments to the `include` matcher. (Eric Mueller, #1479)
22
+
23
+ ### 3.13.1 / 2024-06-13
24
+ [Full Changelog](http://github.com/rspec/rspec-expectations/compare/v3.13.0...v3.13.1)
25
+
26
+ Bug Fixes:
27
+
28
+ * Fix the "false positive" warning message when using a negated `raise_error` matcher
29
+ with a `RegExp` instance. (Eric Mueller, #1456)
30
+
31
+ ### 3.13.0 / 2024-02-04
32
+ [Full Changelog](http://github.com/rspec/rspec-expectations/compare/v3.12.4...v3.13.0)
33
+
34
+ Enhancements:
35
+
36
+ * Update `eq` and `eql` matchers to better highlight difference in string encoding.
37
+ (Alan Foster, #1425)
38
+
39
+ ### 3.12.4 / 2024-02-04
40
+ [Full Changelog](http://github.com/rspec/rspec-expectations/compare/v3.12.3...v3.12.4)
41
+
42
+ Bug Fixes:
43
+
44
+ * Fix the diff for redefined `actual` and reassigned `@actual` in compound
45
+ expectations failure messages. (Phil Pirozhkov, #1440)
46
+
47
+ ### 3.12.3 / 2023-04-20
48
+ [Full Changelog](http://github.com/rspec/rspec-expectations/compare/v3.12.2...v3.12.3)
49
+
50
+ Bug Fixes:
51
+
52
+ * Fix `include` matcher when fuzzy matching on keys with a hash-like actual which
53
+ has a non standard `key?` method which may raise.
54
+ (Jon Rowe, #1416)
55
+
56
+ ### 3.12.2 / 2023-01-07
57
+ [Full Changelog](http://github.com/rspec/rspec-expectations/compare/v3.12.1...v3.12.2)
58
+
59
+ Bug Fixes:
60
+
61
+ * Prevent deprecation warning when using the `exist` matcher with `Dir`.
62
+ (Steve Dierker, #1398)
63
+
64
+ ### 3.12.1 / 2022-12-16
65
+ [Full Changelog](http://github.com/rspec/rspec-expectations/compare/v3.12.0...v3.12.1)
66
+
67
+ Bug Fixes:
68
+
69
+ * Pass keyword arguments through to aliased (and thus negated) matchers. (Jon Rowe, #1394)
70
+ * When handling failures in an aggregated_failures block (or example) prevent
71
+ the failure list leaking out. (Maciek Rząsa, #1392)
72
+
73
+ ### 3.12.0 / 2022-10-26
74
+ [Full Changelog](http://github.com/rspec/rspec-expectations/compare/v3.11.1...v3.12.0)
75
+
76
+ Enhancements:
77
+
78
+ * Add `an_array_matching` alias for `match_array` to improve readability as an argument
79
+ matcher. (Mark Schneider, #1361)
80
+
81
+ ### 3.11.1 / 2022-09-12
82
+ [Full Changelog](http://github.com/rspec/rspec-expectations/compare/v3.11.0...v3.11.1)
83
+
84
+ Bug Fixes:
85
+
86
+ * Allow the `contain_exactly` matcher to be reused by resetting its
87
+ internals on `matches?` (@bclayman-sq, #1326)
88
+ * Using the exist matcher on `FileTest` no longer produces a deprecation warning.
89
+ (Ryo Nakamura, #1383)
3
90
 
4
91
  ### 3.11.0 / 2022-02-09
5
92
  [Full Changelog](http://github.com/rspec/rspec-expectations/compare/v3.10.2...v3.11.0)
@@ -296,10 +383,8 @@ Enhancements:
296
383
  can cause uses of `super` to trigger infinite recursion. (Myron Marston, #816)
297
384
  * Stop rescuing `NoMemoryError`, `SignalExcepetion`, `Interrupt` and
298
385
  `SystemExit`. It is dangerous to interfere with these. (Myron Marston, #845)
299
- * Add `#with_captures` to the
300
- [match matcher](https://www.relishapp.com/rspec/rspec-expectations/docs/built-in-matchers/match-matcher)
301
- which allows a user to specify expected captures when matching a regex
302
- against a string. (Sam Phippen, #848)
386
+ * Add `#with_captures` to the match matcher which allows a user to specify expected
387
+ captures when matching a regex against a string. (Sam Phippen, #848)
303
388
  * Always print compound failure messages in the multi-line form. Trying
304
389
  to print it all on a single line didn't read very well. (Myron Marston, #859)
305
390
 
data/README.md CHANGED
@@ -13,7 +13,9 @@ If you want to use rspec-expectations with rspec, just install the rspec gem
13
13
  and RubyGems will also install rspec-expectations for you (along with
14
14
  rspec-core and rspec-mocks):
15
15
 
16
- gem install rspec
16
+ ```shell
17
+ gem install rspec
18
+ ```
17
19
 
18
20
  Want to run against the `main` branch? You'll need to include the dependent
19
21
  RSpec repos as well. Add the following to your `Gemfile`:
@@ -27,7 +29,9 @@ end
27
29
  If you want to use rspec-expectations with another tool, like Test::Unit,
28
30
  Minitest, or Cucumber, you can install it directly:
29
31
 
30
- gem install rspec-expectations
32
+ ```shell
33
+ gem install rspec-expectations
34
+ ```
31
35
 
32
36
  ## Contributing
33
37
 
@@ -67,8 +71,10 @@ The `describe` and `it` methods come from rspec-core. The `Order`, `LineItem`,
67
71
  expresses an expected outcome. If `order.total == Money.new(5.55, :USD)`, then
68
72
  the example passes. If not, it fails with a message like:
69
73
 
70
- expected: #<Money @value=5.55 @currency=:USD>
71
- got: #<Money @value=1.11 @currency=:USD>
74
+ ```
75
+ expected: #<Money @value=5.55 @currency=:USD>
76
+ got: #<Money @value=1.11 @currency=:USD>
77
+ ```
72
78
 
73
79
  ## Built-in matchers
74
80
 
@@ -46,11 +46,13 @@ module RSpec
46
46
  RSpec.world.source_from_file(file_path)
47
47
  end
48
48
  else
49
+ # :nocov:
49
50
  RSpec::Support.require_rspec_support 'source'
50
51
  def source
51
52
  raise TargetNotFoundError unless File.exist?(file_path)
52
53
  @source ||= RSpec::Support::Source.from_file(file_path)
53
54
  end
55
+ # :nocov:
54
56
  end
55
57
 
56
58
  def file_path
@@ -89,6 +89,7 @@ module RSpec
89
89
  ::RSpec.configuration.color_enabled?
90
90
  end
91
91
  else
92
+ # :nocov:
92
93
  # Indicates whether or not diffs should be colored.
93
94
  # Delegates to rspec-core's color option if rspec-core
94
95
  # is loaded; otherwise you can set it here.
@@ -100,8 +101,11 @@ module RSpec
100
101
  def color?
101
102
  defined?(@color) && @color
102
103
  end
104
+ # :nocov:
103
105
  end
104
106
 
107
+ # :nocov: Because this is only really _useful_ on 1.8, and hard to test elsewhere.
108
+ #
105
109
  # Adds `should` and `should_not` to the given classes
106
110
  # or modules. This can be used to ensure `should` works
107
111
  # properly on things like proxy objects (particular
@@ -114,6 +118,7 @@ module RSpec
114
118
  Expectations::Syntax.enable_should(mod)
115
119
  end
116
120
  end
121
+ # :nocov:
117
122
 
118
123
  # Sets or gets the backtrace formatter. The backtrace formatter should
119
124
  # implement `#format_backtrace(Array<String>)`. This is used
@@ -30,7 +30,7 @@ module RSpec
30
30
  "appropriate failure_message[_when_negated] method to return a string?"
31
31
  end
32
32
 
33
- message = ::RSpec::Matchers::ExpectedsForMultipleDiffs.from(expected).message_with_diff(message, differ, actual)
33
+ message = ::RSpec::Matchers::MultiMatcherDiff.from(expected, actual).message_with_diff(message, differ)
34
34
 
35
35
  RSpec::Support.notify_failure(RSpec::Expectations::ExpectationNotMetError.new message)
36
36
  end
@@ -4,6 +4,26 @@ module RSpec
4
4
  class FailureAggregator
5
5
  attr_reader :block_label, :metadata
6
6
 
7
+ # @private
8
+ class AggregatedFailure
9
+ # :nocov:
10
+ # `inspect` was apparently used by some versions early in ruby 3 while constructing
11
+ # NoMethodError, but seems to be no longer.
12
+ #
13
+ # @private
14
+ MESSAGE =
15
+ 'AggregatedFailure: This method caused a failure which has been ' \
16
+ 'suppressed to be aggregated into our failure report by returning ' \
17
+ 'this value, further errors can be ignored.'
18
+
19
+ def inspect
20
+ MESSAGE
21
+ end
22
+ # :nocov:
23
+ end
24
+
25
+ AGGREGATED_FAILURE = AggregatedFailure.new
26
+
7
27
  def aggregate
8
28
  RSpec::Support.with_failure_notifier(self) do
9
29
  begin
@@ -48,6 +68,8 @@ module RSpec
48
68
  @seen_source_ids[source_id] = true
49
69
  assign_backtrace(failure) unless failure.backtrace
50
70
  failures << failure
71
+
72
+ AGGREGATED_FAILURE
51
73
  end
52
74
 
53
75
  private
@@ -58,11 +80,13 @@ module RSpec
58
80
  # a backtrace that has a continuous common section with the raised `MultipleExpectationsNotMetError`,
59
81
  # so that rspec-core's truncation logic can work properly on it to list the backtrace
60
82
  # relative to the `aggregate_failures` block.
83
+ # :nocov:
61
84
  def assign_backtrace(failure)
62
85
  raise failure
63
86
  rescue failure.class => e
64
87
  failure.set_backtrace(e.backtrace)
65
88
  end
89
+ # :nocov:
66
90
  else
67
91
  # Using `caller` performs better (and is simpler) than `raise` on most Rubies.
68
92
  def assign_backtrace(failure)
@@ -4,11 +4,10 @@ module RSpec
4
4
  module ExpectationHelper
5
5
  def self.check_message(msg)
6
6
  unless msg.nil? || msg.respond_to?(:to_str) || msg.respond_to?(:call)
7
- ::Kernel.warn [
8
- "WARNING: ignoring the provided expectation message argument (",
9
- msg.inspect,
10
- ") since it is not a string or a proc."
11
- ].join
7
+ RSpec.warning(
8
+ "ignoring the provided expectation message argument" \
9
+ "(#{ msg.inspect }) since it is not a string or a proc"
10
+ )
12
11
  end
13
12
  end
14
13
 
@@ -2,7 +2,7 @@ module RSpec
2
2
  module Expectations
3
3
  # @private
4
4
  module Version
5
- STRING = '3.11.0'
5
+ STRING = '3.13.3'
6
6
  end
7
7
  end
8
8
  end
@@ -99,14 +99,14 @@ module RSpec
99
99
  # by going through the effort of defining a negated matcher.
100
100
  #
101
101
  # However, if the override didn't actually change anything, then we
102
- # should return the opposite failure message instead -- the overriden
102
+ # should return the opposite failure message instead -- the overridden
103
103
  # message is going to be confusing if we return it as-is, as it represents
104
104
  # the non-negated failure message for a negated match (or vice versa).
105
105
  def optimal_failure_message(same, inverted)
106
106
  if DefaultFailureMessages.has_default_failure_messages?(@base_matcher)
107
107
  base_message = @base_matcher.__send__(same)
108
- overriden = @description_block.call(base_message)
109
- return overriden if overriden != base_message
108
+ overridden = @description_block.call(base_message)
109
+ return overridden if overridden != base_message
110
110
  end
111
111
 
112
112
  @base_matcher.__send__(inverted)
@@ -124,24 +124,6 @@ module RSpec
124
124
  end
125
125
  private_class_method :underscore
126
126
 
127
- private
128
-
129
- def assert_ivars(*expected_ivars)
130
- return unless (expected_ivars - present_ivars).any?
131
- ivar_list = EnglishPhrasing.list(expected_ivars)
132
- raise "#{self.class.name} needs to supply#{ivar_list}"
133
- end
134
-
135
- if RUBY_VERSION.to_f < 1.9
136
- # :nocov:
137
- def present_ivars
138
- instance_variables.map(&:to_sym)
139
- end
140
- # :nocov:
141
- else
142
- alias present_ivars instance_variables
143
- end
144
-
145
127
  # @private
146
128
  module HashFormatting
147
129
  # `{ :a => 5, :b => 2 }.inspect` produces:
@@ -161,6 +143,51 @@ module RSpec
161
143
 
162
144
  include HashFormatting
163
145
 
146
+ # @private
147
+ module StringEncodingFormatting
148
+ # @api private
149
+ # @return [Boolean] True if the actual and expected string encoding are different.
150
+ # i.e. the failure may be related to encoding differences and the encoding
151
+ # should be shown to the user. false otherwise.
152
+ if String.method_defined?(:encoding)
153
+ def string_encoding_differs?
154
+ actual.is_a?(String) && expected.is_a?(String) && actual.encoding != expected.encoding
155
+ end
156
+ else
157
+ # @api private
158
+ # @return [Boolean] False always as the curent Ruby version does not support String encoding
159
+ # :nocov:
160
+ def string_encoding_differs?
161
+ false
162
+ end
163
+ # :nocov:
164
+ end
165
+ module_function :string_encoding_differs?
166
+
167
+ if String.method_defined?(:encoding)
168
+ # @api private
169
+ # Formats a String's encoding as a human readable string
170
+ # @param value [String]
171
+ # @return [String]
172
+ def format_encoding(value)
173
+ "#<Encoding:#{value.encoding.name}>"
174
+ end
175
+ else
176
+ # @api private
177
+ # Formats a String's encoding as a human readable string
178
+ # @param _value [String]
179
+ # @return [nil] nil as the curent Ruby version does not support String encoding
180
+ # :nocov:
181
+ def format_encoding(_value)
182
+ nil
183
+ end
184
+ # :nocov:
185
+ end
186
+ module_function :format_encoding
187
+ end
188
+
189
+ include StringEncodingFormatting
190
+
164
191
  # @api private
165
192
  # Provides default implementations of failure messages, based on the `description`.
166
193
  module DefaultFailureMessages
@@ -440,9 +440,11 @@ module RSpec
440
440
  Expectations::BlockSnippetExtractor.try_extracting_single_line_body_of(@value_proc, @matcher_name)
441
441
  end
442
442
  else
443
+ # :nocov:
443
444
  def extract_value_block_snippet
444
445
  nil
445
446
  end
447
+ # :nocov:
446
448
  end
447
449
  end
448
450
  end
@@ -51,10 +51,10 @@ module RSpec
51
51
  end
52
52
 
53
53
  # @api private
54
- # @return [RSpec::Matchers::ExpectedsForMultipleDiffs]
54
+ # @return [RSpec::Matchers::MultiMatcherDiff]
55
55
  def expected
56
56
  return nil unless evaluator
57
- ::RSpec::Matchers::ExpectedsForMultipleDiffs.for_many_matchers(diffable_matcher_list)
57
+ ::RSpec::Matchers::MultiMatcherDiff.for_many_matchers(diffable_matcher_list)
58
58
  end
59
59
 
60
60
  protected
@@ -77,8 +77,11 @@ module RSpec
77
77
  def match(_expected, actual)
78
78
  evaluator_klass = if supports_block_expectations? && Proc === actual
79
79
  NestedEvaluator
80
- else
80
+ elsif supports_value_expectations?
81
81
  SequentialEvaluator
82
+ else
83
+ # Can't raise an ArgumentError in this context, as it's rescued
84
+ raise "Block and value matchers can't be combined in a compound expectation (#{matcher_1.description}, #{matcher_2.description})"
82
85
  end
83
86
 
84
87
  @evaluator = evaluator_klass.new(actual, matcher_1, matcher_2)
@@ -171,7 +174,7 @@ module RSpec
171
174
  @match_results.fetch(matcher) do
172
175
  raise ArgumentError, "Your #{matcher.description} has no match " \
173
176
  "results, this can occur when an unexpected call stack or " \
174
- "local jump occurs. Prehaps one of your matchers needs to " \
177
+ "local jump occurs. Perhaps one of your matchers needs to " \
175
178
  "declare `expects_call_stack_jump?` as `true`?"
176
179
  end
177
180
  end
@@ -1,7 +1,7 @@
1
1
  module RSpec
2
2
  module Matchers
3
3
  module BuiltIn
4
- # rubocop:disable ClassLength
4
+ # rubocop:disable Metrics/ClassLength
5
5
  # @api private
6
6
  # Provides the implementation for `contain_exactly` and `match_array`.
7
7
  # Not intended to be instantiated directly.
@@ -31,6 +31,14 @@ module RSpec
31
31
  "contain exactly#{list}"
32
32
  end
33
33
 
34
+ def matches?(actual)
35
+ @pairings_maximizer = nil
36
+ @best_solution = nil
37
+ @extra_items = nil
38
+ @missing_items = nil
39
+ super(actual)
40
+ end
41
+
34
42
  private
35
43
 
36
44
  def generate_failure_message
@@ -100,12 +108,14 @@ module RSpec
100
108
  end
101
109
 
102
110
  if RUBY_VERSION == "1.8.7"
111
+ # :nocov:
103
112
  def to_a_disallowed?(object)
104
113
  case object
105
114
  when NilClass, String then true
106
115
  else Kernel == RSpec::Support.method_handle_for(object, :to_a).owner
107
116
  end
108
117
  end
118
+ # :nocov:
109
119
  else
110
120
  def to_a_disallowed?(object)
111
121
  NilClass === object
@@ -296,7 +306,7 @@ module RSpec
296
306
  end
297
307
  end
298
308
  end
299
- # rubocop:enable ClassLength
309
+ # rubocop:enable Metrics/ClassLength
300
310
  end
301
311
  end
302
312
  end
@@ -2,7 +2,7 @@ module RSpec
2
2
  module Matchers
3
3
  module BuiltIn
4
4
  # @api private
5
- # Asbtract class to implement `once`, `at_least` and other
5
+ # Abstract class to implement `once`, `at_least` and other
6
6
  # count constraints.
7
7
  module CountExpectation
8
8
  # @api public
@@ -61,9 +61,11 @@ module RSpec
61
61
  count.cover?(number)
62
62
  end
63
63
  else
64
+ # :nocov:
64
65
  def cover?(count, number)
65
66
  number >= count.first && number <= count.last
66
67
  end
68
+ # :nocov:
67
69
  end
68
70
 
69
71
  def expected_count_matches?(actual_count)
@@ -8,7 +8,11 @@ module RSpec
8
8
  # @api private
9
9
  # @return [String]
10
10
  def failure_message
11
- "\nexpected: #{expected_formatted}\n got: #{actual_formatted}\n\n(compared using ==)\n"
11
+ if string_encoding_differs?
12
+ "\nexpected: #{format_encoding(expected)} #{expected_formatted}\n got: #{format_encoding(actual)} #{actual_formatted}\n\n(compared using ==)\n"
13
+ else
14
+ "\nexpected: #{expected_formatted}\n got: #{actual_formatted}\n\n(compared using ==)\n"
15
+ end
12
16
  end
13
17
 
14
18
  # @api private
@@ -8,7 +8,11 @@ module RSpec
8
8
  # @api private
9
9
  # @return [String]
10
10
  def failure_message
11
- "\nexpected: #{expected_formatted}\n got: #{actual_formatted}\n\n(compared using eql?)\n"
11
+ if string_encoding_differs?
12
+ "\nexpected: #{format_encoding(expected)} #{expected_formatted}\n got: #{format_encoding(actual)} #{actual_formatted}\n\n(compared using eql?)\n"
13
+ else
14
+ "\nexpected: #{expected_formatted}\n got: #{actual_formatted}\n\n(compared using eql?)\n"
15
+ end
12
16
  end
13
17
 
14
18
  # @api private
@@ -81,7 +81,7 @@ module RSpec
81
81
  end
82
82
 
83
83
  def deprecated(predicate, actual)
84
- predicate == :exists? && File == actual
84
+ predicate == :exists? && (File == actual || FileTest == actual || Dir == actual)
85
85
  end
86
86
  end
87
87
  end
@@ -46,8 +46,27 @@ module RSpec
46
46
 
47
47
  private
48
48
 
49
+ # Catch a semi-frequent typo - if you have strict_predicate_matchers disabled and
50
+ # expect(spy).to have_receieveddd(:foo) it would be evergreen - the dynamic matcher
51
+ # queries `has_receiveddd?`, the spy _fakes_ the method, returning its (truthy) self.
52
+ if defined?(RSpec::Mocks::Double)
53
+ def really_responds_to?(method)
54
+ if RSpec::Mocks::Double === @actual
55
+ @actual.respond_to?(method) && methods_include?(method)
56
+ else
57
+ @actual.respond_to?(method)
58
+ end
59
+ end
60
+ else
61
+ # :nocov:
62
+ def really_responds_to?(method)
63
+ @actual.respond_to?(method)
64
+ end
65
+ # :nocov:
66
+ end
67
+
49
68
  def predicate_accessible?
50
- @actual.respond_to? predicate
69
+ really_responds_to?(predicate)
51
70
  end
52
71
 
53
72
  # support 1.8.7, evaluate once at load time for performance
@@ -56,11 +75,19 @@ module RSpec
56
75
  def private_predicate?
57
76
  @actual.private_methods.include? predicate.to_s
58
77
  end
78
+
79
+ def methods_include?(method)
80
+ @actual.methods.include?(method.to_s)
81
+ end
59
82
  # :nocov:
60
83
  else
61
84
  def private_predicate?
62
85
  @actual.private_methods.include? predicate
63
86
  end
87
+
88
+ def methods_include?(method)
89
+ @actual.methods.include?(method)
90
+ end
64
91
  end
65
92
 
66
93
  def predicate_result
@@ -155,7 +182,7 @@ module RSpec
155
182
  end
156
183
 
157
184
  def predicate_accessible?
158
- super || actual.respond_to?(present_tense_predicate)
185
+ super || really_responds_to?(present_tense_predicate)
159
186
  end
160
187
 
161
188
  def present_tense_predicate
@@ -13,6 +13,7 @@ module RSpec
13
13
 
14
14
  # @api private
15
15
  def initialize(*expecteds)
16
+ raise(ArgumentError, 'include() is not supported, please supply an argument') if expecteds.empty?
16
17
  @expecteds = expecteds
17
18
  end
18
19
 
@@ -153,11 +154,19 @@ module RSpec
153
154
  def actual_hash_has_key?(expected_key)
154
155
  # We check `key?` first for perf:
155
156
  # `key?` is O(1), but `any?` is O(N).
156
- actual.key?(expected_key) ||
157
- actual.keys.any? { |key| values_match?(expected_key, key) }
157
+
158
+ has_exact_key =
159
+ begin
160
+ actual.key?(expected_key)
161
+ rescue
162
+ false
163
+ end
164
+
165
+ has_exact_key || actual.keys.any? { |key| values_match?(expected_key, key) }
158
166
  end
159
167
 
160
168
  def actual_collection_includes?(expected_item)
169
+ return actual.scan(expected_item).size > 0 if Regexp === expected_item && String === actual
161
170
  return true if actual.include?(expected_item)
162
171
 
163
172
  # String lacks an `any?` method...
@@ -167,9 +176,11 @@ module RSpec
167
176
  end
168
177
 
169
178
  if RUBY_VERSION < '1.9'
179
+ # :nocov:
170
180
  def count_enumerable(expected_item)
171
181
  actual.select { |value| values_match?(expected_item, value) }.size
172
182
  end
183
+ # :nocov:
173
184
  else
174
185
  def count_enumerable(expected_item)
175
186
  actual.count { |value| values_match?(expected_item, value) }
@@ -190,6 +201,7 @@ module RSpec
190
201
 
191
202
  def diff_would_wrongly_highlight_matched_item?
192
203
  return false unless actual.is_a?(String) && expected.is_a?(Array)
204
+ return false if Regexp === expecteds.first
193
205
 
194
206
  lines = actual.split("\n")
195
207
  expected.any? do |str|
@@ -78,9 +78,11 @@ module RSpec
78
78
  # @api private
79
79
  # Returns match data names for named captures
80
80
  # @return Array
81
+ # :nocov:
81
82
  def names
82
83
  []
83
84
  end
85
+ # :nocov:
84
86
  else
85
87
  # @api private
86
88
  # Returns match data names for named captures
@@ -4,8 +4,8 @@ module RSpec
4
4
  # @api private
5
5
  # Provides the implementation for `raise_error`.
6
6
  # Not intended to be instantiated directly.
7
- # rubocop:disable ClassLength
8
- # rubocop:disable RescueException
7
+ # rubocop:disable Metrics/ClassLength
8
+ # rubocop:disable Lint/RescueException
9
9
  class RaiseError
10
10
  include Composable
11
11
 
@@ -13,6 +13,10 @@ module RSpec
13
13
  # argument. We can't use `nil` for that because we need to warn when `nil` is
14
14
  # passed in a different way. It's an Object, not a Module, since Module's `===`
15
15
  # does not evaluate to true when compared to itself.
16
+ #
17
+ # Note; this _is_ the default value supplied for expected_error_or_message, but
18
+ # because there are two method-calls involved, that default is actually supplied
19
+ # in the definition of the _matcher_ method, `RSpec::Matchers#raise_error`
16
20
  UndefinedValue = Object.new.freeze
17
21
 
18
22
  def initialize(expected_error_or_message, expected_message, &block)
@@ -25,7 +29,7 @@ module RSpec
25
29
  when nil, UndefinedValue
26
30
  @expected_error = Exception
27
31
  @expected_message = expected_message
28
- when String
32
+ when String, Regexp
29
33
  @expected_error = Exception
30
34
  @expected_message = expected_error_or_message
31
35
  else
@@ -43,7 +47,7 @@ module RSpec
43
47
  self
44
48
  end
45
49
 
46
- # rubocop:disable MethodLength
50
+ # rubocop:disable Metrics/MethodLength
47
51
  # @private
48
52
  def matches?(given_proc, negative_expectation=false, &block)
49
53
  @given_proc = given_proc
@@ -73,7 +77,7 @@ module RSpec
73
77
 
74
78
  expectation_matched?
75
79
  end
76
- # rubocop:enable MethodLength
80
+ # rubocop:enable Metrics/MethodLength
77
81
 
78
82
  # @private
79
83
  def does_not_match?(given_proc)
@@ -264,8 +268,8 @@ module RSpec
264
268
  warning if @actual_error
265
269
  end
266
270
  end
267
- # rubocop:enable RescueException
268
- # rubocop:enable ClassLength
271
+ # rubocop:enable Lint/RescueException
272
+ # rubocop:enable Metrics/ClassLength
269
273
  end
270
274
  end
271
275
  end
@@ -50,9 +50,11 @@ module RSpec
50
50
  Expectations::BlockSnippetExtractor.try_extracting_single_line_body_of(@block, matcher_name)
51
51
  end
52
52
  else
53
+ # :nocov:
53
54
  def block_representation
54
55
  'block'
55
56
  end
57
+ # :nocov:
56
58
  end
57
59
  end
58
60
  end
@@ -13,7 +13,7 @@ module RSpec
13
13
  @caught_symbol = @caught_arg = nil
14
14
  end
15
15
 
16
- # rubocop:disable MethodLength
16
+ # rubocop:disable Metrics/MethodLength
17
17
  # @private
18
18
  def matches?(given_proc)
19
19
  @block = given_proc
@@ -48,7 +48,7 @@ module RSpec
48
48
  rescue => other_exception
49
49
  raise
50
50
  ensure
51
- # rubocop:disable EnsureReturn
51
+ # rubocop:disable Lint/EnsureReturn
52
52
  unless other_exception
53
53
  if @expected_symbol.nil?
54
54
  return !!@caught_symbol
@@ -60,10 +60,10 @@ module RSpec
60
60
  end
61
61
  end
62
62
  end
63
- # rubocop:enable EnsureReturn
63
+ # rubocop:enable Lint/EnsureReturn
64
64
  end
65
65
  end
66
- # rubocop:enable MethodLength
66
+ # rubocop:enable Metrics/MethodLength
67
67
 
68
68
  def does_not_match?(given_proc)
69
69
  !matches?(given_proc) && Proc === given_proc
@@ -83,7 +83,7 @@ module RSpec
83
83
  RSpec::Support::ObjectFormatter.format(object)
84
84
  end
85
85
 
86
- # Transforms the given data structue (typically a hash or array)
86
+ # Transforms the given data structure (typically a hash or array)
87
87
  # into a new data structure that, when `#inspect` is called on it,
88
88
  # will provide descriptions of any contained matchers rather than
89
89
  # the normal `#inspect` output.
@@ -4,7 +4,7 @@ module RSpec
4
4
  module Matchers
5
5
  # Defines the custom matcher DSL.
6
6
  module DSL
7
- # Defines a matcher alias. The returned matcher's `description` will be overriden
7
+ # Defines a matcher alias. The returned matcher's `description` will be overridden
8
8
  # to reflect the phrasing of the new name, which will be used in failure messages
9
9
  # when passed as an argument to another matcher in a composed matcher expression.
10
10
  #
@@ -25,7 +25,7 @@ module RSpec
25
25
  # @param old_name [Symbol] the original name for the matcher
26
26
  # @param options [Hash] options for the aliased matcher
27
27
  # @option options [Class] :klass the ruby class to use as the decorator. (Not normally used).
28
- # @yield [String] optional block that, when given, is used to define the overriden
28
+ # @yield [String] optional block that, when given, is used to define the overridden
29
29
  # logic. The yielded arg is the original description or failure message. If no
30
30
  # block is provided, a default override is used based on the old and new names.
31
31
  # @see RSpec::Matchers
@@ -40,10 +40,11 @@ module RSpec
40
40
  matcher.matcher_name = new_name if matcher.respond_to?(:matcher_name=)
41
41
  klass.new(matcher, description_override)
42
42
  end
43
+ ruby2_keywords new_name if respond_to?(:ruby2_keywords, true)
43
44
  end
44
45
 
45
46
  # Defines a negated matcher. The returned matcher's `description` and `failure_message`
46
- # will be overriden to reflect the phrasing of the new name, and the match logic will
47
+ # will be overridden to reflect the phrasing of the new name, and the match logic will
47
48
  # be based on the original matcher but negated.
48
49
  #
49
50
  # @example
@@ -53,7 +54,7 @@ module RSpec
53
54
  #
54
55
  # @param negated_name [Symbol] the name for the negated matcher
55
56
  # @param base_name [Symbol] the name of the original matcher that will be negated
56
- # @yield [String] optional block that, when given, is used to define the overriden
57
+ # @yield [String] optional block that, when given, is used to define the overridden
57
58
  # logic. The yielded arg is the original description or failure message. If no
58
59
  # block is provided, a default override is used based on the old and new names.
59
60
  # @see RSpec::Matchers
@@ -122,7 +123,7 @@ module RSpec
122
123
  #
123
124
  # By default the match block will swallow expectation errors (e.g.
124
125
  # caused by using an expectation such as `expect(1).to eq 2`), if you
125
- # with to allow these to bubble up, pass in the option
126
+ # wish to allow these to bubble up, pass in the option
126
127
  # `:notify_expectation_failures => true`.
127
128
  #
128
129
  # @param [Hash] options for defining the behavior of the match block.
@@ -151,7 +152,7 @@ module RSpec
151
152
  #
152
153
  # By default the match block will swallow expectation errors (e.g.
153
154
  # caused by using an expectation such as `expect(1).to eq 2`), if you
154
- # with to allow these to bubble up, pass in the option
155
+ # wish to allow these to bubble up, pass in the option
155
156
  # `:notify_expectation_failures => true`.
156
157
  #
157
158
  # @param [Hash] options for defining the behavior of the match block.
@@ -197,7 +198,7 @@ module RSpec
197
198
  end
198
199
  end
199
200
 
200
- # Customizes the failure messsage to use when this matcher is
201
+ # Customizes the failure message to use when this matcher is
201
202
  # asked to positively match. Only use this when the message
202
203
  # generated by default doesn't suit your needs.
203
204
  #
@@ -216,7 +217,7 @@ module RSpec
216
217
  define_user_override(__method__, definition)
217
218
  end
218
219
 
219
- # Customize the failure messsage to use when this matcher is asked
220
+ # Customize the failure message to use when this matcher is asked
220
221
  # to negatively match. Only use this when the message generated by
221
222
  # default doesn't suit your needs.
222
223
  #
@@ -330,7 +331,7 @@ module RSpec
330
331
  # - Defines the named method using a user-provided block
331
332
  # in @user_method_defs, which is included as an ancestor
332
333
  # in the singleton class in which we eval the `define` block.
333
- # - Defines an overriden definition for the same method
334
+ # - Defines an overridden definition for the same method
334
335
  # usign the provided `our_def` block.
335
336
  # - Provides a default `our_def` block for the common case
336
337
  # of needing to call the user's definition with `@actual`
@@ -45,12 +45,14 @@ module RSpec
45
45
  # So here we replace `Kernel#Array` with our own warning-free implementation for 1.8.7.
46
46
  # @private
47
47
  # rubocop:disable Naming/MethodName
48
+ # :nocov:
48
49
  def self.Array(obj)
49
50
  case obj
50
51
  when Array then obj
51
52
  else [obj]
52
53
  end
53
54
  end
55
+ # :nocov:
54
56
  # rubocop:enable Naming/MethodName
55
57
  end
56
58
  end
@@ -1,8 +1,34 @@
1
1
  module RSpec
2
2
  module Matchers
3
+ # Provides a base class with as little methods as possible, so that
4
+ # most methods can be delegated via `method_missing`.
5
+ #
6
+ # On Ruby 2.0+ BasicObject could be used for this purpose, but it
7
+ # introduce some extra complexity with constant resolution, so the
8
+ # BlankSlate pattern was prefered.
9
+ # @private
10
+ class BaseDelegator
11
+ kept_methods = [
12
+ # Methods that raise warnings if removed.
13
+ :__id__, :__send__, :object_id,
14
+
15
+ # Methods that are explicitly undefined in some subclasses.
16
+ :==, :===,
17
+
18
+ # Methods we keep on purpose.
19
+ :class, :respond_to?, :__method__, :method, :dup,
20
+ :clone, :initialize_dup, :initialize_copy, :initialize_clone,
21
+ ]
22
+ instance_methods.each do |method|
23
+ unless kept_methods.include?(method.to_sym)
24
+ undef_method(method)
25
+ end
26
+ end
27
+ end
28
+
3
29
  # Provides the necessary plumbing to wrap a matcher with a decorator.
4
30
  # @private
5
- class MatcherDelegator
31
+ class MatcherDelegator < BaseDelegator
6
32
  include Composable
7
33
  attr_reader :base_matcher
8
34
 
@@ -1,9 +1,9 @@
1
1
  module RSpec
2
2
  module Matchers
3
3
  # @api private
4
- # Handles list of expected values when there is a need to render
5
- # multiple diffs. Also can handle one value.
6
- class ExpectedsForMultipleDiffs
4
+ # Handles list of expected and actual value pairs when there is a need
5
+ # to render multiple diffs. Also can handle one pair.
6
+ class MultiMatcherDiff
7
7
  # @private
8
8
  # Default diff label when there is only one matcher in diff
9
9
  # output
@@ -19,22 +19,23 @@ module RSpec
19
19
 
20
20
  # @api private
21
21
  # Wraps provided expected value in instance of
22
- # ExpectedForMultipleDiffs. If provided value is already an
23
- # ExpectedForMultipleDiffs then it just returns it.
22
+ # MultiMatcherDiff. If provided value is already an
23
+ # MultiMatcherDiff then it just returns it.
24
24
  # @param [Any] expected value to be wrapped
25
- # @return [RSpec::Matchers::ExpectedsForMultipleDiffs]
26
- def self.from(expected)
25
+ # @param [Any] actual value
26
+ # @return [RSpec::Matchers::MultiMatcherDiff]
27
+ def self.from(expected, actual)
27
28
  return expected if self === expected
28
- new([[expected, DEFAULT_DIFF_LABEL]])
29
+ new([[expected, DEFAULT_DIFF_LABEL, actual]])
29
30
  end
30
31
 
31
32
  # @api private
32
33
  # Wraps provided matcher list in instance of
33
- # ExpectedForMultipleDiffs.
34
+ # MultiMatcherDiff.
34
35
  # @param [Array<Any>] matchers list of matchers to wrap
35
- # @return [RSpec::Matchers::ExpectedsForMultipleDiffs]
36
+ # @return [RSpec::Matchers::MultiMatcherDiff]
36
37
  def self.for_many_matchers(matchers)
37
- new(matchers.map { |m| [m.expected, diff_label_for(m)] })
38
+ new(matchers.map { |m| [m.expected, diff_label_for(m), m.actual] })
38
39
  end
39
40
 
40
41
  # @api private
@@ -42,10 +43,9 @@ module RSpec
42
43
  # factory and actual value if there are any
43
44
  # @param [String] message original failure message
44
45
  # @param [Proc] differ
45
- # @param [Any] actual value
46
46
  # @return [String]
47
- def message_with_diff(message, differ, actual)
48
- diff = diffs(differ, actual)
47
+ def message_with_diff(message, differ)
48
+ diff = diffs(differ)
49
49
  message = "#{message}\n#{diff}" unless diff.empty?
50
50
  message
51
51
  end
@@ -65,8 +65,8 @@ module RSpec
65
65
  end
66
66
  end
67
67
 
68
- def diffs(differ, actual)
69
- @expected_list.map do |(expected, diff_label)|
68
+ def diffs(differ)
69
+ @expected_list.map do |(expected, diff_label, actual)|
70
70
  diff = differ.diff(actual, expected)
71
71
  next if diff.strip.empty?
72
72
  if diff == "\e[0m\n\e[0m"
@@ -10,7 +10,7 @@ RSpec::Support.define_optimized_require_for_rspec(:matchers) { |f| require_relat
10
10
  dsl
11
11
  matcher_delegator
12
12
  aliased_matcher
13
- expecteds_for_multiple_diffs
13
+ multi_matcher_diff
14
14
  ].each { |file| RSpec::Support.require_rspec_matchers(file) }
15
15
 
16
16
  # RSpec's top level namespace. All of rspec-expectations is contained
@@ -36,7 +36,7 @@ module RSpec
36
36
  # expect([]).to be_empty # => [].empty?() | passes
37
37
  # expect([]).not_to be_empty # => [].empty?() | fails
38
38
  #
39
- # In addtion to prefixing the predicate matchers with "be_", you can also use "be_a_"
39
+ # In addition to prefixing the predicate matchers with "be_", you can also use "be_a_"
40
40
  # and "be_an_", making your specs read much more naturally:
41
41
  #
42
42
  # expect("a string").to be_an_instance_of(String) # =>"a string".instance_of?(String) # passes
@@ -704,7 +704,7 @@ module RSpec
704
704
 
705
705
  # An alternate form of `contain_exactly` that accepts
706
706
  # the expected contents as a single array arg rather
707
- # that splatted out as individual items.
707
+ # than splatted out as individual items.
708
708
  #
709
709
  # @example
710
710
  # expect(results).to contain_exactly(1, 2)
@@ -715,6 +715,9 @@ module RSpec
715
715
  def match_array(items)
716
716
  contain_exactly(*items)
717
717
  end
718
+ alias_matcher :an_array_matching, :match_array do |desc|
719
+ desc.sub("contain exactly", "an array containing exactly")
720
+ end
718
721
 
719
722
  # With no arg, passes if the block outputs `to_stdout` or `to_stderr`.
720
723
  # With a string, passes if the block outputs that specific string `to_stdout` or `to_stderr`.
@@ -753,8 +756,8 @@ module RSpec
753
756
 
754
757
  # With no args, matches if any error is raised.
755
758
  # With a named error, matches only if that specific error is raised.
756
- # With a named error and messsage specified as a String, matches only if both match.
757
- # With a named error and messsage specified as a Regexp, matches only if both match.
759
+ # With a named error and message specified as a String, matches only if both match.
760
+ # With a named error and message specified as a Regexp, matches only if both match.
758
761
  # Pass an optional block to perform extra verifications on the exception matched
759
762
  #
760
763
  # @example
@@ -1015,6 +1018,7 @@ module RSpec
1015
1018
  # than _before_, like `append_features`. It's important we check this before
1016
1019
  # in order to find the cases where it was already previously included.
1017
1020
  # @api private
1021
+ # :nocov:
1018
1022
  def append_features(mod)
1019
1023
  return super if mod < self # `mod < self` indicates a re-inclusion.
1020
1024
 
@@ -1035,6 +1039,7 @@ module RSpec
1035
1039
 
1036
1040
  super
1037
1041
  end
1042
+ # :nocov:
1038
1043
  end
1039
1044
  end
1040
1045
  end
data.tar.gz.sig CHANGED
Binary file
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rspec-expectations
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.11.0
4
+ version: 3.13.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Steven Baker
@@ -45,7 +45,7 @@ cert_chain:
45
45
  ZsVDj6a7lH3cNqtWXZxrb2wO38qV5AkYj8SQK7Hj3/Yui9myUX3crr+PdetazSqQ
46
46
  F3MdtaDehhjC
47
47
  -----END CERTIFICATE-----
48
- date: 2022-02-09 00:00:00.000000000 Z
48
+ date: 2024-09-07 00:00:00.000000000 Z
49
49
  dependencies:
50
50
  - !ruby/object:Gem::Dependency
51
51
  name: rspec-support
@@ -53,14 +53,14 @@ dependencies:
53
53
  requirements:
54
54
  - - "~>"
55
55
  - !ruby/object:Gem::Version
56
- version: 3.11.0
56
+ version: 3.13.0
57
57
  type: :runtime
58
58
  prerelease: false
59
59
  version_requirements: !ruby/object:Gem::Requirement
60
60
  requirements:
61
61
  - - "~>"
62
62
  - !ruby/object:Gem::Version
63
- version: 3.11.0
63
+ version: 3.13.0
64
64
  - !ruby/object:Gem::Dependency
65
65
  name: diff-lcs
66
66
  requirement: !ruby/object:Gem::Requirement
@@ -193,17 +193,17 @@ files:
193
193
  - lib/rspec/matchers/composable.rb
194
194
  - lib/rspec/matchers/dsl.rb
195
195
  - lib/rspec/matchers/english_phrasing.rb
196
- - lib/rspec/matchers/expecteds_for_multiple_diffs.rb
197
196
  - lib/rspec/matchers/fail_matchers.rb
198
197
  - lib/rspec/matchers/generated_descriptions.rb
199
198
  - lib/rspec/matchers/matcher_delegator.rb
200
199
  - lib/rspec/matchers/matcher_protocol.rb
200
+ - lib/rspec/matchers/multi_matcher_diff.rb
201
201
  homepage: https://github.com/rspec/rspec-expectations
202
202
  licenses:
203
203
  - MIT
204
204
  metadata:
205
205
  bug_tracker_uri: https://github.com/rspec/rspec-expectations/issues
206
- changelog_uri: https://github.com/rspec/rspec-expectations/blob/v3.11.0/Changelog.md
206
+ changelog_uri: https://github.com/rspec/rspec-expectations/blob/v3.13.3/Changelog.md
207
207
  documentation_uri: https://rspec.info/documentation/
208
208
  mailing_list_uri: https://groups.google.com/forum/#!forum/rspec
209
209
  source_code_uri: https://github.com/rspec/rspec-expectations
@@ -223,8 +223,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
223
223
  - !ruby/object:Gem::Version
224
224
  version: '0'
225
225
  requirements: []
226
- rubygems_version: 3.3.3
226
+ rubygems_version: 3.4.19
227
227
  signing_key:
228
228
  specification_version: 4
229
- summary: rspec-expectations-3.11.0
229
+ summary: rspec-expectations-3.13.3
230
230
  test_files: []
metadata.gz.sig CHANGED
Binary file