Skip to content

Commit 8a99807

Browse files
committed
Merge pull request #12 from seegno/enhancement/add-uri-assert
Add URI assert
2 parents 6360a11 + e8a44dd commit 8a99807

File tree

3 files changed

+190
-0
lines changed

3 files changed

+190
-0
lines changed

lib/asserts/uri-assert.js

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
2+
/**
3+
* Module dependencies.
4+
*/
5+
6+
var _ = require('lodash');
7+
var URI = require('URIjs');
8+
var Validator = require('validator.js').Validator;
9+
var Violation = require('validator.js').Violation;
10+
var fmt = require('util').format;
11+
12+
/**
13+
* Export `UriAssert`.
14+
*/
15+
16+
module.exports = function(constraints) {
17+
18+
/**
19+
* Class name.
20+
*/
21+
22+
this.__class__ = 'Uri';
23+
24+
/**
25+
* Constraints.
26+
*/
27+
28+
this.constraints = constraints || {};
29+
30+
/**
31+
* Validate constraints.
32+
*/
33+
34+
_.forEach(this.constraints, function(constraint, key) {
35+
if (!_.has(URI.prototype, key)) {
36+
throw new Error(fmt('Invalid constraint "%s=%s"', key, constraint));
37+
}
38+
});
39+
40+
/**
41+
* Validation algorithm.
42+
*/
43+
44+
this.validate = function(value) {
45+
if ('string' !== typeof value) {
46+
/* jshint camelcase: false */
47+
throw new Violation(this, value, { value: Validator.errorCode.must_be_a_string });
48+
/* jshint camelcase: true */
49+
}
50+
51+
var uri;
52+
53+
try {
54+
uri = new URI(value)
55+
} catch (e) {
56+
throw new Violation(this, value, { constraints: this.constraints });
57+
}
58+
59+
// URIs must have at least a hostname and protocol.
60+
if (!uri.hostname() || !uri.protocol()) {
61+
throw new Violation(this, value, { constraints: this.constraints });
62+
}
63+
64+
// Validate that each constraint matches exactly.
65+
_.forEach(this.constraints, function(constraint, key) {
66+
if (constraint === uri[key]()) {
67+
return;
68+
}
69+
70+
throw new Violation(this, value, { constraints: this.constraints });
71+
}, this);
72+
73+
return true;
74+
};
75+
76+
return this;
77+
};

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
"node": ">= 0.10"
4545
},
4646
"dependencies": {
47+
"URIjs": "^1.15.1",
4748
"bignumber.js": "^2.0.7",
4849
"isoc": "0.0.1",
4950
"lodash": "^3.9.1",

test/asserts/uri-assert_test.js

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
2+
/**
3+
* Module dependencies.
4+
*/
5+
6+
var Assert = require('validator.js').Assert;
7+
var Validator = require('validator.js').Validator;
8+
var Violation = require('validator.js').Violation;
9+
var assert = require('../../lib/asserts/uri-assert');
10+
var fmt = require('util').format;
11+
var should = require('should');
12+
13+
/**
14+
* Test `UriAssert`.
15+
*/
16+
17+
describe('UriAssert', function() {
18+
before(function() {
19+
Assert.prototype.Uri = assert;
20+
});
21+
22+
it('should throw an error if the constraint is invalid', function() {
23+
try {
24+
new Assert().Uri({ foo: 'bar' });
25+
26+
should.fail();
27+
} catch (e) {
28+
e.should.be.instanceOf(Error);
29+
e.message.should.equal('Invalid constraint "foo=bar"');
30+
}
31+
});
32+
33+
it('should throw an error if the input value is not a string', function() {
34+
var choices = [[], {}, 123];
35+
36+
choices.forEach(function(choice) {
37+
try {
38+
new Assert().Uri().validate(choice);
39+
40+
should.fail();
41+
} catch (e) {
42+
e.should.be.instanceOf(Violation);
43+
/* jshint camelcase: false */
44+
e.violation.value.should.equal(Validator.errorCode.must_be_a_string);
45+
/* jshint camelcase: true */
46+
}
47+
});
48+
});
49+
50+
it('should throw an error if the uri does not contain a `hostname`', function() {
51+
try {
52+
new Assert().Uri().validate(fmt('foo-%s-bar', new Array(248).join('-')));
53+
54+
should.fail();
55+
} catch (e) {
56+
e.should.be.instanceOf(Violation);
57+
}
58+
});
59+
60+
it('should throw an error if the uri does not contain a `protocol`', function() {
61+
try {
62+
new Assert().Uri().validate('foobar.com');
63+
64+
should.fail();
65+
} catch (e) {
66+
e.should.be.instanceOf(Violation);
67+
}
68+
});
69+
70+
it('should throw an error if the uri does not match the constraints', function() {
71+
try {
72+
new Assert().Uri({ protocol: 'http' }).validate(fmt('https://%[email protected]', new Array(248).join('-')));
73+
74+
should.fail();
75+
} catch (e) {
76+
e.should.be.instanceOf(Violation);
77+
}
78+
});
79+
80+
it('should expose `constraints` on the violation', function() {
81+
try {
82+
new Assert().Uri({ protocol: 'http' }).validate('https://foobar.com');
83+
84+
should.fail();
85+
} catch(e) {
86+
e.show().violation.constraints.should.eql({ protocol: 'http' });
87+
}
88+
});
89+
90+
it('should expose `assert` equal to `Uri`', function() {
91+
try {
92+
new Assert().Uri().validate('foo');
93+
94+
should.fail();
95+
} catch(e) {
96+
e.show().assert.should.equal('Uri');
97+
}
98+
});
99+
100+
it('should accept valid uris', function() {
101+
[
102+
'http://foobar.com',
103+
'http://føøbåz.com',
104+
'http://foobar.com',
105+
'https://foobar.com',
106+
'ftp://foobar.com',
107+
'biz://foobar.com'
108+
].forEach(function(choice) {
109+
new Assert().Uri().validate(choice);
110+
});
111+
});
112+
});

0 commit comments

Comments
 (0)