addressable 2.8.7 → 2.8.9

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.
@@ -1,1264 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # Copyright (C) Bob Aman
4
- #
5
- # Licensed under the Apache License, Version 2.0 (the "License");
6
- # you may not use this file except in compliance with the License.
7
- # You may obtain a copy of the License at
8
- #
9
- # http://www.apache.org/licenses/LICENSE-2.0
10
- #
11
- # Unless required by applicable law or agreed to in writing, software
12
- # distributed under the License is distributed on an "AS IS" BASIS,
13
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
- # See the License for the specific language governing permissions and
15
- # limitations under the License.
16
-
17
-
18
- require "spec_helper"
19
-
20
- require "bigdecimal"
21
- require "timeout"
22
- require "addressable/template"
23
-
24
- shared_examples_for 'expands' do |tests|
25
- tests.each do |template, expansion|
26
- exp = expansion.is_a?(Array) ? expansion.first : expansion
27
- it "#{template} to #{exp}" do
28
- tmpl = Addressable::Template.new(template).expand(subject)
29
- expect(tmpl.to_str).to eq(expansion)
30
- end
31
- end
32
- end
33
-
34
- describe "eql?" do
35
- let(:template) { Addressable::Template.new('https://www.example.com/{foo}') }
36
- it 'is equal when the pattern matches' do
37
- other_template = Addressable::Template.new('https://www.example.com/{foo}')
38
- expect(template).to be_eql(other_template)
39
- expect(other_template).to be_eql(template)
40
- end
41
- it 'is not equal when the pattern differs' do
42
- other_template = Addressable::Template.new('https://www.example.com/{bar}')
43
- expect(template).to_not be_eql(other_template)
44
- expect(other_template).to_not be_eql(template)
45
- end
46
- it 'is not equal to non-templates' do
47
- uri = 'https://www.example.com/foo/bar'
48
- addressable_template = Addressable::Template.new uri
49
- addressable_uri = Addressable::URI.parse uri
50
- expect(addressable_template).to_not be_eql(addressable_uri)
51
- expect(addressable_uri).to_not be_eql(addressable_template)
52
- end
53
- end
54
-
55
- describe "==" do
56
- let(:template) { Addressable::Template.new('https://www.example.com/{foo}') }
57
- it 'is equal when the pattern matches' do
58
- other_template = Addressable::Template.new('https://www.example.com/{foo}')
59
- expect(template).to eq other_template
60
- expect(other_template).to eq template
61
- end
62
- it 'is not equal when the pattern differs' do
63
- other_template = Addressable::Template.new('https://www.example.com/{bar}')
64
- expect(template).not_to eq other_template
65
- expect(other_template).not_to eq template
66
- end
67
- it 'is not equal to non-templates' do
68
- uri = 'https://www.example.com/foo/bar'
69
- addressable_template = Addressable::Template.new uri
70
- addressable_uri = Addressable::URI.parse uri
71
- expect(addressable_template).not_to eq addressable_uri
72
- expect(addressable_uri).not_to eq addressable_template
73
- end
74
- end
75
-
76
- describe "#to_regexp" do
77
- it "does not match the first line of multiline strings" do
78
- uri = "https://www.example.com/bar"
79
- template = Addressable::Template.new(uri)
80
- expect(template.match(uri)).not_to be_nil
81
- expect(template.match("#{uri}\ngarbage")).to be_nil
82
- end
83
- end
84
-
85
- describe "Type conversion" do
86
- subject {
87
- {
88
- :var => true,
89
- :hello => 1234,
90
- :nothing => nil,
91
- :sym => :symbolic,
92
- :decimal => BigDecimal('1')
93
- }
94
- }
95
-
96
- it_behaves_like 'expands', {
97
- '{var}' => 'true',
98
- '{hello}' => '1234',
99
- '{nothing}' => '',
100
- '{sym}' => 'symbolic',
101
- '{decimal}' => RUBY_VERSION < '2.4.0' ? '0.1E1' : '0.1e1'
102
- }
103
- end
104
-
105
- describe "Level 1:" do
106
- subject {
107
- {:var => "value", :hello => "Hello World!"}
108
- }
109
- it_behaves_like 'expands', {
110
- '{var}' => 'value',
111
- '{hello}' => 'Hello%20World%21'
112
- }
113
- end
114
-
115
- describe "Level 2" do
116
- subject {
117
- {
118
- :var => "value",
119
- :hello => "Hello World!",
120
- :path => "/foo/bar"
121
- }
122
- }
123
- context "Operator +:" do
124
- it_behaves_like 'expands', {
125
- '{+var}' => 'value',
126
- '{+hello}' => 'Hello%20World!',
127
- '{+path}/here' => '/foo/bar/here',
128
- 'here?ref={+path}' => 'here?ref=/foo/bar'
129
- }
130
- end
131
- context "Operator #:" do
132
- it_behaves_like 'expands', {
133
- 'X{#var}' => 'X#value',
134
- 'X{#hello}' => 'X#Hello%20World!'
135
- }
136
- end
137
- end
138
-
139
- describe "Level 3" do
140
- subject {
141
- {
142
- :var => "value",
143
- :hello => "Hello World!",
144
- :empty => "",
145
- :path => "/foo/bar",
146
- :x => "1024",
147
- :y => "768"
148
- }
149
- }
150
- context "Operator nil (multiple vars):" do
151
- it_behaves_like 'expands', {
152
- 'map?{x,y}' => 'map?1024,768',
153
- '{x,hello,y}' => '1024,Hello%20World%21,768'
154
- }
155
- end
156
- context "Operator + (multiple vars):" do
157
- it_behaves_like 'expands', {
158
- '{+x,hello,y}' => '1024,Hello%20World!,768',
159
- '{+path,x}/here' => '/foo/bar,1024/here'
160
- }
161
- end
162
- context "Operator # (multiple vars):" do
163
- it_behaves_like 'expands', {
164
- '{#x,hello,y}' => '#1024,Hello%20World!,768',
165
- '{#path,x}/here' => '#/foo/bar,1024/here'
166
- }
167
- end
168
- context "Operator ." do
169
- it_behaves_like 'expands', {
170
- 'X{.var}' => 'X.value',
171
- 'X{.x,y}' => 'X.1024.768'
172
- }
173
- end
174
- context "Operator /" do
175
- it_behaves_like 'expands', {
176
- '{/var}' => '/value',
177
- '{/var,x}/here' => '/value/1024/here'
178
- }
179
- end
180
- context "Operator ;" do
181
- it_behaves_like 'expands', {
182
- '{;x,y}' => ';x=1024;y=768',
183
- '{;x,y,empty}' => ';x=1024;y=768;empty'
184
- }
185
- end
186
- context "Operator ?" do
187
- it_behaves_like 'expands', {
188
- '{?x,y}' => '?x=1024&y=768',
189
- '{?x,y,empty}' => '?x=1024&y=768&empty='
190
- }
191
- end
192
- context "Operator &" do
193
- it_behaves_like 'expands', {
194
- '?fixed=yes{&x}' => '?fixed=yes&x=1024',
195
- '{&x,y,empty}' => '&x=1024&y=768&empty='
196
- }
197
- end
198
- end
199
-
200
- describe "Level 4" do
201
- subject {
202
- {
203
- :var => "value",
204
- :hello => "Hello World!",
205
- :path => "/foo/bar",
206
- :semi => ";",
207
- :list => %w(red green blue),
208
- :keys => {"semi" => ';', "dot" => '.', :comma => ','}
209
- }
210
- }
211
- context "Expansion with value modifiers" do
212
- it_behaves_like 'expands', {
213
- '{var:3}' => 'val',
214
- '{var:30}' => 'value',
215
- '{list}' => 'red,green,blue',
216
- '{list*}' => 'red,green,blue',
217
- '{keys}' => 'semi,%3B,dot,.,comma,%2C',
218
- '{keys*}' => 'semi=%3B,dot=.,comma=%2C',
219
- }
220
- end
221
- context "Operator + with value modifiers" do
222
- it_behaves_like 'expands', {
223
- '{+path:6}/here' => '/foo/b/here',
224
- '{+list}' => 'red,green,blue',
225
- '{+list*}' => 'red,green,blue',
226
- '{+keys}' => 'semi,;,dot,.,comma,,',
227
- '{+keys*}' => 'semi=;,dot=.,comma=,',
228
- }
229
- end
230
- context "Operator # with value modifiers" do
231
- it_behaves_like 'expands', {
232
- '{#path:6}/here' => '#/foo/b/here',
233
- '{#list}' => '#red,green,blue',
234
- '{#list*}' => '#red,green,blue',
235
- '{#keys}' => '#semi,;,dot,.,comma,,',
236
- '{#keys*}' => '#semi=;,dot=.,comma=,',
237
- }
238
- end
239
- context "Operator . with value modifiers" do
240
- it_behaves_like 'expands', {
241
- 'X{.var:3}' => 'X.val',
242
- 'X{.list}' => 'X.red,green,blue',
243
- 'X{.list*}' => 'X.red.green.blue',
244
- 'X{.keys}' => 'X.semi,%3B,dot,.,comma,%2C',
245
- 'X{.keys*}' => 'X.semi=%3B.dot=..comma=%2C',
246
- }
247
- end
248
- context "Operator / with value modifiers" do
249
- it_behaves_like 'expands', {
250
- '{/var:1,var}' => '/v/value',
251
- '{/list}' => '/red,green,blue',
252
- '{/list*}' => '/red/green/blue',
253
- '{/list*,path:4}' => '/red/green/blue/%2Ffoo',
254
- '{/keys}' => '/semi,%3B,dot,.,comma,%2C',
255
- '{/keys*}' => '/semi=%3B/dot=./comma=%2C',
256
- }
257
- end
258
- context "Operator ; with value modifiers" do
259
- it_behaves_like 'expands', {
260
- '{;hello:5}' => ';hello=Hello',
261
- '{;list}' => ';list=red,green,blue',
262
- '{;list*}' => ';list=red;list=green;list=blue',
263
- '{;keys}' => ';keys=semi,%3B,dot,.,comma,%2C',
264
- '{;keys*}' => ';semi=%3B;dot=.;comma=%2C',
265
- }
266
- end
267
- context "Operator ? with value modifiers" do
268
- it_behaves_like 'expands', {
269
- '{?var:3}' => '?var=val',
270
- '{?list}' => '?list=red,green,blue',
271
- '{?list*}' => '?list=red&list=green&list=blue',
272
- '{?keys}' => '?keys=semi,%3B,dot,.,comma,%2C',
273
- '{?keys*}' => '?semi=%3B&dot=.&comma=%2C',
274
- }
275
- end
276
- context "Operator & with value modifiers" do
277
- it_behaves_like 'expands', {
278
- '{&var:3}' => '&var=val',
279
- '{&list}' => '&list=red,green,blue',
280
- '{&list*}' => '&list=red&list=green&list=blue',
281
- '{&keys}' => '&keys=semi,%3B,dot,.,comma,%2C',
282
- '{&keys*}' => '&semi=%3B&dot=.&comma=%2C',
283
- }
284
- end
285
- end
286
- describe "Modifiers" do
287
- subject {
288
- {
289
- :var => "value",
290
- :semi => ";",
291
- :year => [1965, 2000, 2012],
292
- :dom => %w(example com)
293
- }
294
- }
295
- context "length" do
296
- it_behaves_like 'expands', {
297
- '{var:3}' => 'val',
298
- '{var:30}' => 'value',
299
- '{var}' => 'value',
300
- '{semi}' => '%3B',
301
- '{semi:2}' => '%3B'
302
- }
303
- end
304
- context "explode" do
305
- it_behaves_like 'expands', {
306
- 'find{?year*}' => 'find?year=1965&year=2000&year=2012',
307
- 'www{.dom*}' => 'www.example.com',
308
- }
309
- end
310
- end
311
- describe "Expansion" do
312
- subject {
313
- {
314
- :count => ["one", "two", "three"],
315
- :dom => ["example", "com"],
316
- :dub => "me/too",
317
- :hello => "Hello World!",
318
- :half => "50%",
319
- :var => "value",
320
- :who => "fred",
321
- :base => "http://example.com/home/",
322
- :path => "/foo/bar",
323
- :list => ["red", "green", "blue"],
324
- :keys => {"semi" => ";","dot" => ".",:comma => ","},
325
- :v => "6",
326
- :x => "1024",
327
- :y => "768",
328
- :empty => "",
329
- :empty_keys => {},
330
- :undef => nil
331
- }
332
- }
333
- context "concatenation" do
334
- it_behaves_like 'expands', {
335
- '{count}' => 'one,two,three',
336
- '{count*}' => 'one,two,three',
337
- '{/count}' => '/one,two,three',
338
- '{/count*}' => '/one/two/three',
339
- '{;count}' => ';count=one,two,three',
340
- '{;count*}' => ';count=one;count=two;count=three',
341
- '{?count}' => '?count=one,two,three',
342
- '{?count*}' => '?count=one&count=two&count=three',
343
- '{&count*}' => '&count=one&count=two&count=three'
344
- }
345
- end
346
- context "simple expansion" do
347
- it_behaves_like 'expands', {
348
- '{var}' => 'value',
349
- '{hello}' => 'Hello%20World%21',
350
- '{half}' => '50%25',
351
- 'O{empty}X' => 'OX',
352
- 'O{undef}X' => 'OX',
353
- '{x,y}' => '1024,768',
354
- '{x,hello,y}' => '1024,Hello%20World%21,768',
355
- '?{x,empty}' => '?1024,',
356
- '?{x,undef}' => '?1024',
357
- '?{undef,y}' => '?768',
358
- '{var:3}' => 'val',
359
- '{var:30}' => 'value',
360
- '{list}' => 'red,green,blue',
361
- '{list*}' => 'red,green,blue',
362
- '{keys}' => 'semi,%3B,dot,.,comma,%2C',
363
- '{keys*}' => 'semi=%3B,dot=.,comma=%2C',
364
- }
365
- end
366
- context "reserved expansion (+)" do
367
- it_behaves_like 'expands', {
368
- '{+var}' => 'value',
369
- '{+hello}' => 'Hello%20World!',
370
- '{+half}' => '50%25',
371
- '{base}index' => 'http%3A%2F%2Fexample.com%2Fhome%2Findex',
372
- '{+base}index' => 'http://example.com/home/index',
373
- 'O{+empty}X' => 'OX',
374
- 'O{+undef}X' => 'OX',
375
- '{+path}/here' => '/foo/bar/here',
376
- 'here?ref={+path}' => 'here?ref=/foo/bar',
377
- 'up{+path}{var}/here' => 'up/foo/barvalue/here',
378
- '{+x,hello,y}' => '1024,Hello%20World!,768',
379
- '{+path,x}/here' => '/foo/bar,1024/here',
380
- '{+path:6}/here' => '/foo/b/here',
381
- '{+list}' => 'red,green,blue',
382
- '{+list*}' => 'red,green,blue',
383
- '{+keys}' => 'semi,;,dot,.,comma,,',
384
- '{+keys*}' => 'semi=;,dot=.,comma=,',
385
- }
386
- end
387
- context "fragment expansion (#)" do
388
- it_behaves_like 'expands', {
389
- '{#var}' => '#value',
390
- '{#hello}' => '#Hello%20World!',
391
- '{#half}' => '#50%25',
392
- 'foo{#empty}' => 'foo#',
393
- 'foo{#undef}' => 'foo',
394
- '{#x,hello,y}' => '#1024,Hello%20World!,768',
395
- '{#path,x}/here' => '#/foo/bar,1024/here',
396
- '{#path:6}/here' => '#/foo/b/here',
397
- '{#list}' => '#red,green,blue',
398
- '{#list*}' => '#red,green,blue',
399
- '{#keys}' => '#semi,;,dot,.,comma,,',
400
- '{#keys*}' => '#semi=;,dot=.,comma=,',
401
- }
402
- end
403
- context "label expansion (.)" do
404
- it_behaves_like 'expands', {
405
- '{.who}' => '.fred',
406
- '{.who,who}' => '.fred.fred',
407
- '{.half,who}' => '.50%25.fred',
408
- 'www{.dom*}' => 'www.example.com',
409
- 'X{.var}' => 'X.value',
410
- 'X{.empty}' => 'X.',
411
- 'X{.undef}' => 'X',
412
- 'X{.var:3}' => 'X.val',
413
- 'X{.list}' => 'X.red,green,blue',
414
- 'X{.list*}' => 'X.red.green.blue',
415
- 'X{.keys}' => 'X.semi,%3B,dot,.,comma,%2C',
416
- 'X{.keys*}' => 'X.semi=%3B.dot=..comma=%2C',
417
- 'X{.empty_keys}' => 'X',
418
- 'X{.empty_keys*}' => 'X'
419
- }
420
- end
421
- context "path expansion (/)" do
422
- it_behaves_like 'expands', {
423
- '{/who}' => '/fred',
424
- '{/who,who}' => '/fred/fred',
425
- '{/half,who}' => '/50%25/fred',
426
- '{/who,dub}' => '/fred/me%2Ftoo',
427
- '{/var}' => '/value',
428
- '{/var,empty}' => '/value/',
429
- '{/var,undef}' => '/value',
430
- '{/var,x}/here' => '/value/1024/here',
431
- '{/var:1,var}' => '/v/value',
432
- '{/list}' => '/red,green,blue',
433
- '{/list*}' => '/red/green/blue',
434
- '{/list*,path:4}' => '/red/green/blue/%2Ffoo',
435
- '{/keys}' => '/semi,%3B,dot,.,comma,%2C',
436
- '{/keys*}' => '/semi=%3B/dot=./comma=%2C',
437
- }
438
- end
439
- context "path-style expansion (;)" do
440
- it_behaves_like 'expands', {
441
- '{;who}' => ';who=fred',
442
- '{;half}' => ';half=50%25',
443
- '{;empty}' => ';empty',
444
- '{;v,empty,who}' => ';v=6;empty;who=fred',
445
- '{;v,bar,who}' => ';v=6;who=fred',
446
- '{;x,y}' => ';x=1024;y=768',
447
- '{;x,y,empty}' => ';x=1024;y=768;empty',
448
- '{;x,y,undef}' => ';x=1024;y=768',
449
- '{;hello:5}' => ';hello=Hello',
450
- '{;list}' => ';list=red,green,blue',
451
- '{;list*}' => ';list=red;list=green;list=blue',
452
- '{;keys}' => ';keys=semi,%3B,dot,.,comma,%2C',
453
- '{;keys*}' => ';semi=%3B;dot=.;comma=%2C',
454
- }
455
- end
456
- context "form query expansion (?)" do
457
- it_behaves_like 'expands', {
458
- '{?who}' => '?who=fred',
459
- '{?half}' => '?half=50%25',
460
- '{?x,y}' => '?x=1024&y=768',
461
- '{?x,y,empty}' => '?x=1024&y=768&empty=',
462
- '{?x,y,undef}' => '?x=1024&y=768',
463
- '{?var:3}' => '?var=val',
464
- '{?list}' => '?list=red,green,blue',
465
- '{?list*}' => '?list=red&list=green&list=blue',
466
- '{?keys}' => '?keys=semi,%3B,dot,.,comma,%2C',
467
- '{?keys*}' => '?semi=%3B&dot=.&comma=%2C',
468
- }
469
- end
470
- context "form query expansion (&)" do
471
- it_behaves_like 'expands', {
472
- '{&who}' => '&who=fred',
473
- '{&half}' => '&half=50%25',
474
- '?fixed=yes{&x}' => '?fixed=yes&x=1024',
475
- '{&x,y,empty}' => '&x=1024&y=768&empty=',
476
- '{&x,y,undef}' => '&x=1024&y=768',
477
- '{&var:3}' => '&var=val',
478
- '{&list}' => '&list=red,green,blue',
479
- '{&list*}' => '&list=red&list=green&list=blue',
480
- '{&keys}' => '&keys=semi,%3B,dot,.,comma,%2C',
481
- '{&keys*}' => '&semi=%3B&dot=.&comma=%2C',
482
- }
483
- end
484
- context "non-string key in match data" do
485
- subject {Addressable::Template.new("http://example.com/{one}")}
486
-
487
- it "raises TypeError" do
488
- expect { subject.expand(Object.new => "1") }.to raise_error TypeError
489
- end
490
- end
491
- end
492
-
493
- class ExampleTwoProcessor
494
- def self.restore(name, value)
495
- return value.gsub(/-/, " ") if name == "query"
496
- return value
497
- end
498
-
499
- def self.match(name)
500
- return ".*?" if name == "first"
501
- return ".*"
502
- end
503
- def self.validate(name, value)
504
- return !!(value =~ /^[\w ]+$/) if name == "query"
505
- return true
506
- end
507
-
508
- def self.transform(name, value)
509
- return value.gsub(/ /, "+") if name == "query"
510
- return value
511
- end
512
- end
513
-
514
- class DumbProcessor
515
- def self.match(name)
516
- return ".*?" if name == "first"
517
- end
518
- end
519
-
520
- describe Addressable::Template do
521
- describe 'initialize' do
522
- context 'with a non-string' do
523
- it 'raises a TypeError' do
524
- expect { Addressable::Template.new(nil) }.to raise_error(TypeError)
525
- end
526
- end
527
- end
528
-
529
- describe 'freeze' do
530
- subject { Addressable::Template.new("http://example.com/{first}/{+second}/") }
531
- it 'freezes the template' do
532
- expect(subject.freeze).to be_frozen
533
- end
534
- end
535
-
536
- describe "Matching" do
537
- let(:uri){
538
- Addressable::URI.parse(
539
- "http://example.com/search/an-example-search-query/"
540
- )
541
- }
542
- let(:uri2){
543
- Addressable::URI.parse("http://example.com/a/b/c/")
544
- }
545
- let(:uri3){
546
- Addressable::URI.parse("http://example.com/;a=1;b=2;c=3;first=foo")
547
- }
548
- let(:uri4){
549
- Addressable::URI.parse("http://example.com/?a=1&b=2&c=3&first=foo")
550
- }
551
- let(:uri5){
552
- "http://example.com/foo"
553
- }
554
- context "first uri with ExampleTwoProcessor" do
555
- subject {
556
- Addressable::Template.new(
557
- "http://example.com/search/{query}/"
558
- ).match(uri, ExampleTwoProcessor)
559
- }
560
- its(:variables){ should == ["query"] }
561
- its(:captures){ should == ["an example search query"] }
562
- end
563
-
564
- context "second uri with ExampleTwoProcessor" do
565
- subject {
566
- Addressable::Template.new(
567
- "http://example.com/{first}/{+second}/"
568
- ).match(uri2, ExampleTwoProcessor)
569
- }
570
- its(:variables){ should == ["first", "second"] }
571
- its(:captures){ should == ["a", "b/c"] }
572
- end
573
-
574
- context "second uri with DumbProcessor" do
575
- subject {
576
- Addressable::Template.new(
577
- "http://example.com/{first}/{+second}/"
578
- ).match(uri2, DumbProcessor)
579
- }
580
- its(:variables){ should == ["first", "second"] }
581
- its(:captures){ should == ["a", "b/c"] }
582
- end
583
-
584
- context "second uri" do
585
- subject {
586
- Addressable::Template.new(
587
- "http://example.com/{first}{/second*}/"
588
- ).match(uri2)
589
- }
590
- its(:variables){ should == ["first", "second"] }
591
- its(:captures){ should == ["a", ["b","c"]] }
592
- end
593
- context "third uri" do
594
- subject {
595
- Addressable::Template.new(
596
- "http://example.com/{;hash*,first}"
597
- ).match(uri3)
598
- }
599
- its(:variables){ should == ["hash", "first"] }
600
- its(:captures){ should == [
601
- {"a" => "1", "b" => "2", "c" => "3", "first" => "foo"}, nil] }
602
- end
603
- # Note that this expansion is impossible to revert deterministically - the
604
- # * operator means first could have been a key of hash or a separate key.
605
- # Semantically, a separate key is more likely, but both are possible.
606
- context "fourth uri" do
607
- subject {
608
- Addressable::Template.new(
609
- "http://example.com/{?hash*,first}"
610
- ).match(uri4)
611
- }
612
- its(:variables){ should == ["hash", "first"] }
613
- its(:captures){ should == [
614
- {"a" => "1", "b" => "2", "c" => "3", "first"=> "foo"}, nil] }
615
- end
616
- context "fifth uri" do
617
- subject {
618
- Addressable::Template.new(
619
- "http://example.com/{path}{?hash*,first}"
620
- ).match(uri5)
621
- }
622
- its(:variables){ should == ["path", "hash", "first"] }
623
- its(:captures){ should == ["foo", nil, nil] }
624
- end
625
- end
626
-
627
- describe 'match' do
628
- subject { Addressable::Template.new('http://example.com/first/second/') }
629
- context 'when the URI is the same as the template' do
630
- it 'returns the match data itself with an empty mapping' do
631
- uri = Addressable::URI.parse('http://example.com/first/second/')
632
- match_data = subject.match(uri)
633
- expect(match_data).to be_an Addressable::Template::MatchData
634
- expect(match_data.uri).to eq(uri)
635
- expect(match_data.template).to eq(subject)
636
- expect(match_data.mapping).to be_empty
637
- expect(match_data.inspect).to be_an String
638
- end
639
- end
640
- end
641
-
642
- describe "extract" do
643
- let(:template) {
644
- Addressable::Template.new(
645
- "http://{host}{/segments*}/{?one,two,bogus}{#fragment}"
646
- )
647
- }
648
- let(:uri){ "http://example.com/a/b/c/?one=1&two=2#foo" }
649
- let(:uri2){ "http://example.com/a/b/c/#foo" }
650
- it "should be able to extract with queries" do
651
- expect(template.extract(uri)).to eq({
652
- "host" => "example.com",
653
- "segments" => %w(a b c),
654
- "one" => "1",
655
- "bogus" => nil,
656
- "two" => "2",
657
- "fragment" => "foo"
658
- })
659
- end
660
- it "should be able to extract without queries" do
661
- expect(template.extract(uri2)).to eq({
662
- "host" => "example.com",
663
- "segments" => %w(a b c),
664
- "one" => nil,
665
- "bogus" => nil,
666
- "two" => nil,
667
- "fragment" => "foo"
668
- })
669
- end
670
-
671
- context "issue #137" do
672
- subject { Addressable::Template.new('/path{?page,per_page}') }
673
-
674
- it "can match empty" do
675
- data = subject.extract("/path")
676
- expect(data["page"]).to eq(nil)
677
- expect(data["per_page"]).to eq(nil)
678
- expect(data.keys.sort).to eq(['page', 'per_page'])
679
- end
680
-
681
- it "can match first var" do
682
- data = subject.extract("/path?page=1")
683
- expect(data["page"]).to eq("1")
684
- expect(data["per_page"]).to eq(nil)
685
- expect(data.keys.sort).to eq(['page', 'per_page'])
686
- end
687
-
688
- it "can match second var" do
689
- data = subject.extract("/path?per_page=1")
690
- expect(data["page"]).to eq(nil)
691
- expect(data["per_page"]).to eq("1")
692
- expect(data.keys.sort).to eq(['page', 'per_page'])
693
- end
694
-
695
- it "can match both vars" do
696
- data = subject.extract("/path?page=2&per_page=1")
697
- expect(data["page"]).to eq("2")
698
- expect(data["per_page"]).to eq("1")
699
- expect(data.keys.sort).to eq(['page', 'per_page'])
700
- end
701
- end
702
- end
703
-
704
- describe "Partial expand with symbols" do
705
- context "partial_expand with two simple values" do
706
- subject {
707
- Addressable::Template.new("http://example.com/{one}/{two}/")
708
- }
709
- it "builds a new pattern" do
710
- expect(subject.partial_expand(:one => "1").pattern).to eq(
711
- "http://example.com/1/{two}/"
712
- )
713
- end
714
- end
715
- context "partial_expand query with missing param in middle" do
716
- subject {
717
- Addressable::Template.new("http://example.com/{?one,two,three}/")
718
- }
719
- it "builds a new pattern" do
720
- expect(subject.partial_expand(:one => "1", :three => "3").pattern).to eq(
721
- "http://example.com/?one=1{&two}&three=3/"
722
- )
723
- end
724
- end
725
- context "partial_expand form style query with missing param at beginning" do
726
- subject {
727
- Addressable::Template.new("http://example.com/{?one,two}/")
728
- }
729
- it "builds a new pattern" do
730
- expect(subject.partial_expand(:two => "2").pattern).to eq(
731
- "http://example.com/?two=2{&one}/"
732
- )
733
- end
734
- end
735
- context "issue #307 - partial_expand form query with nil params" do
736
- subject do
737
- Addressable::Template.new("http://example.com/{?one,two,three}/")
738
- end
739
- it "builds a new pattern with two=nil" do
740
- expect(subject.partial_expand(two: nil).pattern).to eq(
741
- "http://example.com/{?one}{&three}/"
742
- )
743
- end
744
- it "builds a new pattern with one=nil and two=nil" do
745
- expect(subject.partial_expand(one: nil, two: nil).pattern).to eq(
746
- "http://example.com/{?three}/"
747
- )
748
- end
749
- it "builds a new pattern with one=1 and two=nil" do
750
- expect(subject.partial_expand(one: 1, two: nil).pattern).to eq(
751
- "http://example.com/?one=1{&three}/"
752
- )
753
- end
754
- it "builds a new pattern with one=nil and two=2" do
755
- expect(subject.partial_expand(one: nil, two: 2).pattern).to eq(
756
- "http://example.com/?two=2{&three}/"
757
- )
758
- end
759
- it "builds a new pattern with one=nil" do
760
- expect(subject.partial_expand(one: nil).pattern).to eq(
761
- "http://example.com/{?two}{&three}/"
762
- )
763
- end
764
- end
765
- context "partial_expand with query string" do
766
- subject {
767
- Addressable::Template.new("http://example.com/{?two,one}/")
768
- }
769
- it "builds a new pattern" do
770
- expect(subject.partial_expand(:one => "1").pattern).to eq(
771
- "http://example.com/?one=1{&two}/"
772
- )
773
- end
774
- end
775
- context "partial_expand with path operator" do
776
- subject {
777
- Addressable::Template.new("http://example.com{/one,two}/")
778
- }
779
- it "builds a new pattern" do
780
- expect(subject.partial_expand(:one => "1").pattern).to eq(
781
- "http://example.com/1{/two}/"
782
- )
783
- end
784
- end
785
- context "partial expand with unicode values" do
786
- subject do
787
- Addressable::Template.new("http://example.com/{resource}/{query}/")
788
- end
789
- it "normalizes unicode by default" do
790
- template = subject.partial_expand("query" => "Cafe\u0301")
791
- expect(template.pattern).to eq(
792
- "http://example.com/{resource}/Caf%C3%A9/"
793
- )
794
- end
795
-
796
- it "normalizes as unicode even with wrong encoding specified" do
797
- template = subject.partial_expand("query" => "Cafe\u0301".b)
798
- expect(template.pattern).to eq(
799
- "http://example.com/{resource}/Caf%C3%A9/"
800
- )
801
- end
802
-
803
- it "raises on invalid unicode input" do
804
- expect {
805
- subject.partial_expand("query" => "M\xE9thode".b)
806
- }.to raise_error(ArgumentError, "invalid byte sequence in UTF-8")
807
- end
808
-
809
- it "does not normalize unicode when byte semantics requested" do
810
- template = subject.partial_expand({"query" => "Cafe\u0301"}, nil, false)
811
- expect(template.pattern).to eq(
812
- "http://example.com/{resource}/Cafe%CC%81/"
813
- )
814
- end
815
- end
816
- end
817
- describe "Partial expand with strings" do
818
- context "partial_expand with two simple values" do
819
- subject {
820
- Addressable::Template.new("http://example.com/{one}/{two}/")
821
- }
822
- it "builds a new pattern" do
823
- expect(subject.partial_expand("one" => "1").pattern).to eq(
824
- "http://example.com/1/{two}/"
825
- )
826
- end
827
- end
828
- context "partial_expand query with missing param in middle" do
829
- subject {
830
- Addressable::Template.new("http://example.com/{?one,two,three}/")
831
- }
832
- it "builds a new pattern" do
833
- expect(subject.partial_expand("one" => "1", "three" => "3").pattern).to eq(
834
- "http://example.com/?one=1{&two}&three=3/"
835
- )
836
- end
837
- end
838
- context "partial_expand with query string" do
839
- subject {
840
- Addressable::Template.new("http://example.com/{?two,one}/")
841
- }
842
- it "builds a new pattern" do
843
- expect(subject.partial_expand("one" => "1").pattern).to eq(
844
- "http://example.com/?one=1{&two}/"
845
- )
846
- end
847
- end
848
- context "partial_expand with path operator" do
849
- subject {
850
- Addressable::Template.new("http://example.com{/one,two}/")
851
- }
852
- it "builds a new pattern" do
853
- expect(subject.partial_expand("one" => "1").pattern).to eq(
854
- "http://example.com/1{/two}/"
855
- )
856
- end
857
- end
858
- end
859
- describe "Expand" do
860
- context "expand with unicode values" do
861
- subject do
862
- Addressable::Template.new("http://example.com/search/{query}/")
863
- end
864
- it "normalizes unicode by default" do
865
- uri = subject.expand("query" => "Cafe\u0301").to_str
866
- expect(uri).to eq("http://example.com/search/Caf%C3%A9/")
867
- end
868
-
869
- it "normalizes as unicode even with wrong encoding specified" do
870
- uri = subject.expand("query" => "Cafe\u0301".b).to_str
871
- expect(uri).to eq("http://example.com/search/Caf%C3%A9/")
872
- end
873
-
874
- it "raises on invalid unicode input" do
875
- expect {
876
- subject.expand("query" => "M\xE9thode".b).to_str
877
- }.to raise_error(ArgumentError, "invalid byte sequence in UTF-8")
878
- end
879
-
880
- it "does not normalize unicode when byte semantics requested" do
881
- uri = subject.expand({ "query" => "Cafe\u0301" }, nil, false).to_str
882
- expect(uri).to eq("http://example.com/search/Cafe%CC%81/")
883
- end
884
- end
885
- context "expand with a processor" do
886
- subject {
887
- Addressable::Template.new("http://example.com/search/{query}/")
888
- }
889
- it "processes spaces" do
890
- expect(subject.expand({"query" => "an example search query"},
891
- ExampleTwoProcessor).to_str).to eq(
892
- "http://example.com/search/an+example+search+query/"
893
- )
894
- end
895
- it "validates" do
896
- expect{
897
- subject.expand({"query" => "Bogus!"},
898
- ExampleTwoProcessor).to_str
899
- }.to raise_error(Addressable::Template::InvalidTemplateValueError)
900
- end
901
- end
902
- context "partial_expand query with missing param in middle" do
903
- subject {
904
- Addressable::Template.new("http://example.com/{?one,two,three}/")
905
- }
906
- it "builds a new pattern" do
907
- expect(subject.partial_expand("one" => "1", "three" => "3").pattern).to eq(
908
- "http://example.com/?one=1{&two}&three=3/"
909
- )
910
- end
911
- end
912
- context "partial_expand with query string" do
913
- subject {
914
- Addressable::Template.new("http://example.com/{?two,one}/")
915
- }
916
- it "builds a new pattern" do
917
- expect(subject.partial_expand("one" => "1").pattern).to eq(
918
- "http://example.com/?one=1{&two}/"
919
- )
920
- end
921
- end
922
- context "partial_expand with path operator" do
923
- subject {
924
- Addressable::Template.new("http://example.com{/one,two}/")
925
- }
926
- it "builds a new pattern" do
927
- expect(subject.partial_expand("one" => "1").pattern).to eq(
928
- "http://example.com/1{/two}/"
929
- )
930
- end
931
- end
932
- end
933
- context "Matching with operators" do
934
- describe "Level 1:" do
935
- subject { Addressable::Template.new("foo{foo}/{bar}baz") }
936
- it "can match" do
937
- data = subject.match("foofoo/bananabaz")
938
- expect(data.mapping["foo"]).to eq("foo")
939
- expect(data.mapping["bar"]).to eq("banana")
940
- end
941
- it "can fail" do
942
- expect(subject.match("bar/foo")).to be_nil
943
- expect(subject.match("foobaz")).to be_nil
944
- end
945
- it "can match empty" do
946
- data = subject.match("foo/baz")
947
- expect(data.mapping["foo"]).to eq(nil)
948
- expect(data.mapping["bar"]).to eq(nil)
949
- end
950
- it "lists vars" do
951
- expect(subject.variables).to eq(["foo", "bar"])
952
- end
953
- end
954
-
955
- describe "Level 2:" do
956
- subject { Addressable::Template.new("foo{+foo}{#bar}baz") }
957
- it "can match" do
958
- data = subject.match("foo/test/banana#bazbaz")
959
- expect(data.mapping["foo"]).to eq("/test/banana")
960
- expect(data.mapping["bar"]).to eq("baz")
961
- end
962
- it "can match empty level 2 #" do
963
- data = subject.match("foo/test/bananabaz")
964
- expect(data.mapping["foo"]).to eq("/test/banana")
965
- expect(data.mapping["bar"]).to eq(nil)
966
- data = subject.match("foo/test/banana#baz")
967
- expect(data.mapping["foo"]).to eq("/test/banana")
968
- expect(data.mapping["bar"]).to eq("")
969
- end
970
- it "can match empty level 2 +" do
971
- data = subject.match("foobaz")
972
- expect(data.mapping["foo"]).to eq(nil)
973
- expect(data.mapping["bar"]).to eq(nil)
974
- data = subject.match("foo#barbaz")
975
- expect(data.mapping["foo"]).to eq(nil)
976
- expect(data.mapping["bar"]).to eq("bar")
977
- end
978
- it "lists vars" do
979
- expect(subject.variables).to eq(["foo", "bar"])
980
- end
981
- end
982
-
983
- describe "Level 3:" do
984
- context "no operator" do
985
- subject { Addressable::Template.new("foo{foo,bar}baz") }
986
- it "can match" do
987
- data = subject.match("foofoo,barbaz")
988
- expect(data.mapping["foo"]).to eq("foo")
989
- expect(data.mapping["bar"]).to eq("bar")
990
- end
991
- it "lists vars" do
992
- expect(subject.variables).to eq(["foo", "bar"])
993
- end
994
- end
995
- context "+ operator" do
996
- subject { Addressable::Template.new("foo{+foo,bar}baz") }
997
- it "can match" do
998
- data = subject.match("foofoo/bar,barbaz")
999
- expect(data.mapping["bar"]).to eq("foo/bar,bar")
1000
- expect(data.mapping["foo"]).to eq("")
1001
- end
1002
- it "lists vars" do
1003
- expect(subject.variables).to eq(["foo", "bar"])
1004
- end
1005
- end
1006
- context ". operator" do
1007
- subject { Addressable::Template.new("foo{.foo,bar}baz") }
1008
- it "can match" do
1009
- data = subject.match("foo.foo.barbaz")
1010
- expect(data.mapping["foo"]).to eq("foo")
1011
- expect(data.mapping["bar"]).to eq("bar")
1012
- end
1013
- it "lists vars" do
1014
- expect(subject.variables).to eq(["foo", "bar"])
1015
- end
1016
- end
1017
- context "/ operator" do
1018
- subject { Addressable::Template.new("foo{/foo,bar}baz") }
1019
- it "can match" do
1020
- data = subject.match("foo/foo/barbaz")
1021
- expect(data.mapping["foo"]).to eq("foo")
1022
- expect(data.mapping["bar"]).to eq("bar")
1023
- end
1024
- it "lists vars" do
1025
- expect(subject.variables).to eq(["foo", "bar"])
1026
- end
1027
- end
1028
- context "; operator" do
1029
- subject { Addressable::Template.new("foo{;foo,bar,baz}baz") }
1030
- it "can match" do
1031
- data = subject.match("foo;foo=bar%20baz;bar=foo;bazbaz")
1032
- expect(data.mapping["foo"]).to eq("bar baz")
1033
- expect(data.mapping["bar"]).to eq("foo")
1034
- expect(data.mapping["baz"]).to eq("")
1035
- end
1036
- it "lists vars" do
1037
- expect(subject.variables).to eq(%w(foo bar baz))
1038
- end
1039
- end
1040
- context "? operator" do
1041
- context "test" do
1042
- subject { Addressable::Template.new("foo{?foo,bar}baz") }
1043
- it "can match" do
1044
- data = subject.match("foo?foo=bar%20baz&bar=foobaz")
1045
- expect(data.mapping["foo"]).to eq("bar baz")
1046
- expect(data.mapping["bar"]).to eq("foo")
1047
- end
1048
- it "lists vars" do
1049
- expect(subject.variables).to eq(%w(foo bar))
1050
- end
1051
- end
1052
-
1053
- context "issue #137" do
1054
- subject { Addressable::Template.new('/path{?page,per_page}') }
1055
-
1056
- it "can match empty" do
1057
- data = subject.match("/path")
1058
- expect(data.mapping["page"]).to eq(nil)
1059
- expect(data.mapping["per_page"]).to eq(nil)
1060
- expect(data.mapping.keys.sort).to eq(['page', 'per_page'])
1061
- end
1062
-
1063
- it "can match first var" do
1064
- data = subject.match("/path?page=1")
1065
- expect(data.mapping["page"]).to eq("1")
1066
- expect(data.mapping["per_page"]).to eq(nil)
1067
- expect(data.mapping.keys.sort).to eq(['page', 'per_page'])
1068
- end
1069
-
1070
- it "can match second var" do
1071
- data = subject.match("/path?per_page=1")
1072
- expect(data.mapping["page"]).to eq(nil)
1073
- expect(data.mapping["per_page"]).to eq("1")
1074
- expect(data.mapping.keys.sort).to eq(['page', 'per_page'])
1075
- end
1076
-
1077
- it "can match both vars" do
1078
- data = subject.match("/path?page=2&per_page=1")
1079
- expect(data.mapping["page"]).to eq("2")
1080
- expect(data.mapping["per_page"]).to eq("1")
1081
- expect(data.mapping.keys.sort).to eq(['page', 'per_page'])
1082
- end
1083
- end
1084
-
1085
- context "issue #71" do
1086
- subject { Addressable::Template.new("http://cyberscore.dev/api/users{?username}") }
1087
- it "can match" do
1088
- data = subject.match("http://cyberscore.dev/api/users?username=foobaz")
1089
- expect(data.mapping["username"]).to eq("foobaz")
1090
- end
1091
- it "lists vars" do
1092
- expect(subject.variables).to eq(%w(username))
1093
- expect(subject.keys).to eq(%w(username))
1094
- end
1095
- end
1096
- end
1097
- context "& operator" do
1098
- subject { Addressable::Template.new("foo{&foo,bar}baz") }
1099
- it "can match" do
1100
- data = subject.match("foo&foo=bar%20baz&bar=foobaz")
1101
- expect(data.mapping["foo"]).to eq("bar baz")
1102
- expect(data.mapping["bar"]).to eq("foo")
1103
- end
1104
- it "lists vars" do
1105
- expect(subject.variables).to eq(%w(foo bar))
1106
- end
1107
- end
1108
- end
1109
- end
1110
-
1111
- context "support regexes:" do
1112
- context "EXPRESSION" do
1113
- subject { Addressable::Template::EXPRESSION }
1114
- it "should be able to match an expression" do
1115
- expect(subject).to match("{foo}")
1116
- expect(subject).to match("{foo,9}")
1117
- expect(subject).to match("{foo.bar,baz}")
1118
- expect(subject).to match("{+foo.bar,baz}")
1119
- expect(subject).to match("{foo,foo%20bar}")
1120
- expect(subject).to match("{#foo:20,baz*}")
1121
- expect(subject).to match("stuff{#foo:20,baz*}things")
1122
- end
1123
- it "should fail on non vars" do
1124
- expect(subject).not_to match("!{foo")
1125
- expect(subject).not_to match("{foo.bar.}")
1126
- expect(subject).not_to match("!{}")
1127
- end
1128
- end
1129
- context "VARNAME" do
1130
- subject { Addressable::Template::VARNAME }
1131
- it "should be able to match a variable" do
1132
- expect(subject).to match("foo")
1133
- expect(subject).to match("9")
1134
- expect(subject).to match("foo.bar")
1135
- expect(subject).to match("foo_bar")
1136
- expect(subject).to match("foo_bar.baz")
1137
- expect(subject).to match("foo%20bar")
1138
- expect(subject).to match("foo%20bar.baz")
1139
- end
1140
- it "should fail on non vars" do
1141
- expect(subject).not_to match("!foo")
1142
- expect(subject).not_to match("foo.bar.")
1143
- expect(subject).not_to match("foo%2%00bar")
1144
- expect(subject).not_to match("foo_ba%r")
1145
- expect(subject).not_to match("foo_bar*")
1146
- expect(subject).not_to match("foo_bar:20")
1147
- end
1148
-
1149
- it 'should parse in a reasonable time' do
1150
- expect do
1151
- Timeout.timeout(0.1) do
1152
- expect(subject).not_to match("0"*25 + "!")
1153
- end
1154
- end.not_to raise_error
1155
- end
1156
- end
1157
- context "VARIABLE_LIST" do
1158
- subject { Addressable::Template::VARIABLE_LIST }
1159
- it "should be able to match a variable list" do
1160
- expect(subject).to match("foo,bar")
1161
- expect(subject).to match("foo")
1162
- expect(subject).to match("foo,bar*,baz")
1163
- expect(subject).to match("foo.bar,bar_baz*,baz:12")
1164
- end
1165
- it "should fail on non vars" do
1166
- expect(subject).not_to match(",foo,bar*,baz")
1167
- expect(subject).not_to match("foo,*bar,baz")
1168
- expect(subject).not_to match("foo,,bar*,baz")
1169
- end
1170
- end
1171
- context "VARSPEC" do
1172
- subject { Addressable::Template::VARSPEC }
1173
- it "should be able to match a variable with modifier" do
1174
- expect(subject).to match("9:8")
1175
- expect(subject).to match("foo.bar*")
1176
- expect(subject).to match("foo_bar:12")
1177
- expect(subject).to match("foo_bar.baz*")
1178
- expect(subject).to match("foo%20bar:12")
1179
- expect(subject).to match("foo%20bar.baz*")
1180
- end
1181
- it "should fail on non vars" do
1182
- expect(subject).not_to match("!foo")
1183
- expect(subject).not_to match("*foo")
1184
- expect(subject).not_to match("fo*o")
1185
- expect(subject).not_to match("fo:o")
1186
- expect(subject).not_to match("foo:")
1187
- end
1188
- end
1189
- end
1190
- end
1191
-
1192
- describe Addressable::Template::MatchData do
1193
- let(:template) { Addressable::Template.new('{foo}/{bar}') }
1194
- subject(:its) { template.match('ab/cd') }
1195
- its(:uri) { should == Addressable::URI.parse('ab/cd') }
1196
- its(:template) { should == template }
1197
- its(:mapping) { should == { 'foo' => 'ab', 'bar' => 'cd' } }
1198
- its(:variables) { should == ['foo', 'bar'] }
1199
- its(:keys) { should == ['foo', 'bar'] }
1200
- its(:names) { should == ['foo', 'bar'] }
1201
- its(:values) { should == ['ab', 'cd'] }
1202
- its(:captures) { should == ['ab', 'cd'] }
1203
- its(:to_a) { should == ['ab/cd', 'ab', 'cd'] }
1204
- its(:to_s) { should == 'ab/cd' }
1205
- its(:string) { should == its.to_s }
1206
- its(:pre_match) { should == "" }
1207
- its(:post_match) { should == "" }
1208
-
1209
- describe 'values_at' do
1210
- it 'returns an array with the values' do
1211
- expect(its.values_at(0, 2)).to eq(['ab/cd', 'cd'])
1212
- end
1213
- it 'allows mixing integer an string keys' do
1214
- expect(its.values_at('foo', 1)).to eq(['ab', 'ab'])
1215
- end
1216
- it 'accepts unknown keys' do
1217
- expect(its.values_at('baz', 'foo')).to eq([nil, 'ab'])
1218
- end
1219
- end
1220
-
1221
- describe '[]' do
1222
- context 'string key' do
1223
- it 'returns the corresponding capture' do
1224
- expect(its['foo']).to eq('ab')
1225
- expect(its['bar']).to eq('cd')
1226
- end
1227
- it 'returns nil for unknown keys' do
1228
- expect(its['baz']).to be_nil
1229
- end
1230
- end
1231
- context 'symbol key' do
1232
- it 'returns the corresponding capture' do
1233
- expect(its[:foo]).to eq('ab')
1234
- expect(its[:bar]).to eq('cd')
1235
- end
1236
- it 'returns nil for unknown keys' do
1237
- expect(its[:baz]).to be_nil
1238
- end
1239
- end
1240
- context 'integer key' do
1241
- it 'returns the full URI for index 0' do
1242
- expect(its[0]).to eq('ab/cd')
1243
- end
1244
- it 'returns the corresponding capture' do
1245
- expect(its[1]).to eq('ab')
1246
- expect(its[2]).to eq('cd')
1247
- end
1248
- it 'returns nil for unknown keys' do
1249
- expect(its[3]).to be_nil
1250
- end
1251
- end
1252
- context 'other key' do
1253
- it 'raises an exception' do
1254
- expect { its[Object.new] }.to raise_error(TypeError)
1255
- end
1256
- end
1257
- context 'with length' do
1258
- it 'returns an array starting at index with given length' do
1259
- expect(its[0, 2]).to eq(['ab/cd', 'ab'])
1260
- expect(its[2, 1]).to eq(['cd'])
1261
- end
1262
- end
1263
- end
1264
- end