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