leifcr-refile 0.6.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. checksums.yaml +7 -0
  2. data/app/assets/javascripts/refile.js +125 -0
  3. data/config/locales/en.yml +10 -0
  4. data/config/routes.rb +5 -0
  5. data/lib/refile.rb +510 -0
  6. data/lib/refile/app.rb +186 -0
  7. data/lib/refile/attacher.rb +190 -0
  8. data/lib/refile/attachment.rb +108 -0
  9. data/lib/refile/attachment/active_record.rb +133 -0
  10. data/lib/refile/attachment_definition.rb +83 -0
  11. data/lib/refile/backend/file_system.rb +120 -0
  12. data/lib/refile/backend/s3.rb +1 -0
  13. data/lib/refile/backend_macros.rb +45 -0
  14. data/lib/refile/custom_logger.rb +48 -0
  15. data/lib/refile/file.rb +102 -0
  16. data/lib/refile/file_double.rb +13 -0
  17. data/lib/refile/image_processing.rb +1 -0
  18. data/lib/refile/rails.rb +54 -0
  19. data/lib/refile/rails/attachment_helper.rb +121 -0
  20. data/lib/refile/random_hasher.rb +11 -0
  21. data/lib/refile/signature.rb +36 -0
  22. data/lib/refile/simple_form.rb +17 -0
  23. data/lib/refile/type.rb +28 -0
  24. data/lib/refile/version.rb +3 -0
  25. data/spec/refile/active_record_helper.rb +35 -0
  26. data/spec/refile/app_spec.rb +424 -0
  27. data/spec/refile/attachment/active_record_spec.rb +568 -0
  28. data/spec/refile/attachment_helper_spec.rb +78 -0
  29. data/spec/refile/attachment_spec.rb +589 -0
  30. data/spec/refile/backend/file_system_spec.rb +5 -0
  31. data/spec/refile/backend_examples.rb +228 -0
  32. data/spec/refile/backend_macros_spec.rb +83 -0
  33. data/spec/refile/custom_logger_spec.rb +21 -0
  34. data/spec/refile/features/direct_upload_spec.rb +63 -0
  35. data/spec/refile/features/multiple_upload_spec.rb +122 -0
  36. data/spec/refile/features/normal_upload_spec.rb +144 -0
  37. data/spec/refile/features/presigned_upload_spec.rb +31 -0
  38. data/spec/refile/features/simple_form_spec.rb +8 -0
  39. data/spec/refile/fixtures/hello.txt +1 -0
  40. data/spec/refile/fixtures/image.jpg +0 -0
  41. data/spec/refile/fixtures/large.txt +44 -0
  42. data/spec/refile/fixtures/monkey.txt +1 -0
  43. data/spec/refile/fixtures/world.txt +1 -0
  44. data/spec/refile/spec_helper.rb +72 -0
  45. data/spec/refile_spec.rb +355 -0
  46. metadata +143 -0
