Passed
Push — 4.1 ( 1362b2...cb7f15 )
by Robbie
25:59 queued 19:36
created

ShortcodeParserTest::testUnquotedArguments()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 0
dl 0
loc 4
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace SilverStripe\View\Tests\Parsers;
4
5
use SilverStripe\Dev\SapphireTest;
6
use SilverStripe\View\Parsers\ShortcodeParser;
7
8
class ShortcodeParserTest extends SapphireTest
9
{
10
11
    protected $arguments, $contents, $tagName, $parser;
0 ignored issues
show
Coding Style introduced by
It is generally advisable to only define one property per statement.

Only declaring a single property per statement allows you to later on add doc comments more easily.

It is also recommended by PSR2, so it is a common style that many people expect.

Loading history...
12
    protected $extra = array();
13
14
    protected function setUp()
15
    {
16
        ShortcodeParser::get('test')->register('test_shortcode', array($this, 'shortcodeSaver'));
17
        $this->parser = ShortcodeParser::get('test');
18
19
        parent::setUp();
20
    }
21
22
    protected function tearDown()
23
    {
24
        ShortcodeParser::get('test')->unregister('test_shortcode');
25
26
        parent::tearDown();
27
    }
28
29
    /**
30
     * Tests that valid short codes that have not been registered are not replaced.
31
     */
32
    public function testNotRegisteredShortcode()
33
    {
34
        ShortcodeParser::$error_behavior = ShortcodeParser::STRIP;
35
36
        $this->assertEquals(
37
            '',
38
            $this->parser->parse('[not_shortcode]')
39
        );
40
41
        $this->assertEquals(
42
            '<img class="">',
43
            $this->parser->parse('<img class="[not_shortcode]">')
44
        );
45
46
        ShortcodeParser::$error_behavior = ShortcodeParser::WARN;
47
48
        $this->assertEquals(
49
            '<strong class="warning">[not_shortcode]</strong>',
50
            $this->parser->parse('[not_shortcode]')
51
        );
52
53
        ShortcodeParser::$error_behavior = ShortcodeParser::LEAVE;
54
55
        $this->assertEquals(
56
            '[not_shortcode]',
57
            $this->parser->parse('[not_shortcode]')
58
        );
59
        $this->assertEquals(
60
            '[not_shortcode /]',
61
            $this->parser->parse('[not_shortcode /]')
62
        );
63
        $this->assertEquals(
64
            '[not_shortcode,foo="bar"]',
65
            $this->parser->parse('[not_shortcode,foo="bar"]')
66
        );
67
        $this->assertEquals(
68
            '[not_shortcode]a[/not_shortcode]',
69
            $this->parser->parse('[not_shortcode]a[/not_shortcode]')
70
        );
71
        $this->assertEquals(
72
            '[/not_shortcode]',
73
            $this->parser->parse('[/not_shortcode]')
74
        );
75
76
        $this->assertEquals(
77
            '<img class="[not_shortcode]">',
78
            $this->parser->parse('<img class="[not_shortcode]">')
79
        );
80
    }
81
82
    public function testSimpleTag()
83
    {
84
        $tests = array(
85
            '[test_shortcode]',
86
            '[test_shortcode ]', '[test_shortcode,]', '[test_shortcode, ]' . '[test_shortcode/]', '[test_shortcode /]', '[test_shortcode,/]', '[test_shortcode, /]'
87
        );
88
89
        foreach ($tests as $test) {
90
            $this->parser->parse($test);
91
92
            $this->assertEquals(array(), $this->arguments, $test);
93
            $this->assertEquals('', $this->contents, $test);
94
            $this->assertEquals('test_shortcode', $this->tagName, $test);
95
        }
96
    }
97
98
    public function testOneArgument()
99
    {
100
        $tests = array (
101
            '[test_shortcode foo="bar"]', '[test_shortcode,foo="bar"]',
102
            "[test_shortcode foo='bar']", "[test_shortcode,foo='bar']",
103
            '[test_shortcode  foo  =  "bar"  /]', '[test_shortcode,  foo  =  "bar"  /]'
104
        );
105
106
        foreach ($tests as $test) {
107
            $this->parser->parse($test);
108
109
            $this->assertEquals(array('foo' => 'bar'), $this->arguments, $test);
110
            $this->assertEquals('', $this->contents, $test);
111
            $this->assertEquals('test_shortcode', $this->tagName, $test);
112
        }
113
    }
114
115
    public function testMultipleArguments()
116
    {
117
        $this->parser->parse('[test_shortcode foo = "bar",bar=\'foo\', baz="buz"]');
118
119
        $this->assertEquals(array('foo' => 'bar', 'bar' => 'foo', 'baz' => 'buz'), $this->arguments);
120
        $this->assertEquals('', $this->contents);
121
        $this->assertEquals('test_shortcode', $this->tagName);
122
    }
123
124
    public function testEnclosing()
125
    {
126
        $this->parser->parse('[test_shortcode]foo[/test_shortcode]');
127
128
        $this->assertEquals(array(), $this->arguments);
129
        $this->assertEquals('foo', $this->contents);
130
        $this->assertEquals('test_shortcode', $this->tagName);
131
    }
132
133
    public function testEnclosingWithArguments()
134
    {
135
        $this->parser->parse('[test_shortcode,foo = "bar",bar=\'foo\',baz="buz"]foo[/test_shortcode]');
136
137
        $this->assertEquals(array('foo' => 'bar', 'bar' => 'foo', 'baz' => 'buz'), $this->arguments);
138
        $this->assertEquals('foo', $this->contents);
139
        $this->assertEquals('test_shortcode', $this->tagName);
140
    }
141
142
    public function testShortcodeEscaping()
143
    {
144
        $this->assertEquals(
145
            '[test_shortcode]',
146
            $this->parser->parse('[[test_shortcode]]')
147
        );
148
149
        $this->assertEquals(
150
            '[test_shortcode /]',
151
            $this->parser->parse('[[test_shortcode /]]')
152
        );
153
154
        $this->assertEquals(
155
            '[test_shortcode]content[/test_shortcode]',
156
            $this->parser->parse('[[test_shortcode]content[/test_shortcode]]')
157
        );
158
159
        $this->assertEquals(
160
            '[test_shortcode]content',
161
            $this->parser->parse('[[test_shortcode]][test_shortcode]content[/test_shortcode]')
162
        );
163
164
        $this->assertEquals(
165
            '[test_shortcode]content[/test_shortcode]content2',
166
            $this->parser->parse('[[test_shortcode]content[/test_shortcode]][test_shortcode]content2[/test_shortcode]')
167
        );
168
169
        $this->assertEquals(
170
            '[[Doesnt strip double [ character if not a shortcode',
171
            $this->parser->parse('[[Doesnt strip double [ character if not a [test_shortcode]shortcode[/test_shortcode]')
172
        );
173
174
        $this->assertEquals(
175
            '[[Doesnt shortcode get confused by double ]] characters',
176
            $this->parser->parse(
177
                '[[Doesnt [test_shortcode]shortcode[/test_shortcode] get confused by double ]] characters'
178
            )
179
        );
180
    }
181
182
    public function testUnquotedArguments()
183
    {
184
        $this->assertEquals('', $this->parser->parse('[test_shortcode,foo=bar!,baz = buz123]'));
185
        $this->assertEquals(array('foo' => 'bar!', 'baz' => 'buz123'), $this->arguments);
186
    }
187
188
    public function testSpacesForDelimiter()
189
    {
190
        $this->assertEquals('', $this->parser->parse('[test_shortcode foo=bar! baz = buz123]'));
191
        $this->assertEquals(array('foo' => 'bar!', 'baz' => 'buz123'), $this->arguments);
192
    }
193
194
    public function testSelfClosingTag()
195
    {
196
        $this->assertEquals(
197
            'morecontent',
198
            $this->parser->parse('[test_shortcode,id="1"/]more[test_shortcode,id="2"]content[/test_shortcode]'),
199
            'Assert that self-closing tags are respected during parsing.'
200
        );
201
202
        $this->assertEquals(2, $this->arguments['id']);
203
    }
204
205
    public function testConsecutiveTags()
206
    {
207
        $this->assertEquals('', $this->parser->parse('[test_shortcode][test_shortcode]'));
208
    }
209
210
    protected function assertEqualsIgnoringWhitespace($a, $b, $message = null)
211
    {
212
        $this->assertEquals(preg_replace('/\s+/', '', $a), preg_replace('/\s+/', '', $b), $message);
213
    }
214
215
    public function testExtractBefore()
216
    {
217
        // Left extracts to before the current block
218
        $this->assertEqualsIgnoringWhitespace(
219
            'Code<div>FooBar</div>',
220
            $this->parser->parse('<div>Foo[test_shortcode class=left]Code[/test_shortcode]Bar</div>')
221
        );
222
        // Even if the immediate parent isn't a the current block
223
        $this->assertEqualsIgnoringWhitespace(
224
            'Code<div>Foo<b>BarBaz</b>Qux</div>',
225
            $this->parser->parse('<div>Foo<b>Bar[test_shortcode class=left]Code[/test_shortcode]Baz</b>Qux</div>')
226
        );
227
    }
228
229
    public function testExtractSplit()
230
    {
231
        $this->markTestSkipped(
232
            'Feature disabled due to https://github.com/silverstripe/silverstripe-framework/issues/5987'
233
        );
234
        // Center splits the current block
235
        $this->assertEqualsIgnoringWhitespace(
236
            '<div>Foo</div>Code<div>Bar</div>',
237
            $this->parser->parse('<div>Foo[test_shortcode class=center]Code[/test_shortcode]Bar</div>')
238
        );
239
        // Even if the immediate parent isn't a the current block
240
        $this->assertEqualsIgnoringWhitespace(
241
            '<div>Foo<b>Bar</b></div>Code<div><b>Baz</b>Qux</div>',
242
            $this->parser->parse('<div>Foo<b>Bar[test_shortcode class=center]Code[/test_shortcode]Baz</b>Qux</div>')
243
        );
244
    }
245
246
    public function testExtractNone()
247
    {
248
        // No class means don't extract
249
        $this->assertEqualsIgnoringWhitespace(
250
            '<div>FooCodeBar</div>',
251
            $this->parser->parse('<div>Foo[test_shortcode]Code[/test_shortcode]Bar</div>')
252
        );
253
    }
254
255
    public function testShortcodesInsideScriptTag()
256
    {
257
        $this->assertEqualsIgnoringWhitespace(
258
            '<script>hello</script>',
259
            $this->parser->parse('<script>[test_shortcode]hello[/test_shortcode]</script>')
260
        );
261
    }
262
263
    public function testFalseyArguments()
264
    {
265
        $this->parser->parse('<p>[test_shortcode falsey=0]');
266
267
        $this->assertEquals(
268
            array(
269
            'falsey' => '',
270
            ),
271
            $this->arguments
272
        );
273
    }
274
275
    public function testNumericShortcodes()
276
    {
277
        $this->assertEqualsIgnoringWhitespace(
278
            '[2]',
279
            $this->parser->parse('[2]')
280
        );
281
        $this->assertEqualsIgnoringWhitespace(
282
            '<script>[2]</script>',
283
            $this->parser->parse('<script>[2]</script>')
284
        );
285
286
        $this->parser->register(
287
            '2',
288
            function () {
289
                return 'this is 2';
290
            }
291
        );
292
293
        $this->assertEqualsIgnoringWhitespace(
294
            'this is 2',
295
            $this->parser->parse('[2]')
296
        );
297
        $this->assertEqualsIgnoringWhitespace(
298
            '<script>this is 2</script>',
299
            $this->parser->parse('<script>[2]</script>')
300
        );
301
302
        $this->parser->unregister('2');
303
    }
304
305
    public function testExtraContext()
306
    {
307
        $this->parser->parse('<a href="[test_shortcode]">Test</a>');
308
309
        $this->assertInstanceOf('DOMNode', $this->extra['node']);
310
        $this->assertInstanceOf('DOMElement', $this->extra['element']);
311
        $this->assertEquals($this->extra['element']->tagName, 'a');
312
    }
313
314
    public function testShortcodeWithAnchorAndQuerystring()
315
    {
316
        $result = $this->parser->parse('<a href="[test_shortcode]?my-string=this&thing=2#my-anchor">Link</a>');
317
318
        $this->assertContains('my-string=this', $result);
319
        $this->assertContains('thing=2', $result);
320
        $this->assertContains('my-anchor', $result);
321
    }
322
323
    public function testNoParseAttemptIfNoCode()
324
    {
325
        $stub = $this->getMockBuilder(ShortcodeParser::class)->setMethods(array('replaceElementTagsWithMarkers'))
326
            ->getMock();
327
        $stub->register(
328
            'test',
329
            function () {
330
                return '';
331
            }
332
        );
333
334
        $stub->expects($this->never())
335
            ->method('replaceElementTagsWithMarkers')->will($this->returnValue(array('', '')));
336
337
        $stub->parse('<p>test</p>');
338
    }
339
340
    public function testSelfClosingHtmlTags()
341
    {
342
        $this->parser->register('img', function () {
343
            return '<img src="http://example.com/image.jpg">';
344
        });
345
346
        $result = $this->parser->parse('[img]');
347
348
        $this->assertContains('http://example.com/image.jpg', $result);
349
    }
350
351
    // -----------------------------------------------------------------------------------------------------------------
352
353
    /**
354
     * Stores the result of a shortcode parse in object properties for easy testing access.
355
     */
356
    public function shortcodeSaver($arguments, $content, $parser, $tagName, $extra)
357
    {
358
        $this->arguments = $arguments;
359
        $this->contents = $content;
360
        $this->tagName = $tagName;
361
        $this->extra = $extra;
362
363
        return $content;
364
    }
365
}
366