1'use strict'; 2 3const { Writable } = require('stream'); 4const assert = require('assert'); 5 6const treeAdapters = { 7 default: require('../../packages/parse5/lib/tree-adapters/default'), 8 htmlparser2: require('../../packages/parse5-htmlparser2-tree-adapter/lib') 9}; 10 11function addSlashes(str) { 12 return str 13 .replace(/\t/g, '\\t') 14 .replace(/\n/g, '\\n') 15 .replace(/\f/g, '\\f') 16 .replace(/\r/g, '\\r') 17 .replace(/\0/g, '\\u0000'); 18} 19 20function createDiffMarker(markerPosition) { 21 let marker = ''; 22 23 for (let i = 0; i < markerPosition - 1; i++) { 24 marker += ' '; 25 } 26 27 return marker + '^\n'; 28} 29 30function getRandomChunkSize(min, max) { 31 const MIN = 1; 32 const MAX = 10; 33 34 min = min || MIN; 35 max = max || MAX; 36 37 return min + Math.floor(Math.random() * (max - min + 1)); 38} 39 40function makeChunks(str, minSize, maxSize) { 41 if (!str.length) { 42 return ['']; 43 } 44 45 const chunks = []; 46 let start = 0; 47 48 // NOTE: add 1 as well, so we avoid situation when we have just one huge chunk 49 let end = Math.min(getRandomChunkSize(minSize, maxSize), str.length, 1); 50 51 while (start < str.length) { 52 chunks.push(str.substring(start, end)); 53 start = end; 54 end = Math.min(end + getRandomChunkSize(minSize, maxSize), str.length); 55 } 56 57 return chunks; 58} 59 60class WritableStreamStub extends Writable { 61 constructor() { 62 super({ decodeStrings: false }); 63 64 this.writtenData = ''; 65 } 66 67 _write(chunk, encoding, callback) { 68 assert.strictEqual(typeof chunk, 'string', 'Expected output to be a string stream'); 69 this.writtenData += chunk; 70 callback(); 71 } 72} 73 74module.exports = { 75 WritableStreamStub, 76 treeAdapters, 77 addSlashes, 78 makeChunks, 79 80 normalizeNewLine(str) { 81 return str.replace(/\r\n/g, '\n'); 82 }, 83 84 removeNewLines(str) { 85 return str.replace(/\r/g, '').replace(/\n/g, ''); 86 }, 87 88 writeChunkedToStream(str, stream) { 89 const chunks = makeChunks(str); 90 const lastChunkIdx = chunks.length - 1; 91 92 chunks.forEach((chunk, idx) => { 93 if (idx === lastChunkIdx) { 94 stream.end(chunk); 95 } else { 96 stream.write(chunk); 97 } 98 }); 99 }, 100 101 generateTestsForEachTreeAdapter(moduleExports, ctor) { 102 Object.keys(treeAdapters).forEach(adapterName => { 103 const tests = {}; 104 const adapter = treeAdapters[adapterName]; 105 106 ctor(tests, adapter); 107 108 Object.keys(tests).forEach(testName => { 109 moduleExports['Tree adapter: ' + adapterName + ' - ' + testName] = tests[testName]; 110 }); 111 }); 112 }, 113 114 getStringDiffMsg(actual, expected) { 115 for (let i = 0; i < expected.length; i++) { 116 if (actual[i] !== expected[i]) { 117 let diffMsg = '\nString differ at index ' + i + '\n'; 118 119 const expectedStr = 'Expected: ' + addSlashes(expected.substring(i - 100, i + 1)); 120 const expectedDiffMarker = createDiffMarker(expectedStr.length); 121 122 diffMsg += expectedStr + addSlashes(expected.substring(i + 1, i + 20)) + '\n' + expectedDiffMarker; 123 124 const actualStr = 'Actual: ' + addSlashes(actual.substring(i - 100, i + 1)); 125 const actualDiffMarker = createDiffMarker(actualStr.length); 126 127 diffMsg += actualStr + addSlashes(actual.substring(i + 1, i + 20)) + '\n' + actualDiffMarker; 128 129 return diffMsg; 130 } 131 } 132 133 return ''; 134 }, 135 136 getSubstringByLineCol(lines, loc) { 137 lines = lines.slice(loc.startLine - 1, loc.endLine); 138 139 const last = lines.length - 1; 140 141 lines[last] = lines[last].substring(0, loc.endCol - 1); 142 lines[0] = lines[0].substring(loc.startCol - 1); 143 144 return lines.join('\n'); 145 } 146}; 147