isSubclassOf(ResourceProviderBaseInterface::class)); self::assertTrue((new ReflectionClass(SystemStoreServiceInterface::class))->isSubclassOf(ResourceServiceBaseInterface::class)); } #[Test] public function listingIsAProviderPaginatedIterable(): void { $method = (new ReflectionClass(SystemStoreServiceInterface::class))->getMethod('list'); self::assertSame('iterable', (string) $method->getReturnType()); self::assertCount(1, $method->getParameters()); } #[Test] public function createsSupportedWriteConditions(): void { self::assertSame(WriteCondition::NONE, WriteCondition::none()->mode); self::assertSame(WriteCondition::IF_ABSENT, WriteCondition::ifAbsent()->mode); $condition = WriteCondition::ifMatch('revision-1'); self::assertSame(WriteCondition::IF_MATCH, $condition->mode); self::assertSame('revision-1', $condition->etag); } #[Test] public function rejectsAnEmptyIfMatchEtag(): void { $this->expectException(InvalidArgumentException::class); WriteCondition::ifMatch(''); } #[Test] public function serializesMetadata(): void { $metadata = new BlobInfo( key: 'previews/example.webp', mimeType: 'image/webp', size: 123, etag: 'revision-1', modifiedAt: new DateTimeImmutable('2026-08-28T12:00:00+00:00'), attributes: ['variant' => 'popover'], ); self::assertSame([ 'key' => 'previews/example.webp', 'mime' => 'image/webp', 'size' => 123, 'etag' => 'revision-1', 'modifiedAt' => '2026-08-28T12:00:00+00:00', 'attributes' => ['variant' => 'popover'], ], $metadata->jsonSerialize()); } }