jnunemaker-mongomapper 0.1.2 → 0.2.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.
@@ -0,0 +1,101 @@
1
+ require 'test_helper'
2
+
3
+ class Comment
4
+ include MongoMapper::Document
5
+
6
+ key :name, String
7
+ key :body, String
8
+
9
+ attr_accessor :callers
10
+ before_validation :record_callers
11
+
12
+ def after_validation
13
+ record_callers
14
+ end
15
+
16
+ def record_callers
17
+ callers << self.class if callers
18
+ end
19
+ end
20
+
21
+ class Article
22
+ include MongoMapper::Document
23
+
24
+ key :title, String
25
+ key :body, String
26
+ end
27
+
28
+ class CommentObserver < MongoMapper::Observer
29
+ attr_accessor :callers
30
+
31
+ def after_validation(model)
32
+ callers << self.class if callers
33
+ end
34
+ end
35
+
36
+ class AuditObserver < MongoMapper::Observer
37
+ observe Article, Comment
38
+ attr_reader :document
39
+
40
+ def after_validation(document)
41
+ @document = document
42
+ end
43
+ end
44
+
45
+ class GlobalObserver < MongoMapper::Observer
46
+ observe Article, Comment
47
+ attr_reader :document
48
+
49
+ def before_save(document)
50
+ @document = document
51
+ end
52
+ end
53
+
54
+ class NonAutomaticObserver < MongoMapper::Observer
55
+ observe Comment
56
+ attr_reader :comment
57
+
58
+ def after_validation(comment)
59
+ @comment = comment
60
+ end
61
+ end
62
+
63
+ class ObserverTest < Test::Unit::TestCase
64
+ should "fire model callbacks before observer" do
65
+ callers = []
66
+ comment = Comment.new
67
+ comment.callers = callers
68
+
69
+ CommentObserver.instance.callers = callers
70
+
71
+ comment.valid?
72
+ callers.should == [Comment, Comment, CommentObserver]
73
+ end
74
+
75
+ should "automatically observe model based on name when possible" do
76
+ CommentObserver.observed_class.should == Comment
77
+ end
78
+
79
+ should "be able to observe other models using observe" do
80
+ obs = NonAutomaticObserver.instance
81
+ comment = Comment.new(:name => 'John Nunemaker', :body => 'is awesome')
82
+ comment.valid?
83
+ obs.comment.name.should == 'John Nunemaker'
84
+ obs.comment.body.should == 'is awesome'
85
+ end
86
+
87
+ should "be able to observe multiple models" do
88
+ obs = AuditObserver.instance
89
+ comment = Comment.new(:name => 'Steve Smith', :body => 'is awesome')
90
+ comment.valid?
91
+
92
+ obs.document.name.should == 'Steve Smith'
93
+ obs.document.body.should == 'is awesome'
94
+
95
+ article = Article.new(:title => 'Ordered List Is Awesome', :body => 'Learn to accept it!')
96
+ article.valid?
97
+
98
+ obs.document.title.should == 'Ordered List Is Awesome'
99
+ obs.document.body.should == 'Learn to accept it!'
100
+ end
101
+ end
@@ -6,17 +6,22 @@ class TestRailsCompatibility < Test::Unit::TestCase
6
6
  include MongoMapper::Document
7
7
  end
8
8
  end
9
-
9
+
10
10
  should "have to_param that returns id" do
11
11
  instance = @document.create('_id' => '1234')
12
12
  instance.to_param.should == '1234'
13
13
  end
14
-
14
+
15
15
  should "alias new to new_record?" do
16
16
  instance = @document.new
17
17
  instance.new_record?.should == instance.new?
18
18
  end
19
-
19
+
20
+ should "alias many to has_many" do
21
+ @document.should respond_to(:has_many)
22
+ @document.method(:has_many).should == @document.method(:many)
23
+ end
24
+
20
25
  should "have column names" do
21
26
  @document.key :fname, String
22
27
  @document.column_names.sort.should == ['_id', 'created_at', 'fname', 'updated_at']
