imgix 3.2.1 → 3.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -3,6 +3,7 @@
3
3
  module Imgix
4
4
  module ParamHelpers
5
5
  def rect(position)
6
+ warn "Warning: `ParamHelpers.rect` has been deprecated and will be removed in the next major version.\n"
6
7
  @options[:rect] = position and return self if position.is_a?(String)
7
8
 
8
9
  @options[:rect] = [
@@ -10,26 +10,26 @@ module Imgix
10
10
  include ParamHelpers
11
11
 
12
12
  ALIASES = {
13
- width: :w,
14
- height: :h,
15
- rotation: :rot,
13
+ width: :w,
14
+ height: :h,
15
+ rotation: :rot,
16
16
  noise_reduction: :nr,
17
- sharpness: :sharp,
18
- exposure: :exp,
19
- vibrance: :vib,
20
- saturation: :sat,
21
- brightness: :bri,
22
- contrast: :con,
23
- highlight: :high,
24
- shadow: :shad,
25
- gamma: :gam,
26
- pixelate: :px,
27
- halftone: :htn,
28
- watermark: :mark,
29
- text: :txt,
30
- format: :fm,
31
- quality: :q
32
- }
17
+ sharpness: :sharp,
18
+ exposure: :exp,
19
+ vibrance: :vib,
20
+ saturation: :sat,
21
+ brightness: :bri,
22
+ contrast: :con,
23
+ highlight: :high,
24
+ shadow: :shad,
25
+ gamma: :gam,
26
+ pixelate: :px,
27
+ halftone: :htn,
28
+ watermark: :mark,
29
+ text: :txt,
30
+ format: :fm,
31
+ quality: :q
32
+ }.freeze
33
33
 
34
34
  def initialize(prefix, secure_url_token, path = '/')
35
35
  @prefix = prefix
@@ -75,10 +75,16 @@ module Imgix
75
75
 
76
76
  ALIASES.each do |from, to|
77
77
  define_method from do |*args|
78
+ warn "Warning: `Path.#{from}' has been deprecated and " \
79
+ "will be removed in the next major version (along " \
80
+ "with all parameter `ALIASES`).\n"
78
81
  self.send(to, *args)
79
82
  end
80
83
 
81
84
  define_method "#{from}=" do |*args|
85
+ warn "Warning: `Path.#{from}=' has been deprecated and " \
86
+ "will be removed in the next major version (along " \
87
+ "with all parameter `ALIASES`).\n"
82
88
  self.send("#{to}=", *args)
83
89
  return self
84
90
  end
@@ -88,20 +94,20 @@ module Imgix
88
94
  prev_options = @options.dup
89
95
  @options.merge!(params)
90
96
 
91
- width = @options['w'.to_sym]
92
- height = @options['h'.to_sym]
93
- aspect_ratio = @options['ar'.to_sym]
97
+ width = @options[:w]
98
+ height = @options[:h]
99
+ aspect_ratio = @options[:ar]
94
100
 
95
- if ((width) || (height && aspect_ratio))
96
- srcset = build_dpr_srcset(options: options, params:@options)
97
- else
98
- srcset = build_srcset_pairs(options: options, params: @options)
99
- end
101
+ srcset = if width || (height && aspect_ratio)
102
+ build_dpr_srcset(options: options, params: @options)
103
+ else
104
+ build_srcset_pairs(options: options, params: @options)
105
+ end
100
106
 
101
107
  @options = prev_options
102
108
  srcset
103
109
  end
104
-
110
+
105
111
  private
106
112
 
107
113
  def signature
@@ -131,23 +137,24 @@ module Imgix
131
137
  def build_srcset_pairs(options:, params:)
132
138
  srcset = ''
133
139
 
134
- widths = options['widths'.to_sym] || []
135
- width_tolerance = options['width_tolerance'.to_sym] || DEFAULT_WIDTH_TOLERANCE
136
- min_srcset = options['min_width'.to_sym] || MIN_WIDTH
137
- max_srcset = options['max_width'.to_sym] || MAX_WIDTH
140
+ widths = options[:widths] || []
141
+ width_tolerance = options[:width_tolerance] || DEFAULT_WIDTH_TOLERANCE
142
+ min_width = options[:min_width] || MIN_WIDTH
143
+ max_width = options[:max_width] || MAX_WIDTH
138
144
 
139
145
  if !widths.empty?
140
146
  validate_widths!(widths)
141
147
  srcset_widths = widths
142
- elsif width_tolerance != DEFAULT_WIDTH_TOLERANCE or min_srcset != MIN_WIDTH or max_srcset != MAX_WIDTH
143
- validate_range!(min_srcset, max_srcset)
144
- srcset_widths = TARGET_WIDTHS.call(width_tolerance, min_srcset, max_srcset)
148
+ elsif width_tolerance != DEFAULT_WIDTH_TOLERANCE || min_width != MIN_WIDTH || max_width != MAX_WIDTH
149
+ validate_range!(min_width, max_width)
150
+ validate_width_tolerance!(width_tolerance)
151
+ srcset_widths = TARGET_WIDTHS.call(width_tolerance, min_width, max_width)
145
152
  else
