Passed
Push — master ( 218c08...7bac60 )
by
unknown
52s queued 11s
created

AbstractGeneratorTest::testGenerateFromHtml()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 34

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 34
rs 9.376
c 0
b 0
f 0
cc 1
nc 1
nop 0
1
<?php
2
3
namespace Knp\Snappy;
4
5
use PHPUnit\Framework\TestCase;
6
use Psr\Log\LoggerInterface;
7
8
class AbstractGeneratorTest extends TestCase
9
{
10
    public function testAddOption()
11
    {
12
        $media = $this->getMockForAbstractClass('Knp\Snappy\AbstractGenerator', [], '', false);
13
14
        $this->assertEquals([], $media->getOptions());
15
16
        $r = new \ReflectionMethod($media, 'addOption');
17
        $r->setAccessible(true);
18
        $r->invokeArgs($media, ['foo', 'bar']);
19
20
        $this->assertEquals(['foo' => 'bar'], $media->getOptions(), '->addOption() adds an option');
21
22
        $r->invokeArgs($media, ['baz', 'bat']);
23
24
        $this->assertEquals(
25
            [
26
                'foo' => 'bar',
27
                'baz' => 'bat',
28
            ],
29
            $media->getOptions(),
30
            '->addOption() appends the option to the existing ones'
31
        );
32
33
        $message = '->addOption() raises an exception when the specified option already exists';
34
35
        try {
36
            $r->invokeArgs($media, ['baz', 'bat']);
37
            $this->fail($message);
38
        } catch (\InvalidArgumentException $e) {
39
            $this->anything($message);
0 ignored issues
show
Unused Code introduced by
The call to AbstractGeneratorTest::anything() has too many arguments starting with $message.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
40
        }
41
    }
42
43
    public function testAddOptions()
44
    {
45
        $media = $this->getMockForAbstractClass('Knp\Snappy\AbstractGenerator', [], '', false);
46
47
        $this->assertEquals([], $media->getOptions());
48
49
        $r = new \ReflectionMethod($media, 'addOptions');
50
        $r->setAccessible(true);
51
        $r->invokeArgs($media, [['foo' => 'bar', 'baz' => 'bat']]);
52
53
        $this->assertEquals(
54
            [
55
                'foo' => 'bar',
56
                'baz' => 'bat',
57
            ],
58
            $media->getOptions(),
59
            '->addOptions() adds all the given options'
60
        );
61
62
        $r->invokeArgs($media, [['ban' => 'bag', 'bal' => 'bac']]);
63
64
        $this->assertEquals(
65
            [
66
                'foo' => 'bar',
67
                'baz' => 'bat',
68
                'ban' => 'bag',
69
                'bal' => 'bac',
70
            ],
71
            $media->getOptions(),
72
            '->addOptions() adds the given options to the existing ones'
73
        );
74
75
        $message = '->addOptions() raises an exception when one of the given options already exists';
76
77
        try {
78
            $r->invokeArgs($media, [['bak' => 'bam', 'bah' => 'bap', 'baz' => 'bat']]);
79
            $this->fail($message);
80
        } catch (\InvalidArgumentException $e) {
81
            $this->anything($message);
0 ignored issues
show
Unused Code introduced by
The call to AbstractGeneratorTest::anything() has too many arguments starting with $message.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
82
        }
83
    }
84
85
    public function testSetOption()
86
    {
87
        $media = $this
88
            ->getMockBuilder(AbstractGenerator::class)
89
            ->setConstructorArgs(['/usr/local/bin/wkhtmltopdf'])
90
            ->getMockForAbstractClass()
91
        ;
92
93
        $logger = $this
94
            ->getMockBuilder(LoggerInterface::class)
95
            ->getMock()
96
        ;
97
        $media->setLogger($logger);
98
        $logger->expects($this->once())->method('debug');
99
100
        $r = new \ReflectionMethod($media, 'addOption');
101
        $r->setAccessible(true);
102
        $r->invokeArgs($media, ['foo', 'bar']);
103
104
        $media->setOption('foo', 'abc');
105
106
        $this->assertEquals(
107
            [
108
                'foo' => 'abc',
109
            ],
110
            $media->getOptions(),
111
            '->setOption() defines the value of an option'
112
        );
113
114
        $message = '->setOption() raises an exception when the specified option does not exist';
115
116
        try {
117
            $media->setOption('bad', 'def');
118
            $this->fail($message);
119
        } catch (\InvalidArgumentException $e) {
120
            $this->anything($message);
0 ignored issues
show
Unused Code introduced by
The call to AbstractGeneratorTest::anything() has too many arguments starting with $message.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
121
        }
122
    }
123
124
    public function testSetOptions()
125
    {
126
        $media = $this
127
            ->getMockBuilder(AbstractGenerator::class)
128
            ->setConstructorArgs(['/usr/local/bin/wkhtmltopdf'])
129
            ->getMockForAbstractClass()
130
        ;
131
132
        $logger = $this
133
            ->getMockBuilder(LoggerInterface::class)
134
            ->getMock()
135
        ;
136
        $media->setLogger($logger);
137
        $logger->expects($this->exactly(4))->method('debug');
138
139
        $r = new \ReflectionMethod($media, 'addOptions');
140
        $r->setAccessible(true);
141
        $r->invokeArgs($media, [['foo' => 'bar', 'baz' => 'bat']]);
142
143
        $media->setOptions(['foo' => 'abc', 'baz' => 'def']);
144
145
        $this->assertEquals(
146
            [
147
                'foo'   => 'abc',
148
                'baz'   => 'def',
149
            ],
150
            $media->getOptions(),
151
            '->setOptions() defines the values of all the specified options'
152
        );
153
154
        $message = '->setOptions() raises an exception when one of the specified options does not exist';
155
156
        try {
157
            $media->setOptions(['foo' => 'abc', 'baz' => 'def', 'bad' => 'ghi']);
158
            $this->fail($message);
159
        } catch (\InvalidArgumentException $e) {
160
            $this->anything($message);
0 ignored issues
show
Unused Code introduced by
The call to AbstractGeneratorTest::anything() has too many arguments starting with $message.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
161
        }
162
    }
163
164
    public function testGenerate()
165
    {
166
        $media = $this->getMockBuilder(AbstractGenerator::class)
167
            ->setMethods([
168
                'configure',
169
                'prepareOutput',
170
                'getCommand',
171
                'executeCommand',
172
                'checkOutput',
173
                'checkProcessStatus',
174
            ])
175
            ->setConstructorArgs(['the_binary', []])
176
            ->getMock()
177
        ;
178
179
        $logger = $this
180
            ->getMockBuilder(LoggerInterface::class)
181
            ->getMock()
182
        ;
183
        $media->setLogger($logger);
184
        $logger
185
            ->expects($this->exactly(2))
186
            ->method('info')
187
            ->with(
188
                $this->logicalOr(
189
                    'Generate from file(s) "the_input_file" to file "the_output_file".',
190
                    'File "the_output_file" has been successfully generated.'
191
                ),
192
                $this->logicalOr(
193
                    ['command' => 'the command', 'env' => null, 'timeout' => false],
194
                    ['command' => 'the command', 'stdout'  => 'stdout', 'stderr'  => 'stderr']
195
                )
196
            )
197
        ;
198
199
        $media
200
            ->expects($this->once())
201
            ->method('prepareOutput')
202
            ->with($this->equalTo('the_output_file'))
203
        ;
204
        $media
205
            ->expects($this->any())
206
            ->method('getCommand')
207
            ->with(
208
                $this->equalTo('the_input_file'),
209
                $this->equalTo('the_output_file'),
210
                $this->equalTo(['foo' => 'bar'])
211
            )
212
            ->will($this->returnValue('the command'))
213
        ;
214
        $media
215
            ->expects($this->once())
216
            ->method('executeCommand')
217
            ->with($this->equalTo('the command'))
218
            ->willReturn([0, 'stdout', 'stderr'])
219
        ;
220
        $media
221
            ->expects($this->once())
222
            ->method('checkProcessStatus')
223
            ->with(0, 'stdout', 'stderr', 'the command')
224
        ;
225
        $media
226
            ->expects($this->once())
227
            ->method('checkOutput')
228
            ->with(
229
                $this->equalTo('the_output_file'),
230
                $this->equalTo('the command')
231
            )
232
        ;
233
234
        $media->generate('the_input_file', 'the_output_file', ['foo' => 'bar']);
235
    }
236
237
    public function testFailingGenerate()
238
    {
239
        $media = $this->getMockBuilder(AbstractGenerator::class)
240
            ->setMethods([
241
                'configure',
242
                'prepareOutput',
243
                'getCommand',
244
                'executeCommand',
245
                'checkOutput',
246
                'checkProcessStatus',
247
            ])
248
            ->setConstructorArgs(['the_binary', [], ['PATH' => '/usr/bin']])
249
            ->getMock()
250
        ;
251
252
        $logger = $this->getMockBuilder(LoggerInterface::class)->getMock();
253
        $media->setLogger($logger);
254
        $media->setTimeout(2000);
255
256
        $logger
257
            ->expects($this->once())
258
            ->method('info')
259
            ->with(
260
                $this->equalTo('Generate from file(s) "the_input_file" to file "the_output_file".'),
261
                $this->equalTo(['command' => 'the command', 'env' => ['PATH' => '/usr/bin'], 'timeout' => 2000])
262
            )
263
        ;
264
265
        $logger
266
            ->expects($this->once())
267
            ->method('error')
268
            ->with(
269
                $this->equalTo('An error happened while generating "the_output_file".'),
270
                $this->equalTo(['command' => 'the command', 'status' => 1, 'stdout'  => 'stdout', 'stderr'  => 'stderr'])
271
            )
272
        ;
273
274
        $media
275
            ->expects($this->once())
276
            ->method('prepareOutput')
277
            ->with($this->equalTo('the_output_file'))
278
        ;
279
        $media
280
            ->expects($this->any())
281
            ->method('getCommand')
282
            ->with(
283
                $this->equalTo('the_input_file'),
284
                $this->equalTo('the_output_file')
285
            )
286
            ->will($this->returnValue('the command'))
287
        ;
288
        $media
289
            ->expects($this->once())
290
            ->method('executeCommand')
291
            ->with($this->equalTo('the command'))
292
            ->willReturn([1, 'stdout', 'stderr'])
293
        ;
294
        $media
295
            ->expects($this->once())
296
            ->method('checkProcessStatus')
297
            ->with(1, 'stdout', 'stderr', 'the command')
298
            ->willThrowException(new \RuntimeException())
299
        ;
300
301
        $this->expectException(\RuntimeException::class);
302
303
        $media->generate('the_input_file', 'the_output_file', ['foo' => 'bar']);
304
    }
305
306
    public function testGenerateFromHtml()
307
    {
308
        $media = $this->getMockBuilder(AbstractGenerator::class)
309
            ->setMethods([
310
                'configure',
311
                'generate',
312
                'createTemporaryFile',
313
            ])
314
            ->setConstructorArgs(['the_binary'])
315
            ->disableOriginalConstructor()
316
            ->getMock()
317
        ;
318
319
        $media
320
            ->expects($this->once())
321
            ->method('createTemporaryFile')
322
            ->with(
323
                $this->equalTo('<html>foo</html>'),
324
                $this->equalTo('html')
325
            )
326
            ->will($this->returnValue('the_temporary_file'))
327
        ;
328
        $media
329
            ->expects($this->once())
330
            ->method('generate')
331
            ->with(
332
                $this->equalTo(['the_temporary_file']),
333
                $this->equalTo('the_output_file'),
334
                $this->equalTo(['foo' => 'bar'])
335
            )
336
        ;
337
338
        $media->generateFromHtml('<html>foo</html>', 'the_output_file', ['foo' => 'bar']);
339
    }
340
341
    public function testGenerateFromHtmlWithHtmlArray()
342
    {
343
        $media = $this->getMockBuilder(AbstractGenerator::class)
344
            ->setMethods([
345
                'configure',
346
                'generate',
347
                'createTemporaryFile',
348
            ])
349
            ->setConstructorArgs(['the_binary'])
350
            ->disableOriginalConstructor()
351
            ->getMock()
352
        ;
353
        $media
354
            ->expects($this->once())
355
            ->method('createTemporaryFile')
356
            ->with(
357
                $this->equalTo('<html>foo</html>'),
358
                $this->equalTo('html')
359
            )
360
            ->will($this->returnValue('the_temporary_file'))
361
        ;
362
        $media
363
            ->expects($this->once())
364
            ->method('generate')
365
            ->with(
366
                $this->equalTo(['the_temporary_file']),
367
                $this->equalTo('the_output_file'),
368
                $this->equalTo(['foo' => 'bar'])
369
            )
370
        ;
371
372
        $media->generateFromHtml(['<html>foo</html>'], 'the_output_file', ['foo' => 'bar']);
373
    }
374
375
    public function testGetOutput()
376
    {
377
        $media = $this->getMockBuilder(AbstractGenerator::class)
378
            ->setMethods([
379
                'configure',
380
                'getDefaultExtension',
381
                'createTemporaryFile',
382
                'generate',
383
                'getFileContents',
384
                'unlink',
385
            ])
386
            ->disableOriginalConstructor()
387
            ->getMock()
388
        ;
389
        $media
390
            ->expects($this->any())
391
            ->method('getDefaultExtension')
392
            ->will($this->returnValue('ext'))
393
        ;
394
        $media
395
            ->expects($this->any())
396
            ->method('createTemporaryFile')
397
            ->with(
398
                $this->equalTo(null),
399
                $this->equalTo('ext')
400
            )
401
            ->will($this->returnValue('the_temporary_file'))
402
        ;
403
        $media
404
            ->expects($this->once())
405
            ->method('generate')
406
            ->with(
407
                $this->equalTo('the_input_file'),
408
                $this->equalTo('the_temporary_file'),
409
                $this->equalTo(['foo' => 'bar'])
410
            )
411
        ;
412
        $media
413
            ->expects($this->once())
414
            ->method('getFileContents')
415
            ->will($this->returnValue('the file contents'))
416
        ;
417
418
        $media
419
            ->expects($this->any())
420
            ->method('unlink')
421
            ->with($this->equalTo('the_temporary_file'))
422
            ->will($this->returnValue(true))
423
        ;
424
425
        $this->assertEquals('the file contents', $media->getOutput('the_input_file', ['foo' => 'bar']));
426
    }
427
428
    public function testGetOutputFromHtml()
429
    {
430
        $media = $this->getMockBuilder(AbstractGenerator::class)
431
            ->setMethods([
432
                'configure',
433
                'getOutput',
434
                'createTemporaryFile',
435
            ])
436
            ->disableOriginalConstructor()
437
            ->getMock()
438
        ;
439
        $media
440
            ->expects($this->once())
441
            ->method('createTemporaryFile')
442
            ->with(
443
                $this->equalTo('<html>foo</html>'),
444
                $this->equalTo('html')
445
            )
446
            ->will($this->returnValue('the_temporary_file'))
447
        ;
448
        $media
449
            ->expects($this->once())
450
            ->method('getOutput')
451
            ->with(
452
                $this->equalTo(['the_temporary_file']),
453
                $this->equalTo(['foo' => 'bar'])
454
            )
455
            ->will($this->returnValue('the output'))
456
        ;
457
458
        $this->assertEquals('the output', $media->getOutputFromHtml('<html>foo</html>', ['foo' => 'bar']));
459
    }
460
461
    public function testGetOutputFromHtmlWithHtmlArray()
462
    {
463
        $media = $this->getMockBuilder(AbstractGenerator::class)
464
            ->setMethods([
465
                'configure',
466
                'getOutput',
467
                'createTemporaryFile',
468
            ])
469
            ->disableOriginalConstructor()
470
            ->getMock()
471
        ;
472
        $media
473
            ->expects($this->once())
474
            ->method('createTemporaryFile')
475
            ->with(
476
                $this->equalTo('<html>foo</html>'),
477
                $this->equalTo('html')
478
            )
479
            ->will($this->returnValue('the_temporary_file'))
480
        ;
481
        $media
482
            ->expects($this->once())
483
            ->method('getOutput')
484
            ->with(
485
                $this->equalTo(['the_temporary_file']),
486
                $this->equalTo(['foo' => 'bar'])
487
            )
488
            ->will($this->returnValue('the output'))
489
        ;
490
491
        $this->assertEquals('the output', $media->getOutputFromHtml(['<html>foo</html>'], ['foo' => 'bar']));
492
    }
493
494
    public function testMergeOptions()
495
    {
496
        $media = $this->getMockForAbstractClass('Knp\Snappy\AbstractGenerator', [], '', false);
497
498
        $originalOptions = ['foo' => 'bar', 'baz' => 'bat'];
499
500
        $addOptions = new \ReflectionMethod($media, 'addOptions');
501
        $addOptions->setAccessible(true);
502
        $addOptions->invokeArgs($media, [$originalOptions]);
503
504
        $r = new \ReflectionMethod($media, 'mergeOptions');
505
        $r->setAccessible(true);
506
507
        $mergedOptions = $r->invokeArgs($media, [['foo' => 'ban']]);
508
509
        $this->assertEquals(
510
            [
511
                'foo' => 'ban',
512
                'baz' => 'bat',
513
            ],
514
            $mergedOptions,
515
            '->mergeOptions() merges an option to the instance ones and returns the result options array'
516
        );
517
518
        $this->assertEquals(
519
            $originalOptions,
520
            $media->getOptions(),
521
            '->mergeOptions() does NOT change the instance options'
522
        );
523
524
        $mergedOptions = $r->invokeArgs($media, [['foo' => 'ban', 'baz' => 'bag']]);
525
526
        $this->assertEquals(
527
            [
528
                'foo' => 'ban',
529
                'baz' => 'bag',
530
            ],
531
            $mergedOptions,
532
            '->mergeOptions() merges many options to the instance ones and returns the result options array'
533
        );
534
535
        $message = '->mergeOptions() throws an InvalidArgumentException once there is an undefined option in the given array';
536
537
        try {
538
            $r->invokeArgs($media, [['foo' => 'ban', 'bad' => 'bah']]);
539
            $this->fail($message);
540
        } catch (\InvalidArgumentException $e) {
541
            $this->anything($message);
0 ignored issues
show
Unused Code introduced by
The call to AbstractGeneratorTest::anything() has too many arguments starting with $message.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
542
        }
543
    }
544
545
    /**
546
     * @dataProvider dataForBuildCommand
547
     */
548
    public function testBuildCommand($binary, $url, $path, $options, $expected)
549
    {
550
        $media = $this->getMockForAbstractClass('Knp\Snappy\AbstractGenerator', [], '', false);
551
552
        $r = new \ReflectionMethod($media, 'buildCommand');
553
        $r->setAccessible(true);
554
555
        $this->assertEquals($expected, $r->invokeArgs($media, [$binary, $url, $path, $options]));
556
    }
557
558
    private function getPHPExecutableFromPath()
0 ignored issues
show
Documentation introduced by
The return type could not be reliably inferred; please add a @return annotation.

Our type inference engine in quite powerful, but sometimes the code does not provide enough clues to go by. In these cases we request you to add a @return annotation as described here.

Loading history...
559
    {
560
        if (isset($_SERVER['_'])) {
561
            return $_SERVER['_'];
562
        }
563
564
        if (@defined(PHP_BINARY)) {
565
            return PHP_BINARY;
566
        }
567
568
        $paths = explode(PATH_SEPARATOR, getenv('PATH'));
569
        foreach ($paths as $path) {
570
            // we need this for XAMPP (Windows)
571
            if (strstr($path, 'php.exe') && isset($_SERVER['WINDIR']) && file_exists($path) && is_file($path)) {
572
                return $path;
573
            } else {
574
                $php_executable = $path . DIRECTORY_SEPARATOR . 'php' . (isset($_SERVER['WINDIR']) ? '.exe' : '');
575
                if (file_exists($php_executable) && is_file($php_executable)) {
576
                    return $php_executable;
577
                }
578
            }
579
        }
580
581
        return false; // not found
582
    }
583
584
    public function dataForBuildCommand()
585
    {
586
        $theBinary = $this->getPHPExecutableFromPath() . ' -v'; // i.e.: '/usr/bin/php -v'
587
588
        return [
589
            [
590
                $theBinary,
591
                'http://the.url/',
592
                '/the/path',
593
                [],
594
                $theBinary . ' ' . escapeshellarg('http://the.url/') . ' ' . escapeshellarg('/the/path'),
595
            ],
596
            [
597
                $theBinary,
598
                'http://the.url/',
599
                '/the/path',
600
                [
601
                    'foo'   => null,
602
                    'bar'   => false,
603
                    'baz'   => [],
604
                ],
605
                $theBinary . ' ' . escapeshellarg('http://the.url/') . ' ' . escapeshellarg('/the/path'),
606
            ],
607
            [
608
                $theBinary,
609
                'http://the.url/',
610
                '/the/path',
611
                [
612
                    'foo'   => 'foovalue',
613
                    'bar'   => ['barvalue1', 'barvalue2'],
614
                    'baz'   => true,
615
                ],
616
                $theBinary . ' --foo ' . escapeshellarg('foovalue') . ' --bar ' . escapeshellarg('barvalue1') . ' --bar ' . escapeshellarg('barvalue2') . ' --baz ' . escapeshellarg('http://the.url/') . ' ' . escapeshellarg('/the/path'),
617
            ],
618
            [
619
                $theBinary,
620
                'http://the.url/',
621
                '/the/path',
622
                [
623
                    'cookie'          => ['session' => 'bla', 'phpsess' => 12],
624
                    'no-background'   => '1',
625
                ],
626
                $theBinary . ' --cookie ' . escapeshellarg('session') . ' ' . escapeshellarg('bla') . ' --cookie ' . escapeshellarg('phpsess') . ' ' . escapeshellarg('12') . ' --no-background ' . escapeshellarg('1') . ' ' . escapeshellarg('http://the.url/') . ' ' . escapeshellarg('/the/path'),
627
            ],
628
            [
629
                $theBinary,
630
                'http://the.url/',
631
                '/the/path',
632
                [
633
                    'allow'           => ['/path1', '/path2'],
634
                    'no-background'   => '1',
635
                ],
636
                $theBinary . ' --allow ' . escapeshellarg('/path1') . ' --allow ' . escapeshellarg('/path2') . ' --no-background ' . escapeshellarg('1') . ' ' . escapeshellarg('http://the.url/') . ' ' . escapeshellarg('/the/path'),
637
            ],
638
            [
639
                $theBinary,
640
                'http://the.url/',
641
                '/the/path',
642
                [
643
                    'image-dpi'     => 100,
644
                    'image-quality' => 50,
645
                ],
646
                $theBinary . ' ' . '--image-dpi 100 --image-quality 50 ' . escapeshellarg('http://the.url/') . ' ' . escapeshellarg('/the/path'),
647
            ],
648
        ];
649
    }
650
651
    public function testCheckOutput()
652
    {
653
        $media = $this->getMockBuilder(AbstractGenerator::class)
654
            ->setMethods([
655
                'configure',
656
                'fileExists',
657
                'filesize',
658
            ])
659
            ->disableOriginalConstructor()
660
            ->getMock()
661
        ;
662
        $media
663
            ->expects($this->once())
664
            ->method('fileExists')
665
            ->with($this->equalTo('the_output_file'))
666
            ->will($this->returnValue(true))
667
        ;
668
        $media
669
            ->expects($this->once())
670
            ->method('filesize')
671
            ->with($this->equalTo('the_output_file'))
672
            ->will($this->returnValue(123))
673
        ;
674
675
        $r = new \ReflectionMethod($media, 'checkOutput');
676
        $r->setAccessible(true);
677
678
        $message = '->checkOutput() checks both file existence and size';
679
680
        try {
681
            $r->invokeArgs($media, ['the_output_file', 'the command']);
682
            $this->anything($message);
0 ignored issues
show
Unused Code introduced by
The call to AbstractGeneratorTest::anything() has too many arguments starting with $message.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
683
        } catch (\RuntimeException $e) {
684
            $this->fail($message);
685
        }
686
    }
687
688
    public function testCheckOutputWhenTheFileDoesNotExist()
689
    {
690
        $media = $this->getMockBuilder(AbstractGenerator::class)
691
            ->setMethods([
692
                'configure',
693
                'fileExists',
694
                'filesize',
695
            ])
696
            ->disableOriginalConstructor()
697
            ->getMock()
698
        ;
699
        $media
700
            ->expects($this->once())
701
            ->method('fileExists')
702
            ->with($this->equalTo('the_output_file'))
703
            ->will($this->returnValue(false))
704
        ;
705
706
        $r = new \ReflectionMethod($media, 'checkOutput');
707
        $r->setAccessible(true);
708
709
        $message = '->checkOutput() throws an InvalidArgumentException when the file does not exist';
710
711
        try {
712
            $r->invokeArgs($media, ['the_output_file', 'the command']);
713
            $this->fail($message);
714
        } catch (\RuntimeException $e) {
715
            $this->anything($message);
0 ignored issues
show
Unused Code introduced by
The call to AbstractGeneratorTest::anything() has too many arguments starting with $message.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
716
        }
717
    }
718
719
    public function testCheckOutputWhenTheFileIsEmpty()
720
    {
721
        $media = $this->getMockBuilder(AbstractGenerator::class)
722
            ->setMethods([
723
                'configure',
724
                'fileExists',
725
                'filesize',
726
            ])
727
            ->disableOriginalConstructor()
728
            ->getMock()
729
        ;
730
731
        $media
732
            ->expects($this->once())
733
            ->method('fileExists')
734
            ->with($this->equalTo('the_output_file'))
735
            ->will($this->returnValue(true))
736
        ;
737
        $media
738
            ->expects($this->once())
739
            ->method('filesize')
740
            ->with($this->equalTo('the_output_file'))
741
            ->will($this->returnValue(0))
742
        ;
743
744
        $r = new \ReflectionMethod($media, 'checkOutput');
745
        $r->setAccessible(true);
746
747
        $message = '->checkOutput() throws an InvalidArgumentException when the file is empty';
748
749
        try {
750
            $r->invokeArgs($media, ['the_output_file', 'the command']);
751
            $this->fail($message);
752
        } catch (\RuntimeException $e) {
753
            $this->anything($message);
0 ignored issues
show
Unused Code introduced by
The call to AbstractGeneratorTest::anything() has too many arguments starting with $message.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
754
        }
755
    }
756
757
    public function testCheckProcessStatus()
758
    {
759
        $media = $this->getMockBuilder(AbstractGenerator::class)
760
            ->setMethods(['configure'])
761
            ->disableOriginalConstructor()
762
            ->getMock()
763
        ;
764
765
        $r = new \ReflectionMethod($media, 'checkProcessStatus');
766
        $r->setAccessible(true);
767
768
        try {
769
            $r->invokeArgs($media, [0, '', '', 'the command']);
770
            $this->anything('0 status means success');
0 ignored issues
show
Unused Code introduced by
The call to AbstractGeneratorTest::anything() has too many arguments starting with '0 status means success'.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
771
        } catch (\RuntimeException $e) {
772
            $this->fail('0 status means success');
773
        }
774
775
        try {
776
            $r->invokeArgs($media, [1, '', '', 'the command']);
777
            $this->anything('1 status means failure, but no stderr content');
0 ignored issues
show
Unused Code introduced by
The call to AbstractGeneratorTest::anything() has too many arguments starting with '1 status means failure, but no stderr content'.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
778
        } catch (\RuntimeException $e) {
779
            $this->fail('1 status means failure, but no stderr content');
780
        }
781
782
        try {
783
            $r->invokeArgs($media, [1, '', 'Could not connect to X', 'the command']);
784
            $this->fail('1 status means failure');
785
        } catch (\RuntimeException $e) {
786
            $this->assertEquals(1, $e->getCode(), 'Exception thrown by checkProcessStatus should pass on the error code');
787
        }
788
    }
789
790
    /**
791
     * @dataProvider dataForIsAssociativeArray
792
     */
793
    public function testIsAssociativeArray($array, $isAssociativeArray)
794
    {
795
        $generator = $this->getMockForAbstractClass('Knp\Snappy\AbstractGenerator', [], '', false);
796
797
        $r = new \ReflectionMethod($generator, 'isAssociativeArray');
798
        $r->setAccessible(true);
799
        $this->assertEquals($isAssociativeArray, $r->invokeArgs($generator, [$array]));
800
    }
801
802
    /**
803
     * @expectedException Knp\Snappy\Exception\FileAlreadyExistsException
804
     */
805
    public function testItThrowsTheProperExceptionWhenFileExistsAndNotOverwritting()
806
    {
807
        $media = $this->getMockBuilder(AbstractGenerator::class)
808
            ->setMethods([
809
                'configure',
810
                'fileExists',
811
                'isFile',
812
            ])
813
            ->disableOriginalConstructor()
814
            ->getMock()
815
        ;
816
817
        $media
818
            ->expects($this->any())
819
            ->method('fileExists')
820
            ->will($this->returnValue(true))
821
        ;
822
        $media
823
            ->expects($this->any())
824
            ->method('isFile')
825
            ->will($this->returnValue(true))
826
        ;
827
        $r = new \ReflectionMethod($media, 'prepareOutput');
828
        $r->setAccessible(true);
829
830
        $r->invokeArgs($media, ['', false]);
831
    }
832
833
    public function dataForIsAssociativeArray()
834
    {
835
        return [
836
            [
837
                ['key' => 'value'],
838
                true,
839
            ],
840
            [
841
                ['key' => 2],
842
                true,
843
            ],
844
            [
845
                ['key' => 'value', 'key2' => 'value2'],
846
                true,
847
            ],
848
            [
849
                [0 => 'value', 1 => 'value2', 'deux' => 'value3'],
850
                true,
851
            ],
852
            [
853
                [0 => 'value'],
854
                false,
855
            ],
856
            [
857
                [0 => 'value', 1 => 'value2', 3 => 'value3'],
858
                false,
859
            ],
860
            [
861
                ['0' => 'value', '1' => 'value2', '3' => 'value3'],
862
                false,
863
            ],
864
            [
865
                [],
866
                false,
867
            ],
868
        ];
869
    }
870
871
    public function testCleanupEmptyTemporaryFiles()
872
    {
873
        $generator = $this->getMockBuilder(AbstractGenerator::class)
874
            ->setMethods([
875
                'configure',
876
                'unlink',
877
            ])
878
            ->setConstructorArgs(['the_binary'])
879
            ->getMock()
880
        ;
881
882
        $generator
883
            ->expects($this->once())
884
            ->method('unlink');
885
886
        $create = new \ReflectionMethod($generator, 'createTemporaryFile');
887
        $create->setAccessible(true);
888
        $create->invoke($generator, null, null);
889
890
        $files = new \ReflectionProperty($generator, 'temporaryFiles');
891
        $files->setAccessible(true);
892
        $this->assertCount(1, $files->getValue($generator));
893
894
        $remove = new \ReflectionMethod($generator, 'removeTemporaryFiles');
895
        $remove->setAccessible(true);
896
        $remove->invoke($generator);
897
    }
898
899
    public function testleanupTemporaryFiles()
900
    {
901
        $generator = $this->getMockBuilder(AbstractGenerator::class)
902
            ->setMethods([
903
                'configure',
904
                'unlink',
905
            ])
906
            ->setConstructorArgs(['the_binary'])
907
            ->getMock()
908
        ;
909
910
        $generator
911
            ->expects($this->once())
912
            ->method('unlink');
913
914
        $create = new \ReflectionMethod($generator, 'createTemporaryFile');
915
        $create->setAccessible(true);
916
        $create->invoke($generator, '<html/>', 'html');
917
918
        $files = new \ReflectionProperty($generator, 'temporaryFiles');
919
        $files->setAccessible(true);
920
        $this->assertCount(1, $files->getValue($generator));
921
922
        $remove = new \ReflectionMethod($generator, 'removeTemporaryFiles');
923
        $remove->setAccessible(true);
924
        $remove->invoke($generator);
925
    }
926
927
    public function testResetOptions()
928
    {
929
        $media = new class('/usr/local/bin/wkhtmltopdf') extends AbstractGenerator {
930
            protected function configure()
931
            {
932
                $this->addOptions([
933
                    'optionA' => null,
934
                    'optionB' => 'abc',
935
                ]);
936
            }
937
        };
938
939
        $media->setOption('optionA', 'bar');
940
941
        $this->assertEquals(
942
            [
943
                'optionA' => 'bar',
944
                'optionB' => 'abc',
945
            ],
946
            $media->getOptions()
947
        );
948
949
        $media->resetOptions();
950
951
        $this->assertEquals(
952
            [
953
                'optionA' => null,
954
                'optionB' => 'abc',
955
            ],
956
            $media->getOptions()
957
        );
958
    }
959
}
960