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.
Files changed (164) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +12 -0
  3. data/.travis.yml +32 -0
  4. data/.yardopts +7 -0
  5. data/Appraisals +45 -0
  6. data/CONTRIBUTING.md +41 -0
  7. data/Gemfile +31 -0
  8. data/Gemfile.lock +166 -0
  9. data/MIT-LICENSE +22 -0
  10. data/NEWS.md +299 -0
  11. data/README.md +163 -0
  12. data/Rakefile +116 -0
  13. data/doc_config/gh-pages/index.html.erb +9 -0
  14. data/doc_config/yard/setup.rb +22 -0
  15. data/doc_config/yard/templates/default/fulldoc/html/css/bootstrap.css +5967 -0
  16. data/doc_config/yard/templates/default/fulldoc/html/css/full_list.css +12 -0
  17. data/doc_config/yard/templates/default/fulldoc/html/css/global.css +45 -0
  18. data/doc_config/yard/templates/default/fulldoc/html/css/solarized.css +69 -0
  19. data/doc_config/yard/templates/default/fulldoc/html/css/style.css +283 -0
  20. data/doc_config/yard/templates/default/fulldoc/html/full_list.erb +32 -0
  21. data/doc_config/yard/templates/default/fulldoc/html/full_list_class.erb +1 -0
  22. data/doc_config/yard/templates/default/fulldoc/html/full_list_method.erb +8 -0
  23. data/doc_config/yard/templates/default/fulldoc/html/js/app.js +300 -0
  24. data/doc_config/yard/templates/default/fulldoc/html/js/full_list.js +1 -0
  25. data/doc_config/yard/templates/default/fulldoc/html/js/jquery.stickyheaders.js +289 -0
  26. data/doc_config/yard/templates/default/fulldoc/html/js/underscore.min.js +6 -0
  27. data/doc_config/yard/templates/default/fulldoc/html/setup.rb +8 -0
  28. data/doc_config/yard/templates/default/layout/html/breadcrumb.erb +14 -0
  29. data/doc_config/yard/templates/default/layout/html/fonts.erb +1 -0
  30. data/doc_config/yard/templates/default/layout/html/layout.erb +23 -0
  31. data/doc_config/yard/templates/default/layout/html/search.erb +13 -0
  32. data/doc_config/yard/templates/default/layout/html/setup.rb +8 -0
  33. data/doc_config/yard/templates/default/method_details/html/source.erb +10 -0
  34. data/doc_config/yard/templates/default/module/html/box_info.erb +31 -0
  35. data/features/rails_integration.feature +113 -0
  36. data/features/step_definitions/rails_steps.rb +162 -0
  37. data/features/support/env.rb +5 -0
  38. data/gemfiles/3.0.gemfile +24 -0
  39. data/gemfiles/3.0.gemfile.lock +150 -0
  40. data/gemfiles/3.1.gemfile +27 -0
  41. data/gemfiles/3.1.gemfile.lock +173 -0
  42. data/gemfiles/3.2.gemfile +27 -0
  43. data/gemfiles/3.2.gemfile.lock +171 -0
  44. data/gemfiles/4.0.0.gemfile +28 -0
  45. data/gemfiles/4.0.0.gemfile.lock +172 -0
  46. data/gemfiles/4.0.1.gemfile +28 -0
  47. data/gemfiles/4.0.1.gemfile.lock +172 -0
  48. data/lib/shoulda-matchers.rb +1 -0
  49. data/lib/shoulda/matchers.rb +11 -0
  50. data/lib/shoulda/matchers/action_controller.rb +17 -0
  51. data/lib/shoulda/matchers/action_controller/filter_param_matcher.rb +64 -0
  52. data/lib/shoulda/matchers/action_controller/redirect_to_matcher.rb +97 -0
  53. data/lib/shoulda/matchers/action_controller/render_template_matcher.rb +81 -0
  54. data/lib/shoulda/matchers/action_controller/render_with_layout_matcher.rb +117 -0
  55. data/lib/shoulda/matchers/action_controller/rescue_from_matcher.rb +114 -0
  56. data/lib/shoulda/matchers/action_controller/respond_with_matcher.rb +154 -0
  57. data/lib/shoulda/matchers/action_controller/route_matcher.rb +116 -0
  58. data/lib/shoulda/matchers/action_controller/route_params.rb +48 -0
  59. data/lib/shoulda/matchers/action_controller/set_session_matcher.rb +164 -0
  60. data/lib/shoulda/matchers/action_controller/set_the_flash_matcher.rb +296 -0
  61. data/lib/shoulda/matchers/active_model.rb +30 -0
  62. data/lib/shoulda/matchers/active_model/allow_mass_assignment_of_matcher.rb +167 -0
  63. data/lib/shoulda/matchers/active_model/allow_value_matcher.rb +314 -0
  64. data/lib/shoulda/matchers/active_model/disallow_value_matcher.rb +46 -0
  65. data/lib/shoulda/matchers/active_model/ensure_exclusion_of_matcher.rb +160 -0
  66. data/lib/shoulda/matchers/active_model/ensure_inclusion_of_matcher.rb +417 -0
  67. data/lib/shoulda/matchers/active_model/ensure_length_of_matcher.rb +337 -0
  68. data/lib/shoulda/matchers/active_model/errors.rb +10 -0
  69. data/lib/shoulda/matchers/active_model/exception_message_finder.rb +58 -0
  70. data/lib/shoulda/matchers/active_model/have_secure_password_matcher.rb +92 -0
  71. data/lib/shoulda/matchers/active_model/helpers.rb +46 -0
  72. data/lib/shoulda/matchers/active_model/numericality_matchers.rb +9 -0
  73. data/lib/shoulda/matchers/active_model/numericality_matchers/comparison_matcher.rb +75 -0
  74. data/lib/shoulda/matchers/active_model/numericality_matchers/even_number_matcher.rb +27 -0
  75. data/lib/shoulda/matchers/active_model/numericality_matchers/numeric_type_matcher.rb +41 -0
  76. data/lib/shoulda/matchers/active_model/numericality_matchers/odd_number_matcher.rb +27 -0
  77. data/lib/shoulda/matchers/active_model/numericality_matchers/only_integer_matcher.rb +26 -0
  78. data/lib/shoulda/matchers/active_model/validate_absence_of_matcher.rb +112 -0
  79. data/lib/shoulda/matchers/active_model/validate_acceptance_of_matcher.rb +77 -0
  80. data/lib/shoulda/matchers/active_model/validate_confirmation_of_matcher.rb +121 -0
  81. data/lib/shoulda/matchers/active_model/validate_numericality_of_matcher.rb +380 -0
  82. data/lib/shoulda/matchers/active_model/validate_presence_of_matcher.rb +89 -0
  83. data/lib/shoulda/matchers/active_model/validate_uniqueness_of_matcher.rb +372 -0
  84. data/lib/shoulda/matchers/active_model/validation_matcher.rb +97 -0
  85. data/lib/shoulda/matchers/active_model/validation_message_finder.rb +69 -0
  86. data/lib/shoulda/matchers/active_record.rb +22 -0
  87. data/lib/shoulda/matchers/active_record/accept_nested_attributes_for_matcher.rb +204 -0
  88. data/lib/shoulda/matchers/active_record/association_matcher.rb +901 -0
  89. data/lib/shoulda/matchers/active_record/association_matchers.rb +9 -0
  90. data/lib/shoulda/matchers/active_record/association_matchers/counter_cache_matcher.rb +41 -0
  91. data/lib/shoulda/matchers/active_record/association_matchers/dependent_matcher.rb +41 -0
  92. data/lib/shoulda/matchers/active_record/association_matchers/model_reflection.rb +81 -0
  93. data/lib/shoulda/matchers/active_record/association_matchers/model_reflector.rb +65 -0
  94. data/lib/shoulda/matchers/active_record/association_matchers/option_verifier.rb +94 -0
  95. data/lib/shoulda/matchers/active_record/association_matchers/order_matcher.rb +41 -0
  96. data/lib/shoulda/matchers/active_record/association_matchers/source_matcher.rb +41 -0
  97. data/lib/shoulda/matchers/active_record/association_matchers/through_matcher.rb +63 -0
  98. data/lib/shoulda/matchers/active_record/have_db_column_matcher.rb +261 -0
  99. data/lib/shoulda/matchers/active_record/have_db_index_matcher.rb +149 -0
  100. data/lib/shoulda/matchers/active_record/have_readonly_attribute_matcher.rb +72 -0
  101. data/lib/shoulda/matchers/active_record/serialize_matcher.rb +181 -0
  102. data/lib/shoulda/matchers/assertion_error.rb +19 -0
  103. data/lib/shoulda/matchers/error.rb +6 -0
  104. data/lib/shoulda/matchers/integrations/rspec.rb +20 -0
  105. data/lib/shoulda/matchers/integrations/test_unit.rb +30 -0
  106. data/lib/shoulda/matchers/rails_shim.rb +50 -0
  107. data/lib/shoulda/matchers/version.rb +6 -0
  108. data/lib/shoulda/matchers/warn.rb +8 -0
  109. data/shoulda-matchers.gemspec +23 -0
  110. data/spec/shoulda/matchers/action_controller/filter_param_matcher_spec.rb +22 -0
  111. data/spec/shoulda/matchers/action_controller/redirect_to_matcher_spec.rb +42 -0
  112. data/spec/shoulda/matchers/action_controller/render_template_matcher_spec.rb +78 -0
  113. data/spec/shoulda/matchers/action_controller/render_with_layout_matcher_spec.rb +63 -0
  114. data/spec/shoulda/matchers/action_controller/rescue_from_matcher_spec.rb +63 -0
  115. data/spec/shoulda/matchers/action_controller/respond_with_matcher_spec.rb +31 -0
  116. data/spec/shoulda/matchers/action_controller/route_matcher_spec.rb +70 -0
  117. data/spec/shoulda/matchers/action_controller/route_params_spec.rb +30 -0
  118. data/spec/shoulda/matchers/action_controller/set_session_matcher_spec.rb +51 -0
  119. data/spec/shoulda/matchers/action_controller/set_the_flash_matcher_spec.rb +153 -0
  120. data/spec/shoulda/matchers/active_model/allow_mass_assignment_of_matcher_spec.rb +111 -0
  121. data/spec/shoulda/matchers/active_model/allow_value_matcher_spec.rb +170 -0
  122. data/spec/shoulda/matchers/active_model/disallow_value_matcher_spec.rb +81 -0
  123. data/spec/shoulda/matchers/active_model/ensure_exclusion_of_matcher_spec.rb +95 -0
  124. data/spec/shoulda/matchers/active_model/ensure_inclusion_of_matcher_spec.rb +320 -0
  125. data/spec/shoulda/matchers/active_model/ensure_length_of_matcher_spec.rb +166 -0
  126. data/spec/shoulda/matchers/active_model/exception_message_finder_spec.rb +111 -0
  127. data/spec/shoulda/matchers/active_model/have_secure_password_matcher_spec.rb +20 -0
  128. data/spec/shoulda/matchers/active_model/helpers_spec.rb +158 -0
  129. data/spec/shoulda/matchers/active_model/numericality_matchers/comparison_matcher_spec.rb +169 -0
  130. data/spec/shoulda/matchers/active_model/numericality_matchers/even_number_matcher_spec.rb +59 -0
  131. data/spec/shoulda/matchers/active_model/numericality_matchers/odd_number_matcher_spec.rb +59 -0
  132. data/spec/shoulda/matchers/active_model/numericality_matchers/only_integer_matcher_spec.rb +57 -0
  133. data/spec/shoulda/matchers/active_model/validate_absence_of_matcher_spec.rb +139 -0
  134. data/spec/shoulda/matchers/active_model/validate_acceptance_of_matcher_spec.rb +41 -0
  135. data/spec/shoulda/matchers/active_model/validate_confirmation_of_matcher_spec.rb +47 -0
  136. data/spec/shoulda/matchers/active_model/validate_numericality_of_matcher_spec.rb +331 -0
  137. data/spec/shoulda/matchers/active_model/validate_presence_of_matcher_spec.rb +180 -0
  138. data/spec/shoulda/matchers/active_model/validate_uniqueness_of_matcher_spec.rb +398 -0
  139. data/spec/shoulda/matchers/active_model/validation_message_finder_spec.rb +127 -0
  140. data/spec/shoulda/matchers/active_record/accept_nested_attributes_for_matcher_spec.rb +107 -0
  141. data/spec/shoulda/matchers/active_record/association_matcher_spec.rb +860 -0
  142. data/spec/shoulda/matchers/active_record/association_matchers/model_reflection_spec.rb +247 -0
  143. data/spec/shoulda/matchers/active_record/have_db_column_matcher_spec.rb +111 -0
  144. data/spec/shoulda/matchers/active_record/have_db_index_matcher_spec.rb +78 -0
  145. data/spec/shoulda/matchers/active_record/have_readonly_attributes_matcher_spec.rb +41 -0
  146. data/spec/shoulda/matchers/active_record/serialize_matcher_spec.rb +86 -0
  147. data/spec/spec_helper.rb +26 -0
  148. data/spec/support/active_model_versions.rb +13 -0
  149. data/spec/support/active_resource_builder.rb +29 -0
  150. data/spec/support/activemodel_helpers.rb +19 -0
  151. data/spec/support/capture_helpers.rb +19 -0
  152. data/spec/support/class_builder.rb +42 -0
  153. data/spec/support/controller_builder.rb +74 -0
  154. data/spec/support/fail_with_message_including_matcher.rb +33 -0
  155. data/spec/support/fail_with_message_matcher.rb +32 -0
  156. data/spec/support/i18n_faker.rb +10 -0
  157. data/spec/support/mailer_builder.rb +10 -0
  158. data/spec/support/model_builder.rb +81 -0
  159. data/spec/support/rails_versions.rb +18 -0
  160. data/spec/support/shared_examples/numerical_submatcher.rb +19 -0
  161. data/spec/support/shared_examples/numerical_type_submatcher.rb +17 -0
  162. data/spec/support/test_application.rb +120 -0
  163. data/yard.watchr +5 -0
  164. metadata +281 -0
