Skip to content

Commit

Permalink
Add test for CollectionAnnotationReader cache
Browse files Browse the repository at this point in the history
  • Loading branch information
clementbirkle committed Jul 27, 2024
1 parent 07eb9f0 commit 72ac7ef
Show file tree
Hide file tree
Showing 2 changed files with 65 additions and 18 deletions.
52 changes: 34 additions & 18 deletions src/Support/Annotations/CollectionAnnotationReader.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ public function __construct(

protected Context $context;

/**
* @param class-string $className
*/
public function getForClass(string $className): ?CollectionAnnotation
{
// Check the cache first
Expand All @@ -33,7 +36,7 @@ public function getForClass(string $className): ?CollectionAnnotation
}

// Create ReflectionClass from class string
$class = new ReflectionClass($className);
$class = $this->getReflectionClass($className);

// Determine if the class is a collection
if (! $this->isCollection($class)) {
Expand Down Expand Up @@ -61,6 +64,36 @@ public function getForClass(string $className): ?CollectionAnnotation
return $annotation;
}

public static function clearCache(): void
{
self::$cache = [];
}

/**
* @param class-string $className
*/
protected function getReflectionClass(string $className): ReflectionClass
{
return new ReflectionClass($className);
}

protected function isCollection(ReflectionClass $class): bool
{
// Check if the class implements common collection interfaces
$collectionInterfaces = [
Iterator::class,
IteratorAggregate::class,
];

foreach ($collectionInterfaces as $interface) {
if ($class->implementsInterface($interface)) {
return true;
}
}

return false;
}

/**
* @return array{keyType: string|null, valueType: string|null}|null
*/
Expand Down Expand Up @@ -128,23 +161,6 @@ protected function getCollectionReturnType(ReflectionClass $class): ?array
return null;
}

protected function isCollection(ReflectionClass $class): bool
{
// Check if the class implements common collection interfaces
$collectionInterfaces = [
Iterator::class,
IteratorAggregate::class,
];

foreach ($collectionInterfaces as $interface) {
if ($class->implementsInterface($interface)) {
return true;
}
}

return false;
}

protected function resolve(string $type): ?string
{
$type = (string) $this->typeResolver->resolve($type, $this->context);
Expand Down
31 changes: 31 additions & 0 deletions tests/Support/Annotations/CollectionAnnotationReaderTest.php
Original file line number Diff line number Diff line change
@@ -1,11 +1,17 @@
<?php

use Illuminate\Support\Collection;
use phpDocumentor\Reflection\TypeResolver;
use Spatie\LaravelData\Resolvers\ContextResolver;
use Spatie\LaravelData\Support\Annotations\CollectionAnnotation;
use Spatie\LaravelData\Support\Annotations\CollectionAnnotationReader;
use Spatie\LaravelData\Tests\Fakes\Enums\DummyBackedEnum;
use Spatie\LaravelData\Tests\Fakes\SimpleData;

beforeEach(function () {
CollectionAnnotationReader::clearCache();
});

it(
'verifies the correct CollectionAnnotation is returned for a given class',
function (string $className, ?CollectionAnnotation $expected) {
Expand Down Expand Up @@ -100,6 +106,31 @@ function (string $className, ?CollectionAnnotation $expected) {
];
});

it('can caches the result', function (string $className) {

// Create a partial mock
$collectionAnnotationReader = Mockery::spy(CollectionAnnotationReader::class, [
app(ContextResolver::class),
app(TypeResolver::class),
])->makePartial();

// Call the getForClass method with a test class
$collectionAnnotation = $collectionAnnotationReader->getForClass($className);

// Call the getForClass method again to test caching
$cachedCollectionAnnotation = $collectionAnnotationReader->getForClass($className);

// Assert the cache is used and the same annotation is returned
expect($cachedCollectionAnnotation)->toBe($collectionAnnotation);

// Check if getReflectionClass was called only once
$collectionAnnotationReader->shouldHaveReceived('getReflectionClass')->once();

})->with([
[CollectionWhoImplementsNothing::class], // first return
[CollectionWithoutDocBlock::class], // second return
[DataCollectionWithTemplate::class], // third return
]);

/**
* @template TKey of array-key
Expand Down

0 comments on commit 72ac7ef

Please sign in to comment.