Wed, 31 Dec 2014 06:55:50 +0100
Added tag UPSTREAM_283F7C6 for changeset ca08bd8f51b2
michael@0 | 1 | <!doctype html> |
michael@0 | 2 | <html> |
michael@0 | 3 | <head> |
michael@0 | 4 | <meta charset="utf-8"> |
michael@0 | 5 | <title>Test for CSS parser diagnostics escaping unprintable |
michael@0 | 6 | characters correctly</title> |
michael@0 | 7 | <script src="/tests/SimpleTest/SimpleTest.js"></script> |
michael@0 | 8 | <link rel="stylesheet" href="/tests/SimpleTest/test.css"> |
michael@0 | 9 | </head> |
michael@0 | 10 | <body> |
michael@0 | 11 | <a target="_blank" |
michael@0 | 12 | href="https://bugzilla.mozilla.org/show_bug.cgi?id=229827" |
michael@0 | 13 | >Mozilla Bug 229827</a> |
michael@0 | 14 | <style id="testbench"></style> |
michael@0 | 15 | <script type="application/javascript;version=1.8"> |
michael@0 | 16 | // This test has intimate knowledge of how to get the CSS parser to |
michael@0 | 17 | // emit diagnostics that contain text under control of the user. |
michael@0 | 18 | // That's not the point of the test, though; the point is only that |
michael@0 | 19 | // *that text* is properly escaped. |
michael@0 | 20 | |
michael@0 | 21 | // There is one "pattern" for each code path through the error reporter |
michael@0 | 22 | // that might need to escape some kind of user-supplied text. |
michael@0 | 23 | // Each "pattern" is tested once with each of the "substitution"s below: |
michael@0 | 24 | // <t>, <i>, and <s> are replaced by the t:, i:, and s: fields of |
michael@0 | 25 | // each substitution object in turn. |
michael@0 | 26 | const patterns = [ |
michael@0 | 27 | // REPORT_UNEXPECTED_P (only ever used in contexts where identifier-like |
michael@0 | 28 | // escaping is appropriate) |
michael@0 | 29 | { i: "<t>|x{}", o: "prefix '<i>'" }, |
michael@0 | 30 | // REPORT_UNEXPECTED_TOKEN with: |
michael@0 | 31 | // _Ident |
michael@0 | 32 | { i: "@namespace fnord <t>;", o: "within @namespace: '<i>'" }, |
michael@0 | 33 | // _Ref |
michael@0 | 34 | { i: "@namespace fnord #<t>;", o: "within @namespace: '#<i>'" }, |
michael@0 | 35 | // _Function |
michael@0 | 36 | { i: "@namespace fnord <t>();", o: "within @namespace: '<i>('" }, |
michael@0 | 37 | // _Dimension |
michael@0 | 38 | { i: "@namespace fnord 14<t>;", o: "within @namespace: '14<i>'" }, |
michael@0 | 39 | // _AtKeyword |
michael@0 | 40 | { i: "x{@<t>: }", o: "declaration but found '@<i>'." }, |
michael@0 | 41 | // _String |
michael@0 | 42 | { i: "x{ '<t>'}" , o: "declaration but found ''<s>''." }, |
michael@0 | 43 | // _Bad_String |
michael@0 | 44 | { i: "x{ '<t>\n}", o: "declaration but found ''<s>'." }, |
michael@0 | 45 | // _URL |
michael@0 | 46 | { i: "x{ url('<t>')}", o: "declaration but found 'url('<s>')'." }, |
michael@0 | 47 | // _Bad_URL |
michael@0 | 48 | { i: "x{ url('<t>'.)}" , o: "declaration but found 'url('<s>''." } |
michael@0 | 49 | ]; |
michael@0 | 50 | |
michael@0 | 51 | // Blocks of characters to test, and how they should be escaped when |
michael@0 | 52 | // they appear in identifiers and string constants. |
michael@0 | 53 | const substitutions = [ |
michael@0 | 54 | // ASCII printables that _can_ normally appear in identifiers, |
michael@0 | 55 | // so should of course _not_ be escaped. |
michael@0 | 56 | { t: "-_0123456789", i: "-_0123456789", |
michael@0 | 57 | s: "-_0123456789" }, |
michael@0 | 58 | { t: "abcdefghijklmnopqrstuvwxyz", i: "abcdefghijklmnopqrstuvwxyz", |
michael@0 | 59 | s: "abcdefghijklmnopqrstuvwxyz" }, |
michael@0 | 60 | { t: "ABCDEFGHIJKLMNOPQRSTUVWXYZ", i: "ABCDEFGHIJKLMNOPQRSTUVWXYZ", |
michael@0 | 61 | s: "ABCDEFGHIJKLMNOPQRSTUVWXYZ" }, |
michael@0 | 62 | |
michael@0 | 63 | // ASCII printables that are not normally valid as the first character |
michael@0 | 64 | // of an identifier, or the character immediately after a leading dash, |
michael@0 | 65 | // but can be forced into that position with escapes. |
michael@0 | 66 | { t: "\\-", i: "\\-", s: "-" }, |
michael@0 | 67 | { t: "\\30 ", i: "\\30 ", s: "0" }, |
michael@0 | 68 | { t: "\\31 ", i: "\\31 ", s: "1" }, |
michael@0 | 69 | { t: "\\32 ", i: "\\32 ", s: "2" }, |
michael@0 | 70 | { t: "\\33 ", i: "\\33 ", s: "3" }, |
michael@0 | 71 | { t: "\\34 ", i: "\\34 ", s: "4" }, |
michael@0 | 72 | { t: "\\35 ", i: "\\35 ", s: "5" }, |
michael@0 | 73 | { t: "\\36 ", i: "\\36 ", s: "6" }, |
michael@0 | 74 | { t: "\\37 ", i: "\\37 ", s: "7" }, |
michael@0 | 75 | { t: "\\38 ", i: "\\38 ", s: "8" }, |
michael@0 | 76 | { t: "\\39 ", i: "\\39 ", s: "9" }, |
michael@0 | 77 | { t: "-\\-", i: "-\\-", s: "--" }, |
michael@0 | 78 | { t: "-\\30 ", i: "-\\30 ", s: "-0" }, |
michael@0 | 79 | { t: "-\\31 ", i: "-\\31 ", s: "-1" }, |
michael@0 | 80 | { t: "-\\32 ", i: "-\\32 ", s: "-2" }, |
michael@0 | 81 | { t: "-\\33 ", i: "-\\33 ", s: "-3" }, |
michael@0 | 82 | { t: "-\\34 ", i: "-\\34 ", s: "-4" }, |
michael@0 | 83 | { t: "-\\35 ", i: "-\\35 ", s: "-5" }, |
michael@0 | 84 | { t: "-\\36 ", i: "-\\36 ", s: "-6" }, |
michael@0 | 85 | { t: "-\\37 ", i: "-\\37 ", s: "-7" }, |
michael@0 | 86 | { t: "-\\38 ", i: "-\\38 ", s: "-8" }, |
michael@0 | 87 | { t: "-\\39 ", i: "-\\39 ", s: "-9" }, |
michael@0 | 88 | |
michael@0 | 89 | // ASCII printables that must be escaped in identifiers. |
michael@0 | 90 | // Most of these should not be escaped in strings. |
michael@0 | 91 | { t: "\\!\\\"\\#\\$", i: "\\!\\\"\\#\\$", s: "!\\\"#$" }, |
michael@0 | 92 | { t: "\\%\\&\\'\\(", i: "\\%\\&\\'\\(", s: "%&\\'(" }, |
michael@0 | 93 | { t: "\\)\\*\\+\\,", i: "\\)\\*\\+\\,", s: ")*+," }, |
michael@0 | 94 | { t: "\\.\\/\\:\\;", i: "\\.\\/\\:\\;", s: "./:;" }, |
michael@0 | 95 | { t: "\\<\\=\\>\\?", i: "\\<\\=\\>\\?", s: "<=>?", }, |
michael@0 | 96 | { t: "\\@\\[\\\\\\]", i: "\\@\\[\\\\\\]", s: "@[\\\\]" }, |
michael@0 | 97 | { t: "\\^\\`\\{\\}\\~", i: "\\^\\`\\{\\}\\~", s: "^`{}~" }, |
michael@0 | 98 | |
michael@0 | 99 | // U+0000 - U+0020 (C0 controls, space) |
michael@0 | 100 | // U+000A LINE FEED, U+000C FORM FEED, and U+000D CARRIAGE RETURN |
michael@0 | 101 | // cannot be put into a CSS token as escaped literal characters, so |
michael@0 | 102 | // we do them with hex escapes instead. |
michael@0 | 103 | // The parser replaces U+0000 with U+FFFD. |
michael@0 | 104 | { t: "\\\x00\\\x01\\\x02\\\x03", i: "�\\1 \\2 \\3 ", |
michael@0 | 105 | s: "�\\1 \\2 \\3 " }, |
michael@0 | 106 | { t: "\\\x04\\\x05\\\x06\\\x07", i: "\\4 \\5 \\6 \\7 ", |
michael@0 | 107 | s: "\\4 \\5 \\6 \\7 " }, |
michael@0 | 108 | { t: "\\\x08\\\x09\\000A\\\x0B", i: "\\8 \\9 \\A \\B ", |
michael@0 | 109 | s: "\\8 \\9 \\A \\B " }, |
michael@0 | 110 | { t: "\\000C\\000D\\\x0E\\\x0F", i: "\\C \\D \\E \\F ", |
michael@0 | 111 | s: "\\C \\D \\E \\F " }, |
michael@0 | 112 | { t: "\\\x10\\\x11\\\x12\\\x13", i: "\\10 \\11 \\12 \\13 ", |
michael@0 | 113 | s: "\\10 \\11 \\12 \\13 " }, |
michael@0 | 114 | { t: "\\\x14\\\x15\\\x16\\\x17", i: "\\14 \\15 \\16 \\17 ", |
michael@0 | 115 | s: "\\14 \\15 \\16 \\17 " }, |
michael@0 | 116 | { t: "\\\x18\\\x19\\\x1A\\\x1B", i: "\\18 \\19 \\1A \\1B ", |
michael@0 | 117 | s: "\\18 \\19 \\1A \\1B " }, |
michael@0 | 118 | { t: "\\\x1C\\\x1D\\\x1E\\\x1F\\ ", i: "\\1C \\1D \\1E \\1F \\ ", |
michael@0 | 119 | s: "\\1C \\1D \\1E \\1F " }, |
michael@0 | 120 | |
michael@0 | 121 | // U+007F (DELETE) and U+0080 - U+009F (C1 controls) |
michael@0 | 122 | { t: "\\\x7f\\\x80\\\x81\\\x82", i: "\\7F \\80 \\81 \\82 ", |
michael@0 | 123 | s: "\\7F \\80 \\81 \\82 " }, |
michael@0 | 124 | { t: "\\\x83\\\x84\\\x85\\\x86", i: "\\83 \\84 \\85 \\86 ", |
michael@0 | 125 | s: "\\83 \\84 \\85 \\86 " }, |
michael@0 | 126 | { t: "\\\x87\\\x88\\\x89\\\x8A", i: "\\87 \\88 \\89 \\8A ", |
michael@0 | 127 | s: "\\87 \\88 \\89 \\8A " }, |
michael@0 | 128 | { t: "\\\x8B\\\x8C\\\x8D\\\x8E", i: "\\8B \\8C \\8D \\8E ", |
michael@0 | 129 | s: "\\8B \\8C \\8D \\8E " }, |
michael@0 | 130 | { t: "\\\x8F\\\x90\\\x91\\\x92", i: "\\8F \\90 \\91 \\92 ", |
michael@0 | 131 | s: "\\8F \\90 \\91 \\92 " }, |
michael@0 | 132 | { t: "\\\x93\\\x94\\\x95\\\x96", i: "\\93 \\94 \\95 \\96 ", |
michael@0 | 133 | s: "\\93 \\94 \\95 \\96 " }, |
michael@0 | 134 | { t: "\\\x97\\\x98\\\x99\\\x9A", i: "\\97 \\98 \\99 \\9A ", |
michael@0 | 135 | s: "\\97 \\98 \\99 \\9A " }, |
michael@0 | 136 | { t: "\\\x9B\\\x9C\\\x9D\\\x9E\\\x9F", i: "\\9B \\9C \\9D \\9E \\9F ", |
michael@0 | 137 | s: "\\9B \\9C \\9D \\9E \\9F " }, |
michael@0 | 138 | |
michael@0 | 139 | // CSS doesn't bother with the full Unicode rules for identifiers, |
michael@0 | 140 | // instead declaring that any code point greater than or equal to |
michael@0 | 141 | // U+00A0 is a valid identifier character. Test a small handful |
michael@0 | 142 | // of both basic and astral plane characters. |
michael@0 | 143 | |
michael@0 | 144 | // Arabic (caution to editors: there is a possibly-invisible U+200E |
michael@0 | 145 | // LEFT-TO-RIGHT MARK in each string, just before the close quote) |
michael@0 | 146 | { t: "أبجدهوزحطيكلمنسعفصقرشتثخذضظغ", |
michael@0 | 147 | i: "أبجدهوزحطيكلمنسعفصقرشتثخذضظغ", |
michael@0 | 148 | s: "أبجدهوزحطيكلمنسعفصقرشتثخذضظغ" }, |
michael@0 | 149 | |
michael@0 | 150 | // Box drawing |
michael@0 | 151 | { t: "─│┌┐└┘├┤┬┴┼╭╮╯╰╴╵╶╷", |
michael@0 | 152 | i: "─│┌┐└┘├┤┬┴┼╭╮╯╰╴╵╶╷", |
michael@0 | 153 | s: "─│┌┐└┘├┤┬┴┼╭╮╯╰╴╵╶╷" }, |
michael@0 | 154 | |
michael@0 | 155 | // CJK Unified Ideographs |
michael@0 | 156 | { t: "一丁丂七丄丅丆万丈三上下丌不与丏", |
michael@0 | 157 | i: "一丁丂七丄丅丆万丈三上下丌不与丏", |
michael@0 | 158 | s: "一丁丂七丄丅丆万丈三上下丌不与丏" }, |
michael@0 | 159 | |
michael@0 | 160 | // CJK Unified Ideographs Extension B (astral) |
michael@0 | 161 | { t: "𠀀𠀁𠀂𠀃𠀄𠀅𠀆𠀇𠀈𠀉𠀊𠀋𠀌𠀍𠀎𠀏", |
michael@0 | 162 | i: "𠀀𠀁𠀂𠀃𠀄𠀅𠀆𠀇𠀈𠀉𠀊𠀋𠀌𠀍𠀎𠀏", |
michael@0 | 163 | s: "𠀀𠀁𠀂𠀃𠀄𠀅𠀆𠀇𠀈𠀉𠀊𠀋𠀌𠀍𠀎𠀏" }, |
michael@0 | 164 | |
michael@0 | 165 | // Devanagari |
michael@0 | 166 | { t: "कखगघङचछजझञटठडढणतथदधनपफबभमयरलळवशषसह", |
michael@0 | 167 | i: "कखगघङचछजझञटठडढणतथदधनपफबभमयरलळवशषसह", |
michael@0 | 168 | s: "कखगघङचछजझञटठडढणतथदधनपफबभमयरलळवशषसह" }, |
michael@0 | 169 | |
michael@0 | 170 | // Emoticons (astral) |
michael@0 | 171 | { t: "😁😂😃😄😅😆😇😈😉😊😋😌😍😎😏😐", |
michael@0 | 172 | i: "😁😂😃😄😅😆😇😈😉😊😋😌😍😎😏😐", |
michael@0 | 173 | s: "😁😂😃😄😅😆😇😈😉😊😋😌😍😎😏😐" }, |
michael@0 | 174 | |
michael@0 | 175 | // Greek |
michael@0 | 176 | { t: "αβγδεζηθικλμνξοπρςστυφχψω", |
michael@0 | 177 | i: "αβγδεζηθικλμνξοπρςστυφχψω", |
michael@0 | 178 | s: "αβγδεζηθικλμνξοπρςστυφχψω" } |
michael@0 | 179 | ]; |
michael@0 | 180 | |
michael@0 | 181 | const npatterns = patterns.length; |
michael@0 | 182 | const nsubstitutions = substitutions.length; |
michael@0 | 183 | |
michael@0 | 184 | function quotemeta(str) { |
michael@0 | 185 | return str.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&"); |
michael@0 | 186 | } |
michael@0 | 187 | function subst(str, sub) { |
michael@0 | 188 | return str.replace("<t>", sub.t) |
michael@0 | 189 | .replace("<i>", sub.i) |
michael@0 | 190 | .replace("<s>", sub.s); |
michael@0 | 191 | } |
michael@0 | 192 | |
michael@0 | 193 | var curpat = 0; |
michael@0 | 194 | var cursubst = -1; |
michael@0 | 195 | var testbench = document.getElementById("testbench"); |
michael@0 | 196 | |
michael@0 | 197 | function nextTest() { |
michael@0 | 198 | cursubst++; |
michael@0 | 199 | if (cursubst == nsubstitutions) { |
michael@0 | 200 | curpat++; |
michael@0 | 201 | cursubst = 0; |
michael@0 | 202 | } |
michael@0 | 203 | if (curpat == npatterns) { |
michael@0 | 204 | SimpleTest.finish(); |
michael@0 | 205 | return; |
michael@0 | 206 | } |
michael@0 | 207 | |
michael@0 | 208 | let css = subst(patterns[curpat].i, substitutions[cursubst]); |
michael@0 | 209 | let msg = quotemeta(subst(patterns[curpat].o, substitutions[cursubst])); |
michael@0 | 210 | |
michael@0 | 211 | SimpleTest.expectConsoleMessages(function () { testbench.innerHTML = css }, |
michael@0 | 212 | [{ errorMessage: new RegExp(msg) }], |
michael@0 | 213 | nextTest); |
michael@0 | 214 | } |
michael@0 | 215 | |
michael@0 | 216 | SimpleTest.waitForExplicitFinish(); |
michael@0 | 217 | nextTest(); |
michael@0 | 218 | </script> |
michael@0 | 219 | </body> |
michael@0 | 220 | </html> |