Passed
Pull Request — 4.10 (#10376)
by Steve
36:32 queued 29:43
created

ConvertTest::testJSON2Array()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 8
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 6
nc 1
nop 0
dl 0
loc 8
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace SilverStripe\Core\Tests;
4
5
use Exception;
6
use InvalidArgumentException;
7
use SilverStripe\Core\Convert;
8
use SilverStripe\Dev\SapphireTest;
9
use SilverStripe\View\Parsers\URLSegmentFilter;
10
use stdClass;
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
    private $previousLocaleSetting = null;
21
22
    protected function setUp(): void
23
    {
24
        parent::setUp();
25
        // clear the previous locale setting
26
        $this->previousLocaleSetting = null;
27
    }
28
29
    protected function tearDown(): void
30
    {
31
        parent::tearDown();
32
        // If a test sets the locale, reset it on teardown
33
        if ($this->previousLocaleSetting) {
34
            setlocale(LC_CTYPE, $this->previousLocaleSetting);
35
        }
36
    }
37
38
    /**
39
     * Tests {@link Convert::raw2att()}
40
     */
41
    public function testRaw2Att()
42
    {
43
        $val1 = '<input type="text">';
44
        $this->assertEquals(
45
            '&lt;input type=&quot;text&quot;&gt;',
46
            Convert::raw2att($val1),
47
            'Special characters are escaped'
48
        );
49
50
        $val2 = 'This is some normal text.';
51
        $this->assertEquals(
52
            'This is some normal text.',
53
            Convert::raw2att($val2),
54
            'Normal text is not escaped'
55
        );
56
    }
57
58
    /**
59
     * Tests {@link Convert::raw2htmlatt()}
60
     */
61
    public function testRaw2HtmlAtt()
62
    {
63
        $val1 = '<input type="text">';
64
        $this->assertEquals(
65
            '&lt;input type=&quot;text&quot;&gt;',
66
            Convert::raw2htmlatt($val1),
67
            'Special characters are escaped'
68
        );
69
70
        $val2 = 'This is some normal text.';
71
        $this->assertEquals(
72
            'This is some normal text.',
73
            Convert::raw2htmlatt($val2),
74
            'Normal text is not escaped'
75
        );
76
    }
77
78
    /**
79
     * Tests {@link Convert::html2raw()}
80
     */
81
    public function testHtml2raw()
82
    {
83
        $val1 = 'This has a <strong>strong tag</strong>.';
84
        $this->assertEquals(
85
            'This has a *strong tag*.',
86
            Convert::html2raw($val1),
87
            'Strong tags are replaced with asterisks'
88
        );
89
90
        $val1 = 'This has a <b class="test" style="font-weight: bold">b tag with attributes</b>.';
91
        $this->assertEquals(
92
            'This has a *b tag with attributes*.',
93
            Convert::html2raw($val1),
94
            'B tags with attributes are replaced with asterisks'
95
        );
96
97
        $val2 = 'This has a <strong class="test" style="font-weight: bold">strong tag with attributes</STRONG>.';
98
        $this->assertEquals(
99
            'This has a *strong tag with attributes*.',
100
            Convert::html2raw($val2),
101
            'Strong tags with attributes are replaced with asterisks'
102
        );
103
104
        $val3 = '<script type="application/javascript">Some really nasty javascript here</script>';
105
        $this->assertEquals(
106
            '',
107
            Convert::html2raw($val3),
108
            'Script tags are completely removed'
109
        );
110
111
        $val4 = '<style type="text/css">Some really nasty CSS here</style>';
112
        $this->assertEquals(
113
            '',
114
            Convert::html2raw($val4),
115
            'Style tags are completely removed'
116
        );
117
118
        $val5 = "<script type=\"application/javascript\">Some really nasty\nmultiline javascript here</script>";
119
        $this->assertEquals(
120
            '',
121
            Convert::html2raw($val5),
122
            'Multiline script tags are completely removed'
123
        );
124
125
        $val6 = "<style type=\"text/css\">Some really nasty\nmultiline CSS here</style>";
126
        $this->assertEquals(
127
            '',
128
            Convert::html2raw($val6),
129
            'Multiline style tags are completely removed'
130
        );
131
132
        $val7 = '<p>That&#39;s absolutely correct</p>';
133
        $this->assertEquals(
134
            "That's absolutely correct",
135
            Convert::html2raw($val7),
136
            'Single quotes are decoded correctly'
137
        );
138
139
        $val8 = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor ' . 'incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud ' . 'exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute ' . 'irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla ' . 'pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia ' . 'deserunt mollit anim id est laborum.';
140
        $this->assertEquals($val8, Convert::html2raw($val8), 'Test long text is unwrapped');
141
        $this->assertEquals(
142
            <<<PHP
143
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed
144
do eiusmod tempor incididunt ut labore et dolore magna
145
aliqua. Ut enim ad minim veniam, quis nostrud exercitation
146
ullamco laboris nisi ut aliquip ex ea commodo consequat.
147
Duis aute irure dolor in reprehenderit in voluptate velit
148
esse cillum dolore eu fugiat nulla pariatur. Excepteur sint
149
occaecat cupidatat non proident, sunt in culpa qui officia
150
deserunt mollit anim id est laborum.
151
PHP
152
            ,
153
            Convert::html2raw($val8, false, 60),
154
            'Test long text is wrapped'
155
        );
156
    }
157
158
    /**
159
     * Tests {@link Convert::raw2xml()}
160
     */
161
    public function testRaw2Xml()
162
    {
163
        $val1 = '<input type="text">';
164
        $this->assertEquals(
165
            '&lt;input type=&quot;text&quot;&gt;',
166
            Convert::raw2xml($val1),
167
            'Special characters are escaped'
168
        );
169
170
        $val2 = 'This is some normal text.';
171
        $this->assertEquals(
172
            'This is some normal text.',
173
            Convert::raw2xml($val2),
174
            'Normal text is not escaped'
175
        );
176
177
        $val3 = "This is test\nNow on a new line.";
178
        $this->assertEquals(
179
            "This is test\nNow on a new line.",
180
            Convert::raw2xml($val3),
181
            'Newlines are retained. They should not be replaced with <br /> as it is not XML valid'
182
        );
183
    }
184
185
    /**
186
     * Tests {@link Convert::raw2htmlid()}
187
     */
188
    public function testRaw2HtmlID()
189
    {
190
        $val1 = 'test test 123';
191
        $this->assertEquals('test_test_123', Convert::raw2htmlid($val1));
192
193
        $val2 = 'test[test][123]';
194
        $this->assertEquals('test_test_123', Convert::raw2htmlid($val2));
195
196
        $val3 = '[test[[test]][123]]';
197
        $this->assertEquals('test_test_123', Convert::raw2htmlid($val3));
198
199
        $val4 = 'A\\Namespaced\\Class';
200
        $this->assertEquals('A_Namespaced_Class', Convert::raw2htmlid($val4));
201
    }
202
203
    /**
204
     * Tests {@link Convert::xml2raw()}
205
     */
206
    public function testXml2Raw()
207
    {
208
        $val1 = '&lt;input type=&quot;text&quot;&gt;';
209
        $this->assertEquals('<input type="text">', Convert::xml2raw($val1), 'Special characters are escaped');
210
211
        $val2 = 'This is some normal text.';
212
        $this->assertEquals('This is some normal text.', Convert::xml2raw($val2), 'Normal text is not escaped');
213
    }
214
215
    /**
216
     * Tests {@link Convert::xml2raw()}
217
     */
218
    public function testArray2JSON()
219
    {
220
        $val = [
221
         'Joe' => 'Bloggs',
222
         'Tom' => 'Jones',
223
         'My' => [
224
          'Complicated' => 'Structure'
225
         ]
226
        ];
227
        $encoded = Convert::array2json($val);
0 ignored issues
show
Deprecated Code introduced by
The function SilverStripe\Core\Convert::array2json() has been deprecated: 4.4.0:5.0.0 Use json_encode() instead ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

227
        $encoded = /** @scrutinizer ignore-deprecated */ Convert::array2json($val);

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
228
        $this->assertEquals(
229
            '{"Joe":"Bloggs","Tom":"Jones","My":{"Complicated":"Structure"}}',
230
            $encoded,
231
            'Array is encoded in JSON'
232
        );
233
    }
234
235
    /**
236
     * Tests {@link Convert::json2array()}
237
     */
238
    public function testJSON2Array()
239
    {
240
        $val = '{"Joe":"Bloggs","Tom":"Jones","My":{"Complicated":"Structure"}}';
241
        $decoded = Convert::json2array($val);
0 ignored issues
show
Deprecated Code introduced by
The function SilverStripe\Core\Convert::json2array() has been deprecated: 4.4.0:5.0.0 Use json_decode() instead ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

241
        $decoded = /** @scrutinizer ignore-deprecated */ Convert::json2array($val);

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
242
        $this->assertEquals(3, count($decoded), '3 items in the decoded array');
0 ignored issues
show
Bug introduced by
It seems like $decoded can also be of type boolean; however, parameter $value of count() does only seem to accept Countable|array, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

242
        $this->assertEquals(3, count(/** @scrutinizer ignore-type */ $decoded), '3 items in the decoded array');
Loading history...
243
        $this->assertContains('Bloggs', $decoded, 'Contains "Bloggs" value in decoded array');
244
        $this->assertContains('Jones', $decoded, 'Contains "Jones" value in decoded array');
245
        $this->assertStringContainsString('Structure', $decoded['My']['Complicated']);
246
    }
247
248
    /**
249
     * Tests {@link Convert::testJSON2Obj()}
250
     */
251
    public function testJSON2Obj()
252
    {
253
        $val = '{"Joe":"Bloggs","Tom":"Jones","My":{"Complicated":"Structure"}}';
254
        $obj = Convert::json2obj($val);
0 ignored issues
show
Deprecated Code introduced by
The function SilverStripe\Core\Convert::json2obj() has been deprecated: 4.4.0:5.0.0 Use json_decode() instead ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

254
        $obj = /** @scrutinizer ignore-deprecated */ Convert::json2obj($val);

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
255
        $this->assertEquals('Bloggs', $obj->Joe);
256
        $this->assertEquals('Jones', $obj->Tom);
257
        $this->assertEquals('Structure', $obj->My->Complicated);
258
    }
259
260
    /**
261
     * Tests {@link Convert::testRaw2URL()}
262
     *
263
     * @todo test toASCII()
264
     */
265
    public function testRaw2URL()
266
    {
267
        URLSegmentFilter::config()->update('default_allow_multibyte', false);
268
        $this->assertEquals('foo', Convert::raw2url('foo'));
269
        $this->assertEquals('foo-and-bar', Convert::raw2url('foo & bar'));
270
        $this->assertEquals('foo-and-bar', Convert::raw2url('foo &amp; bar!'));
271
        $this->assertEquals('foos-bar-2', Convert::raw2url('foo\'s [bar] (2)'));
272
    }
273
274
    /**
275
     * Helper function for comparing characters with significant whitespaces
276
     *
277
     * @param string $expected
278
     * @param string $actual
279
     */
280
    protected function assertEqualsQuoted($expected, $actual)
281
    {
282
        $message = sprintf(
283
            'Expected "%s" but given "%s"',
284
            addcslashes($expected, "\r\n"),
285
            addcslashes($actual, "\r\n")
286
        );
287
        $this->assertEquals($expected, $actual, $message);
288
    }
289
290
    /**
291
     * Tests {@link Convert::nl2os()}
292
     */
293
    public function testNL2OS()
294
    {
295
296
        foreach (["\r\n", "\r", "\n"] as $nl) {
297
            // Base case: no action
298
            $this->assertEqualsQuoted(
299
                'Base case',
300
                Convert::nl2os('Base case', $nl)
301
            );
302
303
            // Mixed formats
304
            $this->assertEqualsQuoted(
305
                "Test{$nl}Text{$nl}Is{$nl}{$nl}Here{$nl}.",
306
                Convert::nl2os("Test\rText\r\nIs\n\rHere\r\n.", $nl)
307
            );
308
309
            // Test that multiple runs are non-destructive
310
            $expected = "Test{$nl}Text{$nl}Is{$nl}{$nl}Here{$nl}.";
311
            $this->assertEqualsQuoted(
312
                $expected,
313
                Convert::nl2os($expected, $nl)
314
            );
315
316
            // Check repeated sequence behaves correctly
317
            $expected = "{$nl}{$nl}{$nl}{$nl}{$nl}{$nl}{$nl}{$nl}";
318
            $input = "\r\r\n\r\r\n\n\n\n\r";
319
            $this->assertEqualsQuoted(
320
                $expected,
321
                Convert::nl2os($input, $nl)
322
            );
323
        }
324
    }
325
326
    /**
327
     * Tests {@link Convert::raw2js()}
328
     */
329
    public function testRaw2JS()
330
    {
331
        // Test attempt to break out of string
332
        $this->assertEquals(
333
            '\\"; window.location=\\"http://www.google.com',
334
            Convert::raw2js('"; window.location="http://www.google.com')
335
        );
336
        $this->assertEquals(
337
            '\\\'; window.location=\\\'http://www.google.com',
338
            Convert::raw2js('\'; window.location=\'http://www.google.com')
339
        );
340
        // Test attempt to close script tag
341
        $this->assertEquals(
342
            '\\"; \\x3c/script\\x3e\\x3ch1\\x3eHa \\x26amp; Ha\\x3c/h1\\x3e\\x3cscript\\x3e',
343
            Convert::raw2js('"; </script><h1>Ha &amp; Ha</h1><script>')
344
        );
345
        // Test newlines are properly escaped
346
        $this->assertEquals(
347
            'New\\nLine\\rReturn',
348
            Convert::raw2js("New\nLine\rReturn")
349
        );
350
        // Check escape of slashes
351
        $this->assertEquals(
352
            '\\\\\\"\\x3eClick here',
353
            Convert::raw2js('\\">Click here')
354
        );
355
    }
356
357
    /**
358
     * Tests {@link Convert::raw2json()}
359
     */
360
    public function testRaw2JSON()
361
    {
362
363
        // Test object
364
        $input = new stdClass();
365
        $input->Title = 'My Object';
366
        $input->Content = '<p>Data</p>';
367
        $this->assertEquals(
368
            '{"Title":"My Object","Content":"<p>Data<\/p>"}',
369
            Convert::raw2json($input)
0 ignored issues
show
Deprecated Code introduced by
The function SilverStripe\Core\Convert::raw2json() has been deprecated: 4.4.0:5.0.0 Use json_encode() instead ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

369
            /** @scrutinizer ignore-deprecated */ Convert::raw2json($input)

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
370
        );
371
372
        // Array
373
        $array = ['One' => 'Apple', 'Two' => 'Banana'];
374
        $this->assertEquals(
375
            '{"One":"Apple","Two":"Banana"}',
376
            Convert::raw2json($array)
0 ignored issues
show
Deprecated Code introduced by
The function SilverStripe\Core\Convert::raw2json() has been deprecated: 4.4.0:5.0.0 Use json_encode() instead ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

376
            /** @scrutinizer ignore-deprecated */ Convert::raw2json($array)

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
377
        );
378
379
        // String value with already encoded data. Result should be quoted.
380
        $value = '{"Left": "Value"}';
381
        $this->assertEquals(
382
            '"{\\"Left\\": \\"Value\\"}"',
383
            Convert::raw2json($value)
0 ignored issues
show
Deprecated Code introduced by
The function SilverStripe\Core\Convert::raw2json() has been deprecated: 4.4.0:5.0.0 Use json_encode() instead ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

383
            /** @scrutinizer ignore-deprecated */ Convert::raw2json($value)

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
384
        );
385
    }
386
387
    /**
388
     * Test that a context bitmask can be passed through to the json_encode method in {@link Convert::raw2json()}
389
     * and in {@link Convert::array2json()}
390
     */
391
    public function testRaw2JsonWithContext()
392
    {
393
        $data = ['foo' => 'b"ar'];
394
        $expected = '{"foo":"b\u0022ar"}';
395
        $result = Convert::raw2json($data, JSON_HEX_QUOT);
0 ignored issues
show
Deprecated Code introduced by
The function SilverStripe\Core\Convert::raw2json() has been deprecated: 4.4.0:5.0.0 Use json_encode() instead ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

395
        $result = /** @scrutinizer ignore-deprecated */ Convert::raw2json($data, JSON_HEX_QUOT);

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
396
        $this->assertSame($expected, $result);
397
        $wrapperResult = Convert::array2json($data, JSON_HEX_QUOT);
0 ignored issues
show
Deprecated Code introduced by
The function SilverStripe\Core\Convert::array2json() has been deprecated: 4.4.0:5.0.0 Use json_encode() instead ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

397
        $wrapperResult = /** @scrutinizer ignore-deprecated */ Convert::array2json($data, JSON_HEX_QUOT);

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
398
        $this->assertSame($expected, $wrapperResult);
399
    }
400
401
    /**
402
     * Tests {@link Convert::xml2array()}
403
     */
404
    public function testXML2Array()
405
    {
406
407
        $inputXML = <<<XML
408
<?xml version="1.0"?>
409
<!DOCTYPE results [
410
  <!ENTITY long "SOME_SUPER_LONG_STRING">
411
]>
412
<results>
413
    <result>My para</result>
414
    <result>Ampersand &amp; is retained and not double encoded</result>
415
</results>
416
XML
417
        ;
418
        $expected = [
419
            'result' => [
420
                'My para',
421
                'Ampersand & is retained and not double encoded'
422
            ]
423
        ];
424
        $actual = Convert::xml2array($inputXML, false);
0 ignored issues
show
Deprecated Code introduced by
The function SilverStripe\Core\Convert::xml2array() has been deprecated: 4.11.0:5.0.0 ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

424
        $actual = /** @scrutinizer ignore-deprecated */ Convert::xml2array($inputXML, false);

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
425
        $this->assertEquals($expected, $actual);
426
        $this->expectException(InvalidArgumentException::class);
427
        $this->expectExceptionMessage('XML Doctype parsing disabled');
428
        Convert::xml2array($inputXML, true);
0 ignored issues
show
Deprecated Code introduced by
The function SilverStripe\Core\Convert::xml2array() has been deprecated: 4.11.0:5.0.0 ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

428
        /** @scrutinizer ignore-deprecated */ Convert::xml2array($inputXML, true);

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
429
    }
430
431
    /**
432
     * Tests {@link Convert::xml2array()} if an exception the contains a reference to a removed <!ENTITY />
433
     */
434
    public function testXML2ArrayEntityException()
435
    {
436
        $inputXML = <<<XML
437
        <?xml version="1.0"?>
438
        <!DOCTYPE results [
439
            <!ENTITY long "SOME_SUPER_LONG_STRING">
440
        ]>
441
        <results>
442
            <result>Now include &long; lots of times to expand the in-memory size of this XML structure</result>
443
            <result>&long;&long;&long;</result>
444
        </results>
445
        XML;
446
        $this->expectException(Exception::class);
447
        $this->expectExceptionMessage('String could not be parsed as XML');
448
        Convert::xml2array($inputXML);
0 ignored issues
show
Deprecated Code introduced by
The function SilverStripe\Core\Convert::xml2array() has been deprecated: 4.11.0:5.0.0 ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

448
        /** @scrutinizer ignore-deprecated */ Convert::xml2array($inputXML);

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
449
    }
450
451
    /**
452
     * Tests {@link Convert::xml2array()} if an exception the contains a reference to a multiple removed <!ENTITY />
453
     */
454
    public function testXML2ArrayMultipleEntitiesException()
455
    {
456
        $inputXML = <<<XML
457
        <?xml version="1.0"?>
458
        <!DOCTYPE results [<!ENTITY long "SOME_SUPER_LONG_STRING"><!ENTITY short "SHORT_STRING">]>
459
        <results>
460
            <result>Now include &long; and &short; lots of times</result>
461
            <result>&long;&long;&long;&short;&short;&short;</result>
462
        </results>
463
        XML;
464
        $this->expectException(Exception::class);
465
        $this->expectExceptionMessage('String could not be parsed as XML');
466
        Convert::xml2array($inputXML);
0 ignored issues
show
Deprecated Code introduced by
The function SilverStripe\Core\Convert::xml2array() has been deprecated: 4.11.0:5.0.0 ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

466
        /** @scrutinizer ignore-deprecated */ Convert::xml2array($inputXML);

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
467
    }
468
469
    /**
470
     * Tests {@link Convert::xml2array()} if there is a malicious <!ENTITY /> present
471
     */
472
    public function testXML2ArrayMaliciousEntityException()
473
    {
474
        $inputXML = <<<XML
475
        <?xml version="1.0"?>
476
        <!DOCTYPE results [
477
            <!ENTITY><!<!ENTITY>ENTITY ext SYSTEM "http://evil.com">
478
        ]>
479
        <results>
480
            <result>Evil document</result>
481
        </results>
482
        XML;
483
        $this->expectException(InvalidArgumentException::class);
484
        $this->expectExceptionMessage('Malicious XML entity detected');
485
        Convert::xml2array($inputXML);
0 ignored issues
show
Deprecated Code introduced by
The function SilverStripe\Core\Convert::xml2array() has been deprecated: 4.11.0:5.0.0 ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

485
        /** @scrutinizer ignore-deprecated */ Convert::xml2array($inputXML);

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
486
    }
487
488
    /**
489
     * Tests {@link Convert::base64url_encode()} and {@link Convert::base64url_decode()}
490
     */
491
    public function testBase64url()
492
    {
493
        $data = 'Wëīrð characters ☺ such as ¤Ø¶÷╬';
494
        // This requires this test file to have UTF-8 character encoding
495
        $this->assertEquals(
496
            $data,
497
            Convert::base64url_decode(Convert::base64url_encode($data))
498
        );
499
500
        $data = 654.423;
501
        $this->assertEquals(
502
            $data,
503
            Convert::base64url_decode(Convert::base64url_encode($data))
504
        );
505
506
        $data = true;
507
        $this->assertEquals(
508
            $data,
509
            Convert::base64url_decode(Convert::base64url_encode($data))
510
        );
511
512
        $data = ['simple','array','¤Ø¶÷╬'];
513
        $this->assertEquals(
514
            $data,
515
            Convert::base64url_decode(Convert::base64url_encode($data))
516
        );
517
518
        $data = [
519
         'a'  => 'associative',
520
         4    => 'array',
521
         '☺' => '¤Ø¶÷╬'
522
        ];
523
        $this->assertEquals(
524
            $data,
525
            Convert::base64url_decode(Convert::base64url_encode($data))
526
        );
527
    }
528
529
    public function testValidUtf8()
530
    {
531
        // Install a UTF-8 locale
532
        $this->previousLocaleSetting = setlocale(LC_CTYPE, 0);
533
534
        $locales = ['en_US.UTF-8', 'en_NZ.UTF-8', 'de_DE.UTF-8'];
535
        $localeInstalled = false;
536
        foreach ($locales as $locale) {
537
            if ($localeInstalled = setlocale(LC_CTYPE, $locale)) {
538
                break;
539
            }
540
        }
541
542
        // If the system doesn't have any of the UTF-8 locales, exit early
543
        if ($localeInstalled === false) {
544
            $this->markTestIncomplete('Unable to run this test because of missing locale!');
545
            return;
546
        }
547
548
        $problematicText = html_entity_decode('<p>This is a&nbsp;Test with non-breaking&nbsp;space!</p>', ENT_COMPAT, 'UTF-8');
549
550
        $this->assertTrue(mb_check_encoding(Convert::html2raw($problematicText), 'UTF-8'));
551
    }
552
553
    public function testUpperCamelToLowerCamel()
554
    {
555
        $this->assertEquals(
556
            'd',
557
            Convert::upperCamelToLowerCamel('D'),
558
            'Single character'
559
        );
560
        $this->assertEquals(
561
            'id',
562
            Convert::upperCamelToLowerCamel('ID'),
563
            'Multi leading upper without trailing lower'
564
        );
565
        $this->assertEquals(
566
            'id',
567
            Convert::upperCamelToLowerCamel('Id'),
568
            'Single leading upper with trailing lower'
569
        );
570
        $this->assertEquals(
571
            'idField',
572
            Convert::upperCamelToLowerCamel('IdField'),
573
            'Single leading upper with trailing upper camel'
574
        );
575
        $this->assertEquals(
576
            'idField',
577
            Convert::upperCamelToLowerCamel('IDField'),
578
            'Multi leading upper with trailing upper camel'
579
        );
580
        $this->assertEquals(
581
            'iDField',
582
            Convert::upperCamelToLowerCamel('iDField'),
583
            'Single leading lower with trailing upper camel'
584
        );
585
        $this->assertEquals(
586
            '_IDField',
587
            Convert::upperCamelToLowerCamel('_IDField'),
588
            'Non-alpha leading  with trailing upper camel'
589
        );
590
    }
591
592
    /**
593
     * Test that memstring2bytes returns the number of bytes for a PHP ini style size declaration
594
     *
595
     * @param string $memString
596
     * @param int    $expected
597
     * @dataProvider memString2BytesProvider
598
     */
599
    public function testMemString2Bytes($memString, $expected)
600
    {
601
        $this->assertSame($expected, Convert::memstring2bytes($memString));
602
    }
603
604
    /**
605
     * @return array
606
     */
607
    public function memString2BytesProvider()
608
    {
609
        return [
610
            'infinite' => ['-1', -1],
611
            'integer' => ['2048', 2 * 1024],
612
            'kilo' => ['2k', 2 * 1024],
613
            'mega' => ['512M', 512 * 1024 * 1024],
614
            'MiB' => ['512MiB', 512 * 1024 * 1024],
615
            'mbytes' => ['512 mbytes', 512 * 1024 * 1024],
616
            'megabytes' => ['512 megabytes', 512 * 1024 * 1024],
617
            'giga' => ['1024g', 1024 * 1024 * 1024 * 1024],
618
            'G' => ['1024G', 1024 * 1024 * 1024 * 1024]
619
        ];
620
    }
621
622
    /**
623
     * Test that bytes2memstring returns a binary prefixed string representing the number of bytes
624
     *
625
     * @param string $bytes
626
     * @param int    $expected
627
     * @dataProvider bytes2MemStringProvider
628
     */
629
    public function testBytes2MemString($bytes, $expected)
630
    {
631
        $this->assertSame($expected, Convert::bytes2memstring($bytes));
0 ignored issues
show
Bug introduced by
$bytes of type string is incompatible with the type double expected by parameter $bytes of SilverStripe\Core\Convert::bytes2memstring(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

631
        $this->assertSame($expected, Convert::bytes2memstring(/** @scrutinizer ignore-type */ $bytes));
Loading history...
632
    }
633
634
    /**
635
     * @return array
636
     */
637
    public function bytes2MemStringProvider()
638
    {
639
        return [
640
            [200, '200B'],
641
            [2 * 1024, '2K'],
642
            [512 * 1024 * 1024, '512M'],
643
            [512 * 1024 * 1024 * 1024, '512G'],
644
            [512 * 1024 * 1024 * 1024 * 1024, '512T'],
645
            [512 * 1024 * 1024 * 1024 * 1024 * 1024, '512P']
646
        ];
647
    }
648
649
    public function providerTestSlashes()
650
    {
651
        return [
652
            ['bob/bob', '/', true, 'bob/bob'],
653
            ['\\bob/bob\\', '/', true, '/bob/bob/'],
654
            ['\\bob////bob\\/', '/', true, '/bob/bob/'],
655
            ['bob/bob', '\\', true, 'bob\\bob'],
656
            ['\\bob/bob\\', '\\', true, '\\bob\\bob\\'],
657
            ['\\bob////bob\\/', '\\', true, '\\bob\\bob\\'],
658
            ['bob/bob', '#', true, 'bob#bob'],
659
            ['\\bob/bob\\', '#', true, '#bob#bob#'],
660
            ['\\bob////bob\\/', '#', true, '#bob#bob#'],
661
            ['bob/bob', '/', false, 'bob/bob'],
662
            ['\\bob/bob\\', '/', false, '/bob/bob/'],
663
            ['\\bob////bob\\/', '/', false, '/bob////bob//'],
664
            ['bob/bob', '\\', false, 'bob\\bob'],
665
            ['\\bob/bob\\', '\\', false, '\\bob\\bob\\'],
666
            ['\\bob////bob\\/', '\\', false, '\\bob\\\\\\\\bob\\\\'],
667
            ['bob/bob', '#', false, 'bob#bob'],
668
            ['\\bob/bob\\', '#', false, '#bob#bob#'],
669
            ['\\bob////bob\\/', '#', false, '#bob####bob##'],
670
        ];
671
    }
672
673
    /**
674
     * @dataProvider providerTestSlashes
675
     * @param string $path
676
     * @param string $separator
677
     * @param bool $multiple
678
     * @param string $expected
679
     */
680
    public function testSlashes($path, $separator, $multiple, $expected)
681
    {
682
        $this->assertEquals($expected, Convert::slashes($path, $separator, $multiple));
683
    }
684
}
685