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,1504 @@
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_Set_Dynamic < Test::Unit::TestCase
9
+
10
+ def setup
11
+ @sd = Runo::Set::Dynamic.new(
12
+ :id => 'foo',
13
+ :klass => 'set-dynamic',
14
+ :workflow => 'blog',
15
+ :group => ['roy', 'don'],
16
+ :tmpl => {
17
+ :index => <<'_tmpl'.chomp,
18
+ <ul id="foo" class="runo-blog">
19
+ $()</ul>
20
+ $(.submit)
21
+ _tmpl
22
+ },
23
+ :item => {
24
+ 'default' => Runo::Parser.parse_html(<<'_html')
25
+ <li>$(name = text 16 0..16 :'nobody'): $(comment = text 64 :'hi.')$(.hidden)</li>
26
+ _html
27
+ }
28
+ )
29
+ @sd[:conds] = {}
30
+ @sd[:order] = nil
31
+ @sd[:tmpl][:action_create] = ''
32
+ def @sd._g_submit(arg)
33
+ "[#{my[:id]}-#{arg[:orig_action]}#{arg[:sub_action] && ('.' + arg[:sub_action].to_s)}]\n"
34
+ end
35
+ @sd[:item]['default'][:item].delete '_timestamp'
36
+ Runo.client = 'root'
37
+ Runo.current[:base] = nil
38
+ end
39
+
40
+ def teardown
41
+ Runo.client = nil
42
+ end
43
+
44
+ def test_storage
45
+ assert_kind_of(
46
+ Runo::Storage,
47
+ @sd.storage,
48
+ 'Set::Dynamic#instance should load an apropriate storage for the list'
49
+ )
50
+ assert_instance_of(
51
+ Runo::Storage::Temp,
52
+ @sd.storage,
53
+ 'Set::Dynamic#instance should load an apropriate storage for the list'
54
+ )
55
+ end
56
+
57
+ class Runo::Workflow::Default_meta < Runo::Workflow
58
+ DEFAULT_META = {:foo => 'FOO'}
59
+ end
60
+ def test_default_meta
61
+ sd = Runo::Set::Dynamic.new(:workflow => 'default_meta')
62
+ assert_equal(
63
+ 'FOO',
64
+ sd[:foo],
65
+ 'Set::Dynamic#[] should look for the default value in the workflow'
66
+ )
67
+
68
+ sd = Runo::Set::Dynamic.new(:workflow => 'default_meta', :foo => 'BAR')
69
+ assert_equal(
70
+ 'BAR',
71
+ sd[:foo],
72
+ 'workflow.DEFAULT_META should be eclipsed by @meta'
73
+ )
74
+
75
+ sd = Runo::Set::Dynamic.new(:workflow => 'default_meta')
76
+ def sd.meta_foo
77
+ 'abc'
78
+ end
79
+ assert_equal(
80
+ 'abc',
81
+ sd[:foo],
82
+ 'workflow.DEFAULT_META should be eclipsed by meta_*()'
83
+ )
84
+ end
85
+
86
+ def test_meta_tid
87
+ tid = @sd[:tid]
88
+ assert_match(
89
+ Runo::REX::TID,
90
+ tid,
91
+ 'Set::Dynamic#meta_tid should return an unique id per an instance'
92
+ )
93
+ assert_equal(
94
+ tid,
95
+ @sd[:tid],
96
+ 'Set::Dynamic#meta_tid should return the same id throughout the lifecycle of the item'
97
+ )
98
+ assert_not_equal(
99
+ tid,
100
+ Runo::Set::Dynamic.new[:tid],
101
+ 'Set::Dynamic#meta_tid should be unique to an item'
102
+ )
103
+ end
104
+
105
+ def test_meta_base_path
106
+ item = Runo::Set::Static::Folder.root.item('foo', 'main')
107
+
108
+ Runo.current[:base] = Runo::Set::Static::Folder.root.item('foo', 'bar', 'sub')
109
+ assert_equal(
110
+ '/foo/bar/sub',
111
+ item[:base_path],
112
+ 'Field#[:base_path] should return the path name of the base SD'
113
+ )
114
+
115
+ Runo.current[:base] = Runo::Set::Static::Folder.root.item('foo', 'bar', 'main')
116
+ assert_equal(
117
+ '/foo/bar',
118
+ item[:base_path],
119
+ "Field#[:base_path] should omit 'main' in the path"
120
+ )
121
+ end
122
+
123
+ def test_meta_order
124
+ sd = Runo::Set::Dynamic.new(
125
+ :id => 'foo',
126
+ :klass => 'set-dynamic',
127
+ :workflow => 'contact'
128
+ )
129
+ assert_nil(
130
+ sd[:order],
131
+ 'Set::Dynamic#[:order] should be nil by default'
132
+ )
133
+
134
+ sd = Runo::Set::Dynamic.new(
135
+ :id => 'foo',
136
+ :klass => 'set-dynamic',
137
+ :workflow => 'blog'
138
+ )
139
+ assert_equal(
140
+ '-id',
141
+ sd[:order],
142
+ 'Set::Dynamic#[:order] should refer to the default_meta[:order]'
143
+ )
144
+
145
+ sd = Runo::Set::Dynamic.new(
146
+ :id => 'foo',
147
+ :klass => 'set-dynamic',
148
+ :workflow => 'blog',
149
+ :tokens => ['asc']
150
+ )
151
+ assert_equal(
152
+ 'id',
153
+ sd[:order],
154
+ 'Set::Dynamic#[:order] should be overriden by meta[:order]'
155
+ )
156
+ end
157
+
158
+ def test_meta_href
159
+ Runo.current[:uri] = nil
160
+
161
+ sd = Runo::Set::Static::Folder.root.item('foo','main')
162
+ assert_equal(
163
+ '/foo/',
164
+ sd[:href],
165
+ 'Set::Dynamic#meta_href should return the uri to itself'
166
+ )
167
+
168
+ sd = Runo::Set::Static::Folder.root.item('foo','sub')
169
+ assert_equal(
170
+ '/foo/sub/',
171
+ sd[:href],
172
+ "Set::Dynamic#meta_href should not omit steps other than 'main'"
173
+ )
174
+
175
+ sd = Runo::Set::Static::Folder.root.item('foo','main','20091120_0001','replies')
176
+ assert_equal(
177
+ '/foo/20091120_0001/replies/',
178
+ sd[:href],
179
+ 'Set::Dynamic#meta_href should return the proper uri for a nested SD'
180
+ )
181
+ end
182
+
183
+ def test_item
184
+ @sd.load('20100131_1234' => {'name' => 'frank'})
185
+ assert_instance_of(
186
+ Runo::Set::Static,
187
+ @sd.item('20100131_1234'),
188
+ 'Set::Dynamic#item should return the child set in the storage'
189
+ )
190
+
191
+ assert_nil(
192
+ @sd.item('non-existent'),
193
+ 'Set::Dynamic#item should return nil when the item is not in the storage'
194
+ )
195
+ assert_nil(
196
+ @sd.item(''),
197
+ 'Set::Dynamic#item should return nil when the item is not in the storage'
198
+ )
199
+ end
200
+
201
+ def test_val
202
+ @sd.load(
203
+ '20100131_1234' => {'name' => 'frank'},
204
+ '20100131_1235' => {'name' => 'carl'}
205
+ )
206
+ assert_equal(
207
+ {
208
+ '20100131_1234' => {'name' => 'frank'},
209
+ '20100131_1235' => {'name' => 'carl'},
210
+ },
211
+ @sd.val,
212
+ 'Set::Dynamic#val without arg should return values of all items in the storage'
213
+ )
214
+ assert_equal(
215
+ {'name' => 'frank'},
216
+ @sd.val('20100131_1234'),
217
+ 'Set::Dynamic#val with an item id should return the value of the item in the storage'
218
+ )
219
+ assert_nil(
220
+ @sd.val('non-existent'),
221
+ 'Set::Dynamic#val with an item id should return nil when the item is not in the storage'
222
+ )
223
+ end
224
+
225
+ def test_get
226
+ @sd.load(
227
+ '20100131_1234' => {'name' => 'frank', 'comment' => 'bar'},
228
+ '20100131_1235' => {'name' => 'carl', 'comment' => 'baz'}
229
+ )
230
+ @sd[:tmpl][:navi] = ''
231
+ @sd.each {|item| item[:tmpl][:action_update] = '' }
232
+ assert_equal(
233
+ <<'_html',
234
+ <ul id="foo" class="runo-blog">
235
+ <li>frank: bar</li>
236
+ <li>carl: baz</li>
237
+ </ul>
238
+ _html
239
+ @sd.get,
240
+ 'Set::Dynamic#get should return the html by [:tmpl]'
241
+ )
242
+ assert_equal(
243
+ <<'_html',
244
+ <ul id="foo" class="runo-blog">
245
+ <li>carl: baz</li>
246
+ </ul>
247
+ _html
248
+ @sd.get(:conds => {:id => '20100131_1235'}),
249
+ 'Set::Dynamic#get should return the html by [:tmpl]'
250
+ )
251
+
252
+ @sd.each {|ss|
253
+ ss.each {|item|
254
+ def item._g_update(arg)
255
+ 'moo!'
256
+ end
257
+ }
258
+ }
259
+ assert_equal(
260
+ <<'_html',
261
+ <ul id="foo" class="runo-blog">
262
+ <li>moo!: moo!</li>
263
+ </ul>
264
+ [foo-update]
265
+ _html
266
+ @sd.get(:conds => {:id => '20100131_1235'}, :action => :update),
267
+ 'Set::Dynamic#get should pass the given action to lower items'
268
+ )
269
+ end
270
+
271
+ def test_get_create
272
+ @sd.load(
273
+ '1234' => {'name' => 'frank', 'comment' => 'bar'},
274
+ '1235' => {'name' => 'carl', 'comment' => 'baz'}
275
+ )
276
+ result = @sd.get(:action => :create)
277
+ assert_match(
278
+ /<input/,
279
+ result,
280
+ 'Set::Dynamic#_g_create should return the _g_create() of a newly created item'
281
+ )
282
+ assert_no_match(
283
+ /bar/,
284
+ result,
285
+ 'Set::Dynamic#_g_create should not include the _g_create() of existing items'
286
+ )
287
+ end
288
+
289
+ def test_get_empty_item
290
+ @sd.load(
291
+ '1234' => {}
292
+ )
293
+
294
+ assert_equal(
295
+ <<'_html',
296
+ <ul id="foo" class="runo-blog">
297
+ </ul>
298
+ _html
299
+ @sd.get(:action => :read),
300
+ 'Set#_g_default should skip empty items'
301
+ )
302
+
303
+ assert_equal(
304
+ <<'_html',
305
+ <ul id="foo" class="runo-blog">
306
+ <li><span class="text"><input type="text" name="name" value="" size="16" /></span>: <span class="text"><input type="text" name="comment" value="" size="64" /></span></li>
307
+ </ul>
308
+ [foo-update]
309
+ _html
310
+ @sd.get(:action => :update),
311
+ 'Set#_g_default should not skip empty items when the action is :create or :update'
312
+ )
313
+ end
314
+
315
+ def test_get_preview
316
+ Runo.current[:base] = nil
317
+ @sd.load(
318
+ '20100330_1234' => {'name' => 'frank', 'comment' => 'bar'},
319
+ '20100330_1235' => {'name' => 'carl', 'comment' => 'baz'}
320
+ )
321
+ assert_equal(
322
+ <<'_html',
323
+ <ul id="foo" class="runo-blog">
324
+ <li>frank: bar<input type="hidden" name="20100330_1234.action" value="howdy" /></li>
325
+ </ul>
326
+ [foo-preview.howdy]
327
+ _html
328
+ @sd.get(:action => :preview, :sub_action => :howdy, :conds => {:id => '20100330_1234'}),
329
+ 'Set::Dynamic#_g_preview should return _g_read + _g_submit'
330
+ )
331
+ end
332
+
333
+ def test_get_by_self_reference
334
+ ss = Runo::Set::Static.new(
335
+ :html => '<ul class="runo-attachment"><li class="body"></li>$(.pipco)</ul>'
336
+ )
337
+ sd = ss.item('main')
338
+ def sd._g_submit(arg)
339
+ ''
340
+ end
341
+ def sd._g_pipco(arg)
342
+ _get_by_action_tmpl(arg) || 'PIPCO'
343
+ end
344
+ def sd._g_jawaka(arg)
345
+ 'JAWAKA'
346
+ end
347
+ sd[:tmpl][:navi] = ''
348
+
349
+ sd[:tmpl][:pipco] = '<foo>$(.jawaka)</foo>'
350
+ sd[:tmpl][:jawaka] = nil
351
+ assert_equal(
352
+ '<ul class="runo-attachment"><foo>JAWAKA</foo></ul>',
353
+ ss.get,
354
+ 'Set::Dynamic#_get_by_self_reference should work via [:parent]._get_by_tmpl()'
355
+ )
356
+
357
+ sd[:tmpl][:pipco] = '<foo>$(.jawaka)</foo>'
358
+ sd[:tmpl][:jawaka] = 'via tmpl'
359
+ assert_equal(
360
+ '<ul class="runo-attachment"><foo>JAWAKA</foo></ul>',
361
+ ss.get,
362
+ 'Set::Dynamic#_get_by_self_reference should not recur'
363
+ )
364
+
365
+ sd[:tmpl][:pipco] = '<foo>$(.pipco)</foo>'
366
+ sd[:tmpl][:jawaka] = nil
367
+ assert_nothing_raised(
368
+ 'Set::Dynamic#_get_by_self_reference should not cause an infinite reference'
369
+ ) {
370
+ ss.get
371
+ }
372
+
373
+ sd[:tmpl][:pipco] = '<foo>$()</foo>'
374
+ assert_nothing_raised(
375
+ 'Set::Dynamic#_get_by_self_reference should not cause an infinite reference'
376
+ ) {
377
+ ss.get
378
+ }
379
+
380
+ sd[:tmpl][:pipco] = '<foo>$(.jawaka)</foo>'
381
+ sd[:tmpl][:jawaka] = '<bar>$(.pipco)</bar>'
382
+ assert_nothing_raised(
383
+ 'Set::Dynamic#_get_by_self_reference should not cause an infinite reference'
384
+ ) {
385
+ ss.get
386
+ }
387
+ end
388
+
389
+ def test_get_by_self_reference_via_parent_tmpl
390
+ ss = Runo::Set::Static.new(
391
+ :html => '$(main.action_pipco)<ul class="runo-attachment"></ul>'
392
+ )
393
+ sd = ss.item('main')
394
+ def sd._g_submit(arg)
395
+ end
396
+ def sd._g_action_pipco(arg)
397
+ 'PIPCO'
398
+ end
399
+ sd[:tmpl][:navi] = ''
400
+
401
+ assert_equal(
402
+ 'PIPCO<ul class="runo-attachment"></ul>',
403
+ ss.get,
404
+ 'Set::Dynamic#_get_by_self_reference should work via [:parent]._get_by_tmpl()'
405
+ )
406
+ assert_equal(
407
+ '<ul class="runo-attachment"></ul>',
408
+ ss.get('main' => {:action => :create}),
409
+ 'Set::Dynamic#_get_by_self_reference should hide unused items via [:parent]._get_by_tmpl()'
410
+ )
411
+ end
412
+
413
+ def test_get_by_self_reference_multiple_vars
414
+ ss = Runo::Set::Static.new(
415
+ :html => '<ul class="runo-attachment">$(.pipco)<li class="body">$(foo=text)</li></ul>'
416
+ )
417
+ sd = ss.item('main')
418
+ def sd._g_pipco(arg)
419
+ 'PIPCO'
420
+ end
421
+ sd[:tmpl][:navi] = ''
422
+
423
+ assert_equal(
424
+ '<ul class="runo-attachment">PIPCO</ul>',
425
+ ss.get,
426
+ 'Set::Dynamic#_get_by_self_reference should not be affected by previous $(.action)'
427
+ )
428
+ end
429
+
430
+ def test_get_uri_prev_next
431
+ @sd[:p_size] = 2
432
+ @sd.load(
433
+ '20091128_0001' => {'name' => 'frank', 'comment' => 'bar'},
434
+ '20091129_0001' => {'name' => 'frank', 'comment' => 'bar'},
435
+ '20091130_0001' => {'name' => 'frank', 'comment' => 'bar'},
436
+ '20091201_0001' => {'name' => 'frank', 'comment' => 'bar'},
437
+ '20091202_0001' => {'name' => 'frank', 'comment' => 'bar'},
438
+ '20091203_0001' => {'name' => 'frank', 'comment' => 'bar'}
439
+ )
440
+
441
+ assert_equal(
442
+ '200912/',
443
+ @sd.send(
444
+ :_g_uri_prev,
445
+ :conds => {:d => '200912', :p => '2'}
446
+ ),
447
+ 'Set::Dynamic#_g_uri_prev should return the previous uri for the given conds'
448
+ )
449
+ assert_nil(
450
+ @sd.send(
451
+ :_g_uri_next,
452
+ :conds => {:d => '200912', :p => '2'}
453
+ ),
454
+ 'Set::Dynamic#_g_uri_next should return nil if there is no next conds'
455
+ )
456
+
457
+ assert_equal(
458
+ '200911/p=2/',
459
+ @sd.send(
460
+ :_g_uri_prev,
461
+ :conds => {:d => '200912', :p => '1'}
462
+ ),
463
+ 'Set::Dynamic#_g_uri_prev should return the previous uri for the given conds'
464
+ )
465
+ assert_equal(
466
+ '200911/',
467
+ @sd.send(
468
+ :_g_uri_prev,
469
+ :conds => {:d => '200911', :p => '2'}
470
+ ),
471
+ 'Set::Dynamic#_g_uri_prev should return the previous uri for the given conds'
472
+ )
473
+ assert_equal(
474
+ '200912/',
475
+ @sd.send(
476
+ :_g_uri_next,
477
+ :conds => {:d => '200911', :p => '2'}
478
+ ),
479
+ 'Set::Dynamic#_g_uri_next should return the next uri for the given conds'
480
+ )
481
+ assert_nil(
482
+ @sd.send(
483
+ :_g_uri_prev,
484
+ :conds => {:d => '200911', :p => '1'}
485
+ ),
486
+ 'Set::Dynamic#_g_uri_prev should return nil if there is no previous conds'
487
+ )
488
+
489
+ assert_equal(
490
+ '200911/p=2/read_detail.html',
491
+ @sd.send(
492
+ :_g_uri_prev,
493
+ {
494
+ :conds => {:d => '200912', :p => '1'},
495
+ :orig_action => :read,
496
+ :sub_action => :detail,
497
+ }
498
+ ),
499
+ 'Set::Dynamic#_g_uri_prev should include the original action if the action is special'
500
+ )
501
+ assert_equal(
502
+ '200912/read_detail.html',
503
+ @sd.send(
504
+ :_g_uri_next,
505
+ {
506
+ :conds => {:d => '200911', :p => '2'},
507
+ :orig_action => :read,
508
+ :sub_action => :detail,
509
+ }
510
+ ),
511
+ 'Set::Dynamic#_g_uri_next should include the original action if the action is special'
512
+ )
513
+
514
+ @sd[:tmpl][:navi] = '$(.uri_prev)'
515
+ assert_equal(
516
+ '200911/',
517
+ @sd.send(
518
+ :_get_by_self_reference,
519
+ :action => :navi,
520
+ :conds => {:d => '200911', :p => '2'},
521
+ :orig_action => :read
522
+ ),
523
+ 'Set::Dynamic#_g_navi should pass the conds to the subsequent calls to _g_*()'
524
+ )
525
+ end
526
+
527
+ def test_recurring_action_tmpl
528
+ @sd.load(
529
+ '20091128_0001' => {'name' => 'frank', 'comment' => 'bar'},
530
+ '20091129_0001' => {'name' => 'frank', 'comment' => 'bar'}
531
+ )
532
+ @sd[:tmpl][:navi] = '$(.navi)'
533
+
534
+ result = nil
535
+ assert_nothing_raised(
536
+ 'Set::Dynamic#_g_navi should not call itself recursively'
537
+ ) {
538
+ result = @sd.send(
539
+ :_get_by_self_reference,
540
+ :action => :navi,
541
+ :conds => {:d => '20091128'},
542
+ :orig_action => :read
543
+ )
544
+ }
545
+ assert_equal(
546
+ '$(.navi)',
547
+ result,
548
+ 'Set::Dynamic#_g_navi should ignore $(.navi)'
549
+ )
550
+
551
+ @sd[:tmpl][:navi] = nil
552
+ @sd[:tmpl][:navi_next] = '$(.navi)'
553
+ assert_nothing_raised(
554
+ 'Set::Dynamic#_g_navi should not call itself recursively'
555
+ ) {
556
+ result = @sd.send(
557
+ :_get_by_self_reference,
558
+ :action => :navi,
559
+ :conds => {:d => '20091128'},
560
+ :orig_action => :read
561
+ )
562
+ }
563
+ assert_match(
564
+ /\$\(\.navi\)/,
565
+ result,
566
+ 'Set::Dynamic#_g_navi_next should ignore $(.navi)'
567
+ )
568
+ end
569
+
570
+ def test_item_arg
571
+ root_arg = {
572
+ :action => :read,
573
+ 'foo' => {
574
+ :action => :update,
575
+ :conds => {:d => '2010'},
576
+ 'bar' => {
577
+ :action => :delete,
578
+ },
579
+ },
580
+ 'baz' => {
581
+ 'qux' => {:action => :create},
582
+ },
583
+ }
584
+
585
+ assert_equal(
586
+ {
587
+ :p_action => :read,
588
+ :action => :update,
589
+ :conds => {:d => '2010'},
590
+ 'bar' => {
591
+ :action => :delete,
592
+ },
593
+ },
594
+ @sd.send(
595
+ :item_arg,
596
+ root_arg,
597
+ 'foo'
598
+ ),
599
+ 'Set#item_arg should return a partial hash of the root arg'
600
+ )
601
+ assert_equal(
602
+ {
603
+ :p_action => :update,
604
+ :action => :delete,
605
+ },
606
+ @sd.send(
607
+ :item_arg,
608
+ root_arg,
609
+ ['foo', 'bar']
610
+ ),
611
+ 'Set#item_arg should dig into multiple steps'
612
+ )
613
+ assert_equal(
614
+ {
615
+ :p_action => :read,
616
+ :action => :read,
617
+ 'qux' => {:action => :create},
618
+ },
619
+ @sd.send(
620
+ :item_arg,
621
+ root_arg,
622
+ ['baz']
623
+ ),
624
+ 'Set#item_arg should supplement item_arg[:action]'
625
+ )
626
+ assert_equal(
627
+ {
628
+ :p_action => :read,
629
+ :action => :create,
630
+ },
631
+ @sd.send(
632
+ :item_arg,
633
+ root_arg,
634
+ ['baz', 'qux']
635
+ ),
636
+ 'Set#item_arg should supplement item_arg[:p_action]'
637
+ )
638
+ assert_equal(
639
+ {
640
+ :p_action => :read,
641
+ :action => :read,
642
+ },
643
+ @sd.send(
644
+ :item_arg,
645
+ root_arg,
646
+ ['baz', 'non-existent']
647
+ ),
648
+ 'Set#item_arg should supplement item_arg[:action] & item_arg[:p_action]'
649
+ )
650
+ end
651
+
652
+ def test_uri_p
653
+ @sd.load(
654
+ '20091128_0001' => {'name' => 'frank', 'comment' => 'bar'},
655
+ '20091129_0001' => {'name' => 'frank', 'comment' => 'bar'},
656
+ '20091130_0001' => {'name' => 'frank', 'comment' => 'bar'},
657
+ '20091201_0001' => {'name' => 'frank', 'comment' => 'bar'}
658
+ )
659
+
660
+ @sd[:p_size] = 2
661
+ assert_equal(
662
+ ['200911/', '200911/p=2/'],
663
+ @sd.send(
664
+ :_uri_p,
665
+ :conds => {:d => '200911', :p => '1'}
666
+ ),
667
+ 'Set::Dynamic#_uri_p should return the array of the sibling conds'
668
+ )
669
+
670
+ @sd[:p_size] = nil
671
+ assert_nil(
672
+ @sd.send(
673
+ :_uri_p,
674
+ :conds => {:d => '200911'}
675
+ ),
676
+ 'Set::Dynamic#_uri_p should return nil if the siblings are not :p'
677
+ )
678
+
679
+ @sd[:p_size] = 2
680
+ assert_nil(
681
+ @sd.send(
682
+ :_uri_p,
683
+ :conds => {:d => '200911', :id => '20091129_0001'}
684
+ ),
685
+ 'Set::Dynamic#_uri_p should return nil if the siblings are not :p'
686
+ )
687
+ assert_nil(
688
+ @sd.send(
689
+ :_uri_p,
690
+ :conds => {:d => '200911', :p => '1', :id => '20091129_0001'}
691
+ ),
692
+ 'Set::Dynamic#_uri_p should return nil if the siblings are not :p'
693
+ )
694
+ end
695
+
696
+ def test_g_view_ym
697
+ @sd[:order] = 'id'
698
+ @sd.load(
699
+ '20091128_0001' => {'name' => 'frank', 'comment' => 'bar'},
700
+ '20091129_0001' => {'name' => 'frank', 'comment' => 'bar'},
701
+ '20091130_0001' => {'name' => 'frank', 'comment' => 'bar'},
702
+ '20091201_0001' => {'name' => 'frank', 'comment' => 'bar'},
703
+ '20100111_0001' => {'name' => 'frank', 'comment' => 'bar'}
704
+ )
705
+ assert_equal(
706
+ <<'_html',
707
+ <div class="view_ym">
708
+ <span class="y">
709
+ 2009 |
710
+ <span class="m"><a href="/foo/200911/">Nov</a></span>
711
+ <span class="m"><a href="/foo/200912/">Dec</a></span>
712
+ <br/>
713
+ </span>
714
+ <span class="y">
715
+ 2010 |
716
+ <span class="m"><a href="/foo/201001/">Jan</a></span>
717
+ <br/>
718
+ </span>
719
+ </div>
720
+ _html
721
+ @sd.send(
722
+ :_g_view_ym,
723
+ {:conds => {}}
724
+ ),
725
+ 'Set::Dynamic#_g_view_ym should return the available ym conds'
726
+ )
727
+
728
+ @sd[:order] = '-id'
729
+ @sd.load(
730
+ '20091128_0001' => {'name' => 'frank', 'comment' => 'bar'},
731
+ '20091129_0001' => {'name' => 'frank', 'comment' => 'bar'},
732
+ '20091130_0001' => {'name' => 'frank', 'comment' => 'bar'},
733
+ '20091201_0001' => {'name' => 'frank', 'comment' => 'bar'},
734
+ '20100111_0001' => {'name' => 'frank', 'comment' => 'bar'}
735
+ )
736
+ assert_equal(
737
+ <<'_html',
738
+ <div class="view_ym">
739
+ <span class="y">
740
+ 2009 |
741
+ <span class="m"><a href="/foo/200911/p=last/">Nov</a></span>
742
+ <span class="m"><a href="/foo/200912/p=last/">Dec</a></span>
743
+ <br/>
744
+ </span>
745
+ <span class="y">
746
+ 2010 |
747
+ <span class="m"><a href="/foo/201001/p=last/">Jan</a></span>
748
+ <br/>
749
+ </span>
750
+ </div>
751
+ _html
752
+ @sd.send(
753
+ :_g_view_ym,
754
+ {:conds => {}}
755
+ ),
756
+ 'Set::Dynamic#_g_view_ym should refer to [:order]'
757
+ )
758
+
759
+ @sd[:order] = 'id'
760
+ assert_equal(
761
+ <<'_html',
762
+ <div class="view_ym">
763
+ <span class="y">
764
+ 2009 |
765
+ <span class="m"><a href="/foo/200911/">Nov</a></span>
766
+ <span class="m"><span class="current">Dec</span></span>
767
+ <br/>
768
+ </span>
769
+ <span class="y">
770
+ 2010 |
771
+ <span class="m"><a href="/foo/201001/">Jan</a></span>
772
+ <br/>
773
+ </span>
774
+ </div>
775
+ _html
776
+ @sd.send(
777
+ :_g_view_ym,
778
+ {:conds => {:d => '200912'}}
779
+ ),
780
+ 'Set::Dynamic#_g_view_ym should distinguish the current cond[:d] if available'
781
+ )
782
+ end
783
+
784
+ def test_g_submit
785
+ Runo.client = nil
786
+ @sd = Runo::Set::Dynamic.new(
787
+ :klass => 'set-dynamic',
788
+ :workflow => 'blog',
789
+ :tmpl => {:index => '$(.submit)'},
790
+ :item => {
791
+ 'default' => Runo::Parser.parse_html(<<'_html')
792
+ <li>$(name = text 32 :'nobody'): $(comment = text 64 :'hi.')$(.hidden)</li>
793
+ _html
794
+ }
795
+ ).load(
796
+ '_001' => {'name' => 'frank', 'comment' => 'bar'},
797
+ '20100401_0001' => {'name' => 'frank', 'comment' => 'bar'}
798
+ )
799
+ wf = @sd.workflow
800
+
801
+ def wf.permit?(roles, action)
802
+ true
803
+ end
804
+ @sd[:preview] = nil
805
+
806
+ assert_equal(
807
+ <<'_html',
808
+ <div class="submit">
809
+ <input name=".status-public" type="submit" value="create" />
810
+ </div>
811
+ _html
812
+ @sd.get(:action => :update, :conds => {:id => '_001'}),
813
+ 'Set#_g_submit should not return preview_delete when there is only new items'
814
+ )
815
+ @sd[:preview] = nil
816
+ assert_equal(
817
+ <<'_html',
818
+ <div class="submit">
819
+ <input name=".status-public" type="submit" value="update" />
820
+ <input name=".action-preview_delete" type="submit" value="delete..." />
821
+ </div>
822
+ _html
823
+ @sd.get(:action => :update, :conds => {:id => '20100401_0001'}),
824
+ 'Set#_g_submit should return buttons according to the permission, meta and orig_action'
825
+ )
826
+ @sd[:preview] = :optional
827
+ assert_equal(
828
+ <<'_html',
829
+ <div class="submit">
830
+ <input name=".status-public" type="submit" value="update" />
831
+ <input name=".action-preview_update" type="submit" value="preview" />
832
+ <input name=".action-preview_delete" type="submit" value="delete..." />
833
+ </div>
834
+ _html
835
+ @sd.get(:action => :update, :conds => {:id => '20100401_0001'}),
836
+ 'Set#_g_submit should return buttons according to the permission, meta and orig_action'
837
+ )
838
+ @sd[:preview] = :mandatory
839
+ assert_equal(
840
+ <<'_html',
841
+ <div class="submit">
842
+ <input name=".action-preview_update" type="submit" value="preview" />
843
+ <input name=".action-preview_delete" type="submit" value="delete..." />
844
+ </div>
845
+ _html
846
+ @sd.get(:action => :update, :conds => {:id => '20100401_0001'}),
847
+ 'Set#_g_submit should return buttons according to the permission, meta and orig_action'
848
+ )
849
+ assert_equal(
850
+ <<'_html',
851
+ <div class="submit">
852
+ <input name=".status-public" type="submit" value="update" />
853
+ </div>
854
+ _html
855
+ @sd.get(:action => :preview, :sub_action => :update),
856
+ 'Set#_g_submit should not show preview buttons when the orig_action is :preview'
857
+ )
858
+ assert_equal(
859
+ <<'_html',
860
+ <div class="submit">
861
+ <input name=".status-public" type="submit" value="delete" />
862
+ </div>
863
+ _html
864
+ @sd.get(:action => :preview, :sub_action => :delete),
865
+ 'Set#_g_submit should not show preview buttons when the orig_action is :preview'
866
+ )
867
+
868
+ def wf.permit?(roles, action)
869
+ true unless action == :delete
870
+ end
871
+ @sd[:preview] = nil
872
+ assert_equal(
873
+ <<'_html',
874
+ <div class="submit">
875
+ <input name=".status-public" type="submit" value="update" />
876
+ </div>
877
+ _html
878
+ @sd.get(:action => :update, :conds => {:id => '20100401_0001'}),
879
+ 'Set#_g_submit should return buttons according to the permission, meta and orig_action'
880
+ )
881
+ @sd[:preview] = :optional
882
+ assert_equal(
883
+ <<'_html',
884
+ <div class="submit">
885
+ <input name=".status-public" type="submit" value="update" />
886
+ <input name=".action-preview_update" type="submit" value="preview" />
887
+ </div>
888
+ _html
889
+ @sd.get(:action => :update, :conds => {:id => '20100401_0001'}),
890
+ 'Set#_g_submit should return buttons according to the permission, meta and orig_action'
891
+ )
892
+ @sd[:preview] = :mandatory
893
+ assert_equal(
894
+ <<'_html',
895
+ <div class="submit">
896
+ <input name=".action-preview_update" type="submit" value="preview" />
897
+ </div>
898
+ _html
899
+ @sd.get(:action => :update, :conds => {:id => '20100401_0001'}),
900
+ 'Set#_g_submit should return buttons according to the permission, meta and orig_action'
901
+ )
902
+ assert_equal(
903
+ <<'_html',
904
+ <div class="submit">
905
+ <input name=".status-public" type="submit" value="update" />
906
+ </div>
907
+ _html
908
+ @sd.get(:action => :preview, :sub_action => :update),
909
+ 'Set#_g_submit should not show preview buttons when the orig_action is :preview'
910
+ )
911
+
912
+ def wf.permit?(roles, action)
913
+ true unless action == :update
914
+ end
915
+ @sd[:preview] = nil
916
+ assert_equal(
917
+ <<'_html',
918
+ <div class="submit">
919
+ <input name=".status-public" type="submit" value="delete" />
920
+ </div>
921
+ _html
922
+ @sd.get(:action => :preview, :sub_action => :delete),
923
+ 'Set#_g_submit should not show preview buttons when the orig_action is :preview'
924
+ )
925
+ end
926
+
927
+ def test_post
928
+ @sd.post(:create, '1234' => {'name' => 'carl'})
929
+ assert_equal(
930
+ :create,
931
+ @sd.action,
932
+ 'Set::Dynamic#post should set @action'
933
+ )
934
+
935
+ @sd.commit
936
+ assert_equal(
937
+ :create,
938
+ @sd.result,
939
+ 'Set::Dynamic#commit should set @result'
940
+ )
941
+
942
+ @sd.post(:update, '1234' => {'name' => 'frank'})
943
+ assert_nil(
944
+ @sd.result,
945
+ 'Set::Dynamic#post should reset @result'
946
+ )
947
+ end
948
+
949
+ def test_post_multiple_attachments
950
+ Runo.client = 'root'
951
+ sd = Runo::Set::Static::Folder.root.item('t_attachment', 'main')
952
+ sd.storage.clear
953
+
954
+ # create an attachment item
955
+ sd.update(
956
+ '_1' => {
957
+ 'files' => {'_1' => {:action => :create, 'file' => 'foo'}},
958
+ }
959
+ )
960
+ sd.commit :temp
961
+ first_id = sd.result.values.first.item('files').val.keys.sort.first
962
+ assert_equal(
963
+ {
964
+ first_id => {'file' => 'foo'},
965
+ },
966
+ sd.result.values.first.item('files').val,
967
+ 'Workflow::Attachment should keep the first item'
968
+ )
969
+
970
+ # create the second attachment
971
+ sd.update(
972
+ '_1' => {
973
+ 'files' => {'_1' => {:action => :create, 'file' => 'bar'}},
974
+ }
975
+ )
976
+ sd.commit :temp
977
+ second_id = sd.result.values.first.item('files').val.keys.sort.last
978
+
979
+ assert_equal(
980
+ first_id.succ,
981
+ second_id,
982
+ 'Workflow::Attachment should not overwrite the first file item'
983
+ )
984
+ assert_equal(
985
+ {
986
+ first_id => {'file' => 'foo'},
987
+ second_id => {'file' => 'bar'},
988
+ },
989
+ sd.result.values.first.item('files').val,
990
+ 'Workflow::Attachment should keep both the first item and the second item'
991
+ )
992
+
993
+ sd.commit :persistent
994
+ baz_id = sd.result.values.first[:id]
995
+
996
+ item = Runo::Set::Static::Folder.root.item('t_attachment', 'main', baz_id, 'files', first_id, 'file')
997
+ assert_equal(
998
+ 'foo',
999
+ item.val,
1000
+ 'Workflow::Attachment should store the body of the first file item'
1001
+ )
1002
+
1003
+ item = Runo::Set::Static::Folder.root.item('t_attachment', 'main', baz_id, 'files', second_id, 'file')
1004
+ assert_equal(
1005
+ 'bar',
1006
+ item.val,
1007
+ 'Workflow::Attachment should store the body of the second file item'
1008
+ )
1009
+ end
1010
+
1011
+ def test_load_default
1012
+ end
1013
+
1014
+ def test_load
1015
+ @sd.load('1235' => {'name' => 'carl'})
1016
+ assert_equal(
1017
+ {'1235' => {'name' => 'carl'}},
1018
+ @sd.val,
1019
+ 'Set::Dynamic#load should load the storage with the given values'
1020
+ )
1021
+ @sd.load('1234' => {'name' => 'frank'})
1022
+ assert_equal(
1023
+ {'1234' => {'name' => 'frank'}},
1024
+ @sd.val,
1025
+ 'Set::Dynamic#load should overwrite all values in the storage'
1026
+ )
1027
+ end
1028
+
1029
+ def test_create
1030
+ s = @sd.storage
1031
+ def s.new_id(v = {})
1032
+ @c ||= 0
1033
+ (@c += 1).to_s
1034
+ end
1035
+
1036
+ @sd.create({})
1037
+ assert_equal(
1038
+ {},
1039
+ @sd.val,
1040
+ 'Set::Dynamic#create should build the empty storage by default'
1041
+ )
1042
+
1043
+ @sd.create('_1235' => {'name' => 'carl'})
1044
+ assert_equal(
1045
+ {'_owner' => 'root', 'name' => 'carl', 'comment' => 'hi.'},
1046
+ @sd.item('_1235').val,
1047
+ 'Set::Dynamic#create should create the new items in the empty storage'
1048
+ )
1049
+ @sd.commit
1050
+ assert_equal(
1051
+ {'1' => {'_owner' => 'root', 'name' => 'carl', 'comment' => 'hi.'}},
1052
+ @sd.val,
1053
+ 'Set::Dynamic#create should create the new items in the empty storage'
1054
+ )
1055
+
1056
+ @sd.create('_1234' => {'name' => 'frank'})
1057
+ assert_equal(
1058
+ {'_owner' => 'root', 'name' => 'frank', 'comment' => 'hi.'},
1059
+ @sd.item('_1234').val,
1060
+ 'Set::Dynamic#create should create the new items in the empty storage'
1061
+ )
1062
+ assert_equal(
1063
+ {},
1064
+ @sd.val,
1065
+ 'Set::Dynamic#val should be empty before the commit'
1066
+ )
1067
+ @sd.commit
1068
+ assert_equal(
1069
+ {'2' => {'_owner' => 'root', 'name' => 'frank', 'comment' => 'hi.'}},
1070
+ @sd.val,
1071
+ 'Set::Dynamic#create should overwrite all items in the storage'
1072
+ )
1073
+
1074
+ @sd.create('_2' => {'name' => 'frank'}, '_1' => {'name' => 'bobby'})
1075
+ assert_equal(
1076
+ {},
1077
+ @sd.val,
1078
+ 'Set::Dynamic#val should be empty before the commit'
1079
+ )
1080
+ @sd.commit
1081
+ assert_equal(
1082
+ {
1083
+ '4' => {'_owner' => 'root', 'name' => 'frank', 'comment' => 'hi.'},
1084
+ '3' => {'_owner' => 'root', 'name' => 'bobby', 'comment' => 'hi.'},
1085
+ },
1086
+ @sd.val,
1087
+ 'Set::Dynamic#create should create multiple items in the empty storage'
1088
+ )
1089
+ end
1090
+
1091
+ def test_update
1092
+ @sd.load(
1093
+ '20091122_1234' => {'name' => 'frank', 'comment' => 'bar'},
1094
+ '20091122_1235' => {'name' => 'carl', 'comment' => 'baz'}
1095
+ )
1096
+ s = @sd.storage
1097
+ def s.new_id(v = {})
1098
+ 'new!'
1099
+ end
1100
+
1101
+ # update an item
1102
+ @sd.update('20091122_1234' => {'comment' => 'qux'})
1103
+ assert_equal(
1104
+ {'name' => 'frank', 'comment' => 'qux'},
1105
+ @sd.item('20091122_1234').val,
1106
+ 'Set::Dynamic#update should update the values of the item instance'
1107
+ )
1108
+ assert_equal(
1109
+ :update,
1110
+ @sd.item('20091122_1234').action,
1111
+ 'Set::Dynamic#update should set a proper action on the item'
1112
+ )
1113
+ assert_equal(
1114
+ nil,
1115
+ @sd.item('20091122_1234', 'name').action,
1116
+ 'Set::Dynamic#update should set a proper action on the item'
1117
+ )
1118
+ assert_equal(
1119
+ :update,
1120
+ @sd.item('20091122_1234', 'comment').action,
1121
+ 'Set::Dynamic#update should set a proper action on the item'
1122
+ )
1123
+
1124
+ # create an item
1125
+ @sd.update('_1236' => {'name' => 'roy'})
1126
+ assert_equal(
1127
+ {'_owner' => 'root', 'name' => 'roy', 'comment' => 'hi.'},
1128
+ @sd.item('_1236').val,
1129
+ 'Set::Dynamic#update should update the values of the item instance'
1130
+ )
1131
+ assert_equal(
1132
+ :create,
1133
+ @sd.item('_1236').action,
1134
+ 'Set::Dynamic#update should set a proper action on the item'
1135
+ )
1136
+ assert_equal(
1137
+ :create,
1138
+ @sd.item('_1236', 'name').action,
1139
+ 'Set::Dynamic#update should set a proper action on the item'
1140
+ )
1141
+ assert_equal(
1142
+ nil,
1143
+ @sd.item('_1236', 'comment').action,
1144
+ 'Set::Dynamic#update should set a proper action on the item'
1145
+ )
1146
+
1147
+ # delete an item
1148
+ @sd.update('20091122_1235' => {:action => :delete})
1149
+ assert_equal(
1150
+ {'name' => 'carl', 'comment' => 'baz'},
1151
+ @sd.item('20091122_1235').val,
1152
+ 'Set::Dynamic#update should not update the values of the item when deleting'
1153
+ )
1154
+ assert_equal(
1155
+ :delete,
1156
+ @sd.item('20091122_1235').action,
1157
+ 'Set::Dynamic#update should set a proper action on the item'
1158
+ )
1159
+
1160
+ # before the commit
1161
+ assert_equal(
1162
+ :update,
1163
+ @sd.action,
1164
+ 'Set::Dynamic#update should set a proper action'
1165
+ )
1166
+ assert_nil(
1167
+ @sd.result,
1168
+ 'Set::Dynamic#result should return nil before the commit'
1169
+ )
1170
+ assert_equal(
1171
+ {
1172
+ '20091122_1234' => {'name' => 'frank', 'comment' => 'bar'},
1173
+ '20091122_1235' => {'name' => 'carl', 'comment' => 'baz'},
1174
+ },
1175
+ @sd.val,
1176
+ 'Set::Dynamic#update should not touch the original values in the storage'
1177
+ )
1178
+
1179
+ @sd.commit :temp
1180
+
1181
+ # after the commit
1182
+ assert(
1183
+ @sd.pending?,
1184
+ 'Set::Dynamic#commit(:temp) should keep the pending status of the items'
1185
+ )
1186
+ assert_equal(
1187
+ {
1188
+ '20091122_1234' => {'name' => 'frank', 'comment' => 'qux'},
1189
+ 'new!' => {'name' => 'roy', 'comment' => 'hi.', '_owner' => 'root'},
1190
+ },
1191
+ @sd.val,
1192
+ 'Set::Dynamic#commit should update the original values in the storage'
1193
+ )
1194
+ assert_equal(
1195
+ {
1196
+ '20091122_1234' => @sd.item('20091122_1234'),
1197
+ '20091122_1235' => @sd.instance_eval { @item_object['20091122_1235'] },
1198
+ '_1236' => @sd.item('_1236'),
1199
+ },
1200
+ @sd.result,
1201
+ 'Set::Dynamic#result should return a hash of the committed items when :update'
1202
+ ) if nil
1203
+ assert_equal(
1204
+ {'comment' => @sd.item('20091122_1234', 'comment')},
1205
+ @sd.item('20091122_1234').result,
1206
+ 'Set::Static#result should return a hash of the committed items when :update'
1207
+ )
1208
+ assert_equal(
1209
+ :delete,
1210
+ @sd.result['20091122_1235'].result,
1211
+ 'Set::Static#result should return the committed action unless :update'
1212
+ )
1213
+ assert_equal(
1214
+ :create,
1215
+ @sd.result['_1236'].result,
1216
+ 'Set::Static#result should return the committed action unless :update'
1217
+ )
1218
+ end
1219
+
1220
+ def test_update_with_eclectic_val
1221
+ @sd.load(
1222
+ '20091122_1234' => {'name' => 'frank', 'comment' => 'bar'},
1223
+ '20091122_1235' => {'name' => 'carl', 'comment' => 'baz'}
1224
+ )
1225
+ s = @sd.storage
1226
+
1227
+ assert_nothing_raised(
1228
+ 'Set::Dynamic#update should work with values other than sub-items'
1229
+ ) {
1230
+ @sd.update('20091122_1234' => {'comment' => 'qux'}, :conds => {}, :action => nil)
1231
+ }
1232
+ assert_equal(
1233
+ {'name' => 'frank', 'comment' => 'qux'},
1234
+ @sd.item('20091122_1234').val,
1235
+ 'Set::Dynamic#update should update the values of the item instance'
1236
+ )
1237
+ end
1238
+
1239
+ def test_delete
1240
+ @sd.delete
1241
+ assert_equal(
1242
+ :delete,
1243
+ @sd.action,
1244
+ 'Set::Dynamic#delete should set @action'
1245
+ )
1246
+ end
1247
+
1248
+ def test_delete_invalid_item
1249
+ @sd.load(
1250
+ '20091122_1234' => {'name' => 'frank', 'comment' => 'bar'}
1251
+ )
1252
+
1253
+ # update with invalid value
1254
+ @sd.update(
1255
+ '20091122_1234' => {'name' => 'too looooooooooooooooooooong'}
1256
+ )
1257
+ assert(!@sd.valid?)
1258
+
1259
+ # delete the invalid item
1260
+ @sd.update(
1261
+ '20091122_1234' => {:action => :delete}
1262
+ )
1263
+ assert_equal(
1264
+ {},
1265
+ @sd.errors,
1266
+ 'Set::Dynamic#errors should ignore items with :delete action'
1267
+ )
1268
+
1269
+ @sd.commit
1270
+ assert(
1271
+ @sd.valid?,
1272
+ 'Set::Dynamic#commit should be able to delete an invalid item'
1273
+ )
1274
+ assert_equal(
1275
+ {},
1276
+ @sd.val,
1277
+ 'Set::Dynamic#commit should be able to delete an invalid item'
1278
+ )
1279
+ end
1280
+
1281
+ def test_get_by_nobody
1282
+ @sd.load(
1283
+ '20091122_0001' => {'_owner' => 'frank', 'comment' => 'bar'},
1284
+ '20091122_0002' => {'_owner' => 'carl', 'comment' => 'baz'}
1285
+ )
1286
+ Runo.client = nil
1287
+
1288
+ arg = {:action => :update, :conds => {:d => '2009'}}
1289
+ assert_raise(
1290
+ Runo::Error::Forbidden,
1291
+ 'Set::Dynamic#get should raise Error::Forbidden when sd[:client] is nobody'
1292
+ ) {
1293
+ @sd.get arg
1294
+ }
1295
+ end
1296
+
1297
+ def test_post_by_nobody
1298
+ @sd.load(
1299
+ '20091122_0001' => {'_owner' => 'frank', 'comment' => 'bar'},
1300
+ '20091122_0002' => {'_owner' => 'carl', 'comment' => 'baz'}
1301
+ )
1302
+ Runo.client = nil
1303
+
1304
+ assert_raise(
1305
+ Runo::Error::Forbidden,
1306
+ "'nobody' should not create a new item"
1307
+ ) {
1308
+ @sd.update('_0001' => {'comment' => 'qux'})
1309
+ }
1310
+ assert_raise(
1311
+ Runo::Error::Forbidden,
1312
+ "'nobody' should not update frank's item"
1313
+ ) {
1314
+ @sd.update('20091122_0001' => {'comment' => 'qux'})
1315
+ }
1316
+ assert_raise(
1317
+ Runo::Error::Forbidden,
1318
+ "'nobody' should not delete frank's item"
1319
+ ) {
1320
+ @sd.update('20091122_0001' => {:action => :delete})
1321
+ }
1322
+ end
1323
+
1324
+ def test_get_by_carl
1325
+ @sd.load(
1326
+ '20091122_0001' => {'_owner' => 'frank', 'comment' => 'bar'},
1327
+ '20091122_0002' => {'_owner' => 'carl', 'comment' => 'baz'}
1328
+ )
1329
+ Runo.client = 'carl' # carl is not the member of the group
1330
+
1331
+ arg = {}
1332
+ @sd.get arg
1333
+ assert_equal(
1334
+ :read,
1335
+ arg[:action],
1336
+ 'Set::Dynamic#get should set the default action'
1337
+ )
1338
+
1339
+ arg = {:action => :create}
1340
+ assert_raise(
1341
+ Runo::Error::Forbidden,
1342
+ 'Set::Dynamic#get should raise Error::Forbidden when an action is given but forbidden'
1343
+ ) {
1344
+ @sd.get arg
1345
+ }
1346
+
1347
+ arg = {:action => :update, :conds => {:d => '2009'}}
1348
+ assert_raise(
1349
+ Runo::Error::Forbidden,
1350
+ 'Set::Dynamic#get should not keep the partially-permitted action'
1351
+ ) {
1352
+ @sd.get arg
1353
+ }
1354
+
1355
+ arg = {:action => :update, :conds => {:id => '20091122_0002'}}
1356
+ @sd.get arg
1357
+ assert_equal(
1358
+ :update,
1359
+ arg[:action],
1360
+ 'Set::Dynamic#get should keep the permitted action'
1361
+ )
1362
+ end
1363
+
1364
+ def test_post_by_carl
1365
+ @sd.load(
1366
+ '20091122_0001' => {'_owner' => 'frank', 'comment' => 'bar'},
1367
+ '20091122_0002' => {'_owner' => 'carl', 'comment' => 'baz'}
1368
+ )
1369
+ Runo.client = 'carl' # carl is not the member of the group
1370
+
1371
+ assert_raise(
1372
+ Runo::Error::Forbidden,
1373
+ 'carl should not create a new item'
1374
+ ) {
1375
+ @sd.update('_0001' => {'comment' => 'qux'})
1376
+ }
1377
+ assert_raise(
1378
+ Runo::Error::Forbidden,
1379
+ "carl should not update frank's item"
1380
+ ) {
1381
+ @sd.update('20091122_0001' => {'comment' => 'qux'})
1382
+ }
1383
+ assert_nothing_raised(
1384
+ 'carl should be able to update his own item'
1385
+ ) {
1386
+ @sd.update('20091122_0002' => {'comment' => 'qux'})
1387
+ }
1388
+ assert_raise(
1389
+ Runo::Error::Forbidden,
1390
+ "carl should not delete frank's item"
1391
+ ) {
1392
+ @sd.update('20091122_0001' => {:action => :delete})
1393
+ }
1394
+ end
1395
+
1396
+ def test_get_by_roy
1397
+ @sd.load(
1398
+ '20091122_0001' => {'_owner' => 'frank', 'comment' => 'bar'},
1399
+ '20091122_0002' => {'_owner' => 'carl', 'comment' => 'baz'}
1400
+ )
1401
+ Runo.client = 'roy' # roy belongs to the group
1402
+
1403
+ arg = {:action => :create}
1404
+ @sd.get arg
1405
+ assert_equal(
1406
+ :create,
1407
+ arg[:action],
1408
+ 'Set::Dynamic#get should keep the permitted action'
1409
+ )
1410
+
1411
+ arg = {:action => :delete, :conds => {:d => '2009'}}
1412
+ assert_raise(
1413
+ Runo::Error::Forbidden,
1414
+ 'Set::Dynamic#get should raise Error::Forbidden when an action is given but forbidden'
1415
+ ) {
1416
+ @sd.get arg
1417
+ }
1418
+ end
1419
+
1420
+ def test_post_by_roy
1421
+ @sd.load(
1422
+ '20091122_0001' => {'_owner' => 'frank', 'comment' => 'bar'},
1423
+ '20091122_0002' => {'_owner' => 'carl', 'comment' => 'baz'}
1424
+ )
1425
+ Runo.client = 'roy' # roy belongs to the group
1426
+
1427
+ assert_nothing_raised(
1428
+ 'roy should be able to create a new item'
1429
+ ) {
1430
+ @sd.update('_0001' => {'comment' => 'qux'})
1431
+ }
1432
+ assert_raise(
1433
+ Runo::Error::Forbidden,
1434
+ "roy should not update frank's item"
1435
+ ) {
1436
+ @sd.update('20091122_0001' => {'comment' => 'qux'})
1437
+ }
1438
+ assert_raise(
1439
+ Runo::Error::Forbidden,
1440
+ "roy should not delete frank's item"
1441
+ ) {
1442
+ @sd.update('20091122_0001' => {:action => :delete})
1443
+ }
1444
+ end
1445
+
1446
+ def test_get_by_root
1447
+ @sd.load(
1448
+ '20091122_0001' => {'_owner' => 'frank', 'comment' => 'bar'},
1449
+ '20091122_0002' => {'_owner' => 'carl', 'comment' => 'baz'}
1450
+ )
1451
+ Runo.client = 'root' # root is the admin
1452
+
1453
+ arg = {:action => :create, :db => 1}
1454
+ @sd.get arg
1455
+ assert_equal(
1456
+ :create,
1457
+ arg[:action],
1458
+ 'Set::Dynamic#get should keep the permitted action'
1459
+ )
1460
+
1461
+ arg = {:action => :delete, :conds => {:d => '2009'}}
1462
+ @sd.get arg
1463
+ assert_equal(
1464
+ :delete,
1465
+ arg[:action],
1466
+ 'Set::Dynamic#get should keep the permitted action'
1467
+ )
1468
+ end
1469
+
1470
+ def test_post_by_root
1471
+ @sd.load(
1472
+ '20091122_0001' => {'_owner' => 'frank', 'comment' => 'bar'},
1473
+ '20091122_0002' => {'_owner' => 'carl', 'comment' => 'baz'}
1474
+ )
1475
+ Runo.client = 'root' # root is the admin
1476
+
1477
+ assert_nothing_raised(
1478
+ 'frank should be able to create a new item'
1479
+ ) {
1480
+ @sd.update('_0001' => {'comment' => 'qux'})
1481
+ }
1482
+ assert_nothing_raised(
1483
+ 'frank should be able to update his own item'
1484
+ ) {
1485
+ @sd.update('20091122_0001' => {'comment' => 'qux'})
1486
+ }
1487
+ assert_nothing_raised(
1488
+ "frank should be able to update carl's item"
1489
+ ) {
1490
+ @sd.update('20091122_0002' => {'comment' => 'qux'})
1491
+ }
1492
+ assert_nothing_raised(
1493
+ 'frank should be able to delete his own item'
1494
+ ) {
1495
+ @sd.update('20091122_0001' => {:action => :delete})
1496
+ }
1497
+ assert_nothing_raised(
1498
+ "frank should be able to delete carl's item"
1499
+ ) {
1500
+ @sd.update('20091122_0002' => {:action => :delete})
1501
+ }
1502
+ end
1503
+
1504
+ end