Completed
Push — master ( efb5c5...a5da08 )
by Daniel
09:31
created

ConvertTest::testBase64url()   B

Complexity

Conditions 1
Paths 1

Size

Total Lines 37
Code Lines 24

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 24
nc 1
nop 0
dl 0
loc 37
rs 8.8571
c 0
b 0
f 0
1
<?php
2
3
namespace SilverStripe\Core\Tests;
4
5
use SilverStripe\Core\Convert;
6
use SilverStripe\Dev\SapphireTest;
7
use SilverStripe\View\Parsers\URLSegmentFilter;
8
use stdClass;
9
use Exception;
10
use InvalidArgumentException;
11
12
/**
13
 * Test various functions on the {@link Convert} class.
14
 */
15
class ConvertTest extends SapphireTest
16
{
17
18
    protected $usesDatabase = false;
19
20
    /**
21
     * Tests {@link Convert::raw2att()}
22
     */
23
    public function testRaw2Att()
24
    {
25
        $val1 = '<input type="text">';
26
        $this->assertEquals(
27
            '&lt;input type=&quot;text&quot;&gt;',
28
            Convert::raw2att($val1),
29
            'Special characters are escaped'
30
        );
31
32
        $val2 = 'This is some normal text.';
33
        $this->assertEquals(
34
            'This is some normal text.',
35
            Convert::raw2att($val2),
36
            'Normal text is not escaped'
37
        );
38
    }
39
40
    /**
41
     * Tests {@link Convert::raw2htmlatt()}
42
     */
43
    public function testRaw2HtmlAtt()
44
    {
45
        $val1 = '<input type="text">';
46
        $this->assertEquals(
47
            '&lt;input type=&quot;text&quot;&gt;',
48
            Convert::raw2htmlatt($val1),
49
            'Special characters are escaped'
50
        );
51
52
        $val2 = 'This is some normal text.';
53
        $this->assertEquals(
54
            'This is some normal text.',
55
            Convert::raw2htmlatt($val2),
56
            'Normal text is not escaped'
57
        );
58
    }
59
60
    /**
61
     * Tests {@link Convert::html2raw()}
62
     */
63
    public function testHtml2raw()
64
    {
65
        $val1 = 'This has a <strong>strong tag</strong>.';
66
        $this->assertEquals(
67
            'This has a *strong tag*.',
68
            Convert::html2raw($val1),
69
            'Strong tags are replaced with asterisks'
70
        );
71
72
        $val1 = 'This has a <b class="test" style="font-weight: bold">b tag with attributes</b>.';
73
        $this->assertEquals(
74
            'This has a *b tag with attributes*.',
75
            Convert::html2raw($val1),
76
            'B tags with attributes are replaced with asterisks'
77
        );
78
79
        $val2 = 'This has a <strong class="test" style="font-weight: bold">strong tag with attributes</STRONG>.';
80
        $this->assertEquals(
81
            'This has a *strong tag with attributes*.',
82
            Convert::html2raw($val2),
83
            'Strong tags with attributes are replaced with asterisks'
84
        );
85
86
        $val3 = '<script type="application/javascript">Some really nasty javascript here</script>';
87
        $this->assertEquals(
88
            '',
89
            Convert::html2raw($val3),
90
            'Script tags are completely removed'
91
        );
92
93
        $val4 = '<style type="text/css">Some really nasty CSS here</style>';
94
        $this->assertEquals(
95
            '',
96
            Convert::html2raw($val4),
97
            'Style tags are completely removed'
98
        );
99
100
        $val5 = "<script type=\"application/javascript\">Some really nasty\nmultiline javascript here</script>";
101
        $this->assertEquals(
102
            '',
103
            Convert::html2raw($val5),
104
            'Multiline script tags are completely removed'
105
        );
106
107
        $val6 = "<style type=\"text/css\">Some really nasty\nmultiline CSS here</style>";
108
        $this->assertEquals(
109
            '',
110
            Convert::html2raw($val6),
111
            'Multiline style tags are completely removed'
112
        );
113
114
        $val7 = '<p>That&#39;s absolutely correct</p>';
115
        $this->assertEquals(
116
            "That's absolutely correct",
117
            Convert::html2raw($val7),
118
            "Single quotes are decoded correctly"
119
        );
120
121
        $val8 = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor '.
122
          'incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud '.
123
          'exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute '.
124
          'irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla '.
125
          'pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia '.
126
          'deserunt mollit anim id est laborum.';
127
        $this->assertEquals($val8, Convert::html2raw($val8), 'Test long text is unwrapped');
128
        $this->assertEquals(
129
            <<<PHP
130
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed
131
do eiusmod tempor incididunt ut labore et dolore magna
132
aliqua. Ut enim ad minim veniam, quis nostrud exercitation
133
ullamco laboris nisi ut aliquip ex ea commodo consequat.
134
Duis aute irure dolor in reprehenderit in voluptate velit
135
esse cillum dolore eu fugiat nulla pariatur. Excepteur sint
136
occaecat cupidatat non proident, sunt in culpa qui officia
137
deserunt mollit anim id est laborum.
138
PHP
139
            ,
140
            Convert::html2raw($val8, false, 60),
141
            'Test long text is wrapped'
142
        );
143
    }
144
145
    /**
146
     * Tests {@link Convert::raw2xml()}
147
     */
148
    public function testRaw2Xml()
149
    {
150
        $val1 = '<input type="text">';
151
        $this->assertEquals(
152
            '&lt;input type=&quot;text&quot;&gt;',
153
            Convert::raw2xml($val1),
154
            'Special characters are escaped'
155
        );
156
157
        $val2 = 'This is some normal text.';
158
        $this->assertEquals(
159
            'This is some normal text.',
160
            Convert::raw2xml($val2),
161
            'Normal text is not escaped'
162
        );
163
164
        $val3 = "This is test\nNow on a new line.";
165
        $this->assertEquals(
166
            "This is test\nNow on a new line.",
167
            Convert::raw2xml($val3),
168
            'Newlines are retained. They should not be replaced with <br /> as it is not XML valid'
169
        );
170
    }
171
172
    /**
173
     * Tests {@link Convert::raw2htmlid()}
174
     */
175
    public function testRaw2HtmlID()
176
    {
177
        $val1 = 'test test 123';
178
        $this->assertEquals('test_test_123', Convert::raw2htmlid($val1));
179
180
        $val1 = 'test[test][123]';
181
        $this->assertEquals('test_test_123', Convert::raw2htmlid($val1));
182
183
        $val1 = '[test[[test]][123]]';
184
        $this->assertEquals('test_test_123', Convert::raw2htmlid($val1));
185
    }
186
187
    /**
188
     * Tests {@link Convert::xml2raw()}
189
     */
190
    public function testXml2Raw()
191
    {
192
        $val1 = '&lt;input type=&quot;text&quot;&gt;';
193
        $this->assertEquals('<input type="text">', Convert::xml2raw($val1), 'Special characters are escaped');
194
195
        $val2 = 'This is some normal text.';
196
        $this->assertEquals('This is some normal text.', Convert::xml2raw($val2), 'Normal text is not escaped');
197
    }
198
199
    /**
200
     * Tests {@link Convert::xml2raw()}
201
     */
202
    public function testArray2JSON()
203
    {
204
        $val = array(
205
         'Joe' => 'Bloggs',
206
         'Tom' => 'Jones',
207
         'My' => array(
208
          'Complicated' => 'Structure'
209
         )
210
        );
211
        $encoded = Convert::array2json($val);
212
        $this->assertEquals(
213
            '{"Joe":"Bloggs","Tom":"Jones","My":{"Complicated":"Structure"}}',
214
            $encoded,
215
            'Array is encoded in JSON'
216
        );
217
    }
218
219
    /**
220
     * Tests {@link Convert::json2array()}
221
     */
222
    public function testJSON2Array()
223
    {
224
        $val = '{"Joe":"Bloggs","Tom":"Jones","My":{"Complicated":"Structure"}}';
225
        $decoded = Convert::json2array($val);
226
        $this->assertEquals(3, count($decoded), '3 items in the decoded array');
227
        $this->assertContains('Bloggs', $decoded, 'Contains "Bloggs" value in decoded array');
228
        $this->assertContains('Jones', $decoded, 'Contains "Jones" value in decoded array');
229
        $this->assertContains('Structure', $decoded['My']['Complicated']);
230
    }
231
232
    /**
233
     * Tests {@link Convert::testJSON2Obj()}
234
     */
235
    public function testJSON2Obj()
236
    {
237
        $val = '{"Joe":"Bloggs","Tom":"Jones","My":{"Complicated":"Structure"}}';
238
        $obj = Convert::json2obj($val);
239
        $this->assertEquals('Bloggs', $obj->Joe);
240
        $this->assertEquals('Jones', $obj->Tom);
241
        $this->assertEquals('Structure', $obj->My->Complicated);
242
    }
243
244
    /**
245
     * Tests {@link Convert::testRaw2URL()}
246
  *
247
     * @todo test toASCII()
248
     */
249
    public function testRaw2URL()
250
    {
251
        URLSegmentFilter::config()->update('default_allow_multibyte', false);
252
        $this->assertEquals('foo', Convert::raw2url('foo'));
253
        $this->assertEquals('foo-and-bar', Convert::raw2url('foo & bar'));
254
        $this->assertEquals('foo-and-bar', Convert::raw2url('foo &amp; bar!'));
255
        $this->assertEquals('foos-bar-2', Convert::raw2url('foo\'s [bar] (2)'));
256
    }
257
258
    /**
259
     * Helper function for comparing characters with significant whitespaces
260
  *
261
     * @param string $expected
262
     * @param string $actual
263
     */
264
    protected function assertEqualsQuoted($expected, $actual)
265
    {
266
        $message = sprintf(
267
            "Expected \"%s\" but given \"%s\"",
268
            addcslashes($expected, "\r\n"),
269
            addcslashes($actual, "\r\n")
270
        );
271
        $this->assertEquals($expected, $actual, $message);
272
    }
273
274
    /**
275
     * Tests {@link Convert::nl2os()}
276
     */
277
    public function testNL2OS()
278
    {
279
280
        foreach (array("\r\n", "\r", "\n") as $nl) {
281
            // Base case: no action
282
            $this->assertEqualsQuoted(
283
                "Base case",
284
                Convert::nl2os("Base case", $nl)
285
            );
286
287
            // Mixed formats
288
            $this->assertEqualsQuoted(
289
                "Test{$nl}Text{$nl}Is{$nl}{$nl}Here{$nl}.",
290
                Convert::nl2os("Test\rText\r\nIs\n\rHere\r\n.", $nl)
291
            );
292
293
            // Test that multiple runs are non-destructive
294
            $expected = "Test{$nl}Text{$nl}Is{$nl}{$nl}Here{$nl}.";
295
            $this->assertEqualsQuoted(
296
                $expected,
297
                Convert::nl2os($expected, $nl)
298
            );
299
300
            // Check repeated sequence behaves correctly
301
            $expected = "{$nl}{$nl}{$nl}{$nl}{$nl}{$nl}{$nl}{$nl}";
302
            $input = "\r\r\n\r\r\n\n\n\n\r";
303
            $this->assertEqualsQuoted(
304
                $expected,
305
                Convert::nl2os($input, $nl)
306
            );
307
        }
308
    }
309
310
    /**
311
     * Tests {@link Convert::raw2js()}
312
     */
313
    public function testRaw2JS()
314
    {
315
        // Test attempt to break out of string
316
        $this->assertEquals(
317
            '\\"; window.location=\\"http://www.google.com',
318
            Convert::raw2js('"; window.location="http://www.google.com')
319
        );
320
        $this->assertEquals(
321
            '\\\'; window.location=\\\'http://www.google.com',
322
            Convert::raw2js('\'; window.location=\'http://www.google.com')
323
        );
324
        // Test attempt to close script tag
325
        $this->assertEquals(
326
            '\\"; \\x3c/script\\x3e\\x3ch1\\x3eHa \\x26amp; Ha\\x3c/h1\\x3e\\x3cscript\\x3e',
327
            Convert::raw2js('"; </script><h1>Ha &amp; Ha</h1><script>')
328
        );
329
        // Test newlines are properly escaped
330
        $this->assertEquals(
331
            'New\\nLine\\rReturn',
332
            Convert::raw2js("New\nLine\rReturn")
333
        );
334
        // Check escape of slashes
335
        $this->assertEquals(
336
            '\\\\\\"\\x3eClick here',
337
            Convert::raw2js('\\">Click here')
338
        );
339
    }
340
341
    /**
342
     * Tests {@link Convert::raw2json()}
343
     */
344
    public function testRaw2JSON()
345
    {
346
347
        // Test object
348
        $input = new stdClass();
349
        $input->Title = 'My Object';
350
        $input->Content = '<p>Data</p>';
351
        $this->assertEquals(
352
            '{"Title":"My Object","Content":"<p>Data<\/p>"}',
353
            Convert::raw2json($input)
354
        );
355
356
        // Array
357
        $array = array('One' => 'Apple', 'Two' => 'Banana');
358
        $this->assertEquals(
359
            '{"One":"Apple","Two":"Banana"}',
360
            Convert::raw2json($array)
361
        );
362
363
        // String value with already encoded data. Result should be quoted.
364
        $value = '{"Left": "Value"}';
365
        $this->assertEquals(
366
            '"{\\"Left\\": \\"Value\\"}"',
367
            Convert::raw2json($value)
368
        );
369
    }
370
371
    /**
372
     * Test that a context bitmask can be passed through to the json_encode method in {@link Convert::raw2json()}
373
     * and in {@link Convert::array2json()}
374
     */
375
    public function testRaw2JsonWithContext()
376
    {
377
        $data = array('foo' => 'b"ar');
378
        $expected = '{"foo":"b\u0022ar"}';
379
        $result = Convert::raw2json($data, JSON_HEX_QUOT);
380
        $this->assertSame($expected, $result);
381
        $wrapperResult = Convert::array2json($data, JSON_HEX_QUOT);
382
        $this->assertSame($expected, $wrapperResult);
383
    }
384
385
    /**
386
     * Tests {@link Convert::xml2array()}
387
     */
388
    public function testXML2Array()
389
    {
390
        // Ensure an XML file at risk of entity expansion can be avoided safely
391
        $inputXML = <<<XML
392
<?xml version="1.0"?>
393
<!DOCTYPE results [<!ENTITY long "SOME_SUPER_LONG_STRING">]>
394
<results>
395
    <result>Now include &long; lots of times to expand the in-memory size of this XML structure</result>
396
    <result>&long;&long;&long;</result>
397
</results>
398
XML
399
         ;
400
        try {
401
            Convert::xml2array($inputXML, true);
402
        } catch (Exception $ex) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
403
        }
404
        $this->assertTrue(
405
            isset($ex)
406
            && $ex instanceof InvalidArgumentException
407
            && $ex->getMessage() === 'XML Doctype parsing disabled'
408
        );
409
410
        // Test without doctype validation
411
        $expected = array(
412
         'result' => array(
413
          "Now include SOME_SUPER_LONG_STRING lots of times to expand the in-memory size of this XML structure",
414
          array(
415
        'long' => array(
416
         array(
417
          'long' => 'SOME_SUPER_LONG_STRING'
418
         ),
419
         array(
420
          'long' => 'SOME_SUPER_LONG_STRING'
421
         ),
422
         array(
423
          'long' => 'SOME_SUPER_LONG_STRING'
424
         )
425
           )
426
          )
427
         )
428
        );
429
        $result = Convert::xml2array($inputXML, false, true);
430
        $this->assertEquals(
431
            $expected,
432
            $result
433
        );
434
        $result = Convert::xml2array($inputXML, false, false);
435
        $this->assertEquals(
436
            $expected,
437
            $result
438
        );
439
    }
