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
@@ -24,24 +24,25 @@ module Shoulda
|
|
24
24
|
reflection.options[:through]
|
25
25
|
end
|
26
26
|
|
27
|
-
def
|
28
|
-
|
27
|
+
def join_table_name
|
28
|
+
join_table_name =
|
29
29
|
if has_and_belongs_to_many_name_table_name
|
30
30
|
has_and_belongs_to_many_name_table_name
|
31
|
-
elsif reflection.respond_to?(:join_table)
|
32
|
-
reflection.join_table
|
33
31
|
else
|
34
|
-
reflection.
|
32
|
+
reflection.join_table
|
35
33
|
end
|
36
34
|
|
37
|
-
|
35
|
+
join_table_name.to_s
|
38
36
|
end
|
39
37
|
|
40
38
|
def association_relation
|
41
|
-
|
42
|
-
|
39
|
+
relation = associated_class.all
|
40
|
+
|
41
|
+
if reflection.scope
|
42
|
+
# Source: AR::Associations::AssociationScope#eval_scope
|
43
|
+
relation.instance_exec(subject, &reflection.scope)
|
43
44
|
else
|
44
|
-
|
45
|
+
relation
|
45
46
|
end
|
46
47
|
end
|
47
48
|
|
@@ -68,37 +69,7 @@ module Shoulda
|
|
68
69
|
|
69
70
|
attr_reader :reflection, :subject
|
70
71
|
|
71
|
-
|
72
|
-
relation = associated_class.all
|
73
|
-
|
74
|
-
if scope
|
75
|
-
# Source: AR::Associations::AssociationScope#eval_scope
|
76
|
-
relation.instance_exec(subject, &scope)
|
77
|
-
else
|
78
|
-
relation
|
79
|
-
end
|
80
|
-
end
|
81
|
-
|
82
|
-
def convert_options_to_relation(options)
|
83
|
-
relation = associated_class.scoped
|
84
|
-
relation = extend_relation_with(relation, :where, options[:conditions])
|
85
|
-
relation = extend_relation_with(relation, :includes, options[:include])
|
86
|
-
relation = extend_relation_with(relation, :order, options[:order])
|
87
|
-
relation = extend_relation_with(relation, :group, options[:group])
|
88
|
-
relation = extend_relation_with(relation, :having, options[:having])
|
89
|
-
relation = extend_relation_with(relation, :limit, options[:limit])
|
90
|
-
relation = extend_relation_with(relation, :offset, options[:offset])
|
91
|
-
relation = extend_relation_with(relation, :select, options[:select])
|
92
|
-
relation
|
93
|
-
end
|
94
|
-
|
95
|
-
def extend_relation_with(relation, method_name, value)
|
96
|
-
if value
|
97
|
-
relation.__send__(method_name, value)
|
98
|
-
else
|
99
|
-
relation
|
100
|
-
end
|
101
|
-
end
|
72
|
+
private
|
102
73
|
|
103
74
|
def has_and_belongs_to_many_name
|
104
75
|
reflection.options[:through]
|
@@ -4,7 +4,7 @@ module Shoulda
|
|
4
4
|
module AssociationMatchers
|
5
5
|
# @private
|
6
6
|
class ModelReflector
|
7
|
-
delegate :associated_class, :through?, :
|
7
|
+
delegate :associated_class, :through?, :join_table_name,
|
8
8
|
:association_relation, :polymorphic?, :foreign_key,
|
9
9
|
:association_foreign_key, to: :reflection
|
10
10
|
|
@@ -99,16 +99,12 @@ module Shoulda
|
|
99
99
|
hashify(options[:expected_enum_values]).with_indifferent_access
|
100
100
|
end
|
101
101
|
|
102
|
-
def enum_method
|
103
|
-
attribute_name.to_s.pluralize
|
104
|
-
end
|
105
|
-
|
106
102
|
def actual_enum_values
|
107
|
-
model.class.send(
|
103
|
+
model.class.send(attribute_name.to_s.pluralize)
|
108
104
|
end
|
109
105
|
|
110
106
|
def enum_defined?
|
111
|
-
model.
|
107
|
+
model.defined_enums.include?(attribute_name.to_s)
|
112
108
|
end
|
113
109
|
|
114
110
|
def enum_values_match?
|
@@ -88,6 +88,22 @@ module Shoulda
|
|
88
88
|
#
|
89
89
|
# #### Qualifiers
|
90
90
|
#
|
91
|
+
# Use `on` if your validation applies only under a certain context.
|
92
|
+
#
|
93
|
+
# class Post < ActiveRecord::Base
|
94
|
+
# validates_uniqueness_of :title, on: :create
|
95
|
+
# end
|
96
|
+
#
|
97
|
+
# # RSpec
|
98
|
+
# describe Post do
|
99
|
+
# it { should validate_uniqueness_of(:title).on(:create) }
|
100
|
+
# end
|
101
|
+
#
|
102
|
+
# # Test::Unit
|
103
|
+
# class PostTest < ActiveSupport::TestCase
|
104
|
+
# should validate_uniqueness_of(:title).on(:create)
|
105
|
+
# end
|
106
|
+
#
|
91
107
|
# ##### with_message
|
92
108
|
#
|
93
109
|
# Use `with_message` if you are using a custom validation message.
|
@@ -241,9 +257,12 @@ module Shoulda
|
|
241
257
|
@original_subject = subject
|
242
258
|
@subject = subject.class.new
|
243
259
|
@expected_message ||= :taken
|
260
|
+
@all_records = @subject.class.all
|
244
261
|
|
245
|
-
|
262
|
+
scopes_match? &&
|
263
|
+
set_scoped_attributes &&
|
246
264
|
validate_everything_except_duplicate_nils_or_blanks? &&
|
265
|
+
validate_case_sensitivity? &&
|
247
266
|
validate_after_scope_change? &&
|
248
267
|
allows_nil? &&
|
249
268
|
allows_blank?
|
@@ -253,6 +272,37 @@ module Shoulda
|
|
253
272
|
|
254
273
|
private
|
255
274
|
|
275
|
+
def validation
|
276
|
+
@subject.class._validators[@attribute].detect do |validator|
|
277
|
+
validator.is_a?(::ActiveRecord::Validations::UniquenessValidator)
|
278
|
+
end
|
279
|
+
end
|
280
|
+
|
281
|
+
def scopes_match?
|
282
|
+
expected_scopes = Array.wrap(@options[:scopes])
|
283
|
+
|
284
|
+
if validation
|
285
|
+
actual_scopes = Array.wrap(validation.options[:scope])
|
286
|
+
else
|
287
|
+
actual_scopes = []
|
288
|
+
end
|
289
|
+
|
290
|
+
if expected_scopes == actual_scopes
|
291
|
+
true
|
292
|
+
else
|
293
|
+
@failure_message = "Expected validation to be scoped to " +
|
294
|
+
"#{expected_scopes}"
|
295
|
+
|
296
|
+
if actual_scopes.present?
|
297
|
+
@failure_message << ", but it was scoped to #{actual_scopes}."
|
298
|
+
else
|
299
|
+
@failure_message << ", but it was not scoped to anything."
|
300
|
+
end
|
301
|
+
|
302
|
+
false
|
303
|
+
end
|
304
|
+
end
|
305
|
+
|
256
306
|
def allows_nil?
|
257
307
|
if @options[:allow_nil]
|
258
308
|
ensure_nil_record_in_database
|
@@ -353,6 +403,22 @@ module Shoulda
|
|
353
403
|
disallows_value_of(existing_value, @expected_message)
|
354
404
|
end
|
355
405
|
|
406
|
+
def validate_case_sensitivity?
|
407
|
+
value = existing_value
|
408
|
+
|
409
|
+
if value.respond_to?(:swapcase)
|
410
|
+
swapcased_value = value.swapcase
|
411
|
+
|
412
|
+
if @options[:case_insensitive]
|
413
|
+
disallows_value_of(swapcased_value, @expected_message)
|
414
|
+
else
|
415
|
+
allows_value_of(swapcased_value, @expected_message)
|
416
|
+
end
|
417
|
+
else
|
418
|
+
true
|
419
|
+
end
|
420
|
+
end
|
421
|
+
|
356
422
|
def create_record_with_value
|
357
423
|
@existing_record = create_record_in_database
|
358
424
|
end
|
@@ -364,17 +430,18 @@ module Shoulda
|
|
364
430
|
end
|
365
431
|
|
366
432
|
def validate_after_scope_change?
|
367
|
-
if @options[:scopes].blank?
|
433
|
+
if @options[:scopes].blank? || all_scopes_are_booleans?
|
368
434
|
true
|
369
435
|
else
|
370
|
-
all_records = @subject.class.all
|
371
436
|
@options[:scopes].all? do |scope|
|
372
|
-
previous_value = all_records.map(&scope).max
|
373
|
-
|
374
|
-
# Assume the scope is a foreign key if the field is nil
|
375
|
-
previous_value ||= correct_type_for_column(@subject.class.columns_hash[scope.to_s])
|
437
|
+
previous_value = @all_records.map(&scope).compact.max
|
376
438
|
|
377
|
-
next_value =
|
439
|
+
next_value =
|
440
|
+
if previous_value.blank?
|
441
|
+
dummy_value_for(scope)
|
442
|
+
else
|
443
|
+
next_value_for(scope, previous_value)
|
444
|
+
end
|
378
445
|
|
379
446
|
@subject.__send__("#{scope}=", next_value)
|
380
447
|
|
@@ -392,49 +459,97 @@ module Shoulda
|
|
392
459
|
end
|
393
460
|
end
|
394
461
|
|
395
|
-
def
|
396
|
-
|
397
|
-
|
398
|
-
|
462
|
+
def dummy_value_for(scope)
|
463
|
+
column = column_for(scope)
|
464
|
+
|
465
|
+
if column.respond_to?(:array) && column.array
|
466
|
+
[ dummy_scalar_value_for(column) ]
|
467
|
+
else
|
468
|
+
dummy_scalar_value_for(column)
|
469
|
+
end
|
470
|
+
end
|
471
|
+
|
472
|
+
def dummy_scalar_value_for(column)
|
473
|
+
case column.type
|
474
|
+
when :integer
|
475
|
+
0
|
476
|
+
when :date
|
477
|
+
Date.today
|
478
|
+
when :datetime
|
399
479
|
DateTime.now
|
400
|
-
|
480
|
+
when :uuid
|
401
481
|
SecureRandom.uuid
|
482
|
+
when :boolean
|
483
|
+
true
|
402
484
|
else
|
403
|
-
|
485
|
+
'dummy value'
|
404
486
|
end
|
405
487
|
end
|
406
488
|
|
407
489
|
def next_value_for(scope, previous_value)
|
408
|
-
if
|
490
|
+
if previous_value.is_a?(Array)
|
491
|
+
[ next_scalar_value_for(scope, previous_value[0]) ]
|
492
|
+
else
|
493
|
+
next_scalar_value_for(scope, previous_value)
|
494
|
+
end
|
495
|
+
end
|
496
|
+
|
497
|
+
def next_scalar_value_for(scope, previous_value)
|
498
|
+
column = column_for(scope)
|
499
|
+
|
500
|
+
if column.type == :uuid
|
501
|
+
SecureRandom.uuid
|
502
|
+
elsif defined_as_enum?(scope)
|
409
503
|
available_values = available_enum_values_for(scope, previous_value)
|
410
504
|
available_values.keys.last
|
411
|
-
elsif scope
|
505
|
+
elsif polymorphic_type_attribute?(scope, previous_value)
|
412
506
|
Uniqueness::TestModels.create(previous_value).to_s
|
413
507
|
elsif previous_value.respond_to?(:next)
|
414
508
|
previous_value.next
|
415
509
|
elsif previous_value.respond_to?(:to_datetime)
|
416
510
|
previous_value.to_datetime.next
|
511
|
+
elsif boolean_value?(previous_value)
|
512
|
+
!previous_value
|
417
513
|
else
|
418
514
|
previous_value.to_s.next
|
419
515
|
end
|
420
516
|
end
|
421
517
|
|
518
|
+
def all_scopes_are_booleans?
|
519
|
+
@options[:scopes].all? do |scope|
|
520
|
+
@all_records.map(&scope).all? { |s| boolean_value?(s) }
|
521
|
+
end
|
522
|
+
end
|
523
|
+
|
524
|
+
def boolean_value?(value)
|
525
|
+
value.in?([true, false])
|
526
|
+
end
|
527
|
+
|
528
|
+
def defined_as_enum?(scope)
|
529
|
+
@subject.class.respond_to?(:defined_enums) &&
|
530
|
+
@subject.defined_enums[scope.to_s]
|
531
|
+
end
|
532
|
+
|
533
|
+
def polymorphic_type_attribute?(scope, previous_value)
|
534
|
+
scope.to_s =~ /_type$/ && model_class?(previous_value)
|
535
|
+
end
|
536
|
+
|
422
537
|
def available_enum_values_for(scope, previous_value)
|
423
538
|
@subject.defined_enums[scope.to_s].reject do |key, _|
|
424
539
|
key == previous_value
|
425
540
|
end
|
426
541
|
end
|
427
542
|
|
543
|
+
def existing_value
|
544
|
+
existing_record.__send__(@attribute)
|
545
|
+
end
|
546
|
+
|
428
547
|
def class_name
|
429
548
|
@subject.class.name
|
430
549
|
end
|
431
550
|
|
432
|
-
def
|
433
|
-
|
434
|
-
if @options[:case_insensitive] && value.respond_to?(:swapcase!)
|
435
|
-
value.swapcase!
|
436
|
-
end
|
437
|
-
value
|
551
|
+
def column_for(scope)
|
552
|
+
@subject.class.columns_hash[scope.to_s]
|
438
553
|
end
|
439
554
|
end
|
440
555
|
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Shoulda
|
2
|
+
module Matchers
|
3
|
+
# @private
|
4
|
+
def self.configure
|
5
|
+
yield configuration
|
6
|
+
end
|
7
|
+
|
8
|
+
# @private
|
9
|
+
def self.configuration
|
10
|
+
@_configuration ||= Configuration.new
|
11
|
+
end
|
12
|
+
|
13
|
+
# @private
|
14
|
+
class Configuration
|
15
|
+
def integrate(&block)
|
16
|
+
Integrations::Configuration.apply(self, &block)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -13,6 +13,16 @@ module Shoulda
|
|
13
13
|
def world
|
14
14
|
@_world ||= World.new
|
15
15
|
end
|
16
|
+
|
17
|
+
def debugging_enabled?
|
18
|
+
ENV['DEBUG_DOUBLESPEAK'] == '1'
|
19
|
+
end
|
20
|
+
|
21
|
+
def debug(&block)
|
22
|
+
if debugging_enabled?
|
23
|
+
puts block.call
|
24
|
+
end
|
25
|
+
end
|
16
26
|
end
|
17
27
|
end
|
18
28
|
end
|
@@ -21,8 +31,8 @@ end
|
|
21
31
|
require 'shoulda/matchers/doublespeak/double'
|
22
32
|
require 'shoulda/matchers/doublespeak/double_collection'
|
23
33
|
require 'shoulda/matchers/doublespeak/double_implementation_registry'
|
34
|
+
require 'shoulda/matchers/doublespeak/method_call'
|
24
35
|
require 'shoulda/matchers/doublespeak/object_double'
|
25
36
|
require 'shoulda/matchers/doublespeak/proxy_implementation'
|
26
|
-
require 'shoulda/matchers/doublespeak/structs'
|
27
37
|
require 'shoulda/matchers/doublespeak/stub_implementation'
|
28
38
|
require 'shoulda/matchers/doublespeak/world'
|
@@ -5,7 +5,8 @@ module Shoulda
|
|
5
5
|
class Double
|
6
6
|
attr_reader :calls
|
7
7
|
|
8
|
-
def initialize(klass, method_name, implementation)
|
8
|
+
def initialize(world, klass, method_name, implementation)
|
9
|
+
@world = world
|
9
10
|
@klass = klass
|
10
11
|
@method_name = method_name
|
11
12
|
@implementation = implementation
|
@@ -36,36 +37,53 @@ module Shoulda
|
|
36
37
|
end
|
37
38
|
end
|
38
39
|
|
39
|
-
def record_call(
|
40
|
-
calls <<
|
40
|
+
def record_call(call)
|
41
|
+
calls << call
|
41
42
|
end
|
42
43
|
|
43
|
-
def call_original_method(
|
44
|
-
|
45
|
-
|
44
|
+
def call_original_method(call)
|
45
|
+
unbound_method = world.original_method_for(klass, call.method_name)
|
46
|
+
|
47
|
+
if unbound_method
|
48
|
+
unbound_method.bind(call.object).call(*call.args, &call.block)
|
46
49
|
end
|
47
50
|
end
|
48
51
|
|
49
52
|
protected
|
50
53
|
|
51
|
-
attr_reader :klass, :method_name, :implementation,
|
54
|
+
attr_reader :world, :klass, :method_name, :implementation,
|
55
|
+
:original_method
|
52
56
|
|
53
57
|
def store_original_method
|
54
|
-
|
58
|
+
world.store_original_method_for(klass, method_name)
|
55
59
|
end
|
56
60
|
|
57
61
|
def replace_method_with_double
|
58
|
-
implementation = @implementation
|
59
62
|
double = self
|
63
|
+
implementation = @implementation
|
64
|
+
_method_name = method_name
|
65
|
+
|
66
|
+
if klass.instance_methods(false).include?(method_name)
|
67
|
+
klass.__send__(:remove_method, method_name)
|
68
|
+
end
|
60
69
|
|
61
70
|
klass.__send__(:define_method, method_name) do |*args, &block|
|
62
|
-
|
71
|
+
call = MethodCall.new(
|
72
|
+
double: double,
|
73
|
+
object: self,
|
74
|
+
method_name: _method_name,
|
75
|
+
args: args,
|
76
|
+
block: block
|
77
|
+
)
|
78
|
+
implementation.call(call)
|
63
79
|
end
|
64
80
|
end
|
65
81
|
|
66
82
|
def restore_original_method
|
67
|
-
original_method =
|
83
|
+
original_method = world.original_method_for(klass, method_name)
|
84
|
+
|
68
85
|
klass.__send__(:remove_method, method_name)
|
86
|
+
|
69
87
|
klass.__send__(:define_method, method_name) do |*args, &block|
|
70
88
|
original_method.bind(self).call(*args, &block)
|
71
89
|
end
|