Actualización

This commit is contained in:
Xes
2025-04-10 12:24:57 +02:00
parent 8969cc929d
commit 45420b6f0d
39760 changed files with 4303286 additions and 0 deletions

View File

@@ -0,0 +1,53 @@
<?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\Serializer\Tests\Annotation;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Serializer\Annotation\Groups;
/**
* @author Kévin Dunglas <dunglas@gmail.com>
*/
class GroupsTest extends TestCase
{
public function testEmptyGroupsParameter()
{
$this->expectException('Symfony\Component\Serializer\Exception\InvalidArgumentException');
new Groups(['value' => []]);
}
public function testNotAnArrayGroupsParameter()
{
$this->expectException('Symfony\Component\Serializer\Exception\InvalidArgumentException');
new Groups(['value' => 12]);
}
public function testInvalidGroupsParameter()
{
$this->expectException('Symfony\Component\Serializer\Exception\InvalidArgumentException');
new Groups(['value' => ['a', 1, new \stdClass()]]);
}
public function testGroupsParameters()
{
$validData = ['a', 'b'];
$groups = new Groups(['value' => $validData]);
$this->assertEquals($validData, $groups->getGroups());
}
public function testSingleGroup()
{
$groups = new Groups(['value' => 'a']);
$this->assertEquals(['a'], $groups->getGroups());
}
}

View File

@@ -0,0 +1,54 @@
<?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\Serializer\Tests\Annotation;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Serializer\Annotation\MaxDepth;
/**
* @author Kévin Dunglas <dunglas@gmail.com>
*/
class MaxDepthTest extends TestCase
{
public function testNotSetMaxDepthParameter()
{
$this->expectException('Symfony\Component\Serializer\Exception\InvalidArgumentException');
$this->expectExceptionMessage('Parameter of annotation "Symfony\Component\Serializer\Annotation\MaxDepth" should be set.');
new MaxDepth([]);
}
public function provideInvalidValues()
{
return [
[''],
['foo'],
['1'],
[0],
];
}
/**
* @dataProvider provideInvalidValues
*/
public function testNotAnIntMaxDepthParameter($value)
{
$this->expectException('Symfony\Component\Serializer\Exception\InvalidArgumentException');
$this->expectExceptionMessage('Parameter of annotation "Symfony\Component\Serializer\Annotation\MaxDepth" must be a positive integer.');
new MaxDepth(['value' => $value]);
}
public function testMaxDepthParameters()
{
$maxDepth = new MaxDepth(['value' => 3]);
$this->assertEquals(3, $maxDepth->getMaxDepth());
}
}

View File

@@ -0,0 +1,71 @@
<?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\Serializer\Tests\DependencyInjection;
use PHPUnit\Framework\TestCase;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\Serializer\DependencyInjection\SerializerPass;
/**
* Tests for the SerializerPass class.
*
* @author Javier Lopez <f12loalf@gmail.com>
*/
class SerializerPassTest extends TestCase
{
public function testThrowExceptionWhenNoNormalizers()
{
$this->expectException('RuntimeException');
$this->expectExceptionMessage('You must tag at least one service as "serializer.normalizer" to use the "serializer" service');
$container = new ContainerBuilder();
$container->register('serializer');
$serializerPass = new SerializerPass();
$serializerPass->process($container);
}
public function testThrowExceptionWhenNoEncoders()
{
$this->expectException('RuntimeException');
$this->expectExceptionMessage('You must tag at least one service as "serializer.encoder" to use the "serializer" service');
$container = new ContainerBuilder();
$container->register('serializer')
->addArgument([])
->addArgument([]);
$container->register('normalizer')->addTag('serializer.normalizer');
$serializerPass = new SerializerPass();
$serializerPass->process($container);
}
public function testServicesAreOrderedAccordingToPriority()
{
$container = new ContainerBuilder();
$definition = $container->register('serializer')->setArguments([null, null]);
$container->register('n2')->addTag('serializer.normalizer', ['priority' => 100])->addTag('serializer.encoder', ['priority' => 100]);
$container->register('n1')->addTag('serializer.normalizer', ['priority' => 200])->addTag('serializer.encoder', ['priority' => 200]);
$container->register('n3')->addTag('serializer.normalizer')->addTag('serializer.encoder');
$serializerPass = new SerializerPass();
$serializerPass->process($container);
$expected = [
new Reference('n1'),
new Reference('n2'),
new Reference('n3'),
];
$this->assertEquals($expected, $definition->getArgument(0));
$this->assertEquals($expected, $definition->getArgument(1));
}
}

View File

@@ -0,0 +1,128 @@
<?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\Serializer\Tests;
use PHPUnit\Framework\TestCase;
use Symfony\Component\PropertyInfo\Extractor\PhpDocExtractor;
use Symfony\Component\Serializer\Encoder\JsonEncoder;
use Symfony\Component\Serializer\Normalizer\ArrayDenormalizer;
use Symfony\Component\Serializer\Normalizer\ObjectNormalizer;
use Symfony\Component\Serializer\Serializer;
class DeserializeNestedArrayOfObjectsTest extends TestCase
{
public function provider()
{
return [
//from property PhpDoc
[Zoo::class],
//from argument constructor PhpDoc
[ZooImmutable::class],
];
}
/**
* @dataProvider provider
*/
public function testPropertyPhpDoc($class)
{
//GIVEN
$json = <<<EOF
{
"animals": [
{"name": "Bug"}
]
}
EOF;
$serializer = new Serializer([
new ObjectNormalizer(null, null, null, new PhpDocExtractor()),
new ArrayDenormalizer(),
], ['json' => new JsonEncoder()]);
//WHEN
/** @var Zoo $zoo */
$zoo = $serializer->deserialize($json, $class, 'json');
//THEN
self::assertCount(1, $zoo->getAnimals());
self::assertInstanceOf(Animal::class, $zoo->getAnimals()[0]);
}
}
class Zoo
{
/** @var Animal[] */
private $animals = [];
/**
* @return Animal[]
*/
public function getAnimals()
{
return $this->animals;
}
/**
* @param Animal[] $animals
*/
public function setAnimals(array $animals)
{
$this->animals = $animals;
}
}
class ZooImmutable
{
/** @var Animal[] */
private $animals = [];
/**
* @param Animal[] $animals
*/
public function __construct(array $animals = [])
{
$this->animals = $animals;
}
/**
* @return Animal[]
*/
public function getAnimals()
{
return $this->animals;
}
}
class Animal
{
/** @var string */
private $name;
public function __construct()
{
echo '';
}
/**
* @return string|null
*/
public function getName()
{
return $this->name;
}
/**
* @param string|null $name
*/
public function setName($name)
{
$this->name = $name;
}
}

View File

@@ -0,0 +1,78 @@
<?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\Serializer\Tests\Encoder;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Serializer\Encoder\ChainDecoder;
class ChainDecoderTest extends TestCase
{
const FORMAT_1 = 'format1';
const FORMAT_2 = 'format2';
const FORMAT_3 = 'format3';
private $chainDecoder;
private $decoder1;
private $decoder2;
protected function setUp()
{
$this->decoder1 = $this
->getMockBuilder('Symfony\Component\Serializer\Encoder\DecoderInterface')
->getMock();
$this->decoder1
->method('supportsDecoding')
->willReturnMap([
[self::FORMAT_1, [], true],
[self::FORMAT_2, [], false],
[self::FORMAT_3, [], false],
[self::FORMAT_3, ['foo' => 'bar'], true],
]);
$this->decoder2 = $this
->getMockBuilder('Symfony\Component\Serializer\Encoder\DecoderInterface')
->getMock();
$this->decoder2
->method('supportsDecoding')
->willReturnMap([
[self::FORMAT_1, [], false],
[self::FORMAT_2, [], true],
[self::FORMAT_3, [], false],
]);
$this->chainDecoder = new ChainDecoder([$this->decoder1, $this->decoder2]);
}
public function testSupportsDecoding()
{
$this->assertTrue($this->chainDecoder->supportsDecoding(self::FORMAT_1));
$this->assertTrue($this->chainDecoder->supportsDecoding(self::FORMAT_2));
$this->assertFalse($this->chainDecoder->supportsDecoding(self::FORMAT_3));
$this->assertTrue($this->chainDecoder->supportsDecoding(self::FORMAT_3, ['foo' => 'bar']));
}
public function testDecode()
{
$this->decoder1->expects($this->never())->method('decode');
$this->decoder2->expects($this->once())->method('decode');
$this->chainDecoder->decode('string_to_decode', self::FORMAT_2);
}
public function testDecodeUnsupportedFormat()
{
$this->expectException('Symfony\Component\Serializer\Exception\RuntimeException');
$this->chainDecoder->decode('string_to_decode', self::FORMAT_3);
}
}

View File

@@ -0,0 +1,106 @@
<?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\Serializer\Tests\Encoder;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Serializer\Encoder\ChainEncoder;
use Symfony\Component\Serializer\Encoder\EncoderInterface;
use Symfony\Component\Serializer\Encoder\NormalizationAwareInterface;
class ChainEncoderTest extends TestCase
{
const FORMAT_1 = 'format1';
const FORMAT_2 = 'format2';
const FORMAT_3 = 'format3';
private $chainEncoder;
private $encoder1;
private $encoder2;
protected function setUp()
{
$this->encoder1 = $this
->getMockBuilder('Symfony\Component\Serializer\Encoder\EncoderInterface')
->getMock();
$this->encoder1
->method('supportsEncoding')
->willReturnMap([
[self::FORMAT_1, [], true],
[self::FORMAT_2, [], false],
[self::FORMAT_3, [], false],
[self::FORMAT_3, ['foo' => 'bar'], true],
]);
$this->encoder2 = $this
->getMockBuilder('Symfony\Component\Serializer\Encoder\EncoderInterface')
->getMock();
$this->encoder2
->method('supportsEncoding')
->willReturnMap([
[self::FORMAT_1, [], false],
[self::FORMAT_2, [], true],
[self::FORMAT_3, [], false],
]);
$this->chainEncoder = new ChainEncoder([$this->encoder1, $this->encoder2]);
}
public function testSupportsEncoding()
{
$this->assertTrue($this->chainEncoder->supportsEncoding(self::FORMAT_1));
$this->assertTrue($this->chainEncoder->supportsEncoding(self::FORMAT_2));
$this->assertFalse($this->chainEncoder->supportsEncoding(self::FORMAT_3));
$this->assertTrue($this->chainEncoder->supportsEncoding(self::FORMAT_3, ['foo' => 'bar']));
}
public function testEncode()
{
$this->encoder1->expects($this->never())->method('encode');
$this->encoder2->expects($this->once())->method('encode');
$this->chainEncoder->encode(['foo' => 123], self::FORMAT_2);
}
public function testEncodeUnsupportedFormat()
{
$this->expectException('Symfony\Component\Serializer\Exception\RuntimeException');
$this->chainEncoder->encode(['foo' => 123], self::FORMAT_3);
}
public function testNeedsNormalizationBasic()
{
$this->assertTrue($this->chainEncoder->needsNormalization(self::FORMAT_1));
$this->assertTrue($this->chainEncoder->needsNormalization(self::FORMAT_2));
}
public function testNeedsNormalizationNormalizationAware()
{
$encoder = new NormalizationAwareEncoder();
$sut = new ChainEncoder([$encoder]);
$this->assertFalse($sut->needsNormalization(self::FORMAT_1));
}
}
class NormalizationAwareEncoder implements EncoderInterface, NormalizationAwareInterface
{
public function supportsEncoding($format)
{
return true;
}
public function encode($data, $format, array $context = [])
{
}
}

View File

@@ -0,0 +1,348 @@
<?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\Serializer\Tests\Encoder;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Serializer\Encoder\CsvEncoder;
/**
* @author Kévin Dunglas <dunglas@gmail.com>
*/
class CsvEncoderTest extends TestCase
{
/**
* @var CsvEncoder
*/
private $encoder;
protected function setUp()
{
$this->encoder = new CsvEncoder();
}
public function testTrueFalseValues()
{
$data = [
'string' => 'foo',
'int' => 2,
'false' => false,
'true' => true,
'int_one' => 1,
'string_one' => '1',
];
// Check that true and false are appropriately handled
$this->assertSame($csv = <<<'CSV'
string,int,false,true,int_one,string_one
foo,2,0,1,1,1
CSV
, $this->encoder->encode($data, 'csv'));
$this->assertSame([
'string' => 'foo',
'int' => '2',
'false' => '0',
'true' => '1',
'int_one' => '1',
'string_one' => '1',
], $this->encoder->decode($csv, 'csv'));
}
/**
* @requires PHP 7.4
*/
public function testDoubleQuotesAndSlashes()
{
$this->assertSame($csv = <<<'CSV'
0,1,2,3,4,5
,"""","foo""","\""",\,foo\
CSV
, $this->encoder->encode($data = ['', '"', 'foo"', '\\"', '\\', 'foo\\'], 'csv'));
$this->assertSame($data, $this->encoder->decode($csv, 'csv'));
}
/**
* @requires PHP 7.4
*/
public function testSingleSlash()
{
$this->assertSame($csv = "0\n\\\n", $this->encoder->encode($data = ['\\'], 'csv'));
$this->assertSame($data, $this->encoder->decode($csv, 'csv'));
$this->assertSame($data, $this->encoder->decode(trim($csv), 'csv'));
}
public function testSupportEncoding()
{
$this->assertTrue($this->encoder->supportsEncoding('csv'));
$this->assertFalse($this->encoder->supportsEncoding('foo'));
}
public function testEncode()
{
$value = ['foo' => 'hello', 'bar' => 'hey ho'];
$this->assertEquals(<<<'CSV'
foo,bar
hello,"hey ho"
CSV
, $this->encoder->encode($value, 'csv'));
}
public function testEncodeCollection()
{
$value = [
['foo' => 'hello', 'bar' => 'hey ho'],
['foo' => 'hi', 'bar' => 'let\'s go'],
];
$this->assertEquals(<<<'CSV'
foo,bar
hello,"hey ho"
hi,"let's go"
CSV
, $this->encoder->encode($value, 'csv'));
}
public function testEncodePlainIndexedArray()
{
$this->assertEquals(<<<'CSV'
0,1,2
a,b,c
CSV
, $this->encoder->encode(['a', 'b', 'c'], 'csv'));
}
public function testEncodeNonArray()
{
$this->assertEquals(<<<'CSV'
0
foo
CSV
, $this->encoder->encode('foo', 'csv'));
}
public function testEncodeNestedArrays()
{
$value = ['foo' => 'hello', 'bar' => [
['id' => 'yo', 1 => 'wesh'],
['baz' => 'Halo', 'foo' => 'olá'],
]];
$this->assertEquals(<<<'CSV'
foo,bar.0.id,bar.0.1,bar.1.baz,bar.1.foo
hello,yo,wesh,Halo,olá
CSV
, $this->encoder->encode($value, 'csv'));
}
public function testEncodeCustomSettings()
{
$this->encoder = new CsvEncoder(';', "'", '|', '-');
$value = ['a' => 'he\'llo', 'c' => ['d' => 'foo']];
$this->assertEquals(<<<'CSV'
a;c-d
'he''llo';foo
CSV
, $this->encoder->encode($value, 'csv'));
}
public function testEncodeCustomSettingsPassedInContext()
{
$value = ['a' => 'he\'llo', 'c' => ['d' => 'foo']];
$this->assertSame(<<<'CSV'
a;c-d
'he''llo';foo
CSV
, $this->encoder->encode($value, 'csv', [
CsvEncoder::DELIMITER_KEY => ';',
CsvEncoder::ENCLOSURE_KEY => "'",
CsvEncoder::ESCAPE_CHAR_KEY => '|',
CsvEncoder::KEY_SEPARATOR_KEY => '-',
]));
}
public function testEncodeEmptyArray()
{
$this->assertEquals("\n\n", $this->encoder->encode([], 'csv'));
$this->assertEquals("\n\n", $this->encoder->encode([[]], 'csv'));
}
public function testEncodeVariableStructure()
{
$value = [
['a' => ['foo', 'bar']],
['a' => [], 'b' => 'baz'],
['a' => ['bar', 'foo'], 'c' => 'pong'],
];
$csv = <<<CSV
a.0,a.1,c,b
foo,bar,,
,,,baz
bar,foo,pong,
CSV;
$this->assertEquals($csv, $this->encoder->encode($value, 'csv'));
}
public function testEncodeCustomHeaders()
{
$context = [
CsvEncoder::HEADERS_KEY => [
'b',
'c',
],
];
$value = [
['a' => 'foo', 'b' => 'bar'],
];
$csv = <<<CSV
b,c,a
bar,,foo
CSV;
$this->assertEquals($csv, $this->encoder->encode($value, 'csv', $context));
}
public function testSupportsDecoding()
{
$this->assertTrue($this->encoder->supportsDecoding('csv'));
$this->assertFalse($this->encoder->supportsDecoding('foo'));
}
public function testDecode()
{
$expected = ['foo' => 'a', 'bar' => 'b'];
$this->assertEquals($expected, $this->encoder->decode(<<<'CSV'
foo,bar
a,b
CSV
, 'csv'));
}
public function testDecodeCollection()
{
$expected = [
['foo' => 'a', 'bar' => 'b'],
['foo' => 'c', 'bar' => 'd'],
['foo' => 'f'],
];
$this->assertEquals($expected, $this->encoder->decode(<<<'CSV'
foo,bar
a,b
c,d
f
CSV
, 'csv'));
}
public function testDecodeToManyRelation()
{
$expected = [
['foo' => 'bar', 'relations' => [['a' => 'b'], ['a' => 'b']]],
['foo' => 'bat', 'relations' => [['a' => 'b'], ['a' => '']]],
['foo' => 'bat', 'relations' => [['a' => 'b']]],
['foo' => 'baz', 'relations' => [['a' => 'c'], ['a' => 'c']]],
];
$this->assertEquals($expected, $this->encoder->decode(<<<'CSV'
foo,relations.0.a,relations.1.a
bar,b,b
bat,b,
bat,b
baz,c,c
CSV
, 'csv'));
}
public function testDecodeNestedArrays()
{
$expected = [
['foo' => 'a', 'bar' => ['baz' => ['bat' => 'b']]],
['foo' => 'c', 'bar' => ['baz' => ['bat' => 'd']]],
];
$this->assertEquals($expected, $this->encoder->decode(<<<'CSV'
foo,bar.baz.bat
a,b
c,d
CSV
, 'csv'));
}
public function testDecodeCustomSettings()
{
$this->encoder = new CsvEncoder(';', "'", '|', '-');
$expected = ['a' => 'hell\'o', 'bar' => ['baz' => 'b']];
$this->assertEquals($expected, $this->encoder->decode(<<<'CSV'
a;bar-baz
'hell''o';b;c
CSV
, 'csv'));
}
public function testDecodeCustomSettingsPassedInContext()
{
$expected = ['a' => 'hell\'o', 'bar' => ['baz' => 'b']];
$this->assertEquals($expected, $this->encoder->decode(<<<'CSV'
a;bar-baz
'hell''o';b;c
CSV
, 'csv', [
CsvEncoder::DELIMITER_KEY => ';',
CsvEncoder::ENCLOSURE_KEY => "'",
CsvEncoder::ESCAPE_CHAR_KEY => '|',
CsvEncoder::KEY_SEPARATOR_KEY => '-',
]));
}
public function testDecodeMalformedCollection()
{
$expected = [
['foo' => 'a', 'bar' => 'b'],
['foo' => 'c', 'bar' => 'd'],
['foo' => 'f'],
];
$this->assertEquals($expected, $this->encoder->decode(<<<'CSV'
foo,bar
a,b,e
c,d,g,h
f
CSV
, 'csv'));
}
public function testDecodeEmptyArray()
{
$this->assertEquals([], $this->encoder->decode('', 'csv'));
}
}

View File

@@ -0,0 +1,75 @@
<?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\Serializer\Tests\Encoder;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Serializer\Encoder\JsonDecode;
use Symfony\Component\Serializer\Encoder\JsonEncoder;
class JsonDecodeTest extends TestCase
{
/** @var \Symfony\Component\Serializer\Encoder\JsonDecode */
private $decode;
protected function setUp()
{
$this->decode = new JsonDecode();
}
public function testSupportsDecoding()
{
$this->assertTrue($this->decode->supportsDecoding(JsonEncoder::FORMAT));
$this->assertFalse($this->decode->supportsDecoding('foobar'));
}
/**
* @dataProvider decodeProvider
*/
public function testDecode($toDecode, $expected, $context)
{
$this->assertEquals(
$expected,
$this->decode->decode($toDecode, JsonEncoder::FORMAT, $context)
);
}
public function decodeProvider()
{
$stdClass = new \stdClass();
$stdClass->foo = 'bar';
$assoc = ['foo' => 'bar'];
return [
['{"foo": "bar"}', $stdClass, []],
['{"foo": "bar"}', $assoc, ['json_decode_associative' => true]],
];
}
/**
* @requires function json_last_error_msg
* @dataProvider decodeProviderException
*/
public function testDecodeWithException($value)
{
$this->expectException('Symfony\Component\Serializer\Exception\UnexpectedValueException');
$this->decode->decode($value, JsonEncoder::FORMAT);
}
public function decodeProviderException()
{
return [
["{'foo': 'bar'}"],
['kaboom!'],
];
}
}

View File

@@ -0,0 +1,60 @@
<?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\Serializer\Tests\Encoder;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Serializer\Encoder\JsonEncode;
use Symfony\Component\Serializer\Encoder\JsonEncoder;
class JsonEncodeTest extends TestCase
{
private $encoder;
protected function setUp()
{
$this->encode = new JsonEncode();
}
public function testSupportsEncoding()
{
$this->assertTrue($this->encode->supportsEncoding(JsonEncoder::FORMAT));
$this->assertFalse($this->encode->supportsEncoding('foobar'));
}
/**
* @dataProvider encodeProvider
*/
public function testEncode($toEncode, $expected, $context)
{
$this->assertEquals(
$expected,
$this->encode->encode($toEncode, JsonEncoder::FORMAT, $context)
);
}
public function encodeProvider()
{
return [
[[], '[]', []],
[[], '{}', ['json_encode_options' => \JSON_FORCE_OBJECT]],
];
}
/**
* @requires function json_last_error_msg
*/
public function testEncodeWithError()
{
$this->expectException('Symfony\Component\Serializer\Exception\UnexpectedValueException');
$this->encode->encode("\xB1\x31", JsonEncoder::FORMAT);
}
}

