strokedb 0.0.2.1 → 0.0.2.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (192) hide show
  1. data/README +18 -20
  2. data/bench.html +4001 -0
  3. data/bin/strokedb +14 -0
  4. data/examples/movies.rb +105 -0
  5. data/examples/movies2.rb +97 -0
  6. data/examples/strokewiki/README +28 -0
  7. data/examples/strokewiki/view/edit.xhtml +27 -0
  8. data/examples/strokewiki/view/new.xhtml +26 -0
  9. data/examples/strokewiki/view/pages.xhtml +27 -0
  10. data/examples/strokewiki/view/show.xhtml +40 -0
  11. data/examples/strokewiki/view/versions.xhtml +25 -0
  12. data/examples/strokewiki/wiki.rb +106 -0
  13. data/examples/todo.rb +92 -0
  14. data/lib/strokedb.rb +85 -0
  15. data/lib/{config → strokedb}/config.rb +14 -9
  16. data/lib/strokedb/console.rb +87 -0
  17. data/lib/strokedb/core_ext.rb +10 -0
  18. data/lib/{util/ext → strokedb/core_ext}/blank.rb +1 -1
  19. data/lib/{util/ext → strokedb/core_ext}/enumerable.rb +0 -0
  20. data/lib/{util/ext → strokedb/core_ext}/fixnum.rb +0 -0
  21. data/lib/strokedb/core_ext/float.rb +4 -0
  22. data/lib/{util/ext → strokedb/core_ext}/hash.rb +0 -0
  23. data/lib/strokedb/core_ext/infinity.rb +33 -0
  24. data/lib/strokedb/core_ext/kernel.rb +41 -0
  25. data/lib/strokedb/core_ext/object.rb +16 -0
  26. data/lib/{util/ext → strokedb/core_ext}/string.rb +28 -1
  27. data/lib/strokedb/core_ext/symbol.rb +13 -0
  28. data/lib/strokedb/data_structures.rb +5 -0
  29. data/lib/strokedb/data_structures/chunked_skiplist.rb +123 -0
  30. data/lib/{data_structures → strokedb/data_structures}/inverted_list.rb +0 -0
  31. data/lib/{data_structures → strokedb/data_structures}/point_query.rb +0 -0
  32. data/lib/strokedb/data_structures/simple_skiplist.rb +350 -0
  33. data/lib/{data_structures → strokedb/data_structures}/skiplist.rb +1 -1
  34. data/lib/{document → strokedb}/document.rb +180 -71
  35. data/lib/{document → strokedb/document}/callback.rb +0 -0
  36. data/lib/{document → strokedb/document}/delete.rb +2 -2
  37. data/lib/strokedb/document/dsl.rb +4 -0
  38. data/lib/{document → strokedb/document/dsl}/associations.rb +0 -0
  39. data/lib/{document → strokedb/document/dsl}/coercions.rb +0 -0
  40. data/lib/strokedb/document/dsl/meta_dsl.rb +7 -0
  41. data/lib/{document → strokedb/document/dsl}/validations.rb +26 -21
  42. data/lib/{document → strokedb/document/dsl}/virtualize.rb +0 -0
  43. data/lib/{document → strokedb/document}/meta.rb +92 -29
  44. data/lib/{document → strokedb/document}/slot.rb +17 -5
  45. data/lib/{document → strokedb/document}/util.rb +0 -0
  46. data/lib/{document → strokedb/document}/versions.rb +2 -2
  47. data/lib/strokedb/index.rb +2 -0
  48. data/lib/strokedb/nsurl.rb +24 -0
  49. data/lib/strokedb/store.rb +149 -0
  50. data/lib/strokedb/stores.rb +6 -0
  51. data/lib/{stores → strokedb/stores}/chainable_storage.rb +20 -14
  52. data/lib/strokedb/stores/file_storage.rb +118 -0
  53. data/lib/{stores/inverted_list_index → strokedb/stores}/inverted_list_file_storage.rb +50 -0
  54. data/lib/strokedb/stores/memory_storage.rb +80 -0
  55. data/lib/{stores → strokedb/stores}/remote_store.rb +10 -4
  56. data/lib/strokedb/sync.rb +4 -0
  57. data/lib/{sync → strokedb/sync}/chain_sync.rb +0 -0
  58. data/lib/{sync → strokedb/sync}/diff.rb +12 -1
  59. data/lib/{sync/stroke_diff → strokedb/sync/diff}/array.rb +1 -1
  60. data/lib/{sync/stroke_diff → strokedb/sync/diff}/default.rb +0 -0
  61. data/lib/{sync/stroke_diff → strokedb/sync/diff}/hash.rb +1 -1
  62. data/lib/{sync/stroke_diff → strokedb/sync/diff}/string.rb +1 -1
  63. data/lib/{sync → strokedb/sync}/lamport_timestamp.rb +0 -0
  64. data/lib/{sync → strokedb/sync}/store_sync.rb +15 -7
  65. data/lib/strokedb/transaction.rb +78 -0
  66. data/lib/{util → strokedb}/util.rb +14 -7
  67. data/lib/strokedb/util/attach_dsl.rb +29 -0
  68. data/lib/{util → strokedb/util}/blankslate.rb +0 -0
  69. data/lib/strokedb/util/class_optimization.rb +93 -0
  70. data/lib/{util → strokedb/util}/inflect.rb +0 -0
  71. data/lib/strokedb/util/java_util.rb +13 -0
  72. data/lib/{util → strokedb/util}/lazy_array.rb +0 -0
  73. data/lib/{util → strokedb/util}/lazy_mapping_array.rb +4 -0
  74. data/lib/{util → strokedb/util}/lazy_mapping_hash.rb +0 -0
  75. data/lib/{util → strokedb/util}/serialization.rb +21 -0
  76. data/lib/strokedb/util/uuid.rb +159 -0
  77. data/lib/{util → strokedb/util}/xml.rb +0 -0
  78. data/lib/{view → strokedb}/view.rb +2 -2
  79. data/lib/strokedb/volumes.rb +5 -0
  80. data/lib/strokedb/volumes/archive_volume.rb +165 -0
  81. data/lib/strokedb/volumes/block_volume.rb +169 -0
  82. data/lib/strokedb/volumes/distributed_pointer.rb +43 -0
  83. data/lib/strokedb/volumes/fixed_length_skiplist_volume.rb +109 -0
  84. data/lib/strokedb/volumes/map_volume.rb +268 -0
  85. data/meta/MANIFEST +175 -0
  86. data/script/console +2 -70
  87. data/spec/integration/remote_store_spec.rb +70 -0
  88. data/spec/integration/search_spec.rb +76 -0
  89. data/spec/integration/spec_helper.rb +1 -0
  90. data/spec/lib/spec_helper.rb +1 -0
  91. data/spec/lib/strokedb/config_spec.rb +250 -0
  92. data/spec/lib/strokedb/core_ext/blank_spec.rb +20 -0
  93. data/spec/lib/strokedb/core_ext/extract_spec.rb +42 -0
  94. data/spec/lib/strokedb/core_ext/float_spec.rb +62 -0
  95. data/spec/lib/strokedb/core_ext/infinity_spec.rb +40 -0
  96. data/spec/lib/strokedb/core_ext/spec_helper.rb +1 -0
  97. data/spec/lib/strokedb/core_ext/string_spec.rb +25 -0
  98. data/spec/lib/strokedb/core_ext/symbol_spec.rb +8 -0
  99. data/spec/lib/strokedb/data_structures/chunked_skiplist_spec.rb +144 -0
  100. data/spec/lib/strokedb/data_structures/inverted_list_spec.rb +172 -0
  101. data/spec/lib/strokedb/data_structures/simple_skiplist_spec.rb +200 -0
  102. data/spec/lib/strokedb/data_structures/skiplist_spec.rb +253 -0
  103. data/spec/lib/strokedb/data_structures/spec_helper.rb +1 -0
  104. data/spec/lib/strokedb/document/associations_spec.rb +319 -0
  105. data/spec/lib/strokedb/document/callbacks_spec.rb +134 -0
  106. data/spec/lib/strokedb/document/coercions_spec.rb +110 -0
  107. data/spec/lib/strokedb/document/document_spec.rb +1063 -0
  108. data/spec/lib/strokedb/document/meta_meta_spec.rb +30 -0
  109. data/spec/lib/strokedb/document/meta_spec.rb +435 -0
  110. data/spec/lib/strokedb/document/metaslot_spec.rb +43 -0
  111. data/spec/lib/strokedb/document/slot_spec.rb +130 -0
  112. data/spec/lib/strokedb/document/spec_helper.rb +1 -0
  113. data/spec/lib/strokedb/document/validations_spec.rb +1081 -0
  114. data/spec/lib/strokedb/document/virtualize_spec.rb +80 -0
  115. data/spec/lib/strokedb/nsurl_spec.rb +73 -0
  116. data/spec/lib/strokedb/spec_helper.rb +1 -0
  117. data/spec/lib/strokedb/stores/chained_storages_spec.rb +116 -0
  118. data/spec/lib/strokedb/stores/spec_helper.rb +1 -0
  119. data/spec/lib/strokedb/stores/store_spec.rb +201 -0
  120. data/spec/lib/strokedb/stores/transaction_spec.rb +107 -0
  121. data/spec/lib/strokedb/sync/chain_sync_spec.rb +43 -0
  122. data/spec/lib/strokedb/sync/diff_spec.rb +111 -0
  123. data/spec/lib/strokedb/sync/lamport_timestamp_spec.rb +174 -0
  124. data/spec/lib/strokedb/sync/slot_diff_spec.rb +164 -0
  125. data/spec/lib/strokedb/sync/spec_helper.rb +1 -0
  126. data/spec/lib/strokedb/sync/store_sync_spec.rb +181 -0
  127. data/spec/lib/strokedb/sync/stroke_diff/array_spec.rb +97 -0
  128. data/spec/lib/strokedb/sync/stroke_diff/complex_spec.rb +58 -0
  129. data/spec/lib/strokedb/sync/stroke_diff/hash_spec.rb +144 -0
  130. data/spec/lib/strokedb/sync/stroke_diff/scalar_spec.rb +23 -0
  131. data/spec/lib/strokedb/sync/stroke_diff/spec_helper.rb +25 -0
  132. data/spec/lib/strokedb/sync/stroke_diff/string_spec.rb +61 -0
  133. data/spec/lib/strokedb/util/attach_dsl_spec.rb +45 -0
  134. data/spec/lib/strokedb/util/inflect_spec.rb +14 -0
  135. data/spec/lib/strokedb/util/lazy_array_spec.rb +157 -0
  136. data/spec/lib/strokedb/util/lazy_mapping_array_spec.rb +174 -0
  137. data/spec/lib/strokedb/util/lazy_mapping_hash_spec.rb +92 -0
  138. data/spec/lib/strokedb/util/spec_helper.rb +1 -0
  139. data/spec/lib/strokedb/util/uuid_spec.rb +46 -0
  140. data/spec/lib/strokedb/view_spec.rb +228 -0
  141. data/spec/lib/strokedb/volumes/archive_volume_spec.rb +105 -0
  142. data/spec/lib/strokedb/volumes/block_volume_spec.rb +100 -0
  143. data/spec/lib/strokedb/volumes/distributed_pointer_spec.rb +14 -0
  144. data/spec/lib/strokedb/volumes/fixed_length_skiplist_volume_spec.rb +177 -0
  145. data/spec/lib/strokedb/volumes/map_volume_spec.rb +172 -0
  146. data/spec/lib/strokedb/volumes/spec_helper.rb +1 -0
  147. data/spec/regression/docref_spec.rb +94 -0
  148. data/spec/regression/meta_spec.rb +23 -0
  149. data/spec/regression/spec_helper.rb +1 -0
  150. data/spec/regression/sync_spec.rb +36 -0
  151. data/spec/spec.opts +7 -0
  152. data/spec/spec_helper.rb +37 -0
  153. data/spec/temp/storages/TIMESTAMP +1 -0
  154. data/spec/temp/storages/UUID +1 -0
  155. data/spec/temp/storages/database-sync/TIMESTAMP +1 -0
  156. data/spec/temp/storages/database-sync/UUID +1 -0
  157. data/spec/temp/storages/database-sync/config +1 -0
  158. data/spec/temp/storages/database-sync/file/LAST +1 -0
  159. data/spec/temp/storages/database-sync/file/bd/f6/bdf675e5-8a7b-494e-97f2-f74a14ccd95d.av +0 -0
  160. data/spec/temp/storages/database-sync/file/uindex.wal +0 -0
  161. data/spec/temp/storages/database-sync/inverted_list_file/INVERTED_INDEX +1 -0
  162. data/spec/temp/storages/inverted_list_storage/INVERTED_INDEX +0 -0
  163. data/strokedb.gemspec +120 -0
  164. data/task/benchmark.task +9 -0
  165. data/task/ditz.task +30 -0
  166. data/task/echoe.rb +17 -0
  167. data/task/rcov.task +50 -0
  168. data/task/rdoc.task +10 -0
  169. data/task/rspec.task +0 -0
  170. data/vendor/java_inline.rb +106 -0
  171. data/vendor/rbmodexcl/mrimodexcl.rb +82 -0
  172. data/vendor/rbmodexcl/rbmodexcl.rb +5 -0
  173. data/vendor/rbmodexcl/rbxmodexcl.rb +48 -0
  174. data/vendor/rbmodexcl/spec/unextend_spec.rb +50 -0
  175. data/vendor/rbmodexcl/spec/uninclude_spec.rb +26 -0
  176. metadata +271 -79
  177. data/CONTRIBUTORS +0 -7
  178. data/CREDITS +0 -13
  179. data/bin/sdbc +0 -2
  180. data/lib/init.rb +0 -57
  181. data/lib/stores/inverted_list_index/inverted_list_index.rb +0 -49
  182. data/lib/stores/skiplist_store/chunk.rb +0 -119
  183. data/lib/stores/skiplist_store/chunk_storage.rb +0 -21
  184. data/lib/stores/skiplist_store/file_chunk_storage.rb +0 -44
  185. data/lib/stores/skiplist_store/memory_chunk_storage.rb +0 -37
  186. data/lib/stores/skiplist_store/skiplist_store.rb +0 -217
  187. data/lib/stores/store.rb +0 -5
  188. data/lib/sync/stroke_diff/stroke_diff.rb +0 -9
  189. data/lib/util/ext/object.rb +0 -8
  190. data/lib/util/java_util.rb +0 -9
  191. data/lib/util/trigger_partition.rb +0 -136
  192. data/strokedb.rb +0 -75
