prolog_minitest_matchers 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 3432250c36aada7c4efaf78622e1c6f538ce804d
4
- data.tar.gz: d312f4b46721223e8796c7b8a08b714335719fd3
3
+ metadata.gz: 81ac10d6ba50c569650a8228fcc14cec39504ee0
4
+ data.tar.gz: 397e377a53f73bcae18ae287c89b13b3e7728bd4
5
5
  SHA512:
6
- metadata.gz: 9c5dcf648b266d338d43023504adcf61004828cca72b101deef1a373570cf010f7ebcf8a640c59fa7e3068713a06f5cdc9f86329648a23950df792bc7ff0e2b6
7
- data.tar.gz: 09a985e617ed970d21f272838491612672ab8f6c59e7b2f700d8f4866ddd1ddb48b02deb54e5ce0bcce34522084ca4981b91d68d9f9e24cb98edb058fd3118e3
6
+ metadata.gz: '081234b6d44e0f0ce04f06da3fa88e6b70209d064062c2b693c21ed58ff49060597be8fe0f9fb85d78dacc35c67ad5282d3fdd9f8fcb2bd2be2a84e43037dca0'
7
+ data.tar.gz: de4ac96c56ca29e0b34be02bde9ea1a4a290916d1ee0dcafb0b1d45f145b5c191e758c6c8e17099fc80fa77f577526f1e459f3622f93e657638dae43ffa80576
data/README.md CHANGED
@@ -2,7 +2,101 @@
2
2
 
3
3
  This is an evolving collection of MiniTest and MiniTest::Spec custom matchers which we have found useful in our work. As we have built up our applications, we've seen the disparity between *tests* and *assertions* grow; often to a differential of 30% or even more. While some standard MiniTest::Spec expectations involve multiple assertions, we can police our own.
4
4
 
5
- For example, we often have class API tests that look something like
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ ```ruby
10
+ gem 'prolog_minitest_matchers'
11
+ ```
12
+
13
+ And then execute:
14
+
15
+ $ bundle
16
+
17
+ Or install it yourself as:
18
+
19
+ $ gem install prolog_minitest_matchers
20
+ ## Usage
21
+
22
+ As of Gem Release 0.3.0, this Gem defines three MiniTest::Spec expectations (and thus three MiniTest asserters) that can be used in your MiniTest code:
23
+
24
+ 1. `must_require_dry_struct_attribute` (`assert_requires_dry_struct_attribute`);
25
+ 2. `must_require_initialize_parameter` (`assert_requires_initialize_parameter`); and
26
+ 3. `must_require_static_call_param` (`assert_requires_static_call_param`).
27
+
28
+ In each case, the expectation (through the implementing asserter) will verify that the parameter expected to cause a failure when omitted **must** exist in the supplied set of full parameters.
29
+
30
+ ### `must_require_dry_struct_attribute`
31
+
32
+ Implemented by asserter `MiniTest::Assertions::AssertRequiresDryStructAttribute`.
33
+
34
+ Suppose that you have code such as
35
+
36
+ ```ruby
37
+ # in foo.rb
38
+ class Foo < Dry::Types::Struct
39
+ attribute :foo, Types::Strict::String
40
+ attribute :bar, Types::Coercible.Int
41
+ # ...
42
+ end
43
+ ```
44
+
45
+ and test code such as
46
+
47
+ ```ruby
48
+ # in foo_test.rb
49
+
50
+ describe 'Foo' do
51
+ describe 'initialisation' do
52
+ describe 'requires parameters for' do
53
+ let(:params) { { foo: 'some foo', bar: 42 } }
54
+
55
+ it 'foo' do
56
+ params.delete :foo
57
+ error = expect { Foo.new params }.must_raise KeyError
58
+ expect(error.message).must_equal "No key :foo in #{params.inspect}!"
59
+ end
60
+
61
+ it 'bar' do
62
+ # ...
63
+ end
64
+ end # describe 'requires parameters for'
65
+ end # describe 'initialisation'
66
+
67
+ # ... other tests
68
+ end
69
+ ```
70
+
71
+ That parameter test has two expectations: first, that a `KeyError` will be raised; and second, that that error's message will be as expected. Instead, how about this:
72
+
73
+ ```ruby
74
+ # in foo_test.rb
75
+
76
+ describe 'Foo' do
77
+ describe 'initialisation requires parameters for' do
78
+ let(:params) { { foo: 'some foo', bar: 42 } }
79
+
80
+ it ':foo' do
81
+ expect(Foo).must_require_dry_struct_attribute params, :foo
82
+ end
83
+
84
+ it ':bar' do
85
+ expect(Foo).must_require_dry_struct_attribute params, :bar
86
+ end
87
+ end # describe 'initialisation requires parameters for'
88
+
89
+ # ... other tests
90
+ end
91
+ ```
92
+
93
+ Somewhat shorter, yes; more importantly, two much more intention-revealing expectations that are counted as one assertion each. If you ascribe to the widely-used recommendation that each test (`it` block in MiniTest::Spec usage) should test one thing, this will have you wondering "how come my tests and assertions don't match up very well" just that little bit less.
94
+
95
+ ### `must_require_initialize_parameter`
96
+
97
+ Implemented by asserter `MiniTest::Assertions::AssertRequiresInitializeParameter`.
98
+
99
+ Again, suppose that you have code such as
6
100
 
