From da57301be8945e99e569a856bd9422296e3f84af Mon Sep 17 00:00:00 2001 From: Tony Brix Date: Wed, 13 Mar 2019 08:50:53 -0500 Subject: [PATCH] use htmldiffer in file tests & update to node 4 --- test/index.js | 259 ++++++++++++++++++++------------------------------ 1 file changed, 104 insertions(+), 155 deletions(-) diff --git a/test/index.js b/test/index.js index 7e8f5e3af3..27bdea66e1 100644 --- a/test/index.js +++ b/test/index.js @@ -1,4 +1,6 @@ #!/usr/bin/env node +'use strict'; +// 'use strict' is here so we can use let and const in node 4 /** * marked tests @@ -10,12 +12,12 @@ * Modules */ -var fs = require('fs'), - path = require('path'), - fm = require('front-matter'), - g2r = require('glob-to-regexp'), - marked = require('../'), - markedMin = require('../marked.min.js'); +const fs = require('fs'); +const path = require('path'); +const fm = require('front-matter'); +const g2r = require('glob-to-regexp'); +let marked = require('../'); +const htmlDiffer = require('./helpers/html-differ.js'); /** * Load Tests @@ -23,44 +25,36 @@ var fs = require('fs'), function load(options) { options = options || {}; - var dir = path.join(__dirname, 'compiled_tests'), - files = {}, - list, - file, - name, - content, - glob = g2r(options.glob || '*', { extended: true }), - i, - l; - - list = fs + const dir = path.join(__dirname, 'compiled_tests'); + const glob = g2r(options.glob || '*', { extended: true }); + + const list = fs .readdirSync(dir) - .filter(function(file) { + .filter(file => { return path.extname(file) === '.md'; }) .sort(); - l = list.length; - - for (i = 0; i < l; i++) { - name = path.basename(list[i], '.md'); + const files = list.reduce((obj, item) => { + const name = path.basename(item, '.md'); if (glob.test(name)) { - file = path.join(dir, list[i]); - content = fm(fs.readFileSync(file, 'utf8')); + const file = path.join(dir, item); + const content = fm(fs.readFileSync(file, 'utf8')); - files[name] = { + obj[name] = { options: content.attributes, text: content.body, html: fs.readFileSync(file.replace(/[^.]+$/, 'html'), 'utf8') }; } - } + return obj; + }, {}); if (options.bench || options.time) { if (!options.glob) { // Change certain tests to allow // comparison to older benchmark times. - fs.readdirSync(path.join(__dirname, 'new')).forEach(function(name) { + fs.readdirSync(path.join(__dirname, 'new')).forEach(name => { if (path.extname(name) === '.html') return; if (name === 'main.md') return; delete files[name]; @@ -93,25 +87,21 @@ function runTests(engine, options) { engine = engine || marked; options = options || {}; - var succeeded = 0, - failed = 0, - files = options.files || load(options), - filenames = Object.keys(files), - len = filenames.length, - success, - i, - filename, - file; + + let succeeded = 0; + let failed = 0; + const files = options.files || load(options); + const filenames = Object.keys(files); if (options.marked) { marked.setOptions(options.marked); } - for (i = 0; i < len; i++) { - filename = filenames[i]; - file = files[filename]; + for (let i = 0; i < filenames.length; i++) { + const filename = filenames[i]; + const file = files[filename]; - success = testFile(engine, file, filename, i + 1); + const success = testFile(engine, file, filename, i + 1); if (success) { succeeded++; @@ -123,8 +113,8 @@ function runTests(engine, options) { } } - console.log('%d/%d tests completed successfully.', succeeded, len); - if (failed) console.log('%d/%d tests failed.', failed, len); + console.log('\n%d/%d tests completed successfully.', succeeded, filenames.length); + if (failed) console.log('%d/%d tests failed.', failed, filenames.length); return !failed; } @@ -134,13 +124,7 @@ function runTests(engine, options) { */ function testFile(engine, file, filename, index) { - var opts = Object.keys(file.options), - text, - html, - j, - l, - before, - elapsed; + const opts = Object.keys(file.options); if (marked._original) { marked.defaults = marked._original; @@ -152,91 +136,63 @@ function testFile(engine, file, filename, index) { if (opts.length) { marked._original = marked.defaults; marked.defaults = {}; - Object.keys(marked._original).forEach(function(key) { + Object.keys(marked._original).forEach(key => { marked.defaults[key] = marked._original[key]; }); - opts.forEach(function(key) { + opts.forEach(key => { if (marked.defaults.hasOwnProperty(key)) { marked.defaults[key] = file.options[key]; } }); } - before = process.hrtime(); + const before = process.hrtime(); + + let text, html, elapsed; try { - text = engine(file.text).replace(/\s/g, ''); - html = file.html.replace(/\s/g, ''); + text = engine(file.text); + html = file.html; } catch (e) { elapsed = process.hrtime(before); - console.log(' failed in %dms', prettyElapsedTime(elapsed)); + console.log('\n failed in %dms\n', prettyElapsedTime(elapsed)); throw e; } elapsed = process.hrtime(before); - l = html.length; - - if (l === 0 && text.length > 0) { - text = text.substring(0, Math.min(30, text.length)); - - console.log(' failed in %dms at offset %d. Near: "%s".\n', prettyElapsedTime(elapsed), 0, text); - - console.log('\nActual:\n%s\n', text.trim() || text); - console.log('\nExpected:\n\n'); - - return false; - } - - for (j = 0; j < l; j++) { - if (text[j] !== html[j]) { - text = text.substring( - Math.max(j - 30, 0), - Math.min(j + 30, text.length)); - - html = html.substring( - Math.max(j - 30, 0), - Math.min(j + 30, l)); - - console.log(' failed in %dms at offset %d. Near: "%s".\n', prettyElapsedTime(elapsed), j, text); - - console.log('\nActual:\n%s\n', text.trim() || text); - console.log('\nExpected:\n%s\n', html.trim() || html); - + if (htmlDiffer.isEqual(text, html)) { + if (elapsed[0] > 0) { + console.log('\n failed because it took too long.\n\n passed in %dms\n', prettyElapsedTime(elapsed)); return false; } + console.log(' passed in %dms', prettyElapsedTime(elapsed)); + return true; } - if (elapsed[0] > 0) { - console.log(' failed because it took too long.\n\n passed in %dms', prettyElapsedTime(elapsed)); - return false; - } + const diff = htmlDiffer.firstDiff(text, html); - console.log(' passed in %dms', prettyElapsedTime(elapsed)); - return true; + console.log('\n failed in %dms', prettyElapsedTime(elapsed)); + console.log(' Expected: %s', diff.expected); + console.log(' Actual: %s\n', diff.actual); + return false; } /** * Benchmark a function */ -function bench(name, files, func) { - var start = Date.now(), - times = 1000, - keys = Object.keys(files), - i, - l = keys.length, - filename, - file; - - while (times--) { - for (i = 0; i < l; i++) { - filename = keys[i]; - file = files[filename]; - func(file.text); +function bench(name, files, engine) { + const start = Date.now(); + + for (let i = 0; i < 1000; i++) { + for (const filename in files) { + engine(files[filename].text); } } - console.log('%s completed in %dms.', name, Date.now() - start); + const end = Date.now(); + + console.log('%s completed in %dms.', name, end - start); } /** @@ -245,7 +201,7 @@ function bench(name, files, func) { function runBench(options) { options = options || {}; - var files = load(options); + const files = load(options); // Non-GFM, Non-pedantic marked.setOptions({ @@ -289,13 +245,13 @@ function runBench(options) { } bench('marked (pedantic)', files, marked); - // showdown + // commonmark try { - bench('commonmark', files, (function() { - var commonmark = require('commonmark'), - parser = new commonmark.Parser(), - writer = new commonmark.HtmlRenderer(); - return function(text) { + bench('commonmark', files, (() => { + const commonmark = require('commonmark'); + const parser = new commonmark.Parser(); + const writer = new commonmark.HtmlRenderer(); + return function (text) { return writer.render(parser.parse(text)); }; })()); @@ -305,12 +261,10 @@ function runBench(options) { // markdown-it try { - bench('markdown-it', files, (function() { - var MarkdownIt = require('markdown-it'); - var md = new MarkdownIt(); - return function(text) { - return md.render(text); - }; + bench('markdown-it', files, (() => { + const MarkdownIt = require('markdown-it'); + const md = new MarkdownIt(); + return md.render.bind(md); })()); } catch (e) { console.log('Could not bench markdown-it. (Error: %s)', e.message); @@ -318,11 +272,9 @@ function runBench(options) { // markdown.js try { - bench('markdown.js', files, (function() { - var markdown = require('markdown').markdown; - return function(text) { - return markdown.toHTML(text); - }; + bench('markdown.js', files, (() => { + const markdown = require('markdown').markdown; + return markdown.toHTML.bind(markdown); })()); } catch (e) { console.log('Could not bench markdown.js. (Error: %s)', e.message); @@ -337,7 +289,7 @@ function runBench(options) { function time(options) { options = options || {}; - var files = load(options); + const files = load(options); if (options.marked) { marked.setOptions(options.marked); } @@ -357,7 +309,7 @@ function time(options) { */ function fix() { - ['compiled_tests', 'original', 'new', 'redos'].forEach(function(dir) { + ['compiled_tests', 'original', 'new', 'redos'].forEach(dir => { try { fs.mkdirSync(path.resolve(__dirname, dir)); } catch (e) { @@ -366,13 +318,13 @@ function fix() { }); // rm -rf tests - fs.readdirSync(path.resolve(__dirname, 'compiled_tests')).forEach(function(file) { + fs.readdirSync(path.resolve(__dirname, 'compiled_tests')).forEach(file => { fs.unlinkSync(path.resolve(__dirname, 'compiled_tests', file)); }); // cp -r original tests - fs.readdirSync(path.resolve(__dirname, 'original')).forEach(function(file) { - var text = fs.readFileSync(path.resolve(__dirname, 'original', file), 'utf8'); + fs.readdirSync(path.resolve(__dirname, 'original')).forEach(file => { + let text = fs.readFileSync(path.resolve(__dirname, 'original', file), 'utf8'); if (path.extname(file) === '.md') { if (fm.test(text)) { @@ -387,13 +339,13 @@ function fix() { }); // node fix.js - var dir = path.join(__dirname, 'compiled_tests'); + const dir = path.join(__dirname, 'compiled_tests'); - fs.readdirSync(dir).filter(function(file) { + fs.readdirSync(dir).filter(file => { return path.extname(file) === '.html'; - }).forEach(function(file) { + }).forEach(file => { file = path.join(dir, file); - var html = fs.readFileSync(file, 'utf8'); + let html = fs.readFileSync(file, 'utf8'); // fix unencoded quotes html = html @@ -408,9 +360,9 @@ function fix() { }); // turn
into
- fs.readdirSync(dir).forEach(function(file) { + fs.readdirSync(dir).forEach(file => { file = path.join(dir, file); - var text = fs.readFileSync(file, 'utf8'); + let text = fs.readFileSync(file, 'utf8'); text = text.replace(/(<|<)hr\s*\/(>|>)/g, '$1hr$2'); @@ -419,22 +371,22 @@ function fix() { // markdown does some strange things. // it does not encode naked `>`, marked does. - (function() { - var file = dir + '/amps_and_angles_encoding.html'; - var html = fs.readFileSync(file, 'utf8') + { + const file = dir + '/amps_and_angles_encoding.html'; + const html = fs.readFileSync(file, 'utf8') .replace('6 > 5.', '6 > 5.'); fs.writeFileSync(file, html); - })(); + } // cp new/* tests/ - fs.readdirSync(path.resolve(__dirname, 'new')).forEach(function(file) { + fs.readdirSync(path.resolve(__dirname, 'new')).forEach(file => { fs.writeFileSync(path.resolve(__dirname, 'compiled_tests', file), fs.readFileSync(path.resolve(__dirname, 'new', file))); }); // cp redos/* tests/ - fs.readdirSync(path.resolve(__dirname, 'redos')).forEach(function(file) { + fs.readdirSync(path.resolve(__dirname, 'redos')).forEach(file => { fs.writeFileSync(path.resolve(__dirname, 'compiled_tests', file), fs.readFileSync(path.resolve(__dirname, 'redos', file))); }); @@ -445,14 +397,13 @@ function fix() { */ function parseArg(argv) { - var options = {}, - opt = '', - orphans = [], - arg; - argv = argv.slice(2); + + const options = {}; + const orphans = []; + function getarg() { - var arg = argv.shift(); + let arg = argv.shift(); if (arg.indexOf('--') === 0) { // e.g. --opt @@ -465,7 +416,7 @@ function parseArg(argv) { } else if (arg[0] === '-') { if (arg.length > 2) { // e.g. -abc - argv = arg.substring(1).split('').map(function(ch) { + argv = arg.substring(1).split('').map(ch => { return '-' + ch; }).concat(argv); arg = argv.shift(); @@ -480,7 +431,7 @@ function parseArg(argv) { } while (argv.length) { - arg = getarg(); + let arg = getarg(); switch (arg) { case '-f': case '--fix': @@ -515,7 +466,7 @@ function parseArg(argv) { break; default: if (arg.indexOf('--') === 0) { - opt = camelize(arg.replace(/^--(no-)?/, '')); + const opt = camelize(arg.replace(/^--(no-)?/, '')); if (!marked.defaults.hasOwnProperty(opt)) { continue; } @@ -544,9 +495,7 @@ function parseArg(argv) { */ function camelize(text) { - return text.replace(/(\w)-(\w)/g, function(_, a, b) { - return a + b.toUpperCase(); - }); + return text.replace(/(\w)-(\w)/g, (_, a, b) => a + b.toUpperCase()); } /** @@ -554,7 +503,7 @@ function camelize(text) { */ function main(argv) { - var opt = parseArg(argv); + const opt = parseArg(argv); if (opt.fix !== false) { fix(); @@ -574,7 +523,7 @@ function main(argv) { } if (opt.minified) { - marked = markedMin; + marked = require('../marked.min.js'); } return runTests(opt); } @@ -599,7 +548,7 @@ if (!module.parent) { // returns time to millisecond granularity function prettyElapsedTime(hrtimeElapsed) { - var seconds = hrtimeElapsed[0]; - var frac = Math.round(hrtimeElapsed[1] / 1e3) / 1e3; + const seconds = hrtimeElapsed[0]; + const frac = Math.round(hrtimeElapsed[1] / 1e3) / 1e3; return seconds * 1e3 + frac; }