ratnikov-shoulda 2.0.6.3 → 2.9.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.
- data/README.rdoc +3 -2
- data/Rakefile +1 -1
- data/lib/shoulda/active_record/assertions.rb +10 -31
- data/lib/shoulda/active_record/helpers.rb +40 -0
- data/lib/shoulda/active_record/macros.rb +171 -325
- data/lib/shoulda/active_record/matchers/allow_mass_assignment_of_matcher.rb +83 -0
- data/lib/shoulda/active_record/matchers/allow_value_matcher.rb +102 -0
- data/lib/shoulda/active_record/matchers/association_matcher.rb +226 -0
- data/lib/shoulda/active_record/matchers/ensure_inclusion_of_matcher.rb +87 -0
- data/lib/shoulda/active_record/matchers/ensure_length_of_matcher.rb +141 -0
- data/lib/shoulda/active_record/matchers/have_db_column_matcher.rb +169 -0
- data/lib/shoulda/active_record/matchers/have_index_matcher.rb +105 -0
- data/lib/shoulda/active_record/matchers/have_named_scope_matcher.rb +125 -0
- data/lib/shoulda/active_record/matchers/have_readonly_attribute_matcher.rb +59 -0
- data/lib/shoulda/active_record/matchers/validate_acceptance_of_matcher.rb +41 -0
- data/lib/shoulda/active_record/matchers/validate_numericality_of_matcher.rb +39 -0
- data/lib/shoulda/active_record/matchers/validate_presence_of_matcher.rb +60 -0
- data/lib/shoulda/active_record/matchers/validate_uniqueness_of_matcher.rb +148 -0
- data/lib/shoulda/active_record/matchers/validation_matcher.rb +56 -0
- data/lib/shoulda/active_record/matchers.rb +42 -0
- data/lib/shoulda/active_record.rb +4 -0
- data/lib/shoulda/assertions.rb +12 -0
- data/lib/shoulda/autoload_macros.rb +46 -0
- data/lib/shoulda/rails.rb +1 -8
- data/lib/shoulda/rspec.rb +5 -0
- data/lib/shoulda/tasks/list_tests.rake +6 -1
- data/lib/shoulda/test_unit.rb +19 -0
- data/lib/shoulda.rb +5 -17
- data/rails/init.rb +1 -1
- data/test/README +2 -2
- data/test/fail_macros.rb +2 -2
- data/test/matchers/allow_mass_assignment_of_matcher_test.rb +68 -0
- data/test/matchers/allow_value_matcher_test.rb +41 -0
- data/test/matchers/association_matcher_test.rb +258 -0
- data/test/matchers/ensure_inclusion_of_matcher_test.rb +80 -0
- data/test/matchers/ensure_length_of_matcher_test.rb +158 -0
- data/test/matchers/have_db_column_matcher_test.rb +169 -0
- data/test/matchers/have_index_matcher_test.rb +74 -0
- data/test/matchers/have_named_scope_matcher_test.rb +65 -0
- data/test/matchers/have_readonly_attributes_matcher_test.rb +29 -0
- data/test/matchers/validate_acceptance_of_matcher_test.rb +44 -0
- data/test/matchers/validate_numericality_of_matcher_test.rb +52 -0
- data/test/matchers/validate_presence_of_matcher_test.rb +86 -0
- data/test/matchers/validate_uniqueness_of_matcher_test.rb +141 -0
- data/test/model_builder.rb +61 -0
- data/test/other/autoload_macro_test.rb +18 -0
- data/test/other/helpers_test.rb +58 -0
- data/test/rails_root/config/database.yml +1 -1
- data/test/rails_root/config/environments/{sqlite3.rb → test.rb} +0 -0
- data/test/rails_root/test/shoulda_macros/custom_macro.rb +6 -0
- data/test/rails_root/vendor/gems/gem_with_macro-0.0.1/shoulda_macros/gem_macro.rb +6 -0
- data/test/rails_root/vendor/plugins/plugin_with_macro/shoulda_macros/plugin_macro.rb +6 -0
- data/test/test_helper.rb +3 -1
- data/test/unit/address_test.rb +1 -1
- data/test/unit/dog_test.rb +1 -1
- data/test/unit/post_test.rb +4 -4
- data/test/unit/product_test.rb +2 -2
- data/test/unit/tag_test.rb +2 -1
- data/test/unit/user_test.rb +8 -7
- metadata +49 -3
|
@@ -1,32 +1,15 @@
|
|
|
1
1
|
module Shoulda # :nodoc:
|
|
2
2
|
module ActiveRecord # :nodoc:
|
|
3
|
-
module MacroHelpers # :nodoc:
|
|
4
|
-
# Helper method that determines the default error message used by Active
|
|
5
|
-
# Record. Works for both existing Rails 2.1 and Rails 2.2 with the newly
|
|
6
|
-
# introduced I18n module used for localization.
|
|
7
|
-
#
|
|
8
|
-
# default_error_message(:blank)
|
|
9
|
-
# default_error_message(:too_short, :count => 5)
|
|
10
|
-
# default_error_message(:too_long, :count => 60)
|
|
11
|
-
def default_error_message(key, values = {})
|
|
12
|
-
if Object.const_defined?(:I18n) # Rails >= 2.2
|
|
13
|
-
I18n.translate("activerecord.errors.messages.#{key}", values)
|
|
14
|
-
else # Rails <= 2.1.x
|
|
15
|
-
::ActiveRecord::Errors.default_error_messages[key] % values[:count]
|
|
16
|
-
end
|
|
17
|
-
end
|
|
18
|
-
end
|
|
19
|
-
|
|
20
3
|
# = Macro test helpers for your active record models
|
|
21
4
|
#
|
|
22
5
|
# These helpers will test most of the validations and associations for your ActiveRecord models.
|
|
23
6
|
#
|
|
24
7
|
# class UserTest < Test::Unit::TestCase
|
|
25
|
-
#
|
|
8
|
+
# should_validate_presence_of :name, :phone_number
|
|
26
9
|
# should_not_allow_values_for :phone_number, "abcd", "1234"
|
|
27
10
|
# should_allow_values_for :phone_number, "(123) 456-7890"
|
|
28
11
|
#
|
|
29
|
-
#
|
|
12
|
+
# should_not_allow_mass_assignment_of :password
|
|
30
13
|
#
|
|
31
14
|
# should_have_one :profile
|
|
32
15
|
# should_have_many :dogs
|
|
@@ -37,7 +20,8 @@ module Shoulda # :nodoc:
|
|
|
37
20
|
# For all of these helpers, the last parameter may be a hash of options.
|
|
38
21
|
#
|
|
39
22
|
module Macros
|
|
40
|
-
include
|
|
23
|
+
include Helpers
|
|
24
|
+
include Matchers
|
|
41
25
|
|
|
42
26
|
# <b>DEPRECATED:</b> Use <tt>fixtures :all</tt> instead
|
|
43
27
|
#
|
|
@@ -58,24 +42,26 @@ module Shoulda # :nodoc:
|
|
|
58
42
|
# Regexp or string. Default = <tt>I18n.translate('activerecord.errors.messages.blank')</tt>
|
|
59
43
|
#
|
|
60
44
|
# Example:
|
|
61
|
-
#
|
|
45
|
+
# should_validate_presence_of :name, :phone_number
|
|
62
46
|
#
|
|
63
|
-
def
|
|
47
|
+
def should_validate_presence_of(*attributes)
|
|
64
48
|
message = get_options!(attributes, :message)
|
|
65
|
-
message ||= default_error_message(:blank)
|
|
66
49
|
klass = model_class
|
|
67
50
|
|
|
68
51
|
attributes.each do |attribute|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
assert_bad_value(klass, attribute, [], message)
|
|
73
|
-
else
|
|
74
|
-
assert_bad_value(klass, attribute, nil, message)
|
|
75
|
-
end
|
|
52
|
+
matcher = validate_presence_of(attribute).with_message(message)
|
|
53
|
+
should matcher.description do
|
|
54
|
+
assert_accepts(matcher, get_instance_of(klass))
|
|
76
55
|
end
|
|
77
56
|
end
|
|
78
57
|
end
|
|
58
|
+
|
|
59
|
+
# Deprecated. See should_validate_presence_of
|
|
60
|
+
def should_require_attributes(*attributes)
|
|
61
|
+
warn "[DEPRECATION] should_require_attributes is deprecated. " <<
|
|
62
|
+
"Use should_validate_presence_of instead."
|
|
63
|
+
should_validate_presence_of(*attributes)
|
|
64
|
+
end
|
|
79
65
|
|
|
80
66
|
# Ensures that the model cannot be saved if one of the attributes listed is not unique.
|
|
81
67
|
# Requires an existing record
|
|
@@ -89,75 +75,75 @@ module Shoulda # :nodoc:
|
|
|
89
75
|
# exact match. Ignored by non-text attributes. Default = <tt>true</tt>
|
|
90
76
|
#
|
|
91
77
|
# Examples:
|
|
92
|
-
#
|
|
93
|
-
#
|
|
94
|
-
#
|
|
95
|
-
#
|
|
96
|
-
#
|
|
78
|
+
# should_validate_uniqueness_of :keyword, :username
|
|
79
|
+
# should_validate_uniqueness_of :name, :message => "O NOES! SOMEONE STOELED YER NAME!"
|
|
80
|
+
# should_validate_uniqueness_of :email, :scoped_to => :name
|
|
81
|
+
# should_validate_uniqueness_of :address, :scoped_to => [:first_name, :last_name]
|
|
82
|
+
# should_validate_uniqueness_of :email, :case_sensitive => false
|
|
97
83
|
#
|
|
98
|
-
def
|
|
84
|
+
def should_validate_uniqueness_of(*attributes)
|
|
99
85
|
message, scope, case_sensitive = get_options!(attributes, :message, :scoped_to, :case_sensitive)
|
|
100
86
|
scope = [*scope].compact
|
|
101
|
-
message ||= default_error_message(:taken)
|
|
102
87
|
case_sensitive = true if case_sensitive.nil?
|
|
103
88
|
|
|
104
89
|
klass = model_class
|
|
90
|
+
|
|
105
91
|
attributes.each do |attribute|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
92
|
+
matcher = validate_uniqueness_of(attribute).
|
|
93
|
+
with_message(message).scoped_to(scope)
|
|
94
|
+
matcher = matcher.case_insensitive unless case_sensitive
|
|
95
|
+
should matcher.description do
|
|
96
|
+
assert_accepts(matcher, get_instance_of(klass))
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
# Deprecated. See should_validate_uniqueness_of
|
|
102
|
+
def should_require_unique_attributes(*attributes)
|
|
103
|
+
warn "[DEPRECATION] should_require_unique_attributes is deprecated. " <<
|
|
104
|
+
"Use should_validate_uniqueness_of instead."
|
|
105
|
+
should_validate_uniqueness_of(*attributes)
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
# Ensures that the attribute can be set on mass update.
|
|
109
|
+
#
|
|
110
|
+
# should_allow_mass_assignment_of :first_name, :last_name
|
|
111
|
+
#
|
|
112
|
+
def should_allow_mass_assignment_of(*attributes)
|
|
113
|
+
get_options!(attributes)
|
|
114
|
+
klass = model_class
|
|
115
|
+
|
|
116
|
+
attributes.each do |attribute|
|
|
117
|
+
matcher = allow_mass_assignment_of(attribute)
|
|
118
|
+
should matcher.description do
|
|
119
|
+
assert_accepts matcher, klass.new
|
|
134
120
|
end
|
|
135
121
|
end
|
|
136
122
|
end
|
|
137
123
|
|
|
138
124
|
# Ensures that the attribute cannot be set on mass update.
|
|
139
125
|
#
|
|
140
|
-
#
|
|
126
|
+
# should_not_allow_mass_assignment_of :password, :admin_flag
|
|
141
127
|
#
|
|
142
|
-
def
|
|
128
|
+
def should_not_allow_mass_assignment_of(*attributes)
|
|
143
129
|
get_options!(attributes)
|
|
144
130
|
klass = model_class
|
|
145
131
|
|
|
146
132
|
attributes.each do |attribute|
|
|
147
|
-
|
|
148
|
-
should "
|
|
149
|
-
|
|
150
|
-
accessible = klass.accessible_attributes || []
|
|
151
|
-
|
|
152
|
-
assert protected.include?(attribute.to_s) ||
|
|
153
|
-
(!accessible.empty? && !accessible.include?(attribute.to_s)),
|
|
154
|
-
(accessible.empty? ?
|
|
155
|
-
"#{klass} is protecting #{protected.to_a.to_sentence}, but not #{attribute}." :
|
|
156
|
-
"#{klass} has made #{attribute} accessible")
|
|
133
|
+
matcher = allow_mass_assignment_of(attribute)
|
|
134
|
+
should "not #{matcher.description}" do
|
|
135
|
+
assert_rejects matcher, klass.new
|
|
157
136
|
end
|
|
158
137
|
end
|
|
159
138
|
end
|
|
160
139
|
|
|
140
|
+
# Deprecated. See should_not_allow_mass_assignment_of
|
|
141
|
+
def should_protect_attributes(*attributes)
|
|
142
|
+
warn "[DEPRECATION] should_protect_attributes is deprecated. " <<
|
|
143
|
+
"Use should_not_allow_mass_assignment_of instead."
|
|
144
|
+
should_not_allow_mass_assignment_of(*attributes)
|
|
145
|
+
end
|
|
146
|
+
|
|
161
147
|
# Ensures that the attribute cannot be changed once the record has been created.
|
|
162
148
|
#
|
|
163
149
|
# should_have_readonly_attributes :password, :admin_flag
|
|
@@ -167,14 +153,9 @@ module Shoulda # :nodoc:
|
|
|
167
153
|
klass = model_class
|
|
168
154
|
|
|
169
155
|
attributes.each do |attribute|
|
|
170
|
-
|
|
171
|
-
should
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
assert readonly.include?(attribute.to_s),
|
|
175
|
-
(readonly.empty? ?
|
|
176
|
-
"#{klass} attribute #{attribute} is not read-only" :
|
|
177
|
-
"#{klass} is making #{readonly.to_a.to_sentence} read-only, but not #{attribute}.")
|
|
156
|
+
matcher = have_readonly_attribute(attribute)
|
|
157
|
+
should matcher.description do
|
|
158
|
+
assert_accepts matcher, klass.new
|
|
178
159
|
end
|
|
179
160
|
end
|
|
180
161
|
end
|
|
@@ -194,11 +175,11 @@ module Shoulda # :nodoc:
|
|
|
194
175
|
#
|
|
195
176
|
def should_not_allow_values_for(attribute, *bad_values)
|
|
196
177
|
message = get_options!(bad_values, :message)
|
|
197
|
-
message ||= default_error_message(:invalid)
|
|
198
178
|
klass = model_class
|
|
199
|
-
bad_values.each do |
|
|
200
|
-
|
|
201
|
-
|
|
179
|
+
bad_values.each do |value|
|
|
180
|
+
matcher = allow_value(value).for(attribute).with_message(message)
|
|
181
|
+
should "not #{matcher.description}" do
|
|
182
|
+
assert_rejects matcher, get_instance_of(klass)
|
|
202
183
|
end
|
|
203
184
|
end
|
|
204
185
|
end
|
|
@@ -215,9 +196,11 @@ module Shoulda # :nodoc:
|
|
|
215
196
|
def should_allow_values_for(attribute, *good_values)
|
|
216
197
|
get_options!(good_values)
|
|
217
198
|
klass = model_class
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
199
|
+
klass = model_class
|
|
200
|
+
good_values.each do |value|
|
|
201
|
+
matcher = allow_value(value).for(attribute)
|
|
202
|
+
should matcher.description do
|
|
203
|
+
assert_accepts matcher, get_instance_of(klass)
|
|
221
204
|
end
|
|
222
205
|
end
|
|
223
206
|
end
|
|
@@ -238,39 +221,19 @@ module Shoulda # :nodoc:
|
|
|
238
221
|
# should_ensure_length_in_range :password, (6..20)
|
|
239
222
|
#
|
|
240
223
|
def should_ensure_length_in_range(attribute, range, opts = {})
|
|
241
|
-
short_message, long_message = get_options!([opts],
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
224
|
+
short_message, long_message = get_options!([opts],
|
|
225
|
+
:short_message,
|
|
226
|
+
:long_message)
|
|
245
227
|
klass = model_class
|
|
246
|
-
min_length = range.first
|
|
247
|
-
max_length = range.last
|
|
248
|
-
same_length = (min_length == max_length)
|
|
249
|
-
|
|
250
|
-
if min_length > 0
|
|
251
|
-
should "not allow #{attribute} to be less than #{min_length} chars long" do
|
|
252
|
-
min_value = "x" * (min_length - 1)
|
|
253
|
-
assert_bad_value(klass, attribute, min_value, short_message)
|
|
254
|
-
end
|
|
255
|
-
end
|
|
256
228
|
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
end
|
|
229
|
+
matcher = ensure_length_of(attribute).
|
|
230
|
+
is_at_least(range.first).
|
|
231
|
+
with_short_message(short_message).
|
|
232
|
+
is_at_most(range.last).
|
|
233
|
+
with_long_message(long_message)
|
|
263
234
|
|
|
264
|
-
should
|
|
265
|
-
|
|
266
|
-
assert_bad_value(klass, attribute, max_value, long_message)
|
|
267
|
-
end
|
|
268
|
-
|
|
269
|
-
unless same_length
|
|
270
|
-
should "allow #{attribute} to be exactly #{max_length} chars long" do
|
|
271
|
-
max_value = "x" * max_length
|
|
272
|
-
assert_good_value(klass, attribute, max_value, long_message)
|
|
273
|
-
end
|
|
235
|
+
should matcher.description do
|
|
236
|
+
assert_accepts matcher, get_instance_of(klass)
|
|
274
237
|
end
|
|
275
238
|
end
|
|
276
239
|
|
|
@@ -289,19 +252,14 @@ module Shoulda # :nodoc:
|
|
|
289
252
|
#
|
|
290
253
|
def should_ensure_length_at_least(attribute, min_length, opts = {})
|
|
291
254
|
short_message = get_options!([opts], :short_message)
|
|
292
|
-
short_message ||= default_error_message(:too_short, :count => min_length)
|
|
293
|
-
|
|
294
255
|
klass = model_class
|
|
295
256
|
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
should "allow #{attribute} to be at least #{min_length} chars long" do
|
|
303
|
-
valid_value = "x" * (min_length)
|
|
304
|
-
assert_good_value(klass, attribute, valid_value, short_message)
|
|
257
|
+
matcher = ensure_length_of(attribute).
|
|
258
|
+
is_at_least(min_length).
|
|
259
|
+
with_short_message(short_message)
|
|
260
|
+
|
|
261
|
+
should matcher.description do
|
|
262
|
+
assert_accepts matcher, get_instance_of(klass)
|
|
305
263
|
end
|
|
306
264
|
end
|
|
307
265
|
|
|
@@ -320,23 +278,13 @@ module Shoulda # :nodoc:
|
|
|
320
278
|
#
|
|
321
279
|
def should_ensure_length_is(attribute, length, opts = {})
|
|
322
280
|
message = get_options!([opts], :message)
|
|
323
|
-
|
|
281
|
+
klass = model_class
|
|
282
|
+
matcher = ensure_length_of(attribute).
|
|
283
|
+
is_equal_to(length).
|
|
284
|
+
with_message(message)
|
|
324
285
|
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
should "not allow #{attribute} to be less than #{length} chars long" do
|
|
328
|
-
min_value = "x" * (length - 1)
|
|
329
|
-
assert_bad_value(klass, attribute, min_value, message)
|
|
330
|
-
end
|
|
331
|
-
|
|
332
|
-
should "not allow #{attribute} to be greater than #{length} chars long" do
|
|
333
|
-
max_value = "x" * (length + 1)
|
|
334
|
-
assert_bad_value(klass, attribute, max_value, message)
|
|
335
|
-
end
|
|
336
|
-
|
|
337
|
-
should "allow #{attribute} to be #{length} chars long" do
|
|
338
|
-
valid_value = "x" * (length)
|
|
339
|
-
assert_good_value(klass, attribute, valid_value, message)
|
|
286
|
+
should matcher.description do
|
|
287
|
+
assert_accepts matcher, get_instance_of(klass)
|
|
340
288
|
end
|
|
341
289
|
end
|
|
342
290
|
|
|
@@ -356,32 +304,15 @@ module Shoulda # :nodoc:
|
|
|
356
304
|
# should_ensure_value_in_range :age, (0..100)
|
|
357
305
|
#
|
|
358
306
|
def should_ensure_value_in_range(attribute, range, opts = {})
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
high_message ||= default_error_message(:inclusion)
|
|
307
|
+
message = get_options!([opts], :message)
|
|
308
|
+
message ||= default_error_message(:inclusion)
|
|
362
309
|
|
|
363
310
|
klass = model_class
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
should
|
|
368
|
-
|
|
369
|
-
assert_bad_value(klass, attribute, v, low_message)
|
|
370
|
-
end
|
|
371
|
-
|
|
372
|
-
should "allow #{attribute} to be #{min}" do
|
|
373
|
-
v = min
|
|
374
|
-
assert_good_value(klass, attribute, v, low_message)
|
|
375
|
-
end
|
|
376
|
-
|
|
377
|
-
should "not allow #{attribute} to be more than #{max}" do
|
|
378
|
-
v = max + 1
|
|
379
|
-
assert_bad_value(klass, attribute, v, high_message)
|
|
380
|
-
end
|
|
381
|
-
|
|
382
|
-
should "allow #{attribute} to be #{max}" do
|
|
383
|
-
v = max
|
|
384
|
-
assert_good_value(klass, attribute, v, high_message)
|
|
311
|
+
matcher = ensure_inclusion_of(attribute).
|
|
312
|
+
in_range(range).
|
|
313
|
+
with_message(message)
|
|
314
|
+
should matcher.description do
|
|
315
|
+
assert_accepts matcher, get_instance_of(klass)
|
|
385
316
|
end
|
|
386
317
|
end
|
|
387
318
|
|
|
@@ -396,20 +327,27 @@ module Shoulda # :nodoc:
|
|
|
396
327
|
# Regexp or string. Default = <tt>I18n.translate('activerecord.errors.messages.not_a_number')</tt>
|
|
397
328
|
#
|
|
398
329
|
# Example:
|
|
399
|
-
#
|
|
330
|
+
# should_validate_numericality_of :age
|
|
400
331
|
#
|
|
401
|
-
def
|
|
332
|
+
def should_validate_numericality_of(*attributes)
|
|
402
333
|
message = get_options!(attributes, :message)
|
|
403
|
-
message ||= default_error_message(:not_a_number)
|
|
404
334
|
klass = model_class
|
|
405
335
|
attributes.each do |attribute|
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
336
|
+
matcher = validate_numericality_of(attribute).
|
|
337
|
+
with_message(message)
|
|
338
|
+
should matcher.description do
|
|
339
|
+
assert_accepts matcher, get_instance_of(klass)
|
|
409
340
|
end
|
|
410
341
|
end
|
|
411
342
|
end
|
|
412
343
|
|
|
344
|
+
# Deprecated. See should_validate_uniqueness_of
|
|
345
|
+
def should_only_allow_numeric_values_for(*attributes)
|
|
346
|
+
warn "[DEPRECATION] should_only_allow_numeric_values_for is " <<
|
|
347
|
+
"deprecated. Use should_validate_numericality_of instead."
|
|
348
|
+
should_validate_numericality_of(*attributes)
|
|
349
|
+
end
|
|
350
|
+
|
|
413
351
|
# Ensures that the has_many relationship exists. Will also test that the
|
|
414
352
|
# associated table has the required columns. Works with polymorphic
|
|
415
353
|
# associations.
|
|
@@ -427,42 +365,9 @@ module Shoulda # :nodoc:
|
|
|
427
365
|
through, dependent = get_options!(associations, :through, :dependent)
|
|
428
366
|
klass = model_class
|
|
429
367
|
associations.each do |association|
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
should name do
|
|
434
|
-
reflection = klass.reflect_on_association(association)
|
|
435
|
-
assert reflection, "#{klass.name} does not have any relationship to #{association}"
|
|
436
|
-
assert_equal :has_many, reflection.macro
|
|
437
|
-
|
|
438
|
-
if through
|
|
439
|
-
through_reflection = klass.reflect_on_association(through)
|
|
440
|
-
assert through_reflection, "#{klass.name} does not have any relationship to #{through}"
|
|
441
|
-
assert_equal(through, reflection.options[:through])
|
|
442
|
-
end
|
|
443
|
-
|
|
444
|
-
if dependent
|
|
445
|
-
assert_equal dependent.to_s,
|
|
446
|
-
reflection.options[:dependent].to_s,
|
|
447
|
-
"#{association} should have #{dependent} dependency"
|
|
448
|
-
end
|
|
449
|
-
|
|
450
|
-
# Check for the existence of the foreign key on the other table
|
|
451
|
-
unless reflection.options[:through]
|
|
452
|
-
if reflection.options[:foreign_key]
|
|
453
|
-
fk = reflection.options[:foreign_key]
|
|
454
|
-
elsif reflection.options[:as]
|
|
455
|
-
fk = reflection.options[:as].to_s.foreign_key
|
|
456
|
-
else
|
|
457
|
-
fk = reflection.primary_key_name
|
|
458
|
-
end
|
|
459
|
-
|
|
460
|
-
associated_klass_name = (reflection.options[:class_name] || association.to_s.classify)
|
|
461
|
-
associated_klass = associated_klass_name.constantize
|
|
462
|
-
|
|
463
|
-
assert associated_klass.column_names.include?(fk.to_s),
|
|
464
|
-
"#{associated_klass.name} does not have a #{fk} foreign key."
|
|
465
|
-
end
|
|
368
|
+
matcher = have_many(association).through(through).dependent(dependent)
|
|
369
|
+
should matcher.description do
|
|
370
|
+
assert_accepts(matcher, klass.new)
|
|
466
371
|
end
|
|
467
372
|
end
|
|
468
373
|
end
|
|
@@ -481,33 +386,9 @@ module Shoulda # :nodoc:
|
|
|
481
386
|
dependent = get_options!(associations, :dependent)
|
|
482
387
|
klass = model_class
|
|
483
388
|
associations.each do |association|
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
reflection = klass.reflect_on_association(association)
|
|
488
|
-
assert reflection, "#{klass.name} does not have any relationship to #{association}"
|
|
489
|
-
assert_equal :has_one, reflection.macro
|
|
490
|
-
|
|
491
|
-
associated_klass = (reflection.options[:class_name] || association.to_s.camelize).constantize
|
|
492
|
-
|
|
493
|
-
if reflection.options[:foreign_key]
|
|
494
|
-
fk = reflection.options[:foreign_key]
|
|
495
|
-
elsif reflection.options[:as]
|
|
496
|
-
fk = reflection.options[:as].to_s.foreign_key
|
|
497
|
-
fk_type = fk.gsub(/_id$/, '_type')
|
|
498
|
-
assert associated_klass.column_names.include?(fk_type),
|
|
499
|
-
"#{associated_klass.name} does not have a #{fk_type} column."
|
|
500
|
-
else
|
|
501
|
-
fk = klass.name.foreign_key
|
|
502
|
-
end
|
|
503
|
-
assert associated_klass.column_names.include?(fk.to_s),
|
|
504
|
-
"#{associated_klass.name} does not have a #{fk} foreign key."
|
|
505
|
-
|
|
506
|
-
if dependent
|
|
507
|
-
assert_equal dependent.to_s,
|
|
508
|
-
reflection.options[:dependent].to_s,
|
|
509
|
-
"#{association} should have #{dependent} dependency"
|
|
510
|
-
end
|
|
389
|
+
matcher = have_one(association).dependent(dependent)
|
|
390
|
+
should matcher.description do
|
|
391
|
+
assert_accepts(matcher, klass.new)
|
|
511
392
|
end
|
|
512
393
|
end
|
|
513
394
|
end
|
|
@@ -522,12 +403,9 @@ module Shoulda # :nodoc:
|
|
|
522
403
|
klass = model_class
|
|
523
404
|
|
|
524
405
|
associations.each do |association|
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
assert_equal :has_and_belongs_to_many, reflection.macro
|
|
529
|
-
table = reflection.options[:join_table]
|
|
530
|
-
assert ::ActiveRecord::Base.connection.tables.include?(table.to_s), "table #{table} doesn't exist"
|
|
406
|
+
matcher = have_and_belong_to_many(association)
|
|
407
|
+
should matcher.description do
|
|
408
|
+
assert_accepts(matcher, klass.new)
|
|
531
409
|
end
|
|
532
410
|
end
|
|
533
411
|
end
|
|
@@ -540,22 +418,9 @@ module Shoulda # :nodoc:
|
|
|
540
418
|
dependent = get_options!(associations, :dependent)
|
|
541
419
|
klass = model_class
|
|
542
420
|
associations.each do |association|
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
assert_equal :belongs_to, reflection.macro
|
|
547
|
-
|
|
548
|
-
unless reflection.options[:polymorphic]
|
|
549
|
-
associated_klass = (reflection.options[:class_name] || association.to_s.camelize).constantize
|
|
550
|
-
fk = reflection.options[:foreign_key] || reflection.primary_key_name
|
|
551
|
-
assert klass.column_names.include?(fk.to_s), "#{klass.name} does not have a #{fk} foreign key."
|
|
552
|
-
end
|
|
553
|
-
|
|
554
|
-
if dependent
|
|
555
|
-
assert_equal dependent.to_s,
|
|
556
|
-
reflection.options[:dependent].to_s,
|
|
557
|
-
"#{association} should have #{dependent} dependency"
|
|
558
|
-
end
|
|
421
|
+
matcher = belong_to(association).dependent(dependent)
|
|
422
|
+
should matcher.description do
|
|
423
|
+
assert_accepts(matcher, klass.new)
|
|
559
424
|
end
|
|
560
425
|
end
|
|
561
426
|
end
|
|
@@ -589,41 +454,36 @@ module Shoulda # :nodoc:
|
|
|
589
454
|
end
|
|
590
455
|
|
|
591
456
|
# Ensure that the given columns are defined on the models backing SQL table.
|
|
457
|
+
# Also aliased to should_have_index for readability.
|
|
458
|
+
# Takes the same options available in migrations:
|
|
459
|
+
# :type, :precision, :limit, :default, :null, and :scale
|
|
460
|
+
#
|
|
461
|
+
# Examples:
|
|
592
462
|
#
|
|
593
463
|
# should_have_db_columns :id, :email, :name, :created_at
|
|
594
464
|
#
|
|
465
|
+
# should_have_db_column :email, :type => "string", :limit => 255
|
|
466
|
+
# should_have_db_column :salary, :decimal, :precision => 15, :scale => 2
|
|
467
|
+
# should_have_db_column :admin, :default => false, :null => false
|
|
468
|
+
#
|
|
595
469
|
def should_have_db_columns(*columns)
|
|
596
|
-
column_type
|
|
470
|
+
column_type, precision, limit, default, null, scale, sql_type =
|
|
471
|
+
get_options!(columns, :type, :precision, :limit,
|
|
472
|
+
:default, :null, :scale, :sql_type)
|
|
597
473
|
klass = model_class
|
|
598
474
|
columns.each do |name|
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
end
|
|
607
|
-
|
|
608
|
-
# Ensure that the given column is defined on the models backing SQL table. The options are the same as
|
|
609
|
-
# the instance variables defined on the column definition: :precision, :limit, :default, :null,
|
|
610
|
-
# :primary, :type, :scale, and :sql_type.
|
|
611
|
-
#
|
|
612
|
-
# should_have_db_column :email, :type => "string", :default => nil, :precision => nil, :limit => 255,
|
|
613
|
-
# :null => true, :primary => false, :scale => nil, :sql_type => 'varchar(255)'
|
|
614
|
-
#
|
|
615
|
-
def should_have_db_column(name, opts = {})
|
|
616
|
-
klass = model_class
|
|
617
|
-
test_name = "have column named :#{name}"
|
|
618
|
-
test_name += " with options " + opts.inspect unless opts.empty?
|
|
619
|
-
should test_name do
|
|
620
|
-
column = klass.columns.detect {|c| c.name == name.to_s }
|
|
621
|
-
assert column, "#{klass.name} does not have column #{name}"
|
|
622
|
-
opts.each do |k, v|
|
|
623
|
-
assert_equal column.instance_variable_get("@#{k}").to_s, v.to_s, ":#{name} column on table for #{klass} does not match option :#{k}"
|
|
475
|
+
matcher = have_db_column(name).
|
|
476
|
+
of_type(column_type).
|
|
477
|
+
with_options(:precision => precision, :limit => limit,
|
|
478
|
+
:default => default, :null => null,
|
|
479
|
+
:scale => scale, :sql_type => sql_type)
|
|
480
|
+
should matcher.description do
|
|
481
|
+
assert_accepts(matcher, klass.new)
|
|
624
482
|
end
|
|
625
483
|
end
|
|
626
484
|
end
|
|
485
|
+
|
|
486
|
+
alias_method :should_have_db_column, :should_have_db_columns
|
|
627
487
|
|
|
628
488
|
# Ensures that there are DB indices on the given columns or tuples of columns.
|
|
629
489
|
# Also aliased to should_have_index for readability
|
|
@@ -643,19 +503,12 @@ module Shoulda # :nodoc:
|
|
|
643
503
|
#
|
|
644
504
|
def should_have_indices(*columns)
|
|
645
505
|
unique = get_options!(columns, :unique)
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
index_types = { true => "unique", false => "non-unique" }
|
|
649
|
-
index_type = index_types[unique] || "an"
|
|
650
|
-
|
|
506
|
+
klass = model_class
|
|
507
|
+
|
|
651
508
|
columns.each do |column|
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
assert index, "#{table} does not have an index for #{column.inspect}"
|
|
656
|
-
if [true, false].include?(unique)
|
|
657
|
-
assert_equal unique, index.unique, "Expected #{index_type} index but was #{index_types[index.unique]}."
|
|
658
|
-
end
|
|
509
|
+
matcher = have_index(column).unique(unique)
|
|
510
|
+
should matcher.description do
|
|
511
|
+
assert_accepts(matcher, klass.new)
|
|
659
512
|
end
|
|
660
513
|
end
|
|
661
514
|
end
|
|
@@ -673,20 +526,27 @@ module Shoulda # :nodoc:
|
|
|
673
526
|
# Regexp or string. Default = <tt>I18n.translate('activerecord.errors.messages.accepted')</tt>
|
|
674
527
|
#
|
|
675
528
|
# Example:
|
|
676
|
-
#
|
|
529
|
+
# should_validate_acceptance_of :eula
|
|
677
530
|
#
|
|
678
|
-
def
|
|
531
|
+
def should_validate_acceptance_of(*attributes)
|
|
679
532
|
message = get_options!(attributes, :message)
|
|
680
|
-
message ||= default_error_message(:accepted)
|
|
681
533
|
klass = model_class
|
|
682
534
|
|
|
683
535
|
attributes.each do |attribute|
|
|
684
|
-
|
|
685
|
-
|
|
536
|
+
matcher = validate_acceptance_of(attribute).with_message(message)
|
|
537
|
+
should matcher.description do
|
|
538
|
+
assert_accepts matcher, get_instance_of(klass)
|
|
686
539
|
end
|
|
687
540
|
end
|
|
688
541
|
end
|
|
689
542
|
|
|
543
|
+
# Deprecated. See should_validate_uniqueness_of
|
|
544
|
+
def should_require_acceptance_of(*attributes)
|
|
545
|
+
warn "[DEPRECATION] should_require_acceptance_of is deprecated. " <<
|
|
546
|
+
"Use should_validate_acceptance_of instead."
|
|
547
|
+
should_validate_acceptance_of(*attributes)
|
|
548
|
+
end
|
|
549
|
+
|
|
690
550
|
# Ensures that the model has a method named scope_name that returns a NamedScope object with the
|
|
691
551
|
# proxy options set to the options you supply. scope_name can be either a symbol, or a method
|
|
692
552
|
# call which will be evaled against the model. The eval'd method call has access to all the same
|
|
@@ -722,25 +582,11 @@ module Shoulda # :nodoc:
|
|
|
722
582
|
# scoped(:limit => c)
|
|
723
583
|
# end
|
|
724
584
|
#
|
|
725
|
-
def should_have_named_scope(scope_call,
|
|
585
|
+
def should_have_named_scope(scope_call, find_options = nil)
|
|
726
586
|
klass = model_class
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
context scope_call do
|
|
731
|
-
setup do
|
|
732
|
-
@scope = eval("#{klass}.#{scope_call}")
|
|
733
|
-
end
|
|
734
|
-
|
|
735
|
-
should "return a scope object" do
|
|
736
|
-
assert_equal ::ActiveRecord::NamedScope::Scope, @scope.class
|
|
737
|
-
end
|
|
738
|
-
|
|
739
|
-
unless scope_opts.empty?
|
|
740
|
-
should "scope itself to #{scope_opts.inspect}" do
|
|
741
|
-
assert_equal scope_opts, @scope.proxy_options
|
|
742
|
-
end
|
|
743
|
-
end
|
|
587
|
+
matcher = have_named_scope(scope_call).finding(find_options)
|
|
588
|
+
should matcher.description do
|
|
589
|
+
assert_accepts matcher.in_context(self), klass.new
|
|
744
590
|
end
|
|
745
591
|
end
|
|
746
592
|
end
|