146
153
  srcset_widths = @target_widths
147
154
  end
148
155
 
149
156
  for width in srcset_widths do
150
- params['w'.to_sym] = width
157
+ params[:w] = width
151
158
  srcset += "#{to_url(params)} #{width}w,\n"
152
159
  end
153
160
 
@@ -157,17 +164,17 @@ module Imgix
157
164
  def build_dpr_srcset(options:, params:)
158
165
  srcset = ''
159
166
 
160
- disable_variable_quality = options['disable_variable_quality'.to_sym] || false
167
+ disable_variable_quality = options[:disable_variable_quality] || false
161
168
  validate_variable_qualities!(disable_variable_quality)
162
169
 
163
- target_ratios = [1,2,3,4,5]
164
- quality = params['q'.to_sym]
170
+ target_ratios = [1, 2, 3, 4, 5]
171
+ quality = params[:q]
165
172
 
166
173
  for ratio in target_ratios do
167
- params['dpr'.to_sym] = ratio
174
+ params[:dpr] = ratio
168
175
 
169
176
  unless disable_variable_quality
170
- params['q'.to_sym] = quality || DPR_QUALITY[ratio]
177
+ params[:q] = quality || DPR_QUALITY[ratio]
171
178
  end
172
179
 
173
180
  srcset += "#{to_url(params)} #{ratio}x,\n"
@@ -176,30 +183,37 @@ module Imgix
176
183
  srcset[0..-3]
177
184
  end
178
185
 
179
- def validate_widths!(widths)
180
- unless widths.is_a? Array
181
- raise ArgumentError, "The widths argument must be passed a valid array of integers"
182
- else
183
- positive_integers = widths.all? {|i| i.is_a?(Integer) and i > 0}
184
- unless positive_integers
185
- raise ArgumentError, "A custom widths array must only contain positive integer values"
186
- end
186
+ def validate_width_tolerance!(width_tolerance)
187
+ width_increment_error = 'error: `width_tolerance` must be a positive `Numeric` value'
188
+
189
+ if !width_tolerance.is_a?(Numeric) || width_tolerance <= 0
190
+ raise ArgumentError, width_increment_error
187
191
  end
188
192
  end
189
193
 
194
+ def validate_widths!(widths)
195
+ widths_error = 'error: `widths` must be an array of positive `Numeric` values'
196
+ raise ArgumentError, widths_error unless widths.is_a?(Array)
197
+
198
+ all_positive_integers = widths.all? { |i| i.is_a?(Integer) && i > 0 }
199
+ raise ArgumentError, widths_error unless all_positive_integers
200
+ end
201
+
190
202
  def validate_range!(min_srcset, max_srcset)
191
- if min_srcset.is_a? Numeric and max_srcset.is_a? Numeric
192
- unless min_srcset > 0 and max_srcset > 0
193
- raise ArgumentError, "The min and max arguments must be passed positive Numeric values"
194
- end
195
- else
196
- raise ArgumentError, "The min and max arguments must be passed positive Numeric values"
203
+ range_numeric_error = 'error: `min_width` and `max_width` must be positive `Numeric` values'
204
+ unless min_srcset.is_a?(Numeric) && max_srcset.is_a?(Numeric)
205
+ raise ArgumentError, range_numeric_error
206
+ end
207
+
208
+ unless min_srcset > 0 && max_srcset > 0
209
+ raise ArgumentError, range_numeric_error
197
210
  end
198
211
  end
199
212
 
200
- def validate_variable_qualities!(disable_variable_quality)
201
- unless disable_variable_quality.is_a?(TrueClass) || disable_variable_quality.is_a?(FalseClass)
202
- raise ArgumentError, "The disable_variable_quality argument must be passed a Boolean value"
213
+ def validate_variable_qualities!(disable_quality)
214
+ disable_quality_error = 'error: `disable_quality` must be a Boolean value'
215
+ unless disable_quality.is_a?(TrueClass) || disable_quality.is_a?(FalseClass)
216
+ raise ArgumentError, disable_quality_error
203
217
  end
204
218
  end
205
219
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Imgix
4
- VERSION = '3.2.1'
4
+ VERSION = '3.3.0'
5
5
  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
@@ -3,6 +3,27 @@
3
3
  require 'test_helper'
4
4
 
5
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
+
6
27
  def test_creating_a_path
7
28
  path = client.path('/images/demo.png')
8
29
  assert_equal 'https://demo.imgix.net/images/demo.png?s=2c7c157eaf23b06a0deb2f60b81938c4', path.to_url
@@ -14,7 +35,12 @@ class PathTest < Imgix::Test
14
35
  def test_signing_path_with_param
15
36
  url = 'https://demo.imgix.net/images/demo.png?w=200&s=da421114ca238d1f4a927b889f67c34e'
16
37
  path = client.path('/images/demo.png')
