shoulda-matchers 6.2.0 → 6.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
  SHA256:
3
- metadata.gz: d549ac8f3629ad37bc56d0d09daf37416ec23d78374a8ed6a630ea23e5c9e487
4
- data.tar.gz: f09bc94b6be181564cdde56729c2055192a4725adee4ba8b6b7f8e84429fe9a0
3
+ metadata.gz: 87a298f618f08949dbe1c165b17dfbfc940a6675b2f790e655c9a43568956c31
4
+ data.tar.gz: ea5eaad001d24f89a698a4a944f2596da029c019a4bcc2f893c0881146dea058
5
5
  SHA512:
6
- metadata.gz: 1f3ba08a6d15ad56cb583c0a8289e180854f5d89020b3182b2d6140289800d71bca467f187c9a4718ba26078cc2562f6377d77b00a0e84f2e683079d62ef60d3
7
- data.tar.gz: 45d0141c79d9642439c9c03ffcd8e41d1aee993eafaea11fc72812456ead1dcf17d1698e9eb7f311c40945c54c77fc4e573a820ffa115fc344e9b0049ed69479
6
+ metadata.gz: bcaf6fc8e3e59cf1936c2a346d1a02c1269ab8e231b7820c273873ed81cf6f97501bf15ea44503f357008064f34eaec66bc9a81f2938fd3876078d707979daea
7
+ data.tar.gz: 94a53d9576ea0df451d2ff0ff34528f8c035699e9d216e877ced2cdff156ae0a5d18bc106dc0b5fc487aebfd56807bd836d2cb9aa51ababfc232be5e3b94c2cf
data/README.md CHANGED
@@ -527,7 +527,6 @@ The names and logos for thoughtbot are trademarks of thoughtbot, inc.
527
527
 
528
528
  We love open source software!
529
529
  See [our other projects][community].
530
-
531
530
  We are [available for hire][hire].
532
531
 
533
532
  [community]: https://thoughtbot.com/community?utm_source=github
@@ -133,7 +133,7 @@ module Shoulda
133
133
  when :missing then 404
134
134
  when :error then 500..599
135
135
  when Symbol
136
- ::Rack::Utils::SYMBOL_TO_STATUS_CODE[potential_symbol]
136
+ ::Rack::Utils.status_code(potential_symbol)
137
137
  else
138
138
  potential_symbol
139
139
  end
@@ -187,8 +187,95 @@ module Shoulda
187
187
  # without_scopes
188
188
  # end
189
189
  #
190
- # @return [DefineEnumForMatcher]
190
+ # ##### with_default
191
+ #
192
+ # Use `with_default` to test that the enum is defined with a
193
+ # default value. A proc can also be passed, and will be called once each
194
+ # time a new value is needed. (If using Time or Date, it's recommended to
195
+ # freeze time or date to avoid flaky tests):
196
+ #
197
+ # class Issue < ActiveRecord::Base
198
+ # enum status: [:open, :closed], default: :closed
199
+ # end
200
+ #
201
+ # # RSpec
202
+ # RSpec.describe Issue, type: :model do
203
+ # it do
204
+ # should define_enum_for(:status).
205
+ # with_default(:closed)
206
+ # end
207
+ # end
208
+ #
209
+ # # Minitest (Shoulda)
210
+ # class ProcessTest < ActiveSupport::TestCase
211
+ # should define_enum_for(:status).
212
+ # with_default(:closed)
213
+ # end
191
214
  #
215
+ # ##### validating
216
+ #
217
+ # Use `validating` to test that the enum is being validated.
218
+ # Can take a boolean value and an allowing_nil keyword argument:
219
+ #
220
+ # class Issue < ActiveRecord::Base
221
+ # enum status: [:open, :closed], validate: true
222
+ # end
223
+ #
224
+ # # RSpec
225
+ # RSpec.describe Issue, type: :model do
226
+ # it do
227
+ # should define_enum_for(:status).
228
+ # validating
229
+ # end
230
+ # end
231
+ #
232
+ # # Minitest (Shoulda)
233
+ # class ProcessTest < ActiveSupport::TestCase
234
+ # should define_enum_for(:status).
235
+ # validating
236
+ # end
237
+ #
238
+ # class Issue < ActiveRecord::Base
239
+ # enum status: [:open, :closed], validate: { allow_nil: true }
240
+ # end
241
+ #
242
+ # # RSpec
243
+ # RSpec.describe Issue, type: :model do
244
+ # it do
245
+ # should define_enum_for(:status).
246
+ # validating(allowing_nil: true)
247
+ # end
248
+ # end
249
+ #
250
+ # # Minitest (Shoulda)
251
+ # class ProcessTest < ActiveSupport::TestCase
252
+ # should define_enum_for(:status).
253
+ # validating(allowing_nil: true)
254
+ # end
255
+ #
256
+ # ##### without_instance_methods
257
+ #
258
+ # Use `without_instance_methods` to exclude the check for instance methods.
259
+ #
260
+ # class Issue < ActiveRecord::Base
261
+ # enum status: [:open, :closed], instance_methods: false
262
+ # end
263
+ #
264
+ # # RSpec
265
+ # RSpec.describe Issue, type: :model do
266
+ # it do
267
+ # should define_enum_for(:status).
268
+ # without_instance_methods
269
+ # end
270
+ # end
271
+ #
272
+ # # Minitest (Shoulda)
273
+ # class ProcessTest < ActiveSupport::TestCase
274
+ # should define_enum_for(:status).
275
+ # without_instance_methods
276
+ # end
277
+ #
278
+ # @return [DefineEnumForMatcher]
192
279
  def define_enum_for(attribute_name)
