shoulda-matchers 2.8.0 → 3.0.0.rc1
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.
- checksums.yaml +4 -4
- data/.hound_config/ruby.yml +7 -0
- data/.travis.yml +11 -54
- data/Appraisals +45 -100
- data/CONTRIBUTING.md +51 -7
- data/Gemfile +7 -19
- data/Gemfile.lock +60 -134
- data/Guardfile +5 -0
- data/NEWS.md +203 -0
- data/README.md +95 -50
- data/Rakefile +1 -0
- data/doc_config/yard/templates/default/layout/html/setup.rb +1 -1
- data/gemfiles/4.0.0.gemfile +10 -7
- data/gemfiles/4.0.0.gemfile.lock +103 -79
- data/gemfiles/4.0.1.gemfile +10 -7
- data/gemfiles/4.0.1.gemfile.lock +109 -83
- data/gemfiles/4.1.gemfile +10 -7
- data/gemfiles/4.1.gemfile.lock +109 -85
- data/gemfiles/4.2.gemfile +10 -9
- data/gemfiles/4.2.gemfile.lock +86 -78
- data/lib/shoulda/matchers.rb +13 -18
- data/lib/shoulda/matchers/action_controller.rb +4 -1
- data/lib/shoulda/matchers/action_controller/flash_store.rb +95 -0
- data/lib/shoulda/matchers/action_controller/{strong_parameters_matcher.rb → permit_matcher.rb} +147 -30
- data/lib/shoulda/matchers/action_controller/redirect_to_matcher.rb +1 -1
- data/lib/shoulda/matchers/action_controller/render_template_matcher.rb +1 -1
- data/lib/shoulda/matchers/action_controller/render_with_layout_matcher.rb +1 -1
- data/lib/shoulda/matchers/action_controller/rescue_from_matcher.rb +1 -1
- data/lib/shoulda/matchers/action_controller/route_matcher.rb +5 -1
- data/lib/shoulda/matchers/action_controller/route_params.rb +15 -6
- data/lib/shoulda/matchers/action_controller/session_store.rb +34 -0
- data/lib/shoulda/matchers/action_controller/set_flash_matcher.rb +30 -136
- data/lib/shoulda/matchers/action_controller/set_session_matcher.rb +28 -109
- data/lib/shoulda/matchers/action_controller/set_session_or_flash_matcher.rb +103 -0
- data/lib/shoulda/matchers/active_model/allow_mass_assignment_of_matcher.rb +1 -12
- data/lib/shoulda/matchers/active_model/allow_value_matcher.rb +79 -10
- data/lib/shoulda/matchers/active_model/numericality_matchers/numeric_type_matcher.rb +10 -0
- data/lib/shoulda/matchers/active_model/validate_absence_of_matcher.rb +21 -0
- data/lib/shoulda/matchers/active_model/validate_acceptance_of_matcher.rb +24 -0
- data/lib/shoulda/matchers/active_model/validate_confirmation_of_matcher.rb +22 -5
- data/lib/shoulda/matchers/active_model/validate_exclusion_of_matcher.rb +29 -10
- data/lib/shoulda/matchers/active_model/validate_inclusion_of_matcher.rb +27 -10
- data/lib/shoulda/matchers/active_model/validate_length_of_matcher.rb +27 -12
- data/lib/shoulda/matchers/active_model/validate_numericality_of_matcher.rb +56 -20
- data/lib/shoulda/matchers/active_model/validate_presence_of_matcher.rb +3 -11
- data/lib/shoulda/matchers/active_model/validation_message_finder.rb +65 -0
- data/lib/shoulda/matchers/active_record/association_matcher.rb +40 -6
- data/lib/shoulda/matchers/active_record/association_matchers/join_table_matcher.rb +21 -7
- data/lib/shoulda/matchers/active_record/association_matchers/model_reflection.rb +11 -40
- data/lib/shoulda/matchers/active_record/association_matchers/model_reflector.rb +1 -1
- data/lib/shoulda/matchers/active_record/define_enum_for_matcher.rb +2 -6
- data/lib/shoulda/matchers/active_record/validate_uniqueness_of_matcher.rb +137 -22
- data/lib/shoulda/matchers/configuration.rb +20 -0
- data/lib/shoulda/matchers/doublespeak.rb +11 -1
- data/lib/shoulda/matchers/doublespeak/double.rb +29 -11
- data/lib/shoulda/matchers/doublespeak/double_collection.rb +4 -3
- data/lib/shoulda/matchers/doublespeak/method_call.rb +35 -0
- data/lib/shoulda/matchers/doublespeak/object_double.rb +7 -2
- data/lib/shoulda/matchers/doublespeak/proxy_implementation.rb +4 -3
- data/lib/shoulda/matchers/doublespeak/stub_implementation.rb +3 -3
- data/lib/shoulda/matchers/doublespeak/world.rb +21 -1
- data/lib/shoulda/matchers/integrations.rb +43 -0
- data/lib/shoulda/matchers/integrations/configuration.rb +68 -0
- data/lib/shoulda/matchers/integrations/configuration_error.rb +9 -0
- data/lib/shoulda/matchers/integrations/inclusion.rb +20 -0
- data/lib/shoulda/matchers/integrations/libraries.rb +15 -0
- data/lib/shoulda/matchers/integrations/libraries/action_controller.rb +31 -0
- data/lib/shoulda/matchers/integrations/libraries/active_model.rb +26 -0
- data/lib/shoulda/matchers/integrations/libraries/active_record.rb +26 -0
- data/lib/shoulda/matchers/integrations/libraries/missing_library.rb +19 -0
- data/lib/shoulda/matchers/integrations/libraries/rails.rb +30 -0
- data/lib/shoulda/matchers/integrations/rails.rb +12 -0
- data/lib/shoulda/matchers/integrations/registry.rb +28 -0
- data/lib/shoulda/matchers/integrations/test_frameworks.rb +16 -0
- data/lib/shoulda/matchers/integrations/test_frameworks/active_support_test_case.rb +37 -0
- data/lib/shoulda/matchers/integrations/test_frameworks/minitest_4.rb +36 -0
- data/lib/shoulda/matchers/integrations/test_frameworks/minitest_5.rb +37 -0
- data/lib/shoulda/matchers/integrations/test_frameworks/missing_test_framework.rb +40 -0
- data/lib/shoulda/matchers/integrations/test_frameworks/rspec.rb +29 -0
- data/lib/shoulda/matchers/integrations/test_frameworks/test_unit.rb +36 -0
- data/lib/shoulda/matchers/rails_shim.rb +0 -40
- data/lib/shoulda/matchers/version.rb +1 -1
- data/script/SUPPORTED_VERSIONS +1 -1
- data/script/update_gems_in_all_appraisals +14 -0
- data/shoulda-matchers.gemspec +2 -2
- data/spec/acceptance/active_model_integration_spec.rb +4 -1
- data/spec/acceptance/independent_matchers_spec.rb +6 -6
- data/spec/acceptance/multiple_libraries_integration_spec.rb +52 -0
- data/spec/acceptance/rails_integration_spec.rb +15 -5
- data/spec/acceptance_spec_helper.rb +8 -0
- data/spec/doublespeak_spec_helper.rb +14 -0
- data/spec/support/acceptance/adds_shoulda_matchers_to_project.rb +110 -0
- data/spec/support/acceptance/helpers.rb +2 -0
- data/spec/support/acceptance/helpers/base_helpers.rb +6 -1
- data/spec/support/acceptance/helpers/command_helpers.rb +6 -2
- data/spec/support/acceptance/helpers/minitest_helpers.rb +0 -8
- data/spec/support/acceptance/helpers/n_unit_helpers.rb +25 -0
- data/spec/support/acceptance/helpers/rspec_helpers.rb +2 -0
- data/spec/support/acceptance/helpers/step_helpers.rb +13 -19
- data/spec/support/acceptance/matchers/have_output.rb +1 -1
- data/spec/support/tests/bundle.rb +1 -1
- data/spec/support/tests/command_runner.rb +25 -13
- data/spec/support/tests/current_bundle.rb +47 -0
- data/spec/support/tests/database.rb +28 -0
- data/spec/support/tests/database_adapters/postgresql.rb +25 -0
- data/spec/support/tests/database_adapters/sqlite3.rb +26 -0
- data/spec/support/tests/database_configuration.rb +33 -0
- data/spec/support/tests/database_configuration_registry.rb +28 -0
- data/spec/support/tests/filesystem.rb +25 -2
- data/spec/support/unit/helpers/active_record_versions.rb +12 -0
- data/spec/support/unit/helpers/class_builder.rb +6 -2
- data/spec/support/unit/helpers/column_type_helpers.rb +26 -0
- data/spec/support/unit/helpers/controller_builder.rb +0 -28
- data/spec/support/unit/helpers/database_helpers.rb +18 -0
- data/spec/support/unit/helpers/model_builder.rb +38 -6
- data/spec/support/unit/helpers/rails_versions.rb +2 -2
- data/spec/support/unit/matchers/fail_with_message_including_matcher.rb +9 -8
- data/spec/support/unit/matchers/fail_with_message_matcher.rb +1 -1
- data/spec/support/unit/rails_application.rb +29 -13
- data/spec/support/unit/record_validating_confirmation_builder.rb +1 -2
- data/spec/support/unit/shared_examples/set_session_or_flash.rb +355 -0
- data/spec/unit/shoulda/matchers/action_controller/permit_matcher_spec.rb +433 -0
- data/spec/unit/shoulda/matchers/action_controller/render_with_layout_matcher_spec.rb +1 -5
- data/spec/unit/shoulda/matchers/action_controller/route_matcher_spec.rb +37 -0
- data/spec/unit/shoulda/matchers/action_controller/set_flash_matcher_spec.rb +23 -147
- data/spec/unit/shoulda/matchers/action_controller/set_session_matcher_spec.rb +8 -285
- data/spec/unit/shoulda/matchers/action_controller/set_session_or_flash_matcher_spec.rb +562 -0
- data/spec/unit/shoulda/matchers/active_model/allow_value_matcher_spec.rb +81 -14
- data/spec/unit/shoulda/matchers/active_model/disallow_value_matcher_spec.rb +16 -8
- data/spec/unit/shoulda/matchers/active_model/numericality_matchers/comparison_matcher_spec.rb +101 -9
- data/spec/unit/shoulda/matchers/active_model/numericality_matchers/even_number_matcher_spec.rb +39 -1
- data/spec/unit/shoulda/matchers/active_model/numericality_matchers/odd_number_matcher_spec.rb +39 -1
- data/spec/unit/shoulda/matchers/active_model/numericality_matchers/only_integer_matcher_spec.rb +39 -0
- data/spec/unit/shoulda/matchers/active_model/validate_exclusion_of_matcher_spec.rb +0 -17
- data/spec/unit/shoulda/matchers/active_model/validate_inclusion_of_matcher_spec.rb +0 -17
- data/spec/unit/shoulda/matchers/active_model/validate_length_of_matcher_spec.rb +0 -17
- data/spec/unit/shoulda/matchers/active_model/validate_numericality_of_matcher_spec.rb +838 -271
- data/spec/unit/shoulda/matchers/active_model/validate_presence_of_matcher_spec.rb +0 -19
- data/spec/unit/shoulda/matchers/active_record/association_matcher_spec.rb +93 -0
- data/spec/unit/shoulda/matchers/active_record/association_matchers/model_reflection_spec.rb +3 -3
- data/spec/unit/shoulda/matchers/active_record/define_enum_for_matcher_spec.rb +25 -0
- data/spec/unit/shoulda/matchers/active_record/validate_uniqueness_of_matcher_spec.rb +905 -0
- data/spec/unit/shoulda/matchers/doublespeak/double_collection_spec.rb +17 -11
- data/spec/unit/shoulda/matchers/doublespeak/double_implementation_registry_spec.rb +1 -1
- data/spec/unit/shoulda/matchers/doublespeak/double_spec.rb +144 -43
- data/spec/unit/shoulda/matchers/doublespeak/object_double_spec.rb +1 -1
- data/spec/unit/shoulda/matchers/doublespeak/proxy_implementation_spec.rb +36 -11
- data/spec/unit/shoulda/matchers/doublespeak/stub_implementation_spec.rb +29 -16
- data/spec/unit/shoulda/matchers/doublespeak/world_spec.rb +8 -5
- data/spec/unit/shoulda/matchers/doublespeak_spec.rb +1 -1
- data/spec/unit_spec_helper.rb +15 -14
- data/spec/warnings_spy.rb +1 -1
- metadata +68 -29
- data/docs.watchr +0 -5
- data/gemfiles/3.0.gemfile +0 -26
- data/gemfiles/3.0.gemfile.lock +0 -173
- data/gemfiles/3.1.gemfile +0 -32
- data/gemfiles/3.1.gemfile.lock +0 -212
- data/gemfiles/3.1_1.9.2.gemfile +0 -32
- data/gemfiles/3.1_1.9.2.gemfile.lock +0 -212
- data/gemfiles/3.2.gemfile +0 -33
- data/gemfiles/3.2.gemfile.lock +0 -212
- data/gemfiles/3.2_1.9.2.gemfile +0 -31
- data/gemfiles/3.2_1.9.2.gemfile.lock +0 -207
- data/lib/shoulda/matchers/assertion_error.rb +0 -27
- data/lib/shoulda/matchers/doublespeak/structs.rb +0 -10
- data/lib/shoulda/matchers/integrations/nunit_test_case_detection.rb +0 -39
- data/lib/shoulda/matchers/integrations/rspec.rb +0 -19
- data/lib/shoulda/matchers/integrations/test_unit.rb +0 -34
- data/spec/unit/shoulda/matchers/action_controller/strong_parameters_matcher_spec.rb +0 -331
- data/spec/unit/shoulda/matchers/active_model/validate_uniqueness_of_matcher_spec.rb +0 -564
@@ -67,6 +67,33 @@ module Shoulda
|
|
67
67
|
#
|
68
68
|
# #### Qualifiers
|
69
69
|
#
|
70
|
+
# Use `on` if your validation applies only under a certain context.
|
71
|
+
#
|
72
|
+
# class Issue
|
73
|
+
# include ActiveModel::Model
|
74
|
+
# attr_accessor :severity
|
75
|
+
#
|
76
|
+
# validates_inclusion_of :severity,
|
77
|
+
# in: %w(low medium high),
|
78
|
+
# on: :create
|
79
|
+
# end
|
80
|
+
#
|
81
|
+
# # RSpec
|
82
|
+
# describe Issue do
|
83
|
+
# it do
|
84
|
+
# should validate_inclusion_of(:severity).
|
85
|
+
# in_array(%w(low medium high)).
|
86
|
+
# on(:create)
|
87
|
+
# end
|
88
|
+
# end
|
89
|
+
#
|
90
|
+
# # Test::Unit
|
91
|
+
# class IssueTest < ActiveSupport::TestCase
|
92
|
+
# should validate_inclusion_of(:severity).
|
93
|
+
# in_array(%w(low medium high)).
|
94
|
+
# on(:create)
|
95
|
+
# end
|
96
|
+
#
|
70
97
|
# ##### with_message
|
71
98
|
#
|
72
99
|
# Use `with_message` if you are using a custom validation message.
|
@@ -234,16 +261,6 @@ module Shoulda
|
|
234
261
|
ValidateInclusionOfMatcher.new(attr)
|
235
262
|
end
|
236
263
|
|
237
|
-
# @deprecated Use {#validate_inclusion_of} instead.
|
238
|
-
# @return [ValidateInclusionOfMatcher]
|
239
|
-
def ensure_inclusion_of(attr)
|
240
|
-
Shoulda::Matchers.warn_about_deprecated_method(
|
241
|
-
:ensure_inclusion_of,
|
242
|
-
:validate_inclusion_of
|
243
|
-
)
|
244
|
-
validate_inclusion_of(attr)
|
245
|
-
end
|
246
|
-
|
247
264
|
# @private
|
248
265
|
class ValidateInclusionOfMatcher < ValidationMatcher
|
249
266
|
ARBITRARY_OUTSIDE_STRING = 'shouldamatchersteststring'
|
@@ -7,6 +7,31 @@ module Shoulda
|
|
7
7
|
#
|
8
8
|
# #### Qualifiers
|
9
9
|
#
|
10
|
+
# Use `on` if your validation applies only under a certain context.
|
11
|
+
#
|
12
|
+
# class User
|
13
|
+
# include ActiveModel::Model
|
14
|
+
# attr_accessor :password
|
15
|
+
#
|
16
|
+
# validates_length_of :password, minimum: 10, on: :create
|
17
|
+
# end
|
18
|
+
#
|
19
|
+
# # RSpec
|
20
|
+
# describe User do
|
21
|
+
# it do
|
22
|
+
# should validate_length_of(:password).
|
23
|
+
# is_at_least(10).
|
24
|
+
# on(:create)
|
25
|
+
# end
|
26
|
+
# end
|
27
|
+
#
|
28
|
+
# # Test::Unit
|
29
|
+
# class UserTest < ActiveSupport::TestCase
|
30
|
+
# should validate_length_of(:password).
|
31
|
+
# is_at_least(10).
|
32
|
+
# on(:create)
|
33
|
+
# end
|
34
|
+
#
|
10
35
|
# ##### is_at_least
|
11
36
|
#
|
12
37
|
# Use `is_at_least` to test usage of the `:minimum` option. This asserts
|
@@ -110,9 +135,9 @@ module Shoulda
|
|
110
135
|
#
|
111
136
|
# class User
|
112
137
|
# include ActiveModel::Model
|
113
|
-
# attr_accessor :
|
138
|
+
# attr_accessor :password
|
114
139
|
#
|
115
|
-
# validates_length_of :
|
140
|
+
# validates_length_of :password,
|
116
141
|
# minimum: 10,
|
117
142
|
# message: "Password isn't long enough"
|
118
143
|
# end
|
@@ -197,16 +222,6 @@ module Shoulda
|
|
197
222
|
ValidateLengthOfMatcher.new(attr)
|
198
223
|
end
|
199
224
|
|
200
|
-
# @deprecated Use {#validate_length_of} instead.
|
201
|
-
# @return [ValidateLengthOfMatcher]
|
202
|
-
def ensure_length_of(attr)
|
203
|
-
Shoulda::Matchers.warn_about_deprecated_method(
|
204
|
-
:ensure_length_of,
|
205
|
-
:validate_length_of
|
206
|
-
)
|
207
|
-
validate_length_of(attr)
|
208
|
-
end
|
209
|
-
|
210
225
|
# @private
|
211
226
|
class ValidateLengthOfMatcher < ValidationMatcher
|
212
227
|
include Helpers
|
@@ -23,6 +23,30 @@ module Shoulda
|
|
23
23
|
#
|
24
24
|
# #### Qualifiers
|
25
25
|
#
|
26
|
+
# ##### on
|
27
|
+
#
|
28
|
+
# Use `on` if your validation applies only under a certain context.
|
29
|
+
#
|
30
|
+
# class Person
|
31
|
+
# include ActiveModel::Model
|
32
|
+
# attr_accessor :number_of_dependents
|
33
|
+
#
|
34
|
+
# validates_numericality_of :number_of_dependents, on: :create
|
35
|
+
# end
|
36
|
+
#
|
37
|
+
# # RSpec
|
38
|
+
# describe Person do
|
39
|
+
# it do
|
40
|
+
# should validate_numericality_of(:number_of_dependents).
|
41
|
+
# on(:create)
|
42
|
+
# end
|
43
|
+
# end
|
44
|
+
#
|
45
|
+
# # Test::Unit
|
46
|
+
# class PersonTest < ActiveSupport::TestCase
|
47
|
+
# should validate_numericality_of(:number_of_dependents).on(:create)
|
48
|
+
# end
|
49
|
+
#
|
26
50
|
# ##### only_integer
|
27
51
|
#
|
28
52
|
# Use `only_integer` to test usage of the `:only_integer` option. This
|
@@ -290,9 +314,16 @@ module Shoulda
|
|
290
314
|
@attribute = attribute
|
291
315
|
@submatchers = []
|
292
316
|
@diff_to_compare = DEFAULT_DIFF_TO_COMPARE
|
317
|
+
@strict = false
|
293
318
|
add_disallow_value_matcher
|
294
319
|
end
|
295
320
|
|
321
|
+
def strict
|
322
|
+
@submatchers.each(&:strict)
|
323
|
+
@strict = true
|
324
|
+
self
|
325
|
+
end
|
326
|
+
|
296
327
|
def only_integer
|
297
328
|
prepare_submatcher(
|
298
329
|
NumericalityMatchers::OnlyIntegerMatcher.new(@attribute)
|
@@ -353,22 +384,38 @@ module Shoulda
|
|
353
384
|
self
|
354
385
|
end
|
355
386
|
|
387
|
+
def on(context)
|
388
|
+
@submatchers.each { |matcher| matcher.on(context) }
|
389
|
+
self
|
390
|
+
end
|
391
|
+
|
356
392
|
def matches?(subject)
|
357
393
|
@subject = subject
|
358
|
-
|
394
|
+
first_failing_submatcher.nil?
|
359
395
|
end
|
360
396
|
|
361
397
|
def description
|
362
|
-
"only allow #{allowed_types} for #{@attribute}
|
398
|
+
description_parts = ["only allow #{allowed_types} for #{@attribute}"]
|
399
|
+
|
400
|
+
if comparison_descriptions.present?
|
401
|
+
description_parts << comparison_descriptions
|
402
|
+
end
|
403
|
+
|
404
|
+
if @strict
|
405
|
+
description_parts.insert(1, 'strictly')
|
406
|
+
description_parts.join(', ')
|
407
|
+
else
|
408
|
+
description_parts.join(' ')
|
409
|
+
end
|
363
410
|
end
|
364
411
|
|
365
412
|
def failure_message
|
366
|
-
|
413
|
+
first_failing_submatcher.failure_message
|
367
414
|
end
|
368
415
|
alias failure_message_for_should failure_message
|
369
416
|
|
370
417
|
def failure_message_when_negated
|
371
|
-
|
418
|
+
first_failing_submatcher.failure_message_when_negated
|
372
419
|
end
|
373
420
|
alias failure_message_for_should_not failure_message_when_negated
|
374
421
|
|
@@ -403,21 +450,10 @@ module Shoulda
|
|
403
450
|
@diff_to_compare = [@diff_to_compare, matcher.diff_to_compare].max
|
404
451
|
end
|
405
452
|
|
406
|
-
def
|
407
|
-
@
|
408
|
-
@
|
409
|
-
|
410
|
-
end
|
411
|
-
end
|
412
|
-
|
413
|
-
def failing_submatchers
|
414
|
-
submatchers_and_results.
|
415
|
-
select { |x| !x[:matched] }.
|
416
|
-
map { |x| x[:matcher] }
|
417
|
-
end
|
418
|
-
|
419
|
-
def last_failing_submatcher
|
420
|
-
failing_submatchers.last
|
453
|
+
def first_failing_submatcher
|
454
|
+
@_first_failing_submatcher ||= @submatchers.detect do |submatcher|
|
455
|
+
!submatcher.matches?(@subject)
|
456
|
+
end
|
421
457
|
end
|
422
458
|
|
423
459
|
def allowed_types
|
@@ -431,7 +467,7 @@ module Shoulda
|
|
431
467
|
|
432
468
|
def comparison_descriptions
|
433
469
|
description_array = submatcher_comparison_descriptions
|
434
|
-
description_array.empty? ? '' : '
|
470
|
+
description_array.empty? ? '' : 'which are ' + submatcher_comparison_descriptions.join(' and ')
|
435
471
|
end
|
436
472
|
|
437
473
|
def submatcher_comparison_descriptions
|
@@ -140,17 +140,9 @@ module Shoulda
|
|
140
140
|
end
|
141
141
|
|
142
142
|
def disallows_and_double_checks_value_of!(value, message)
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
matcher._after_setting_value do
|
147
|
-
actual_value = @subject.__send__(@attribute)
|
148
|
-
|
149
|
-
if !actual_value.nil?
|
150
|
-
raise error_class.create(@subject.class)
|
151
|
-
end
|
152
|
-
end
|
153
|
-
end
|
143
|
+
disallows_value_of(value, message)
|
144
|
+
rescue ActiveModel::AllowValueMatcher::CouldNotSetAttributeError
|
145
|
+
raise ActiveModel::CouldNotSetPasswordError.create(@subject.class)
|
154
146
|
end
|
155
147
|
|
156
148
|
def blank_value
|
@@ -0,0 +1,65 @@
|
|
1
|
+
module Shoulda
|
2
|
+
module Matchers
|
3
|
+
module ActiveModel
|
4
|
+
# @private
|
5
|
+
class ValidationMessageFinder
|
6
|
+
include Helpers
|
7
|
+
|
8
|
+
def initialize(instance, attribute, context=nil)
|
9
|
+
@instance = instance
|
10
|
+
@attribute = attribute
|
11
|
+
@context = context
|
12
|
+
end
|
13
|
+
|
14
|
+
def allow_description(allowed_values)
|
15
|
+
"allow #{@attribute} to be set to #{allowed_values}"
|
16
|
+
end
|
17
|
+
|
18
|
+
def expected_message_from(attribute_message)
|
19
|
+
attribute_message
|
20
|
+
end
|
21
|
+
|
22
|
+
def has_messages?
|
23
|
+
errors.present?
|
24
|
+
end
|
25
|
+
|
26
|
+
def source_description
|
27
|
+
'errors'
|
28
|
+
end
|
29
|
+
|
30
|
+
def messages_description
|
31
|
+
if errors.empty?
|
32
|
+
' no errors'
|
33
|
+
else
|
34
|
+
" errors:\n#{pretty_error_messages(validated_instance)}"
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def messages
|
39
|
+
Array(messages_for_attribute)
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
def messages_for_attribute
|
45
|
+
errors[@attribute]
|
46
|
+
end
|
47
|
+
|
48
|
+
def errors
|
49
|
+
validated_instance.errors
|
50
|
+
end
|
51
|
+
|
52
|
+
def validated_instance
|
53
|
+
@validated_instance ||= validate_instance
|
54
|
+
end
|
55
|
+
|
56
|
+
def validate_instance
|
57
|
+
@instance.valid?(*@context)
|
58
|
+
@instance
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
@@ -774,6 +774,29 @@ module Shoulda
|
|
774
774
|
# class_name('City')
|
775
775
|
# end
|
776
776
|
#
|
777
|
+
# ##### join_table
|
778
|
+
#
|
779
|
+
# Use `join_table` to test usage of the `:join_table` option. This
|
780
|
+
# asserts that the table you're referring to actually exists.
|
781
|
+
#
|
782
|
+
# class Person < ActiveRecord::Base
|
783
|
+
# has_and_belongs_to_many :issues, join_table: 'people_tickets'
|
784
|
+
# end
|
785
|
+
#
|
786
|
+
# # RSpec
|
787
|
+
# describe Person do
|
788
|
+
# it do
|
789
|
+
# should have_and_belong_to_many(:issues).
|
790
|
+
# join_table('people_tickets')
|
791
|
+
# end
|
792
|
+
# end
|
793
|
+
#
|
794
|
+
# # Test::Unit
|
795
|
+
# class PersonTest < ActiveSupport::TestCase
|
796
|
+
# should have_and_belong_to_many(:issues).
|
797
|
+
# join_table('people_tickets')
|
798
|
+
# end
|
799
|
+
#
|
777
800
|
# ##### validate
|
778
801
|
#
|
779
802
|
# Use `validate` to test that the `:validate` option was specified.
|
@@ -823,7 +846,9 @@ module Shoulda
|
|
823
846
|
# @private
|
824
847
|
class AssociationMatcher
|
825
848
|
delegate :reflection, :model_class, :associated_class, :through?,
|
826
|
-
:
|
849
|
+
:polymorphic?, to: :reflector
|
850
|
+
|
851
|
+
attr_reader :name, :options
|
827
852
|
|
828
853
|
def initialize(macro, name)
|
829
854
|
@macro = macro
|
@@ -905,6 +930,11 @@ module Shoulda
|
|
905
930
|
self
|
906
931
|
end
|
907
932
|
|
933
|
+
def join_table(join_table_name)
|
934
|
+
@options[:join_table_name] = join_table_name
|
935
|
+
self
|
936
|
+
end
|
937
|
+
|
908
938
|
def description
|
909
939
|
description = "#{macro_description} #{name}"
|
910
940
|
description += " class_name => #{options[:class_name]}" if options.key?(:class_name)
|
@@ -937,18 +967,22 @@ module Shoulda
|
|
937
967
|
submatchers_match?
|
938
968
|
end
|
939
969
|
|
970
|
+
def join_table_name
|
971
|
+
options[:join_table_name] || reflector.join_table_name
|
972
|
+
end
|
973
|
+
|
974
|
+
def option_verifier
|
975
|
+
@option_verifier ||= AssociationMatchers::OptionVerifier.new(reflector)
|
976
|
+
end
|
977
|
+
|
940
978
|
protected
|
941
979
|
|
942
|
-
attr_reader :submatchers, :missing, :subject, :macro
|
980
|
+
attr_reader :submatchers, :missing, :subject, :macro
|
943
981
|
|
944
982
|
def reflector
|
945
983
|
@reflector ||= AssociationMatchers::ModelReflector.new(subject, name)
|
946
984
|
end
|
947
985
|
|
948
|
-
def option_verifier
|
949
|
-
@option_verifier ||= AssociationMatchers::OptionVerifier.new(reflector)
|
950
|
-
end
|
951
|
-
|
952
986
|
def add_submatcher(matcher)
|
953
987
|
@submatchers << matcher
|
954
988
|
end
|
@@ -8,8 +8,8 @@ module Shoulda
|
|
8
8
|
|
9
9
|
alias :missing_option :failure_message
|
10
10
|
|
11
|
-
delegate :model_class, :
|
12
|
-
to: :association_matcher
|
11
|
+
delegate :model_class, :join_table_name, :associated_class, :options,
|
12
|
+
:name, :option_verifier, to: :association_matcher
|
13
13
|
|
14
14
|
delegate :connection, to: :model_class
|
15
15
|
|
@@ -19,12 +19,26 @@ module Shoulda
|
|
19
19
|
end
|
20
20
|
|
21
21
|
def matches?(subject)
|
22
|
-
|
22
|
+
join_table_option_correct? &&
|
23
|
+
join_table_exists? &&
|
23
24
|
join_table_has_correct_columns?
|
24
25
|
end
|
25
26
|
|
27
|
+
def join_table_option_correct?
|
28
|
+
if options.key?(:join_table_name)
|
29
|
+
if option_verifier.correct_for_string?(:join_table, options[:join_table_name])
|
30
|
+
true
|
31
|
+
else
|
32
|
+
@failure_message = "#{name} should use '#{options[:join_table_name]}' for :join_table option"
|
33
|
+
false
|
34
|
+
end
|
35
|
+
else
|
36
|
+
true
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
26
40
|
def join_table_exists?
|
27
|
-
if connection.tables.include?(
|
41
|
+
if connection.tables.include?(join_table_name)
|
28
42
|
true
|
29
43
|
else
|
30
44
|
@failure_message = missing_table_message
|
@@ -60,16 +74,16 @@ module Shoulda
|
|
60
74
|
end
|
61
75
|
|
62
76
|
def actual_join_table_columns
|
63
|
-
connection.columns(
|
77
|
+
connection.columns(join_table_name).map(&:name)
|
64
78
|
end
|
65
79
|
|
66
80
|
def missing_table_message
|
67
|
-
"join table #{
|
81
|
+
"join table #{join_table_name} doesn't exist"
|
68
82
|
end
|
69
83
|
|
70
84
|
def missing_columns_message
|
71
85
|
missing = missing_columns.join(', ')
|
72
|
-
"join table #{
|
86
|
+
"join table #{join_table_name} missing #{column_label}: #{missing}"
|
73
87
|
end
|
74
88
|
|
75
89
|
def column_label
|