7
101
  ```ruby
8
102
  # in foo.rb
@@ -13,7 +107,11 @@ class Foo
13
107
 
14
108
  # ...
15
109
  end
110
+ ```
111
+
112
+ and test code such as
16
113
 
114
+ ```ruby
17
115
  # in foo_test.rb
18
116
 
19
117
  describe 'Foo' do
@@ -37,13 +135,11 @@ describe 'Foo' do
37
135
 
38
136
  # ... other tests
39
137
  end
40
-
41
138
  ```
42
139
 
43
- That parameter test has two expectations: first, that an `ArgumentError` will be raised; and second, that that error's message will be as expected. Instead, how about this:
140
+ As before, that parameter test has two expectations: first, that an `ArgumentError` will be raised; and second, that that error's message will be as expected. Instead, we can now use this:
44
141
 
45
142
  ```ruby
46
-
47
143
  # in foo_test.rb
48
144
 
49
145
  describe 'Foo' do
@@ -65,45 +161,153 @@ describe 'Foo' do
65
161
 
66
162
  # ... other tests
67
163
  end
164
+ ```
165
+
166
+ Again, two much more intention-revealing expectations that are counted as one assertion each.
167
+
168
+ ### `must_require_static_call_param`
68
169
 
170
+ Implemented by asserter `MiniTest::Assertions::AssertRequiresInitializeParameter`.
171
+
172
+ This is useful, not for initialisation in the traditional sense, but for service objects implementing a *class-level* `.call` interface that takes one or more named parameters. You might have code that looks like:
173
+
174
+ ```ruby
175
+ # in foo.rb
176
+ class Foo
177
+ def self.call(foo:, bar:)
178
+ Foo.new(foo, bar).call
179
+ end
180
+
181
+ def call
182
+ # ...
183
+ end
184
+
185
+ protected
186
+
187
+ def initialize(foo, bar)
188
+ @foo = massage_initial_foo_with foo
189
+ @bar = massage_initial_bar_with bar
190
+ self
191
+ end
192
+
193
+ private
194
+
195
+ attr_reader :bar, :foo
196
+ # ...
197
+ end
69
198
  ```
70
199
 
71
- Two expectations; two assertions; two much more *intention-revealing* expectations.
200
+ and test code such as
72
201
 
73
- ## Installation
202
+ ```ruby
203
+ # in foo_test.rb
74
204
 
75
- Add this line to your application's Gemfile:
205
+ describe 'Foo' do
206
+ describe 'initialisation' do
207
+ describe 'requires parameters for' do
208
+ let(:params) { { foo: 'some foo', bar: 'some bar' } }
209
+
210
+ it 'foo' do
211
+ params.delete :foo
212
+ error = expect { Foo.new params }.must_raise KeyError
213
+ expect(error.message).must_equal "No key :foo in #{params.inspect}!"
214
+ end
215
+
216
+ it 'bar' do
217
+ # ...
218
+ end
219
+ end
220
+
221
+ # ... other initialisation tests
222
+ end
223
+
224
+ # ... other tests
225
+ end
226
+ ```
227
+
228
+ As before, that parameter test has two expectations: first, that a `KeyError` will be raised; and second, that that error's message will be as expected. We can use this instead:
76
229
 
