runo 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (149) hide show
  1. data/LICENSE +19 -0
  2. data/README.rdoc +120 -0
  3. data/bin/runo +35 -0
  4. data/lib/_error.rb +14 -0
  5. data/lib/_field.rb +260 -0
  6. data/lib/_i18n.rb +141 -0
  7. data/lib/_parser.rb +243 -0
  8. data/lib/_path.rb +86 -0
  9. data/lib/_storage/_storage.rb +213 -0
  10. data/lib/_storage/file.rb +200 -0
  11. data/lib/_storage/sequel.rb +174 -0
  12. data/lib/_storage/temp.rb +73 -0
  13. data/lib/_widget/action_create.rb +23 -0
  14. data/lib/_widget/action_login.rb +22 -0
  15. data/lib/_widget/action_signup.rb +16 -0
  16. data/lib/_widget/action_update.rb +16 -0
  17. data/lib/_widget/crumb.rb +24 -0
  18. data/lib/_widget/done.rb +16 -0
  19. data/lib/_widget/login.rb +25 -0
  20. data/lib/_widget/me.rb +31 -0
  21. data/lib/_widget/message.rb +51 -0
  22. data/lib/_widget/navi.rb +88 -0
  23. data/lib/_widget/submit.rb +49 -0
  24. data/lib/_widget/view_ym.rb +77 -0
  25. data/lib/_workflow/_workflow.rb +89 -0
  26. data/lib/_workflow/attachment.rb +50 -0
  27. data/lib/_workflow/blog.rb +28 -0
  28. data/lib/_workflow/contact.rb +23 -0
  29. data/lib/_workflow/forum.rb +26 -0
  30. data/lib/_workflow/register.rb +39 -0
  31. data/lib/meta/_meta.rb +20 -0
  32. data/lib/meta/group.rb +19 -0
  33. data/lib/meta/id.rb +59 -0
  34. data/lib/meta/owner.rb +21 -0
  35. data/lib/meta/timestamp.rb +118 -0
  36. data/lib/runo.rb +396 -0
  37. data/lib/scalar/checkbox.rb +68 -0
  38. data/lib/scalar/file.rb +144 -0
  39. data/lib/scalar/img.rb +112 -0
  40. data/lib/scalar/password.rb +58 -0
  41. data/lib/scalar/radio.rb +47 -0
  42. data/lib/scalar/select.rb +47 -0
  43. data/lib/scalar/text.rb +38 -0
  44. data/lib/scalar/textarea.rb +35 -0
  45. data/lib/scalar/textarea_pre.rb +14 -0
  46. data/lib/scalar/textarea_wiki.rb +173 -0
  47. data/lib/set/_set.rb +195 -0
  48. data/lib/set/dynamic.rb +177 -0
  49. data/lib/set/static.rb +102 -0
  50. data/lib/set/static_folder.rb +96 -0
  51. data/locale/en/index.po +242 -0
  52. data/locale/index.pot +243 -0
  53. data/locale/ja/index.po +242 -0
  54. data/locale/lazy_parser.rb +54 -0
  55. data/skel/config.ru +27 -0
  56. data/skel/skin/_users/00000000_frank-avatar.jpg +0 -0
  57. data/skel/skin/_users/00000000_frank-avatar_small.jpg +0 -0
  58. data/skel/skin/_users/00000000_frank.yaml +12 -0
  59. data/skel/skin/_users/00000000_root-avatar.jpg +0 -0
  60. data/skel/skin/_users/00000000_root-avatar_small.jpg +0 -0
  61. data/skel/skin/_users/00000000_root.yaml +11 -0
  62. data/skel/skin/_users/css/users.css +21 -0
  63. data/skel/skin/_users/css/users.less +25 -0
  64. data/skel/skin/_users/done.html +42 -0
  65. data/skel/skin/_users/index.html +46 -0
  66. data/skel/skin/_users/index.yaml +3 -0
  67. data/skel/skin/_users/summary.html +40 -0
  68. data/skel/skin/css/base.css +93 -0
  69. data/skel/skin/css/base.less +139 -0
  70. data/skel/skin/css/coax.css +199 -0
  71. data/skel/skin/css/coax.less +244 -0
  72. data/skel/skin/examples/blog/20091214_0001.yaml +8 -0
  73. data/skel/skin/examples/blog/20100630_0001.yaml +8 -0
  74. data/skel/skin/examples/blog/20100630_0002.yaml +14 -0
  75. data/skel/skin/examples/blog/20100701_0001.yaml +8 -0
  76. data/skel/skin/examples/blog/20100701_0002-a-20100701_0001-f.jpg +0 -0
  77. data/skel/skin/examples/blog/20100701_0002-a-20100701_0001-f_small.jpg +0 -0
  78. data/skel/skin/examples/blog/20100701_0002.yaml +19 -0
  79. data/skel/skin/examples/blog/frank/20100701_0001.yaml +10 -0
  80. data/skel/skin/examples/blog/frank/index.yaml +4 -0
  81. data/skel/skin/examples/blog/index.html +51 -0
  82. data/skel/skin/examples/blog/rss.xml +18 -0
  83. data/skel/skin/examples/contact/20100701_0001-file.txt +1 -0
  84. data/skel/skin/examples/contact/20100701_0001.yaml +15 -0
  85. data/skel/skin/examples/contact/20100701_0002.yaml +8 -0
  86. data/skel/skin/examples/contact/20100701_0003.yaml +9 -0
  87. data/skel/skin/examples/contact/index.html +47 -0
  88. data/skel/skin/examples/contact/js/contact.js +13 -0
  89. data/skel/skin/examples/contact/summary.html +54 -0
  90. data/skel/skin/examples/forum/20100701_0001.yaml +41 -0
  91. data/skel/skin/examples/forum/20100701_0002.yaml +25 -0
  92. data/skel/skin/examples/forum/index.html +68 -0
  93. data/skel/skin/examples/forum/summary.html +47 -0
  94. data/skel/skin/examples/index.html +75 -0
  95. data/skel/skin/index.html +41 -0
  96. data/skel/skin/js/base.js +50 -0
  97. data/t/locale/de/index.po +19 -0
  98. data/t/locale/en-GB/index.po +25 -0
  99. data/t/locale/ja/index.po +30 -0
  100. data/t/skin/_users/00000000_test.yaml +3 -0
  101. data/t/skin/_users/index.html +13 -0
  102. data/t/skin/foo/20091120_0001.yaml +7 -0
  103. data/t/skin/foo/bar/20091120_0001.yaml +5 -0
  104. data/t/skin/foo/bar/index.yaml +5 -0
  105. data/t/skin/foo/baz/css/baz.css +1 -0
  106. data/t/skin/foo/css/foo.css +1 -0
  107. data/t/skin/foo/index.html +14 -0
  108. data/t/skin/foo/index.yaml +7 -0
  109. data/t/skin/foo/not_css/foo.css +1 -0
  110. data/t/skin/foo/sub-20100306_0001.yaml +3 -0
  111. data/t/skin/index.yaml +3 -0
  112. data/t/skin/t_attachment/index.html +13 -0
  113. data/t/skin/t_contact/done.html +6 -0
  114. data/t/skin/t_contact/index.html +9 -0
  115. data/t/skin/t_file/index.html +16 -0
  116. data/t/skin/t_img/index.html +14 -0
  117. data/t/skin/t_img/test.jpg +0 -0
  118. data/t/skin/t_select/index.html +9 -0
  119. data/t/skin/t_store/index.html +9 -0
  120. data/t/skin/t_summary/20100326_0001.yaml +3 -0
  121. data/t/skin/t_summary/create.html +9 -0
  122. data/t/skin/t_summary/index.html +9 -0
  123. data/t/skin/t_summary/summary.html +9 -0
  124. data/t/t.rb +27 -0
  125. data/t/test_checkbox.rb +273 -0
  126. data/t/test_field.rb +330 -0
  127. data/t/test_file.rb +900 -0
  128. data/t/test_id.rb +215 -0
  129. data/t/test_img.rb +328 -0
  130. data/t/test_meta.rb +57 -0
  131. data/t/test_parser.rb +1266 -0
  132. data/t/test_password.rb +188 -0
  133. data/t/test_radio.rb +226 -0
  134. data/t/test_role.rb +249 -0
  135. data/t/test_runo.rb +742 -0
  136. data/t/test_runo_call.rb +1286 -0
  137. data/t/test_runo_i18n.rb +318 -0
  138. data/t/test_select.rb +182 -0
  139. data/t/test_set_complex.rb +527 -0
  140. data/t/test_set_dynamic.rb +1504 -0
  141. data/t/test_set_folder.rb +515 -0
  142. data/t/test_set_permit.rb +246 -0
  143. data/t/test_set_static.rb +445 -0
  144. data/t/test_storage.rb +915 -0
  145. data/t/test_text.rb +125 -0
  146. data/t/test_textarea.rb +138 -0
  147. data/t/test_timestamp.rb +473 -0
  148. data/t/test_workflow.rb +367 -0
  149. metadata +345 -0
