addressable 2.5.0 → 2.8.8

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,4 +1,5 @@
1
- # coding: utf-8
1
+ # frozen_string_literal: true
2
+
2
3
  # Copyright (C) Bob Aman
3
4
  #
4
5
  # Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,6 +18,7 @@
17
18
  require "spec_helper"
18
19
 
19
20
  require "bigdecimal"
21
+ require "timeout"
20
22
  require "addressable/template"
21
23
 
22
24
  shared_examples_for 'expands' do |tests|
@@ -24,11 +26,7 @@ shared_examples_for 'expands' do |tests|
24
26
  exp = expansion.is_a?(Array) ? expansion.first : expansion
25
27
  it "#{template} to #{exp}" do
26
28
  tmpl = Addressable::Template.new(template).expand(subject)
27
- if expansion.is_a?(Array)
28
- expect(expansion.any?{|i| i == tmpl.to_str}).to be true
29
- else
30
- expect(tmpl.to_str).to eq(expansion)
31
- end
29
+ expect(tmpl.to_str).to eq(expansion)
32
30
  end
33
31
  end
34
32
  end
@@ -75,6 +73,15 @@ describe "==" do
75
73
  end
76
74
  end
77
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
+
78
85
  describe "Type conversion" do
79
86
  subject {
80
87
  {
@@ -82,7 +89,7 @@ describe "Type conversion" do
82
89
  :hello => 1234,
83
90
  :nothing => nil,
84
91
  :sym => :symbolic,
85
- :decimal => BigDecimal.new('1')
92
+ :decimal => BigDecimal('1')
86
93
  }
87
94
  }
88
95
 
@@ -91,7 +98,7 @@ describe "Type conversion" do
91
98
  '{hello}' => '1234',
92
99
  '{nothing}' => '',
93
100
  '{sym}' => 'symbolic',
94
- '{decimal}' => '0.1E1'
101
+ '{decimal}' => RUBY_VERSION < '2.4.0' ? '0.1E1' : '0.1e1'
95
102
  }
96
103
  end
97
104
 
@@ -198,7 +205,7 @@ describe "Level 4" do
198
205
  :path => "/foo/bar",
199
206
  :semi => ";",
200
207
  :list => %w(red green blue),
201
- :keys => {"semi" => ';', "dot" => '.', "comma" => ','}
208
+ :keys => {"semi" => ';', "dot" => '.', :comma => ','}
202
209
  }
203
210
  }
204
211
  context "Expansion with value modifiers" do
@@ -207,22 +214,8 @@ describe "Level 4" do
207
214
  '{var:30}' => 'value',
208
215
  '{list}' => 'red,green,blue',
209
216
  '{list*}' => 'red,green,blue',
210
- '{keys}' => [
211
- 'semi,%3B,dot,.,comma,%2C',
212
- 'dot,.,semi,%3B,comma,%2C',
213
- 'comma,%2C,semi,%3B,dot,.',
214
- 'semi,%3B,comma,%2C,dot,.',
215
- 'dot,.,comma,%2C,semi,%3B',
216
- 'comma,%2C,dot,.,semi,%3B'
217
- ],
218
- '{keys*}' => [
219
- 'semi=%3B,dot=.,comma=%2C',
220
- 'dot=.,semi=%3B,comma=%2C',
221
- 'comma=%2C,semi=%3B,dot=.',
222
- 'semi=%3B,comma=%2C,dot=.',
223
- 'dot=.,comma=%2C,semi=%3B',
224
- 'comma=%2C,dot=.,semi=%3B'
225
- ]
217
+ '{keys}' => 'semi,%3B,dot,.,comma,%2C',
218
+ '{keys*}' => 'semi=%3B,dot=.,comma=%2C',
226
219
  }
227
220
  end
228
221
  context "Operator + with value modifiers" do
@@ -230,22 +223,8 @@ describe "Level 4" do
230
223
  '{+path:6}/here' => '/foo/b/here',
231
224
  '{+list}' => 'red,green,blue',
232
225
  '{+list*}' => 'red,green,blue',
