jnunemaker-mongomapper 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,938 @@
1
+ require 'test_helper'
2
+
3
+ class Address
4
+ include MongoMapper::EmbeddedDocument
5
+ key :city, String
6
+ key :state, String
7
+ end
8
+
9
+ class DocumentTest < Test::Unit::TestCase
10
+ context "The Document Class" do
11
+ setup do
12
+ @document = Class.new do
13
+ include MongoMapper::Document
14
+ end
15
+ end
16
+
17
+ should "should be able to define a key" do
18
+ key = @document.key(:name, String)
19
+ key.name.should == 'name'
20
+ key.type.should == String
21
+ key.should be_instance_of(MongoMapper::Key)
22
+ end
23
+
24
+ should "be able to define a key with options" do
25
+ key = @document.key(:name, String, :required => true)
26
+ key.options[:required].should be(true)
27
+ end
28
+
29
+ should "know what keys have been defined" do
30
+ @document.key(:name, String)
31
+ @document.key(:age, Integer)
32
+ @document.keys['name'].name.should == 'name'
33
+ @document.keys['name'].type.should == String
34
+ @document.keys['age'].name.should == 'age'
35
+ @document.keys['age'].type.should == Integer
36
+ end
37
+
38
+ should "use default database by default" do
39
+ @document.database.should == MongoMapper.database
40
+ end
41
+
42
+ should "have a connection" do
43
+ @document.connection.should be_instance_of(XGen::Mongo::Driver::Mongo)
44
+ end
45
+
46
+ should "allow setting different connection without affecting the default" do
47
+ conn = XGen::Mongo::Driver::Mongo.new
48
+ @document.connection conn
49
+ @document.connection.should == conn
50
+ @document.connection.should_not == MongoMapper.connection
51
+ end
52
+
53
+ should "allow setting a different database without affecting the default" do
54
+ @document.database AlternateDatabase
55
+ @document.database.name.should == AlternateDatabase
56
+
57
+ another_document = Class.new do
58
+ include MongoMapper::Document
59
+ end
60
+ another_document.database.should == MongoMapper.database
61
+ end
62
+
63
+ class Item; include MongoMapper::Document; end
64
+ should "default collection name to class name tableized" do
65
+ Item.collection.should be_instance_of(XGen::Mongo::Driver::Collection)
66
+ Item.collection.name.should == 'items'
67
+ end
68
+
69
+ should "allow setting the collection name" do
70
+ @document.collection('foobar')
71
+ @document.collection.should be_instance_of(XGen::Mongo::Driver::Collection)
72
+ @document.collection.name.should == 'foobar'
73
+ end
74
+ end # Document class
75
+
76
+ context "Database operations" do
77
+ setup do
78
+ @document = Class.new do
79
+ include MongoMapper::Document
80
+ collection 'users'
81
+
82
+ key :fname, String
83
+ key :lname, String
84
+ key :age, Integer
85
+ end
86
+
87
+ @document.collection.clear
88
+ end
89
+
90
+ context "Using key with type Array" do
91
+ setup do
92
+ @document.key :tags, Array
93
+ end
94
+
95
+ should "work" do
96
+ doc = @document.new
97
+ doc.tags.should == []
98
+ doc.tags = %w(foo bar)
99
+ doc.save
100
+ doc.tags.should == %w(foo bar)
101
+ @document.find(doc.id).tags.should == %w(foo bar)
102
+ end
103
+ end
104
+
105
+ context "Using key with type Hash" do
106
+ setup do
107
+ @document.key :foo, Hash
108
+ end
109
+
110
+ should "work with indifferent access" do
111
+ doc = @document.new
112
+ doc.foo = {:baz => 'bar'}
113
+ doc.save
114
+
115
+ doc = @document.find(doc.id)
116
+ doc.foo[:baz].should == 'bar'
117
+ doc.foo['baz'].should == 'bar'
118
+ end
119
+ end
120
+
121
+ context "Saving a document with an embedded document" do
122
+ setup do
123
+ @document.class_eval do
124
+ key :foo, Address
125
+ end
126
+ end
127
+
128
+ should "embed embedded document" do
129
+ address = Address.new(:city => 'South Bend', :state => 'IN')
130
+ doc = @document.new(:foo => address)
131
+ doc.save
132
+ doc.foo.city.should == 'South Bend'
133
+ doc.foo.state.should == 'IN'
134
+
135
+ from_db = @document.find(doc.id)
136
+ from_db.foo.city.should == 'South Bend'
137
+ from_db.foo.state.should == 'IN'
138
+ end
139
+ end
140
+
141
+ context "Creating a single document" do
142
+ setup do
143
+ @doc_instance = @document.create({:fname => 'John', :lname => 'Nunemaker', :age => '27'})
144
+ end
145
+
146
+ should "create a document in correct collection" do
147
+ @document.count.should == 1
148
+ end
149
+
150
+ should "automatically set id" do
151
+ @doc_instance.id.should_not be_nil
152
+ @doc_instance.id.size.should == 24
153
+ end
154
+
155
+ should "return instance of document" do
156
+ @doc_instance.should be_instance_of(@document)
157
+ @doc_instance.fname.should == 'John'
158
+ @doc_instance.lname.should == 'Nunemaker'
159
+ @doc_instance.age.should == 27
160
+ end
161
+ end
162
+
163
+ context "Creating multiple documents" do
164
+ setup do
165
+ @doc_instances = @document.create([
166
+ {:fname => 'John', :lname => 'Nunemaker', :age => '27'},
167
+ {:fname => 'Steve', :lname => 'Smith', :age => '28'},
168
+ ])
169
+ end
170
+
171
+ should "create multiple documents" do
172
+ @document.count.should == 2
173
+ end
174
+
175
+ should "return an array of doc instances" do
176
+ @doc_instances.map do |doc_instance|
177
+ doc_instance.should be_instance_of(@document)
178
+ end
179
+ end
180
+ end
181
+
182
+ context "Updating a document" do
183
+ setup do
184
+ doc = @document.create({:fname => 'John', :lname => 'Nunemaker', :age => '27'})
185
+ @doc_instance = @document.update(doc.id, {:age => 40})
186
+ end
187
+
188
+ should "update attributes provided" do
189
+ @doc_instance.age.should == 40
190
+ end
191
+
192
+ should "not update existing attributes that were not set to update" do
193
+ @doc_instance.fname.should == 'John'
194
+ @doc_instance.lname.should == 'Nunemaker'
195
+ end
196
+
197
+ should "not create new document" do
198
+ @document.count.should == 1
199
+ end
200
+ end
201
+
202
+ should "raise error when updating single doc if not provided id and attributes" do
203
+ doc = @document.create({:fname => 'John', :lname => 'Nunemaker', :age => '27'})
204
+ lambda { @document.update }.should raise_error(ArgumentError)
205
+ lambda { @document.update(doc.id) }.should raise_error(ArgumentError)
206
+ lambda { @document.update(doc.id, [1]) }.should raise_error(ArgumentError)
207
+ end
208
+
209
+ context "Updating multiple documents" do
210
+ setup do
211
+ @doc1 = @document.create({:fname => 'John', :lname => 'Nunemaker', :age => '27'})
212
+ @doc2 = @document.create({:fname => 'Steve', :lname => 'Smith', :age => '28'})
213
+
214
+ @doc_instances = @document.update({
215
+ @doc1.id => {:age => 30},
216
+ @doc2.id => {:age => 30},
217
+ })
218
+ end
219
+
220
+ should "not create any new documents" do
221
+ @document.count.should == 2
222
+ end
223
+
224
+ should "should return an array of doc instances" do
225
+ @doc_instances.map do |doc_instance|
226
+ doc_instance.should be_instance_of(@document)
227
+ end
228
+ end
229
+
230
+ should "update the documents" do
231
+ @document.find(@doc1.id).age.should == 30
232
+ @document.find(@doc2.id).age.should == 30
233
+ end
234
+ end
235
+
236
+ should "raise error when updating multiple documents if not a hash" do
237
+ lambda { @document.update([1, 2]) }.should raise_error(ArgumentError)
238
+ end
239
+
240
+ context "Finding documents" do
241
+ setup do
242
+ @doc1 = @document.create({:fname => 'John', :lname => 'Nunemaker', :age => '27'})
243
+ @doc2 = @document.create({:fname => 'Steve', :lname => 'Smith', :age => '28'})
244
+ @doc3 = @document.create({:fname => 'Steph', :lname => 'Nunemaker', :age => '26'})
245
+ end
246
+
247
+ should "raise document not found if nothing provided" do
248
+ lambda { @document.find }.should raise_error(MongoMapper::DocumentNotFound)
249
+ end
250
+
251
+ context "with a single id" do
252
+ should "work" do
253
+ @document.find(@doc1.id).should == @doc1
254
+ end
255
+
256
+ should "raise error if document not found" do
257
+ lambda { @document.find(1) }.should raise_error(MongoMapper::DocumentNotFound)
258
+ end
259
+ end
260
+
261
+ context "with multiple id's" do
262
+ should "work as arguments" do
263
+ @document.find(@doc1.id, @doc2.id).should == [@doc1, @doc2]
264
+ end
265
+
266
+ should "work as array" do
267
+ @document.find([@doc1.id, @doc2.id]).should == [@doc1, @doc2]
268
+ end
269
+ end
270
+
271
+ context "with :all" do
272
+ should "find all documents" do
273
+ @document.find(:all).should == [@doc1, @doc2, @doc3]
274
+ end
275
+
276
+ should "be able to add conditions" do
277
+ @document.find(:all, :conditions => {:fname => 'John'}).should == [@doc1]
278
+ end
279
+ end
280
+
281
+ context "with #all" do
282
+ should "find all documents based on criteria" do
283
+ @document.all.should == [@doc1, @doc2, @doc3]
284
+ @document.all(:conditions => {:lname => 'Nunemaker'}).should == [@doc1, @doc3]
285
+ end
286
+ end
287
+
288
+ context "with :first" do
289
+ should "find first document" do
290
+ @document.find(:first).should == @doc1
291
+ end
292
+ end
293
+
294
+ context "with #first" do
295
+ should "find first document based on criteria" do
296
+ @document.first.should == @doc1
297
+ @document.first(:conditions => {:age => 28}).should == @doc2
298
+ end
299
+ end
300
+
301
+ context "with :last" do
302
+ should "find last document" do
303
+ @document.find(:last).should == @doc3
304
+ end
305
+ end
306
+
307
+ context "with #last" do
308
+ should "find last document based on criteria" do
309
+ @document.last.should == @doc3
310
+ @document.last(:conditions => {:age => 28}).should == @doc2
311
+ end
312
+ end
313
+ end # finding documents
314
+
315
+ context "Finding document by id" do
316
+ setup do
317
+ @doc1 = @document.create({:fname => 'John', :lname => 'Nunemaker', :age => '27'})
318
+ @doc2 = @document.create({:fname => 'Steve', :lname => 'Smith', :age => '28'})
319
+ end
320
+
321
+ should "be able to find by id" do
322
+ @document.find_by_id(@doc1.id).should == @doc1
323
+ @document.find_by_id(@doc2.id).should == @doc2
324
+ end
325
+
326
+ should "return nil if document not found" do
327
+ @document.find_by_id(1234).should be(nil)
328
+ end
329
+ end
330
+
331
+ context "Deleting a document" do
332
+ setup do
333
+ @doc1 = @document.create({:fname => 'John', :lname => 'Nunemaker', :age => '27'})
334
+ @doc2 = @document.create({:fname => 'Steve', :lname => 'Smith', :age => '28'})
335
+ @document.delete(@doc1.id)
336
+ end
337
+
338
+ should "remove document from collection" do
339
+ @document.count.should == 1
340
+ end
341
+
342
+ should "not remove other documents" do
343
+ @document.find(@doc2.id).should_not be(nil)
344
+ end
345
+ end
346
+
347
+ context "Deleting multiple documents" do
348
+ should "work with multiple arguments" do
349
+ @doc1 = @document.create({:fname => 'John', :lname => 'Nunemaker', :age => '27'})
350
+ @doc2 = @document.create({:fname => 'Steve', :lname => 'Smith', :age => '28'})
351
+ @doc3 = @document.create({:fname => 'Steph', :lname => 'Nunemaker', :age => '26'})
352
+ @document.delete(@doc1.id, @doc2.id)
353
+
354
+ @document.count.should == 1
355
+ end
356
+
357
+ should "work with array as argument" do
358
+ @doc1 = @document.create({:fname => 'John', :lname => 'Nunemaker', :age => '27'})
359
+ @doc2 = @document.create({:fname => 'Steve', :lname => 'Smith', :age => '28'})
360
+ @doc3 = @document.create({:fname => 'Steph', :lname => 'Nunemaker', :age => '26'})
361
+ @document.delete([@doc1.id, @doc2.id])
362
+
363
+ @document.count.should == 1
364
+ end
365
+ end
366
+
367
+ context "Deleting all documents" do
368
+ setup do
369
+ @doc1 = @document.create({:fname => 'John', :lname => 'Nunemaker', :age => '27'})
370
+ @doc2 = @document.create({:fname => 'Steve', :lname => 'Smith', :age => '28'})
371
+ @doc3 = @document.create({:fname => 'Steph', :lname => 'Nunemaker', :age => '26'})
372
+ end
373
+
374
+ should "remove all documents when given no conditions" do
375
+ @document.delete_all
376
+ @document.count.should == 0
377
+ end
378
+
379
+ should "only remove matching documents when given conditions" do
380
+ @document.delete_all({:fname => 'John'})
381
+ @document.count.should == 2
382
+ end
383
+ end
384
+
385
+ context "Destroying a document" do
386
+ setup do
387
+ @doc1 = @document.create({:fname => 'John', :lname => 'Nunemaker', :age => '27'})
388
+ @doc2 = @document.create({:fname => 'Steve', :lname => 'Smith', :age => '28'})
389
+ @document.destroy(@doc1.id)
390
+ end
391
+
392
+ should "remove document from collection" do
393
+ @document.count.should == 1
394
+ end
395
+
396
+ should "not remove other documents" do
397
+ @document.find(@doc2.id).should_not be(nil)
398
+ end
399
+ end
400
+
401
+ context "Destroying multiple documents" do
402
+ should "work with multiple arguments" do
403
+ @doc1 = @document.create({:fname => 'John', :lname => 'Nunemaker', :age => '27'})
404
+ @doc2 = @document.create({:fname => 'Steve', :lname => 'Smith', :age => '28'})
405
+ @doc3 = @document.create({:fname => 'Steph', :lname => 'Nunemaker', :age => '26'})
406
+ @document.destroy(@doc1.id, @doc2.id)
407
+
408
+ @document.count.should == 1
409
+ end
410
+
411
+ should "work with array as argument" do
412
+ @doc1 = @document.create({:fname => 'John', :lname => 'Nunemaker', :age => '27'})
413
+ @doc2 = @document.create({:fname => 'Steve', :lname => 'Smith', :age => '28'})
414
+ @doc3 = @document.create({:fname => 'Steph', :lname => 'Nunemaker', :age => '26'})
415
+ @document.destroy([@doc1.id, @doc2.id])
416
+
417
+ @document.count.should == 1
418
+ end
419
+ end
420
+
421
+ context "Destroying all documents" do
422
+ setup do
423
+ @doc1 = @document.create({:fname => 'John', :lname => 'Nunemaker', :age => '27'})
424
+ @doc2 = @document.create({:fname => 'Steve', :lname => 'Smith', :age => '28'})
425
+ @doc3 = @document.create({:fname => 'Steph', :lname => 'Nunemaker', :age => '26'})
426
+ end
427
+
428
+ should "remove all documents when given no conditions" do
429
+ @document.destroy_all
430
+ @document.count.should == 0
431
+ end
432
+
433
+ should "only remove matching documents when given conditions" do
434
+ @document.destroy_all(:fname => 'John')
435
+ @document.count.should == 2
436
+ @document.destroy_all(:age => 26)
437
+ @document.count.should == 1
438
+ end
439
+ end
440
+
441
+ context "Counting documents in collection" do
442
+ setup do
443
+ @doc1 = @document.create({:fname => 'John', :lname => 'Nunemaker', :age => '27'})
444
+ @doc2 = @document.create({:fname => 'Steve', :lname => 'Smith', :age => '28'})
445
+ @doc3 = @document.create({:fname => 'Steph', :lname => 'Nunemaker', :age => '26'})
446
+ end
447
+
448
+ should "count all with no arguments" do
449
+ @document.count.should == 3
450
+ end
451
+
452
+ should "return 0 if there are no documents in the collection" do
453
+ @document.delete_all
454
+ @document.count.should == 0
455
+ end
456
+
457
+ should "return 0 if the collection does not exist" do
458
+ klass = Class.new do
459
+ include MongoMapper::Document
460
+ collection 'foobarbazwickdoesnotexist'
461
+ end
462
+
463
+ klass.count.should == 0
464
+ end
465
+
466
+ should "return count for matching documents if conditions provided" do
467
+ @document.count(:age => 27).should == 1
468
+ end
469
+ end
470
+
471
+ context "Indexing" do
472
+ setup do
473
+ @document.collection.drop_indexes
474
+ end
475
+
476
+ should "allow creating index for a key" do
477
+ lambda {
478
+ @document.ensure_index :fname
479
+ }.should change { @document.collection.index_information.size }.by(1)
480
+
481
+ index = @document.collection.index_information.last
482
+ index.should_not be_nil
483
+ index[:keys].keys.should == %w(fname)
484
+ end
485
+
486
+ should "allow creating unique index for a key" do
487
+ @document.collection.expects(:create_index).with('fname', true)
488
+ @document.ensure_index :fname, :unique => true
489
+ end
490
+
491
+ should "allow creating index on multiple keys" do
492
+ lambda {
493
+ @document.ensure_index [[:fname, 1], [:lname, -1]]
494
+ }.should change { @document.collection.index_information.size }.by(1)
495
+
496
+ index = @document.collection.index_information.last
497
+ index.should_not be_nil
498
+ index[:keys].keys.should == %w(fname lname)
499
+ end
500
+
501
+ should "work with :index shortcut when defining key" do
502
+ lambda {
503
+ @document.key :father, String, :index => true
504
+ }.should change { @document.collection.index_information.size }.by(1)
505
+
506
+ index = @document.collection.index_information.last
507
+ index.should_not be_nil
508
+ index[:keys].keys.should == %w(father)
509
+ end
510
+ end
511
+
512
+ end # Database operations
513
+
514
+ context "An instance of a document" do
515
+ setup do
516
+ @document = Class.new do
517
+ include MongoMapper::Document
518
+
519
+ key :name, String
520
+ key :age, Integer
521
+ end
522
+ @document.collection.clear
523
+ end
524
+
525
+ should "have access to the class's collection" do
526
+ doc = @document.new
527
+ doc.collection.should == @document.collection
528
+ end
529
+
530
+ should "automatically have an _id key" do
531
+ @document.keys.keys.should include('_id')
532
+ end
533
+
534
+ should "automatically have a created_at key" do
535
+ @document.keys.keys.should include('created_at')
536
+ end
537
+
538
+ should "automatically have an updated_at key" do
539
+ @document.keys.keys.should include('updated_at')
540
+ end
541
+
542
+ should "use default values if defined for keys" do
543
+ @document.key :active, Boolean, :default => true
544
+
545
+ @document.new.active.should be_true
546
+ @document.new(:active => false).active.should be_false
547
+ end
548
+
549
+ context "new?" do
550
+ should "be true if no id" do
551
+ @document.new.new?.should be(true)
552
+ end
553
+
554
+ should "be true if has id but id not in database" do
555
+ @document.new('_id' => 1).new?.should be(true)
556
+ end
557
+
558
+ should "be false if has id and id is in database" do
559
+ doc = @document.create(:name => 'John Nunemaker', :age => 27)
560
+ doc.new?.should be(false)
561
+ end
562
+ end
563
+
564
+ context "when initialized" do
565
+ should "accept a hash that sets keys and values" do
566
+ doc = @document.new(:name => 'John', :age => 23)
567
+ doc.attributes.should == {'name' => 'John', 'age' => 23}
568
+ end
569
+
570
+ should "silently reject keys that have not been defined" do
571
+ doc = @document.new(:foobar => 'baz')
572
+ doc.attributes.should == {}
573
+ end
574
+ end
575
+
576
+ context "mass assigning keys" do
577
+ should "update values for keys provided" do
578
+ doc = @document.new(:name => 'foobar', :age => 10)
579
+ doc.attributes = {:name => 'new value', :age => 5}
580
+ doc.attributes[:name].should == 'new value'
581
+ doc.attributes[:age].should == 5
582
+ end
583
+
584
+ should "not update values for keys that were not provided" do
585
+ doc = @document.new(:name => 'foobar', :age => 10)
586
+ doc.attributes = {:name => 'new value'}
587
+ doc.attributes[:name].should == 'new value'
588
+ doc.attributes[:age].should == 10
589
+ end
590
+
591
+ should "ignore keys that do not exist" do
592
+ doc = @document.new(:name => 'foobar', :age => 10)
593
+ doc.attributes = {:name => 'new value', :foobar => 'baz'}
594
+ doc.attributes[:name].should == 'new value'
595
+ doc.attributes[:foobar].should be(nil)
596
+ end
597
+
598
+ should "typecast key values" do
599
+ doc = @document.new(:name => 1234, :age => '21')
600
+ doc.name.should == '1234'
601
+ doc.age.should == 21
602
+ end
603
+ end
604
+
605
+ context "requesting keys" do
606
+ should "default to empty hash" do
607
+ doc = @document.new
608
+ doc.attributes.should == {}
609
+ end
610
+
611
+ should "return all keys that aren't nil" do
612
+ doc = @document.new(:name => 'string', :age => nil)
613
+ doc.attributes.should == {'name' => 'string'}
614
+ end
615
+ end
616
+
617
+ context "key shorcuts" do
618
+ should "be able to read key with []" do
619
+ doc = @document.new(:name => 'string')
620
+ doc[:name].should == 'string'
621
+ end
622
+
623
+ should "be able to write key value with []=" do
624
+ doc = @document.new
625
+ doc[:name] = 'string'
626
+ doc[:name].should == 'string'
627
+ end
628
+ end
629
+
630
+ context "indifferent access" do
631
+ should "be enabled for keys" do
632
+ doc = @document.new(:name => 'string')
633
+ doc.attributes[:name].should == 'string'
634
+ doc.attributes['name'].should == 'string'
635
+ end
636
+ end
637
+
638
+ context "reading an attribute" do
639
+ should "work for defined keys" do
640
+ doc = @document.new(:name => 'string')
641
+ doc.name.should == 'string'
642
+ end
643
+
644
+ should "raise no method error for undefined keys" do
645
+ doc = @document.new
646
+ lambda { doc.fart }.should raise_error(NoMethodError)
647
+ end
648
+
649
+ should "know if reader defined" do
650
+ doc = @document.new
651
+ doc.reader?('name').should be(true)
652
+ doc.reader?(:name).should be(true)
653
+ doc.reader?('age').should be(true)
654
+ doc.reader?(:age).should be(true)
655
+ doc.reader?('foobar').should be(false)
656
+ doc.reader?(:foobar).should be(false)
657
+ end
658
+
659
+ should "be accessible for use in the model" do
660
+ @document.class_eval do
661
+ def name_and_age
662
+ "#{read_attribute(:name)} (#{read_attribute(:age)})"
663
+ end
664
+ end
665
+
666
+ doc = @document.new(:name => 'John', :age => 27)
667
+ doc.name_and_age.should == 'John (27)'
668
+ end
669
+ end
670
+
671
+ context "reading an attribute before typcasting" do
672
+ should "work for defined keys" do
673
+ doc = @document.new(:name => 12)
674
+ doc.name_before_typecast.should == 12
675
+ end
676
+
677
+ should "raise no method error for undefined keys" do
678
+ doc = @document.new
679
+ lambda { doc.foo_before_typecast }.should raise_error(NoMethodError)
680
+ end
681
+
682
+ should "be accessible for use in a document" do
683
+ @document.class_eval do
684
+ def untypcasted_name
685
+ read_attribute_before_typecast(:name)
686
+ end
687
+ end
688
+
689
+ doc = @document.new(:name => 12)
690
+ doc.name.should == '12'
691
+ doc.untypcasted_name.should == 12
692
+ end
693
+ end
694
+
695
+ context "writing an attribute" do
696
+ should "work for defined keys" do
697
+ doc = @document.new
698
+ doc.name = 'John'
699
+ doc.name.should == 'John'
700
+ end
701
+
702
+ should "raise no method error for undefined keys" do
703
+ doc = @document.new
704
+ lambda { doc.fart = 'poof!' }.should raise_error(NoMethodError)
705
+ end
706
+
707
+ should "typecast value" do
708
+ doc = @document.new
709
+ doc.name = 1234
710
+ doc.name.should == '1234'
711
+ doc.age = '21'
712
+ doc.age.should == 21
713
+ end
714
+
715
+ should "know if writer defined" do
716
+ doc = @document.new
717
+ doc.writer?('name').should be(true)
718
+ doc.writer?('name=').should be(true)
719
+ doc.writer?(:name).should be(true)
720
+ doc.writer?('age').should be(true)
721
+ doc.writer?('age=').should be(true)
722
+ doc.writer?(:age).should be(true)
723
+ doc.writer?('foobar').should be(false)
724
+ doc.writer?('foobar=').should be(false)
725
+ doc.writer?(:foobar).should be(false)
726
+ end
727
+
728
+ should "be accessible for use in the model" do
729
+ @document.class_eval do
730
+ def name_and_age=(new_value)
731
+ new_value.match(/([^\(\s]+) \((.*)\)/)
732
+ write_attribute :name, $1
733
+ write_attribute :age, $2
734
+ end
735
+ end
736
+
737
+ doc = @document.new
738
+ doc.name_and_age = 'Frank (62)'
739
+ doc.name.should == 'Frank'
740
+ doc.age.should == 62
741
+ end
742
+ end # writing an attribute
743
+
744
+ context "respond_to?" do
745
+ setup do
746
+ @doc = @document.new
747
+ end
748
+
749
+ should "work for readers" do
750
+ @doc.respond_to?(:name).should be_true
751
+ @doc.respond_to?('name').should be_true
752
+ end
753
+
754
+ should "work for writers" do
755
+ @doc.respond_to?(:name=).should be_true
756
+ @doc.respond_to?('name=').should be_true
757
+ end
758
+
759
+ should "work for readers before typecast" do
760
+ @doc.respond_to?(:name_before_typecast).should be_true
761
+ @doc.respond_to?('name_before_typecast').should be_true
762
+ end
763
+ end
764
+
765
+ context "equality" do
766
+ should "be equal if id and class are the same" do
767
+ (@document.new('_id' => 1) == @document.new('_id' => 1)).should be(true)
768
+ end
769
+
770
+ should "not be equal if class same but id different" do
771
+ (@document.new('_id' => 1) == @document.new('_id' => 2)).should be(false)
772
+ end
773
+
774
+ should "not be equal if id same but class different" do
775
+ @another_document = Class.new do
776
+ include MongoMapper::Document
777
+ end
778
+
779
+ (@document.new('_id' => 1) == @another_document.new('_id' => 1)).should be(false)
780
+ end
781
+ end
782
+
783
+ context "Saving a new document" do
784
+ setup do
785
+ @doc = @document.new(:name => 'John Nunemaker', :age => '27')
786
+ @doc.save
787
+ end
788
+
789
+ should "insert document into the collection" do
790
+ @document.count.should == 1
791
+ end
792
+
793
+ should "assign an id for the document" do
794
+ @doc.id.should_not be(nil)
795
+ @doc.id.size.should == 24
796
+ end
797
+
798
+ should "save attributes" do
799
+ @doc.name.should == 'John Nunemaker'
800
+ @doc.age.should == 27
801
+ end
802
+
803
+ should "update attributes in the database" do
804
+ from_db = @document.find(@doc.id)
805
+ from_db.should == @doc
806
+ from_db.name.should == 'John Nunemaker'
807
+ from_db.age.should == 27
808
+ end
809
+ end
810
+
811
+ context "Saving an existing document" do
812
+ setup do
813
+ @doc = @document.create(:name => 'John Nunemaker', :age => '27')
814
+ @doc.name = 'John Doe'
815
+ @doc.age = 30
816
+ @doc.save
817
+ end
818
+
819
+ should "not insert document into collection" do
820
+ @document.count.should == 1
821
+ end
822
+
823
+ should "update attributes" do
824
+ @doc.name.should == 'John Doe'
825
+ @doc.age.should == 30
826
+ end
827
+
828
+ should "update attributes in the database" do
829
+ from_db = @document.find(@doc.id)
830
+ from_db.name.should == 'John Doe'
831
+ from_db.age.should == 30
832
+ end
833
+ end
834
+
835
+ context "Calling update attributes on a new document" do
836
+ setup do
837
+ @doc = @document.new(:name => 'John Nunemaker', :age => '27')
838
+ @doc.update_attributes(:name => 'John Doe', :age => 30)
839
+ end
840
+
841
+ should "insert document into the collection" do
842
+ @document.count.should == 1
843
+ end
844
+
845
+ should "assign an id for the document" do
846
+ @doc.id.should_not be(nil)
847
+ @doc.id.size.should == 24
848
+ end
849
+
850
+ should "save attributes" do
851
+ @doc.name.should == 'John Doe'
852
+ @doc.age.should == 30
853
+ end
854
+
855
+ should "update attributes in the database" do
856
+ from_db = @document.find(@doc.id)
857
+ from_db.should == @doc
858
+ from_db.name.should == 'John Doe'
859
+ from_db.age.should == 30
860
+ end
861
+ end
862
+
863
+ context "Updating an existing document using update attributes" do
864
+ setup do
865
+ @doc = @document.create(:name => 'John Nunemaker', :age => '27')
866
+ @doc.update_attributes(:name => 'John Doe', :age => 30)
867
+ end
868
+
869
+ should "not insert document into collection" do
870
+ @document.count.should == 1
871
+ end
872
+
873
+ should "update attributes" do
874
+ @doc.name.should == 'John Doe'
875
+ @doc.age.should == 30
876
+ end
877
+
878
+ should "update attributes in the database" do
879
+ from_db = @document.find(@doc.id)
880
+ from_db.name.should == 'John Doe'
881
+ from_db.age.should == 30
882
+ end
883
+ end
884
+
885
+ context "Destroying a document that exists" do
886
+ setup do
887
+ @doc = @document.create(:name => 'John Nunemaker', :age => '27')
888
+ @doc.destroy
889
+ end
890
+
891
+ should "remove the document from the collection" do
892
+ @document.count.should == 0
893
+ end
894
+
895
+ should "raise error if assignment is attempted" do
896
+ lambda { @doc.name = 'Foo' }.should raise_error(TypeError)
897
+ end
898
+ end
899
+
900
+ context "Destroying a document that is a new" do
901
+ setup do
902
+ setup do
903
+ @doc = @document.new(:name => 'John Nunemaker', :age => '27')
904
+ @doc.destroy
905
+ end
906
+
907
+ should "not affect collection count" do
908
+ @document.collection.count.should == 0
909
+ end
910
+
911
+ should "raise error if assignment is attempted" do
912
+ lambda { @doc.name = 'Foo' }.should raise_error(TypeError)
913
+ end
914
+ end
915
+ end
916
+
917
+ context "timestamping" do
918
+ should "set created_at and updated_at on create" do
919
+ doc = @document.new(:name => 'John Nunemaker', :age => 27)
920
+ doc.created_at.should be(nil)
921
+ doc.updated_at.should be(nil)
922
+ doc.save
923
+ doc.created_at.should_not be(nil)
924
+ doc.updated_at.should_not be(nil)
925
+ end
926
+
927
+ should "set updated_at on update but leave created_at alone" do
928
+ doc = @document.create(:name => 'John Nunemaker', :age => 27)
929
+ old_created_at = doc.created_at
930
+ old_updated_at = doc.updated_at
931
+ doc.name = 'John Doe'
932
+ doc.save
933
+ doc.created_at.should == old_created_at
934
+ doc.updated_at.should_not == old_updated_at
935
+ end
936
+ end
937
+ end # instance of a document
938
+ end # DocumentTest