minor documentation updates
[squeep-api-dingus] / test / lib / common.js
1 /* eslint-disable capitalized-comments */
2 /* eslint-env mocha */
3 'use strict';
4
5 const assert = require('assert');
6 const sinon = require('sinon'); // eslint-disable-line node/no-unpublished-require
7 const common = require('../../lib/common');
8
9
10 describe('common', function () {
11
12 describe('fileScope', function () {
13 it('names a file path', function () {
14 const filename = 'lib/foo/bar.js';
15 const result = common.fileScope(filename)('baz');
16 assert.strictEqual(result, 'bar:baz');
17 });
18 it('names an index path', function () {
19 const filename = 'lib/foo/index.js';
20 const result = common.fileScope(filename)('baz');
21 assert.strictEqual(result, 'foo:baz');
22 });
23 }); // fileScope
24
25 describe('generateETag', function () {
26 it('generates a tag from data', function () {
27 const expected = '"RHUvNyculE/SyROjU0LqzN0arxibrlBnazAashP8UGE"';
28 const data = 'example data';
29 const result = common.generateETag(undefined, undefined, data);
30 assert.strictEqual(result, expected);
31 });
32 it('generates a tag from data and stats', function () {
33 const expected = '"mtI0qCyqXsZVfX0Pgi+G6mQM10y9yVyi1NZejXSYttk"';
34 const stat = {
35 mtimeMs: 1600113038270.2375,
36 };
37 const data = 'example data';
38 const result = common.generateETag(undefined, stat, data);
39 assert.strictEqual(result, expected);
40 });
41 }); // generateETag
42
43 describe('get', function () {
44 const def = 'default';
45 it('covers missing obj', function () {
46 const result = common.get(undefined, undefined, def);
47 assert.strictEqual(result, def);
48 });
49 it('covers missing prop', function () {
50 const result = common.get({}, undefined, def);
51 assert.strictEqual(result, def);
52 });
53 it('covers default', function () {
54 const result = common.get({ k: 'v' }, 'x', def);
55 assert.strictEqual(result, def);
56 });
57 it('covers prop', function () {
58 const result = common.get({ k: 'v' }, 'k', def);
59 assert.strictEqual(result, 'v');
60 });
61 }); // get
62
63 describe('isClientCached', function () {
64 let req, modifiedTimeMs, eTag;
65 const blueMoon = 'Sat, 31 Oct 2020 07:51:00 GMT';
66 const blueMoonMs = 1604130660000;
67 const oneDayMs = 86400000;
68 const anotherETag = '"RHUvNyculE/SyROjU0LqzN0arxibrlBnazAashP8UGE"';
69 beforeEach(function () {
70 req = {
71 getHeader: sinon.stub(),
72 };
73 modifiedTimeMs = 0;
74 eTag = '"mtI0qCyqXsZVfX0Pgi+G6mQM10y9yVyi1NZejXSYttk"';
75 });
76 it('no headers, not cached', function () {
77 const result = common.isClientCached(req, modifiedTimeMs, eTag);
78 assert.strictEqual(result, false);
79 });
80 it('modified header, not cached', function () {
81 req.getHeader.onCall(0).returns(blueMoon);
82 modifiedTimeMs = blueMoonMs + oneDayMs;
83 const result = common.isClientCached(req, modifiedTimeMs, eTag);
84 assert.strictEqual(result, false);
85 });
86 it('modified header, cached', function () {
87 req.getHeader.onCall(0).returns(blueMoon);
88 modifiedTimeMs = blueMoonMs - oneDayMs;
89 const result = common.isClientCached(req, modifiedTimeMs, eTag);
90 assert.strictEqual(result, true);
91 });
92 it('match header, not matched', function () {
93 req.getHeader.onCall(1).returns(anotherETag);
94 const result = common.isClientCached(req, modifiedTimeMs, eTag);
95 assert.strictEqual(result, false);
96 });
97 it('match header, matched', function () {
98 req.getHeader.onCall(1).returns(`${anotherETag}, ${eTag}, ${anotherETag}`);
99 const result = common.isClientCached(req, modifiedTimeMs, eTag);
100 assert.strictEqual(result, true);
101 });
102 it('match header any, matched', function () {
103 req.getHeader.onCall(1).returns('*');
104 const result = common.isClientCached(req, modifiedTimeMs, eTag);
105 assert.strictEqual(result, true);
106 });
107 it('modified header cached, match header not matched, not cached', function () {
108 req.getHeader.onCall(0).returns(blueMoon);
109 modifiedTimeMs = blueMoonMs - oneDayMs;
110 req.getHeader.onCall(1).returns(`${anotherETag}, ${anotherETag}`);
111 const result = common.isClientCached(req, modifiedTimeMs, eTag);
112 assert.strictEqual(result, false);
113 });
114 }); // iscClientCached
115
116 describe('pick', function () {
117 it('picks', function () {
118 const srcObj = {
119 a: 1,
120 b: 2,
121 c: 3,
122 };
123 const result = common.pick(srcObj, ['a', 'c', 'd']);
124 assert.deepStrictEqual(result, {
125 'a': 1,
126 'c': 3,
127 });
128 });
129 }); // pick
130
131 describe('requestLogData', function () {
132 it('gives data', function () {
133 const req = {
134 method: 'GET',
135 somethingElse: 'blah',
136 };
137 const result = common.requestLogData(req);
138 assert.deepStrictEqual(result, {
139 method: 'GET',
140 });
141 });
142 }); // requestLogData
143
144 describe('obscureAuthorizationHeader', function () {
145 it('obscures basic data', function () {
146 const authHeader = 'Basic Zm9vOmJhcg==';
147 const expected = 'Basic ************';
148 const result = common.obscureAuthorizationHeader(authHeader);
149 assert.strictEqual(result, expected);
150 });
151 it('obscures all of other types', function () {
152 const authHeader = 'someWeirdAuth';
153 const expected = '*************';
154 const result = common.obscureAuthorizationHeader(authHeader);
155 assert.strictEqual(result, expected);
156 });
157 it('does nothing when empty', function () {
158 const authHeader = undefined;
159 const expected = undefined;
160 const result = common.obscureAuthorizationHeader(authHeader);
161 assert.strictEqual(result, expected);
162 });
163 }); // obscureAuthorizationHeader
164
165 describe('scrubHeaderObject', function () {
166 it('', function () {
167 const data = {
168 headers: {
169 'foo': 'bar',
170 'authorization': 'Basic Zm9vOmJhcg==',
171 },
172 };
173 const expected = {
174 headers: {
175 'foo': 'bar',
176 'authorization': 'Basic ************',
177 },
178 };
179 common.scrubHeaderObject(data);
180 assert.deepStrictEqual(data, expected);
181 });
182 }); // scrubHeaderObject
183
184 describe('responseLogData', function () {
185 it('gives data', function () {
186 const res = {
187 getHeaders: () => ({}),
188 statusCode: 200,
189 blah: 'blah',
190 };
191 const result = common.responseLogData(res);
192 assert.deepStrictEqual(result, {
193 headers: {},
194 statusCode: 200,
195 });
196 });
197 }); // responseLogData
198
199 describe('handlerLogData', function () {
200 it('covers', function () {
201 const req = {
202 method: 'GET',
203 somethingElse: 'blah',
204 };
205 const res = {
206 getHeaders: () => ({}),
207 statusCode: 200,
208 blah: 'blah',
209 };
210 const ctx = {};
211 const result = common.handlerLogData(req, res, ctx);
212 assert.deepStrictEqual(result, {
213 req: {
214 method: 'GET',
215 },
216 res: {
217 headers: {},
218 statusCode: 200,
219 },
220 ctx: {},
221 });
222 });
223 }); // handlerLogData
224
225 describe('setOptions', function () {
226 it('sets options', function () {
227 const expected = {
228 keyOne: 'default',
229 keyTwo: 'option',
230 keyThree: 'default',
231 };
232 const target = {};
233 const defaultOptions = {
234 keyOne: 'default',
235 keyTwo: 'default',
236 keyThree: 'default',
237 };
238 const options = {
239 keyTwo: 'option',
240 keyFour: 'option',
241 };
242 common.setOptions(target, defaultOptions, options);
243 assert.deepStrictEqual(target, expected);
244 });
245 }); // setOptions
246
247 describe('splitFirst', function () {
248 it('splits', function () {
249 const expected = ['foo', 'awoo'];
250 const src = 'foo?awoo';
251 const delim = '?';
252 const fill = 'fill';
253 const result = common.splitFirst(src, delim, fill);
254 assert.deepStrictEqual(result, expected);
255 });
256 it('fills', function () {
257 const expected = ['foo', 'fill'];
258 const src = 'foo';
259 const delim = '?';
260 const fill = 'fill';
261 const result = common.splitFirst(src, delim, fill);
262 assert.deepStrictEqual(result, expected);
263 });
264 }); // splitFirst
265
266 describe('mergeEnum', function () {
267 it('merges enums', function () {
268 const origEnum = {
269 ContentType: {
270 TextHTML: 'text/html',
271 },
272 ErrorResponse: {
273 BadRequest: {
274 statusCode: 400,
275 errorMessage: 'Bad Request',
276 },
277 },
278 };
279 const newEnum = {
280 ContentType: {
281 TextPlain: 'text/plain',
282 },
283 ErrorResponse: {
284 BadResponse: {
285 statusCode: 401,
286 errorMessage: 'Unauthorized',
287 },
288 },
289 Header: {
290 Accept: 'accept',
291 },
292 Value: 'value',
293 };
294 const mergedEnum = {
295 ContentType: {
296 TextHTML: 'text/html',
297 TextPlain: 'text/plain',
298 },
299 ErrorResponse: {
300 BadRequest: {
301 statusCode: 400,
302 errorMessage: 'Bad Request',
303 },
304 BadResponse: {
305 statusCode: 401,
306 errorMessage: 'Unauthorized',
307 },
308 },
309 Header: {
310 Accept: 'accept',
311 },
312 Value: 'value',
313 };
314 const result = common.mergeEnum(origEnum, newEnum);
315 assert.deepStrictEqual(result, mergedEnum);
316 });
317 }); // mergeEnum
318
319 describe('requestId', function () {
320 it('returns a string', function () {
321 const id = common.requestId();
322 assert.strictEqual(typeof id, 'string');
323 assert(id.length > 0);
324 });
325 }); // requestId
326
327 describe('ensureLoggerLevels', function () {
328 it('adds missing levels', function () {
329 const result = common.ensureLoggerLevels();
330 assert.deepStrictEqual(result, common.nullLogger);
331 });
332 }); // ensureLoggerLevels
333
334 describe('httpStatusCodeClass', function () {
335 it('works', function () {
336 for (const [statusCode, statusClassExpected] of Object.entries({
337 200: 2,
338 304: 3,
339 404: 4,
340 500: 5,
341 })) {
342 const statusClass = common.httpStatusCodeClass(statusCode);
343 assert.strictEqual(statusClass, statusClassExpected);
344 }
345 });
346 }); // ensureLoggerLevels
347
348 describe('mergeDeep', function () {
349 it('simple merge', function () {
350 const o1 = {
351 foo1: 'one',
352 };
353 const o2 = {
354 foo2: 'two',
355 };
356 const o3 = {
357 foo3: 'three',
358 };
359 const expected = {
360 foo1: 'one',
361 foo2: 'two',
362 foo3: 'three',
363 };
364 const result = common.mergeDeep(o1, o2, o3);
365 assert.deepStrictEqual(result, expected);
366 });
367 it('deep merge', function () {
368 const o1 = {
369 foo: {
370 quux: 1,
371 },
372 bar: 'baz',
373 };
374 const o2 = {
375 foo: {
376 myList: ['fancy'],
377 gleep: {
378 fraz: 2,
379 },
380 },
381 blah: 'frop',
382 };
383 const o3 = {
384 foo: {
385 myList: ['pants'],
386 gleep: {
387 troz: 'poit',
388 },
389 narf: 3,
390 },
391 bar: 'yup',
392 };
393 const expected = {
394 foo: {
395 myList: ['fancy', 'pants'],
396 gleep: {
397 fraz: 2,
398 troz: 'poit',
399 },
400 narf: 3,
401 quux: 1,
402 },
403 bar: 'yup',
404 blah: 'frop',
405 };
406 const result = common.mergeDeep(o1, o2, o3);
407 assert.deepStrictEqual(result, expected);
408 });
409 it('merged object is distinct', function () {
410 const o1 = {
411 foo: {
412 bar: 3,
413 },
414 };
415 const o2 = {
416 baz: {
417 quux: 4,
418 },
419 };
420 const expected = {
421 foo: {
422 bar: 3,
423 },
424 baz: {
425 quux: 4,
426 },
427 };
428 const result = common.mergeDeep(o1, o2);
429 assert.deepStrictEqual(result, expected);
430 const expected2 = {
431 foo: {
432 bar: 5,
433 },
434 baz: {
435 quux: 5,
436 },
437 };
438 result.foo.bar = 5;
439 result.baz.quux = 5;
440 assert.deepStrictEqual(result, expected2);
441 assert.strictEqual(o1.foo.bar, 3);
442 assert.strictEqual(o2.baz.quux, 4);
443 });
444 }); // mergeDeep
445
446 describe('unfoldHeaderLines', function () {
447 it('folds', function () {
448 const lines = [
449 'Normal-Header: some header data',
450 'Folded-Header: more data',
451 ' second line of data',
452 ' third line of data',
453 ];
454 const expected = [
455 'Normal-Header: some header data',
456 'Folded-Header: more data second line of data third line of data',
457 ];
458 const result = common.unfoldHeaderLines(lines);
459 assert.deepStrictEqual(result, expected);
460 });
461 it('covers no input', function () {
462 const lines = undefined;
463 const result = common.unfoldHeaderLines();
464 assert.deepStrictEqual(result, lines);
465 });
466 }); // unfoldHeaderLines
467
468 });