233
- '{+keys}' => [
234
- 'semi,;,dot,.,comma,,',
235
- 'dot,.,semi,;,comma,,',
236
- 'comma,,,semi,;,dot,.',
237
- 'semi,;,comma,,,dot,.',
238
- 'dot,.,comma,,,semi,;',
239
- 'comma,,,dot,.,semi,;'
240
- ],
241
- '{+keys*}' => [
242
- 'semi=;,dot=.,comma=,',
243
- 'dot=.,semi=;,comma=,',
244
- 'comma=,,semi=;,dot=.',
245
- 'semi=;,comma=,,dot=.',
246
- 'dot=.,comma=,,semi=;',
247
- 'comma=,,dot=.,semi=;'
248
- ]
226
+ '{+keys}' => 'semi,;,dot,.,comma,,',
227
+ '{+keys*}' => 'semi=;,dot=.,comma=,',
249
228
  }
250
229
  end
251
230
  context "Operator # with value modifiers" do
@@ -253,22 +232,8 @@ describe "Level 4" do
253
232
  '{#path:6}/here' => '#/foo/b/here',
254
233
  '{#list}' => '#red,green,blue',
255
234
  '{#list*}' => '#red,green,blue',
256
- '{#keys}' => [
257
- '#semi,;,dot,.,comma,,',
258
- '#dot,.,semi,;,comma,,',
259
- '#comma,,,semi,;,dot,.',
260
- '#semi,;,comma,,,dot,.',
261
- '#dot,.,comma,,,semi,;',
262
- '#comma,,,dot,.,semi,;'
263
- ],
264
- '{#keys*}' => [
265
- '#semi=;,dot=.,comma=,',
266
- '#dot=.,semi=;,comma=,',
267
- '#comma=,,semi=;,dot=.',
268
- '#semi=;,comma=,,dot=.',
269
- '#dot=.,comma=,,semi=;',
270
- '#comma=,,dot=.,semi=;'
271
- ]
235
+ '{#keys}' => '#semi,;,dot,.,comma,,',
236
+ '{#keys*}' => '#semi=;,dot=.,comma=,',
272
237
  }
273
238
  end
274
239
  context "Operator . with value modifiers" do
@@ -276,22 +241,8 @@ describe "Level 4" do
276
241
  'X{.var:3}' => 'X.val',
277
242
  'X{.list}' => 'X.red,green,blue',
278
243
  'X{.list*}' => 'X.red.green.blue',
279
- 'X{.keys}' => [
280
- 'X.semi,%3B,dot,.,comma,%2C',
281
- 'X.dot,.,semi,%3B,comma,%2C',
282
- 'X.comma,%2C,semi,%3B,dot,.',
283
- 'X.semi,%3B,comma,%2C,dot,.',
284
- 'X.dot,.,comma,%2C,semi,%3B',
285
- 'X.comma,%2C,dot,.,semi,%3B'
286
- ],
287
- 'X{.keys*}' => [
288
- 'X.semi=%3B.dot=..comma=%2C',
289
- 'X.dot=..semi=%3B.comma=%2C',
290
- 'X.comma=%2C.semi=%3B.dot=.',
291
- 'X.semi=%3B.comma=%2C.dot=.',
292
- 'X.dot=..comma=%2C.semi=%3B',
293
- 'X.comma=%2C.dot=..semi=%3B'
294
- ]
244
+ 'X{.keys}' => 'X.semi,%3B,dot,.,comma,%2C',
245
+ 'X{.keys*}' => 'X.semi=%3B.dot=..comma=%2C',
295
246
  }
296
247
  end
297
248
  context "Operator / with value modifiers" do
@@ -300,22 +251,8 @@ describe "Level 4" do
300
251
  '{/list}' => '/red,green,blue',
301
252
  '{/list*}' => '/red/green/blue',
302
253
  '{/list*,path:4}' => '/red/green/blue/%2Ffoo',
303
- '{/keys}' => [
304
- '/semi,%3B,dot,.,comma,%2C',
305
- '/dot,.,semi,%3B,comma,%2C',
306
- '/comma,%2C,semi,%3B,dot,.',
307
- '/semi,%3B,comma,%2C,dot,.',
308
- '/dot,.,comma,%2C,semi,%3B',
309
- '/comma,%2C,dot,.,semi,%3B'
310
- ],
311
- '{/keys*}' => [
312
- '/semi=%3B/dot=./comma=%2C',
313
- '/dot=./semi=%3B/comma=%2C',
314
- '/comma=%2C/semi=%3B/dot=.',
315
- '/semi=%3B/comma=%2C/dot=.',
316
- '/dot=./comma=%2C/semi=%3B',
317
- '/comma=%2C/dot=./semi=%3B'
318
- ]
254
+ '{/keys}' => '/semi,%3B,dot,.,comma,%2C',
255
+ '{/keys*}' => '/semi=%3B/dot=./comma=%2C',
319
256
  }