17
- path.width = 200
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
+ }
18
44
 
19
45
  assert_equal url, path.to_url
20
46
 
@@ -22,13 +48,23 @@ class PathTest < Imgix::Test
22
48
  assert_equal url, path.to_url(w: 200)
23
49
 
24
50
  path = client.path('/images/demo.png')
25
- assert_equal url, path.width(200).to_url
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
+ }
26
57
  end
27
58
 
28
59
  def test_resetting_defaults
29
60
  url = 'https://demo.imgix.net/images/demo.png?w=200&s=da421114ca238d1f4a927b889f67c34e'
30
61
  path = client.path('/images/demo.png')
31
- path.height = 300
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
+ }
32
68
 
33
69
  assert_equal url, path.defaults.to_url(w: 200)
34
70
  end
@@ -40,7 +76,21 @@ class PathTest < Imgix::Test
40
76
  assert_equal url, path.to_url(h: 200, w: 200)
41
77
 
42
78
  path = client.path('/images/demo.png')
43
- assert_equal url, path.height(200).width(200).to_url
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
44
94
  end
45
95
 
46
96
  def test_path_with_multi_value_param_safely_encoded
@@ -1,716 +1,755 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'test_helper'
2
4
 
3
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
4
746
 
5
- class SrcsetDefault < Imgix::Test
6
- def test_no_parameters
7
- srcset = path.to_srcset()
8
- expected_number_of_pairs = 31
9
- assert_equal expected_number_of_pairs, srcset.split(',').length
10
- end
11
-
12
- def test_srcset_pair_values
13
- resolutions = [100, 116, 134, 156, 182, 210, 244, 282,
14
- 328, 380, 442, 512, 594, 688, 798, 926,
15
- 1074, 1246, 1446, 1678, 1946, 2258, 2618,
16
- 3038, 3524, 4088, 4742, 5500, 6380, 7400, 8192]
17
- srcset = path.to_srcset()
18
- srclist = srcset.split(',').map { |srcset_split|
19
- srcset_split.split(' ')[1].to_i
20
- }
21
-
22
- for i in 0..srclist.length - 1 do
23
- assert_equal(srclist[i], resolutions[i])
24
- end
25
- end
26
-
27
- private
28
- def path
29
- @client ||= Imgix::Client.new(host: 'testing.imgix.net', secure_url_token: 'MYT0KEN', include_library_param: false).path('image.jpg')
30
- end
31
- end
32
-
33
- class SrcsetGivenWidth < Imgix::Test
34
- def test_srcset_in_dpr_form
35
- device_pixel_ratio = 1
36
-
37
- srcset.split(',').map { |src|
38
- ratio = src.split(' ')[1]
39
- assert_equal ("#{device_pixel_ratio}x"), ratio
40
- device_pixel_ratio += 1
41
- }
42
- end
43
-
44
- def test_srcset_has_dpr_params
45
- i = 1
46
- srcset.split(',').map { |srcset_split|
47
- src = srcset_split.split(' ')[0]
48
- assert_includes src, "dpr=#{i}"
49
- i += 1
50
- }
51
- end
52
-
53
- def test_srcset_signs_urls
54
- srcset.split(',').map { |srcset_split|
55
- src = srcset_split.split(' ')[0]
56
- assert_includes src, 's='
57
-
58
- # parses out all parameters except for 's=...'
59
- params = src[src.index('?')..src.index('s=') - 2]
60
-
61
- # parses out the 's=...' parameter
62
- generated_signature = src.slice(src.index('s=') + 2, src.length)
63
-
64
- signature_base = 'MYT0KEN' + '/image.jpg' + params;
65
- expected_signature = Digest::MD5.hexdigest(signature_base)
66
-
67
- assert_equal expected_signature, generated_signature
68
- }
69
- end
70
-
71
- def test_srcset_has_variable_qualities
72
- i = 0
73
- srcset.split(',').map { |src|
74
- assert_includes src, "q=#{DPR_QUALITY[i]}"
75
- i += 1
76
- }
77
- end
78
-
79
- def test_srcset_respects_overriding_quality
80
- quality_override = 100
81
- srcset = Imgix::Client.new(host: 'testing.imgix.net', secure_url_token: 'MYT0KEN', include_library_param: false).path('image.jpg').to_srcset(w:100, q:quality_override)
82
-
83
- srcset.split(',').map { |src|
84
- assert_includes src, "q=#{quality_override}"
85
- }
86
- end
87
-
88
- def test_disable_variable_quality
89
- srcset = Imgix::Client.new(host: 'testing.imgix.net', secure_url_token: 'MYT0KEN', include_library_param: false).path('image.jpg').to_srcset(w:100, options: { disable_variable_quality: true })
90
-
91
- srcset.split(',').map { |src|
92
- assert(not(src.include? "q="))
93
- }
94
- end
95
-
96
- def test_respects_quality_param_when_disabled
97
- quality_override = 100
98
- srcset = Imgix::Client.new(host: 'testing.imgix.net', secure_url_token: 'MYT0KEN', include_library_param: false).path('image.jpg').to_srcset(w:100, q:100, options: { disable_variable_quality: true })
99
-
100
- srcset.split(',').map { |src|
101
- assert_includes src, "q=#{quality_override}"
102
- }
103
- end
104
-
105
- private
106
- DPR_QUALITY = [75, 50, 35, 23, 20]
107
-
108
- def srcset
109
- @client ||= Imgix::Client.new(host: 'testing.imgix.net', secure_url_token: 'MYT0KEN', include_library_param: false).path('image.jpg').to_srcset(w:100)
110
- end
111
- end
112
-
113
- class SrcsetGivenHeight < Imgix::Test
114
- def test_srcset_generates_width_pairs
115
- expected_number_of_pairs = 31
116
- assert_equal expected_number_of_pairs, srcset.split(',').length
117
- end
118
-
119
- def test_srcset_pair_values
120
- resolutions = [100, 116, 134, 156, 182, 210, 244, 282,
121
- 328, 380, 442, 512, 594, 688, 798, 926,
122
- 1074, 1246, 1446, 1678, 1946, 2258, 2618,
123
- 3038, 3524, 4088, 4742, 5500, 6380, 7400, 8192]
124
- srclist = srcset.split(',').map { |srcset_split|
125
- srcset_split.split(' ')[1].to_i
126
- }
127
-
128
- for i in 0..srclist.length - 1 do
129
- assert_equal(srclist[i], resolutions[i])
130
- end
131
- end
132
-
133
- def test_srcset_respects_height_parameter
134
- srcset.split(',').map { |src|
135
- assert_includes src, 'h='
136
- }
137
- end
138
-
139
- def test_srcset_within_bounds
140
- min, *max = srcset.split(',')
141
-
142
- # parse out the width descriptor as an integer
143
- min = min.split(' ')[1].to_i
144
- max = max[max.length - 1].split(' ')[1].to_i
145
-
146
- assert_operator min, :>=, 100
147
- assert_operator max, :<=, 8192
148
- end
149
-
150
- # a 17% testing threshold is used to account for rounding
151
- def test_srcset_iterates_17_percent
152
- increment_allowed = 0.17
153
-
154
- # create an array of widths
155
- widths = srcset.split(',').map { |src|
156
- src.split(' ')[1].to_i
157
- }
158
-
159
- prev = widths[0]
160
-
161
- for i in 1..widths.length - 1 do
162
- element = widths[i]
163
- assert_operator (element.to_f / prev.to_f), :<, (1 + increment_allowed)
164
- prev = element
165
- end
166
- end
167
-
168
- def test_srcset_signs_urls
169
- srcset.split(',').map { |srcset_split|
170
- src = srcset_split.split(' ')[0]
171
- assert_includes src, 's='
172
-
173
- # parses out all parameters except for 's=...'
174
- params = src[src.index('?')..src.index('s=') - 2]
175
-
176
- # parses out the 's=...' parameter
177
- generated_signature = src.slice(src.index('s=') + 2, src.length)
178
-
179
- signature_base = 'MYT0KEN' + '/image.jpg' + params;
180
- expected_signature = Digest::MD5.hexdigest(signature_base)
181
-
182
- assert_equal expected_signature, generated_signature
183
- }
184
- end
185
-
186
- private
187
- def srcset
188
- @client ||= Imgix::Client.new(host: 'testing.imgix.net', secure_url_token: 'MYT0KEN', include_library_param: false).path('image.jpg').to_srcset(h:100)
189
- end
190
- end
191
-
192
- class SrcsetGivenWidthAndHeight < Imgix::Test
193
- def test_srcset_in_dpr_form
194
- device_pixel_ratio = 1
195
- srcset.split(',').map { |src|
196
- ratio = src.split(' ')[1]
197
- assert_equal ("#{device_pixel_ratio}x"), ratio
198
- device_pixel_ratio += 1
199
- }
200
- end
201
-
202
- def test_srcset_has_dpr_params
203
- i = 1
204
- srcset.split(',').map { |srcset_split|
205
- src = srcset_split.split(' ')[0]
206
- assert_includes src, "dpr=#{i}"
207
- i += 1
208
- }
209
- end
210
-
211
- def test_srcset_signs_urls
212
- srcset.split(',').map { |srcset_split|
213
- src = srcset_split.split(' ')[0]
214
- assert_includes src, 's='
215
-
216
- # parses out all parameters except for 's=...'
217
- params = src[src.index('?')..src.index('s=') - 2]
218
-
219
- # parses out the 's=...' parameter
220
- generated_signature = src.slice(src.index('s=') + 2, src.length)
221
-
222
- signature_base = 'MYT0KEN' + '/image.jpg' + params;
223
- expected_signature = Digest::MD5.hexdigest(signature_base)
224
-
225
- assert_equal expected_signature, generated_signature
226
- }
227
- end
228
-
229
- def test_srcset_has_variable_qualities
230
- i = 0
231
- srcset.split(',').map { |src|
232
- assert_includes src, "q=#{DPR_QUALITY[i]}"
233
- i += 1
234
- }
235
- end
236
-
237
- def test_srcset_respects_overriding_quality
238
- quality_override = 100
239
- srcset = Imgix::Client.new(host: 'testing.imgix.net', secure_url_token: 'MYT0KEN', include_library_param: false).path('image.jpg').to_srcset(w:100, h:100, q:quality_override)
240
-
241
- srcset.split(',').map { |src|
242
- assert_includes src, "q=#{quality_override}"
243
- }
244
- end
245
-
246
- def test_disable_variable_quality
247
- srcset = Imgix::Client.new(host: 'testing.imgix.net', secure_url_token: 'MYT0KEN', include_library_param: false).path('image.jpg').to_srcset(w:100, h:100, options: { disable_variable_quality: true })
248
-
249
- srcset.split(',').map { |src|
250
- assert(not(src.include? "q="))
251
- }
252
- end
253
-
254
- def test_respects_quality_param_when_disabled
255
- quality_override = 100
256
- srcset = Imgix::Client.new(host: 'testing.imgix.net', secure_url_token: 'MYT0KEN', include_library_param: false).path('image.jpg').to_srcset(w:100, h:100, q:100, options: { disable_variable_quality: true })
257
-
258
- srcset.split(',').map { |src|
259
- assert_includes src, "q=#{quality_override}"
260
- }
261
- end
262
-
263
- private
264
- DPR_QUALITY = [75, 50, 35, 23, 20]
265
-
266
- def srcset
267
- @client ||= Imgix::Client.new(host: 'testing.imgix.net', secure_url_token: 'MYT0KEN', include_library_param: false).path('image.jpg').to_srcset(w:100,h:100)
268
- end
269
- end
270
-
271
- class SrcsetGivenAspectRatio < Imgix::Test
272
- def test_srcset_generates_width_pairs
273
- expected_number_of_pairs = 31
274
- assert_equal expected_number_of_pairs, srcset.split(',').length
275
- end
276
-
277
- def test_srcset_pair_values
278
- resolutions = [100, 116, 134, 156, 182, 210, 244, 282,
279
- 328, 380, 442, 512, 594, 688, 798, 926,
280
- 1074, 1246, 1446, 1678, 1946, 2258, 2618,
281
- 3038, 3524, 4088, 4742, 5500, 6380, 7400, 8192]
282
- srclist = srcset.split(',').map { |srcset_split|
283
- srcset_split.split(' ')[1].to_i
284
- }
285
-
286
- for i in 0..srclist.length - 1 do
287
- assert_equal(srclist[i], resolutions[i])
288
- end
289
- end
290
-
291
- def test_srcset_within_bounds
292
- min, *max = srcset.split(',')
293
-
294
- # parse out the width descriptor as an integer
295
- min = min.split(' ')[1].to_i
296
- max = max[max.length - 1].split(' ')[1].to_i
297
-
298
- assert_operator min, :>=, 100
299
- assert_operator max, :<=, 8192
300
- end
301
-
302
- # a 17% testing threshold is used to account for rounding
303
- def test_srcset_iterates_17_percent
304
- increment_allowed = 0.17
305
-
306
- # create an array of widths
307
- widths = srcset.split(',').map { |src|
308
- src.split(' ')[1].to_i
309
- }
310
-
311
- prev = widths[0]
312
-
313
- for i in 1..widths.length - 1 do
314
- element = widths[i]
315
- assert_operator (element.to_f / prev.to_f), :<, (1 + increment_allowed)
316
- prev = element
317
- end
318
- end
319
-
320
- def test_srcset_signs_urls
321
- srcset.split(',').map { |srcset_split|
322
- src = srcset_split.split(' ')[0]
323
- assert_includes src, 's='
324
-
325
- # parses out all parameters except for 's=...'
326
- params = src[src.index('?')..src.index('s=') - 2]
327
-
328
- # parses out the 's=...' parameter
329
- generated_signature = src.slice(src.index('s=') + 2, src.length)
330
-
331
- signature_base = 'MYT0KEN' + '/image.jpg' + params;
332
- expected_signature = Digest::MD5.hexdigest(signature_base)
333
-
334
- assert_equal expected_signature, generated_signature
335
- }
336
- end
337
-
338
- private
339
- def srcset
340
- @client ||= Imgix::Client.new(host: 'testing.imgix.net', secure_url_token: 'MYT0KEN', include_library_param: false).path('image.jpg').to_srcset(ar:'3:2')
341
- end
342
- end
343
-
344
- class SrcsetGivenAspectRatioAndHeight < Imgix::Test
345
- def test_srcset_in_dpr_form
346
- device_pixel_ratio = 1
347
-
348
- srcset.split(',').map { |src|
349
- ratio = src.split(' ')[1]
350
- assert_equal ("#{device_pixel_ratio}x"), ratio
351
- device_pixel_ratio += 1
352
- }
353
- end
354
-
355
- def test_srcset_has_dpr_params
356
- i = 1
357
- srcset.split(',').map { |srcset_split|
358
- src = srcset_split.split(' ')[0]
359
- assert_includes src, "dpr=#{i}"
360
- i += 1
361
- }
362
- end
363
-
364
- def test_srcset_signs_urls
365
- srcset.split(',').map { |srcset_split|
366
- src = srcset_split.split(' ')[0]
367
- assert_includes src, 's='
368
-
369
- # parses out all parameters except for 's=...'
370
- params = src[src.index('?')..src.index('s=') - 2]
371
-
372
- # parses out the 's=...' parameter
373
- generated_signature = src.slice(src.index('s=') + 2, src.length)
374
-
375
- signature_base = 'MYT0KEN' + '/image.jpg' + params;
376
- expected_signature = Digest::MD5.hexdigest(signature_base)
377
-
378
- assert_equal expected_signature, generated_signature
379
- }
380
- end
381
-
382
- def test_srcset_has_variable_qualities
383
- i = 0
384
- srcset.split(',').map { |src|
385
- assert_includes src, "q=#{DPR_QUALITY[i]}"
386
- i += 1
387
- }
388
- end
389
-
390
- def test_srcset_respects_overriding_quality
391
- quality_override = 100
392
- srcset = Imgix::Client.new(host: 'testing.imgix.net', secure_url_token: 'MYT0KEN', include_library_param: false).path('image.jpg').to_srcset(w:100, ar:'3:2', q:quality_override)
393
-
394
- srcset.split(',').map { |src|
395
- assert_includes src, "q=#{quality_override}"
396
- }
397
- end
398
-
399
- def test_disable_variable_quality
400
- srcset = Imgix::Client.new(host: 'testing.imgix.net', secure_url_token: 'MYT0KEN', include_library_param: false).path('image.jpg').to_srcset(w:100, ar:'3:2', options: { disable_variable_quality: true })
401
-
402
- srcset.split(',').map { |src|
403
- assert(not(src.include? "q="))
404
- }
405
- end
406
-
407
- def test_respects_quality_param_when_disabled
408
- quality_override = 100
409
- srcset = Imgix::Client.new(host: 'testing.imgix.net', secure_url_token: 'MYT0KEN', include_library_param: false).path('image.jpg').to_srcset(w:100, h:100, q:100, options: { disable_variable_quality: true })
410
-
411
- srcset.split(',').map { |src|
412
- assert_includes src, "q=#{quality_override}"
413
- }
414
- end
415
-
416
- private
417
- DPR_QUALITY = [75, 50, 35, 23, 20]
418
-
419
- def srcset
420
- @client ||= Imgix::Client.new(host: 'testing.imgix.net', secure_url_token: 'MYT0KEN', include_library_param: false).path('image.jpg').to_srcset({h:100,ar:'3:2'})
421
- end
422
- end
423
-
424
- class SrcsetWidthTolerance < Imgix::Test
425
- def test_srcset_generates_width_pairs
426
- expected_number_of_pairs = 15
427
- assert_equal expected_number_of_pairs, srcset.split(',').length
428
- end
429
-
430
- def test_srcset_pair_values
431
- resolutions = [100,140,196,274,384,538,752,1054,1476,2066,2892,4050,5670,7938,8192]
432
- srclist = srcset.split(',').map { |srcset_split|
433
- srcset_split.split(' ')[1].to_i
434
- }
435
-
436
- for i in 0..srclist.length - 1 do
437
- assert_equal(srclist[i], resolutions[i])
438
- end
439
- end
440
-
441
- def test_srcset_within_bounds
442
- min, *max = srcset.split(',')
443
-
444
- # parse out the width descriptor as an integer
445
- min = min.split(' ')[1].to_i
446
- max = max[max.length - 1].split(' ')[1].to_i
447
- assert_operator min, :>=, 100
448
- assert_operator max, :<=, 8192
449
- end
450
-
451
- # a 41% testing threshold is used to account for rounding
452
- def test_srcset_iterates_41_percent
453
- increment_allowed = 0.41
454
-
455
- # create an array of widths
456
- widths = srcset.split(',').map { |src|
457
- src.split(' ')[1].to_i
458
- }
459
-
460
- prev = widths[0]
461
-
462
- for i in 1..widths.length - 1 do
463
- element = widths[i]
464
- assert_operator (element.to_f / prev.to_f), :<, (1 + increment_allowed)
465
- prev = element
466
- end
467
- end
468
-
469
- def test_invalid_tolerance_emits_error
470
- assert_raises(ArgumentError) {
471
- Imgix::Client.new(host: 'testing.imgix.net')
472
- .path('image.jpg')
473
- .to_srcset(options: {width_tolerance: 'abc'})
474
- }
475
- end
476
-
477
- def test_negative_tolerance_emits_error
478
- assert_raises(ArgumentError) {
479
- Imgix::Client.new(host: 'testing.imgix.net')
480
- .path('image.jpg')
481
- .to_srcset(options: {width_tolerance: -0.10})
482
- }
483
- end
484
-
485
- def test_with_param_after
486
- srcset = Imgix::Client.new(host: 'testing.imgix.net', secure_url_token: 'MYT0KEN', include_library_param: false)
487
- .path('image.jpg')
488
- .to_srcset(options: {width_tolerance: 0.20}, h:1000, fit:"clip")
489
- assert_includes(srcset, "h=")
490
- assert(not(srcset.include? "width_tolerance="))
491
- end
492
-
493
- def test_with_param_before
494
- srcset = Imgix::Client.new(host: 'testing.imgix.net', secure_url_token: 'MYT0KEN', include_library_param: false)
495
- .path('image.jpg')
496
- .to_srcset(h:1000, fit:"clip", options: {width_tolerance: 0.20})
497
- assert_includes(srcset, "h=")
498
- assert(not(srcset.include? "width_tolerance="))
499
- end
500
-
501
- private
502
- def srcset
503
- @client ||= Imgix::Client.new(host: 'testing.imgix.net', secure_url_token: 'MYT0KEN', include_library_param: false).path('image.jpg').to_srcset(options: {width_tolerance: 0.20})
504
- end
505
- end
506
-
507
- class SrcsetCustomWidths < Imgix::Test
508
- def test_srcset_generates_width_pairs
509
- expected_number_of_pairs = 4
510
- assert_equal expected_number_of_pairs, srcset.split(',').length
511
- end
512
-
513
- def test_srcset_pair_values
514
- resolutions = [100, 500, 1000, 1800]
515
- srclist = srcset.split(',').map { |srcset_split|
516
- srcset_split.split(' ')[1].to_i
517
- }
518
-
519
- for i in 0..srclist.length - 1 do
520
- assert_equal(srclist[i], resolutions[i])
521
- end
522
- end
523
-
524
- def test_srcset_within_bounds
525
- min, *max = srcset.split(',')
526
-
527
- # parse out the width descriptor as an integer
528
- min = min.split(' ')[1].to_i
529
- max = max[max.length - 1].split(' ')[1].to_i
530
-
531
- assert_operator min, :>=, @widths[0]
532
- assert_operator max, :<=, @widths[-1]
533
- end
534
-
535
- def test_invalid_widths_input_emits_error
536
- assert_raises(ArgumentError) {
537
- Imgix::Client.new(host: 'testing.imgix.net')
538
- .path('image.jpg')
539
- .to_srcset(options: {widths: 'abc'})
540
- }
541
- end
542
-
543
- def test_non_integer_array_emits_error
544
- assert_raises(ArgumentError) {
545
- Imgix::Client.new(host: 'testing.imgix.net')
546
- .path('image.jpg')
547
- .to_srcset(options: {widths: [100, 200, false]})
548
- }
549
- end
550
-
551
- def test_negative_integer_array_emits_error
552
- assert_raises(ArgumentError) {
553
- Imgix::Client.new(host: 'testing.imgix.net')
554
- .path('image.jpg')
555
- .to_srcset(options: {widths: [100, 200, -100]})
556
- }
557
- end
558
-
559
- def test_with_param_after
560
- srcset = Imgix::Client.new(host: 'testing.imgix.net', secure_url_token: 'MYT0KEN', include_library_param: false)
561
- .path('image.jpg')
562
- .to_srcset(options: {widths: [100, 200, 300]}, h:1000, fit:"clip")
563
- assert_includes(srcset, "h=")
564
- assert(not(srcset.include? "widths="))
565
- end
566
-
567
- def test_with_param_before
568
- srcset = Imgix::Client.new(host: 'testing.imgix.net', secure_url_token: 'MYT0KEN', include_library_param: false)
569
- .path('image.jpg')
570
- .to_srcset(h:1000, fit:"clip", options: {widths: [100, 200, 300]})
571
- assert_includes(srcset, "h=")
572
- assert(not(srcset.include? "widths="))
573
- end
574
-
575
- private
576
- def srcset
577
- @widths = [100, 500, 1000, 1800]
578
- @client ||= Imgix::Client.new(
579
- host: 'testing.imgix.net',
580
- include_library_param: false)
581
- .path('image.jpg')
582
- .to_srcset(options: {widths: @widths})
583
- end
584
- end
585
-
586
- class SrcsetMinMaxWidths < Imgix::Test
587
- def test_srcset_generates_width_pairs
588
- expected_number_of_pairs = 11
589
- assert_equal expected_number_of_pairs, srcset.split(',').length
590
- end
591
-
592
- def test_srcset_pair_values
593
- resolutions = [500,580,672,780,906,1050,1218,1414,1640,1902,2000]
594
- srclist = srcset.split(',').map { |srcset_split|
595
- srcset_split.split(' ')[1].to_i
596
- }
597
-
598
- for i in 0..srclist.length - 1 do
599
- assert_equal(srclist[i], resolutions[i])
600
- end
601
- end
602
-
603
- def test_srcset_within_bounds
604
- min, *max = srcset.split(',')
605
-
606
- # parse out the width descriptor as an integer
607
- min = min.split(' ')[1].to_i
608
- max = max[max.length - 1].split(' ')[1].to_i
609
-
610
- assert_operator min, :>=, @MIN
611
- assert_operator max, :<=, @MAX
612
- end
613
-
614
- # a 41% testing threshold is used to account for rounding
615
- def test_with_custom_width_tolerance
616
- srcset = Imgix::Client.new(host: 'testing.imgix.net', secure_url_token: 'MYT0KEN', include_library_param: false).path('image.jpg').to_srcset(options: {min_width: 500, max_width: 2000, width_tolerance: 0.20})
617
-
618
- increment_allowed = 0.41
619
-
620
- # create an array of widths
621
- widths = srcset.split(',').map { |src|
622
- src.split(' ')[1].to_i
623
- }
624
-
625
- prev = widths[0]
626
-
627
- for i in 1..widths.length - 1 do
628
- element = widths[i]
629
- assert_operator (element.to_f / prev.to_f), :<, (1 + increment_allowed)
630
- prev = element
631
- end
632
- end
633
-
634
- def test_invalid_min_emits_error
635
- assert_raises(ArgumentError) {
636
- Imgix::Client.new(host: 'testing.imgix.net')
637
- .path('image.jpg')
638
- .to_srcset(options: {min_width: 'abc'})
639
- }
640
- end
641
-
642
- def test_negative_max_emits_error
643
- assert_raises(ArgumentError) {
644
- Imgix::Client.new(host: 'testing.imgix.net')
645
- .path('image.jpg')
646
- .to_srcset(options: {max_width: -100})
647
- }
648
- end
649
-
650
- def test_with_param_after
651
- srcset = Imgix::Client.new(host: 'testing.imgix.net', include_library_param: false)
652
- .path('image.jpg')
653
- .to_srcset(options: {min_width: 500, max_width:2000}, h:1000, fit:"clip")
654
-
655
- assert_includes(srcset, "h=")
656
- assert(not(srcset.include? "min_width="))
657
- assert(not(srcset.include? "max_width="))
658
- end
659
-
660
- def test_with_param_before
661
- srcset = Imgix::Client.new(host: 'testing.imgix.net', include_library_param: false)
662
- .path('image.jpg')
663
- .to_srcset(h:1000, fit:"clip", options: {min_width: 500, max_width:2000})
664
-
665
- assert_includes(srcset, "h=")
666
- assert(not(srcset.include? "min_width="))
667
- assert(not(srcset.include? "max_width="))
668
- end
669
-
670
- def test_only_min
671
- min_width = 1000
672
- max_width = 8192
673
- srcset = Imgix::Client.new(host: 'testing.imgix.net', include_library_param: false).path('image.jpg').to_srcset(options: {min_width: min_width})
674
-
675
- min, *max = srcset.split(',')
676
-
677
- # parse out the width descriptor as an integer
678
- min = min.split(' ')[1].to_i
679
- max = max[max.length - 1].split(' ')[1].to_i
680
-
681
- assert_operator min, :>=, min_width
682
- assert_operator max, :<=, max_width
683
- end
684
-
685
- def test_only_max
686
- min_width = 100
687
- max_width = 1000
688
- srcset = Imgix::Client.new(host: 'testing.imgix.net', include_library_param: false).path('image.jpg').to_srcset(options: {max_width: max_width})
689
- min, *max = srcset.split(',')
690
-
691
- # parse out the width descriptor as an integer
692
- min = min.split(' ')[1].to_i
693
- max = max[max.length - 1].split(' ')[1].to_i
694
-
695
- assert_operator min, :>=, min_width
696
- assert_operator max, :<=, max_width
697
- end
698
-
699
- def test_max_as_100
700
- srcset = Imgix::Client.new(host: 'testing.imgix.net', include_library_param: false).path('image.jpg').to_srcset(options: {max_width: 100})
701
- assert_equal(srcset, "https://testing.imgix.net/image.jpg?w=100 100w")
702
- end
703
-
704
- def test_min_as_8192
705
- srcset = Imgix::Client.new(host: 'testing.imgix.net', include_library_param: false).path('image.jpg').to_srcset(options: {min_width: 8192})
706
- assert_equal(srcset, "https://testing.imgix.net/image.jpg?w=8192 8192w")
707
- end
708
-
709
- private
710
- def srcset
711
- @MIN = 500
712
- @MAX = 2000
713
- @client ||= Imgix::Client.new(host: 'testing.imgix.net', include_library_param: false).path('image.jpg').to_srcset(options: {min_width: @MIN, max_width: @MAX})
714
- end
747
+ def srcset
748
+ @MIN = 500
749
+ @MAX = 2000
750
+ @client ||= mock_client.to_srcset(
751
+ options: { min_width: @MIN, max_width: @MAX }
752
+ )
715
753
  end
754
+ end
716
755
  end