associo 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Binary file
Binary file
Binary file
Binary file
@@ -0,0 +1 @@
1
+ test1
@@ -0,0 +1 @@
1
+ test2
Binary file
@@ -0,0 +1,96 @@
1
+ require 'bundler/setup'
2
+ Bundler.setup(:default, 'test', 'development')
3
+
4
+ require 'tempfile'
5
+ require 'pp'
6
+ require 'shoulda'
7
+ require 'matchy'
8
+ require 'mocha'
9
+ require 'mongo_mapper'
10
+
11
+ require File.expand_path(File.dirname(__FILE__) + '/../lib/joint')
12
+
13
+ MongoMapper.database = "testing"
14
+
15
+ class Test::Unit::TestCase
16
+ def setup
17
+ MongoMapper.database.collections.each(&:remove)
18
+ end
19
+
20
+ def assert_difference(expression, difference = 1, message = nil, &block)
21
+ b = block.send(:binding)
22
+ exps = Array.wrap(expression)
23
+ before = exps.map { |e| eval(e, b) }
24
+ yield
25
+ exps.each_with_index do |e, i|
26
+ error = "#{e.inspect} didn't change by #{difference}"
27
+ error = "#{message}.\n#{error}" if message
28
+ after = eval(e, b)
29
+ assert_equal(before[i] + difference, after, error)
30
+ end
31
+ end
32
+
33
+ def assert_no_difference(expression, message = nil, &block)
34
+ assert_difference(expression, 0, message, &block)
35
+ end
36
+
37
+ def assert_grid_difference(difference=1, &block)
38
+ assert_difference("MongoMapper.database['fs.files'].find().count", difference, &block)
39
+ end
40
+
41
+ def assert_no_grid_difference(&block)
42
+ assert_grid_difference(0, &block)
43
+ end
44
+ end
45
+
46
+ class Asset
47
+ include MongoMapper::Document
48
+ plugin Joint
49
+
50
+ key :title, String
51
+ attachment :image
52
+ attachment :file
53
+ has_many :embedded_assets
54
+ end
55
+
56
+ class EmbeddedAsset
57
+ include MongoMapper::EmbeddedDocument
58
+ plugin Joint
59
+
60
+ key :title, String
61
+ attachment :image
62
+ attachment :file
63
+ end
64
+
65
+ class BaseModel
66
+ include MongoMapper::Document
67
+ plugin Joint
68
+ attachment :file
69
+ end
70
+
71
+ class Image < BaseModel; attachment :image end
72
+ class Video < BaseModel; attachment :video end
73
+
74
+ module JointTestHelpers
75
+ def all_files
76
+ [@file, @image, @image2, @test1, @test2]
77
+ end
78
+
79
+ def rewind_files
80
+ all_files.each { |file| file.rewind }
81
+ end
82
+
83
+ def open_file(name)
84
+ f = File.open(File.join(File.dirname(__FILE__), 'fixtures', name), 'r')
85
+ f.binmode
86
+ f
87
+ end
88
+
89
+ def grid
90
+ @grid ||= Mongo::Grid.new(MongoMapper.database)
91
+ end
92
+
93
+ def key_names
94
+ [:id, :name, :type, :size]
95
+ end
96
+ end
@@ -0,0 +1,52 @@
1
+ require 'helper'
2
+
3
+ class FileHelpersTest < Test::Unit::TestCase
4
+ include JointTestHelpers
5
+
6
+ def setup
7
+ super
8
+ @image = open_file('mr_t.jpg')
9
+ end
10
+
11
+ def teardown
12
+ @image.close
13
+ end
14
+
15
+ context ".name" do
16
+ should "return original_filename" do
17
+ def @image.original_filename
18
+ 'frank.jpg'
19
+ end
20
+ Joint::FileHelpers.name(@image).should == 'frank.jpg'
21
+ end
22
+
23
+ should "fall back to File.basename" do
24
+ Joint::FileHelpers.name(@image).should == 'mr_t.jpg'
25
+ end
26
+ end
27
+
28
+ context ".size" do
29
+ should "return size" do
30
+ def @image.size
31
+ 25
32
+ end
33
+ Joint::FileHelpers.size(@image).should == 25
34
+ end
35
+
36
+ should "fall back to File.size" do
37
+ Joint::FileHelpers.size(@image).should == 13661
38
+ end
39
+ end
40
+
41
+ context ".type" do
42
+ should "return type if Joint::Io instance" do
43
+ file = Joint::IO.new(:type => 'image/jpeg')
44
+ Joint::FileHelpers.type(@image).should == 'image/jpeg'
45
+ end
46
+
47
+ should "fall back to Wand" do
48
+ Joint::FileHelpers.type(@image).should == 'image/jpeg'
49
+ end
50
+ end
51
+
52
+ end
@@ -0,0 +1,39 @@
1
+ require 'helper'
2
+
3
+ class IOTest < Test::Unit::TestCase
4
+ context "#initialize" do
5
+ should "set attributes from hash" do
6
+ Joint::IO.new(:name => 'foo').name.should == 'foo'
7
+ end
8
+ end
9
+
10
+ should "default type to plain text" do
11
+ Joint::IO.new.type.should == 'plain/text'
12
+ end
13
+
14
+ should "default size to content size" do
15
+ content = 'This is my content'
16
+ Joint::IO.new(:content => content).size.should == content.size
17
+ end
18
+
19
+ should "alias path to name" do
20
+ Joint::IO.new(:name => 'foo').path.should == 'foo'
21
+ end
22
+
23
+ context "#read" do
24
+ should "return content" do
25
+ Joint::IO.new(:content => 'Testing').read.should == 'Testing'
26
+ end
27
+ end
28
+
29
+ context "#rewind" do
30
+ should "rewinds the io to position 0" do
31
+ io = Joint::IO.new(:content => 'Testing')
32
+ io.read.should == 'Testing'
33
+ io.read.should == ''
34
+ io.rewind
35
+ io.read.should == 'Testing'
36
+ end
37
+ end
38
+
39
+ end
@@ -0,0 +1,554 @@
1
+ require 'helper'
2
+
3
+ class JointTest < Test::Unit::TestCase
4
+ include JointTestHelpers
5
+
6
+ def setup
7
+ super
8
+ @file = open_file('unixref.pdf')
9
+ @image = open_file('mr_t.jpg')
10
+ @image2 = open_file('harmony.png')
11
+ @test1 = open_file('test1.txt')
12
+ @test2 = open_file('test2.txt')
13
+ end
14
+
15
+ def teardown
16
+ all_files.each { |file| file.close }
17
+ end
18
+
19
+ context "Using Joint plugin" do
20
+ should "add each attachment to attachment_names" do
21
+ Asset.attachment_names.should == Set.new([:image, :file])
22
+ EmbeddedAsset.attachment_names.should == Set.new([:image, :file])
23
+ end
24
+
25
+ should "add keys for each attachment" do
26
+ key_names.each do |key|
27
+ Asset.keys.should include("image_#{key}")
28
+ Asset.keys.should include("file_#{key}")
29
+ EmbeddedAsset.keys.should include("image_#{key}")
30
+ EmbeddedAsset.keys.should include("file_#{key}")
31
+ end
32
+ end
33
+
34
+ should "add memoized accessors module" do
35
+ Asset.attachment_accessor_module.should be_instance_of(Module)
36
+ EmbeddedAsset.attachment_accessor_module.should be_instance_of(Module)
37
+ end
38
+
39
+ context "with inheritance" do
40
+ should "add attachment to attachment_names" do
41
+ BaseModel.attachment_names.should == Set.new([:file])
42
+ end
43
+
44
+ should "inherit attachments from superclass, but not share other inherited class attachments" do
45
+ Image.attachment_names.should == Set.new([:file, :image])
46
+ Video.attachment_names.should == Set.new([:file, :video])
47
+ end
48
+
49
+ should "add inherit keys from superclass" do
50
+ key_names.each do |key|
51
+ BaseModel.keys.should include("file_#{key}")
52
+ Image.keys.should include("file_#{key}")
53
+ Image.keys.should include("image_#{key}")
54
+ Video.keys.should include("file_#{key}")
55
+ Video.keys.should include("video_#{key}")
56
+ end
57
+ end
58
+ end
59
+ end
60
+
61
+ context "Assigning new attachments to document" do
62
+ setup do
63
+ @doc = Asset.create(:image => @image, :file => @file)
64
+ rewind_files
65
+ end
66
+ subject { @doc }
67
+
68
+ should "assign GridFS content_type" do
69
+ grid.get(subject.image_id).content_type.should == 'image/jpeg'
70
+ grid.get(subject.file_id).content_type.should == 'application/pdf'
71
+ end
72
+
73
+ should "assign joint keys" do
74
+ subject.image_size.should == 13661
75
+ subject.file_size.should == 68926
76
+
77
+ subject.image_type.should == "image/jpeg"
78
+ subject.file_type.should == "application/pdf"
79
+
80
+ subject.image_id.should_not be_nil
81
+ subject.file_id.should_not be_nil
82
+
83
+ subject.image_id.should be_instance_of(BSON::ObjectId)
84
+ subject.file_id.should be_instance_of(BSON::ObjectId)
85
+ end
86
+
87
+ should "allow accessing keys through attachment proxy" do
88
+ subject.image.size.should == 13661
89
+ subject.file.size.should == 68926
90
+
91
+ subject.image.type.should == "image/jpeg"
92
+ subject.file.type.should == "application/pdf"
93
+
94
+ subject.image.id.should_not be_nil
95
+ subject.file.id.should_not be_nil
96
+
97
+ subject.image.id.should be_instance_of(BSON::ObjectId)
98
+ subject.file.id.should be_instance_of(BSON::ObjectId)
99
+ end
100
+
101
+ should "proxy unknown methods to GridIO object" do
102
+ subject.image.files_id.should == subject.image_id
103
+ subject.image.content_type.should == 'image/jpeg'
104
+ subject.image.filename.should == 'mr_t.jpg'
105
+ subject.image.file_length.should == 13661
106
+ end
107
+
108
+ should "assign file name from path if original file name not available" do
109
+ subject.image_name.should == 'mr_t.jpg'
110
+ subject.file_name.should == 'unixref.pdf'
111
+ end
112
+
113
+ should "save attachment contents correctly" do
114
+ subject.file.read.should == @file.read
115
+ subject.image.read.should == @image.read
116
+ end
117
+
118
+ should "know that attachment exists" do
119
+ subject.image?.should be(true)
120
+ subject.file?.should be(true)
121
+ end
122
+
123
+ should "respond with false when asked if the attachment is blank?" do
124
+ subject.image.blank?.should be(false)
125
+ subject.file.blank?.should be(false)
126
+ end
127
+
128
+ should "clear assigned attachments so they don't get uploaded twice" do
129
+ Mongo::Grid.any_instance.expects(:put).never
130
+ subject.save
131
+ end
132
+ end
133
+
134
+ context "Assigning new attachments to embedded document" do
135
+ setup do
136
+ @asset = Asset.new
137
+ @doc = @asset.embedded_assets.build(:image => @image, :file => @file)
138
+ @asset.save!
139
+ rewind_files
140
+ end
141
+ subject { @doc }
142
+
143
+ should "assign GridFS content_type" do
144
+ grid.get(subject.image_id).content_type.should == 'image/jpeg'
145
+ grid.get(subject.file_id).content_type.should == 'application/pdf'
146
+ end
147
+
148
+ should "assign joint keys" do
149
+ subject.image_size.should == 13661
150
+ subject.file_size.should == 68926
151
+
152
+ subject.image_type.should == "image/jpeg"
153
+ subject.file_type.should == "application/pdf"
154
+
155
+ subject.image_id.should_not be_nil
156
+ subject.file_id.should_not be_nil
157
+
158
+ subject.image_id.should be_instance_of(BSON::ObjectId)
159
+ subject.file_id.should be_instance_of(BSON::ObjectId)
160
+ end
161
+
162
+ should "allow accessing keys through attachment proxy" do
163
+ subject.image.size.should == 13661
164
+ subject.file.size.should == 68926
165
+
166
+ subject.image.type.should == "image/jpeg"
167
+ subject.file.type.should == "application/pdf"
168
+
169
+ subject.image.id.should_not be_nil
170
+ subject.file.id.should_not be_nil
171
+
172
+ subject.image.id.should be_instance_of(BSON::ObjectId)
173
+ subject.file.id.should be_instance_of(BSON::ObjectId)
174
+ end
175
+
176
+ should "proxy unknown methods to GridIO object" do
177
+ subject.image.files_id.should == subject.image_id
178
+ subject.image.content_type.should == 'image/jpeg'
179
+ subject.image.filename.should == 'mr_t.jpg'
180
+ subject.image.file_length.should == 13661
181
+ end
182
+
183
+ should "assign file name from path if original file name not available" do
184
+ subject.image_name.should == 'mr_t.jpg'
185
+ subject.file_name.should == 'unixref.pdf'
186
+ end
187
+
188
+ should "save attachment contents correctly" do
189
+ subject.file.read.should == @file.read
190
+ subject.image.read.should == @image.read
191
+ end
192
+
193
+ should "know that attachment exists" do
194
+ subject.image?.should be(true)
195
+ subject.file?.should be(true)
196
+ end
197
+
198
+ should "respond with false when asked if the attachment is blank?" do
199
+ subject.image.blank?.should be(false)
200
+ subject.file.blank?.should be(false)
201
+ end
202
+
203
+ should "clear assigned attachments so they don't get uploaded twice" do
204
+ Mongo::Grid.any_instance.expects(:put).never
205
+ subject.save
206
+ end
207
+ end
208
+
209
+ context "Updating existing attachment" do
210
+ setup do
211
+ @doc = Asset.create(:file => @test1)
212
+ assert_no_grid_difference do
213
+ @doc.file = @test2
214
+ @doc.save!
215
+ end
216
+ rewind_files
217
+ end
218
+ subject { @doc }
219
+
220
+ should "not change attachment id" do
221
+ subject.file_id_changed?.should be(false)
222
+ end
223
+
224
+ should "update keys" do
225
+ subject.file_name.should == 'test2.txt'
226
+ subject.file_type.should == "text/plain"
227
+ subject.file_size.should == 5
228
+ end
229
+
230
+ should "update GridFS" do
231
+ grid.get(subject.file_id).filename.should == 'test2.txt'
232
+ grid.get(subject.file_id).content_type.should == 'text/plain'
233
+ grid.get(subject.file_id).file_length.should == 5
234
+ grid.get(subject.file_id).read.should == @test2.read
235
+ end
236
+ end
237
+
238
+ context "Updating existing attachment in embedded document" do
239
+ setup do
240
+ @asset = Asset.new
241
+ @doc = @asset.embedded_assets.build(:file => @test1)
242
+ @asset.save!
243
+ assert_no_grid_difference do
244
+ @doc.file = @test2
245
+ @doc.save!
246
+ end
247
+ rewind_files
248
+ end
249
+ subject { @doc }
250
+
251
+ should "update keys" do
252
+ subject.file_name.should == 'test2.txt'
253
+ subject.file_type.should == "text/plain"
254
+ subject.file_size.should == 5
255
+ end
256
+
257
+ should "update GridFS" do
258
+ grid.get(subject.file_id).filename.should == 'test2.txt'
259
+ grid.get(subject.file_id).content_type.should == 'text/plain'
260
+ grid.get(subject.file_id).file_length.should == 5
261
+ grid.get(subject.file_id).read.should == @test2.read
262
+ end
263
+ end
264
+
265
+ context "Updating document but not attachments" do
266
+ setup do
267
+ @doc = Asset.create(:image => @image)
268
+ @doc.update_attributes(:title => 'Updated')
269
+ @doc.reload
270
+ rewind_files
271
+ end
272
+ subject { @doc }
273
+
274
+ should "not affect attachment" do
275
+ subject.image.read.should == @image.read
276
+ end
277
+
278
+ should "update document attributes" do
279
+ subject.title.should == 'Updated'
280
+ end
281
+ end
282
+
283
+ context "Updating embedded document but not attachments" do
284
+ setup do
285
+ @asset = Asset.new
286
+ @doc = @asset.embedded_assets.build(:image => @image)
287
+ @doc.update_attributes(:title => 'Updated')
288
+ @asset.reload
289
+ @doc = @asset.embedded_assets.first
290
+ rewind_files
291
+ end
292
+ subject { @doc }
293
+
294
+ should "not affect attachment" do
295
+ subject.image.read.should == @image.read
296
+ end
297
+
298
+ should "update document attributes" do
299
+ subject.title.should == 'Updated'
300
+ end
301
+ end
302
+
303
+ context "Assigning file where file pointer is not at beginning" do
304
+ setup do
305
+ @image.read
306
+ @doc = Asset.create(:image => @image)
307
+ @doc.reload
308
+ rewind_files
309
+ end
310
+ subject { @doc }
311
+
312
+ should "rewind and correctly store contents" do
313
+ subject.image.read.should == @image.read
314
+ end
315
+ end
316
+
317
+ context "Setting attachment to nil" do
318
+ setup do
319
+ @doc = Asset.create(:image => @image)
320
+ rewind_files
321
+ end
322
+ subject { @doc }
323
+
324
+ should "delete attachment after save" do
325
+ assert_no_grid_difference { subject.image = nil }
326
+ assert_grid_difference(-1) { subject.save }
327
+ end
328
+
329
+ should "know that the attachment has been nullified" do
330
+ subject.image = nil
331
+ subject.image?.should be(false)
332
+ end
333
+
334
+ should "respond with true when asked if the attachment is nil?" do
335
+ subject.image = nil
336
+ subject.image.nil?.should be(true)
337
+ end
338
+
339
+ should "respond with true when asked if the attachment is blank?" do
340
+ subject.image = nil
341
+ subject.image.blank?.should be(true)
342
+ end
343
+
344
+ should "clear nil attachments after save and not attempt to delete again" do
345
+ Mongo::Grid.any_instance.expects(:delete).once
346
+ subject.image = nil
347
+ subject.save
348
+ Mongo::Grid.any_instance.expects(:delete).never
349
+ subject.save
350
+ end
351
+
352
+ should "clear id, name, type, size" do
353
+ subject.image = nil
354
+ subject.save
355
+ assert_nil subject.image_id
356
+ assert_nil subject.image_name
357
+ assert_nil subject.image_type
358
+ assert_nil subject.image_size
359
+ subject.reload
360
+ assert_nil subject.image_id
361
+ assert_nil subject.image_name
362
+ assert_nil subject.image_type
363
+ assert_nil subject.image_size
364
+ end
365
+ end
366
+
367
+ context "Setting attachment to nil on embedded document" do
368
+ setup do
369
+ @asset = Asset.new
370
+ @doc = @asset.embedded_assets.build(:image => @image)
371
+ @asset.save!
372
+ rewind_files
373
+ end
374
+ subject { @doc }
375
+
376
+ should "delete attachment after save" do
377
+ assert_no_grid_difference { subject.image = nil }
378
+ assert_grid_difference(-1) { subject.save }
379
+ end
380
+
381
+ should "know that the attachment has been nullified" do
382
+ subject.image = nil
383
+ subject.image?.should be(false)
384
+ end
385
+
386
+ should "respond with true when asked if the attachment is nil?" do
387
+ subject.image = nil
388
+ subject.image.nil?.should be(true)
389
+ end
390
+
391
+ should "respond with true when asked if the attachment is blank?" do
392
+ subject.image = nil
393
+ subject.image.blank?.should be(true)
394
+ end
395
+
396
+ should "clear nil attachments after save and not attempt to delete again" do
397
+ Mongo::Grid.any_instance.expects(:delete).once
398
+ subject.image = nil
399
+ subject.save
400
+ Mongo::Grid.any_instance.expects(:delete).never
401
+ subject.save
402
+ end
403
+
404
+ should "clear id, name, type, size" do
405
+ subject.image = nil
406
+ subject.save
407
+ assert_nil subject.image_id
408
+ assert_nil subject.image_name
409
+ assert_nil subject.image_type
410
+ assert_nil subject.image_size
411
+ s = subject._root_document.reload.embedded_assets.first
412
+ assert_nil s.image_id
413
+ assert_nil s.image_name
414
+ assert_nil s.image_type
415
+ assert_nil s.image_size
416
+ end
417
+ end
418
+
419
+ context "Retrieving attachment that does not exist" do
420
+ setup do
421
+ @doc = Asset.create
422
+ rewind_files
423
+ end
424
+ subject { @doc }
425
+
426
+ should "know that the attachment is not present" do
427
+ subject.image?.should be(false)
428
+ end
429
+
430
+ should "respond with true when asked if the attachment is nil?" do
431
+ subject.image.nil?.should be(true)
432
+ end
433
+
434
+ should "raise Mongo::GridFileNotFound" do
435
+ assert_raises(Mongo::GridFileNotFound) { subject.image.read }
436
+ end
437
+ end
438
+
439
+ context "Destroying a document" do
440
+ setup do
441
+ @doc = Asset.create(:image => @image)
442
+ rewind_files
443
+ end
444
+ subject { @doc }
445
+
446
+ should "remove files from grid fs as well" do
447
+ assert_grid_difference(-1) { subject.destroy }
448
+ end
449
+ end
450
+
451
+ context "Destroying an embedded document's _root_document" do
452
+ setup do
453
+ @asset = Asset.new
454
+ @doc = @asset.embedded_assets.build(:image => @image)
455
+ @doc.save!
456
+ rewind_files
457
+ end
458
+ subject { @doc }
459
+
460
+ should "remove files from grid fs as well" do
461
+ assert_grid_difference(-1) { subject._root_document.destroy }
462
+ end
463
+ end
464
+
465
+ # What about when an embedded document is removed?
466
+
467
+ context "Assigning file name" do
468
+ should "default to path" do
469
+ Asset.create(:image => @image).image.name.should == 'mr_t.jpg'
470
+ end
471
+
472
+ should "use original_filename if available" do
473
+ def @image.original_filename
474
+ 'testing.txt'
475
+ end
476
+ doc = Asset.create(:image => @image)
477
+ assert_equal 'testing.txt', doc.image_name
478
+ end
479
+ end
480
+
481
+ context "Validating attachment presence" do
482
+ setup do
483
+ @model_class = Class.new do
484
+ include MongoMapper::Document
485
+ plugin Joint
486
+ attachment :file, :required => true
487
+
488
+ def self.name; "Foo"; end
489
+ end
490
+ end
491
+
492
+ should "work" do
493
+ model = @model_class.new
494
+ model.should_not be_valid
495
+
496
+ model.file = @file
497
+ model.should be_valid
498
+
499
+ model.file = nil
500
+ model.should_not be_valid
501
+
502
+ model.file = @image
503
+ model.should be_valid
504
+ end
505
+ end
506
+
507
+ context "Assigning joint io instance" do
508
+ setup do
509
+ io = Joint::IO.new({
510
+ :name => 'foo.txt',
511
+ :type => 'plain/text',
512
+ :content => 'This is my stuff'
513
+ })
514
+ @asset = Asset.create(:file => io)
515
+ end
516
+
517
+ should "work" do
518
+ @asset.file_name.should == 'foo.txt'
519
+ @asset.file_size.should == 16
520
+ @asset.file_type.should == 'plain/text'
521
+ @asset.file.read.should == 'This is my stuff'
522
+ end
523
+ end
524
+
525
+ context "A font file" do
526
+ setup do
527
+ @file = open_file('font.eot')
528
+ @doc = Asset.create(:file => @file)
529
+ end
530
+ subject { @doc }
531
+
532
+ should "assign joint keys" do
533
+ subject.file_size.should == 17610
534
+ subject.file_type.should == "application/octet-stream"
535
+ subject.file_id.should_not be_nil
536
+ subject.file_id.should be_instance_of(BSON::ObjectId)
537
+ end
538
+ end
539
+
540
+ context "A music file" do
541
+ setup do
542
+ @file = open_file('example.m4r')
543
+ @doc = Asset.create(:file => @file)
544
+ end
545
+ subject { @doc }
546
+
547
+ should "assign joint keys" do
548
+ subject.file_size.should == 50790
549
+ subject.file_type.should == "audio/mp4"
550
+ subject.file_id.should_not be_nil
551
+ subject.file_id.should be_instance_of(BSON::ObjectId)
552
+ end
553
+ end
554
+ end