Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: load needed information only during interface inferring #511

Merged
merged 1 commit into from
Mar 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/Mapper/Tree/Builder/InterfaceNodeBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ public function build(Shell $shell, RootNodeBuilder $rootBuilder): TreeNode
try {
$classType = $this->implementations->implementation($className, $values);
} catch (ObjectImplementationCallbackError $exception) {
throw UserlandError::from($exception->original());
throw UserlandError::from($exception);
}

$class = $this->classDefinitionRepository->for($classType);
Expand Down
26 changes: 10 additions & 16 deletions src/Mapper/Tree/Builder/ObjectImplementations.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,21 @@

use CuyZ\Valinor\Definition\FunctionDefinition;
use CuyZ\Valinor\Definition\FunctionsContainer;
use CuyZ\Valinor\Mapper\Tree\Exception\InvalidAbstractObjectName;
use CuyZ\Valinor\Mapper\Tree\Exception\InvalidResolvedImplementationValue;
use CuyZ\Valinor\Mapper\Tree\Exception\MissingObjectImplementationRegistration;
use CuyZ\Valinor\Mapper\Tree\Exception\ObjectImplementationCallbackError;
use CuyZ\Valinor\Mapper\Tree\Exception\ObjectImplementationNotRegistered;
use CuyZ\Valinor\Mapper\Tree\Exception\ResolvedImplementationIsNotAccepted;
use CuyZ\Valinor\Type\ClassType;
use CuyZ\Valinor\Type\Parser\Exception\InvalidType;
use CuyZ\Valinor\Type\Parser\TypeParser;
use CuyZ\Valinor\Type\Type;
use CuyZ\Valinor\Type\Types\ClassStringType;
use CuyZ\Valinor\Type\Types\InterfaceType;
use CuyZ\Valinor\Type\Types\UnionType;
use Exception;

use function assert;

/** @internal */
final class ObjectImplementations
{
Expand All @@ -30,12 +30,7 @@ final class ObjectImplementations
public function __construct(
private FunctionsContainer $functions,
private TypeParser $typeParser
) {
foreach ($functions as $name => $function) {
/** @var string $name */
$this->implementations[$name] = $this->implementations($name);
}
}
) {}

