rod 0.6.1 → 0.6.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (50) hide show
  1. data/.gitignore +7 -0
  2. data/{README → README.rdoc} +33 -2
  3. data/Rakefile +7 -2
  4. data/changelog.txt +13 -0
  5. data/contributors.txt +2 -0
  6. data/features/append.feature +221 -0
  7. data/features/assoc_indexing.feature +66 -0
  8. data/features/basic.feature +199 -0
  9. data/features/collection.feature +171 -0
  10. data/features/flat_indexing.feature +140 -0
  11. data/features/fred.feature +49 -0
  12. data/features/inheritence.feature +211 -0
  13. data/features/muliple_db.feature +113 -0
  14. data/features/relationships.feature +195 -0
  15. data/features/segmented_indexing.feature +172 -0
  16. data/features/steps/model.rb +386 -0
  17. data/features/steps/rod.rb +71 -0
  18. data/features/steps/test_helper.rb +5 -0
  19. data/lib/rod/abstract_database.rb +17 -5
  20. data/lib/rod/constants.rb +1 -1
  21. data/lib/rod/database.rb +95 -74
  22. data/lib/rod/join_element.rb +6 -2
  23. data/lib/rod/model.rb +37 -9
  24. data/rod.gemspec +15 -12
  25. data/tests/check_strings.rb +10 -0
  26. data/tests/class_compatibility_create.rb +14 -0
  27. data/tests/class_compatibility_verify.rb +18 -0
  28. data/tests/eff1_test.rb +60 -0
  29. data/tests/eff2_test.rb +61 -0
  30. data/tests/full_runs.rb +68 -0
  31. data/tests/generate_classes_create.rb +25 -0
  32. data/tests/generate_classes_model.rb +23 -0
  33. data/tests/generate_classes_rewrite.rb +7 -0
  34. data/tests/generate_classes_verify.rb +46 -0
  35. data/tests/load_struct.rb +24 -0
  36. data/tests/migration_create.rb +25 -0
  37. data/tests/migration_migrate.rb +22 -0
  38. data/tests/migration_model1.rb +23 -0
  39. data/tests/migration_model2.rb +27 -0
  40. data/tests/migration_verify.rb +56 -0
  41. data/tests/mock_tests.rb +128 -0
  42. data/tests/read_on_create.rb +45 -0
  43. data/tests/save_struct.rb +49 -0
  44. data/tests/structures.rb +52 -0
  45. data/tests/unit/database.rb +60 -0
  46. data/tests/unit/model.rb +36 -0
  47. data/tests/unit/model_tests.rb +116 -0
  48. data/tests/validate_read_on_create.rb +12 -0
  49. data/utils/convert_index.rb +31 -0
  50. metadata +77 -28