320
257
  end
321
258
  context "Operator ; with value modifiers" do
@@ -323,22 +260,8 @@ describe "Level 4" do
323
260
  '{;hello:5}' => ';hello=Hello',
324
261
  '{;list}' => ';list=red,green,blue',
325
262
  '{;list*}' => ';list=red;list=green;list=blue',
326
- '{;keys}' => [
327
- ';keys=semi,%3B,dot,.,comma,%2C',
328
- ';keys=dot,.,semi,%3B,comma,%2C',
329
- ';keys=comma,%2C,semi,%3B,dot,.',
330
- ';keys=semi,%3B,comma,%2C,dot,.',
331
- ';keys=dot,.,comma,%2C,semi,%3B',
332
- ';keys=comma,%2C,dot,.,semi,%3B'
333
- ],
334
- '{;keys*}' => [
335
- ';semi=%3B;dot=.;comma=%2C',
336
- ';dot=.;semi=%3B;comma=%2C',
337
- ';comma=%2C;semi=%3B;dot=.',
338
- ';semi=%3B;comma=%2C;dot=.',
339
- ';dot=.;comma=%2C;semi=%3B',
340
- ';comma=%2C;dot=.;semi=%3B'
341
- ]
263
+ '{;keys}' => ';keys=semi,%3B,dot,.,comma,%2C',
264
+ '{;keys*}' => ';semi=%3B;dot=.;comma=%2C',
342
265
  }
343
266
  end
344
267
  context "Operator ? with value modifiers" do
@@ -346,22 +269,8 @@ describe "Level 4" do
346
269
  '{?var:3}' => '?var=val',
347
270
  '{?list}' => '?list=red,green,blue',
348
271
  '{?list*}' => '?list=red&list=green&list=blue',
349
- '{?keys}' => [
350
- '?keys=semi,%3B,dot,.,comma,%2C',
351
- '?keys=dot,.,semi,%3B,comma,%2C',
352
- '?keys=comma,%2C,semi,%3B,dot,.',
353
- '?keys=semi,%3B,comma,%2C,dot,.',
354
- '?keys=dot,.,comma,%2C,semi,%3B',
355
- '?keys=comma,%2C,dot,.,semi,%3B'
356
- ],
357
- '{?keys*}' => [
358
- '?semi=%3B&dot=.&comma=%2C',
359
- '?dot=.&semi=%3B&comma=%2C',
360
- '?comma=%2C&semi=%3B&dot=.',
361
- '?semi=%3B&comma=%2C&dot=.',
362
- '?dot=.&comma=%2C&semi=%3B',
363
- '?comma=%2C&dot=.&semi=%3B'
364
- ]
272
+ '{?keys}' => '?keys=semi,%3B,dot,.,comma,%2C',
273
+ '{?keys*}' => '?semi=%3B&dot=.&comma=%2C',
365
274
  }
366
275
  end
367
276
  context "Operator & with value modifiers" do
@@ -369,22 +278,8 @@ describe "Level 4" do
369
278
  '{&var:3}' => '&var=val',
370
279
  '{&list}' => '&list=red,green,blue',
371
280
  '{&list*}' => '&list=red&list=green&list=blue',
372
- '{&keys}' => [
373
- '&keys=semi,%3B,dot,.,comma,%2C',
374
- '&keys=dot,.,semi,%3B,comma,%2C',
375
- '&keys=comma,%2C,semi,%3B,dot,.',
376
- '&keys=semi,%3B,comma,%2C,dot,.',
377
- '&keys=dot,.,comma,%2C,semi,%3B',
378
- '&keys=comma,%2C,dot,.,semi,%3B'
379
- ],
380
- '{&keys*}' => [
381
- '&semi=%3B&dot=.&comma=%2C',
382
- '&dot=.&semi=%3B&comma=%2C',
383
- '&comma=%2C&semi=%3B&dot=.',
384
- '&semi=%3B&comma=%2C&dot=.',
385
- '&dot=.&comma=%2C&semi=%3B',
386
- '&comma=%2C&dot=.&semi=%3B'
387
- ]
281
+ '{&keys}' => '&keys=semi,%3B,dot,.,comma,%2C',
282
+ '{&keys*}' => '&semi=%3B&dot=.&comma=%2C',
388
283
  }
