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,742 @@
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_Runo < Test::Unit::TestCase
9
+
10
+ def setup
11
+ end
12
+
13
+ def teardown
14
+ end
15
+
16
+ def test_session
17
+ assert(
18
+ Runo.session.respond_to?(:[]),
19
+ 'Runo.session should be a Session or Hash'
20
+ )
21
+ end
22
+
23
+ def test_client
24
+ Runo.client = nil
25
+ assert_equal(
26
+ 'nobody',
27
+ Runo.client,
28
+ 'Runo.client should return nobody before login'
29
+ )
30
+
31
+ Runo.client = 'frank'
32
+ assert_equal(
33
+ 'frank',
34
+ Runo.client,
35
+ 'Runo.client should return the user who logged in'
36
+ )
37
+
38
+ Runo.client = nil
39
+ assert_equal(
40
+ 'nobody',
41
+ Runo.client,
42
+ 'Runo.client should return nobody after logout'
43
+ )
44
+ end
45
+
46
+ def test_rebuild_params
47
+ runo = Runo.new
48
+
49
+ hash = runo.instance_eval {
50
+ rebuild_params(
51
+ '.action' => 'update'
52
+ )
53
+ }
54
+ assert_equal(
55
+ {:action => :update},
56
+ hash,
57
+ 'Runo#rebuild_params should be able to rebuild special symbols'
58
+ )
59
+
60
+ hash = runo.instance_eval {
61
+ rebuild_params(
62
+ '.action-update' => 'submit'
63
+ )
64
+ }
65
+ assert_equal(
66
+ {:action => :update},
67
+ hash,
68
+ 'Runo#rebuild_params should be able to rebuild special symbols'
69
+ )
70
+
71
+ hash = runo.instance_eval {
72
+ rebuild_params(
73
+ 'noo' => 'what?',
74
+ 'noo.action-update' => 'submit',
75
+ 'noo.conds-id' => '4567'
76
+ )
77
+ }
78
+ assert_equal(
79
+ {
80
+ 'noo' => {
81
+ :self => 'what?',
82
+ :action => :update,
83
+ :conds => {:id => '4567'},
84
+ },
85
+ },
86
+ hash,
87
+ 'Runo#rebuild_params should rebuild both the special symbols and regular items'
88
+ )
89
+
90
+ hash = runo.instance_eval {
91
+ rebuild_params(
92
+ 'moo.conds-p' => '9',
93
+ 'moo-4567-addr.conds-zip-upper' => '110'
94
+ )
95
+ }
96
+ assert_equal(
97
+ {
98
+ 'moo' => {
99
+ :conds => {:p => '9'},
100
+ '4567' => {
101
+ 'addr' => {
102
+ :conds => {:'zip-upper' => '110'},
103
+ },
104
+ },
105
+ },
106
+ },
107
+ hash,
108
+ 'Runo#rebuild_params should be able to rebuild any combination of symbols and items'
109
+ )
110
+
111
+ hash = runo.instance_eval {
112
+ rebuild_params(
113
+ 'foo-bar.conds-id' => '1234',
114
+ 'foo-bar.conds-p' => ['42'],
115
+ 'foo-bar.action' => 'update',
116
+ 'foo-baz' => ['boo', 'bee'],
117
+ 'foo' => 'oops',
118
+ 'qux.action-create' => 'submit',
119
+ 'qux.status-public' => 'oops'
120
+ )
121
+ }
122
+ assert_equal(
123
+ {
124
+ 'foo' => {
125
+ :self => 'oops',
126
+ 'bar' => {
127
+ :action => :update,
128
+ :conds => {
129
+ :id => '1234',
130
+ :p => ['42'],
131
+ },
132
+ },
133
+ 'baz' => ['boo', 'bee'],
134
+ },
135
+ 'qux' => {
136
+ :action => :create,
137
+ :status => :public,
138
+ },
139
+ },
140
+ hash,
141
+ 'Runo#rebuild_params should be able to rebuild any combination of symbols and items'
142
+ )
143
+ end
144
+
145
+ def test_steps_of
146
+ assert_equal(
147
+ ['foo', 'bar'],
148
+ Runo::Path.steps_of('/foo/bar/'),
149
+ 'Runo::Path.steps_of should be able to extract item steps from path_info'
150
+ )
151
+ assert_equal(
152
+ ['foo', 'bar'],
153
+ Runo::Path.steps_of('/foo/bar/create.html'),
154
+ 'Runo::Path.steps_of should ignore the pseudo-filename'
155
+ )
156
+ assert_equal(
157
+ ['foo'],
158
+ Runo::Path.steps_of('/foo/bar'),
159
+ 'Runo::Path.steps_of should ignore the last step without a following slash'
160
+ )
161
+ assert_equal(
162
+ ['foo', 'bar'],
163
+ Runo::Path.steps_of('/foo//bar/baz=123/'),
164
+ 'Runo::Path.steps_of should distinguish item steps from conds'
165
+ )
166
+ assert_equal(
167
+ ['foo', 'bar'],
168
+ Runo::Path.steps_of('/1234567890.123456/foo/bar/'),
169
+ 'Runo::Path.steps_of should distinguish item steps from a tid'
170
+ )
171
+ end
172
+
173
+ def test_steps_of_with_empty_steps
174
+ assert_equal(
175
+ [],
176
+ Runo::Path.steps_of(''),
177
+ 'Runo::Path.steps_of should return empty array when there is no item steps'
178
+ )
179
+ assert_equal(
180
+ [],
181
+ Runo::Path.steps_of('/'),
182
+ 'Runo::Path.steps_of should return empty array when there is no item steps'
183
+ )
184
+ assert_equal(
185
+ [],
186
+ Runo::Path.steps_of('/index.html'),
187
+ 'Runo::Path.steps_of should return empty array when there is no item steps'
188
+ )
189
+ end
190
+
191
+ def test_steps_of_with_cond_d
192
+ assert_equal(
193
+ ['foo', 'bar'],
194
+ Runo::Path.steps_of('/foo/bar/2009/'),
195
+ 'Runo::Path.steps_of should distinguish item steps from ambiguous conds[:d]'
196
+ )
197
+ assert_equal(
198
+ ['foo', 'bar'],
199
+ Runo::Path.steps_of('/foo/bar/1970/'),
200
+ 'Runo::Path.steps_of should distinguish item steps from ambiguous conds[:d]'
201
+ )
202
+ assert_equal(
203
+ ['foo', 'bar', '3001'],
204
+ Runo::Path.steps_of('/foo/bar/3001/'),
205
+ 'Runo::Path.steps_of should be patched in the next millennium :-)'
206
+ )
207
+ end
208
+
209
+ def test_conds_of
210
+ assert_equal(
211
+ {},
212
+ Runo::Path.conds_of('/foo/bar/'),
213
+ 'Runo::Path.conds_of should return empty hash when there is no conds'
214
+ )
215
+ assert_equal(
216
+ {
217
+ :baz => '123',
218
+ :qux => '456',
219
+ },
220
+ Runo::Path.conds_of('/foo/bar/baz=123/qux=456/'),
221
+ 'Runo::Path.conds_of should be able to extract conds from path_info'
222
+ )
223
+ assert_equal(
224
+ {
225
+ :baz => '123',
226
+ :qux => '456',
227
+ },
228
+ Runo::Path.conds_of('/foo/bar/baz=123/qux=456/create.html'),
229
+ 'Runo::Path.conds_of should ignore the pseudo-filename'
230
+ )
231
+ assert_equal(
232
+ {
233
+ :baz => '1234',
234
+ },
235
+ Runo::Path.conds_of('/foo/bar//baz=1234//qux=4567'),
236
+ 'Runo::Path.conds_of should ignore the item steps and the last step without a slash'
237
+ )
238
+ end
239
+
240
+ def test_conds_of_with_empty_conds
241
+ assert_equal(
242
+ {},
243
+ Runo::Path.conds_of(''),
244
+ 'Runo::Path.conds_of should return empty hash when there is no conds'
245
+ )
246
+ assert_equal(
247
+ {},
248
+ Runo::Path.conds_of('/'),
249
+ 'Runo::Path.conds_of should return empty hash when there is no conds'
250
+ )
251
+ assert_equal(
252
+ {},
253
+ Runo::Path.conds_of('/index.html'),
254
+ 'Runo::Path.conds_of should return empty hash when there is no conds'
255
+ )
256
+ end
257
+
258
+ def test_conds_of_with_cond_d
259
+ assert_equal(
260
+ {
261
+ :d => '200911',
262
+ :baz => '1234',
263
+ :qux => '4567',
264
+ },
265
+ Runo::Path.conds_of('/foo/bar/200911/baz=1234/qux=4567/'),
266
+ 'Runo::Path.conds_of should be able to distinguish ambiguous conds[:d]'
267
+ )
268
+ assert_equal(
269
+ {
270
+ :baz => '1234',
271
+ :qux => '4567',
272
+ },
273
+ Runo::Path.conds_of('/foo/bar/20091129_0001/baz=1234/qux=4567/'),
274
+ 'Runo::Path.conds_of should ignore the full-formatted id'
275
+ )
276
+ end
277
+
278
+ def test_conds_of_with_cond_id
279
+ assert_equal(
280
+ ['foo', 'bar'],
281
+ Runo::Path.steps_of('/foo/bar/20091205/9/baz=1234/qux=4567/'),
282
+ 'Runo::Path.steps_of should ignore conds[:id]'
283
+ )
284
+ assert_equal(
285
+ {
286
+ :id => '20091205_0009',
287
+ :baz => '1234',
288
+ :qux => '4567',
289
+ },
290
+ Runo::Path.conds_of('/foo/bar/20091205/9/baz=1234/qux=4567/'),
291
+ 'Runo::Path.conds_of should extract conds[:id] from the path sequence'
292
+ )
293
+ end
294
+
295
+ def test_action_of
296
+ assert_equal(
297
+ :create,
298
+ Runo::Path.action_of('/foo/bar/create.html'),
299
+ 'Runo::Path.action_of should extract the action from path_info'
300
+ )
301
+
302
+ assert_nil(
303
+ Runo::Path.action_of('/foo/bar/index.html'),
304
+ 'Runo::Path.action_of should return nil if the pseudo-filename is index.*'
305
+ )
306
+ assert_nil(
307
+ Runo::Path.action_of('/foo/bar/'),
308
+ 'Runo::Path.action_of should return nil if no pseudo-filename is given'
309
+ )
310
+ assert_nil(
311
+ Runo::Path.action_of('/foo/bar/_detail.html'),
312
+ "Runo::Path.action_of should return nil if the pseudo-filename begins with '_'"
313
+ )
314
+ end
315
+
316
+ def test_sub_action_of
317
+ assert_equal(
318
+ :detail,
319
+ Runo::Path.sub_action_of('/foo/bar/read_detail.html'),
320
+ 'Runo::Path.sub_action_of should extract the sub_action from path_info'
321
+ )
322
+ assert_nil(
323
+ Runo::Path.sub_action_of('/foo/bar/read.html'),
324
+ "Runo::Path.sub_action_of should return nil if the pseudo-filename does not include '_'"
325
+ )
326
+ end
327
+
328
+ def test_base_of
329
+ sd = Runo::Path.base_of '/foo/bar/main/index.html'
330
+ assert_instance_of(
331
+ Runo::Set::Dynamic,
332
+ sd,
333
+ 'Runo::Path.base_of should return a set_dynamic'
334
+ )
335
+ assert_equal(
336
+ '-foo-bar-main',
337
+ sd[:full_name],
338
+ 'Runo::Path.base_of should return a set_dynamic at the bottom of the given steps'
339
+ )
340
+
341
+ sd = Runo::Path.base_of '/foo/bar/index.html'
342
+ assert_instance_of(
343
+ Runo::Set::Dynamic,
344
+ sd,
345
+ 'Runo::Path.base_of should return a set_dynamic'
346
+ )
347
+ assert_equal(
348
+ '-foo-bar-main',
349
+ sd[:full_name],
350
+ "Runo::Path.base_of should return the item('main') if the given steps point at a folder"
351
+ )
352
+
353
+ sd = Runo::Path.base_of '/foo/bar/20091120_0001/comment/index.html'
354
+ assert_instance_of(
355
+ Runo::Text,
356
+ sd,
357
+ 'Runo::Path.base_of should return a text if designated'
358
+ )
359
+
360
+ sd = Runo::Path.base_of '/foo/bar/20091120_0001/files/index.html'
361
+ assert_instance_of(
362
+ Runo::Set::Dynamic,
363
+ sd,
364
+ 'Runo::Path.base_of should return a set_dynamic'
365
+ )
366
+ assert_equal(
367
+ '-foo-bar-main-20091120_0001-files',
368
+ sd[:full_name],
369
+ "Runo::Path.base_of should be able to dive into any depth from the folder"
370
+ )
371
+
372
+ sd = Runo::Path.base_of '/foo/bar/20091120_0002/files/index.html'
373
+ assert_nil(
374
+ sd,
375
+ 'Runo::Path.base_of should return nil if there is no set_dynamic at the steps'
376
+ )
377
+ end
378
+
379
+ def test_path_of
380
+ assert_equal(
381
+ '20091224/123/',
382
+ Runo::Path.path_of(:id => '20091224_0123'),
383
+ 'Runo::Path.path_of should return a special combination of pseudo-steps for conds[:id]'
384
+ )
385
+ assert_equal(
386
+ '20091224/123/',
387
+ Runo::Path.path_of(:d => '2009', :id => '20091224_0123'),
388
+ 'Runo::Path.path_of should ignore the other conds if there is conds[:id]'
389
+ )
390
+
391
+ assert_equal(
392
+ '20091224/123/',
393
+ Runo::Path.path_of(:id => ['20091224_0123']),
394
+ 'Runo::Path.path_of should return a special combination of pseudo-steps for conds[:id]'
395
+ )
396
+ assert_equal(
397
+ 'id=20091224_0123,20100222_1234/',
398
+ Runo::Path.path_of(:id => ['20091224_0123', '20100222_1234']),
399
+ 'Runo::Path.path_of should return multiple ids as a comma-separated form'
400
+ )
401
+ assert_equal(
402
+ '',
403
+ Runo::Path.path_of(:id => []),
404
+ 'Runo::Path.path_of should return an empty string when given an empty conds[:id]'
405
+ )
406
+
407
+ assert_equal(
408
+ 'id=carl/',
409
+ Runo::Path.path_of(:id => '00000000_carl'),
410
+ "Runo::Path.path_of should use '/id=xxx/' form for a short id"
411
+ )
412
+ assert_equal(
413
+ 'id=20091224_0123,carl/',
414
+ Runo::Path.path_of(:id => ['20091224_0123', '00000000_carl']),
415
+ "Runo::Path.path_of should use short ids in a comma-separated form"
416
+ )
417
+
418
+ assert_equal(
419
+ 'foo=bar/',
420
+ Runo::Path.path_of(:foo => 'bar'),
421
+ 'Runo::Path.path_of should return a path of which steps represent the conds'
422
+ )
423
+ assert_equal(
424
+ 'foo=bar/p=123/',
425
+ Runo::Path.path_of(:p => 123, :foo => 'bar'),
426
+ 'Runo::Path.path_of should return the step for conds[:p] at the tail end'
427
+ )
428
+ assert_equal(
429
+ 'foo=bar/order=desc/p=123/',
430
+ Runo::Path.path_of(:p => 123, :order =>'desc', :foo => 'bar'),
431
+ 'Runo::Path.path_of should return the step for conds[:order] at the tail end'
432
+ )
433
+
434
+ assert_equal(
435
+ 'foo=bar/',
436
+ Runo::Path.path_of(:p => 1, :foo => 'bar'),
437
+ 'Runo::Path.path_of should omit the step for conds[:p] when conds[:p] == 1'
438
+ )
439
+ assert_equal(
440
+ 'p=1/',
441
+ Runo::Path.path_of(:p => 1),
442
+ 'Runo::Path.path_of should not omit the step for conds[:p] when there is no other conds'
443
+ )
444
+
445
+ assert_equal(
446
+ 'foo=1,2,3/',
447
+ Runo::Path.path_of(:foo => [1, 2, 3]),
448
+ 'Runo::Path.path_of should return multiple values as a comma-separated form'
449
+ )
450
+ end
451
+
452
+ def test_params_from_request
453
+ runo = Runo.new
454
+
455
+ env = Rack::MockRequest.env_for(
456
+ 'http://example.com/foo/bar/main/qux=456/read_detail.html?acorn=round',
457
+ {
458
+ :method => 'post',
459
+ :script_name => '',
460
+ :input => 'coax=true&some-doors=open',
461
+ }
462
+ )
463
+ req = Rack::Request.new env
464
+ params = runo.instance_eval {
465
+ params_from_request req
466
+ }
467
+ assert_equal(
468
+ {
469
+ :conds => {:qux => '456'},
470
+ :action => :read,
471
+ :sub_action => :detail,
472
+ 'acorn' => 'round',
473
+ 'coax' => 'true',
474
+ 'some' => {'doors' => 'open'},
475
+ },
476
+ params,
477
+ 'Runo#params_from_request should build params from req.path_info and req.params'
478
+ )
479
+
480
+ env = Rack::MockRequest.env_for(
481
+ 'http://example.com/foo/bar/qux=456/index.html?acorn=round',
482
+ {
483
+ :method => 'post',
484
+ :script_name => '',
485
+ :input => 'coax=true&some-doors=open',
486
+ }
487
+ )
488
+ req = Rack::Request.new env
489
+ params = runo.instance_eval {
490
+ params_from_request req
491
+ }
492
+ assert_equal(
493
+ {
494
+ :conds => {:qux => '456'},
495
+ :action => nil,
496
+ :sub_action => nil,
497
+ 'acorn' => 'round',
498
+ 'coax' => 'true',
499
+ 'some' => {'doors' => 'open'},
500
+ },
501
+ params,
502
+ 'Runo#params_from_request should build params from req.path_info and req.params'
503
+ )
504
+
505
+ env = Rack::MockRequest.env_for(
506
+ 'http://example.com/foo/bar/20091120_0001/files/qux=456/index.html?acorn=round',
507
+ {
508
+ :method => 'post',
509
+ :script_name => '',
510
+ :input => 'coax=true&some-doors=open',
511
+ }
512
+ )
513
+ req = Rack::Request.new env
514
+ params = runo.instance_eval {
515
+ params_from_request req
516
+ }
517
+ assert_equal(
518
+ {
519
+ :conds => {:qux => '456'},
520
+ :action => nil,
521
+ :sub_action => nil,
522
+ 'acorn' => 'round',
523
+ 'coax' => 'true',
524
+ 'some' => {'doors' => 'open'},
525
+ },
526
+ params,
527
+ 'Runo#params_from_request should attach the params from path_info to the base SD'
528
+ )
529
+
530
+ env = Rack::MockRequest.env_for(
531
+ 'http://example.com/foo/bar/qux=456/index.html?acorn=round',
532
+ {
533
+ :method => 'post',
534
+ :script_name => '',
535
+ :input => 'some-doors=open&some.action-open=submit',
536
+ }
537
+ )
538
+ req = Rack::Request.new env
539
+ params = runo.instance_eval {
540
+ params_from_request req
541
+ }
542
+ assert_equal(
543
+ {
544
+ :conds => {:qux => '456'},
545
+ :action => nil,
546
+ :sub_action => nil,
547
+ 'acorn' => 'round',
548
+ 'some' => {'doors' => 'open', :action => :open},
549
+ },
550
+ params,
551
+ 'Runo#params_from_request should build params from req.path_info and req.params'
552
+ )
553
+
554
+ env = Rack::MockRequest.env_for(
555
+ 'http://example.com/foo/bar/update.html',
556
+ {
557
+ :method => 'post',
558
+ :script_name => '',
559
+ :input => '.action=open_sesami',
560
+ }
561
+ )
562
+ req = Rack::Request.new env
563
+ params = runo.instance_eval {
564
+ params_from_request req
565
+ }
566
+ assert_equal(
567
+ {
568
+ :conds => {},
569
+ :action => :open,
570
+ :sub_action => :sesami,
571
+ },
572
+ params,
573
+ 'Runo#params_from_request should override path_info by :input'
574
+ )
575
+
576
+ env = Rack::MockRequest.env_for(
577
+ 'http://example.com/foo/bar/update.html',
578
+ {
579
+ :method => 'post',
580
+ :script_name => '',
581
+ :input => '.action-open_sesami=submit',
582
+ }
583
+ )
584
+ req = Rack::Request.new env
585
+ params = runo.instance_eval {
586
+ params_from_request req
587
+ }
588
+ assert_equal(
589
+ {
590
+ :conds => {},
591
+ :action => :open,
592
+ :sub_action => :sesami,
593
+ },
594
+ params,
595
+ 'Runo#params_from_request should override path_info by :input'
596
+ )
597
+ end
598
+
599
+ def test_current
600
+ Runo.current[:foo] = 'main foo'
601
+ main_current = Runo.current
602
+
603
+ t = Thread.new {
604
+ assert_not_equal(
605
+ main_current,
606
+ Runo.current,
607
+ 'Runo.current should be unique per a thread'
608
+ )
609
+ assert_not_equal(
610
+ 'main foo',
611
+ Runo.current[:foo],
612
+ 'Runo.current should be unique per a thread'
613
+ )
614
+ Runo.current[:foo] = 'child foo'
615
+ }
616
+ t.join
617
+
618
+ assert_equal(
619
+ 'main foo',
620
+ Runo.current[:foo],
621
+ 'Runo.current should be unique per a thread'
622
+ )
623
+ end
624
+
625
+ def test_login
626
+ Runo.client = nil
627
+ res = Runo.new.send(
628
+ :login,
629
+ Runo::Set::Static::Folder.root.item('foo', 'main'),
630
+ {'id' => 'test', 'pw' => 'test', :conds => {:id => '20100222_0123'}, 'dest_action' => 'update'}
631
+ )
632
+ assert_equal(
633
+ 'test',
634
+ Runo.client,
635
+ 'Runo#login should set Runo.client given a valid pair of user/password'
636
+ )
637
+ assert_match(
638
+ %r{/foo/20100222/123/update.html},
639
+ res[1]['Location'],
640
+ 'Runo#login should return a proper location header'
641
+ )
642
+ end
643
+
644
+ def test_login_default_action
645
+ Runo.client = nil
646
+ res = Runo.new.send(
647
+ :login,
648
+ Runo::Set::Static::Folder.root.item('foo', 'main'),
649
+ {'id' => 'test', 'pw' => 'test', :conds => {:id => '20100222_0123'}}
650
+ )
651
+ assert_match(
652
+ %r{/foo/20100222/123/index.html},
653
+ res[1]['Location'],
654
+ "Runo#login should set 'index' as the default action of a location"
655
+ )
656
+ end
657
+
658
+ def test_login_with_wrong_account
659
+ Runo.client = nil
660
+
661
+ assert_raise(
662
+ Runo::Error::Forbidden,
663
+ 'Runo#login should raise Error::Forbidden given a non-existent user'
664
+ ) {
665
+ Runo.new.send(
666
+ :login,
667
+ Runo::Set::Static::Folder.root.item('foo', 'main'),
668
+ {'id' => 'non-existent', 'pw' => 'test'}
669
+ )
670
+ }
671
+ assert_equal(
672
+ 'nobody',
673
+ Runo.client,
674
+ 'Runo#login should not set Runo.client with a non-existent user'
675
+ )
676
+
677
+ assert_raise(
678
+ Runo::Error::Forbidden,
679
+ 'Runo#login should raise Error::Forbidden given a empty password'
680
+ ) {
681
+ Runo.new.send(
682
+ :login,
683
+ Runo::Set::Static::Folder.root.item('foo', 'main'),
684
+ {'id' => 'test', 'pw' => nil}
685
+ )
686
+ }
687
+ assert_equal(
688
+ 'nobody',
689
+ Runo.client,
690
+ 'Runo#login should not set Runo.client with an empty password'
691
+ )
692
+
693
+ assert_raise(
694
+ Runo::Error::Forbidden,
695
+ 'Runo#login should raise Error::Forbidden given a wrong password'
696
+ ) {
697
+ res = Runo.new.send(
698
+ :login,
699
+ Runo::Set::Static::Folder.root.item('foo', 'main'),
700
+ {
701
+ 'id' => 'test',
702
+ 'pw' => 'wrong',
703
+ :conds => {:id => '20100222_0123'},
704
+ 'dest_action' => 'update'
705
+ }
706
+ )
707
+ }
708
+ assert_equal(
709
+ 'nobody',
710
+ Runo.client,
711
+ 'Runo#login should not set Runo.client with a wrong password'
712
+ )
713
+ end
714
+
715
+ def test_logout
716
+ Runo.client = 'frank'
717
+ res = Runo.new.send(
718
+ :logout,
719
+ Runo::Set::Static::Folder.root.item('foo', 'main'),
720
+ {'id' => 'test', 'pw' => 'test', :conds => {:id => '20100222_0123'}}
721
+ )
722
+ assert_equal(
723
+ 'nobody',
724
+ Runo.client,
725
+ 'Runo#logout should clear Runo.client'
726
+ )
727
+ assert_match(
728
+ %r{/foo/20100222/123/index.html},
729
+ res[1]['Location'],
730
+ 'Runo#logout should return a proper location header'
731
+ )
732
+ end
733
+
734
+ def test_libdir
735
+ assert_match(
736
+ %r{^.*/lib$},
737
+ Runo.libdir,
738
+ 'Runo#libdir should return the lib/ directory where the runo.rb is in'
739
+ )
740
+ end
741
+
742
+ end