public function has(string $name): bool
{
Expand All @@ -52,6 +47,9 @@ public function function(string $name): FunctionDefinition
*/
public function implementation(string $name, array $arguments): ClassType
{
/** @infection-ignore-all / We cannot test the assignment */
$this->implementations[$name] ??= $this->implementations($name);

$class = $this->call($name, $arguments);

return $this->implementations[$name][$class]
Expand Down Expand Up @@ -83,18 +81,14 @@ private function implementations(string $name): array
{
$function = $this->functions->get($name)->definition;

try {
$type = $this->typeParser->parse($name);
} catch (InvalidType) {
}
$type = $this->typeParser->parse($name);

if (! isset($type) || (! $type instanceof InterfaceType && ! $type instanceof ClassType)) {
throw new InvalidAbstractObjectName($name);
}
/** @infection-ignore-all */
assert($type instanceof InterfaceType || $type instanceof ClassType);

$classes = $this->implementationsByReturnSignature($name, $function);

if (empty($classes)) {
if ($classes === []) {
throw new MissingObjectImplementationRegistration($name, $function);
}

Expand Down
2 changes: 1 addition & 1 deletion tests/Integration/Cache/CacheInjectionTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ public function test_cache_entries_are_written_once_during_mapping(): void

$files = $this->recursivelyFindPhpFiles($cacheDirectory);

self::assertCount(6, $files);
self::assertCount(4, $files);

foreach ($files as $file) {
$file->setContent($file->getContent() . "\n// generated value 1661895014");
Expand Down
4 changes: 2 additions & 2 deletions tests/Integration/Cache/CacheWarmupTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,8 @@ public function test_will_warmup_type_parser_cache_for_object_with_constructor()
$mapper->warmup(ObjectToWarmupWithConstructors::class);
$mapper->warmup(ObjectToWarmupWithConstructors::class, SomeObjectC::class);

self::assertSame(7, $this->cache->countEntries());
self::assertSame(7, $this->cache->timeSetWasCalled());
self::assertSame(6, $this->cache->countEntries());
self::assertSame(6, $this->cache->timeSetWasCalled());
}

public function test_will_warmup_type_parser_cache_for_interface(): void
Expand Down
49 changes: 2 additions & 47 deletions tests/Integration/Mapping/InterfaceInferringMappingTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,11 @@

use CuyZ\Valinor\Mapper\MappingError;
use CuyZ\Valinor\Mapper\Tree\Exception\CannotResolveObjectType;
use CuyZ\Valinor\Mapper\Tree\Exception\InvalidAbstractObjectName;
use CuyZ\Valinor\Mapper\Tree\Exception\InvalidResolvedImplementationValue;
use CuyZ\Valinor\Mapper\Tree\Exception\MissingObjectImplementationRegistration;
use CuyZ\Valinor\Mapper\Tree\Exception\ObjectImplementationCallbackError;
use CuyZ\Valinor\Mapper\Tree\Exception\ObjectImplementationNotRegistered;
use CuyZ\Valinor\Mapper\Tree\Exception\ResolvedImplementationIsNotAccepted;
use CuyZ\Valinor\Tests\Fake\Mapper\Tree\Message\FakeErrorMessage;
use CuyZ\Valinor\Tests\Fixture\Object\InterfaceWithDifferentNamespaces\A\ClassThatInheritsInterfaceA;
use CuyZ\Valinor\Tests\Fixture\Object\InterfaceWithDifferentNamespaces\B\ClassThatInheritsInterfaceB;
use CuyZ\Valinor\Tests\Fixture\Object\InterfaceWithDifferentNamespaces\ClassWithBothInterfaces;
Expand Down Expand Up @@ -279,30 +277,6 @@ public function test_object_implementation_callback_error_throws_exception(): vo
->map(DateTimeInterface::class, []);
}

public function test_invalid_abstract_object_name_throws_exception(): void
{
$this->expectException(InvalidAbstractObjectName::class);
$this->expectExceptionCode(1653990369);
$this->expectExceptionMessage('Invalid interface or class name `invalid type`.');

$this->mapperBuilder()
->infer('invalid type', fn () => stdClass::class) // @phpstan-ignore-line
->mapper()
->map(stdClass::class, []);
}

public function test_invalid_abstract_object_type_throws_exception(): void
{
$this->expectException(InvalidAbstractObjectName::class);
$this->expectExceptionCode(1653990369);
$this->expectExceptionMessage('Invalid interface or class name `string`.');

$this->mapperBuilder()
->infer('string', fn () => stdClass::class) // @phpstan-ignore-line
->mapper()
->map(stdClass::class, []);
}

public function test_missing_object_implementation_registration_throws_exception(): void
{
$this->expectException(MissingObjectImplementationRegistration::class);
Expand All @@ -315,7 +289,7 @@ public function test_missing_object_implementation_registration_throws_exception
fn (string $type) => SomeClassThatInheritsInterfaceA::class
)
->mapper()
->map(SomeInterface::class, []);
->map(SomeInterface::class, 'foo');
}

public function test_invalid_union_object_implementation_registration_throws_exception(): void
Expand All @@ -330,7 +304,7 @@ public function test_invalid_union_object_implementation_registration_throws_exc
fn (string $value): string|int => $value === 'foo' ? 'foo' : 42
)
->mapper()
->map(SomeInterface::class, []);
->map(SomeInterface::class, 'foo');
}

public function test_invalid_class_string_object_implementation_registration_throws_exception(): void
Expand Down Expand Up @@ -402,25 +376,6 @@ public function test_invalid_source_value_throws_exception(): void
}
}

public function test_exception_thrown_is_caught_and_throws_message_exception(): void
{
try {
$this->mapperBuilder()
->infer(
DateTimeInterface::class,
/** @return class-string<DateTime> */
fn (string $value) => throw new FakeErrorMessage('some error message', 1645303304)
)
->mapper()
->map(DateTimeInterface::class, 'foo');
} catch (MappingError $exception) {
$error = $exception->node()->messages()[0];

self::assertSame('1645303304', $error->code());
self::assertSame('some error message', (string)$error);
}
}

public function test_superfluous_values_throws_exception(): void
{
try {
Expand Down
Loading