giraffesoft-attribute_fu 0.2 → 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,6 +0,0 @@
1
- require File.dirname(__FILE__) + '/../test_helper'
2
-
3
- class CommentTest < ActiveSupport::TestCase
4
- should_belong_to :photo
5
- should_require_attributes :author, :body
6
- end
@@ -1,149 +0,0 @@
1
- require File.dirname(__FILE__) + '/../test_helper'
2
-
3
- class PhotoTest < ActiveSupport::TestCase
4
- should_have_many :comments
5
-
6
- context "comment_attributes" do
7
- context "with valid children" do
8
- setup do
9
- create_photo_and_children
10
-
11
- @photo.comment_attributes = { @gob.id.to_s => { :author => "Buster Bluth", :body => "I said it was _our_ nausia..." },
12
- :new => { "0" => { :author => "George-Michael", :body => "I was going to smoke the marijuana like a ciggarette." },
13
- "-1" => { :author => "Tobias Funke", :body => "I am an actor! An actor for crying out loud!" }}}
14
-
15
- end
16
-
17
- context "before save" do
18
- should "not have deleted anything in the remove array" do
19
- assert @photo.comments.any? { |comment| comment.author == "Bob Loblaw" }, "Comment in remove array was removed."
20
- end
21
-
22
- should "not have saved any new objects" do
23
- assert @photo.comments.any? { |comment| comment.new_record? }
24
- end
25
- end
26
-
27
- context "after save" do
28
- setup do
29
- @photo.save
30
- end
31
-
32
- context "with existing child" do
33
- setup do
34
- @gob.reload
35
- end
36
-
37
- should "update attributes" do
38
- assert_equal "Buster Bluth", @gob.author, "Author attribute of child model was not updated."
39
- assert_equal "I said it was _our_ nausia...", @gob.body, "Body attribute of child model was not updated."
40
- end
41
- end
42
-
43
- context "with new hash" do
44
- should "create new comment" do
45
- assert @photo.comments.any? { |comment| comment.author == "George-Michael" && comment.body =~ /was going to smoke/i }, "New comment was not created."
46
- end
47
-
48
- should "order the negatives after the positives" do
49
- assert_equal "Tobias Funke", @photo.comments.last.author, "Tobias is not the last comment: #{@photo.comments.inspect}"
50
- end
51
- end
52
-
53
- context "with missing associated" do
54
- should "remove those children from the parent" do
55
- assert !@photo.comments.any? { |comment| comment.author == "Bob Loblaw" }, "Comment not included was not removed."
56
- end
57
- end
58
- end
59
-
60
- context "with comment_attributes = nil" do
61
- setup do
62
- @photo.save
63
- @photo.comment_attributes = nil
64
- @photo.save
65
- end
66
-
67
- should "remove all comments" do
68
- assert @photo.comments.empty?, "one or more comments not removed: #{@photo.comments.inspect}"
69
- end
70
- end
71
-
72
- context "with discard_if => proc { }" do
73
- setup do
74
- create_photo_with_discard(proc { |comment| comment.author.blank? && comment.body.blank? })
75
- end
76
-
77
- teardown do
78
- Photo.class_eval do
79
- managed_association_attributes[:comments].delete(:discard_if)
80
- end
81
- end
82
-
83
- should "discard any child objects for which discard_if evaluates to true" do
84
- assert !@photo.comments.any? { |comment| comment.author.blank? && comment.body.blank? }, @photo.comments.inspect
85
- end
86
-
87
- should "not discard other objects" do
88
- assert_equal 1, @photo.comments.length
89
- end
90
- end
91
-
92
- context "with discard_if => :symbol" do
93
- setup do
94
- create_photo_with_discard(:blank?)
95
- end
96
-
97
- teardown do
98
- Photo.class_eval do
99
- managed_association_attributes[:comments].delete(:discard_if)
100
- end
101
- end
102
-
103
- should "discard any child objects for which discard_if evaluates to true" do
104
- assert !@photo.comments.any? { |comment| comment.author.blank? && comment.body.blank? }, @photo.comments.inspect
105
- end
106
-
107
- should "not discard other objects" do
108
- assert_equal 1, @photo.comments.length
109
- end
110
- end
111
- end
112
-
113
- context "updating with invalid children" do
114
- setup do
115
- @photo = Photo.create
116
- @saved = @photo.update_attributes :comment_attributes => {:new => {"0" => {:author => "Tobias"}}}
117
- end
118
-
119
- should "not save" do
120
- assert !@saved
121
- end
122
-
123
- should "have errors on child" do
124
- assert @photo.comments.first.errors.on(:body)
125
- end
126
- end
127
- end
128
-
129
- private
130
- def create_photo_and_children
131
- @photo = Photo.create
132
- @gob = @photo.comments.create :author => "Gob Bluth", :body => "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed..."
133
- @bob = @photo.comments.create :author => "Bob Loblaw", :body => "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed..."
134
- end
135
-
136
- def create_photo_with_discard(discard_if)
137
- Photo.class_eval do
138
- has_many :comments, :attributes => true, :discard_if => discard_if
139
- end
140
-
141
- create_photo_and_children
142
-
143
-
144
- @photo.comment_attributes = { @gob.id.to_s => { :author => "Buster Bluth", :body => "I said it was _our_ nausia..." },
145
- @bob.id.to_s => { :author => '', :body => '' },
146
- :new => { "0" => { :author => "", :body => "" }}}
147
- @photo.save
148
- end
149
- end
@@ -1,3 +0,0 @@
1
- require 'rubygems'
2
- require 'active_support'
3
- require 'shoulda'
@@ -1,20 +0,0 @@
1
- require 'yaml'
2
- require 'shoulda/private_helpers'
3
- require 'shoulda/general'
4
- require 'shoulda/context'
5
- require 'shoulda/active_record_helpers'
6
-
7
-
8
- module Test # :nodoc: all
9
- module Unit
10
- class TestCase
11
-
12
- include ThoughtBot::Shoulda::General
13
-
14
- class << self
15
- include ThoughtBot::Shoulda::Context
16
- include ThoughtBot::Shoulda::ActiveRecord
17
- end
18
- end
19
- end
20
- end
@@ -1,338 +0,0 @@
1
- module ThoughtBot # :nodoc:
2
- module Shoulda # :nodoc:
3
- # = Macro test helpers for your active record models
4
- #
5
- # These helpers will test most of the validations and associations for your ActiveRecord models.
6
- #
7
- # class UserTest < Test::Unit::TestCase
8
- # should_require_attributes :name, :phone_number
9
- # should_not_allow_values_for :phone_number, "abcd", "1234"
10
- # should_allow_values_for :phone_number, "(123) 456-7890"
11
- #
12
- # should_protect_attributes :password
13
- #
14
- # should_have_one :profile
15
- # should_have_many :dogs
16
- # should_have_many :messes, :through => :dogs
17
- # should_belong_to :lover
18
- # end
19
- #
20
- # For all of these helpers, the last parameter may be a hash of options.
21
- #
22
- module ActiveRecord
23
- # Ensures that the model cannot be saved if one of the attributes listed is not present.
24
- # Requires an existing record.
25
- #
26
- # Options:
27
- # * <tt>:message</tt> - value the test expects to find in <tt>errors.on(:attribute)</tt>.
28
- # Regexp or string. Default = <tt>/blank/</tt>
29
- #
30
- # Example:
31
- # should_require_attributes :name, :phone_number
32
- def should_require_attributes(*attributes)
33
- message = get_options!(attributes, :message)
34
- message ||= /blank/
35
- klass = model_class
36
-
37
- attributes.each do |attribute|
38
- should "require #{attribute} to be set" do
39
- object = klass.new
40
- assert !object.valid?, "#{klass.name} does not require #{attribute}."
41
- assert object.errors.on(attribute), "#{klass.name} does not require #{attribute}."
42
- assert_contains(object.errors.on(attribute), message)
43
- end
44
- end
45
- end
46
-
47
- # Ensures that the model cannot be saved if one of the attributes listed is not unique.
48
- # Requires an existing record
49
- #
50
- # Options:
51
- # * <tt>:message</tt> - value the test expects to find in <tt>errors.on(:attribute)</tt>.
52
- # Regexp or string. Default = <tt>/taken/</tt>
53
- #
54
- # Example:
55
- # should_require_unique_attributes :keyword, :username
56
- def should_require_unique_attributes(*attributes)
57
- message, scope = get_options!(attributes, :message, :scoped_to)
58
- message ||= /taken/
59
-
60
- klass = model_class
61
- attributes.each do |attribute|
62
- attribute = attribute.to_sym
63
- should "require unique value for #{attribute}#{" scoped to #{scope}" if scope}" do
64
- assert existing = klass.find(:first), "Can't find first #{klass}"
65
- object = klass.new
66
-
67
- object.send(:"#{attribute}=", existing.send(attribute))
68
- if scope
69
- assert_respond_to object, :"#{scope}=", "#{klass.name} doesn't seem to have a #{scope} attribute."
70
- object.send(:"#{scope}=", existing.send(scope))
71
- end
72
-
73
- assert !object.valid?, "#{klass.name} does not require a unique value for #{attribute}."
74
- assert object.errors.on(attribute), "#{klass.name} does not require a unique value for #{attribute}."
75
-
76
- assert_contains(object.errors.on(attribute), message)
77
-
78
- if scope
79
- # Now test that the object is valid when changing the scoped attribute
80
- # TODO: actually find all values for scope and create a unique one.
81
- object.send(:"#{scope}=", existing.send(scope).nil? ? 1 : existing.send(scope).next)
82
- object.errors.clear
83
- object.valid?
84
- assert_does_not_contain(object.errors.on(attribute), message,
85
- "after :#{scope} set to #{object.send(scope.to_sym)}")
86
- end
87
- end
88
- end
89
- end
90
-
91
- # Ensures that the attribute cannot be set on update
92
- # Requires an existing record
93
- #
94
- # should_protect_attributes :password, :admin_flag
95
- def should_protect_attributes(*attributes)
96
- get_options!(attributes)
97
- klass = model_class
98
- attributes.each do |attribute|
99
- attribute = attribute.to_sym
100
- should "not allow #{attribute} to be changed by update" do
101
- assert object = klass.find(:first), "Can't find first #{klass}"
102
- value = object[attribute]
103
- # TODO: 1 may not be a valid value for the attribute (due to validations)
104
- assert object.update_attributes({ attribute => 1 }),
105
- "Cannot update #{klass} with { :#{attribute} => 1 }, #{object.errors.full_messages.to_sentence}"
106
- assert object.valid?, "#{klass} isn't valid after changing #{attribute}"
107
- assert_equal value, object[attribute], "Was able to change #{klass}##{attribute}"
108
- end
109
- end
110
- end
111
-
112
- # Ensures that the attribute cannot be set to the given values
113
- # Requires an existing record
114
- #
115
- # Options:
116
- # * <tt>:message</tt> - value the test expects to find in <tt>errors.on(:attribute)</tt>.
117
- # Regexp or string. Default = <tt>/invalid/</tt>
118
- #
119
- # Example:
120
- # should_not_allow_values_for :isbn, "bad 1", "bad 2"
121
- def should_not_allow_values_for(attribute, *bad_values)
122
- message = get_options!(bad_values, :message)
123
- message ||= /invalid/
124
- klass = model_class
125
- bad_values.each do |v|
126
- should "not allow #{attribute} to be set to \"#{v}\"" do
127
- assert object = klass.find(:first), "Can't find first #{klass}"
128
- object.send("#{attribute}=", v)
129
- assert !object.save, "Saved #{klass} with #{attribute} set to \"#{v}\""
130
- assert object.errors.on(attribute), "There are no errors set on #{attribute} after being set to \"#{v}\""
131
- assert_contains(object.errors.on(attribute), message, "when set to \"#{v}\"")
132
- end
133
- end
134
- end
135
-
136
- # Ensures that the attribute can be set to the given values.
137
- # Requires an existing record
138
- #
139
- # Options:
140
- # * <tt>:message</tt> - value the test expects to find in <tt>errors.on(:attribute)</tt>.
141
- # Regexp or string. Default = <tt>/invalid/</tt>
142
- #
143
- # Example:
144
- # should_allow_values_for :isbn, "isbn 1 2345 6789 0", "ISBN 1-2345-6789-0"
145
- def should_allow_values_for(attribute, *good_values)
146
- message = get_options!(good_values, :message)
147
- message ||= /invalid/
148
- klass = model_class
149
- good_values.each do |v|
150
- should "allow #{attribute} to be set to \"#{v}\"" do
151
- assert object = klass.find(:first), "Can't find first #{klass}"
152
- object.send("#{attribute}=", v)
153
- object.save
154
- assert_does_not_contain(object.errors.on(attribute), message, "when set to \"#{v}\"")
155
- end
156
- end
157
- end
158
-
159
- # Ensures that the length of the attribute is in the given range
160
- # Requires an existing record
161
- #
162
- # Options:
163
- # * <tt>:short_message</tt> - value the test expects to find in <tt>errors.on(:attribute)</tt>.
164
- # Regexp or string. Default = <tt>/short/</tt>
165
- # * <tt>:long_message</tt> - value the test expects to find in <tt>errors.on(:attribute)</tt>.
166
- # Regexp or string. Default = <tt>/long/</tt>
167
- #
168
- # Example:
169
- # should_ensure_length_in_range :password, (6..20)
170
- def should_ensure_length_in_range(attribute, range, opts = {})
171
- short_message, long_message = get_options!([opts], :short_message, :long_message)
172
- short_message ||= /short/
173
- long_message ||= /long/
174
-
175
- klass = model_class
176
- min_length = range.first
177
- max_length = range.last
178
-
179
- if min_length > 0
180
- min_value = "x" * (min_length - 1)
181
- should "not allow #{attribute} to be less than #{min_length} chars long" do
182
- assert object = klass.find(:first), "Can't find first #{klass}"
183
- object.send("#{attribute}=", min_value)
184
- assert !object.save, "Saved #{klass} with #{attribute} set to \"#{min_value}\""
185
- assert object.errors.on(attribute), "There are no errors set on #{attribute} after being set to \"#{min_value}\""
186
- assert_contains(object.errors.on(attribute), short_message, "when set to \"#{min_value}\"")
187
- end
188
- end
189
-
190
- max_value = "x" * (max_length + 1)
191
- should "not allow #{attribute} to be more than #{max_length} chars long" do
192
- assert object = klass.find(:first), "Can't find first #{klass}"
193
- object.send("#{attribute}=", max_value)
194
- assert !object.save, "Saved #{klass} with #{attribute} set to \"#{max_value}\""
195
- assert object.errors.on(attribute), "There are no errors set on #{attribute} after being set to \"#{max_value}\""
196
- assert_contains(object.errors.on(attribute), long_message, "when set to \"#{max_value}\"")
197
- end
198
- end
199
-
200
- # Ensure that the attribute is in the range specified
201
- # Requires an existing record
202
- #
203
- # Options:
204
- # * <tt>:low_message</tt> - value the test expects to find in <tt>errors.on(:attribute)</tt>.
205
- # Regexp or string. Default = <tt>/included/</tt>
206
- # * <tt>:high_message</tt> - value the test expects to find in <tt>errors.on(:attribute)</tt>.
207
- # Regexp or string. Default = <tt>/included/</tt>
208
- #
209
- # Example:
210
- # should_ensure_value_in_range :age, (0..100)
211
- def should_ensure_value_in_range(attribute, range, opts = {})
212
- low_message, high_message = get_options!([opts], :low_message, :high_message)
213
- low_message ||= /included/
214
- high_message ||= /included/
215
-
216
- klass = model_class
217
- min = range.first
218
- max = range.last
219
-
220
- should "not allow #{attribute} to be less than #{min}" do
221
- v = min - 1
222
- assert object = klass.find(:first), "Can't find first #{klass}"
223
- object.send("#{attribute}=", v)
224
- assert !object.save, "Saved #{klass} with #{attribute} set to \"#{v}\""
225
- assert object.errors.on(attribute), "There are no errors set on #{attribute} after being set to \"#{v}\""
226
- assert_contains(object.errors.on(attribute), low_message, "when set to \"#{v}\"")
227
- end
228
-
229
- should "not allow #{attribute} to be more than #{max}" do
230
- v = max + 1
231
- assert object = klass.find(:first), "Can't find first #{klass}"
232
- object.send("#{attribute}=", v)
233
- assert !object.save, "Saved #{klass} with #{attribute} set to \"#{v}\""
234
- assert object.errors.on(attribute), "There are no errors set on #{attribute} after being set to \"#{v}\""
235
- assert_contains(object.errors.on(attribute), high_message, "when set to \"#{v}\"")
236
- end
237
- end
238
-
239
- # Ensure that the attribute is numeric
240
- # Requires an existing record
241
- #
242
- # Options:
243
- # * <tt>:message</tt> - value the test expects to find in <tt>errors.on(:attribute)</tt>.
244
- # Regexp or string. Default = <tt>/number/</tt>
245
- #
246
- # Example:
247
- # should_only_allow_numeric_values_for :age
248
- def should_only_allow_numeric_values_for(*attributes)
249
- message = get_options!(attributes, :message)
250
- message ||= /number/
251
- klass = model_class
252
- attributes.each do |attribute|
253
- attribute = attribute.to_sym
254
- should "only allow numeric values for #{attribute}" do
255
- assert object = klass.find(:first), "Can't find first #{klass}"
256
- object.send(:"#{attribute}=", "abcd")
257
- assert !object.valid?, "Instance is still valid"
258
- assert_contains(object.errors.on(attribute), message)
259
- end
260
- end
261
- end
262
-
263
- # Ensures that the has_many relationship exists.
264
- #
265
- # Options:
266
- # * <tt>:through</tt> - association name for <tt>has_many :through</tt>
267
- #
268
- # Example:
269
- # should_have_many :friends
270
- # should_have_many :enemies, :through => :friends
271
- def should_have_many(*associations)
272
- through = get_options!(associations, :through)
273
- klass = model_class
274
- associations.each do |association|
275
- should "have many #{association}#{" through #{through}" if through}" do
276
- reflection = klass.reflect_on_association(association)
277
- assert reflection, "#{klass.name} does not have any relationship to #{association}"
278
- assert_equal :has_many, reflection.macro
279
- if through
280
- through_reflection = klass.reflect_on_association(through)
281
- assert through_reflection, "#{klass.name} does not have any relationship to #{through}"
282
- assert_equal(through, reflection.options[:through])
283
- end
284
- end
285
- end
286
- end
287
-
288
- # Ensures that the has_and_belongs_to_many relationship exists.
289
- #
290
- # should_have_and_belong_to_many :posts, :cars
291
- def should_have_and_belong_to_many(*associations)
292
- get_options!(associations)
293
- klass = model_class
294
- associations.each do |association|
295
- should "should have and belong to many #{association}" do
296
- assert klass.reflect_on_association(association), "#{klass.name} does not have any relationship to #{association}"
297
- assert_equal :has_and_belongs_to_many, klass.reflect_on_association(association).macro
298
- end
299
- end
300
- end
301
-
302
- # Ensure that the has_one relationship exists.
303
- #
304
- # should_have_one :god # unless hindu
305
- def should_have_one(*associations)
306
- get_options!(associations)
307
- klass = model_class
308
- associations.each do |association|
309
- should "have one #{association}" do
310
- assert klass.reflect_on_association(association), "#{klass.name} does not have any relationship to #{association}"
311
- assert_equal :has_one, klass.reflect_on_association(association).macro
312
- end
313
- end
314
- end
315
-
316
- # Ensure that the belongs_to relationship exists.
317
- #
318
- # should_belong_to :parent
319
- def should_belong_to(*associations)
320
- get_options!(associations)
321
- klass = model_class
322
- associations.each do |association|
323
- should "belong_to #{association}" do
324
- reflection = klass.reflect_on_association(association)
325
- assert reflection, "#{klass.name} does not have any relationship to #{association}"
326
- assert_equal :belongs_to, reflection.macro
327
- fk = reflection.options[:foreign_key] || "#{association}_id"
328
- assert klass.column_names.include?(fk), "#{klass.name} does not have a #{fk} foreign key."
329
- end
330
- end
331
- end
332
-
333
- private
334
-
335
- include ThoughtBot::Shoulda::Private
336
- end
337
- end
338
- end