ramsingla-mongomapper 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.
Files changed (42) hide show
  1. data/.gitignore +7 -0
  2. data/History +30 -0
  3. data/LICENSE +20 -0
  4. data/README.rdoc +39 -0
  5. data/Rakefile +71 -0
  6. data/VERSION +1 -0
  7. data/lib/mongomapper.rb +60 -0
  8. data/lib/mongomapper/associations.rb +69 -0
  9. data/lib/mongomapper/associations/array_proxy.rb +6 -0
  10. data/lib/mongomapper/associations/base.rb +50 -0
  11. data/lib/mongomapper/associations/belongs_to_proxy.rb +26 -0
  12. data/lib/mongomapper/associations/has_many_embedded_proxy.rb +19 -0
  13. data/lib/mongomapper/associations/has_many_proxy.rb +28 -0
  14. data/lib/mongomapper/associations/polymorphic_belongs_to_proxy.rb +31 -0
  15. data/lib/mongomapper/associations/proxy.rb +60 -0
  16. data/lib/mongomapper/callbacks.rb +106 -0
  17. data/lib/mongomapper/document.rb +263 -0
  18. data/lib/mongomapper/embedded_document.rb +295 -0
  19. data/lib/mongomapper/finder_options.rb +81 -0
  20. data/lib/mongomapper/key.rb +82 -0
  21. data/lib/mongomapper/observing.rb +50 -0
  22. data/lib/mongomapper/pagination.rb +52 -0
  23. data/lib/mongomapper/rails_compatibility.rb +23 -0
  24. data/lib/mongomapper/save_with_validation.rb +19 -0
  25. data/lib/mongomapper/serialization.rb +55 -0
  26. data/lib/mongomapper/serializers/json_serializer.rb +77 -0
  27. data/lib/mongomapper/validations.rb +47 -0
  28. data/mongomapper.gemspec +105 -0
  29. data/test/serializers/test_json_serializer.rb +104 -0
  30. data/test/test_associations.rb +211 -0
  31. data/test/test_callbacks.rb +84 -0
  32. data/test/test_document.rb +995 -0
  33. data/test/test_embedded_document.rb +253 -0
  34. data/test/test_finder_options.rb +148 -0
  35. data/test/test_helper.rb +62 -0
  36. data/test/test_key.rb +200 -0
  37. data/test/test_mongomapper.rb +28 -0
  38. data/test/test_observing.rb +101 -0
  39. data/test/test_rails_compatibility.rb +29 -0
  40. data/test/test_serializations.rb +54 -0
  41. data/test/test_validations.rb +409 -0
  42. metadata +156 -0