193
280
  DefineEnumForMatcher.new(attribute_name)
194
281
  end
@@ -197,7 +284,7 @@ module Shoulda
197
284
  class DefineEnumForMatcher
198
285
  def initialize(attribute_name)
199
286
  @attribute_name = attribute_name
200
- @options = { expected_enum_values: [], scopes: true }
287
+ @options = { expected_enum_values: [], scopes: true, instance_methods: true }
201
288
  end
202
289
 
203
290
  def description
@@ -222,6 +309,12 @@ module Shoulda
222
309
  description
223
310
  end
224
311
 
312
+ def validating(value = true, allowing_nil: false)
313
+ options[:validating] = value
314
+ options[:allowing_nil] = allowing_nil
315
+ self
316
+ end
317
+
225
318
  def with_values(expected_enum_values)
226
319
  options[:expected_enum_values] = expected_enum_values
227
320
  self
@@ -247,6 +340,16 @@ module Shoulda
247
340
  self
248
341
  end
249
342
 
343
+ def without_instance_methods
344
+ options[:instance_methods] = false
345
+ self
346
+ end
347
+
348
+ def with_default(default_value)
349
+ options[:default] = default_value
350
+ self
351
+ end
352
+
250
353
  def matches?(subject)
251
354
  @record = subject
252
355
 
@@ -254,7 +357,9 @@ module Shoulda
254
357
  enum_values_match? &&
255
358
  column_type_matches? &&
256
359
  enum_value_methods_exist? &&
257
- scope_presence_matches?
360
+ scope_presence_matches? &&
361
+ default_value_matches? &&
362
+ validating_matches?
258
363
  end
259
364
 
260
365
  def failure_message
@@ -277,6 +382,30 @@ module Shoulda
277
382
 
278
383
  private
279
384
 
385
+ def validating_matches?
386
+ return true if options[:validating].nil?
387
+
388
+ validator = find_enum_validator
389
+
390
+ if expected_validating? == !!validator
391
+ if validator&.options&.dig(:allow_nil).present? == expected_allowing_nil?
392
+ true
393
+ else
394
+ @failure_message_continuation =
395
+ "However, #{attribute_name.inspect} is allowing nil values"
396
+ false
397
+ end
398
+ else
399
+ @failure_message_continuation =
400
+ if expected_validating?
401
+ "However, #{attribute_name.inspect} is not being validated"
402
+ else
403
+ "However, #{attribute_name.inspect} is being validated"
404
+ end
405
+ false
406
+ end
407
+ end
408
+
280
409
  attr_reader :attribute_name, :options, :record,
281
410
  :failure_message_continuation
282
411
 
@@ -292,6 +421,21 @@ module Shoulda
292
421
  )
293
422
  end
294
423
 
424
+ if options[:default].present?
425
+ expectation << ', with a default value of '
426
+ expectation << Shoulda::Matchers::Util.inspect_value(expected_default_value)
427
+ end
428
+
429
+ if expected_validating?
430
+ expectation << ', and being validated '
431
+ expectation <<
432
+ if expected_allowing_nil?
433
+ 'allowing nil values'
434
+ else
435
+ 'not allowing nil values'
436
+ end
437
+ end
438
+
295
439
  if expected_prefix
296
440
  expectation <<
297
441
  if expected_suffix
@@ -413,16 +557,24 @@ module Shoulda
413
557
  end
414
558
 
415
559
  def enum_value_methods_exist?
416
- if instance_methods_exist?
417
- true
418
- else
560
+ if options[:instance_methods]
561
+ return true if instance_methods_exist?
562
+
419
563
  message = missing_methods_message
564
+ message << " (we can't tell which)" if [expected_prefix, expected_suffix].any?
565
+
566
+ @failure_message_continuation = message
420
567
 