389
284
  end
390
285
  end
@@ -393,7 +288,7 @@ describe "Modifiers" do
393
288
  {
394
289
  :var => "value",
395
290
  :semi => ";",
396
- :year => %w(1965 2000 2012),
291
+ :year => [1965, 2000, 2012],
397
292
  :dom => %w(example com)
398
293
  }
399
294
  }
@@ -426,7 +321,7 @@ describe "Expansion" do
426
321
  :base => "http://example.com/home/",
427
322
  :path => "/foo/bar",
428
323
  :list => ["red", "green", "blue"],
429
- :keys => {"semi" => ";","dot" => ".","comma" => ","},
324
+ :keys => {"semi" => ";","dot" => ".",:comma => ","},
430
325
  :v => "6",
431
326
  :x => "1024",
432
327
  :y => "768",
@@ -464,22 +359,8 @@ describe "Expansion" do
464
359
  '{var:30}' => 'value',
465
360
  '{list}' => 'red,green,blue',
466
361
  '{list*}' => 'red,green,blue',
467
- '{keys}' => [
468
- 'semi,%3B,dot,.,comma,%2C',
469
- 'dot,.,semi,%3B,comma,%2C',
470
- 'comma,%2C,semi,%3B,dot,.',
471
- 'semi,%3B,comma,%2C,dot,.',
472
- 'dot,.,comma,%2C,semi,%3B',
473
- 'comma,%2C,dot,.,semi,%3B'
474
- ],
475
- '{keys*}' => [
476
- 'semi=%3B,dot=.,comma=%2C',
477
- 'dot=.,semi=%3B,comma=%2C',
478
- 'comma=%2C,semi=%3B,dot=.',
479
- 'semi=%3B,comma=%2C,dot=.',
480
- 'dot=.,comma=%2C,semi=%3B',
481
- 'comma=%2C,dot=.,semi=%3B'
482
- ]
362
+ '{keys}' => 'semi,%3B,dot,.,comma,%2C',
363
+ '{keys*}' => 'semi=%3B,dot=.,comma=%2C',
483
364
  }
484
365
  end
485
366
  context "reserved expansion (+)" do
@@ -499,22 +380,8 @@ describe "Expansion" do
499
380
  '{+path:6}/here' => '/foo/b/here',
500
381
  '{+list}' => 'red,green,blue',
501
382
  '{+list*}' => 'red,green,blue',
502
- '{+keys}' => [
503
- 'semi,;,dot,.,comma,,',
504
- 'dot,.,semi,;,comma,,',
505
- 'comma,,,semi,;,dot,.',
506
- 'semi,;,comma,,,dot,.',
507
- 'dot,.,comma,,,semi,;',
508
- 'comma,,,dot,.,semi,;'
509
- ],
510
- '{+keys*}' => [
511
- 'semi=;,dot=.,comma=,',
512
- 'dot=.,semi=;,comma=,',
513
- 'comma=,,semi=;,dot=.',
514
- 'semi=;,comma=,,dot=.',
515
- 'dot=.,comma=,,semi=;',
516
- 'comma=,,dot=.,semi=;'
517
- ]
383
+ '{+keys}' => 'semi,;,dot,.,comma,,',
384
+ '{+keys*}' => 'semi=;,dot=.,comma=,',
518
385
  }
519
386
  end
520
387
  context "fragment expansion (#)" do
@@ -529,22 +396,8 @@ describe "Expansion" do
529
396
  '{#path:6}/here' => '#/foo/b/here',
530
397
  '{#list}' => '#red,green,blue',
531
398
  '{#list*}' => '#red,green,blue',
532
- '{#keys}' => [
533
- '#semi,;,dot,.,comma,,',
534
- '#dot,.,semi,;,comma,,',
535
- '#comma,,,semi,;,dot,.',
536
- '#semi,;,comma,,,dot,.',
537
- '#dot,.,comma,,,semi,;',
538
- '#comma,,,dot,.,semi,;'
539
- ],
540
- '{#keys*}' => [
541
- '#semi=;,dot=.,comma=,',
542
- '#dot=.,semi=;,comma=,',
543
- '#comma=,,semi=;,dot=.',
544
- '#semi=;,comma=,,dot=.',
545
- '#dot=.,comma=,,semi=;',
546
- '#comma=,,dot=.,semi=;'
547
- ]
399
+ '{#keys}' => '#semi,;,dot,.,comma,,',
400
+ '{#keys*}' => '#semi=;,dot=.,comma=,',
548
401
  }