77
230
  ```ruby
78
- gem 'prolog_minitest_matchers'
231
+ # in foo_test.rb
232
+
233
+ describe 'Foo' do
234
+ describe 'initialisation' do
235
+ describe 'requires parameters for' do
236
+ let(:params) { { foo: 'some foo', bar: 'some bar' } }
237
+
238
+ it 'foo' do
239
+ expect(Foo).must_require_static_call_param params, :foo
240
+ end
241
+
242
+ it 'bar' do
243
+ expect(Foo).must_require_static_call_param params, :bar
244
+ end
245
+ end
246
+
247
+ # ... other initialisation tests
248
+ end
249
+
250
+ # ... other tests
251
+ end
79
252
  ```
80
253
 
81
- And then execute:
254
+ Once again, two much more intention-revealing expectations that are counted as one assertion each.
82
255
 
83
- $ bundle
256
+ ### Notes on Implementation
84
257
 
85
- Or install it yourself as:
258
+ Attentive readers may note the strong similarity between these three expectations. They would be right; although the use cases differ in important ways, the implementation details that set each apart from the others have been reduced to a minimum, as inspecting the code itself will reveal. See some room for improvement? Great! Open an issue and let's talk about it!
86
259
 
87
- $ gem install prolog_minitest_matchers
88
260
 
89
- ## Usage
261
+ ## Errata
262
+
263
+ ### Reversing MiniTest::Spec expectations does not work (Issue [#1](https://github.com/TheProlog/prolog_minitest_matchers/issues/1))
90
264
 
91
- See the discussion at the top of this page for a description of how to use the `must_require_initialize_parameter` expectation, which is a MiniTest::Spec wrapper around the `assert_requires_initialize_parameter` MiniTest assertion.
265
+ Ordinarily, MiniTest::Spec matchers provide reversible expectations; that is, expectations can be positive (`must_`) *or* negative (`won't_`). For a trivial example,
266
+
267
+ ```ruby
268
+ expect(2 + 2).must_equal 4
269
+ expect(2 + 2).wont_equal 5
270
+ ```
92
271
 
93
- Note that this assertion will verify that the parameter expected to fail when removed must exist in the full set of parameters specified.
272
+ The same "asserter" code is being exercised, and fails if the asserted condition is false (for `must_equal`) or true (for `wont_equal`).
94
273
 
95
- As other assertions/expectations are added to this Gem over the next few weeks, *including* formal test coverage of the asserters and expectations themselves, this usage information will be broken out into a separate document. Stay tuned &ndash; or open a pull request!
274
+ None of the matchers included as part of Gem Release 0.3.0 (`must_require_dry_struct_attribute`, `must_require_initialize_parameter`, and `must_require_static_call_param`) are reversible in this way. Given the expected use cases of these matchers, this has been judged to be acceptable; the issue has been left open but labelled `wontfix`. (PRs welcome).
96
275
 
97
276
  ## Development
98
277
 
