bulldog 0.0.1
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.
- data/.gitignore +2 -0
- data/DESCRIPTION.txt +3 -0
- data/LICENSE +20 -0
- data/README.rdoc +18 -0
- data/Rakefile +64 -0
- data/VERSION +1 -0
- data/bulldog.gemspec +157 -0
- data/lib/bulldog.rb +95 -0
- data/lib/bulldog/attachment.rb +49 -0
- data/lib/bulldog/attachment/base.rb +167 -0
- data/lib/bulldog/attachment/has_dimensions.rb +94 -0
- data/lib/bulldog/attachment/image.rb +63 -0
- data/lib/bulldog/attachment/maybe.rb +229 -0
- data/lib/bulldog/attachment/none.rb +37 -0
- data/lib/bulldog/attachment/pdf.rb +63 -0
- data/lib/bulldog/attachment/unknown.rb +11 -0
- data/lib/bulldog/attachment/video.rb +143 -0
- data/lib/bulldog/error.rb +5 -0
- data/lib/bulldog/has_attachment.rb +214 -0
- data/lib/bulldog/interpolation.rb +73 -0
- data/lib/bulldog/missing_file.rb +12 -0
- data/lib/bulldog/processor.rb +5 -0
- data/lib/bulldog/processor/argument_tree.rb +116 -0
- data/lib/bulldog/processor/base.rb +124 -0
- data/lib/bulldog/processor/ffmpeg.rb +172 -0
- data/lib/bulldog/processor/image_magick.rb +134 -0
- data/lib/bulldog/processor/one_shot.rb +19 -0
- data/lib/bulldog/reflection.rb +234 -0
- data/lib/bulldog/saved_file.rb +19 -0
- data/lib/bulldog/stream.rb +186 -0
- data/lib/bulldog/style.rb +38 -0
- data/lib/bulldog/style_set.rb +101 -0
- data/lib/bulldog/tempfile.rb +28 -0
- data/lib/bulldog/util.rb +92 -0
- data/lib/bulldog/validations.rb +68 -0
- data/lib/bulldog/vector2.rb +18 -0
- data/rails/init.rb +9 -0
- data/script/console +8 -0
- data/spec/data/empty.txt +0 -0
- data/spec/data/test.jpg +0 -0
- data/spec/data/test.mov +0 -0
- data/spec/data/test.pdf +0 -0
- data/spec/data/test.png +0 -0
- data/spec/data/test2.jpg +0 -0
- data/spec/helpers/image_creation.rb +8 -0
- data/spec/helpers/temporary_directory.rb +25 -0
- data/spec/helpers/temporary_models.rb +76 -0
- data/spec/helpers/temporary_values.rb +102 -0
- data/spec/helpers/test_upload_files.rb +108 -0
- data/spec/helpers/time_travel.rb +20 -0
- data/spec/integration/data/test.jpg +0 -0
- data/spec/integration/lifecycle_hooks_spec.rb +213 -0
- data/spec/integration/processing_image_attachments.rb +72 -0
- data/spec/integration/processing_video_attachments_spec.rb +82 -0
- data/spec/integration/saving_an_attachment_spec.rb +31 -0
- data/spec/matchers/file_operations.rb +159 -0
- data/spec/spec_helper.rb +76 -0
- data/spec/unit/attachment/base_spec.rb +311 -0
- data/spec/unit/attachment/image_spec.rb +128 -0
- data/spec/unit/attachment/maybe_spec.rb +126 -0
- data/spec/unit/attachment/pdf_spec.rb +137 -0
- data/spec/unit/attachment/video_spec.rb +176 -0
- data/spec/unit/attachment_spec.rb +61 -0
- data/spec/unit/has_attachment_spec.rb +700 -0
- data/spec/unit/interpolation_spec.rb +108 -0
- data/spec/unit/processor/argument_tree_spec.rb +159 -0
- data/spec/unit/processor/ffmpeg_spec.rb +467 -0
- data/spec/unit/processor/image_magick_spec.rb +260 -0
- data/spec/unit/processor/one_shot_spec.rb +70 -0
- data/spec/unit/reflection_spec.rb +338 -0
- data/spec/unit/stream_spec.rb +234 -0
- data/spec/unit/style_set_spec.rb +44 -0
- data/spec/unit/style_spec.rb +51 -0
- data/spec/unit/validations_spec.rb +491 -0
- data/spec/unit/vector2_spec.rb +27 -0
- data/tasks/bulldog_tasks.rake +4 -0
- metadata +193 -0
@@ -0,0 +1,128 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Attachment::Image do
|
4
|
+
use_model_class(:Thing,
|
5
|
+
:photo_file_name => :string,
|
6
|
+
:photo_width => :integer,
|
7
|
+
:photo_height => :integer,
|
8
|
+
:photo_aspect_ratio => :float,
|
9
|
+
:photo_dimensions => :string)
|
10
|
+
|
11
|
+
before do
|
12
|
+
Thing.has_attachment :photo do
|
13
|
+
style :double, :size => '80x60'
|
14
|
+
style :filled, :size => '60x60', :filled => true
|
15
|
+
style :unfilled, :size => '120x120'
|
16
|
+
default_style :double
|
17
|
+
end
|
18
|
+
@thing = Thing.new(:photo => test_image_file)
|
19
|
+
end
|
20
|
+
|
21
|
+
def run(command)
|
22
|
+
`#{command}`
|
23
|
+
$?.success? or
|
24
|
+
raise "command failed: #{command}"
|
25
|
+
end
|
26
|
+
|
27
|
+
describe "#dimensions" do
|
28
|
+
it "should return 1x1 if the style is missing" do
|
29
|
+
Thing.attachment_reflections[:photo].configure do
|
30
|
+
detect_type_by{:image}
|
31
|
+
end
|
32
|
+
@thing.save.should be_true
|
33
|
+
File.unlink(@thing.photo.path(:original))
|
34
|
+
@thing = Thing.find(@thing.id)
|
35
|
+
@thing.photo.is_a?(Attachment::Image) # sanity check
|
36
|
+
@thing.photo.stream.missing? # sanity check
|
37
|
+
@thing.photo.dimensions(:original).should == [1, 1]
|
38
|
+
end
|
39
|
+
|
40
|
+
it "should return the width and height of the default style if no style name is given" do
|
41
|
+
@thing.photo.dimensions.should == [80, 60]
|
42
|
+
end
|
43
|
+
|
44
|
+
it "should return the width and height of the given style" do
|
45
|
+
@thing.photo.dimensions(:original).should == [40, 30]
|
46
|
+
@thing.photo.dimensions(:double).should == [80, 60]
|
47
|
+
end
|
48
|
+
|
49
|
+
it "should return the calculated width according to style filledness" do
|
50
|
+
@thing.photo.dimensions(:filled).should == [60, 60]
|
51
|
+
@thing.photo.dimensions(:unfilled).should == [120, 90]
|
52
|
+
end
|
53
|
+
|
54
|
+
it "should honor the exif:Orientation header" do
|
55
|
+
path = create_image("#{temporary_directory}/test.jpg", :size => '40x30')
|
56
|
+
rotated_path = "#{temporary_directory}/rotated-test.jpg"
|
57
|
+
run "exif --create-exif --ifd=EXIF --tag=Orientation --set-value=4 --output=#{rotated_path} #{path}"
|
58
|
+
open(rotated_path) do |file|
|
59
|
+
@thing.photo = file
|
60
|
+
@thing.photo.dimensions(:original).should == [30, 40]
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
it "should only invoke identify once"
|
65
|
+
it "should log the result"
|
66
|
+
end
|
67
|
+
|
68
|
+
describe "#width" do
|
69
|
+
it "should return the width of the default style if no style name is given" do
|
70
|
+
@thing.photo.width.should == 80
|
71
|
+
end
|
72
|
+
|
73
|
+
it "should return the width of the given style" do
|
74
|
+
@thing.photo.width(:original).should == 40
|
75
|
+
@thing.photo.width(:double).should == 80
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
describe "#height" do
|
80
|
+
it "should return the height of the default style if no style name is given" do
|
81
|
+
@thing.photo.height.should == 60
|
82
|
+
end
|
83
|
+
|
84
|
+
it "should return the height of the given style" do
|
85
|
+
@thing.photo.height(:original).should == 30
|
86
|
+
@thing.photo.height(:double).should == 60
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
describe "#aspect_ratio" do
|
91
|
+
it "should return the aspect ratio of the default style if no style name is given" do
|
92
|
+
@thing.photo.aspect_ratio.should be_close(4.0/3, 1e-5)
|
93
|
+
end
|
94
|
+
|
95
|
+
it "should return the aspect ratio of the given style" do
|
96
|
+
@thing.photo.aspect_ratio(:original).should be_close(4.0/3, 1e-5)
|
97
|
+
@thing.photo.aspect_ratio(:filled).should be_close(1, 1e-5)
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
describe "storable attributes" do
|
102
|
+
it "should set the stored attributes on assignment" do
|
103
|
+
@thing.photo_width.should == 40
|
104
|
+
@thing.photo_height.should == 30
|
105
|
+
@thing.photo_aspect_ratio.should be_close(4.0/3, 1e-5)
|
106
|
+
@thing.photo_dimensions.should == '40x30'
|
107
|
+
end
|
108
|
+
|
109
|
+
describe "after roundtripping through the database" do
|
110
|
+
before do
|
111
|
+
@thing.save
|
112
|
+
@thing = Thing.find(@thing.id)
|
113
|
+
end
|
114
|
+
|
115
|
+
it "should restore the stored attributes" do
|
116
|
+
@thing.photo_width.should == 40
|
117
|
+
@thing.photo_height.should == 30
|
118
|
+
@thing.photo_aspect_ratio.should be_close(4.0/3, 1e-5)
|
119
|
+
@thing.photo_dimensions.should == '40x30'
|
120
|
+
end
|
121
|
+
|
122
|
+
it "should recalculate the dimensions correctly" do
|
123
|
+
@thing.photo.dimensions(:filled).should == [60, 60]
|
124
|
+
@thing.photo.dimensions(:unfilled).should == [120, 90]
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
@@ -0,0 +1,126 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Attachment::Maybe do
|
4
|
+
use_model_class(:Thing, :photo_file_name => :string)
|
5
|
+
|
6
|
+
before do
|
7
|
+
spec = self
|
8
|
+
Thing.has_attachment :photo do
|
9
|
+
path "#{spec.temporary_directory}/photo.:style.:extension"
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def configure_attachment(&block)
|
14
|
+
spec = self
|
15
|
+
Thing.has_attachment :photo do
|
16
|
+
instance_exec(spec, &block)
|
17
|
+
end
|
18
|
+
@thing = Thing.new
|
19
|
+
end
|
20
|
+
|
21
|
+
describe "#interpolate_path" do
|
22
|
+
it "should return the path that the given style name would be stored at" do
|
23
|
+
spec = self
|
24
|
+
configure_attachment do
|
25
|
+
path "#{spec.temporary_directory}/:attachment.:style.jpg"
|
26
|
+
end
|
27
|
+
@thing.photo.interpolate_path(:original).should == "#{temporary_directory}/photo.original.jpg"
|
28
|
+
end
|
29
|
+
|
30
|
+
it "should use the given interpolation parameters" do
|
31
|
+
spec = self
|
32
|
+
configure_attachment do
|
33
|
+
path "#{spec.temporary_directory}/:attachment.:style.jpg"
|
34
|
+
end
|
35
|
+
@thing.photo.interpolate_path(:original, :style => 'STYLE').should == "#{temporary_directory}/photo.STYLE.jpg"
|
36
|
+
end
|
37
|
+
|
38
|
+
it "should use the style's format attribute for the extension by default" do
|
39
|
+
spec = self
|
40
|
+
configure_attachment do
|
41
|
+
style :processed, :format => 'png'
|
42
|
+
path "#{spec.temporary_directory}/:attachment.:style.:extension"
|
43
|
+
end
|
44
|
+
@thing.photo.interpolate_path(:processed, :format => 'png').should == "#{temporary_directory}/photo.processed.png"
|
45
|
+
end
|
46
|
+
|
47
|
+
describe "for the original style" do
|
48
|
+
it "should support the :basename interpolation key if the basename is given" do
|
49
|
+
spec = self
|
50
|
+
configure_attachment do
|
51
|
+
path "#{spec.temporary_directory}/:attachment.:style/:basename"
|
52
|
+
end
|
53
|
+
@thing.photo.interpolate_path(:original, :basename => 'file.xyz').should == "#{temporary_directory}/photo.original/file.xyz"
|
54
|
+
end
|
55
|
+
|
56
|
+
it "should support the :extension interpolation key if the basename is given" do
|
57
|
+
spec = self
|
58
|
+
configure_attachment do
|
59
|
+
path "#{spec.temporary_directory}/:attachment.:style.:extension"
|
60
|
+
end
|
61
|
+
@thing.photo.interpolate_path(:original, :basename => 'file.xyz').should == "#{temporary_directory}/photo.original.xyz"
|
62
|
+
end
|
63
|
+
|
64
|
+
it "should support the :extension interpolation key if the extension is given" do
|
65
|
+
spec = self
|
66
|
+
configure_attachment do
|
67
|
+
path "#{spec.temporary_directory}/:attachment.:style.:extension"
|
68
|
+
end
|
69
|
+
@thing.photo.interpolate_path(:original, :extension => 'xyz').should == "#{temporary_directory}/photo.original.xyz"
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
describe "#interpolate_url" do
|
75
|
+
it "should return the url that the given style name would be found at" do
|
76
|
+
spec = self
|
77
|
+
configure_attachment do
|
78
|
+
url "/:attachment.:style.jpg"
|
79
|
+
end
|
80
|
+
@thing.photo.interpolate_url(:original).should == "/photo.original.jpg"
|
81
|
+
end
|
82
|
+
|
83
|
+
it "should use the given interpolation parameters" do
|
84
|
+
spec = self
|
85
|
+
configure_attachment do
|
86
|
+
url "/:attachment.:style.jpg"
|
87
|
+
end
|
88
|
+
@thing.photo.interpolate_url(:original, :style => 'STYLE').should == "/photo.STYLE.jpg"
|
89
|
+
end
|
90
|
+
|
91
|
+
it "should use the style's format attribute for the extension by default" do
|
92
|
+
spec = self
|
93
|
+
configure_attachment do
|
94
|
+
style :processed, :format => 'png'
|
95
|
+
url "/:attachment.:style.:extension"
|
96
|
+
end
|
97
|
+
@thing.photo.interpolate_url(:processed).should == "/photo.processed.png"
|
98
|
+
end
|
99
|
+
|
100
|
+
describe "for the original style" do
|
101
|
+
it "should support the :basename interpolation key if the basename is given" do
|
102
|
+
spec = self
|
103
|
+
configure_attachment do
|
104
|
+
url "/:attachment.:style/:basename"
|
105
|
+
end
|
106
|
+
@thing.photo.interpolate_url(:original, :basename => 'file.xyz').should == "/photo.original/file.xyz"
|
107
|
+
end
|
108
|
+
|
109
|
+
it "should support the :extension interpolation key if the basename is given" do
|
110
|
+
spec = self
|
111
|
+
configure_attachment do
|
112
|
+
url "/:attachment.:style.:extension"
|
113
|
+
end
|
114
|
+
@thing.photo.interpolate_url(:original, :basename => 'file.xyz').should == "/photo.original.xyz"
|
115
|
+
end
|
116
|
+
|
117
|
+
it "should support the :extension interpolation key if the extension is given" do
|
118
|
+
spec = self
|
119
|
+
configure_attachment do
|
120
|
+
url "/:attachment.:style.:extension"
|
121
|
+
end
|
122
|
+
@thing.photo.interpolate_url(:original, :extension => 'xyz').should == "/photo.original.xyz"
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
@@ -0,0 +1,137 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Attachment::Pdf do
|
4
|
+
use_model_class(:Thing,
|
5
|
+
:attachment_file_name => :string,
|
6
|
+
:attachment_width => :integer,
|
7
|
+
:attachment_height => :integer,
|
8
|
+
:attachment_aspect_ratio => :float,
|
9
|
+
:attachment_dimensions => :string)
|
10
|
+
|
11
|
+
before do
|
12
|
+
Thing.has_attachment :attachment do
|
13
|
+
style :double, :size => '1224x1584'
|
14
|
+
style :filled, :size => '500x500', :filled => true
|
15
|
+
style :unfilled, :size => '1000x1000'
|
16
|
+
default_style :double
|
17
|
+
end
|
18
|
+
@thing = Thing.new(:attachment => test_file)
|
19
|
+
end
|
20
|
+
|
21
|
+
def test_file
|
22
|
+
path = "#{temporary_directory}/test.pdf"
|
23
|
+
FileUtils.cp("#{ROOT}/spec/data/test.pdf", path)
|
24
|
+
autoclose open(path)
|
25
|
+
end
|
26
|
+
|
27
|
+
def configure(&block)
|
28
|
+
Thing.attachment_reflections[:attachment].configure(&block)
|
29
|
+
end
|
30
|
+
|
31
|
+
describe "#process" do
|
32
|
+
it "should be processed with ImageMagick by default" do
|
33
|
+
context = nil
|
34
|
+
configure do
|
35
|
+
style :output
|
36
|
+
process :on => :event do
|
37
|
+
context = self
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
@thing.attachment.process(:event)
|
42
|
+
context.should be_a(Processor::ImageMagick)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
describe "#dimensions" do
|
47
|
+
it "should return 1x1 if the style is missing" do
|
48
|
+
Thing.attachment_reflections[:attachment].configure do
|
49
|
+
detect_type_by{:pdf}
|
50
|
+
end
|
51
|
+
@thing.save.should be_true
|
52
|
+
File.unlink(@thing.attachment.path(:original))
|
53
|
+
@thing = Thing.find(@thing.id)
|
54
|
+
@thing.attachment.is_a?(Attachment::Pdf) # sanity check
|
55
|
+
@thing.attachment.stream.missing? # sanity check
|
56
|
+
@thing.attachment.dimensions(:original).should == [1, 1]
|
57
|
+
end
|
58
|
+
|
59
|
+
it "should return the width and height of the default style if no style name is given" do
|
60
|
+
@thing.attachment.dimensions.should == [1224, 1584]
|
61
|
+
end
|
62
|
+
|
63
|
+
it "should return the width and height of the given style" do
|
64
|
+
@thing.attachment.dimensions(:original).should == [612, 792]
|
65
|
+
@thing.attachment.dimensions(:double).should == [1224, 1584]
|
66
|
+
end
|
67
|
+
|
68
|
+
it "should return the calculated width according to style filledness" do
|
69
|
+
@thing.attachment.dimensions(:filled).should == [500, 500]
|
70
|
+
@thing.attachment.dimensions(:unfilled).should == [773, 1000]
|
71
|
+
end
|
72
|
+
|
73
|
+
it "should only invoke identify once"
|
74
|
+
it "should log the result"
|
75
|
+
end
|
76
|
+
|
77
|
+
describe "#width" do
|
78
|
+
it "should return the width of the default style if no style name is given" do
|
79
|
+
@thing.attachment.width.should == 1224
|
80
|
+
end
|
81
|
+
|
82
|
+
it "should return the width of the given style" do
|
83
|
+
@thing.attachment.width(:original).should == 612
|
84
|
+
@thing.attachment.width(:double).should == 1224
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
describe "#height" do
|
89
|
+
it "should return the height of the default style if no style name is given" do
|
90
|
+
@thing.attachment.height.should == 1584
|
91
|
+
end
|
92
|
+
|
93
|
+
it "should return the height of the given style" do
|
94
|
+
@thing.attachment.height(:original).should == 792
|
95
|
+
@thing.attachment.height(:double).should == 1584
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
describe "#aspect_ratio" do
|
100
|
+
it "should return the aspect ratio of the default style if no style name is given" do
|
101
|
+
@thing.attachment.aspect_ratio.should be_close(612.0/792, 1e-5)
|
102
|
+
end
|
103
|
+
|
104
|
+
it "should return the aspect ratio of the given style" do
|
105
|
+
@thing.attachment.aspect_ratio(:original).should be_close(612.0/792, 1e-5)
|
106
|
+
@thing.attachment.aspect_ratio(:filled).should be_close(1, 1e-5)
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
describe "storable attributes" do
|
111
|
+
it "should set the stored attributes on assignment" do
|
112
|
+
@thing.attachment_width.should == 612
|
113
|
+
@thing.attachment_height.should == 792
|
114
|
+
@thing.attachment_aspect_ratio.should be_close(612.0/792, 1e-5)
|
115
|
+
@thing.attachment_dimensions.should == '612x792'
|
116
|
+
end
|
117
|
+
|
118
|
+
describe "after roundtripping through the database" do
|
119
|
+
before do
|
120
|
+
@thing.save
|
121
|
+
@thing = Thing.find(@thing.id)
|
122
|
+
end
|
123
|
+
|
124
|
+
it "should restore the stored attributes" do
|
125
|
+
@thing.attachment_width.should == 612
|
126
|
+
@thing.attachment_height.should == 792
|
127
|
+
@thing.attachment_aspect_ratio.should be_close(612.0/792, 1e-5)
|
128
|
+
@thing.attachment_dimensions.should == '612x792'
|
129
|
+
end
|
130
|
+
|
131
|
+
it "should recalculate the dimensions correctly" do
|
132
|
+
@thing.attachment.dimensions(:filled).should == [500, 500]
|
133
|
+
@thing.attachment.dimensions(:unfilled).should == [773, 1000]
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
@@ -0,0 +1,176 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Attachment::Video do
|
4
|
+
use_model_class(:Thing,
|
5
|
+
:video_file_name => :string,
|
6
|
+
:video_width => :integer,
|
7
|
+
:video_height => :integer,
|
8
|
+
:video_aspect_ratio => :float,
|
9
|
+
:video_dimensions => :string,
|
10
|
+
:video_duration => :string)
|
11
|
+
|
12
|
+
before do
|
13
|
+
Thing.has_attachment :video do
|
14
|
+
# original video is 640x480.
|
15
|
+
style :half, :size => '320x240'
|
16
|
+
style :filled, :size => '60x60', :filled => true
|
17
|
+
style :unfilled, :size => '120x120'
|
18
|
+
default_style :half
|
19
|
+
end
|
20
|
+
@thing = Thing.new(:video => test_file)
|
21
|
+
end
|
22
|
+
|
23
|
+
def test_file
|
24
|
+
path = "#{temporary_directory}/test.mov"
|
25
|
+
FileUtils.cp("#{ROOT}/spec/data/test.mov", path)
|
26
|
+
autoclose open(path)
|
27
|
+
end
|
28
|
+
|
29
|
+
def run(command)
|
30
|
+
`#{command}`
|
31
|
+
$?.success? or
|
32
|
+
raise "command failed: #{command}"
|
33
|
+
end
|
34
|
+
|
35
|
+
describe "#dimensions" do
|
36
|
+
it "should return 2x2 if the style is missing" do
|
37
|
+
Thing.attachment_reflections[:video].configure do
|
38
|
+
detect_type_by{:video}
|
39
|
+
end
|
40
|
+
@thing.save.should be_true
|
41
|
+
File.unlink(@thing.video.path(:original))
|
42
|
+
@thing = Thing.find(@thing.id)
|
43
|
+
@thing.video.is_a?(Attachment::Video) # sanity check
|
44
|
+
@thing.video.stream.missing? # sanity check
|
45
|
+
@thing.video.dimensions(:original).should == [2, 2]
|
46
|
+
end
|
47
|
+
|
48
|
+
it "should return the width and height of the default style if no style name is given" do
|
49
|
+
@thing.video.dimensions.should == [320, 240]
|
50
|
+
end
|
51
|
+
|
52
|
+
it "should return the width and height of the given style" do
|
53
|
+
@thing.video.dimensions(:original).should == [640, 480]
|
54
|
+
@thing.video.dimensions(:half).should == [320, 240]
|
55
|
+
end
|
56
|
+
|
57
|
+
it "should return the calculated width according to style filledness" do
|
58
|
+
@thing.video.dimensions(:filled).should == [60, 60]
|
59
|
+
@thing.video.dimensions(:unfilled).should == [120, 90]
|
60
|
+
end
|
61
|
+
|
62
|
+
it "should round calculated dimensions down to the nearest multiple of 2" do
|
63
|
+
# TODO: ick!
|
64
|
+
Thing.attachment_reflections[:video].styles[:filled][:size] = '59x59'
|
65
|
+
@thing.video.dimensions(:filled).should == [58, 58]
|
66
|
+
end
|
67
|
+
|
68
|
+
it "should only invoke ffmpeg once"
|
69
|
+
it "should log the result"
|
70
|
+
end
|
71
|
+
|
72
|
+
describe "#width" do
|
73
|
+
it "should return the width of the default style if no style name is given" do
|
74
|
+
@thing.video.width.should == 320
|
75
|
+
end
|
76
|
+
|
77
|
+
it "should return the width of the given style" do
|
78
|
+
@thing.video.width(:original).should == 640
|
79
|
+
@thing.video.width(:half).should == 320
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
describe "#height" do
|
84
|
+
it "should return the height of the default style if no style name is given" do
|
85
|
+
@thing.video.height.should == 240
|
86
|
+
end
|
87
|
+
|
88
|
+
it "should return the height of the given style" do
|
89
|
+
@thing.video.height(:original).should == 480
|
90
|
+
@thing.video.height(:half).should == 240
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
describe "#aspect_ratio" do
|
95
|
+
it "should return the aspect ratio of the default style if no style name is given" do
|
96
|
+
@thing.video.aspect_ratio.should be_close(4.0/3, 1e-5)
|
97
|
+
end
|
98
|
+
|
99
|
+
it "should return the aspect ratio of the given style" do
|
100
|
+
@thing.video.aspect_ratio(:original).should be_close(4.0/3, 1e-5)
|
101
|
+
@thing.video.aspect_ratio(:filled).should be_close(1, 1e-5)
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
describe "#duration" do
|
106
|
+
it "should return the duration of the original style if no style name is given" do
|
107
|
+
@thing.video.duration.should == 1.second
|
108
|
+
end
|
109
|
+
|
110
|
+
it "should return the duration of the original style if a style name is given" do
|
111
|
+
@thing.video.duration(:filled).should == 1.second
|
112
|
+
end
|
113
|
+
|
114
|
+
# TODO: make these work instead of the above
|
115
|
+
it "should return the duration of the default style if no style name is given"
|
116
|
+
it "should return the duration of the given style"
|
117
|
+
end
|
118
|
+
|
119
|
+
describe "#video_tracks" do
|
120
|
+
it "should return the video tracks of the original style if no style name is given" do
|
121
|
+
@thing.video.video_tracks.should have(1).video_track
|
122
|
+
@thing.video.video_tracks.first.dimensions.should == [320, 240]
|
123
|
+
end
|
124
|
+
|
125
|
+
it "should return the video tracks of the target style if a style name is given" do
|
126
|
+
@thing.video.video_tracks(:original).should have(1).video_track
|
127
|
+
@thing.video.video_tracks(:original).first.dimensions.should == [640, 480]
|
128
|
+
|
129
|
+
@thing.video.video_tracks(:filled).should have(1).video_track
|
130
|
+
@thing.video.video_tracks(:filled).first.dimensions.should == [60, 60]
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
describe "#audio_tracks" do
|
135
|
+
it "should return the audio tracks of the original style if no style name is given" do
|
136
|
+
@thing.video.video_tracks.should have(1).video_track
|
137
|
+
@thing.video.video_tracks.first.dimensions.should == [320, 240]
|
138
|
+
end
|
139
|
+
|
140
|
+
it "should return the audio tracks of the target style if a style name is given" do
|
141
|
+
@thing.video.video_tracks(:original).should have(1).video_track
|
142
|
+
@thing.video.video_tracks(:original).first.dimensions.should == [640, 480]
|
143
|
+
|
144
|
+
@thing.video.video_tracks(:filled).should have(1).video_track
|
145
|
+
@thing.video.video_tracks(:filled).first.dimensions.should == [60, 60]
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
describe "storable attributes" do
|
150
|
+
it "should set the stored attributes on assignment" do
|
151
|
+
@thing.video_width.should == 640
|
152
|
+
@thing.video_height.should == 480
|
153
|
+
@thing.video_aspect_ratio.should be_close(4.0/3, 1e-5)
|
154
|
+
@thing.video_dimensions.should == '640x480'
|
155
|
+
end
|
156
|
+
|
157
|
+
describe "after roundtripping through the database" do
|
158
|
+
before do
|
159
|
+
@thing.save
|
160
|
+
@thing = Thing.find(@thing.id)
|
161
|
+
end
|
162
|
+
|
163
|
+
it "should restore the stored attributes" do
|
164
|
+
@thing.video_width.should == 640
|
165
|
+
@thing.video_height.should == 480
|
166
|
+
@thing.video_aspect_ratio.should be_close(4.0/3, 1e-5)
|
167
|
+
@thing.video_dimensions.should == '640x480'
|
168
|
+
end
|
169
|
+
|
170
|
+
it "should recalculate the dimensions correctly" do
|
171
|
+
@thing.video.dimensions(:filled).should == [60, 60]
|
172
|
+
@thing.video.dimensions(:unfilled).should == [120, 90]
|
173
|
+
end
|
174
|
+
end
|
175
|
+
end
|
176
|
+
end
|