549
402
  end
550
403
  context "label expansion (.)" do
@@ -559,22 +412,8 @@ describe "Expansion" do
559
412
  'X{.var:3}' => 'X.val',
560
413
  'X{.list}' => 'X.red,green,blue',
561
414
  'X{.list*}' => 'X.red.green.blue',
562
- 'X{.keys}' => [
563
- 'X.semi,%3B,dot,.,comma,%2C',
564
- 'X.dot,.,semi,%3B,comma,%2C',
565
- 'X.comma,%2C,semi,%3B,dot,.',
566
- 'X.semi,%3B,comma,%2C,dot,.',
567
- 'X.dot,.,comma,%2C,semi,%3B',
568
- 'X.comma,%2C,dot,.,semi,%3B'
569
- ],
570
- 'X{.keys*}' => [
571
- 'X.semi=%3B.dot=..comma=%2C',
572
- 'X.dot=..semi=%3B.comma=%2C',
573
- 'X.comma=%2C.semi=%3B.dot=.',
574
- 'X.semi=%3B.comma=%2C.dot=.',
575
- 'X.dot=..comma=%2C.semi=%3B',
576
- 'X.comma=%2C.dot=..semi=%3B'
577
- ],
415
+ 'X{.keys}' => 'X.semi,%3B,dot,.,comma,%2C',
416
+ 'X{.keys*}' => 'X.semi=%3B.dot=..comma=%2C',
578
417
  'X{.empty_keys}' => 'X',
579
418
  'X{.empty_keys*}' => 'X'
580
419
  }
@@ -593,22 +432,8 @@ describe "Expansion" do
593
432
  '{/list}' => '/red,green,blue',
594
433
  '{/list*}' => '/red/green/blue',
595
434
  '{/list*,path:4}' => '/red/green/blue/%2Ffoo',
596
- '{/keys}' => [
597
- '/semi,%3B,dot,.,comma,%2C',
598
- '/dot,.,semi,%3B,comma,%2C',
599
- '/comma,%2C,semi,%3B,dot,.',
600
- '/semi,%3B,comma,%2C,dot,.',
601
- '/dot,.,comma,%2C,semi,%3B',
602
- '/comma,%2C,dot,.,semi,%3B'
603
- ],
604
- '{/keys*}' => [
605
- '/semi=%3B/dot=./comma=%2C',
606
- '/dot=./semi=%3B/comma=%2C',
607
- '/comma=%2C/semi=%3B/dot=.',
608
- '/semi=%3B/comma=%2C/dot=.',
609
- '/dot=./comma=%2C/semi=%3B',
610
- '/comma=%2C/dot=./semi=%3B'
611
- ]
435
+ '{/keys}' => '/semi,%3B,dot,.,comma,%2C',
436
+ '{/keys*}' => '/semi=%3B/dot=./comma=%2C',
612
437
  }
613
438
  end
614
439
  context "path-style expansion (;)" do
@@ -624,22 +449,8 @@ describe "Expansion" do
624
449
  '{;hello:5}' => ';hello=Hello',
625
450
  '{;list}' => ';list=red,green,blue',
626
451
  '{;list*}' => ';list=red;list=green;list=blue',
627
- '{;keys}' => [
628
- ';keys=semi,%3B,dot,.,comma,%2C',
629
- ';keys=dot,.,semi,%3B,comma,%2C',
630
- ';keys=comma,%2C,semi,%3B,dot,.',
631
- ';keys=semi,%3B,comma,%2C,dot,.',
632
- ';keys=dot,.,comma,%2C,semi,%3B',
633
- ';keys=comma,%2C,dot,.,semi,%3B'
634
- ],
635
- '{;keys*}' => [
636
- ';semi=%3B;dot=.;comma=%2C',
637
- ';dot=.;semi=%3B;comma=%2C',
638
- ';comma=%2C;semi=%3B;dot=.',
639
- ';semi=%3B;comma=%2C;dot=.',
640
- ';dot=.;comma=%2C;semi=%3B',
641
- ';comma=%2C;dot=.;semi=%3B'
642
- ]
452
+ '{;keys}' => ';keys=semi,%3B,dot,.,comma,%2C',
453
+ '{;keys*}' => ';semi=%3B;dot=.;comma=%2C',
643
454
  }