@@ -7,7 +7,7 @@ class ValidationsTest < Test::Unit::TestCase
7
7
  include MongoMapper::Document
8
8
  end
9
9
  end
10
-
10
+
11
11
  context "Validating acceptance of" do
12
12
  should "work with validates_acceptance_of macro" do
13
13
  @document.key :terms, String
@@ -40,7 +40,7 @@ class ValidationsTest < Test::Unit::TestCase
40
40
  doc.name = 'John'
41
41
  doc.should_not have_error_on(:name)
42
42
  end
43
-
43
+
44
44
  should "work with :format shorcut key" do
45
45
  @document.key :name, String, :format => /.+/
46
46
  doc = @document.new
@@ -49,7 +49,7 @@ class ValidationsTest < Test::Unit::TestCase
49
49
  doc.should_not have_error_on(:name)
50
50
  end
51
51
  end
52
-
52
+
53
53
  context "validating length of" do
54
54
  should "work with validates_length_of macro" do
55
55
  @document.key :name, String
@@ -57,7 +57,7 @@ class ValidationsTest < Test::Unit::TestCase
57
57
  doc = @document.new
58
58
  doc.should have_error_on(:name)
59
59
  end
60
-
60
+
61
61
  context "with :length => integer shortcut" do
62
62
  should "set maximum of integer provided" do
63
63
  @document.key :name, String, :length => 5
@@ -68,19 +68,19 @@ class ValidationsTest < Test::Unit::TestCase
68
68
  doc.should_not have_error_on(:name)
69
69
  end
70
70
  end
71
-
71
+
72
72
  context "with :length => range shortcut" do
73
73
  setup do
74
74
  @document.key :name, String, :length => 5..7
75
75
  end
76
-
76
+
77
77
  should "set minimum of range min" do
78
78
  doc = @document.new
79
79
  doc.should have_error_on(:name)
80
80
  doc.name = '123456'
81
81
  doc.should_not have_error_on(:name)
82
82
  end
83
-
83
+
84
84
  should "set maximum of range max" do
85
85
  doc = @document.new
86
86
  doc.should have_error_on(:name)
@@ -90,7 +90,7 @@ class ValidationsTest < Test::Unit::TestCase
90
90
  doc.should_not have_error_on(:name)
91
91
  end
92
92
  end
93
-
93
+
94
94
  context "with :length => hash shortcut" do
95
95
  should "pass options through" do
96
96
  @document.key :name, String, :length => {:minimum => 2}
@@ -101,7 +101,7 @@ class ValidationsTest < Test::Unit::TestCase
101
101
  end
102
102
  end
103
103
  end # validates_length_of
104
-
104
+
105
105
  context "Validating numericality of" do
106
106
  should "work with validates_numericality_of macro" do
107
107
  @document.key :age, Integer
@@ -112,7 +112,7 @@ class ValidationsTest < Test::Unit::TestCase
112
112
  doc.age = 23
113
113
  doc.should_not have_error_on(:age)
114
114
  end
115
-
115
+
116
116
  context "with :numeric shortcut" do
117
117
  should "work with integer or float" do
118
118
  @document.key :weight, Float, :numeric => true
@@ -125,7 +125,7 @@ class ValidationsTest < Test::Unit::TestCase
125
125
  doc.should_not have_error_on(:weight)
126
126
  end
127
127
  end
128
-
128
+
129
129
  context "with :numeric shortcut on Integer key" do
130
130
  should "only work with integers" do
131
131
  @document.key :age, Integer, :numeric => true
@@ -139,7 +139,7 @@ class ValidationsTest < Test::Unit::TestCase
139
139
  end
140
140
  end
141
141
  end # numericality of
142
-
142
+
143
143
  context "validating presence of" do
144
144
  should "work with validates_presence_of macro" do
145
145
  @document.key :name, String
@@ -147,22 +147,140 @@ class ValidationsTest < Test::Unit::TestCase
147
147
  doc = @document.new
148
148
  doc.should have_error_on(:name)
149
149
  end
150
-
150
+
151
151
  should "work with :required shortcut on key definition" do
