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,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