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,318 @@
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_I18n < Test::Unit::TestCase
9
+
10
+ include Runo::I18n
11
+
12
+ def setup
13
+ Runo::I18n.domain = 'index'
14
+ Runo::I18n.po_dir = './t/locale'
15
+ end
16
+
17
+ def teardown
18
+ end
19
+
20
+ def test_lang
21
+ Runo::I18n.lang = 'ja'
22
+ assert_instance_of(
23
+ Array,
24
+ Runo::I18n.lang,
25
+ 'Runo::I18n.lang should return an array'
26
+ )
27
+ assert_equal(
28
+ ['ja'],
29
+ Runo::I18n.lang,
30
+ 'Runo::I18n.lang should return the current acceptable language-ranges'
31
+ )
32
+ end
33
+
34
+ def test_lang_case
35
+ Runo::I18n.lang = 'JA-jp'
36
+ assert_equal(
37
+ ['ja-JP'],
38
+ Runo::I18n.lang,
39
+ 'Runo::I18n.lang should be properly downcase/upcased'
40
+ )
41
+ end
42
+
43
+ def test_multiple_lang
44
+ Runo::I18n.lang = 'ja, de;q=0.5, en;q=0.8'
45
+ assert_equal(
46
+ ['ja', 'en', 'de'],
47
+ Runo::I18n.lang,
48
+ 'Runo::I18n.lang should sort the language-ranges by their quality values'
49
+ )
50
+ end
51
+
52
+ def test_same_qvalues
53
+ Runo::I18n.lang = 'ja, de;q=0.5, en;q=0.5'
54
+ assert_equal(
55
+ ['ja', 'de', 'en'],
56
+ Runo::I18n.lang,
57
+ 'Runo::I18n.lang should be sorted by their original order if the qvalues are same'
58
+ )
59
+ Runo::I18n.lang = 'ja, de, en'
60
+ assert_equal(
61
+ ['ja', 'de', 'en'],
62
+ Runo::I18n.lang,
63
+ 'Runo::I18n.lang should be sorted by their original order if the qvalues are same'
64
+ )
65
+ end
66
+
67
+ def test_po_dir
68
+ Runo::I18n.po_dir = 'foo/bar'
69
+ assert_equal(
70
+ 'foo/bar',
71
+ Runo::I18n.po_dir,
72
+ 'Runo::I18n.po_dir should be return the path to po files'
73
+ )
74
+ end
75
+
76
+ def test_domain
77
+ Runo::I18n.domain = 'foo'
78
+ assert_equal(
79
+ 'foo',
80
+ Runo::I18n.domain,
81
+ 'Runo::I18n.domain should be return the current domain'
82
+ )
83
+ end
84
+
85
+ def test_bindtextdomain
86
+ Runo::I18n.bindtextdomain('foo', 'bar/baz')
87
+ assert_equal(
88
+ 'foo',
89
+ Runo::I18n.domain,
90
+ 'Runo::I18n.bindtextdomain should set the current domain'
91
+ )
92
+ assert_equal(
93
+ 'bar/baz',
94
+ Runo::I18n.po_dir,
95
+ 'Runo::I18n.bindtextdomain should set the path to po files'
96
+ )
97
+ end
98
+
99
+ def test_msg
100
+ Runo::I18n.lang = 'ja'
101
+ assert_instance_of(
102
+ ::Hash,
103
+ Runo::I18n.msg,
104
+ 'Runo::I18n.msg should return a hash'
105
+ )
106
+ assert_equal(
107
+ {'color' => '色', 'one color' =>['%{n}色']},
108
+ Runo::I18n.msg.reject {|k, v| k == :plural },
109
+ 'Runo::I18n.msg should return a hash containing {msgid => msgstr}'
110
+ )
111
+ assert_instance_of(
112
+ ::Proc,
113
+ Runo::I18n.msg[:plural],
114
+ 'Runo::I18n.msg[:plural] should return a proc'
115
+ )
116
+
117
+ Runo::I18n.lang = 'po'
118
+ assert_equal(
119
+ {},
120
+ Runo::I18n.msg,
121
+ 'Runo::I18n.msg should be reset when the lang is updated'
122
+ )
123
+ end
124
+
125
+ def test_merge_msg!
126
+ Runo::I18n.lang = 'no'
127
+ assert_equal({}, Runo::I18n.msg)
128
+
129
+ Runo::I18n.merge_msg!('color' => 'farge')
130
+ assert_equal(
131
+ {'color' => 'farge'},
132
+ Runo::I18n.msg,
133
+ 'Runo::I18n.merge_msg! should dynamically merge a hash to the msg of the current thread'
134
+ )
135
+
136
+ Runo::I18n.merge_msg!(:plural => Proc.new { 123 })
137
+ assert_equal(
138
+ {'color' => 'farge'},
139
+ Runo::I18n.msg,
140
+ 'Runo::I18n.merge_msg! should not merge :plural'
141
+ )
142
+
143
+ Runo::I18n.lang = 'no'
144
+ assert_equal(
145
+ {},
146
+ Runo::I18n.msg,
147
+ 'Runo::I18n.merge_msg! should not affect anything other than the current thread'
148
+ )
149
+ end
150
+
151
+ def test_rex_plural_expression_ok
152
+ src = <<'_eos'.split "\n"
153
+ "Plural-Forms: nplurals=1; plural=0;"
154
+ "Plural-Forms: nplurals=2; plural=n != 1;"
155
+ "Plural-Forms: nplurals=2; plural=n>1;"
156
+ "Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n != 0 ? 1 : 2;"
157
+ "Plural-Forms: nplurals=3; plural=n==1 ? 0 : n==2 ? 1 : 2;"
158
+ "Plural-Forms: nplurals=3; Plural=n==1 ? 0 : (n==0 || (n%100 > 0 && n%100 < 20)) ? 1 : 2;"
159
+ "Plural-Forms: nplurals=3; Plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && (n%100<10 || n%100>=20) ? 1 : 2;"
160
+ "Plural-Forms: nplurals=3; Plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;"
161
+ "Plural-Forms: nplurals=3; Plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;"
162
+ "Plural-Forms: nplurals=3; Plural=n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;"
163
+ "Plural-Forms: nplurals=4; Plural=n%100==1 ? 0 : n%100==2 ? 1 : n%100==3 || n%100==4 ? 2 : 3;"
164
+ _eos
165
+ src.each {|s|
166
+ assert_match(
167
+ Runo::I18n::REX::PLURAL_EXPRESSION,
168
+ s,
169
+ 'Runo::I18n::REX::PLURAL_EXPRESSION should match'
170
+ )
171
+ }
172
+ end
173
+
174
+ def test_rex_plural_expression_ng
175
+ src = <<'_eos'.split "\n"
176
+ "Plural-Forms: nplurals=1; plural=rm '.';"
177
+ "Plural-Forms: nplurals=1; plural=Fileutils.rm_r('.');"
178
+ "Plural-Forms: nplurals=1; plural=Fileutils.rm_r '.';"
179
+ "Plural-Forms: nplurals=1; plural=Fileutils.rm_r ".";"
180
+ "Plural-Forms: nplurals=2; plural=n;"
181
+ "Plural-Forms: nplurals=2; plural=nn;"
182
+ "Plural-Forms: nplurals=3; plural=n();"
183
+ "Plural-Forms: nplurals=3; plural=n(123);"
184
+ "Plural-Forms: nplurals=3; plural=n 123;"
185
+ _eos
186
+ src.each {|s|
187
+ assert_no_match(
188
+ Runo::I18n::REX::PLURAL_EXPRESSION,
189
+ s,
190
+ 'Runo::I18n::REX::PLURAL_EXPRESSION should not match malicious expressions'
191
+ )
192
+ }
193
+ end
194
+
195
+ def test__
196
+ Runo::I18n.lang = 'ja'
197
+ assert_equal(
198
+ '色',
199
+ _('color'),
200
+ 'Runo::I18n#_() should return a string according to the msgid'
201
+ )
202
+
203
+ Runo::I18n.lang = 'en-GB'
204
+ assert_equal(
205
+ 'colour',
206
+ _('color'),
207
+ 'Runo::I18n#_() should return a string according to the msgid'
208
+ )
209
+
210
+ Runo::I18n.lang = 'no'
211
+ assert_equal(
212
+ 'color',
213
+ _('color'),
214
+ 'Runo::I18n#_() should return a msgid if the msgid is not existed in the msg'
215
+ )
216
+ end
217
+
218
+ def test_n_
219
+ Runo::I18n.lang = 'ja'
220
+ assert_equal(
221
+ '%{n}色',
222
+ n_('one color', '%{n} colors', 1),
223
+ 'Runo::I18n#n_() should return a string according to the msgid and the n'
224
+ )
225
+ assert_equal(
226
+ '%{n}色',
227
+ n_('one color', '%{n} colors', 2),
228
+ 'Runo::I18n#n_() should return a string according to the msgid and the n'
229
+ )
230
+
231
+ Runo::I18n.lang = 'en-GB'
232
+ assert_equal(
233
+ 'one colour',
234
+ n_('one color', '%{n} colors', 1),
235
+ 'Runo::I18n#n_() should return a string according to the msgid and the n'
236
+ )
237
+ assert_equal(
238
+ '%{n} colours',
239
+ n_('one color', '%{n} colors', 2),
240
+ 'Runo::I18n#n_() should return a string according to the msgid and the n'
241
+ )
242
+
243
+ Runo::I18n.lang = 'no'
244
+ assert_equal(
245
+ 'one color',
246
+ n_('one color', '%{n} colors', 1),
247
+ 'Runo::I18n#_() should return a msgid if the msgid is not existed in the msg'
248
+ )
249
+ assert_equal(
250
+ '%{n} colors',
251
+ n_('one color', '%{n} colors', 2),
252
+ 'Runo::I18n#_() should return a msgid if the msgid is not existed in the msg'
253
+ )
254
+ end
255
+
256
+ def test__with_n_
257
+ Runo::I18n.lang = 'en-GB'
258
+ assert_equal(
259
+ 'one colour',
260
+ _('one color'),
261
+ 'Runo::I18n#_() should return msgstr[0] if the msgid refer to plural msgstrs'
262
+ )
263
+ end
264
+
265
+ def test_n_with__
266
+ Runo::I18n.lang = 'en-GB'
267
+ assert_equal(
268
+ 'color',
269
+ n_('color', '%{n} colors', 1),
270
+ 'Runo::I18n#n_() should return msgid if the msgid refer to sigular msgstr'
271
+ )
272
+ end
273
+
274
+ def test_msgstr
275
+ Runo::I18n.lang = 'en-GB'
276
+
277
+ assert_instance_of(
278
+ Runo::I18n::Msgstr,
279
+ _('color'),
280
+ 'Runo::I18n#_() should return a instance of Runo::I18n::Msgstr'
281
+ )
282
+
283
+ s = n_('one color', '%{n} colors', 2)
284
+ assert_instance_of(
285
+ Runo::I18n::Msgstr,
286
+ s,
287
+ 'Runo::I18n#n_() should return a instance of Runo::I18n::Msgstr'
288
+ )
289
+ assert_equal(
290
+ '2 colours',
291
+ s % {:n => 2},
292
+ 'Runo::I18n::Msgstr#% should be able to proccess named variables'
293
+ )
294
+ assert_equal(
295
+ '2 colours',
296
+ s % [2],
297
+ "Runo::I18n::Msgstr#% should regard %{...} as '%s' if given an array"
298
+ )
299
+ assert_equal(
300
+ '2 colours',
301
+ s % 2,
302
+ "Runo::I18n::Msgstr#% should regard %{...} as '%s' if given a scalar"
303
+ )
304
+
305
+ s = n_('one color', '%{n} colors', 1)
306
+ assert_instance_of(
307
+ Runo::I18n::Msgstr,
308
+ s,
309
+ 'Runo::I18n#n_() should return a instance of Runo::I18n::Msgstr'
310
+ )
311
+ assert_equal(
312
+ 'one colour',
313
+ s % {:n => 1},
314
+ 'Runo::I18n::Msgstr#% should work with msgstrs without a placeholder'
315
+ )
316
+ end
317
+
318
+ end
@@ -0,0 +1,182 @@
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_Select < Test::Unit::TestCase
9
+
10
+ def setup
11
+ meta = nil
12
+ Runo::Parser.gsub_scalar("$(foo select bar, baz, qux :'baz' mandatory)") {|id, m|
13
+ meta = m
14
+ ''
15
+ }
16
+ @f = Runo::Field.instance meta
17
+ end
18
+
19
+ def teardown
20
+ end
21
+
22
+ def test_meta
23
+ assert_equal(
24
+ ['bar', 'baz', 'qux'],
25
+ @f[:options],
26
+ 'Select#initialize should set :options from the csv token'
27
+ )
28
+ assert_equal(
29
+ true,
30
+ @f[:mandatory],
31
+ 'Select#initialize should set :mandatory from the misc token'
32
+ )
33
+ assert_equal(
34
+ 'baz',
35
+ @f[:default],
36
+ 'Select#initialize should set :default from the token'
37
+ )
38
+ end
39
+
40
+ def test_meta_options_from_range
41
+ meta = nil
42
+ Runo::Parser.gsub_scalar("$(foo select 1..5)") {|id, m|
43
+ meta = m
44
+ ''
45
+ }
46
+ f = Runo::Field.instance meta
47
+ assert_equal(
48
+ ['1', '2', '3', '4', '5'],
49
+ f[:options],
50
+ 'Select#initialize should set :options from the range token'
51
+ )
52
+
53
+ meta = nil
54
+ Runo::Parser.gsub_scalar("$(foo select ..5)") {|id, m|
55
+ meta = m
56
+ ''
57
+ }
58
+ f = Runo::Field.instance meta
59
+ assert_equal(
60
+ ['0', '1', '2', '3', '4', '5'],
61
+ f[:options],
62
+ 'Select#initialize should set :options from the range token'
63
+ )
64
+
65
+ meta = nil
66
+ Runo::Parser.gsub_scalar("$(foo select 1..)") {|id, m|
67
+ meta = m
68
+ ''
69
+ }
70
+ f = Runo::Field.instance meta
71
+ assert_equal(
72
+ nil,
73
+ f[:options],
74
+ 'Select#initialize should not refer to the range token if there is no maximum'
75
+ )
76
+ end
77
+
78
+ def test_val_cast
79
+ assert_equal(
80
+ '',
81
+ @f.val,
82
+ 'Select#val_cast should cast the given val to String'
83
+ )
84
+
85
+ @f.load 123
86
+ assert_equal(
87
+ '123',
88
+ @f.val,
89
+ 'Select#val_cast should cast the given val to String'
90
+ )
91
+ end
92
+
93
+ def test_get
94
+ @f.load ''
95
+ assert_equal(
96
+ '',
97
+ @f.get,
98
+ 'Select#get should return proper string'
99
+ )
100
+ assert_equal(
101
+ <<_html,
102
+ <span class="select">
103
+ <select name="">
104
+ <option value="">please select</option>
105
+ <option>bar</option>
106
+ <option>baz</option>
107
+ <option>qux</option>
108
+ </select>
109
+ </span>
110
+ _html
111
+ @f.get(:action => :create),
112
+ 'Select#get should return proper string'
113
+ )
114
+
115
+ @f.load 'qux'
116
+ assert_equal(
117
+ 'qux',
118
+ @f.get,
119
+ 'Select#get should return proper string'
120
+ )
121
+ assert_equal(
122
+ <<_html,
123
+ <span class="select">
124
+ <select name="">
125
+ <option>bar</option>
126
+ <option>baz</option>
127
+ <option selected>qux</option>
128
+ </select>
129
+ </span>
130
+ _html
131
+ @f.get(:action => :update),
132
+ 'Select#get should return proper string'
133
+ )
134
+ end
135
+
136
+ def test_get_escape
137
+ @f[:options] = ['foo', '<bar>']
138
+ @f.load '<bar>'
139
+ assert_equal(
140
+ '&lt;bar&gt;',
141
+ @f.get,
142
+ 'Select#get should escape the special characters'
143
+ )
144
+ assert_equal(
145
+ <<_html,
146
+ <span class="select">
147
+ <select name="">
148
+ <option>foo</option>
149
+ <option selected>&lt;bar&gt;</option>
150
+ </select>
151
+ </span>
152
+ _html
153
+ @f.get(:action => :update),
154
+ 'Select#get should escape the special characters'
155
+ )
156
+ end
157
+
158
+ def test_errors
159
+ @f.load ''
160
+ @f[:mandatory] = nil
161
+ assert_equal(
162
+ [],
163
+ @f.errors,
164
+ 'Select#errors should return the errors of the current val'
165
+ )
166
+ @f[:mandatory] = true
167
+ assert_equal(
168
+ ['mandatory'],
169
+ @f.errors,
170
+ 'Select#errors should return the errors of the current val'
171
+ )
172
+
173
+ @f.load 'boo'
174
+ @f[:mandatory] = nil
175
+ assert_equal(
176
+ ['no such option'],
177
+ @f.errors,
178
+ 'Select#errors should return the errors of the current val'
179
+ )
180
+ end
181
+
182
+ end