UNPKG

10.5 kBJavaScriptView Raw
1'use strict';
2
3var assert = require('assert');
4var crypto = require('crypto');
5var hash = require('../index');
6var validSha1 = /^[0-9a-f]{40}$/i;
7
8describe('hash', function() {
9 it('throws when nothing to hash', function () {
10 assert.throws(hash, 'no arguments');
11 assert.throws(function() {
12 hash(undefined, {algorithm: 'md5'});
13 }, 'undefined');
14 });
15
16 it('throws when passed an invalid options', function() {
17 assert.throws(function() {
18 hash({foo: 'bar'}, {algorithm: 'shalala'});
19 }, 'bad algorithm');
20 assert.throws(function() {
21 hash({foo: 'bar'}, {encoding: 'base16'});
22 }, 'bad encoding');
23 });
24
25 it('copies options rather than mutating', function() {
26 var options = {
27 algorithm: 'MD5',
28 encoding: 'HEX'
29 }
30
31 hash({foo: 'bar'}, options)
32
33 assert.deepEqual(options, {
34 algorithm: 'MD5',
35 encoding: 'HEX'
36 }, 'source options have neither been modified nor added to')
37 });
38
39 it('hashes a simple object', function() {
40 assert.ok(validSha1.test(hash({foo: 'bar', bar: 'baz'})), 'hash object');
41 });
42
43 if (typeof Buffer !== 'undefined') {
44 it('can return buffers', function() {
45 assert.ok(Buffer.isBuffer(hash({foo: 'bar', bar: 'baz'}, {encoding: 'buffer'})), 'hash object');
46 });
47 }
48
49 it('hashes identical objects with different key ordering', function() {
50 var hash1 = hash({foo: 'bar', bar: 'baz'});
51 var hash2 = hash({bar: 'baz', foo: 'bar'});
52 var hash3 = hash({bar: 'foo', foo: 'baz'});
53 assert.equal(hash1, hash2, 'hashes are equal');
54 assert.notEqual(hash1, hash3, 'different objects not equal');
55 });
56
57 it('respects object key ordering when unorderedObjects = false', function() {
58 var hash1 = hash({foo: 'bar', bar: 'baz'}, { unorderedObjects: false });
59 var hash2 = hash({bar: 'baz', foo: 'bar'}, { unorderedObjects: false });
60 assert.notEqual(hash1, hash2, 'hashes are not equal');
61 });
62
63 it('hashes only object keys when excludeValues option is set', function() {
64 var hash1 = hash({foo: false, bar: 'OK'}, { excludeValues: true });
65 var hash2 = hash({foo: true, bar: 'NO'}, { excludeValues: true });
66 var hash3 = hash({foo: true, bar: 'OK', baz: false}, { excludeValues: true });
67 assert.equal(hash1, hash2, 'values not in hash digest');
68 assert.notEqual(hash1, hash3, 'different keys not equal');
69 });
70
71 it('array values are hashed', function() {
72 var hash1 = hash({foo: ['bar', 'baz'], bax: true });
73 var hash2 = hash({foo: ['baz', 'bar'], bax: true });
74 assert.notEqual(hash1, hash2, 'different array orders are unique');
75 });
76
77 it('nested object values are hashed', function() {
78 var hash1 = hash({foo: {bar: true, bax: 1}});
79 var hash2 = hash({foo: {bar: true, bax: 1}});
80 var hash3 = hash({foo: {bar: false, bax: 1}});
81 assert.equal(hash1, hash2, 'hashes are equal');
82 assert.notEqual(hash1, hash3, 'different objects not equal');
83 });
84
85 it('sugar methods should be equivalent', function() {
86 var obj = {foo: 'bar', baz: true};
87 assert.equal(hash.keys(obj), hash(obj, {excludeValues: true}), 'keys');
88 assert.equal(hash.sha1(obj), hash(obj, {algorithm: 'sha1'}), 'sha1');
89 assert.equal(hash.MD5(obj), hash(obj, {algorithm: 'md5'}), 'md5');
90 assert.equal(hash.keysMD5(obj),
91 hash(obj, {algorithm: 'md5', excludeValues: true}), 'keys md5');
92 });
93
94 it('array of nested object values are hashed', function() {
95 var hash1 = hash({foo: [ {bar: true, bax: 1}, {bar: false, bax: 2} ] });
96 var hash2 = hash({foo: [ {bar: true, bax: 1}, {bar: false, bax: 2} ] });
97 var hash3 = hash({foo: [ {bar: false, bax: 2} ] });
98 assert.equal(hash1, hash2, 'hashes are equal');
99 assert.notEqual(hash1, hash3, 'different objects not equal');
100 });
101
102 it("recursive objects don't blow up stack", function() {
103 var hash1 = {foo: 'bar'};
104 hash1.recursive = hash1;
105 assert.doesNotThrow(function() {hash(hash1);}, /Maximum call stack size exceeded/, 'Should not throw an stack size exceeded exception');
106 });
107
108 it("recursive arrays don't blow up stack", function() {
109 var hash1 = ['foo', 'bar'];
110 hash1.push(hash1);
111 assert.doesNotThrow(function() {hash(hash1);}, /Maximum call stack size exceeded/, 'Should not throw an stack size exceeded exception');
112 });
113
114 it("recursive arrays don't blow up stack with unorderedArrays", function() {
115 var hash1 = ['foo', 'bar'];
116 hash1.push(hash1);
117 assert.doesNotThrow(function() {hash(hash1, {unorderedArrays: true});}, /Maximum call stack size exceeded/, 'Should not throw an stack size exceeded exception');
118 });
119
120 it("recursive handling tracks identity", function() {
121 var hash1 = {k1: {k: 'v'}, k2: {k: 'k2'}};
122 hash1.k1.r1 = hash1.k1;
123 hash1.k2.r2 = hash1.k2;
124 var hash2 = {k1: {k: 'v'}, k2: {k: 'k2'}};
125 hash2.k1.r1 = hash2.k2;
126 hash2.k2.r2 = hash2.k1;
127 assert.notEqual(hash(hash1), hash(hash2), "order of recursive objects should matter");
128 });
129
130 it("object types are hashed", function() {
131 var hash1 = hash({foo: 'bar'});
132 var hash2 = hash(['foo', 'bar']);
133 assert.notEqual(hash1, hash2, "arrays and objects should not produce identical hashes");
134 });
135
136 it("utf8 strings are hashed correctly", function() {
137 var hash1 = hash('\u03c3'); // cf 83 in utf8
138 var hash2 = hash('\u01c3'); // c7 83 in utf8
139 assert.notEqual(hash1, hash2, "different strings with similar utf8 encodings should produce different hashes");
140 });
141
142 it("strings passed as new String are hashed correctly", function() {
143 var hash1 = hash(new String('foo'));
144 assert.equal(hash1, '7cd3edacc4c9dd43908177508c112608a398bb9a');
145 var hash2 = hash({foo: new String('bar')});
146 assert.equal(hash2, 'a75c05bdca7d704bdfcd761913e5a4e4636e956b');
147 });
148
149 it("various hashes in crypto.getHashes() should be supported", function() {
150 var hashes = ['sha1', 'md5'];
151
152 if (crypto.getHashes) {
153 // take all hashes from crypto.getHashes() starting with MD or SHA
154 hashes = crypto.getHashes().filter(RegExp.prototype.test.bind(/^(md|sha)/i));
155 }
156
157 var obj = {randomText: 'bananas'};
158
159 for (var i = 0; i < hashes.length; i++) {
160 assert.ok(hash(obj, {algorithm: hashes[i]}), 'Algorithm ' + hashes[i] + ' should be supported');
161 }
162 });
163
164 it("null and 'Null' string produce different hashes", function() {
165 var hash1 = hash({foo: null});
166 var hash2 = hash({foo: 'Null'});
167 assert.notEqual(hash1, hash2, "null and 'Null' should not produce identical hashes");
168 });
169
170 it('Distinguish functions based on their properties', function() {
171
172 var a, b, c, d;
173 function Foo() {}
174 a = hash(Foo);
175
176 Foo.foo = 22;
177 b = hash(Foo);
178
179 Foo.bar = "42";
180 c = hash(Foo);
181
182 Foo.foo = "22";
183 d = hash(Foo);
184
185 assert.notEqual(a,b, 'adding a property changes the hash');
186 assert.notEqual(b,c, 'adding another property changes the hash');
187 assert.notEqual(c,d, 'changing a property changes the hash');
188 });
189
190 it('respectFunctionProperties = false', function() {
191
192 var a, b;
193 function Foo() {}
194 a = hash(Foo, {respectFunctionProperties: false});
195
196 Foo.foo = 22;
197 b = hash(Foo, {respectFunctionProperties: false});
198
199 assert.equal(a,b, 'function properties are ignored');
200 });
201
202 it('Distinguish functions based on prototype properties', function() {
203
204 var a, b, c, d;
205 function Foo() {}
206 a = hash(Foo);
207
208 Foo.prototype.foo = 22;
209 b = hash(Foo);
210
211 Foo.prototype.bar = "42";
212 c = hash(Foo);
213
214 Foo.prototype.foo = "22";
215 d = hash(Foo);
216
217 assert.notEqual(a,b, 'adding a property to the prototype changes the hash');
218 assert.notEqual(b,c, 'adding another property to the prototype changes the hash');
219 assert.notEqual(c,d, 'changing a property in the prototype changes the hash');
220 });
221
222 it('distinguishes async functions based on their properties', function() {
223 var a, b;
224
225 var Foo;
226
227 try {
228 Foo = eval('async function Foo() {}; Foo');
229 } catch (err) {
230 if (err.name === 'SyntaxError')
231 return this.skip('Not available on Node 6');
232 else
233 throw err;
234 }
235
236 a = hash(Foo);
237
238 Foo.foo = 22;
239 b = hash(Foo);
240
241 assert.notEqual(a,b, 'adding a property changes the hash');
242 });
243
244 it('Distinguish objects based on their type', function() {
245
246 function Foo() {}
247 function Bar() {}
248
249 var f = new Foo(), b = new Bar();
250
251 assert.notEqual(hash(Foo), hash(Bar), 'Functions with different names should produce a different Hash.');
252 assert.notEqual(hash(f), hash(b), 'Objects with different constructor should have a different Hash.');
253 });
254
255 it('respectType = false', function() {
256 var opt = { respectType: false };
257
258
259 function Foo() {}
260 function Bar() {}
261
262 var f = new Foo(), b = new Bar();
263 assert.equal(hash(f, opt), hash(b, opt), 'Hashing should disregard the different constructor');
264
265
266 var ha, hb;
267 function F() {}
268 ha = hash(F, opt);
269
270 F.prototype.meaningOfLife = 42;
271 hb = hash(F, opt);
272
273 assert.equal(ha, hb, 'Hashing should disregard changes in the function\'s prototype');
274 });
275
276 it('unorderedArrays = false', function() {
277 var ha, hb;
278 ha = hash([1, 2, 3]);
279 hb = hash([3, 2, 1]);
280
281 assert.notEqual(ha, hb, 'Hashing should respect the order of array entries');
282 });
283
284 it('unorderedArrays = true', function() {
285 var opt = { unorderedArrays: true };
286
287 var ha, hb;
288 ha = hash([1, 2, 3], opt);
289 hb = hash([3, 2, 1], opt);
290
291 assert.equal(ha, hb, 'Hashing should not respect the order of array entries');
292
293 ha = hash([{a: 1}, {a: 2}], opt);
294 hb = hash([{a: 2}, {a: 1}], opt);
295
296 assert.equal(ha, hb, 'Hashing should not respect the order of array entries');
297 });
298
299 it('excludeKeys works', function() {
300 var ha, hb;
301 ha = hash({a: 1, b: 4}, { excludeKeys: function(key) { return key === 'b' } });
302 hb = hash({a: 1});
303
304 assert.equal(ha, hb, 'Hashing should ignore key `b`');
305 });
306
307 if (typeof Set !== 'undefined') {
308 it('unorderedSets = false', function() {
309 var opt = { unorderedSets: false };
310
311 var ha, hb;
312 ha = hash(new Set([1, 2, 3]), opt);
313 hb = hash(new Set([3, 2, 1]), opt);
314
315 assert.notEqual(ha, hb, 'Hashing should respect the order of Set entries');
316 });
317
318 it('unorderedSets = true', function() {
319 var ha, hb;
320 ha = hash(new Set([1, 2, 3]));
321 hb = hash(new Set([3, 2, 1]));
322
323 assert.equal(ha, hb, 'Hashing should not respect the order of Set entries');
324 });
325 }
326});