runo 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (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