99
- After checking out the repo, run `bin/setup` to install dependencies (which as of now must already be installed on your local system). Then, run `bin/rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
278
+ After checking out the repo, run `bin/setup` to install dependencies (which as of now must already be installed on your local system). Then, run `bin/rake test` to run the tests, or `bin/rake` to run tests and, if tests are successful, further static-analysis tools ([RuboCop](https://github.com/bbatsov/rubocop), [Flay](https://github.com/seattlerb/flay), [Flog](https://github.com/seattlerb/flog), and [Reek](https://github.com/troessner/reek)).
100
279
 
101
- To install this gem onto your local machine, run `bin/rake install`. Maintainers should be familiar with the standard procedure for releasing an updated Gem version to RubyGems.
280
+ To install *your build* of this Gem onto your local machine, run `bin/rake install`. We recommend that you uninstall any previously-installed "official" Gem to increase your confidence that your tests are running against your build.
102
281
 
103
282
  ## Contributing
104
283
 
105
- Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/prolog_minitest_matchers. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
284
+ Bug reports and pull requests are welcome on GitHub at https://github.com/TheProlog/prolog_minitest_matchers. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
285
+
286
+ ### Process
287
+
288
+ If you wish to submit a new feature, such as a new matcher, to the Gem, please [open an issue](https://github.com/TheProlog/prolog_minitest_matchers/issues/new) to discuss your idea with the maintainer and other interested community members. Issue threads are a great place to thrash out the details of what you're trying to accomplish and how your work would affect other code and/or community members. If you need help with something, or aren't sure how to choose between different ideas to accomplish some detail of what you're setting out to do, this is the place to discuss that. There is *no such thing as a stupid question that you don't know the answer to* (once you've researched in your search engine of choice, of course; please do respect people's time and attention).
289
+
290
+ The processes for proposing a new feature or a fix to an open bug-report issue are very similar:
291
+
292
+ 1. Make sure that you have forked this Gem's [repository on GitHub](https://github.com/TheProlog/prolog_minitest_matchers) to your own GitHub account. (If you don't yet have a GitHub account, [join](https://github.com/join?source=header-home); it's free.)
293
+ 2. If you're proposing a new feature, [open an issue](https://github.com/TheProlog/prolog_minitest_matchers/issues/new) as suggested above. If you're addressing an existing issue, *thanks;* you don't need to open a new one.
294
+ 3. Clone *your* copy of the repo to your local development system.
295
+ 4. Create a new Git branch for your work. It's best to give it a reasonably short name that's suggestive of what you're specifically trying to accomplish.
296
+ 1. If you're adding a new feature, such as a new matcher, consider that `dry-struct-attribute` was a more useful branch name for the `must_require_static_call_param` matcher than, say, `my-new-matcher` for (hopefully) obvious reasons.
297
+ 2. If you're adding a fix for an existing issue, say Issue #4172, then a branch name of `issue-4172` is probably perfect.
298
+ 3. **Do not** work on your copy of the `master` branch! Any pull request (see below) that you later submit for changes you've made on `master` will be rejected, and you will be asked to submit your proposed changes on a branch that branches from a commit on the upstream `master` branch.
299
+ 5. Now write great (tests and) code!
300
+ 6. As soon as you have something to show, *even if it's not complete yet* (but it passes what tests you have), [push your branch](https://help.github.com/articles/pushing-to-a-remote/) to *your forked repo* on GitHub and open a [new pull request](https://github.com/TheProlog/prolog_minitest_matchers/compare) ("PR") for *your branch* compared to `master` on the [upstream](https://github.com/TheProlog/prolog_minitest_matchers/) repository. That lets the maintainer and other community members review your code and tests, comment, help out, and so on.
301
+ 7. Continuing with your pull requests, it's usually better if you make small, incremental changes in each commit in a sequence. We (endeavour to) practice [behaviour-driven development](https://en.wikipedia.org/wiki/Behavior-driven_development): write tests for the simplest thing that could possibly work; see the tests fail; then make them pass, commit, and go on to the next simplest thing. Don't get hung up on lots of refactoring until you have code that does everything you want it to do; once you have a legitimately complete green bar, *that's* the time to apply SOLID principles and patterns to DRY things up. Better to have (temporary) duplication than choose the wrong abstraction.
302
+
303
+ ### Notes on Contributing
304
+
305
+ Don't be discouraged if it takes several commits to complete your work and then several more to get everybody agreeing that it's complete and well done. ("Useful" and "worth adding" should have been settled at the issue stage, before you started working on your PR.) That's because…
306
+
307
+ When pull requests are *merged* into the `master` branch, they are *squashed* so that all changes are applied to `master` in a single commit. This means that, even if you have a dozen or more commits in your PR where you've been *very* incremental, and even changed direction once or twice, what matters is the final result; not what it took to get there.
308
+
309
+ Once your PR has been merged, it's a good idea to pull the upstream `master` branch to your development system (`git pull upstream master`) and then push it to your fork (`git push origin master`). (What? You don't *have* an `upstream` remote as shown by `git remote -v`? Run the command `git remote add upstream https://github.com/TheProlog/prolog_minitest_matchers.git` from your local development directory, and now you do.)
106
310
 
107
311
  ## License
108
312
 
109
- The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
313
+ The Gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
data/config.reek CHANGED
@@ -2,7 +2,7 @@
2
2
  LongParameterList:
3
3
  max_params: 4 # If it's good enough for Sandi, it's good enough for us.
4
4
 
