Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
12 / 12
100.00% covered (success)
100.00%
4 / 4
CRAP
100.00% covered (success)
100.00%
1 / 1
BootstrapShimGenerator
100.00% covered (success)
100.00%
12 / 12
100.00% covered (success)
100.00%
4 / 4
4
100.00% covered (success)
100.00%
1 / 1
 __construct
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 generate
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
1
 render
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
1
 export
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
1<?php
2
3declare(strict_types=1);
4
5/**
6 * Fast Forward Development Tools for PHP projects.
7 *
8 * This file is part of fast-forward/dev-tools project.
9 *
10 * @author   Felipe SayĆ£o Lobato Abreu <github@mentordosnerds.com>
11 * @license  https://opensource.org/licenses/MIT MIT License
12 *
13 * @see      https://github.com/php-fast-forward/
14 * @see      https://github.com/php-fast-forward/dev-tools
15 * @see      https://github.com/php-fast-forward/dev-tools/issues
16 * @see      https://php-fast-forward.github.io/dev-tools/
17 * @see      https://datatracker.ietf.org/doc/html/rfc2119
18 */
19
20namespace FastForward\DevTools\PhpUnit\Bootstrap;
21
22use FastForward\DevTools\Filesystem\FilesystemInterface;
23use FastForward\DevTools\Path\DevToolsPathResolver;
24use Symfony\Component\Filesystem\Path;
25
26/**
27 * Generates deterministic PHPUnit bootstrap shims for working-directory test runs.
28 *
29 * The generated shim MUST load the consumer bootstrap first and MAY then load
30 * the active DevTools package autoloader so packaged PHPUnit configuration can
31 * still resolve DevTools-owned extension classes during global installations.
32 */
33  class BootstrapShimGenerator
34{
35    /**
36     * @param FilesystemInterface $filesystem the filesystem used to persist generated shims
37     */
38    public function __construct(
39        private FilesystemInterface $filesystem,
40    ) {}
41
42    /**
43     * Writes a deterministic bootstrap shim under the resolved cache directory.
44     *
45     * @param string $projectBootstrap the consumer-project bootstrap path
46     * @param string $cacheDirectory the cache directory where the shim SHOULD be stored
47     *
48     * @return string the generated bootstrap shim path
49     */
50    public function generate(string $projectBootstrap, string $cacheDirectory): string
51    {
52        $bootstrapShim = Path::join($cacheDirectory, 'bootstrap.php');
53
54        $this->filesystem->dumpFile($bootstrapShim, $this->render($projectBootstrap));
55
56        return $bootstrapShim;
57    }
58
59    /**
60     * Renders the bootstrap shim contents.
61     *
62     * @param string $projectBootstrap the consumer-project bootstrap path
63     *
64     * @return string the bootstrap shim source code
65     */
66    private function render(string $projectBootstrap): string
67    {
68        $devToolsAutoload = DevToolsPathResolver::getRuntimeAutoloadPath();
69
70        return <<<PHP
71            <?php
72
73            declare(strict_types=1);
74
75            require_once {$this->export($projectBootstrap)};
76
77            if (file_exists({$this->export($devToolsAutoload)})) {
78                require_once {$this->export($devToolsAutoload)};
79            }
80            PHP;
81    }
82
83    /**
84     * Escapes a runtime string as a valid PHP string literal.
85     *
86     * @param string $value the value to render as PHP code
87     *
88     * @return string the exported PHP literal
89     */
90    private function export(string $value): string
91    {
92        return var_export($value, true);
93    }
94}