@@ -0,0 +1,915 @@
1
+ # encoding: UTF-8
2
+
3
+ # Author:: Akira FUNAI
4
+ # Copyright:: Copyright (c) 2009 Akira FUNAI
5
+
6
+ require "#{::File.dirname __FILE__}/t"
7
+
8
+ class TC_Storage < Test::Unit::TestCase
9
+
10
+ def setup
11
+ end
12
+
13
+ def teardown
14
+ end
15
+
16
+ def test_instance
17
+ sd = Runo::Set::Static::Folder.root.item('t_select', 'main')
18
+
19
+ assert_instance_of(
20
+ Runo::Storage.const_get(Runo['storage']['default']),
21
+ sd.storage,
22
+ 'Storage.instance should return a File instance when the set is right under the folder'
23
+ )
24
+
25
+ child_set = Runo::Field.instance(
26
+ :klass => 'set-dynamic',
27
+ :parent => sd
28
+ )
29
+ assert_instance_of(
30
+ Runo::Storage::Temp,
31
+ child_set.storage,
32
+ 'Storage.instance should return a Temp when the set is not a child of the folder'
33
+ )
34
+
35
+ orphan_set = Runo::Field.instance(
36
+ :klass => 'set-dynamic'
37
+ )
38
+ assert_instance_of(
39
+ Runo::Storage::Temp,
40
+ orphan_set.storage,
41
+ 'Storage.instance should return a Temp when the set is a direct child of the folder'
42
+ )
43
+ end
44
+
45
+ def test_fetch
46
+ sd = Runo::Set::Static::Folder.root.item('t_select', 'main')
47
+ sd[:order] = 'id'
48
+ sd[:p_size] = 10
49
+
50
+ Runo::Storage.constants.collect {|c| Runo::Storage.const_get c }.each {|klass|
51
+ next unless klass.is_a?(::Class) && klass.available?
52
+
53
+ storage = klass.new sd
54
+ storage.build(
55
+ '20091114_0001' => {'name' => 'bar', 'comment' => 'I am BAR!'},
56
+ '20091115_0001' => {'name' => 'qux', 'comment' => 'Qux! Qux!'},
57
+ '20091114_0002' => {'name' => 'baz', 'comment' => 'BAZ BAZ...'},
58
+ '20091225_0001' => {'name' => 'quux', 'comment' => 'Quux?'},
59
+ '20091225_0002' => {'name' => 'corge', 'comment' => 'Corge.'},
60
+ '20091226_0001' => {'name' => 'bar', 'comment' => 'I am BAR again!'}
61
+ )
62
+
63
+ _test_select(storage)
64
+ _test_sort(storage)
65
+ _test_order(storage)
66
+ _test_page(storage)
67
+ _test_val(storage)
68
+ _test_navi(storage)
69
+ _test_last(storage)
70
+
71
+ storage.build(
72
+ '00000000_frank' => {'name' => 'fz', 'comment' => 'I am FZ!'},
73
+ '00000000_carl' => {'name' => 'cz', 'comment' => 'I am CZ!'},
74
+ '00000000_bobby' => {'name' => 'bz', 'comment' => 'I am BZ!'}
75
+ )
76
+ _test_fetch_special_id(storage)
77
+
78
+ storage.clear # so far, storage with raw values can not be built at once.
79
+ storage.store('20100406_0001', "\x01\x02\x03", 'jpg')
80
+ _test_val_raw(storage)
81
+
82
+ storage.clear
83
+
84
+ _test_traverse(storage) if storage.is_a? Runo::Storage::File # TODO: other parsistent
85
+ }
86
+ end
87
+
88
+ def _test_select(storage)
89
+ assert_equal(
90
+ [
91
+ '20091114_0001',
92
+ '20091114_0002',
93
+ '20091115_0001',
94
+ '20091225_0001',
95
+ '20091225_0002',
96
+ '20091226_0001',
97
+ ],
98
+ storage.select,
99
+ "#{storage.class}#select should return item ids that match given conds"
100
+ )
101
+ assert_equal(
102
+ ['20091114_0001'],
103
+ storage.select(:id => '20091114_0001'),
104
+ "#{storage.class}#select should return item ids that match given conds"
105
+ )
106
+ assert_equal(
107
+ ['20091115_0001'],
108
+ storage.select(:d => '20091115'),
109
+ "#{storage.class}#select should return item ids that match given conds"
110
+ )
111
+ end
112
+
113
+ def _test_sort(storage)
114
+ assert_equal(
115
+ [
116
+ '20091114_0001',
117
+ '20091114_0002',
118
+ '20091115_0001',
119
+ '20091225_0001',
120
+ '20091225_0002',
121
+ '20091226_0001',
122
+ ],
123
+ storage.select(:order => 'd'),
124
+ "#{storage.class}#_sort should sort the item ids returned by _select()"
125
+ )
126
+ assert_equal(
127
+ [
128
+ '20091226_0001',
129
+ '20091225_0002',
130
+ '20091225_0001',
131
+ '20091115_0001',
132
+ '20091114_0002',
133
+ '20091114_0001',
134
+ ],
135
+ storage.select(:order => '-d'),
136
+ "#{storage.class}#_sort should sort the item ids returned by _select()"
137
+ )
138
+ end
139
+
140
+ def _test_order(storage)
141
+ storage.sd[:order] = 'id'
142
+ assert_equal(
143
+ [
144
+ '20091114_0001',
145
+ '20091114_0002',
146
+ '20091115_0001',
147
+ '20091225_0001',
148
+ '20091225_0002',
149
+ '20091226_0001',
150
+ ],
151
+ storage.select,
152
+ "#{storage.class}#_sort should refer to sd[:order]"
153
+ )
154
+
155
+ storage.sd[:order] = '-id'
156
+ assert_equal(
157
+ [
158
+ '20091226_0001',
159
+ '20091225_0002',
160
+ '20091225_0001',
161
+ '20091115_0001',
162
+ '20091114_0002',
163
+ '20091114_0001',
164
+ ],
165
+ storage.select,
166
+ "#{storage.class}#_sort should refer to sd[:order]"
167
+ )
168
+
169
+ storage.sd[:order] = '-id'
170
+ assert_equal(
171
+ [
172
+ '20091114_0001',
173
+ '20091114_0002',
174
+ '20091115_0001',
175
+ '20091225_0001',
176
+ '20091225_0002',
177
+ '20091226_0001',
178
+ ],
179
+ storage.select(:order => 'id'),
180
+ "#{storage.class}#_sort should override sd[:order] by conds[:order]"
181
+ )
182
+
183
+ storage.sd[:order] = 'id'
184
+ end
185
+
186
+ def _test_page(storage)
187
+ storage.sd[:p_size] = 4
188
+ assert_equal(
189
+ ['20091114_0001', '20091114_0002', '20091115_0001', '20091225_0001'],
190
+ storage.select(:p => 1),
191
+ "#{storage.class}#_page should paginate the item ids returned by _select()"
192
+ )
193
+ assert_equal(
194
+ ['20091225_0002', '20091226_0001'],
195
+ storage.select(:p => 2),
196
+ "#{storage.class}#_page should paginate the item ids returned by _select()"
197
+ )
198
+ assert_equal(
199
+ [],
200
+ storage.select(:p => 3),
201
+ "#{storage.class}#_page should return an empty list if the page does not exist"
202
+ )
203
+ storage.sd[:p_size] = 10
204
+ end
205
+
206
+ def _test_val(storage)
207
+ assert_equal(
208
+ {'name' => 'baz', 'comment' => 'BAZ BAZ...'},
209
+ storage.val('20091114_0002'),
210
+ "#{storage.class}#val should return the item value"
211
+ )
212
+ assert_nil(
213
+ storage.val('non-existent'),
214
+ "#{storage.class}#val should return nil when there is no item"
215
+ )
216
+ assert_nil(
217
+ storage.val(''),
218
+ "#{storage.class}#val should return nil when there is no item"
219
+ )
220
+ end
221
+
222
+ def _test_val_raw(storage)
223
+ assert_equal(
224
+ "\x01\x02\x03",
225
+ storage.val('20100406_0001'),
226
+ "#{storage.class}#val should return the raw value unless the value is not a hash"
227
+ )
228
+ end
229
+
230
+ def _test_traverse(storage)
231
+ assert_equal(
232
+ [
233
+ '-foo-main-20091120_0001, yaml',
234
+ '-foo-bar-main-20091120_0001, yaml',
235
+ '-foo-sub-20100306_0001, yaml',
236
+ ],
237
+ storage.class.traverse('/foo') {|entry| "#{entry[:full_name]}, #{entry[:ext]}" },
238
+ "#{storage.class}.traverse should traverse over the given dir"
239
+ )
240
+ end
241
+
242
+ def _test_navi(storage)
243
+ _test_navi_p(storage)
244
+ _test_navi_id(storage)
245
+ _test_navi_d(storage)
246
+ _test_navi_all(storage)
247
+
248
+ storage.sd[:p_size] = 10
249
+ end
250
+
251
+ def _test_navi_p(storage)
252
+ storage.sd[:p_size] = 2
253
+ assert_equal(
254
+ {
255
+ :prev => {:d => '200912', :p => '1'},
256
+ :sibs => {:p => ['1', '2']},
257
+ },
258
+ storage.navi(:d => '200912', :p => '2'),
259
+ "#{storage.class}#navi should return the next conditions for the given conds"
260
+ )
261
+ assert_equal(
262
+ {
263
+ :prev => {:d => '200911', :p => '2'},
264
+ :next => {:d => '200912', :p => '2'},
265
+ :sibs => {:p => ['1', '2']},
266
+ },
267
+ storage.navi(:d => '200912', :p => '1'),
268
+ "#{storage.class}#navi should return the next conditions for the given conds"
269
+ )
270
+ assert_equal(
271
+ {
272
+ :prev => {:d => '200911', :p => '1'},
273
+ :next => {:d => '200912', :p => '1'},
274
+ :sibs => {:p => ['1', '2']},
275
+ },
276
+ storage.navi(:d => '200911', :p => '2'),
277
+ "#{storage.class}#navi should return the next conditions for the given conds"
278
+ )
279
+ assert_equal(
280
+ {
281
+ :next => {:d => '200911', :p => '2'},
282
+ :sibs => {:p => ['1', '2']},
283
+ },
284
+ storage.navi(:d => '200911', :p => '1'),
285
+ "#{storage.class}#navi should return the next conditions for the given conds"
286
+ )
287
+ end
288
+
289
+ def _test_navi_id(storage)
290
+ storage.sd[:p_size] = 2
291
+ assert_equal(
292
+ {
293
+ :prev => {:id => '20091225_0002'},
294
+ :sibs => {
295
+ :id => [
296
+ '20091114_0001',
297
+ '20091114_0002',
298
+ '20091115_0001',
299
+ '20091225_0001',
300
+ '20091225_0002',
301
+ '20091226_0001',
302
+ ],
303
+ },
304
+ },
305
+ storage.navi(:id => '20091226_0001'),
306
+ "#{storage.class}#navi should return the next conditions for the given conds"
307
+ )
308
+
309
+ assert_equal(
310
+ {
311
+ :prev => {:d => '200912', :id => '20091225_0002'},
312
+ :sibs => {:id => ['20091225_0001', '20091225_0002', '20091226_0001']},
313
+ },
314
+ storage.navi(:d => '200912', :id => '20091226_0001'),
315
+ "#{storage.class}#navi should return the next conditions for the given conds"
316
+ )
317
+ assert_equal(
318
+ {
319
+ :prev => {:d => '200911', :id => '20091115_0001'},
320
+ :next => {:d => '200912', :id => '20091225_0002'},
321
+ :sibs => {:id => ['20091225_0001', '20091225_0002', '20091226_0001']},
322
+ },
323
+ storage.navi(:d => '200912', :id => '20091225_0001'),
324
+ "#{storage.class}#navi should return the next conditions for the given conds"
325
+ )
326
+ assert_equal(
327
+ {
328
+ :prev => {:d => '200911', :id => '20091114_0002'},
329
+ :next => {:d => '200912', :id => '20091225_0001'},
330
+ :sibs => {:id => ['20091114_0001', '20091114_0002', '20091115_0001']},
331
+ },
332
+ storage.navi(:d => '200911', :id => '20091115_0001'),
333
+ "#{storage.class}#navi should return the next conditions for the given conds"
334
+ )
335
+ assert_equal(
336
+ {
337
+ :next => {:d => '200911', :id => '20091114_0002'},
338
+ :sibs => {:id => ['20091114_0001', '20091114_0002', '20091115_0001']},
339
+ },
340
+ storage.navi(:d => '200911', :id => '20091114_0001'),
341
+ "#{storage.class}#navi should return the next conditions for the given conds"
342
+ )
343
+ end
344
+
345
+ def _test_navi_d(storage)
346
+ storage.sd[:p_size] = nil
347
+ assert_equal(
348
+ {
349
+ :prev => {:d => '200911'},
350
+ :sibs => {:d => ['200911', '200912']},
351
+ },
352
+ storage.navi(:d => '200912'),
353
+ "#{storage.class}#navi should return the next conditions for the given conds"
354
+ )
355
+ assert_equal(
356
+ {
357
+ :next => {:d => '200912'},
358
+ :sibs => {:d => ['200911', '200912']},
359
+ },
360
+ storage.navi(:d => '200911'),
361
+ "#{storage.class}#navi should return the next conditions for the given conds"
362
+ )
363
+
364
+ assert_equal(
365
+ {
366
+ :prev => {:d => '200911', :order => 'd'},
367
+ :sibs => {:d => ['200911', '200912']},
368
+ },
369
+ storage.navi(:d => '200912', :order => 'd'),
370
+ "#{storage.class}#navi should return the next conditions for the given conds"
371
+ )
372
+ assert_equal(
373
+ {
374
+ :next => {:d => '200912', :order => '-d'},
375
+ :sibs => {:d => ['200911', '200912']},
376
+ },
377
+ storage.navi(:d => '200911', :order => '-d'),
378
+ "#{storage.class}#navi should return the next conditions for the given conds"
379
+ )
380
+ end
381
+
382
+ def _test_navi_all(storage)
383
+ storage.sd[:p_size] = nil
384
+ assert_equal(
385
+ {},
386
+ storage.navi({}),
387
+ "#{storage.class}#navi without conds should return an empty navi"
388
+ )
389
+ end
390
+
391
+ def _test_last(storage)
392
+ assert_equal(
393
+ '20091226',
394
+ storage.last(:d, :d => '99999999'),
395
+ "#{storage.class}#last should cast 'the last' conds"
396
+ )
397
+ assert_equal(
398
+ '200912',
399
+ storage.last(:d, :d => '999999'),
400
+ "#{storage.class}#last should cast 'the last' conds"
401
+ )
402
+
403
+ assert_equal(
404
+ '20091226_0001',
405
+ storage.last(:id, :id => ['20091114_0001', 'last']),
406
+ "#{storage.class}#last should cast 'the last' conds"
407
+ )
408
+
409
+ storage.sd[:p_size] = 2
410
+ assert_equal(
411
+ '3',
412
+ storage.last(:p, :p => 'last'),
413
+ "#{storage.class}#last should cast 'the last' conds"
414
+ )
415
+ storage.sd[:p_size] = 10
416
+ end
417
+
418
+ def _test_fetch_special_id(storage)
419
+ assert_equal(
420
+ [
421
+ '00000000_bobby',
422
+ '00000000_carl',
423
+ '00000000_frank',
424
+ ],
425
+ storage.select,
426
+ "#{storage.class}#select should be able to select special ids"
427
+ )
428
+ assert_equal(
429
+ ['00000000_carl'],
430
+ storage.select(:id => '00000000_carl'),
431
+ "#{storage.class}#select should be able to select special ids"
432
+ )
433
+ assert_equal(
434
+ ['00000000_bobby'],
435
+ storage.select(:id => 'bobby'),
436
+ "#{storage.class}#select should expand short ids"
437
+ )
438
+
439
+ assert_equal(
440
+ [
441
+ '00000000_frank',
442
+ '00000000_carl',
443
+ '00000000_bobby',
444
+ ],
445
+ storage.select(:order => '-id'),
446
+ "#{storage.class}#select should sort special ids"
447
+ )
448
+
449
+ assert_equal(
450
+ {
451
+ :next => {:id => '00000000_carl'},
452
+ :sibs => {:id => ['00000000_bobby', '00000000_carl', '00000000_frank']},
453
+ },
454
+ storage.navi(:id => '00000000_bobby'),
455
+ "#{storage.class}#navi should return the next conditions for special ids"
456
+ )
457
+ end
458
+
459
+ def test_store
460
+ sd = Runo::Set::Static::Folder.root.item('t_store', 'main')
461
+
462
+ Runo::Storage.constants.collect {|c| Runo::Storage.const_get c }.each {|klass|
463
+ next unless klass.is_a?(::Class) && klass.available?
464
+
465
+ storage = klass.new sd
466
+ storage.clear
467
+
468
+ id = _test_add(storage)
469
+ _test_update(storage, id)
470
+ _test_delete(storage, id)
471
+
472
+ _test_new_id(storage)
473
+ _test_rename(storage)
474
+ _test_clear(storage)
475
+
476
+ id = _test_add_raw(storage)
477
+ _test_update_raw(storage, id)
478
+ _test_delete_raw(storage, id)
479
+ _test_clear_raw(storage)
480
+
481
+ _test_delete_substr(storage) unless klass == Runo::Storage::Temp
482
+ _test_load_skel(storage) unless klass == Runo::Storage::Temp
483
+ }
484
+ end
485
+
486
+ def _test_add(storage)
487
+ id = nil
488
+ assert_nothing_raised(
489
+ "#{storage.class}#store should work nicely"
490
+ ) {
491
+ id = storage.store(:new_id, {'foo' => 'bar'})
492
+ }
493
+ assert_match(
494
+ Runo::REX::ID,
495
+ id,
496
+ "#{storage.class}#store should return the id of the created item"
497
+ )
498
+ assert_equal(
499
+ {'foo' => 'bar'},
500
+ storage.val(id),
501
+ "#{storage.class}#store should store the element with the given id"
502
+ )
503
+ id # for other tests
504
+ end
505
+
506
+ def _test_update(storage, id)
507
+ storage.store(id, {'foo' => 'updated'})
508
+ assert_equal(
509
+ {'foo' => 'updated'},
510
+ storage.val(id),
511
+ "#{storage.class}#store should store the element with the given id"
512
+ )
513
+ end
514
+
515
+ def _test_delete(storage, id)
516
+ assert_nothing_raised(
517
+ "#{storage.class}#delete should work nicely"
518
+ ) {
519
+ id = storage.delete(id)
520
+ }
521
+ assert_match(
522
+ Runo::REX::ID,
523
+ id,
524
+ "#{storage.class}#delete should return the id of the deleted item"
525
+ )
526
+ assert_nil(
527
+ storage.val(id),
528
+ "#{storage.class}#delete should delete the element with the given id"
529
+ )
530
+ end
531
+
532
+ def _test_new_id(storage)
533
+ id1 = storage.store(:new_id, {'foo' => 'bar'})
534
+ assert_match(
535
+ Runo::REX::ID,
536
+ id1,
537
+ "#{storage.class}#new_id should return a valid id for the element"
538
+ )
539
+
540
+ id2 = storage.store(:new_id, {'foo' => 'bar'})
541
+ assert_match(
542
+ Runo::REX::ID,
543
+ id2,
544
+ "#{storage.class}#new_id should return a valid id for the element"
545
+ )
546
+ assert_not_equal(
547
+ id1,
548
+ id2,
549
+ "#{storage.class}#new_id should return a unique id for the element"
550
+ )
551
+
552
+ id3 = storage.store(:new_id, {'foo' => 'bar', '_id' => 'carl'})
553
+ assert_match(
554
+ Runo::REX::ID,
555
+ id3,
556
+ "#{storage.class}#new_id should return a valid id for the element"
557
+ )
558
+ assert_equal(
559
+ '00000000_carl',
560
+ id3,
561
+ "#{storage.class}#new_id should refer to val['_id'] if available"
562
+ )
563
+
564
+ id4 = storage.store(:new_id, {'foo' => 'duplicated!', '_id' => 'carl'})
565
+ assert_nil(
566
+ id4,
567
+ "#{storage.class}#store should not create an item with a duplicate id"
568
+ )
569
+
570
+ id5 = storage.store(
571
+ :new_id,
572
+ {'_timestamp' => {'published' => Time.local(1981, 4, 26)}}
573
+ )
574
+ assert_match(
575
+ Runo::REX::ID,
576
+ id5,
577
+ "#{storage.class}#new_id should return a valid id for the element"
578
+ )
579
+ assert_equal(
580
+ '19810426_0001',
581
+ id5,
582
+ "#{storage.class}#new_id should refer to val['_timestamp'] if available"
583
+ )
584
+ end
585
+
586
+ def _test_rename(storage)
587
+ orig_id = storage.store(:new_id, {'_id' => 'test', 'foo' => 'bar'})
588
+ file_id = storage.store("#{orig_id}-file", 'i am file.', 'bin')
589
+ new_id = storage.store(orig_id, {'_id' => 'renamed'})
590
+
591
+ assert_not_equal(
592
+ orig_id,
593
+ new_id,
594
+ "#{storage.class}#store should rename the element given a different _id"
595
+ )
596
+ assert_equal(
597
+ {'_id' => 'renamed'},
598
+ storage.val(new_id),
599
+ "#{storage.class}#store should rename the element given a different _id"
600
+ )
601
+ assert_equal(
602
+ 'i am file.',
603
+ storage.val("#{new_id}-file"),
604
+ "#{storage.class}#store should rename the descendant elements"
605
+ )
606
+ assert_nil(
607
+ storage.val(orig_id),
608
+ "#{storage.class}#store should rename the element given a different _id"
609
+ )
610
+ assert_nil(
611
+ storage.val(file_id),
612
+ "#{storage.class}#store should rename the descendant elements"
613
+ )
614
+
615
+ orig_id = storage.store(:new_id, {'foo' => 'bar'})
616
+ new_id = storage.store(orig_id, {'_timestamp' => {'published' => Time.local(2010, 4, 15)}})
617
+
618
+ assert_not_equal(
619
+ orig_id,
620
+ new_id,
621
+ "#{storage.class}#store should rename the element given a different _timestamp"
622
+ )
623
+ assert_equal(
624
+ {'_timestamp' => {'published' => Time.local(2010, 4, 15)}},
625
+ storage.val(new_id),
626
+ "#{storage.class}#store should rename the element given a different _timestamp"
627
+ )
628
+ assert_nil(
629
+ storage.val(orig_id),
630
+ "#{storage.class}#store should rename the element given a different _timestamp"
631
+ )
632
+ end
633
+
634
+ def _test_clear(storage)
635
+ id1 = storage.store(:new_id, {'foo' => 'bar'})
636
+ id2 = storage.store(:new_id, {'foo' => 'bar'})
637
+
638
+ storage.clear
639
+
640
+ assert_nil(
641
+ storage.val(id1),
642
+ "#{storage.class}#clear should delete all elements"
643
+ )
644
+ assert_nil(
645
+ storage.val(id2),
646
+ "#{storage.class}#clear should delete all elements"
647
+ )
648
+ end
649
+
650
+ def _test_add_raw(storage)
651
+ id = nil
652
+ assert_nothing_raised(
653
+ "#{storage.class}#store should store raw value nicely"
654
+ ) {
655
+ id = storage.store(:new_id, "\x01\x02\x03", 'jpg')
656
+ }
657
+ assert_equal(
658
+ "\x01\x02\x03",
659
+ storage.val(id),
660
+ "#{storage.class}#store should store the raw file with the given id"
661
+ )
662
+ id # for other tests
663
+ end
664
+
665
+ def _test_update_raw(storage, id)
666
+ storage.store(id, "\x04\x05\x06", 'png')
667
+ assert_equal(
668
+ "\x04\x05\x06",
669
+ storage.val(id),
670
+ "#{storage.class}#store should overwrite a file with the same id"
671
+ )
672
+ end
673
+
674
+ def _test_delete_raw(storage, id)
675
+ assert_nothing_raised(
676
+ "#{storage.class}#delete should work nicely on raw files"
677
+ ) {
678
+ id = storage.delete(id)
679
+ }
680
+ assert_match(
681
+ Runo::REX::ID,
682
+ id,
683
+ "#{storage.class}#delete should return the id of the deleted item"
684
+ )
685
+ assert_nil(
686
+ storage.val(id),
687
+ "#{storage.class}#delete should delete the element with the given id"
688
+ )
689
+ end
690
+
691
+ def _test_clear_raw(storage)
692
+ id1 = storage.store('20100430_0001-file', "\x03\x02\x01", 'jpg')
693
+ id2 = storage.store('20100430_0002-file', "\x03\x02\x01", 'png')
694
+
695
+ storage.clear
696
+
697
+ assert_nil(
698
+ storage.val(id1),
699
+ "#{storage.class}#clear should delete all elements"
700
+ )
701
+ assert_nil(
702
+ storage.val(id2),
703
+ "#{storage.class}#clear should delete all elements"
704
+ )
705
+ end
706
+
707
+ def _test_load_skel(storage)
708
+ sd = Runo::Set::Static::Folder.root.item('t_summary', 'main')
709
+ storage = storage.class.new sd
710
+
711
+ storage.delete '20100326_0001'
712
+ assert_nil(storage.val('20100326_0001'))
713
+
714
+ storage.class.load_skel
715
+ assert_equal(
716
+ {'name' => 'frank', 'comment' => 'hi.'},
717
+ storage.val('20100326_0001'),
718
+ "#{storage.class}.load_skel should load the default entries"
719
+ )
720
+ end
721
+
722
+ def _test_delete_substr(storage)
723
+ storage.clear
724
+ storage.store('00000000_bob', {'foo' => 'bar'})
725
+ storage.store('00000000_bobby', {'foo' => 'baz'})
726
+ storage.delete '00000000_bob'
727
+ assert_equal(
728
+ {'00000000_bobby' => {'foo' => 'baz'}},
729
+ storage.val,
730
+ "#{storage.class}#delete should not delete another ids that matches the given id"
731
+ )
732
+
733
+ storage.clear
734
+ storage.store('20100527_1234', {'foo' => 'bar'})
735
+ storage.store('20100527_12345', {'foo' => 'baz'})
736
+ storage.delete '20100527_1234'
737
+ assert_equal(
738
+ {'20100527_12345' => {'foo' => 'baz'}},
739
+ storage.val,
740
+ "#{storage.class}#delete should not delete another ids that matches the given id"
741
+ )
742
+
743
+ storage.clear
744
+ storage.store('00000000_bob', {'foo' => 'bar'})
745
+ storage.store('00000000_bob-foo', 'qux', 'bin')
746
+ storage.store('00000000_bobby', {'foo' => 'baz'})
747
+ storage.delete '00000000_bob'
748
+ assert_equal(
749
+ {'00000000_bobby' => {'foo' => 'baz'}},
750
+ storage.val,
751
+ "#{storage.class}#delete should delete child ids that matches the given id"
752
+ )
753
+ end
754
+
755
+ def test_cast_d
756
+ sd = Runo::Set::Dynamic.new(
757
+ :klass => 'set-dynamic'
758
+ ).load(
759
+ '20091128_0001' => {'name' => 'frank', 'comment' => 'bar'},
760
+ '20091130_0001' => {'name' => 'frank', 'comment' => 'bar'},
761
+ '20091201_0001' => {'name' => 'frank', 'comment' => 'bar'}
762
+ )
763
+ storage = sd.storage
764
+
765
+ assert_equal(
766
+ {:d => '20100131'},
767
+ storage.send(
768
+ :_cast,
769
+ {:d => ['20100131']}
770
+ ),
771
+ 'Storage#_cast should cast conds[:d] as a string'
772
+ )
773
+ assert_equal(
774
+ {:d => nil},
775
+ storage.send(
776
+ :_cast,
777
+ {:d => '30100131'}
778
+ ),
779
+ 'Storage#_cast should bang malformed conds[:d]'
780
+ )
781
+ assert_equal(
782
+ {:d => '20091201'},
783
+ storage.send(
784
+ :_cast,
785
+ {:d => '99999999'}
786
+ ),
787
+ "Storage#_cast should cast 'the last' conds"
788
+ )
789
+ assert_equal(
790
+ {:d => '200912'},
791
+ storage.send(
792
+ :_cast,
793
+ {:d => '999999'}
794
+ ),
795
+ "Storage#_cast should cast 'the last' conds"
796
+ )
797
+ end
798
+
799
+ def test_cast_id
800
+ sd = Runo::Set::Dynamic.new(
801
+ :klass => 'set-dynamic'
802
+ ).load(
803
+ '20091128_0001' => {'name' => 'frank', 'comment' => 'bar'},
804
+ '20091130_0001' => {'name' => 'frank', 'comment' => 'bar'},
805
+ '20091226_0001' => {'name' => 'frank', 'comment' => 'bar'}
806
+ )
807
+ storage = sd.storage
808
+
809
+ assert_equal(
810
+ {:id => ['20091226_0001']},
811
+ storage.send(
812
+ :_cast,
813
+ {:id => '20091226_0001'}
814
+ ),
815
+ 'Storage#_cast should cast conds[:id] as an array'
816
+ )
817
+ assert_equal(
818
+ {:id => ['20091226_0001']},
819
+ storage.send(
820
+ :_cast,
821
+ {:id => ['20091226_0001', '../i_am_evil']}
822
+ ),
823
+ 'Storage#_cast should bang malformed conds[:id]'
824
+ )
825
+ assert_equal(
826
+ {:id => ['20091114_0001', '20091226_0001']},
827
+ storage.send(
828
+ :_cast,
829
+ {:id => ['20091114_0001', 'last']}
830
+ ),
831
+ "Storage#_cast should cast 'the last' conds"
832
+ )
833
+ end
834
+
835
+ def test_cast_p
836
+ sd = Runo::Set::Dynamic.new(
837
+ :klass => 'set-dynamic'
838
+ ).load(
839
+ '20091128_0001' => {'name' => 'frank', 'comment' => 'bar'},
840
+ '20091130_0001' => {'name' => 'frank', 'comment' => 'bar'},
841
+ '20091226_0001' => {'name' => 'frank', 'comment' => 'bar'},
842
+ '20100207_0001' => {'name' => 'frank', 'comment' => 'bar'},
843
+ '20100207_0002' => {'name' => 'frank', 'comment' => 'bar'}
844
+ )
845
+ storage = sd.storage
846
+
847
+ sd[:p_size] = 2
848
+ assert_equal(
849
+ {:p => '123'},
850
+ storage.send(
851
+ :_cast,
852
+ {:p => ['123']}
853
+ ),
854
+ 'Storage#_cast should cast conds[:p] as a string'
855
+ )
856
+ assert_equal(
857
+ {:p => nil},
858
+ storage.send(
859
+ :_cast,
860
+ {:p => 'i am evil'}
861
+ ),
862
+ 'Storage#_cast should bang malformed conds[:p]'
863
+ )
864
+ assert_equal(
865
+ {:p => '3'},
866
+ storage.send(
867
+ :_cast,
868
+ {:p => 'last'}
869
+ ),
870
+ "Storage#_cast should cast 'the last' conds"
871
+ )
872
+ end
873
+
874
+ def test_new_id?
875
+ storage = Runo::Set::Static::Folder.root.item('t_select', 'main').storage
876
+
877
+ assert(
878
+ storage.send(:new_id?, :new_id, {}),
879
+ 'Storage#new_id? should return true if the current id is :new_id'
880
+ )
881
+
882
+ assert(
883
+ !storage.send(:new_id?, '20100523_0001', 'foo'),
884
+ 'Storage#new_id? should return false if v is a scalar'
885
+ )
886
+
887
+ assert(
888
+ !storage.send(:new_id?, '00000000_foo', {'_id' => 'foo'}),
889
+ "Storage#new_id? should return false if v['_id'] is same as the current id"
890
+ )
891
+ assert(
892
+ storage.send(:new_id?, '00000000_foo', {'_id' => 'bar'}),
893
+ "Storage#new_id? should return true if v['_id'] differs from the current id"
894
+ )
895
+
896
+ assert(
897
+ !storage.send(:new_id?, '20100523_0001', {'_timestamp' => {'published' => Time.parse('2010-05-23')}}),
898
+ "Storage#new_id? should return false if v['_timestamp'] is same as the current id"
899
+ )
900
+ assert(
901
+ storage.send(:new_id?, '20100523_0001', {'_timestamp' => {'published' => Time.parse('2010-05-24')}}),
902
+ "Storage#new_id? should return false if v['_timestamp'] differs from the current id"
903
+ )
904
+
905
+ assert(
906
+ !storage.send(:new_id?, '00000000_foo', {'_id' => 'foo', '_timestamp' => {'published' => Time.parse('2010-05-24')}}),
907
+ "Storage#new_id? should not refer to v['timestamp'] if v['_id'] matched SHORT_ID"
908
+ )
909
+ assert(
910
+ !storage.send(:new_id?, '00000000_foo', {'_timestamp' => {'published' => Time.parse('2010-05-24')}}),
911
+ "Storage#new_id? should not refer to v['timestamp'] if v['_id'] matched SHORT_ID"
912
+ )
913
+ end
914
+
915
+ end