5
- # NestedIterators:
6
- # max_allowed_nesting: 2
7
- # ignore_iterators:
8
- # - lambda
5
+ NestedIterators:
6
+ max_allowed_nesting: 2
7
+ ignore_iterators:
8
+ - lambda
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'dry-types'
4
+
5
+ require_relative './base_assert_required_parameter'
6
+
7
+ module MiniTest
8
+ # Adding custom assertions to make specs easier to read
9
+ module Assertions
10
+ # Actual test logic for `#assert_requires_struct_attribute`.
11
+ class AssertRequiresDryStructAttribute < BaseAssertRequiredParameter
12
+ private
13
+
14
+ def default_message_for(param_key)
15
+ "] :#{param_key} is missing in Hash input"
16
+ end
17
+
18
+ def error_class
19
+ Dry::Types::StructError
20
+ end
21
+
22
+ def error_inducer
23
+ -> { klass.new params }
24
+ end
25
+ end # class MiniTest::Assertions::AssertRequiresDryStructAttribute
26
+ end
27
+ end
@@ -1,68 +1,24 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative './base_assert_required_parameter'
4
+
3
5
  module MiniTest
4
6
  # Adding custom assertions to make specs easier to read
5
7
  module Assertions
6
8
  # Actual test logic for `#assert_requires_initialize_parameter`.
7
- class AssertRequiresInitializeParameter
8
- def initialize(klass, full_params, param_key, message)
9
- @klass = klass
10
- @full_params = full_params
11
- @param_key = param_key
12
- @message = initial_message_from(message, param_key)
13
- self
14
- end
15
-
16
- def call(assert)
17
- assert.call(errors_as_expected(save_and_try_to_init), message)
18
- end
19
-
9
+ class AssertRequiresInitializeParameter < BaseAssertRequiredParameter
20
10
  private
21
11
 
22
- attr_reader :full_params, :klass, :message, :param_key
23
-
24
- def errors_as_expected(errors)
25
- errors[:expected]&.message == message
26
- end
27
-
28
- def filtered_params
29
- full_params.dup.reject { |source_key, _| source_key == param_key }
30
- end
31
-
32
- # Running Reek will complain about a :reek:ControlParameter. Protocol is.
33
- def initial_message_from(message, param_key)
34
- message || "missing keyword: #{param_key}"
35
- end
36
-
37
- def save_and_try_to_init
38
- verify_param_in_list
39
- save_and_delete_param_before { |params| try_to_init params }
40
- end
41
-
42
- def save_and_delete_param_before
43
- yield filtered_params
44
- end
45
-
46
- def try_to_init(params)
47
- expected_error = nil
48
- begin
49
- klass.new params
50
- rescue ArgumentError => error
51
- expected_error = error
52
- end
53
- { expected: expected_error }
54
- end
55
-
56
- def verify_param_in_list
57
- raise KeyError, no_param_message unless param_in_full_list?
12
+ def default_message_for(param_key)
13
+ "missing keyword: #{param_key}"
58
14
  end
59
15
 
60
- def no_param_message
61
- "No key :#{param_key} in #{full_params}!"
16
+ def error_class
17
+ ArgumentError
62
18
  end
63
19
 
64
- def param_in_full_list?
65
- full_params.key? param_key
20
+ def error_inducer
21
+ -> { klass.new params }
66
22
  end
67
23
  end # class MiniTest::Assertions::AssertRequiresInitializeParameter
68
24
  end
@@ -1,73 +1,24 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative './base_assert_required_parameter'
4
+
3
5
  module MiniTest
4
6
  # Adding custom assertions to make specs easier to read
5
7
  module Assertions
6
8
  # Actual test logic for `#assert_requires_static_call_paramr`.
7
- class AssertRequiresStaticCallParam
8
- def initialize(klass, full_params, param_key, message)
9
- @klass = klass
10
- @full_params = full_params
11
- @param_key = param_key
12
- @message = initial_message_from(message, param_key)
13
- self
14
- end
15
-
16
- def call(assert)
17
- verify_param_in_list(assert)
18
- assert.call(errors_as_expected(save_and_try_to_call), message)
19
- end
20
-
9
+ class AssertRequiresStaticCallParam < BaseAssertRequiredParameter
21
10
  private
22
11
 
