/
githubmirror
/
symfony
Обзор
Документация
Войти
/
githubmirror
/
symfony
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
8.2
src/Symfony/Component/JsonStreamer/Tests/JsonStreamWriterTest.php
625 строк
26 KB
Nicolas Grekas
Merge branch '8.1' into 8.2
01 авг 2026, 19:09
01 авг 2026, 19:09
11635ef
Код
Авторство
О чём код?
<?php /* * This file is part of the Symfony package. * * (c) Fabien Potencier <fabien@symfony.com> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\JsonStreamer\Tests; use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\Attributes\RequiresPhpExtension; use PHPUnit\Framework\TestCase; use Symfony\Component\DependencyInjection\Container; use Symfony\Component\JsonStreamer\Exception\NotEncodableValueException; use Symfony\Component\JsonStreamer\JsonStreamWriter; use Symfony\Component\JsonStreamer\Tests\Fixtures\Enum\DummyBackedEnum; use Symfony\Component\JsonStreamer\Tests\Fixtures\Mapping\SyntheticPropertyMetadataLoader; use Symfony\Component\JsonStreamer\Tests\Fixtures\Model\ClassicDummy; use Symfony\Component\JsonStreamer\Tests\Fixtures\Model\DummyWithArray; use Symfony\Component\JsonStreamer\Tests\Fixtures\Model\DummyWithBcMathNumber; use Symfony\Component\JsonStreamer\Tests\Fixtures\Model\DummyWithDateIntervals; use Symfony\Component\JsonStreamer\Tests\Fixtures\Model\DummyWithDateTimes; use Symfony\Component\JsonStreamer\Tests\Fixtures\Model\DummyWithDateTimeZones; use Symfony\Component\JsonStreamer\Tests\Fixtures\Model\DummyWithDollarNamedProperties; use Symfony\Component\JsonStreamer\Tests\Fixtures\Model\DummyWithGenerics; use Symfony\Component\JsonStreamer\Tests\Fixtures\Model\DummyWithGmpNumber; use Symfony\Component\JsonStreamer\Tests\Fixtures\Model\DummyWithList; use Symfony\Component\JsonStreamer\Tests\Fixtures\Model\DummyWithNameAttributes; use Symfony\Component\JsonStreamer\Tests\Fixtures\Model\DummyWithNestedArray; use Symfony\Component\JsonStreamer\Tests\Fixtures\Model\DummyWithNestedDictDummies; use Symfony\Component\JsonStreamer\Tests\Fixtures\Model\DummyWithNestedList; use Symfony\Component\JsonStreamer\Tests\Fixtures\Model\DummyWithNestedListDummies; use Symfony\Component\JsonStreamer\Tests\Fixtures\Model\DummyWithNullableProperties; use Symfony\Component\JsonStreamer\Tests\Fixtures\Model\DummyWithPhpDoc; use Symfony\Component\JsonStreamer\Tests\Fixtures\Model\DummyWithSelfReferencingDummy; use Symfony\Component\JsonStreamer\Tests\Fixtures\Model\DummyWithSpecialCharacterNamedProperties; use Symfony\Component\JsonStreamer\Tests\Fixtures\Model\DummyWithSyntheticProperties; use Symfony\Component\JsonStreamer\Tests\Fixtures\Model\DummyWithUids; use Symfony\Component\JsonStreamer\Tests\Fixtures\Model\DummyWithUnionProperties; use Symfony\Component\JsonStreamer\Tests\Fixtures\Model\DummyWithValueObjects; use Symfony\Component\JsonStreamer\Tests\Fixtures\Model\DummyWithValueTransformerAttributes; use Symfony\Component\JsonStreamer\Tests\Fixtures\Model\SelfReferencingDummy; use Symfony\Component\JsonStreamer\Tests\Fixtures\Model\SelfReferencingDummyDict; use Symfony\Component\JsonStreamer\Tests\Fixtures\Model\SelfReferencingDummyList; use Symfony\Component\JsonStreamer\Tests\Fixtures\Model\SelfReferencingDummyWithOtherDummy; use Symfony\Component\JsonStreamer\Tests\Fixtures\Transformer\BooleanToStringValueTransformer; use Symfony\Component\JsonStreamer\Tests\Fixtures\Transformer\DoubleIntAndCastToStringValueTransformer; use Symfony\Component\JsonStreamer\Tests\Fixtures\Transformer\HeightValueObjectTransformer; use Symfony\Component\JsonStreamer\Tests\Fixtures\ValueObject\Height; use Symfony\Component\JsonStreamer\Transformer\DateIntervalValueObjectTransformer; use Symfony\Component\JsonStreamer\Transformer\DateTimeValueObjectTransformer; use Symfony\Component\JsonStreamer\Transformer\PropertyValueTransformerInterface; use Symfony\Component\JsonStreamer\Transformer\UuidValueObjectTransformer; use Symfony\Component\JsonStreamer\Transformer\ValueObjectTransformerInterface; use Symfony\Component\TypeInfo\Type; use Symfony\Component\Uid\Ulid; use Symfony\Component\Uid\Uuid; use Symfony\Component\Uid\UuidV7; class JsonStreamWriterTest extends TestCase { private string $streamWritersDir; protected function setUp(): void { parent::setUp(); $this->streamWritersDir = \sprintf('%s/symfony_json_streamer_test/stream_writer', sys_get_temp_dir()); if (is_dir($this->streamWritersDir)) { array_map('unlink', glob($this->streamWritersDir.'/*')); rmdir($this->streamWritersDir); } } public function testReturnTraversableAndStringable() { $writer = JsonStreamWriter::create(streamWritersDir: $this->streamWritersDir); $this->assertSame(['true'], iterator_to_array($writer->write(true, Type::bool()))); $this->assertSame('true', (string) $writer->write(true, Type::bool())); } public function testWriteScalar() { $this->assertWritten('null', null, Type::null()); $this->assertWritten('true', true, Type::bool()); $this->assertWritten('[{"foo":1,"bar":2},{"foo":3}]', [['foo' => 1, 'bar' => 2], ['foo' => 3]], Type::list()); $this->assertWritten('{"foo":"bar"}', (object) ['foo' => 'bar'], Type::object()); $this->assertWritten('1', DummyBackedEnum::ONE, Type::enum(DummyBackedEnum::class)); } public function testWriteReadableJsonByDefault() { $this->assertWritten('{"url":"https://symfony.com/école","ratio":1.0}', ['url' => 'https://symfony.com/école', 'ratio' => 1.0], Type::dict()); } public function testWriteReadableDictionaryKeysByDefault() { $this->assertWritten( '{"https://symfony.com/école":{"id":1,"name":"dummy"}}', ['https://symfony.com/école' => new ClassicDummy()], Type::dict(Type::object(ClassicDummy::class)), ); } public function testWriteReadablePropertyNamesByDefault() { $this->assertWritten( '{"https://symfony.com/école":1,"line\\u2028separator":2}', new DummyWithSpecialCharacterNamedProperties(), Type::object(DummyWithSpecialCharacterNamedProperties::class), ); } public function testThrowWhenDictionaryKeyCannotBeEncoded() { $writer = JsonStreamWriter::create(streamWritersDir: $this->streamWritersDir); $this->expectException(NotEncodableValueException::class); $this->expectExceptionMessage('Malformed UTF-8 characters, possibly incorrectly encoded'); (string) $writer->write(["invalid\xB1key" => new ClassicDummy()], Type::dict(Type::object(ClassicDummy::class))); } public function testWriteUnion() { $this->assertWritten( '[1,true,["foo","bar"]]', [DummyBackedEnum::ONE, true, ['foo', 'bar']], Type::list(Type::union(Type::enum(DummyBackedEnum::class), Type::bool(), Type::list(Type::string()))), ); $dummy = new DummyWithUnionProperties(); $dummy->value = DummyBackedEnum::ONE; $this->assertWritten('{"value":1}', $dummy, Type::object(DummyWithUnionProperties::class)); $dummy->value = 'foo'; $this->assertWritten('{"value":"foo"}', $dummy, Type::object(DummyWithUnionProperties::class)); $dummy->value = null; $this->assertWritten('{}', $dummy, Type::object(DummyWithUnionProperties::class)); } public function testWriteCollection() { $this->assertWritten( '{"0":{"id":1,"name":"dummy"},"1":{"id":1,"name":"dummy"}}', [new ClassicDummy(), new ClassicDummy()], Type::array(Type::object(ClassicDummy::class)), ); $this->assertWritten( '[{"id":1,"name":"dummy"},{"id":1,"name":"dummy"}]', [new ClassicDummy(), new ClassicDummy()], Type::list(Type::object(ClassicDummy::class)), ); $this->assertWritten( '{"0":{"id":1,"name":"dummy"},"1":{"id":1,"name":"dummy"}}', new \ArrayObject([new ClassicDummy(), new ClassicDummy()]), Type::iterable(Type::object(ClassicDummy::class)), ); $this->assertWritten( '[{"id":1,"name":"dummy"},{"id":1,"name":"dummy"}]', new \ArrayObject([new ClassicDummy(), new ClassicDummy()]), Type::iterable(Type::object(ClassicDummy::class), Type::int()), ); } public function testWriteNestedCollection() { $dummyWithArray1 = new DummyWithArray(); $dummyWithArray1->dummies = [new ClassicDummy()]; $dummyWithArray1->customProperty = 'customProperty1'; $dummyWithArray2 = new DummyWithArray(); $dummyWithArray2->dummies = [new ClassicDummy()]; $dummyWithArray2->customProperty = 'customProperty2'; $this->assertWritten( '[{"dummies":{"0":{"id":1,"name":"dummy"}},"customProperty":"customProperty1"},{"dummies":{"0":{"id":1,"name":"dummy"}},"customProperty":"customProperty2"}]', [$dummyWithArray1, $dummyWithArray2], Type::list(Type::object(DummyWithArray::class)), ); $dummyWithNestedArray1 = new DummyWithNestedArray(); $dummyWithNestedArray1->dummies = [$dummyWithArray1]; $dummyWithNestedArray1->stringProperty = 'stringProperty1'; $dummyWithNestedArray2 = new DummyWithNestedArray(); $dummyWithNestedArray2->dummies = [$dummyWithArray2]; $dummyWithNestedArray2->stringProperty = 'stringProperty2'; $this->assertWritten( '[{"dummies":{"0":{"dummies":{"0":{"id":1,"name":"dummy"}},"customProperty":"customProperty1"}},"stringProperty":"stringProperty1"},{"dummies":{"0":{"dummies":{"0":{"id":1,"name":"dummy"}},"customProperty":"customProperty2"}},"stringProperty":"stringProperty2"}]', [$dummyWithNestedArray1, $dummyWithNestedArray2], Type::list(Type::object(DummyWithNestedArray::class)), ); $dummyWithList1 = new DummyWithList(); $dummyWithList1->dummies = [new ClassicDummy()]; $dummyWithList1->customProperty = 'customProperty1'; $dummyWithList2 = new DummyWithList(); $dummyWithList2->dummies = [new ClassicDummy()]; $dummyWithList2->customProperty = 'customProperty2'; $this->assertWritten( '[{"dummies":[{"id":1,"name":"dummy"}],"customProperty":"customProperty1"},{"dummies":[{"id":1,"name":"dummy"}],"customProperty":"customProperty2"}]', [$dummyWithList1, $dummyWithList2], Type::list(Type::object(DummyWithList::class)), ); $dummyWithNestedList1 = new DummyWithNestedList(); $dummyWithNestedList1->dummies = [$dummyWithList1]; $dummyWithNestedList1->stringProperty = 'stringProperty1'; $dummyWithNestedList2 = new DummyWithNestedList(); $dummyWithNestedList2->dummies = [$dummyWithList2]; $dummyWithNestedList2->stringProperty = 'stringProperty2'; $this->assertWritten( '[{"dummies":[{"dummies":[{"id":1,"name":"dummy"}],"customProperty":"customProperty1"}],"stringProperty":"stringProperty1"},{"dummies":[{"dummies":[{"id":1,"name":"dummy"}],"customProperty":"customProperty2"}],"stringProperty":"stringProperty2"}]', [$dummyWithNestedList1, $dummyWithNestedList2], Type::list(Type::object(DummyWithNestedList::class)), ); } public function testWriteObject() { $dummy = new ClassicDummy(); $dummy->id = 10; $dummy->name = 'dummy name'; $this->assertWritten('{"id":10,"name":"dummy name"}', $dummy, Type::object(ClassicDummy::class)); } public function testWriteObjectWithGenerics() { $nestedDummy = new DummyWithNameAttributes(); $nestedDummy->id = 10; $nestedDummy->name = 'dummy name'; $dummy = new DummyWithGenerics(); $dummy->dummies = [$nestedDummy]; $this->assertWritten('{"dummies":[{"id":10,"name":"dummy name"}]}', $dummy, Type::generic(Type::object(DummyWithGenerics::class), Type::object(ClassicDummy::class))); } public function testWriteObjectWithStreamedName() { $dummy = new DummyWithNameAttributes(); $dummy->id = 10; $dummy->name = 'dummy name'; $this->assertWritten('{"@id":10,"name":"dummy name"}', $dummy, Type::object(DummyWithNameAttributes::class)); } public function testWriteObjectWithValueTransformer() { $dummy = new DummyWithValueTransformerAttributes(); $dummy->id = 10; $dummy->active = true; $this->assertWritten( '{"id":"20","active":"true","name":"dummy","range":"10..20"}', $dummy, Type::object(DummyWithValueTransformerAttributes::class), options: ['scale' => 1], transformers: [ BooleanToStringValueTransformer::class => new BooleanToStringValueTransformer(), DoubleIntAndCastToStringValueTransformer::class => new DoubleIntAndCastToStringValueTransformer(), ], ); } public function testValueTransformerHasAccessToCurrentObject() { $dummy = new DummyWithValueTransformerAttributes(); $dummy->id = 10; $dummy->active = true; $this->assertWritten( '{"id":"20","active":"true","name":"dummy","range":"10..20"}', $dummy, Type::object(DummyWithValueTransformerAttributes::class), options: ['scale' => 1], transformers: [ BooleanToStringValueTransformer::class => new class($this) implements PropertyValueTransformerInterface { public function __construct( private JsonStreamWriterTest $test, ) { } public function transform(mixed $value, array $options = []): mixed { $this->test->assertArrayHasKey('_current_object', $options); $this->test->assertInstanceof(DummyWithValueTransformerAttributes::class, $options['_current_object']); return (new BooleanToStringValueTransformer())->transform($value, $options); } public static function getStreamValueType(): Type { return BooleanToStringValueTransformer::getStreamValueType(); } }, DoubleIntAndCastToStringValueTransformer::class => new DoubleIntAndCastToStringValueTransformer(), ], ); } public function testWriteObjectWithValueObject() { $dummy = new DummyWithValueObjects(); $dummy->height = new Height(10, 'm'); $dummy->nullableHeight = new Height(10, 'dm'); $dummy->unionHeight = new Height(10, 'cm'); $this->assertWritten( '{"height":"10 m","nullableHeight":"10 dm","unionHeight":"10 cm"}', $dummy, Type::object(DummyWithValueObjects::class), transformers: [ Height::class => new HeightValueObjectTransformer(), ], ); $dummy->nullableHeight = null; $dummy->unionHeight = 10; $this->assertWritten( '{"height":"10 m","unionHeight":10}', $dummy, Type::object(DummyWithValueObjects::class), transformers: [ Height::class => new HeightValueObjectTransformer(), ], ); } public function testWriteObjectWithPhpDoc() { $dummy = new DummyWithPhpDoc(); $dummy->arrayOfDummies = ['key' => new DummyWithNameAttributes()]; $this->assertWritten('{"arrayOfDummies":{"key":{"@id":1,"name":"dummy"}},"array":[]}', $dummy, Type::object(DummyWithPhpDoc::class)); } public function testWriteObjectWithNullableProperties() { $dummy = new DummyWithNullableProperties(); $this->assertWritten('{}', $dummy, Type::object(DummyWithNullableProperties::class)); $dummy->name = 'name'; $this->assertWritten('{"name":"name"}', $dummy, Type::object(DummyWithNullableProperties::class)); $this->assertWritten('{"name":"name","enum":null}', $dummy, Type::object(DummyWithNullableProperties::class), options: ['include_null_properties' => true]); $dummy->name = null; $dummy->enum = DummyBackedEnum::ONE; $this->assertWritten('{"enum":1}', $dummy, Type::object(DummyWithNullableProperties::class)); $this->assertWritten('{"name":null,"enum":1}', $dummy, Type::object(DummyWithNullableProperties::class), options: ['include_null_properties' => true]); } public function testWriteObjectWithDateTimes() { $dummy = new DummyWithDateTimes(); $dummy->interface = new \DateTimeImmutable('2024-11-20'); $dummy->immutable = new \DateTimeImmutable('2025-11-20'); $dummy->union = new \DateTimeImmutable('2026-11-20'); $this->assertWritten( '{"interface":"2024-11-20","immutable":"2025-11-20","union":"2026-11-20"}', $dummy, Type::object(DummyWithDateTimes::class), options: [DateTimeValueObjectTransformer::FORMAT_KEY => 'Y-m-d'], ); $dummy->union = 10; $this->assertWritten( '{"interface":"2024-11-20","immutable":"2025-11-20","union":10}', $dummy, Type::object(DummyWithDateTimes::class), options: [DateTimeValueObjectTransformer::FORMAT_KEY => 'Y-m-d'], ); } public function testWriteObjectWithDateIntervals() { $dummy = new DummyWithDateIntervals(); $dummy->interval = new \DateInterval('P2Y6M1DT12H30M5S'); $this->assertWritten( '{"interval":"P2Y6M1DT12H30M5S"}', $dummy, Type::object(DummyWithDateIntervals::class), options: [DateIntervalValueObjectTransformer::FORMAT_KEY => 'P%yY%mM%dDT%hH%iM%sS'], ); } public function testWriteObjectWithDateTimeZones() { $dummy = new DummyWithDateTimeZones(); $dummy->timezone = new \DateTimeZone('Asia/Tokyo'); $this->assertWritten( '{"timezone":"Asia/Tokyo"}', $dummy, Type::object(DummyWithDateTimeZones::class), ); } #[RequiresPhpExtension('bcmath')] public function testWriteObjectWithBcMathNumber() { $dummy = new DummyWithBcMathNumber(); $dummy->number = new \BcMath\Number('3.14'); $this->assertWritten('{"number":"3.14"}', $dummy, Type::object(DummyWithBcMathNumber::class)); } #[RequiresPhpExtension('gmp')] public function testWriteObjectWithGmpNumber() { $dummy = new DummyWithGmpNumber(); $dummy->gmp = new \GMP('99999999999999999999'); $this->assertWritten('{"gmp":"99999999999999999999"}', $dummy, Type::object(DummyWithGmpNumber::class)); } public function testWriteObjectWithUids() { $dummy = new DummyWithUids(); $dummy->uuid = Uuid::fromString('a7613e0a-5986-4f29-b3f8-3b6f8e5e6b40'); $dummy->uuidV7 = UuidV7::fromString('018f7a5e-3c1e-7a4e-8b1a-2c3d4e5f6a7b'); $dummy->ulid = Ulid::fromString('01ARZ3NDEKTSV4RRFFQ69G5FAV'); $this->assertWritten('{"uuid":"a7613e0a-5986-4f29-b3f8-3b6f8e5e6b40","uuidV7":"018f7a5e-3c1e-7a4e-8b1a-2c3d4e5f6a7b","ulid":"01ARZ3NDEKTSV4RRFFQ69G5FAV"}', $dummy, Type::object(DummyWithUids::class)); } public function testWriteObjectWithUidsUsingFormat() { $dummy = new DummyWithUids(); $dummy->uuid = Uuid::fromString('a7613e0a-5986-4f29-b3f8-3b6f8e5e6b40'); $dummy->uuidV7 = UuidV7::fromString('018f7a5e-3c1e-7a4e-8b1a-2c3d4e5f6a7b'); $dummy->ulid = Ulid::fromString('01ARZ3NDEKTSV4RRFFQ69G5FAV'); $this->assertWritten( \sprintf('{"uuid":"%s","uuidV7":"%s","ulid":"%s"}', $dummy->uuid->toBase32(), $dummy->uuidV7->toBase32(), $dummy->ulid->toBase32()), $dummy, Type::object(DummyWithUids::class), options: [UuidValueObjectTransformer::FORMAT_KEY => UuidValueObjectTransformer::FORMAT_BASE32], ); } public function testWriteObjectWithDollarNamedProperties() { $this->assertWritten('{"$foo":true,"{$foo->bar}":true}', new DummyWithDollarNamedProperties(), Type::object(DummyWithDollarNamedProperties::class)); } public function testWriteObjectWithSyntheticProperty() { $writer = new JsonStreamWriter(new Container(), new SyntheticPropertyMetadataLoader(), $this->streamWritersDir); $this->assertSame('{"synthetic":true}', (string) $writer->write(new DummyWithSyntheticProperties(), Type::object(DummyWithSyntheticProperties::class))); } public function testWriteSelfReferencingWithOtherDummy() { $dummy = new DummyWithSelfReferencingDummy(); $dummy->otherDummy = new ClassicDummy(); $dummy->selfReferencing = new SelfReferencingDummyWithOtherDummy(); $dummy->selfReferencing->otherDummy = new ClassicDummy(); $dummy->selfReferencing->self = new SelfReferencingDummyWithOtherDummy(); $dummy->selfReferencing->self->otherDummy = new ClassicDummy(); $this->assertWritten( '{"otherDummy":{"id":1,"name":"dummy"},"selfReferencing":{"otherDummy":{"id":1,"name":"dummy"},"self":{"otherDummy":{"id":1,"name":"dummy"}}}}', $dummy, Type::object(DummyWithSelfReferencingDummy::class), ); } public function testWriteNestedSelfList() { $dummy = new SelfReferencingDummyList(); $dummy->items = [new SelfReferencingDummyList(), new SelfReferencingDummyList(), new SelfReferencingDummyList()]; $this->assertWritten( '{"items":{"0":{"items":{}},"1":{"items":{}},"2":{"items":{}}}}', $dummy, Type::object(SelfReferencingDummyList::class) ); $dummy = new DummyWithNestedListDummies(); $dummy->dummies = [new DummyWithNestedListDummies(), new DummyWithNestedListDummies(), new DummyWithNestedListDummies()]; $this->assertWritten( '{"dummies":{"0":{"dummies":{}},"1":{"dummies":{}},"2":{"dummies":{}}}}', $dummy, Type::object(DummyWithNestedListDummies::class) ); } public function testWriteNestedSelfDict() { $dummy = new SelfReferencingDummyDict(); $dummy->items = [ 'first' => new SelfReferencingDummyDict(), 'second' => new SelfReferencingDummyDict(), 'third' => new SelfReferencingDummyDict(), ]; $this->assertWritten( '{"items":{"first":{"items":{}},"second":{"items":{}},"third":{"items":{}}}}', $dummy, Type::object(SelfReferencingDummyDict::class) ); $dummy = new DummyWithNestedDictDummies(); $dummy->dummies = [ 'first' => new DummyWithNestedDictDummies(), 'second' => new DummyWithNestedDictDummies(), 'third' => new DummyWithNestedDictDummies(), ]; $this->assertWritten( '{"dummies":{"first":{"dummies":{}},"second":{"dummies":{}},"third":{"dummies":{}}}}', $dummy, Type::object(DummyWithNestedDictDummies::class) ); } #[DataProvider('throwWhenMaxDepthIsReachedDataProvider')] public function testThrowWhenMaxDepthIsReached(Type $type, mixed $data) { $writer = JsonStreamWriter::create(streamWritersDir: $this->streamWritersDir); $this->expectException(NotEncodableValueException::class); $this->expectExceptionMessage('Maximum stack depth exceeded'); (string) $writer->write($data, $type); } /** * @return iterable<array{0: Type, 1: mixed}> */ public static function throwWhenMaxDepthIsReachedDataProvider(): iterable { $dummy = new SelfReferencingDummy(); for ($i = 0; $i < 512; ++$i) { $tmp = new SelfReferencingDummy(); $tmp->self = $dummy; $dummy = $tmp; } yield [Type::object(SelfReferencingDummy::class), $dummy]; $dummy = new SelfReferencingDummy(); for ($i = 0; $i < 511; ++$i) { $tmp = new SelfReferencingDummy(); $tmp->self = $dummy; $dummy = $tmp; } yield [Type::list(Type::object(SelfReferencingDummy::class)), [$dummy]]; yield [Type::dict(Type::object(SelfReferencingDummy::class)), ['k' => $dummy]]; } public function testThrowWhenEncodeError() { $writer = JsonStreamWriter::create(streamWritersDir: $this->streamWritersDir); $this->expectException(NotEncodableValueException::class); $this->expectExceptionMessage('Cannot encode "int" to JSON: Inf and NaN cannot be JSON encoded.'); (string) $writer->write(\INF, Type::int()); } public function testCreateStreamWriterFile() { $writer = JsonStreamWriter::create(streamWritersDir: $this->streamWritersDir); $writer->write(true, Type::bool()); $this->assertFileExists($this->streamWritersDir); $this->assertCount(1, glob($this->streamWritersDir.'/*')); } public function testCreateStreamWriterFileOnlyIfNotExists() { $writer = JsonStreamWriter::create(streamWritersDir: $this->streamWritersDir); if (!file_exists($this->streamWritersDir)) { mkdir($this->streamWritersDir, recursive: true); } file_put_contents( \sprintf('%s%s%s.json.php', $this->streamWritersDir, \DIRECTORY_SEPARATOR, hash('xxh128', (string) Type::bool())), '<?php return static function ($data): \Traversable { yield "CACHED"; };' ); $this->assertSame('CACHED', (string) $writer->write(true, Type::bool())); } /** * @param array<string, mixed> $options * @param array<string, PropertyValueTransformerInterface|ValueObjectTransformerInterface> $transformers */ private function assertWritten(string $json, mixed $data, Type $type, array $options = [], array $transformers = []): void { $writer = JsonStreamWriter::create($transformers, $this->streamWritersDir); $this->assertSame($json, (string) $writer->write($data, $type, $options)); } }