@@ -0,0 +1,43 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
+
3
+ describe "Document" do
4
+
5
+ before(:each) do
6
+ setup_default_store
7
+ Object.send!(:remove_const,'SomeMeta') if defined?(SomeMeta)
8
+ SomeMeta = Meta.new
9
+ @document = Document.new
10
+ end
11
+
12
+ it "should assign a uuid-named slot for metaslot" do
13
+ @document[Meta] = SomeMeta
14
+ @document.slotnames.should include(Meta.document.uuid)
15
+ end
16
+
17
+ it "should assign a uuid-named slot for metaslot" do
18
+ @document[SomeMeta] = "some value"
19
+ @document.slotnames.should include(SomeMeta.document.uuid)
20
+ end
21
+
22
+ it "should be able to read metaslot" do
23
+ @document[SomeMeta] = "some value"
24
+ @document[SomeMeta].should == "some value"
25
+ end
26
+
27
+ describe "with metaslot assigned, once saved and reloaded" do
28
+
29
+ before(:each) do
30
+ @document[SomeMeta] = "some value"
31
+ @document.save!
32
+ @document = @document.reload
33
+ end
34
+
35
+ it "should be able to read metaslot" do
36
+ @document[SomeMeta].should == "some value"
37
+ end
38
+
39
+ end
40
+
41
+
42
+
43
+ end
@@ -0,0 +1,130 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
+
3
+ describe "Slot" do
4
+
5
+ before(:each) do
6
+ @store = setup_default_store
7
+ @document = Document.new
8
+ @slot = Slot.new(@document)
9
+ end
10
+
11
+ it "should store string value" do
12
+ @slot.value = "some value"
13
+ @slot.value.should == "some value"
14
+ end
15
+
16
+ it "should store numeric value" do
17
+ @slot.value = 1
18
+ @slot.value.should == 1
19
+ @slot.value = 1.1
20
+ @slot.value.should == 1.1
21
+ end
22
+
23
+ it "should store Array value" do
24
+ @slot.value = [1,2,3]
25
+ @slot.value.should == [1,2,3]
26
+ end
27
+
28
+ it "should store Hash value" do
29
+ @slot.value = { "1" => "2"}
30
+ @slot.value.should == { "1" => "2"}
31
+ end
32
+
33
+ it "should store boolean value" do
34
+ @slot.value = true
35
+ @slot.value.should == true
36
+ end
37
+
38
+ it "should store nil value" do
39
+ @slot.value = nil
40
+ @slot.value.should be_nil
41
+ end
42
+
43
+ it "should store symbol value and convert it to string" do
44
+ @slot.value = :a
45
+ @slot.value.should == 'a'
46
+ end
47
+
48
+ it "should store Range value" do
49
+ @slot.value = 1..100
50
+ @slot.value.should == (1..100)
51
+ end
52
+
53
+ it "should store Regexp value" do
54
+ @slot.value = /.+/
55
+ @slot.value.should == /.+/
56
+ end
57
+
58
+ it "should store Time object" do
59
+ t = Time.now
60
+ @slot.value = t
61
+ @slot.value.should be_close(t, 0.000002)
62
+ @slot.to_raw.should match(XMLSCHEMA_TIME_RE)
63
+ end
64
+
65
+ it "should store VersionedDocument reference if value is a saved Document" do
66
+ some_doc = Document.create!(:something => 1)
67
+ some_doc.save!
68
+ @slot.value = some_doc
69
+ @slot.value.should == some_doc
70
+ @slot.to_raw.should match(/@##{UUID_RE}.#{VERSION_RE}/)
71
+ end
72
+
73
+ it "should store VersionedDocument reference if value is a VersionedDocument" do
74
+ some_doc = Document.new(:something => 1)
75
+ some_doc.extend(VersionedDocument)
76
+ some_doc.save!
77
+ @slot.value = some_doc
78
+ @slot.value.should == some_doc
79
+ @slot.to_raw.should match(/@##{UUID_RE}.#{VERSION_RE}/)
80
+ end
81
+
82
+ it "should store Document reference if value is a saved Document" do
83
+ some_doc = Document.new
84
+ @slot.value = some_doc
85
+ @slot.value.should == some_doc
86
+ @slot.to_raw.should match(/@##{UUID_RE}/)
87
+ end
88
+
89
+ it "should raise ArgumentError for non-supported types" do
90
+ lambda { @slot.value = Object.new }.should raise_error(ArgumentError)
91
+ end
92
+
93
+ it "should preserve Ruby object for a complex value" do
94
+ @slot.value = ["some value"]
95
+ @slot.value.object_id.should == @slot.value.object_id
96
+ end
97
+
98
+ end
99
+
100
+ describe "Slot that directly references document" do
101
+
102
+ before(:each) do
103
+ setup_default_store
104
+ @another_doc = Document.create! :some_data => "1"
105
+ @doc = Document.create! :another_doc => @another_doc
106
+ end
107
+
108
+ it "should load the same Ruby object each time" do
109
+ doc = @doc.reload
110
+ doc_obj = doc.another_doc
111
+ doc.another_doc.object_id.should == doc_obj.object_id
112
+ end
113
+
114
+ end
115
+
116
+ describe "Slot that indirectly references document" do
117
+
118
+ before(:each) do
119
+ setup_default_store
120
+ @another_doc = Document.create! :some_data => "1"
121
+ @doc = Document.create! :another_docs => [@another_doc]
122
+ end
123
+
124
+ it "should load the same Ruby object each time" do
125
+ doc = @doc.reload
126
+ doc_obj = doc.another_docs.first
127
+ doc.another_docs.first.object_id.should == doc_obj.object_id
128
+ end
129
+
130
+ end
@@ -0,0 +1 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper'))
@@ -0,0 +1,1081 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
+
3
+ def validations_setup
4
+ setup_default_store
5
+ setup_index
6
+ Object.send!(:remove_const, 'Foo') if defined?(Foo)
7
+ Object.send!(:remove_const, 'Bar') if defined?(Bar)
8
+ Object.send!(:remove_const, 'User') if defined?(User)
9
+ Object.send!(:remove_const, 'Email') if defined?(Email)
10
+ Object.send!(:remove_const, 'Item') if defined?(Item)
11
+ Object.send!(:remove_const, 'OneMoreItem') if defined?(OneMoreItem)
12
+ end
13
+
14
+ def erroneous_stuff
15
+ Meta.new(:name => "ErroneousStuff") do
16
+ on_validation do |doc|
17
+ doc.errors.add(:something, "123")
18
+ doc.errors.add(:other, "456")
19
+ end
20
+ end.new
21
+ end
22
+
23
+ describe "Document validation" do
24
+ before :each do
25
+ validations_setup
26
+ end
27
+
28
+ it "should treat an empty document as valid" do
29
+ Foo = Meta.new
30
+ s = Foo.new
31
+
32
+ s.should be_valid
33
+ s.errors.should be_empty
34
+ end
35
+
36
+ it "should not treat a document with errors as valid" do
37
+ s = erroneous_stuff
38
+
39
+ s.should_not be_valid
40
+ s.errors.messages.sort.should == %w(123 456)
41
+ end
42
+
43
+ it "should raise InvalidDocumentError on a save! call" do
44
+ lambda { erroneous_stuff.save! }.should raise_error(InvalidDocumentError)
45
+ end
46
+
47
+ it "should not raise InvalidDocumentError on a save!(false) call" do
48
+ lambda { erroneous_stuff.save!(false) }.should_not raise_error(InvalidDocumentError)
49
+ end
50
+ end
51
+
52
+ describe "Document with errors" do
53
+ before :each do
54
+ validations_setup
55
+ @erroneous_doc = erroneous_stuff
56
+ end
57
+
58
+ it "should return the number of errors" do
59
+ @erroneous_doc.should_not be_valid
60
+ @erroneous_doc.errors.size.should == 2
61
+ end
62
+
63
+ it "should yield each attribute and associated message per error added" do
64
+ @erroneous_doc.should_not be_valid
65
+ @erroneous_doc.errors.each { }.should == {"something"=>["123"], "other"=>["456"]}
66
+ end
67
+
68
+ end
69
+
70
+ describe "validates_presence_of" do
71
+ before :each do
72
+ validations_setup
73
+ end
74
+
75
+ it "should tell valid if slot is there" do
76
+ Foo = Meta.new { validates_presence_of :name, :on => :save }
77
+ s = Foo.new({:name => "Rick Roll"})
78
+ s.should be_valid
79
+ end
80
+
81
+ it "should tell invalid if slot is absent" do
82
+ Foo = Meta.new { validates_presence_of :name, :on => :save }
83
+ s = Foo.new
84
+
85
+ s.should_not be_valid
86
+ s.errors.messages.should == [ "Foo's name should be present on save" ]
87
+ end
88
+ end
89
+
90
+ describe "Validation helpers" do
91
+ before(:each) { validations_setup }
92
+
93
+ it "should respect :on => :create" do
94
+ Foo = Meta.new { validates_presence_of :name, :on => :create }
95
+ s1 = Foo.new
96
+ bang { s1.save! }
97
+
98
+ s2 = Foo.new(:name => "Rick Roll")
99
+ no_bang { s2.save! }
100
+ s2.remove_slot!(:name)
101
+ no_bang { s2.save! }
102
+ end
103
+
104
+ it "should respect :on => :update" do
105
+ Foo = Meta.new { validates_presence_of :name, :on => :update }
106
+
107
+ s = Foo.new
108
+ no_bang { s.save! }
109
+ bang { s.save! }
110
+ s[:name] = "Rick Roll"
111
+ no_bang { s.save! }
112
+ end
113
+
114
+ it "should respect :on => :save" do
115
+ Foo = Meta.new { validates_presence_of :name, :on => :save }
116
+ s1 = Foo.new
117
+ bang { s1.save! }
118
+
119
+ s2 = Foo.new(:name => "Rick Roll")
120
+ no_bang { s2.save! }
121
+ s2.remove_slot!(:name)
122
+ bang { s2.save! }
123
+ end
124
+
125
+ it "should respect :message" do
126
+ Foo = Meta.new do
127
+ validates_presence_of :name, :on => :save, :message => 'On #{on} Meta #{meta} SlotName #{slotname}'
128
+ end
129
+
130
+ s = Foo.new
131
+ s.valid?.should be_false
132
+ s.errors.messages.should == [ "On save Meta Foo SlotName name" ]
133
+ end
134
+
135
+ it "should allow to use document slot for :if and :unless evaluation" do
136
+ Foo = Meta.new do validates_presence_of :name, :on => :save, :if => :slot end
137
+ bang { Foo.create!(:slot => true) }
138
+ no_bang { Foo.create!(:slot => false) }
139
+
140
+ Bar = Meta.new do validates_presence_of :name, :on => :save, :unless => :slot end
141
+ no_bang { Bar.create!(:slot => true) }
142
+ bang { Bar.create!(:slot => false) }
143
+ end
144
+
145
+ it "should raise an ArgumentError when given something not callable for :if and :unless" do
146
+ lambda do
147
+ Meta.new { validates_presence_of :name, :on => :save, :if => 123 }
148
+ end.should raise_error(ArgumentError)
149
+
150
+ lambda do
151
+ Meta.new { validates_presence_of :name, :on => :save, :if => lambda { } }
152
+ end.should raise_error(ArgumentError)
153
+
154
+ lambda do
155
+ Meta.new { validates_presence_of :name, :on => :save, :unless => 123 }
156
+ end.should raise_error(ArgumentError)
157
+
158
+ lambda do
159
+ Meta.new { validates_presence_of :name, :on => :save, :unless => lambda { } }
160
+ end.should raise_error(ArgumentError)
161
+
162
+ end
163
+
164
+ def bang
165
+ lambda { yield }.should raise_error(InvalidDocumentError)
166
+ end
167
+
168
+ def no_bang
169
+ lambda { yield }.should_not raise_error(InvalidDocumentError)
170
+ end
171
+ end
172
+
173
+ describe "validates_type_of" do
174
+ before :each do
175
+ validations_setup
176
+
177
+ Email = Meta.new
178
+ User = Meta.new { validates_type_of :email, :as => :email }
179
+ end
180
+
181
+ it "should actually check the type" do
182
+ e = Email.create!
183
+ User.new(:email => e).should be_valid
184
+ end
185
+
186
+ it "should treat other types as invalid" do
187
+ OmgEmail = Meta.new
188
+ e = OmgEmail.create!
189
+
190
+ User.new(:email => e).should_not be_valid
191
+ User.new(:email => "name@server.com").should_not be_valid
192
+ u = User.new(:email => nil)
193
+ u.should_not be_valid
194
+ u.errors.messages.should == [ "User's email should be of type Email" ]
195
+ end
196
+
197
+ it "should treat absent slot as valid with :allow_nil => true" do
198
+ Foo = Meta.new { validates_type_of :email, :as => :email, :allow_nil => true }
199
+ Foo.new.should be_valid
200
+ end
201
+
202
+ end
203
+
204
+ describe "validates_format_of" do
205
+ before(:each) do
206
+ validations_setup
207
+ User = Meta.new { validates_format_of :email, :with => /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\Z/i }
208
+ end
209
+
210
+ it "should be valid when :email value match regexp" do
211
+ User.new(:email => 'cool@strokedb.com').should be_valid
212
+ end
213
+
214
+ it "should be invalid when :email value does not match regexp" do
215
+ User.new(:email => 'cool-strokedb.com').should_not be_valid
216
+ end
217
+
218
+ it "should raise an exception if no regex is provided" do
219
+ lambda { Meta.new { validates_format_of :email, :with => "nothing" } }.should raise_error(ArgumentError)
220
+ end
221
+ end
222
+
223
+ describe "validates_uniqueness_of" do
224
+ before :each do
225
+ validations_setup
226
+ User = Meta.new { validates_uniqueness_of :email }
227
+ end
228
+
229
+ it "should treat unique slot values as valid" do
230
+ u1 = User.create!(:email => "name@server.com")
231
+ u2 = User.new(:email => "othername@otherserver.com")
232
+ u2.should be_valid
233
+ end
234
+
235
+ it "should treat duplicate slot values as invalid" do
236
+ u1 = User.create!(:email => "name@server.com")
237
+ u2 = User.new(:email => "name@server.com")
238
+ u2.should_not be_valid
239
+ u2.errors.messages.should == [ "A document with a email of name@server.com already exists" ]
240
+ end
241
+
242
+ it "should respect slot name" do
243
+ u1 = User.create!(:email => "name@server.com")
244
+ u2 = User.new(:otherfield => "name@server.com")
245
+ u2.should be_valid
246
+ end
247
+
248
+ describe "document with multiple metas" do
249
+ before :each do
250
+ validations_setup
251
+ Object.send!(:remove_const,'User') if defined?(User)
252
+ Object.send!(:remove_const,'Admin') if defined?(Admin)
253
+
254
+ User = Meta.new { validates_uniqueness_of :email }
255
+ Admin = Meta.new
256
+ end
257
+
258
+ it "should be valid" do
259
+ u = (User+Admin).create!(:email => 'foo@bar.org')
260
+ u.should be_valid
261
+ end
262
+
263
+ it "should be valid" do
264
+ u = User.create!(:email => 'foo@bar.org')
265
+ u.should be_valid
266
+ u.metas << Admin
267
+ u.should be_valid
268
+ end
269
+
270
+ it "should not be valid" do
271
+ u = User.create!(:email => 'foo@bar.org')
272
+ u.should be_valid
273
+ a = Admin.create!(:email => 'foo@bar.org')
274
+ a.should be_valid
275
+
276
+ u.metas << Admin
277
+ a.should be_valid
278
+ u.should_not be_valid
279
+ end
280
+ end
281
+
282
+ describe "should allow to modify an existing document" do
283
+ it "test 1" do
284
+ u = User.create!(:email => "name@server.com", :status => :newbie)
285
+ u.status = :hacker
286
+ u.should be_valid
287
+ u.save!
288
+ u.status = :hax0r
289
+ u.should be_valid
290
+ u.save!
291
+ u.email = "hax0r@hax0r.com"
292
+ u.should be_valid
293
+ u.save!
294
+ u.email = "name@server.com"
295
+ u.status = :newbie_again
296
+ u.should be_valid
297
+ u.save!
298
+ u.email = "hax0r@hax0r.com"
299
+ u.should be_valid
300
+ end
301
+
302
+ it "test 2" do
303
+ Foo = Meta.new do
304
+ validates_uniqueness_of :login
305
+ virtualizes :blah
306
+ end
307
+
308
+ foo = Foo.create!(:login => "vasya")
309
+
310
+ foo.somefield = 777
311
+ foo.should be_valid
312
+ end
313
+ end
314
+
315
+ it "should respect :allow_nil set to false" do
316
+ Foo = Meta.new { validates_uniqueness_of :slot, :allow_nil => false }
317
+ Foo.create!(:slot => nil)
318
+ Foo.new.should_not be_valid
319
+ end
320
+
321
+ it "should respect :allow_nil set to true" do
322
+ Foo = Meta.new { validates_uniqueness_of :slot, :allow_nil => true }
323
+ Foo.create!(:slot => nil)
324
+ Foo.new.should be_valid
325
+ end
326
+
327
+ it "should default :allow_nil to false" do
328
+ Foo = Meta.new { validates_uniqueness_of :slot }
329
+ Foo.create!(:slot => nil)
330
+ Foo.new.should_not be_valid
331
+ end
332
+
333
+ it "should respect :allow_blank set to false" do
334
+ Foo = Meta.new { validates_uniqueness_of :slot, :allow_blank => false }
335
+ Foo.create!(:slot => "")
336
+ Foo.new.should_not be_valid
337
+ end
338
+
339
+ it "should respect :allow_blank set to true" do
340
+ Foo = Meta.new { validates_uniqueness_of :slot, :allow_blank => true }
341
+ Foo.create!(:slot => "")
342
+ Foo.new.should be_valid
343
+ end
344
+
345
+ it "should default :allow_blank to false" do
346
+ Foo = Meta.new { validates_uniqueness_of :slot }
347
+ Foo.create!(:slot => "")
348
+ Foo.new.should_not be_valid
349
+ end
350
+
351
+ it "should respect :case_sensitive"
352
+ end
353
+
354
+ describe "validates_confirmation_of" do
355
+ before :each do
356
+ validations_setup
357
+ User = Meta.new { validates_confirmation_of :password }
358
+ end
359
+
360
+ it "should be valid when confirmed" do
361
+ User.new(:password => "sekret", :password_confirmation => "sekret").should be_valid
362
+ end
363
+
364
+ it "should be valid when confirmation is not set" do
365
+ User.new(:password => "sekret").should be_valid
366
+ end
367
+
368
+ it "should not be valid when not confirmed" do
369
+ u = User.new(:password => "sekret", :password_confirmation => "invalid_guess")
370
+ u.should_not be_valid
371
+ u.errors.messages.should == [ "User's password doesn't match confirmation" ]
372
+ end
373
+
374
+ it "should not serialize confirmation slot" do
375
+ u = User.create!(:password => "sekret", :password_confirmation => "sekret")
376
+ User.find(u.uuid).has_slot?("password_confirmation").should_not be_true
377
+ end
378
+ end
379
+
380
+ describe "validates_acceptance_of" do
381
+ before :each do
382
+ validations_setup
383
+ end
384
+
385
+ it "should treat accepted value as valid" do
386
+ Meta.new(:name => 'some') { validates_acceptance_of :eula, :accept => "yep" }.new(:eula => "yep").should be_valid
387
+ end
388
+
389
+ it "should treat not accepted value as invalid" do
390
+ Meta.new(:name => 'some') { validates_acceptance_of :eula, :accept => "yep" }.new(:eula => "nope").should_not be_valid
391
+ end
392
+
393
+ it "should respect allow_nil" do
394
+ Meta.new(:name => 'some') { validates_acceptance_of :eula, :accept => "yep", :allow_nil => true }.new.should be_valid
395
+ Meta.new(:name => 'some') { validates_acceptance_of :eula, :accept => "yep", :allow_nil => false }.new.should_not be_valid
396
+ end
397
+
398
+ it "should set :allow_nil to true by default" do
399
+ Meta.new(:name => 'some') { validates_acceptance_of :eula, :accept => "yep" }.new.should be_valid
400
+ end
401
+
402
+ it "should set :accept to \"1\" by default" do
403
+ Meta.new(:name => 'some') { validates_acceptance_of :eula }.new(:eula => "1").should be_valid
404
+ end
405
+
406
+ it "should make a slot virtual" do
407
+ Foo = Meta.new{ validates_acceptance_of :eula, :accept => "yep" }
408
+ f = Foo.create!(:eula => "yep")
409
+ Foo.find(f.uuid).has_slot?("eula").should_not be_true
410
+ end
411
+ end
412
+
413
+ describe "validates_length_of" do
414
+ before :each do
415
+ validations_setup
416
+ end
417
+
418
+ describe "options handling" do
419
+ it "should raise ArgumentError when more than one range option is specified" do
420
+ arg_bang { Meta.new(:name => 'some') { validates_length_of :name, :is => 10, :maximum => 20 } }
421
+ arg_bang { Meta.new(:name => 'some') { validates_length_of :name, :is => 10, :within => 1..20 } }
422
+ end
423
+
424
+ it "should raise ArgumentError when no range option is specified" do
425
+ arg_bang { Meta.new(:name => 'some') { validates_length_of :name } }
426
+ end
427
+
428
+ it "should raise ArgumentError when not Range given to :in or :within" do
429
+ arg_bang { Meta.new(:name => 'some') { validates_length_of :name, :in => 10 } }
430
+ arg_bang { Meta.new(:name => 'some') { validates_length_of :name, :within => "somewhere between one and a million" } }
431
+ end
432
+
433
+ it "should raise ArgumentError when something other than nonnegative Integer is given to :is, :minimum, :maximum" do
434
+ %w(is minimum maximum).each do |arg|
435
+ arg_bang { Meta.new(:name => 'some') { validates_length_of :name, arg => "blah" } }
436
+ arg_bang { Meta.new(:name => 'some') { validates_length_of :name, arg => -1 } }
437
+ end
438
+ end
439
+
440
+ def arg_bang
441
+ lambda { yield }.should raise_error(ArgumentError)
442
+ end
443
+ end
444
+
445
+ %w(within in).each do |within|
446
+ describe ":#{within}" do
447
+ before :each do
448
+ Foo = Meta.new { validates_length_of :bar, within => 10..50 }
449
+ end
450
+
451
+ it "should consider valid when slot is within the range" do
452
+ Foo.new(:bar => "*"*30).should be_valid
453
+ Foo.new(:bar => [1]*30).should be_valid
454
+ end
455
+
456
+ it "should consider invalid when slot is too small" do
457
+ f = Foo.new(:bar => "12345")
458
+ f.should_not be_valid
459
+ f.errors.messages.should == [ "bar is too short (minimum is 10 characters)" ]
460
+ Foo.new(:bar => [1]*5).should_not be_valid
461
+ end
462
+
463
+ it "should consider invalid when slot is too big" do
464
+ f = Foo.new(:bar => "!"*100)
465
+ f.should_not be_valid
466
+ f.errors.messages.should == [ "bar is too long (maximum is 50 characters)" ]
467
+ Foo.new(:bar => [1]*100).should_not be_valid
468
+ end
469
+
470
+ it "should respect :too_short" do
471
+ Bar = Meta.new { validates_length_of :foo, within => 1..5, :too_short => "blah %d" }
472
+ b = Bar.new(:foo => "")
473
+ b.should_not be_valid
474
+ b.errors.messages.should == [ "blah 1" ]
475
+ end
476
+
477
+ it "should respect :too_long" do
478
+ Bar = Meta.new { validates_length_of :foo, within => 1..5, :too_long => "blah %d" }
479
+ b = Bar.new(:foo => "123456")
480
+ b.should_not be_valid
481
+ b.errors.messages.should == [ "blah 5" ]
482
+ end
483
+ end
484
+ end
485
+
486
+ describe ":is" do
487
+ before :each do
488
+ Foo = Meta.new { validates_length_of :bar, :is => 4 }
489
+ end
490
+
491
+ it "should consider valid when slot value has the right length" do
492
+ Foo.new(:bar => "1234").should be_valid
493
+ Foo.new(:bar => %w(ein zwei drei Polizei)).should be_valid
494
+ end
495
+
496
+ it "should consider invalid when slot value has invalid length" do
497
+ f = Foo.new(:bar => "12345")
498
+ f.should_not be_valid
499
+ f.errors.messages.should == [ "bar has the wrong length (should be 4 characters)" ]
500
+
501
+ Foo.new(:bar => %w(ein zwei alles)).should_not be_valid
502
+ end
503
+
504
+ it "should respect :message" do
505
+ Bar = Meta.new { validates_length_of :foo, :is => 66, :message => "fkup %d" }
506
+ b = Bar.new(:foo => "123456")
507
+ b.should_not be_valid
508
+ b.errors.messages.should == [ "fkup 66" ]
509
+ end
510
+ end
511
+
512
+ describe ":minimum" do
513
+ before :each do
514
+ Foo = Meta.new { validates_length_of :bar, :minimum => 4 }
515
+ end
516
+
517
+ it "should consider valid when slot value has the right length" do
518
+ Foo.new(:bar => "1234").should be_valid
519
+ Foo.new(:bar => "12345").should be_valid
520
+ Foo.new(:bar => %w(ein zwei drei vier Polizei)).should be_valid
521
+ end
522
+
523
+ it "should consider invalid when slot value has invalid length" do
524
+ f = Foo.new(:bar => "125")
525
+ f.should_not be_valid
526
+ f.errors.messages.should == [ "bar is too short (minimum is 4 characters)" ]
527
+
528
+ Foo.new(:bar => %w(ein zwei alles)).should_not be_valid
529
+ end
530
+
531
+ it "should respect :message" do
532
+ Bar = Meta.new { validates_length_of :foo, :minimum => 66, :message => "fkup %d" }
533
+ b = Bar.new(:foo => "123456")
534
+ b.should_not be_valid
535
+ b.errors.messages.should == [ "fkup 66" ]
536
+ end
537
+ end
538
+
539
+ describe :maximum do
540
+ before :each do
541
+ Foo = Meta.new { validates_length_of :bar, :maximum => 4 }
542
+ end
543
+
544
+ it "should consider valid when slot value has the right length" do
545
+ Foo.new(:bar => "1234").should be_valid
546
+ Foo.new(:bar => "123").should be_valid
547
+ Foo.new(:bar => %w(ein zwei drei)).should be_valid
548
+ end
549
+
550
+ it "should consider invalid when slot value has invalid length" do
551
+ f = Foo.new(:bar => "123456")
552
+ f.should_not be_valid
553
+ f.errors.messages.should == [ "bar is too long (maximum is 4 characters)" ]
554
+
555
+ Foo.new(:bar => %w(ein zwei drei vier Polizei)).should_not be_valid
556
+ end
557
+
558
+ it "should respect :message" do
559
+ Bar = Meta.new { validates_length_of :foo, :maximum => 66, :message => "fkup %d" }
560
+ b = Bar.new(:foo => "6"*67)
561
+ b.should_not be_valid
562
+ b.errors.messages.should == [ "fkup 66" ]
563
+ end
564
+ end
565
+
566
+ it "should respect :allow_nil" do
567
+ Meta.new(:name => 'some') { validates_length_of :bar, :is => 10, :allow_nil => false }.new.should_not be_valid
568
+ Meta.new(:name => 'some') { validates_length_of :bar, :is => 10, :allow_nil => true }.new.should be_valid
569
+ end
570
+
571
+ it "should respect :allow_blank" do
572
+ Foo = Meta.new { validates_length_of :bar, :is => 10, :allow_blank => false }
573
+ Foo.new.should_not be_valid
574
+ Foo.new(:bar => " ").should_not be_valid
575
+
576
+ Bar = Meta.new { validates_length_of :bar, :is => 10, :allow_blank => true }
577
+ Bar.new.should be_valid
578
+ Bar.new(:bar => " ").should be_valid
579
+ end
580
+ end
581
+
582
+ describe "validates_inclusion_of" do
583
+ before :each do
584
+ validations_setup
585
+ Item = Meta.new do
586
+ validates_inclusion_of :gender, :in => %w( m f )
587
+ validates_inclusion_of :age, :in => 0..99
588
+ end
589
+ end
590
+
591
+ it "should raise ArgumentError unless option :in is suplied" do
592
+ lambda do
593
+ Meta.new { validates_inclusion_of :format }
594
+ end.should raise_error(ArgumentError)
595
+ end
596
+
597
+ it "should raise ArgumentError unless param is an enumerable" do
598
+ lambda do
599
+ Meta.new { validates_inclusion_of :format, :in => 42 }
600
+ end.should raise_error(ArgumentError)
601
+ end
602
+
603
+ it "should be valid" do
604
+ i = Item.new(:gender => 'm', :age => 42)
605
+ i.should be_valid
606
+ i.errors.messages.should be_empty
607
+ end
608
+
609
+ it "should not be valid" do
610
+ i = Item.new(:gender => 'x', :age => 'x')
611
+ i.should_not be_valid
612
+ i.errors.messages.should == [ "Value of gender is not included in the list", "Value of age is not included in the list" ]
613
+ end
614
+
615
+ it "should be invalid without gender and age set" do
616
+ Item.new.should_not be_valid
617
+ end
618
+ end
619
+
620
+ describe "validates_exclusion_of" do
621
+ before :each do
622
+ validations_setup
623
+ Item = Meta.new do
624
+ validates_exclusion_of :gender, :in => %w( m f )
625
+ validates_exclusion_of :age, :in => 30..70
626
+ end
627
+ end
628
+
629
+ it "should raise ArgumentError unless option :in is suplied" do
630
+ lambda do
631
+ Meta.new { validates_exclusion_of :gender }
632
+ end.should raise_error(ArgumentError)
633
+ end
634
+
635
+ it "should raise ArgumentError unless param is an enumerable" do
636
+ lambda do
637
+ Meta.new { validates_inclusion_of :gender, :in => 42 }
638
+ end.should raise_error(ArgumentError)
639
+ end
640
+
641
+ it "should be valid" do
642
+ i = Item.new(:gender => 'x', :age => 25)
643
+ i.should be_valid
644
+ end
645
+
646
+ it "should not be valid" do
647
+ i = Item.new(:gender => 'm', :age => 42)
648
+ i.should_not be_valid
649
+ i.errors.messages.should == [ "Value of gender is reserved", "Value of age is reserved" ]
650
+ end
651
+ end
652
+
653
+ describe "validates_associated" do
654
+ before :each do
655
+ validations_setup
656
+
657
+ Foo = Meta.new { has_many :bars; validates_associated :bars }
658
+ Bar = Meta.new { has_many :items; validates_associated :items }
659
+ Item = Meta.new { validates_associated :associate }
660
+ OneMoreItem = Meta.new { validates_associated :associate; validates_presence_of :something }
661
+ User = Meta.new
662
+ end
663
+
664
+ it "should consider not existing association as valid" do
665
+ Foo.new.should be_valid
666
+ end
667
+
668
+ it "should consider valid when associated document is also valid" do
669
+ perfectly_valid = User.new
670
+ Item.new(:associate => perfectly_valid).should be_valid
671
+ end
672
+
673
+ it "should consider invalid when associated document is invalid" do
674
+ invalid = erroneous_stuff
675
+ invalid.should_not be_valid
676
+ item = Item.new(:associate => invalid)
677
+ item.should_not be_valid
678
+ item.errors.messages.should == [ "associate is invalid" ]
679
+ end
680
+
681
+ it "should work with has_many association" do
682
+ f = Foo.new
683
+ f.bars << Bar.new
684
+ f.should be_valid
685
+ f.bars << Bar.new
686
+ f.should be_valid
687
+
688
+ err = erroneous_stuff
689
+
690
+ lambda { f.bars << err }.should raise_error(InvalidDocumentError)
691
+ f.should be_valid
692
+ end
693
+
694
+ it "should work with a document chain" do
695
+ i3 = erroneous_stuff
696
+ i3.should_not be_valid
697
+
698
+ i2 = Item.new
699
+ i2.should be_valid
700
+ i2.associate = i3
701
+ i2.should_not be_valid
702
+
703
+ i1 = Item.new
704
+ i1.should be_valid
705
+ i1.associate = i2
706
+ i1.should_not be_valid
707
+
708
+ i1.associate = i3
709
+ i1.should_not be_valid
710
+ i1.associate = nil
711
+ i1.should be_valid
712
+ end
713
+
714
+ it "should catch direct circular referenced validations" do
715
+ i = Item.new
716
+ i1 = Item.new(:associate => i)
717
+ i.associate = i1
718
+ lambda { i.valid? }.should_not raise_error(SystemStackError)
719
+ i.should be_valid
720
+ oi = OneMoreItem.new
721
+ oi1 = OneMoreItem.new(:associate => oi)
722
+ oi.associate = oi1
723
+ oi.should_not be_valid
724
+ oi1.should_not be_valid
725
+ end
726
+
727
+ it "should catch circular referenced validations through has_many association" do
728
+ b = Bar.new
729
+ b.items << (i = Item.new(:associate => b))
730
+ lambda { b.valid? }.should_not raise_error(SystemStackError)
731
+ lambda { i.valid? }.should_not raise_error(SystemStackError)
732
+ end
733
+
734
+ end
735
+
736
+ describe "validates_numericality_of" do
737
+ before :each do
738
+ validations_setup
739
+ end
740
+
741
+ describe "general behaviour" do
742
+ before :each do
743
+ Item = Meta.new do
744
+ validates_numericality_of :price
745
+ end
746
+ end
747
+
748
+ it "should raise error on String value" do
749
+ i = Item.new(:price => "A")
750
+ i.should_not be_valid
751
+ i.errors.messages.should == [ "price is not a number" ]
752
+ end
753
+
754
+ it "should treat integer as valid" do
755
+ i = Item.new(:price => 1)
756
+ i.should be_valid
757
+ end
758
+
759
+ it "should treat negative integer as valid" do
760
+ i = Item.new(:price => -1)
761
+ i.should be_valid
762
+ end
763
+
764
+ it "should treat float as valid" do
765
+ i = Item.new(:price => 2.5)
766
+ i.should be_valid
767
+ end
768
+
769
+ it "should treat negative float as valid" do
770
+ i = Item.new(:price => -2.5)
771
+ i.should be_valid
772
+ end
773
+
774
+ it "should treat float in exponential notation as valid" do
775
+ i = Item.new(:price => "1.23456E-3")
776
+ i.should be_valid
777
+ end
778
+ end
779
+
780
+ describe "should respect :only_integer" do
781
+ before :each do
782
+ Item = Meta.new do
783
+ validates_numericality_of :price, :only_integer => true
784
+ end
785
+ end
786
+
787
+ it "should treat integer as valid when :only_integer is specified" do
788
+ Item.new(:price => 123).should be_valid
789
+ end
790
+
791
+ it "should treat integer in string as valid when :only_integer is specified" do
792
+ Item.new(:price => "123").should be_valid
793
+ end
794
+
795
+ it "should treat string as invalid when :only_integer is specified" do
796
+ i = Item.new(:price => "ququ")
797
+ i.should_not be_valid
798
+ i.errors.messages.should == [ "price must be integer" ]
799
+ end
800
+
801
+ it "should treat float as invalid when :only_integer is specified" do
802
+ i = Item.new(:price => 1.5)
803
+ i.should_not be_valid
804
+ i.errors.messages.should == [ "price must be integer" ]
805
+ end
806
+ end
807
+
808
+ describe "should respect :greater_than" do
809
+ before :each do
810
+ Item = Meta.new do
811
+ validates_numericality_of :number, :greater_than => 42
812
+ end
813
+ end
814
+
815
+ it "should raise ArgumentError if value is not numeric" do
816
+ lambda do
817
+ Meta.new { validates_numericality_of :number, :greater_than => "chicken" }
818
+ end.should raise_error(ArgumentError)
819
+ end
820
+
821
+ it "should be valid if value > 42" do
822
+ i = Item.new(:number => 44)
823
+ i.should be_valid
824
+ i.errors.messages.should be_empty
825
+ i.number = 44.3
826
+ i.should be_valid
827
+ i.errors.messages.should be_empty
828
+ end
829
+
830
+ it "should not be valid if value < 42" do
831
+ i = Item.new(:number => 41)
832
+ i.should_not be_valid
833
+ i.errors.messages.should == [ "number must be greater than 42" ]
834
+ end
835
+
836
+ it "should not be valid if value == 42" do
837
+ i = Item.new(:number => 42)
838
+ i.should_not be_valid
839
+ i.errors.messages.should == [ "number must be greater than 42" ]
840
+ end
841
+ end
842
+
843
+ describe "should respect :greater_than_or_equal_to" do
844
+ before :each do
845
+ Item = Meta.new do
846
+ validates_numericality_of :number, :greater_than_or_equal_to => 42
847
+ end
848
+ end
849
+
850
+ it "should raise ArgumentError if value is not numeric" do
851
+ lambda do
852
+ Meta.new { validates_numericality_of :number, :greater_than => "chicken" }
853
+ end.should raise_error(ArgumentError)
854
+ end
855
+
856
+ it "should be valid if value > 42" do
857
+ i = Item.new(:number => 44)
858
+ i.should be_valid
859
+ i.number = 44.3
860
+ i.should be_valid
861
+ end
862
+
863
+ it "should be valid if value == 42" do
864
+ i = Item.new(:number => 42)
865
+ i.should be_valid
866
+ end
867
+
868
+ it "should not be valid if value < 42" do
869
+ i = Item.new(:number => 41)
870
+ i.should_not be_valid
871
+ i.errors.messages.should == [ "number must be greater than or equal to 42" ]
872
+ end
873
+ end
874
+
875
+ describe "should respect :equal_to" do
876
+ before :each do
877
+ Item = Meta.new do
878
+ validates_numericality_of :number, :equal_to => 42
879
+ end
880
+ end
881
+
882
+ it "should raise ArgumentError if value is not numeric" do
883
+ lambda do
884
+ Meta.new { validates_numericality_of :number, :greater_than => "chicken" }
885
+ end.should raise_error(ArgumentError)
886
+ end
887
+
888
+ it "should be valid if value == 42" do
889
+ i = Item.new(:number => 42)
890
+ i.should be_valid
891
+ i.errors.messages.should be_empty
892
+ end
893
+
894
+ it "should not be valid if value > 42" do
895
+ i = Item.new(:number => 44)
896
+ i.should_not be_valid
897
+ i.errors.messages.should == [ "number must be equal to 42" ]
898
+ end
899
+
900
+ it "should not be valid if value < 42" do
901
+ i = Item.new(:number => 41)
902
+ i.should_not be_valid
903
+ i.errors.messages.should == [ "number must be equal to 42" ]
904
+ end
905
+ end
906
+
907
+ describe "should respect :less_than" do
908
+ before :each do
909
+ Item = Meta.new do
910
+ validates_numericality_of :number, :less_than => 42
911
+ end
912
+ end
913
+
914
+ it "should raise ArgumentError if value is not numeric" do
915
+ lambda do
916
+ Meta.new { validates_numericality_of :number, :less_than => "chicken" }
917
+ end.should raise_error(ArgumentError)
918
+ end
919
+
920
+ it "should be valid if value < 42" do
921
+ i = Item.new(:number => 41)
922
+ i.should be_valid
923
+ i.errors.messages.should be_empty
924
+ i.number = 41.3
925
+ i.should be_valid
926
+ i.errors.messages.should be_empty
927
+ end
928
+
929
+ it "should not be valid if value > 42" do
930
+ i = Item.new(:number => 43)
931
+ i.should_not be_valid
932
+ i.errors.messages.should == [ "number must be less than 42" ]
933
+ end
934
+
935
+ it "should not be valid if value == 42" do
936
+ i = Item.new(:number => 42)
937
+ i.should_not be_valid
938
+ i.errors.messages.should == [ "number must be less than 42" ]
939
+ end
940
+ end
941
+
942
+ describe "should respect :less_than_or_equal_to" do
943
+ before :each do
944
+ Item = Meta.new do
945
+ validates_numericality_of :number, :less_than_or_equal_to => 42
946
+ end
947
+ end
948
+
949
+ it "should raise ArgumentError if value is not numeric" do
950
+ lambda do
951
+ Meta.new { validates_numericality_of :number, :less_than_or_equal_to => "chicken" }
952
+ end.should raise_error(ArgumentError)
953
+ end
954
+
955
+ it "should be valid if value < 42" do
956
+ i = Item.new(:number => 41)
957
+ i.should be_valid
958
+ i.errors.messages.should be_empty
959
+ i.number = 41.3
960
+ i.should be_valid
961
+ i.errors.messages.should be_empty
962
+ end
963
+
964
+ it "should be valid if value == 42" do
965
+ i = Item.new(:number => 42)
966
+ i.should be_valid
967
+ i.errors.messages.should be_empty
968
+ end
969
+
970
+ it "should not be valid if value > 42" do
971
+ i = Item.new(:number => 43)
972
+ i.should_not be_valid
973
+ i.errors.messages.should == [ "number must be less than or equal to 42" ]
974
+ end
975
+ end
976
+
977
+ describe "should respect :odd" do
978
+ before :each do
979
+ Item = Meta.new do
980
+ validates_numericality_of :oddnumber, :odd => true
981
+ end
982
+ end
983
+
984
+ it "should raise ArgumentError when argument is not true" do
985
+ lambda do
986
+ Meta.new { validates_numericality_of :number, :odd => :really? }
987
+ end.should raise_error(ArgumentError)
988
+ end
989
+
990
+ it "should be valid when value is odd" do
991
+ i = Item.new(:oddnumber => 1)
992
+ i.should be_valid
993
+ i.errors.messages.should be_empty
994
+ end
995
+
996
+ it "should not be valid when value is even" do
997
+ i = Item.new(:oddnumber => 2)
998
+ i.should_not be_valid
999
+ i.errors.messages.should == [ "oddnumber must be odd" ]
1000
+ end
1001
+ end
1002
+
1003
+ describe "should respect :even" do
1004
+ before :each do
1005
+ Item = Meta.new do
1006
+ validates_numericality_of :evennumber, :even => true
1007
+ end
1008
+ end
1009
+
1010
+ it "should raise ArgumentError when argument is not true" do
1011
+ lambda do
1012
+ Meta.new { validates_numericality_of :number, :even => :really? }
1013
+ end.should raise_error(ArgumentError)
1014
+ end
1015
+
1016
+ it "should be valid when value is even" do
1017
+ i = Item.new(:evennumber => 4)
1018
+ i.should be_valid
1019
+ i.errors.messages.should be_empty
1020
+ end
1021
+
1022
+ it "should not be valid when value is odd" do
1023
+ i = Item.new(:evennumber => 1)
1024
+ i.should_not be_valid
1025
+ i.errors.messages.should == [ "evennumber must be even" ]
1026
+ end
1027
+ end
1028
+
1029
+ it "should respect :allow_nil" do
1030
+ Meta.new(:name => 'some') { validates_numericality_of :number, :allow_nil => true }.new.should be_valid
1031
+ end
1032
+
1033
+ describe "should allow for option combinations" do
1034
+ it ":less_than and :greater_than" do
1035
+ Item = Meta.new do
1036
+ validates_numericality_of :number, :less_than => 100, :greater_than => 50
1037
+ end
1038
+
1039
+ Item.new(:number => 60).should be_valid
1040
+
1041
+ i1 = Item.new(:number => 40)
1042
+ i1.should_not be_valid
1043
+ i1.errors.messages.should == [ "number must be greater than 50" ]
1044
+
1045
+ i2 = Item.new(:number => 150)
1046
+ i2.should_not be_valid
1047
+ i2.errors.messages.should == [ "number must be less than 100" ]
1048
+ end
1049
+
1050
+ it ":even and :less_than_or_equal_to" do
1051
+ Item = Meta.new do
1052
+ validates_numericality_of :number, :less_than_or_equal_to => 100, :even => true
1053
+ end
1054
+
1055
+ Item.new(:number => 60).should be_valid
1056
+
1057
+ i1 = Item.new(:number => 111)
1058
+ i1.should_not be_valid
1059
+ i1.errors.messages.sort.should == ["number must be less than or equal to 100", "number must be even"].sort
1060
+ end
1061
+ end
1062
+ end
1063
+
1064
+ describe "Complex validations" do
1065
+ it "should gather errors for all slots"
1066
+ it "should run all validations for the same slot"
1067
+ it "should run all validations from all metas"
1068
+ it "should somehow deal with the case when different metas contain same validations types for the same slot"
1069
+ end
1070
+
1071
+ describe "Meta with validation enabled" do
1072
+ before(:each) do
1073
+ validations_setup
1074
+ User = Meta.new { validates_uniqueness_of :email }
1075
+ end
1076
+
1077
+ it "should be able to find instances of all documents" do
1078
+ doc = User.create! :email => "yrashk@gmail.com"
1079
+ User.find.should == [doc]
1080
+ end
1081
+ end