node tests: Add nice diffs to js markdown tests.

Fix #3915
This commit is contained in:
Andy Perez 2017-12-04 03:49:22 -05:00 committed by showell
parent 695affd44e
commit fc2298ec54
5 changed files with 175 additions and 13 deletions

View File

@ -23,6 +23,8 @@
const jsdom = require('jsdom');
const _ = require('underscore');
const mdiff = require('./mdiff.js');
// Module-level global instance of MarkdownComparer, initialized when needed
let _markdownComparerInstance = null;
@ -155,25 +157,28 @@ class MarkdownComparer {
}
}
function returnComparer() {
if (!_markdownComparerInstance) {
_markdownComparerInstance = new MarkdownComparer((actual, expected) => {
return [
"Actual and expected output do not match. Showing diff",
mdiff.diff_strings(actual, expected),
].join('\n');
});
}
return _markdownComparerInstance;
}
module.exports = {
equal(expected, actual, message) {
if (!_markdownComparerInstance) {
_markdownComparerInstance = new MarkdownComparer();
}
_markdownComparerInstance.assertEqual(actual, expected, message);
returnComparer().assertEqual(actual, expected, message);
},
notEqual(expected, actual, message) {
if (!_markdownComparerInstance) {
_markdownComparerInstance = new MarkdownComparer();
}
_markdownComparerInstance.assertNotEqual(actual, expected, message);
returnComparer().assertNotEqual(actual, expected, message);
},
setFormatter(output_formatter) {
if (!_markdownComparerInstance) {
_markdownComparerInstance = new MarkdownComparer();
}
_markdownComparerInstance.setFormatter(output_formatter);
returnComparer().setFormatter(output_formatter);
},
};

View File

@ -0,0 +1,146 @@
/**
* mdiff.js
*
* Used to produce colorful and informative diffs for comparison of generated
* Markdown. Unlike the built-in diffs used in python or node.js assert libraries,
* is actually designed to be effective for long, single-line comparisons.
*
* Based on diffing library difflib, a js port of the python library.
*
* The sole exported function diff_strings(string_0, string_1) returns a pretty-printed
* unicode string containing their diff.
*/
const _ = require('underscore');
const difflib = require('difflib');
function apply_color(input_string, changes) {
let previous_index = 0;
let processed_string = input_string.slice(0,2);
input_string = input_string.slice(2);
const formatter = {
delete : (string) => { return "\u001b[31m" + string + "\u001b[0m"; },
insert : (string) => { return "\u001b[32m" + string + "\u001b[0m"; },
replace : (string) => { return "\u001b[33m" + string + "\u001b[0m"; },
};
changes.forEach((change) => {
if (formatter.hasOwnProperty(change.tag)) {
processed_string += input_string.slice(previous_index, change.beginning_index);
processed_string += formatter[change.tag](
input_string.slice(change.beginning_index, change.ending_index)
);
previous_index = change.ending_index;
}
});
processed_string += input_string.slice(previous_index);
return processed_string;
}
/**
* The library difflib produces diffs that look as follows:
*
* - <p>upgrade! yes</p>
* ? ^^ -
* + <p>downgrade yes.</p>
* ? ^^^^ +
*
* The purpose of this function is to facilitate converting these diffs into
* colored versions, where the question-mark lines are removed, replaced with
* directions to add appropriate color to the lines that they annotate.
*/
function parse_questionmark_line(questionmark_line) {
let current_sequence = ""; // Either "^", "-", "+", or ""
let beginning_index = 0;
let index = 0;
const changes_list = [];
const aliases = {
"^" : "replace",
"+" : "insert",
"-" : "delete",
};
const add_change = () => {
if (current_sequence) {
changes_list.push({
tag : aliases[current_sequence],
beginning_index,
ending_index : index,
});
current_sequence = "";
}
};
questionmark_line = questionmark_line.slice(2).trimRight("\n");
for (const character of questionmark_line) {
if (aliases.hasOwnProperty(character)) {
if (current_sequence !== character) {
add_change();
current_sequence = character;
beginning_index = index;
}
} else {
add_change();
}
index += 1;
}
// In case we have a "change" involving the last character on a line
// e.g. a string such as "? ^^ -- ++++"
add_change();
return changes_list;
}
function diff_strings(string_0, string_1) {
let output_lines = [];
let ndiff_output = "";
let changes_list = [];
ndiff_output = difflib.ndiff(string_0.split("\n"), string_1.split("\n"));
ndiff_output.forEach((line) => {
if (line.startsWith("+")) {
output_lines.push(line);
} else if (line.startsWith("-")) {
output_lines.push(line);
} else if (line.startsWith("?")) {
changes_list = parse_questionmark_line(line);
output_lines[output_lines.length - 1] = apply_color(
output_lines[output_lines.length -1], changes_list);
} else {
output_lines.push(line);
}
});
const emphasize_codes = (string) => {
return "\u001b[34m" + string.slice(0,1) + "\u001b[0m" + string.slice(1);
};
output_lines = _.map(output_lines, emphasize_codes);
return output_lines.join("\n");
}
module.exports = { diff_strings };
// Simple CLI for this module
// Only run this code if called as a command-line utility
if (require.main === module) {
// First two args are just "node" and "mdiff.js"
const argv = require('minimist')(process.argv.slice(2));
if (_.has(argv, "help")) {
console.log(process.argv[0] + " " + process.argv[1] +
" [ --help ]" +
" string_0" +
" string_1" +
"\n" +
"Where string_0 and string_1 are the strings to be diffed"
);
}
const output = diff_strings(argv._[0], argv._[1]);
console.log(output);
}

View File

@ -9,6 +9,7 @@
"@types/webpack": "3.0.13",
"blueimp-md5": "2.10.0",
"clipboard": "1.5.16",
"difflib": "0.2.4",
"emoji-datasource": "3.0.0",
"emoji-datasource-apple": "3.0.0",
"emoji-datasource-emojione": "3.0.0",

View File

@ -1,3 +1,3 @@
ZULIP_VERSION = "1.7.1+git"
PROVISION_VERSION = '14.1'
PROVISION_VERSION = '14.2'

View File

@ -1207,6 +1207,12 @@ diffie-hellman@^5.0.0:
miller-rabin "^4.0.0"
randombytes "^2.0.0"
difflib@^0.2.4:
version "0.2.4"
resolved "https://registry.yarnpkg.com/difflib/-/difflib-0.2.4.tgz#b5e30361a6db023176d562892db85940a718f47e"
dependencies:
heap ">= 0.2.0"
doctrine@^1.2.2:
version "1.5.0"
resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-1.5.0.tgz#379dce730f6166f76cefa4e6707a159b02c5a6fa"
@ -2631,6 +2637,10 @@ hawk@~3.1.3:
hoek "2.x.x"
sntp "1.x.x"
"heap@>= 0.2.0":
version "0.2.6"
resolved "https://registry.yarnpkg.com/heap/-/heap-0.2.6.tgz#087e1f10b046932fc8594dd9e6d378afc9d1e5ac"
hmac-drbg@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1"