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.
Files changed (50) hide show
  1. checksums.yaml +8 -8
  2. data/.appveyor.yml +95 -0
  3. data/.rubocop.yml +3 -0
  4. data/.travis.yml +27 -22
  5. data/CHANGELOG.markdown +10 -0
  6. data/CONTRIBUTING.markdown +2 -1
  7. data/Gemfile +1 -1
  8. data/README.markdown +10 -2
  9. data/image_optim.gemspec +4 -4
  10. data/lib/image_optim.rb +32 -16
  11. data/lib/image_optim/bin_resolver/bin.rb +11 -4
  12. data/lib/image_optim/cache.rb +71 -0
  13. data/lib/image_optim/cache_path.rb +16 -0
  14. data/lib/image_optim/config.rb +12 -2
  15. data/lib/image_optim/handler.rb +1 -1
  16. data/lib/image_optim/image_meta.rb +5 -10
  17. data/lib/image_optim/optimized_path.rb +25 -0
  18. data/lib/image_optim/path.rb +70 -0
  19. data/lib/image_optim/runner/option_parser.rb +13 -0
  20. data/lib/image_optim/worker.rb +5 -8
  21. data/lib/image_optim/worker/class_methods.rb +3 -1
  22. data/lib/image_optim/worker/jpegoptim.rb +3 -0
  23. data/lib/image_optim/worker/jpegrecompress.rb +3 -0
  24. data/lib/image_optim/worker/pngquant.rb +3 -0
  25. data/script/worker_analysis +10 -9
  26. data/spec/image_optim/bin_resolver/comparable_condition_spec.rb +1 -1
  27. data/spec/image_optim/bin_resolver/simple_version_spec.rb +48 -40
  28. data/spec/image_optim/bin_resolver_spec.rb +190 -172
  29. data/spec/image_optim/cache_path_spec.rb +59 -0
  30. data/spec/image_optim/cache_spec.rb +159 -0
  31. data/spec/image_optim/cmd_spec.rb +11 -7
  32. data/spec/image_optim/config_spec.rb +92 -71
  33. data/spec/image_optim/handler_spec.rb +3 -6
  34. data/spec/image_optim/image_meta_spec.rb +61 -0
  35. data/spec/image_optim/optimized_path_spec.rb +58 -0
  36. data/spec/image_optim/option_helpers_spec.rb +25 -0
  37. data/spec/image_optim/path_spec.rb +105 -0
  38. data/spec/image_optim/railtie_spec.rb +6 -6
  39. data/spec/image_optim/runner/glob_helpers_spec.rb +2 -6
  40. data/spec/image_optim/runner/option_parser_spec.rb +3 -3
  41. data/spec/image_optim/space_spec.rb +16 -18
  42. data/spec/image_optim/worker/optipng_spec.rb +3 -3
  43. data/spec/image_optim/worker/pngquant_spec.rb +47 -7
  44. data/spec/image_optim/worker_spec.rb +114 -17
  45. data/spec/image_optim_spec.rb +58 -69
  46. data/spec/images/broken_jpeg +1 -0
  47. data/spec/spec_helper.rb +40 -10
  48. metadata +30 -8
  49. data/lib/image_optim/image_path.rb +0 -68
  50. data/spec/image_optim/image_path_spec.rb +0 -54
@@ -2,7 +2,7 @@ require 'spec_helper'
2
2
  require 'image_optim/bin_resolver/comparable_condition'
3
3
 
4
4
  describe ImageOptim::BinResolver::ComparableCondition do
5
- is = ImageOptim::BinResolver::ComparableCondition.is
5
+ let(:is){ ImageOptim::BinResolver::ComparableCondition.is }
6
6
 
7
7
  it 'builds conditions' do
8
8
  expect(is.between?(10, 20).method).to eq(:between?)
@@ -2,56 +2,64 @@ require 'spec_helper'
2
2
  require 'image_optim/bin_resolver/simple_version'
3
3
 
4
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' }
5
+ def v(str)
6
+ described_class.new(str)
23
7
  end
24
8
 
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)
9
+ describe '#initialize' do
10
+ describe 'conversion' do
11
+ it 'converts Integer' do
12
+ expect(v(117)).to eq('117')
36
13
  end
37
- end
38
- end
39
14
 