@@ -0,0 +1,78 @@
1
+ require "refile/rails/attachment_helper"
2
+ require "refile/active_record_helper"
3
+ require "refile/attachment/active_record"
4
+ require "action_view"
5
+
6
+ describe Refile::AttachmentHelper do
7
+ include Refile::AttachmentHelper
8
+ include ActionView::Helpers::AssetTagHelper
9
+ include ActionView::Helpers::FormHelper
10
+
11
+ let(:klass) do
12
+ Class.new(ActiveRecord::Base) do
13
+ self.table_name = :posts
14
+
15
+ def self.name
16
+ "Post"
17
+ end
18
+
19
+ attachment :document
20
+ end
21
+ end
22
+ let(:attachment_path) { "/attachments/00cc2633d08c6045485f1fae2cd6d4de20a5a159/store/xxx/document" }
23
+
24
+ before do
25
+ allow(Refile).to receive(:secret_key).and_return("xxxxxxxxxxx")
26
+ end
27
+
28
+ describe "#attachment_image_tag" do
29
+ let(:src) { attachment_image_tag(klass.new(document_id: "xxx"), :document)[/src="(\S+)"/, 1] }
30
+
31
+ it "builds with path" do
32
+ allow(Refile).to receive(:app_host).and_return(nil)
33
+ expect(src).to eq attachment_path
34
+ end
35
+
36
+ it "builds with host" do
37
+ expect(src).to eq "http://localhost:56120#{attachment_path}"
38
+ end
39
+ end
40
+
41
+ describe "#attachment_field" do
42
+ context "with index given" do
43
+ let(:html) { Capybara.string(attachment_field("post", :document, object: klass.new, index: 0)) }
44
+
45
+ it "generates file and hidden inputs with identical names" do
46
+ field_name = "post[0][document]"
47
+ expect(html).to have_field(field_name, type: "file")
48
+ expect(html).to have_selector(:css, "input[name='#{field_name}'][type=hidden]", visible: false, count: 1)
49
+ end
50
+ end
51
+ end
52
+
53
+ describe "#attachment_cache_field" do
54
+ context "with index given" do
55
+ let(:html) { Capybara.string(attachment_cache_field("post", :document, object: klass.new, index: 0)) }
56
+
57
+ it "generates hidden input with given index" do
58
+ expect(html).to have_selector(:css, "input[name='post[0][document]'][type=hidden]", visible: false)
59
+ end
60
+ end
61
+
62
+ context "with reference given" do
63
+ let(:html) { Capybara.string(attachment_cache_field("post", :document, object: klass.new, data: { reference: "xyz" })) }
64
+
65
+ it "generates hidden input with given reference" do
66
+ expect(html).to have_selector(:css, "input[data-reference=xyz]", visible: false)
67
+ end
68
+ end
69
+
70
+ context "without reference given" do
71
+ let(:html) { Capybara.string(attachment_cache_field("post", :document, object: klass.new)) }
72
+
73
+ it "generates hidden input with a random reference" do
74
+ expect(html).to have_selector(:css, "input[data-reference]", visible: false)
75
+ end
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,589 @@
1
+ describe Refile::Attachment do
2
+ let(:options) { {} }
3
+ let(:klass) do
4
+ opts = options
5
+ Class.new do
6
+ extend Refile::Attachment
7
+
8
+ attr_accessor :document_id, :document_filename, :document_size, :document_content_type
9
+
10
+ attachment :document, **opts
11
+ end
12
+ end
13
+ let(:instance) { klass.new }
14
+
15
+ describe ":name=" do
16
+ it "receives a file, caches it and sets the _id parameter" do
17
+ instance.document = Refile::FileDouble.new("hello", "foo.txt", content_type: "text/plain")
18
+
19
+ expect(instance.document.read).to eq("hello")
20
+
21
+ expect(instance.document_attacher.data[:filename]).to eq("foo.txt")
22
+ expect(instance.document_attacher.data[:size]).to eq(5)
23
+ expect(instance.document_attacher.data[:content_type]).to eq("text/plain")
24
+
25
+ expect(instance.document_filename).to eq("foo.txt")
26
+ expect(instance.document_size).to eq(5)
27
+ expect(instance.document_content_type).to eq("text/plain")
28
+ end
29
+
30
+ it "receives serialized data and retrieves file from it" do
31
+ file = Refile.cache.upload(Refile::FileDouble.new("hello"))
32
+ instance.document = { id: file.id, filename: "foo.txt", content_type: "text/plain", size: 5 }.to_json
33
+
34
+ expect(instance.document.read).to eq("hello")
35
+
36
+ expect(instance.document_attacher.data[:filename]).to eq("foo.txt")
37
+ expect(instance.document_attacher.data[:size]).to eq(5)
38
+ expect(instance.document_attacher.data[:content_type]).to eq("text/plain")
39
+
40
+ expect(instance.document_filename).to eq("foo.txt")
41
+ expect(instance.document_size).to eq(5)
42
+ expect(instance.document_content_type).to eq("text/plain")
43
+ end
44
+
45
+ it "receives parsed data and retrieves file from it" do
46
+ file = Refile.cache.upload(Refile::FileDouble.new("hello"))
47
+ instance.document = { id: file.id, filename: "foo.txt", content_type: "text/plain", size: 5 }
48
+
49
+ expect(instance.document.read).to eq("hello")
50
+
51
+ expect(instance.document_attacher.data[:filename]).to eq("foo.txt")
52
+ expect(instance.document_attacher.data[:size]).to eq(5)
53
+ expect(instance.document_attacher.data[:content_type]).to eq("text/plain")
54
+
55
+ expect(instance.document_filename).to eq("foo.txt")
56
+ expect(instance.document_size).to eq(5)
57
+ expect(instance.document_content_type).to eq("text/plain")
58
+ end
59
+
60
+ it "does nothing when assigned string lacks an id" do
61
+ instance.document = { size: 5 }.to_json
62
+
63
+ expect(instance.document).to be_nil
64
+ expect(instance.document_size).to be_nil
65
+ end
66
+
67
+ it "does nothing when assigned string is not valid JSON" do
68
+ instance.document = "size:f{oo}"
69
+
70
+ expect(instance.document).to be_nil
71
+ expect(instance.document_size).to be_nil
72
+ end
73
+
74
+ it "accepts nil" do
75
+ instance.document = nil
76
+ expect(instance.document).to be_nil
77
+ end
78
+
79
+ it "removes a document when assigned nil" do
80
+ instance.document = Refile::FileDouble.new("hello", "foo.txt", content_type: "text/plain")
81
+ instance.document = nil
82
+ expect(instance.document).to be_nil
83
+ end
84
+ end
85
+
86
+ describe ":name" do
87
+ it "gets a file from the store" do
88
+ file = Refile.store.upload(Refile::FileDouble.new("hello"))
89
+ instance.document_id = file.id
90
+
91
+ expect(instance.document.id).to eq(file.id)
92
+ end
93
+
94
+ it "complains when `id` attribute not readable" do
95
+ klass.class_eval do
96
+ undef :document_id
97
+ end
98
+
99
+ expect do
100
+ instance.document
101
+ end.to raise_error(NoMethodError)
102
+ end
103
+ end
104
+
105
+ describe ":url" do
106
+ it "generates URL with extra options" do
107
+ allow(Refile).to receive(:token).and_return("token")
108
+
109
+ file = Refile.store.upload(Refile::FileDouble.new("hello"))
110
+ instance.document_id = file.id
111
+
112
+ expect(instance.document_url("fill", 800, 800)).to eq("http://localhost:56120/attachments/token/store/fill/800/800/#{file.id}/document")
113
+ end
114
+ end
115
+
116
+ describe "presigned_:name_url=" do
117
+ it "generates presigned URL" do
118
+ file = Refile.store.upload(Refile::FileDouble.new("hello"))
119
+ instance.document_id = file.id
120
+
121
+ allow(Refile.store).to receive_message_chain(:object, :presigned_url).with(file.id).with(:get, expires_in: 900).and_return("PRESIGNED_URL")
122
+ expect(instance.presigned_document_url).to eq("PRESIGNED_URL")
123
+ end
124
+
125
+ it "generates presigned URL with custom expiration" do
126
+ file = Refile.store.upload(Refile::FileDouble.new("hello"))
127
+ instance.document_id = file.id
128
+
129
+ allow(Refile.store).to receive_message_chain(:object, :presigned_url).with(file.id).with(:get, expires_in: 901).and_return("PRESIGNED_URL")
130
+ expect(instance.presigned_document_url(901)).to eq("PRESIGNED_URL")
131
+ end
132
+
133
+ it "does nothing when id is nill" do
134
+ expect(instance.presigned_document_url).to be_nil
135
+ end
136
+ end
137
+
138
+ describe "remote_:name_url=" do
139
+ it "does nothing when nil is assigned" do
140
+ instance.remote_document_url = nil
141
+ expect(instance.document).to be_nil
142
+ end
143
+
144
+ it "does nothing when empty string is assigned" do
145
+ instance.remote_document_url = nil
146
+ expect(instance.document).to be_nil
147
+ end
148
+
149
+ context "without redirects" do
150
+ before(:each) do
151
+ stub_request(:get, "http://www.example.com/some_file.txt").to_return(
152
+ status: 200,
153
+ body: "abc",
154
+ headers: { "Content-Length" => 3, "Content-Type" => "text/plain" }
155
+ )
156
+ end
157
+
158
+ it "downloads file, caches it and sets the _id parameter and metadata" do
159
+ instance.remote_document_url = "http://www.example.com/some_file.txt"
160
+ expect(instance.document.read).to eq("abc")
161
+
162
+ expect(instance.document_attacher.data[:filename]).to eq("some_file.txt")
163
+ expect(instance.document_attacher.data[:size]).to eq(3)
164
+ expect(instance.document_attacher.data[:content_type]).to eq("text/plain")
165
+
166
+ expect(instance.document_filename).to eq("some_file.txt")
167
+ expect(instance.document_size).to eq(3)
168
+ expect(instance.document_content_type).to eq("text/plain")
169
+
170
+ expect(Refile.cache.get(instance.document.id).read).to eq("abc")
171
+ end
172
+ end
173
+
174
+ context "with redirects" do
175
+ before(:each) do
176
+ stub_request(:get, "http://www.example.com/1").to_return(status: 302, headers: { "Location" => "http://www.example.com/2" })
177
+ stub_request(:get, "http://www.example.com/2").to_return(status: 200, body: "woop", headers: { "Content-Length" => 4 })
178
+ stub_request(:get, "http://www.example.com/loop").to_return(status: 302, headers: { "Location" => "http://www.example.com/loop" })
179
+ end
180
+
181
+ it "follows redirects and fetches the file, caches it and sets the _id parameter" do
182
+ instance.remote_document_url = "http://www.example.com/1"
183
+ expect(instance.document.read).to eq("woop")
184
+ expect(Refile.cache.get(instance.document.id).read).to eq("woop")
185
+ end
186
+
187
+ context "when errors enabled" do
188
+ let(:options) { { raise_errors: true } }
189
+ it "handles redirect loops by trowing errors" do
190
+ expect do
191
+ instance.remote_document_url = "http://www.example.com/loop"
192
+ end.to raise_error(RestClient::Exception)
193
+ end
194
+ end
195
+
196
+ context "when errors disabled" do
197
+ let(:options) { { raise_errors: false } }
198
+ it "handles redirect loops by setting generic download error" do
199
+ expect do
200
+ instance.remote_document_url = "http://www.example.com/loop"
201
+ end.not_to raise_error
202
+ expect(instance.document_attacher.errors).to eq([:download_failed])
203
+ expect(instance.document).to be_nil
204
+ end
205
+ end
206
+ end
207
+ end
208
+
209
+ describe ":name_attacher.store!" do
210
+ it "puts a cached file into the store" do
211
+ instance.document = Refile::FileDouble.new("hello")
212
+ cache = instance.document
213
+
214
+ instance.document_attacher.store!
215
+
216
+ expect(Refile.store.get(instance.document_id).read).to eq("hello")
217
+ expect(Refile.store.get(instance.document.id).read).to eq("hello")
218
+
219
+ expect(instance.document.read).to eq("hello")
220
+ expect(instance.document_size).to eq(5)
221
+ expect(Refile.cache.get(cache.id).exists?).to be_falsy
222
+ end
223
+
224
+ it "complains when `id` attribute not writable" do
225
+ instance.document = Refile::FileDouble.new("hello")
226
+
227
+ klass.class_eval do
228
+ undef :document_id=
229
+ end
230
+
231
+ expect do
232
+ instance.document_attacher.store!
233
+ end.to raise_error(NoMethodError)
234
+ end
235
+
236
+ it "does nothing when not cached" do
237
+ file = Refile.store.upload(Refile::FileDouble.new("hello"))
238
+ instance.document_id = file.id
239
+
240
+ instance.document_attacher.store!
241
+
242
+ expect(Refile.store.get(instance.document_id).read).to eq("hello")
243
+ expect(Refile.store.get(instance.document.id).read).to eq("hello")
244
+ end
245
+
246
+ it "overwrites previously stored file" do
247
+ file = Refile.store.upload(Refile::FileDouble.new("hello"))
248
+ instance.document_id = file.id
249
+
250
+ instance.document = Refile::FileDouble.new("world")
251
+ cache = instance.document
252
+
253
+ instance.document_attacher.store!
254
+
255
+ expect(Refile.store.get(instance.document_id).read).to eq("world")
256
+ expect(Refile.store.get(instance.document.id).read).to eq("world")
257
+
258
+ expect(instance.document.read).to eq("world")
259
+ expect(Refile.cache.get(cache.id).exists?).to be_falsy
260
+ expect(Refile.store.get(file.id).exists?).to be_falsy
261
+ end
262
+
263
+ it "removes an uploaded file when remove? returns true" do
264
+ file = Refile.store.upload(Refile::FileDouble.new("hello"))
265
+ instance.document_id = file.id
266
+
267
+ instance.document_attacher.remove = true
268
+ instance.document_attacher.store!
269
+
270
+ expect(instance.document_id).to be_nil
271
+ expect(Refile.store.exists?(file.id)).to be_falsy
272
+ end
273
+
274
+ it "removes metadata when remove? returns true" do
275
+ file = Refile.store.upload(Refile::FileDouble.new("hello"))
276
+ instance.document_id = file.id
277
+ instance.document_size = file.size
278
+ instance.document_filename = "foo"
279
+ instance.document_content_type = "bar"
280
+
281
+ instance.document_attacher.remove = true
282
+ instance.document_attacher.store!
283
+
284
+ expect(instance.document_id).to be_nil
285
+ expect(instance.document_size).to be_nil
286
+ expect(instance.document_filename).to be_nil
287
+ expect(instance.document_content_type).to be_nil
288
+ end
289
+ end
290
+
291
+ describe ":name_attacher.delete!" do
292
+ it "deletes a stored file" do
293
+ instance.document = Refile::FileDouble.new("hello")
294
+ instance.document_attacher.store!
295
+ file = instance.document
296
+
297
+ instance.document_attacher.delete!
298
+
299
+ expect(Refile.store.exists?(file.id)).to be_falsy
300
+ end
301
+
302
+ it "deletes a cached file" do
303
+ instance.document = Refile::FileDouble.new("hello")
304
+ file = instance.document
305
+
306
+ instance.document_attacher.delete!
307
+
308
+ expect(Refile.cache.exists?(file.id)).to be_falsy
309
+ end
310
+ end
311
+
312
+ describe ":name_attacher.remove?" do
313
+ it "should be true when the value is truthy" do
314
+ instance.document_attacher.remove = true
315
+ expect(instance.document_attacher.remove?).to be_truthy
316
+ end
317
+
318
+ it "should be false when the value is falsey" do
319
+ instance.document_attacher.remove = false
320
+ expect(instance.document_attacher.remove?).to be_falsy
321
+ end
322
+
323
+ it "should be false when the value is ''" do
324
+ instance.document_attacher.remove = ""
325
+ expect(instance.document_attacher.remove?).to be_falsy
326
+ end
327
+
328
+ it "should be false when the value is '0'" do
329
+ instance.document_attacher.remove = "0"
330
+ expect(instance.document_attacher.remove?).to be_falsy
331
+ end
332
+
333
+ it "should be false when the value is 'false'" do
334
+ instance.document_attacher.remove = "false"
335
+ expect(instance.document_attacher.remove?).to be_falsy
336
+ end
337
+ end
338
+
339
+ describe ":name_attacher.valid?" do
340
+ let(:options) { { type: :image, raise_errors: false } }
341
+
342
+ it "returns false if no file is attached" do
343
+ expect(instance.document_attacher.valid?).to be_falsy
344
+ end
345
+
346
+ it "returns true if valid file is attached" do
347
+ file = Refile::FileDouble.new("hello", content_type: "image/png")
348
+
349
+ instance.document = file
350
+
351
+ expect(instance.document_attacher.valid?).to be_truthy
352
+ end
353
+
354
+ it "returns false and sets errors if invalid file is attached" do
355
+ file = Refile::FileDouble.new("hello", content_type: "text/plain")
356
+
357
+ instance.document = file
358
+
359
+ expect(instance.document_attacher.valid?).to be_falsy
360
+ expect(instance.document_attacher.errors).to match_array [[:invalid_content_type, anything]]
361
+ end
362
+
363
+ it "returns false and sets errors if file with zero byte is uploaded" do
364
+ file = Refile::FileDouble.new("", "hello", content_type: "image/png")
365
+ instance.document = file
366
+
367
+ expect(instance.document_attacher.valid?).to be_falsy
368
+ expect(instance.document_attacher.errors).to eq([:zero_byte_detected])
369
+ end
370
+ end
371
+
372
+ describe ":name_attacher.extension" do
373
+ it "is nil when not inferrable" do
374
+ file = Refile::FileDouble.new("hello")
375
+ instance.document = file
376
+ expect(instance.document_attacher.extension).to be_nil
377
+ end
378
+
379
+ it "is inferred from the filename" do
380
+ file = Refile::FileDouble.new("hello", "hello.txt")
381
+ instance.document = file
382
+ expect(instance.document_attacher.extension).to eq("txt")
383
+ end
384
+
385
+ it "is inferred from the content type" do
386
+ file = Refile::FileDouble.new("hello", content_type: "image/png")
387
+ instance.document = file
388
+ expect(instance.document_attacher.extension).to eq("png")
389
+ end
390
+
391
+ it "returns nil with unknown content type" do
392
+ file = Refile::FileDouble.new("hello", content_type: "foo/doesnotexist")
393
+ instance.document = file
394
+ expect(instance.document_attacher.extension).to be_nil
395
+ end
396
+
397
+ it "is nil when filename has no extension" do
398
+ file = Refile::FileDouble.new("hello", "hello")
399
+ instance.document = file
400
+ expect(instance.document_attacher.extension).to be_nil
401
+ end
402
+ end
403
+
404
+ describe ":name_attacher.basename" do
405
+ it "is nil when not inferrable" do
406
+ file = Refile::FileDouble.new("hello")
407
+ instance.document = file
408
+ expect(instance.document_attacher.basename).to be_nil
409
+ end
410
+
411
+ it "is inferred from the filename" do
412
+ file = Refile::FileDouble.new("hello", "hello.txt")
413
+ instance.document = file
414
+ expect(instance.document_attacher.basename).to eq("hello")
415
+ end
416
+
417
+ it "returns filename if filename has no extension" do
418
+ file = Refile::FileDouble.new("hello", "hello")
419
+ instance.document = file
420
+ expect(instance.document_attacher.basename).to eq("hello")
421
+ end
422
+ end
423
+
424
+ describe ":name_attacher.error" do
425
+ let(:options) { { cache: :limited_cache, raise_errors: false } }
426
+
427
+ it "is blank when valid file uploaded" do
428
+ file = Refile::FileDouble.new("hello")
429
+ instance.document = file
430
+
431
+ expect(instance.document_attacher.errors).to be_empty
432
+ expect(Refile.cache.get(instance.document.id).exists?).to be_truthy
433
+ end
434
+
435
+ it "contains a list of errors when invalid file uploaded" do
436
+ file = Refile::FileDouble.new("a" * 120)
437
+ instance.document = file
438
+
439
+ expect(instance.document_attacher.errors).to eq([:too_large])
440
+ expect(instance.document).to be_nil
441
+ end
442
+
443
+ it "is reset when valid file uploaded" do
444
+ file = Refile::FileDouble.new("a" * 120)
445
+ instance.document = file
446
+
447
+ file = Refile::FileDouble.new("hello")
448
+ instance.document = file
449
+
450
+ expect(instance.document_attacher.errors).to be_empty
451
+ expect(Refile.cache.get(instance.document.id).exists?).to be_truthy
452
+ end
453
+ end
454
+
455
+ describe ":name_definition.accept" do
456
+ context "with `extension`" do
457
+ let(:options) { { extension: %w[jpg png] } }
458
+
459
+ it "returns an accept string" do
460
+ expect(instance.document_attachment_definition.accept).to eq(".jpg,.png")
461
+ end
462
+ end
463
+
464
+ context "with `content_type`" do
465
+ let(:options) { { content_type: %w[image/jpeg image/png], extension: "zip" } }
466
+
467
+ it "returns an accept string" do
468
+ expect(instance.document_attachment_definition.accept).to eq("image/jpeg,image/png")
469
+ end
470
+ end
471
+ end
472
+
473
+ describe "with option `raise_errors: true" do
474
+ let(:options) { { cache: :limited_cache, raise_errors: true } }
475
+
476
+ it "raises an error when invalid file assigned" do
477
+ file = Refile::FileDouble.new("a" * 120)
478
+ expect do
479
+ instance.document = file
480
+ end.to raise_error(Refile::Invalid)
481
+
482
+ expect(instance.document_attacher.errors).to eq([:too_large])
483
+ expect(instance.document).to be_nil
484
+ end
485
+ end
486
+
487
+ describe "with option `raise_errors: false" do
488
+ let(:options) { { cache: :limited_cache, raise_errors: false } }
489
+
490
+ it "does not raise an error when invalid file assigned" do
491
+ file = Refile::FileDouble.new("a" * 120)
492
+ instance.document = file
493
+
494
+ expect(instance.document_attacher.errors).to eq([:too_large])
495
+ expect(instance.document).to be_nil
496
+ end
497
+ end
498
+
499
+ describe "with option `extension`: %w[txt]`" do
500
+ let(:options) { { extension: "txt", raise_errors: false } }
501
+
502
+ it "allows file with correct extension to be uploaded" do
503
+ file = Refile::FileDouble.new("hello", "hello.txt")
504
+ instance.document = file
505
+
506
+ expect(instance.document_attacher.errors).to be_empty
507
+ expect(Refile.cache.get(instance.document.id).exists?).to be_truthy
508
+ end
509
+
510
+ it "sets error when file with other extension is uploaded" do
511
+ file = Refile::FileDouble.new("hello", "hello.php")
512
+ instance.document = file
513
+
514
+ expect(instance.document_attacher.errors).to match_array [[:invalid_extension, anything]]
515
+ expect(instance.document).to be_nil
516
+ end
517
+
518
+ it "sets error when file with no extension is uploaded" do
519
+ file = Refile::FileDouble.new("hello")
520
+ instance.document = file
521
+
522
+ expect(instance.document_attacher.errors).to match_array [[:invalid_extension, anything]]
523
+ expect(instance.document).to be_nil
524
+ end
525
+ end
526
+
527
+ describe "with option `content_type: %w[txt]`" do
528
+ let(:options) { { content_type: "text/plain", raise_errors: false } }
529
+
530
+ it "allows file with correct content type to be uploaded" do
531
+ file = Refile::FileDouble.new("hello", content_type: "text/plain")
532
+ instance.document = file
533
+
534
+ expect(instance.document_attacher.errors).to be_empty
535
+ expect(Refile.cache.get(instance.document.id).exists?).to be_truthy
536
+ end
537
+
538
+ it "sets error when file with other content type is uploaded" do
539
+ file = Refile::FileDouble.new("hello", content_type: "application/php")
540
+ instance.document = file
541
+
542
+ expect(instance.document_attacher.errors).to match_array [[:invalid_content_type, anything]]
543
+ expect(instance.document).to be_nil
544
+ end
545
+
546
+ it "sets error when file with no content type is uploaded" do
547
+ file = Refile::FileDouble.new("hello")
548
+ instance.document = file
549
+
550
+ expect(instance.document_attacher.errors).to match_array [[:invalid_content_type, anything]]
551
+ expect(instance.document).to be_nil
552
+ end
553
+ end
554
+
555
+ describe "with option `type: :image`" do
556
+ let(:options) { { type: :image, raise_errors: false } }
557
+
558
+ it "allows image to be uploaded" do
559
+ file = Refile::FileDouble.new("hello", content_type: "image/jpeg")
560
+ instance.document = file
561
+
562
+ expect(instance.document_attacher.errors).to be_empty
563
+ expect(Refile.cache.get(instance.document.id).exists?).to be_truthy
564
+ end
565
+
566
+ it "sets error when file with other content type is uploaded" do
567
+ file = Refile::FileDouble.new("hello", content_type: "application/php")
568
+ instance.document = file
569
+
570
+ expect(instance.document_attacher.errors).to match_array [[:invalid_content_type, anything]]
571
+ expect(instance.document).to be_nil
572
+ end
573
+
574
+ it "sets error when file with no content type is uploaded" do
575
+ file = Refile::FileDouble.new("hello")
576
+ instance.document = file
577
+
578
+ expect(instance.document_attacher.errors).to match_array [[:invalid_content_type, anything]]
579
+ expect(instance.document).to be_nil
580
+ end
581
+ end
582
+
583
+ it "includes the module with methods in an instrospectable way" do
584
+ expect { puts klass.ancestors }
585
+ .to output(/Refile::Attachment\(document\)/).to_stdout
586
+ expect { p klass.ancestors }
587
+ .to output(/Refile::Attachment\(document\)/).to_stdout
588
+ end
589
+ end