uploadcolumn 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,514 @@
1
+ require File.join(File.dirname(__FILE__), 'spec_helper')
2
+
3
+ gem 'activerecord'
4
+ require 'active_record'
5
+
6
+ require File.join(File.dirname(__FILE__), '../lib/upload_column')
7
+
8
+ class Entry < ActiveRecord::Base; end # setup a basic AR class for testing
9
+
10
+ describe "an ActiveRecord class" do
11
+
12
+ include UploadColumnSpecHelper
13
+
14
+ it "should respond to upload_column" do
15
+ Entry.should respond_to(:upload_column)
16
+ end
17
+
18
+ it "should reflect on upload_columns" do
19
+ Entry.send(:reset_upload_columns)
20
+
21
+ Entry.upload_column(:avatar)
22
+
23
+ Entry.reflect_on_upload_columns[:avatar].should be_an_instance_of(UploadColumn::Column)
24
+ Entry.reflect_on_upload_columns[:monkey].should == nil
25
+
26
+ Entry.upload_column(:monkey)
27
+
28
+ Entry.reflect_on_upload_columns[:avatar].should be_an_instance_of(UploadColumn::Column)
29
+ Entry.reflect_on_upload_columns[:monkey].should be_an_instance_of(UploadColumn::Column)
30
+ end
31
+
32
+ it "should reset upload columns" do
33
+ Entry.upload_column(:avatar)
34
+
35
+ Entry.reflect_on_upload_columns[:avatar].should be_an_instance_of(UploadColumn::Column)
36
+
37
+ Entry.send(:reset_upload_columns)
38
+
39
+ Entry.reflect_on_upload_columns[:avatar].should == nil
40
+ end
41
+
42
+ end
43
+
44
+ describe "an Active Record class with an upload_column" do
45
+
46
+ include UploadColumnSpecHelper
47
+
48
+ it "should add accessor methods" do
49
+ # use a name that hasn't been used before!
50
+ entry = disconnected_model(Entry)
51
+ entry.should_not respond_to(:llama)
52
+ entry.should_not respond_to(:llama_temp)
53
+ entry.should_not respond_to(:llama=)
54
+ entry.should_not respond_to(:llama_temp=)
55
+
56
+ Entry.upload_column(:llama)
57
+
58
+ entry = disconnected_model(Entry)
59
+
60
+ entry.should respond_to(:llama)
61
+ entry.should respond_to(:llama_temp)
62
+ entry.should respond_to(:llama=)
63
+ entry.should respond_to(:llama_temp=)
64
+ end
65
+
66
+ it "should save the name of the column to be reflected upon" do
67
+ Entry.upload_column(:walruss)
68
+ Entry.reflect_on_upload_columns[:walruss].name.should == :walruss
69
+ end
70
+
71
+ it "should save the options to be reflected upon" do
72
+ options = { :donkey => true }
73
+
74
+ Entry.upload_column(:walruss, options)
75
+
76
+ Entry.reflect_on_upload_columns[:walruss].options.should == options
77
+ end
78
+ end
79
+
80
+ describe "an Active Record with no upload_column" do
81
+
82
+ before(:all) do
83
+ class Monkey < ActiveRecord::Base; end
84
+ end
85
+
86
+ it "should have no uploads_column" do
87
+ Monkey.reflect_on_upload_columns.should == {}
88
+ end
89
+
90
+ it "should be instantiable" do
91
+ Monkey.stub!(:columns).and_return([])
92
+ Monkey.new
93
+ end
94
+
95
+ end
96
+
97
+ describe "uploading a file" do
98
+
99
+ include UploadColumnSpecHelper
100
+
101
+ before do
102
+ setup_standard_mocking
103
+ UploadColumn::UploadedFile.should_receive(:upload).with(@file, @entry, :avatar, @options).and_return(@uploaded_file)
104
+ end
105
+
106
+ it "should pass it to UploadedFile and remember it" do
107
+ @entry.avatar.should == nil
108
+ @entry.avatar = @file
109
+ @entry.avatar.should == @uploaded_file
110
+ end
111
+
112
+ it "should set the attribute on the ActiveRecord" do
113
+ @entry.should_receive(:[]=).with(:avatar, 'monkey.png')
114
+ @entry.avatar = @file
115
+ end
116
+
117
+ end
118
+
119
+ describe "uploading an empty String" do
120
+
121
+ include UploadColumnSpecHelper
122
+
123
+ before do
124
+ setup_standard_mocking
125
+ end
126
+
127
+ it "should do nothing" do
128
+ UploadColumn::UploadedFile.should_receive(:upload).with("", @entry, :avatar, @options).and_return(nil)
129
+ @entry.avatar.should == nil
130
+ @entry.avatar = ""
131
+ @entry.avatar.should == nil
132
+ end
133
+
134
+ it "shouldn't affect an already uploaded file" do
135
+ UploadColumn::UploadedFile.should_receive(:upload).with(@file, @entry, :avatar, @options).and_return(@uploaded_file)
136
+ @entry.avatar = @file
137
+ @entry.avatar.should == @uploaded_file
138
+
139
+ UploadColumn::UploadedFile.should_receive(:upload).with("", @entry, :avatar, @options).and_return(nil)
140
+ @entry.avatar = ""
141
+ @entry.avatar.should == @uploaded_file
142
+ end
143
+
144
+ end
145
+
146
+ describe "setting nil explicitly" do
147
+
148
+ include UploadColumnSpecHelper
149
+
150
+ before do
151
+ setup_standard_mocking
152
+ end
153
+
154
+ it "should reset the column" do
155
+ UploadColumn::UploadedFile.should_receive(:upload).with(@file, @entry, :avatar, @options).and_return(@uploaded_file)
156
+ @entry.avatar = @file
157
+ @entry.avatar.should == @uploaded_file
158
+
159
+ @entry.avatar = nil
160
+ @entry.avatar.should == nil
161
+ end
162
+ end
163
+
164
+ describe "an upload_column with a value stored in the database and no uploaded_file" do
165
+
166
+ include UploadColumnSpecHelper
167
+
168
+ before do
169
+ @options = mock('options', :null_object => true)
170
+ Entry.upload_column(:avatar, @options)
171
+
172
+ @entry = disconnected_model(Entry)
173
+ @entry.stub!(:inspect).and_return('<#Entry>')
174
+ @string = mock('some string')
175
+ @entry.should_receive(:[]).with(:avatar).at_least(:once).and_return(@string)
176
+ end
177
+
178
+ it "should retrieve the file from the database" do
179
+ uploaded_file = mock('uploaded file')
180
+
181
+ UploadColumn::UploadedFile.should_receive(:retrieve).with(@string, @entry, :avatar, @options).and_return(uploaded_file)
182
+
183
+ @entry.avatar.should == uploaded_file
184
+ end
185
+ end
186
+
187
+ describe "saving uploaded files" do
188
+
189
+ include UploadColumnSpecHelper
190
+
191
+ before do
192
+ setup_standard_mocking
193
+ end
194
+
195
+ it "should call save on the uploaded file if they are temporary files" do
196
+ UploadColumn::UploadedFile.should_receive(:upload).with(@file, @entry, :avatar, @options).and_return(@uploaded_file)
197
+
198
+ @uploaded_file.should_receive(:tempfile?).and_return(true)
199
+ @uploaded_file.should_receive(:save)
200
+ @entry.avatar = @file
201
+
202
+ @entry.send(:save_uploaded_files)
203
+ end
204
+
205
+ it "should not call save on the uploaded file if they are not temporary files" do
206
+ UploadColumn::UploadedFile.should_receive(:upload).with(@file, @entry, :avatar, @options).and_return(@uploaded_file)
207
+
208
+ @uploaded_file.should_receive(:tempfile?).and_return(false)
209
+ @uploaded_file.should_not_receive(:save)
210
+ @entry.avatar = @file
211
+
212
+ @entry.send(:save_uploaded_files)
213
+ end
214
+
215
+ it "should happen automatically" do
216
+ # TODO: hmmm, how to test this? do we have to rely on an integration test?
217
+ #@entry.should_receive(:save_uploaded_files)
218
+ #@entry.save
219
+ end
220
+
221
+ end
222
+
223
+ describe "fetching a temp value" do
224
+
225
+ include UploadColumnSpecHelper
226
+
227
+ setup do
228
+ setup_standard_mocking
229
+
230
+ UploadColumn::UploadedFile.should_receive(:upload).with(@file, @entry, :avatar, @options).and_return(@uploaded_file)
231
+
232
+ @temp_value = '12345.1234.12345/somewhere.png'
233
+
234
+ @uploaded_file.should_receive(:temp_value).and_return(@temp_value)
235
+ @entry.avatar = @file
236
+ end
237
+
238
+ it "should fetch the value from the uploaded file" do
239
+ @entry.avatar_temp.should == @temp_value
240
+ end
241
+
242
+ end
243
+
244
+ describe "assigning a tempfile" do
245
+
246
+ include UploadColumnSpecHelper
247
+
248
+ setup do
249
+ setup_standard_mocking
250
+ end
251
+
252
+ it "should not override a new file" do
253
+ UploadColumn::UploadedFile.should_receive(:upload).with(@file, @entry, :avatar, @options).and_return(@uploaded_file)
254
+ @uploaded_file.stub!(:new_file?).and_return(true)
255
+ @entry.avatar = @file
256
+
257
+ temp_value = '12345.1234.12345/somewhere.png'
258
+
259
+ UploadColumn::UploadedFile.should_not_receive(:retrieve_temp)
260
+ @entry.avatar_temp = temp_value
261
+
262
+ @entry.avatar.should == @uploaded_file
263
+ end
264
+
265
+ it "should override a file that is not new" do
266
+ UploadColumn::UploadedFile.should_receive(:upload).with(@file, @entry, :avatar, @options).and_return(@uploaded_file)
267
+ @uploaded_file.stub!(:new_file?).and_return(false)
268
+ @entry.avatar = @file
269
+
270
+ temp_value = '12345.1234.12345/somewhere.png'
271
+
272
+ retrieved_file = mock('a retrieved file')
273
+ retrieved_file.should_receive(:actual_filename).and_return('walruss.png')
274
+ UploadColumn::UploadedFile.should_receive(:retrieve_temp).with(temp_value, @entry, :avatar, @options).and_return(retrieved_file)
275
+ @entry.should_receive(:[]=).with(:avatar, 'walruss.png')
276
+
277
+ @entry.avatar_temp = temp_value
278
+
279
+ @entry.avatar.should == retrieved_file
280
+ end
281
+
282
+ it "should set the file if there is none" do
283
+
284
+ temp_value = '12345.1234.12345/somewhere.png'
285
+
286
+ retrieved_file = mock('a retrieved file')
287
+ retrieved_file.should_receive(:actual_filename).and_return('walruss.png')
288
+ UploadColumn::UploadedFile.should_receive(:retrieve_temp).with(temp_value, @entry, :avatar, @options).and_return(retrieved_file)
289
+ @entry.should_receive(:[]=).with(:avatar, 'walruss.png')
290
+
291
+ @entry.avatar_temp = temp_value
292
+
293
+ @entry.avatar.should == retrieved_file
294
+ end
295
+
296
+ end
297
+
298
+ describe "assigning nil to temp" do
299
+
300
+ include UploadColumnSpecHelper
301
+
302
+ before(:each) do
303
+ setup_standard_mocking
304
+ end
305
+
306
+ it "should do nothing" do
307
+ UploadColumn::UploadedFile.stub!(:upload).and_return(@uploaded_file)
308
+ @uploaded_file.stub!(:new_file?).and_return(false)
309
+ @entry.avatar = @file
310
+
311
+ UploadColumn::UploadedFile.should_not_receive(:retrieve_temp)
312
+ @entry.should_not_receive(:[]=)
313
+
314
+ lambda {
315
+ @entry.avatar_temp = nil
316
+ }.should_not change(@entry, :avatar)
317
+ end
318
+ end
319
+
320
+ describe "assigning a blank string to temp" do
321
+
322
+ include UploadColumnSpecHelper
323
+
324
+ before(:each) do
325
+ setup_standard_mocking
326
+ end
327
+
328
+ it "should do nothing" do
329
+ UploadColumn::UploadedFile.should_receive(:upload).with(@file, @entry, :avatar, @options).and_return(@uploaded_file)
330
+ @uploaded_file.stub!(:new_file?).and_return(false)
331
+ @entry.avatar = @file
332
+
333
+ UploadColumn::UploadedFile.should_not_receive(:retrieve_temp)
334
+ @entry.should_not_receive(:[]=)
335
+
336
+ lambda {
337
+ @entry.avatar_temp = ""
338
+ }.should_not change(@entry, :avatar)
339
+ end
340
+ end
341
+
342
+ describe "an upload column with no file" do
343
+
344
+ include UploadColumnSpecHelper
345
+
346
+ before(:each) do
347
+ setup_standard_mocking
348
+ end
349
+
350
+ it "should return no value" do
351
+ @entry.avatar.should be_nil
352
+ end
353
+
354
+ it "should return no temp_value" do
355
+ @entry.avatar_temp.should be_nil
356
+ end
357
+
358
+ it "should return nothing in the _public_path method" do
359
+ @entry.avatar_public_path.should == nil
360
+ end
361
+
362
+ it "should return nothing in the _path method" do
363
+ @entry.avatar_path.should == nil
364
+ end
365
+ end
366
+
367
+ describe "an upload column with an uploaded file" do
368
+
369
+ include UploadColumnSpecHelper
370
+
371
+ before(:each) do
372
+ setup_standard_mocking
373
+ UploadColumn::UploadedFile.stub!(:upload).and_return(@uploaded_file)
374
+ @entry.avatar = @file
375
+ end
376
+
377
+ it "should delegate the _public_path method to the column" do
378
+ @uploaded_file.should_receive(:public_path).and_return('/url/to/file.exe')
379
+ @entry.avatar_public_path.should == '/url/to/file.exe'
380
+ end
381
+
382
+ it "should delegate the _path method to the column" do
383
+ @uploaded_file.should_receive(:path).and_return('/path/to/file.exe')
384
+ @entry.avatar_path.should == '/path/to/file.exe'
385
+ end
386
+
387
+ end
388
+
389
+ describe "an upload column with different versions and no uploaded file" do
390
+
391
+ include UploadColumnSpecHelper
392
+
393
+ before(:each) do
394
+ setup_version_mocking # sets up a column with thumb and large versions
395
+ end
396
+
397
+ it "should return nil for the _thumb method" do
398
+ @entry.avatar_thumb.should == nil
399
+ end
400
+
401
+ it "should return nil for the _large method" do
402
+ @entry.avatar_large.should == nil
403
+ end
404
+
405
+ it "should return nil for the _thumb_url method" do
406
+ @entry.avatar_thumb_public_path.should == nil
407
+ end
408
+
409
+ it "should return nil for the _large_path method" do
410
+ @entry.avatar_large_path.should == nil
411
+ end
412
+
413
+ end
414
+
415
+ describe "an upload column with different versions and an uploaded file" do
416
+
417
+ include UploadColumnSpecHelper
418
+
419
+ before(:each) do
420
+ setup_version_mocking # sets up a column with thumb and large versions
421
+ UploadColumn::UploadedFile.stub!(:upload).and_return(@uploaded_file)
422
+ @entry.avatar = @file
423
+ end
424
+
425
+ it "should delegate the _thumb method to the column" do
426
+ thumb = mock('thumb')
427
+ @uploaded_file.should_receive(:thumb).and_return(thumb)
428
+ @entry.avatar_thumb.should == thumb
429
+ end
430
+
431
+ it "should delegate the _large method to the column" do
432
+ large = mock('large')
433
+ @uploaded_file.should_receive(:large).and_return(large)
434
+ @entry.avatar_large.should == large
435
+ end
436
+
437
+ it "should delegate the _thumb_url method to the column" do
438
+ thumb = mock('thumb')
439
+ thumb.should_receive(:public_path).and_return('/url/to/file.exe')
440
+ @uploaded_file.should_receive(:thumb).and_return(thumb)
441
+
442
+ @entry.avatar_thumb_public_path.should == '/url/to/file.exe'
443
+ end
444
+
445
+ it "should delegate the _large_path method to the column" do
446
+ large = mock('large')
447
+ large.should_receive(:path).and_return('/path/to/file.exe')
448
+ @uploaded_file.should_receive(:large).and_return(large)
449
+
450
+ @entry.avatar_large_path.should == '/path/to/file.exe'
451
+ end
452
+
453
+ end
454
+
455
+ describe "uploading a file that fails an integrity check" do
456
+
457
+ include UploadColumnSpecHelper
458
+
459
+ before(:all) do
460
+ Entry.validates_integrity_of :avatar
461
+ end
462
+
463
+ before(:each) do
464
+ setup_standard_mocking
465
+ end
466
+
467
+ it "should set the column to nil" do
468
+ UploadColumn::UploadedFile.should_receive(:upload).and_raise(UploadColumn::IntegrityError.new('something'))
469
+ @entry.avatar = @file
470
+
471
+ @entry.avatar.should be_nil
472
+ end
473
+
474
+ it "should fail an integrity validation" do
475
+ UploadColumn::UploadedFile.should_receive(:upload).and_raise(UploadColumn::IntegrityError.new('something'))
476
+ @entry.avatar = @file
477
+
478
+ @entry.should_not be_valid
479
+ @entry.errors.on(:avatar).should == 'something'
480
+ end
481
+ end
482
+
483
+ describe UploadColumn::ActiveRecordExtension::ClassMethods, ".image_column" do
484
+
485
+ include UploadColumnSpecHelper
486
+
487
+ before(:each) do
488
+ @class = Class.new(ActiveRecord::Base)
489
+ @class.send(:include, UploadColumn)
490
+ end
491
+
492
+ it "should call an upload column with some specialized options" do
493
+ @class.should_receive(:upload_column).with(:sicada,
494
+ :manipulator => UploadColumn::Manipulators::RMagick,
495
+ :root_dir => File.join(RAILS_ROOT, 'public', 'images'),
496
+ :web_root => '/images',
497
+ :monkey => 'blah',
498
+ :extensions => UploadColumn.image_extensions
499
+ )
500
+ @class.image_column(:sicada, :monkey => 'blah')
501
+ end
502
+ end
503
+
504
+ describe UploadColumn::ActiveRecordExtension::ClassMethods, ".validate_integrity" do
505
+
506
+ include UploadColumnSpecHelper
507
+
508
+ it "should change the options for this upload_column" do
509
+ Entry.upload_column :avatar
510
+ Entry.reflect_on_upload_columns[:avatar].options[:validate_integrity].should be_nil
511
+ Entry.validates_integrity_of :avatar
512
+ Entry.reflect_on_upload_columns[:avatar].options[:validate_integrity].should == true
513
+ end
514
+ end
@@ -0,0 +1,148 @@
1
+ class BeIdenticalWith
2
+ def initialize(expected)
3
+ @expected = expected
4
+ end
5
+ def matches?(actual)
6
+ @actual = actual
7
+ FileUtils.identical?(@actual, @expected)
8
+ end
9
+ def failure_message
10
+ "expected #{@actual.inspect} to be identical with #{@expected.inspect}"
11
+ end
12
+ def negative_failure_message
13
+ "expected #{@actual.inspect} to not be identical with #{@expected.inspect}"
14
+ end
15
+ end
16
+
17
+ def be_identical_with(expected)
18
+ BeIdenticalWith.new(expected)
19
+ end
20
+
21
+ class ExistsPredicate
22
+
23
+ def matches?(actual)
24
+ actual.exists?
25
+ end
26
+ def failure_message
27
+ "expected #{@actual.inspect} to exist, it doesn't."
28
+ end
29
+ def negative_failure_message
30
+ "expected #{@actual.inspect} to not exist, yet it does."
31
+ end
32
+ end
33
+
34
+ def be_in_existence
35
+ ExistsPredicate.new
36
+ end
37
+
38
+ class MatchPath
39
+ def initialize(*expected)
40
+ if(expected.size < 2)
41
+ @expected = File.expand_path(expected.first)
42
+ else
43
+ @expected = expected.map {|e| e.is_a?(Regexp) ? e.to_s : Regexp.escape(e)}
44
+ @expected = File.expand_path(File.join(*@expected), RAILS_ROOT)
45
+ @expected = %r(^#{@expected}$)
46
+ end
47
+ end
48
+ def matches?(actual)
49
+ @actual = actual
50
+ if @expected.is_a?(Regexp)
51
+ File.expand_path(actual) =~ @expected
52
+ else
53
+ File.expand_path(actual) == @expected
54
+ end
55
+ end
56
+ def failure_message
57
+ "expected #{@actual.inspect} to match #{@expected}."
58
+ end
59
+ def negative_failure_message
60
+ "expected #{@actual.inspect} to not match #{@expected}, yet it does."
61
+ end
62
+ end
63
+
64
+ # Match a path without bothering whether they are formatted the same way.
65
+ # can also take several parameters, any number of which may be regexes
66
+ def match_path(*expected)
67
+ MatchPath.new(*expected)
68
+ end
69
+
70
+ class HavePermissions
71
+ def initialize(expected)
72
+ @expected = expected
73
+ end
74
+
75
+ def matches?(actual)
76
+ @actual = actual
77
+ # Satisfy expectation here. Return false or raise an error if it's not met.
78
+ (File.stat(@actual.path).mode & 0777) == @expected
79
+ end
80
+
81
+ def failure_message
82
+ "expected #{@actual.inspect} to have permissions #{@expected.to_s(8)}, but they were #{(File.stat(@actual.path).mode & 0777).to_s(8)}"
83
+ end
84
+
85
+ def negative_failure_message
86
+ "expected #{@actual.inspect} not to have permissions #{@expected.to_s(8)}, but it did"
87
+ end
88
+ end
89
+
90
+ def have_permissions(expected)
91
+ HavePermissions.new(expected)
92
+ end
93
+
94
+ class BeNoLargerThan
95
+ def initialize(width, height)
96
+ @width, @height = width, height
97
+ end
98
+
99
+ def matches?(actual)
100
+ @actual = actual
101
+ # Satisfy expectation here. Return false or raise an error if it's not met.
102
+ require 'RMagick'
103
+ img = ::Magick::Image.read(@actual.path).first
104
+ @actual_width = img.columns
105
+ @actual_height = img.rows
106
+ @actual_width <= @width && @actual_height <= @height
107
+ end
108
+
109
+ def failure_message
110
+ "expected #{@actual.inspect} to be no larger than #{@width} by #{@height}, but it was #{@actual_height} by #{@actual_width}."
111
+ end
112
+
113
+ def negative_failure_message
114
+ "expected #{@actual.inspect} to be larger than #{@width} by #{@height}, but it wasn't."
115
+ end
116
+ end
117
+
118
+ def be_no_larger_than(width, height)
119
+ BeNoLargerThan.new(width, height)
120
+ end
121
+
122
+ class HaveTheExactDimensionsOf
123
+ def initialize(width, height)
124
+ @width, @height = width, height
125
+ end
126
+
127
+ def matches?(actual)
128
+ @actual = actual
129
+ # Satisfy expectation here. Return false or raise an error if it's not met.
130
+ require 'RMagick'
131
+ img = ::Magick::Image.read(@actual.path).first
132
+ @actual_width = img.columns
133
+ @actual_height = img.rows
134
+ @actual_width == @width && @actual_height == @height
135
+ end
136
+
137
+ def failure_message
138
+ "expected #{@actual.inspect} to have an exact size of #{@width} by #{@height}, but it was #{@actual_height} by #{@actual_width}."
139
+ end
140
+
141
+ def negative_failure_message
142
+ "expected #{@actual.inspect} not to have an exact size of #{@width} by #{@height}, but it did."
143
+ end
144
+ end
145
+
146
+ def have_the_exact_dimensions_of(width, height)
147
+ HaveTheExactDimensionsOf.new(width, height)
148
+ end
Binary file
@@ -0,0 +1 @@
1
+ this is certainly not a JPEG image
Binary file
Binary file
Binary file
Binary file