Skip to content
Open
Show file tree
Hide file tree
Changes from 9 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
9 changes: 2 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,14 +47,10 @@ public function withoutAutomaticTagging(\Closure $fn): mixed
$result = $fn();

if ($result instanceof \Generator) {
$index = 0;
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,
Expand All @@ -64,7 +60,6 @@ public function withoutAutomaticTagging(\Closure $fn): mixed

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

$result = $result->getReturn();
}
} finally {
Expand Down
16 changes: 8 additions & 8 deletions tests/Unit/Cache/ResponseTagger/TraceableResponseTaggerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,31 +14,31 @@ 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;

protected function setUp(): void
{
$this->innerTagger = $this->prophesize(ResponseTagger::class);
$this->collectTagsResponseTagger = new TraceableResponseTagger($this->innerTagger->reveal());
$this->traceableResponseTagger = new TraceableResponseTagger($this->innerTagger->reveal());
}

/**
* @test
*/
public function tag_should_collect_tags(): void
{
$this->collectTagsResponseTagger->tag(
$this->traceableResponseTagger->tag(
new CacheTags(
CacheTag::fromString('tag1'),
CacheTag::fromString('tag2'),
));

self::assertSame(
'tag1,tag2',
$this->collectTagsResponseTagger->recordedTags->toString(),
$this->traceableResponseTagger->recordedTags->toString(),
);
}

Expand All @@ -52,7 +52,7 @@ public function tag_should_forward_tags_to_inner_tagger(): void
CacheTag::fromString('tag2'),
);

$this->collectTagsResponseTagger->tag($tags);
$this->traceableResponseTagger->tag($tags);

$this->innerTagger->tag($tags)->shouldHaveBeenCalledOnce();
}
Expand All @@ -62,16 +62,16 @@ public function tag_should_forward_tags_to_inner_tagger(): void
*/
public function reset_should_reset_collected_tags(): void
{
$this->collectTagsResponseTagger->tag(
$this->traceableResponseTagger->tag(
new CacheTags(
CacheTag::fromString('tag1'),
CacheTag::fromString('tag2'),
));

$this->collectTagsResponseTagger->reset();
$this->traceableResponseTagger->reset();

self::assertTrue(
$this->collectTagsResponseTagger->recordedTags->isEmpty(),
$this->traceableResponseTagger->recordedTags->isEmpty(),
);
}
}
134 changes: 133 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,124 @@ 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';
});
}

}