@@ -0,0 +1,59 @@
1
+ require 'spec_helper'
2
+
3
+ describe Shoulda::Matchers::ActiveModel::NumericalityMatchers::EvenNumberMatcher do
4
+ subject { described_class.new(:attr) }
5
+
6
+ it_behaves_like 'a numerical submatcher'
7
+ it_behaves_like 'a numerical type submatcher'
8
+
9
+ it 'allows even number' do
10
+ expect(subject.allowed_type).to eq 'even numbers'
11
+ end
12
+
13
+ describe '#diff_to_compare' do
14
+ it { expect(subject.diff_to_compare).to eq 2 }
15
+ end
16
+
17
+ context 'when the model has an even validation' do
18
+ it 'matches' do
19
+ match = subject
20
+ expect(validating_even_number).to match
21
+ end
22
+ end
23
+
24
+ context 'when the model does not have an even validation' do
25
+ it 'does not match' do
26
+ match = subject
27
+ expect(not_validating_even_number).not_to match
28
+ end
29
+
30
+ it 'fails with the ActiveRecord :even message' do
31
+ match = subject
32
+ expect {
33
+ expect(not_validating_even_number).to match
34
+ }.to fail_with_message_including('Expected errors to include "must be even"')
35
+ end
36
+ end
37
+
38
+ context 'with custom validation message' do
39
+ it 'only accepts even number values for that attribute with that message' do
40
+ expect(validating_even_number(message: 'custom')).to subject.with_message(/custom/)
41
+ end
42
+
43
+ it 'fails even number values for that attribute with another message' do
44
+ expect(validating_even_number(message: 'custom')).not_to subject.with_message(/wrong/)
45
+ end
46
+ end
47
+
48
+
49
+ def validating_even_number(options = {})
50
+ define_model :example, attr: :string do
51
+ validates_numericality_of :attr, { even: true }.merge(options)
52
+ end.new
53
+ end
54
+
55
+ def not_validating_even_number
56
+ define_model(:example, attr: :string).new
57
+ end
58
+
59
+ end
@@ -0,0 +1,59 @@
1
+ require 'spec_helper'
2
+
3
+ describe Shoulda::Matchers::ActiveModel::NumericalityMatchers::OddNumberMatcher do
4
+ subject { described_class.new(:attr) }
5
+
6
+ it_behaves_like 'a numerical submatcher'
7
+ it_behaves_like 'a numerical type submatcher'
8
+
9
+ it 'allows odd number' do
10
+ expect(subject.allowed_type).to eq 'odd numbers'
11
+ end
12
+
13
+ describe '#diff_to_compare' do
14
+ it { expect(subject.diff_to_compare).to eq 2 }
15
+ end
16
+
17
+ context 'when the model has an odd validation' do
18
+ it 'matches' do
19
+ match = subject
20
+ expect(validating_odd_number).to match
21
+ end
22
+ end
23
+
24
+ context 'when the model does not have an odd validation' do
25
+ it 'does not match' do
26
+ match = subject
27
+ expect(not_validating_odd_number).not_to match
28
+ end
29
+
30
+ it 'fails with the ActiveRecord :odd message' do
31
+ match = subject
32
+ expect {
33
+ expect(not_validating_odd_number).to match
34
+ }.to fail_with_message_including('Expected errors to include "must be odd"')
35
+ end
36
+ end
37
+
38
+ context 'with custom validation message' do
39
+ it 'only accepts odd number values for that attribute with that message' do
40
+ expect(validating_odd_number(message: 'custom')).to subject.with_message(/custom/)
41
+ end
42
+
43
+ it 'fails odd number values for that attribute with another message' do
44
+ expect(validating_odd_number(message: 'custom')).not_to subject.with_message(/wrong/)
45
+ end
46
+ end
47
+
48
+
49
+ def validating_odd_number(options = {})
50
+ define_model :example, attr: :string do
51
+ validates_numericality_of :attr, { odd: true }.merge(options)
52
+ end.new
53
+ end
54
+
55
+ def not_validating_odd_number
56
+ define_model(:example, attr: :string).new
57
+ end
58
+
59
+ end
@@ -0,0 +1,57 @@
1
+ require 'spec_helper'
2
+
3
+ describe Shoulda::Matchers::ActiveModel::NumericalityMatchers::OnlyIntegerMatcher do
4
+ subject { described_class.new(:attr) }
5
+
6
+ it_behaves_like 'a numerical submatcher'
7
+ it_behaves_like 'a numerical type submatcher'
8
+
9
+ it 'allows integer types' do
10
+ expect(subject.allowed_type).to eq 'integers'
11
+ end
12
+
13
+ describe '#diff_to_compare' do
14
+ it { expect(subject.diff_to_compare).to eq 1 }
15
+ end
16
+
17
+ context 'given an attribute that only allows integer values' do
18
+ it 'matches' do
19
+ match = subject
20
+ expect(validating_only_integer).to match
21
+ end
22
+ end
23
+
24
+ context 'given an attribute that only allows integer values with a custom validation message' do
25
+ it 'only accepts integer values for that attribute with that message' do
26
+ expect(validating_only_integer(message: 'custom')).to subject.with_message(/custom/)
27
+ end
28
+
29
+ it 'rejects integer values for that attribute with another message' do
30
+ expect(validating_only_integer(message: 'custom')).not_to subject.with_message(/wrong/)
31
+ end
32
+ end
33
+
34
+ context 'when the model does not have an only_integer validation' do
35
+ it 'does not match' do
36
+ match = subject
37
+ expect(not_validating_only_integer).not_to match
38
+ end
39
+
40
+ it 'fails with the ActiveRecord :not_an_integer message' do
41
+ match = subject
42
+ expect {
43
+ expect(not_validating_only_integer).to match
44
+ }.to fail_with_message_including('Expected errors to include "must be an integer"')
45
+ end
46
+ end
47
+
48
+ def validating_only_integer(options = {})
49
+ define_model :example, attr: :string do
50
+ validates_numericality_of :attr, { only_integer: true }.merge(options)
51
+ end.new
52
+ end
53
+
54
+ def not_validating_only_integer
55
+ define_model(:example, attr: :string).new
56
+ end
57
+ end
@@ -0,0 +1,139 @@
1
+ require 'spec_helper'
2
+
3
+ describe Shoulda::Matchers::ActiveModel::ValidateAbsenceOfMatcher do
4
+ if active_model_4_0?
5
+ context 'a model with an absence validation' do
6
+ it 'accepts' do
7
+ expect(validating_absence_of(:attr)).to validate_absence_of(:attr)
8
+ end
9
+
10
+ it 'does not override the default message with a present' do
11
+ expect(validating_absence_of(:attr)).to validate_absence_of(:attr).with_message(nil)
12
+ end
13
+ end
14
+
15
+ context 'a model without an absence validation' do
16
+ it 'rejects' do
17
+ model = define_model(:example, attr: :string).new
18
+ expect(model).not_to validate_absence_of(:attr)
19
+ end
20
+ end
21
+
22
+ context 'an ActiveModel class with an absence validation' do
23
+ it 'accepts' do
24
+ expect(active_model_validating_absence_of(:attr)).to validate_absence_of(:attr)
25
+ end
26
+
27
+ it 'does not override the default message with a blank' do
28
+ expect(active_model_validating_absence_of(:attr)).to validate_absence_of(:attr).with_message(nil)
29
+ end
30
+ end
31
+
32
+ context 'an ActiveModel class without an absence validation' do
33
+ it 'rejects' do
34
+ expect(active_model_with(:attr)).not_to validate_absence_of(:attr)
35
+ end
36
+
37
+ it 'provides the correct failure message' do
38
+ message = %{Expected errors to include "must be blank" when attr is set to "an arbitrary value", got no errors}
39
+
40
+ expect { expect(active_model_with(:attr)).to validate_absence_of(:attr) }.to fail_with_message(message)
41
+ end
42
+ end
43
+
44
+ context 'a has_many association with an absence validation' do
45
+ it 'requires the attribute to not be set' do
46
+ expect(having_many(:children, absence: true)).to validate_absence_of(:children)
47
+ end
48
+ end
49
+
50
+ context 'a has_many association without an absence validation' do
51
+ it 'does not require the attribute to not be set' do
52
+ expect(having_many(:children, absence: false)).
53
+ not_to validate_absence_of(:children)
54
+ end
55
+ end
56
+
57
+ context 'an absent has_and_belongs_to_many association' do
58
+ it 'accepts' do
59
+ model = having_and_belonging_to_many(:children, absence: true)
60
+ expect(model).to validate_absence_of(:children)
61
+ end
62
+ end
63
+
64
+ context 'a non-absent has_and_belongs_to_many association' do
65
+ it 'rejects' do
66
+ model = having_and_belonging_to_many(:children, absence: false)
67
+ expect(model).not_to validate_absence_of(:children)
68
+ end
69
+ end
70
+
71
+ context "an i18n translation containing %{attribute} and %{model}" do
72
+ after { I18n.backend.reload! }
73
+
74
+ it "does not raise an exception" do
75
+ stub_translation("activerecord.errors.messages.present",
76
+ "%{attribute} must be blank in a %{model}")
77
+
78
+ expect {
79
+ expect(validating_absence_of(:attr)).to validate_absence_of(:attr)
80
+ }.to_not raise_exception
81
+ end
82
+ end
83
+
84
+ context "an attribute with a context-dependent validation" do
85
+ context "without the validation context" do
86
+ it "does not match" do
87
+ expect(validating_absence_of(:attr, on: :customisable)).not_to validate_absence_of(:attr)
88
+ end
89
+ end
90
+
91
+ context "with the validation context" do
92
+ it "matches" do
93
+ expect(validating_absence_of(:attr, on: :customisable)).to validate_absence_of(:attr).on(:customisable)
94
+ end
95
+ end
96
+ end
97
+
98
+ def validating_absence_of(attr, options = {})
99
+ define_model :example, attr => :string do
100
+ validates_absence_of attr, options
101
+ end.new
102
+ end
103
+
104
+ def active_model_with(attr, &block)
105
+ define_active_model_class('Example', accessors: [attr], &block).new
106
+ end
107
+
108
+ def active_model_validating_absence_of(attr)
109
+ active_model_with(attr) do
110
+ validates_absence_of attr
111
+ end
112
+ end
113
+
114
+ def having_many(plural_name, options = {})
115
+ define_model plural_name.to_s.singularize
116
+ define_model :parent do
117
+ has_many plural_name
118
+ if options[:absence]
119
+ validates_absence_of plural_name
120
+ end
121
+ end.new
122
+ end
123
+
124
+ def having_and_belonging_to_many(plural_name, options = {})
125
+ create_table 'children_parents', id: false do |t|
126
+ t.integer "#{plural_name.to_s.singularize}_id"
127
+ t.integer :parent_id
128
+ end
129
+
130
+ define_model plural_name.to_s.singularize
131
+ define_model :parent do
132
+ has_and_belongs_to_many plural_name
133
+ if options[:absence]
134
+ validates_absence_of plural_name
135
+ end
136
+ end.new
137
+ end
138
+ end
139
+ end
@@ -0,0 +1,41 @@
1
+ require 'spec_helper'
2
+
3
+ describe Shoulda::Matchers::ActiveModel::ValidateAcceptanceOfMatcher do
4
+ context 'a model with an acceptance validation' do
5
+ it 'accepts when the attributes match' do
6
+ expect(validating_acceptance).to matcher
7
+ end
8
+
9
+ it 'does not overwrite the default message with nil' do
10
+ expect(validating_acceptance).to matcher.with_message(nil)
11
+ end
12
+ end
13
+
14
+ context 'a model without an acceptance validation' do
15
+ it 'rejects' do
16
+ expect(define_model(:example, attr: :string).new).not_to matcher
17
+ end
18
+ end
19
+
20
+ context 'an attribute which must be accepted with a custom message' do
21
+ it 'accepts when the message matches' do
22
+ expect(validating_acceptance(message: 'custom')).
23
+ to matcher.with_message(/custom/)
24
+ end
25
+
26
+ it 'rejects when the message does not match' do
27
+ expect(validating_acceptance(message: 'custom')).
28
+ not_to matcher.with_message(/wrong/)
29
+ end
30
+ end
31
+
32
+ def matcher
33
+ validate_acceptance_of(:attr)
34
+ end
35
+
36
+ def validating_acceptance(options = {})
37
+ define_model(:example, attr: :string) do
38
+ validates_acceptance_of :attr, options
39
+ end.new
40
+ end
41
+ end
@@ -0,0 +1,47 @@
1
+ require 'spec_helper'
2
+
3
+ describe Shoulda::Matchers::ActiveModel::ValidateConfirmationOfMatcher do
4
+ context '#description' do
5
+ it 'states that the confirmation must match its base attribute' do
6
+ expect(matcher.description).to eq 'require attr_confirmation to match attr'
7
+ end
8
+ end
9
+
10
+ context 'a model with a confirmation validation' do
11
+ it 'accepts' do
12
+ expect(validating_confirmation).to matcher
13
+ end
14
+
15
+ it 'does not override the default message with a blank' do
16
+ expect(validating_confirmation).to matcher.with_message(nil)
17
+ end
18
+ end
19
+
20
+ context 'a model without a confirmation validation' do
21
+ it 'rejects' do
22
+ expect(define_model(:example, attr: :string).new).not_to matcher
23
+ end
24
+ end
25
+
26
+ context 'a confirmation validation with a custom message' do
27
+ it 'accepts when the message matches' do
28
+ expect(validating_confirmation(message: 'custom')).
29
+ to matcher.with_message(/custom/)
30
+ end
31
+
32
+ it 'rejects when the messages do not match' do
33
+ expect(validating_confirmation(message: 'custom')).
34
+ not_to matcher.with_message(/wrong/)
35
+ end
36
+ end
37
+
38
+ def matcher
39
+ validate_confirmation_of(:attr)
40
+ end
41
+
42
+ def validating_confirmation(options = {})
43
+ define_model(:example, attr: :string) do
44
+ validates_confirmation_of :attr, options
45
+ end.new
46
+ end
47
+ end
@@ -0,0 +1,331 @@
1
+ require 'spec_helper'
2
+
3
+ describe Shoulda::Matchers::ActiveModel::ValidateNumericalityOfMatcher do
4
+
5
+ context 'with a model with a numericality validation' do
6
+ it 'accepts' do
7
+ expect(validating_numericality).to matcher
8
+ end
9
+
10
+ it 'does not override the default message with a blank' do
11
+ expect(validating_numericality).to matcher.with_message(nil)
12
+ end
13
+ end
14
+
15
+ context 'with a model without a numericality validation' do
16
+ it 'rejects' do
17
+ expect(not_validating_numericality).not_to matcher
18
+ end
19
+
20
+ it 'rejects with the ActiveRecord :not_a_number message' do
21
+ the_matcher = matcher
22
+
23
+ the_matcher.matches?(define_model(:example, attr: :string).new)
24
+
25
+ expect(the_matcher.failure_message_when_negated)
26
+ .to include 'Did not expect errors to include "is not a number"'
27
+ end
28
+
29
+ it 'rejects with the ActiveRecord :not_an_integer message' do
30
+ the_matcher = matcher.only_integer
31
+ expect do
32
+ expect(not_validating_numericality).to the_matcher
33
+ end.to fail_with_message_including(
34
+ 'Expected errors to include "must be an integer"'
35
+ )
36
+ end
37
+
38
+ it 'rejects with the ActiveRecord :odd message' do
39
+ the_matcher = matcher.odd
40
+ expect do
41
+ expect(not_validating_numericality).to the_matcher
42
+ end.to fail_with_message_including(
43
+ 'Expected errors to include "must be odd"'
44
+ )
45
+ end
46
+
47
+ it 'rejects with the ActiveRecord :even message' do
48
+ the_matcher = matcher.even
49
+ expect do
50
+ expect(not_validating_numericality).to the_matcher
51
+ end.to fail_with_message_including(
52
+ 'Expected errors to include "must be even"'
53
+ )
54
+ end
55
+ end
56
+
57
+ context 'with the allow_nil option' do
58
+ it 'allows nil values for that attribute' do
59
+ expect(validating_numericality(allow_nil: true)).to matcher.allow_nil
60
+ end
61
+
62
+ it 'rejects when the model does not allow nil' do
63
+ the_matcher = matcher.allow_nil
64
+ expect {
65
+ expect(validating_numericality).to the_matcher
66
+ }.to fail_with_message_including('Did not expect errors to include "is not a number"')
67
+ end
68
+ end
69
+
70
+ context 'with the only_integer option' do
71
+ it 'allows integer values for that attribute' do
72
+ expect(validating_numericality(only_integer: true)).to matcher.only_integer
73
+ end
74
+
75
+ it 'rejects when the model does not enforce integer values' do
76
+ expect(validating_numericality).not_to matcher.only_integer
77
+ end
78
+
79
+ it 'rejects with the ActiveRecord :not_an_integer message' do
80
+ the_matcher = matcher.only_integer
81
+ expect do
82
+ expect(validating_numericality).to the_matcher
83
+ end.to fail_with_message_including(
84
+ 'Expected errors to include "must be an integer"'
85
+ )
86
+ end
87
+ end
88
+
89
+ context 'with the odd option' do
90
+ it 'allows odd number values for that attribute' do
91
+ expect(validating_numericality(odd: true)).to matcher.odd
92
+ end
93
+
94
+ it 'rejects when the model does not enforce odd number values' do
95
+ expect(validating_numericality).not_to matcher.odd
96
+ end
97
+
98
+ it 'rejects with the ActiveRecord :odd message' do
99
+ the_matcher = matcher.odd
100
+ expect do
101
+ expect(validating_numericality).to the_matcher
102
+ end.to fail_with_message_including(
103
+ 'Expected errors to include "must be odd"'
104
+ )
105
+ end
106
+ end
107
+
108
+ context 'with the even option' do
109
+ it 'allows even number values for that attribute' do
110
+ expect(validating_numericality(even: true)).to matcher.even
111
+ end
112
+
113
+ it 'rejects when the model does not enforce even number values' do
114
+ expect(validating_numericality).not_to matcher.even
115
+ end
116
+
117
+ it 'rejects with the ActiveRecord :even message' do
118
+ the_matcher = matcher.even
119
+ expect do
120
+ expect(validating_numericality).to the_matcher
121
+ end.to fail_with_message_including(
122
+ 'Expected errors to include "must be even"'
123
+ )
124
+ end
125
+ end
126
+
127
+ context 'with multiple options together' do
128
+ context 'the success cases' do
129
+ it do
130
+ expect(validating_numericality(only_integer: true, greater_than: 18))
131
+ .to matcher.only_integer.is_greater_than(18)
132
+ end
133
+
134
+ it do
135
+ expect(validating_numericality(even: true, greater_than: 18))
136
+ .to matcher.even.is_greater_than(18)
137
+ end
138
+ it do
139
+ expect(validating_numericality(odd: true, less_than_or_equal_to: 99))
140
+ .to matcher.odd.is_less_than_or_equal_to(99)
141
+ end
142
+
143
+ it do
144
+ expect(validating_numericality(
145
+ only_integer: true,
146
+ greater_than: 18,
147
+ less_than: 99)
148
+ ).to matcher.only_integer.is_greater_than(18).is_less_than(99)
149
+ end
150
+ end
151
+
152
+ context 'the failure cases with different validators' do
153
+ it do
154
+ expect(validating_numericality(even: true, greater_than: 18))
155
+ .not_to matcher.only_integer.is_greater_than(18)
156
+ end
157
+
158
+ it do
159
+ expect(validating_numericality(greater_than: 18))
160
+ .not_to matcher.only_integer.is_greater_than(18)
161
+ end
162
+
163
+ it do
164
+ expect(
165
+ validating_numericality(even: true, greater_than_or_equal_to: 18)
166
+ ).not_to matcher.even.is_greater_than(18)
167
+ end
168
+
169
+ it do
170
+ expect(validating_numericality(odd: true, greater_than: 18))
171
+ .not_to matcher.even.is_greater_than(18)
172
+ end
173
+
174
+ it do
175
+ expect(validating_numericality(
176
+ odd: true,
177
+ greater_than_or_equal_to: 99
178
+ )
179
+ ).not_to matcher.odd.is_less_than_or_equal_to(99)
180
+ end
181
+
182
+ it do
183
+ expect(validating_numericality(
184
+ only_integer: true,
185
+ greater_than_or_equal_to: 18,
186
+ less_than: 99
187
+ )
188
+ ).not_to matcher.only_integer.is_greater_than(18).is_less_than(99)
189
+ end
190
+ end
191
+
192
+ context 'the failure cases with wrong values' do
193
+ it do
194
+ expect(validating_numericality(only_integer: true, greater_than: 19))
195
+ .not_to matcher.only_integer.is_greater_than(18)
196
+ end
197
+
198
+ it do
199
+ expect(validating_numericality(only_integer: true, greater_than: 17))
200
+ .not_to matcher.only_integer.is_greater_than(18)
201
+ end
202
+
203
+ it do
204
+ expect(validating_numericality(even: true, greater_than: 20))
205
+ .not_to matcher.even.is_greater_than(18)
206
+ end
207
+
208
+ it do
209
+ expect(validating_numericality(even: true, greater_than: 16))
210
+ .not_to matcher.even.is_greater_than(18)
211
+ end
212
+
213
+ it do
214
+ expect(validating_numericality(odd: true, less_than_or_equal_to: 101))
215
+ .not_to matcher.odd.is_less_than_or_equal_to(99)
216
+ end
217
+
218
+ it do
219
+ expect(validating_numericality(odd: true, less_than_or_equal_to: 97))
220
+ .not_to matcher.odd.is_less_than_or_equal_to(99)
221
+ end
222
+
223
+ it do
224
+ expect(validating_numericality(only_integer: true,
225
+ greater_than: 19,
226
+ less_than: 99))
227
+ .not_to matcher.only_integer.is_greater_than(18).is_less_than(99)
228
+ end
229
+
230
+ it do
231
+ expect(validating_numericality(only_integer: true,
232
+ greater_than: 18,
233
+ less_than: 100))
234
+ .not_to matcher.only_integer.is_greater_than(18).is_less_than(99)
235
+ end
236
+ end
237
+ end
238
+
239
+ context 'with a custom validation message' do
240
+ it 'accepts when the messages match' do
241
+ expect(validating_numericality(message: 'custom')).
242
+ to matcher.with_message(/custom/)
243
+ end
244
+
245
+ it 'rejects when the messages do not match' do
246
+ expect(validating_numericality(message: 'custom')).
247
+ not_to matcher.with_message(/wrong/)
248
+ end
249
+ end
250
+
251
+ context 'when the subject is stubbed' do
252
+ it 'retains stubs on submatchers' do
253
+ subject = define_model :example, attr: :string do
254
+ validates_numericality_of :attr, odd: true
255
+ before_validation :set_attr!
256
+ def set_attr!; self.attr = 5 end
257
+ end.new
258
+
259
+ subject.stubs(:set_attr!)
260
+ expect(subject).to matcher.odd
261
+ end
262
+ end
263
+
264
+ describe '#description' do
265
+ context 'without submatchers' do
266
+ it { expect(matcher.description).to eq 'only allow numbers for attr' }
267
+ end
268
+
269
+ context 'with only integer option' do
270
+ it do
271
+ expect(matcher.only_integer.description)
272
+ .to eq 'only allow integers for attr'
273
+ end
274
+ end
275
+
276
+ [:odd, :even].each do |type|
277
+ context "with #{type} option" do
278
+ it do
279
+ expect(matcher.__send__(type).description)
280
+ .to eq "only allow #{type} numbers for attr"
281
+ end
282
+ end
283
+ end
284
+
285
+ [:is_greater_than,
286
+ :is_greater_than_or_equal_to,
287
+ :is_less_than,
288
+ :is_less_than_or_equal_to,
289
+ :is_equal_to ].each do |comparison|
290
+ context "with #{comparison} option" do
291
+ it do
292
+ expect(matcher.__send__(comparison, 18).description)
293
+ .to eq(
294
+ 'only allow numbers for attr which are ' +
295
+ "#{comparison.to_s.sub('is_', '').gsub('_', ' ')} 18"
296
+ )
297
+ end
298
+ end
299
+ end
300
+
301
+ context 'with odd, is_greater_than_or_equal_to option' do
302
+ it do
303
+ expect(matcher.odd.is_greater_than_or_equal_to(18).description)
304
+ .to eq(
305
+ 'only allow odd numbers for attr ' +
306
+ 'which are greater than or equal to 18'
307
+ )
308
+ end
309
+ end
310
+
311
+ context 'with only integer, is_greater_than and less_than_or_equal_to option' do
312
+ it { expect(matcher.only_integer.is_greater_than(18).is_less_than_or_equal_to(100).description).
313
+ to eq "only allow integers for attr which are greater than 18 and less than or equal to 100" }
314
+ end
315
+ end
316
+
317
+
318
+ def validating_numericality(options = {})
319
+ define_model :example, attr: :string do
320
+ validates_numericality_of :attr, options
321
+ end.new
322
+ end
323
+
324
+ def not_validating_numericality
325
+ define_model(:example, attr: :string).new
326
+ end
327
+
328
+ def matcher
329
+ validate_numericality_of(:attr)
330
+ end
331
+ end