421
- message << " (we can't tell which)"
568
+ false
569
+ elsif instance_methods_exist?
570
+ message = "#{attribute_name.inspect} does map to these values"
571
+ message << ' with instance methods, but expected no instance methods'
422
572
 
423
573
  @failure_message_continuation = message
424
574
 
425
575
  false
576
+ else
577
+ true
426
578
  end
427
579
  end
428
580
 
@@ -471,11 +623,50 @@ module Shoulda
471
623
  elsif expected_suffix
472
624
  message << 'configured with either a different suffix or no '
473
625
  message << 'suffix at all'
626
+ elsif expected_instance_methods?
627
+ message << 'configured with no instance methods'
474
628
  else
475
629
  ''
476
630
  end
477
631
  end
478
632
 
633
+ def default_value_matches?
634
+ return true if options[:default].blank?
635
+
636
+ if actual_default_value.nil?
637
+ @failure_message_continuation = 'However, no default value was set'
638
+ return false
639
+ end
640
+
641
+ if actual_default_value == expected_default_value
642
+ true
643
+ else
644
+ String.new.tap do |message|
645
+ message << 'However, the default value is '
646
+ message << Shoulda::Matchers::Util.inspect_value(actual_default_value)
647
+ @failure_message_continuation = message
648
+ end
649
+ false
650
+ end
651
+ end
652
+
653
+ def expected_default_value
654
+ options[:default].respond_to?(:call) ? options[:default].call : options[:default]
655
+ end
656
+
657
+ def actual_default_value
658
+ attribute_schema = model.attributes_to_define_after_schema_loads[attribute_name.to_s]
659
+
660
+ value = case attribute_schema
661
+ in [_, { default: default_value } ]
662
+ default_value
663
+ in [_, default_value]
664
+ default_value
665
+ end
666
+
667
+ value.respond_to?(:call) ? value.call : value
668
+ end
669
+
479
670
  def singleton_methods_exist?
480
671
  expected_singleton_methods.all? do |method|
481
672
  model.singleton_methods.include?(method)
@@ -509,6 +700,10 @@ module Shoulda
509
700
  end
510
701
  end
511
702
 
703
+ def expected_instance_methods?
704
+ options[:instance_methods]
705
+ end
706
+
512
707
  def expected_prefix
513
708
  if options.include?(:prefix)
514
709
  if options[:prefix] == true
@@ -529,6 +724,22 @@ module Shoulda
529
724
  end
530
725
  end
531
726
 
727
+ def expected_validating?
728
+ options[:validating].present?
729
+ end
730
+
731
+ def expected_allowing_nil?
732
+ options[:allowing_nil].present?
733
+ end
734
+
735
+ def find_enum_validator
736
+ record.class.validators.detect do |validator|
737
+ validator.kind == :inclusion &&
738
+ validator.attributes.include?(attribute_name.to_s) &&
739
+ validator.options[:in] == expected_enum_values
740
+ end
741
+ end
742
+
532
743
  def exclude_scopes?
533
744
  !options[:scopes]
534
745
  end
@@ -29,7 +29,19 @@ module Shoulda
29
29
  end
30
30
 
31
31
  def symlink_to(parent)
32
- namespace.set(name, Class.new(parent))
32
+ table_name = parent.table_name
33
+
34
+ new_class = Class.new(parent) do
35
+ define_singleton_method :table_name do
36
+ table_name
37
+ end
38
+
39
+ define_singleton_method :base_class do
40
+ self
41
+ end
42
+ end
43
+
44
+ namespace.set(name, new_class)
33
45
  end
34
46
 
35
47
  def to_s
@@ -1,5 +1,4 @@
1
1
  require 'forwardable'
2
- require 'logger'
3
2
 
4
3
  module Shoulda
5
4
  module Matchers
@@ -1,6 +1,6 @@
1
1
  module Shoulda
2
2
  module Matchers
3
3
  # @private
4
- VERSION = '6.2.0'.freeze
4
+ VERSION = '6.3.0'.freeze
5
5
  end
6
6
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: shoulda-matchers
3
3
  version: !ruby/object:Gem::Version
4
- version: 6.2.0
4
+ version: 6.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tammer Saleh
@@ -14,7 +14,7 @@ authors:
14
14
  autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
- date: 2024-03-15 00:00:00.000000000 Z
17
+ date: 2024-08-09 00:00:00.000000000 Z
18
18
  dependencies:
19
19
  - !ruby/object:Gem::Dependency
20
20
  name: activesupport
@@ -198,7 +198,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
198
198
  - !ruby/object:Gem::Version
199
199
  version: '0'
200
200
  requirements: []
201
- rubygems_version: 3.5.6
201
+ rubygems_version: 3.5.3
202
202
  signing_key:
203
203
  specification_version: 4
204
204
  summary: Simple one-liner tests for common Rails functionality