File modules/editor/codemirror/test/mode_test.min.js
Last commit: Tue May 22 22:39:53 2018 +0200 Jan Dankert Fix für PHP 7.2: 'Object' darf nun nicht mehr als Klassennamen verwendet werden. AUCH NICHT IN EINEM NAMESPACE! WTF, wozu habe ich das in einen verfickten Namespace gepackt? Wozu soll der sonst da sein??? Amateure. Daher nun notgedrungen unbenannt in 'BaseObject'.
1 /** 2 * Helper to test CodeMirror highlighting modes. It pretty prints output of the 3 * highlighter and can check against expected styles. 4 * 5 * Mode tests are registered by calling test.mode(testName, mode, 6 * tokens), where mode is a mode object as returned by 7 * CodeMirror.getMode, and tokens is an array of lines that make up 8 * the test. 9 * 10 * These lines are strings, in which styled stretches of code are 11 * enclosed in brackets `[]`, and prefixed by their style. For 12 * example, `[keyword if]`. Brackets in the code itself must be 13 * duplicated to prevent them from being interpreted as token 14 * boundaries. For example `a[[i]]` for `a[i]`. If a token has 15 * multiple styles, the styles must be separated by ampersands, for 16 * example `[tag&error </hmtl>]`. 17 * 18 * See the test.js files in the css, markdown, gfm, and stex mode 19 * directories for examples. 20 */ 21 (function() { 22 function findSingle(str, pos, ch) { 23 for (;;) { 24 var found = str.indexOf(ch, pos); 25 if (found == -1) return null; 26 if (str.charAt(found + 1) != ch) return found; 27 pos = found + 2; 28 } 29 } 30 31 var styleName = /[\w&-_]+/g; 32 function parseTokens(strs) { 33 var tokens = [], plain = ""; 34 for (var i = 0; i < strs.length; ++i) { 35 if (i) plain += "\n"; 36 var str = strs[i], pos = 0; 37 while (pos < str.length) { 38 var style = null, text; 39 if (str.charAt(pos) == "[" && str.charAt(pos+1) != "[") { 40 styleName.lastIndex = pos + 1; 41 var m = styleName.exec(str); 42 style = m[0].replace(/&/g, " "); 43 var textStart = pos + style.length + 2; 44 var end = findSingle(str, textStart, "]"); 45 if (end == null) throw new Error("Unterminated token at " + pos + " in '" + str + "'" + style); 46 text = str.slice(textStart, end); 47 pos = end + 1; 48 } else { 49 var end = findSingle(str, pos, "["); 50 if (end == null) end = str.length; 51 text = str.slice(pos, end); 52 pos = end; 53 } 54 text = text.replace(/\[\[|\]\]/g, function(s) {return s.charAt(0);}); 55 tokens.push({style: style, text: text}); 56 plain += text; 57 } 58 } 59 return {tokens: tokens, plain: plain}; 60 } 61 62 test.mode = function(name, mode, tokens, modeName) { 63 var data = parseTokens(tokens); 64 return test((modeName || mode.name) + "_" + name, function() { 65 return compare(data.plain, data.tokens, mode); 66 }); 67 }; 68 69 function esc(str) { 70 return str.replace('&', '&').replace('<', '<').replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'"); 71 } 72 73 function compare(text, expected, mode) { 74 75 var expectedOutput = []; 76 for (var i = 0; i < expected.length; ++i) { 77 var sty = expected[i].style; 78 if (sty && sty.indexOf(" ")) sty = sty.split(' ').sort().join(' '); 79 expectedOutput.push({style: sty, text: expected[i].text}); 80 } 81 82 var observedOutput = highlight(text, mode); 83 84 var s = ""; 85 var diff = highlightOutputsDifferent(expectedOutput, observedOutput); 86 if (diff != null) { 87 s += '<div class="mt-test mt-fail">'; 88 s += '<pre>' + esc(text) + '</pre>'; 89 s += '<div class="cm-s-default">'; 90 s += 'expected:'; 91 s += prettyPrintOutputTable(expectedOutput, diff); 92 s += 'observed: [<a onclick="this.parentElement.className+=\' mt-state-unhide\'">display states</a>]'; 93 s += prettyPrintOutputTable(observedOutput, diff); 94 s += '</div>'; 95 s += '</div>'; 96 } 97 if (observedOutput.indentFailures) { 98 for (var i = 0; i < observedOutput.indentFailures.length; i++) 99 s += "<div class='mt-test mt-fail'>" + esc(observedOutput.indentFailures[i]) + "</div>"; 100 } 101 if (s) throw new Failure(s); 102 } 103 104 function stringify(obj) { 105 function replacer(key, obj) { 106 if (typeof obj == "function") { 107 var m = obj.toString().match(/function\s*[^\s(]*/); 108 return m ? m[0] : "function"; 109 } 110 return obj; 111 } 112 if (window.JSON && JSON.stringify) 113 return JSON.stringify(obj, replacer, 2); 114 return "[unsupported]"; // Fail safely if no native JSON. 115 } 116 117 function highlight(string, mode) { 118 var state = mode.startState(); 119 120 var lines = string.replace(/\r\n/g,'\n').split('\n'); 121 var st = [], pos = 0; 122 for (var i = 0; i < lines.length; ++i) { 123 var line = lines[i], newLine = true; 124 if (mode.indent) { 125 var ws = line.match(/^\s*/)[0]; 126 var indent = mode.indent(state, line.slice(ws.length)); 127 if (indent != CodeMirror.Pass && indent != ws.length) 128 (st.indentFailures || (st.indentFailures = [])).push( 129 "Indentation of line " + (i + 1) + " is " + indent + " (expected " + ws.length + ")"); 130 } 131 var stream = new CodeMirror.StringStream(line, 4, { 132 lookAhead: function(n) { return lines[i + n] } 133 }); 134 if (line == "" && mode.blankLine) mode.blankLine(state); 135 /* Start copied code from CodeMirror.highlight */ 136 while (!stream.eol()) { 137 for (var j = 0; j < 10 && stream.start >= stream.pos; j++) 138 var compare = mode.token(stream, state); 139 if (j == 10) 140 throw new Failure("Failed to advance the stream." + stream.string + " " + stream.pos); 141 var substr = stream.current(); 142 if (compare && compare.indexOf(" ") > -1) compare = compare.split(' ').sort().join(' '); 143 stream.start = stream.pos; 144 if (pos && st[pos-1].style == compare && !newLine) { 145 st[pos-1].text += substr; 146 } else if (substr) { 147 st[pos++] = {style: compare, text: substr, state: stringify(state)}; 148 } 149 // Give up when line is ridiculously long 150 if (stream.pos > 5000) { 151 st[pos++] = {style: null, text: this.text.slice(stream.pos)}; 152 break; 153 } 154 newLine = false; 155 } 156 } 157 158 return st; 159 } 160 161 function highlightOutputsDifferent(o1, o2) { 162 var minLen = Math.min(o1.length, o2.length); 163 for (var i = 0; i < minLen; ++i) 164 if (o1[i].style != o2[i].style || o1[i].text != o2[i].text) return i; 165 if (o1.length > minLen || o2.length > minLen) return minLen; 166 } 167 168 function prettyPrintOutputTable(output, diffAt) { 169 var s = '<table class="mt-output">'; 170 s += '<tr>'; 171 for (var i = 0; i < output.length; ++i) { 172 var style = output[i].style, val = output[i].text; 173 s += 174 '<td class="mt-token"' + (i == diffAt ? " style='background: pink'" : "") + '>' + 175 '<span class="cm-' + esc(String(style)) + '">' + 176 esc(val.replace(/ /g,'\xb7')) + // · MIDDLE DOT 177 '</span>' + 178 '</td>'; 179 } 180 s += '</tr><tr>'; 181 for (var i = 0; i < output.length; ++i) { 182 s += '<td class="mt-style"><span>' + (output[i].style || null) + '</span></td>'; 183 } 184 if(output[0].state) { 185 s += '</tr><tr class="mt-state-row" title="State AFTER each token">'; 186 for (var i = 0; i < output.length; ++i) { 187 s += '<td class="mt-state"><pre>' + esc(output[i].state) + '</pre></td>'; 188 } 189 } 190 s += '</tr></table>'; 191 return s; 192 } 193 })();
Downloadmodules/editor/codemirror/test/mode_test.min.js
History Tue, 22 May 2018 22:39:53 +0200 Jan Dankert Fix für PHP 7.2: 'Object' darf nun nicht mehr als Klassennamen verwendet werden. AUCH NICHT IN EINEM NAMESPACE! WTF, wozu habe ich das in einen verfickten Namespace gepackt? Wozu soll der sonst da sein??? Amateure. Daher nun notgedrungen unbenannt in 'BaseObject'.