discourse_image_optim 0.24.4
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/.appveyor.yml +46 -0
- data/.gitignore +18 -0
- data/.rubocop.yml +110 -0
- data/.travis.yml +42 -0
- data/CHANGELOG.markdown +316 -0
- data/CONTRIBUTING.markdown +11 -0
- data/Gemfile +16 -0
- data/LICENSE.txt +20 -0
- data/README.markdown +358 -0
- data/Vagrantfile +38 -0
- data/bin/image_optim +28 -0
- data/image_optim.gemspec +34 -0
- data/lib/image_optim.rb +267 -0
- data/lib/image_optim/bin_resolver.rb +142 -0
- data/lib/image_optim/bin_resolver/bin.rb +115 -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/cache.rb +72 -0
- data/lib/image_optim/cache_path.rb +16 -0
- data/lib/image_optim/cmd.rb +122 -0
- data/lib/image_optim/config.rb +219 -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 +20 -0
- data/lib/image_optim/non_negative_integer_range.rb +11 -0
- data/lib/image_optim/optimized_path.rb +25 -0
- data/lib/image_optim/option_definition.rb +38 -0
- data/lib/image_optim/option_helpers.rb +17 -0
- data/lib/image_optim/path.rb +70 -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 +246 -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 +170 -0
- data/lib/image_optim/worker/advpng.rb +37 -0
- data/lib/image_optim/worker/class_methods.rb +107 -0
- data/lib/image_optim/worker/gifsicle.rb +65 -0
- data/lib/image_optim/worker/jhead.rb +47 -0
- data/lib/image_optim/worker/jpegoptim.rb +63 -0
- data/lib/image_optim/worker/jpegrecompress.rb +49 -0
- data/lib/image_optim/worker/jpegtran.rb +48 -0
- data/lib/image_optim/worker/optipng.rb +53 -0
- data/lib/image_optim/worker/pngcrush.rb +56 -0
- data/lib/image_optim/worker/pngout.rb +40 -0
- data/lib/image_optim/worker/pngquant.rb +61 -0
- data/lib/image_optim/worker/svgo.rb +34 -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 +59 -0
- data/script/worker_analysis +589 -0
- data/spec/image_optim/bin_resolver/comparable_condition_spec.rb +37 -0
- data/spec/image_optim/bin_resolver/simple_version_spec.rb +65 -0
- data/spec/image_optim/bin_resolver_spec.rb +290 -0
- data/spec/image_optim/cache_path_spec.rb +57 -0
- data/spec/image_optim/cache_spec.rb +162 -0
- data/spec/image_optim/cmd_spec.rb +93 -0
- data/spec/image_optim/config_spec.rb +254 -0
- data/spec/image_optim/handler_spec.rb +90 -0
- data/spec/image_optim/hash_helpers_spec.rb +74 -0
- 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_definition_spec.rb +138 -0
- data/spec/image_optim/option_helpers_spec.rb +25 -0
- data/spec/image_optim/path_spec.rb +103 -0
- data/spec/image_optim/runner/glob_helpers_spec.rb +21 -0
- data/spec/image_optim/runner/option_parser_spec.rb +105 -0
- data/spec/image_optim/space_spec.rb +23 -0
- data/spec/image_optim/worker/optipng_spec.rb +102 -0
- data/spec/image_optim/worker/pngquant_spec.rb +67 -0
- data/spec/image_optim/worker_spec.rb +303 -0
- data/spec/image_optim_spec.rb +259 -0
- data/spec/images/broken_jpeg +1 -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 +93 -0
- metadata +281 -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
|
+
let(: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,65 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
require 'image_optim/bin_resolver/simple_version'
|
|
3
|
+
|
|
4
|
+
describe ImageOptim::BinResolver::SimpleVersion do
|
|
5
|
+
def v(str)
|
|
6
|
+
described_class.new(str)
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
describe '#initialize' do
|
|
10
|
+
describe 'conversion' do
|
|
11
|
+
it 'converts Integer' do
|
|
12
|
+
expect(v(117)).to eq('117')
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
it 'converts Float' do
|
|
16
|
+
expect(v(1.17)).to eq('1.17')
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
it 'converts String' do
|
|
20
|
+
expect(v('1.17')).to eq('1.17')
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
it 'converts self' do
|
|
24
|
+
expect(v(v(1.17))).to eq('1.17')
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
describe 'normalization' do
|
|
29
|
+
%w[
|
|
30
|
+
1
|
|
31
|
+
01
|
|
32
|
+
1.0
|
|
33
|
+
1.00
|
|
34
|
+
1.0.0
|
|
35
|
+
1.0.0.0
|
|
36
|
+
].each do |variation|
|
|
37
|
+
it "normalizes #{variation}" do
|
|
38
|
+
expect(v(variation)).to eq(1)
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
describe '#to_s' do
|
|
45
|
+
it 'returns the original value converted to String' do
|
|
46
|
+
expect(v(117).to_s).to eq('117')
|
|
47
|
+
expect(v(1.17).to_s).to eq('1.17')
|
|
48
|
+
expect(v('0117').to_s).to eq('0117')
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
describe '#<=>' do
|
|
53
|
+
describe 'comparing version 1.17' do
|
|
54
|
+
subject{ v '1.17' }
|
|
55
|
+
|
|
56
|
+
it{ is_expected.to be > '0' }
|
|
57
|
+
it{ is_expected.to be > '0.1' }
|
|
58
|
+
it{ is_expected.to be > '0.9' }
|
|
59
|
+
it{ is_expected.to be > '1.9' }
|
|
60
|
+
it{ is_expected.to be < '1.17.1' }
|
|
61
|
+
it{ is_expected.to be < '1.99' }
|
|
62
|
+
it{ is_expected.to be < '2.1' }
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
@@ -0,0 +1,290 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
require 'image_optim/bin_resolver'
|
|
3
|
+
require 'image_optim/cmd'
|
|
4
|
+
require 'image_optim/path'
|
|
5
|
+
|
|
6
|
+
describe ImageOptim::BinResolver do
|
|
7
|
+
def stub_env(key, value)
|
|
8
|
+
allow(ENV).to receive(:[]).with(key).and_return(value)
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
before do
|
|
12
|
+
stub_const('BinResolver', ImageOptim::BinResolver)
|
|
13
|
+
stub_const('Bin', BinResolver::Bin)
|
|
14
|
+
stub_const('SimpleVersion', BinResolver::SimpleVersion)
|
|
15
|
+
stub_const('Cmd', ImageOptim::Cmd)
|
|
16
|
+
|
|
17
|
+
allow(ENV).to receive(:[]).and_call_original
|
|
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
|
+
context 'when PATHEXT is not set' do
|
|
29
|
+
it 'finds binary without ext in combined path' do
|
|
30
|
+
stub_env 'PATH', %w[/a /b /c /d].join(File::PATH_SEPARATOR)
|
|
31
|
+
stub_env 'PATHEXT', nil
|
|
32
|
+
|
|
33
|
+
[
|
|
34
|
+
[:file?, '/a/abc', false],
|
|
35
|
+
[:file?, '/b/abc', true],
|
|
36
|
+
[:executable?, '/b/abc', false],
|
|
37
|
+
[:file?, '/c/abc', true],
|
|
38
|
+
[:executable?, '/c/abc', true],
|
|
39
|
+
].each do |method, path, result|
|
|
40
|
+
allow(File).to receive(method).
|
|
41
|
+
with(File.expand_path(path)).and_return(result)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
expect(full_path('abc')).
|
|
45
|
+
to eq(File.expand_path('/c/abc'))
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
context 'when PATHEXT is set' do
|
|
50
|
+
it 'finds binary with ext in combined path' do
|
|
51
|
+
stub_env 'PATH', %w[/a /b].join(File::PATH_SEPARATOR)
|
|
52
|
+
stub_env 'PATHEXT', '.com;.bat'
|
|
53
|
+
|
|
54
|
+
[
|
|
55
|
+
[:file?, '/a/abc.com', false],
|
|
56
|
+
[:file?, '/a/abc.bat', true],
|
|
57
|
+
[:executable?, '/a/abc.bat', false],
|
|
58
|
+
[:file?, '/b/abc.com', true],
|
|
59
|
+
[:executable?, '/b/abc.com', true],
|
|
60
|
+
].each do |method, path, result|
|
|
61
|
+
allow(File).to receive(method).
|
|
62
|
+
with(File.expand_path(path)).and_return(result)
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
expect(full_path('abc')).
|
|
66
|
+
to eq(File.expand_path('/b/abc.com'))
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
it 'returns nil on failure' do
|
|
71
|
+
stub_env 'PATH', ''
|
|
72
|
+
expect(full_path('image_optim')).to be_nil
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
it 'combines path in order dir, pack, path, vendor' do
|
|
77
|
+
allow(image_optim).to receive(:pack).and_return(true)
|
|
78
|
+
stub_const('ImageOptim::Pack', Class.new do
|
|
79
|
+
def self.path
|
|
80
|
+
'pack_path'
|
|
81
|
+
end
|
|
82
|
+
end)
|
|
83
|
+
allow(resolver).to receive(:dir).and_return('temp_dir')
|
|
84
|
+
|
|
85
|
+
expect(resolver.env_path).to eq([
|
|
86
|
+
'temp_dir',
|
|
87
|
+
'pack_path',
|
|
88
|
+
ENV['PATH'],
|
|
89
|
+
BinResolver::VENDOR_PATH,
|
|
90
|
+
].join(File::PATH_SEPARATOR))
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
it 'resolves bin in path and returns instance of Bin' do
|
|
94
|
+
stub_env 'LS_BIN', nil
|
|
95
|
+
expect(FSPath).not_to receive(:temp_dir)
|
|
96
|
+
expect(resolver).to receive(:full_path).with(:ls).and_return('/bin/ls')
|
|
97
|
+
bin = double
|
|
98
|
+
expect(Bin).to receive(:new).with(:ls, '/bin/ls').and_return(bin)
|
|
99
|
+
expect(bin).to receive(:check!).once
|
|
100
|
+
expect(bin).to receive(:check_fail!).exactly(5).times
|
|
101
|
+
|
|
102
|
+
5.times do
|
|
103
|
+
expect(resolver.resolve!(:ls)).to eq(bin)
|
|
104
|
+
end
|
|
105
|
+
expect(resolver.env_path).to eq([
|
|
106
|
+
ENV['PATH'],
|
|
107
|
+
BinResolver::VENDOR_PATH,
|
|
108
|
+
].join(File::PATH_SEPARATOR))
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
it 'raises on failure to resolve bin' do
|
|
112
|
+
stub_env 'LS_BIN', nil
|
|
113
|
+
expect(FSPath).not_to receive(:temp_dir)
|
|
114
|
+
expect(resolver).to receive(:full_path).with(:ls).and_return(nil)
|
|
115
|
+
expect(Bin).not_to receive(:new)
|
|
116
|
+
|
|
117
|
+
5.times do
|
|
118
|
+
expect do
|
|
119
|
+
resolver.resolve!(:ls)
|
|
120
|
+
end.to raise_error BinResolver::BinNotFound
|
|
121
|
+
end
|
|
122
|
+
expect(resolver.env_path).to eq([
|
|
123
|
+
ENV['PATH'],
|
|
124
|
+
BinResolver::VENDOR_PATH,
|
|
125
|
+
].join(File::PATH_SEPARATOR))
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
it 'resolves bin specified in ENV' do
|
|
129
|
+
path = 'bin/the_optimizer'
|
|
130
|
+
stub_env 'THE_OPTIMIZER_BIN', path
|
|
131
|
+
tmpdir = double(:tmpdir, :to_str => 'tmpdir')
|
|
132
|
+
symlink = double(:symlink)
|
|
133
|
+
|
|
134
|
+
full_path = File.expand_path(path)
|
|
135
|
+
allow(File).to receive(:exist?).with(full_path).and_return(true)
|
|
136
|
+
allow(File).to receive(:file?).with(full_path).and_return(true)
|
|
137
|
+
allow(File).to receive(:executable?).with(full_path).and_return(true)
|
|
138
|
+
|
|
139
|
+
expect(FSPath).to receive(:temp_dir).
|
|
140
|
+
once.and_return(tmpdir)
|
|
141
|
+
expect(tmpdir).to receive(:/).
|
|
142
|
+
with(:the_optimizer).once.and_return(symlink)
|
|
143
|
+
expect(symlink).to receive(:make_symlink).
|
|
144
|
+
with(File.expand_path(path)).once
|
|
145
|
+
|
|
146
|
+
expect(resolver).not_to receive(:full_path)
|
|
147
|
+
bin = double
|
|
148
|
+
expect(Bin).to receive(:new).
|
|
149
|
+
with(:the_optimizer, File.expand_path(path)).and_return(bin)
|
|
150
|
+
expect(bin).to receive(:check!).once
|
|
151
|
+
expect(bin).to receive(:check_fail!).exactly(5).times
|
|
152
|
+
|
|
153
|
+
at_exit_blocks = []
|
|
154
|
+
expect(resolver).to receive(:at_exit).once do |&block|
|
|
155
|
+
at_exit_blocks.unshift(block)
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
5.times do
|
|
159
|
+
resolver.resolve!(:the_optimizer)
|
|
160
|
+
end
|
|
161
|
+
expect(resolver.env_path).to eq([
|
|
162
|
+
tmpdir,
|
|
163
|
+
ENV['PATH'],
|
|
164
|
+
BinResolver::VENDOR_PATH,
|
|
165
|
+
].join(File::PATH_SEPARATOR))
|
|
166
|
+
|
|
167
|
+
expect(FileUtils).to receive(:remove_entry_secure).with(tmpdir)
|
|
168
|
+
at_exit_blocks.each(&:call)
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
describe 'checking bin' do
|
|
172
|
+
let(:path){ 'the_optimizer' }
|
|
173
|
+
let(:exist?){ true }
|
|
174
|
+
let(:file?){ true }
|
|
175
|
+
let(:executable?){ true }
|
|
176
|
+
|
|
177
|
+
before do
|
|
178
|
+
stub_env 'THE_OPTIMIZER_BIN', path
|
|
179
|
+
expect(FSPath).not_to receive(:temp_dir)
|
|
180
|
+
expect(resolver).not_to receive(:at_exit)
|
|
181
|
+
allow(File).to receive_messages(:exist? => exist?,
|
|
182
|
+
:file? => file?,
|
|
183
|
+
:executable? => executable?)
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
after do
|
|
187
|
+
expect(resolver.env_path).to eq([
|
|
188
|
+
ENV['PATH'],
|
|
189
|
+
BinResolver::VENDOR_PATH,
|
|
190
|
+
].join(File::PATH_SEPARATOR))
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
def raises_error(error_message)
|
|
194
|
+
5.times do
|
|
195
|
+
expect do
|
|
196
|
+
resolver.resolve!(:the_optimizer)
|
|
197
|
+
end.to raise_error RuntimeError, /#{Regexp.escape(error_message)}/
|
|
198
|
+
end
|
|
199
|
+
end
|
|
200
|
+
|
|
201
|
+
context 'presence' do
|
|
202
|
+
let(:exist?){ false }
|
|
203
|
+
|
|
204
|
+
it{ raises_error('doesn\'t exist') }
|
|
205
|
+
end
|
|
206
|
+
|
|
207
|
+
context 'been a file' do
|
|
208
|
+
let(:file?){ false }
|
|
209
|
+
|
|
210
|
+
it{ raises_error('is not a file') }
|
|
211
|
+
end
|
|
212
|
+
|
|
213
|
+
context 'been a file' do
|
|
214
|
+
let(:executable?){ false }
|
|
215
|
+
|
|
216
|
+
it{ raises_error('is not executable') }
|
|
217
|
+
end
|
|
218
|
+
end
|
|
219
|
+
|
|
220
|
+
it 'resolves bin only once, but checks every time' do
|
|
221
|
+
stub_env 'LS_BIN', nil
|
|
222
|
+
expect(resolver).to receive(:full_path).once.with(:ls) do
|
|
223
|
+
sleep 0.1
|
|
224
|
+
'/bin/ls'
|
|
225
|
+
end
|
|
226
|
+
bin = double
|
|
227
|
+
expect(Bin).to receive(:new).once.with(:ls, '/bin/ls').and_return(bin)
|
|
228
|
+
|
|
229
|
+
count = 0
|
|
230
|
+
mutex = Mutex.new
|
|
231
|
+
allow(bin).to receive(:check!).once
|
|
232
|
+
allow(bin).to receive(:check_fail!){ mutex.synchronize{ count += 1 } }
|
|
233
|
+
|
|
234
|
+
Array.new(10) do
|
|
235
|
+
Thread.new do
|
|
236
|
+
resolver.resolve!(:ls)
|
|
237
|
+
end
|
|
238
|
+
end.each(&:join)
|
|
239
|
+
|
|
240
|
+
expect(count).to eq(10)
|
|
241
|
+
end
|
|
242
|
+
|
|
243
|
+
describe 'checking version' do
|
|
244
|
+
before do
|
|
245
|
+
allow(resolver).to receive(:full_path){ |name| "/bin/#{name}" }
|
|
246
|
+
end
|
|
247
|
+
|
|
248
|
+
it 'raises every time if did not get bin version' do
|
|
249
|
+
stub_env 'PNGCRUSH_BIN', nil
|
|
250
|
+
bin = Bin.new(:pngcrush, '/bin/pngcrush')
|
|
251
|
+
|
|
252
|
+
expect(Bin).to receive(:new).and_return(bin)
|
|
253
|
+
allow(bin).to receive(:version).and_return(nil)
|
|
254
|
+
|
|
255
|
+
5.times do
|
|
256
|
+
expect do
|
|
257
|
+
resolver.resolve!(:pngcrush)
|
|
258
|
+
end.to raise_error Bin::UnknownVersion, %r{pngcrush at /bin/pngcrush}
|
|
259
|
+
end
|
|
260
|
+
end
|
|
261
|
+
|
|
262
|
+
it 'raises every time on detection of misbehaving version' do
|
|
263
|
+
stub_env 'PNGCRUSH_BIN', nil
|
|
264
|
+
bin = Bin.new(:pngcrush, '/bin/pngcrush')
|
|
265
|
+
|
|
266
|
+
expect(Bin).to receive(:new).and_return(bin)
|
|
267
|
+
allow(bin).to receive(:version).and_return(SimpleVersion.new('1.7.60'))
|
|
268
|
+
|
|
269
|
+
5.times do
|
|
270
|
+
expect do
|
|
271
|
+
resolver.resolve!(:pngcrush)
|
|
272
|
+
end.to raise_error Bin::BadVersion, /is known to produce broken pngs/
|
|
273
|
+
end
|
|
274
|
+
end
|
|
275
|
+
|
|
276
|
+
it 'warns once on detection of problematic version' do
|
|
277
|
+
stub_env 'ADVPNG_BIN', nil
|
|
278
|
+
bin = Bin.new(:advpng, '/bin/advpng')
|
|
279
|
+
|
|
280
|
+
expect(Bin).to receive(:new).and_return(bin)
|
|
281
|
+
allow(bin).to receive(:version).and_return(SimpleVersion.new('1.15'))
|
|
282
|
+
|
|
283
|
+
expect(bin).to receive(:warn).once.with(match(/does not use zopfli/))
|
|
284
|
+
|
|
285
|
+
5.times do
|
|
286
|
+
resolver.resolve!(:pngcrush)
|
|
287
|
+
end
|
|
288
|
+
end
|
|
289
|
+
end
|
|
290
|
+
end
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
require 'image_optim/cache_path'
|
|
3
|
+
require 'tempfile'
|
|
4
|
+
|
|
5
|
+
describe ImageOptim::CachePath do
|
|
6
|
+
include CapabilityCheckHelpers
|
|
7
|
+
|
|
8
|
+
before do
|
|
9
|
+
stub_const('CachePath', ImageOptim::CachePath)
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
describe '#replace' do
|
|
13
|
+
let(:src){ CachePath.temp_file_path }
|
|
14
|
+
let(:dst){ CachePath.temp_file_path }
|
|
15
|
+
|
|
16
|
+
it 'moves data to destination' do
|
|
17
|
+
src.write('src')
|
|
18
|
+
|
|
19
|
+
src.replace(dst)
|
|
20
|
+
|
|
21
|
+
expect(dst.read).to eq('src')
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
it 'does not remove original file' do
|
|
25
|
+
src.replace(dst)
|
|
26
|
+
|
|
27
|
+
expect(src).to exist
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
it 'preserves attributes of destination file' do
|
|
31
|
+
skip 'full file modes are not support' unless any_file_modes_allowed?
|
|
32
|
+
mode = 0o666
|
|
33
|
+
|
|
34
|
+
dst.chmod(mode)
|
|
35
|
+
|
|
36
|
+
src.replace(dst)
|
|
37
|
+
|
|
38
|
+
got = dst.stat.mode & 0o777
|
|
39
|
+
expect(got).to eq(mode), format('expected %04o, got %04o', mode, got)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
it 'does not preserve mtime of destination file' do
|
|
43
|
+
time = src.mtime
|
|
44
|
+
|
|
45
|
+
dst.utime(time - 1000, time - 1000)
|
|
46
|
+
|
|
47
|
+
src.replace(dst)
|
|
48
|
+
|
|
49
|
+
expect(dst.mtime).to be >= time
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
it 'changes inode of destination' do
|
|
53
|
+
skip 'inodes are not supported' unless inodes_supported?
|
|
54
|
+
expect{ src.replace(dst) }.to change{ dst.stat.ino }
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|