Browse code

moved tests

Fabien Potencier authored on 21/05/2019 13:36:37
Showing 2 changed files
... ...
@@ -16,6 +16,326 @@ use Twig\Loader\LoaderInterface;
16 16
 class Twig_Tests_Extension_EscaperTest extends \PHPUnit\Framework\TestCase
17 17
 {
18 18
     /**
19
+     * All character encodings supported by htmlspecialchars().
20
+     */
21
+    protected $htmlSpecialChars = [
22
+        '\'' => ''',
23
+        '"' => '"',
24
+        '<' => '&lt;',
25
+        '>' => '&gt;',
26
+        '&' => '&amp;',
27
+    ];
28
+
29
+    protected $htmlAttrSpecialChars = [
30
+        '\'' => '&#x27;',
31
+        /* Characters beyond ASCII value 255 to unicode escape */
32
+        'Ā' => '&#x0100;',
33
+        '😀' => '&#x1F600;',
34
+        /* Immune chars excluded */
35
+        ',' => ',',
36
+        '.' => '.',
37
+        '-' => '-',
38
+        '_' => '_',
39
+        /* Basic alnums excluded */
40
+        'a' => 'a',
41
+        'A' => 'A',
42
+        'z' => 'z',
43
+        'Z' => 'Z',
44
+        '0' => '0',
45
+        '9' => '9',
46
+        /* Basic control characters and null */
47
+        "\r" => '&#x0D;',
48
+        "\n" => '&#x0A;',
49
+        "\t" => '&#x09;',
50
+        "\0" => '&#xFFFD;', // should use Unicode replacement char
51
+        /* Encode chars as named entities where possible */
52
+        '<' => '&lt;',
53
+        '>' => '&gt;',
54
+        '&' => '&amp;',
55
+        '"' => '&quot;',
56
+        /* Encode spaces for quoteless attribute protection */
57
+        ' ' => '&#x20;',
58
+    ];
59
+
60
+    protected $jsSpecialChars = [
61
+        /* HTML special chars - escape without exception to hex */
62
+        '<' => '\\u003C',
63
+        '>' => '\\u003E',
64
+        '\'' => '\\u0027',
65
+        '"' => '\\u0022',
66
+        '&' => '\\u0026',
67
+        '/' => '\\/',
68
+        /* Characters beyond ASCII value 255 to unicode escape */
69
+        'Ā' => '\\u0100',
70
+        '😀' => '\\uD83D\\uDE00',
71
+        /* Immune chars excluded */
72
+        ',' => ',',
73
+        '.' => '.',
74
+        '_' => '_',
75
+        /* Basic alnums excluded */
76
+        'a' => 'a',
77
+        'A' => 'A',
78
+        'z' => 'z',
79
+        'Z' => 'Z',
80
+        '0' => '0',
81
+        '9' => '9',
82
+        /* Basic control characters and null */
83
+        "\r" => '\r',
84
+        "\n" => '\n',
85
+        "\x08" => '\b',
86
+        "\t" => '\t',
87
+        "\x0C" => '\f',
88
+        "\0" => '\\u0000',
89
+        /* Encode spaces for quoteless attribute protection */
90
+        ' ' => '\\u0020',
91
+    ];
92
+
93
+    protected $urlSpecialChars = [
94
+        /* HTML special chars - escape without exception to percent encoding */
95
+        '<' => '%3C',
96
+        '>' => '%3E',
97
+        '\'' => '%27',
98
+        '"' => '%22',
99
+        '&' => '%26',
100
+        /* Characters beyond ASCII value 255 to hex sequence */
101
+        'Ā' => '%C4%80',
102
+        /* Punctuation and unreserved check */
103
+        ',' => '%2C',
104
+        '.' => '.',
105
+        '_' => '_',
106
+        '-' => '-',
107
+        ':' => '%3A',
108
+        ';' => '%3B',
109
+        '!' => '%21',
110
+        /* Basic alnums excluded */
111
+        'a' => 'a',
112
+        'A' => 'A',
113
+        'z' => 'z',
114
+        'Z' => 'Z',
115
+        '0' => '0',
116
+        '9' => '9',
117
+        /* Basic control characters and null */
118
+        "\r" => '%0D',
119
+        "\n" => '%0A',
120
+        "\t" => '%09',
121
+        "\0" => '%00',
122
+        /* PHP quirks from the past */
123
+        ' ' => '%20',
124
+        '~' => '~',
125
+        '+' => '%2B',
126
+    ];
127
+
128
+    protected $cssSpecialChars = [
129
+        /* HTML special chars - escape without exception to hex */
130
+        '<' => '\\3C ',
131
+        '>' => '\\3E ',
132
+        '\'' => '\\27 ',
133
+        '"' => '\\22 ',
134
+        '&' => '\\26 ',
135
+        /* Characters beyond ASCII value 255 to unicode escape */
136
+        'Ā' => '\\100 ',
137
+        /* Immune chars excluded */
138
+        ',' => '\\2C ',
139
+        '.' => '\\2E ',
140
+        '_' => '\\5F ',
141
+        /* Basic alnums excluded */
142
+        'a' => 'a',
143
+        'A' => 'A',
144
+        'z' => 'z',
145
+        'Z' => 'Z',
146
+        '0' => '0',
147
+        '9' => '9',
148
+        /* Basic control characters and null */
149
+        "\r" => '\\D ',
150
+        "\n" => '\\A ',
151
+        "\t" => '\\9 ',
152
+        "\0" => '\\0 ',
153
+        /* Encode spaces for quoteless attribute protection */
154
+        ' ' => '\\20 ',
155
+    ];
156
+
157
+    public function testHtmlEscapingConvertsSpecialChars()
158
+    {
159
+        $twig = new \Twig\Environment($this->getMockBuilder(\Twig\Loader\LoaderInterface::class)->getMock());
160
+        foreach ($this->htmlSpecialChars as $key => $value) {
161
+            $this->assertEquals($value, twig_escape_filter($twig, $key, 'html'), 'Failed to escape: '.$key);
162
+        }
163
+    }
164
+
165
+    public function testHtmlAttributeEscapingConvertsSpecialChars()
166
+    {
167
+        $twig = new \Twig\Environment($this->getMockBuilder(\Twig\Loader\LoaderInterface::class)->getMock());
168
+        foreach ($this->htmlAttrSpecialChars as $key => $value) {
169
+            $this->assertEquals($value, twig_escape_filter($twig, $key, 'html_attr'), 'Failed to escape: '.$key);
170
+        }
171
+    }
172
+
173
+    public function testJavascriptEscapingConvertsSpecialChars()
174
+    {
175
+        $twig = new \Twig\Environment($this->getMockBuilder(\Twig\Loader\LoaderInterface::class)->getMock());
176
+        foreach ($this->jsSpecialChars as $key => $value) {
177
+            $this->assertEquals($value, twig_escape_filter($twig, $key, 'js'), 'Failed to escape: '.$key);
178
+        }
179
+    }
180
+
181
+    public function testJavascriptEscapingReturnsStringIfZeroLength()
182
+    {
183
+        $twig = new \Twig\Environment($this->getMockBuilder(\Twig\Loader\LoaderInterface::class)->getMock());
184
+        $this->assertEquals('', twig_escape_filter($twig, '', 'js'));
185
+    }
186
+
187
+    public function testJavascriptEscapingReturnsStringIfContainsOnlyDigits()
188
+    {
189
+        $twig = new \Twig\Environment($this->getMockBuilder(\Twig\Loader\LoaderInterface::class)->getMock());
190
+        $this->assertEquals('123', twig_escape_filter($twig, '123', 'js'));
191
+    }
192
+
193
+    public function testCssEscapingConvertsSpecialChars()
194
+    {
195
+        $twig = new \Twig\Environment($this->getMockBuilder(\Twig\Loader\LoaderInterface::class)->getMock());
196
+        foreach ($this->cssSpecialChars as $key => $value) {
197
+            $this->assertEquals($value, twig_escape_filter($twig, $key, 'css'), 'Failed to escape: '.$key);
198
+        }
199
+    }
200
+
201
+    public function testCssEscapingReturnsStringIfZeroLength()
202
+    {
203
+        $twig = new \Twig\Environment($this->getMockBuilder(\Twig\Loader\LoaderInterface::class)->getMock());
204
+        $this->assertEquals('', twig_escape_filter($twig, '', 'css'));
205
+    }
206
+
207
+    public function testCssEscapingReturnsStringIfContainsOnlyDigits()
208
+    {
209
+        $twig = new \Twig\Environment($this->getMockBuilder(\Twig\Loader\LoaderInterface::class)->getMock());
210
+        $this->assertEquals('123', twig_escape_filter($twig, '123', 'css'));
211
+    }
212
+
213
+    public function testUrlEscapingConvertsSpecialChars()
214
+    {
215
+        $twig = new \Twig\Environment($this->getMockBuilder(\Twig\Loader\LoaderInterface::class)->getMock());
216
+        foreach ($this->urlSpecialChars as $key => $value) {
217
+            $this->assertEquals($value, twig_escape_filter($twig, $key, 'url'), 'Failed to escape: '.$key);
218
+        }
219
+    }
220
+
221
+    /**
222
+     * Range tests to confirm escaped range of characters is within OWASP recommendation.
223
+     */
224
+
225
+    /**
226
+     * Only testing the first few 2 ranges on this prot. function as that's all these
227
+     * other range tests require.
228
+     */
229
+    public function testUnicodeCodepointConversionToUtf8()
230
+    {
231
+        $expected = ' ~ޙ';
232
+        $codepoints = [0x20, 0x7e, 0x799];
233
+        $result = '';
234
+        foreach ($codepoints as $value) {
235
+            $result .= $this->codepointToUtf8($value);
236
+        }
237
+        $this->assertEquals($expected, $result);
238
+    }
239
+
240
+    /**
241
+     * Convert a Unicode Codepoint to a literal UTF-8 character.
242
+     *
243
+     * @param int $codepoint Unicode codepoint in hex notation
244
+     *
245
+     * @return string UTF-8 literal string
246
+     */
247
+    protected function codepointToUtf8($codepoint)
248
+    {
249
+        if ($codepoint < 0x80) {
250
+            return \chr($codepoint);
251
+        }
252
+        if ($codepoint < 0x800) {
253
+            return \chr($codepoint >> 6 & 0x3f | 0xc0)
254
+                .\chr($codepoint & 0x3f | 0x80);
255
+        }
256
+        if ($codepoint < 0x10000) {
257
+            return \chr($codepoint >> 12 & 0x0f | 0xe0)
258
+                .\chr($codepoint >> 6 & 0x3f | 0x80)
259
+                .\chr($codepoint & 0x3f | 0x80);
260
+        }
261
+        if ($codepoint < 0x110000) {
262
+            return \chr($codepoint >> 18 & 0x07 | 0xf0)
263
+                .\chr($codepoint >> 12 & 0x3f | 0x80)
264
+                .\chr($codepoint >> 6 & 0x3f | 0x80)
265
+                .\chr($codepoint & 0x3f | 0x80);
266
+        }
267
+        throw new \Exception('Codepoint requested outside of Unicode range.');
268
+    }
269
+
270
+    public function testJavascriptEscapingEscapesOwaspRecommendedRanges()
271
+    {
272
+        $twig = new \Twig\Environment($this->getMockBuilder(\Twig\Loader\LoaderInterface::class)->getMock());
273
+        $immune = [',', '.', '_']; // Exceptions to escaping ranges
274
+        for ($chr = 0; $chr < 0xFF; ++$chr) {
275
+            if ($chr >= 0x30 && $chr <= 0x39
276
+            || $chr >= 0x41 && $chr <= 0x5A
277
+            || $chr >= 0x61 && $chr <= 0x7A) {
278
+                $literal = $this->codepointToUtf8($chr);
279
+                $this->assertEquals($literal, twig_escape_filter($twig, $literal, 'js'));
280
+            } else {
281
+                $literal = $this->codepointToUtf8($chr);
282
+                if (\in_array($literal, $immune)) {
283
+                    $this->assertEquals($literal, twig_escape_filter($twig, $literal, 'js'));
284
+                } else {
285
+                    $this->assertNotEquals(
286
+                        $literal,
287
+                        twig_escape_filter($twig, $literal, 'js'),
288
+                        "$literal should be escaped!");
289
+                }
290
+            }
291
+        }
292
+    }
293
+
294
+    public function testHtmlAttributeEscapingEscapesOwaspRecommendedRanges()
295
+    {
296
+        $twig = new \Twig\Environment($this->getMockBuilder(\Twig\Loader\LoaderInterface::class)->getMock());
297
+        $immune = [',', '.', '-', '_']; // Exceptions to escaping ranges
298
+        for ($chr = 0; $chr < 0xFF; ++$chr) {
299
+            if ($chr >= 0x30 && $chr <= 0x39
300
+            || $chr >= 0x41 && $chr <= 0x5A
301
+            || $chr >= 0x61 && $chr <= 0x7A) {
302
+                $literal = $this->codepointToUtf8($chr);
303
+                $this->assertEquals($literal, twig_escape_filter($twig, $literal, 'html_attr'));
304
+            } else {
305
+                $literal = $this->codepointToUtf8($chr);
306
+                if (\in_array($literal, $immune)) {
307
+                    $this->assertEquals($literal, twig_escape_filter($twig, $literal, 'html_attr'));
308
+                } else {
309
+                    $this->assertNotEquals(
310
+                        $literal,
311
+                        twig_escape_filter($twig, $literal, 'html_attr'),
312
+                        "$literal should be escaped!");
313
+                }
314
+            }
315
+        }
316
+    }
317
+
318
+    public function testCssEscapingEscapesOwaspRecommendedRanges()
319
+    {
320
+        $twig = new \Twig\Environment($this->getMockBuilder(\Twig\Loader\LoaderInterface::class)->getMock());
321
+        // CSS has no exceptions to escaping ranges
322
+        for ($chr = 0; $chr < 0xFF; ++$chr) {
323
+            if ($chr >= 0x30 && $chr <= 0x39
324
+            || $chr >= 0x41 && $chr <= 0x5A
325
+            || $chr >= 0x61 && $chr <= 0x7A) {
326
+                $literal = $this->codepointToUtf8($chr);
327
+                $this->assertEquals($literal, twig_escape_filter($twig, $literal, 'css'));
328
+            } else {
329
+                $literal = $this->codepointToUtf8($chr);
330
+                $this->assertNotEquals(
331
+                    $literal,
332
+                    twig_escape_filter($twig, $literal, 'css'),
333
+                    "$literal should be escaped!");
334
+            }
335
+        }
336
+    }
337
+
338
+    /**
19 339
      * @dataProvider provideCustomEscaperCases
20 340
      */
21 341
     public function testCustomEscaper($expected, $string, $strategy)
... ...
@@ -44,7 +364,7 @@ class Twig_Tests_Extension_EscaperTest extends \PHPUnit\Framework\TestCase
44 364
     }
45 365
 }
46 366
 
47
-function foo_escaper_for_test(Environment $env, $string, $charset)
367
+function foo_escaper_for_test(Environment $twig, $string, $charset)
48 368
 {
49 369
     return $string.$charset;
50 370
 }
51 371
deleted file mode 100644
... ...
@@ -1,325 +0,0 @@
1
-<?php
2
-
3
-/**
4
- * This class is adapted from code coming from Zend Framework.
5
- *
6
- * @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (https://www.zend.com)
7
- * @license   https://framework.zend.com/license/new-bsd New BSD License
8
- */
9
-class Twig_Test_EscapingTest extends \PHPUnit\Framework\TestCase
10
-{
11
-    /**
12
-     * All character encodings supported by htmlspecialchars().
13
-     */
14
-    protected $htmlSpecialChars = [
15
-        '\'' => '&#039;',
16
-        '"' => '&quot;',
17
-        '<' => '&lt;',
18
-        '>' => '&gt;',
19
-        '&' => '&amp;',
20
-    ];
21
-
22
-    protected $htmlAttrSpecialChars = [
23
-        '\'' => '&#x27;',
24
-        /* Characters beyond ASCII value 255 to unicode escape */
25
-        'Ā' => '&#x0100;',
26
-        '😀' => '&#x1F600;',
27
-        /* Immune chars excluded */
28
-        ',' => ',',
29
-        '.' => '.',
30
-        '-' => '-',
31
-        '_' => '_',
32
-        /* Basic alnums excluded */
33
-        'a' => 'a',
34
-        'A' => 'A',
35
-        'z' => 'z',
36
-        'Z' => 'Z',
37
-        '0' => '0',
38
-        '9' => '9',
39
-        /* Basic control characters and null */
40
-        "\r" => '&#x0D;',
41
-        "\n" => '&#x0A;',
42
-        "\t" => '&#x09;',
43
-        "\0" => '&#xFFFD;', // should use Unicode replacement char
44
-        /* Encode chars as named entities where possible */
45
-        '<' => '&lt;',
46
-        '>' => '&gt;',
47
-        '&' => '&amp;',
48
-        '"' => '&quot;',
49
-        /* Encode spaces for quoteless attribute protection */
50
-        ' ' => '&#x20;',
51
-    ];
52
-
53
-    protected $jsSpecialChars = [
54
-        /* HTML special chars - escape without exception to hex */
55
-        '<' => '\\u003C',
56
-        '>' => '\\u003E',
57
-        '\'' => '\\u0027',
58
-        '"' => '\\u0022',
59
-        '&' => '\\u0026',
60
-        '/' => '\\/',
61
-        /* Characters beyond ASCII value 255 to unicode escape */
62
-        'Ā' => '\\u0100',
63
-        '😀' => '\\uD83D\\uDE00',
64
-        /* Immune chars excluded */
65
-        ',' => ',',
66
-        '.' => '.',
67
-        '_' => '_',
68
-        /* Basic alnums excluded */
69
-        'a' => 'a',
70
-        'A' => 'A',
71
-        'z' => 'z',
72
-        'Z' => 'Z',
73
-        '0' => '0',
74
-        '9' => '9',
75
-        /* Basic control characters and null */
76
-        "\r" => '\r',
77
-        "\n" => '\n',
78
-        "\x08" => '\b',
79
-        "\t" => '\t',
80
-        "\x0C" => '\f',
81
-        "\0" => '\\u0000',
82
-        /* Encode spaces for quoteless attribute protection */
83
-        ' ' => '\\u0020',
84
-    ];
85
-
86
-    protected $urlSpecialChars = [
87
-        /* HTML special chars - escape without exception to percent encoding */
88
-        '<' => '%3C',
89
-        '>' => '%3E',
90
-        '\'' => '%27',
91
-        '"' => '%22',
92
-        '&' => '%26',
93
-        /* Characters beyond ASCII value 255 to hex sequence */
94
-        'Ā' => '%C4%80',
95
-        /* Punctuation and unreserved check */
96
-        ',' => '%2C',
97
-        '.' => '.',
98
-        '_' => '_',
99
-        '-' => '-',
100
-        ':' => '%3A',
101
-        ';' => '%3B',
102
-        '!' => '%21',
103
-        /* Basic alnums excluded */
104
-        'a' => 'a',
105
-        'A' => 'A',
106
-        'z' => 'z',
107
-        'Z' => 'Z',
108
-        '0' => '0',
109
-        '9' => '9',
110
-        /* Basic control characters and null */
111
-        "\r" => '%0D',
112
-        "\n" => '%0A',
113
-        "\t" => '%09',
114
-        "\0" => '%00',
115
-        /* PHP quirks from the past */
116
-        ' ' => '%20',
117
-        '~' => '~',
118
-        '+' => '%2B',
119
-    ];
120
-
121
-    protected $cssSpecialChars = [
122
-        /* HTML special chars - escape without exception to hex */
123
-        '<' => '\\3C ',
124
-        '>' => '\\3E ',
125
-        '\'' => '\\27 ',
126
-        '"' => '\\22 ',
127
-        '&' => '\\26 ',
128
-        /* Characters beyond ASCII value 255 to unicode escape */
129
-        'Ā' => '\\100 ',
130
-        /* Immune chars excluded */
131
-        ',' => '\\2C ',
132
-        '.' => '\\2E ',
133
-        '_' => '\\5F ',
134
-        /* Basic alnums excluded */
135
-        'a' => 'a',
136
-        'A' => 'A',
137
-        'z' => 'z',
138
-        'Z' => 'Z',
139
-        '0' => '0',
140
-        '9' => '9',
141
-        /* Basic control characters and null */
142
-        "\r" => '\\D ',
143
-        "\n" => '\\A ',
144
-        "\t" => '\\9 ',
145
-        "\0" => '\\0 ',
146
-        /* Encode spaces for quoteless attribute protection */
147
-        ' ' => '\\20 ',
148
-    ];
149
-
150
-    protected $env;
151
-
152
-    protected function setUp()
153
-    {
154
-        $this->env = new \Twig\Environment($this->getMockBuilder(\Twig\Loader\LoaderInterface::class)->getMock());
155
-    }
156
-
157
-    public function testHtmlEscapingConvertsSpecialChars()
158
-    {
159
-        foreach ($this->htmlSpecialChars as $key => $value) {
160
-            $this->assertEquals($value, twig_escape_filter($this->env, $key, 'html'), 'Failed to escape: '.$key);
161
-        }
162
-    }
163
-
164
-    public function testHtmlAttributeEscapingConvertsSpecialChars()
165
-    {
166
-        foreach ($this->htmlAttrSpecialChars as $key => $value) {
167
-            $this->assertEquals($value, twig_escape_filter($this->env, $key, 'html_attr'), 'Failed to escape: '.$key);
168
-        }
169
-    }
170
-
171
-    public function testJavascriptEscapingConvertsSpecialChars()
172
-    {
173
-        foreach ($this->jsSpecialChars as $key => $value) {
174
-            $this->assertEquals($value, twig_escape_filter($this->env, $key, 'js'), 'Failed to escape: '.$key);
175
-        }
176
-    }
177
-
178
-    public function testJavascriptEscapingReturnsStringIfZeroLength()
179
-    {
180
-        $this->assertEquals('', twig_escape_filter($this->env, '', 'js'));
181
-    }
182
-
183
-    public function testJavascriptEscapingReturnsStringIfContainsOnlyDigits()
184
-    {
185
-        $this->assertEquals('123', twig_escape_filter($this->env, '123', 'js'));
186
-    }
187
-
188
-    public function testCssEscapingConvertsSpecialChars()
189
-    {
190
-        foreach ($this->cssSpecialChars as $key => $value) {
191
-            $this->assertEquals($value, twig_escape_filter($this->env, $key, 'css'), 'Failed to escape: '.$key);
192
-        }
193
-    }
194
-
195
-    public function testCssEscapingReturnsStringIfZeroLength()
196
-    {
197
-        $this->assertEquals('', twig_escape_filter($this->env, '', 'css'));
198
-    }
199
-
200
-    public function testCssEscapingReturnsStringIfContainsOnlyDigits()
201
-    {
202
-        $this->assertEquals('123', twig_escape_filter($this->env, '123', 'css'));
203
-    }
204
-
205
-    public function testUrlEscapingConvertsSpecialChars()
206
-    {
207
-        foreach ($this->urlSpecialChars as $key => $value) {
208
-            $this->assertEquals($value, twig_escape_filter($this->env, $key, 'url'), 'Failed to escape: '.$key);
209
-        }
210
-    }
211
-
212
-    /**
213
-     * Range tests to confirm escaped range of characters is within OWASP recommendation.
214
-     */
215
-
216
-    /**
217
-     * Only testing the first few 2 ranges on this prot. function as that's all these
218
-     * other range tests require.
219
-     */
220
-    public function testUnicodeCodepointConversionToUtf8()
221
-    {
222
-        $expected = ' ~ޙ';
223
-        $codepoints = [0x20, 0x7e, 0x799];
224
-        $result = '';
225
-        foreach ($codepoints as $value) {
226
-            $result .= $this->codepointToUtf8($value);
227
-        }
228
-        $this->assertEquals($expected, $result);
229
-    }
230
-
231
-    /**
232
-     * Convert a Unicode Codepoint to a literal UTF-8 character.
233
-     *
234
-     * @param int $codepoint Unicode codepoint in hex notation
235
-     *
236
-     * @return string UTF-8 literal string
237
-     */
238
-    protected function codepointToUtf8($codepoint)
239
-    {
240
-        if ($codepoint < 0x80) {
241
-            return \chr($codepoint);
242
-        }
243
-        if ($codepoint < 0x800) {
244
-            return \chr($codepoint >> 6 & 0x3f | 0xc0)
245
-                .\chr($codepoint & 0x3f | 0x80);
246
-        }
247
-        if ($codepoint < 0x10000) {
248
-            return \chr($codepoint >> 12 & 0x0f | 0xe0)
249
-                .\chr($codepoint >> 6 & 0x3f | 0x80)
250
-                .\chr($codepoint & 0x3f | 0x80);
251
-        }
252
-        if ($codepoint < 0x110000) {
253
-            return \chr($codepoint >> 18 & 0x07 | 0xf0)
254
-                .\chr($codepoint >> 12 & 0x3f | 0x80)
255
-                .\chr($codepoint >> 6 & 0x3f | 0x80)
256
-                .\chr($codepoint & 0x3f | 0x80);
257
-        }
258
-        throw new \Exception('Codepoint requested outside of Unicode range.');
259
-    }
260
-
261
-    public function testJavascriptEscapingEscapesOwaspRecommendedRanges()
262
-    {
263
-        $immune = [',', '.', '_']; // Exceptions to escaping ranges
264
-        for ($chr = 0; $chr < 0xFF; ++$chr) {
265
-            if ($chr >= 0x30 && $chr <= 0x39
266
-            || $chr >= 0x41 && $chr <= 0x5A
267
-            || $chr >= 0x61 && $chr <= 0x7A) {
268
-                $literal = $this->codepointToUtf8($chr);
269
-                $this->assertEquals($literal, twig_escape_filter($this->env, $literal, 'js'));
270
-            } else {
271
-                $literal = $this->codepointToUtf8($chr);
272
-                if (\in_array($literal, $immune)) {
273
-                    $this->assertEquals($literal, twig_escape_filter($this->env, $literal, 'js'));
274
-                } else {
275
-                    $this->assertNotEquals(
276
-                        $literal,
277
-                        twig_escape_filter($this->env, $literal, 'js'),
278
-                        "$literal should be escaped!");
279
-                }
280
-            }
281
-        }
282
-    }
283
-
284
-    public function testHtmlAttributeEscapingEscapesOwaspRecommendedRanges()
285
-    {
286
-        $immune = [',', '.', '-', '_']; // Exceptions to escaping ranges
287
-        for ($chr = 0; $chr < 0xFF; ++$chr) {
288
-            if ($chr >= 0x30 && $chr <= 0x39
289
-            || $chr >= 0x41 && $chr <= 0x5A
290
-            || $chr >= 0x61 && $chr <= 0x7A) {
291
-                $literal = $this->codepointToUtf8($chr);
292
-                $this->assertEquals($literal, twig_escape_filter($this->env, $literal, 'html_attr'));
293
-            } else {
294
-                $literal = $this->codepointToUtf8($chr);
295
-                if (\in_array($literal, $immune)) {
296
-                    $this->assertEquals($literal, twig_escape_filter($this->env, $literal, 'html_attr'));
297
-                } else {
298
-                    $this->assertNotEquals(
299
-                        $literal,
300
-                        twig_escape_filter($this->env, $literal, 'html_attr'),
301
-                        "$literal should be escaped!");
302
-                }
303
-            }
304
-        }
305
-    }
306
-
307
-    public function testCssEscapingEscapesOwaspRecommendedRanges()
308
-    {
309
-        // CSS has no exceptions to escaping ranges
310
-        for ($chr = 0; $chr < 0xFF; ++$chr) {
311
-            if ($chr >= 0x30 && $chr <= 0x39
312
-            || $chr >= 0x41 && $chr <= 0x5A
313
-            || $chr >= 0x61 && $chr <= 0x7A) {
314
-                $literal = $this->codepointToUtf8($chr);
315
-                $this->assertEquals($literal, twig_escape_filter($this->env, $literal, 'css'));
316
-            } else {
317
-                $literal = $this->codepointToUtf8($chr);
318
-                $this->assertNotEquals(
319
-                    $literal,
320
-                    twig_escape_filter($this->env, $literal, 'css'),
321
-                    "$literal should be escaped!");
322
-            }
323
-        }
324
-    }
325
-}