Skip to content

Commit 3ffcccc

Browse files
committed
Add unit tests
1 parent 4633aa0 commit 3ffcccc

File tree

1 file changed

+161
-0
lines changed

1 file changed

+161
-0
lines changed

tests/AggregateContainerTest.php

Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/**
6+
* This file is part of php-fast-forward/container.
7+
*
8+
* This source file is subject to the license bundled
9+
* with this source code in the file LICENSE.
10+
*
11+
* @link https://github.com/php-fast-forward/container
12+
* @copyright Copyright (c) 2025 Felipe Sayão Lobato Abreu <github@mentordosnerds.com>
13+
* @license https://opensource.org/licenses/MIT MIT License
14+
*/
15+
16+
namespace FastForward\Container\Tests;
17+
18+
use FastForward\Container\AggregateContainer;
19+
use FastForward\Container\Exception\NotFoundException;
20+
use PHPUnit\Framework\Attributes\CoversClass;
21+
use PHPUnit\Framework\Attributes\Test;
22+
use PHPUnit\Framework\Attributes\UsesClass;
23+
use PHPUnit\Framework\TestCase;
24+
use Prophecy\PhpUnit\ProphecyTrait;
25+
use Psr\Container\ContainerExceptionInterface;
26+
use Psr\Container\ContainerInterface;
27+
use Psr\Container\NotFoundExceptionInterface;
28+
29+
/**
30+
* @internal
31+
*/
32+
#[CoversClass(AggregateContainer::class)]
33+
#[UsesClass(NotFoundException::class)]
34+
final class AggregateContainerTest extends TestCase
35+
{
36+
use ProphecyTrait;
37+
38+
#[Test]
39+
public function testHasReturnsTrueForAliasAndClassBindings(): void
40+
{
41+
$container = new AggregateContainer();
42+
43+
self::assertTrue($container->has(AggregateContainer::ALIAS));
44+
self::assertTrue($container->has(AggregateContainer::class));
45+
self::assertTrue($container->has(ContainerInterface::class));
46+
}
47+
48+
#[Test]
49+
public function testHasReturnsFalseForUnknownKey(): void
50+
{
51+
$container = new AggregateContainer();
52+
53+
self::assertFalse($container->has(uniqid('unknown_', true)));
54+
}
55+
56+
#[Test]
57+
public function testGetReturnsSelfForAliasAndClassBindings(): void
58+
{
59+
$container = new AggregateContainer();
60+
61+
self::assertSame($container, $container->get(AggregateContainer::ALIAS));
62+
self::assertSame($container, $container->get(AggregateContainer::class));
63+
self::assertSame($container, $container->get(ContainerInterface::class));
64+
}
65+
66+
#[Test]
67+
public function testHasReturnsTrueIfSubContainerHasEntry(): void
68+
{
69+
$key = uniqid('svc_', true);
70+
71+
$sub = $this->prophesize(ContainerInterface::class);
72+
$sub->has($key)->willReturn(true);
73+
74+
$container = new AggregateContainer($sub->reveal());
75+
76+
self::assertTrue($container->has($key));
77+
}
78+
79+
#[Test]
80+
public function testGetReturnsResolvedEntryFromSubContainer(): void
81+
{
82+
$key = uniqid('dep_', true);
83+
$value = uniqid('value_', true);
84+
85+
$sub = $this->prophesize(ContainerInterface::class);
86+
$sub->has($key)->willReturn(true);
87+
$sub->get($key)->willReturn($value);
88+
89+
$container = new AggregateContainer($sub->reveal());
90+
91+
self::assertSame($value, $container->get($key));
92+
self::assertSame($value, $container->get($key)); // ensures internal caching
93+
}
94+
95+
#[Test]
96+
public function testGetSkipsContainersThrowingNotFoundException(): void
97+
{
98+
$key = uniqid('missing_', true);
99+
$value = uniqid('fallback_', true);
100+
101+
$first = $this->prophesize(ContainerInterface::class);
102+
$first->has($key)->willReturn(true);
103+
$first->get($key)->willThrow(NotFoundException::class);
104+
105+
$second = $this->prophesize(ContainerInterface::class);
106+
$second->has($key)->willReturn(true);
107+
$second->get($key)->willReturn($value);
108+
109+
$container = new AggregateContainer($first->reveal(), $second->reveal());
110+
111+
self::assertSame($value, $container->get($key));
112+
}
113+
114+
#[Test]
115+
public function testGetSkipsContainersThrowingStandardInterfaces(): void
116+
{
117+
$key = uniqid('service_', true);
118+
$value = new \stdClass();
119+
120+
$nf = new class extends \Exception implements NotFoundExceptionInterface {};
121+
$ce = new class extends \Exception implements ContainerExceptionInterface {};
122+
123+
$first = $this->prophesize(ContainerInterface::class);
124+
$first->has($key)->willReturn(true);
125+
$first->get($key)->willThrow($nf);
126+
127+
$second = $this->prophesize(ContainerInterface::class);
128+
$second->has($key)->willReturn(true);
129+
$second->get($key)->willThrow($ce);
130+
131+
$third = $this->prophesize(ContainerInterface::class);
132+
$third->has($key)->willReturn(true);
133+
$third->get($key)->willReturn($value);
134+
135+
$container = new AggregateContainer(
136+
$first->reveal(),
137+
$second->reveal(),
138+
$third->reveal(),
139+
);
140+
141+
self::assertSame($value, $container->get($key));
142+
}
143+
144+
#[Test]
145+
public function testGetThrowsWhenNoContainerCanResolve(): void
146+
{
147+
$this->expectException(NotFoundException::class);
148+
149+
$key = uniqid('unavailable_', true);
150+
151+
$c1 = $this->prophesize(ContainerInterface::class);
152+
$c1->has($key)->willReturn(false);
153+
154+
$c2 = $this->prophesize(ContainerInterface::class);
155+
$c2->has($key)->willReturn(false);
156+
157+
$container = new AggregateContainer($c1->reveal(), $c2->reveal());
158+
159+
$container->get($key);
160+
}
161+
}

0 commit comments

Comments
 (0)