152
152
  @document.key :name, String, :required => true
153
153
  doc = @document.new
154
154
  doc.should have_error_on(:name)
155
155
  end
156
- end
156
+ end
157
+
158
+ context "validating uniqueness of" do
159
+ setup do
160
+ @document.key :name, String
161
+ @document.validates_uniqueness_of :name
162
+ end
163
+
164
+ should "not fail if object is new" do
165
+ doc = @document.new
166
+ doc.should_not have_error_on(:name)
167
+ end
168
+
169
+ should "allow to update an object" do
170
+ doc = @document.new("name" => "joe")
171
+ doc.save
172
+ doc.name = "joe"
173
+ doc.valid?.should be_true
174
+ doc.should_not have_error_on(:name)
175
+ end
176
+
177
+ should "fail if object name is not unique" do
178
+ doc = @document.new("name" => "joe")
179
+ doc.save.should be_true
180
+ sleep 0.2 # hack to avoid race condition
181
+ doc2 = @document.new("name" => "joe")
182
+ doc2.should have_error_on(:name)
183
+ end
184
+ end
185
+
186
+ context "validates uniqueness of with :unique shortcut" do
187
+ should "work" do
188
+ @document.key :name, String, :unique => true
189
+
190
+ doc = @document.create(:name => 'John')
191
+ doc.should_not have_error_on(:name)
192
+ sleep 0.2 # hack to avoid race condition
193
+ second_john = @document.create(:name => 'John')
194
+ second_john.should have_error_on(:name, 'has already been taken')
195
+ end
196
+ end
197
+
198
+ context "validating exclusion of" do
199
+ should "throw error if enumerator not provided" do
200
+ @document.key :action, String
201
+ lambda {
202
+ @document.validates_exclusion_of :action
203
+ }.should raise_error(ArgumentError)
204
+ end
205
+
206
+ should "work with validates_exclusion_of macro" do
207
+ @document.key :action, String
208
+ @document.validates_exclusion_of :action, :within => %w(kick run)
209
+
210
+ doc = @document.new
211
+ doc.should_not have_error_on(:action)
212
+
213
+ doc.action = 'fart'
214
+ doc.should_not have_error_on(:action)
215
+
216
+ doc.action = 'kick'
217
+ doc.should have_error_on(:action, 'is reserved')
218
+ end
219
+
220
+ should "not have error if allow nil is true and value is nil" do
221
+ @document.key :action, String
222
+ @document.validates_exclusion_of :action, :within => %w(kick run), :allow_nil => true
223
+
224
+ doc = @document.new
225
+ doc.should_not have_error_on(:action)
226
+ end
227
+
228
+ should "not have error if allow blank is true and value is blank" do
229
+ @document.key :action, String
230
+ @document.validates_exclusion_of :action, :within => %w(kick run), :allow_nil => true
231
+
232
+ doc = @document.new(:action => '')
233
+ doc.should_not have_error_on(:action)
234
+ end
235
+ end
236
+
237
+ context "validating inclusion of" do
238
+ should "throw error if enumerator not provided" do
239
+ @document.key :action, String
240
+ lambda {
241
+ @document.validates_inclusion_of :action
242
+ }.should raise_error(ArgumentError)
243
+ end
244
+
245
+ should "work with validates_inclusion_of macro" do
246
+ @document.key :action, String
247
+ @document.validates_inclusion_of :action, :within => %w(kick run)
248
+
249
+ doc = @document.new
250
+ doc.should have_error_on(:action, 'is not in the list')
251
+
252
+ doc.action = 'fart'
253
+ doc.should have_error_on(:action, 'is not in the list')
254
+
255
+ doc.action = 'kick'
256
+ doc.should_not have_error_on(:action)
257
+ end
258
+
259
+ should "not have error if allow nil is true and value is nil" do
260
+ @document.key :action, String
261
+ @document.validates_inclusion_of :action, :within => %w(kick run), :allow_nil => true
262
+
263
+ doc = @document.new
264
+ doc.should_not have_error_on(:action)
265
+ end
266
+
267
+ should "not have error if allow blank is true and value is blank" do
268
+ @document.key :action, String
269
+ @document.validates_inclusion_of :action, :within => %w(kick run), :allow_blank => true
270
+
271
+ doc = @document.new(:action => '')
272
+ doc.should_not have_error_on(:action)
273
+ end
274
+ end
157
275
  end # Validations