23
- attr_reader :full_params, :klass, :message, :param_key
24
-
25
- def errors_as_expected(errors)
26
- errors[:expected]&.message == message
27
- end
28
-
29
- def filtered_params
30
- full_params.dup.reject { |source_key, _| source_key == param_key }
31
- end
32
-
33
- # Running Reek will complain about a :reek:ControlParameter. Protocol is.
34
- def initial_message_from(message, param_key)
35
- message || "missing keyword: #{param_key}"
36
- end
37
-
38
- def key_not_found_message
39
- "Key :#{param_key} not found in #{full_params}!"
40
- end
41
-
42
- def save_and_try_to_call
43
- save_and_delete_param_before { |params| try_to_call params }
44
- # saved_item = full_params[param_key]
45
- # full_params.delete param_key
46
- # errors = try_to_call
47
- # full_params[param_key] = saved_item
48
- # errors
49
- end
50
-
51
- def try_to_call(params)
52
- expected_error = nil
53
- begin
54
- klass.call params
55
- rescue ArgumentError => error
56
- expected_error = error
57
- end
58
- { expected: expected_error }
59
- end
60
-
61
- def save_and_delete_param_before
62
- yield filtered_params
12
+ def default_message_for(param_key)
13
+ "missing keyword: #{param_key}"
63
14
  end
64
15
 
65
- def verify_param_in_list(assert)
66
- assert.call(param_in_list?, key_not_found_message)
16
+ def error_class
17
+ ArgumentError
67
18
  end
68
19
 
69
- def param_in_list?
70
- full_params.key?(param_key)
20
+ def error_inducer
21
+ -> { klass.call params }
71
22
  end
72
23
  end # class MiniTest::Assertions::AssertRequiresStaticCallParam
73
24
  end
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative './induce_error'
4
+ require_relative './verify_key_in_hash'
5
+
6
+ module MiniTest
7
+ # Adding custom assertions to make specs easier to read
8
+ module Assertions
9
+ # Base assertion class to verify error raised when parameter omitted.
10
+ class BaseAssertRequiredParameter
11
+ def initialize(klass, params, param_key, message)
12
+ message ||= default_message_for(param_key)
13
+ @params = Internals.hash_without_key(params, param_key)
14
+ @klass = klass
15
+ @param_key = param_key
16
+ @message = message
17
+ self
18
+ end
19
+
20
+ def call(assert)
21
+ assert.call(correct_error_message?, message)
22
+ end
23
+
24
+ private
25
+
26
+ attr_reader :params, :klass, :message, :param_key
27
+
28
+ def actual_error_message
29
+ errors[:expected]&.message
30
+ end
31
+
32
+ def correct_error_message?
33
+ actual_error_message.match message
34
+ end
35
+
36
+ def errors
37
+ InduceError.call error_class: error_class, inducer: error_inducer
38
+ end
39
+
40
+ # Methods that neither affect nor are affected by instance state.
41
+ module Internals
42
+ def self.hash_without_key(hash, key)
43
+ VerifyKeyInHash.call hash, key
44
+ hash.dup.reject { |source_key, _| source_key == key }
45
+ end
46
+ end
47
+ private_constant :Internals
48
+ end # class MiniTest::Assertions::BaseAssertRequiredParameter
49
+ end
50
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Attempt to induce a specified failure, and report if successful or not.
4
+ class InduceError
5
+ def self.call(error_class:, inducer:)
6
+ InduceError.new(error_class, inducer).call
7
+ end
8
+
9
+ def call
10
+ expected_error = nil
11
+ begin
12
+ inducer.call
13
+ rescue error_class => error
14
+ expected_error = error
15
+ end
16
+ { expected: expected_error }
17
+ end
18
+
19
+ protected
20
+
21
+ def initialize(error_class, inducer)
22
+ @error_class = error_class
23
+ @inducer = inducer
24
+ self
25
+ end
26
+
27
+ private
28
+
29
+ attr_reader :error_class, :inducer
30
+ end # class InduceError
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Used to validate incoming parameter hash.
4
+ class VerifyKeyInHash
5
+ def self.call(hash, key)
6
+ VerifyKeyInHash.new(hash, key).call
7
+ end
8
+
9
+ def call
10
+ raise KeyError, no_key_message unless key_in_hash?
11
+ end
12
+
13
+ protected
14
+
15
+ def initialize(hash, key)
16
+ @hash = hash
17
+ @key = key
18
+ self
19
+ end
20
+
21
+ private
22
+
23
+ attr_reader :hash, :key
24
+
25
+ def key_in_hash?
26
+ hash.key? key
27
+ end
28
+
29
+ def no_key_message
30
+ "No key :#{key} in #{hash}!"
31
+ end
32
+ end # class VerifyKeyInHash
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'minitest/spec'
4
+
5
+ require_relative './asserters/assert_requires_dry_struct_attribute'
6
+
7
+ module MiniTest
8
+ # Adding custom assertions to make specs easier to read
9
+ module Assertions
10
+ def assert_requires_dry_struct_attribute(klass, full_params, param_key,
11
+ message = nil)
12
+ AssertRequiresDryStructAttribute.new(klass, full_params, param_key,
13
+ message).call(method(:assert))
14
+ end
15
+ end
16
+
17
+ # Make it available to MiniTest::Spec
18
+ module Expectations
19
+ infect_an_assertion :assert_requires_dry_struct_attribute,
20
+ :must_require_dry_struct_attribute, :reverse
21
+ end
22
+ end
@@ -2,5 +2,5 @@
2
2
 
