/* global describe, it */
var util = require('util')
var expect = require('chai').expect
var pathToRegexp = require('./')
/**
* An array of test cases with expected inputs and outputs.
*
* @type {Array}
*/
var TESTS = [
/**
* Simple paths.
*/
[
'/',
null,
[
'/'
],
[
['/', ['/']],
['/route', null]
],
[
[null, '/'],
[{}, '/'],
[{ id: 123 }, '/']
]
],
[
'/test',
null,
[
'/test'
],
[
['/test', ['/test']],
['/route', null],
['/test/route', null],
['/test/', ['/test/']]
],
[
[null, '/test'],
[{}, '/test']
]
],
[
'/test/',
null,
[
'/test/'
],
[
['/test', ['/test']],
['/test/', ['/test/']],
['/test//', null]
],
[
[null, '/test/']
]
],
/**
* Case-sensitive paths.
*/
[
'/test',
{
sensitive: true
},
[
'/test'
],
[
['/test', ['/test']],
['/TEST', null]
],
[
[null, '/test']
]
],
[
'/TEST',
{
sensitive: true
},
[
'/TEST'
],
[
['/test', null],
['/TEST', ['/TEST']]
],
[
[null, '/TEST']
]
],
/**
* Strict mode.
*/
[
'/test',
{
strict: true
},
[
'/test'
],
[
['/test', ['/test']],
['/test/', null],
['/TEST', ['/TEST']]
],
[
[null, '/test']
]
],
[
'/test/',
{
strict: true
},
[
'/test/'
],
[
['/test', null],
['/test/', ['/test/']],
['/test//', null]
],
[
[null, '/test/']
]
],
/**
* Non-ending mode.
*/
[
'/test',
{
end: false
},
[
'/test'
],
[
['/test', ['/test']],
['/test/', ['/test/']],
['/test/route', ['/test']],
['/route', null]
],
[
[null, '/test']
]
],
[
'/test/',
{
end: false
},
[
'/test/'
],
[
['/test/route', ['/test']],
['/test//', ['/test']],
['/test//route', ['/test']]
],
[
[null, '/test/']
]
],
[
'/:test',
{
end: false
},
[
{
name: 'test',
prefix: '/',
delimiter: '/',
optional: false,
repeat: false,
pattern: '[^\\/]+?'
}
],
[
['/route', ['/route', 'route']]
],
[
[{}, null],
[{ test: 'abc' }, '/abc']
]
],
[
'/:test/',
{
end: false
},
[
{
name: 'test',
prefix: '/',
delimiter: '/',
optional: false,
repeat: false,
pattern: '[^\\/]+?'
},
'/'
],
[
['/route', ['/route', 'route']]
],
[
[{ test: 'abc' }, '/abc/']
]
],
/**
* Combine modes.
*/
[
'/test',
{
end: false,
strict: true
},
[
'/test'
],
[
['/test', ['/test']],
['/test/', ['/test']],
['/test/route', ['/test']]
],
[
[null, '/test']
]
],
[
'/test/',
{
end: false,
strict: true
},
[
'/test/'
],
[
['/test', null],
['/test/', ['/test/']],
['/test//', ['/test/']],
['/test/route', ['/test/']]
],
[
[null, '/test/']
]
],
[
'/test.json',
{
end: false,
strict: true
},
[
'/test.json'
],
[
['/test.json', ['/test.json']],
['/test.json.hbs', null],
['/test.json/route', ['/test.json']]
],
[
[null, '/test.json']
]
],
[
'/:test',
{
end: false,
strict: true
},
[
{
name: 'test',
prefix: '/',
delimiter: '/',
optional: false,
repeat: false,
pattern: '[^\\/]+?'
}
],
[
['/route', ['/route', 'route']],
['/route/', ['/route', 'route']]
],
[
[{}, null],
[{ test: 'abc' }, '/abc']
]
],
[
'/:test/',
{
end: false,
strict: true
},
[
{
name: 'test',
prefix: '/',
delimiter: '/',
optional: false,
repeat: false,
pattern: '[^\\/]+?'
},
'/'
],
[
['/route', null],
['/route/', ['/route/', 'route']]
],
[
[{ test: 'foobar' }, '/foobar/']
]
],
/**
* Arrays of simple paths.
*/
[
['/one', '/two'],
null,
[],
[
['/one', ['/one']],
['/two', ['/two']],
['/three', null],
['/one/two', null]
]
],
/**
* Non-ending simple path.
*/
[
'/test',
{
end: false
},
[
'/test'
],
[
['/test/route', ['/test']]
],
[
[null, '/test']
]
],
/**
* Single named parameter.
*/
[
'/:test',
null,
[
{
name: 'test',
prefix: '/',
delimiter: '/',
optional: false,
repeat: false,
pattern: '[^\\/]+?'
}
],
[
['/route', ['/route', 'route']],
['/another', ['/another', 'another']],
['/something/else', null],
['/route.json', ['/route.json', 'route.json']],
['/something%2Felse', ['/something%2Felse', 'something%2Felse']]
],
[
[{ test: 'route' }, '/route'],
[{ test: 'something/else' }, '/something%2Felse']
]
],
[
'/:test',
{
strict: true
},
[
{
name: 'test',
prefix: '/',
delimiter: '/',
optional: false,
repeat: false,
pattern: '[^\\/]+?'
}
],
[
['/route', ['/route', 'route']],
['/route/', null]
],
[
[{ test: 'route' }, '/route']
]
],
[
'/:test/',
{
strict: true
},
[
{
name: 'test',
prefix: '/',
delimiter: '/',
optional: false,
repeat: false,
pattern: '[^\\/]+?'
},
'/'
],
[
['/route/', ['/route/', 'route']],
['/route//', null]
],
[
[{ test: 'route' }, '/route/']
]
],
[
'/:test',
{
end: false
},
[
{
name: 'test',
prefix: '/',
delimiter: '/',
optional: false,
repeat: false,
pattern: '[^\\/]+?'
}
],
[
['/route.json', ['/route.json', 'route.json']],
['/route//', ['/route', 'route']]
],
[
[{ test: 'route' }, '/route']
]
],
/**
* Optional named parameter.
*/
[
'/:test?',
null,
[
{
name: 'test',
prefix: '/',
delimiter: '/',
optional: true,
repeat: false,
pattern: '[^\\/]+?'
}
],
[
['/route', ['/route', 'route']],
['/route/nested', null],
['/', ['/', undefined]],
['//', null]
],
[
[null, ''],
[{ test: 'foobar' }, '/foobar']
]
],
[
'/:test?',
{
strict: true
},
[
{
name: 'test',
prefix: '/',
delimiter: '/',
optional: true,
repeat: false,
pattern: '[^\\/]+?'
}
],
[
['/route', ['/route', 'route']],
['/', null], // Questionable behaviour.
['//', null]
],
[
[null, ''],
[{ test: 'foobar' }, '/foobar']
]
],
[
'/:test?/',
{
strict: true
},
[
{
name: 'test',
prefix: '/',
delimiter: '/',
optional: true,
repeat: false,
pattern: '[^\\/]+?'
},
'/'
],
[
['/route', null],
['/route/', ['/route/', 'route']],
['/', ['/', undefined]],
['//', null]
],
[
[null, '/'],
[{ test: 'foobar' }, '/foobar/']
]
],
/**
* Repeated one or more times parameters.
*/
[
'/:test+',
null,
[
{
name: 'test',
prefix: '/',
delimiter: '/',
optional: false,
repeat: true,
pattern: '[^\\/]+?'
}
],
[
['/', null],
['/route', ['/route', 'route']],
['/some/basic/route', ['/some/basic/route', 'some/basic/route']],
['//', null]
],
[
[{}, null],
[{ test: 'foobar' }, '/foobar'],
[{ test: ['a', 'b', 'c'] }, '/a/b/c']
]
],
[
'/:test(\\d+)+',
null,
[
{
name: 'test',
prefix: '/',
delimiter: '/',
optional: false,
repeat: true,
pattern: '\\d+'
}
],
[
['/abc/456/789', null],
['/123/456/789', ['/123/456/789', '123/456/789']]
],
[
[{ test: 'abc' }, null],
[{ test: 123 }, '/123'],
[{ test: [1, 2, 3] }, '/1/2/3']
]
],
[
'/route.:ext(json|xml)+',
null,
[
'/route',
{
name: 'ext',
prefix: '.',
delimiter: '.',
optional: false,
repeat: true,
pattern: 'json|xml'
}
],
[
['/route', null],
['/route.json', ['/route.json', 'json']],
['/route.xml.json', ['/route.xml.json', 'xml.json']],
['/route.html', null]
],
[
[{ ext: 'foobar' }, null],
[{ ext: 'xml' }, '/route.xml'],
[{ ext: ['xml', 'json'] }, '/route.xml.json']
]
],
/**
* Repeated zero or more times parameters.
*/
[
'/:test*',
null,
[
{
name: 'test',
prefix: '/',
delimiter: '/',
optional: true,
repeat: true,
pattern: '[^\\/]+?'
}
],
[
['/', ['/', undefined]],
['//', null],
['/route', ['/route', 'route']],
['/some/basic/route', ['/some/basic/route', 'some/basic/route']]
],
[
[{}, ''],
[{ test: 'foobar' }, '/foobar'],
[{ test: ['foo', 'bar'] }, '/foo/bar']
]
],
[
'/route.:ext([a-z]+)*',
null,
[
'/route',
{
name: 'ext',
prefix: '.',
delimiter: '.',
optional: true,
repeat: true,
pattern: '[a-z]+'
}
],
[
['/route', ['/route', undefined]],
['/route.json', ['/route.json', 'json']],
['/route.json.xml', ['/route.json.xml', 'json.xml']],
['/route.123', null]
],
[
[{}, '/route'],
[{ ext: [] }, '/route'],
[{ ext: '123' }, null],
[{ ext: 'foobar' }, '/route.foobar'],
[{ ext: ['foo', 'bar'] }, '/route.foo.bar']
]
],
/**
* Custom named parameters.
*/
[
'/:test(\\d+)',
null,
[
{
name: 'test',
prefix: '/',
delimiter: '/',
optional: false,
repeat: false,
pattern: '\\d+'
}
],
[
['/123', ['/123', '123']],
['/abc', null],
['/123/abc', null]
],
[
[{ test: 'abc' }, null],
[{ test: '123' }, '/123']
]
],
[
'/:test(\\d+)',
{
end: false
},
[
{
name: 'test',
prefix: '/',
delimiter: '/',
optional: false,
repeat: false,
pattern: '\\d+'
}
],
[
['/123', ['/123', '123']],
['/abc', null],
['/123/abc', ['/123', '123']]
],
[
[{ test: '123' }, '/123']
]
],
[
'/:test(.*)',
null,
[
{
name: 'test',
prefix: '/',
delimiter: '/',
optional: false,
repeat: false,
pattern: '.*'
}
],
[
['/anything/goes/here', ['/anything/goes/here', 'anything/goes/here']]
],
[
[{ test: '' }, '/'],
[{ test: 'abc' }, '/abc'],
[{ test: 'abc/123' }, '/abc%2F123']
]
],
[
'/:route([a-z]+)',
null,
[
{
name: 'route',
prefix: '/',
delimiter: '/',
optional: false,
repeat: false,
pattern: '[a-z]+'
}
],
[
['/abcde', ['/abcde', 'abcde']],
['/12345', null]
],
[
[{ route: '' }, null],
[{ route: '123' }, null],
[{ route: 'abc' }, '/abc']
]
],
[
'/:route(this|that)',
null,
[
{
name: 'route',
prefix: '/',
delimiter: '/',
optional: false,
repeat: false,
pattern: 'this|that'
}
],
[
['/this', ['/this', 'this']],
['/that', ['/that', 'that']],
['/foo', null]
],
[
[{ route: 'this' }, '/this'],
[{ route: 'foo' }, null],
[{ route: 'that' }, '/that']
]
],
/**
* Prefixed slashes could be omitted.
*/
[
'test',
null,
[
'test'
],
[
['test', ['test']],
['/test', null]
],
[
[null, 'test']
]
],
[
':test',
null,
[
{
name: 'test',
prefix: '',
delimiter: '/',
optional: false,
repeat: false,
pattern: '[^\\/]+?'
}
],
[
['route', ['route', 'route']],
['/route', null],
['route/', ['route/', 'route']]
],
[
[{ test: '' }, null],
[{}, null],
[{ test: null }, null],
[{ test: 'route' }, 'route']
]
],
[
':test',
{
strict: true
},
[
{
name: 'test',
prefix: '',
delimiter: '/',
optional: false,
repeat: false,
pattern: '[^\\/]+?'
}
],
[
['route', ['route', 'route']],
['/route', null],
['route/', null]
],
[
[{ test: 'route' }, 'route']
]
],
[
':test',
{
end: false
},
[
{
name: 'test',
prefix: '',
delimiter: '/',
optional: false,
repeat: false,
pattern: '[^\\/]+?'
}
],
[
['route', ['route', 'route']],
['/route', null],
['route/', ['route/', 'route']],
['route/foobar', ['route', 'route']]
],
[
[{ test: 'route' }, 'route']
]
],
[
':test?',
null,
[
{
name: 'test',
prefix: '',
delimiter: '/',
optional: true,
repeat: false,
pattern: '[^\\/]+?'
}
],
[
['route', ['route', 'route']],
['/route', null],
['', ['', undefined]],
['route/foobar', null]
],
[
[{}, ''],
[{ test: '' }, null],
[{ test: 'route' }, 'route']
]
],
/**
* Formats.
*/
[
'/test.json',
null,
[
'/test.json'
],
[
['/test.json', ['/test.json']],
['/route.json', null]
],
[
[{}, '/test.json']
]
],
[
'/:test.json',
null,
[
{
name: 'test',
prefix: '/',
delimiter: '/',
optional: false,
repeat: false,
pattern: '[^\\/]+?'
},
'.json'
],
[
['/test.json', ['/test.json', 'test']],
['/route.json', ['/route.json', 'route']],
['/route.json.json', ['/route.json.json', 'route.json']]
],
[
[{ test: 'foo' }, '/foo.json']
]
],
/**
* Format params.
*/
[
'/test.:format',
null,
[
'/test',
{
name: 'format',
prefix: '.',
delimiter: '.',
optional: false,
repeat: false,
pattern: '[^.]+?'
}
],
[
['/test.html', ['/test.html', 'html']],
['/test.hbs.html', null]
],
[
[{}, null],
[{ format: '' }, null],
[{ format: 'foo' }, '/test.foo']
]
],
[
'/test.:format.:format',
null,
[
'/test',
{
name: 'format',
prefix: '.',
delimiter: '.',
optional: false,
repeat: false,
pattern: '[^.]+?'
},
{
name: 'format',
prefix: '.',
delimiter: '.',
optional: false,
repeat: false,
pattern: '[^.]+?'
}
],
[
['/test.html', null],
['/test.hbs.html', ['/test.hbs.html', 'hbs', 'html']]
],
[
[{ format: 'foo.bar' }, null],
[{ format: 'foo' }, '/test.foo.foo']
]
],
[
'/test.:format+',
null,
[
'/test',
{
name: 'format',
prefix: '.',
delimiter: '.',
optional: false,
repeat: true,
pattern: '[^.]+?'
}
],
[
['/test.html', ['/test.html', 'html']],
['/test.hbs.html', ['/test.hbs.html', 'hbs.html']]
],
[
[{ format: [] }, null],
[{ format: 'foo' }, '/test.foo'],
[{ format: ['foo', 'bar'] }, '/test.foo.bar']
]
],
[
'/test.:format',
{
end: false
},
[
'/test',
{
name: 'format',
prefix: '.',
delimiter: '.',
optional: false,
repeat: false,
pattern: '[^.]+?'
}
],
[
['/test.html', ['/test.html', 'html']],
['/test.hbs.html', null]
],
[
[{ format: 'foo' }, '/test.foo']
]
],
[
'/test.:format.',
null,
[
'/test',
{
name: 'format',
prefix: '.',
delimiter: '.',
optional: false,
repeat: false,
pattern: '[^.]+?'
},
'.'
],
[
['/test.html.', ['/test.html.', 'html']],
['/test.hbs.html', null]
],
[
[{ format: '' }, null],
[{ format: 'foo' }, '/test.foo.']
]
],
/**
* Format and path params.
*/
[
'/:test.:format',
null,
[
{
name: 'test',
prefix: '/',
delimiter: '/',
optional: false,
repeat: false,
pattern: '[^\\/]+?'
},
{
name: 'format',
prefix: '.',
delimiter: '.',
optional: false,
repeat: false,
pattern: '[^.]+?'
}
],
[
['/route.html', ['/route.html', 'route', 'html']],
['/route', null],
['/route.html.json', ['/route.html.json', 'route.html', 'json']]
],
[
[{}, null],
[{ test: 'route', format: 'foo' }, '/route.foo']
]
],
[
'/:test.:format?',
null,
[
{
name: 'test',
prefix: '/',
delimiter: '/',
optional: false,
repeat: false,
pattern: '[^\\/]+?'
},
{
name: 'format',
prefix: '.',
delimiter: '.',
optional: true,
repeat: false,
pattern: '[^.]+?'
}
],
[
['/route', ['/route', 'route', undefined]],
['/route.json', ['/route.json', 'route', 'json']],
['/route.json.html', ['/route.json.html', 'route.json', 'html']]
],
[
[{ test: 'route' }, '/route'],
[{ test: 'route', format: '' }, null],
[{ test: 'route', format: 'foo' }, '/route.foo']
]
],
[
'/:test.:format?',
{
end: false
},
[
{
name: 'test',
prefix: '/',
delimiter: '/',
optional: false,
repeat: false,
pattern: '[^\\/]+?'
},
{
name: 'format',
prefix: '.',
delimiter: '.',
optional: true,
repeat: false,
pattern: '[^.]+?'
}
],
[
['/route', ['/route', 'route', undefined]],
['/route.json', ['/route.json', 'route', 'json']],
['/route.json.html', ['/route.json.html', 'route.json', 'html']]
],
[
[{ test: 'route' }, '/route'],
[{ test: 'route', format: undefined }, '/route'],
[{ test: 'route', format: '' }, null],
[{ test: 'route', format: 'foo' }, '/route.foo']
]
],
[
'/test.:format(.*)z',
{
end: false
},
[
'/test',
{
name: 'format',
prefix: '.',
delimiter: '.',
optional: false,
repeat: false,
pattern: '.*'
},
'z'
],
[
['/test.abc', null],
['/test.z', ['/test.z', '']],
['/test.abcz', ['/test.abcz', 'abc']]
],
[
[{}, null],
[{ format: '' }, '/test.z'],
[{ format: 'foo' }, '/test.fooz']
]
],
/**
* Unnamed params.
*/
[
'/(\\d+)',
null,
[
{
name: 0,
prefix: '/',
delimiter: '/',
optional: false,
repeat: false,
pattern: '\\d+'
}
],
[
['/123', ['/123', '123']],
['/abc', null],
['/123/abc', null]
],
[
[{}, null],
[{ '0': '123' }, '/123']
]
],
[
'/(\\d+)',
{
end: false
},
[
{
name: 0,
prefix: '/',
delimiter: '/',
optional: false,
repeat: false,
pattern: '\\d+'
}
],
[
['/123', ['/123', '123']],
['/abc', null],
['/123/abc', ['/123', '123']],
['/123/', ['/123/', '123']]
],
[
[{ '0': '123' }, '/123']
]
],
[
'/(\\d+)?',
null,
[
{
name: 0,
prefix: '/',
delimiter: '/',
optional: true,
repeat: false,
pattern: '\\d+'
}
],
[
['/', ['/', undefined]],
['/123', ['/123', '123']]
],
[
[{}, ''],
[{ '0': '123' }, '/123']
]
],
[
'/(.*)',
null,
[
{
name: 0,
prefix: '/',
delimiter: '/',
optional: false,
repeat: false,
pattern: '.*'
}
],
[
['/', ['/', '']],
['/route', ['/route', 'route']],
['/route/nested', ['/route/nested', 'route/nested']]
],
[
[{ '0': '' }, '/'],
[{ '0': '123' }, '/123']
]
],
/**
* Regexps.
*/
[
/.*/,
null,
[],
[
['/match/anything', ['/match/anything']]
]
],
[
/(.*)/,
null,
[
{
name: 0,
prefix: null,
delimiter: null,
optional: false,
repeat: false,
pattern: null
}
],
[
['/match/anything', ['/match/anything', '/match/anything']]
]
],
[
/\/(\d+)/,
null,
[
{
name: 0,
prefix: null,
delimiter: null,
optional: false,
repeat: false,
pattern: null
}
],
[
['/abc', null],
['/123', ['/123', '123']]
]
],
/**
* Mixed arrays.
*/
[
['/test', /\/(\d+)/],
null,
[
{
name: 0,
prefix: null,
delimiter: null,
optional: false,
repeat: false,
pattern: null
}
],
[
['/test', ['/test', undefined]]
]
],
[
['/:test(\\d+)', /(.*)/],
null,
[
{
name: 'test',
prefix: '/',
delimiter: '/',
optional: false,
repeat: false,
pattern: '\\d+'
},
{
name: 0,
prefix: null,
delimiter: null,
optional: false,
repeat: false,
pattern: null
}
],
[
['/123', ['/123', '123', undefined]],
['/abc', ['/abc', undefined, '/abc']]
]
],
/**
* Correct names and indexes.
*/
[
['/:test', '/route/:test'],
null,
[
{
name: 'test',
prefix: '/',
delimiter: '/',
optional: false,
repeat: false,
pattern: '[^\\/]+?'
},
{
name: 'test',
prefix: '/',
delimiter: '/',
optional: false,
repeat: false,
pattern: '[^\\/]+?'
}
],
[
['/test', ['/test', 'test', undefined]],
['/route/test', ['/route/test', undefined, 'test']]
]
],
[
[/^\/([^\/]+)$/, /^\/route\/([^\/]+)$/],
null,
[
{
name: 0,
prefix: null,
delimiter: null,
optional: false,
repeat: false,
pattern: null
},
{
name: 0,
prefix: null,
delimiter: null,
optional: false,
repeat: false,
pattern: null
}
],
[
['/test', ['/test', 'test', undefined]],
['/route/test', ['/route/test', undefined, 'test']]
]
],
/**
* Ignore non-matching groups in regexps.
*/
[
/(?:.*)/,
null,
[],
[
['/anything/you/want', ['/anything/you/want']]
]
],
/**
* Respect escaped characters.
*/
[
'/\\(testing\\)',
null,
[
'/(testing)'
],
[
['/testing', null],
['/(testing)', ['/(testing)']]
],
[
[null, '/(testing)']
]
],
[
'/.+\\*?=^!:${}[]|',
null,
[
'/.+*?=^!:${}[]|'
],
[
['/.+*?=^!:${}[]|', ['/.+*?=^!:${}[]|']]
],
[
[null, '/.+*?=^!:${}[]|']
]
],
/**
* Asterisk functionality.
*/
[
'/*',
null,
[
{
name: 0,
prefix: '/',
delimiter: '/',
optional: false,
repeat: false,
pattern: '.*'
}
],
[
['', null],
['/', ['/', '']],
['/foo/bar', ['/foo/bar', 'foo/bar']]
],
[
[null, null],
[{ '0': '' }, '/'],
[{ '0': 'foobar' }, '/foobar']
]
],
[
'/foo/*',
null,
[
'/foo',
{
name: 0,
prefix: '/',
delimiter: '/',
optional: false,
repeat: false,
pattern: '.*'
}
],
[
['', null],
['/test', null],
['/foo', null],
['/foo/', ['/foo/', '']],
['/foo/bar', ['/foo/bar', 'bar']]
],
[
[{ '0': 'bar' }, '/foo/bar']
]
],
[
'/:foo/*',
null,
[
{
name: 'foo',
prefix: '/',
delimiter: '/',
optional: false,
repeat: false,
pattern: '[^\\/]+?'
},
{
name: 0,
prefix: '/',
delimiter: '/',
optional: false,
repeat: false,
pattern: '.*'
}
],
[
['', null],
['/test', null],
['/foo', null],
['/foo/', ['/foo/', 'foo', '']],
['/foo/bar', ['/foo/bar', 'foo', 'bar']]
],
[
[{ foo: 'foo' }, null],
[{ '0': 'bar' }, null],
[{ foo: 'foo', '0': 'bar' }, '/foo/bar']
]
],
/**
* Random examples.
*/
[
'/:foo/:bar',
null,
[
{
name: 'foo',
prefix: '/',
delimiter: '/',
optional: false,
repeat: false,
pattern: '[^\\/]+?'
},
{
name: 'bar',
prefix: '/',
delimiter: '/',
optional: false,
repeat: false,
pattern: '[^\\/]+?'
}
],
[
['/match/route', ['/match/route', 'match', 'route']]
],
[
[{ foo: 'a', bar: 'b' }, '/a/b']
]
],
[
'/:remote([\\w-.]+)/:user([\\w-]+)',
null,
[
{
name: 'remote',
prefix: '/',
delimiter: '/',
optional: false,
repeat: false,
pattern: '[\\w-.]+'
},
{
name: 'user',
prefix: '/',
delimiter: '/',
optional: false,
repeat: false,
pattern: '[\\w-]+'
}
],
[
['/endpoint/user', ['/endpoint/user', 'endpoint', 'user']],
['/endpoint/user-name', ['/endpoint/user-name', 'endpoint', 'user-name']],
['/foo.bar/user-name', ['/foo.bar/user-name', 'foo.bar', 'user-name']]
],
[
[{ remote: 'foo', user: 'bar' }, '/foo/bar'],
[{ remote: 'foo.bar', user: 'uno' }, '/foo.bar/uno']
]
],
[
'/:foo\\?',
null,
[
{
name: 'foo',
prefix: '/',
delimiter: '/',
optional: false,
repeat: false,
pattern: '[^\\/]+?'
},
'?'
],
[
['/route?', ['/route?', 'route']]
],
[
[{ foo: 'bar' }, '/bar?']
]
],
[
'/:foo\\(:bar?\\)',
null,
[
{
name: 'foo',
prefix: '/',
delimiter: '/',
optional: false,
repeat: false,
pattern: '[^\\/]+?'
},
'(',
{
name: 'bar',
prefix: '',
delimiter: '/',
optional: true,
repeat: false,
pattern: '[^\\/]+?'
},
')'
],
[
['/hello(world)', ['/hello(world)', 'hello', 'world']],
['/hello()', ['/hello()', 'hello', undefined]]
],
[
[{ foo: 'hello', bar: 'world' }, '/hello(world)'],
[{ foo: 'hello' }, '/hello()']
]
],
[
'/:postType(video|audio|text)(\\+.+)?',
null,
[
{
name: 'postType',
prefix: '/',
delimiter: '/',
optional: false,
repeat: false,
pattern: 'video|audio|text'
},
{
name: 0,
prefix: '',
delimiter: '/',
optional: true,
repeat: false,
pattern: '\\+.+'
}
],
[
['/video', ['/video', 'video', undefined]],
['/video+test', ['/video+test', 'video', '+test']],
['/video+', null]
],
[
[{ postType: 'video' }, '/video'],
[{ postType: 'random' }, null]
]
],
/**
* Unicode characters.
*/
[
'/:foo',
null,
[
{
name: 'foo',
prefix: '/',
delimiter: '/',
optional: false,
repeat: false,
pattern: '[^\\/]+?'
}
],
[
['/café', ['/café', 'café']]
],
[
[{ foo: 'café' }, '/caf%C3%A9']
]
]
]
/**
* Dynamically generate the entire test suite.
*/
describe('path-to-regexp', function () {
var TEST_PATH = '/user/:id'
var TEST_PARAM = {
name: 'id',
prefix: '/',
delimiter: '/',
optional: false,
repeat: false,
pattern: '[^\\/]+?'
}
describe('arguments', function () {
it('should accept an array of keys as the second argument', function () {
var keys = []
var re = pathToRegexp(TEST_PATH, keys, { end: false })
expect(re.keys).to.equal(keys)
expect(keys).to.deep.equal([TEST_PARAM])
expect(exec(re, '/user/123/show')).to.deep.equal(['/user/123', '123'])
})
it('should work with keys as null', function () {
var re = pathToRegexp(TEST_PATH, null, { end: false })
expect(re.keys).to.deep.equal([TEST_PARAM])
expect(exec(re, '/user/123/show')).to.deep.equal(['/user/123', '123'])
})
})
describe('tokens', function () {
var tokens = pathToRegexp.parse(TEST_PATH)
it('should expose method to compile tokens to regexp', function () {
var re = pathToRegexp.tokensToRegExp(tokens)
expect(exec(re, '/user/123')).to.deep.equal(['/user/123', '123'])
})
it('should expose method to compile tokens to a path function', function () {
var fn = pathToRegexp.tokensToFunction(tokens)
expect(fn({ id: 123 })).to.equal('/user/123')
})
})
describe('rules', function () {
TESTS.forEach(function (test) {
var path = test[0]
var opts = test[1]
var tokens = test[2]
var matchCases = test[3]
var compileCases = test[4]
var keys = tokens.filter(function (token) {
return typeof token !== 'string'
})
describe(util.inspect(path), function () {
// Parsing and compiling is only supported with string input.
if (typeof path === 'string') {
it('should parse', function () {
expect(pathToRegexp.parse(path)).to.deep.equal(tokens)
})
describe('compile', function () {
var toPath = pathToRegexp.compile(path)
compileCases.forEach(function (io) {
var input = io[0]
var output = io[1]
if (output != null) {
it('should compile using ' + util.inspect(input), function () {
expect(toPath(input)).to.equal(output)
})
} else {
it('should not compile using ' + util.inspect(input), function () {
expect(function () {
toPath(input)
}).to.throw(TypeError)
})
}
})
})
}
describe('match' + (opts ? ' using ' + util.inspect(opts) : ''), function () {
matchCases.forEach(function (io) {
var input = io[0]
var output = io[1]
var message = 'should' + (output ? ' ' : ' not ') + 'match ' + util.inspect(input)
it(message, function () {
var re = pathToRegexp(path, opts)
expect(re.keys).to.deep.equal(keys)
expect(exec(re, input)).to.deep.equal(output)
})
})
})
})
})
})
describe('compile errors', function () {
it('should throw when a required param is undefined', function () {
var toPath = pathToRegexp.compile('/a/:b/c')
expect(function () {
toPath()
}).to.throw(TypeError, 'Expected "b" to be defined')
})
it('should throw when it does not match the pattern', function () {
var toPath = pathToRegexp.compile('/:foo(\\d+)')
expect(function () {
toPath({ foo: 'abc' })
}).to.throw(TypeError, 'Expected "foo" to match "\\d+"')
})
it('should throw when expecting a repeated value', function () {
var toPath = pathToRegexp.compile('/:foo+')
expect(function () {
toPath({ foo: [] })
}).to.throw(TypeError, 'Expected "foo" to not be empty')
})
it('should throw when not expecting a repeated value', function () {
var toPath = pathToRegexp.compile('/:foo')
expect(function () {
toPath({ foo: [] })
}).to.throw(TypeError, 'Expected "foo" to not repeat')
})
it('should throw when repeated value does not match', function () {
var toPath = pathToRegexp.compile('/:foo(\\d+)+')
expect(function () {
toPath({ foo: [1, 2, 3, 'a'] })
}).to.throw(TypeError, 'Expected all "foo" to match "\\d+"')
})
})
})
/**
* Execute a regular expression and return a flat array for comparison.
*
* @param {RegExp} re
* @param {String} str
* @return {Array}
*/
function exec (re, str) {
var match = re.exec(str)
return match && Array.prototype.slice.call(match)
}