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,215 @@
1
+ # encoding: UTF-8
2
+
3
+ # Author:: Akira FUNAI
4
+ # Copyright:: Copyright (c) 2009-2010 Akira FUNAI
5
+
6
+ require "#{::File.dirname __FILE__}/t"
7
+
8
+ class TC_Id < Test::Unit::TestCase
9
+
10
+ def setup
11
+ meta = nil
12
+ Runo::Parser.gsub_scalar('$(foo meta-id 3 1..5)') {|id, m|
13
+ meta = m
14
+ ''
15
+ }
16
+ @f = Runo::Field.instance meta
17
+
18
+ Runo.current[:base] = nil
19
+ end
20
+
21
+ def teardown
22
+ end
23
+
24
+ def test_meta
25
+ assert_equal(
26
+ 3,
27
+ @f[:size],
28
+ 'Meta::Id#initialize should set :size from the token'
29
+ )
30
+ assert_equal(
31
+ 1,
32
+ @f[:min],
33
+ 'Meta::Id#initialize should set :min from the range token'
34
+ )
35
+ assert_equal(
36
+ 5,
37
+ @f[:max],
38
+ 'Meta::Id#initialize should set :max from the range token'
39
+ )
40
+ end
41
+
42
+ def test_val_cast
43
+ assert_equal(
44
+ '',
45
+ @f.val,
46
+ 'Meta::Id#val_cast should cast the given val to String'
47
+ )
48
+
49
+ @f.load 123
50
+ assert_equal(
51
+ '123',
52
+ @f.val,
53
+ 'Meta::Id#val_cast should cast the given val to String'
54
+ )
55
+ end
56
+
57
+ def test_new_id?
58
+ @f[:parent] = Runo::Set::Static.new(:id => '20100526_0001')
59
+ assert_equal(
60
+ false,
61
+ @f.send(:new_id?),
62
+ 'Meta::Id#new_id? should return whether the ancestors is new or not'
63
+ )
64
+
65
+ @f[:parent] = Runo::Set::Static.new(:id => '_001')
66
+ assert_equal(
67
+ true,
68
+ @f.send(:new_id?),
69
+ 'Meta::Id#new_id? should return whether the ancestors is new or not'
70
+ )
71
+ end
72
+
73
+ def test_get
74
+ @f[:parent] = Runo::Set::Static.new(:id => '_001')
75
+ assert_equal(
76
+ '<span class="meta-id"><input type="text" name="" value="" size="3" /></span>',
77
+ @f.get(:action => :create),
78
+ 'Meta::Id#_g_create should return <input> if the ancestor is new'
79
+ )
80
+
81
+ @f[:parent] = Runo::Set::Static.new(:id => '20100526_0001')
82
+ assert_equal(
83
+ '',
84
+ @f.get(:action => :create),
85
+ 'Meta::Id#_g_create should return val if the ancestor is not new'
86
+ )
87
+
88
+ @f.load 'bar'
89
+ assert_equal(
90
+ 'bar',
91
+ @f.get,
92
+ 'Meta::Id#get should return proper string'
93
+ )
94
+
95
+ @f[:parent] = Runo::Set::Static.new(:id => '_001')
96
+ assert_equal(
97
+ '<span class="meta-id"><input type="text" name="" value="bar" size="3" /></span>',
98
+ @f.get(:action => :update),
99
+ 'Meta::Id#_g_update should return <input> if the ancestor is new'
100
+ )
101
+
102
+ @f[:parent] = Runo::Set::Static.new(:id => '20100526_0001')
103
+ assert_equal(
104
+ 'bar',
105
+ @f.get(:action => :update),
106
+ 'Meta::Id#_g_update should return val if the ancestor is not new'
107
+ )
108
+
109
+ @f.load '<bar>'
110
+ assert_equal(
111
+ '&lt;bar&gt;',
112
+ @f.get,
113
+ 'Meta::Id#get should escape the special characters'
114
+ )
115
+
116
+ @f[:parent] = Runo::Set::Static.new(:id => '_001')
117
+ @f.load '<bar>'
118
+ assert_equal(
119
+ '<span class="meta-id error"><input type="text" name="" value="&lt;bar&gt;" size="3" /><span class="error_message">malformatted id</span>' + "\n</span>",
120
+ @f.get(:action => :update),
121
+ 'Meta::Id#get should escape the special characters'
122
+ )
123
+ end
124
+
125
+ def test_post_new_ancestor
126
+ @f[:parent] = Runo::Set::Static.new(:id => '_001')
127
+ @f.create 'frank'
128
+ assert_equal(
129
+ 'frank',
130
+ @f.val,
131
+ 'Meta::Id#post should create like a normal field'
132
+ )
133
+
134
+ @f.update 'bobby'
135
+ assert_equal(
136
+ 'bobby',
137
+ @f.val,
138
+ 'Meta::Id#post should update the current val if the ancestor is new'
139
+ )
140
+ end
141
+
142
+ def test_post_old_ancestor
143
+ @f[:parent] = Runo::Set::Static.new(:id => '20100526_0001')
144
+ @f.load 'frank'
145
+
146
+ @f.update 'bobby'
147
+ assert_equal(
148
+ 'frank',
149
+ @f.val,
150
+ 'Meta::Id#post should not update the current val if the ancestor is not new'
151
+ )
152
+ end
153
+
154
+ def test_errors
155
+ @f.load '<a'
156
+ assert_equal(
157
+ ['malformatted id'],
158
+ @f.errors,
159
+ 'Meta::Id#errors should return the errors of the current val'
160
+ )
161
+
162
+ @f.load '123a'
163
+ assert_equal(
164
+ ['malformatted id'],
165
+ @f.errors,
166
+ 'Meta::Id#errors should return the errors of the current val'
167
+ )
168
+
169
+ @f.load 'abcdefghijk'
170
+ assert_equal(
171
+ ['too long: 5 characters maximum'],
172
+ @f.errors,
173
+ 'Meta::Id#errors should return the errors of the current val'
174
+ )
175
+
176
+ @f.load 'frank'
177
+ assert_equal(
178
+ [],
179
+ @f.errors,
180
+ 'Meta::Id#errors should return an empty array if there is no error'
181
+ )
182
+ end
183
+
184
+ def test_errors_duplicate_id
185
+ Runo.client = 'root'
186
+ sd = Runo::Set::Static::Folder.root.item('_users', 'main')
187
+
188
+ sd.update(
189
+ '_001' => {:action => :create, '_id' => 'test'}
190
+ )
191
+ assert_equal(
192
+ ['duplicate id: test'],
193
+ sd.item('_001', '_id').errors,
194
+ 'Meta::Id#errors should return an error if the current val is duplicated in the sd'
195
+ )
196
+
197
+ sd.update(
198
+ '_001' => {:action => :create, '_id' => 'frank'}
199
+ )
200
+ assert_equal(
201
+ [],
202
+ sd.item('_001', '_id').errors,
203
+ 'Meta::Id#errors should return no error if the current val is unique in the sd'
204
+ )
205
+
206
+ f = Runo::Set::Static::Folder.root.item('_users', 'main', 'test', '_id')
207
+ f.update 'test'
208
+ assert_equal(
209
+ [],
210
+ f.errors,
211
+ 'Meta::Id#errors should return no error if the current val is unchanged'
212
+ )
213
+ end
214
+
215
+ end
@@ -0,0 +1,328 @@
1
+ # encoding: UTF-8
2
+
3
+ # Author:: Akira FUNAI
4
+ # Copyright:: Copyright (c) 2009-2010 Akira FUNAI
5
+
6
+ require "#{::File.dirname __FILE__}/t"
7
+
8
+ class TC_Img < Test::Unit::TestCase
9
+
10
+ def setup
11
+ Runo.current[:uri] = nil
12
+
13
+ File.open('t/skin/t_img/test.jpg') {|f|
14
+ @img = f.read
15
+ @file = Tempfile.open('tc_img')
16
+ @file << @img
17
+ }
18
+
19
+ meta = nil
20
+ Runo::Parser.gsub_scalar('$(foo img 32*32 1..100000 jpg, gif, png crop)') {|id, m|
21
+ meta = m
22
+ ''
23
+ }
24
+ @f = Runo::Field.instance meta.merge(:id => 'foo')
25
+ end
26
+
27
+ def test_meta
28
+ assert_equal(
29
+ 1,
30
+ @f[:min],
31
+ 'Img#initialize should set :min from the range token'
32
+ )
33
+ assert_equal(
34
+ 100000,
35
+ @f[:max],
36
+ 'Img#initialize should set :max from the range token'
37
+ )
38
+ assert_equal(
39
+ ['jpg', 'gif', 'png'],
40
+ @f[:options],
41
+ 'Img#initialize should set :options from the csv token'
42
+ )
43
+ assert_equal(
44
+ true,
45
+ @f[:crop],
46
+ 'Img#initialize should set :options from the csv token'
47
+ )
48
+ end
49
+
50
+ def test_val_cast_from_rack
51
+ @f.create(
52
+ :type => 'image/jpeg',
53
+ :tempfile => @file,
54
+ :head => <<'_eos',
55
+ Content-Disposition: form-data; name="t_img"; filename="baz.jpg"
56
+ Content-Type: image/jpeg
57
+ _eos
58
+ :filename => 'baz.jpg',
59
+ :name => 't_img'
60
+ )
61
+
62
+ assert_equal(
63
+ {
64
+ 'basename' => 'baz.jpg',
65
+ 'type' => 'image/jpeg',
66
+ 'size' => @file.length,
67
+ },
68
+ @f.val,
69
+ 'Img#val_cast should re-map a hash from Rack'
70
+ )
71
+ assert_equal(
72
+ @img,
73
+ @f.body,
74
+ 'Img#val_cast should store the file body in @body'
75
+ )
76
+ assert_equal(
77
+ @f.send(:_thumbnail, @file),
78
+ @f.thumbnail,
79
+ 'Img#val_cast should store the thumbnail in @thumbnail'
80
+ )
81
+ end
82
+
83
+ def test_val_cast_load
84
+ @f.load(
85
+ 'basename' => 'baz.jpg',
86
+ 'type' => 'image/jpeg',
87
+ 'size' => 123
88
+ )
89
+ assert_equal(
90
+ {
91
+ 'basename' => 'baz.jpg',
92
+ 'type' => 'image/jpeg',
93
+ 'size' => 123,
94
+ },
95
+ @f.val,
96
+ 'Img#val_cast should load() a hash without :tempfile like Set#load'
97
+ )
98
+ end
99
+
100
+ def test_large_thumbnail
101
+ @f[:width] = @f[:height] = 640
102
+ @f.create(
103
+ :type => 'image/jpeg',
104
+ :tempfile => @file,
105
+ :head => <<'_eos',
106
+ Content-Disposition: form-data; name="t_img"; filename="baz.jpg"
107
+ Content-Type: image/jpeg
108
+ _eos
109
+ :filename => 'baz.jpg',
110
+ :name => 't_img'
111
+ )
112
+ assert_not_equal(
113
+ 0,
114
+ @f.instance_variable_get(:@thumbnail).to_s.size,
115
+ 'Img#_thumbnail should make a thumbnail larger than the original img'
116
+ )
117
+ end
118
+
119
+ def test_get
120
+ Runo.client = 'root'
121
+
122
+ @f[:parent] = Runo::Set::Static::Folder.root.item('t_img', 'main')
123
+ Runo.current[:base] = @f[:parent]
124
+ tid = @f[:parent][:tid]
125
+
126
+ @f.load({})
127
+ assert_equal(
128
+ <<'_html'.chomp,
129
+ <span class="dummy_img" style="width: 32px; height: 32px;"></span>
130
+ _html
131
+ @f.get,
132
+ 'Img#get should return default span when the val is empty'
133
+ )
134
+
135
+ @f.load(
136
+ 'basename' => 'baz.jpg',
137
+ 'type' => 'image/jpeg',
138
+ 'size' => 12
139
+ )
140
+ assert_equal(
141
+ <<'_html'.chomp,
142
+ <a href="/t_img/main/foo/baz.jpg"><img src="/t_img/main/foo/baz_small.jpg" alt="baz.jpg" /></a>
143
+ _html
144
+ @f.get,
145
+ 'Img#get should return proper string'
146
+ )
147
+ assert_equal(
148
+ <<"_html",
149
+ <span class="img">
150
+ <a href="/t_img/#{tid}/foo/baz.jpg"><img src="/t_img/#{tid}/foo/baz_small.jpg" alt="baz.jpg" /></a>
151
+ <input type="file" name="foo" size="" class="file" />
152
+ </span>
153
+ _html
154
+ @f.get(:action => :update),
155
+ 'Img#get should return proper string'
156
+ )
157
+
158
+ @f.load(
159
+ 'basename' => '<baz>.jpg',
160
+ 'type' => 'image/<jpeg>',
161
+ 'size' => 12
162
+ )
163
+ assert_equal(
164
+ <<'_html'.chomp,
165
+ <a href="/t_img/main/foo/&lt;baz&gt;.jpg"><img src="/t_img/main/foo/&lt;baz&gt;_small.jpg" alt="&lt;baz&gt;.jpg" /></a>
166
+ _html
167
+ @f.get,
168
+ 'Img#get should escape the special characters in file information'
169
+ )
170
+ end
171
+
172
+ def test_get_not_image
173
+ @f.create(
174
+ :type => 'text/plain',
175
+ :tempfile => @file,
176
+ :head => <<'_eos',
177
+ Content-Disposition: form-data; name="t_img"; filename="baz.txt"
178
+ Content-Type: text/plain
179
+ _eos
180
+ :filename => 'baz.txt',
181
+ :name => 't_img'
182
+ )
183
+ assert_equal(
184
+ '<a href="foo/baz.txt">baz.txt (3535 bytes)</a>',
185
+ @f.get,
186
+ 'Img#get should fall back to File#get if the file is not an image'
187
+ )
188
+ end
189
+
190
+ def test_call_body
191
+ Runo.client = 'root'
192
+ sd = Runo::Set::Static::Folder.root.item('t_img', 'main')
193
+ sd.storage.clear
194
+
195
+ # post a multipart request
196
+ input = <<"_eos".gsub(/\r?\n/, "\r\n").sub('@img', @img)
197
+ ---foobarbaz
198
+ Content-Disposition: form-data; name="_1-foo"; filename="foo.jpg"
199
+ Content-Type: image/jpeg
200
+ Content-Transfer-Encoding: binary
201
+
202
+ @img
203
+ ---foobarbaz
204
+ Content-Disposition: form-data; name="_token"
205
+
206
+ #{Runo.token}
207
+ ---foobarbaz--
208
+ _eos
209
+ res = Rack::MockRequest.new(Runo.new).post(
210
+ 'http://example.com/t_img/main/update.html',
211
+ {
212
+ :input => input,
213
+ 'CONTENT_TYPE' => 'multipart/form-data; boundary=-foobarbaz',
214
+ 'CONTENT_LENGTH' => input.length,
215
+ }
216
+ )
217
+ tid = res.headers['Location'][Runo::REX::TID]
218
+
219
+ # commit the base
220
+ res = Rack::MockRequest.new(Runo.new).post(
221
+ "http://example.com/#{tid}/update.html",
222
+ {
223
+ :input => ".status-public=create&_token=#{Runo.token}",
224
+ }
225
+ )
226
+
227
+ res.headers['Location'] =~ Runo::REX::PATH_ID
228
+ new_id = sprintf('%.8d_%.4d', $1, $2)
229
+
230
+ res = Rack::MockRequest.new(Runo.new).get(
231
+ "http://example.com/t_img/#{new_id}/foo/foo.jpg"
232
+ )
233
+ assert_equal(
234
+ 'image/jpeg',
235
+ res.headers['Content-Type'],
236
+ 'Runo#call to a img item should return the mime type of the file'
237
+ )
238
+ assert_equal(
239
+ @img.size,
240
+ res.body.size,
241
+ 'Runo#call to a img item should return the binary body of the file'
242
+ )
243
+
244
+ res = Rack::MockRequest.new(Runo.new).get(
245
+ "http://example.com/t_img/#{new_id}/foo/foo_small.jpg"
246
+ )
247
+ assert_equal(
248
+ 'image/jpeg',
249
+ res.headers['Content-Type'],
250
+ "Runo#call to 'file-small.*' should return the thumbnail of the file"
251
+ )
252
+ @file.rewind
253
+ assert_equal(
254
+ @f.send(:_thumbnail, @file).size,
255
+ res.body.size,
256
+ "Runo#call to 'file-small.*' should return the thumbnail of the file"
257
+ )
258
+
259
+ # delete
260
+ Rack::MockRequest.new(Runo.new).post(
261
+ 'http://example.com/t_img/update.html',
262
+ {
263
+ :input => "#{new_id}.action=delete&.status-public=delete&_token=#{Runo.token}",
264
+ }
265
+ )
266
+ res = Rack::MockRequest.new(Runo.new).get(
267
+ "http://example.com/t_img/#{new_id}/foo/foo.jpg"
268
+ )
269
+ assert_equal(
270
+ 404,
271
+ res.status,
272
+ 'Runo#call should delete child files as well'
273
+ )
274
+ res = Rack::MockRequest.new(Runo.new).get(
275
+ "http://example.com/t_img/#{new_id}/foo/foo_small.jpg"
276
+ )
277
+ assert_equal(
278
+ 404,
279
+ res.status,
280
+ 'Runo#call should delete child files as well'
281
+ )
282
+ end
283
+
284
+ def test_errors
285
+ File.open('t/skin/t_img/index.html') {|f|
286
+ @img = f.read
287
+ @file = Tempfile.open('tc_img')
288
+ @file << @img
289
+ }
290
+ @f.create(
291
+ :type => 'image/jpeg',
292
+ :tempfile => @file,
293
+ :head => <<'_eos',
294
+ Content-Disposition: form-data; name="t_img"; filename="baz.jpg"
295
+ Content-Type: image/jpeg
296
+ _eos
297
+ :filename => 'baz.jpg',
298
+ :name => 't_img'
299
+ )
300
+ assert_equal(
301
+ ['wrong file type: should be jpg/gif/png'],
302
+ @f.errors,
303
+ "Img#errors should regard quick_magick errors as 'wrong file type'"
304
+ )
305
+
306
+ File.open('t/skin/t_img/test.jpg') {|f|
307
+ @img = f.read
308
+ @file = Tempfile.open('tc_img')
309
+ @file << @img
310
+ }
311
+ @f.update(
312
+ :type => 'image/jpeg',
313
+ :tempfile => @file,
314
+ :head => <<'_eos',
315
+ Content-Disposition: form-data; name="t_img"; filename="baz.jpg"
316
+ Content-Type: image/jpeg
317
+ _eos
318
+ :filename => 'baz.jpg',
319
+ :name => 't_img'
320
+ )
321
+ assert_equal(
322
+ [],
323
+ @f.errors,
324
+ "Img#errors should raise no errors for good imgs"
325
+ )
326
+ end
327
+
328
+ end