644
455
  end
645
456
  context "form query expansion (?)" do
@@ -652,22 +463,8 @@ describe "Expansion" do
652
463
  '{?var:3}' => '?var=val',
653
464
  '{?list}' => '?list=red,green,blue',
654
465
  '{?list*}' => '?list=red&list=green&list=blue',
655
- '{?keys}' => [
656
- '?keys=semi,%3B,dot,.,comma,%2C',
657
- '?keys=dot,.,semi,%3B,comma,%2C',
658
- '?keys=comma,%2C,semi,%3B,dot,.',
659
- '?keys=semi,%3B,comma,%2C,dot,.',
660
- '?keys=dot,.,comma,%2C,semi,%3B',
661
- '?keys=comma,%2C,dot,.,semi,%3B'
662
- ],
663
- '{?keys*}' => [
664
- '?semi=%3B&dot=.&comma=%2C',
665
- '?dot=.&semi=%3B&comma=%2C',
666
- '?comma=%2C&semi=%3B&dot=.',
667
- '?semi=%3B&comma=%2C&dot=.',
668
- '?dot=.&comma=%2C&semi=%3B',
669
- '?comma=%2C&dot=.&semi=%3B'
670
- ]
466
+ '{?keys}' => '?keys=semi,%3B,dot,.,comma,%2C',
467
+ '{?keys*}' => '?semi=%3B&dot=.&comma=%2C',
671
468
  }
672
469
  end
673
470
  context "form query expansion (&)" do
@@ -680,22 +477,8 @@ describe "Expansion" do
680
477
  '{&var:3}' => '&var=val',
681
478
  '{&list}' => '&list=red,green,blue',
682
479
  '{&list*}' => '&list=red&list=green&list=blue',
683
- '{&keys}' => [
684
- '&keys=semi,%3B,dot,.,comma,%2C',
685
- '&keys=dot,.,semi,%3B,comma,%2C',
686
- '&keys=comma,%2C,semi,%3B,dot,.',
687
- '&keys=semi,%3B,comma,%2C,dot,.',
688
- '&keys=dot,.,comma,%2C,semi,%3B',
689
- '&keys=comma,%2C,dot,.,semi,%3B'
690
- ],
691
- '{&keys*}' => [
692
- '&semi=%3B&dot=.&comma=%2C',
693
- '&dot=.&semi=%3B&comma=%2C',
694
- '&comma=%2C&semi=%3B&dot=.',
695
- '&semi=%3B&comma=%2C&dot=.',
696
- '&dot=.&comma=%2C&semi=%3B',
697
- '&comma=%2C&dot=.&semi=%3B'
698
- ]
480
+ '{&keys}' => '&keys=semi,%3B,dot,.,comma,%2C',
481
+ '{&keys*}' => '&semi=%3B&dot=.&comma=%2C',
699
482
  }
700
483
  end
701
484
  context "non-string key in match data" do
@@ -949,6 +732,36 @@ describe Addressable::Template do
949
732
  )
950
733
  end
951
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
952
765
  context "partial_expand with query string" do
953
766
  subject {
954
767
  Addressable::Template.new("http://example.com/{?two,one}/")
@@ -969,6 +782,37 @@ describe Addressable::Template do
969
782
  )
970
783
  end
971
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
972
816
  end
973
817
  describe "Partial expand with strings" do
974
818
  context "partial_expand with two simple values" do
@@ -1013,6 +857,31 @@ describe Addressable::Template do
1013
857
  end
1014
858
  end
1015
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
1016
885
  context "expand with a processor" do
1017
886
  subject {
1018
887
  Addressable::Template.new("http://example.com/search/{query}/")
@@ -1276,6 +1145,14 @@ describe Addressable::Template do
1276
1145
  expect(subject).not_to match("foo_bar*")
1277
1146
  expect(subject).not_to match("foo_bar:20")
1278
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
1279
1156
  end
1280
1157
  context "VARIABLE_LIST" do
1281
1158
  subject { Addressable::Template::VARIABLE_LIST }