runo 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (149) hide show
  1. data/LICENSE +19 -0
  2. data/README.rdoc +120 -0
  3. data/bin/runo +35 -0
  4. data/lib/_error.rb +14 -0
  5. data/lib/_field.rb +260 -0
  6. data/lib/_i18n.rb +141 -0
  7. data/lib/_parser.rb +243 -0
  8. data/lib/_path.rb +86 -0
  9. data/lib/_storage/_storage.rb +213 -0
  10. data/lib/_storage/file.rb +200 -0
  11. data/lib/_storage/sequel.rb +174 -0
  12. data/lib/_storage/temp.rb +73 -0
  13. data/lib/_widget/action_create.rb +23 -0
  14. data/lib/_widget/action_login.rb +22 -0
  15. data/lib/_widget/action_signup.rb +16 -0
  16. data/lib/_widget/action_update.rb +16 -0
  17. data/lib/_widget/crumb.rb +24 -0
  18. data/lib/_widget/done.rb +16 -0
  19. data/lib/_widget/login.rb +25 -0
  20. data/lib/_widget/me.rb +31 -0
  21. data/lib/_widget/message.rb +51 -0
  22. data/lib/_widget/navi.rb +88 -0
  23. data/lib/_widget/submit.rb +49 -0
  24. data/lib/_widget/view_ym.rb +77 -0
  25. data/lib/_workflow/_workflow.rb +89 -0
  26. data/lib/_workflow/attachment.rb +50 -0
  27. data/lib/_workflow/blog.rb +28 -0
  28. data/lib/_workflow/contact.rb +23 -0
  29. data/lib/_workflow/forum.rb +26 -0
  30. data/lib/_workflow/register.rb +39 -0
  31. data/lib/meta/_meta.rb +20 -0
  32. data/lib/meta/group.rb +19 -0
  33. data/lib/meta/id.rb +59 -0
  34. data/lib/meta/owner.rb +21 -0
  35. data/lib/meta/timestamp.rb +118 -0
  36. data/lib/runo.rb +396 -0
  37. data/lib/scalar/checkbox.rb +68 -0
  38. data/lib/scalar/file.rb +144 -0
  39. data/lib/scalar/img.rb +112 -0
  40. data/lib/scalar/password.rb +58 -0
  41. data/lib/scalar/radio.rb +47 -0
  42. data/lib/scalar/select.rb +47 -0
  43. data/lib/scalar/text.rb +38 -0
  44. data/lib/scalar/textarea.rb +35 -0
  45. data/lib/scalar/textarea_pre.rb +14 -0
  46. data/lib/scalar/textarea_wiki.rb +173 -0
  47. data/lib/set/_set.rb +195 -0
  48. data/lib/set/dynamic.rb +177 -0
  49. data/lib/set/static.rb +102 -0
  50. data/lib/set/static_folder.rb +96 -0
  51. data/locale/en/index.po +242 -0
  52. data/locale/index.pot +243 -0
  53. data/locale/ja/index.po +242 -0
  54. data/locale/lazy_parser.rb +54 -0
  55. data/skel/config.ru +27 -0
  56. data/skel/skin/_users/00000000_frank-avatar.jpg +0 -0
  57. data/skel/skin/_users/00000000_frank-avatar_small.jpg +0 -0
  58. data/skel/skin/_users/00000000_frank.yaml +12 -0
  59. data/skel/skin/_users/00000000_root-avatar.jpg +0 -0
  60. data/skel/skin/_users/00000000_root-avatar_small.jpg +0 -0
  61. data/skel/skin/_users/00000000_root.yaml +11 -0
  62. data/skel/skin/_users/css/users.css +21 -0
  63. data/skel/skin/_users/css/users.less +25 -0
  64. data/skel/skin/_users/done.html +42 -0
  65. data/skel/skin/_users/index.html +46 -0
  66. data/skel/skin/_users/index.yaml +3 -0
  67. data/skel/skin/_users/summary.html +40 -0
  68. data/skel/skin/css/base.css +93 -0
  69. data/skel/skin/css/base.less +139 -0
  70. data/skel/skin/css/coax.css +199 -0
  71. data/skel/skin/css/coax.less +244 -0
  72. data/skel/skin/examples/blog/20091214_0001.yaml +8 -0
  73. data/skel/skin/examples/blog/20100630_0001.yaml +8 -0
  74. data/skel/skin/examples/blog/20100630_0002.yaml +14 -0
  75. data/skel/skin/examples/blog/20100701_0001.yaml +8 -0
  76. data/skel/skin/examples/blog/20100701_0002-a-20100701_0001-f.jpg +0 -0
  77. data/skel/skin/examples/blog/20100701_0002-a-20100701_0001-f_small.jpg +0 -0
  78. data/skel/skin/examples/blog/20100701_0002.yaml +19 -0
  79. data/skel/skin/examples/blog/frank/20100701_0001.yaml +10 -0
  80. data/skel/skin/examples/blog/frank/index.yaml +4 -0
  81. data/skel/skin/examples/blog/index.html +51 -0
  82. data/skel/skin/examples/blog/rss.xml +18 -0
  83. data/skel/skin/examples/contact/20100701_0001-file.txt +1 -0
  84. data/skel/skin/examples/contact/20100701_0001.yaml +15 -0
  85. data/skel/skin/examples/contact/20100701_0002.yaml +8 -0
  86. data/skel/skin/examples/contact/20100701_0003.yaml +9 -0
  87. data/skel/skin/examples/contact/index.html +47 -0
  88. data/skel/skin/examples/contact/js/contact.js +13 -0
  89. data/skel/skin/examples/contact/summary.html +54 -0
  90. data/skel/skin/examples/forum/20100701_0001.yaml +41 -0
  91. data/skel/skin/examples/forum/20100701_0002.yaml +25 -0
  92. data/skel/skin/examples/forum/index.html +68 -0
  93. data/skel/skin/examples/forum/summary.html +47 -0
  94. data/skel/skin/examples/index.html +75 -0
  95. data/skel/skin/index.html +41 -0
  96. data/skel/skin/js/base.js +50 -0
  97. data/t/locale/de/index.po +19 -0
  98. data/t/locale/en-GB/index.po +25 -0
  99. data/t/locale/ja/index.po +30 -0
  100. data/t/skin/_users/00000000_test.yaml +3 -0
  101. data/t/skin/_users/index.html +13 -0
  102. data/t/skin/foo/20091120_0001.yaml +7 -0
  103. data/t/skin/foo/bar/20091120_0001.yaml +5 -0
  104. data/t/skin/foo/bar/index.yaml +5 -0
  105. data/t/skin/foo/baz/css/baz.css +1 -0
  106. data/t/skin/foo/css/foo.css +1 -0
  107. data/t/skin/foo/index.html +14 -0
  108. data/t/skin/foo/index.yaml +7 -0
  109. data/t/skin/foo/not_css/foo.css +1 -0
  110. data/t/skin/foo/sub-20100306_0001.yaml +3 -0
  111. data/t/skin/index.yaml +3 -0
  112. data/t/skin/t_attachment/index.html +13 -0
  113. data/t/skin/t_contact/done.html +6 -0
  114. data/t/skin/t_contact/index.html +9 -0
  115. data/t/skin/t_file/index.html +16 -0
  116. data/t/skin/t_img/index.html +14 -0
  117. data/t/skin/t_img/test.jpg +0 -0
  118. data/t/skin/t_select/index.html +9 -0
  119. data/t/skin/t_store/index.html +9 -0
  120. data/t/skin/t_summary/20100326_0001.yaml +3 -0
  121. data/t/skin/t_summary/create.html +9 -0
  122. data/t/skin/t_summary/index.html +9 -0
  123. data/t/skin/t_summary/summary.html +9 -0
  124. data/t/t.rb +27 -0
  125. data/t/test_checkbox.rb +273 -0
  126. data/t/test_field.rb +330 -0
  127. data/t/test_file.rb +900 -0
  128. data/t/test_id.rb +215 -0
  129. data/t/test_img.rb +328 -0
  130. data/t/test_meta.rb +57 -0
  131. data/t/test_parser.rb +1266 -0
  132. data/t/test_password.rb +188 -0
  133. data/t/test_radio.rb +226 -0
  134. data/t/test_role.rb +249 -0
  135. data/t/test_runo.rb +742 -0
  136. data/t/test_runo_call.rb +1286 -0
  137. data/t/test_runo_i18n.rb +318 -0
  138. data/t/test_select.rb +182 -0
  139. data/t/test_set_complex.rb +527 -0
  140. data/t/test_set_dynamic.rb +1504 -0
  141. data/t/test_set_folder.rb +515 -0
  142. data/t/test_set_permit.rb +246 -0
  143. data/t/test_set_static.rb +445 -0
  144. data/t/test_storage.rb +915 -0
  145. data/t/test_text.rb +125 -0
  146. data/t/test_textarea.rb +138 -0
  147. data/t/test_timestamp.rb +473 -0
  148. data/t/test_workflow.rb +367 -0
  149. metadata +345 -0
@@ -0,0 +1,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