From fecb4676c351d61db7c444084cea171ddff583a2 Mon Sep 17 00:00:00 2001 From: lgrossi Date: Fri, 5 May 2023 17:22:55 +0200 Subject: [PATCH] Fix subnamespace when there is no namespace to avoid issues with the base class When creating a new build configuration without namespace and adding later on a subnamespace to it (e.g. using getTestContainer() will add a subnamespace 'Test') the dumped file will have an invalid namespace '\Test' and that will make the di compiler fail. --- .gitignore | 1 + bin/phpunit | 123 +++++++++++++++++++++ src/Config/ContainerConfiguration.php | 2 +- test/Config/ContainerConfigurationTest.php | 30 +++++ 4 files changed, 155 insertions(+), 1 deletion(-) create mode 100755 bin/phpunit diff --git a/.gitignore b/.gitignore index 4aacdff9..54185a9a 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,4 @@ /infection.log /.phpunit.cache /build +/.idea \ No newline at end of file diff --git a/bin/phpunit b/bin/phpunit new file mode 100755 index 00000000..e92cddc5 --- /dev/null +++ b/bin/phpunit @@ -0,0 +1,123 @@ +#!/usr/bin/env php +realpath = realpath($opened_path) ?: $opened_path; + $opened_path = 'phpvfscomposer://'.$this->realpath; + $this->handle = fopen($this->realpath, $mode); + $this->position = 0; + + return (bool) $this->handle; + } + + public function stream_read($count) + { + $data = fread($this->handle, $count); + + if ($this->position === 0) { + $data = preg_replace('{^#!.*\r?\n}', '', $data); + } + $data = str_replace('__DIR__', var_export(dirname($this->realpath), true), $data); + $data = str_replace('__FILE__', var_export($this->realpath, true), $data); + + $this->position += strlen($data); + + return $data; + } + + public function stream_cast($castAs) + { + return $this->handle; + } + + public function stream_close() + { + fclose($this->handle); + } + + public function stream_lock($operation) + { + return $operation ? flock($this->handle, $operation) : true; + } + + public function stream_seek($offset, $whence) + { + if (0 === fseek($this->handle, $offset, $whence)) { + $this->position = ftell($this->handle); + return true; + } + + return false; + } + + public function stream_tell() + { + return $this->position; + } + + public function stream_eof() + { + return feof($this->handle); + } + + public function stream_stat() + { + return array(); + } + + public function stream_set_option($option, $arg1, $arg2) + { + return true; + } + + public function url_stat($path, $flags) + { + $path = substr($path, 17); + if (file_exists($path)) { + return stat($path); + } + + return false; + } + } + } + + if ( + (function_exists('stream_get_wrappers') && in_array('phpvfscomposer', stream_get_wrappers(), true)) + || (function_exists('stream_wrapper_register') && stream_wrapper_register('phpvfscomposer', 'Composer\BinProxyWrapper')) + ) { + include("phpvfscomposer://" . __DIR__ . '/..'.'/phpunit/phpunit/phpunit'); + exit(0); + } +} + +include __DIR__ . '/..'.'/phpunit/phpunit/phpunit'; diff --git a/src/Config/ContainerConfiguration.php b/src/Config/ContainerConfiguration.php index 1561a782..fd561c02 100644 --- a/src/Config/ContainerConfiguration.php +++ b/src/Config/ContainerConfiguration.php @@ -196,7 +196,7 @@ public function getDumpOptions(): array { $options = [ 'class' => self::CLASS_NAME, - 'namespace' => $this->namespace, + 'namespace' => ltrim($this->namespace, '\\'), ]; if ($this->baseClass !== null) { diff --git a/test/Config/ContainerConfigurationTest.php b/test/Config/ContainerConfigurationTest.php index 61f24551..f154185e 100644 --- a/test/Config/ContainerConfigurationTest.php +++ b/test/Config/ContainerConfigurationTest.php @@ -318,6 +318,36 @@ public function getDumpOptionsShouldIncludeBaseWhenWasConfigured(): void self::assertSame($options, $config->getDumpOptions()); } + #[PHPUnit\Test] + public function getDumpOptionsNamespaceShouldNeverStartWithBackSlash(): void + { + $config = new ContainerConfiguration('\\MyApp'); + $config->setBaseClass('Test'); + + $options = [ + 'class' => ContainerConfiguration::CLASS_NAME, + 'namespace' => 'MyApp', + 'base_class' => '\\Test', + 'hot_path_tag' => 'container.hot_path', + ]; + + self::assertSame($options, $config->getDumpOptions()); + } + + #[PHPUnit\Test] + public function getDumpOptionsNamespaceShouldAcceptSubNamespaceWithoutMainNamespace(): void + { + $config =(new ContainerConfiguration(''))->withSubNamespace('Test'); + + $options = [ + 'class' => ContainerConfiguration::CLASS_NAME, + 'namespace' => 'Test', + 'hot_path_tag' => 'container.hot_path', + ]; + + self::assertSame($options, $config->getDumpOptions()); + } + #[PHPUnit\Test] public function withAddedNamespaceShouldModifyTheNamespaceOfANewInstanceOnly(): void {