1<?php
2/**
3 * Horde Routes package
4 *
5 * This package is heavily inspired by the Python "Routes" library
6 * by Ben Bangert (http://routes.groovie.org).  Routes is based
7 * largely on ideas from Ruby on Rails (http://www.rubyonrails.org).
8 *
9 * @author  Maintainable Software, LLC. (http://www.maintainable.com)
10 * @author  Mike Naberezny <mike@maintainable.com>
11 * @license http://www.horde.org/licenses/bsd BSD
12 * @package Routes
13 */
14
15/**
16 * @package Routes
17 */
18class Horde_Routes_RecognitionTest extends PHPUnit_Framework_TestCase
19{
20    public function testRegexpCharEscaping()
21    {
22        $m = new Horde_Routes_Mapper();
23        $m->connect(':controller/:(action).:(id)');
24        $m->createRegs(array('content'));
25
26        $this->assertNull($m->match('/content/view#2'));
27
28        $matchdata = array('action' => 'view', 'controller' => 'content', 'id' => '2');
29        $this->assertEquals($matchdata, $m->match('/content/view.2'));
30
31        $m->connect(':controller/:action/:id');
32        $m->createRegs(array('content', 'find.all'));
33
34        $matchdata = array('action' => 'view#2', 'controller' => 'content', 'id' => null);
35        $this->assertEquals($matchdata, $m->match('/content/view#2'));
36
37        $matchdata = array('action' => 'view', 'controller' => 'find.all', 'id'=> null);
38        $this->assertEquals($matchdata, $m->match('/find.all/view'));
39
40        $this->assertNull($m->match('/findzall/view'));
41    }
42
43    public function testAllStatic()
44    {
45        $m = new Horde_Routes_Mapper();
46        $m->connect('hello/world/how/are/you', array('controller' => 'content', 'action' => 'index'));
47        $m->createRegs(array());
48
49        $this->assertNull($m->match('/x'));
50        $this->assertNull($m->match('/hello/world/how'));
51        $this->assertNull($m->match('/hello/world/how/are'));
52        $this->assertNull($m->match('/hello/world/how/are/you/today'));
53
54        $matchdata = array('controller' => 'content', 'action' =>'index');
55        $this->assertEquals($matchdata, $m->match('/hello/world/how/are/you'));
56    }
57
58    public function testUnicode()
59    {
60        // php version does not handing decoding
61    }
62
63    public function testDisablingUnicode()
64    {
65        // php version does not handing decoding
66    }
67
68    public function testBasicDynamic()
69    {
70        foreach(array('hi/:name', 'hi/:(name)') as $path) {
71            $m = new Horde_Routes_Mapper();
72            $m->connect($path, array('controller' => 'content'));
73            $m->createRegs();
74
75            $this->assertNull($m->match('/boo'));
76            $this->assertNull($m->match('/boo/blah'));
77            $this->assertNull($m->match('/hi'));
78            $this->assertNull($m->match('/hi/dude/what'));
79
80            $matchdata = array('controller' => 'content', 'name' => 'dude', 'action' => 'index');
81            $this->assertEquals($matchdata, $m->match('/hi/dude'));
82            $this->assertEquals($matchdata, $m->match('/hi/dude/'));
83        }
84    }
85
86    public function testBasicDynamicBackwards()
87    {
88        foreach (array(':name/hi', ':(name)/hi') as $path) {
89            $m = new Horde_Routes_Mapper();
90            $m->connect($path);
91            $m->createRegs();
92
93            $this->assertNull($m->match('/'));
94            $this->assertNull($m->match('/hi'));
95            $this->assertNull($m->match('/boo'));
96            $this->assertNull($m->match('/boo/blah'));
97            $this->assertNull($m->match('/shop/walmart/hi'));
98
99            $matchdata = array('name' => 'fred', 'action' => 'index', 'controller' => 'content');
100            $this->assertEquals($matchdata, $m->match('/fred/hi'));
101
102            $matchdata = array('name' => 'index', 'action' => 'index', 'controller' => 'content');
103            $this->assertEquals($matchdata, $m->match('/index/hi'));
104        }
105    }
106
107    public function testDynamicWithUnderscores()
108    {
109        $m = new Horde_Routes_Mapper();
110        $m->connect('article/:small_page', array('small_page' => false));
111        $m->connect(':(controller)/:(action)/:(id)');
112        $m->createRegs(array('article', 'blog'));
113
114        $matchdata = array('controller' => 'blog', 'action' => 'view', 'id' => '0');
115        $this->assertEquals($matchdata, $m->match('/blog/view/0'));
116
117        $matchdata = array('controller' => 'blog', 'action' => 'view', 'id' => null);
118        $this->assertEquals($matchdata, $m->match('/blog/view'));
119    }
120
121    public function testDynamicWithDefault()
122    {
123        foreach (array('hi/:action', 'hi/:(action)') as $path) {
124            $m = new Horde_Routes_Mapper();
125            $m->connect($path, array('controller' => 'content'));
126            $m->createRegs();
127
128            $this->assertNull($m->match('/boo'));
129            $this->assertNull($m->match('/boo/blah'));
130            $this->assertNull($m->match('/hi/dude/what'));
131
132            $matchdata = array('controller' => 'content', 'action' => 'index');
133            $this->assertEquals($matchdata, $m->match('/hi'));
134
135            $matchdata = array('controller' => 'content', 'action' => 'index');
136            $this->assertEquals($matchdata, $m->match('/hi/index'));
137
138            $matchdata = array('controller' => 'content', 'action' => 'dude');
139            $this->assertEquals($matchdata, $m->match('/hi/dude'));
140        }
141    }
142
143    public function testDynamicWithDefaultBackwards()
144    {
145        foreach (array(':action/hi', ':(action)/hi') as $path) {
146            $m = new Horde_Routes_Mapper();
147            $m->connect($path, array('controller' => 'content'));
148            $m->createRegs();
149
150            $this->assertNull($m->match('/'));
151            $this->assertNull($m->match('/boo'));
152            $this->assertNull($m->match('/boo/blah'));
153            $this->assertNull($m->match('/hi'));
154
155            $matchdata = array('controller' => 'content', 'action' => 'index');
156            $this->assertEquals($matchdata, $m->match('/index/hi'));
157            $this->assertEquals($matchdata, $m->match('/index/hi/'));
158
159            $matchdata = array('controller' => 'content', 'action' => 'dude');
160            $this->assertEquals($matchdata, $m->match('/dude/hi'));
161        }
162    }
163
164    public function testDynamicWithStringCondition()
165    {
166        foreach (array(':name/hi', ':(name)/hi') as $path) {
167            $m = new Horde_Routes_Mapper();
168            $m->connect($path, array('controller'   => 'content',
169                                     'requirements' => array('name' => 'index')));
170            $m->createRegs();
171
172            $this->assertNull($m->match('/boo'));
173            $this->assertNull($m->match('/boo/blah'));
174            $this->assertNull($m->match('/hi'));
175            $this->assertNull($m->match('/dude/what/hi'));
176
177            $matchdata = array('controller' => 'content', 'name' => 'index', 'action' => 'index');
178            $this->assertEquals($matchdata, $m->match('/index/hi'));
179            $this->assertNull($m->match('/dude/hi'));
180        }
181    }
182
183    public function testDynamicWithStringConditionBackwards()
184    {
185        foreach (array('hi/:name', 'hi/:(name)') as $path) {
186            $m = new Horde_Routes_Mapper();
187            $m->connect($path, array('controller'   => 'content',
188                                     'requirements' => array('name' => 'index')));
189            $m->createRegs();
190
191            $this->assertNull($m->match('/boo'));
192            $this->assertNull($m->match('/boo/blah'));
193            $this->assertNull($m->match('/hi'));
194            $this->assertNull($m->match('/hi/dude/what'));
195
196            $matchdata = array('controller' => 'content', 'name' => 'index', 'action' => 'index');
197            $this->assertEquals($matchdata, $m->match('/hi/index'));
198
199            $this->assertEquals($matchdata, $m->match('/hi/index'));
200
201            $this->assertNull($m->match('/dude/hi'));
202        }
203    }
204
205    public function testDynamicWithRegexpCondition()
206    {
207        foreach (array('hi/:name', 'hi/:(name)') as $path) {
208            $m = new Horde_Routes_Mapper();
209            $m->connect($path, array('controller'   => 'content',
210                                     'requirements' => array('name' => '[a-z]+')));
211            $m->createRegs();
212
213            $this->assertNull($m->match('/boo'));
214            $this->assertNull($m->match('/boo/blah'));
215            $this->assertNull($m->match('/hi'));
216            $this->assertNull($m->match('/hi/FOXY'));
217            $this->assertNull($m->match('/hi/138708jkhdf'));
218            $this->assertNull($m->match('/hi/dkjfl8792343dfsf'));
219            $this->assertNull($m->match('/hi/dude/what'));
220            $this->assertNull($m->match('/hi/dude/what/'));
221
222            $matchdata = array('controller' => 'content', 'name' => 'index', 'action' => 'index');
223            $this->assertEquals($matchdata, $m->match('/hi/index'));
224
225            $matchdata = array('controller' => 'content', 'name' => 'dude', 'action' => 'index');
226            $this->assertEquals($matchdata, $m->match('/hi/dude'));
227        }
228    }
229
230    public function testDynamicWithRegexpAndDefault()
231    {
232        foreach (array('hi/:action', 'hi/:(action)') as $path) {
233            $m = new Horde_Routes_Mapper();
234            $m->connect($path, array('controller'   => 'content',
235                                     'requirements' => array('action' => '[a-z]+')));
236            $m->createRegs();
237
238            $this->assertNull($m->match('/boo'));
239            $this->assertNull($m->match('/boo/blah'));
240            $this->assertNull($m->match('/hi/FOXY'));
241            $this->assertNull($m->match('/hi/138708jkhdf'));
242            $this->assertNull($m->match('/hi/dkjfl8792343dfsf'));
243            $this->assertNull($m->match('/hi/dude/what/'));
244
245            $matchdata = array('controller' => 'content', 'action' => 'index');
246            $this->assertEquals($matchdata, $m->match('/hi'));
247            $this->assertEquals($matchdata, $m->match('/hi/index'));
248
249            $matchdata = array('controller' => 'content', 'action' => 'dude');
250            $this->assertEquals($matchdata, $m->match('/hi/dude'));
251        }
252    }
253
254    public function testDynamicWithDefaultAndStringConditionBackwards()
255    {
256        foreach (array(':action/hi', ':(action)/hi') as $path) {
257            $m = new Horde_Routes_Mapper();
258            $m->connect($path);
259            $m->createRegs();
260
261            $this->assertNull($m->match('/'));
262            $this->assertNull($m->match('/boo'));
263            $this->assertNull($m->match('/boo/blah'));
264            $this->assertNull($m->match('/hi'));
265
266            $matchdata = array('action' => 'index', 'controller' => 'content');
267            $this->assertEquals($matchdata, $m->match('/index/hi'));
268        }
269    }
270
271    public function testDynamicAndControllerWithStringAndDefaultBackwards()
272    {
273        foreach (array(':controller/:action/hi', ':(controller)/:(action)/hi') as $path) {
274            $m = new Horde_Routes_Mapper();
275
276            $m->connect($path, array('controller' => 'content'));
277            $m->createRegs(array('content', 'admin/user'));
278
279            $this->assertNull($m->match('/'));
280            $this->assertNull($m->match('/fred'));
281        }
282    }
283
284    public function testMultiroute()
285    {
286        $m = new Horde_Routes_Mapper();
287        $m->connect('archive/:year/:month/:day', array('controller' => 'blog', 'action' => 'view',
288                                                       'month' => null, 'day' => null,
289	                                                   'requirements' => array('month' => '\d{1,2}',
290	                                                                           'day'   => '\d{1,2}')));
291        $m->connect('viewpost/:id', array('controller' => 'post', 'action' => 'view'));
292        $m->connect(':controller/:action/:id');
293        $m->createRegs(array('post','blog','admin/user'));
294
295        $this->assertNull($m->match('/'));
296        $this->assertNull($m->match('/archive'));
297        $this->assertNull($m->match('/archive/2004/ab'));
298
299        $matchdata = array('controller' => 'blog', 'action' => 'view', 'id' => null);
300        $this->assertEquals($matchdata, $m->match('/blog/view'));
301
302        $matchdata = array('controller' => 'blog', 'action' => 'view',
303                           'month' => null, 'day' => null, 'year' => '2004');
304        $this->assertEquals($matchdata, $m->match('/archive/2004'));
305
306        $matchdata = array('controller' => 'blog', 'action' => 'view',
307                           'month' => '4', 'day' => null, 'year' =>'2004');
308        $this->assertEquals($matchdata, $m->match('/archive/2004/4'));
309    }
310
311    public function testMultirouteWithSplits()
312    {
313        $m = new Horde_Routes_Mapper();
314        $m->connect('archive/:(year)/:(month)/:(day)', array('controller' => 'blog', 'action' => 'view',
315                                                             'month' => null, 'day' => null,
316	                                                         'requirements' => array('month' => '\d{1,2}',
317	                                                                                 'day'   => '\d{1,2}')));
318        $m->connect('viewpost/:(id)', array('controller' => 'post', 'action' => 'view'));
319        $m->connect(':(controller)/:(action)/:(id)');
320        $m->createRegs(array('post','blog','admin/user'));
321
322        $this->assertNull($m->match('/'));
323        $this->assertNull($m->match('/archive'));
324        $this->assertNull($m->match('/archive/2004/ab'));
325
326        $matchdata = array('controller' => 'blog', 'action' => 'view', 'id' => null);
327        $this->assertEquals($matchdata, $m->match('/blog/view'));
328
329        $matchdata = array('controller' => 'blog', 'action' => 'view',
330                           'month' => null, 'day' => null, 'year' => '2004');
331        $this->assertEquals($matchdata, $m->match('/archive/2004'));
332
333        $matchdata = array('controller' => 'blog', 'action' => 'view',
334                           'month' => '4', 'day' => null, 'year' => '2004');
335        $this->assertEquals($matchdata, $m->match('/archive/2004/4'));
336    }
337
338    public function testDynamicWithRegexpDefaultsAndGaps()
339    {
340        $m = new Horde_Routes_Mapper();
341        $m->connect('archive/:year/:month/:day', array('controller' => 'blog', 'action' => 'view',
342                                                       'month' => null, 'day' => null,
343	                                                   'requirements' => array('month' => '\d{1,2}')));
344        $m->connect('view/:id/:controller', array('controller' => 'blog', 'action' => 'view',
345                                                      'id' => 2, 'requirements' => array('id' => '\d{1,2}')));
346        $m->createRegs(array('post','blog','admin/user'));
347
348        $this->assertNull($m->match('/'));
349        $this->assertNull($m->match('/archive'));
350        $this->assertNull($m->match('/archive/2004/haha'));
351        $this->assertNull($m->match('/view/blog'));
352
353        $matchdata = array('controller' => 'blog', 'action' => 'view', 'id' => '2');
354        $this->assertEquals($matchdata, $m->match('/view'));
355
356        $matchdata = array('controller' => 'blog', 'action' => 'view',
357                           'month' => null, 'day' => null, 'year' => '2004');
358        $this->assertEquals($matchdata, $m->match('/archive/2004'));
359    }
360
361    public function testDynamicWithRegexpDefaultsAndGapsAndSplits()
362    {
363        $m = new Horde_Routes_Mapper();
364        $m->connect('archive/:(year)/:(month)/:(day)', array('controller' => 'blog', 'action' => 'view',
365                                                             'month' => null, 'day' => null,
366	                                                         'requirements' => array('month' => '\d{1,2}')));
367        $m->connect('view/:(id)/:(controller)', array('controller' => 'blog', 'action' => 'view',
368                                                          'id' => 2, 'requirements' => array('id' => '\d{1,2}')));
369        $m->createRegs(array('post','blog','admin/user'));
370
371        $this->assertNull($m->match('/'));
372        $this->assertNull($m->match('/archive'));
373        $this->assertNull($m->match('/archive/2004/haha'));
374        $this->assertNull($m->match('/view/blog'));
375
376        $matchdata = array('controller' => 'blog', 'action' => 'view', 'id' => '2');
377        $this->assertEquals($matchdata, $m->match('/view'));
378
379        $matchdata = array('controller' => 'blog', 'action' => 'view',
380                           'month' => null, 'day' => null, 'year' => '2004');
381        $this->assertEquals($matchdata, $m->match('/archive/2004'));
382    }
383
384    public function testDynamicWithRegexpGapsControllers()
385    {
386        foreach(array('view/:id/:controller', 'view/:(id)/:(controller)') as $path) {
387            $m = new Horde_Routes_Mapper();
388            $m->connect($path, array('id' => 2, 'action' => 'view', 'requirements' => array('id' => '\d{1,2}')));
389            $m->createRegs(array('post', 'blog', 'admin/user'));
390
391            $this->assertNull($m->match('/'));
392            $this->assertNull($m->match('/view'));
393            $this->assertNull($m->match('/view/blog'));
394            $this->assertNull($m->match('/view/3'));
395            $this->assertNull($m->match('/view/4/honker'));
396
397            $matchdata = array('controller' => 'blog', 'action' => 'view', 'id' => '2');
398            $this->assertEquals($matchdata, $m->match('/view/2/blog'));
399        }
400    }
401
402    public function testDynamicWithTrailingStrings()
403    {
404        foreach (array('view/:id/:controller/super', 'view/:(id)/:(controller)/super') as $path) {
405            $m = new Horde_Routes_Mapper();
406            $m->connect($path, array('controller' => 'blog', 'action' => 'view',
407                                     'id' => 2, 'requirements' => array('id' => '\d{1,2}')));
408            $m->createRegs(array('post', 'blog', 'admin/user'));
409
410            $this->assertNull($m->match('/'));
411            $this->assertNull($m->match('/view'));
412            $this->assertNull($m->match('/view/blah/blog/super'));
413            $this->assertNull($m->match('/view/ha/super'));
414            $this->assertNull($m->match('/view/super'));
415            $this->assertNull($m->match('/view/4/super'));
416
417            $matchdata = array('controller' => 'blog', 'action' => 'view', 'id' => '2');
418            $this->assertEquals($matchdata, $m->match('/view/2/blog/super'));
419
420            $matchdata = array('controller' => 'admin/user', 'action' => 'view', 'id' => '4');
421            $this->assertEquals($matchdata, $m->match('/view/4/admin/user/super'));
422        }
423    }
424
425    public function testDynamicWithTrailingNonKeywordStrings()
426    {
427        $m = new Horde_Routes_Mapper();
428        $m->connect('somewhere/:over/rainbow', array('controller' => 'blog'));
429        $m->connect('somewhere/:over', array('controller' => 'post'));
430        $m->createRegs(array('post', 'blog', 'admin/user'));
431
432        $this->assertNull($m->match('/'));
433        $this->assertNull($m->match('/somewhere'));
434
435        $matchdata = array('controller' => 'blog', 'action' => 'index', 'over' => 'near');
436        $this->assertEquals($matchdata, $m->match('/somewhere/near/rainbow'));
437
438        $matchdata = array('controller' => 'post', 'action' => 'index', 'over' => 'tomorrow');
439        $this->assertEquals($matchdata, $m->match('/somewhere/tomorrow'));
440    }
441
442    public function testDynamicWithTrailingDynamicDefaults()
443    {
444        foreach (array('archives/:action/:article', 'archives/:(action)/:(article)') as $path) {
445            $m = new Horde_Routes_Mapper();
446            $m->connect($path, array('controller' => 'blog'));
447            $m->createRegs(array('blog'));
448
449            $this->assertNull($m->match('/'));
450            $this->assertNull($m->match('/archives'));
451            $this->assertNull($m->match('/archives/introduction'));
452            $this->assertNull($m->match('/archives/sample'));
453            $this->assertNull($m->match('/view/super'));
454            $this->assertNull($m->match('/view/4/super'));
455
456            $matchdata = array('controller' => 'blog', 'action' => 'view', 'article' => 'introduction');
457            $this->assertEquals($matchdata, $m->match('/archives/view/introduction'));
458
459            $matchdata = array('controller' => 'blog', 'action' => 'edit', 'article' => 'recipes');
460            $this->assertEquals($matchdata, $m->match('/archives/edit/recipes'));
461        }
462    }
463
464    public function testPath()
465    {
466        foreach (array('hi/*file', 'hi/*(file)') as $path) {
467            $m = new Horde_Routes_Mapper();
468            $m->connect($path, array('controller' => 'content', 'action' => 'download'));
469            $m->createRegs();
470
471            $this->assertNull($m->match('/boo'));
472            $this->assertNull($m->match('/boo/blah'));
473            $this->assertNull($m->match('/hi'));
474
475            $matchdata = array('controller' => 'content', 'action' => 'download',
476                               'file' => 'books/learning_python.pdf');
477            $this->assertEquals($matchdata, $m->match('/hi/books/learning_python.pdf'));
478
479            $matchdata = array('controller' => 'content', 'action' => 'download',
480                               'file' => 'dude');
481            $this->assertEquals($matchdata, $m->match('/hi/dude'));
482
483            $matchdata = array('controller' => 'content', 'action' => 'download',
484                               'file' => 'dude/what');
485            $this->assertEquals($matchdata, $m->match('/hi/dude/what'));
486        }
487    }
488
489    public function testDynamicWithPath()
490    {
491        foreach (array(':controller/:action/*url', ':(controller)/:(action)/*(url)') as $path) {
492            $m = new Horde_Routes_Mapper();
493            $m->connect($path);
494            $m->createRegs(array('content', 'admin/user'));
495
496            $this->assertNull($m->match('/'));
497            $this->assertNull($m->match('/blog'));
498            $this->assertNull($m->match('/content'));
499            $this->assertNull($m->match('/content/view'));
500
501            $matchdata = array('controller' => 'content', 'action' => 'view', 'url' => 'blob');
502            $this->assertEquals($matchdata, $m->match('/content/view/blob'));
503
504            $this->assertNull($m->match('/admin/user'));
505            $this->assertNull($m->match('/admin/user/view'));
506
507            $matchdata = array('controller' => 'admin/user', 'action' => 'view',
508                               'url' => 'blob/check');
509            $this->assertEquals($matchdata, $m->match('/admin/user/view/blob/check'));
510        }
511    }
512
513    public function testPathWithDynamicAndDefault()
514    {
515        foreach (array(':controller/:action/*url', ':(controller)/:(action)/*(url)') as $path) {
516            $m = new Horde_Routes_Mapper();
517            $m->connect($path, array('controller' => 'content', 'action' => 'view', 'url' => null));
518            $m->createRegs(array('content', 'admin/user'));
519
520            $this->assertNull($m->match('/goober/view/here'));
521
522            $matchdata = array('controller' => 'content', 'action' => 'view', 'url' => null);
523            $this->assertEquals($matchdata, $m->match('/content'));
524            $this->assertEquals($matchdata, $m->match('/content/'));
525            $this->assertEquals($matchdata, $m->match('/content/view'));
526
527            $matchdata = array('controller' => 'content', 'action' => 'view', 'url' => 'fred');
528            $this->assertEquals($matchdata, $m->match('/content/view/fred'));
529
530            $matchdata = array('controller' => 'admin/user', 'action' => 'view', 'url' => null);
531            $this->assertEquals($matchdata, $m->match('/admin/user'));
532            $this->assertEquals($matchdata, $m->match('/admin/user/view'));
533        }
534    }
535
536    public function testPathWithDynamicAndDefaultBackwards()
537    {
538        foreach (array('*file/login', '*(file)/login') as $path) {
539            $m = new Horde_Routes_Mapper();
540            $m->connect($path, array('controller' => 'content', 'action' => 'download', 'file' => null));
541            $m->createRegs();
542
543            $this->assertNull($m->match('/boo'));
544            $this->assertNull($m->match('/boo/blah'));
545
546            $matchdata = array('controller' => 'content', 'action' => 'download', 'file' => '');
547            $this->assertEquals($matchdata, $m->match('//login'));
548
549            $matchdata = array('controller' => 'content', 'action' => 'download',
550                               'file' => 'books/learning_python.pdf');
551            $this->assertEquals($matchdata, $m->match('/books/learning_python.pdf/login'));
552
553            $matchdata = array('controller' => 'content', 'action' => 'download', 'file' => 'dude');
554            $this->assertEquals($matchdata, $m->match('/dude/login'));
555
556            $matchdata = array('controller' => 'content', 'action' => 'download', 'file' => 'dude/what');
557            $this->assertEquals($matchdata, $m->match('/dude/what/login'));
558        }
559    }
560
561    public function testPathBackwards()
562    {
563        foreach (array('*file/login', '*(file)/login') as $path) {
564            $m = new Horde_Routes_Mapper();
565            $m->connect($path, array('controller' => 'content', 'action' => 'download'));
566            $m->createRegs();
567
568            $this->assertNull($m->match('/boo'));
569            $this->assertNull($m->match('/boo/blah'));
570            $this->assertNull($m->match('/login'));
571
572            $matchdata = array('controller' => 'content', 'action' => 'download',
573                               'file' => 'books/learning_python.pdf');
574            $this->assertEquals($matchdata, $m->match('/books/learning_python.pdf/login'));
575
576            $matchdata = array('controller' => 'content', 'action' => 'download', 'file' => 'dude');
577            $this->assertEquals($matchdata, $m->match('/dude/login'));
578
579            $matchdata = array('controller' => 'content', 'action' => 'download', 'file' => 'dude/what');
580            $this->assertEquals($matchdata, $m->match('/dude/what/login'));
581        }
582    }
583
584    public function testPathBackwardsWithController()
585    {
586        $m = new Horde_Routes_Mapper();
587        $m->connect('*url/login', array('controller' => 'content', 'action' => 'check_access'));
588        $m->connect('*url/:controller', array('action' => 'view'));
589        $m->createRegs(array('content', 'admin/user'));
590
591        $this->assertNull($m->match('/boo'));
592        $this->assertNull($m->match('/boo/blah'));
593        $this->assertNull($m->match('/login'));
594
595        $matchdata = array('controller' => 'content', 'action' => 'check_access',
596                           'url' => 'books/learning_python.pdf');
597        $this->assertEquals($matchdata, $m->match('/books/learning_python.pdf/login'));
598
599        $matchdata = array('controller' => 'content', 'action' => 'check_access', 'url' => 'dude');
600        $this->assertEquals($matchdata, $m->match('/dude/login'));
601
602        $matchdata = array('controller' => 'content', 'action' => 'check_access', 'url' => 'dude/what');
603        $this->assertEquals($matchdata, $m->match('/dude/what/login'));
604
605        $this->assertNull($m->match('/admin/user'));
606
607        $matchdata = array('controller' => 'admin/user', 'action' => 'view',
608                           'url' => 'books/learning_python.pdf');
609        $this->assertEquals($matchdata, $m->match('/books/learning_python.pdf/admin/user'));
610
611        $matchdata = array('controller' => 'admin/user', 'action' => 'view', 'url' => 'dude');
612        $this->assertEquals($matchdata, $m->match('/dude/admin/user'));
613
614        $matchdata = array('controller' => 'admin/user', 'action' => 'view', 'url' => 'dude/what');
615        $this->assertEquals($matchdata, $m->match('/dude/what/admin/user'));
616    }
617
618    public function testPathBackwardsWithControllerAndSplits()
619    {
620        $m = new Horde_Routes_Mapper();
621        $m->connect('*(url)/login', array('controller' => 'content', 'action' => 'check_access'));
622        $m->connect('*(url)/:(controller)', array('action' => 'view'));
623        $m->createRegs(array('content', 'admin/user'));
624
625        $this->assertNull($m->match('/boo'));
626        $this->assertNull($m->match('/boo/blah'));
627        $this->assertNull($m->match('/login'));
628
629        $matchdata = array('controller' => 'content', 'action' => 'check_access',
630                           'url' => 'books/learning_python.pdf');
631        $this->assertEquals($matchdata, $m->match('/books/learning_python.pdf/login'));
632
633        $matchdata = array('controller' => 'content', 'action' => 'check_access', 'url' => 'dude');
634        $this->assertEquals($matchdata, $m->match('/dude/login'));
635
636        $matchdata = array('controller' => 'content', 'action' => 'check_access', 'url' => 'dude/what');
637        $this->assertEquals($matchdata, $m->match('/dude/what/login'));
638
639        $this->assertNull($m->match('/admin/user'));
640
641        $matchdata = array('controller' => 'admin/user', 'action' => 'view',
642                           'url' => 'books/learning_python.pdf');
643        $this->assertEquals($matchdata, $m->match('/books/learning_python.pdf/admin/user'));
644
645        $matchdata = array('controller' => 'admin/user', 'action' => 'view', 'url' => 'dude');
646        $this->assertEquals($matchdata, $m->match('/dude/admin/user'));
647
648        $matchdata = array('controller' => 'admin/user', 'action' => 'view', 'url' => 'dude/what');
649        $this->assertEquals($matchdata, $m->match('/dude/what/admin/user'));
650    }
651
652    public function testController()
653    {
654        $m = new Horde_Routes_Mapper();
655        $m->connect('hi/:controller', array('action' => 'hi'));
656        $m->createRegs(array('content', 'admin/user'));
657
658        $this->assertNull($m->match('/boo'));
659        $this->assertNull($m->match('/boo/blah'));
660        $this->assertNull($m->match('/hi/13870948'));
661        $this->assertNull($m->match('/hi/content/dog'));
662        $this->assertNull($m->match('/hi/admin/user/foo'));
663        $this->assertNull($m->match('/hi/admin/user/foo/'));
664
665        $matchdata = array('controller' => 'content', 'action' => 'hi');
666        $this->assertEquals($matchdata, $m->match('/hi/content'));
667
668        $matchdata = array('controller' => 'admin/user', 'action' => 'hi');
669        $this->assertEquals($matchdata, $m->match('/hi/admin/user'));
670    }
671
672    public function testStandardRoute()
673    {
674        $m = new Horde_Routes_Mapper();
675        $m->connect(':controller/:action/:id');
676        $m->createRegs(array('content', 'admin/user'));
677
678        $matchdata = array('controller' => 'content', 'action' => 'index', 'id' => null);
679        $this->assertEquals($matchdata, $m->match('/content'));
680
681        $matchdata = array('controller' => 'content', 'action' => 'list', 'id' => null);
682        $this->assertEquals($matchdata, $m->match('/content/list'));
683
684        $matchdata = array('controller' => 'content', 'action' => 'show', 'id' => '10');
685        $this->assertEquals($matchdata, $m->match('/content/show/10'));
686
687        $matchdata = array('controller' => 'admin/user', 'action' => 'index', 'id' => null);
688        $this->assertEquals($matchdata, $m->match('/admin/user'));
689
690        $matchdata = array('controller' => 'admin/user', 'action' => 'list', 'id' => null);
691        $this->assertEquals($matchdata, $m->match('/admin/user/list'));
692
693        $matchdata = array('controller' => 'admin/user', 'action' => 'show', 'id' => 'bbangert');
694        $this->assertEquals($matchdata, $m->match('/admin/user/show/bbangert'));
695
696        $this->assertNull($m->match('/content/show/10/20'));
697        $this->assertNull($m->match('/food'));
698    }
699
700    public function testStandardRouteWithGaps()
701    {
702        $m = new Horde_Routes_Mapper();
703        $m->connect(':controller/:action/:(id).py');
704        $m->createRegs(array('content', 'admin/user'));
705
706        $matchdata = array('controller' => 'content', 'action' => 'index', 'id' => 'None');
707        $this->assertEquals($matchdata, $m->match('/content/index/None.py'));
708
709        $matchdata = array('controller' =>'content', 'action' => 'list', 'id' => 'None');
710        $this->assertEquals($matchdata, $m->match('/content/list/None.py'));
711
712        $matchdata = array('controller' => 'content', 'action' => 'show', 'id' => '10');
713        $this->assertEquals($matchdata, $m->match('/content/show/10.py'));
714    }
715
716    public function testStandardRouteWithGapsAndDomains()
717    {
718        $m = new Horde_Routes_Mapper();
719        $m->connect('manage/:domain.:ext', array('controller' => 'admin/user', 'action' => 'view',
720                                                 'ext' => 'html'));
721        $m->connect(':controller/:action/:id');
722        $m->createRegs(array('content', 'admin/user'));
723
724        $matchdata = array('controller' => 'content', 'action' => 'index', 'id' => 'None.py');
725        $this->assertEquals($matchdata, $m->match('/content/index/None.py'));
726
727        $matchdata = array('controller' => 'content', 'action' => 'list', 'id' => 'None.py');
728        $this->assertEquals($matchdata, $m->match('/content/list/None.py'));
729
730        $matchdata = array('controller' => 'content', 'action' => 'show', 'id' => '10.py');
731        $this->assertEquals($matchdata, $m->match('/content/show/10.py'));
732
733        $matchdata = array('controller' => 'content', 'action' => 'show.all', 'id' => '10.py');
734        $this->assertEquals($matchdata, $m->match('/content/show.all/10.py'));
735
736        $matchdata = array('controller' => 'content', 'action' => 'show', 'id' => 'www.groovie.org');
737        $this->assertEquals($matchdata, $m->match('/content/show/www.groovie.org'));
738
739        $matchdata = array('controller' => 'admin/user', 'action' => 'view',
740                           'ext' => 'html', 'domain' => 'groovie');
741        $this->assertEquals($matchdata, $m->match('/manage/groovie'));
742
743        $matchdata = array('controller' => 'admin/user', 'action' => 'view',
744                           'ext' => 'xml', 'domain' => 'groovie');
745        $this->assertEquals($matchdata, $m->match('/manage/groovie.xml'));
746    }
747
748    public function testStandardWithDomains()
749    {
750        $m = new Horde_Routes_Mapper();
751        $m->connect('manage/:domain', array('controller' => 'domains', 'action' => 'view'));
752        $m->createRegs(array('domains'));
753
754        $matchdata = array('controller' => 'domains', 'action' => 'view', 'domain' => 'www.groovie.org');
755        $this->assertEquals($matchdata, $m->match('/manage/www.groovie.org'));
756    }
757
758    public function testDefaultRoute()
759    {
760        $m = new Horde_Routes_Mapper();
761        $m->connect('', array('controller' => 'content', 'action' => 'index'));
762        $m->createRegs(array('content'));
763
764        $this->assertNull($m->match('/x'));
765        $this->assertNull($m->match('/hello/world'));
766        $this->assertNull($m->match('/hello/world/how/are'));
767        $this->assertNull($m->match('/hello/world/how/are/you/today'));
768
769        $matchdata = array('controller' => 'content', 'action' => 'index');
770        $this->assertEquals($matchdata, $m->match('/'));
771    }
772
773    public function testDynamicWithPrefix()
774    {
775        $m = new Horde_Routes_Mapper();
776        $m->prefix = '/blog';
777        $m->connect(':controller/:action/:id');
778        $m->connect('', array('controller' => 'content', 'action' => 'index'));
779        $m->createRegs(array('content', 'archive', 'admin/comments'));
780
781        $this->assertNull($m->match('/x'));
782        $this->assertNull($m->match('/admin/comments'));
783        $this->assertNull($m->match('/content/view'));
784        $this->assertNull($m->match('/archive/view/4'));
785
786        $matchdata = array('controller' => 'content', 'action' => 'index');
787        $this->assertEquals($matchdata, $m->match('/blog'));
788
789        $matchdata = array('controller' => 'content', 'action' => 'index', 'id' => null);
790        $this->assertEquals($matchdata, $m->match('/blog/content'));
791
792        $matchdata = array('controller' => 'admin/comments', 'action' => 'view', 'id' => null);
793        $this->assertEquals($matchdata, $m->match('/blog/admin/comments/view'));
794
795        $matchdata = array('controller' => 'archive', 'action' => 'index', 'id' => null);
796        $this->assertEquals($matchdata, $m->match('/blog/archive'));
797
798        $matchdata = array('controller' => 'archive', 'action' => 'view', 'id' => '4');
799        $this->assertEquals($matchdata, $m->match('/blog/archive/view/4'));
800    }
801
802    public function testDynamicWithMultipleAndPrefix()
803    {
804        $m = new Horde_Routes_Mapper();
805        $m->prefix = '/blog';
806        $m->connect(':controller/:action/:id');
807        $m->connect('home/:action', array('controller' => 'archive'));
808        $m->connect('', array('controller' => 'content'));
809        $m->createRegs(array('content', 'archive', 'admin/comments'));
810
811        $this->assertNull($m->match('/x'));
812        $this->assertNull($m->match('/admin/comments'));
813        $this->assertNull($m->match('/content/view'));
814        $this->assertNull($m->match('/archive/view/4'));
815
816        $matchdata = array('controller' => 'content', 'action' => 'index');
817        $this->assertEquals($matchdata, $m->match('/blog/'));
818
819        $matchdata = array('controller' => 'archive', 'action' => 'view');
820        $this->assertEquals($matchdata, $m->match('/blog/home/view'));
821
822        $matchdata = array('controller' => 'content', 'action' => 'index', 'id' => null);
823        $this->assertEquals($matchdata, $m->match('/blog/content'));
824
825        $matchdata = array('controller' => 'admin/comments', 'action' => 'view', 'id' => null);
826        $this->assertEquals($matchdata, $m->match('/blog/admin/comments/view'));
827
828        $matchdata = array('controller' => 'archive', 'action' => 'index', 'id' => null);
829        $this->assertEquals($matchdata, $m->match('/blog/archive'));
830
831        $matchdata = array('controller' => 'archive', 'action' => 'view', 'id' => '4');
832        $this->assertEquals($matchdata, $m->match('/blog/archive/view/4'));
833    }
834
835    public function testSplitsWithExtension()
836    {
837        $m = new Horde_Routes_Mapper();
838        $m->connect('hi/:(action).html', array('controller' => 'content'));
839        $m->createRegs();
840
841        $this->assertNull($m->match('/boo'));
842        $this->assertNull($m->match('/boo/blah'));
843        $this->assertNull($m->match('/hi/dude/what'));
844        $this->assertNull($m->match('/hi'));
845
846        $matchdata = array('controller' => 'content', 'action' => 'index');
847        $this->assertEquals($matchdata, $m->match('/hi/index.html'));
848
849        $matchdata = array('controller' => 'content', 'action' => 'dude');
850        $this->assertEquals($matchdata, $m->match('/hi/dude.html'));
851    }
852
853    public function testSplitsWithDashes()
854    {
855        $m = new Horde_Routes_Mapper();
856        $m->connect('archives/:(year)-:(month)-:(day).html',
857                    array('controller' => 'archives', 'action' => 'view'));
858        $m->createRegs();
859
860        $this->assertNull($m->match('/boo'));
861        $this->assertNull($m->match('/archives'));
862
863        $matchdata = array('controller' => 'archives', 'action' => 'view',
864                           'year' => '2004', 'month' => '12', 'day' => '4');
865        $this->assertEquals($matchdata, $m->match('/archives/2004-12-4.html'));
866
867        $matchdata = array('controller' => 'archives', 'action' => 'view',
868                           'year' => '04', 'month' => '10', 'day' => '4');
869        $this->assertEquals($matchdata, $m->match('/archives/04-10-4.html'));
870
871        $matchdata = array('controller' => 'archives', 'action' => 'view',
872                           'year' => '04', 'month' => '1', 'day' => '1');
873        $this->assertEquals($matchdata, $m->match('/archives/04-1-1.html'));
874    }
875
876    public function testSplitsPackedWithRegexps()
877    {
878        $m = new Horde_Routes_Mapper();
879        $m->connect('archives/:(year):(month):(day).html',
880                    array('controller' => 'archives', 'action' => 'view',
881                          'requirements' => array('year' => '\d{4}', 'month' => '\d{2}',
882                                                  'day'  => '\d{2}')));
883        $m->createRegs();
884
885        $this->assertNull($m->match('/boo'));
886        $this->assertNull($m->match('/archives'));
887        $this->assertNull($m->match('/archives/2004020.html'));
888        $this->assertNull($m->match('/archives/200502.html'));
889
890        $matchdata = array('controller' => 'archives', 'action' => 'view',
891                           'year' => '2004', 'month' => '12', 'day' => '04');
892        $this->assertEquals($matchdata, $m->match('/archives/20041204.html'));
893
894        $matchdata = array('controller' => 'archives', 'action' => 'view',
895                           'year' => '2005', 'month' => '10', 'day' => '04');
896        $this->assertEquals($matchdata, $m->match('/archives/20051004.html'));
897
898        $matchdata = array('controller' => 'archives', 'action' => 'view',
899                           'year' => '2006', 'month' => '01', 'day' => '01');
900        $this->assertEquals($matchdata, $m->match('/archives/20060101.html'));
901    }
902
903    public function testSplitsWithSlashes()
904    {
905        $m = new Horde_Routes_Mapper();
906        $m->connect(':name/:(action)-:(day)', array('controller' => 'content'));
907
908        $this->assertNull($m->match('/something'));
909        $this->assertNull($m->match('/something/is-'));
910
911        $matchdata = array('controller' => 'content', 'action' => 'view',
912                           'day' => '3', 'name' => 'group');
913        $this->assertEquals($matchdata, $m->match('/group/view-3'));
914
915        $matchdata = array('controller' => 'content', 'action' => 'view',
916                           'day' => '5', 'name' => 'group');
917        $this->assertEquals($matchdata, $m->match('/group/view-5'));
918    }
919
920    public function testSplitsWithSlashesAndDefault()
921    {
922        $m = new Horde_Routes_Mapper();
923        $m->connect(':name/:(action)-:(id)', array('controller' => 'content'));
924        $m->createRegs();
925
926        $this->assertNull($m->match('/something'));
927        $this->assertNull($m->match('/something/is'));
928
929        $matchdata = array('controller' => 'content', 'action' => 'view',
930                           'id' => '3', 'name' => 'group');
931        $this->assertEquals($matchdata, $m->match('/group/view-3'));
932
933        $matchdata = array('controller' => 'content', 'action' => 'view',
934                           'id' => null, 'name' => 'group');
935        $this->assertEquals($matchdata, $m->match('/group/view-'));
936    }
937
938    public function testNoRegMake()
939    {
940        $m = new Horde_Routes_Mapper();
941        $m->connect(':name/:(action)-:(id)', array('controller' => 'content'));
942        $m->controllerScan = false;
943        try {
944            $m->match('/group/view-3');
945            $this->fail();
946        } catch (Horde_Routes_Exception $e) {
947            $this->assertRegExp('/must generate the regular expressions/i', $e->getMessage());
948        }
949    }
950
951    public function testRoutematch()
952    {
953        $m = new Horde_Routes_Mapper();
954        $m->connect(':controller/:action/:id');
955        $m->createRegs(array('content'));
956        $route = $m->matchList[0];
957
958        list($resultdict, $resultObj) = $m->routematch('/content');
959
960        $this->assertEquals(array('controller' => 'content', 'action' => 'index', 'id' => null),
961                            $resultdict);
962        $this->assertSame($route, $resultObj);
963        $this->assertNull($m->routematch('/nowhere'));
964    }
965
966    public function testRoutematchDebug()
967    {
968        $m = new Horde_Routes_Mapper();
969        $m->connect(':controller/:action/:id');
970        $m->debug = true;
971        $m->createRegs(array('content'));
972        $route = $m->matchList[0];
973
974        list($resultdict, $resultObj, $debug) = $m->routematch('/content');
975
976        $this->assertEquals(array('controller' => 'content', 'action' => 'index', 'id' => null),
977                            $resultdict);
978        $this->assertSame($route, $resultObj);
979
980        list($resultdict, $resultObj, $debug) = $m->routematch('/nowhere');
981        $this->assertNull($resultdict);
982        $this->assertNull($resultObj);
983        $this->assertEquals(1, count($debug));
984    }
985
986    public function testMatchDebug()
987    {
988        $m = new Horde_Routes_Mapper();
989        $m->connect('nowhere', 'http://nowhere.com/', array('_static' => true));
990        $m->connect(':controller/:action/:id');
991        $m->debug = true;
992        $m->createRegs(array('content'));
993        $route = $m->matchList[1];
994
995        list($resultdict, $resultObj, $debug) = $m->match('/content');
996        $this->assertEquals(array('controller' => 'content', 'action' => 'index', 'id' => null),
997                            $resultdict);
998
999        $this->assertSame($route, $resultObj);
1000
1001        list($resultdict, $resultObj, $debug) = $m->match('/nowhere');
1002        $this->assertNull($resultdict);
1003        $this->assertNull($resultObj);
1004        $this->assertEquals(2, count($debug));
1005    }
1006
1007    public function testResourceCollection()
1008    {
1009        $m = new Horde_Routes_Mapper();
1010        $m->resource('message', 'messages');
1011        $m->createRegs(array('messages'));
1012
1013        $path = '/messages';
1014
1015        $m->environ = array('REQUEST_METHOD' => 'GET');
1016        $this->assertEquals(array('controller' => 'messages', 'action' => 'index'),
1017                            $m->match($path));
1018
1019        $m->environ = array('REQUEST_METHOD' => 'POST');
1020        $this->assertEquals(array('controller' => 'messages', 'action' => 'create'),
1021                            $m->match($path));
1022    }
1023
1024    public function testFormattedResourceCollection()
1025    {
1026        $m = new Horde_Routes_Mapper();
1027        $m->resource('message', 'messages');
1028        $m->createRegs(array('messages'));
1029
1030        $path = '/messages.xml';
1031
1032        $m->environ = array('REQUEST_METHOD' => 'GET');
1033        $this->assertEquals(array('controller' => 'messages', 'action' => 'index',
1034                                  'format' => 'xml'),
1035                            $m->match($path));
1036
1037        $m->environ = array('REQUEST_METHOD' => 'POST');
1038        $this->assertEquals(array('controller' => 'messages', 'action' => 'create',
1039                                  'format' => 'xml'),
1040                            $m->match($path));
1041    }
1042
1043    public function testResourceMember()
1044    {
1045        $m = new Horde_Routes_Mapper();
1046        $m->resource('message', 'messages');
1047        $m->createRegs(array('messages'));
1048
1049        $path = '/messages/42';
1050
1051        $m->environ = array('REQUEST_METHOD' => 'GET');
1052        $this->assertEquals(array('controller' => 'messages', 'action' => 'show',
1053                                  'id' => 42),
1054                            $m->match($path));
1055
1056        $m->environ = array('REQUEST_METHOD' => 'POST');
1057        $this->assertNull($m->match($path));
1058
1059        $m->environ = array('REQUEST_METHOD' => 'PUT');
1060        $this->assertEquals(array('controller' => 'messages', 'action' => 'update',
1061                                  'id' => 42),
1062                            $m->match($path));
1063
1064        $m->environ = array('REQUEST_METHOD' => 'DELETE');
1065        $this->assertEquals(array('controller' => 'messages', 'action' => 'delete',
1066                                  'id' => 42),
1067                            $m->match($path));
1068    }
1069
1070    public function testFormattedResourceMember()
1071    {
1072        $m = new Horde_Routes_Mapper();
1073        $m->resource('message', 'messages');
1074        $m->createRegs(array('messages'));
1075
1076        $path = '/messages/42.xml';
1077
1078        $m->environ = array('REQUEST_METHOD' => 'GET');
1079        $this->assertEquals(array('controller' => 'messages', 'action' => 'show',
1080                                  'id' => 42, 'format' => 'xml'),
1081                            $m->match($path));
1082
1083        $m->environ = array('REQUEST_METHOD' => 'POST');
1084        $this->assertNull($m->match($path));
1085
1086        $m->environ = array('REQUEST_METHOD' => 'PUT');
1087        $this->assertEquals(array('controller' => 'messages', 'action' => 'update',
1088                                  'id' => 42, 'format' => 'xml'),
1089                            $m->match($path));
1090
1091        $m->environ = array('REQUEST_METHOD' => 'DELETE');
1092        $this->assertEquals(array('controller' => 'messages', 'action' => 'delete',
1093                                  'id' => 42, 'format' => 'xml'),
1094                            $m->match($path));
1095    }
1096
1097}
1098