1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/layout/style/test/test_parser_diagnostics_unprintables.html Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,220 @@ 1.4 +<!doctype html> 1.5 +<html> 1.6 +<head> 1.7 + <meta charset="utf-8"> 1.8 + <title>Test for CSS parser diagnostics escaping unprintable 1.9 + characters correctly</title> 1.10 + <script src="/tests/SimpleTest/SimpleTest.js"></script> 1.11 + <link rel="stylesheet" href="/tests/SimpleTest/test.css"> 1.12 +</head> 1.13 +<body> 1.14 +<a target="_blank" 1.15 + href="https://bugzilla.mozilla.org/show_bug.cgi?id=229827" 1.16 +>Mozilla Bug 229827</a> 1.17 +<style id="testbench"></style> 1.18 +<script type="application/javascript;version=1.8"> 1.19 +// This test has intimate knowledge of how to get the CSS parser to 1.20 +// emit diagnostics that contain text under control of the user. 1.21 +// That's not the point of the test, though; the point is only that 1.22 +// *that text* is properly escaped. 1.23 + 1.24 +// There is one "pattern" for each code path through the error reporter 1.25 +// that might need to escape some kind of user-supplied text. 1.26 +// Each "pattern" is tested once with each of the "substitution"s below: 1.27 +// <t>, <i>, and <s> are replaced by the t:, i:, and s: fields of 1.28 +// each substitution object in turn. 1.29 +const patterns = [ 1.30 + // REPORT_UNEXPECTED_P (only ever used in contexts where identifier-like 1.31 + // escaping is appropriate) 1.32 + { i: "<t>|x{}", o: "prefix '<i>'" }, 1.33 + // REPORT_UNEXPECTED_TOKEN with: 1.34 + // _Ident 1.35 + { i: "@namespace fnord <t>;", o: "within @namespace: '<i>'" }, 1.36 + // _Ref 1.37 + { i: "@namespace fnord #<t>;", o: "within @namespace: '#<i>'" }, 1.38 + // _Function 1.39 + { i: "@namespace fnord <t>();", o: "within @namespace: '<i>('" }, 1.40 + // _Dimension 1.41 + { i: "@namespace fnord 14<t>;", o: "within @namespace: '14<i>'" }, 1.42 + // _AtKeyword 1.43 + { i: "x{@<t>: }", o: "declaration but found '@<i>'." }, 1.44 + // _String 1.45 + { i: "x{ '<t>'}" , o: "declaration but found ''<s>''." }, 1.46 + // _Bad_String 1.47 + { i: "x{ '<t>\n}", o: "declaration but found ''<s>'." }, 1.48 + // _URL 1.49 + { i: "x{ url('<t>')}", o: "declaration but found 'url('<s>')'." }, 1.50 + // _Bad_URL 1.51 + { i: "x{ url('<t>'.)}" , o: "declaration but found 'url('<s>''." } 1.52 +]; 1.53 + 1.54 +// Blocks of characters to test, and how they should be escaped when 1.55 +// they appear in identifiers and string constants. 1.56 +const substitutions = [ 1.57 + // ASCII printables that _can_ normally appear in identifiers, 1.58 + // so should of course _not_ be escaped. 1.59 + { t: "-_0123456789", i: "-_0123456789", 1.60 + s: "-_0123456789" }, 1.61 + { t: "abcdefghijklmnopqrstuvwxyz", i: "abcdefghijklmnopqrstuvwxyz", 1.62 + s: "abcdefghijklmnopqrstuvwxyz" }, 1.63 + { t: "ABCDEFGHIJKLMNOPQRSTUVWXYZ", i: "ABCDEFGHIJKLMNOPQRSTUVWXYZ", 1.64 + s: "ABCDEFGHIJKLMNOPQRSTUVWXYZ" }, 1.65 + 1.66 + // ASCII printables that are not normally valid as the first character 1.67 + // of an identifier, or the character immediately after a leading dash, 1.68 + // but can be forced into that position with escapes. 1.69 + { t: "\\-", i: "\\-", s: "-" }, 1.70 + { t: "\\30 ", i: "\\30 ", s: "0" }, 1.71 + { t: "\\31 ", i: "\\31 ", s: "1" }, 1.72 + { t: "\\32 ", i: "\\32 ", s: "2" }, 1.73 + { t: "\\33 ", i: "\\33 ", s: "3" }, 1.74 + { t: "\\34 ", i: "\\34 ", s: "4" }, 1.75 + { t: "\\35 ", i: "\\35 ", s: "5" }, 1.76 + { t: "\\36 ", i: "\\36 ", s: "6" }, 1.77 + { t: "\\37 ", i: "\\37 ", s: "7" }, 1.78 + { t: "\\38 ", i: "\\38 ", s: "8" }, 1.79 + { t: "\\39 ", i: "\\39 ", s: "9" }, 1.80 + { t: "-\\-", i: "-\\-", s: "--" }, 1.81 + { t: "-\\30 ", i: "-\\30 ", s: "-0" }, 1.82 + { t: "-\\31 ", i: "-\\31 ", s: "-1" }, 1.83 + { t: "-\\32 ", i: "-\\32 ", s: "-2" }, 1.84 + { t: "-\\33 ", i: "-\\33 ", s: "-3" }, 1.85 + { t: "-\\34 ", i: "-\\34 ", s: "-4" }, 1.86 + { t: "-\\35 ", i: "-\\35 ", s: "-5" }, 1.87 + { t: "-\\36 ", i: "-\\36 ", s: "-6" }, 1.88 + { t: "-\\37 ", i: "-\\37 ", s: "-7" }, 1.89 + { t: "-\\38 ", i: "-\\38 ", s: "-8" }, 1.90 + { t: "-\\39 ", i: "-\\39 ", s: "-9" }, 1.91 + 1.92 + // ASCII printables that must be escaped in identifiers. 1.93 + // Most of these should not be escaped in strings. 1.94 + { t: "\\!\\\"\\#\\$", i: "\\!\\\"\\#\\$", s: "!\\\"#$" }, 1.95 + { t: "\\%\\&\\'\\(", i: "\\%\\&\\'\\(", s: "%&\\'(" }, 1.96 + { t: "\\)\\*\\+\\,", i: "\\)\\*\\+\\,", s: ")*+," }, 1.97 + { t: "\\.\\/\\:\\;", i: "\\.\\/\\:\\;", s: "./:;" }, 1.98 + { t: "\\<\\=\\>\\?", i: "\\<\\=\\>\\?", s: "<=>?", }, 1.99 + { t: "\\@\\[\\\\\\]", i: "\\@\\[\\\\\\]", s: "@[\\\\]" }, 1.100 + { t: "\\^\\`\\{\\}\\~", i: "\\^\\`\\{\\}\\~", s: "^`{}~" }, 1.101 + 1.102 + // U+0000 - U+0020 (C0 controls, space) 1.103 + // U+000A LINE FEED, U+000C FORM FEED, and U+000D CARRIAGE RETURN 1.104 + // cannot be put into a CSS token as escaped literal characters, so 1.105 + // we do them with hex escapes instead. 1.106 + // The parser replaces U+0000 with U+FFFD. 1.107 + { t: "\\\x00\\\x01\\\x02\\\x03", i: "�\\1 \\2 \\3 ", 1.108 + s: "�\\1 \\2 \\3 " }, 1.109 + { t: "\\\x04\\\x05\\\x06\\\x07", i: "\\4 \\5 \\6 \\7 ", 1.110 + s: "\\4 \\5 \\6 \\7 " }, 1.111 + { t: "\\\x08\\\x09\\000A\\\x0B", i: "\\8 \\9 \\A \\B ", 1.112 + s: "\\8 \\9 \\A \\B " }, 1.113 + { t: "\\000C\\000D\\\x0E\\\x0F", i: "\\C \\D \\E \\F ", 1.114 + s: "\\C \\D \\E \\F " }, 1.115 + { t: "\\\x10\\\x11\\\x12\\\x13", i: "\\10 \\11 \\12 \\13 ", 1.116 + s: "\\10 \\11 \\12 \\13 " }, 1.117 + { t: "\\\x14\\\x15\\\x16\\\x17", i: "\\14 \\15 \\16 \\17 ", 1.118 + s: "\\14 \\15 \\16 \\17 " }, 1.119 + { t: "\\\x18\\\x19\\\x1A\\\x1B", i: "\\18 \\19 \\1A \\1B ", 1.120 + s: "\\18 \\19 \\1A \\1B " }, 1.121 + { t: "\\\x1C\\\x1D\\\x1E\\\x1F\\ ", i: "\\1C \\1D \\1E \\1F \\ ", 1.122 + s: "\\1C \\1D \\1E \\1F " }, 1.123 + 1.124 + // U+007F (DELETE) and U+0080 - U+009F (C1 controls) 1.125 + { t: "\\\x7f\\\x80\\\x81\\\x82", i: "\\7F \\80 \\81 \\82 ", 1.126 + s: "\\7F \\80 \\81 \\82 " }, 1.127 + { t: "\\\x83\\\x84\\\x85\\\x86", i: "\\83 \\84 \\85 \\86 ", 1.128 + s: "\\83 \\84 \\85 \\86 " }, 1.129 + { t: "\\\x87\\\x88\\\x89\\\x8A", i: "\\87 \\88 \\89 \\8A ", 1.130 + s: "\\87 \\88 \\89 \\8A " }, 1.131 + { t: "\\\x8B\\\x8C\\\x8D\\\x8E", i: "\\8B \\8C \\8D \\8E ", 1.132 + s: "\\8B \\8C \\8D \\8E " }, 1.133 + { t: "\\\x8F\\\x90\\\x91\\\x92", i: "\\8F \\90 \\91 \\92 ", 1.134 + s: "\\8F \\90 \\91 \\92 " }, 1.135 + { t: "\\\x93\\\x94\\\x95\\\x96", i: "\\93 \\94 \\95 \\96 ", 1.136 + s: "\\93 \\94 \\95 \\96 " }, 1.137 + { t: "\\\x97\\\x98\\\x99\\\x9A", i: "\\97 \\98 \\99 \\9A ", 1.138 + s: "\\97 \\98 \\99 \\9A " }, 1.139 + { t: "\\\x9B\\\x9C\\\x9D\\\x9E\\\x9F", i: "\\9B \\9C \\9D \\9E \\9F ", 1.140 + s: "\\9B \\9C \\9D \\9E \\9F " }, 1.141 + 1.142 + // CSS doesn't bother with the full Unicode rules for identifiers, 1.143 + // instead declaring that any code point greater than or equal to 1.144 + // U+00A0 is a valid identifier character. Test a small handful 1.145 + // of both basic and astral plane characters. 1.146 + 1.147 + // Arabic (caution to editors: there is a possibly-invisible U+200E 1.148 + // LEFT-TO-RIGHT MARK in each string, just before the close quote) 1.149 + { t: "أبجدهوزحطيكلمنسعفصقرشتثخذضظغ", 1.150 + i: "أبجدهوزحطيكلمنسعفصقرشتثخذضظغ", 1.151 + s: "أبجدهوزحطيكلمنسعفصقرشتثخذضظغ" }, 1.152 + 1.153 + // Box drawing 1.154 + { t: "─│┌┐└┘├┤┬┴┼╭╮╯╰╴╵╶╷", 1.155 + i: "─│┌┐└┘├┤┬┴┼╭╮╯╰╴╵╶╷", 1.156 + s: "─│┌┐└┘├┤┬┴┼╭╮╯╰╴╵╶╷" }, 1.157 + 1.158 + // CJK Unified Ideographs 1.159 + { t: "一丁丂七丄丅丆万丈三上下丌不与丏", 1.160 + i: "一丁丂七丄丅丆万丈三上下丌不与丏", 1.161 + s: "一丁丂七丄丅丆万丈三上下丌不与丏" }, 1.162 + 1.163 + // CJK Unified Ideographs Extension B (astral) 1.164 + { t: "𠀀𠀁𠀂𠀃𠀄𠀅𠀆𠀇𠀈𠀉𠀊𠀋𠀌𠀍𠀎𠀏", 1.165 + i: "𠀀𠀁𠀂𠀃𠀄𠀅𠀆𠀇𠀈𠀉𠀊𠀋𠀌𠀍𠀎𠀏", 1.166 + s: "𠀀𠀁𠀂𠀃𠀄𠀅𠀆𠀇𠀈𠀉𠀊𠀋𠀌𠀍𠀎𠀏" }, 1.167 + 1.168 + // Devanagari 1.169 + { t: "कखगघङचछजझञटठडढणतथदधनपफबभमयरलळवशषसह", 1.170 + i: "कखगघङचछजझञटठडढणतथदधनपफबभमयरलळवशषसह", 1.171 + s: "कखगघङचछजझञटठडढणतथदधनपफबभमयरलळवशषसह" }, 1.172 + 1.173 + // Emoticons (astral) 1.174 + { t: "😁😂😃😄😅😆😇😈😉😊😋😌😍😎😏😐", 1.175 + i: "😁😂😃😄😅😆😇😈😉😊😋😌😍😎😏😐", 1.176 + s: "😁😂😃😄😅😆😇😈😉😊😋😌😍😎😏😐" }, 1.177 + 1.178 + // Greek 1.179 + { t: "αβγδεζηθικλμνξοπρςστυφχψω", 1.180 + i: "αβγδεζηθικλμνξοπρςστυφχψω", 1.181 + s: "αβγδεζηθικλμνξοπρςστυφχψω" } 1.182 +]; 1.183 + 1.184 +const npatterns = patterns.length; 1.185 +const nsubstitutions = substitutions.length; 1.186 + 1.187 +function quotemeta(str) { 1.188 + return str.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&"); 1.189 +} 1.190 +function subst(str, sub) { 1.191 + return str.replace("<t>", sub.t) 1.192 + .replace("<i>", sub.i) 1.193 + .replace("<s>", sub.s); 1.194 +} 1.195 + 1.196 +var curpat = 0; 1.197 +var cursubst = -1; 1.198 +var testbench = document.getElementById("testbench"); 1.199 + 1.200 +function nextTest() { 1.201 + cursubst++; 1.202 + if (cursubst == nsubstitutions) { 1.203 + curpat++; 1.204 + cursubst = 0; 1.205 + } 1.206 + if (curpat == npatterns) { 1.207 + SimpleTest.finish(); 1.208 + return; 1.209 + } 1.210 + 1.211 + let css = subst(patterns[curpat].i, substitutions[cursubst]); 1.212 + let msg = quotemeta(subst(patterns[curpat].o, substitutions[cursubst])); 1.213 + 1.214 + SimpleTest.expectConsoleMessages(function () { testbench.innerHTML = css }, 1.215 + [{ errorMessage: new RegExp(msg) }], 1.216 + nextTest); 1.217 +} 1.218 + 1.219 +SimpleTest.waitForExplicitFinish(); 1.220 +nextTest(); 1.221 +</script> 1.222 +</body> 1.223 +</html>