View File

@@ -0,0 +1,119 @@
<?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\Serializer\Tests\Encoder;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Serializer\Encoder\JsonEncoder;
use Symfony\Component\Serializer\Normalizer\CustomNormalizer;
use Symfony\Component\Serializer\Serializer;
class JsonEncoderTest extends TestCase
{
private $encoder;
private $serializer;
protected function setUp()
{
$this->encoder = new JsonEncoder();
$this->serializer = new Serializer([new CustomNormalizer()], ['json' => new JsonEncoder()]);
}
public function testEncodeScalar()
{
$obj = new \stdClass();
$obj->foo = 'foo';
$expected = '{"foo":"foo"}';
$this->assertEquals($expected, $this->encoder->encode($obj, 'json'));
}
public function testComplexObject()
{
$obj = $this->getObject();
$expected = $this->getJsonSource();
$this->assertEquals($expected, $this->encoder->encode($obj, 'json'));
}
public function testOptions()
{
$context = ['json_encode_options' => \JSON_NUMERIC_CHECK];
$arr = [];
$arr['foo'] = '3';
$expected = '{"foo":3}';
$this->assertEquals($expected, $this->serializer->serialize($arr, 'json', $context));
$arr = [];
$arr['foo'] = '3';
$expected = '{"foo":"3"}';
$this->assertEquals($expected, $this->serializer->serialize($arr, 'json'), 'Context should not be persistent');
}
public function testEncodeNotUtf8WithoutPartialOnError()
{
$this->expectException('Symfony\Component\Serializer\Exception\UnexpectedValueException');
$arr = [
'utf8' => 'Hello World!',
'notUtf8' => "\xb0\xd0\xb5\xd0",
];
$this->encoder->encode($arr, 'json');
}
public function testEncodeNotUtf8WithPartialOnError()
{
$context = ['json_encode_options' => \JSON_PARTIAL_OUTPUT_ON_ERROR];
$arr = [
'utf8' => 'Hello World!',
'notUtf8' => "\xb0\xd0\xb5\xd0",
];
$result = $this->encoder->encode($arr, 'json', $context);
$jsonLastError = json_last_error();
$this->assertSame(\JSON_ERROR_UTF8, $jsonLastError);
$this->assertEquals('{"utf8":"Hello World!","notUtf8":null}', $result);
$this->assertEquals('0', $this->serializer->serialize(\NAN, 'json', $context));
}
public function testDecodeFalseString()
{
$result = $this->encoder->decode('false', 'json');
$this->assertSame(\JSON_ERROR_NONE, json_last_error());
$this->assertFalse($result);
}
protected function getJsonSource()
{
return '{"foo":"foo","bar":["a","b"],"baz":{"key":"val","key2":"val","A B":"bar","item":[{"title":"title1"},{"title":"title2"}],"Barry":{"FooBar":{"Baz":"Ed","@id":1}}},"qux":"1"}';
}
protected function getObject()
{
$obj = new \stdClass();
$obj->foo = 'foo';
$obj->bar = ['a', 'b'];
$obj->baz = ['key' => 'val', 'key2' => 'val', 'A B' => 'bar', 'item' => [['title' => 'title1'], ['title' => 'title2']], 'Barry' => ['FooBar' => ['Baz' => 'Ed', '@id' => 1]]];
$obj->qux = '1';
return $obj;
}
}

View File

