Skip to content
Open
Show file tree
Hide file tree
Changes from 7 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
3 changes: 1 addition & 2 deletions src/Cache/ResponseTagger/TraceableResponseTagger.php
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
<?php
declare(strict_types=1);
<?php declare(strict_types=1);

namespace Neusta\Pimcore\HttpCacheBundle\Cache\ResponseTagger;

Expand Down
12 changes: 5 additions & 7 deletions src/CacheActivator.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ public function deactivateCaching(): void
/**
* @template T
*
* @param \Closure(): (T|\Generator<int, CacheTag|CacheTags, null, T>) $fn
* @param \Closure(): (T|\Generator<array-key, CacheTag|CacheTags, null, T>) $fn
*
* @return T
*/
Expand All @@ -47,24 +47,22 @@ public function withoutAutomaticTagging(\Closure $fn): mixed
$result = $fn();

if ($result instanceof \Generator) {
$index = 0;
$accumulated = new CacheTags();
Comment thread
jan888adams marked this conversation as resolved.
Outdated
foreach ($result as $key => $yielded) {
++$index;

if (!$yielded instanceof CacheTag && !$yielded instanceof CacheTags) {
Comment thread
jan888adams marked this conversation as resolved.
throw new \LogicException(\sprintf(
'Invalid yielded value at index %d (key: %s): Expected only "%s" or "%s", got "%s".',
$index,
'Invalid yielded value (key: %s): Expected only "%s" or "%s", got "%s".',
Comment thread
jan888adams marked this conversation as resolved.
Outdated
\is_int($key) || \is_string($key) ? $key : get_debug_type($key),
CacheTag::class,
CacheTags::class,
get_debug_type($yielded),
));
}

$tags = $tags->with($yielded);
$accumulated = $accumulated->with($yielded);
}

$tags = $accumulated;
$result = $result->getReturn();
Comment thread
jan888adams marked this conversation as resolved.
Outdated
}
} finally {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ final class TraceableResponseTaggerTest extends TestCase
{
use ProphecyTrait;

private TraceableResponseTagger $collectTagsResponseTagger;
private TraceableResponseTagger $traceableResponseTagger;
Comment thread
jan888adams marked this conversation as resolved.

/** @var ObjectProphecy<ResponseTagger> */
private ObjectProphecy $innerTagger;
Expand Down
147 changes: 146 additions & 1 deletion tests/Unit/CacheActivatorTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,28 @@

namespace Neusta\Pimcore\HttpCacheBundle\Tests\Unit;

use Neusta\Pimcore\HttpCacheBundle\Cache\CacheTag;
use Neusta\Pimcore\HttpCacheBundle\Cache\CacheTags;
use Neusta\Pimcore\HttpCacheBundle\Cache\ResponseTagger;
use Neusta\Pimcore\HttpCacheBundle\CacheActivator;
use PHPUnit\Framework\TestCase;
use Prophecy\Argument;
use Prophecy\PhpUnit\ProphecyTrait;
use Prophecy\Prophecy\ObjectProphecy;

final class CacheActivatorTest extends TestCase
{
use ProphecyTrait;

private CacheActivator $cacheActivator;

/** @var ObjectProphecy<ResponseTagger> */
private ObjectProphecy $responseTagger;

protected function setUp(): void
{
$this->cacheActivator = new CacheActivator();
$this->responseTagger = $this->prophesize(ResponseTagger::class);
$this->cacheActivator = new CacheActivator(fn () => $this->responseTagger->reveal());
}

/**
Expand Down Expand Up @@ -42,4 +54,137 @@ public function it_must_be_activated_after_activateCaching_is_called(): void

self::assertTrue($this->cacheActivator->isCachingActive());
}

/**
* @test
*/
public function without_automatic_tagging_returns_closure_result(): void
{
$result = $this->cacheActivator->withoutAutomaticTagging(static fn () => 'my_result');

self::assertSame('my_result', $result);
}

/**
* @test
*/
public function without_automatic_tagging_disables_caching_during_execution(): void
{
$activator = $this->cacheActivator;
$wasCachingActive = null;

$this->cacheActivator->withoutAutomaticTagging(static function () use ($activator, &$wasCachingActive) {
$wasCachingActive = $activator->isCachingActive();
});

self::assertFalse($wasCachingActive);
}

/**
* @test
*/
public function without_automatic_tagging_restores_caching_state_after_execution(): void
{
$this->cacheActivator->withoutAutomaticTagging(static fn () => null);

self::assertTrue($this->cacheActivator->isCachingActive());
}

/**
* @test
*/
public function without_automatic_tagging_restores_inactive_state_when_caching_was_already_disabled(): void
{
$this->cacheActivator->deactivateCaching();

$this->cacheActivator->withoutAutomaticTagging(static fn () => null);

self::assertFalse($this->cacheActivator->isCachingActive());
}

/**
* @test
*/
public function without_automatic_tagging_restores_caching_state_even_when_closure_throws(): void
{
try {
$this->cacheActivator->withoutAutomaticTagging(static fn () => throw new \RuntimeException('error'));
} catch (\RuntimeException) {
}

self::assertTrue($this->cacheActivator->isCachingActive());
}

/**
* @test
*/
public function without_automatic_tagging_tags_a_yielded_cache_tag(): void
{
$tag = CacheTag::fromString('42');

$this->cacheActivator->withoutAutomaticTagging(static function () use ($tag) {
yield $tag;
});

$this->responseTagger->tag(Argument::that(
static fn (CacheTags $tags) => $tags->toString() === $tag->toString(),
))->shouldHaveBeenCalledOnce();
}

/**
* @test
*/
public function without_automatic_tagging_tags_a_yielded_cache_tags_collection(): void
{
$tags = CacheTags::fromStrings(['17', '42']);

$this->cacheActivator->withoutAutomaticTagging(static function () use ($tags) {
yield $tags;
});

$this->responseTagger->tag(Argument::that(
static fn (CacheTags $t) => $t->toString() === $tags->toString(),
))->shouldHaveBeenCalledOnce();
}

/**
* @test
*/
public function without_automatic_tagging_returns_generator_return_value(): void
{
$result = $this->cacheActivator->withoutAutomaticTagging(static function () {
yield CacheTag::fromString('42');

return 'generator_result';
});

self::assertSame('generator_result', $result);
}

/**
* @test
*/
public function without_automatic_tagging_throws_logic_exception_for_invalid_yield(): void
{
$this->expectException(\LogicException::class);
$this->expectExceptionMessageMatches('/Invalid yielded value \(key: 0\)/');

$this->cacheActivator->withoutAutomaticTagging(static function () {
yield 'not_a_cache_tag';
});
}

/**
* @test
*/
public function without_automatic_tagging_does_not_apply_partial_tags_when_invalid_yield_encountered(): void
{
$this->responseTagger->tag(Argument::any())->shouldNotBeCalled();
$this->expectException(\LogicException::class);

$this->cacheActivator->withoutAutomaticTagging(static function () {
yield CacheTag::fromString('42');
yield 'not_a_cache_tag';
});
}
}