mcmire-shoulda-matchers 2.5.0
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 +7 -0
- data/.gitignore +12 -0
- data/.travis.yml +32 -0
- data/.yardopts +7 -0
- data/Appraisals +45 -0
- data/CONTRIBUTING.md +41 -0
- data/Gemfile +31 -0
- data/Gemfile.lock +166 -0
- data/MIT-LICENSE +22 -0
- data/NEWS.md +299 -0
- data/README.md +163 -0
- data/Rakefile +116 -0
- data/doc_config/gh-pages/index.html.erb +9 -0
- data/doc_config/yard/setup.rb +22 -0
- data/doc_config/yard/templates/default/fulldoc/html/css/bootstrap.css +5967 -0
- data/doc_config/yard/templates/default/fulldoc/html/css/full_list.css +12 -0
- data/doc_config/yard/templates/default/fulldoc/html/css/global.css +45 -0
- data/doc_config/yard/templates/default/fulldoc/html/css/solarized.css +69 -0
- data/doc_config/yard/templates/default/fulldoc/html/css/style.css +283 -0
- data/doc_config/yard/templates/default/fulldoc/html/full_list.erb +32 -0
- data/doc_config/yard/templates/default/fulldoc/html/full_list_class.erb +1 -0
- data/doc_config/yard/templates/default/fulldoc/html/full_list_method.erb +8 -0
- data/doc_config/yard/templates/default/fulldoc/html/js/app.js +300 -0
- data/doc_config/yard/templates/default/fulldoc/html/js/full_list.js +1 -0
- data/doc_config/yard/templates/default/fulldoc/html/js/jquery.stickyheaders.js +289 -0
- data/doc_config/yard/templates/default/fulldoc/html/js/underscore.min.js +6 -0
- data/doc_config/yard/templates/default/fulldoc/html/setup.rb +8 -0
- data/doc_config/yard/templates/default/layout/html/breadcrumb.erb +14 -0
- data/doc_config/yard/templates/default/layout/html/fonts.erb +1 -0
- data/doc_config/yard/templates/default/layout/html/layout.erb +23 -0
- data/doc_config/yard/templates/default/layout/html/search.erb +13 -0
- data/doc_config/yard/templates/default/layout/html/setup.rb +8 -0
- data/doc_config/yard/templates/default/method_details/html/source.erb +10 -0
- data/doc_config/yard/templates/default/module/html/box_info.erb +31 -0
- data/features/rails_integration.feature +113 -0
- data/features/step_definitions/rails_steps.rb +162 -0
- data/features/support/env.rb +5 -0
- data/gemfiles/3.0.gemfile +24 -0
- data/gemfiles/3.0.gemfile.lock +150 -0
- data/gemfiles/3.1.gemfile +27 -0
- data/gemfiles/3.1.gemfile.lock +173 -0
- data/gemfiles/3.2.gemfile +27 -0
- data/gemfiles/3.2.gemfile.lock +171 -0
- data/gemfiles/4.0.0.gemfile +28 -0
- data/gemfiles/4.0.0.gemfile.lock +172 -0
- data/gemfiles/4.0.1.gemfile +28 -0
- data/gemfiles/4.0.1.gemfile.lock +172 -0
- data/lib/shoulda-matchers.rb +1 -0
- data/lib/shoulda/matchers.rb +11 -0
- data/lib/shoulda/matchers/action_controller.rb +17 -0
- data/lib/shoulda/matchers/action_controller/filter_param_matcher.rb +64 -0
- data/lib/shoulda/matchers/action_controller/redirect_to_matcher.rb +97 -0
- data/lib/shoulda/matchers/action_controller/render_template_matcher.rb +81 -0
- data/lib/shoulda/matchers/action_controller/render_with_layout_matcher.rb +117 -0
- data/lib/shoulda/matchers/action_controller/rescue_from_matcher.rb +114 -0
- data/lib/shoulda/matchers/action_controller/respond_with_matcher.rb +154 -0
- data/lib/shoulda/matchers/action_controller/route_matcher.rb +116 -0
- data/lib/shoulda/matchers/action_controller/route_params.rb +48 -0
- data/lib/shoulda/matchers/action_controller/set_session_matcher.rb +164 -0
- data/lib/shoulda/matchers/action_controller/set_the_flash_matcher.rb +296 -0
- data/lib/shoulda/matchers/active_model.rb +30 -0
- data/lib/shoulda/matchers/active_model/allow_mass_assignment_of_matcher.rb +167 -0
- data/lib/shoulda/matchers/active_model/allow_value_matcher.rb +314 -0
- data/lib/shoulda/matchers/active_model/disallow_value_matcher.rb +46 -0
- data/lib/shoulda/matchers/active_model/ensure_exclusion_of_matcher.rb +160 -0
- data/lib/shoulda/matchers/active_model/ensure_inclusion_of_matcher.rb +417 -0
- data/lib/shoulda/matchers/active_model/ensure_length_of_matcher.rb +337 -0
- data/lib/shoulda/matchers/active_model/errors.rb +10 -0
- data/lib/shoulda/matchers/active_model/exception_message_finder.rb +58 -0
- data/lib/shoulda/matchers/active_model/have_secure_password_matcher.rb +92 -0
- data/lib/shoulda/matchers/active_model/helpers.rb +46 -0
- data/lib/shoulda/matchers/active_model/numericality_matchers.rb +9 -0
- data/lib/shoulda/matchers/active_model/numericality_matchers/comparison_matcher.rb +75 -0
- data/lib/shoulda/matchers/active_model/numericality_matchers/even_number_matcher.rb +27 -0
- data/lib/shoulda/matchers/active_model/numericality_matchers/numeric_type_matcher.rb +41 -0
- data/lib/shoulda/matchers/active_model/numericality_matchers/odd_number_matcher.rb +27 -0
- data/lib/shoulda/matchers/active_model/numericality_matchers/only_integer_matcher.rb +26 -0
- data/lib/shoulda/matchers/active_model/validate_absence_of_matcher.rb +112 -0
- data/lib/shoulda/matchers/active_model/validate_acceptance_of_matcher.rb +77 -0
- data/lib/shoulda/matchers/active_model/validate_confirmation_of_matcher.rb +121 -0
- data/lib/shoulda/matchers/active_model/validate_numericality_of_matcher.rb +380 -0
- data/lib/shoulda/matchers/active_model/validate_presence_of_matcher.rb +89 -0
- data/lib/shoulda/matchers/active_model/validate_uniqueness_of_matcher.rb +372 -0
- data/lib/shoulda/matchers/active_model/validation_matcher.rb +97 -0
- data/lib/shoulda/matchers/active_model/validation_message_finder.rb +69 -0
- data/lib/shoulda/matchers/active_record.rb +22 -0
- data/lib/shoulda/matchers/active_record/accept_nested_attributes_for_matcher.rb +204 -0
- data/lib/shoulda/matchers/active_record/association_matcher.rb +901 -0
- data/lib/shoulda/matchers/active_record/association_matchers.rb +9 -0
- data/lib/shoulda/matchers/active_record/association_matchers/counter_cache_matcher.rb +41 -0
- data/lib/shoulda/matchers/active_record/association_matchers/dependent_matcher.rb +41 -0
- data/lib/shoulda/matchers/active_record/association_matchers/model_reflection.rb +81 -0
- data/lib/shoulda/matchers/active_record/association_matchers/model_reflector.rb +65 -0
- data/lib/shoulda/matchers/active_record/association_matchers/option_verifier.rb +94 -0
- data/lib/shoulda/matchers/active_record/association_matchers/order_matcher.rb +41 -0
- data/lib/shoulda/matchers/active_record/association_matchers/source_matcher.rb +41 -0
- data/lib/shoulda/matchers/active_record/association_matchers/through_matcher.rb +63 -0
- data/lib/shoulda/matchers/active_record/have_db_column_matcher.rb +261 -0
- data/lib/shoulda/matchers/active_record/have_db_index_matcher.rb +149 -0
- data/lib/shoulda/matchers/active_record/have_readonly_attribute_matcher.rb +72 -0
- data/lib/shoulda/matchers/active_record/serialize_matcher.rb +181 -0
- data/lib/shoulda/matchers/assertion_error.rb +19 -0
- data/lib/shoulda/matchers/error.rb +6 -0
- data/lib/shoulda/matchers/integrations/rspec.rb +20 -0
- data/lib/shoulda/matchers/integrations/test_unit.rb +30 -0
- data/lib/shoulda/matchers/rails_shim.rb +50 -0
- data/lib/shoulda/matchers/version.rb +6 -0
- data/lib/shoulda/matchers/warn.rb +8 -0
- data/shoulda-matchers.gemspec +23 -0
- data/spec/shoulda/matchers/action_controller/filter_param_matcher_spec.rb +22 -0
- data/spec/shoulda/matchers/action_controller/redirect_to_matcher_spec.rb +42 -0
- data/spec/shoulda/matchers/action_controller/render_template_matcher_spec.rb +78 -0
- data/spec/shoulda/matchers/action_controller/render_with_layout_matcher_spec.rb +63 -0
- data/spec/shoulda/matchers/action_controller/rescue_from_matcher_spec.rb +63 -0
- data/spec/shoulda/matchers/action_controller/respond_with_matcher_spec.rb +31 -0
- data/spec/shoulda/matchers/action_controller/route_matcher_spec.rb +70 -0
- data/spec/shoulda/matchers/action_controller/route_params_spec.rb +30 -0
- data/spec/shoulda/matchers/action_controller/set_session_matcher_spec.rb +51 -0
- data/spec/shoulda/matchers/action_controller/set_the_flash_matcher_spec.rb +153 -0
- data/spec/shoulda/matchers/active_model/allow_mass_assignment_of_matcher_spec.rb +111 -0
- data/spec/shoulda/matchers/active_model/allow_value_matcher_spec.rb +170 -0
- data/spec/shoulda/matchers/active_model/disallow_value_matcher_spec.rb +81 -0
- data/spec/shoulda/matchers/active_model/ensure_exclusion_of_matcher_spec.rb +95 -0
- data/spec/shoulda/matchers/active_model/ensure_inclusion_of_matcher_spec.rb +320 -0
- data/spec/shoulda/matchers/active_model/ensure_length_of_matcher_spec.rb +166 -0
- data/spec/shoulda/matchers/active_model/exception_message_finder_spec.rb +111 -0
- data/spec/shoulda/matchers/active_model/have_secure_password_matcher_spec.rb +20 -0
- data/spec/shoulda/matchers/active_model/helpers_spec.rb +158 -0
- data/spec/shoulda/matchers/active_model/numericality_matchers/comparison_matcher_spec.rb +169 -0
- data/spec/shoulda/matchers/active_model/numericality_matchers/even_number_matcher_spec.rb +59 -0
- data/spec/shoulda/matchers/active_model/numericality_matchers/odd_number_matcher_spec.rb +59 -0
- data/spec/shoulda/matchers/active_model/numericality_matchers/only_integer_matcher_spec.rb +57 -0
- data/spec/shoulda/matchers/active_model/validate_absence_of_matcher_spec.rb +139 -0
- data/spec/shoulda/matchers/active_model/validate_acceptance_of_matcher_spec.rb +41 -0
- data/spec/shoulda/matchers/active_model/validate_confirmation_of_matcher_spec.rb +47 -0
- data/spec/shoulda/matchers/active_model/validate_numericality_of_matcher_spec.rb +331 -0
- data/spec/shoulda/matchers/active_model/validate_presence_of_matcher_spec.rb +180 -0
- data/spec/shoulda/matchers/active_model/validate_uniqueness_of_matcher_spec.rb +398 -0
- data/spec/shoulda/matchers/active_model/validation_message_finder_spec.rb +127 -0
- data/spec/shoulda/matchers/active_record/accept_nested_attributes_for_matcher_spec.rb +107 -0
- data/spec/shoulda/matchers/active_record/association_matcher_spec.rb +860 -0
- data/spec/shoulda/matchers/active_record/association_matchers/model_reflection_spec.rb +247 -0
- data/spec/shoulda/matchers/active_record/have_db_column_matcher_spec.rb +111 -0
- data/spec/shoulda/matchers/active_record/have_db_index_matcher_spec.rb +78 -0
- data/spec/shoulda/matchers/active_record/have_readonly_attributes_matcher_spec.rb +41 -0
- data/spec/shoulda/matchers/active_record/serialize_matcher_spec.rb +86 -0
- data/spec/spec_helper.rb +26 -0
- data/spec/support/active_model_versions.rb +13 -0
- data/spec/support/active_resource_builder.rb +29 -0
- data/spec/support/activemodel_helpers.rb +19 -0
- data/spec/support/capture_helpers.rb +19 -0
- data/spec/support/class_builder.rb +42 -0
- data/spec/support/controller_builder.rb +74 -0
- data/spec/support/fail_with_message_including_matcher.rb +33 -0
- data/spec/support/fail_with_message_matcher.rb +32 -0
- data/spec/support/i18n_faker.rb +10 -0
- data/spec/support/mailer_builder.rb +10 -0
- data/spec/support/model_builder.rb +81 -0
- data/spec/support/rails_versions.rb +18 -0
- data/spec/support/shared_examples/numerical_submatcher.rb +19 -0
- data/spec/support/shared_examples/numerical_type_submatcher.rb +17 -0
- data/spec/support/test_application.rb +120 -0
- data/yard.watchr +5 -0
- metadata +281 -0
@@ -0,0 +1,41 @@
|
|
1
|
+
module Shoulda
|
2
|
+
module Matchers
|
3
|
+
module ActiveRecord
|
4
|
+
module AssociationMatchers
|
5
|
+
# @private
|
6
|
+
class CounterCacheMatcher
|
7
|
+
attr_accessor :missing_option
|
8
|
+
|
9
|
+
def initialize(counter_cache, name)
|
10
|
+
@counter_cache = counter_cache
|
11
|
+
@name = name
|
12
|
+
@missing_option = ''
|
13
|
+
end
|
14
|
+
|
15
|
+
def description
|
16
|
+
"counter_cache => #{counter_cache}"
|
17
|
+
end
|
18
|
+
|
19
|
+
def matches?(subject)
|
20
|
+
self.subject = ModelReflector.new(subject, name)
|
21
|
+
|
22
|
+
if option_verifier.correct_for_string?(:counter_cache, counter_cache)
|
23
|
+
true
|
24
|
+
else
|
25
|
+
self.missing_option = "#{name} should have #{description}"
|
26
|
+
false
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
attr_accessor :subject, :counter_cache, :name
|
33
|
+
|
34
|
+
def option_verifier
|
35
|
+
@option_verifier ||= OptionVerifier.new(subject)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module Shoulda
|
2
|
+
module Matchers
|
3
|
+
module ActiveRecord
|
4
|
+
module AssociationMatchers
|
5
|
+
# @private
|
6
|
+
class DependentMatcher
|
7
|
+
attr_accessor :missing_option
|
8
|
+
|
9
|
+
def initialize(dependent, name)
|
10
|
+
@dependent = dependent
|
11
|
+
@name = name
|
12
|
+
@missing_option = ''
|
13
|
+
end
|
14
|
+
|
15
|
+
def description
|
16
|
+
"dependent => #{dependent}"
|
17
|
+
end
|
18
|
+
|
19
|
+
def matches?(subject)
|
20
|
+
self.subject = ModelReflector.new(subject, name)
|
21
|
+
|
22
|
+
if option_verifier.correct_for_string?(:dependent, dependent)
|
23
|
+
true
|
24
|
+
else
|
25
|
+
self.missing_option = "#{name} should have #{dependent} dependency"
|
26
|
+
false
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
attr_accessor :subject, :dependent, :name
|
33
|
+
|
34
|
+
def option_verifier
|
35
|
+
@option_verifier ||= OptionVerifier.new(subject)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
require 'delegate'
|
2
|
+
|
3
|
+
module Shoulda
|
4
|
+
module Matchers
|
5
|
+
module ActiveRecord
|
6
|
+
module AssociationMatchers
|
7
|
+
# @private
|
8
|
+
class ModelReflection < SimpleDelegator
|
9
|
+
def initialize(reflection)
|
10
|
+
super(reflection)
|
11
|
+
@reflection = reflection
|
12
|
+
@subject = reflection.active_record
|
13
|
+
end
|
14
|
+
|
15
|
+
def associated_class
|
16
|
+
reflection.klass
|
17
|
+
end
|
18
|
+
|
19
|
+
def through?
|
20
|
+
reflection.options[:through]
|
21
|
+
end
|
22
|
+
|
23
|
+
def join_table
|
24
|
+
join_table =
|
25
|
+
if reflection.respond_to?(:join_table)
|
26
|
+
reflection.join_table
|
27
|
+
else
|
28
|
+
reflection.options[:join_table]
|
29
|
+
end
|
30
|
+
|
31
|
+
join_table.to_s
|
32
|
+
end
|
33
|
+
|
34
|
+
def association_relation
|
35
|
+
if reflection.respond_to?(:scope)
|
36
|
+
convert_scope_to_relation(reflection.scope)
|
37
|
+
else
|
38
|
+
convert_options_to_relation(reflection.options)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
attr_reader :reflection, :subject
|
45
|
+
|
46
|
+
def convert_scope_to_relation(scope)
|
47
|
+
relation = associated_class.all
|
48
|
+
|
49
|
+
if scope
|
50
|
+
# Source: AR::Associations::AssociationScope#eval_scope
|
51
|
+
relation.instance_exec(subject, &scope)
|
52
|
+
else
|
53
|
+
relation
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def convert_options_to_relation(options)
|
58
|
+
relation = associated_class.scoped
|
59
|
+
relation = extend_relation_with(relation, :where, options[:conditions])
|
60
|
+
relation = extend_relation_with(relation, :includes, options[:include])
|
61
|
+
relation = extend_relation_with(relation, :order, options[:order])
|
62
|
+
relation = extend_relation_with(relation, :group, options[:group])
|
63
|
+
relation = extend_relation_with(relation, :having, options[:having])
|
64
|
+
relation = extend_relation_with(relation, :limit, options[:limit])
|
65
|
+
relation = extend_relation_with(relation, :offset, options[:offset])
|
66
|
+
relation = extend_relation_with(relation, :select, options[:select])
|
67
|
+
relation
|
68
|
+
end
|
69
|
+
|
70
|
+
def extend_relation_with(relation, method_name, value)
|
71
|
+
if value
|
72
|
+
relation.__send__(method_name, value)
|
73
|
+
else
|
74
|
+
relation
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
module Shoulda
|
2
|
+
module Matchers
|
3
|
+
module ActiveRecord
|
4
|
+
module AssociationMatchers
|
5
|
+
# @private
|
6
|
+
class ModelReflector
|
7
|
+
delegate :associated_class, :through?, :join_table,
|
8
|
+
:association_relation, to: :reflection
|
9
|
+
|
10
|
+
def initialize(subject, name)
|
11
|
+
@subject = subject
|
12
|
+
@name = name
|
13
|
+
end
|
14
|
+
|
15
|
+
def reflection
|
16
|
+
@reflection ||= reflect_on_association(name)
|
17
|
+
end
|
18
|
+
|
19
|
+
def reflect_on_association(name)
|
20
|
+
reflection = model_class.reflect_on_association(name)
|
21
|
+
|
22
|
+
if reflection
|
23
|
+
ModelReflection.new(reflection)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def model_class
|
28
|
+
subject.class
|
29
|
+
end
|
30
|
+
|
31
|
+
def build_relation_with_clause(name, value)
|
32
|
+
case name
|
33
|
+
when :conditions then associated_class.where(value)
|
34
|
+
when :order then associated_class.order(value)
|
35
|
+
else raise ArgumentError, "Unknown clause '#{name}'"
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def extract_relation_clause_from(relation, name)
|
40
|
+
case name
|
41
|
+
when :conditions
|
42
|
+
relation.where_values_hash
|
43
|
+
when :order
|
44
|
+
relation.order_values.map { |value| value_as_sql(value) }.join(', ')
|
45
|
+
else
|
46
|
+
raise ArgumentError, "Unknown clause '#{name}'"
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
private
|
51
|
+
|
52
|
+
attr_reader :subject, :name
|
53
|
+
|
54
|
+
def value_as_sql(value)
|
55
|
+
if value.respond_to?(:to_sql)
|
56
|
+
value.to_sql
|
57
|
+
else
|
58
|
+
value
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,94 @@
|
|
1
|
+
module Shoulda
|
2
|
+
module Matchers
|
3
|
+
module ActiveRecord
|
4
|
+
module AssociationMatchers
|
5
|
+
# @private
|
6
|
+
class OptionVerifier
|
7
|
+
delegate :reflection, to: :reflector
|
8
|
+
|
9
|
+
attr_reader :reflector
|
10
|
+
|
11
|
+
RELATION_OPTIONS = [:conditions, :order]
|
12
|
+
|
13
|
+
def initialize(reflector)
|
14
|
+
@reflector = reflector
|
15
|
+
end
|
16
|
+
|
17
|
+
def correct_for_string?(name, expected_value)
|
18
|
+
correct_for?(:string, name, expected_value)
|
19
|
+
end
|
20
|
+
|
21
|
+
def correct_for_boolean?(name, expected_value)
|
22
|
+
correct_for?(:boolean, name, expected_value)
|
23
|
+
end
|
24
|
+
|
25
|
+
def correct_for_hash?(name, expected_value)
|
26
|
+
correct_for?(:hash, name, expected_value)
|
27
|
+
end
|
28
|
+
|
29
|
+
def correct_for_relation_clause?(name, expected_value)
|
30
|
+
correct_for?(:relation_clause, name, expected_value)
|
31
|
+
end
|
32
|
+
|
33
|
+
def actual_value_for(name)
|
34
|
+
if RELATION_OPTIONS.include?(name)
|
35
|
+
actual_value_for_relation_clause(name)
|
36
|
+
else
|
37
|
+
method_name = "actual_value_for_#{name}"
|
38
|
+
if respond_to?(method_name, true)
|
39
|
+
__send__(method_name)
|
40
|
+
else
|
41
|
+
reflection.options[name]
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
private
|
47
|
+
|
48
|
+
attr_reader :reflector
|
49
|
+
|
50
|
+
def correct_for?(*args)
|
51
|
+
expected_value, name, type = args.reverse
|
52
|
+
if expected_value.nil?
|
53
|
+
true
|
54
|
+
else
|
55
|
+
expected_value = type_cast(type, expected_value_for(name, expected_value))
|
56
|
+
actual_value = type_cast(type, actual_value_for(name))
|
57
|
+
expected_value == actual_value
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def type_cast(type, value)
|
62
|
+
case type
|
63
|
+
when :string, :relation_clause then value.to_s
|
64
|
+
when :boolean then !!value
|
65
|
+
when :hash then Hash(value).stringify_keys
|
66
|
+
else value
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def expected_value_for(name, value)
|
71
|
+
if RELATION_OPTIONS.include?(name)
|
72
|
+
expected_value_for_relation_clause(name, value)
|
73
|
+
else
|
74
|
+
value
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def expected_value_for_relation_clause(name, value)
|
79
|
+
relation = reflector.build_relation_with_clause(name, value)
|
80
|
+
reflector.extract_relation_clause_from(relation, name)
|
81
|
+
end
|
82
|
+
|
83
|
+
def actual_value_for_relation_clause(name)
|
84
|
+
reflector.extract_relation_clause_from(reflector.association_relation, name)
|
85
|
+
end
|
86
|
+
|
87
|
+
def actual_value_for_class_name
|
88
|
+
reflector.associated_class
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module Shoulda
|
2
|
+
module Matchers
|
3
|
+
module ActiveRecord
|
4
|
+
module AssociationMatchers
|
5
|
+
# @private
|
6
|
+
class OrderMatcher
|
7
|
+
attr_accessor :missing_option
|
8
|
+
|
9
|
+
def initialize(order, name)
|
10
|
+
@order = order
|
11
|
+
@name = name
|
12
|
+
@missing_option = ''
|
13
|
+
end
|
14
|
+
|
15
|
+
def description
|
16
|
+
"order => #{order}"
|
17
|
+
end
|
18
|
+
|
19
|
+
def matches?(subject)
|
20
|
+
self.subject = ModelReflector.new(subject, name)
|
21
|
+
|
22
|
+
if option_verifier.correct_for_relation_clause?(:order, order)
|
23
|
+
true
|
24
|
+
else
|
25
|
+
self.missing_option = "#{name} should be ordered by #{order}"
|
26
|
+
false
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
attr_accessor :subject, :order, :name
|
33
|
+
|
34
|
+
def option_verifier
|
35
|
+
@option_verifier ||= OptionVerifier.new(subject)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module Shoulda
|
2
|
+
module Matchers
|
3
|
+
module ActiveRecord
|
4
|
+
module AssociationMatchers
|
5
|
+
# @private
|
6
|
+
class SourceMatcher
|
7
|
+
attr_accessor :missing_option
|
8
|
+
|
9
|
+
def initialize(source, name)
|
10
|
+
@source = source
|
11
|
+
@name = name
|
12
|
+
@missing_option = ''
|
13
|
+
end
|
14
|
+
|
15
|
+
def description
|
16
|
+
"source => #{source}"
|
17
|
+
end
|
18
|
+
|
19
|
+
def matches?(subject)
|
20
|
+
self.subject = ModelReflector.new(subject, name)
|
21
|
+
|
22
|
+
if option_verifier.correct_for_string?(:source, source)
|
23
|
+
true
|
24
|
+
else
|
25
|
+
self.missing_option = "#{name} should have #{source} as source option"
|
26
|
+
false
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
attr_accessor :subject, :source, :name
|
33
|
+
|
34
|
+
def option_verifier
|
35
|
+
@option_verifier ||= OptionVerifier.new(subject)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
module Shoulda
|
2
|
+
module Matchers
|
3
|
+
module ActiveRecord
|
4
|
+
module AssociationMatchers
|
5
|
+
# @private
|
6
|
+
class ThroughMatcher
|
7
|
+
attr_accessor :missing_option
|
8
|
+
|
9
|
+
def initialize(through, name)
|
10
|
+
@through = through
|
11
|
+
@name = name
|
12
|
+
@missing_option = ''
|
13
|
+
end
|
14
|
+
|
15
|
+
def description
|
16
|
+
"through #{through}"
|
17
|
+
end
|
18
|
+
|
19
|
+
def matches?(subject)
|
20
|
+
self.subject = ModelReflector.new(subject, name)
|
21
|
+
through.nil? || association_set_properly?
|
22
|
+
end
|
23
|
+
|
24
|
+
def association_set_properly?
|
25
|
+
through_association_exists? && through_association_correct?
|
26
|
+
end
|
27
|
+
|
28
|
+
def through_association_exists?
|
29
|
+
if through_reflection.present?
|
30
|
+
true
|
31
|
+
else
|
32
|
+
self.missing_option = "#{name} does not have any relationship to #{through}"
|
33
|
+
false
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def through_reflection
|
38
|
+
@through_reflection ||= subject.reflect_on_association(through)
|
39
|
+
end
|
40
|
+
|
41
|
+
def through_association_correct?
|
42
|
+
if option_verifier.correct_for_string?(:through, through)
|
43
|
+
true
|
44
|
+
else
|
45
|
+
self.missing_option =
|
46
|
+
"Expected #{name} to have #{name} through #{through}, " +
|
47
|
+
"but got it through #{option_verifier.actual_value_for(:through)}"
|
48
|
+
false
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
private
|
53
|
+
|
54
|
+
attr_accessor :through, :name, :subject
|
55
|
+
|
56
|
+
def option_verifier
|
57
|
+
@option_verifier ||= OptionVerifier.new(subject)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|