jnunemaker-mongomapper 0.1.2 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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