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,162 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
require 'fspath'
|
|
3
|
+
require 'image_optim/cache'
|
|
4
|
+
require 'image_optim/path'
|
|
5
|
+
|
|
6
|
+
describe ImageOptim::Cache do
|
|
7
|
+
before do
|
|
8
|
+
stub_const('Cache', ImageOptim::Cache)
|
|
9
|
+
stub_const('CachePath', ImageOptim::CachePath)
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
let(:tmp_file){ double('/somewhere/tmp/foo/bar', :rename => 0) }
|
|
13
|
+
|
|
14
|
+
let(:cache_dir) do
|
|
15
|
+
dir = '/somewhere/cache'
|
|
16
|
+
allow(FileUtils).to receive(:mkpath).with(Regexp.new(Regexp.escape(dir)))
|
|
17
|
+
allow(FileUtils).to receive(:touch)
|
|
18
|
+
allow(FSPath).to receive(:temp_file_path) do
|
|
19
|
+
tmp_file
|
|
20
|
+
end
|
|
21
|
+
FSPath.new(dir)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
let(:original) do
|
|
25
|
+
original = double('/somewhere/original', :image_format => :ext)
|
|
26
|
+
allow(Digest::SHA1).to receive(:file).with(original) do
|
|
27
|
+
Digest::SHA1.new << 'some content!'
|
|
28
|
+
end
|
|
29
|
+
original
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
let(:optimized) do
|
|
33
|
+
double('/somewhere/optimized', :format => :ext, :basename => 'optimized')
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
let(:cached) do
|
|
37
|
+
cached = cache_dir / digest
|
|
38
|
+
allow(Digest::SHA1).to receive(:file).with(cached) do
|
|
39
|
+
Digest::SHA1.new << 'some optimized content!'
|
|
40
|
+
end
|
|
41
|
+
CachePath.convert(cached)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
context 'when cache is disabled (default)' do
|
|
45
|
+
let(:image_optim) do
|
|
46
|
+
double(:image_optim, :cache_dir => nil, :cache_worker_digests => false)
|
|
47
|
+
end
|
|
48
|
+
let(:cache){ Cache.new(image_optim, double) }
|
|
49
|
+
|
|
50
|
+
describe :fetch do
|
|
51
|
+
it 'always return block' do
|
|
52
|
+
expect(cache.fetch(original){ optimized }).to be optimized
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
describe :fetch do
|
|
57
|
+
it 'does not write to disk' do
|
|
58
|
+
expect(FileUtils).not_to receive(:mv)
|
|
59
|
+
expect(FileUtils).not_to receive(:touch)
|
|
60
|
+
expect(cache.fetch(original){ optimized })
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
shared_examples 'an enabled cache' do
|
|
66
|
+
context 'when cached file does not exist' do
|
|
67
|
+
describe :fetch do
|
|
68
|
+
it 'writes to cache when file is optimizable' do
|
|
69
|
+
cached_s = cached.to_s
|
|
70
|
+
expect(FileTest).to receive(:file?).with(cached_s).and_return(false)
|
|
71
|
+
expect(FileTest).not_to receive(:size?).with(cached_s)
|
|
72
|
+
expect(FileUtils).to receive(:mv).with(optimized, tmp_file)
|
|
73
|
+
expect(tmp_file).to receive(:rename).with(cached)
|
|
74
|
+
|
|
75
|
+
allow(File).to receive(:umask).and_return(0o024)
|
|
76
|
+
expect(tmp_file).to receive(:chmod).with(0o642)
|
|
77
|
+
|
|
78
|
+
expect(cache.fetch(original){ optimized }).to eq(cached)
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
it 'writes an empty file to cache when file is already optimized' do
|
|
82
|
+
cached_s = cached.to_s
|
|
83
|
+
expect(FileTest).to receive(:file?).with(cached_s).and_return(false)
|
|
84
|
+
expect(FileTest).not_to receive(:size?).with(cached_s)
|
|
85
|
+
expect(FileUtils).not_to receive(:mv)
|
|
86
|
+
expect(FileUtils).to receive(:touch).with(cached)
|
|
87
|
+
|
|
88
|
+
expect(cache.fetch(original){ nil }).to eq(nil)
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
context 'when cached file exists (options and/or workers match)' do
|
|
94
|
+
describe(:fetch) do
|
|
95
|
+
it 'returns cached file' do
|
|
96
|
+
cached_s = cached.to_s
|
|
97
|
+
allow(FileTest).to receive(:file?).with(cached_s).and_return(true)
|
|
98
|
+
allow(FileTest).to receive(:size?).with(cached_s).and_return(1234)
|
|
99
|
+
expect(FileUtils).not_to receive(:mv)
|
|
100
|
+
expect(File).not_to receive(:rename)
|
|
101
|
+
|
|
102
|
+
expect(cache.fetch(original){}).to eq(cached)
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
it 'returns nil when file is already optimized' do
|
|
106
|
+
cached_s = cached.to_s
|
|
107
|
+
allow(FileTest).to receive(:file?).with(cached_s).and_return(true)
|
|
108
|
+
allow(FileTest).to receive(:size?).with(cached_s).and_return(nil)
|
|
109
|
+
expect(FileUtils).not_to receive(:mv)
|
|
110
|
+
expect(File).not_to receive(:rename)
|
|
111
|
+
|
|
112
|
+
expect(cache.fetch(original){ nil }).to eq(nil)
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
context 'when cache is enabled (without worker digests)' do
|
|
119
|
+
let(:image_optim) do
|
|
120
|
+
double(:image_optim,
|
|
121
|
+
:cache_dir => cache_dir, :cache_worker_digests => false)
|
|
122
|
+
end
|
|
123
|
+
let(:cache) do
|
|
124
|
+
cache = Cache.new(image_optim, {})
|
|
125
|
+
allow(cache).
|
|
126
|
+
to receive(:options_by_format).
|
|
127
|
+
with(original.image_format).
|
|
128
|
+
and_return('some options!')
|
|
129
|
+
allow(cache).
|
|
130
|
+
to receive(:bins_by_format).
|
|
131
|
+
with(original.image_format).
|
|
132
|
+
and_return('some bins!')
|
|
133
|
+
cache
|
|
134
|
+
end
|
|
135
|
+
let(:digest){ cache.send(:digest, original, original.image_format) }
|
|
136
|
+
|
|
137
|
+
it_behaves_like 'an enabled cache'
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
context 'when cache is enabled (with worker digests)' do
|
|
141
|
+
let(:image_optim) do
|
|
142
|
+
double(:image_optim,
|
|
143
|
+
:cache_dir => cache_dir,
|
|
144
|
+
:cache_worker_digests => true)
|
|
145
|
+
end
|
|
146
|
+
let(:cache) do
|
|
147
|
+
cache = Cache.new(image_optim, {})
|
|
148
|
+
allow(cache).
|
|
149
|
+
to receive(:options_by_format).
|
|
150
|
+
with(original.image_format).
|
|
151
|
+
and_return('some options!')
|
|
152
|
+
allow(cache).
|
|
153
|
+
to receive(:bins_by_format).
|
|
154
|
+
with(original.image_format).
|
|
155
|
+
and_return('some bins!')
|
|
156
|
+
cache
|
|
157
|
+
end
|
|
158
|
+
let(:digest){ cache.send(:digest, original, original.image_format) }
|
|
159
|
+
|
|
160
|
+
it_behaves_like 'an enabled cache'
|
|
161
|
+
end
|
|
162
|
+
end
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
require 'image_optim/cmd'
|
|
3
|
+
|
|
4
|
+
describe ImageOptim::Cmd do
|
|
5
|
+
include CapabilityCheckHelpers
|
|
6
|
+
|
|
7
|
+
before do
|
|
8
|
+
stub_const('Cmd', ImageOptim::Cmd)
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def expect_int_exception(&block)
|
|
12
|
+
expect(&block).to raise_error(SignalException) do |error|
|
|
13
|
+
expect(error.message.to_s).to match(/INT|#{Signal.list['INT']}/)
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
describe '.run' do
|
|
18
|
+
it 'calls system and returns result' do
|
|
19
|
+
status = double
|
|
20
|
+
expect(Cmd).to receive(:system).with('cmd', 'arg').and_return(status)
|
|
21
|
+
allow(Cmd).to receive(:check_status!)
|
|
22
|
+
expect(Cmd.run('cmd', 'arg')).to eq(status)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
it 'returns process success status' do
|
|
26
|
+
expect(Cmd.run('sh -c "exit 0"')).to eq(true)
|
|
27
|
+
expect($CHILD_STATUS.exitstatus).to eq(0)
|
|
28
|
+
|
|
29
|
+
expect(Cmd.run('sh -c "exit 1"')).to eq(false)
|
|
30
|
+
expect($CHILD_STATUS.exitstatus).to eq(1)
|
|
31
|
+
|
|
32
|
+
expect(Cmd.run('sh -c "exit 66"')).to eq(false)
|
|
33
|
+
expect($CHILD_STATUS.exitstatus).to eq(66)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
it 'raises SignalException if process terminates after signal' do
|
|
37
|
+
skip 'signals are not supported' unless signals_supported?
|
|
38
|
+
expect_int_exception do
|
|
39
|
+
Cmd.run('kill -s INT $$')
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
describe '.run_with_timeout', :if => ImageOptim::Cmd.support_timeout? do
|
|
45
|
+
it 'spawns a process in a thread and returns status' do
|
|
46
|
+
expect(Cmd.run_with_timeout(20, 'sh -c "exit 0"')).to eq(true)
|
|
47
|
+
|
|
48
|
+
[1, 66].each do |status|
|
|
49
|
+
expect(Cmd.run_with_timeout(20, "sh -c \"exit #{status}\"")).
|
|
50
|
+
to eq(false)
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
it 'raises Timeout::Error if process timeout' do
|
|
55
|
+
expect{ Cmd.run_with_timeout(0.001, 'sleep 1') }.
|
|
56
|
+
to raise_error(Cmd::TimeoutExceeded)
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
it 'calls system if timeout is <= zero' do
|
|
60
|
+
expect(Cmd.run_with_timeout(0, 'sh -c "sleep 0.001; exit 0"')).to eq(true)
|
|
61
|
+
|
|
62
|
+
expect(Cmd.run_with_timeout(-1, 'sh -c "sleep 0.001; exit 1"')).
|
|
63
|
+
to eq(false)
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
describe '.capture' do
|
|
68
|
+
it 'calls ` and returns result' do
|
|
69
|
+
output = double
|
|
70
|
+
expect(Cmd).to receive(:`).with('cmd arg arg+').and_return(output)
|
|
71
|
+
allow(Cmd).to receive(:check_status!)
|
|
72
|
+
expect(Cmd.capture('cmd arg arg+')).to eq(output)
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
it 'returns output' do
|
|
76
|
+
expect(Cmd.capture('echo test')).to eq("test\n")
|
|
77
|
+
expect($CHILD_STATUS.exitstatus).to eq(0)
|
|
78
|
+
|
|
79
|
+
expect(Cmd.capture('printf more && sh -c "exit 1"')).to eq('more')
|
|
80
|
+
expect($CHILD_STATUS.exitstatus).to eq(1)
|
|
81
|
+
|
|
82
|
+
expect(Cmd.capture('sh -c "exit 66"')).to eq('')
|
|
83
|
+
expect($CHILD_STATUS.exitstatus).to eq(66)
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
it 'raises SignalException if process terminates after signal' do
|
|
87
|
+
skip 'signals are not supported' unless signals_supported?
|
|
88
|
+
expect_int_exception do
|
|
89
|
+
Cmd.capture('kill -s INT $$')
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
end
|
|
@@ -0,0 +1,254 @@
|
|
|
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 '#cache_dir' do
|
|
71
|
+
before do
|
|
72
|
+
allow(IOConfig).to receive(:read_options).and_return({})
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
it 'is nil by default' do
|
|
76
|
+
config = IOConfig.new({})
|
|
77
|
+
expect(config.cache_dir).to be nil
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
it 'is nil if set to the empty string' do
|
|
81
|
+
config = IOConfig.new(:cache_dir => '')
|
|
82
|
+
expect(config.cache_dir).to be nil
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
describe '#cache_worker_digests' do
|
|
87
|
+
before do
|
|
88
|
+
allow(IOConfig).to receive(:read_options).and_return({})
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
it 'is false by default' do
|
|
92
|
+
config = IOConfig.new({})
|
|
93
|
+
expect(config.cache_worker_digests).to be false
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
describe '#timeout' do
|
|
98
|
+
before do
|
|
99
|
+
allow(IOConfig).to receive(:read_options).and_return({})
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
it 'is 0 by default' do
|
|
103
|
+
config = IOConfig.new({})
|
|
104
|
+
expect(config.timeout).to eq(0)
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
it 'converts value to number' do
|
|
108
|
+
config = IOConfig.new(:timeout => '15')
|
|
109
|
+
expect(config.timeout).to eq(15)
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
describe '#for_worker' do
|
|
114
|
+
before do
|
|
115
|
+
allow(IOConfig).to receive(:read_options).and_return({})
|
|
116
|
+
stub_const('Abc', Class.new do
|
|
117
|
+
def self.bin_sym
|
|
118
|
+
:abc
|
|
119
|
+
end
|
|
120
|
+
end)
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
it 'returns empty hash by default' do
|
|
124
|
+
config = IOConfig.new({})
|
|
125
|
+
expect(config.for_worker(Abc)).to eq({})
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
it 'returns passed hash' do
|
|
129
|
+
config = IOConfig.new(:abc => {:option => true})
|
|
130
|
+
expect(config.for_worker(Abc)).to eq(:option => true)
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
it 'returns {:disable => true} for false' do
|
|
134
|
+
config = IOConfig.new(:abc => false)
|
|
135
|
+
expect(config.for_worker(Abc)).to eq(:disable => true)
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
it 'raises on unknown option' do
|
|
139
|
+
config = IOConfig.new(:abc => 13)
|
|
140
|
+
expect do
|
|
141
|
+
config.for_worker(Abc)
|
|
142
|
+
end.to raise_error(ImageOptim::ConfigurationError)
|
|
143
|
+
end
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
describe '#initialize' do
|
|
147
|
+
it 'reads options from default locations' do
|
|
148
|
+
expect(IOConfig).to receive(:read_options).
|
|
149
|
+
with(IOConfig::GLOBAL_PATH).and_return(:a => 1, :b => 2, :c => 3)
|
|
150
|
+
expect(IOConfig).to receive(:read_options).
|
|
151
|
+
with(IOConfig::LOCAL_PATH).and_return(:a => 10, :b => 20)
|
|
152
|
+
|
|
153
|
+
config = IOConfig.new(:a => 100)
|
|
154
|
+
expect(config.get!(:a)).to eq(100)
|
|
155
|
+
expect(config.get!(:b)).to eq(20)
|
|
156
|
+
expect(config.get!(:c)).to eq(3)
|
|
157
|
+
config.assert_no_unused_options!
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
it 'does not read options with empty config_paths' do
|
|
161
|
+
expect(IOConfig).not_to receive(:read_options)
|
|
162
|
+
|
|
163
|
+
config = IOConfig.new(:config_paths => [])
|
|
164
|
+
config.assert_no_unused_options!
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
it 'reads options from specified paths' do
|
|
168
|
+
expect(IOConfig).to receive(:read_options).
|
|
169
|
+
with('/etc/image_optim.yml').and_return(:a => 1, :b => 2, :c => 3)
|
|
170
|
+
expect(IOConfig).to receive(:read_options).
|
|
171
|
+
with('config/image_optim.yml').and_return(:a => 10, :b => 20)
|
|
172
|
+
|
|
173
|
+
config = IOConfig.new(:a => 100, :config_paths => %w[
|
|
174
|
+
/etc/image_optim.yml
|
|
175
|
+
config/image_optim.yml
|
|
176
|
+
])
|
|
177
|
+
expect(config.get!(:a)).to eq(100)
|
|
178
|
+
expect(config.get!(:b)).to eq(20)
|
|
179
|
+
expect(config.get!(:c)).to eq(3)
|
|
180
|
+
config.assert_no_unused_options!
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
it 'converts config_paths to array' do
|
|
184
|
+
expect(IOConfig).to receive(:read_options).
|
|
185
|
+
with('config/image_optim.yml').and_return({})
|
|
186
|
+
|
|
187
|
+
config = IOConfig.new(:config_paths => 'config/image_optim.yml')
|
|
188
|
+
config.assert_no_unused_options!
|
|
189
|
+
end
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
describe '.read_options' do
|
|
193
|
+
let(:path){ double(:path) }
|
|
194
|
+
let(:full_path){ double(:full_path) }
|
|
195
|
+
|
|
196
|
+
it 'warns if expand path fails' do
|
|
197
|
+
expect(IOConfig).to receive(:warn)
|
|
198
|
+
expect(File).to receive(:expand_path).
|
|
199
|
+
with(path).and_raise(ArgumentError)
|
|
200
|
+
expect(File).not_to receive(:size?)
|
|
201
|
+
|
|
202
|
+
expect(IOConfig.read_options(path)).to eq({})
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
it 'returns empty hash if path is not a file or is an empty file' do
|
|
206
|
+
expect(IOConfig).not_to receive(:warn)
|
|
207
|
+
expect(File).to receive(:expand_path).
|
|
208
|
+
with(path).and_return(full_path)
|
|
209
|
+
expect(File).to receive(:size?).
|
|
210
|
+
with(full_path).and_return(false)
|
|
211
|
+
|
|
212
|
+
expect(IOConfig.read_options(path)).to eq({})
|
|
213
|
+
end
|
|
214
|
+
|
|
215
|
+
it 'returns hash with deep symbolised keys from reader' do
|
|
216
|
+
stringified = {'config' => {'this' => true}}
|
|
217
|
+
symbolized = {:config => {:this => true}}
|
|
218
|
+
|
|
219
|
+
expect(IOConfig).not_to receive(:warn)
|
|
220
|
+
expect(File).to receive(:expand_path).
|
|
221
|
+
with(path).and_return(full_path)
|
|
222
|
+
expect(File).to receive(:size?).
|
|
223
|
+
with(full_path).and_return(true)
|
|
224
|
+
expect(YAML).to receive(:load_file).
|
|
225
|
+
with(full_path).and_return(stringified)
|
|
226
|
+
|
|
227
|
+
expect(IOConfig.read_options(path)).to eq(symbolized)
|
|
228
|
+
end
|
|
229
|
+
|
|
230
|
+
it 'warns and returns an empty hash if reader returns non hash' do
|
|
231
|
+
expect(IOConfig).to receive(:warn)
|
|
232
|
+
expect(File).to receive(:expand_path).
|
|
233
|
+
with(path).and_return(full_path)
|
|
234
|
+
expect(File).to receive(:size?).
|
|
235
|
+
with(full_path).and_return(true)
|
|
236
|
+
expect(YAML).to receive(:load_file).
|
|
237
|
+
with(full_path).and_return([:config])
|
|
238
|
+
|
|
239
|
+
expect(IOConfig.read_options(path)).to eq({})
|
|
240
|
+
end
|
|
241
|
+
|
|
242
|
+
it 'warns and returns an empty hash if reader raises exception' do
|
|
243
|
+
expect(IOConfig).to receive(:warn)
|
|
244
|
+
expect(File).to receive(:expand_path).
|
|
245
|
+
with(path).and_return(full_path)
|
|
246
|
+
expect(File).to receive(:size?).
|
|
247
|
+
with(full_path).and_return(true)
|
|
248
|
+
expect(YAML).to receive(:load_file).
|
|
249
|
+
with(full_path).and_raise
|
|
250
|
+
|
|
251
|
+
expect(IOConfig.read_options(path)).to eq({})
|
|
252
|
+
end
|
|
253
|
+
end
|
|
254
|
+
end
|