440
441
    /**
442
     * Tests {@link Convert::base64url_encode()} and {@link Convert::base64url_decode()}
443
     */
444
    public function testBase64url()
445
    {
446
        $data = 'Wëīrð characters ☺ such as ¤Ø¶÷╬';
447
        // This requires this test file to have UTF-8 character encoding
448
        $this->assertEquals(
449
            $data,
450
            Convert::base64url_decode(Convert::base64url_encode($data))
451
        );
452
453
        $data = 654.423;
454
        $this->assertEquals(
455
            $data,
456
            Convert::base64url_decode(Convert::base64url_encode($data))
457
        );
458
459
        $data = true;
460
        $this->assertEquals(
461
            $data,
462
            Convert::base64url_decode(Convert::base64url_encode($data))
463
        );
464
465
        $data = array('simple','array','¤Ø¶÷╬');
466
        $this->assertEquals(
467
            $data,
468
            Convert::base64url_decode(Convert::base64url_encode($data))
469
        );
470
471
        $data = array(
472
         'a'  => 'associative',
473
         4    => 'array',
474
         '☺' => '¤Ø¶÷╬'
475
        );
476
        $this->assertEquals(
477
            $data,
478
            Convert::base64url_decode(Convert::base64url_encode($data))
479
        );
480
    }
