giraffesoft-attribute_fu 0.2 → 0.2.1

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.
@@ -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