@@ -0,0 +1,768 @@
<?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\Serializer\Tests\Encoder;
use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Serializer\Encoder\XmlEncoder;
use Symfony\Component\Serializer\Exception\NotEncodableValueException;
use Symfony\Component\Serializer\Normalizer\CustomNormalizer;
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
use Symfony\Component\Serializer\Serializer;
use Symfony\Component\Serializer\Tests\Fixtures\Dummy;
use Symfony\Component\Serializer\Tests\Fixtures\NormalizableTraversableDummy;
use Symfony\Component\Serializer\Tests\Fixtures\ScalarDummy;
class XmlEncoderTest extends TestCase
{
/**
* @var XmlEncoder
*/
private $encoder;
private $exampleDateTimeString = '2017-02-19T15:16:08+0300';
protected function setUp()
{
$this->encoder = new XmlEncoder();
$serializer = new Serializer([new CustomNormalizer()], ['xml' => new XmlEncoder()]);
$this->encoder->setSerializer($serializer);
}
public function testEncodeScalar()
{
$obj = new ScalarDummy();
$obj->xmlFoo = 'foo';
$expected = '<?xml version="1.0"?>'."\n".
'<response>foo</response>'."\n";
$this->assertEquals($expected, $this->encoder->encode($obj, 'xml'));
}
public function testSetRootNodeName()
{
$obj = new ScalarDummy();
$obj->xmlFoo = 'foo';
$this->encoder->setRootNodeName('test');
$expected = '<?xml version="1.0"?>'."\n".
'<test>foo</test>'."\n";
$this->assertEquals($expected, $this->encoder->encode($obj, 'xml'));
}
public function testDocTypeIsNotAllowed()
{
$this->expectException('Symfony\Component\Serializer\Exception\UnexpectedValueException');
$this->expectExceptionMessage('Document types are not allowed.');
$this->encoder->decode('<?xml version="1.0"?><!DOCTYPE foo><foo></foo>', 'foo');
}
public function testAttributes()
{
$obj = new ScalarDummy();
$obj->xmlFoo = [
'foo-bar' => [
'@id' => 1,
'@name' => 'Bar',
],
'Foo' => [
'Bar' => 'Test',
'@Type' => 'test',
],
'föo_bär' => 'a',
'Bar' => [1, 2, 3],
'a' => 'b',
];
$expected = '<?xml version="1.0"?>'."\n".
'<response>'.
'<foo-bar id="1" name="Bar"/>'.
'<Foo Type="test"><Bar>Test</Bar></Foo>'.
'<föo_bär>a</föo_bär>'.
'<Bar>1</Bar>'.
'<Bar>2</Bar>'.
'<Bar>3</Bar>'.
'<a>b</a>'.
'</response>'."\n";
$this->assertEquals($expected, $this->encoder->encode($obj, 'xml'));
}
public function testElementNameValid()
{
$obj = new ScalarDummy();
$obj->xmlFoo = [
'foo-bar' => 'a',
'foo_bar' => 'a',
'föo_bär' => 'a',
];
$expected = '<?xml version="1.0"?>'."\n".
'<response>'.
'<foo-bar>a</foo-bar>'.
'<foo_bar>a</foo_bar>'.
'<föo_bär>a</föo_bär>'.
'</response>'."\n";
$this->assertEquals($expected, $this->encoder->encode($obj, 'xml'));
}
public function testEncodeSimpleXML()
{
$xml = simplexml_load_string('<firstname>Peter</firstname>');
$array = ['person' => $xml];
$expected = '<?xml version="1.0"?>'."\n".
'<response><person><firstname>Peter</firstname></person></response>'."\n";
$this->assertEquals($expected, $this->encoder->encode($array, 'xml'));
}
public function testEncodeXmlAttributes()
{
$xml = simplexml_load_string('<firstname>Peter</firstname>');
$array = ['person' => $xml];
$expected = '<?xml version="1.1" encoding="utf-8" standalone="yes"?>'."\n".
'<response><person><firstname>Peter</firstname></person></response>'."\n";
$context = [
'xml_version' => '1.1',
'xml_encoding' => 'utf-8',
'xml_standalone' => true,
];
$this->assertSame($expected, $this->encoder->encode($array, 'xml', $context));
}
public function testEncodeRemovingEmptyTags()
{
$array = ['person' => ['firstname' => 'Peter', 'lastname' => null]];
$expected = '<?xml version="1.0"?>'."\n".
'<response><person><firstname>Peter</firstname></person></response>'."\n";
$context = ['remove_empty_tags' => true];
$this->assertSame($expected, $this->encoder->encode($array, 'xml', $context));
}
public function testEncodeNotRemovingEmptyTags()
{
$array = ['person' => ['firstname' => 'Peter', 'lastname' => null]];
$expected = '<?xml version="1.0"?>'."\n".
'<response><person><firstname>Peter</firstname><lastname/></person></response>'."\n";
$this->assertSame($expected, $this->encoder->encode($array, 'xml'));
}
public function testContext()
{
$array = ['person' => ['name' => 'George Abitbol']];
$expected = <<<'XML'
<?xml version="1.0"?>
<response>
<person>
<name>George Abitbol</name>
</person>
</response>
XML;
$context = [
'xml_format_output' => true,
];
$this->assertSame($expected, $this->encoder->encode($array, 'xml', $context));
}
public function testEncodeScalarRootAttributes()
{
$array = [
'#' => 'Paul',
'@eye-color' => 'brown',
];
$expected = '<?xml version="1.0"?>'."\n".
'<response eye-color="brown">Paul</response>'."\n";
$this->assertEquals($expected, $this->encoder->encode($array, 'xml'));
}
public function testEncodeRootAttributes()
{
$array = [
'firstname' => 'Paul',
'@eye-color' => 'brown',
];
$expected = '<?xml version="1.0"?>'."\n".
'<response eye-color="brown"><firstname>Paul</firstname></response>'."\n";
$this->assertEquals($expected, $this->encoder->encode($array, 'xml'));
}
public function testEncodeCdataWrapping()
{
$array = [
'firstname' => 'Paul <or Me>',
];
$expected = '<?xml version="1.0"?>'."\n".
'<response><firstname><![CDATA[Paul <or Me>]]></firstname></response>'."\n";
$this->assertEquals($expected, $this->encoder->encode($array, 'xml'));
}
public function testEncodeScalarWithAttribute()
{
$array = [
'person' => ['@eye-color' => 'brown', '#' => 'Peter'],
];
$expected = '<?xml version="1.0"?>'."\n".
'<response><person eye-color="brown">Peter</person></response>'."\n";
$this->assertEquals($expected, $this->encoder->encode($array, 'xml'));
}
public function testDecodeScalar()
{
$source = '<?xml version="1.0"?>'."\n".
'<response>foo</response>'."\n";
$this->assertEquals('foo', $this->encoder->decode($source, 'xml'));
}
public function testDecodeBigDigitAttributes()
{
$source = <<<XML
<?xml version="1.0"?>
<document index="182077241760011681341821060401202210011000045913000000017100">Name</document>
XML;
$this->assertSame(['@index' => 182077241760011681341821060401202210011000045913000000017100, '#' => 'Name'], $this->encoder->decode($source, 'xml'));
}
public function testDecodeNegativeIntAttribute()
{
$source = <<<XML
<?xml version="1.0"?>
<document index="-1234">Name</document>
XML;
$this->assertSame(['@index' => -1234, '#' => 'Name'], $this->encoder->decode($source, 'xml'));
}
public function testDecodeFloatAttribute()
{
$source = <<<XML
<?xml version="1.0"?>
<document index="12.11">Name</document>
XML;
$this->assertSame(['@index' => 12.11, '#' => 'Name'], $this->encoder->decode($source, 'xml'));
}
public function testDecodeNegativeFloatAttribute()
{
$source = <<<XML
<?xml version="1.0"?>
<document index="-12.11">Name</document>
XML;
$this->assertSame(['@index' => -12.11, '#' => 'Name'], $this->encoder->decode($source, 'xml'));
}
public function testDecodeFloatAttributeWithZeroWholeNumber()
{
$source = <<<XML
<?xml version="1.0"?>
<document index="0.123">Name</document>
XML;
$this->assertSame(['@index' => 0.123, '#' => 'Name'], $this->encoder->decode($source, 'xml'));
}
public function testNoTypeCastAttribute()
{
$source = <<<XML
<?xml version="1.0"?>
<document a="018" b="-12.11">
<node a="018" b="-12.11"/>
</document>
XML;
$data = $this->encoder->decode($source, 'xml', ['xml_type_cast_attributes' => false]);
$expected = [
'@a' => '018',
'@b' => '-12.11',
'node' => [
'@a' => '018',
'@b' => '-12.11',
'#' => '',
],
];
$this->assertSame($expected, $data);
}
public function testDoesNotTypeCastStringsStartingWith0()
{
$source = <<<XML
<?xml version="1.0"?>
<document a="018"></document>
XML;
$data = $this->encoder->decode($source, 'xml');
$this->assertSame('018', $data['@a']);
}
public function testEncode()
{
$source = $this->getXmlSource();
$obj = $this->getObject();
$this->assertEquals($source, $this->encoder->encode($obj, 'xml'));
}
public function testEncodeWithNamespace()
{
$source = $this->getNamespacedXmlSource();
$array = $this->getNamespacedArray();
$this->assertEquals($source, $this->encoder->encode($array, 'xml'));
}
public function testEncodeSerializerXmlRootNodeNameOption()
{
$options = ['xml_root_node_name' => 'test'];
$this->encoder = new XmlEncoder();
$serializer = new Serializer([], ['xml' => new XmlEncoder()]);
$this->encoder->setSerializer($serializer);
$array = [
'person' => ['@eye-color' => 'brown', '#' => 'Peter'],
];
$expected = '<?xml version="1.0"?>'."\n".
'<test><person eye-color="brown">Peter</person></test>'."\n";
$this->assertEquals($expected, $serializer->serialize($array, 'xml', $options));
}
public function testEncodeTraversableWhenNormalizable()
{
$this->encoder = new XmlEncoder();
$serializer = new Serializer([new CustomNormalizer()], ['xml' => new XmlEncoder()]);
$this->encoder->setSerializer($serializer);
$expected = <<<'XML'
<?xml version="1.0"?>
<response><foo>normalizedFoo</foo><bar>normalizedBar</bar></response>
XML;
$this->assertEquals($expected, $serializer->serialize(new NormalizableTraversableDummy(), 'xml'));
}
public function testDecode()
{
$source = $this->getXmlSource();
$obj = $this->getObject();
$this->assertEquals(get_object_vars($obj), $this->encoder->decode($source, 'xml'));
}
public function testDecodeCdataWrapping()
{
$expected = [
'firstname' => 'Paul <or Me>',
];
$xml = '<?xml version="1.0"?>'."\n".
'<response><firstname><![CDATA[Paul <or Me>]]></firstname></response>'."\n";
$this->assertEquals($expected, $this->encoder->decode($xml, 'xml'));
}
public function testDecodeCdataWrappingAndWhitespace()
{
$expected = [
'firstname' => 'Paul <or Me>',
];
$xml = '<?xml version="1.0"?>'."\n".
'<response><firstname>'."\n".
'<![CDATA[Paul <or Me>]]></firstname></response>'."\n";
$this->assertEquals($expected, $this->encoder->decode($xml, 'xml'));
}
public function testDecodeWithNamespace()
{
$source = $this->getNamespacedXmlSource();
$array = $this->getNamespacedArray();
$this->assertEquals($array, $this->encoder->decode($source, 'xml'));
}
public function testDecodeScalarWithAttribute()
{
$source = '<?xml version="1.0"?>'."\n".
'<response><person eye-color="brown">Peter</person></response>'."\n";
$expected = [
'person' => ['@eye-color' => 'brown', '#' => 'Peter'],
];
$this->assertEquals($expected, $this->encoder->decode($source, 'xml'));
}
public function testDecodeScalarRootAttributes()
{
$source = '<?xml version="1.0"?>'."\n".
'<person eye-color="brown">Peter</person>'."\n";
$expected = [
'#' => 'Peter',
'@eye-color' => 'brown',
];
$this->assertEquals($expected, $this->encoder->decode($source, 'xml'));
}
public function testDecodeRootAttributes()
{
$source = '<?xml version="1.0"?>'."\n".
'<person eye-color="brown"><firstname>Peter</firstname><lastname>Mac Calloway</lastname></person>'."\n";
$expected = [
'firstname' => 'Peter',
'lastname' => 'Mac Calloway',
'@eye-color' => 'brown',
];
$this->assertEquals($expected, $this->encoder->decode($source, 'xml'));
}
public function testDecodeArray()
{
$source = '<?xml version="1.0"?>'."\n".
'<response>'.
'<people>'.
'<person><firstname>Benjamin</firstname><lastname>Alexandre</lastname></person>'.
'<person><firstname>Damien</firstname><lastname>Clay</lastname></person>'.
'</people>'.
'</response>'."\n";
$expected = [
'people' => ['person' => [
['firstname' => 'Benjamin', 'lastname' => 'Alexandre'],
['firstname' => 'Damien', 'lastname' => 'Clay'],
]],
];
$this->assertEquals($expected, $this->encoder->decode($source, 'xml'));
}
public function testDecodeXMLWithProcessInstruction()
{
$source = <<<'XML'
<?xml version="1.0"?>
<?xml-stylesheet type="text/xsl" href="/xsl/xmlverbatimwrapper.xsl"?>
<?display table-view?>
<?sort alpha-ascending?>
<response>
<foo>foo</foo>
<?textinfo whitespace is allowed ?>
<bar>a</bar>
<bar>b</bar>
<baz>
<key>val</key>
<key2>val</key2>
<item key="A B">bar</item>
<item>
<title>title1</title>
</item>
<?item ignore-title ?>
<item>
<title>title2</title>
</item>
<Barry>
<FooBar id="1">
<Baz>Ed</Baz>
</FooBar>
</Barry>
</baz>
<qux>1</qux>
</response>
<?instruction <value> ?>
XML;
$obj = $this->getObject();
$this->assertEquals(get_object_vars($obj), $this->encoder->decode($source, 'xml'));
}
public function testDecodeIgnoreWhiteSpace()
{
$source = <<<'XML'
<?xml version="1.0"?>
<people>
<person>
<firstname>Benjamin</firstname>
<lastname>Alexandre</lastname>
</person>
<person>
<firstname>Damien</firstname>
<lastname>Clay</lastname>
</person>
</people>
XML;
$expected = ['person' => [
['firstname' => 'Benjamin', 'lastname' => 'Alexandre'],
['firstname' => 'Damien', 'lastname' => 'Clay'],
]];
$this->assertEquals($expected, $this->encoder->decode($source, 'xml'));
}
public function testDecodeWithoutItemHash()
{
$obj = new ScalarDummy();
$obj->xmlFoo = [
'foo-bar' => [
'@key' => 'value',
'item' => ['@key' => 'key', 'key-val' => 'val'],
],
'Foo' => [
'Bar' => 'Test',
'@Type' => 'test',
],
'föo_bär' => 'a',
'Bar' => [1, 2, 3],
'a' => 'b',
];
$expected = [
'foo-bar' => [
'@key' => 'value',
'key' => ['@key' => 'key', 'key-val' => 'val'],
],
'Foo' => [
'Bar' => 'Test',
'@Type' => 'test',
],
'föo_bär' => 'a',
'Bar' => [1, 2, 3],
'a' => 'b',
];
$xml = $this->encoder->encode($obj, 'xml');
$this->assertEquals($expected, $this->encoder->decode($xml, 'xml'));
}
public function testDecodeInvalidXml()
{
$this->expectException('Symfony\Component\Serializer\Exception\UnexpectedValueException');
$this->encoder->decode('<?xml version="1.0"?><invalid><xml>', 'xml');
}
public function testPreventsComplexExternalEntities()
{
$this->expectException('Symfony\Component\Serializer\Exception\UnexpectedValueException');
$this->encoder->decode('<?xml version="1.0"?><!DOCTYPE scan[<!ENTITY test SYSTEM "php://filter/read=convert.base64-encode/resource=XmlEncoderTest.php">]><scan>&test;</scan>', 'xml');
}
public function testDecodeEmptyXml()
{
$this->expectException('Symfony\Component\Serializer\Exception\UnexpectedValueException');
$this->expectExceptionMessage('Invalid XML data, it can not be empty.');
$this->encoder->decode(' ', 'xml');
}
protected function getXmlSource()
{
return '<?xml version="1.0"?>'."\n".
'<response>'.
'<foo>foo</foo>'.
'<bar>a</bar><bar>b</bar>'.
'<baz><key>val</key><key2>val</key2><item key="A B">bar</item>'.
'<item><title>title1</title></item><item><title>title2</title></item>'.
'<Barry><FooBar id="1"><Baz>Ed</Baz></FooBar></Barry></baz>'.
'<qux>1</qux>'.
'</response>'."\n";
}
protected function getNamespacedXmlSource()
{
return '<?xml version="1.0"?>'."\n".
'<response xmlns="http://www.w3.org/2005/Atom" xmlns:app="http://www.w3.org/2007/app" xmlns:media="http://search.yahoo.com/mrss/" xmlns:gd="http://schemas.google.com/g/2005" xmlns:yt="http://gdata.youtube.com/schemas/2007">'.
'<qux>1</qux>'.
'<app:foo>foo</app:foo>'.
'<yt:bar>a</yt:bar><yt:bar>b</yt:bar>'.
'<media:baz><media:key>val</media:key><media:key2>val</media:key2><item key="A B">bar</item>'.
'<item><title>title1</title></item><item><title>title2</title></item>'.
'<Barry size="large"><FooBar gd:id="1"><Baz>Ed</Baz></FooBar></Barry></media:baz>'.
'</response>'."\n";
}
protected function getNamespacedArray()
{
return [
'@xmlns' => 'http://www.w3.org/2005/Atom',
'@xmlns:app' => 'http://www.w3.org/2007/app',
'@xmlns:media' => 'http://search.yahoo.com/mrss/',
'@xmlns:gd' => 'http://schemas.google.com/g/2005',
'@xmlns:yt' => 'http://gdata.youtube.com/schemas/2007',
'qux' => '1',
'app:foo' => 'foo',
'yt:bar' => ['a', 'b'],
'media:baz' => [
'media:key' => 'val',
'media:key2' => 'val',
'A B' => 'bar',
'item' => [
[
'title' => 'title1',
],
[
'title' => 'title2',
],
],
'Barry' => [
'@size' => 'large',
'FooBar' => [
'Baz' => 'Ed',
'@gd:id' => 1,
],
],
],
];
}
protected function getObject()
{
$obj = new Dummy();
$obj->foo = 'foo';
$obj->bar = ['a', 'b'];
$obj->baz = ['key' => 'val', 'key2' => 'val', 'A B' => 'bar', 'item' => [['title' => 'title1'], ['title' => 'title2']], 'Barry' => ['FooBar' => ['Baz' => 'Ed', '@id' => 1]]];
$obj->qux = '1';
return $obj;
}
public function testEncodeXmlWithBoolValue()
{
$expectedXml = <<<'XML'
<?xml version="1.0"?>
<response><foo>1</foo><bar>0</bar></response>
XML;
$actualXml = $this->encoder->encode(['foo' => true, 'bar' => false], 'xml');
$this->assertEquals($expectedXml, $actualXml);
}
public function testEncodeXmlWithDomNodeValue()
{
$expectedXml = <<<'XML'
<?xml version="1.0"?>
<response><foo>bar</foo><bar>foo &amp; bar</bar></response>
XML;
$document = new \DOMDocument();
$actualXml = $this->encoder->encode(['foo' => $document->createTextNode('bar'), 'bar' => $document->createTextNode('foo & bar')], 'xml');
$this->assertEquals($expectedXml, $actualXml);
}
public function testEncodeXmlWithDateTimeObjectValue()
{
$xmlEncoder = $this->createXmlEncoderWithDateTimeNormalizer();
$actualXml = $xmlEncoder->encode(['dateTime' => new \DateTime($this->exampleDateTimeString)], 'xml');
$this->assertEquals($this->createXmlWithDateTime(), $actualXml);
}
public function testEncodeXmlWithDateTimeObjectField()
{
$xmlEncoder = $this->createXmlEncoderWithDateTimeNormalizer();
$actualXml = $xmlEncoder->encode(['foo' => ['@dateTime' => new \DateTime($this->exampleDateTimeString)]], 'xml');
$this->assertEquals($this->createXmlWithDateTimeField(), $actualXml);
}
public function testNotEncodableValueExceptionMessageForAResource()
{
$this->expectException(NotEncodableValueException::class);
$this->expectExceptionMessage('An unexpected value could not be serialized: stream resource');
(new XmlEncoder())->encode(tmpfile(), 'xml');
}
/**
* @return XmlEncoder
*/
private function createXmlEncoderWithDateTimeNormalizer()
{
$encoder = new XmlEncoder();
$serializer = new Serializer([$this->createMockDateTimeNormalizer()], ['xml' => new XmlEncoder()]);
$encoder->setSerializer($serializer);
return $encoder;
}
/**
* @return MockObject|NormalizerInterface
*/
private function createMockDateTimeNormalizer()
{
$mock = $this->getMockBuilder('\Symfony\Component\Serializer\Normalizer\CustomNormalizer')->getMock();
$mock
->expects($this->once())
->method('normalize')
->with(new \DateTime($this->exampleDateTimeString), 'xml', [])
->willReturn($this->exampleDateTimeString);
$mock
->expects($this->once())
->method('supportsNormalization')
->with(new \DateTime($this->exampleDateTimeString), 'xml')
->willReturn(true);
return $mock;
}
/**
* @return string
*/
private function createXmlWithDateTime()
{
return sprintf('<?xml version="1.0"?>
<response><dateTime>%s</dateTime></response>
', $this->exampleDateTimeString);
}
/**
* @return string
*/
private function createXmlWithDateTimeField()
{
return sprintf('<?xml version="1.0"?>
<response><foo dateTime="%s"/></response>
', $this->exampleDateTimeString);
}
}

View File

@@ -0,0 +1,71 @@
<?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\Serializer\Tests\Encoder;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Serializer\Encoder\YamlEncoder;
use Symfony\Component\Yaml\Dumper;
use Symfony\Component\Yaml\Parser;
use Symfony\Component\Yaml\Yaml;
/**
* @author Kévin Dunglas <dunglas@gmail.com>
*/
class YamlEncoderTest extends TestCase
{
public function testEncode()
{
$encoder = new YamlEncoder();
$this->assertEquals('foo', $encoder->encode('foo', 'yaml'));
$this->assertEquals('{ foo: 1 }', $encoder->encode(['foo' => 1], 'yaml'));
}
public function testSupportsEncoding()
{
$encoder = new YamlEncoder();
$this->assertTrue($encoder->supportsEncoding('yaml'));
$this->assertFalse($encoder->supportsEncoding('json'));
}
public function testDecode()
{
$encoder = new YamlEncoder();
$this->assertEquals('foo', $encoder->decode('foo', 'yaml'));
$this->assertEquals(['foo' => 1], $encoder->decode('{ foo: 1 }', 'yaml'));
}
public function testSupportsDecoding()
{
$encoder = new YamlEncoder();
$this->assertTrue($encoder->supportsDecoding('yaml'));
$this->assertFalse($encoder->supportsDecoding('json'));
}
public function testContext()
{
$encoder = new YamlEncoder(new Dumper(), new Parser(), ['yaml_inline' => 1, 'yaml_indent' => 4, 'yaml_flags' => Yaml::DUMP_OBJECT | Yaml::PARSE_OBJECT]);
$obj = new \stdClass();
$obj->bar = 2;
$legacyTag = " foo: !php/object:O:8:\"stdClass\":1:{s:3:\"bar\";i:2;}\n";
$spacedTag = " foo: !php/object 'O:8:\"stdClass\":1:{s:3:\"bar\";i:2;}'\n";
$this->assertThat($encoder->encode(['foo' => $obj], 'yaml'), $this->logicalOr($this->equalTo($legacyTag), $this->equalTo($spacedTag)));
$this->assertEquals(' { foo: null }', $encoder->encode(['foo' => $obj], 'yaml', ['yaml_inline' => 0, 'yaml_indent' => 2, 'yaml_flags' => 0]));
$this->assertEquals(['foo' => $obj], $encoder->decode("foo: !php/object 'O:8:\"stdClass\":1:{s:3:\"bar\";i:2;}'", 'yaml'));
$this->assertEquals(['foo' => null], $encoder->decode("foo: !php/object 'O:8:\"stdClass\":1:{s:3:\"bar\";i:2;}'", 'yaml', ['yaml_flags' => 0]));
}
}

View File

@@ -0,0 +1,60 @@
<?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\Serializer\Tests\Fixtures;
use Symfony\Component\Serializer\Normalizer\AbstractNormalizer;
/**
* Provides a dummy Normalizer which extends the AbstractNormalizer.
*
* @author Konstantin S. M. Möllers <ksm.moellers@gmail.com>
*/
class AbstractNormalizerDummy extends AbstractNormalizer
{
/**
* {@inheritdoc}
*/
public function getAllowedAttributes($classOrObject, array $context, $attributesAsString = false)
{
return parent::getAllowedAttributes($classOrObject, $context, $attributesAsString);
}
/**
* {@inheritdoc}
*/
public function normalize($object, $format = null, array $context = [])
{
}
/**
* {@inheritdoc}
*/
public function supportsNormalization($data, $format = null)
{
return true;
}
/**
* {@inheritdoc}
*/
public function denormalize($data, $type, $format = null, array $context = [])
{
}
/**
* {@inheritdoc}
*/
public function supportsDenormalization($data, $type, $format = null)
{
return true;
}
}

View File

@@ -0,0 +1,23 @@
<?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\Serializer\Tests\Fixtures;
/**
* @author Kévin Dunglas <dunglas@gmail.com>
*/
class CircularReferenceDummy
{
public function getMe()
{
return $this;
}
}

View File

@@ -0,0 +1,22 @@
<?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\Serializer\Tests\Fixtures;
use Symfony\Component\Serializer\Normalizer\DenormalizableInterface;
use Symfony\Component\Serializer\Normalizer\DenormalizerInterface;
class DenormalizableDummy implements DenormalizableInterface
{
public function denormalize(DenormalizerInterface $denormalizer, $data, $format = null, array $context = [])
{
}
}

View File

@@ -0,0 +1,43 @@
<?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\Serializer\Tests\Fixtures;
use Symfony\Component\Serializer\Normalizer\DenormalizableInterface;
use Symfony\Component\Serializer\Normalizer\DenormalizerInterface;
use Symfony\Component\Serializer\Normalizer\NormalizableInterface;
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
class Dummy implements NormalizableInterface, DenormalizableInterface
{
public $foo;
public $bar;
public $baz;
public $qux;
public function normalize(NormalizerInterface $normalizer, $format = null, array $context = [])
{
return [
'foo' => $this->foo,
'bar' => $this->bar,
'baz' => $this->baz,
'qux' => $this->qux,
];
}
public function denormalize(DenormalizerInterface $denormalizer, $data, $format = null, array $context = [])
{
$this->foo = $data['foo'];
$this->bar = $data['bar'];
$this->baz = $data['baz'];
$this->qux = $data['qux'];
}
}

View File

@@ -0,0 +1,80 @@
<?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\Serializer\Tests\Fixtures;
use Symfony\Component\Serializer\Annotation\Groups;
/**
* @author Kévin Dunglas <dunglas@gmail.com>
*/
class GroupDummy extends GroupDummyParent implements GroupDummyInterface
{
/**
* @Groups({"a"})
*/
private $foo;
/**
* @Groups({"b", "c", "name_converter"})
*/
protected $bar;
private $fooBar;
private $symfony;
/**
* @Groups({"b"})
*/
public function setBar($bar)
{
$this->bar = $bar;
}
/**
* @Groups({"c"})
*/
public function getBar()
{
return $this->bar;
}
public function setFoo($foo)
{
$this->foo = $foo;
}
public function getFoo()
{
return $this->foo;
}
public function setFooBar($fooBar)
{
$this->fooBar = $fooBar;
}
/**
* @Groups({"a", "b", "name_converter"})
*/
public function isFooBar()
{
return $this->fooBar;
}
public function setSymfony($symfony)
{
$this->symfony = $symfony;
}
public function getSymfony()
{
return $this->symfony;
}
}

View File

@@ -0,0 +1,33 @@
<?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\Serializer\Tests\Fixtures;
class GroupDummyChild extends GroupDummy
{
private $baz;
/**
* @return mixed
*/
public function getBaz()
{
return $this->baz;
}
/**
* @param mixed $baz
*/
public function setBaz($baz)
{
$this->baz = $baz;
}
}

View File

@@ -0,0 +1,25 @@
<?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\Serializer\Tests\Fixtures;
use Symfony\Component\Serializer\Annotation\Groups;
/**
* @author Kévin Dunglas <dunglas@gmail.com>
*/
interface GroupDummyInterface
{
/**
* @Groups({"a", "name_converter"})
*/
public function getSymfony();
}

View File

@@ -0,0 +1,49 @@
<?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\Serializer\Tests\Fixtures;
use Symfony\Component\Serializer\Annotation\Groups;
/**
* @author Kévin Dunglas <dunglas@gmail.com>
*/
class GroupDummyParent
{
/**
* @Groups({"a"})
*/
private $kevin;
private $coopTilleuls;
public function setKevin($kevin)
{
$this->kevin = $kevin;
}
public function getKevin()
{
return $this->kevin;
}
public function setCoopTilleuls($coopTilleuls)
{
$this->coopTilleuls = $coopTilleuls;
}
/**
* @Groups({"a", "b"})
*/
public function getCoopTilleuls()
{
return $this->coopTilleuls;
}
}

View File

@@ -0,0 +1,25 @@
<?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\Serializer\Tests\Fixtures;
class JsonSerializableDummy implements \JsonSerializable
{
public function jsonSerialize()
{
return [
'foo' => 'a',
'bar' => 'b',
'baz' => 'c',
'qux' => $this,
];
}
}

View File

@@ -0,0 +1,45 @@
<?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\Serializer\Tests\Fixtures;
use Symfony\Component\Serializer\Annotation\MaxDepth;
/**
* @author Kévin Dunglas <dunglas@gmail.com>
*/
class MaxDepthDummy
{
/**
* @MaxDepth(2)
*/
public $foo;
public $bar;
/**
* @var self
*/
public $child;
/**
* @MaxDepth(3)
*/
public function getBar()
{
return $this->bar;
}
public function getChild()
{
return $this->child;
}
}

View File

@@ -0,0 +1,36 @@
<?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\Serializer\Tests\Fixtures;
use Symfony\Component\Serializer\Normalizer\DenormalizableInterface;
use Symfony\Component\Serializer\Normalizer\DenormalizerInterface;
use Symfony\Component\Serializer\Normalizer\NormalizableInterface;
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
class NormalizableTraversableDummy extends TraversableDummy implements NormalizableInterface, DenormalizableInterface
{
public function normalize(NormalizerInterface $normalizer, $format = null, array $context = [])
{
return [
'foo' => 'normalizedFoo',
'bar' => 'normalizedBar',
];
}
public function denormalize(DenormalizerInterface $denormalizer, $data, $format = null, array $context = [])
{
return [
'foo' => 'denormalizedFoo',
'bar' => 'denormalizedBar',
];
}
}

View File

@@ -0,0 +1,32 @@
<?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\Serializer\Tests\Fixtures;
class NullableConstructorArgumentDummy
{
private $foo;
public function __construct(?\stdClass $foo)
{
$this->foo = $foo;
}
public function setFoo($foo)
{
$this->foo = 'this setter should not be called when using the constructor argument';
}
public function getFoo()
{
return $this->foo;
}
}

View File

@@ -0,0 +1,22 @@
<?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\Serializer\Tests\Fixtures;
/**
* @author Valentin Udaltsov <udaltsov.valentin@gmail.com>
*/
final class Php74Dummy
{
public string $uninitializedProperty;
public string $initializedProperty = 'defaultValue';
}

View File

@@ -0,0 +1,25 @@
<?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\Serializer\Tests\Fixtures;
/**
* @author Kévin Dunglas <dunglas@gmail.com>
*/
class PropertyCircularReferenceDummy
{
public $me;
public function __construct()
{
$this->me = $this;
}
}

View File

@@ -0,0 +1,39 @@
<?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\Serializer\Tests\Fixtures;
/**
* @author Kévin Dunglas <dunglas@gmail.com>
*/
class PropertySiblingHolder
{
public $sibling0;
public $sibling1;
public $sibling2;
public function __construct()
{
$sibling = new PropertySibling();
$this->sibling0 = $sibling;
$this->sibling1 = $sibling;
$this->sibling2 = $sibling;
}
}
/**
* @author Kévin Dunglas <dunglas@gmail.com>
*/
class PropertySibling
{
public $coopTilleuls = 'Les-Tilleuls.coop';
}

View File

@@ -0,0 +1,19 @@
<?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\Serializer\Tests\Fixtures;
/**
* @author Kévin Dunglas <dunglas@gmail.com>
*/
class ProxyDummy extends ToBeProxyfiedDummy
{
}

View File

@@ -0,0 +1,37 @@
<?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\Serializer\Tests\Fixtures;
use Symfony\Component\Serializer\Normalizer\DenormalizableInterface;
use Symfony\Component\Serializer\Normalizer\DenormalizerInterface;
use Symfony\Component\Serializer\Normalizer\NormalizableInterface;
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
class ScalarDummy implements NormalizableInterface, DenormalizableInterface
{
public $foo;
public $xmlFoo;
public function normalize(NormalizerInterface $normalizer, $format = null, array $context = [])
{
return 'xml' === $format ? $this->xmlFoo : $this->foo;
}
public function denormalize(DenormalizerInterface $denormalizer, $data, $format = null, array $context = [])
{
if ('xml' === $format) {
$this->xmlFoo = $data;
} else {
$this->foo = $data;
}
}
}

View File

@@ -0,0 +1,57 @@
<?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\Serializer\Tests\Fixtures;
/**
* @author Kévin Dunglas <dunglas@gmail.com>
*/
class SiblingHolder
{
private $sibling0;
private $sibling1;
private $sibling2;
public function __construct()
{
$sibling = new Sibling();
$this->sibling0 = $sibling;
$this->sibling1 = $sibling;
$this->sibling2 = $sibling;
}
public function getSibling0()
{
return $this->sibling0;
}
public function getSibling1()
{
return $this->sibling1;
}
public function getSibling2()
{
return $this->sibling2;
}
}
/**
* @author Kévin Dunglas <dunglas@gmail.com>
*/
class Sibling
{
public function getCoopTilleuls()
{
return 'Les-Tilleuls.coop';
}
}

View File

@@ -0,0 +1,31 @@
<?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\Serializer\Tests\Fixtures;
class StaticConstructorDummy
{
public $foo;
public $bar;
public $quz;
public static function create($foo)
{
$dummy = new self();
$dummy->quz = $foo;
return $dummy;
}
private function __construct()
{
}
}

View File

@@ -0,0 +1,32 @@
<?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\Serializer\Tests\Fixtures;
use Symfony\Component\Serializer\Normalizer\ObjectNormalizer;
/**
* @author Guilhem N. <egetick@gmail.com>
*/
class StaticConstructorNormalizer extends ObjectNormalizer
{
/**
* {@inheritdoc}
*/
protected function getConstructor(array &$data, $class, array &$context, \ReflectionClass $reflectionClass, $allowedAttributes)
{
if (is_a($class, StaticConstructorDummy::class, true)) {
return new \ReflectionMethod($class, 'create');
}
return parent::getConstructor($data, $class, $context, $reflectionClass, $allowedAttributes);
}
}

View File

@@ -0,0 +1,30 @@
<?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\Serializer\Tests\Fixtures;
/**
* @author Kévin Dunglas <dunglas@gmail.com>
*/
class ToBeProxyfiedDummy
{
private $foo;
public function setFoo($foo)
{
$this->foo = $foo;
}
public function getFoo()
{
return $this->foo;
}
}

View File

@@ -0,0 +1,23 @@
<?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\Serializer\Tests\Fixtures;
class TraversableDummy implements \IteratorAggregate
{
public $foo = 'foo';
public $bar = 'bar';
public function getIterator()
{
return new \ArrayIterator(get_object_vars($this));
}
}

View File

@@ -0,0 +1,27 @@
<?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\Serializer\Tests\Fixtures;
class VariadicConstructorArgsDummy
{
private $foo;
public function __construct(...$foo)
{
$this->foo = $foo;
}
public function getFoo()
{
return $this->foo;
}
}

View File

@@ -0,0 +1,28 @@
<?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\Serializer\Tests\Fixtures;
class VariadicConstructorTypedArgsDummy
{
private $foo;
public function __construct(Dummy ...$foo)
{
$this->foo = $foo;
}
/** @return Dummy[] */
public function getFoo()
{
return $this->foo;
}
}

View File

@@ -0,0 +1 @@
foo

View File

@@ -0,0 +1,23 @@
<?xml version="1.0" ?>
<serializer xmlns="http://symfony.com/schema/dic/serializer-mapping"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/dic/serializer-mapping https://symfony.com/schema/dic/serializer-mapping/serializer-mapping-1.0.xsd">
<class name="Symfony\Component\Serializer\Tests\Fixtures\GroupDummy">
<attribute name="foo">
<group>group1</group>
<group>group2</group>
</attribute>
<attribute name="bar">
<group>group2</group>
</attribute>
</class>
<class name="Symfony\Component\Serializer\Tests\Fixtures\MaxDepthDummy">
<attribute name="foo" max-depth="2" />
<attribute name="bar" max-depth="3" />
</class>
</serializer>

View File

@@ -0,0 +1,12 @@
'Symfony\Component\Serializer\Tests\Fixtures\GroupDummy':
attributes:
foo:
groups: ['group1', 'group2']
bar:
groups: ['group2']
'Symfony\Component\Serializer\Tests\Fixtures\MaxDepthDummy':
attributes:
foo:
max_depth: 2
bar:
max_depth: 3

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 B

View File

@@ -0,0 +1 @@
Kévin Dunglas

View File

@@ -0,0 +1,79 @@
<?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\Serializer\Tests\Mapping;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Serializer\Mapping\AttributeMetadata;
/**
* @author Kévin Dunglas <dunglas@gmail.com>
*/
class AttributeMetadataTest extends TestCase
{
public function testInterface()
{
$attributeMetadata = new AttributeMetadata('name');
$this->assertInstanceOf('Symfony\Component\Serializer\Mapping\AttributeMetadataInterface', $attributeMetadata);
}
public function testGetName()
{
$attributeMetadata = new AttributeMetadata('name');
$this->assertEquals('name', $attributeMetadata->getName());
}
public function testGroups()
{
$attributeMetadata = new AttributeMetadata('group');
$attributeMetadata->addGroup('a');
$attributeMetadata->addGroup('a');
$attributeMetadata->addGroup('b');
$this->assertEquals(['a', 'b'], $attributeMetadata->getGroups());
}
public function testMaxDepth()
{
$attributeMetadata = new AttributeMetadata('name');
$attributeMetadata->setMaxDepth(69);
$this->assertEquals(69, $attributeMetadata->getMaxDepth());
}
public function testMerge()
{
$attributeMetadata1 = new AttributeMetadata('a1');
$attributeMetadata1->addGroup('a');
$attributeMetadata1->addGroup('b');
$attributeMetadata2 = new AttributeMetadata('a2');
$attributeMetadata2->addGroup('a');
$attributeMetadata2->addGroup('c');
$attributeMetadata2->setMaxDepth(2);
$attributeMetadata1->merge($attributeMetadata2);
$this->assertEquals(['a', 'b', 'c'], $attributeMetadata1->getGroups());
$this->assertEquals(2, $attributeMetadata1->getMaxDepth());
}
public function testSerialize()
{
$attributeMetadata = new AttributeMetadata('attribute');
$attributeMetadata->addGroup('a');
$attributeMetadata->addGroup('b');
$attributeMetadata->setMaxDepth(3);
$serialized = serialize($attributeMetadata);
$this->assertEquals($attributeMetadata, unserialize($serialized));
}
}

View File

@@ -0,0 +1,76 @@
<?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\Serializer\Tests\Mapping;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Serializer\Mapping\AttributeMetadata;
use Symfony\Component\Serializer\Mapping\ClassMetadata;
/**
* @author Kévin Dunglas <dunglas@gmail.com>
*/
class ClassMetadataTest extends TestCase
{
public function testInterface()
{
$classMetadata = new ClassMetadata('name');
$this->assertInstanceOf('Symfony\Component\Serializer\Mapping\ClassMetadataInterface', $classMetadata);
}
public function testAttributeMetadata()
{
$classMetadata = new ClassMetadata('c');
$a1 = new AttributeMetadata('a1');
$a2 = new AttributeMetadata('a2');
$classMetadata->addAttributeMetadata($a1);
$classMetadata->addAttributeMetadata($a2);
$this->assertEquals(['a1' => $a1, 'a2' => $a2], $classMetadata->getAttributesMetadata());
}
public function testMerge()
{
$classMetadata1 = new ClassMetadata('c1');
$classMetadata2 = new ClassMetadata('c2');
$ac1 = new AttributeMetadata('a1');
$ac1->addGroup('a');
$ac1->addGroup('b');
$ac2 = new AttributeMetadata('a1');
$ac2->addGroup('b');
$ac2->addGroup('c');
$classMetadata1->addAttributeMetadata($ac1);
$classMetadata2->addAttributeMetadata($ac2);
$classMetadata1->merge($classMetadata2);
$this->assertSame(['a', 'b', 'c'], $ac1->getGroups());
$this->assertEquals(['a1' => $ac1], $classMetadata1->getAttributesMetadata());
}
public function testSerialize()
{
$classMetadata = new ClassMetadata('a');
$a1 = new AttributeMetadata('b1');
$a2 = new AttributeMetadata('b2');
$classMetadata->addAttributeMetadata($a1);
$classMetadata->addAttributeMetadata($a2);
$serialized = serialize($classMetadata);
$this->assertEquals($classMetadata, unserialize($serialized));
}
}

View File

@@ -0,0 +1,66 @@
<?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\Serializer\Tests\Mapping\Factory;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Cache\Adapter\ArrayAdapter;
use Symfony\Component\Serializer\Mapping\ClassMetadata;
use Symfony\Component\Serializer\Mapping\Factory\CacheClassMetadataFactory;
use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactoryInterface;
use Symfony\Component\Serializer\Tests\Fixtures\Dummy;
/**
* @author Kévin Dunglas <dunglas@gmail.com>
*/
class CacheMetadataFactoryTest extends TestCase
{
public function testGetMetadataFor()
{
$metadata = new ClassMetadata(Dummy::class);
$decorated = $this->getMockBuilder(ClassMetadataFactoryInterface::class)->getMock();
$decorated
->expects($this->once())
->method('getMetadataFor')
->willReturn($metadata)
;
$factory = new CacheClassMetadataFactory($decorated, new ArrayAdapter());
$this->assertEquals($metadata, $factory->getMetadataFor(Dummy::class));
// The second call should retrieve the value from the cache
$this->assertEquals($metadata, $factory->getMetadataFor(Dummy::class));
}
public function testHasMetadataFor()
{
$decorated = $this->getMockBuilder(ClassMetadataFactoryInterface::class)->getMock();
$decorated
->expects($this->once())
->method('hasMetadataFor')
->willReturn(true)
;
$factory = new CacheClassMetadataFactory($decorated, new ArrayAdapter());
$this->assertTrue($factory->hasMetadataFor(Dummy::class));
}
public function testInvalidClassThrowsException()
{
$this->expectException('Symfony\Component\Serializer\Exception\InvalidArgumentException');
$decorated = $this->getMockBuilder(ClassMetadataFactoryInterface::class)->getMock();
$factory = new CacheClassMetadataFactory($decorated, new ArrayAdapter());
$factory->getMetadataFor('Not\Exist');
}
}

View File

@@ -0,0 +1,79 @@
<?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\Serializer\Tests\Mapping\Factory;
use Doctrine\Common\Annotations\AnnotationReader;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactory;
use Symfony\Component\Serializer\Mapping\Loader\AnnotationLoader;
use Symfony\Component\Serializer\Mapping\Loader\LoaderChain;
use Symfony\Component\Serializer\Tests\Mapping\TestClassMetadataFactory;
/**
* @author Kévin Dunglas <dunglas@gmail.com>
*/
class ClassMetadataFactoryTest extends TestCase
{
public function testInterface()
{
$classMetadata = new ClassMetadataFactory(new LoaderChain([]));
$this->assertInstanceOf('Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactoryInterface', $classMetadata);
}
public function testGetMetadataFor()
{
$factory = new ClassMetadataFactory(new AnnotationLoader(new AnnotationReader()));
$classMetadata = $factory->getMetadataFor('Symfony\Component\Serializer\Tests\Fixtures\GroupDummy');
$this->assertEquals(TestClassMetadataFactory::createClassMetadata(true, true), $classMetadata);
}
public function testHasMetadataFor()
{
$factory = new ClassMetadataFactory(new AnnotationLoader(new AnnotationReader()));
$this->assertTrue($factory->hasMetadataFor('Symfony\Component\Serializer\Tests\Fixtures\GroupDummy'));
$this->assertTrue($factory->hasMetadataFor('Symfony\Component\Serializer\Tests\Fixtures\GroupDummyParent'));
$this->assertTrue($factory->hasMetadataFor('Symfony\Component\Serializer\Tests\Fixtures\GroupDummyInterface'));
$this->assertFalse($factory->hasMetadataFor('Dunglas\Entity'));
}
/**
* @group legacy
*/
public function testCacheExists()
{
$cache = $this->getMockBuilder('Doctrine\Common\Cache\Cache')->getMock();
$cache
->expects($this->once())
->method('fetch')
->willReturn('foo')
;
$factory = new ClassMetadataFactory(new AnnotationLoader(new AnnotationReader()), $cache);
$this->assertEquals('foo', $factory->getMetadataFor('Symfony\Component\Serializer\Tests\Fixtures\GroupDummy'));
}
/**
* @group legacy
*/
public function testCacheNotExists()
{
$cache = $this->getMockBuilder('Doctrine\Common\Cache\Cache')->getMock();
$cache->method('fetch')->willReturn(false);
$cache->method('save');
$factory = new ClassMetadataFactory(new AnnotationLoader(new AnnotationReader()), $cache);
$metadata = $factory->getMetadataFor('Symfony\Component\Serializer\Tests\Fixtures\GroupDummy');
$this->assertEquals(TestClassMetadataFactory::createClassMetadata(true, true), $metadata);
}
}

View File

@@ -0,0 +1,77 @@
<?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\Serializer\Tests\Mapping\Loader;
use Doctrine\Common\Annotations\AnnotationReader;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Serializer\Mapping\ClassMetadata;
use Symfony\Component\Serializer\Mapping\Loader\AnnotationLoader;
use Symfony\Component\Serializer\Tests\Mapping\TestClassMetadataFactory;
/**
* @author Kévin Dunglas <dunglas@gmail.com>
*/
class AnnotationLoaderTest extends TestCase
{
/**
* @var AnnotationLoader
*/
private $loader;
protected function setUp()
{
$this->loader = new AnnotationLoader(new AnnotationReader());
}
public function testInterface()
{
$this->assertInstanceOf('Symfony\Component\Serializer\Mapping\Loader\LoaderInterface', $this->loader);
}
public function testLoadClassMetadataReturnsTrueIfSuccessful()
{
$classMetadata = new ClassMetadata('Symfony\Component\Serializer\Tests\Fixtures\GroupDummy');
$this->assertTrue($this->loader->loadClassMetadata($classMetadata));
}
public function testLoadGroups()
{
$classMetadata = new ClassMetadata('Symfony\Component\Serializer\Tests\Fixtures\GroupDummy');
$this->loader->loadClassMetadata($classMetadata);
$this->assertEquals(TestClassMetadataFactory::createClassMetadata(), $classMetadata);
}
public function testLoadMaxDepth()
{
$classMetadata = new ClassMetadata('Symfony\Component\Serializer\Tests\Fixtures\MaxDepthDummy');
$this->loader->loadClassMetadata($classMetadata);
$attributesMetadata = $classMetadata->getAttributesMetadata();
$this->assertEquals(2, $attributesMetadata['foo']->getMaxDepth());
$this->assertEquals(3, $attributesMetadata['bar']->getMaxDepth());
}
public function testLoadClassMetadataAndMerge()
{
$classMetadata = new ClassMetadata('Symfony\Component\Serializer\Tests\Fixtures\GroupDummy');
$parentClassMetadata = new ClassMetadata('Symfony\Component\Serializer\Tests\Fixtures\GroupDummyParent');
$this->loader->loadClassMetadata($parentClassMetadata);
$classMetadata->merge($parentClassMetadata);
$this->loader->loadClassMetadata($classMetadata);
$this->assertEquals(TestClassMetadataFactory::createClassMetadata(true), $classMetadata);
}
}

View File

@@ -0,0 +1,65 @@
<?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\Serializer\Tests\Mapping\Loader;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Serializer\Mapping\ClassMetadata;
use Symfony\Component\Serializer\Mapping\Loader\XmlFileLoader;
use Symfony\Component\Serializer\Tests\Mapping\TestClassMetadataFactory;
/**
* @author Kévin Dunglas <dunglas@gmail.com>
*/
class XmlFileLoaderTest extends TestCase
{
/**
* @var XmlFileLoader
*/
private $loader;
/**
* @var ClassMetadata
*/
private $metadata;
protected function setUp()
{
$this->loader = new XmlFileLoader(__DIR__.'/../../Fixtures/serialization.xml');
$this->metadata = new ClassMetadata('Symfony\Component\Serializer\Tests\Fixtures\GroupDummy');
}
public function testInterface()
{
$this->assertInstanceOf('Symfony\Component\Serializer\Mapping\Loader\LoaderInterface', $this->loader);
}
public function testLoadClassMetadataReturnsTrueIfSuccessful()
{
$this->assertTrue($this->loader->loadClassMetadata($this->metadata));
}
public function testLoadClassMetadata()
{
$this->loader->loadClassMetadata($this->metadata);
$this->assertEquals(TestClassMetadataFactory::createXmlCLassMetadata(), $this->metadata);
}
public function testMaxDepth()
{
$classMetadata = new ClassMetadata('Symfony\Component\Serializer\Tests\Fixtures\MaxDepthDummy');
$this->loader->loadClassMetadata($classMetadata);
$attributesMetadata = $classMetadata->getAttributesMetadata();
$this->assertEquals(2, $attributesMetadata['foo']->getMaxDepth());
$this->assertEquals(3, $attributesMetadata['bar']->getMaxDepth());
}
}

View File

@@ -0,0 +1,78 @@
<?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\Serializer\Tests\Mapping\Loader;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Serializer\Mapping\ClassMetadata;
use Symfony\Component\Serializer\Mapping\Loader\YamlFileLoader;
use Symfony\Component\Serializer\Tests\Mapping\TestClassMetadataFactory;
/**
* @author Kévin Dunglas <dunglas@gmail.com>
*/
class YamlFileLoaderTest extends TestCase
{
/**
* @var YamlFileLoader
*/
private $loader;
/**
* @var ClassMetadata
*/
private $metadata;
protected function setUp()
{
$this->loader = new YamlFileLoader(__DIR__.'/../../Fixtures/serialization.yml');
$this->metadata = new ClassMetadata('Symfony\Component\Serializer\Tests\Fixtures\GroupDummy');
}
public function testInterface()
{
$this->assertInstanceOf('Symfony\Component\Serializer\Mapping\Loader\LoaderInterface', $this->loader);
}
public function testLoadClassMetadataReturnsTrueIfSuccessful()
{
$this->assertTrue($this->loader->loadClassMetadata($this->metadata));
}
public function testLoadClassMetadataReturnsFalseWhenEmpty()
{
$loader = new YamlFileLoader(__DIR__.'/../../Fixtures/empty-mapping.yml');
$this->assertFalse($loader->loadClassMetadata($this->metadata));
}
public function testLoadClassMetadataReturnsThrowsInvalidMapping()
{
$this->expectException('Symfony\Component\Serializer\Exception\MappingException');
$loader = new YamlFileLoader(__DIR__.'/../../Fixtures/invalid-mapping.yml');
$loader->loadClassMetadata($this->metadata);
}
public function testLoadClassMetadata()
{
$this->loader->loadClassMetadata($this->metadata);
$this->assertEquals(TestClassMetadataFactory::createXmlCLassMetadata(), $this->metadata);
}
public function testMaxDepth()
{
$classMetadata = new ClassMetadata('Symfony\Component\Serializer\Tests\Fixtures\MaxDepthDummy');
$this->loader->loadClassMetadata($classMetadata);
$attributesMetadata = $classMetadata->getAttributesMetadata();
$this->assertEquals(2, $attributesMetadata['foo']->getMaxDepth());
$this->assertEquals(3, $attributesMetadata['bar']->getMaxDepth());
}
}

View File

@@ -0,0 +1,82 @@
<?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\Serializer\Tests\Mapping;
use Symfony\Component\Serializer\Mapping\AttributeMetadata;
use Symfony\Component\Serializer\Mapping\ClassMetadata;
/**
* @author Kévin Dunglas <dunglas@gmail.com>
*/
class TestClassMetadataFactory
{
public static function createClassMetadata($withParent = false, $withInterface = false)
{
$expected = new ClassMetadata('Symfony\Component\Serializer\Tests\Fixtures\GroupDummy');
$foo = new AttributeMetadata('foo');
$foo->addGroup('a');
$expected->addAttributeMetadata($foo);
$bar = new AttributeMetadata('bar');
$bar->addGroup('b');
$bar->addGroup('c');
$bar->addGroup('name_converter');
$expected->addAttributeMetadata($bar);
$fooBar = new AttributeMetadata('fooBar');
$fooBar->addGroup('a');
$fooBar->addGroup('b');
$fooBar->addGroup('name_converter');
$expected->addAttributeMetadata($fooBar);
$symfony = new AttributeMetadata('symfony');
$expected->addAttributeMetadata($symfony);
if ($withParent) {
$kevin = new AttributeMetadata('kevin');
$kevin->addGroup('a');
$expected->addAttributeMetadata($kevin);
$coopTilleuls = new AttributeMetadata('coopTilleuls');
$coopTilleuls->addGroup('a');
$coopTilleuls->addGroup('b');
$expected->addAttributeMetadata($coopTilleuls);
}
if ($withInterface) {
$symfony->addGroup('a');
$symfony->addGroup('name_converter');
}
// load reflection class so that the comparison passes
$expected->getReflectionClass();
return $expected;
}
public static function createXmlCLassMetadata()
{
$expected = new ClassMetadata('Symfony\Component\Serializer\Tests\Fixtures\GroupDummy');
$foo = new AttributeMetadata('foo');
$foo->addGroup('group1');
$foo->addGroup('group2');
$expected->addAttributeMetadata($foo);
$bar = new AttributeMetadata('bar');
$bar->addGroup('group2');
$expected->addAttributeMetadata($bar);
return $expected;
}
}

View File

@@ -0,0 +1,57 @@
<?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\Serializer\Tests\NameConverter;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Serializer\NameConverter\CamelCaseToSnakeCaseNameConverter;
/**
* @author Kévin Dunglas <dunglas@gmail.com>
*/
class CamelCaseToSnakeCaseNameConverterTest extends TestCase
{
public function testInterface()
{
$attributeMetadata = new CamelCaseToSnakeCaseNameConverter();
$this->assertInstanceOf('Symfony\Component\Serializer\NameConverter\NameConverterInterface', $attributeMetadata);
}
/**
* @dataProvider attributeProvider
*/
public function testNormalize($underscored, $camelCased, $useLowerCamelCase)
{
$nameConverter = new CamelCaseToSnakeCaseNameConverter(null, $useLowerCamelCase);
$this->assertEquals($nameConverter->normalize($camelCased), $underscored);
}
/**
* @dataProvider attributeProvider
*/
public function testDenormalize($underscored, $camelCased, $useLowerCamelCase)
{
$nameConverter = new CamelCaseToSnakeCaseNameConverter(null, $useLowerCamelCase);
$this->assertEquals($nameConverter->denormalize($underscored), $camelCased);
}
public function attributeProvider()
{
return [
['coop_tilleuls', 'coopTilleuls', true],
['_kevin_dunglas', '_kevinDunglas', true],
['this_is_a_test', 'thisIsATest', true],
['coop_tilleuls', 'CoopTilleuls', false],
['_kevin_dunglas', '_kevinDunglas', false],
['this_is_a_test', 'ThisIsATest', false],
];
}
}

View File

@@ -0,0 +1,185 @@
<?php
namespace Symfony\Component\Serializer\Tests\Normalizer;
use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;
use Symfony\Component\PropertyInfo\Extractor\PhpDocExtractor;
use Symfony\Component\Serializer\Encoder\JsonEncoder;
use Symfony\Component\Serializer\Mapping\AttributeMetadata;
use Symfony\Component\Serializer\Mapping\ClassMetadata;
use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactoryInterface;
use Symfony\Component\Serializer\Normalizer\AbstractNormalizer;
use Symfony\Component\Serializer\Normalizer\ObjectNormalizer;
use Symfony\Component\Serializer\Normalizer\PropertyNormalizer;
use Symfony\Component\Serializer\Serializer;
use Symfony\Component\Serializer\Tests\Fixtures\AbstractNormalizerDummy;
use Symfony\Component\Serializer\Tests\Fixtures\Dummy;
use Symfony\Component\Serializer\Tests\Fixtures\NullableConstructorArgumentDummy;
use Symfony\Component\Serializer\Tests\Fixtures\ProxyDummy;
use Symfony\Component\Serializer\Tests\Fixtures\StaticConstructorDummy;
use Symfony\Component\Serializer\Tests\Fixtures\StaticConstructorNormalizer;
use Symfony\Component\Serializer\Tests\Fixtures\VariadicConstructorTypedArgsDummy;
/**
* Provides a dummy Normalizer which extends the AbstractNormalizer.
*
* @author Konstantin S. M. Möllers <ksm.moellers@gmail.com>
*/
class AbstractNormalizerTest extends TestCase
{
/**
* @var AbstractNormalizerDummy
*/
private $normalizer;
/**
* @var ClassMetadataFactoryInterface|MockObject
*/
private $classMetadata;
protected function setUp()
{
$loader = $this->getMockBuilder('Symfony\Component\Serializer\Mapping\Loader\LoaderChain')->setConstructorArgs([[]])->getMock();
$this->classMetadata = $this->getMockBuilder('Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactory')->setConstructorArgs([$loader])->getMock();
$this->normalizer = new AbstractNormalizerDummy($this->classMetadata);
}
public function testGetAllowedAttributesAsString()
{
$classMetadata = new ClassMetadata('c');
$a1 = new AttributeMetadata('a1');
$classMetadata->addAttributeMetadata($a1);
$a2 = new AttributeMetadata('a2');
$a2->addGroup('test');
$classMetadata->addAttributeMetadata($a2);
$a3 = new AttributeMetadata('a3');
$a3->addGroup('other');
$classMetadata->addAttributeMetadata($a3);
$a4 = new AttributeMetadata('a4');
$a4->addGroup('test');
$a4->addGroup('other');
$classMetadata->addAttributeMetadata($a4);
$this->classMetadata->method('getMetadataFor')->willReturn($classMetadata);
$result = $this->normalizer->getAllowedAttributes('c', [AbstractNormalizer::GROUPS => ['test']], true);
$this->assertEquals(['a2', 'a4'], $result);
$result = $this->normalizer->getAllowedAttributes('c', [AbstractNormalizer::GROUPS => ['other']], true);
$this->assertEquals(['a3', 'a4'], $result);
}
public function testGetAllowedAttributesAsObjects()
{
$classMetadata = new ClassMetadata('c');
$a1 = new AttributeMetadata('a1');
$classMetadata->addAttributeMetadata($a1);
$a2 = new AttributeMetadata('a2');
$a2->addGroup('test');
$classMetadata->addAttributeMetadata($a2);
$a3 = new AttributeMetadata('a3');
$a3->addGroup('other');
$classMetadata->addAttributeMetadata($a3);
$a4 = new AttributeMetadata('a4');
$a4->addGroup('test');
$a4->addGroup('other');
$classMetadata->addAttributeMetadata($a4);
$this->classMetadata->method('getMetadataFor')->willReturn($classMetadata);
$result = $this->normalizer->getAllowedAttributes('c', [AbstractNormalizer::GROUPS => ['test']], false);
$this->assertEquals([$a2, $a4], $result);
$result = $this->normalizer->getAllowedAttributes('c', [AbstractNormalizer::GROUPS => ['other']], false);
$this->assertEquals([$a3, $a4], $result);
}
public function testObjectToPopulateWithProxy()
{
$proxyDummy = new ProxyDummy();
$context = [AbstractNormalizer::OBJECT_TO_POPULATE => $proxyDummy];
$normalizer = new ObjectNormalizer();
$normalizer->denormalize(['foo' => 'bar'], 'Symfony\Component\Serializer\Tests\Fixtures\ToBeProxyfiedDummy', null, $context);
$this->assertSame('bar', $proxyDummy->getFoo());
}
public function testObjectWithStaticConstructor()
{
$normalizer = new StaticConstructorNormalizer();
$dummy = $normalizer->denormalize(['foo' => 'baz'], StaticConstructorDummy::class);
$this->assertInstanceOf(StaticConstructorDummy::class, $dummy);
$this->assertEquals('baz', $dummy->quz);
$this->assertNull($dummy->foo);
}
/**
* @requires PHP 7.1
*/
public function testObjectWithNullableConstructorArgument()
{
$normalizer = new ObjectNormalizer();
$dummy = $normalizer->denormalize(['foo' => null], NullableConstructorArgumentDummy::class);
$this->assertNull($dummy->getFoo());
}
/**
* @dataProvider getNormalizer
*
* @requires PHP 5.6
*/
public function testObjectWithVariadicConstructorTypedArguments(AbstractNormalizer $normalizer)
{
$d1 = new Dummy();
$d1->foo = 'Foo';
$d1->bar = 'Bar';
$d1->baz = 'Baz';
$d1->qux = 'Quz';
$d2 = new Dummy();
$d2->foo = 'FOO';
$d2->bar = 'BAR';
$d2->baz = 'BAZ';
$d2->qux = 'QUZ';
$obj = new VariadicConstructorTypedArgsDummy($d1, $d2);
$serializer = new Serializer([$normalizer], [new JsonEncoder()]);
$normalizer->setSerializer($serializer);
$data = $serializer->serialize($obj, 'json');
$dummy = $normalizer->denormalize(json_decode($data, true), VariadicConstructorTypedArgsDummy::class);
$this->assertInstanceOf(VariadicConstructorTypedArgsDummy::class, $dummy);
$this->assertCount(2, $dummy->getFoo());
foreach ($dummy->getFoo() as $foo) {
$this->assertInstanceOf(Dummy::class, $foo);
}
$dummy = $serializer->deserialize($data, VariadicConstructorTypedArgsDummy::class, 'json');
$this->assertInstanceOf(VariadicConstructorTypedArgsDummy::class, $dummy);
$this->assertCount(2, $dummy->getFoo());
foreach ($dummy->getFoo() as $foo) {
$this->assertInstanceOf(Dummy::class, $foo);
}
}
public function getNormalizer()
{
$extractor = new PhpDocExtractor();
yield [new PropertyNormalizer()];
yield [new PropertyNormalizer(null, null, $extractor)];
yield [new ObjectNormalizer()];
yield [new ObjectNormalizer(null, null, null, $extractor)];
}
}

View File

@@ -0,0 +1,401 @@
<?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\Serializer\Tests\Normalizer;
use Doctrine\Common\Annotations\AnnotationReader;
use PHPUnit\Framework\TestCase;
use Symfony\Component\PropertyInfo\Extractor\PhpDocExtractor;
use Symfony\Component\PropertyInfo\Type;
use Symfony\Component\Serializer\Exception\NotNormalizableValueException;
use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactory;
use Symfony\Component\Serializer\Mapping\Loader\AnnotationLoader;
use Symfony\Component\Serializer\Normalizer\AbstractObjectNormalizer;
use Symfony\Component\Serializer\Normalizer\DenormalizerInterface;
use Symfony\Component\Serializer\Normalizer\ObjectNormalizer;
use Symfony\Component\Serializer\SerializerAwareInterface;
use Symfony\Component\Serializer\SerializerInterface;
class AbstractObjectNormalizerTest extends TestCase
{
public function testDenormalize()
{
$normalizer = new AbstractObjectNormalizerDummy();
$normalizedData = $normalizer->denormalize(['foo' => 'foo', 'bar' => 'bar', 'baz' => 'baz'], Dummy::class);
$this->assertSame('foo', $normalizedData->foo);
$this->assertNull($normalizedData->bar);
$this->assertSame('baz', $normalizedData->baz);
}
public function testInstantiateObjectDenormalizer()
{
$data = ['foo' => 'foo', 'bar' => 'bar', 'baz' => 'baz'];
$class = Dummy::class;
$context = [];
$normalizer = new AbstractObjectNormalizerDummy();
$this->assertInstanceOf(Dummy::class, $normalizer->instantiateObject($data, $class, $context, new \ReflectionClass($class), []));
}
public function testDenormalizeWithExtraAttributes()
{
$this->expectException('Symfony\Component\Serializer\Exception\ExtraAttributesException');
$this->expectExceptionMessage('Extra attributes are not allowed ("fooFoo", "fooBar" are unknown).');
$factory = new ClassMetadataFactory(new AnnotationLoader(new AnnotationReader()));
$normalizer = new AbstractObjectNormalizerDummy($factory);
$normalizer->denormalize(
['fooFoo' => 'foo', 'fooBar' => 'bar'],
Dummy::class,
'any',
['allow_extra_attributes' => false]
);
}
public function testDenormalizeWithExtraAttributesAndNoGroupsWithMetadataFactory()
{
$this->expectException('Symfony\Component\Serializer\Exception\ExtraAttributesException');
$this->expectExceptionMessage('Extra attributes are not allowed ("fooFoo", "fooBar" are unknown).');
$normalizer = new AbstractObjectNormalizerWithMetadata();
$normalizer->denormalize(
['fooFoo' => 'foo', 'fooBar' => 'bar', 'bar' => 'bar'],
Dummy::class,
'any',
['allow_extra_attributes' => false]
);
}
public function testDenormalizeCollectionDecodedFromXmlWithOneChild()
{
$denormalizer = $this->getDenormalizerForDummyCollection();
$dummyCollection = $denormalizer->denormalize(
[
'children' => [
'bar' => 'first',
],
],
DummyCollection::class,
'xml'
);
$this->assertInstanceOf(DummyCollection::class, $dummyCollection);
$this->assertIsArray($dummyCollection->children);
$this->assertCount(1, $dummyCollection->children);
$this->assertInstanceOf(DummyChild::class, $dummyCollection->children[0]);
}
public function testDenormalizeCollectionDecodedFromXmlWithTwoChildren()
{
$denormalizer = $this->getDenormalizerForDummyCollection();
$dummyCollection = $denormalizer->denormalize(
[
'children' => [
['bar' => 'first'],
['bar' => 'second'],
],
],
DummyCollection::class,
'xml'
);
$this->assertInstanceOf(DummyCollection::class, $dummyCollection);
$this->assertIsArray($dummyCollection->children);
$this->assertCount(2, $dummyCollection->children);
$this->assertInstanceOf(DummyChild::class, $dummyCollection->children[0]);
$this->assertInstanceOf(DummyChild::class, $dummyCollection->children[1]);
}
private function getDenormalizerForDummyCollection()
{
$extractor = $this->getMockBuilder(PhpDocExtractor::class)->getMock();
$extractor->method('getTypes')
->will($this->onConsecutiveCalls(
[new Type('array', false, null, true, new Type('int'), new Type('object', false, DummyChild::class))],
null
));
$denormalizer = new AbstractObjectNormalizerCollectionDummy(null, null, $extractor);
$arrayDenormalizer = new ArrayDenormalizerDummy();
$serializer = new SerializerCollectionDummy([$arrayDenormalizer, $denormalizer]);
$arrayDenormalizer->setSerializer($serializer);
$denormalizer->setSerializer($serializer);
return $denormalizer;
}
public function testDenormalizeStringCollectionDecodedFromXmlWithOneChild()
{
$denormalizer = $this->getDenormalizerForStringCollection();
// if an xml-node can have children which should be deserialized as string[]
// and only one child exists
$stringCollection = $denormalizer->denormalize(['children' => 'foo'], StringCollection::class, 'xml');
$this->assertInstanceOf(StringCollection::class, $stringCollection);
$this->assertIsArray($stringCollection->children);
$this->assertCount(1, $stringCollection->children);
$this->assertEquals('foo', $stringCollection->children[0]);
}
public function testDenormalizeStringCollectionDecodedFromXmlWithTwoChildren()
{
$denormalizer = $this->getDenormalizerForStringCollection();
// if an xml-node can have children which should be deserialized as string[]
// and only one child exists
$stringCollection = $denormalizer->denormalize(['children' => ['foo', 'bar']], StringCollection::class, 'xml');
$this->assertInstanceOf(StringCollection::class, $stringCollection);
$this->assertIsArray($stringCollection->children);
$this->assertCount(2, $stringCollection->children);
$this->assertEquals('foo', $stringCollection->children[0]);
$this->assertEquals('bar', $stringCollection->children[1]);
}
public function testDenormalizeNotSerializableObjectToPopulate()
{
$normalizer = new AbstractObjectNormalizerDummy();
$normalizedData = $normalizer->denormalize(['foo' => 'foo'], Dummy::class, null, [AbstractObjectNormalizer::OBJECT_TO_POPULATE => new NotSerializable()]);
$this->assertSame('foo', $normalizedData->foo);
}
private function getDenormalizerForStringCollection()
{
$extractor = $this->getMockBuilder(PhpDocExtractor::class)->getMock();
$extractor->method('getTypes')
->will($this->onConsecutiveCalls(
[new Type('array', false, null, true, new Type('int'), new Type('string'))],
null
));
$denormalizer = new AbstractObjectNormalizerCollectionDummy(null, null, $extractor);
$arrayDenormalizer = new ArrayDenormalizerDummy();
$serializer = new SerializerCollectionDummy([$arrayDenormalizer, $denormalizer]);
$arrayDenormalizer->setSerializer($serializer);
$denormalizer->setSerializer($serializer);
return $denormalizer;
}
/**
* Test that additional attributes throw an exception if no metadata factory is specified.
*/
public function testExtraAttributesException()
{
$this->expectException('Symfony\Component\Serializer\Exception\LogicException');
$this->expectExceptionMessage('A class metadata factory must be provided in the constructor when setting "allow_extra_attributes" to false.');
$normalizer = new ObjectNormalizer();
$normalizer->denormalize([], \stdClass::class, 'xml', [
'allow_extra_attributes' => false,
]);
}
}
class AbstractObjectNormalizerDummy extends AbstractObjectNormalizer
{
protected function extractAttributes($object, $format = null, array $context = [])
{
}
protected function getAttributeValue($object, $attribute, $format = null, array $context = [])
{
}
protected function setAttributeValue($object, $attribute, $value, $format = null, array $context = [])
{
$object->$attribute = $value;
}
protected function isAllowedAttribute($classOrObject, $attribute, $format = null, array $context = [])
{
return \in_array($attribute, ['foo', 'baz']);
}
public function instantiateObject(array &$data, $class, array &$context, \ReflectionClass $reflectionClass, $allowedAttributes, $format = null)
{
return parent::instantiateObject($data, $class, $context, $reflectionClass, $allowedAttributes, $format);
}
}
class Dummy
{
public $foo;
public $bar;
public $baz;
}
class AbstractObjectNormalizerWithMetadata extends AbstractObjectNormalizer
{
public function __construct()
{
parent::__construct(new ClassMetadataFactory(new AnnotationLoader(new AnnotationReader())));
}
protected function extractAttributes($object, $format = null, array $context = [])
{
}
protected function getAttributeValue($object, $attribute, $format = null, array $context = [])
{
}
protected function setAttributeValue($object, $attribute, $value, $format = null, array $context = [])
{
$object->$attribute = $value;
}
}
class StringCollection
{
/** @var string[] */
public $children;
}
class DummyCollection
{
/** @var DummyChild[] */
public $children;
}
class DummyChild
{
public $bar;
}
class SerializerCollectionDummy implements SerializerInterface, DenormalizerInterface
{
private $normalizers;
/**
* @param DenormalizerInterface[] $normalizers
*/
public function __construct($normalizers)
{
$this->normalizers = $normalizers;
}
public function serialize($data, $format, array $context = [])
{
}
public function deserialize($data, $type, $format, array $context = [])
{
}
public function denormalize($data, $type, $format = null, array $context = [])
{
foreach ($this->normalizers as $normalizer) {
if ($normalizer instanceof DenormalizerInterface && $normalizer->supportsDenormalization($data, $type, $format, $context)) {
return $normalizer->denormalize($data, $type, $format, $context);
}
}
return null;
}
public function supportsDenormalization($data, $type, $format = null)
{
return true;
}
}
class AbstractObjectNormalizerCollectionDummy extends AbstractObjectNormalizer
{
protected function extractAttributes($object, $format = null, array $context = [])
{
}
protected function getAttributeValue($object, $attribute, $format = null, array $context = [])
{
}
protected function setAttributeValue($object, $attribute, $value, $format = null, array $context = [])
{
$object->$attribute = $value;
}
protected function isAllowedAttribute($classOrObject, $attribute, $format = null, array $context = [])
{
return true;
}
public function instantiateObject(array &$data, $class, array &$context, \ReflectionClass $reflectionClass, $allowedAttributes, $format = null)
{
return parent::instantiateObject($data, $class, $context, $reflectionClass, $allowedAttributes, $format);
}
public function serialize($data, $format, array $context = [])
{
}
public function deserialize($data, $type, $format, array $context = [])
{
}
}
class ArrayDenormalizerDummy implements DenormalizerInterface, SerializerAwareInterface
{
/**
* @var SerializerInterface|DenormalizerInterface
*/
private $serializer;
/**
* {@inheritdoc}
*
* @throws NotNormalizableValueException
*/
public function denormalize($data, $type, $format = null, array $context = [])
{
$serializer = $this->serializer;
$type = substr($type, 0, -2);
foreach ($data as $key => $value) {
$data[$key] = $serializer->denormalize($value, $type, $format, $context);
}
return $data;
}
/**
* {@inheritdoc}
*/
public function supportsDenormalization($data, $type, $format = null, array $context = [])
{
return '[]' === substr($type, -2)
&& $this->serializer->supportsDenormalization($data, substr($type, 0, -2), $format, $context);
}
/**
* {@inheritdoc}
*/
public function setSerializer(SerializerInterface $serializer)
{
$this->serializer = $serializer;
}
}
class NotSerializable
{
public function __sleep()
{
if (class_exists(\Error::class)) {
throw new \Error('not serializable');
}
throw new \Exception('not serializable');
}
}

View File

@@ -0,0 +1,124 @@
<?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\Serializer\Tests\Normalizer;
use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Serializer\Normalizer\ArrayDenormalizer;
use Symfony\Component\Serializer\SerializerInterface;
class ArrayDenormalizerTest extends TestCase
{
/**
* @var ArrayDenormalizer
*/
private $denormalizer;
/**
* @var SerializerInterface|MockObject
*/
private $serializer;
protected function setUp()
{
$this->serializer = $this->getMockBuilder('Symfony\Component\Serializer\Serializer')->getMock();
$this->denormalizer = new ArrayDenormalizer();
$this->denormalizer->setSerializer($this->serializer);
}
public function testDenormalize()
{
$this->serializer->expects($this->exactly(2))
->method('denormalize')
->withConsecutive(
[['foo' => 'one', 'bar' => 'two']],
[['foo' => 'three', 'bar' => 'four']]
)
->willReturnOnConsecutiveCalls(
new ArrayDummy('one', 'two'),
new ArrayDummy('three', 'four')
);
$result = $this->denormalizer->denormalize(
[
['foo' => 'one', 'bar' => 'two'],
['foo' => 'three', 'bar' => 'four'],
],
__NAMESPACE__.'\ArrayDummy[]'
);
$this->assertEquals(
[
new ArrayDummy('one', 'two'),
new ArrayDummy('three', 'four'),
],
$result
);
}
public function testSupportsValidArray()
{
$this->serializer->expects($this->once())
->method('supportsDenormalization')
->with($this->anything(), ArrayDummy::class, $this->anything())
->willReturn(true);
$this->assertTrue(
$this->denormalizer->supportsDenormalization(
[
['foo' => 'one', 'bar' => 'two'],
['foo' => 'three', 'bar' => 'four'],
],
__NAMESPACE__.'\ArrayDummy[]'
)
);
}
public function testSupportsInvalidArray()
{
$this->serializer->expects($this->any())
->method('supportsDenormalization')
->willReturn(false);
$this->assertFalse(
$this->denormalizer->supportsDenormalization(
[
['foo' => 'one', 'bar' => 'two'],
['foo' => 'three', 'bar' => 'four'],
],
__NAMESPACE__.'\InvalidClass[]'
)
);
}
public function testSupportsNoArray()
{
$this->assertFalse(
$this->denormalizer->supportsDenormalization(
['foo' => 'one', 'bar' => 'two'],
ArrayDummy::class
)
);
}
}
class ArrayDummy
{
public $foo;
public $bar;
public function __construct($foo, $bar)
{
$this->foo = $foo;
$this->bar = $bar;
}
}

View File

@@ -0,0 +1,83 @@
<?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\Serializer\Tests\Normalizer;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Serializer\Normalizer\CustomNormalizer;
use Symfony\Component\Serializer\Serializer;
use Symfony\Component\Serializer\Tests\Fixtures\ScalarDummy;
class CustomNormalizerTest extends TestCase
{
/**
* @var CustomNormalizer
*/
private $normalizer;
protected function setUp()
{
$this->normalizer = new CustomNormalizer();
$this->normalizer->setSerializer(new Serializer());
}
public function testInterface()
{
$this->assertInstanceOf('Symfony\Component\Serializer\Normalizer\NormalizerInterface', $this->normalizer);
$this->assertInstanceOf('Symfony\Component\Serializer\Normalizer\DenormalizerInterface', $this->normalizer);
$this->assertInstanceOf('Symfony\Component\Serializer\SerializerAwareInterface', $this->normalizer);
}
public function testSerialize()
{
$obj = new ScalarDummy();
$obj->foo = 'foo';
$obj->xmlFoo = 'xml';
$this->assertEquals('foo', $this->normalizer->normalize($obj, 'json'));
$this->assertEquals('xml', $this->normalizer->normalize($obj, 'xml'));
}
public function testDeserialize()
{
$obj = $this->normalizer->denormalize('foo', \get_class(new ScalarDummy()), 'xml');
$this->assertEquals('foo', $obj->xmlFoo);
$this->assertNull($obj->foo);
$obj = $this->normalizer->denormalize('foo', \get_class(new ScalarDummy()), 'json');
$this->assertEquals('foo', $obj->foo);
$this->assertNull($obj->xmlFoo);
}
public function testDenormalizeWithObjectToPopulateUsesProvidedObject()
{
$expected = new ScalarDummy();
$obj = $this->normalizer->denormalize('foo', ScalarDummy::class, 'json', [
'object_to_populate' => $expected,
]);
$this->assertSame($expected, $obj);
$this->assertEquals('foo', $obj->foo);
$this->assertNull($obj->xmlFoo);
}
public function testSupportsNormalization()
{
$this->assertTrue($this->normalizer->supportsNormalization(new ScalarDummy()));
$this->assertFalse($this->normalizer->supportsNormalization(new \stdClass()));
}
public function testSupportsDenormalization()
{
$this->assertTrue($this->normalizer->supportsDenormalization([], 'Symfony\Component\Serializer\Tests\Fixtures\ScalarDummy'));
$this->assertFalse($this->normalizer->supportsDenormalization([], 'stdClass'));
$this->assertTrue($this->normalizer->supportsDenormalization([], 'Symfony\Component\Serializer\Tests\Fixtures\DenormalizableDummy'));
}
}

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,148 @@
<?php
namespace Symfony\Component\Serializer\Tests\Normalizer;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Serializer\Normalizer\DateIntervalNormalizer;
/**
* @author Jérôme Parmentier <jerome@prmntr.me>
*/
class DateIntervalNormalizerTest extends TestCase
{
/**
* @var DateIntervalNormalizer
*/
private $normalizer;
protected function setUp()
{
$this->normalizer = new DateIntervalNormalizer();
}
public function dataProviderISO()
{
$data = [
['P%YY%MM%DDT%HH%IM%SS', 'P00Y00M00DT00H00M00S', 'PT0S'],
['P%yY%mM%dDT%hH%iM%sS', 'P0Y0M0DT0H0M0S', 'PT0S'],
['P%yY%mM%dDT%hH%iM%sS', 'P10Y2M3DT16H5M6S', 'P10Y2M3DT16H5M6S'],
['P%yY%mM%dDT%hH%iM', 'P10Y2M3DT16H5M', 'P10Y2M3DT16H5M'],
['P%yY%mM%dDT%hH', 'P10Y2M3DT16H', 'P10Y2M3DT16H'],
['P%yY%mM%dD', 'P10Y2M3D', 'P10Y2M3DT0H'],
['%RP%yY%mM%dD', '-P10Y2M3D', '-P10Y2M3DT0H'],
['%RP%yY%mM%dD', '+P10Y2M3D', '+P10Y2M3DT0H'],
['%RP%yY%mM%dD', '+P10Y2M3D', 'P10Y2M3DT0H'],
['%rP%yY%mM%dD', '-P10Y2M3D', '-P10Y2M3DT0H'],
['%rP%yY%mM%dD', 'P10Y2M3D', 'P10Y2M3DT0H'],
];
return $data;
}
public function testSupportsNormalization()
{
$this->assertTrue($this->normalizer->supportsNormalization(new \DateInterval('P00Y00M00DT00H00M00S')));
$this->assertFalse($this->normalizer->supportsNormalization(new \stdClass()));
}
public function testNormalize()
{
$this->assertEquals('P0Y0M0DT0H0M0S', $this->normalizer->normalize(new \DateInterval('PT0S')));
}
/**
* @dataProvider dataProviderISO
*/
public function testNormalizeUsingFormatPassedInContext($format, $output, $input)
{
$this->assertEquals($output, $this->normalizer->normalize($this->getInterval($input), null, [DateIntervalNormalizer::FORMAT_KEY => $format]));
}
/**
* @dataProvider dataProviderISO
*/
public function testNormalizeUsingFormatPassedInConstructor($format, $output, $input)
{
$this->assertEquals($output, (new DateIntervalNormalizer($format))->normalize($this->getInterval($input)));
}
public function testNormalizeInvalidObjectThrowsException()
{
$this->expectException('Symfony\Component\Serializer\Exception\InvalidArgumentException');
$this->expectExceptionMessage('The object must be an instance of "\DateInterval".');
$this->normalizer->normalize(new \stdClass());
}
public function testSupportsDenormalization()
{
$this->assertTrue($this->normalizer->supportsDenormalization('P00Y00M00DT00H00M00S', \DateInterval::class));
$this->assertFalse($this->normalizer->supportsDenormalization('foo', 'Bar'));
}
public function testDenormalize()
{
$this->assertDateIntervalEquals(new \DateInterval('P00Y00M00DT00H00M00S'), $this->normalizer->denormalize('P00Y00M00DT00H00M00S', \DateInterval::class));
}
/**
* @dataProvider dataProviderISO
*/
public function testDenormalizeUsingFormatPassedInContext($format, $input, $output)
{
$this->assertDateIntervalEquals($this->getInterval($output), $this->normalizer->denormalize($input, \DateInterval::class, null, [DateIntervalNormalizer::FORMAT_KEY => $format]));
}
/**
* @dataProvider dataProviderISO
*/
public function testDenormalizeUsingFormatPassedInConstructor($format, $input, $output)
{
$this->assertDateIntervalEquals($this->getInterval($output), (new DateIntervalNormalizer($format))->denormalize($input, \DateInterval::class));
}
public function testDenormalizeExpectsString()
{
$this->expectException('Symfony\Component\Serializer\Exception\InvalidArgumentException');
$this->normalizer->denormalize(1234, \DateInterval::class);
}
public function testDenormalizeNonISO8601IntervalStringThrowsException()
{
$this->expectException('Symfony\Component\Serializer\Exception\UnexpectedValueException');
$this->expectExceptionMessage('Expected a valid ISO 8601 interval string.');
$this->normalizer->denormalize('10 years 2 months 3 days', \DateInterval::class, null);
}
public function testDenormalizeInvalidDataThrowsException()
{
$this->expectException('Symfony\Component\Serializer\Exception\UnexpectedValueException');
$this->normalizer->denormalize('invalid interval', \DateInterval::class);
}
public function testDenormalizeFormatMismatchThrowsException()
{
$this->expectException('Symfony\Component\Serializer\Exception\UnexpectedValueException');
$this->normalizer->denormalize('P00Y00M00DT00H00M00S', \DateInterval::class, null, [DateIntervalNormalizer::FORMAT_KEY => 'P%yY%mM%dD']);
}
private function assertDateIntervalEquals(\DateInterval $expected, \DateInterval $actual)
{
$this->assertEquals($expected->format('%RP%yY%mM%dDT%hH%iM%sS'), $actual->format('%RP%yY%mM%dDT%hH%iM%sS'));
}
private function getInterval($data)
{
if ('-' === $data[0]) {
$interval = new \DateInterval(substr($data, 1));
$interval->invert = 1;
return $interval;
}
if ('+' === $data[0]) {
return new \DateInterval(substr($data, 1));
}
return new \DateInterval($data);
}
}

View File

@@ -0,0 +1,261 @@
<?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\Serializer\Tests\Normalizer;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Serializer\Normalizer\DateTimeNormalizer;
/**
* @author Kévin Dunglas <dunglas@gmail.com>
*/
class DateTimeNormalizerTest extends TestCase
{
/**
* @var DateTimeNormalizer
*/
private $normalizer;
protected function setUp()
{
$this->normalizer = new DateTimeNormalizer();
}
public function testSupportsNormalization()
{
$this->assertTrue($this->normalizer->supportsNormalization(new \DateTime()));
$this->assertTrue($this->normalizer->supportsNormalization(new \DateTimeImmutable()));
$this->assertFalse($this->normalizer->supportsNormalization(new \stdClass()));
}
public function testNormalize()
{
$this->assertEquals('2016-01-01T00:00:00+00:00', $this->normalizer->normalize(new \DateTime('2016/01/01', new \DateTimeZone('UTC'))));
$this->assertEquals('2016-01-01T00:00:00+00:00', $this->normalizer->normalize(new \DateTimeImmutable('2016/01/01', new \DateTimeZone('UTC'))));
}
public function testNormalizeUsingFormatPassedInContext()
{
$this->assertEquals('2016', $this->normalizer->normalize(new \DateTime('2016/01/01'), null, [DateTimeNormalizer::FORMAT_KEY => 'Y']));
}
public function testNormalizeUsingFormatPassedInConstructor()
{
$this->assertEquals('16', (new DateTimeNormalizer('y'))->normalize(new \DateTime('2016/01/01', new \DateTimeZone('UTC'))));
}
public function testNormalizeUsingTimeZonePassedInConstructor()
{
$normalizer = new DateTimeNormalizer(\DateTime::RFC3339, new \DateTimeZone('Japan'));
$this->assertSame('2016-12-01T00:00:00+09:00', $normalizer->normalize(new \DateTime('2016/12/01', new \DateTimeZone('Japan'))));
$this->assertSame('2016-12-01T09:00:00+09:00', $normalizer->normalize(new \DateTime('2016/12/01', new \DateTimeZone('UTC'))));
}
/**
* @dataProvider normalizeUsingTimeZonePassedInContextProvider
*/
public function testNormalizeUsingTimeZonePassedInContext($expected, $input, $timezone)
{
$this->assertSame($expected, $this->normalizer->normalize($input, null, [
DateTimeNormalizer::TIMEZONE_KEY => $timezone,
]));
}
public function normalizeUsingTimeZonePassedInContextProvider()
{
yield ['2016-12-01T00:00:00+00:00', new \DateTime('2016/12/01', new \DateTimeZone('UTC')), null];
yield ['2016-12-01T00:00:00+09:00', new \DateTime('2016/12/01', new \DateTimeZone('Japan')), new \DateTimeZone('Japan')];
yield ['2016-12-01T09:00:00+09:00', new \DateTime('2016/12/01', new \DateTimeZone('UTC')), new \DateTimeZone('Japan')];
yield ['2016-12-01T09:00:00+09:00', new \DateTimeImmutable('2016/12/01', new \DateTimeZone('UTC')), new \DateTimeZone('Japan')];
}
/**
* @dataProvider normalizeUsingTimeZonePassedInContextAndExpectedFormatWithMicrosecondsProvider
*/
public function testNormalizeUsingTimeZonePassedInContextAndFormattedWithMicroseconds($expected, $expectedFormat, $input, $timezone)
{
$this->assertSame(
$expected,
$this->normalizer->normalize(
$input,
null,
[
DateTimeNormalizer::TIMEZONE_KEY => $timezone,
DateTimeNormalizer::FORMAT_KEY => $expectedFormat,
]
)
);
}
public function normalizeUsingTimeZonePassedInContextAndExpectedFormatWithMicrosecondsProvider()
{
yield [
'2018-12-01T18:03:06.067634',
'Y-m-d\TH:i:s.u',
\DateTime::createFromFormat(
'Y-m-d\TH:i:s.u',
'2018-12-01T18:03:06.067634',
new \DateTimeZone('UTC')
),
null,
];
yield [
'2018-12-01T18:03:06.067634',
'Y-m-d\TH:i:s.u',
\DateTime::createFromFormat(
'Y-m-d\TH:i:s.u',
'2018-12-01T18:03:06.067634',
new \DateTimeZone('UTC')
),
new \DateTimeZone('UTC'),
];
yield [
'2018-12-01T19:03:06.067634+01:00',
'Y-m-d\TH:i:s.uP',
\DateTimeImmutable::createFromFormat(
'Y-m-d\TH:i:s.u',
'2018-12-01T18:03:06.067634',
new \DateTimeZone('UTC')
),
new \DateTimeZone('Europe/Rome'),
];
yield [
'2018-12-01T20:03:06.067634+02:00',
'Y-m-d\TH:i:s.uP',
\DateTime::createFromFormat(
'Y-m-d\TH:i:s.u',
'2018-12-01T18:03:06.067634',
new \DateTimeZone('UTC')
),
new \DateTimeZone('Europe/Kiev'),
];
yield [
'2018-12-01T19:03:06.067634',
'Y-m-d\TH:i:s.u',
\DateTime::createFromFormat(
'Y-m-d\TH:i:s.u',
'2018-12-01T18:03:06.067634',
new \DateTimeZone('UTC')
),
new \DateTimeZone('Europe/Berlin'),
];
}
public function testNormalizeInvalidObjectThrowsException()
{
$this->expectException('Symfony\Component\Serializer\Exception\InvalidArgumentException');
$this->expectExceptionMessage('The object must implement the "\DateTimeInterface".');
$this->normalizer->normalize(new \stdClass());
}
public function testSupportsDenormalization()
{
$this->assertTrue($this->normalizer->supportsDenormalization('2016-01-01T00:00:00+00:00', \DateTimeInterface::class));
$this->assertTrue($this->normalizer->supportsDenormalization('2016-01-01T00:00:00+00:00', \DateTime::class));
$this->assertTrue($this->normalizer->supportsDenormalization('2016-01-01T00:00:00+00:00', \DateTimeImmutable::class));
$this->assertFalse($this->normalizer->supportsDenormalization('foo', 'Bar'));
}
public function testDenormalize()
{
$this->assertEquals(new \DateTimeImmutable('2016/01/01', new \DateTimeZone('UTC')), $this->normalizer->denormalize('2016-01-01T00:00:00+00:00', \DateTimeInterface::class));
$this->assertEquals(new \DateTimeImmutable('2016/01/01', new \DateTimeZone('UTC')), $this->normalizer->denormalize('2016-01-01T00:00:00+00:00', \DateTimeImmutable::class));
$this->assertEquals(new \DateTime('2016/01/01', new \DateTimeZone('UTC')), $this->normalizer->denormalize('2016-01-01T00:00:00+00:00', \DateTime::class));
}
public function testDenormalizeUsingTimezonePassedInConstructor()
{
$timezone = new \DateTimeZone('Japan');
$expected = new \DateTime('2016/12/01 17:35:00', $timezone);
$normalizer = new DateTimeNormalizer(null, $timezone);
$this->assertEquals($expected, $normalizer->denormalize('2016.12.01 17:35:00', \DateTime::class, null, [
DateTimeNormalizer::FORMAT_KEY => 'Y.m.d H:i:s',
]));
}
public function testDenormalizeUsingFormatPassedInContext()
{
$this->assertEquals(new \DateTimeImmutable('2016/01/01'), $this->normalizer->denormalize('2016.01.01', \DateTimeInterface::class, null, [DateTimeNormalizer::FORMAT_KEY => 'Y.m.d|']));
$this->assertEquals(new \DateTimeImmutable('2016/01/01'), $this->normalizer->denormalize('2016.01.01', \DateTimeImmutable::class, null, [DateTimeNormalizer::FORMAT_KEY => 'Y.m.d|']));
$this->assertEquals(new \DateTime('2016/01/01'), $this->normalizer->denormalize('2016.01.01', \DateTime::class, null, [DateTimeNormalizer::FORMAT_KEY => 'Y.m.d|']));
}
/**
* @dataProvider denormalizeUsingTimezonePassedInContextProvider
*/
public function testDenormalizeUsingTimezonePassedInContext($input, $expected, $timezone, $format = null)
{
$actual = $this->normalizer->denormalize($input, \DateTimeInterface::class, null, [
DateTimeNormalizer::TIMEZONE_KEY => $timezone,
DateTimeNormalizer::FORMAT_KEY => $format,
]);
$this->assertEquals($expected, $actual);
}
public function denormalizeUsingTimezonePassedInContextProvider()
{
yield 'with timezone' => [
'2016/12/01 17:35:00',
new \DateTimeImmutable('2016/12/01 17:35:00', new \DateTimeZone('Japan')),
new \DateTimeZone('Japan'),
];
yield 'with timezone as string' => [
'2016/12/01 17:35:00',
new \DateTimeImmutable('2016/12/01 17:35:00', new \DateTimeZone('Japan')),
'Japan',
];
yield 'with format without timezone information' => [
'2016.12.01 17:35:00',
new \DateTimeImmutable('2016/12/01 17:35:00', new \DateTimeZone('Japan')),
new \DateTimeZone('Japan'),
'Y.m.d H:i:s',
];
yield 'ignored with format with timezone information' => [
'2016-12-01T17:35:00Z',
new \DateTimeImmutable('2016/12/01 17:35:00', new \DateTimeZone('UTC')),
'Europe/Paris',
\DateTime::RFC3339,
];
}
public function testDenormalizeInvalidDataThrowsException()
{
$this->expectException('Symfony\Component\Serializer\Exception\UnexpectedValueException');
$this->normalizer->denormalize('invalid date', \DateTimeInterface::class);
}
public function testDenormalizeNullThrowsException()
{
$this->expectException('Symfony\Component\Serializer\Exception\UnexpectedValueException');
$this->expectExceptionMessage('The data is either an empty string or null, you should pass a string that can be parsed with the passed format or a valid DateTime string.');
$this->normalizer->denormalize(null, \DateTimeInterface::class);
}
public function testDenormalizeEmptyStringThrowsException()
{
$this->expectException('Symfony\Component\Serializer\Exception\UnexpectedValueException');
$this->expectExceptionMessage('The data is either an empty string or null, you should pass a string that can be parsed with the passed format or a valid DateTime string.');
$this->normalizer->denormalize('', \DateTimeInterface::class);
}
public function testDenormalizeFormatMismatchThrowsException()
{
$this->expectException('Symfony\Component\Serializer\Exception\UnexpectedValueException');
$this->normalizer->denormalize('2016-01-01T00:00:00+00:00', \DateTimeInterface::class, null, [DateTimeNormalizer::FORMAT_KEY => 'Y-m-d|']);
}
}

View File

@@ -0,0 +1,815 @@
<?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\Serializer\Tests\Normalizer;
use Doctrine\Common\Annotations\AnnotationReader;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactory;
use Symfony\Component\Serializer\Mapping\Loader\AnnotationLoader;
use Symfony\Component\Serializer\NameConverter\CamelCaseToSnakeCaseNameConverter;
use Symfony\Component\Serializer\Normalizer\GetSetMethodNormalizer;
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
use Symfony\Component\Serializer\Serializer;
use Symfony\Component\Serializer\SerializerInterface;
use Symfony\Component\Serializer\Tests\Fixtures\CircularReferenceDummy;
use Symfony\Component\Serializer\Tests\Fixtures\GroupDummy;
use Symfony\Component\Serializer\Tests\Fixtures\MaxDepthDummy;
use Symfony\Component\Serializer\Tests\Fixtures\SiblingHolder;
class GetSetMethodNormalizerTest extends TestCase
{
/**
* @var GetSetMethodNormalizer
*/
private $normalizer;
/**
* @var SerializerInterface
*/
private $serializer;
protected function setUp()
{
$this->serializer = $this->getMockBuilder(SerializerNormalizer::class)->getMock();
$this->normalizer = new GetSetMethodNormalizer();
$this->normalizer->setSerializer($this->serializer);
}
public function testInterface()
{
$this->assertInstanceOf('Symfony\Component\Serializer\Normalizer\NormalizerInterface', $this->normalizer);
$this->assertInstanceOf('Symfony\Component\Serializer\Normalizer\DenormalizerInterface', $this->normalizer);
}
public function testNormalize()
{
$obj = new GetSetDummy();
$object = new \stdClass();
$obj->setFoo('foo');
$obj->setBar('bar');
$obj->setBaz(true);
$obj->setCamelCase('camelcase');
$obj->setObject($object);
$this->serializer
->expects($this->once())
->method('normalize')
->with($object, 'any')
->willReturn('string_object')
;
$this->assertEquals(
[
'foo' => 'foo',
'bar' => 'bar',
'baz' => true,
'fooBar' => 'foobar',
'camelCase' => 'camelcase',
'object' => 'string_object',
],
$this->normalizer->normalize($obj, 'any')
);
}
public function testDenormalize()
{
$obj = $this->normalizer->denormalize(
['foo' => 'foo', 'bar' => 'bar', 'baz' => true, 'fooBar' => 'foobar'],
GetSetDummy::class,
'any'
);
$this->assertEquals('foo', $obj->getFoo());
$this->assertEquals('bar', $obj->getBar());
$this->assertTrue($obj->isBaz());
}
public function testIgnoredAttributesInContext()
{
$ignoredAttributes = ['foo', 'bar', 'baz', 'object'];
$this->normalizer->setIgnoredAttributes($ignoredAttributes);
$obj = new GetSetDummy();
$obj->setFoo('foo');
$obj->setBar('bar');
$obj->setCamelCase(true);
$this->assertEquals(
[
'fooBar' => 'foobar',
'camelCase' => true,
],
$this->normalizer->normalize($obj, 'any')
);
}
public function testDenormalizeWithObject()
{
$data = new \stdClass();
$data->foo = 'foo';
$data->bar = 'bar';
$data->fooBar = 'foobar';
$obj = $this->normalizer->denormalize($data, GetSetDummy::class, 'any');
$this->assertEquals('foo', $obj->getFoo());
$this->assertEquals('bar', $obj->getBar());
}
public function testDenormalizeNull()
{
$this->assertEquals(new GetSetDummy(), $this->normalizer->denormalize(null, GetSetDummy::class));
}
public function testConstructorDenormalize()
{
$obj = $this->normalizer->denormalize(
['foo' => 'foo', 'bar' => 'bar', 'baz' => true, 'fooBar' => 'foobar'],
GetConstructorDummy::class, 'any');
$this->assertEquals('foo', $obj->getFoo());
$this->assertEquals('bar', $obj->getBar());
$this->assertTrue($obj->isBaz());
}
public function testConstructorDenormalizeWithNullArgument()
{
$obj = $this->normalizer->denormalize(
['foo' => 'foo', 'bar' => null, 'baz' => true],
GetConstructorDummy::class, 'any');
$this->assertEquals('foo', $obj->getFoo());
$this->assertNull($obj->getBar());
$this->assertTrue($obj->isBaz());
}
public function testConstructorDenormalizeWithMissingOptionalArgument()
{
$obj = $this->normalizer->denormalize(
['foo' => 'test', 'baz' => [1, 2, 3]],
GetConstructorOptionalArgsDummy::class, 'any');
$this->assertEquals('test', $obj->getFoo());
$this->assertEquals([], $obj->getBar());
$this->assertEquals([1, 2, 3], $obj->getBaz());
}
public function testConstructorDenormalizeWithOptionalDefaultArgument()
{
$obj = $this->normalizer->denormalize(
['bar' => 'test'],
GetConstructorArgsWithDefaultValueDummy::class, 'any');
$this->assertEquals([], $obj->getFoo());
$this->assertEquals('test', $obj->getBar());
}
/**
* @requires PHP 5.6
*/
public function testConstructorDenormalizeWithVariadicArgument()
{
$obj = $this->normalizer->denormalize(
['foo' => [1, 2, 3]],
'Symfony\Component\Serializer\Tests\Fixtures\VariadicConstructorArgsDummy', 'any');
$this->assertEquals([1, 2, 3], $obj->getFoo());
}
/**
* @requires PHP 5.6
*/
public function testConstructorDenormalizeWithMissingVariadicArgument()
{
$obj = $this->normalizer->denormalize(
[],
'Symfony\Component\Serializer\Tests\Fixtures\VariadicConstructorArgsDummy', 'any');
$this->assertEquals([], $obj->getFoo());
}
public function testConstructorWithObjectDenormalize()
{
$data = new \stdClass();
$data->foo = 'foo';
$data->bar = 'bar';
$data->baz = true;
$data->fooBar = 'foobar';
$obj = $this->normalizer->denormalize($data, GetConstructorDummy::class, 'any');
$this->assertEquals('foo', $obj->getFoo());
$this->assertEquals('bar', $obj->getBar());
}
public function testConstructorWArgWithPrivateMutator()
{
$obj = $this->normalizer->denormalize(['foo' => 'bar'], ObjectConstructorArgsWithPrivateMutatorDummy::class, 'any');
$this->assertEquals('bar', $obj->getFoo());
}
public function testGroupsNormalize()
{
$classMetadataFactory = new ClassMetadataFactory(new AnnotationLoader(new AnnotationReader()));
$this->normalizer = new GetSetMethodNormalizer($classMetadataFactory);
$this->normalizer->setSerializer($this->serializer);
$obj = new GroupDummy();
$obj->setFoo('foo');
$obj->setBar('bar');
$obj->setFooBar('fooBar');
$obj->setSymfony('symfony');
$obj->setKevin('kevin');
$obj->setCoopTilleuls('coopTilleuls');
$this->assertEquals([
'bar' => 'bar',
], $this->normalizer->normalize($obj, null, [GetSetMethodNormalizer::GROUPS => ['c']]));
$this->assertEquals([
'symfony' => 'symfony',
'foo' => 'foo',
'fooBar' => 'fooBar',
'bar' => 'bar',
'kevin' => 'kevin',
'coopTilleuls' => 'coopTilleuls',
], $this->normalizer->normalize($obj, null, [GetSetMethodNormalizer::GROUPS => ['a', 'c']]));
}
public function testGroupsDenormalize()
{
$classMetadataFactory = new ClassMetadataFactory(new AnnotationLoader(new AnnotationReader()));
$this->normalizer = new GetSetMethodNormalizer($classMetadataFactory);
$this->normalizer->setSerializer($this->serializer);
$obj = new GroupDummy();
$obj->setFoo('foo');
$toNormalize = ['foo' => 'foo', 'bar' => 'bar'];
$normalized = $this->normalizer->denormalize(
$toNormalize,
'Symfony\Component\Serializer\Tests\Fixtures\GroupDummy',
null,
[GetSetMethodNormalizer::GROUPS => ['a']]
);
$this->assertEquals($obj, $normalized);
$obj->setBar('bar');
$normalized = $this->normalizer->denormalize(
$toNormalize,
'Symfony\Component\Serializer\Tests\Fixtures\GroupDummy',
null,
[GetSetMethodNormalizer::GROUPS => ['a', 'b']]
);
$this->assertEquals($obj, $normalized);
}
public function testGroupsNormalizeWithNameConverter()
{
$classMetadataFactory = new ClassMetadataFactory(new AnnotationLoader(new AnnotationReader()));
$this->normalizer = new GetSetMethodNormalizer($classMetadataFactory, new CamelCaseToSnakeCaseNameConverter());
$this->normalizer->setSerializer($this->serializer);
$obj = new GroupDummy();
$obj->setFooBar('@dunglas');
$obj->setSymfony('@coopTilleuls');
$obj->setCoopTilleuls('les-tilleuls.coop');
$this->assertEquals(
[
'bar' => null,
'foo_bar' => '@dunglas',
'symfony' => '@coopTilleuls',
],
$this->normalizer->normalize($obj, null, [GetSetMethodNormalizer::GROUPS => ['name_converter']])
);
}
public function testGroupsDenormalizeWithNameConverter()
{
$classMetadataFactory = new ClassMetadataFactory(new AnnotationLoader(new AnnotationReader()));
$this->normalizer = new GetSetMethodNormalizer($classMetadataFactory, new CamelCaseToSnakeCaseNameConverter());
$this->normalizer->setSerializer($this->serializer);
$obj = new GroupDummy();
$obj->setFooBar('@dunglas');
$obj->setSymfony('@coopTilleuls');
$this->assertEquals(
$obj,
$this->normalizer->denormalize([
'bar' => null,
'foo_bar' => '@dunglas',
'symfony' => '@coopTilleuls',
'coop_tilleuls' => 'les-tilleuls.coop',
], 'Symfony\Component\Serializer\Tests\Fixtures\GroupDummy', null, [GetSetMethodNormalizer::GROUPS => ['name_converter']])
);
}
/**
* @dataProvider provideCallbacks
*/
public function testCallbacks($callbacks, $value, $result, $message)
{
$this->normalizer->setCallbacks($callbacks);
$obj = new GetConstructorDummy('', $value, true);
$this->assertEquals(
$result,
$this->normalizer->normalize($obj, 'any'),
$message
);
}
public function testUncallableCallbacks()
{
$this->expectException('InvalidArgumentException');
$this->normalizer->setCallbacks(['bar' => null]);
$obj = new GetConstructorDummy('baz', 'quux', true);
$this->normalizer->normalize($obj, 'any');
}
public function testIgnoredAttributes()
{
$this->normalizer->setIgnoredAttributes(['foo', 'bar', 'baz', 'camelCase', 'object']);
$obj = new GetSetDummy();
$obj->setFoo('foo');
$obj->setBar('bar');
$obj->setBaz(true);
$this->assertEquals(
['fooBar' => 'foobar'],
$this->normalizer->normalize($obj, 'any')
);
}
public function provideCallbacks()
{
return [
[
[
'bar' => function ($bar) {
return 'baz';
},
],
'baz',
['foo' => '', 'bar' => 'baz', 'baz' => true],
'Change a string',
],
[
[
'bar' => function ($bar) {
},
],
'baz',
['foo' => '', 'bar' => null, 'baz' => true],
'Null an item',
],
[
[
'bar' => function ($bar) {
return $bar->format('d-m-Y H:i:s');
},
],
new \DateTime('2011-09-10 06:30:00'),
['foo' => '', 'bar' => '10-09-2011 06:30:00', 'baz' => true],
'Format a date',
],
[
[
'bar' => function ($bars) {
$foos = '';
foreach ($bars as $bar) {
$foos .= $bar->getFoo();
}
return $foos;
},
],
[new GetConstructorDummy('baz', '', false), new GetConstructorDummy('quux', '', false)],
['foo' => '', 'bar' => 'bazquux', 'baz' => true],
'Collect a property',
],
[
[
'bar' => function ($bars) {
return \count($bars);
},
],
[new GetConstructorDummy('baz', '', false), new GetConstructorDummy('quux', '', false)],
['foo' => '', 'bar' => 2, 'baz' => true],
'Count a property',
],
];
}
public function testUnableToNormalizeObjectAttribute()
{
$this->expectException('Symfony\Component\Serializer\Exception\LogicException');
$this->expectExceptionMessage('Cannot normalize attribute "object" because the injected serializer is not a normalizer');
$serializer = $this->getMockBuilder('Symfony\Component\Serializer\SerializerInterface')->getMock();
$this->normalizer->setSerializer($serializer);
$obj = new GetSetDummy();
$object = new \stdClass();
$obj->setObject($object);
$this->normalizer->normalize($obj, 'any');
}
public function testUnableToNormalizeCircularReference()
{
$this->expectException('Symfony\Component\Serializer\Exception\CircularReferenceException');
$serializer = new Serializer([$this->normalizer]);
$this->normalizer->setSerializer($serializer);
$this->normalizer->setCircularReferenceLimit(2);
$obj = new CircularReferenceDummy();
$this->normalizer->normalize($obj);
}
public function testSiblingReference()
{
$serializer = new Serializer([$this->normalizer]);
$this->normalizer->setSerializer($serializer);
$siblingHolder = new SiblingHolder();
$expected = [
'sibling0' => ['coopTilleuls' => 'Les-Tilleuls.coop'],
'sibling1' => ['coopTilleuls' => 'Les-Tilleuls.coop'],
'sibling2' => ['coopTilleuls' => 'Les-Tilleuls.coop'],
];
$this->assertEquals($expected, $this->normalizer->normalize($siblingHolder));
}
public function testCircularReferenceHandler()
{
$serializer = new Serializer([$this->normalizer]);
$this->normalizer->setSerializer($serializer);
$this->normalizer->setCircularReferenceHandler(function ($obj) {
return \get_class($obj);
});
$obj = new CircularReferenceDummy();
$expected = ['me' => 'Symfony\Component\Serializer\Tests\Fixtures\CircularReferenceDummy'];
$this->assertEquals($expected, $this->normalizer->normalize($obj));
}
public function testObjectToPopulate()
{
$dummy = new GetSetDummy();
$dummy->setFoo('foo');
$obj = $this->normalizer->denormalize(
['bar' => 'bar'],
GetSetDummy::class,
null,
[GetSetMethodNormalizer::OBJECT_TO_POPULATE => $dummy]
);
$this->assertEquals($dummy, $obj);
$this->assertEquals('foo', $obj->getFoo());
$this->assertEquals('bar', $obj->getBar());
}
public function testDenormalizeNonExistingAttribute()
{
$this->assertEquals(
new GetSetDummy(),
$this->normalizer->denormalize(['non_existing' => true], GetSetDummy::class)
);
}
public function testDenormalizeShouldNotSetStaticAttribute()
{
$obj = $this->normalizer->denormalize(['staticObject' => true], GetSetDummy::class);
$this->assertEquals(new GetSetDummy(), $obj);
$this->assertNull(GetSetDummy::getStaticObject());
}
public function testNoTraversableSupport()
{
$this->assertFalse($this->normalizer->supportsNormalization(new \ArrayObject()));
}
public function testNoStaticGetSetSupport()
{
$this->assertFalse($this->normalizer->supportsNormalization(new ObjectWithJustStaticSetterDummy()));
}
public function testPrivateSetter()
{
$obj = $this->normalizer->denormalize(['foo' => 'foobar'], ObjectWithPrivateSetterDummy::class);
$this->assertEquals('bar', $obj->getFoo());
}
public function testHasGetterDenormalize()
{
$obj = $this->normalizer->denormalize(['foo' => true], ObjectWithHasGetterDummy::class);
$this->assertTrue($obj->hasFoo());
}
public function testHasGetterNormalize()
{
$obj = new ObjectWithHasGetterDummy();
$obj->setFoo(true);
$this->assertEquals(
['foo' => true],
$this->normalizer->normalize($obj, 'any')
);
}
public function testMaxDepth()
{
$classMetadataFactory = new ClassMetadataFactory(new AnnotationLoader(new AnnotationReader()));
$this->normalizer = new GetSetMethodNormalizer($classMetadataFactory);
$serializer = new Serializer([$this->normalizer]);
$this->normalizer->setSerializer($serializer);
$level1 = new MaxDepthDummy();
$level1->bar = 'level1';
$level2 = new MaxDepthDummy();
$level2->bar = 'level2';
$level1->child = $level2;
$level3 = new MaxDepthDummy();
$level3->bar = 'level3';
$level2->child = $level3;
$level4 = new MaxDepthDummy();
$level4->bar = 'level4';
$level3->child = $level4;
$result = $serializer->normalize($level1, null, [GetSetMethodNormalizer::ENABLE_MAX_DEPTH => true]);
$expected = [
'bar' => 'level1',
'child' => [
'bar' => 'level2',
'child' => [
'bar' => 'level3',
'child' => [
'child' => null,
],
],
],
];
$this->assertEquals($expected, $result);
}
}
class GetSetDummy
{
protected $foo;
private $bar;
private $baz;
protected $camelCase;
protected $object;
private static $staticObject;
public function getFoo()
{
return $this->foo;
}
public function setFoo($foo)
{
$this->foo = $foo;
}
public function getBar()
{
return $this->bar;
}
public function setBar($bar)
{
$this->bar = $bar;
}
public function isBaz()
{
return $this->baz;
}
public function setBaz($baz)
{
$this->baz = $baz;
}
public function getFooBar()
{
return $this->foo.$this->bar;
}
public function getCamelCase()
{
return $this->camelCase;
}
public function setCamelCase($camelCase)
{
$this->camelCase = $camelCase;
}
public function otherMethod()
{
throw new \RuntimeException('Dummy::otherMethod() should not be called');
}
public function setObject($object)
{
$this->object = $object;
}
public function getObject()
{
return $this->object;
}
public static function getStaticObject()
{
return self::$staticObject;
}
public static function setStaticObject($object)
{
self::$staticObject = $object;
}
protected function getPrivate()
{
throw new \RuntimeException('Dummy::getPrivate() should not be called');
}
}
class GetConstructorDummy
{
protected $foo;
private $bar;
private $baz;
public function __construct($foo, $bar, $baz)
{
$this->foo = $foo;
$this->bar = $bar;
$this->baz = $baz;
}
public function getFoo()
{
return $this->foo;
}
public function getBar()
{
return $this->bar;
}
public function isBaz()
{
return $this->baz;
}
public function otherMethod()
{
throw new \RuntimeException('Dummy::otherMethod() should not be called');
}
}
abstract class SerializerNormalizer implements SerializerInterface, NormalizerInterface
{
}
class GetConstructorOptionalArgsDummy
{
protected $foo;
private $bar;
private $baz;
public function __construct($foo, $bar = [], $baz = [])
{
$this->foo = $foo;
$this->bar = $bar;
$this->baz = $baz;
}
public function getFoo()
{
return $this->foo;
}
public function getBar()
{
return $this->bar;
}
public function getBaz()
{
return $this->baz;
}
public function otherMethod()
{
throw new \RuntimeException('Dummy::otherMethod() should not be called');
}
}
class GetConstructorArgsWithDefaultValueDummy
{
protected $foo;
protected $bar;
public function __construct($foo = [], $bar = null)
{
$this->foo = $foo;
$this->bar = $bar;
}
public function getFoo()
{
return $this->foo;
}
public function getBar()
{
return $this->bar;
}
public function otherMethod()
{
throw new \RuntimeException('Dummy::otherMethod() should not be called');
}
}
class ObjectConstructorArgsWithPrivateMutatorDummy
{
private $foo;
public function __construct($foo)
{
$this->setFoo($foo);
}
public function getFoo()
{
return $this->foo;
}
private function setFoo($foo)
{
$this->foo = $foo;
}
}
class ObjectWithPrivateSetterDummy
{
private $foo = 'bar';
public function getFoo()
{
return $this->foo;
}
private function setFoo($foo)
{
}
}
class ObjectWithJustStaticSetterDummy
{
private static $foo = 'bar';
public static function getFoo()
{
return self::$foo;
}
public static function setFoo($foo)
{
self::$foo = $foo;
}
}
class ObjectWithHasGetterDummy
{
private $foo;
public function setFoo($foo)
{
$this->foo = $foo;
}
public function hasFoo()
{
return $this->foo;
}
}

View File

@@ -0,0 +1,92 @@
<?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\Serializer\Tests\Normalizer;
use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Serializer\Normalizer\JsonSerializableNormalizer;
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
use Symfony\Component\Serializer\SerializerInterface;
use Symfony\Component\Serializer\Tests\Fixtures\JsonSerializableDummy;
/**
* @author Fred Cox <mcfedr@gmail.com>
*/
class JsonSerializableNormalizerTest extends TestCase
{
/**
* @var JsonSerializableNormalizer
*/
private $normalizer;
/**
* @var MockObject|SerializerInterface
*/
private $serializer;
protected function setUp()
{
$this->serializer = $this->getMockBuilder(JsonSerializerNormalizer::class)->getMock();
$this->normalizer = new JsonSerializableNormalizer();
$this->normalizer->setSerializer($this->serializer);
}
public function testSupportNormalization()
{
$this->assertTrue($this->normalizer->supportsNormalization(new JsonSerializableDummy()));
$this->assertFalse($this->normalizer->supportsNormalization(new \stdClass()));
}
public function testNormalize()
{
$this->serializer
->expects($this->once())
->method('normalize')
->willReturnCallback(function ($data) {
$this->assertSame(['foo' => 'a', 'bar' => 'b', 'baz' => 'c'], array_diff_key($data, ['qux' => '']));
return 'string_object';
})
;
$this->assertEquals('string_object', $this->normalizer->normalize(new JsonSerializableDummy()));
}
public function testCircularNormalize()
{
$this->expectException('Symfony\Component\Serializer\Exception\CircularReferenceException');
$this->normalizer->setCircularReferenceLimit(1);
$this->serializer
->expects($this->once())
->method('normalize')
->willReturnCallback(function ($data, $format, $context) {
$this->normalizer->normalize($data['qux'], $format, $context);
return 'string_object';
})
;
$this->assertEquals('string_object', $this->normalizer->normalize(new JsonSerializableDummy()));
}
public function testInvalidDataThrowException()
{
$this->expectException('Symfony\Component\Serializer\Exception\InvalidArgumentException');
$this->expectExceptionMessage('The object must implement "JsonSerializable".');
$this->normalizer->normalize(new \stdClass());
}
}
abstract class JsonSerializerNormalizer implements SerializerInterface, NormalizerInterface
{
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,47 @@
<?php
namespace Symfony\Component\Serializer\Tests\Normalizer;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Serializer\Normalizer\ObjectToPopulateTrait;
use Symfony\Component\Serializer\Tests\Fixtures\ProxyDummy;
class ObjectToPopulateTraitTest extends TestCase
{
use ObjectToPopulateTrait;
public function testExtractObjectToPopulateReturnsNullWhenKeyIsMissing()
{
$object = $this->extractObjectToPopulate(ProxyDummy::class, []);
$this->assertNull($object);
}
public function testExtractObjectToPopulateReturnsNullWhenNonObjectIsProvided()
{
$object = $this->extractObjectToPopulate(ProxyDummy::class, [
'object_to_populate' => 'not an object',
]);
$this->assertNull($object);
}
public function testExtractObjectToPopulateReturnsNullWhenTheClassIsNotAnInstanceOfTheProvidedClass()
{
$object = $this->extractObjectToPopulate(ProxyDummy::class, [
'object_to_populate' => new \stdClass(),
]);
$this->assertNull($object);
}
public function testExtractObjectToPopulateReturnsObjectWhenEverythingChecksOut()
{
$expected = new ProxyDummy();
$object = $this->extractObjectToPopulate(ProxyDummy::class, [
'object_to_populate' => $expected,
]);
$this->assertSame($expected, $object);
}
}

View File

@@ -0,0 +1,519 @@
<?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\Serializer\Tests\Normalizer;
use Doctrine\Common\Annotations\AnnotationReader;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactory;
use Symfony\Component\Serializer\Mapping\Loader\AnnotationLoader;
use Symfony\Component\Serializer\NameConverter\CamelCaseToSnakeCaseNameConverter;
use Symfony\Component\Serializer\Normalizer\PropertyNormalizer;
use Symfony\Component\Serializer\Serializer;
use Symfony\Component\Serializer\SerializerInterface;
use Symfony\Component\Serializer\Tests\Fixtures\GroupDummy;
use Symfony\Component\Serializer\Tests\Fixtures\GroupDummyChild;
use Symfony\Component\Serializer\Tests\Fixtures\MaxDepthDummy;
use Symfony\Component\Serializer\Tests\Fixtures\Php74Dummy;
use Symfony\Component\Serializer\Tests\Fixtures\PropertyCircularReferenceDummy;
use Symfony\Component\Serializer\Tests\Fixtures\PropertySiblingHolder;
class PropertyNormalizerTest extends TestCase
{
/**
* @var PropertyNormalizer
*/
private $normalizer;
/**
* @var SerializerInterface
*/
private $serializer;
protected function setUp()
{
$this->serializer = $this->getMockBuilder('Symfony\Component\Serializer\SerializerInterface')->getMock();
$this->normalizer = new PropertyNormalizer();
$this->normalizer->setSerializer($this->serializer);
}
public function testNormalize()
{
$obj = new PropertyDummy();
$obj->foo = 'foo';
$obj->setBar('bar');
$obj->setCamelCase('camelcase');
$this->assertEquals(
['foo' => 'foo', 'bar' => 'bar', 'camelCase' => 'camelcase'],
$this->normalizer->normalize($obj, 'any')
);
}
/**
* @requires PHP 7.4
*/
public function testNormalizeObjectWithUninitializedProperties()
{
$obj = new Php74Dummy();
$this->assertEquals(
['initializedProperty' => 'defaultValue'],
$this->normalizer->normalize($obj, 'any')
);
}
public function testDenormalize()
{
$obj = $this->normalizer->denormalize(
['foo' => 'foo', 'bar' => 'bar'],
PropertyDummy::class,
'any'
);
$this->assertEquals('foo', $obj->foo);
$this->assertEquals('bar', $obj->getBar());
}
public function testNormalizeWithParentClass()
{
$group = new GroupDummyChild();
$group->setBaz('baz');
$group->setFoo('foo');
$group->setBar('bar');
$group->setKevin('Kevin');
$group->setCoopTilleuls('coop');
$this->assertEquals(
['foo' => 'foo', 'bar' => 'bar', 'kevin' => 'Kevin', 'coopTilleuls' => 'coop', 'fooBar' => null, 'symfony' => null, 'baz' => 'baz'],
$this->normalizer->normalize($group, 'any')
);
}
public function testDenormalizeWithParentClass()
{
$obj = $this->normalizer->denormalize(
['foo' => 'foo', 'bar' => 'bar', 'kevin' => 'Kevin', 'baz' => 'baz'],
GroupDummyChild::class,
'any'
);
$this->assertEquals('foo', $obj->getFoo());
$this->assertEquals('bar', $obj->getBar());
$this->assertEquals('Kevin', $obj->getKevin());
$this->assertEquals('baz', $obj->getBaz());
$this->assertNull($obj->getSymfony());
}
public function testConstructorDenormalize()
{
$obj = $this->normalizer->denormalize(
['foo' => 'foo', 'bar' => 'bar'],
PropertyConstructorDummy::class,
'any'
);
$this->assertEquals('foo', $obj->getFoo());
$this->assertEquals('bar', $obj->getBar());
}
public function testConstructorDenormalizeWithNullArgument()
{
$obj = $this->normalizer->denormalize(
['foo' => null, 'bar' => 'bar'],
PropertyConstructorDummy::class, '
any'
);
$this->assertNull($obj->getFoo());
$this->assertEquals('bar', $obj->getBar());
}
/**
* @dataProvider provideCallbacks
*/
public function testCallbacks($callbacks, $value, $result, $message)
{
$this->normalizer->setCallbacks($callbacks);
$obj = new PropertyConstructorDummy('', $value);
$this->assertEquals(
$result,
$this->normalizer->normalize($obj, 'any'),
$message
);
}
public function testUncallableCallbacks()
{
$this->expectException('InvalidArgumentException');
$this->normalizer->setCallbacks(['bar' => null]);
$obj = new PropertyConstructorDummy('baz', 'quux');
$this->normalizer->normalize($obj, 'any');
}
public function testIgnoredAttributes()
{
$this->normalizer->setIgnoredAttributes(['foo', 'bar', 'camelCase']);
$obj = new PropertyDummy();
$obj->foo = 'foo';
$obj->setBar('bar');
$this->assertEquals(
[],
$this->normalizer->normalize($obj, 'any')
);
}
public function testGroupsNormalize()
{
$classMetadataFactory = new ClassMetadataFactory(new AnnotationLoader(new AnnotationReader()));
$this->normalizer = new PropertyNormalizer($classMetadataFactory);
$this->normalizer->setSerializer($this->serializer);
$obj = new GroupDummy();
$obj->setFoo('foo');
$obj->setBar('bar');
$obj->setFooBar('fooBar');
$obj->setSymfony('symfony');
$obj->setKevin('kevin');
$obj->setCoopTilleuls('coopTilleuls');
$this->assertEquals([
'bar' => 'bar',
], $this->normalizer->normalize($obj, null, [PropertyNormalizer::GROUPS => ['c']]));
// The PropertyNormalizer is also able to hydrate properties from parent classes
$this->assertEquals([
'symfony' => 'symfony',
'foo' => 'foo',
'fooBar' => 'fooBar',
'bar' => 'bar',
'kevin' => 'kevin',
'coopTilleuls' => 'coopTilleuls',
], $this->normalizer->normalize($obj, null, [PropertyNormalizer::GROUPS => ['a', 'c']]));
}
public function testGroupsDenormalize()
{
$classMetadataFactory = new ClassMetadataFactory(new AnnotationLoader(new AnnotationReader()));
$this->normalizer = new PropertyNormalizer($classMetadataFactory);
$this->normalizer->setSerializer($this->serializer);
$obj = new GroupDummy();
$obj->setFoo('foo');
$toNormalize = ['foo' => 'foo', 'bar' => 'bar'];
$normalized = $this->normalizer->denormalize(
$toNormalize,
'Symfony\Component\Serializer\Tests\Fixtures\GroupDummy',
null,
[PropertyNormalizer::GROUPS => ['a']]
);
$this->assertEquals($obj, $normalized);
$obj->setBar('bar');
$normalized = $this->normalizer->denormalize(
$toNormalize,
'Symfony\Component\Serializer\Tests\Fixtures\GroupDummy',
null,
[PropertyNormalizer::GROUPS => ['a', 'b']]
);
$this->assertEquals($obj, $normalized);
}
public function testGroupsNormalizeWithNameConverter()
{
$classMetadataFactory = new ClassMetadataFactory(new AnnotationLoader(new AnnotationReader()));
$this->normalizer = new PropertyNormalizer($classMetadataFactory, new CamelCaseToSnakeCaseNameConverter());
$this->normalizer->setSerializer($this->serializer);
$obj = new GroupDummy();
$obj->setFooBar('@dunglas');
$obj->setSymfony('@coopTilleuls');
$obj->setCoopTilleuls('les-tilleuls.coop');
$this->assertEquals(
[
'bar' => null,
'foo_bar' => '@dunglas',
'symfony' => '@coopTilleuls',
],
$this->normalizer->normalize($obj, null, [PropertyNormalizer::GROUPS => ['name_converter']])
);
}
public function testGroupsDenormalizeWithNameConverter()
{
$classMetadataFactory = new ClassMetadataFactory(new AnnotationLoader(new AnnotationReader()));
$this->normalizer = new PropertyNormalizer($classMetadataFactory, new CamelCaseToSnakeCaseNameConverter());
$this->normalizer->setSerializer($this->serializer);
$obj = new GroupDummy();
$obj->setFooBar('@dunglas');
$obj->setSymfony('@coopTilleuls');
$this->assertEquals(
$obj,
$this->normalizer->denormalize([
'bar' => null,
'foo_bar' => '@dunglas',
'symfony' => '@coopTilleuls',
'coop_tilleuls' => 'les-tilleuls.coop',
], 'Symfony\Component\Serializer\Tests\Fixtures\GroupDummy', null, [PropertyNormalizer::GROUPS => ['name_converter']])
);
}
public function provideCallbacks()
{
return [
[
[
'bar' => function ($bar) {
return 'baz';
},
],
'baz',
['foo' => '', 'bar' => 'baz'],
'Change a string',
],
[
[
'bar' => function ($bar) {
return;
},
],
'baz',
['foo' => '', 'bar' => null],
'Null an item',
],
[
[
'bar' => function ($bar) {
return $bar->format('d-m-Y H:i:s');
},
],
new \DateTime('2011-09-10 06:30:00'),
['foo' => '', 'bar' => '10-09-2011 06:30:00'],
'Format a date',
],
[
[
'bar' => function ($bars) {
$foos = '';
foreach ($bars as $bar) {
$foos .= $bar->getFoo();
}
return $foos;
},
],
[new PropertyConstructorDummy('baz', ''), new PropertyConstructorDummy('quux', '')],
['foo' => '', 'bar' => 'bazquux'],
'Collect a property',
],
[
[
'bar' => function ($bars) {
return \count($bars);
},
],
[new PropertyConstructorDummy('baz', ''), new PropertyConstructorDummy('quux', '')],
['foo' => '', 'bar' => 2],
'Count a property',
],
];
}
public function testUnableToNormalizeCircularReference()
{
$this->expectException('Symfony\Component\Serializer\Exception\CircularReferenceException');
$serializer = new Serializer([$this->normalizer]);
$this->normalizer->setSerializer($serializer);
$this->normalizer->setCircularReferenceLimit(2);
$obj = new PropertyCircularReferenceDummy();
$this->normalizer->normalize($obj);
}
public function testSiblingReference()
{
$serializer = new Serializer([$this->normalizer]);
$this->normalizer->setSerializer($serializer);
$siblingHolder = new PropertySiblingHolder();
$expected = [
'sibling0' => ['coopTilleuls' => 'Les-Tilleuls.coop'],
'sibling1' => ['coopTilleuls' => 'Les-Tilleuls.coop'],
'sibling2' => ['coopTilleuls' => 'Les-Tilleuls.coop'],
];
$this->assertEquals($expected, $this->normalizer->normalize($siblingHolder));
}
public function testCircularReferenceHandler()
{
$serializer = new Serializer([$this->normalizer]);
$this->normalizer->setSerializer($serializer);
$this->normalizer->setCircularReferenceHandler(function ($obj) {
return \get_class($obj);
});
$obj = new PropertyCircularReferenceDummy();
$expected = ['me' => 'Symfony\Component\Serializer\Tests\Fixtures\PropertyCircularReferenceDummy'];
$this->assertEquals($expected, $this->normalizer->normalize($obj));
}
public function testDenormalizeNonExistingAttribute()
{
$this->assertEquals(
new PropertyDummy(),
$this->normalizer->denormalize(['non_existing' => true], PropertyDummy::class)
);
}
public function testDenormalizeShouldIgnoreStaticProperty()
{
$obj = $this->normalizer->denormalize(['outOfScope' => true], PropertyDummy::class);
$this->assertEquals(new PropertyDummy(), $obj);
$this->assertEquals('out_of_scope', PropertyDummy::$outOfScope);
}
public function testUnableToNormalizeObjectAttribute()
{
$this->expectException('Symfony\Component\Serializer\Exception\LogicException');
$this->expectExceptionMessage('Cannot normalize attribute "bar" because the injected serializer is not a normalizer');
$serializer = $this->getMockBuilder('Symfony\Component\Serializer\SerializerInterface')->getMock();
$this->normalizer->setSerializer($serializer);
$obj = new PropertyDummy();
$object = new \stdClass();
$obj->setBar($object);
$this->normalizer->normalize($obj, 'any');
}
public function testNoTraversableSupport()
{
$this->assertFalse($this->normalizer->supportsNormalization(new \ArrayObject()));
}
public function testNoStaticPropertySupport()
{
$this->assertFalse($this->normalizer->supportsNormalization(new StaticPropertyDummy()));
}
public function testMaxDepth()
{
$classMetadataFactory = new ClassMetadataFactory(new AnnotationLoader(new AnnotationReader()));
$this->normalizer = new PropertyNormalizer($classMetadataFactory);
$serializer = new Serializer([$this->normalizer]);
$this->normalizer->setSerializer($serializer);
$level1 = new MaxDepthDummy();
$level1->foo = 'level1';
$level2 = new MaxDepthDummy();
$level2->foo = 'level2';
$level1->child = $level2;
$level3 = new MaxDepthDummy();
$level3->foo = 'level3';
$level2->child = $level3;
$result = $serializer->normalize($level1, null, [PropertyNormalizer::ENABLE_MAX_DEPTH => true]);
$expected = [
'foo' => 'level1',
'child' => [
'foo' => 'level2',
'child' => [
'child' => null,
'bar' => null,
],
'bar' => null,
],
'bar' => null,
];
$this->assertEquals($expected, $result);
}
public function testInheritedPropertiesSupport()
{
$this->assertTrue($this->normalizer->supportsNormalization(new PropertyChildDummy()));
}
}
class PropertyDummy
{
public static $outOfScope = 'out_of_scope';
public $foo;
private $bar;
protected $camelCase;
public function getBar()
{
return $this->bar;
}
public function setBar($bar)
{
$this->bar = $bar;
}
public function getCamelCase()
{
return $this->camelCase;
}
public function setCamelCase($camelCase)
{
$this->camelCase = $camelCase;
}
}
class PropertyConstructorDummy
{
protected $foo;
private $bar;
public function __construct($foo, $bar)
{
$this->foo = $foo;
$this->bar = $bar;
}
public function getFoo()
{
return $this->foo;
}
public function getBar()
{
return $this->bar;
}
}
class StaticPropertyDummy
{
private static $property = 'value';
}
class PropertyParentDummy
{
private $foo = 'bar';
}
class PropertyChildDummy extends PropertyParentDummy
{
}

View File

@@ -0,0 +1,37 @@
<?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\Serializer\Tests\Normalizer;
use Symfony\Component\Serializer\Normalizer\DenormalizerInterface;
/**
* Provides a test Normalizer which only implements the DenormalizerInterface.
*
* @author Lin Clark <lin@lin-clark.com>
*/
class TestDenormalizer implements DenormalizerInterface
{
/**
* {@inheritdoc}
*/
public function denormalize($data, $type, $format = null, array $context = [])
{
}
/**
* {@inheritdoc}
*/
public function supportsDenormalization($data, $type, $format = null)
{
return true;
}
}

View File

@@ -0,0 +1,37 @@
<?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\Serializer\Tests\Normalizer;
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
/**
* Provides a test Normalizer which only implements the NormalizerInterface.
*
* @author Lin Clark <lin@lin-clark.com>
*/
class TestNormalizer implements NormalizerInterface
{
/**
* {@inheritdoc}
*/
public function normalize($object, $format = null, array $context = [])
{
}
/**
* {@inheritdoc}
*/
public function supportsNormalization($data, $format = null)
{
return true;
}
}

View File

@@ -0,0 +1,404 @@
<?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\Serializer\Tests;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Serializer\Encoder\JsonEncoder;
use Symfony\Component\Serializer\Exception\NotNormalizableValueException;
use Symfony\Component\Serializer\Normalizer\ArrayDenormalizer;
use Symfony\Component\Serializer\Normalizer\CustomNormalizer;
use Symfony\Component\Serializer\Normalizer\DenormalizerAwareInterface;
use Symfony\Component\Serializer\Normalizer\DenormalizerInterface;
use Symfony\Component\Serializer\Normalizer\GetSetMethodNormalizer;
use Symfony\Component\Serializer\Normalizer\NormalizerAwareInterface;
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
use Symfony\Component\Serializer\Normalizer\ObjectNormalizer;
use Symfony\Component\Serializer\Normalizer\PropertyNormalizer;
use Symfony\Component\Serializer\Serializer;
use Symfony\Component\Serializer\Tests\Fixtures\NormalizableTraversableDummy;
use Symfony\Component\Serializer\Tests\Fixtures\TraversableDummy;
use Symfony\Component\Serializer\Tests\Normalizer\TestDenormalizer;
use Symfony\Component\Serializer\Tests\Normalizer\TestNormalizer;
class SerializerTest extends TestCase
{
public function testInterface()
{
$serializer = new Serializer();
$this->assertInstanceOf('Symfony\Component\Serializer\SerializerInterface', $serializer);
$this->assertInstanceOf('Symfony\Component\Serializer\Normalizer\NormalizerInterface', $serializer);
$this->assertInstanceOf('Symfony\Component\Serializer\Normalizer\DenormalizerInterface', $serializer);
$this->assertInstanceOf('Symfony\Component\Serializer\Encoder\EncoderInterface', $serializer);
$this->assertInstanceOf('Symfony\Component\Serializer\Encoder\DecoderInterface', $serializer);
}
public function testNormalizeNoMatch()
{
$this->expectException('Symfony\Component\Serializer\Exception\UnexpectedValueException');
$serializer = new Serializer([$this->getMockBuilder('Symfony\Component\Serializer\Normalizer\CustomNormalizer')->getMock()]);
$serializer->normalize(new \stdClass(), 'xml');
}
public function testNormalizeTraversable()
{
$serializer = new Serializer([], ['json' => new JsonEncoder()]);
$result = $serializer->serialize(new TraversableDummy(), 'json');
$this->assertEquals('{"foo":"foo","bar":"bar"}', $result);
}
public function testNormalizeGivesPriorityToInterfaceOverTraversable()
{
$serializer = new Serializer([new CustomNormalizer()], ['json' => new JsonEncoder()]);
$result = $serializer->serialize(new NormalizableTraversableDummy(), 'json');
$this->assertEquals('{"foo":"normalizedFoo","bar":"normalizedBar"}', $result);
}
public function testNormalizeOnDenormalizer()
{
$this->expectException('Symfony\Component\Serializer\Exception\UnexpectedValueException');
$serializer = new Serializer([new TestDenormalizer()], []);
$this->assertTrue($serializer->normalize(new \stdClass(), 'json'));
}
public function testDenormalizeNoMatch()
{
$this->expectException('Symfony\Component\Serializer\Exception\UnexpectedValueException');
$serializer = new Serializer([$this->getMockBuilder('Symfony\Component\Serializer\Normalizer\CustomNormalizer')->getMock()]);
$serializer->denormalize('foo', 'stdClass');
}
public function testDenormalizeOnNormalizer()
{
$this->expectException('Symfony\Component\Serializer\Exception\UnexpectedValueException');
$serializer = new Serializer([new TestNormalizer()], []);
$data = ['title' => 'foo', 'numbers' => [5, 3]];
$this->assertTrue($serializer->denormalize(json_encode($data), 'stdClass', 'json'));
}
public function testCustomNormalizerCanNormalizeCollectionsAndScalar()
{
$serializer = new Serializer([new TestNormalizer()], []);
$this->assertNull($serializer->normalize(['a', 'b']));
$this->assertNull($serializer->normalize(new \ArrayObject(['c', 'd'])));
$this->assertNull($serializer->normalize([]));
$this->assertNull($serializer->normalize('test'));
}
public function testNormalizeWithSupportOnData()
{
$normalizer1 = $this->getMockBuilder('Symfony\Component\Serializer\Normalizer\NormalizerInterface')->getMock();
$normalizer1->method('supportsNormalization')
->willReturnCallback(function ($data, $format) {
return isset($data->test);
});
$normalizer1->method('normalize')->willReturn('test1');
$normalizer2 = $this->getMockBuilder('Symfony\Component\Serializer\Normalizer\NormalizerInterface')->getMock();
$normalizer2->method('supportsNormalization')
->willReturn(true);
$normalizer2->method('normalize')->willReturn('test2');
$serializer = new Serializer([$normalizer1, $normalizer2]);
$data = new \stdClass();
$data->test = true;
$this->assertEquals('test1', $serializer->normalize($data));
$this->assertEquals('test2', $serializer->normalize(new \stdClass()));
}
public function testDenormalizeWithSupportOnData()
{
$denormalizer1 = $this->getMockBuilder('Symfony\Component\Serializer\Normalizer\DenormalizerInterface')->getMock();
$denormalizer1->method('supportsDenormalization')
->willReturnCallback(function ($data, $type, $format) {
return isset($data['test1']);
});
$denormalizer1->method('denormalize')->willReturn('test1');
$denormalizer2 = $this->getMockBuilder('Symfony\Component\Serializer\Normalizer\DenormalizerInterface')->getMock();
$denormalizer2->method('supportsDenormalization')
->willReturn(true);
$denormalizer2->method('denormalize')->willReturn('test2');
$serializer = new Serializer([$denormalizer1, $denormalizer2]);
$this->assertEquals('test1', $serializer->denormalize(['test1' => true], 'test'));
$this->assertEquals('test2', $serializer->denormalize([], 'test'));
}
public function testSerialize()
{
$serializer = new Serializer([new GetSetMethodNormalizer()], ['json' => new JsonEncoder()]);
$data = ['title' => 'foo', 'numbers' => [5, 3]];
$result = $serializer->serialize(Model::fromArray($data), 'json');
$this->assertEquals(json_encode($data), $result);
}
public function testSerializeScalar()
{
$serializer = new Serializer([], ['json' => new JsonEncoder()]);
$result = $serializer->serialize('foo', 'json');
$this->assertEquals('"foo"', $result);
}
public function testSerializeArrayOfScalars()
{
$serializer = new Serializer([], ['json' => new JsonEncoder()]);
$data = ['foo', [5, 3]];
$result = $serializer->serialize($data, 'json');
$this->assertEquals(json_encode($data), $result);
}
public function testSerializeNoEncoder()
{
$this->expectException('Symfony\Component\Serializer\Exception\UnexpectedValueException');
$serializer = new Serializer([], []);
$data = ['title' => 'foo', 'numbers' => [5, 3]];
$serializer->serialize($data, 'json');
}
public function testSerializeNoNormalizer()
{
$this->expectException('Symfony\Component\Serializer\Exception\LogicException');
$serializer = new Serializer([], ['json' => new JsonEncoder()]);
$data = ['title' => 'foo', 'numbers' => [5, 3]];
$serializer->serialize(Model::fromArray($data), 'json');
}
public function testDeserialize()
{
$serializer = new Serializer([new GetSetMethodNormalizer()], ['json' => new JsonEncoder()]);
$data = ['title' => 'foo', 'numbers' => [5, 3]];
$result = $serializer->deserialize(json_encode($data), '\Symfony\Component\Serializer\Tests\Model', 'json');
$this->assertEquals($data, $result->toArray());
}
public function testDeserializeUseCache()
{
$serializer = new Serializer([new GetSetMethodNormalizer()], ['json' => new JsonEncoder()]);
$data = ['title' => 'foo', 'numbers' => [5, 3]];
$serializer->deserialize(json_encode($data), '\Symfony\Component\Serializer\Tests\Model', 'json');
$data = ['title' => 'bar', 'numbers' => [2, 8]];
$result = $serializer->deserialize(json_encode($data), '\Symfony\Component\Serializer\Tests\Model', 'json');
$this->assertEquals($data, $result->toArray());
}
public function testDeserializeNoNormalizer()
{
$this->expectException('Symfony\Component\Serializer\Exception\LogicException');
$serializer = new Serializer([], ['json' => new JsonEncoder()]);
$data = ['title' => 'foo', 'numbers' => [5, 3]];
$serializer->deserialize(json_encode($data), '\Symfony\Component\Serializer\Tests\Model', 'json');
}
public function testDeserializeWrongNormalizer()
{
$this->expectException('Symfony\Component\Serializer\Exception\UnexpectedValueException');
$serializer = new Serializer([new CustomNormalizer()], ['json' => new JsonEncoder()]);
$data = ['title' => 'foo', 'numbers' => [5, 3]];
$serializer->deserialize(json_encode($data), '\Symfony\Component\Serializer\Tests\Model', 'json');
}
public function testDeserializeNoEncoder()
{
$this->expectException('Symfony\Component\Serializer\Exception\UnexpectedValueException');
$serializer = new Serializer([], []);
$data = ['title' => 'foo', 'numbers' => [5, 3]];
$serializer->deserialize(json_encode($data), '\Symfony\Component\Serializer\Tests\Model', 'json');
}
public function testDeserializeSupported()
{
$serializer = new Serializer([new GetSetMethodNormalizer()], []);
$data = ['title' => 'foo', 'numbers' => [5, 3]];
$this->assertTrue($serializer->supportsDenormalization(json_encode($data), '\Symfony\Component\Serializer\Tests\Model', 'json'));
}
public function testDeserializeNotSupported()
{
$serializer = new Serializer([new GetSetMethodNormalizer()], []);
$data = ['title' => 'foo', 'numbers' => [5, 3]];
$this->assertFalse($serializer->supportsDenormalization(json_encode($data), 'stdClass', 'json'));
}
public function testDeserializeNotSupportedMissing()
{
$serializer = new Serializer([], []);
$data = ['title' => 'foo', 'numbers' => [5, 3]];
$this->assertFalse($serializer->supportsDenormalization(json_encode($data), '\Symfony\Component\Serializer\Tests\Model', 'json'));
}
public function testEncode()
{
$serializer = new Serializer([], ['json' => new JsonEncoder()]);
$data = ['foo', [5, 3]];
$result = $serializer->encode($data, 'json');
$this->assertEquals(json_encode($data), $result);
}
public function testDecode()
{
$serializer = new Serializer([], ['json' => new JsonEncoder()]);
$data = ['foo', [5, 3]];
$result = $serializer->decode(json_encode($data), 'json');
$this->assertEquals($data, $result);
}
public function testSupportsArrayDeserialization()
{
$serializer = new Serializer(
[
new GetSetMethodNormalizer(),
new PropertyNormalizer(),
new ObjectNormalizer(),
new CustomNormalizer(),
new ArrayDenormalizer(),
],
[
'json' => new JsonEncoder(),
]
);
$this->assertTrue(
$serializer->supportsDenormalization([], __NAMESPACE__.'\Model[]', 'json')
);
}
public function testDeserializeArray()
{
$jsonData = '[{"title":"foo","numbers":[5,3]},{"title":"bar","numbers":[2,8]}]';
$expectedData = [
Model::fromArray(['title' => 'foo', 'numbers' => [5, 3]]),
Model::fromArray(['title' => 'bar', 'numbers' => [2, 8]]),
];
$serializer = new Serializer(
[
new GetSetMethodNormalizer(),
new ArrayDenormalizer(),
],
[
'json' => new JsonEncoder(),
]
);
$this->assertEquals(
$expectedData,
$serializer->deserialize($jsonData, __NAMESPACE__.'\Model[]', 'json')
);
}
public function testNormalizerAware()
{
$normalizerAware = $this->getMockBuilder(NormalizerAwareInterface::class)->getMock();
$normalizerAware->expects($this->once())
->method('setNormalizer')
->with($this->isInstanceOf(NormalizerInterface::class));
new Serializer([$normalizerAware]);
}
public function testDenormalizerAware()
{
$denormalizerAware = $this->getMockBuilder(DenormalizerAwareInterface::class)->getMock();
$denormalizerAware->expects($this->once())
->method('setDenormalizer')
->with($this->isInstanceOf(DenormalizerInterface::class));
new Serializer([$denormalizerAware]);
}
public function testDeserializeObjectConstructorWithObjectTypeHint()
{
$jsonData = '{"bar":{"value":"baz"}}';
$serializer = new Serializer([new ObjectNormalizer()], ['json' => new JsonEncoder()]);
$this->assertEquals(new Foo(new Bar('baz')), $serializer->deserialize($jsonData, Foo::class, 'json'));
}
public function testNotNormalizableValueExceptionMessageForAResource()
{
$this->expectException(NotNormalizableValueException::class);
$this->expectExceptionMessage('An unexpected value could not be normalized: stream resource');
(new Serializer())->normalize(tmpfile());
}
}
class Model
{
private $title;
private $numbers;
public static function fromArray($array)
{
$model = new self();
if (isset($array['title'])) {
$model->setTitle($array['title']);
}
if (isset($array['numbers'])) {
$model->setNumbers($array['numbers']);
}
return $model;
}
public function getTitle()
{
return $this->title;
}
public function setTitle($title)
{
$this->title = $title;
}
public function getNumbers()
{
return $this->numbers;
}
public function setNumbers($numbers)
{
$this->numbers = $numbers;
}
public function toArray()
{
return ['title' => $this->title, 'numbers' => $this->numbers];
}
}
class Foo
{
private $bar;
public function __construct(Bar $bar)
{
$this->bar = $bar;
}
}
class Bar
{
private $value;
public function __construct($value)
{
$this->value = $value;
}
}