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