@@ -0,0 +1,386 @@
1
+ require 'rspec/expectations'
2
+ require File.join(File.dirname(__FILE__),"test_helper")
3
+
4
+ def get_class(class_name,type=:model)
5
+ klass = RodTest.const_get(class_name) rescue nil
6
+ if klass.nil?
7
+ superclass =
8
+ case type
9
+ when :model
10
+ RodTest::TestModel
11
+ when :db
12
+ Rod::Database
13
+ end
14
+ klass = Class.new(superclass)
15
+ RodTest.const_set(class_name,klass)
16
+ end
17
+ klass
18
+ end
19
+
20
+ def get_db(db_name)
21
+ case db_name
22
+ when "database"
23
+ RodTest::Database
24
+ else
25
+ get_class(db_name,:db)
26
+ end
27
+ end
28
+
29
+ def get_instance(class_name,position,cache=false)
30
+ if cache
31
+ @instances[class_name][get_position(position)]
32
+ else
33
+ get_class(class_name)[get_position(position)]
34
+ end
35
+ end
36
+
37
+ def get_value(value)
38
+ case value
39
+ when /^(-)?\d+\.\d+$/
40
+ value.to_f
41
+ when /^(-)?\d+$/
42
+ value.to_i
43
+ when /^:/
44
+ value[1..-1].to_sym
45
+ else
46
+ value = value.scan(/[^\d\\]+|\\\d+/).map do |segment|
47
+ case segment
48
+ when /\\\d+/
49
+ $&.to_i.chr
50
+ else
51
+ segment
52
+ end
53
+ end.join("")
54
+ value
55
+ end
56
+ end
57
+
58
+ def get_position(position)
59
+ case position
60
+ when "first"
61
+ 0
62
+ when "second"
63
+ 1
64
+ when "third"
65
+ 2
66
+ when "last"
67
+ -1
68
+ when Fixnum
69
+ position
70
+ end
71
+ end
72
+
73
+ ################################################################
74
+ # Given
75
+ ################################################################
76
+ Given /^the model is connected with the default database$/ do
77
+ RodTest::TestModel.send(:database_class,RodTest::Database)
78
+ end
79
+
80
+ Given /^a class (\w+) inherits from ([\w:]+)$/ do |name1,name2|
81
+ if name2 =~ /::/
82
+ base_module = Module
83
+ else
84
+ base_module = RodTest
85
+ end
86
+ class2 = name2.split("::").inject(base_module){|m,n| m.const_get(n)}
87
+ class1 = Class.new(class2)
88
+ RodTest.const_set(name1,class1)
89
+ end
90
+
91
+ Given /^a class (\w+) has an? (\w+) field of type (\w+)( with (\w+) index)?$/ do |class_name,field,type,index,index_type|
92
+ index_type = index_type == "flat" ? :flat : :segmented
93
+ if index
94
+ get_class(class_name).send(:field,field.to_sym,type.to_sym,:index => index_type)
95
+ else
96
+ get_class(class_name).send(:field,field.to_sym,type.to_sym)
97
+ end
98
+ end
99
+
100
+ Given /^a class (\w+) has one (\w+ )?(\w+)( with (\w+) index)?$/ do |class_name,type,assoc,index,index_type|
101
+ options = {}
102
+ unless type.nil?
103
+ case type
104
+ when /polymorphic/
105
+ options[:polymorphic] = true
106
+ end
107
+ end
108
+ unless index.nil?
109
+ index_type = (index_type == "flat" ? :flat : :segmented)
110
+ options[:index] = index_type
111
+ end
112
+ get_class(class_name).send(:has_one,assoc.to_sym,options)
113
+ end
114
+
115
+ Given /^a class (\w+) has many (\w+ )?(\w+)( with (\w+) index)?$/ do |class_name,type,assoc,index,index_type|
116
+ options = {}
117
+ unless type.nil?
118
+ case type
119
+ when /polymorphic/
120
+ options[:polymorphic] = true
121
+ end
122
+ end
123
+ unless index.nil?
124
+ index_type = (index_type == "flat" ? :flat : :segmented)
125
+ options[:index] = index_type
126
+ end
127
+ get_class(class_name).send(:has_many,assoc.to_sym,options)
128
+ end
129
+
130
+ ################################################################
131
+ # When
132
+ ################################################################
133
+ # When I create a Caveman
134
+ When /^I create a(?:nother|n)? (\w+)$/ do |class_name|
135
+ @instance = get_class(class_name).new
136
+ @instances[class_name] ||= []
137
+ @instances[class_name] << @instance
138
+ end
139
+
140
+ # When I create a Caveman with 'Fred' name and 'Flintstone' surname
141
+ When /^I create a(?:nother|n)? (\w+) with (.*)$/ do |class_name,rest|
142
+ hash = {}
143
+ rest.split(/\s+and\s+/).each do |pair|
144
+ matched = pair.match(/'(?<value>[^']*)' (?<name>\w+)/)
145
+ hash[matched[:name].to_sym] = get_value(matched[:value])
146
+ end
147
+ begin
148
+ @instance = get_class(class_name).new(hash)
149
+ @instances[class_name] ||= []
150
+ @instances[class_name] << @instance
151
+ rescue Exception => ex
152
+ @error = ex
153
+ end
154
+ end
155
+
156
+ # When I fetch the first Caveman (created)
157
+ When /^I fetch the (\w+) (\w+)( created)?$/ do |position,class_name,created|
158
+ created = !created.nil?
159
+ @instance = get_instance(class_name,position,created)
160
+ end
161
+
162
+ # When I create and store the following Caveman(s):
163
+ # | name | surname |
164
+ # | Fred | Flintstone |
165
+ When /^I create and store the following (\w+)\(s\):$/ do |class_name,table|
166
+ klass = get_class(class_name)
167
+ table.hashes.each do |attributes|
168
+ instance = klass.new
169
+ attributes.each do |field,value|
170
+ instance.send("#{field}=",get_value(value))
171
+ end
172
+ @instances[class_name] ||= []
173
+ @instances[class_name] << instance
174
+ instance.store
175
+ end
176
+ end
177
+
178
+ # When his name is 'Fred' (multiplied 300 times)
179
+ When /^(?:his|her|its) (\w+) is '([^']*)'(?: multiplied (\d+) times)?$/ do |field,value,multiplier|
180
+ value = get_value(value)
181
+ if multiplier
182
+ value *= multiplier.to_i
183
+ end
184
+ @instance.send("#{field}=".to_sym,value)
185
+ end
186
+
187
+ When /^(his|her|its) (\w+) is nil$/ do |ignore,field|
188
+ @instance.send("#{field}=".to_sym,nil)
189
+ end
190
+
191
+
192
+ When /^(his|her|its) (\w+) is the (\w+) (\w+) created$/ do |ignore,field,position,class_name|
193
+ @instance.send("#{field}=".to_sym,get_instance(class_name,position,true))
194
+ end
195
+
196
+ When /^(his|her|its) (\w+) contain the (\w+) (\w+) created$/ do |ignore,field,position,class_name|
197
+ @instance.send("#{field}".to_sym) << get_instance(class_name,position,true)
198
+ end
199
+
200
+ When /^(his|her|its) (\w+) contain nil$/ do |ignore,field|
201
+ @instance.send("#{field}".to_sym) << nil
202
+ end
203
+
204
+ When /^I store (him|her|it) in the database( (\d+) times)?$/ do |ignore,times,count|
205
+ if times
206
+ count.to_i.times do |index|
207
+ instance = @instance.dup
208
+ instance.store
209
+ end
210
+ else
211
+ @instance.store
212
+ end
213
+ end
214
+
215
+ When /^I store the (\w+) (\w+) in the database$/ do |position,class_name|
216
+ get_instance(class_name,position,true).store
217
+ end
218
+
219
+ When /^I access the (\w+) (\w+) index$/ do |class_name,field|
220
+ get_class(class_name).send("find_by_#{field}",nil)
221
+ end
222
+
223
+ When /^I remember the (\w+) (\w+)$/ do |position,class_name|
224
+ @remembered = get_instance(class_name,position)
225
+ end
226
+
227
+ ################################################################
228
+ # Then
229
+ ################################################################
230
+ Then /^there should be (\d+) (\w+)(\([^)]*\))?$/ do |count,class_name,ignore|
231
+ get_class(class_name).count.should == count.to_i
232
+ end
233
+
234
+ Then /^the (\w+) of the (\w+) ([A-Z]\w+) should be '([^']*)'$/ do |field, position, class_name,value|
235
+ get_instance(class_name,position).send(field.to_sym).should == get_value(value)
236
+ end
237
+
238
+ Then /^the (\w+) of the (\w+) (\w+) should be '([^']*)'( multiplied (\d+) times)$/ do |field, position, class_name,value,multi,multiplier|
239
+ value = get_value(value)
240
+ if multi
241
+ value *= multiplier.to_i
242
+ end
243
+ get_instance(class_name,position).send(field.to_sym).should == value
244
+ end
245
+
246
+ Then /^the (\w+) of the remembered instance should be '([^']*)'( multiplied (\d+) times)?$/ do |field, value,multi,multiplier|
247
+ value = get_value(value)
248
+ if multi
249
+ value *= multiplier.to_i
250
+ end
251
+ @remembered.send(field.to_sym).should == value
252
+ end
253
+
254
+ Then /^the (\w+) (\w+) should not have a (\w+) field$/ do |position, class_name, field|
255
+ (lambda {get_instance(class_name,position).send(field.to_sym)}).should raise_error(NoMethodError)
256
+ end
257
+
258
+ Then /^the (\w+) (\w+) should not have (a|an )?(\w+)$/ do |position, class_name, ignore, assoc|
259
+ (lambda {get_instance(class_name,position).send(assoc.to_sym)}).should raise_error(NoMethodError)
260
+ end
261
+
262
+ Then /^the (\w+) (\w+) should not exist$/ do |position,class_name|
263
+ (lambda {get_instance(class_name,position)}).should raise_error(IndexError)
264
+ end
265
+
266
+ Then /^the (\w+) of the (\w+) (\w+) should be equal to the (\w+) (\w+)$/ do |field, position1,class1,position2,class2|
267
+ get_instance(class1,position1).send(field.to_sym).should ==
268
+ get_instance(class2,position2,true)
269
+ end
270
+
271
+ Then /^the (\w+) of the (\w+) (\w+) should be nil$/ do |field,position1,class1|
272
+ get_instance(class1,position1).send(field.to_sym).should == nil
273
+ end
274
+
275
+
276
+ Then /^the (\w+) (\w+) should have (\d+) (\w+)$/ do |position,class_name,count,field|
277
+ get_instance(class_name,position).send(field.to_sym).count.should == count.to_i
278
+ end
279
+
280
+ Then /^(\w+)(\([^)]*\))? from (\d+) to (\d+) should have '([^']*)' (\w+)$/ do |class_name,ignore,first,last,value,field|
281
+ (first.to_i - 1).upto(last.to_i - 1) do |index|
282
+ get_instance(class_name,index).send(field.to_sym).should == value
283
+ end
284
+ end
285
+
286
+ Then /^(\w+)(\([^)]*\))? from (\d+) to (\d+) should have a(n)? (\w+) equal to the (\w+) (\w+)$/ do |class1,ignore,first,last,ignore1,field,position,class2|
287
+ (first.to_i - 1).upto(last.to_i - 1) do |index|
288
+ get_instance(class1,index).send(field.to_sym).should == get_instance(class2,position)
289
+ end
290
+ end
291
+
292
+ Then /^(\w+)(\([^)]*\))? from (\d+) to (\d+) should have (\d+) (\w+)$/ do |class1,ignore,first,last,count,field|
293
+ (first.to_i - 1).upto(last.to_i - 1) do |index|
294
+ get_instance(class1,index).send(field.to_sym).count.should == count.to_i
295
+ end
296
+ end
297
+
298
+ Then /^(\w+)(\([^)]*\))? from (\d+) to (\d+) should have (\w+) of (\w+) equal to the (\w+) (\w+) created$/ do |class1,ignore,first,last,position1,field,position2,class2|
299
+ (first.to_i - 1).upto(last.to_i - 1) do |index|
300
+ get_instance(class1,index).send(field.to_sym)[get_position(position1)] == get_instance(class2,position2)
301
+ end
302
+ end
303
+
304
+ Then /^the (\w+) of (\w+) of the (\w+) (\w+) should be equal to the (\w+) (\w+)$/ do |position0,field,position1,class1,position2,class2|
305
+ get_instance(class1,position1).send(field.to_sym)[get_position(position0)].should ==
306
+ get_instance(class2,position2,true)
307
+ end
308
+
309
+ Then /^the (\w+) of (\w+) of the (\w+) (\w+) should be nil$/ do |position0,field,position1,class1|
310
+ get_instance(class1,position1).send(field.to_sym)[get_position(position0)].should == nil
311
+ end
312
+
313
+ # Then his name should be 'Fred'
314
+ Then /^(?:his|her|its) (\w+) should be '([^']*)'$/ do |property, value|
315
+ value = get_value(value)
316
+ @instance.send(property.to_sym).should == value
317
+ end
318
+
319
+ # Then his name should be nil
320
+ Then /^(?:his|her|its) (\w+) should be nil$/ do |property|
321
+ @instance.send(property.to_sym).should == nil
322
+ end
323
+
324
+ # Then his items should be empty
325
+ Then /^(?:his|her|its) (\w+) should be empty$/ do |property|
326
+ @instance.send(property.to_sym).should be_empty
327
+ end
328
+
329
+ Then /^the (\w+) (\w+) should be equal with the instance$/ do |position1,class1|
330
+ instance1 = get_instance(class1,position1)
331
+ instance1.should == @instance
332
+ end
333
+
334
+ Then /^the (\w+) (\w+) should be identical with the (\w+) (\w+)$/ do |position1,class1,position2,class2|
335
+ instance1 = get_instance(class1,position1)
336
+ instance2 = get_instance(class2,position2)
337
+ instance1.object_id.should == instance2.object_id
338
+ end
339
+
340
+ Then /^there should be (\d+) (\w+)(?:\([^)]*\))? with '([^']*)' (\w+)$/ do |count,class_name,value,field|
341
+ get_class(class_name).send("find_all_by_#{field}",get_value(value)).count.should == count.to_i
342
+ end
343
+
344
+ # Then there should exist a User with 'Adam' name
345
+ Then /^there should exist a(?:n)? (\w+) with '([^']*)' (\w+)$/ do |class_name,value,field|
346
+ get_class(class_name).send("find_by_#{field}",get_value(value)).should_not == nil
347
+ end
348
+
349
+ # Then there should be 5 User(s) with the first Dog as dog
350
+ Then /^there should be (\d+) (\w+)(?:\([^)]*\))? with the (\w+) (\w+) as (\w+)$/ do |count,class1,position,class2,assoc|
351
+ get_class(class1).send("find_all_by_#{assoc}",get_instance(class2,position)).count.should == count.to_i
352
+ end
353
+
354
+ # Then there should exist a User with the first Dog as dog
355
+ Then /^there should exist a(?:n)? (\w+) with the (\w+) (\w+) as (\w+)$/ do |class1,position,class2,assoc|
356
+ get_class(class1).send("find_by_#{assoc}",get_instance(class2,position)).should_not == nil
357
+ end
358
+
359
+
360
+ Then /^I should be able to iterate( with index)? over these (\w+)\(s\)$/ do |with_index,class_name|
361
+ if with_index
362
+ (lambda {get_class(class_name).each.with_index{|e,i| e}}).should_not raise_error(Exception)
363
+ else
364
+ (lambda {get_class(class_name).each{|e| e}}).should_not raise_error(Exception)
365
+ end
366
+ end
367
+
368
+ Then /^I should be able to find a (\w+) with '([^']*)' (\w+) and '([^']*)' (\w+)$/ do |class_name,value1,field1,value2,field2|
369
+ get_class(class_name).find{|e| e.send(field1) == get_value(value1) && e.send(field2) == get_value(value2)}.should_not == nil
370
+ end
371
+
372
+ Then /^there should be (\d+) (\w+)(\([^)]*\))? with (\w+) (below|above) (\d+)( with index (below|above) (\d+))?$/ do |count1,class_name,ignore,field,relation1,value,with_index,relation2,count2|
373
+ relation1 = relation1 == "below" ? :< : :>
374
+ relation2 = relation2 == "below" ? :< : :>
375
+ if with_index
376
+ get_class(class_name).each.with_index.select{|e,i| e.send(field).send(relation1,value.to_i) &&
377
+ i.send(relation2,count2.to_i)}.size.should == count1.to_i
378
+ else
379
+ get_class(class_name).select{|e| e.send(field).send(relation1, value.to_i)}.size.should == count1.to_i
380
+ end
381
+
382
+ end
383
+
384
+ Then /^([\w:]+) should be raised$/ do |exception|
385
+ @error.class.to_s.should == exception
386
+ end
@@ -0,0 +1,71 @@
1
+ require File.join(File.dirname(__FILE__),"test_helper")
2
+
3
+ #$ROD_DEBUG = true
4
+
5
+ Given /^the library works in development mode$/ do
6
+ Rod::Database.development_mode = true
7
+ end
8
+
9
+ Given /^(the )?(\w+) is created( in (\w+))?$/ do |ignore,db_name,location,location_name|
10
+ get_db(db_name).instance.close_database if get_db(db_name).instance.opened?
11
+ if File.exist?("tmp")
12
+ if location
13
+ db_location = location_name
14
+ else
15
+ db_location = db_name
16
+ end
17
+ end
18
+ get_db(db_name).instance.create_database("tmp/#{db_location}")
19
+ @instances = {}
20
+ end
21
+
22
+ Given /^a class (\w+) is connected to (\w+)$/ do |class_name,db_name|
23
+ get_class(class_name).send(:database_class,get_class(db_name,:db))
24
+ end
25
+
26
+ Given /^the class space is cleared$/ do
27
+ #RodTest::Database.instance.close_database(true) if RodTest::Database.instance.opened?
28
+ RodTest.constants.each do |constant|
29
+ klass = RodTest.const_get(constant)
30
+ if constant.to_s =~ /Database/
31
+ if klass.instance.opened?
32
+ klass.instance.close_database(true)
33
+ end
34
+ end
35
+ RodTest.send(:remove_const,constant)
36
+ end
37
+ # TODO separate step?
38
+ default_db = Class.new(Rod::Database)
39
+ RodTest.const_set("Database",default_db)
40
+ default_model = Class.new(Rod::Model)
41
+ RodTest.const_set("TestModel",default_model)
42
+ end
43
+
44
+ # Should be split
45
+ When /^I reopen (\w+)( for reading)?( in (\w+))?$/ do |db_name,reading,location,location_name|
46
+ if location
47
+ db_location = location_name
48
+ else
49
+ db_location = db_name
50
+ end
51
+ get_db(db_name).instance.close_database
52
+ get_db(db_name).instance.clear_cache
53
+ readonly = reading.nil? ? false : true
54
+ get_db(db_name).instance.open_database("tmp/#{db_location}",readonly)
55
+ end
56
+
57
+ When /^I open (\w+)( for reading)?( in (\w+))?$/ do |db_name,reading,location,location_name|
58
+ if location
59
+ db_location = location_name
60
+ else
61
+ db_location = db_name
62
+ end
63
+ get_db(db_name).instance.clear_cache
64
+ readonly = reading.nil? ? false : true
65
+ get_db(db_name).instance.open_database("tmp/#{db_location}",readonly)
66
+ end
67
+
68
+ Then /^database should be opened for reading$/ do
69
+ RodTest::Database.instance.opened?.should be_true
70
+ RodTest::Database.instance.readonly_data?.should be_true
71
+ end