Path: blob/master/web-gui/buildyourownbotnet/assets/js/codemirror/test/mode_test.js
1293 views
/**1* Helper to test CodeMirror highlighting modes. It pretty prints output of the2* highlighter and can check against expected styles.3*4* Mode tests are registered by calling test.mode(testName, mode,5* tokens), where mode is a mode object as returned by6* CodeMirror.getMode, and tokens is an array of lines that make up7* the test.8*9* These lines are strings, in which styled stretches of code are10* enclosed in brackets `[]`, and prefixed by their style. For11* example, `[keyword if]`. Brackets in the code itself must be12* duplicated to prevent them from being interpreted as token13* boundaries. For example `a[[i]]` for `a[i]`. If a token has14* multiple styles, the styles must be separated by ampersands, for15* example `[tag&error </hmtl>]`.16*17* See the test.js files in the css, markdown, gfm, and stex mode18* directories for examples.19*/20(function() {21function findSingle(str, pos, ch) {22for (;;) {23var found = str.indexOf(ch, pos);24if (found == -1) return null;25if (str.charAt(found + 1) != ch) return found;26pos = found + 2;27}28}2930var styleName = /[\w&-_]+/g;31function parseTokens(strs) {32var tokens = [], plain = "";33for (var i = 0; i < strs.length; ++i) {34if (i) plain += "\n";35var str = strs[i], pos = 0;36while (pos < str.length) {37var style = null, text;38if (str.charAt(pos) == "[" && str.charAt(pos+1) != "[") {39styleName.lastIndex = pos + 1;40var m = styleName.exec(str);41style = m[0].replace(/&/g, " ");42var textStart = pos + style.length + 2;43var end = findSingle(str, textStart, "]");44if (end == null) throw new Error("Unterminated token at " + pos + " in '" + str + "'" + style);45text = str.slice(textStart, end);46pos = end + 1;47} else {48var end = findSingle(str, pos, "[");49if (end == null) end = str.length;50text = str.slice(pos, end);51pos = end;52}53text = text.replace(/\[\[|\]\]/g, function(s) {return s.charAt(0);});54tokens.push(style, text);55plain += text;56}57}58return {tokens: tokens, plain: plain};59}6061test.mode = function(name, mode, tokens, modeName) {62var data = parseTokens(tokens);63return test((modeName || mode.name) + "_" + name, function() {64return compare(data.plain, data.tokens, mode);65});66};6768function esc(str) {69return str.replace('&', '&').replace('<', '<');70}7172function compare(text, expected, mode) {7374var expectedOutput = [];75for (var i = 0; i < expected.length; i += 2) {76var sty = expected[i];77if (sty && sty.indexOf(" ")) sty = sty.split(' ').sort().join(' ');78expectedOutput.push(sty, expected[i + 1]);79}8081var observedOutput = highlight(text, mode);8283var s = "";84var diff = highlightOutputsDifferent(expectedOutput, observedOutput);85if (diff != null) {86s += '<div class="mt-test mt-fail">';87s += '<pre>' + esc(text) + '</pre>';88s += '<div class="cm-s-default">';89s += 'expected:';90s += prettyPrintOutputTable(expectedOutput, diff);91s += 'observed:';92s += prettyPrintOutputTable(observedOutput, diff);93s += '</div>';94s += '</div>';95}96if (observedOutput.indentFailures) {97for (var i = 0; i < observedOutput.indentFailures.length; i++)98s += "<div class='mt-test mt-fail'>" + esc(observedOutput.indentFailures[i]) + "</div>";99}100if (s) throw new Failure(s);101}102103function highlight(string, mode) {104var state = mode.startState()105106var lines = string.replace(/\r\n/g,'\n').split('\n');107var st = [], pos = 0;108for (var i = 0; i < lines.length; ++i) {109var line = lines[i], newLine = true;110if (mode.indent) {111var ws = line.match(/^\s*/)[0];112var indent = mode.indent(state, line.slice(ws.length));113if (indent != CodeMirror.Pass && indent != ws.length)114(st.indentFailures || (st.indentFailures = [])).push(115"Indentation of line " + (i + 1) + " is " + indent + " (expected " + ws.length + ")");116}117var stream = new CodeMirror.StringStream(line);118if (line == "" && mode.blankLine) mode.blankLine(state);119/* Start copied code from CodeMirror.highlight */120while (!stream.eol()) {121var compare = mode.token(stream, state), substr = stream.current();122if (compare && compare.indexOf(" ") > -1) compare = compare.split(' ').sort().join(' ');123stream.start = stream.pos;124if (pos && st[pos-2] == compare && !newLine) {125st[pos-1] += substr;126} else if (substr) {127st[pos++] = compare; st[pos++] = substr;128}129// Give up when line is ridiculously long130if (stream.pos > 5000) {131st[pos++] = null; st[pos++] = this.text.slice(stream.pos);132break;133}134newLine = false;135}136}137138return st;139}140141function highlightOutputsDifferent(o1, o2) {142var minLen = Math.min(o1.length, o2.length);143for (var i = 0; i < minLen; ++i)144if (o1[i] != o2[i]) return i >> 1;145if (o1.length > minLen || o2.length > minLen) return minLen;146}147148function prettyPrintOutputTable(output, diffAt) {149var s = '<table class="mt-output">';150s += '<tr>';151for (var i = 0; i < output.length; i += 2) {152var style = output[i], val = output[i+1];153s +=154'<td class="mt-token"' + (i == diffAt * 2 ? " style='background: pink'" : "") + '>' +155'<span class="cm-' + esc(String(style)) + '">' +156esc(val.replace(/ /g,'\xb7')) +157'</span>' +158'</td>';159}160s += '</tr><tr>';161for (var i = 0; i < output.length; i += 2) {162s += '<td class="mt-style"><span>' + (output[i] || null) + '</span></td>';163}164s += '</table>';165return s;166}167})();168169170