158
-
276
+
159
277
  context "Saving a new document that is invalid" do
160
278
  setup do
161
279
  @document = Class.new do
162
280
  include MongoMapper::Document
163
281
  key :name, String, :required => true
164
282
  end
165
-
283
+
166
284
  @document.collection.clear
167
285
  end
168
286
 
@@ -171,7 +289,7 @@ class ValidationsTest < Test::Unit::TestCase
171
289
  doc.save
172
290
  @document.count.should == 0
173
291
  end
174
-
292
+
175
293
  should "populate document's errors" do
176
294
  doc = @document.new
177
295
  doc.errors.size.should == 0
@@ -179,14 +297,14 @@ class ValidationsTest < Test::Unit::TestCase
179
297
  doc.errors.full_messages.should == ["Name can't be empty"]
180
298
  end
181
299
  end
182
-
300
+
183
301
  context "Saving a document that is invalid (destructive)" do
184
302
  setup do
185
303
  @document = Class.new do
186
304
  include MongoMapper::Document
187
305
  key :name, String, :required => true
188
306
  end
189
-
307
+
190
308
  @document.collection.clear
191
309
  end
192
310
 
@@ -195,14 +313,14 @@ class ValidationsTest < Test::Unit::TestCase
195
313
  lambda { doc.save! }.should raise_error(MongoMapper::DocumentNotValid)
196
314
  end
197
315
  end
198
-
316
+
199
317
  context "Saving an existing document that is invalid" do
200
318
  setup do
201
319
  @document = Class.new do
202
320
  include MongoMapper::Document
203
321
  key :name, String, :required => true
204
322
  end
205
-
323
+
206
324
  @document.collection.clear
207
325
  @doc = @document.create(:name => 'John Nunemaker')
208
326
  end
@@ -212,11 +330,64 @@ class ValidationsTest < Test::Unit::TestCase
212
330
  @doc.save
213
331
  @document.find(@doc.id).name.should == 'John Nunemaker'
214
332
  end
215
-
333
+
216
334
  should "populate document's errors" do
217
335
  @doc.name = nil
218
336
  @doc.save
219
337
  @doc.errors.full_messages.should == ["Name can't be empty"]
220
338
  end
221
339
  end
340
+
341
+ context "Adding validation errors" do
342
+ setup do
343
+ @document = Class.new do
344
+ include MongoMapper::Document
345
+ key :action, String
346
+ def action_present
347
+ errors.add(:action, 'is invalid') if action.blank?
348
+ end
349
+ end
350
+ end
351
+
352
+ should "work with validate callback" do
353
+ @document.validate :action_present
354
+
355
+ doc = @document.new
356
+ doc.action = nil
357
+ doc.should have_error_on(:action)
358
+
359
+ doc.action = 'kick'
360
+ doc.should_not have_error_on(:action)
361
+ end
362
+
363
+ should "work with validate_on_create callback" do
364
+ @document.validate_on_create :action_present
365
+
366
+ doc = @document.new
367
+ doc.action = nil
368
+ doc.should have_error_on(:action)
369
+
370
+ doc.action = 'kick'
371
+ doc.should_not have_error_on(:action)
372
+ doc.save
373
+
374
+ doc.action = nil
375
+ doc.should_not have_error_on(:action)
376
+ end
377
+
378
+ should "work with validate_on_update callback" do
379
+ @document.validate_on_update :action_present
380
+
381
+ doc = @document.new
382
+ doc.action = nil
383
+ doc.should_not have_error_on(:action)
384
+ doc.save
385
+
386
+ doc.action = nil
387
+ doc.should have_error_on(:action)
388
+
389
+ doc.action = 'kick'
390
+ doc.should_not have_error_on(:action)
391
+ end
392
+ end
222
393
  end