* @license http://www.opensource.org/licenses/mit-license.html MIT License * @version 5.2 * @link https://git.timshome.page/timw4mail/HummingBirdAnimeClient */ namespace Aviat\Ion\Tests\Di; use Aviat\Ion\Di\ContainerInterface; use Aviat\Ion\Di\Exception\{ContainerException, NotFoundException}; use Aviat\Ion\Di\{Container, ContainerAware}; use Aviat\Ion\Tests\IonTestCase; use Monolog\Handler\{NullHandler, TestHandler}; use Monolog\Logger; use PHPUnit\Framework\Attributes\DataProvider; use Throwable; use TypeError; /** * @internal */ final class FooTest { public function __construct(public $item) { } } class FooTest2 { use ContainerAware; } /** * @internal */ final class ContainerTest extends IonTestCase { protected function setUp(): void { $this->container = new Container(); } public static function dataGetWithException(): array { return [ 'Bad index type: number' => [ 'id' => 42, 'exception' => TypeError::class, ], 'Bad index type: array' => [ 'id' => [], 'exception' => TypeError::class, ], 'Non-existent id' => [ 'id' => 'foo', 'exception' => NotFoundException::class, 'message' => "Item 'foo' does not exist in container.", ], ]; } #[DataProvider('dataGetWithException')] public function testGetWithException(mixed $id, mixed $exception, ?string $message = NULL): void { try { $this->container->get($id); } catch (ContainerException $e) { $this->assertInstanceOf($exception, $e); $this->assertSame($message, $e->getMessage()); } catch (Throwable $e) { $this->assertInstanceOf($exception, $e); } } #[DataProvider('dataGetWithException')] public function testGetNewWithException(mixed $id, mixed $exception, ?string $message = NULL): void { $this->expectException($exception); if ($message !== NULL) { $this->expectExceptionMessage($message); } $this->container->getNew($id); } public static function dataSetInstanceWithException(): array { return [ 'Non-existent id' => [ 'id' => 'foo', 'exception' => NotFoundException::class, 'message' => "Factory 'foo' does not exist in container. Set that first.", ], 'Non-existent id 2' => [ 'id' => 'foobarbaz', 'exception' => NotFoundException::class, 'message' => "Factory 'foobarbaz' does not exist in container. Set that first.", ], ]; } #[DataProvider('dataSetInstanceWithException')] public function testSetInstanceWithException(mixed $id, mixed $exception, mixed $message): void { try { $this->container->setInstance($id, NULL); } catch (ContainerException $e) { $this->assertInstanceOf($exception, $e); $this->assertSame($message, $e->getMessage()); } } public function testGetNew(): void { $this->container->set('footest', static fn ($item) => new FooTest($item)); // Check that the item is the container, if called without arguments $footest1 = $this->container->getNew('footest'); $this->assertInstanceOf(ContainerInterface::class, $footest1->item); $footest2 = $this->container->getNew('footest', ['Test String']); $this->assertSame('Test String', $footest2->item); } public function testSetContainerInInstance(): void { $this->container->set('footest2', static fn () => new FooTest2()); $footest2 = $this->container->get('footest2'); $this->assertSame($this->container, $footest2->getContainer()); } public function testGetNewReturnCallable(): void { $this->container->set('footest', static fn ($item) => static fn () => $item); // Check that the item is the container, if called without arguments $footest1 = $this->container->getNew('footest'); $this->assertInstanceOf(ContainerInterface::class, $footest1()); $footest2 = $this->container->getNew('footest', ['Test String']); $this->assertSame('Test String', $footest2()); } public function testGetSet(): void { $container = $this->container->set('foo', static fn () => static function (): void {}); $this->assertInstanceOf(Container::class, $container); $this->assertInstanceOf(ContainerInterface::class, $container); // The factory returns a callable $this->assertIsCallable($container->get('foo')); } public function testLoggerMethods(): void { // Does the container have the default logger? $this->assertFalse($this->container->hasLogger()); $this->assertFalse($this->container->hasLogger('default')); $logger1 = new Logger('default'); $logger2 = new Logger('testing'); $logger1->pushHandler(new NullHandler()); $logger2->pushHandler(new TestHandler()); // Set the logger channels $container = $this->container->setLogger($logger1); $container2 = $this->container->setLogger($logger2, 'test'); $this->assertInstanceOf(ContainerInterface::class, $container); $this->assertInstanceOf(Container::class, $container2); $this->assertSame($logger1, $this->container->getLogger('default')); $this->assertSame($logger2, $this->container->getLogger('test')); $this->assertNull($this->container->getLogger('foo')); $this->assertTrue($this->container->hasLogger()); $this->assertTrue($this->container->hasLogger('default')); $this->assertTrue($this->container->hasLogger('test')); } }