40
- describe 'conversion' do
41
- it 'converts Integer' do
42
- expect(v(117)).to eq('117')
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
43
26
  end
44
27
 
45
- it 'converts Float' do
46
- expect(v(1.17)).to eq('1.17')
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
47
41
  end
42
+ end
48
43
 
49
- it 'converts String' do
50
- expect(v('1.17')).to eq('1.17')
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')
51
49
  end
50
+ end
51
+
52
+ describe '#<=>' do
53
+ describe 'comparing version 1.17' do
54
+ subject{ v '1.17' }
52
55
 
53
- it 'converts self' do
54
- expect(v(v(1.17))).to eq('1.17')
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' }
55
63
  end
56
64
  end
57
65
  end
@@ -1,13 +1,11 @@
1
1
  require 'spec_helper'
2
2
  require 'image_optim/bin_resolver'
3
3
  require 'image_optim/cmd'
4
+ require 'image_optim/path'
4
5
 
5
6
  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
7
+ def stub_env(key, value)
8
+ allow(ENV).to receive(:[]).with(key).and_return(value)
11
9
  end
12
10
 
13
11
  before do
@@ -15,71 +13,67 @@ describe ImageOptim::BinResolver do
15
13
  stub_const('Bin', BinResolver::Bin)
16
14
  stub_const('SimpleVersion', BinResolver::SimpleVersion)
17
15
  stub_const('Cmd', ImageOptim::Cmd)
16
+
17
+ allow(ENV).to receive(:[]).and_call_original
18
18
  end
19
19
 
20
20
  let(:image_optim){ double(:image_optim, :verbose => false, :pack => false) }
21
21
  let(:resolver){ BinResolver.new(image_optim) }
22
22
 
23
- describe :full_path do
23
+ describe '#full_path' do
24
24
  def full_path(name)
25
25
  resolver.instance_eval{ full_path(name) }
26
26
  end
27
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
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
39
43
 
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
+ expect(full_path('abc')).
45
+ to eq(File.expand_path('/c/abc'))
44
46
  end
45
47
  end
46
48
 
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'
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)
52
63
  end
53
- end)
54
64
 
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'))
65
+ expect(full_path('abc')).
66
+ to eq(File.expand_path('/b/abc.com'))
66
67
  end
67
68
  end
68
69
 
69
70
  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
71
+ stub_env 'PATH', ''
72
+ expect(full_path('image_optim')).to be_nil
79
73
  end
80
74
  end
81
75
 
82
- it 'combines path in order dir:pack:path:vendor' do
76
+ it 'combines path in order dir, pack, path, vendor' do
83
77
  allow(image_optim).to receive(:pack).and_return(true)
84
78
  stub_const('ImageOptim::Pack', Class.new do
85
79
  def self.path
@@ -93,130 +87,157 @@ describe ImageOptim::BinResolver do
93
87
  'pack_path',
94
88
  ENV['PATH'],
95
89
  BinResolver::VENDOR_PATH,
96
- ].join(':'))
90
+ ].join(File::PATH_SEPARATOR))
97
91
  end
98
92
 
99
93
  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(':'))
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)
115
104
  end
105
+ expect(resolver.env_path).to eq([
106
+ ENV['PATH'],
107
+ BinResolver::VENDOR_PATH,
108
+ ].join(File::PATH_SEPARATOR))
116
109
  end
117
110
 
118
111
  it 'raises on failure to resolve bin' do
119
- with_env 'LS_BIN', nil 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
120
179
  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)
180
+ expect(resolver).not_to receive(:at_exit)
181
+ allow(File).to receive_messages(:exist? => exist?,
182
+ :file? => file?,
183
+ :executable? => executable?)
184
+ end
123
185
 
124
- 5.times do
125
- expect do
126
- resolver.resolve!(:ls)
127
- end.to raise_error BinResolver::BinNotFound
128
- end
186
+ after do
129
187
  expect(resolver.env_path).to eq([
130
188
  ENV['PATH'],
131
189
  BinResolver::VENDOR_PATH,
132
- ].join(':'))
190
+ ].join(File::PATH_SEPARATOR))
133
191
  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
192
 
193
+ def raises_error(error_message)
161
194
  5.times do
