openstreetmap-image_optim 0.21.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.
- checksums.yaml +7 -0
- data/.gitignore +17 -0
- data/.rubocop.yml +65 -0
- data/.travis.yml +42 -0
- data/CHANGELOG.markdown +272 -0
- data/CONTRIBUTING.markdown +10 -0
- data/Gemfile +9 -0
- data/LICENSE.txt +20 -0
- data/README.markdown +344 -0
- data/Vagrantfile +33 -0
- data/bin/image_optim +28 -0
- data/image_optim.gemspec +29 -0
- data/lib/image_optim.rb +228 -0
- data/lib/image_optim/bin_resolver.rb +144 -0
- data/lib/image_optim/bin_resolver/bin.rb +105 -0
- data/lib/image_optim/bin_resolver/comparable_condition.rb +60 -0
- data/lib/image_optim/bin_resolver/error.rb +6 -0
- data/lib/image_optim/bin_resolver/simple_version.rb +31 -0
- data/lib/image_optim/cmd.rb +49 -0
- data/lib/image_optim/config.rb +205 -0
- data/lib/image_optim/configuration_error.rb +3 -0
- data/lib/image_optim/handler.rb +57 -0
- data/lib/image_optim/hash_helpers.rb +45 -0
- data/lib/image_optim/image_meta.rb +25 -0
- data/lib/image_optim/image_path.rb +68 -0
- data/lib/image_optim/non_negative_integer_range.rb +11 -0
- data/lib/image_optim/option_definition.rb +32 -0
- data/lib/image_optim/option_helpers.rb +17 -0
- data/lib/image_optim/railtie.rb +38 -0
- data/lib/image_optim/runner.rb +139 -0
- data/lib/image_optim/runner/glob_helpers.rb +45 -0
- data/lib/image_optim/runner/option_parser.rb +227 -0
- data/lib/image_optim/space.rb +29 -0
- data/lib/image_optim/true_false_nil.rb +16 -0
- data/lib/image_optim/worker.rb +159 -0
- data/lib/image_optim/worker/advpng.rb +35 -0
- data/lib/image_optim/worker/class_methods.rb +91 -0
- data/lib/image_optim/worker/gifsicle.rb +63 -0
- data/lib/image_optim/worker/jhead.rb +43 -0
- data/lib/image_optim/worker/jpegoptim.rb +58 -0
- data/lib/image_optim/worker/jpegrecompress.rb +44 -0
- data/lib/image_optim/worker/jpegtran.rb +46 -0
- data/lib/image_optim/worker/optipng.rb +45 -0
- data/lib/image_optim/worker/pngcrush.rb +54 -0
- data/lib/image_optim/worker/pngout.rb +38 -0
- data/lib/image_optim/worker/pngquant.rb +51 -0
- data/lib/image_optim/worker/svgo.rb +32 -0
- data/script/template/jquery-2.1.3.min.js +4 -0
- data/script/template/sortable-0.6.0.min.js +2 -0
- data/script/template/worker_analysis.erb +254 -0
- data/script/update_worker_options_in_readme +60 -0
- data/script/worker_analysis +599 -0
- data/spec/image_optim/bin_resolver/comparable_condition_spec.rb +37 -0
- data/spec/image_optim/bin_resolver/simple_version_spec.rb +57 -0
- data/spec/image_optim/bin_resolver_spec.rb +272 -0
- data/spec/image_optim/cmd_spec.rb +66 -0
- data/spec/image_optim/config_spec.rb +217 -0
- data/spec/image_optim/handler_spec.rb +95 -0
- data/spec/image_optim/hash_helpers_spec.rb +76 -0
- data/spec/image_optim/image_path_spec.rb +54 -0
- data/spec/image_optim/railtie_spec.rb +121 -0
- data/spec/image_optim/runner/glob_helpers_spec.rb +25 -0
- data/spec/image_optim/runner/option_parser_spec.rb +99 -0
- data/spec/image_optim/space_spec.rb +25 -0
- data/spec/image_optim/worker_spec.rb +192 -0
- data/spec/image_optim_spec.rb +242 -0
- data/spec/images/comparison.png +0 -0
- data/spec/images/decompressed.jpeg +0 -0
- data/spec/images/icecream.gif +0 -0
- data/spec/images/image.jpg +0 -0
- data/spec/images/invisiblepixels/generate +24 -0
- data/spec/images/invisiblepixels/image.png +0 -0
- data/spec/images/lena.jpg +0 -0
- data/spec/images/orient/0.jpg +0 -0
- data/spec/images/orient/1.jpg +0 -0
- data/spec/images/orient/2.jpg +0 -0
- data/spec/images/orient/3.jpg +0 -0
- data/spec/images/orient/4.jpg +0 -0
- data/spec/images/orient/5.jpg +0 -0
- data/spec/images/orient/6.jpg +0 -0
- data/spec/images/orient/7.jpg +0 -0
- data/spec/images/orient/8.jpg +0 -0
- data/spec/images/orient/generate +23 -0
- data/spec/images/orient/original.jpg +0 -0
- data/spec/images/quant/64.png +0 -0
- data/spec/images/quant/generate +25 -0
- data/spec/images/rails.png +0 -0
- data/spec/images/test.svg +3 -0
- data/spec/images/transparency1.png +0 -0
- data/spec/images/transparency2.png +0 -0
- data/spec/images/vergroessert.jpg +0 -0
- data/spec/spec_helper.rb +64 -0
- data/vendor/jpegrescan +143 -0
- metadata +308 -0
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
require 'image_optim/bin_resolver/comparable_condition'
|
|
3
|
+
|
|
4
|
+
describe ImageOptim::BinResolver::ComparableCondition do
|
|
5
|
+
is = ImageOptim::BinResolver::ComparableCondition.is
|
|
6
|
+
|
|
7
|
+
it 'builds conditions' do
|
|
8
|
+
expect(is.between?(10, 20).method).to eq(:between?)
|
|
9
|
+
expect(is.between?(10, 20).args).to eq([10, 20])
|
|
10
|
+
|
|
11
|
+
expect((is >= 15).method).to eq(:>=)
|
|
12
|
+
expect((is >= 15).args).to eq([15])
|
|
13
|
+
|
|
14
|
+
expect((is < 30).method).to eq(:<)
|
|
15
|
+
expect((is < 30).args).to eq([30])
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
it 'stringifies conditions' do
|
|
19
|
+
expect(is.between?(10, 20).to_s).to eq('10..20')
|
|
20
|
+
expect((is >= 15).to_s).to eq('>= 15')
|
|
21
|
+
expect((is < 30).to_s).to eq('< 30')
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
it 'matches conditions' do
|
|
25
|
+
expect(is.between?(10, 20)).not_to match 9
|
|
26
|
+
expect(is.between?(10, 20)).to match 15
|
|
27
|
+
expect(is.between?(10, 20)).not_to match 21
|
|
28
|
+
|
|
29
|
+
expect(is >= 15).not_to match 14
|
|
30
|
+
expect(is >= 15).to match 15
|
|
31
|
+
expect(is >= 15).to match 16
|
|
32
|
+
|
|
33
|
+
expect(is < 30).to match 29
|
|
34
|
+
expect(is < 30).not_to match 30
|
|
35
|
+
expect(is < 30).not_to match 31
|
|
36
|
+
end
|
|
37
|
+
end
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
require 'image_optim/bin_resolver/simple_version'
|
|
3
|
+
|
|
4
|
+
describe ImageOptim::BinResolver::SimpleVersion do
|
|
5
|
+
helpers = Module.new do
|
|
6
|
+
def v(str)
|
|
7
|
+
ImageOptim::BinResolver::SimpleVersion.new(str)
|
|
8
|
+
end
|
|
9
|
+
end
|
|
10
|
+
include helpers
|
|
11
|
+
extend helpers
|
|
12
|
+
|
|
13
|
+
describe 'compares version 1.17' do
|
|
14
|
+
subject{ v '1.17' }
|
|
15
|
+
|
|
16
|
+
it{ is_expected.to be > '0' }
|
|
17
|
+
it{ is_expected.to be > '0.1' }
|
|
18
|
+
it{ is_expected.to be > '0.9' }
|
|
19
|
+
it{ is_expected.to be > '1.9' }
|
|
20
|
+
it{ is_expected.to be < '1.17.1' }
|
|
21
|
+
it{ is_expected.to be < '1.99' }
|
|
22
|
+
it{ is_expected.to be < '2.1' }
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
describe 'normalization' do
|
|
26
|
+
%w[
|
|
27
|
+
1
|
|
28
|
+
01
|
|
29
|
+
1.0
|
|
30
|
+
1.00
|
|
31
|
+
1.0.0
|
|
32
|
+
1.0.0.0
|
|
33
|
+
].each do |variation|
|
|
34
|
+
it "normalizes #{variation}" do
|
|
35
|
+
expect(v variation).to eq(1)
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
describe 'conversion' do
|
|
41
|
+
it 'converts Integer' do
|
|
42
|
+
expect(v 117).to eq('117')
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
it 'converts Float' do
|
|
46
|
+
expect(v 1.17).to eq('1.17')
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
it 'converts String' do
|
|
50
|
+
expect(v '1.17').to eq('1.17')
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
it 'converts self' do
|
|
54
|
+
expect(v(v 1.17)).to eq('1.17')
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
@@ -0,0 +1,272 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
require 'image_optim/bin_resolver'
|
|
3
|
+
require 'image_optim/cmd'
|
|
4
|
+
|
|
5
|
+
describe ImageOptim::BinResolver do
|
|
6
|
+
def with_env(key, value)
|
|
7
|
+
saved, ENV[key] = ENV[key], value
|
|
8
|
+
yield
|
|
9
|
+
ensure
|
|
10
|
+
ENV[key] = saved
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
before do
|
|
14
|
+
stub_const('BinResolver', ImageOptim::BinResolver)
|
|
15
|
+
stub_const('Bin', BinResolver::Bin)
|
|
16
|
+
stub_const('SimpleVersion', BinResolver::SimpleVersion)
|
|
17
|
+
stub_const('Cmd', ImageOptim::Cmd)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
let(:image_optim){ double(:image_optim, :verbose => false, :pack => false) }
|
|
21
|
+
let(:resolver){ BinResolver.new(image_optim) }
|
|
22
|
+
|
|
23
|
+
describe :full_path do
|
|
24
|
+
def full_path(name)
|
|
25
|
+
resolver.instance_eval{ full_path(name) }
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def command_v(name)
|
|
29
|
+
path = Cmd.capture("sh -c 'command -v #{name}' 2> /dev/null").strip
|
|
30
|
+
path unless path.empty?
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
it 'finds binary in path' do
|
|
34
|
+
with_env 'PATH', 'bin' do
|
|
35
|
+
expect(full_path('image_optim')).
|
|
36
|
+
to eq(File.expand_path('bin/image_optim'))
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
it 'finds bin in vendor' do
|
|
41
|
+
with_env 'PATH', nil do
|
|
42
|
+
expect(full_path('jpegrescan')).
|
|
43
|
+
to eq(File.expand_path('vendor/jpegrescan'))
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
it 'finds bin in pack' do
|
|
48
|
+
allow(image_optim).to receive(:pack).and_return(true)
|
|
49
|
+
stub_const('ImageOptim::Pack', Class.new do
|
|
50
|
+
def self.path
|
|
51
|
+
'script'
|
|
52
|
+
end
|
|
53
|
+
end)
|
|
54
|
+
|
|
55
|
+
with_env 'PATH', nil do
|
|
56
|
+
expect(full_path('update_worker_options_in_readme')).
|
|
57
|
+
to eq(File.expand_path('script/update_worker_options_in_readme'))
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
it 'works with different path separator' do
|
|
62
|
+
stub_const('File::PATH_SEPARATOR', 'O_o')
|
|
63
|
+
with_env 'PATH', 'bin' do
|
|
64
|
+
expect(full_path('image_optim')).
|
|
65
|
+
to eq(File.expand_path('bin/image_optim'))
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
it 'returns nil on failure' do
|
|
70
|
+
with_env 'PATH', 'lib' do
|
|
71
|
+
expect(full_path('image_optim')).to be_nil
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
%w[ls sh which bash image_optim does_not_exist].each do |name|
|
|
76
|
+
it "returns same path as `command -v` for #{name}" do
|
|
77
|
+
expect(full_path(name)).to eq(command_v(name))
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
it 'combines path in order dir:pack:path:vendor' do
|
|
83
|
+
allow(image_optim).to receive(:pack).and_return(true)
|
|
84
|
+
stub_const('ImageOptim::Pack', Class.new do
|
|
85
|
+
def self.path
|
|
86
|
+
'pack_path'
|
|
87
|
+
end
|
|
88
|
+
end)
|
|
89
|
+
allow(resolver).to receive(:dir).and_return('temp_dir')
|
|
90
|
+
|
|
91
|
+
expect(resolver.env_path).to eq([
|
|
92
|
+
'temp_dir',
|
|
93
|
+
'pack_path',
|
|
94
|
+
ENV['PATH'],
|
|
95
|
+
BinResolver::VENDOR_PATH,
|
|
96
|
+
].join(':'))
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
it 'resolves bin in path and returns instance of Bin' do
|
|
100
|
+
with_env 'LS_BIN', nil do
|
|
101
|
+
expect(FSPath).not_to receive(:temp_dir)
|
|
102
|
+
expect(resolver).to receive(:full_path).with(:ls).and_return('/bin/ls')
|
|
103
|
+
bin = double
|
|
104
|
+
expect(Bin).to receive(:new).with(:ls, '/bin/ls').and_return(bin)
|
|
105
|
+
expect(bin).to receive(:check!).once
|
|
106
|
+
expect(bin).to receive(:check_fail!).exactly(5).times
|
|
107
|
+
|
|
108
|
+
5.times do
|
|
109
|
+
expect(resolver.resolve!(:ls)).to eq(bin)
|
|
110
|
+
end
|
|
111
|
+
expect(resolver.env_path).to eq([
|
|
112
|
+
ENV['PATH'],
|
|
113
|
+
BinResolver::VENDOR_PATH,
|
|
114
|
+
].join(':'))
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
it 'raises on failure to resolve bin' do
|
|
119
|
+
with_env 'LS_BIN', nil do
|
|
120
|
+
expect(FSPath).not_to receive(:temp_dir)
|
|
121
|
+
expect(resolver).to receive(:full_path).with(:ls).and_return(nil)
|
|
122
|
+
expect(Bin).not_to receive(:new)
|
|
123
|
+
|
|
124
|
+
5.times do
|
|
125
|
+
expect do
|
|
126
|
+
resolver.resolve!(:ls)
|
|
127
|
+
end.to raise_error BinResolver::BinNotFound
|
|
128
|
+
end
|
|
129
|
+
expect(resolver.env_path).to eq([
|
|
130
|
+
ENV['PATH'],
|
|
131
|
+
BinResolver::VENDOR_PATH,
|
|
132
|
+
].join(':'))
|
|
133
|
+
end
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
it 'resolves bin specified in ENV' do
|
|
137
|
+
path = 'bin/image_optim'
|
|
138
|
+
with_env 'IMAGE_OPTIM_BIN', path do
|
|
139
|
+
tmpdir = double(:tmpdir, :to_str => 'tmpdir')
|
|
140
|
+
symlink = double(:symlink)
|
|
141
|
+
|
|
142
|
+
expect(FSPath).to receive(:temp_dir).
|
|
143
|
+
once.and_return(tmpdir)
|
|
144
|
+
expect(tmpdir).to receive(:/).
|
|
145
|
+
with(:image_optim).once.and_return(symlink)
|
|
146
|
+
expect(symlink).to receive(:make_symlink).
|
|
147
|
+
with(File.expand_path(path)).once
|
|
148
|
+
|
|
149
|
+
expect(resolver).not_to receive(:full_path)
|
|
150
|
+
bin = double
|
|
151
|
+
expect(Bin).to receive(:new).
|
|
152
|
+
with(:image_optim, File.expand_path(path)).and_return(bin)
|
|
153
|
+
expect(bin).to receive(:check!).once
|
|
154
|
+
expect(bin).to receive(:check_fail!).exactly(5).times
|
|
155
|
+
|
|
156
|
+
at_exit_blocks = []
|
|
157
|
+
expect(resolver).to receive(:at_exit).once do |&block|
|
|
158
|
+
at_exit_blocks.unshift(block)
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
5.times do
|
|
162
|
+
resolver.resolve!(:image_optim)
|
|
163
|
+
end
|
|
164
|
+
expect(resolver.env_path).to eq([
|
|
165
|
+
tmpdir,
|
|
166
|
+
ENV['PATH'],
|
|
167
|
+
BinResolver::VENDOR_PATH,
|
|
168
|
+
].join(':'))
|
|
169
|
+
|
|
170
|
+
expect(FileUtils).to receive(:remove_entry_secure).with(tmpdir)
|
|
171
|
+
at_exit_blocks.each(&:call)
|
|
172
|
+
end
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
{
|
|
176
|
+
'some/path/does/not/exist' => 'doesn\'t exist',
|
|
177
|
+
'.' => 'is not a file',
|
|
178
|
+
__FILE__ => 'is not executable',
|
|
179
|
+
}.each do |path, error_message|
|
|
180
|
+
it "raises when bin specified in ENV #{error_message}" do
|
|
181
|
+
with_env 'IMAGE_OPTIM_BIN', path do
|
|
182
|
+
expect(FSPath).not_to receive(:temp_dir)
|
|
183
|
+
expect(resolver).not_to receive(:at_exit)
|
|
184
|
+
|
|
185
|
+
5.times do
|
|
186
|
+
expect do
|
|
187
|
+
resolver.resolve!(:image_optim)
|
|
188
|
+
end.to raise_error RuntimeError, /#{Regexp.escape(error_message)}/
|
|
189
|
+
end
|
|
190
|
+
expect(resolver.env_path).to eq([
|
|
191
|
+
ENV['PATH'],
|
|
192
|
+
BinResolver::VENDOR_PATH,
|
|
193
|
+
].join(':'))
|
|
194
|
+
end
|
|
195
|
+
end
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
it 'resolves bin only once, but checks every time' do
|
|
199
|
+
with_env 'LS_BIN', nil do
|
|
200
|
+
expect(resolver).to receive(:full_path).once.with(:ls) do
|
|
201
|
+
sleep 0.1
|
|
202
|
+
'/bin/ls'
|
|
203
|
+
end
|
|
204
|
+
bin = double
|
|
205
|
+
expect(Bin).to receive(:new).once.with(:ls, '/bin/ls').and_return(bin)
|
|
206
|
+
|
|
207
|
+
count = 0
|
|
208
|
+
mutex = Mutex.new
|
|
209
|
+
allow(bin).to receive(:check!).once
|
|
210
|
+
allow(bin).to receive(:check_fail!){ mutex.synchronize{ count += 1 } }
|
|
211
|
+
|
|
212
|
+
10.times.map do
|
|
213
|
+
Thread.new do
|
|
214
|
+
resolver.resolve!(:ls)
|
|
215
|
+
end
|
|
216
|
+
end.each(&:join)
|
|
217
|
+
|
|
218
|
+
expect(count).to eq(10)
|
|
219
|
+
end
|
|
220
|
+
end
|
|
221
|
+
|
|
222
|
+
describe 'checking version' do
|
|
223
|
+
before do
|
|
224
|
+
allow(resolver).to receive(:full_path){ |name| "/bin/#{name}" }
|
|
225
|
+
end
|
|
226
|
+
|
|
227
|
+
it 'raises every time if did not get bin version' do
|
|
228
|
+
with_env 'PNGCRUSH_BIN', nil do
|
|
229
|
+
bin = Bin.new(:pngcrush, '/bin/pngcrush')
|
|
230
|
+
|
|
231
|
+
expect(Bin).to receive(:new).and_return(bin)
|
|
232
|
+
allow(bin).to receive(:version).and_return(nil)
|
|
233
|
+
|
|
234
|
+
5.times do
|
|
235
|
+
expect do
|
|
236
|
+
resolver.resolve!(:pngcrush)
|
|
237
|
+
end.to raise_error Bin::UnknownVersion
|
|
238
|
+
end
|
|
239
|
+
end
|
|
240
|
+
end
|
|
241
|
+
|
|
242
|
+
it 'raises every time on detection of misbehaving version' do
|
|
243
|
+
with_env 'PNGCRUSH_BIN', nil do
|
|
244
|
+
bin = Bin.new(:pngcrush, '/bin/pngcrush')
|
|
245
|
+
|
|
246
|
+
expect(Bin).to receive(:new).and_return(bin)
|
|
247
|
+
allow(bin).to receive(:version).and_return(SimpleVersion.new('1.7.60'))
|
|
248
|
+
|
|
249
|
+
5.times do
|
|
250
|
+
expect do
|
|
251
|
+
resolver.resolve!(:pngcrush)
|
|
252
|
+
end.to raise_error Bin::BadVersion
|
|
253
|
+
end
|
|
254
|
+
end
|
|
255
|
+
end
|
|
256
|
+
|
|
257
|
+
it 'warns once on detection of problematic version' do
|
|
258
|
+
with_env 'ADVPNG_BIN', nil do
|
|
259
|
+
bin = Bin.new(:advpng, '/bin/advpng')
|
|
260
|
+
|
|
261
|
+
expect(Bin).to receive(:new).and_return(bin)
|
|
262
|
+
allow(bin).to receive(:version).and_return(SimpleVersion.new('1.15'))
|
|
263
|
+
|
|
264
|
+
expect(bin).to receive(:warn).once
|
|
265
|
+
|
|
266
|
+
5.times do
|
|
267
|
+
resolver.resolve!(:pngcrush)
|
|
268
|
+
end
|
|
269
|
+
end
|
|
270
|
+
end
|
|
271
|
+
end
|
|
272
|
+
end
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
require 'image_optim/cmd'
|
|
3
|
+
|
|
4
|
+
describe ImageOptim::Cmd do
|
|
5
|
+
before do
|
|
6
|
+
stub_const('Cmd', ImageOptim::Cmd)
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def expect_int_exception(&block)
|
|
10
|
+
expect(&block).to raise_error(SignalException) do |error|
|
|
11
|
+
expect(error.message.to_s).to match(/INT|#{Signal.list['INT']}/)
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
describe :run do
|
|
16
|
+
it 'calls system and returns result' do
|
|
17
|
+
status = double
|
|
18
|
+
expect(Cmd).to receive(:system).with('cmd', 'arg').and_return(status)
|
|
19
|
+
allow(Cmd).to receive(:check_status!)
|
|
20
|
+
expect(Cmd.run('cmd', 'arg')).to eq(status)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
it 'returns process success status' do
|
|
24
|
+
expect(Cmd.run('sh -c exit\ 0')).to eq(true)
|
|
25
|
+
expect($CHILD_STATUS.exitstatus).to eq(0)
|
|
26
|
+
|
|
27
|
+
expect(Cmd.run('sh -c exit\ 1')).to eq(false)
|
|
28
|
+
expect($CHILD_STATUS.exitstatus).to eq(1)
|
|
29
|
+
|
|
30
|
+
expect(Cmd.run('sh -c exit\ 66')).to eq(false)
|
|
31
|
+
expect($CHILD_STATUS.exitstatus).to eq(66)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
it 'raises SignalException if process terminates after signal' do
|
|
35
|
+
expect_int_exception do
|
|
36
|
+
Cmd.run('kill -s INT $$')
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
describe :capture do
|
|
42
|
+
it 'calls ` and returns result' do
|
|
43
|
+
output = double
|
|
44
|
+
expect(Cmd).to receive(:`).with('cmd arg arg+').and_return(output)
|
|
45
|
+
allow(Cmd).to receive(:check_status!)
|
|
46
|
+
expect(Cmd.capture('cmd arg arg+')).to eq(output)
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
it 'returns output' do
|
|
50
|
+
expect(Cmd.capture('echo test')).to eq("test\n")
|
|
51
|
+
expect($CHILD_STATUS.exitstatus).to eq(0)
|
|
52
|
+
|
|
53
|
+
expect(Cmd.capture('printf more; sh -c exit\ 1')).to eq('more')
|
|
54
|
+
expect($CHILD_STATUS.exitstatus).to eq(1)
|
|
55
|
+
|
|
56
|
+
expect(Cmd.capture('sh -c exit\ 66')).to eq('')
|
|
57
|
+
expect($CHILD_STATUS.exitstatus).to eq(66)
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
it 'raises SignalException if process terminates after signal' do
|
|
61
|
+
expect_int_exception do
|
|
62
|
+
Cmd.capture('kill -s INT $$')
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
require 'image_optim/config'
|
|
3
|
+
|
|
4
|
+
describe ImageOptim::Config do
|
|
5
|
+
before do
|
|
6
|
+
stub_const('IOConfig', ImageOptim::Config)
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
describe :assert_no_unused_options! do
|
|
10
|
+
before do
|
|
11
|
+
allow(IOConfig).to receive(:read_options).and_return({})
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
it 'does not raise when no unused options' do
|
|
15
|
+
config = IOConfig.new({})
|
|
16
|
+
config.assert_no_unused_options!
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
it 'raises when there are unused options' do
|
|
20
|
+
config = IOConfig.new(:unused => true)
|
|
21
|
+
expect do
|
|
22
|
+
config.assert_no_unused_options!
|
|
23
|
+
end.to raise_error(ImageOptim::ConfigurationError)
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
describe :nice do
|
|
28
|
+
before do
|
|
29
|
+
allow(IOConfig).to receive(:read_options).and_return({})
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
it 'is 10 by default' do
|
|
33
|
+
config = IOConfig.new({})
|
|
34
|
+
expect(config.nice).to eq(10)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
it 'is 0 if disabled' do
|
|
38
|
+
config = IOConfig.new(:nice => false)
|
|
39
|
+
expect(config.nice).to eq(0)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
it 'converts value to number' do
|
|
43
|
+
config = IOConfig.new(:nice => '13')
|
|
44
|
+
expect(config.nice).to eq(13)
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
describe :threads do
|
|
49
|
+
before do
|
|
50
|
+
allow(IOConfig).to receive(:read_options).and_return({})
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
it 'is processor_count by default' do
|
|
54
|
+
config = IOConfig.new({})
|
|
55
|
+
allow(config).to receive(:processor_count).and_return(13)
|
|
56
|
+
expect(config.threads).to eq(13)
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
it 'is 1 if disabled' do
|
|
60
|
+
config = IOConfig.new(:threads => false)
|
|
61
|
+
expect(config.threads).to eq(1)
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
it 'converts value to number' do
|
|
65
|
+
config = IOConfig.new(:threads => '616')
|
|
66
|
+
expect(config.threads).to eq(616)
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
describe :for_worker do
|
|
71
|
+
before do
|
|
72
|
+
allow(IOConfig).to receive(:read_options).and_return({})
|
|
73
|
+
stub_const('Abc', Class.new do
|
|
74
|
+
def self.bin_sym
|
|
75
|
+
:abc
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def image_formats
|
|
79
|
+
[]
|
|
80
|
+
end
|
|
81
|
+
end)
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
it 'returns empty hash by default' do
|
|
85
|
+
config = IOConfig.new({})
|
|
86
|
+
expect(config.for_worker(Abc)).to eq({})
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
it 'returns passed hash' do
|
|
90
|
+
config = IOConfig.new(:abc => {:option => true})
|
|
91
|
+
expect(config.for_worker(Abc)).to eq(:option => true)
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
it 'returns {:disable => true} for false' do
|
|
95
|
+
config = IOConfig.new(:abc => false)
|
|
96
|
+
expect(config.for_worker(Abc)).to eq(:disable => true)
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
it 'raises on unknown option' do
|
|
100
|
+
config = IOConfig.new(:abc => 13)
|
|
101
|
+
expect do
|
|
102
|
+
config.for_worker(Abc)
|
|
103
|
+
end.to raise_error(ImageOptim::ConfigurationError)
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
describe 'config' do
|
|
108
|
+
it 'reads options from default locations' do
|
|
109
|
+
expect(IOConfig).to receive(:read_options).
|
|
110
|
+
with(IOConfig::GLOBAL_PATH).and_return(:a => 1, :b => 2, :c => 3)
|
|
111
|
+
expect(IOConfig).to receive(:read_options).
|
|
112
|
+
with(IOConfig::LOCAL_PATH).and_return(:a => 10, :b => 20)
|
|
113
|
+
|
|
114
|
+
config = IOConfig.new(:a => 100)
|
|
115
|
+
expect(config.get!(:a)).to eq(100)
|
|
116
|
+
expect(config.get!(:b)).to eq(20)
|
|
117
|
+
expect(config.get!(:c)).to eq(3)
|
|
118
|
+
config.assert_no_unused_options!
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
it 'does not read options with empty config_paths' do
|
|
122
|
+
expect(IOConfig).not_to receive(:read_options)
|
|
123
|
+
|
|
124
|
+
config = IOConfig.new(:config_paths => [])
|
|
125
|
+
config.assert_no_unused_options!
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
it 'reads options from specified paths' do
|
|
129
|
+
expect(IOConfig).to receive(:read_options).
|
|
130
|
+
with('/etc/image_optim.yml').and_return(:a => 1, :b => 2, :c => 3)
|
|
131
|
+
expect(IOConfig).to receive(:read_options).
|
|
132
|
+
with('config/image_optim.yml').and_return(:a => 10, :b => 20)
|
|
133
|
+
|
|
134
|
+
config = IOConfig.new(:a => 100, :config_paths => %w[
|
|
135
|
+
/etc/image_optim.yml
|
|
136
|
+
config/image_optim.yml
|
|
137
|
+
])
|
|
138
|
+
expect(config.get!(:a)).to eq(100)
|
|
139
|
+
expect(config.get!(:b)).to eq(20)
|
|
140
|
+
expect(config.get!(:c)).to eq(3)
|
|
141
|
+
config.assert_no_unused_options!
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
it 'converts config_paths to array' do
|
|
145
|
+
expect(IOConfig).to receive(:read_options).
|
|
146
|
+
with('config/image_optim.yml').and_return({})
|
|
147
|
+
|
|
148
|
+
config = IOConfig.new(:config_paths => 'config/image_optim.yml')
|
|
149
|
+
config.assert_no_unused_options!
|
|
150
|
+
end
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
describe 'class methods' do
|
|
154
|
+
describe :read_options do
|
|
155
|
+
let(:path){ double(:path) }
|
|
156
|
+
let(:full_path){ double(:full_path) }
|
|
157
|
+
|
|
158
|
+
it 'warns if expand path fails' do
|
|
159
|
+
expect(IOConfig).to receive(:warn)
|
|
160
|
+
expect(File).to receive(:expand_path).
|
|
161
|
+
with(path).and_raise(ArgumentError)
|
|
162
|
+
expect(File).not_to receive(:file?)
|
|
163
|
+
|
|
164
|
+
expect(IOConfig.read_options(path)).to eq({})
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
it 'returns empty hash if path is not a file' do
|
|
168
|
+
expect(IOConfig).not_to receive(:warn)
|
|
169
|
+
expect(File).to receive(:expand_path).
|
|
170
|
+
with(path).and_return(full_path)
|
|
171
|
+
expect(File).to receive(:file?).
|
|
172
|
+
with(full_path).and_return(false)
|
|
173
|
+
|
|
174
|
+
expect(IOConfig.read_options(path)).to eq({})
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
it 'returns hash with deep symbolised keys from reader' do
|
|
178
|
+
stringified = {'config' => {'this' => true}}
|
|
179
|
+
symbolized = {:config => {:this => true}}
|
|
180
|
+
|
|
181
|
+
expect(IOConfig).not_to receive(:warn)
|
|
182
|
+
expect(File).to receive(:expand_path).
|
|
183
|
+
with(path).and_return(full_path)
|
|
184
|
+
expect(File).to receive(:file?).
|
|
185
|
+
with(full_path).and_return(true)
|
|
186
|
+
expect(YAML).to receive(:load_file).
|
|
187
|
+
with(full_path).and_return(stringified)
|
|
188
|
+
|
|
189
|
+
expect(IOConfig.read_options(path)).to eq(symbolized)
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
it 'warns and returns an empty hash if reader returns non hash' do
|
|
193
|
+
expect(IOConfig).to receive(:warn)
|
|
194
|
+
expect(File).to receive(:expand_path).
|
|
195
|
+
with(path).and_return(full_path)
|
|
196
|
+
expect(File).to receive(:file?).
|
|
197
|
+
with(full_path).and_return(true)
|
|
198
|
+
expect(YAML).to receive(:load_file).
|
|
199
|
+
with(full_path).and_return([:config])
|
|
200
|
+
|
|
201
|
+
expect(IOConfig.read_options(path)).to eq({})
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
it 'warns and returns an empty hash if reader raises exception' do
|
|
205
|
+
expect(IOConfig).to receive(:warn)
|
|
206
|
+
expect(File).to receive(:expand_path).
|
|
207
|
+
with(path).and_return(full_path)
|
|
208
|
+
expect(File).to receive(:file?).
|
|
209
|
+
with(full_path).and_return(true)
|
|
210
|
+
expect(YAML).to receive(:load_file).
|
|
211
|
+
with(full_path).and_raise
|
|
212
|
+
|
|
213
|
+
expect(IOConfig.read_options(path)).to eq({})
|
|
214
|
+
end
|
|
215
|
+
end
|
|
216
|
+
end
|
|
217
|
+
end
|