3
3
  # Module to satisfy Gem requirements; nothing inside but version-spec constant.
4
4
  module PrologMinitestMatchers
5
- VERSION = '0.2.0'
5
+ VERSION = '0.3.0'
6
6
  end
@@ -1,7 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'prolog_minitest_matchers/version'
4
+ require 'prolog_minitest_matchers/matchers/requires_dry_struct_attribute'
4
5
  require 'prolog_minitest_matchers/matchers/requires_initialize_parameter'
6
+ require 'prolog_minitest_matchers/matchers/requires_static_call_param'
5
7
 
6
8
  # Module to satisfy Gem requirements; nothing inside but version-spec constant.
7
9
  module PrologMinitestMatchers
@@ -27,6 +27,8 @@ Gem::Specification.new do |spec|
27
27
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
28
28
  spec.require_paths = ["lib"]
29
29
 
30
+ spec.add_dependency "dry-types", "~> 0.7", ">= 0.7.2"
31
+
30
32
  spec.add_development_dependency "bundler", "~> 1.12", ">= 1.12.5"
31
33
  spec.add_development_dependency "rake", "~> 11.2", ">= 11.2.2"
32
34
  spec.add_development_dependency "minitest", "~> 5.9", ">= 5.9.0"
metadata CHANGED
@@ -1,15 +1,35 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: prolog_minitest_matchers
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jeff Dickey
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2016-07-26 00:00:00.000000000 Z
11
+ date: 2016-07-29 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: dry-types
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '0.7'
20
+ - - ">="
21
+ - !ruby/object:Gem::Version
22
+ version: 0.7.2
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - "~>"
28
+ - !ruby/object:Gem::Version
29
+ version: '0.7'
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: 0.7.2
13
33
  - !ruby/object:Gem::Dependency
14
34
  name: bundler
15
35
  requirement: !ruby/object:Gem::Requirement
@@ -187,8 +207,13 @@ files:
187
207
  - Rakefile
188
208
  - config.reek
189
209
  - lib/prolog_minitest_matchers.rb
210
+ - lib/prolog_minitest_matchers/matchers/asserters/assert_requires_dry_struct_attribute.rb
190
211
  - lib/prolog_minitest_matchers/matchers/asserters/assert_requires_initialize_parameter.rb
191
212
  - lib/prolog_minitest_matchers/matchers/asserters/assert_requires_static_call_param.rb
213
+ - lib/prolog_minitest_matchers/matchers/asserters/base_assert_required_parameter.rb
214
+ - lib/prolog_minitest_matchers/matchers/asserters/induce_error.rb
215
+ - lib/prolog_minitest_matchers/matchers/asserters/verify_key_in_hash.rb
216
+ - lib/prolog_minitest_matchers/matchers/requires_dry_struct_attribute.rb
192
217
  - lib/prolog_minitest_matchers/matchers/requires_initialize_parameter.rb
193
218
  - lib/prolog_minitest_matchers/matchers/requires_static_call_param.rb
194
219
  - lib/prolog_minitest_matchers/version.rb
@@ -219,3 +244,4 @@ signing_key:
219
244
  specification_version: 4
220
245
  summary: Custom Minitest matcher(s) we've developed for our own use.
221
246
  test_files: []
247
+ has_rdoc: