image_optim 0.22.1 → 0.23.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.
- checksums.yaml +8 -8
- data/.appveyor.yml +95 -0
- data/.rubocop.yml +3 -0
- data/.travis.yml +27 -22
- data/CHANGELOG.markdown +10 -0
- data/CONTRIBUTING.markdown +2 -1
- data/Gemfile +1 -1
- data/README.markdown +10 -2
- data/image_optim.gemspec +4 -4
- data/lib/image_optim.rb +32 -16
- data/lib/image_optim/bin_resolver/bin.rb +11 -4
- data/lib/image_optim/cache.rb +71 -0
- data/lib/image_optim/cache_path.rb +16 -0
- data/lib/image_optim/config.rb +12 -2
- data/lib/image_optim/handler.rb +1 -1
- data/lib/image_optim/image_meta.rb +5 -10
- data/lib/image_optim/optimized_path.rb +25 -0
- data/lib/image_optim/path.rb +70 -0
- data/lib/image_optim/runner/option_parser.rb +13 -0
- data/lib/image_optim/worker.rb +5 -8
- data/lib/image_optim/worker/class_methods.rb +3 -1
- data/lib/image_optim/worker/jpegoptim.rb +3 -0
- data/lib/image_optim/worker/jpegrecompress.rb +3 -0
- data/lib/image_optim/worker/pngquant.rb +3 -0
- data/script/worker_analysis +10 -9
- data/spec/image_optim/bin_resolver/comparable_condition_spec.rb +1 -1
- data/spec/image_optim/bin_resolver/simple_version_spec.rb +48 -40
- data/spec/image_optim/bin_resolver_spec.rb +190 -172
- data/spec/image_optim/cache_path_spec.rb +59 -0
- data/spec/image_optim/cache_spec.rb +159 -0
- data/spec/image_optim/cmd_spec.rb +11 -7
- data/spec/image_optim/config_spec.rb +92 -71
- data/spec/image_optim/handler_spec.rb +3 -6
- data/spec/image_optim/image_meta_spec.rb +61 -0
- data/spec/image_optim/optimized_path_spec.rb +58 -0
- data/spec/image_optim/option_helpers_spec.rb +25 -0
- data/spec/image_optim/path_spec.rb +105 -0
- data/spec/image_optim/railtie_spec.rb +6 -6
- data/spec/image_optim/runner/glob_helpers_spec.rb +2 -6
- data/spec/image_optim/runner/option_parser_spec.rb +3 -3
- data/spec/image_optim/space_spec.rb +16 -18
- data/spec/image_optim/worker/optipng_spec.rb +3 -3
- data/spec/image_optim/worker/pngquant_spec.rb +47 -7
- data/spec/image_optim/worker_spec.rb +114 -17
- data/spec/image_optim_spec.rb +58 -69
- data/spec/images/broken_jpeg +1 -0
- data/spec/spec_helper.rb +40 -10
- metadata +30 -8
- data/lib/image_optim/image_path.rb +0 -68
- data/spec/image_optim/image_path_spec.rb +0 -54
@@ -6,12 +6,36 @@ describe ImageOptim::Worker do
|
|
6
6
|
before do
|
7
7
|
stub_const('Worker', ImageOptim::Worker)
|
8
8
|
stub_const('BinResolver', ImageOptim::BinResolver)
|
9
|
+
|
10
|
+
# don't add to list of wokers
|
11
|
+
allow(ImageOptim::Worker).to receive(:inherited)
|
12
|
+
end
|
13
|
+
|
14
|
+
describe '#initialize' do
|
15
|
+
it 'expects first argument to be an instanace of ImageOptim' do
|
16
|
+
expect do
|
17
|
+
Worker.new(double)
|
18
|
+
end.to raise_error ArgumentError
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
describe '#options' do
|
23
|
+
it 'returns a Hash with options' do
|
24
|
+
worker_class = Class.new(Worker) do
|
25
|
+
option(:one, 1, 'One')
|
26
|
+
option(:two, 2, 'Two')
|
27
|
+
option(:three, 3, 'Three')
|
28
|
+
end
|
29
|
+
|
30
|
+
worker = worker_class.new(ImageOptim.new, :three => '...')
|
31
|
+
|
32
|
+
expect(worker.options).to eq(:one => 1, :two => 2, :three => '...')
|
33
|
+
end
|
9
34
|
end
|
10
35
|
|
11
|
-
describe
|
36
|
+
describe '#optimize' do
|
12
37
|
it 'raises NotImplementedError' do
|
13
|
-
|
14
|
-
worker = Worker.new(image_optim, {})
|
38
|
+
worker = Worker.new(ImageOptim.new, {})
|
15
39
|
|
16
40
|
expect do
|
17
41
|
worker.optimize(double, double)
|
@@ -19,7 +43,50 @@ describe ImageOptim::Worker do
|
|
19
43
|
end
|
20
44
|
end
|
21
45
|
|
22
|
-
describe
|
46
|
+
describe '#image_formats' do
|
47
|
+
{
|
48
|
+
'GifOptim' => :gif,
|
49
|
+
'JpegOptim' => :jpeg,
|
50
|
+
'PngOptim' => :png,
|
51
|
+
'SvgOptim' => :svg,
|
52
|
+
}.each do |class_name, image_format|
|
53
|
+
it "detects if class name contains #{image_format}" do
|
54
|
+
worker = stub_const(class_name, Class.new(Worker)).new(ImageOptim.new)
|
55
|
+
expect(worker.image_formats).to eq([image_format])
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
it 'fails if class name does not contain known type' do
|
60
|
+
worker = stub_const('TiffOptim', Class.new(Worker)).new(ImageOptim.new)
|
61
|
+
expect{ worker.image_formats }.to raise_error(/can't guess/)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
describe '#inspect' do
|
66
|
+
it 'returns inspect String containing options' do
|
67
|
+
stub_const('DefOptim', Class.new(Worker) do
|
68
|
+
option(:one, 1, 'One')
|
69
|
+
option(:two, 2, 'Two')
|
70
|
+
option(:three, 3, 'Three')
|
71
|
+
end)
|
72
|
+
|
73
|
+
worker = DefOptim.new(ImageOptim.new, :three => '...')
|
74
|
+
|
75
|
+
expect(worker.inspect).to eq('#<DefOptim @one=1, @two=2, @three="...">')
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
describe '.inherited' do
|
80
|
+
it 'adds subclasses to klasses' do
|
81
|
+
base_class = Class.new{ extend ImageOptim::Worker::ClassMethods }
|
82
|
+
expect(base_class.klasses.to_a).to eq([])
|
83
|
+
|
84
|
+
worker_class = Class.new(base_class)
|
85
|
+
expect(base_class.klasses.to_a).to eq([worker_class])
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
describe '.create_all_by_format' do
|
23
90
|
it 'passes arguments to create_all' do
|
24
91
|
image_optim = double
|
25
92
|
options_proc = proc{ true }
|
@@ -52,17 +119,21 @@ describe ImageOptim::Worker do
|
|
52
119
|
end
|
53
120
|
end
|
54
121
|
|
55
|
-
describe
|
122
|
+
describe '.create_all' do
|
56
123
|
def worker_double(override = {})
|
57
124
|
stubs = {:resolve_used_bins! => nil, :run_order => 0}.merge(override)
|
58
125
|
instance_double(Worker, stubs)
|
59
126
|
end
|
60
127
|
|
128
|
+
def worker_class_doubles(workers)
|
129
|
+
workers.map{ |worker| class_double(Worker, :init => worker) }
|
130
|
+
end
|
131
|
+
|
61
132
|
let(:image_optim){ double(:allow_lossy => false) }
|
62
133
|
|
63
134
|
it 'creates all workers for which options_proc returns true' do
|
64
135
|
workers = Array.new(3){ worker_double }
|
65
|
-
klasses = workers
|
136
|
+
klasses = worker_class_doubles(workers)
|
66
137
|
options_proc = proc do |klass|
|
67
138
|
klass == klasses[1] ? {:disable => true} : {}
|
68
139
|
end
|
@@ -79,7 +150,7 @@ describe ImageOptim::Worker do
|
|
79
150
|
[worker_double, worker_double, worker_double],
|
80
151
|
worker_double,
|
81
152
|
]
|
82
|
-
klasses = workers
|
153
|
+
klasses = worker_class_doubles(workers)
|
83
154
|
|
84
155
|
allow(Worker).to receive(:klasses).and_return(klasses)
|
85
156
|
|
@@ -98,7 +169,7 @@ describe ImageOptim::Worker do
|
|
98
169
|
worker
|
99
170
|
end
|
100
171
|
end
|
101
|
-
let(:klasses){ workers
|
172
|
+
let(:klasses){ worker_class_doubles(workers) }
|
102
173
|
|
103
174
|
before do
|
104
175
|
allow(Worker).to receive(:klasses).and_return(klasses)
|
@@ -136,12 +207,11 @@ describe ImageOptim::Worker do
|
|
136
207
|
end
|
137
208
|
|
138
209
|
it 'orders workers by run_order' do
|
139
|
-
image_optim = double(:allow_lossy => false)
|
140
210
|
run_orders = [10, -10, 0, 0, 0, 10, -10]
|
141
211
|
workers = run_orders.map do |run_order|
|
142
212
|
worker_double(:run_order => run_order)
|
143
213
|
end
|
144
|
-
klasses_list = workers
|
214
|
+
klasses_list = worker_class_doubles(workers)
|
145
215
|
|
146
216
|
[
|
147
217
|
klasses_list,
|
@@ -157,13 +227,43 @@ describe ImageOptim::Worker do
|
|
157
227
|
expect(Worker.create_all(image_optim){ {} }).to eq(expected_order)
|
158
228
|
end
|
159
229
|
end
|
230
|
+
|
231
|
+
describe 'passing allow_lossy' do
|
232
|
+
it 'passes allow_lossy if worker has such attribute' do
|
233
|
+
klasses = worker_class_doubles([worker_double, worker_double])
|
234
|
+
|
235
|
+
allow(Worker).to receive(:klasses).and_return(klasses)
|
236
|
+
|
237
|
+
klasses[0].send(:attr_reader, :allow_lossy)
|
238
|
+
expect(klasses[0]).to receive(:init).
|
239
|
+
with(image_optim, hash_including(:allow_lossy))
|
240
|
+
expect(klasses[1]).to receive(:init).
|
241
|
+
with(image_optim, hash_not_including(:allow_lossy))
|
242
|
+
|
243
|
+
Worker.create_all(image_optim){ {} }
|
244
|
+
end
|
245
|
+
|
246
|
+
it 'allows overriding per worker' do
|
247
|
+
klasses = worker_class_doubles([worker_double, worker_double])
|
248
|
+
options_proc = proc do |klass|
|
249
|
+
klass == klasses[1] ? {:allow_lossy => :b} : {}
|
250
|
+
end
|
251
|
+
|
252
|
+
allow(Worker).to receive(:klasses).and_return(klasses)
|
253
|
+
|
254
|
+
klasses.each{ |klass| klass.send(:attr_reader, :allow_lossy) }
|
255
|
+
expect(klasses[0]).to receive(:init).
|
256
|
+
with(image_optim, hash_including(:allow_lossy => false))
|
257
|
+
expect(klasses[1]).to receive(:init).
|
258
|
+
with(image_optim, hash_including(:allow_lossy => :b))
|
259
|
+
|
260
|
+
Worker.create_all(image_optim, &options_proc)
|
261
|
+
end
|
262
|
+
end
|
160
263
|
end
|
161
264
|
|
162
|
-
describe
|
265
|
+
describe '.option' do
|
163
266
|
it 'runs option block in context of worker' do
|
164
|
-
# don't add Abc to list of wokers
|
165
|
-
allow(ImageOptim::Worker).to receive(:inherited)
|
166
|
-
|
167
267
|
stub_const('Abc', Class.new(Worker) do
|
168
268
|
option(:test, 1, 'Test context') do |_v|
|
169
269
|
some_instance_method
|
@@ -176,9 +276,6 @@ describe ImageOptim::Worker do
|
|
176
276
|
end
|
177
277
|
|
178
278
|
it 'returns instance of OptionDefinition' do
|
179
|
-
# don't add Abc to list of wokers
|
180
|
-
allow(ImageOptim::Worker).to receive(:inherited)
|
181
|
-
|
182
279
|
definition = nil
|
183
280
|
Class.new(Worker) do
|
184
281
|
definition = option(:test, 1, 'Test'){ |v| v }
|
data/spec/image_optim_spec.rb
CHANGED
@@ -5,7 +5,7 @@ require 'tempfile'
|
|
5
5
|
require 'English'
|
6
6
|
|
7
7
|
describe ImageOptim do
|
8
|
-
root_dir = ImageOptim::
|
8
|
+
root_dir = ImageOptim::Path.new(__FILE__).dirname.dirname
|
9
9
|
images_dir = root_dir / 'spec/images'
|
10
10
|
test_images = images_dir.glob('**/*.*').freeze
|
11
11
|
|
@@ -17,15 +17,8 @@ describe ImageOptim do
|
|
17
17
|
include helpers
|
18
18
|
extend helpers
|
19
19
|
|
20
|
-
matcher :be_in_range do |expected|
|
21
|
-
match{ |actual| expected.include?(actual) }
|
22
|
-
end
|
23
|
-
|
24
20
|
before do
|
25
21
|
stub_const('Cmd', ImageOptim::Cmd)
|
26
|
-
|
27
|
-
allow(ImageOptim::Config).to receive(:global).and_return({})
|
28
|
-
allow(ImageOptim::Config).to receive(:local).and_return({})
|
29
22
|
end
|
30
23
|
|
31
24
|
isolated_options_base = {:skip_missing_workers => false}
|
@@ -50,7 +43,7 @@ describe ImageOptim do
|
|
50
43
|
end
|
51
44
|
end
|
52
45
|
|
53
|
-
describe
|
46
|
+
describe '#optimize_image' do
|
54
47
|
define :have_same_data_as do |expected|
|
55
48
|
match{ |actual| actual.binread == expected.binread }
|
56
49
|
end
|
@@ -68,30 +61,28 @@ describe ImageOptim do
|
|
68
61
|
['lossless', base_options, 0],
|
69
62
|
['lossy', base_options.merge(:allow_lossy => true), 0.001],
|
70
63
|
].each do |type, options, max_difference|
|
71
|
-
|
72
|
-
|
64
|
+
it "does it #{type}" do
|
65
|
+
image_optim = ImageOptim.new(options)
|
73
66
|
copies = test_images.map{ |image| temp_copy(image) }
|
74
67
|
pairs = image_optim.optimize_images(copies)
|
75
68
|
test_images.zip(*pairs.transpose).each do |original, copy, optimized|
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
expect(optimized).to be_similar_to(compare_to, max_difference)
|
87
|
-
end
|
69
|
+
expect(copy).to have_same_data_as(original)
|
70
|
+
|
71
|
+
expect(optimized).not_to be_nil
|
72
|
+
expect(optimized).to be_a(ImageOptim::OptimizedPath)
|
73
|
+
expect(optimized).to have_size
|
74
|
+
expect(optimized).to be_smaller_than(original)
|
75
|
+
expect(optimized).not_to have_same_data_as(original)
|
76
|
+
|
77
|
+
compare_to = rotate_images.include?(original) ? rotated : original
|
78
|
+
expect(optimized).to be_similar_to(compare_to, max_difference)
|
88
79
|
end
|
89
80
|
end
|
90
81
|
end
|
91
82
|
end
|
92
83
|
|
93
84
|
it 'ignores text file' do
|
94
|
-
original = ImageOptim::
|
85
|
+
original = ImageOptim::Path.new(__FILE__)
|
95
86
|
copy = temp_copy(original)
|
96
87
|
|
97
88
|
expect(Tempfile).not_to receive(:new)
|
@@ -106,27 +97,27 @@ describe ImageOptim do
|
|
106
97
|
}.each do |type, data|
|
107
98
|
it "ingores broken #{type}" do
|
108
99
|
path = FSPath.temp_file_path
|
109
|
-
path.
|
100
|
+
path.binwrite(data)
|
110
101
|
expect(ImageOptim::ImageMeta).to receive(:warn)
|
111
102
|
expect(ImageOptim.optimize_image(path)).to be_nil
|
112
103
|
end
|
113
104
|
end
|
114
105
|
end
|
115
106
|
|
116
|
-
describe
|
107
|
+
describe '#optimize_image!' do
|
117
108
|
it 'optimizes image and replaces original' do
|
118
109
|
original = double
|
119
110
|
optimized = double(:original_size => 12_345)
|
120
111
|
optimized_wrap = double
|
121
112
|
image_optim = ImageOptim.new
|
122
113
|
|
123
|
-
allow(ImageOptim::
|
114
|
+
allow(ImageOptim::Path).to receive(:convert).
|
124
115
|
with(original).and_return(original)
|
125
116
|
|
126
117
|
expect(image_optim).to receive(:optimize_image).
|
127
118
|
with(original).and_return(optimized)
|
128
119
|
expect(optimized).to receive(:replace).with(original)
|
129
|
-
expect(ImageOptim::
|
120
|
+
expect(ImageOptim::OptimizedPath).to receive(:new).
|
130
121
|
with(original, 12_345).and_return(optimized_wrap)
|
131
122
|
|
132
123
|
expect(image_optim.optimize_image!(original)).to eq(optimized_wrap)
|
@@ -136,18 +127,18 @@ describe ImageOptim do
|
|
136
127
|
original = double
|
137
128
|
image_optim = ImageOptim.new
|
138
129
|
|
139
|
-
allow(ImageOptim::
|
130
|
+
allow(ImageOptim::Path).to receive(:convert).
|
140
131
|
with(original).and_return(original)
|
141
132
|
|
142
133
|
expect(image_optim).to receive(:optimize_image).
|
143
134
|
with(original).and_return(nil)
|
144
|
-
expect(ImageOptim::
|
135
|
+
expect(ImageOptim::OptimizedPath).not_to receive(:new)
|
145
136
|
|
146
137
|
expect(image_optim.optimize_image!(original)).to eq(nil)
|
147
138
|
end
|
148
139
|
end
|
149
140
|
|
150
|
-
describe
|
141
|
+
describe '#optimize_image_data' do
|
151
142
|
it 'create temp file, optimizes image and returns data' do
|
152
143
|
data = double
|
153
144
|
temp = double(:path => double)
|
@@ -155,10 +146,10 @@ describe ImageOptim do
|
|
155
146
|
optimized_data = double
|
156
147
|
image_optim = ImageOptim.new
|
157
148
|
|
158
|
-
allow(ImageOptim::ImageMeta).to receive(:
|
159
|
-
with(data).and_return(
|
149
|
+
allow(ImageOptim::ImageMeta).to receive(:format_for_data).
|
150
|
+
with(data).and_return('xxx')
|
160
151
|
|
161
|
-
expect(ImageOptim::
|
152
|
+
expect(ImageOptim::Path).to receive(:temp_file).and_yield(temp)
|
162
153
|
expect(temp).to receive(:binmode)
|
163
154
|
expect(temp).to receive(:write).with(data)
|
164
155
|
expect(temp).to receive(:close)
|
@@ -174,10 +165,10 @@ describe ImageOptim do
|
|
174
165
|
temp = double(:path => double)
|
175
166
|
image_optim = ImageOptim.new
|
176
167
|
|
177
|
-
allow(ImageOptim::ImageMeta).to receive(:
|
178
|
-
with(data).and_return(
|
168
|
+
allow(ImageOptim::ImageMeta).to receive(:format_for_data).
|
169
|
+
with(data).and_return('xxx')
|
179
170
|
|
180
|
-
expect(ImageOptim::
|
171
|
+
expect(ImageOptim::Path).to receive(:temp_file).and_yield(temp)
|
181
172
|
expect(temp).to receive(:binmode)
|
182
173
|
expect(temp).to receive(:write).with(data)
|
183
174
|
expect(temp).to receive(:close)
|
@@ -191,49 +182,47 @@ describe ImageOptim do
|
|
191
182
|
data = double
|
192
183
|
image_optim = ImageOptim.new
|
193
184
|
|
194
|
-
allow(ImageOptim::ImageMeta).to receive(:
|
195
|
-
with(data).and_return(
|
185
|
+
allow(ImageOptim::ImageMeta).to receive(:format_for_data).
|
186
|
+
with(data).and_return(nil)
|
196
187
|
|
197
|
-
expect(ImageOptim::
|
188
|
+
expect(ImageOptim::Path).not_to receive(:temp_file)
|
198
189
|
expect(image_optim).not_to receive(:optimize_image)
|
199
190
|
|
200
191
|
expect(image_optim.optimize_image_data(data)).to eq(nil)
|
201
192
|
end
|
202
193
|
end
|
203
194
|
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
[src, dst]
|
219
|
-
end
|
220
|
-
expect(image_optim.send(list_method, test_images)).to eq(results)
|
195
|
+
%w[
|
196
|
+
optimize_images
|
197
|
+
optimize_images!
|
198
|
+
optimize_images_data
|
199
|
+
].each do |list_method|
|
200
|
+
describe "##{list_method}" do
|
201
|
+
method = list_method.sub('images', 'image')
|
202
|
+
describe 'without block' do
|
203
|
+
it 'optimizes images and returns array of results' do
|
204
|
+
image_optim = ImageOptim.new
|
205
|
+
results = test_images.map do |src|
|
206
|
+
dst = double
|
207
|
+
expect(image_optim).to receive(method).with(src).and_return(dst)
|
208
|
+
[src, dst]
|
221
209
|
end
|
210
|
+
expect(image_optim.send(list_method, test_images)).to eq(results)
|
222
211
|
end
|
212
|
+
end
|
223
213
|
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
end
|
233
|
-
expect(image_optim.send(list_method, test_images) do |src, dst|
|
234
|
-
[src, dst, :test]
|
235
|
-
end).to eq(results)
|
214
|
+
describe 'given block' do
|
215
|
+
it 'optimizes images, yields path and result for each and '\
|
216
|
+
'returns array of yield results' do
|
217
|
+
image_optim = ImageOptim.new
|
218
|
+
results = test_images.map do |src|
|
219
|
+
dst = double
|
220
|
+
expect(image_optim).to receive(method).with(src).and_return(dst)
|
221
|
+
[src, dst, :test]
|
236
222
|
end
|
223
|
+
expect(image_optim.send(list_method, test_images) do |src, dst|
|
224
|
+
[src, dst, :test]
|
225
|
+
end).to eq(results)
|
237
226
|
end
|
238
227
|
end
|
239
228
|
end
|
@@ -0,0 +1 @@
|
|
1
|
+
��
|
data/spec/spec_helper.rb
CHANGED
@@ -1,18 +1,28 @@
|
|
1
|
-
if ENV['CODECLIMATE_REPO_TOKEN']
|
2
|
-
|
3
|
-
|
4
|
-
CodeClimate::TestReporter.start
|
5
|
-
rescue LoadError => e
|
6
|
-
$stderr.puts "Got following while loading codeclimate-test-reporter: #{e}"
|
7
|
-
end
|
1
|
+
if ENV['CODECLIMATE'] && ENV['CODECLIMATE_REPO_TOKEN']
|
2
|
+
require 'codeclimate-test-reporter'
|
3
|
+
CodeClimate::TestReporter.start
|
8
4
|
end
|
9
5
|
|
6
|
+
require 'image_optim/pack'
|
7
|
+
require 'image_optim/path'
|
8
|
+
|
9
|
+
ENV['PATH'] = [
|
10
|
+
ImageOptim::Pack.path,
|
11
|
+
ENV['PATH'],
|
12
|
+
].compact.join File::PATH_SEPARATOR
|
13
|
+
|
10
14
|
RSpec.configure do |c|
|
11
|
-
c.
|
15
|
+
c.before do
|
16
|
+
stub_const('ImageOptim::Config::GLOBAL_PATH', ImageOptim::Path::NULL)
|
17
|
+
stub_const('ImageOptim::Config::LOCAL_PATH', ImageOptim::Path::NULL)
|
18
|
+
ImageOptim.class_eval{ def pack; end }
|
19
|
+
end
|
20
|
+
|
21
|
+
c.order = :random
|
12
22
|
end
|
13
23
|
|
14
24
|
def flatten_animation(image)
|
15
|
-
if image.
|
25
|
+
if image.image_format == :gif
|
16
26
|
flattened = image.temp_path
|
17
27
|
command = %W[
|
18
28
|
convert
|
@@ -37,7 +47,7 @@ def mepp(image_a, image_b)
|
|
37
47
|
-alpha Background
|
38
48
|
#{coalesce_a.to_s.shellescape}
|
39
49
|
#{coalesce_b.to_s.shellescape}
|
40
|
-
|
50
|
+
#{ImageOptim::Path::NULL}
|
41
51
|
2>&1
|
42
52
|
].join(' ')
|
43
53
|
output = ImageOptim::Cmd.capture(command)
|
@@ -63,3 +73,23 @@ RSpec::Matchers.define :be_similar_to do |expected, max_difference|
|
|
63
73
|
"#{expected}, got normalized root-mean-square error of #{@diff}"
|
64
74
|
end
|
65
75
|
end
|
76
|
+
|
77
|
+
module CapabilityCheckHelpers
|
78
|
+
def any_file_modes_allowed?
|
79
|
+
Tempfile.open 'posix' do |f|
|
80
|
+
File.chmod(0, f.path)
|
81
|
+
File.stat(f.path).mode & 0o777 == 0
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def inodes_supported?
|
86
|
+
File.stat(__FILE__).ino != 0
|
87
|
+
end
|
88
|
+
|
89
|
+
def signals_supported?
|
90
|
+
Process.kill(0, 0)
|
91
|
+
true
|
92
|
+
rescue
|
93
|
+
false
|
94
|
+
end
|
95
|
+
end
|