associo 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.
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