imgix 3.3.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.
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'test_helper'
4
+
5
+ class DomainsTest < Imgix::Test
6
+ def test_invalid_domain_append_slash
7
+ assert_raises(ArgumentError) {Imgix::Client.new(host: "assets.imgix.net/")}
8
+ end
9
+
10
+ def test_invalid_domain_prepend_scheme
11
+ assert_raises(ArgumentError) {Imgix::Client.new(host: "https://assets.imgix.net")}
12
+ end
13
+
14
+ def test_invalid_domain_append_dash
15
+ assert_raises(ArgumentError) {Imgix::Client.new(host: "assets.imgix.net-")}
16
+ end
17
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'test_helper'
4
+
5
+ class ParamHelpers < Imgix::Test
6
+ def test_param_helpers_emits_dep_warning
7
+ host_warn = "Warning: The identifier `host' has been deprecated and " \
8
+ "will\nappear as `domain' in the next major version, e.g. " \
9
+ "`@host'\nbecomes `@domain', `options[:host]' becomes " \
10
+ "`options[:domain]'.\n"
11
+
12
+ assert_output(nil, host_warn) {
13
+ client = Imgix::Client.new(host: 'test.imgix.net')
14
+
15
+ rect_warn = "Warning: `ParamHelpers.rect` has been deprecated and " \
16
+ "will be removed in the next major version.\n"
17
+
18
+ assert_output(nil, rect_warn){
19
+ client.path('/images/demo.png').rect(x: 0, y: 50, width: 200, height: 300)
20
+ }
21
+ }
22
+ end
23
+ end
@@ -0,0 +1,182 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'test_helper'
4
+
5
+ class PathTest < Imgix::Test
6
+ def test_prefix_with_arg_warns
7
+ prefix_warn = "Warning: `Client::prefix' will take zero arguments " \
8
+ "in the next major version.\n"
9
+
10
+ assert_output(nil, prefix_warn) {
11
+ Imgix::Client.new(
12
+ domain: 'test.imgix.net',
13
+ include_library_param: false
14
+ ).prefix("")
15
+ }
16
+
17
+ # `new_prefix' is a placeholder until the bump, when it will become
18
+ # `prefix`.
19
+ assert_output(nil, nil) {
20
+ Imgix::Client.new(
21
+ domain: 'test.imgix.net',
22
+ include_library_param: false
23
+ ).new_prefix
24
+ }
25
+ end
26
+
27
+ def test_creating_a_path
28
+ path = client.path('/images/demo.png')
29
+ assert_equal 'https://demo.imgix.net/images/demo.png?s=2c7c157eaf23b06a0deb2f60b81938c4', path.to_url
30
+
31
+ path = client.path('images/demo.png')
32
+ assert_equal 'https://demo.imgix.net/images/demo.png?s=2c7c157eaf23b06a0deb2f60b81938c4', path.to_url
33
+ end
34
+
35
+ def test_signing_path_with_param
36
+ url = 'https://demo.imgix.net/images/demo.png?w=200&s=da421114ca238d1f4a927b889f67c34e'
37
+ path = client.path('/images/demo.png')
38
+
39
+ assert_output(nil, "Warning: `Path.width=' has been deprecated and " \
40
+ "will be removed in the next major version (along " \
41
+ "with all parameter `ALIASES`).\n") {
42
+ path.width = 200
43
+ }
44
+
45
+ assert_equal url, path.to_url
46
+
47
+ path = client.path('/images/demo.png')
48
+ assert_equal url, path.to_url(w: 200)
49
+
50
+ path = client.path('/images/demo.png')
51
+
52
+ assert_output(nil, "Warning: `Path.width' has been deprecated and " \
53
+ "will be removed in the next major version (along " \
54
+ "with all parameter `ALIASES`).\n") {
55
+ assert_equal url, path.width(200).to_url
56
+ }
57
+ end
58
+
59
+ def test_resetting_defaults
60
+ url = 'https://demo.imgix.net/images/demo.png?w=200&s=da421114ca238d1f4a927b889f67c34e'
61
+ path = client.path('/images/demo.png')
62
+
63
+ assert_output(nil, "Warning: `Path.height=' has been deprecated and " \
64
+ "will be removed in the next major version (along " \
65
+ "with all parameter `ALIASES`).\n") {
66
+ path.height = 300
67
+ }
68
+
69
+ assert_equal url, path.defaults.to_url(w: 200)
70
+ end
71
+
72
+ def test_path_with_multiple_params
73
+ url = 'https://demo.imgix.net/images/demo.png?h=200&w=200&s=d570a1ecd765470f7b34a69b56718a7a'
74
+ path = client.path('/images/demo.png')
75
+
76
+ assert_equal url, path.to_url(h: 200, w: 200)
77
+
78
+ path = client.path('/images/demo.png')
79
+
80
+ assert_output(nil, "Warning: `Path.height' has been deprecated and " \
81
+ "will be removed in the next major version (along " \
82
+ "with all parameter `ALIASES`).\n") {
83
+ path.height(200)
84
+ }
85
+
86
+
87
+ assert_output(nil, "Warning: `Path.width' has been deprecated and " \
88
+ "will be removed in the next major version (along " \
89
+ "with all parameter `ALIASES`).\n") {
90
+ path.width(200)
91
+ }
92
+
93
+ assert_equal url, path.to_url
94
+ end
95
+
96
+ def test_path_with_multi_value_param_safely_encoded
97
+ url = 'https://demo.imgix.net/images/demo.png?markalign=middle%2Ccenter&s=f0d0e28a739f022638f4ba6dddf9b694'
98
+ path = client.path('/images/demo.png')
99
+
100
+ assert_equal url, path.markalign('middle', 'center').to_url
101
+ end
102
+
103
+ def test_param_keys_are_escaped
104
+ ix_url = unsigned_client.path('demo.png').to_url({
105
+ :'hello world' => 'interesting'
106
+ })
107
+
108
+ assert_equal "https://demo.imgix.net/demo.png?hello%20world=interesting", ix_url
109
+ end
110
+
111
+ def test_param_values_are_escaped
112
+ ix_url = unsigned_client.path('demo.png').to_url({
113
+ hello_world: '/foo"> <script>alert("hacked")</script><'
114
+ })
115
+
116
+ assert_equal "https://demo.imgix.net/demo.png?hello_world=%2Ffoo%22%3E%20%3Cscript%3Ealert%28%22hacked%22%29%3C%2Fscript%3E%3C", ix_url
117
+ end
118
+
119
+ def test_base64_param_variants_are_base64_encoded
120
+ ix_url = unsigned_client.path('~text').to_url({
121
+ txt64: 'I cannøt belîév∑ it wors! 😱'
122
+ })
123
+
124
+ assert_equal "https://demo.imgix.net/~text?txt64=SSBjYW5uw7h0IGJlbMOuw6l24oiRIGl0IHdvcu-jv3MhIPCfmLE", ix_url
125
+ end
126
+
127
+ def test_host_is_required
128
+ assert_raises(ArgumentError) {Imgix::Client.new}
129
+ end
130
+
131
+ def test_token_is_optional
132
+ client = Imgix::Client.new(host: 'demo.imgix.net', include_library_param: false)
133
+ url = 'https://demo.imgix.net/images/demo.png'
134
+ path = client.path('/images/demo.png')
135
+
136
+ assert_equal url, path.to_url
137
+ end
138
+
139
+ def test_https_is_optional
140
+ client = Imgix::Client.new(host: 'demo.imgix.net', include_library_param: false, use_https: false)
141
+ url = 'http://demo.imgix.net/images/demo.png'
142
+ path = client.path('/images/demo.png')
143
+
144
+ assert_equal url, path.to_url
145
+ end
146
+
147
+ def test_full_url
148
+ path = 'https://google.com/cats.gif'
149
+
150
+ assert_equal "https://demo.imgix.net/#{CGI.escape(path)}?s=e686099fbba86fc2b8141d3c1ff60605", client.path(path).to_url
151
+ end
152
+
153
+ def test_full_url_with_a_space
154
+ path = 'https://my-demo-site.com/files/133467012/avatar icon.png'
155
+ assert_equal "https://demo.imgix.net/#{CGI.escape(path)}?s=35ca40e2e7b6bd208be2c4f7073f658e", client.path(path).to_url
156
+ end
157
+
158
+ def test_include_library_param
159
+ client = Imgix::Client.new(host: 'demo.imgix.net') # enabled by default
160
+ url = client.path('/images/demo.png').to_url
161
+
162
+ assert_equal "ixlib=rb-#{Imgix::VERSION}", URI(url).query
163
+ end
164
+
165
+ def test_configure_library_param
166
+ library = "sinatra"
167
+ version = Imgix::VERSION
168
+ client = Imgix::Client.new(host: 'demo.imgix.net', library_param: library, library_version: version) # enabled by default
169
+ url = client.path('/images/demo.png').to_url
170
+
171
+ assert_equal "ixlib=#{library}-#{version}", URI(url).query
172
+ end
173
+
174
+ private
175
+ def client
176
+ @client ||= Imgix::Client.new(host: 'demo.imgix.net', secure_url_token: '10adc394', include_library_param: false)
177
+ end
178
+
179
+ def unsigned_client
180
+ @unsigned_client ||= Imgix::Client.new(host: 'demo.imgix.net', include_library_param: false)
181
+ end
182
+ end
@@ -0,0 +1,25 @@
1
+ require 'test_helper'
2
+
3
+ class PurgeTest < Imgix::Test
4
+ def test_runtime_error_without_api_key
5
+ assert_raises(RuntimeError) {
6
+ Imgix::Client.new(host: 'demo.imgix.net', include_library_param: false)
7
+ .purge('https://demo.imgix.net/images/demo.png')
8
+ }
9
+ end
10
+
11
+ def test_successful_purge
12
+ stub_request(:post, "https://api.imgix.com/v2/image/purger").
13
+ with(
14
+ body: {"url"=>"https://demo.imgix.net/images/demo.png"}).
15
+ to_return(status: 200)
16
+
17
+ Imgix::Client.new(host: 'demo.imgix.net', api_key: '10adc394')
18
+ .purge('/images/demo.png')
19
+
20
+ assert_requested :post, 'https://api.imgix.com/v2/image/purger',
21
+ body: 'url=https%3A%2F%2Fdemo.imgix.net%2Fimages%2Fdemo.png',
22
+ headers: {'Accept'=>'*/*', 'Accept-Encoding'=>'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', 'Authorization'=>'Basic MTBhZGMzOTQ6', 'Content-Type'=>'application/x-www-form-urlencoded', 'User-Agent'=>"imgix rb-#{ Imgix::VERSION}"},
23
+ times: 1
24
+ end
25
+ end
@@ -0,0 +1,755 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'test_helper'
4
+
5
+ module SrcsetTest
6
+ RESOLUTIONS = [
7
+ 100, 116, 135, 156, 181, 210, 244, 283,
8
+ 328, 380, 441, 512, 594, 689, 799, 927,
9
+ 1075, 1247, 1446, 1678, 1946, 2257, 2619,
10
+ 3038, 3524, 4087, 4741, 5500, 6380, 7401, 8192
11
+ ].freeze
12
+
13
+ DPR_QUALITY = [75, 50, 35, 23, 20].freeze
14
+
15
+ DOMAIN = 'testing.imgix.net'
16
+ TOKEN = 'MYT0KEN'
17
+ JPG_PATH = 'image.jpg'
18
+
19
+ def mock_client
20
+ Imgix::Client.new(
21
+ host: DOMAIN,
22
+ include_library_param: false
23
+ ).path(JPG_PATH)
24
+ end
25
+
26
+ def mock_signed_client
27
+ Imgix::Client.new(
28
+ host: DOMAIN,
29
+ secure_url_token: TOKEN,
30
+ include_library_param: false
31
+ ).path(JPG_PATH)
32
+ end
33
+
34
+ def signature_base(params)
35
+ TOKEN + '/' + JPG_PATH + params
36
+ end
37
+
38
+ def get_sig_from(src)
39
+ src.slice(src.index('s=') + 2, src.length)
40
+ end
41
+
42
+ def get_params_from(src)
43
+ src[src.index('?')..src.index('s=') - 2]
44
+ end
45
+
46
+ def get_expected_signature(src)
47
+ # Ensure signature param exists.
48
+ assert_includes src, 's='
49
+
50
+ params = get_params_from(src)
51
+ signature_base = signature_base(params)
52
+
53
+ Digest::MD5.hexdigest(signature_base)
54
+ end
55
+
56
+ class SrcsetDefault < Imgix::Test
57
+ include SrcsetTest
58
+
59
+ def test_no_parameters
60
+ srcset = path.to_srcset
61
+
62
+ expected_number_of_pairs = 31
63
+ assert_equal expected_number_of_pairs, srcset.split(',').length
64
+ end
65
+
66
+ def test_srcset_pair_values
67
+ resolutions = RESOLUTIONS
68
+ srcset = path.to_srcset
69
+ srclist = srcset.split(',').map do |srcset_split|
70
+ srcset_split.split(' ')[1].to_i
71
+ end
72
+
73
+ for i in 0..srclist.length - 1
74
+ assert_equal(srclist[i], resolutions[i])
75
+ end
76
+ end
77
+
78
+ private
79
+
80
+ def path
81
+ @client ||= mock_signed_client
82
+ end
83
+ end
84
+
85
+ class SrcsetGivenWidth < Imgix::Test
86
+ include SrcsetTest
87
+
88
+ def test_srcset_in_dpr_form
89
+ device_pixel_ratio = 1
90
+
91
+ srcset.split(',').map do |src|
92
+ ratio = src.split(' ')[1]
93
+ assert_equal "#{device_pixel_ratio}x", ratio
94
+ device_pixel_ratio += 1
95
+ end
96
+ end
97
+
98
+ def test_srcset_has_dpr_params
99
+ i = 1
100
+ srcset.split(',').map do |srcset_split|
101
+ src = srcset_split.split(' ')[0]
102
+ assert_includes src, "dpr=#{i}"
103
+ i += 1
104
+ end
105
+ end
106
+
107
+ def test_srcset_signs_urls
108
+ srcset.split(',').map do |srcset_split|
109
+ src = srcset_split.split(' ')[0]
110
+ expected_signature = get_expected_signature(src)
111
+
112
+ assert_includes src, expected_signature
113
+ end
114
+ end
115
+
116
+ def test_srcset_has_variable_qualities
117
+ i = 0
118
+ srcset.split(',').map do |src|
119
+ assert_includes src, "q=#{DPR_QUALITY[i]}"
120
+ i += 1
121
+ end
122
+ end
123
+
124
+ def test_srcset_respects_overriding_quality
125
+ quality_override = 100
126
+ srcset = mock_signed_client.to_srcset(w: 100, q: quality_override)
127
+
128
+ srcset.split(',').map do |src|
129
+ assert_includes src, "q=#{quality_override}"
130
+ end
131
+ end
132
+
133
+ def test_disable_variable_quality
134
+ srcset = mock_signed_client.to_srcset(
135
+ w: 100,
136
+ options: { disable_variable_quality: true }
137
+ )
138
+
139
+ srcset.split(',').map do |src|
140
+ assert(not(src.include?('q=')))
141
+ end
142
+ end
143
+
144
+ def test_respects_quality_param_when_disabled
145
+ quality_override = 100
146
+ srcset = mock_signed_client.to_srcset(
147
+ w: 100, q: 100,
148
+ options: { disable_variable_quality: true }
149
+ )
150
+
151
+ srcset.split(',').map do |src|
152
+ assert_includes src, "q=#{quality_override}"
153
+ end
154
+ end
155
+
156
+ private
157
+
158
+ def srcset
159
+ @client ||= mock_signed_client.to_srcset(w: 100)
160
+ end
161
+ end
162
+
163
+ class SrcsetGivenHeight < Imgix::Test
164
+ include SrcsetTest
165
+
166
+ def test_srcset_generates_width_pairs
167
+ expected_number_of_pairs = 31
168
+ assert_equal expected_number_of_pairs, srcset.split(',').length
169
+ end
170
+
171
+ def test_srcset_pair_values
172
+ resolutions = RESOLUTIONS
173
+ srclist = srcset.split(',').map do |srcset_split|
174
+ srcset_split.split(' ')[1].to_i
175
+ end
176
+
177
+ for i in 0..srclist.length - 1
178
+ assert_equal(srclist[i], resolutions[i])
179
+ end
180
+ end
181
+
182
+ def test_srcset_respects_height_parameter
183
+ srcset.split(',').map do |src|
184
+ assert_includes src, 'h='
185
+ end
186
+ end
187
+
188
+ def test_srcset_within_bounds
189
+ min, *max = srcset.split(',')
190
+
191
+ # parse out the width descriptor as an integer
192
+ min = min.split(' ')[1].to_i
193
+ max = max[max.length - 1].split(' ')[1].to_i
194
+
195
+ assert_operator min, :>=, 100
196
+ assert_operator max, :<=, 8192
197
+ end
198
+
199
+ # a 17% testing threshold is used to account for rounding
200
+ def test_srcset_iterates_17_percent
201
+ increment_allowed = 0.17
202
+
203
+ # create an array of widths
204
+ widths = srcset.split(',').map do |src|
205
+ src.split(' ')[1].to_i
206
+ end
207
+
208
+ prev = widths[0]
209
+
210
+ for i in 1..widths.length - 1
211
+ element = widths[i]
212
+ assert_operator (element.to_f / prev.to_f), :<, (1 + increment_allowed)
213
+ prev = element
214
+ end
215
+ end
216
+
217
+ def test_srcset_signs_urls
218
+ srcset.split(',').map do |srcset_split|
219
+ src = srcset_split.split(' ')[0]
220
+ expected_signature = get_expected_signature(src)
221
+
222
+ assert_includes src, expected_signature
223
+ end
224
+ end
225
+
226
+ private
227
+
228
+ def srcset
229
+ @client ||= mock_signed_client.to_srcset(h: 100)
230
+ end
231
+ end
232
+
233
+ class SrcsetGivenWidthAndHeight < Imgix::Test
234
+ include SrcsetTest
235
+
236
+ def test_srcset_in_dpr_form
237
+ device_pixel_ratio = 1
238
+ srcset.split(',').map do |src|
239
+ ratio = src.split(' ')[1]
240
+ assert_equal "#{device_pixel_ratio}x", ratio
241
+ device_pixel_ratio += 1
242
+ end
243
+ end
244
+
245
+ def test_srcset_has_dpr_params
246
+ i = 1
247
+ srcset.split(',').map do |srcset_split|
248
+ src = srcset_split.split(' ')[0]
249
+ assert_includes src, "dpr=#{i}"
250
+ i += 1
251
+ end
252
+ end
253
+
254
+ def test_srcset_signs_urls
255
+ srcset.split(',').map do |srcset_split|
256
+ src = srcset_split.split(' ')[0]
257
+ expected_signature = get_expected_signature(src)
258
+
259
+ assert_includes src, expected_signature
260
+ end
261
+ end
262
+
263
+ def test_srcset_has_variable_qualities
264
+ i = 0
265
+ srcset.split(',').map do |src|
266
+ assert_includes src, "q=#{DPR_QUALITY[i]}"
267
+ i += 1
268
+ end
269
+ end
270
+
271
+ def test_srcset_respects_overriding_quality
272
+ quality_override = 100
273
+ srcset = mock_signed_client.to_srcset(w: 100, h: 100, q: quality_override)
274
+
275
+ srcset.split(',').map do |src|
276
+ assert_includes src, "q=#{quality_override}"
277
+ end
278
+ end
279
+
280
+ def test_disable_variable_quality
281
+ srcset = mock_signed_client.to_srcset(
282
+ w: 100, h: 100,
283
+ options: { disable_variable_quality: true }
284
+ )
285
+
286
+ srcset.split(',').map do |src|
287
+ assert(not(src.include?('q=')))
288
+ end
289
+ end
290
+
291
+ def test_respects_quality_param_when_disabled
292
+ quality_override = 100
293
+ srcset = mock_signed_client.to_srcset(
294
+ w: 100, h: 100, q: 100,
295
+ options: { disable_variable_quality: true }
296
+ )
297
+
298
+ srcset.split(',').map do |src|
299
+ assert_includes src, "q=#{quality_override}"
300
+ end
301
+ end
302
+
303
+ private
304
+
305
+ def srcset
306
+ @client ||= mock_signed_client.to_srcset(w: 100, h: 100)
307
+ end
308
+ end
309
+
310
+ class SrcsetGivenAspectRatio < Imgix::Test
311
+ include SrcsetTest
312
+
313
+ def test_srcset_generates_width_pairs
314
+ expected_number_of_pairs = 31
315
+ assert_equal expected_number_of_pairs, srcset.split(',').length
316
+ end
317
+
318
+ def test_srcset_pair_values
319
+ srclist = srcset.split(',').map do |srcset_split|
320
+ srcset_split.split(' ')[1].to_i
321
+ end
322
+
323
+ for i in 0..srclist.length - 1
324
+ assert_equal(srclist[i], RESOLUTIONS[i])
325
+ end
326
+ end
327
+
328
+ def test_srcset_within_bounds
329
+ min, *max = srcset.split(',')
330
+
331
+ # parse out the width descriptor as an integer
332
+ min = min.split(' ')[1].to_i
333
+ max = max[max.length - 1].split(' ')[1].to_i
334
+
335
+ assert_operator min, :>=, 100
336
+ assert_operator max, :<=, 8192
337
+ end
338
+
339
+ # a 17% testing threshold is used to account for rounding
340
+ def test_srcset_iterates_17_percent
341
+ increment_allowed = 0.17
342
+
343
+ # create an array of widths
344
+ widths = srcset.split(',').map do |src|
345
+ src.split(' ')[1].to_i
346
+ end
347
+
348
+ prev = widths[0]
349
+
350
+ for i in 1..widths.length - 1
351
+ element = widths[i]
352
+ assert_operator (element.to_f / prev.to_f), :<, (1 + increment_allowed)
353
+ prev = element
354
+ end
355
+ end
356
+
357
+ def test_srcset_signs_urls
358
+ srcset.split(',').map do |srcset_split|
359
+ src = srcset_split.split(' ')[0]
360
+ expected_signature = get_expected_signature(src)
361
+
362
+ assert_includes src, expected_signature
363
+ end
364
+ end
365
+
366
+ private
367
+
368
+ def srcset
369
+ @client ||= mock_signed_client.to_srcset(ar: '3:2')
370
+ end
371
+ end
372
+
373
+ class SrcsetGivenAspectRatioAndHeight < Imgix::Test
374
+ include SrcsetTest
375
+
376
+ def test_srcset_in_dpr_form
377
+ device_pixel_ratio = 1
378
+
379
+ srcset.split(',').map do |src|
380
+ ratio = src.split(' ')[1]
381
+ assert_equal "#{device_pixel_ratio}x", ratio
382
+ device_pixel_ratio += 1
383
+ end
384
+ end
385
+
386
+ def test_srcset_has_dpr_params
387
+ i = 1
388
+ srcset.split(',').map do |srcset_split|
389
+ src = srcset_split.split(' ')[0]
390
+ assert_includes src, "dpr=#{i}"
391
+ i += 1
392
+ end
393
+ end
394
+
395
+ def test_srcset_signs_urls
396
+ srcset.split(',').map do |srcset_split|
397
+ src = srcset_split.split(' ')[0]
398
+ expected_signature = get_expected_signature(src)
399
+
400
+ assert_includes src, expected_signature
401
+ end
402
+ end
403
+
404
+ def test_srcset_has_variable_qualities
405
+ i = 0
406
+ srcset.split(',').map do |src|
407
+ assert_includes src, "q=#{DPR_QUALITY[i]}"
408
+ i += 1
409
+ end
410
+ end
411
+
412
+ def test_srcset_respects_overriding_quality
413
+ quality_override = 100
414
+ srcset = mock_signed_client.to_srcset(
415
+ w: 100, ar: '3:2', q: quality_override
416
+ )
417
+
418
+ srcset.split(',').map do |src|
419
+ assert_includes src, "q=#{quality_override}"
420
+ end
421
+ end
422
+
423
+ def test_disable_variable_quality
424
+ srcset = mock_signed_client.to_srcset(
425
+ w: 100, ar: '3:2',
426
+ options: { disable_variable_quality: true }
427
+ )
428
+
429
+ srcset.split(',').map do |src|
430
+ assert(not(src.include?('q=')))
431
+ end
432
+ end
433
+
434
+ def test_respects_quality_param_when_disabled
435
+ quality_override = 100
436
+ srcset = mock_signed_client.to_srcset(
437
+ w: 100, h: 100, q: 100,
438
+ options: { disable_variable_quality: true }
439
+ )
440
+
441
+ srcset.split(',').map do |src|
442
+ assert_includes src, "q=#{quality_override}"
443
+ end
444
+ end
445
+
446
+ private
447
+
448
+ def srcset
449
+ @client ||= mock_signed_client.to_srcset({ h: 100, ar: '3:2' })
450
+ end
451
+ end
452
+
453
+ class SrcsetWidthTolerance < Imgix::Test
454
+ include SrcsetTest
455
+
456
+ def test_srcset_generates_width_pairs
457
+ expected_number_of_pairs = 15
458
+ assert_equal expected_number_of_pairs, srcset.split(',').length
459
+ end
460
+
461
+ def test_srcset_pair_values
462
+ resolutions = [100, 140, 196, 274, 384,
463
+ 538, 753, 1054, 1476, 2066,
464
+ 2893, 4050, 5669, 7937, 8192]
465
+
466
+ srclist = srcset.split(',').map do |srcset_split|
467
+ srcset_split.split(' ')[1].to_i
468
+ end
469
+
470
+ for i in 0..srclist.length - 1
471
+ assert_equal(srclist[i], resolutions[i])
472
+ end
473
+ end
474
+
475
+ def test_srcset_within_bounds
476
+ min, *max = srcset.split(',')
477
+
478
+ # parse out the width descriptor as an integer
479
+ min = min.split(' ')[1].to_i
480
+ max = max[max.length - 1].split(' ')[1].to_i
481
+ assert_operator min, :>=, 100
482
+ assert_operator max, :<=, 8192
483
+ end
484
+
485
+ # a 41% testing threshold is used to account for rounding
486
+ def test_srcset_iterates_41_percent
487
+ increment_allowed = 0.41
488
+
489
+ # create an array of widths
490
+ widths = srcset.split(',').map do |src|
491
+ src.split(' ')[1].to_i
492
+ end
493
+
494
+ prev = widths[0]
495
+
496
+ for i in 1..widths.length - 1
497
+ element = widths[i]
498
+ assert_operator (element.to_f / prev.to_f), :<, (1 + increment_allowed)
499
+ prev = element
500
+ end
501
+ end
502
+
503
+ def test_invalid_tolerance_emits_error
504
+ assert_raises(ArgumentError) do
505
+ mock_client.to_srcset(options: { width_tolerance: 'abc' })
506
+ end
507
+ end
508
+
509
+ def test_negative_tolerance_emits_error
510
+ assert_raises(ArgumentError) do
511
+ mock_client.to_srcset(options: { width_tolerance: -0.10 })
512
+ end
513
+ end
514
+
515
+ def test_with_param_after
516
+ srcset = mock_signed_client.to_srcset(
517
+ options: { width_tolerance: 0.20 },
518
+ h: 1000, fit: 'clip'
519
+ )
520
+
521
+ assert_includes(srcset, 'h=')
522
+ assert(not(srcset.include?('width_tolerance=')))
523
+ end
524
+
525
+ def test_with_param_before
526
+ srcset = mock_signed_client.to_srcset(
527
+ h: 1000, fit: 'clip',
528
+ options: { width_tolerance: 0.20 }
529
+ )
530
+
531
+ assert_includes(srcset, 'h=')
532
+ assert(not(srcset.include?('width_tolerance=')))
533
+ end
534
+
535
+ private
536
+
537
+ def srcset
538
+ @client ||= mock_signed_client.to_srcset(
539
+ options: { width_tolerance: 0.20 }
540
+ )
541
+ end
542
+ end
543
+
544
+ class SrcsetCustomWidths < Imgix::Test
545
+ include SrcsetTest
546
+
547
+ def test_srcset_generates_width_pairs
548
+ expected_number_of_pairs = 4
549
+ assert_equal expected_number_of_pairs, srcset.split(',').length
550
+ end
551
+
552
+ def test_srcset_pair_values
553
+ resolutions = [100, 500, 1000, 1800]
554
+ srclist = srcset.split(',').map do |srcset_split|
555
+ srcset_split.split(' ')[1].to_i
556
+ end
557
+
558
+ for i in 0..srclist.length - 1
559
+ assert_equal(srclist[i], resolutions[i])
560
+ end
561
+ end
562
+
563
+ def test_srcset_within_bounds
564
+ min, *max = srcset.split(',')
565
+
566
+ # parse out the width descriptor as an integer
567
+ min = min.split(' ')[1].to_i
568
+ max = max[max.length - 1].split(' ')[1].to_i
569
+
570
+ assert_operator min, :>=, @widths[0]
571
+ assert_operator max, :<=, @widths[-1]
572
+ end
573
+
574
+ def test_invalid_widths_input_emits_error
575
+ assert_raises(ArgumentError) do
576
+ mock_client.to_srcset(options: { widths: 'abc' })
577
+ end
578
+ end
579
+
580
+ def test_non_integer_array_emits_error
581
+ assert_raises(ArgumentError) do
582
+ mock_client.to_srcset(options: { widths: [100, 200, false] })
583
+ end
584
+ end
585
+
586
+ def test_negative_integer_array_emits_error
587
+ assert_raises(ArgumentError) do
588
+ mock_client.to_srcset(options: { widths: [100, 200, -100] })
589
+ end
590
+ end
591
+
592
+ def test_with_param_after
593
+ srcset = mock_signed_client.to_srcset(
594
+ options: { widths: [100, 200, 300] },
595
+ h: 1000, fit: 'clip'
596
+ )
597
+
598
+ assert_includes(srcset, 'h=')
599
+ assert(not(srcset.include?('widths=')))
600
+ end
601
+
602
+ def test_with_param_before
603
+ srcset = mock_client.to_srcset(
604
+ h: 1000, fit: 'clip',
605
+ options: { widths: [100, 200, 300] }
606
+ )
607
+ assert_includes(srcset, 'h=')
608
+ assert(not(srcset.include?('widths=')))
609
+ end
610
+
611
+ private
612
+
613
+ def srcset
614
+ @widths = [100, 500, 1000, 1800]
615
+ @client ||= mock_signed_client.to_srcset(options: { widths: @widths })
616
+ end
617
+ end
618
+
619
+ class SrcsetMinMaxWidths < Imgix::Test
620
+ include SrcsetTest
621
+
622
+ def test_srcset_generates_width_pairs
623
+ expected_number_of_pairs = 11
624
+ assert_equal expected_number_of_pairs, srcset.split(',').length
625
+ end
626
+
627
+ def test_srcset_pair_values
628
+ resolutions = [500, 580, 673, 780, 905, 1050,
629
+ 1218, 1413, 1639, 1901, 2000]
630
+ srclist = srcset.split(',').map do |srcset_split|
631
+ srcset_split.split(' ')[1].to_i
632
+ end
633
+
634
+ for i in 0..srclist.length - 1
635
+ assert_equal(srclist[i], resolutions[i])
636
+ end
637
+ end
638
+
639
+ def test_srcset_within_bounds
640
+ min, *max = srcset.split(',')
641
+
642
+ # parse out the width descriptor as an integer
643
+ min = min.split(' ')[1].to_i
644
+ max = max[max.length - 1].split(' ')[1].to_i
645
+
646
+ assert_operator min, :>=, @MIN
647
+ assert_operator max, :<=, @MAX
648
+ end
649
+
650
+ # a 41% testing threshold is used to account for rounding
651
+ def test_with_custom_width_tolerance
652
+ srcset = mock_client.to_srcset(
653
+ options: { min_width: 500, max_width: 2000, width_tolerance: 0.20 }
654
+ )
655
+
656
+ increment_allowed = 0.41
657
+
658
+ # create an array of widths
659
+ widths = srcset.split(',').map do |src|
660
+ src.split(' ')[1].to_i
661
+ end
662
+
663
+ prev = widths[0]
664
+
665
+ for i in 1..widths.length - 1
666
+ element = widths[i]
667
+ assert_operator (element.to_f / prev.to_f), :<, (1 + increment_allowed)
668
+ prev = element
669
+ end
670
+ end
671
+
672
+ def test_invalid_min_emits_error
673
+ assert_raises(ArgumentError) do
674
+ mock_client.to_srcset(options: { min_width: 'abc' })
675
+ end
676
+ end
677
+
678
+ def test_negative_max_emits_error
679
+ assert_raises(ArgumentError) do
680
+ mock_client.to_srcset(options: { max_width: -100 })
681
+ end
682
+ end
683
+
684
+ def test_with_param_after
685
+ srcset = mock_client.to_srcset(
686
+ options: { min_width: 500, max_width: 2000 },
687
+ h: 1000, fit: 'clip'
688
+ )
689
+
690
+ assert_includes(srcset, 'h=')
691
+ assert(not(srcset.include?('min_width=')))
692
+ assert(not(srcset.include?('max_width=')))
693
+ end
694
+
695
+ def test_with_param_before
696
+ srcset = mock_client.to_srcset(
697
+ h: 1000, fit: 'clip',
698
+ options: { min_width: 500, max_width: 2000 }
699
+ )
700
+
701
+ assert_includes(srcset, 'h=')
702
+ assert(not(srcset.include?('min_width=')))
703
+ assert(not(srcset.include?('max_width=')))
704
+ end
705
+
706
+ def test_only_min
707
+ min_width = 1000
708
+ max_width = 8192
709
+ srcset = mock_client.to_srcset(options: { min_width: min_width })
710
+
711
+ min, *max = srcset.split(',')
712
+
713
+ # parse out the width descriptor as an integer
714
+ min = min.split(' ')[1].to_i
715
+ max = max[max.length - 1].split(' ')[1].to_i
716
+
717
+ assert_operator min, :>=, min_width
718
+ assert_operator max, :<=, max_width
719
+ end
720
+
721
+ def test_only_max
722
+ min_width = 100
723
+ max_width = 1000
724
+ srcset = mock_client.to_srcset(options: { max_width: max_width })
725
+ min, *max = srcset.split(',')
726
+
727
+ # parse out the width descriptor as an integer
728
+ min = min.split(' ')[1].to_i
729
+ max = max[max.length - 1].split(' ')[1].to_i
730
+
731
+ assert_operator min, :>=, min_width
732
+ assert_operator max, :<=, max_width
733
+ end
734
+
735
+ def test_max_as_100
736
+ srcset = mock_client.to_srcset(options: { max_width: 100 })
737
+ assert_equal(srcset, 'https://testing.imgix.net/image.jpg?w=100 100w')
738
+ end
739
+
740
+ def test_min_as_8192
741
+ srcset = mock_client.to_srcset(options: { min_width: 8192 })
742
+ assert_equal(srcset, 'https://testing.imgix.net/image.jpg?w=8192 8192w')
743
+ end
744
+
745
+ private
746
+
747
+ def srcset
748
+ @MIN = 500
749
+ @MAX = 2000
750
+ @client ||= mock_client.to_srcset(
751
+ options: { min_width: @MIN, max_width: @MAX }
752
+ )
753
+ end
754
+ end
755
+ end