shoulda-matchers 2.8.0 → 3.0.0.rc1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|