Completed
Push — master ( 9af8a4...8336df )
by Marco
11s
created

FatalPreventionFunctionalTest::getTestedClasses()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 26

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 26
rs 9.504
c 0
b 0
f 0
cc 1
nc 1
nop 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace ProxyManagerTest\Functional;
6
7
use PHPUnit\Framework\TestCase;
8
use ProxyManager\Exception\ExceptionInterface;
9
use ProxyManager\Generator\ClassGenerator;
10
use ProxyManager\GeneratorStrategy\EvaluatingGeneratorStrategy;
11
use ProxyManager\Proxy\ProxyInterface;
12
use ProxyManager\ProxyGenerator\AccessInterceptorScopeLocalizerGenerator;
13
use ProxyManager\ProxyGenerator\AccessInterceptorValueHolderGenerator;
14
use ProxyManager\ProxyGenerator\LazyLoadingGhostGenerator;
15
use ProxyManager\ProxyGenerator\LazyLoadingValueHolderGenerator;
16
use ProxyManager\ProxyGenerator\NullObjectGenerator;
17
use ProxyManager\ProxyGenerator\ProxyGeneratorInterface;
18
use ProxyManager\ProxyGenerator\RemoteObjectGenerator;
19
use ProxyManager\Signature\ClassSignatureGenerator;
20
use ProxyManager\Signature\SignatureGenerator;
21
use ReflectionClass;
22
use ReflectionException;
23
use function array_filter;
24
use function array_map;
25
use function array_merge;
26
use function get_declared_classes;
27
use function realpath;
28
use function strpos;
29
use function uniqid;
30
31
/**
32
 * Verifies that proxy-manager will not attempt to `eval()` code that will cause fatal errors
33
 *
34
 * @group Functional
35
 * @coversNothing
36
 */
37
class FatalPreventionFunctionalTest extends TestCase
38
{
39
    /**
40
     * Verifies that code generation and evaluation will not cause fatals with any given class
41
     *
42
     * @param string $generatorClass an instantiable class (no arguments) implementing
43
     *                               the {@see \ProxyManager\ProxyGenerator\ProxyGeneratorInterface}
44
     * @param string $className      a valid (existing/autoloadable) class name
45
     *
46
     * @dataProvider getTestedClasses
47
     */
48
    public function testCodeGeneration(string $generatorClass, string $className) : void
49
    {
50
        $generatedClass    = new ClassGenerator(uniqid('generated'));
51
        $generatorStrategy = new EvaluatingGeneratorStrategy();
52
        /** @var ProxyGeneratorInterface $classGenerator */
53
        $classGenerator          = new $generatorClass();
54
        $classSignatureGenerator = new ClassSignatureGenerator(new SignatureGenerator());
55
56
        try {
57
            $classGenerator->generate(new ReflectionClass($className), $generatedClass);
58
            $classSignatureGenerator->addSignature($generatedClass, ['eval tests']);
59
            $generatorStrategy->generate($generatedClass);
60
        } catch (ExceptionInterface $e) {
61
            // empty catch: this is actually a supported failure
62
        } catch (ReflectionException $e) {
63
            // empty catch: this is actually a supported failure
64
        }
65
66
        self::assertTrue(true, 'Code generation succeeded: proxy is valid or couldn\'t be generated at all');
67
    }
68
69
    /**
70
     * @return string[][]
71
     */
72
    public function getTestedClasses() : array
73
    {
74
        $that = $this;
75
76
        return array_merge(
77
            [],
78
            ...array_map(
79
                function ($generator) use ($that) : array {
80
                    return array_map(
81
                        function ($class) use ($generator) : array {
82
                            return [$generator, $class];
83
                        },
84
                        $that->getProxyTestedClasses()
85
                    );
86
                },
87
                [
88
                    AccessInterceptorScopeLocalizerGenerator::class,
89
                    AccessInterceptorValueHolderGenerator::class,
90
                    LazyLoadingGhostGenerator::class,
91
                    LazyLoadingValueHolderGenerator::class,
92
                    NullObjectGenerator::class,
93
                    RemoteObjectGenerator::class,
94
                ]
95
            )
96
        );
97
    }
98
99
    /**
100
     * @private (public only for PHP 5.3 compatibility)
101
     *
102
     * @return string[]
103
     */
104
    public function getProxyTestedClasses() : array
105
    {
106
        $skippedPaths = [
107
            realpath(__DIR__ . '/../../../src'),
108
            realpath(__DIR__ . '/../../../vendor'),
109
            realpath(__DIR__ . '/../../ProxyManagerTest'),
110
        ];
111
112
        return array_filter(
113
            get_declared_classes(),
114
            function ($className) use ($skippedPaths) : bool {
115
                $reflectionClass = new ReflectionClass($className);
116
                $fileName        = $reflectionClass->getFileName();
117
118
                if (! $fileName) {
119
                    return false;
120
                }
121
122
                if ($reflectionClass->implementsInterface(ProxyInterface::class)) {
123
                    return false;
124
                }
125
126
                $realPath = realpath($fileName);
127
128
                self::assertInternalType('string', $realPath);
129
130
                foreach ($skippedPaths as $skippedPath) {
131
                    self::assertInternalType('string', $skippedPath);
132
133
                    if (strpos($realPath, $skippedPath) === 0) {
134
                        // skip classes defined within ProxyManager, vendor or the test suite
135
                        return false;
136
                    }
137
                }
138
139
                return true;
140
            }
141
        );
142
    }
143
}
144