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,247 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Shoulda::Matchers::ActiveRecord::AssociationMatchers::ModelReflection do
|
4
|
+
it 'delegates other methods to the given Reflection object' do
|
5
|
+
define_model(:country)
|
6
|
+
person_model = define_model(:person, country_id: :integer) do
|
7
|
+
belongs_to :country
|
8
|
+
end
|
9
|
+
delegate_reflection = person_model.reflect_on_association(:country)
|
10
|
+
delegate_reflection.stubs(foo: 'bar')
|
11
|
+
reflection = described_class.new(delegate_reflection)
|
12
|
+
|
13
|
+
expect(reflection.foo).to eq 'bar'
|
14
|
+
end
|
15
|
+
|
16
|
+
describe '#associated_class' do
|
17
|
+
it 'returns the model that the association refers to' do
|
18
|
+
define_model(:country)
|
19
|
+
person_model = define_model(:person, country_id: :integer) do
|
20
|
+
belongs_to :country
|
21
|
+
end
|
22
|
+
delegate_reflection = person_model.reflect_on_association(:country)
|
23
|
+
reflection = described_class.new(delegate_reflection)
|
24
|
+
|
25
|
+
expect(reflection.associated_class).to be Country
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
describe '#through?' do
|
30
|
+
it 'returns true if the reflection is for a has_many :through association' do
|
31
|
+
define_model(:city, person_id: :integer)
|
32
|
+
define_model(:person, country_id: :integer) do
|
33
|
+
has_many :cities
|
34
|
+
end
|
35
|
+
country_model = define_model(:country) do
|
36
|
+
has_many :people
|
37
|
+
has_many :cities, through: :people
|
38
|
+
end
|
39
|
+
delegate_reflection = country_model.reflect_on_association(:cities)
|
40
|
+
reflection = described_class.new(delegate_reflection)
|
41
|
+
|
42
|
+
expect(reflection).to be_through
|
43
|
+
end
|
44
|
+
|
45
|
+
it 'returns false if not' do
|
46
|
+
define_model(:person, country_id: :integer)
|
47
|
+
country_model = define_model(:country) do
|
48
|
+
has_many :people
|
49
|
+
end
|
50
|
+
delegate_reflection = country_model.reflect_on_association(:people)
|
51
|
+
reflection = described_class.new(delegate_reflection)
|
52
|
+
|
53
|
+
expect(reflection).not_to be_through
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
describe '#join_table' do
|
58
|
+
context 'when the association was defined with a :join_table option' do
|
59
|
+
it 'returns the value of the option' do
|
60
|
+
define_model(:person, country_id: :integer)
|
61
|
+
country_model = define_model(:country) do
|
62
|
+
has_and_belongs_to_many :people, join_table: 'foos'
|
63
|
+
end
|
64
|
+
delegate_reflection = country_model.reflect_on_association(:people)
|
65
|
+
reflection = described_class.new(delegate_reflection)
|
66
|
+
|
67
|
+
expect(reflection.join_table).to eq 'foos'
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
context 'when the association was not defined with :join_table' do
|
72
|
+
it 'returns the default join_table that ActiveRecord generates' do
|
73
|
+
define_model(:person, country_id: :integer)
|
74
|
+
country_model = define_model(:country) do
|
75
|
+
has_and_belongs_to_many :people
|
76
|
+
end
|
77
|
+
delegate_reflection = country_model.reflect_on_association(:people)
|
78
|
+
reflection = described_class.new(delegate_reflection)
|
79
|
+
|
80
|
+
expect(reflection.join_table).to eq 'countries_people'
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
describe '#association_relation' do
|
86
|
+
if rails_4_x?
|
87
|
+
context 'when the reflection object has a #scope method' do
|
88
|
+
context 'when the scope is a block' do
|
89
|
+
it 'executes the block in the context of an empty scope' do
|
90
|
+
define_model(:country, mood: :string)
|
91
|
+
person_model = define_model(:person, country_id: :integer) do
|
92
|
+
belongs_to :country, -> { where(mood: 'nice') }
|
93
|
+
end
|
94
|
+
delegate_reflection = person_model.reflect_on_association(:country)
|
95
|
+
reflection = described_class.new(delegate_reflection)
|
96
|
+
|
97
|
+
actual_sql = reflection.association_relation.to_sql
|
98
|
+
expected_sql = Country.where(mood: 'nice').to_sql
|
99
|
+
expect(actual_sql).to eq expected_sql
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
context 'when the scope is nil' do
|
104
|
+
it 'returns an empty scope' do
|
105
|
+
define_model(:country)
|
106
|
+
person_model = define_model(:person, country_id: :integer) do
|
107
|
+
belongs_to :country
|
108
|
+
end
|
109
|
+
delegate_reflection = person_model.reflect_on_association(:country)
|
110
|
+
reflection = described_class.new(delegate_reflection)
|
111
|
+
|
112
|
+
actual_sql = reflection.association_relation.to_sql
|
113
|
+
expected_sql = Country.all.to_sql
|
114
|
+
expect(actual_sql).to eq expected_sql
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
if rails_3_x?
|
121
|
+
context 'when the reflection object does not have a #scope method' do
|
122
|
+
context 'when the reflection options contain :conditions' do
|
123
|
+
it 'creates an ActiveRecord::Relation from the conditions' do
|
124
|
+
define_model(:country, mood: :string)
|
125
|
+
person_model = define_model(:person, country_id: :integer) do
|
126
|
+
belongs_to :country, conditions: { mood: 'nice' }
|
127
|
+
end
|
128
|
+
delegate_reflection = person_model.reflect_on_association(:country)
|
129
|
+
reflection = described_class.new(delegate_reflection)
|
130
|
+
|
131
|
+
actual_sql = reflection.association_relation.to_sql
|
132
|
+
expected_sql = Country.where(mood: 'nice').to_sql
|
133
|
+
expect(actual_sql).to eq expected_sql
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
context 'when the reflection options contain :order' do
|
138
|
+
it 'creates an ActiveRecord::Relation from the order' do
|
139
|
+
define_model(:person, country_id: :integer, age: :integer)
|
140
|
+
country_model = define_model(:country) do
|
141
|
+
has_many :people, order: 'age'
|
142
|
+
end
|
143
|
+
delegate_reflection = country_model.reflect_on_association(:people)
|
144
|
+
reflection = described_class.new(delegate_reflection)
|
145
|
+
|
146
|
+
actual_sql = reflection.association_relation.to_sql
|
147
|
+
expected_sql = Person.order('age').to_sql
|
148
|
+
expect(actual_sql).to eq expected_sql
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
context 'when the reflection options contain :include' do
|
153
|
+
it 'creates an ActiveRecord::Relation from the include' do
|
154
|
+
define_model(:city, country_id: :integer)
|
155
|
+
define_model(:country) do
|
156
|
+
has_many :cities
|
157
|
+
end
|
158
|
+
person_model = define_model(:person, country_id: :integer) do
|
159
|
+
belongs_to :country, include: :cities
|
160
|
+
end
|
161
|
+
delegate_reflection = person_model.reflect_on_association(:country)
|
162
|
+
reflection = described_class.new(delegate_reflection)
|
163
|
+
|
164
|
+
actual_includes = reflection.association_relation.includes_values
|
165
|
+
expected_includes = Country.includes(:cities).includes_values
|
166
|
+
expect(actual_includes).to eq expected_includes
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
context 'when the reflection options contain :group' do
|
171
|
+
it 'creates an ActiveRecord::Relation from the group' do
|
172
|
+
country_model = define_model(:country, mood: :string) do
|
173
|
+
has_many :people, group: 'age'
|
174
|
+
end
|
175
|
+
define_model(:person, country_id: :integer, age: :integer)
|
176
|
+
delegate_reflection = country_model.reflect_on_association(:people)
|
177
|
+
reflection = described_class.new(delegate_reflection)
|
178
|
+
|
179
|
+
actual_sql = reflection.association_relation.to_sql
|
180
|
+
expected_sql = Person.group('age').to_sql
|
181
|
+
expect(actual_sql).to eq expected_sql
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
context 'when the reflection options contain :having' do
|
186
|
+
it 'creates an ActiveRecord::Relation from the having' do
|
187
|
+
country_model = define_model(:country) do
|
188
|
+
has_many :people, having: 'country_id > 1'
|
189
|
+
end
|
190
|
+
define_model(:person, country_id: :integer)
|
191
|
+
delegate_reflection = country_model.reflect_on_association(:people)
|
192
|
+
reflection = described_class.new(delegate_reflection)
|
193
|
+
|
194
|
+
actual_sql = reflection.association_relation.to_sql
|
195
|
+
expected_sql = Person.having('country_id > 1').to_sql
|
196
|
+
expect(actual_sql).to eq expected_sql
|
197
|
+
end
|
198
|
+
end
|
199
|
+
|
200
|
+
context 'when the reflection options contain :limit' do
|
201
|
+
it 'creates an ActiveRecord::Relation from the limit' do
|
202
|
+
country_model = define_model(:country) do
|
203
|
+
has_many :people, limit: 10
|
204
|
+
end
|
205
|
+
define_model(:person, country_id: :integer)
|
206
|
+
delegate_reflection = country_model.reflect_on_association(:people)
|
207
|
+
reflection = described_class.new(delegate_reflection)
|
208
|
+
|
209
|
+
actual_sql = reflection.association_relation.to_sql
|
210
|
+
expected_sql = Person.limit(10).to_sql
|
211
|
+
expect(actual_sql).to eq expected_sql
|
212
|
+
end
|
213
|
+
end
|
214
|
+
|
215
|
+
context 'when the reflection options contain :offset' do
|
216
|
+
it 'creates an ActiveRecord::Relation from the offset' do
|
217
|
+
country_model = define_model(:country) do
|
218
|
+
has_many :people, offset: 5
|
219
|
+
end
|
220
|
+
define_model(:person, country_id: :integer)
|
221
|
+
delegate_reflection = country_model.reflect_on_association(:people)
|
222
|
+
reflection = described_class.new(delegate_reflection)
|
223
|
+
|
224
|
+
actual_sql = reflection.association_relation.to_sql
|
225
|
+
expected_sql = Person.offset(5).to_sql
|
226
|
+
expect(actual_sql).to eq expected_sql
|
227
|
+
end
|
228
|
+
end
|
229
|
+
|
230
|
+
context 'when the reflection options contain :select' do
|
231
|
+
it 'creates an ActiveRecord::Relation from the select' do
|
232
|
+
country_model = define_model(:country) do
|
233
|
+
has_many :people, select: 'age'
|
234
|
+
end
|
235
|
+
define_model(:person, country_id: :integer, age: :integer)
|
236
|
+
delegate_reflection = country_model.reflect_on_association(:people)
|
237
|
+
reflection = described_class.new(delegate_reflection)
|
238
|
+
|
239
|
+
actual_sql = reflection.association_relation.to_sql
|
240
|
+
expected_sql = Person.select('age').to_sql
|
241
|
+
expect(actual_sql).to eq expected_sql
|
242
|
+
end
|
243
|
+
end
|
244
|
+
end
|
245
|
+
end
|
246
|
+
end
|
247
|
+
end
|
@@ -0,0 +1,111 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Shoulda::Matchers::ActiveRecord::HaveDbColumnMatcher do
|
4
|
+
it 'accepts an existing database column' do
|
5
|
+
expect(model(nickname: :string)).to have_db_column(:nickname)
|
6
|
+
end
|
7
|
+
|
8
|
+
it 'rejects a nonexistent database column' do
|
9
|
+
expect(define_model(:employee).new).not_to have_db_column(:nickname)
|
10
|
+
end
|
11
|
+
|
12
|
+
context '#of_type' do
|
13
|
+
it 'accepts a column of correct type' do
|
14
|
+
expect(model(nickname: :string)).
|
15
|
+
to have_db_column(:nickname).of_type(:string)
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'rejects a nonexistent database column' do
|
19
|
+
expect(define_model(:superhero).new).
|
20
|
+
not_to have_db_column(:nickname).of_type(:string)
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'rejects a column of wrong type' do
|
24
|
+
expect(model(nickname: :integer)).
|
25
|
+
not_to have_db_column(:nickname).of_type(:string)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
context 'with precision option' do
|
30
|
+
it 'accepts a column of correct precision' do
|
31
|
+
expect(with_table(:salary, :decimal, precision: 5)).
|
32
|
+
to have_db_column(:salary).with_options(precision: 5)
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'rejects a column of wrong precision' do
|
36
|
+
expect(with_table(:salary, :decimal, precision: 6)).
|
37
|
+
not_to have_db_column(:salary).with_options(precision: 5)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
context 'with limit option' do
|
42
|
+
it 'accepts a column of correct limit' do
|
43
|
+
expect(with_table(:email, :string, limit: 255)).
|
44
|
+
to have_db_column(:email).with_options(limit: 255)
|
45
|
+
end
|
46
|
+
|
47
|
+
it 'rejects a column of wrong limit' do
|
48
|
+
expect(with_table(:email, :string, limit: 100)).
|
49
|
+
not_to have_db_column(:email).with_options(limit: 255)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
context 'with default option' do
|
54
|
+
it 'accepts a column with correct default' do
|
55
|
+
expect(with_table(:admin, :boolean, default: false)).
|
56
|
+
to have_db_column(:admin).with_options(default: false)
|
57
|
+
end
|
58
|
+
|
59
|
+
it 'rejects a column with wrong default' do
|
60
|
+
expect(with_table(:admin, :boolean, default: true)).
|
61
|
+
not_to have_db_column(:admin).with_options(default: false)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
context 'with null option' do
|
66
|
+
it 'accepts a column of correct null' do
|
67
|
+
expect(with_table(:admin, :boolean, null: false)).
|
68
|
+
to have_db_column(:admin).with_options(null: false)
|
69
|
+
end
|
70
|
+
|
71
|
+
it 'rejects a column of wrong null' do
|
72
|
+
expect(with_table(:admin, :boolean, null: true)).
|
73
|
+
not_to have_db_column(:admin).with_options(null: false)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
context 'with scale option' do
|
78
|
+
it 'accepts a column of correct scale' do
|
79
|
+
expect(with_table(:salary, :decimal, precision: 10, scale: 2)).
|
80
|
+
to have_db_column(:salary).with_options(scale: 2)
|
81
|
+
end
|
82
|
+
|
83
|
+
it 'rejects a column of wrong scale' do
|
84
|
+
expect(with_table(:salary, :decimal, precision: 10, scale: 4)).
|
85
|
+
not_to have_db_column(:salary).with_options(scale: 2)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
context 'with primary option' do
|
90
|
+
it 'accepts a column that is primary' do
|
91
|
+
expect(with_table(:custom_id, :integer, primary: true)).
|
92
|
+
to have_db_column(:id).with_options(primary: true)
|
93
|
+
end
|
94
|
+
|
95
|
+
it 'rejects a column that is not primary' do
|
96
|
+
expect(with_table(:whatever, :integer, primary: false)).
|
97
|
+
not_to have_db_column(:whatever).with_options(primary: true)
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
def model(options = {})
|
102
|
+
define_model(:employee, options).new
|
103
|
+
end
|
104
|
+
|
105
|
+
def with_table(column_name, column_type, options)
|
106
|
+
create_table 'employees' do |table|
|
107
|
+
table.__send__(column_type, column_name, options)
|
108
|
+
end
|
109
|
+
define_model_class('Employee').new
|
110
|
+
end
|
111
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Shoulda::Matchers::ActiveRecord::HaveDbIndexMatcher do
|
4
|
+
context 'have_db_index' do
|
5
|
+
it 'accepts an existing index' do
|
6
|
+
expect(with_index_on(:age)).to have_db_index(:age)
|
7
|
+
end
|
8
|
+
|
9
|
+
it 'rejects a nonexistent index' do
|
10
|
+
expect(define_model(:employee).new).not_to have_db_index(:age)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
context 'have_db_index with unique option' do
|
15
|
+
it 'accepts an index of correct unique' do
|
16
|
+
expect(with_index_on(:ssn, unique: true)).
|
17
|
+
to have_db_index(:ssn).unique(true)
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'rejects an index of wrong unique' do
|
21
|
+
expect(with_index_on(:ssn, unique: false)).
|
22
|
+
not_to have_db_index(:ssn).unique(true)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
context 'have_db_index on multiple columns' do
|
27
|
+
it 'accepts an existing index' do
|
28
|
+
db_connection = create_table 'geocodings' do |table|
|
29
|
+
table.integer :geocodable_id
|
30
|
+
table.string :geocodable_type
|
31
|
+
end
|
32
|
+
db_connection.add_index :geocodings, [:geocodable_type, :geocodable_id]
|
33
|
+
expect(define_model_class('Geocoding').new).
|
34
|
+
to have_db_index([:geocodable_type, :geocodable_id])
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'rejects a nonexistent index' do
|
38
|
+
create_table 'geocodings' do |table|
|
39
|
+
table.integer :geocodable_id
|
40
|
+
table.string :geocodable_type
|
41
|
+
end
|
42
|
+
expect(define_model_class('Geocoding').new).
|
43
|
+
not_to have_db_index([:geocodable_type, :geocodable_id])
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
it 'join columns with and when describing multiple columns' do
|
48
|
+
expect(have_db_index([:user_id, :post_id]).description).to match(/on columns user_id and post_id/)
|
49
|
+
end
|
50
|
+
|
51
|
+
it 'describes a unique index as unique' do
|
52
|
+
expect(have_db_index(:user_id).unique(true).description).to match(/a unique index/)
|
53
|
+
end
|
54
|
+
|
55
|
+
it 'describes a non-unique index as non-unique' do
|
56
|
+
expect(have_db_index(:user_id).unique(false).description).to match(/a non-unique index/)
|
57
|
+
end
|
58
|
+
|
59
|
+
it "does not display an index's uniqueness when it's not important" do
|
60
|
+
expect(have_db_index(:user_id).description).not_to match(/unique/)
|
61
|
+
end
|
62
|
+
|
63
|
+
it 'allows an IndexDefinition to have a truthy value for unique' do
|
64
|
+
index_definition = stub('ActiveRecord::ConnectionAdapters::IndexDefinition',
|
65
|
+
unique: 7, name: :age)
|
66
|
+
matcher = have_db_index(:age).unique(true)
|
67
|
+
matcher.stubs(matched_index: index_definition)
|
68
|
+
|
69
|
+
expect(with_index_on(:age)).to matcher
|
70
|
+
end
|
71
|
+
|
72
|
+
def with_index_on(column_name, index_options = {})
|
73
|
+
create_table 'employees' do |table|
|
74
|
+
table.integer column_name
|
75
|
+
end.add_index(:employees, column_name, index_options)
|
76
|
+
define_model_class('Employee').new
|
77
|
+
end
|
78
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Shoulda::Matchers::ActiveRecord::HaveReadonlyAttributeMatcher do
|
4
|
+
context 'a read-only attribute' do
|
5
|
+
it 'accepts' do
|
6
|
+
expect(with_readonly_attr).to have_readonly_attribute(:attr)
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
context 'an attribute that is not part of the read-only set' do
|
11
|
+
it 'rejects being read-only' do
|
12
|
+
model = define_model :example, attr: :string, other: :string do
|
13
|
+
attr_readonly :attr
|
14
|
+
end.new
|
15
|
+
|
16
|
+
expect(model).not_to have_readonly_attribute(:other)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
context 'an attribute on a class with no readonly attributes' do
|
21
|
+
it 'rejects being read-only' do
|
22
|
+
expect(define_model(:example, attr: :string).new).
|
23
|
+
not_to have_readonly_attribute(:attr)
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'assigns a failure message' do
|
27
|
+
model = define_model(:example, attr: :string).new
|
28
|
+
matcher = have_readonly_attribute(:attr)
|
29
|
+
|
30
|
+
matcher.matches?(model)
|
31
|
+
|
32
|
+
expect(matcher.failure_message).not_to be_nil
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def with_readonly_attr
|
37
|
+
define_model :example, attr: :string do
|
38
|
+
attr_readonly :attr
|
39
|
+
end.new
|
40
|
+
end
|
41
|
+
end
|