481
482
    public function testUpperCamelToLowerCamel()
483
    {
484
        $this->assertEquals(
485
            'd',
486
            Convert::upperCamelToLowerCamel('D'),
487
            'Single character'
488
        );
489
        $this->assertEquals(
490
            'id',
491
            Convert::upperCamelToLowerCamel('ID'),
492
            'Multi leading upper without trailing lower'
493
        );
494
        $this->assertEquals(
495
            'id',
496
            Convert::upperCamelToLowerCamel('Id'),
497
            'Single leading upper with trailing lower'
498
        );
499
        $this->assertEquals(
500
            'idField',
501
            Convert::upperCamelToLowerCamel('IdField'),
502
            'Single leading upper with trailing upper camel'
503
        );
504
        $this->assertEquals(
505
            'idField',
506
            Convert::upperCamelToLowerCamel('IDField'),
507
            'Multi leading upper with trailing upper camel'
508
        );
509
        $this->assertEquals(
510
            'iDField',
511
            Convert::upperCamelToLowerCamel('iDField'),
512
            'Single leading lower with trailing upper camel'
513
        );
514
        $this->assertEquals(
515
            '_IDField',
516
            Convert::upperCamelToLowerCamel('_IDField'),
517
            'Non-alpha leading  with trailing upper camel'
518
        );
519
    }
520
}
521