162
- resolver.resolve!(:image_optim)
195
+ expect do
196
+ resolver.resolve!(:the_optimizer)
197
+ end.to raise_error RuntimeError, /#{Regexp.escape(error_message)}/
163
198
  end
164
- expect(resolver.env_path).to eq([
165
- tmpdir,
166
- ENV['PATH'],
167
- BinResolver::VENDOR_PATH,
168
- ].join(':'))
199
+ end
169
200
 
170
- expect(FileUtils).to receive(:remove_entry_secure).with(tmpdir)
171
- at_exit_blocks.each(&:call)
201
+ context 'presence' do
202
+ let(:exist?){ false }
203
+
204
+ it{ raises_error('doesn\'t exist') }
172
205
  end
173
- end
174
206
 
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
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') }
195
217
  end
196
218
  end
197
219
 
198
220
  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)
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)
206
228
 
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 } }
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 } }
211
233
 
212
- Array.new(10) do
213
- Thread.new do
214
- resolver.resolve!(:ls)
215
- end
216
- end.each(&:join)
234
+ Array.new(10) do
235
+ Thread.new do
236
+ resolver.resolve!(:ls)
237
+ end
238
+ end.each(&:join)
217
239
 
218
- expect(count).to eq(10)
219
- end
240
+ expect(count).to eq(10)
220
241
  end
221
242
 
222
243
  describe 'checking version' do
@@ -225,47 +246,44 @@ describe ImageOptim::BinResolver do
225
246
  end
226
247
 
227
248
  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')
249
+ stub_env 'PNGCRUSH_BIN', nil
250
+ bin = Bin.new(:pngcrush, '/bin/pngcrush')
230
251
 
231
- expect(Bin).to receive(:new).and_return(bin)
232
- allow(bin).to receive(:version).and_return(nil)
252
+ expect(Bin).to receive(:new).and_return(bin)
253
+ allow(bin).to receive(:version).and_return(nil)
233
254
 
234
- 5.times do
235
- expect do
236
- resolver.resolve!(:pngcrush)
237
- end.to raise_error Bin::UnknownVersion
238
- end
255
+ 5.times do
256
+ expect do
257
+ resolver.resolve!(:pngcrush)
258
+ end.to raise_error Bin::UnknownVersion
239
259
  end
240
260
  end
241
261
 
242
262
  it 'raises every time on detection of misbehaving version' do
243
- with_env 'PNGCRUSH_BIN', nil do
244
- bin = Bin.new(:pngcrush, '/bin/pngcrush')
263
+ stub_env 'PNGCRUSH_BIN', nil
264
+ bin = Bin.new(:pngcrush, '/bin/pngcrush')
245
265
 
246
- expect(Bin).to receive(:new).and_return(bin)
247
- allow(bin).to receive(:version).and_return(SimpleVersion.new('1.7.60'))
266
+ expect(Bin).to receive(:new).and_return(bin)
267
+ allow(bin).to receive(:version).and_return(SimpleVersion.new('1.7.60'))
248
268
 
249
- 5.times do
250
- expect do
251
- resolver.resolve!(:pngcrush)
252
- end.to raise_error Bin::BadVersion
253
- end
269
+ 5.times do
270
+ expect do
271
+ resolver.resolve!(:pngcrush)
272
+ end.to raise_error Bin::BadVersion
254
273
  end
255
274
  end
256
275
 
257
276
  it 'warns once on detection of problematic version' do
258
- with_env 'ADVPNG_BIN', nil do
259
- bin = Bin.new(:advpng, '/bin/advpng')
277
+ stub_env 'ADVPNG_BIN', nil
278
+ bin = Bin.new(:advpng, '/bin/advpng')
260
279
 
261
- expect(Bin).to receive(:new).and_return(bin)
262
- allow(bin).to receive(:version).and_return(SimpleVersion.new('1.15'))
280
+ expect(Bin).to receive(:new).and_return(bin)
281
+ allow(bin).to receive(:version).and_return(SimpleVersion.new('1.15'))
263
282
 
264
- expect(bin).to receive(:warn).once
283
+ expect(bin).to receive(:warn).once
265
284
 
266
- 5.times do
267
- resolver.resolve!(:pngcrush)
268
- end
285
+ 5.times do
286
+ resolver.resolve!(:pngcrush)
269
287
  end
270
288
  end
271
289
  end