@@ -0,0 +1,200 @@
1
+ require 'test_helper'
2
+
3
+ class Address
4
+ include MongoMapper::EmbeddedDocument
5
+
6
+ key :address, String
7
+ key :city, String
8
+ key :state, String
9
+ key :zip, Integer
10
+ end
11
+
12
+ class KeyTest < Test::Unit::TestCase
13
+ include MongoMapper
14
+
15
+ context "The Key Class" do
16
+ should "have the native types defined" do
17
+ Key::NativeTypes.should == [String, Float, Time, Integer, Boolean, Array, Hash, Ref]
18
+ end
19
+ end
20
+
21
+ context "Initializing a new key" do
22
+ should "allow setting the name" do
23
+ Key.new(:foo, String).name.should == 'foo'
24
+ end
25
+
26
+ should "allow setting the type" do
27
+ Key.new(:foo, Integer).type.should be(Integer)
28
+ end
29
+
30
+ should "allow setting options" do
31
+ Key.new(:foo, Integer, :required => true).options[:required].should be(true)
32
+ end
33
+
34
+ should "symbolize option keys" do
35
+ Key.new(:foo, Integer, 'required' => true).options[:required].should be(true)
36
+ end
37
+ end
38
+
39
+ context "A key" do
40
+ should "be equal to another key with same name and type" do
41
+ Key.new(:name, String).should == Key.new(:name, String)
42
+ end
43
+
44
+ should "not be equal to another key with different name" do
45
+ Key.new(:name, String).should_not == Key.new(:foo, String)
46
+ end
47
+
48
+ should "not be equal to another key with different type" do
49
+ Key.new(:name, String).should_not == Key.new(:name, Integer)
50
+ end
51
+
52
+ should "know if it is native" do
53
+ Key.new(:name, String).native?.should be_true
54
+ end
55
+
56
+ should "know if it is not native" do
57
+ klass = Class.new
58
+ Key.new(:name, klass).native?.should be_false
59
+ end
60
+
61
+ should "know if it is a embedded_document" do
62
+ klass = Class.new do
63
+ include MongoMapper::EmbeddedDocument
64
+ end
65
+ Key.new(:name, klass).embedded_document?.should be_true
66
+ end
67
+
68
+ should "know if it is not a embedded_document" do
69
+ Key.new(:name, String).embedded_document?.should be_false
70
+ end
71
+ end
72
+
73
+ context "setting a value" do
74
+ should "correctly typecast Strings" do
75
+ key = Key.new(:foo, String)
76
+ [21, '21'].each do |a|
77
+ key.set(a).should == '21'
78
+ end
79
+ end
80
+
81
+ should "correctly typecast Integers" do
82
+ key = Key.new(:foo, Integer)
83
+ [21, 21.0, '21'].each do |a|
84
+ key.set(a).should == 21
85
+ end
86
+ end
87
+
88
+ should "correctly typecast Floats" do
89
+ key = Key.new(:foo, Float)
90
+ [21, 21.0, '21'].each do |a|
91
+ key.set(a).should == 21.0
92
+ end
93
+ end
94
+
95
+ should "correctly typecast Times" do
96
+ key = Key.new(:foo, Time)
97
+ key.set('2000-01-01 01:01:01.123456').should == Time.local(2000, 1, 1, 1, 1, 1, 123456)
98
+ end
99
+
100
+ should_eventually "correctly typecast Dates" do
101
+ key = Key.new(:foo, Date)
102
+ key.set('2000-01-01').should == Date.new(2000, 1, 1)
103
+ end
104
+
105
+ should "correctly typecast Boolean" do
106
+ key = Key.new(:foo, Boolean)
107
+ ['false', false, 'f', '0', 0].each do |b|
108
+ key.set(b).should == false
109
+ end
110
+
111
+ ['true', true, 't', '1', 1].each do |b|
112
+ key.set(b).should == true
113
+ end
114
+ end
115
+
116
+ should "correctly typecast Array" do
117
+ key = Key.new(:foo, Array)
118
+ key.set([1,2,3,4]).should == [1,2,3,4]
119
+ key.set({'1' => '2', '3' => '4'}).should == [['1', '2'], ['3', '4']]
120
+ key.set('1').should == ['1']
121
+ end
122
+
123
+ should "correctly typecast Hash using indifferent access" do
124
+ key = Key.new(:foo, Hash)
125
+ key.set(:foo => 'bar')[:foo].should == 'bar'
126
+ key.set(:foo => 'bar')['foo'].should == 'bar'
127
+ key.set(:foo => {:bar => 'baz'})[:foo][:bar].should == 'baz'
128
+ key.set(:foo => {:bar => 'baz'})['foo']['bar'].should == 'baz'
129
+ end
130
+ end
131
+
132
+ context "getting a value" do
133
+ should "work" do
134
+ key = Key.new(:foo, String)
135
+ key.get('bar').should == 'bar'
136
+ end
137
+
138
+ context "for a key with a default value set" do
139
+ setup do
140
+ @key = Key.new(:foo, String, :default => 'baz')
141
+ end
142
+
143
+ should "return default value if value nil" do
144
+ @key.get(nil).should == 'baz'
145
+ end
146
+
147
+ should "return value if not blank" do
148
+ @key.get('foobar').should == 'foobar'
149
+ end
150
+ end
151
+
152
+ context "for a boolean key" do
153
+ should "allow setting default to false" do
154
+ Key.new(:active, Boolean, :default => false).get(nil).should be_false
155
+ end
156
+
157
+ should "allow setting default to true" do
158
+ Key.new(:active, Boolean, :default => true).get(nil).should be_true
159
+ end
160
+ end
161
+
162
+ context "for an array" do
163
+ should "return array" do
164
+ key = Key.new(:foo, Array)
165
+ key.get([1,2]).should == [1,2]
166
+ end
167
+
168
+ should "default to empty array" do
169
+ key = Key.new(:foo, Array)
170
+ key.get(nil).should == []
171
+ end
172
+ end
173
+
174
+ context "for a hash" do
175
+ should "default to empty hash" do
176
+ key = Key.new(:foo, Hash)
177
+ key.get(nil).should == {}
178
+ end
179
+
180
+ should "use hash with indifferent access" do
181
+ key = Key.new(:foo, Hash)
182
+ key.get({:foo => 'bar'})['foo'].should == 'bar'
183
+ key.get({:foo => 'bar'})[:foo].should == 'bar'
184
+ end
185
+ end
186
+
187
+ context "for a embedded_document" do
188
+ should "default to nil" do
189
+ key = Key.new(:foo, Address)
190
+ key.get(nil).should be_nil
191
+ end
192
+
193
+ should "return instance if instance" do
194
+ address = Address.new(:city => 'South Bend', :state => 'IN', :zip => 46544)
195
+ key = Key.new(:foo, Address)
196
+ key.get(address).should == address
197
+ end
198
+ end
199
+ end
200
+ end # KeyTest
@@ -0,0 +1,28 @@
1
+ require 'test_helper'
2
+
3
+ class Address; end
4
+
5
+ class MongoMapperTest < Test::Unit::TestCase
6
+ should "be able to write and read connection" do
7
+ conn = XGen::Mongo::Driver::Mongo.new
8
+ MongoMapper.connection = conn
9
+ MongoMapper.connection.should == conn
10
+ end
11
+
12
+ should "default connection to new mongo ruby driver" do
13
+ MongoMapper.connection = nil
14
+ MongoMapper.connection.should be_instance_of(XGen::Mongo::Driver::Mongo)
15
+ end
16
+
17
+ should "be able to write and read default database" do
18
+ MongoMapper.database = DefaultDatabase
19
+ MongoMapper.database.should be_instance_of(XGen::Mongo::Driver::DB)
20
+ MongoMapper.database.name.should == DefaultDatabase
21
+ end
22
+
23
+ should "have document not found error" do
24
+ lambda {
25
+ MongoMapper::DocumentNotFound
26
+ }.should_not raise_error
27
+ end
28
+ end
@@ -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
@@ -0,0 +1,29 @@
1
+ require 'test_helper'
2
+
3
+ class TestRailsCompatibility < Test::Unit::TestCase
4
+ def setup
5
+ @document = Class.new do
6
+ include MongoMapper::Document
7
+ end
8
+ end
9
+
10
+ should "have to_param that returns id" do
11
+ instance = @document.create('_id' => '1234')
12
+ instance.to_param.should == '1234'
13
+ end
14
+
15
+ should "alias new to new_record?" do
16
+ instance = @document.new
17
+ instance.new_record?.should == instance.new?
18
+ end
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
+
25
+ should "have column names" do
26
+ @document.key :fname, String
27
+ @document.column_names.sort.should == ['_id', 'created_at', 'fname', 'updated_at']
28
+ end
29
+ end
@@ -0,0 +1,54 @@
1
+ require 'test_helper'
2
+
3
+ class SerializationTest < Test::Unit::TestCase
4
+ def setup
5
+ @document = Class.new do
6
+ include MongoMapper::EmbeddedDocument
7
+ key :name, String
8
+ key :age, Integer
9
+ key :awesome, Boolean
10
+ key :preferences, Hash
11
+ key :created_at, Time
12
+ end
13
+
14
+ @instance = @document.new(
15
+ :name => 'John Doe',
16
+ :age => 25,
17
+ :awesome => true,
18
+ :preferences => {:language => 'Ruby'},
19
+ :created_at => Time.now.change(:usec => 0)
20
+ )
21
+ end
22
+
23
+ # [:xml, :json].each do |format|
24
+ [:json].each do |format|
25
+ context format do
26
+ should "be reversable" do
27
+ serialized = @instance.send("to_#{format}")
28
+ unserialized = @document.new.send("from_#{format}", serialized)
29
+
30
+ assert_equal @instance, unserialized
31
+ end
32
+
33
+ should "allow attribute only filtering" do
34
+ serialized = @instance.send("to_#{format}", :only => [ :age, :name ])
35
+ unserialized = @document.new.send("from_#{format}", serialized)
36
+
37
+ assert_equal @instance.name, unserialized.name
38
+ assert_equal @instance.age, unserialized.age
39
+ assert_nil unserialized.awesome
40
+ assert_nil unserialized.created_at
41
+ end
42
+
43
+ should "allow attribute except filtering" do
44
+ serialized = @instance.send("to_#{format}", :except => [ :age, :name ])
45
+ unserialized = @document.new.send("from_#{format}", serialized)
46
+
47
+ assert_nil unserialized.name
48
+ assert_nil unserialized.age
49
+ assert_equal @instance.awesome, unserialized.awesome
50
+ end
51
+
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,409 @@
1
+ require 'test_helper'
2
+
3
+ class ValidationsTest < Test::Unit::TestCase
4
+ context "Validations" do
5
+ setup do
6
+ @document = Class.new do
7
+ include MongoMapper::Document
8
+ end
9
+ end
10
+
11
+ context "Validating acceptance of" do
12
+ should "work with validates_acceptance_of macro" do
13
+ @document.key :terms, String
14
+ @document.validates_acceptance_of :terms
15
+ doc = @document.new(:terms => '')
16
+ doc.should have_error_on(:terms)
17
+ doc.terms = '1'
18
+ doc.should_not have_error_on(:terms)
19
+ end
20
+ end
21
+
22
+ context "validating confirmation of" do
23
+ should "work with validates_confirmation_of macro" do
24
+ @document.key :password, String
25
+ @document.validates_confirmation_of :password
26
+ doc = @document.new
27
+ doc.password = 'foobar'
28
+ doc.should have_error_on(:password)
29
+ doc.password_confirmation = 'foobar'
30
+ doc.should_not have_error_on(:password)
31
+ end
32
+ end
33
+
34
+ context "validating format of" do
35
+ should "work with validates_format_of macro" do
36
+ @document.key :name, String
37
+ @document.validates_format_of :name, :with => /.+/
38
+ doc = @document.new
39
+ doc.should have_error_on(:name)
40
+ doc.name = 'John'
41
+ doc.should_not have_error_on(:name)
42
+ end
43
+
44
+ should "work with :format shorcut key" do
45
+ @document.key :name, String, :format => /.+/
46
+ doc = @document.new
47
+ doc.should have_error_on(:name)
48
+ doc.name = 'John'
49
+ doc.should_not have_error_on(:name)
50
+ end
51
+ end
52
+
53
+ context "validating length of" do
54
+ should "work with validates_length_of macro" do
55
+ @document.key :name, String
56
+ @document.validates_length_of :name, :minimum => 5
57
+ doc = @document.new
58
+ doc.should have_error_on(:name)
59
+ end
60
+
61
+ context "with :length => integer shortcut" do
62
+ should "set maximum of integer provided" do
63
+ @document.key :name, String, :length => 5
64
+ doc = @document.new
65
+ doc.name = '123456'
66
+ doc.should have_error_on(:name)
67
+ doc.name = '12345'
68
+ doc.should_not have_error_on(:name)
69
+ end
70
+ end
71
+
72
+ context "with :length => range shortcut" do
73
+ setup do
74
+ @document.key :name, String, :length => 5..7
75
+ end
76
+
77
+ should "set minimum of range min" do
78
+ doc = @document.new
79
+ doc.should have_error_on(:name)
80
+ doc.name = '123456'
81
+ doc.should_not have_error_on(:name)
82
+ end
83
+
84
+ should "set maximum of range max" do
85
+ doc = @document.new
86
+ doc.should have_error_on(:name)
87
+ doc.name = '12345678'
88
+ doc.should have_error_on(:name)
89
+ doc.name = '123456'
90
+ doc.should_not have_error_on(:name)
91
+ end
92
+ end
93
+
94
+ context "with :length => hash shortcut" do
95
+ should "pass options through" do
96
+ @document.key :name, String, :length => {:minimum => 2}
97
+ doc = @document.new
98
+ doc.should have_error_on(:name)
99
+ doc.name = '12'
100
+ doc.should_not have_error_on(:name)
101
+ end
102
+ end
103
+ end # validates_length_of
104
+
105
+ context "Validating numericality of" do
106
+ should "work with validates_numericality_of macro" do
107
+ @document.key :age, Integer
108
+ @document.validates_numericality_of :age
109
+ doc = @document.new
110
+ doc.age = 'String'
111
+ doc.should have_error_on(:age)
112
+ doc.age = 23
113
+ doc.should_not have_error_on(:age)
114
+ end
115
+
116
+ context "with :numeric shortcut" do
117
+ should "work with integer or float" do
118
+ @document.key :weight, Float, :numeric => true
119
+ doc = @document.new
120
+ doc.weight = 'String'
121
+ doc.should have_error_on(:weight)
122
+ doc.weight = 23.0
123
+ doc.should_not have_error_on(:weight)
124
+ doc.weight = 23
125
+ doc.should_not have_error_on(:weight)
126
+ end
127
+ end
128
+
129
+ context "with :numeric shortcut on Integer key" do
130
+ should "only work with integers" do
131
+ @document.key :age, Integer, :numeric => true
132
+ doc = @document.new
133
+ doc.age = 'String'
134
+ doc.should have_error_on(:age)
135
+ doc.age = 23.1
136
+ doc.should have_error_on(:age)
137
+ doc.age = 23
138
+ doc.should_not have_error_on(:age)
139
+ end
140
+ end
141
+ end # numericality of
142
+
143
+ context "validating presence of" do
144
+ should "work with validates_presence_of macro" do
145
+ @document.key :name, String
146
+ @document.validates_presence_of :name
147
+ doc = @document.new
148
+ doc.should have_error_on(:name)
149
+ end
150
+
151
+ should "work with :required shortcut on key definition" do
152
+ @document.key :name, String, :required => true
153
+ doc = @document.new
154
+ doc.should have_error_on(:name)
155
+ 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
+
173
+ @document \
174
+ .stubs(:find) \
175
+ .with(:first, :conditions => {:name => 'joe'}, :limit => 1) \
176
+ .returns(doc)
177
+
178
+ doc.name = "joe"
179
+ doc.valid?.should be_true
180
+ doc.should_not have_error_on(:name)
181
+ end
182
+
183
+ should "fail if object name is not unique" do
184
+ doc = @document.new("name" => "joe")
185
+ doc.save.should be_true
186
+
187
+ @document \
188
+ .stubs(:find) \
189
+ .with(:first, :conditions => {:name => 'joe'}, :limit => 1) \
190
+ .returns(doc)
191
+
192
+ doc2 = @document.new("name" => "joe")
193
+ doc2.should have_error_on(:name)
194
+ end
195
+ end
196
+
197
+ context "validates uniqueness of with :unique shortcut" do
198
+ should "work" do
199
+ @document.key :name, String, :unique => true
200
+
201
+ doc = @document.create(:name => 'John')
202
+ doc.should_not have_error_on(:name)
203
+
204
+ @document \
205
+ .stubs(:find) \
206
+ .with(:first, :conditions => {:name => 'John'}, :limit => 1) \
207
+ .returns(doc)
208
+
209
+ second_john = @document.create(:name => 'John')
210
+ second_john.should have_error_on(:name, 'has already been taken')
211
+ end
212
+ end
213
+
214
+ context "validating exclusion of" do
215
+ should "throw error if enumerator not provided" do
216
+ @document.key :action, String
217
+ lambda {
218
+ @document.validates_exclusion_of :action
219
+ }.should raise_error(ArgumentError)
220
+ end
221
+
222
+ should "work with validates_exclusion_of macro" do
223
+ @document.key :action, String
224
+ @document.validates_exclusion_of :action, :within => %w(kick run)
225
+
226
+ doc = @document.new
227
+ doc.should_not have_error_on(:action)
228
+
229
+ doc.action = 'fart'
230
+ doc.should_not have_error_on(:action)
231
+
232
+ doc.action = 'kick'
233
+ doc.should have_error_on(:action, 'is reserved')
234
+ end
235
+
236
+ should "not have error if allow nil is true and value is nil" do
237
+ @document.key :action, String
238
+ @document.validates_exclusion_of :action, :within => %w(kick run), :allow_nil => true
239
+
240
+ doc = @document.new
241
+ doc.should_not have_error_on(:action)
242
+ end
243
+
244
+ should "not have error if allow blank is true and value is blank" do
245
+ @document.key :action, String
246
+ @document.validates_exclusion_of :action, :within => %w(kick run), :allow_nil => true
247
+
248
+ doc = @document.new(:action => '')
249
+ doc.should_not have_error_on(:action)
250
+ end
251
+ end
252
+
253
+ context "validating inclusion of" do
254
+ should "throw error if enumerator not provided" do
255
+ @document.key :action, String
256
+ lambda {
257
+ @document.validates_inclusion_of :action
258
+ }.should raise_error(ArgumentError)
259
+ end
260
+
261
+ should "work with validates_inclusion_of macro" do
262
+ @document.key :action, String
263
+ @document.validates_inclusion_of :action, :within => %w(kick run)
264
+
265
+ doc = @document.new
266
+ doc.should have_error_on(:action, 'is not in the list')
267
+
268
+ doc.action = 'fart'
269
+ doc.should have_error_on(:action, 'is not in the list')
270
+
271
+ doc.action = 'kick'
272
+ doc.should_not have_error_on(:action)
273
+ end
274
+
275
+ should "not have error if allow nil is true and value is nil" do
276
+ @document.key :action, String
277
+ @document.validates_inclusion_of :action, :within => %w(kick run), :allow_nil => true
278
+
279
+ doc = @document.new
280
+ doc.should_not have_error_on(:action)
281
+ end
282
+
283
+ should "not have error if allow blank is true and value is blank" do
284
+ @document.key :action, String
285
+ @document.validates_inclusion_of :action, :within => %w(kick run), :allow_blank => true
286
+
287
+ doc = @document.new(:action => '')
288
+ doc.should_not have_error_on(:action)
289
+ end
290
+ end
291
+ end # Validations
292
+
293
+ context "Saving a new document that is invalid" do
294
+ setup do
295
+ @document = Class.new do
296
+ include MongoMapper::Document
297
+ key :name, String, :required => true
298
+ end
299
+
300
+ @document.collection.clear
301
+ end
302
+
303
+ should "not insert document" do
304
+ doc = @document.new
305
+ doc.save
306
+ @document.count.should == 0
307
+ end
308
+
309
+ should "populate document's errors" do
310
+ doc = @document.new
311
+ doc.errors.size.should == 0
312
+ doc.save
313
+ doc.errors.full_messages.should == ["Name can't be empty"]
314
+ end
315
+ end
316
+
317
+ context "Saving a document that is invalid (destructive)" do
318
+ setup do
319
+ @document = Class.new do
320
+ include MongoMapper::Document
321
+ key :name, String, :required => true
322
+ end
323
+
324
+ @document.collection.clear
325
+ end
326
+
327
+ should "raise error" do
328
+ doc = @document.new
329
+ lambda { doc.save! }.should raise_error(MongoMapper::DocumentNotValid)
330
+ end
331
+ end
332
+
333
+ context "Saving an existing document that is invalid" do
334
+ setup do
335
+ @document = Class.new do
336
+ include MongoMapper::Document
337
+ key :name, String, :required => true
338
+ end
339
+
340
+ @document.collection.clear
341
+ @doc = @document.create(:name => 'John Nunemaker')
342
+ end
343
+
344
+ should "not update document" do
345
+ @doc.name = nil
346
+ @doc.save
347
+ @document.find(@doc.id).name.should == 'John Nunemaker'
348
+ end
349
+
350
+ should "populate document's errors" do
351
+ @doc.name = nil
352
+ @doc.save
353
+ @doc.errors.full_messages.should == ["Name can't be empty"]
354
+ end
355
+ end
356
+
357
+ context "Adding validation errors" do
358
+ setup do
359
+ @document = Class.new do
360
+ include MongoMapper::Document
361
+ key :action, String
362
+ def action_present
363
+ errors.add(:action, 'is invalid') if action.blank?
364
+ end
365
+ end
366
+ end
367
+
368
+ should "work with validate callback" do
369
+ @document.validate :action_present
370
+
371
+ doc = @document.new
372
+ doc.action = nil
373
+ doc.should have_error_on(:action)
374
+
375
+ doc.action = 'kick'
376
+ doc.should_not have_error_on(:action)
377
+ end
378
+
379
+ should "work with validate_on_create callback" do
380
+ @document.validate_on_create :action_present
381
+
382
+ doc = @document.new
383
+ doc.action = nil
384
+ doc.should have_error_on(:action)
385
+
386
+ doc.action = 'kick'
387
+ doc.should_not have_error_on(:action)
388
+ doc.save
389
+
390
+ doc.action = nil
391
+ doc.should_not have_error_on(:action)
392
+ end
393
+
394
+ should "work with validate_on_update callback" do
395
+ @document.validate_on_update :action_present
396
+
397
+ doc = @document.new
398
+ doc.action = nil
399
+ doc.should_not have_error_on(:action)
400
+ doc.save
401
+
402
+ doc.action = nil
403
+ doc.should have_error_on(:action)
404
+
405
+ doc.action = 'kick'
406
+ doc.should_not have_error_on(:action)
407
+ end
408
+ end
409
+ end