diff --git a/src/Symfony/Component/Form/Tests/AbstractFormTest.php b/src/Symfony/Component/Form/Tests/AbstractFormTest.php deleted file mode 100644 index 193bb31b15edb..0000000000000 --- a/src/Symfony/Component/Form/Tests/AbstractFormTest.php +++ /dev/null @@ -1,77 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Form\Tests; - -use PHPUnit\Framework\MockObject\MockObject; -use PHPUnit\Framework\TestCase; -use Symfony\Component\EventDispatcher\EventDispatcher; -use Symfony\Component\EventDispatcher\EventDispatcherInterface; -use Symfony\Component\Form\DataMapperInterface; -use Symfony\Component\Form\DataTransformerInterface; -use Symfony\Component\Form\FormBuilder; -use Symfony\Component\Form\FormFactoryInterface; -use Symfony\Component\Form\FormInterface; - -abstract class AbstractFormTest extends TestCase -{ - /** - * @var EventDispatcherInterface - */ - protected $dispatcher; - - /** - * @var MockObject&FormFactoryInterface - */ - protected $factory; - - /** - * @var FormInterface - */ - protected $form; - - protected function setUp(): void - { - $this->dispatcher = new EventDispatcher(); - $this->factory = $this->createMock(FormFactoryInterface::class); - $this->form = $this->createForm(); - } - - protected function tearDown(): void - { - $this->dispatcher = null; - $this->factory = null; - $this->form = null; - } - - abstract protected function createForm(): FormInterface; - - protected function getBuilder(?string $name = 'name', EventDispatcherInterface $dispatcher = null, string $dataClass = null, array $options = []): FormBuilder - { - return new FormBuilder($name, $dataClass, $dispatcher ?: $this->dispatcher, $this->factory, $options); - } - - /** - * @return MockObject&DataMapperInterface - */ - protected function getDataMapper(): DataMapperInterface - { - return $this->createMock(DataMapperInterface::class); - } - - /** - * @return MockObject&DataTransformerInterface - */ - protected function getDataTransformer(): DataTransformerInterface - { - return $this->createMock(DataTransformerInterface::class); - } -} diff --git a/src/Symfony/Component/Form/Tests/AbstractRequestHandlerTest.php b/src/Symfony/Component/Form/Tests/AbstractRequestHandlerTest.php index 857b2bbde469d..a1fd4285bda5c 100644 --- a/src/Symfony/Component/Form/Tests/AbstractRequestHandlerTest.php +++ b/src/Symfony/Component/Form/Tests/AbstractRequestHandlerTest.php @@ -18,9 +18,10 @@ use Symfony\Component\Form\FormBuilder; use Symfony\Component\Form\FormError; use Symfony\Component\Form\FormFactory; -use Symfony\Component\Form\FormFactoryInterface; +use Symfony\Component\Form\FormRegistry; use Symfony\Component\Form\Forms; use Symfony\Component\Form\RequestHandlerInterface; +use Symfony\Component\Form\ResolvedFormTypeFactory; use Symfony\Component\Form\Util\ServerParams; /** @@ -417,7 +418,7 @@ protected function createForm($name, $method = null, $compound = false) protected function createBuilder($name, $compound = false, array $options = []) { - $builder = new FormBuilder($name, null, new EventDispatcher(), $this->createMock(FormFactoryInterface::class), $options); + $builder = new FormBuilder($name, null, new EventDispatcher(), new FormFactory(new FormRegistry([], new ResolvedFormTypeFactory())), $options); $builder->setCompound($compound); if ($compound) { diff --git a/src/Symfony/Component/Form/Tests/ButtonTest.php b/src/Symfony/Component/Form/Tests/ButtonTest.php index e665eca5f804c..0113acab24939 100644 --- a/src/Symfony/Component/Form/Tests/ButtonTest.php +++ b/src/Symfony/Component/Form/Tests/ButtonTest.php @@ -12,27 +12,19 @@ namespace Symfony\Component\Form\Tests; use PHPUnit\Framework\TestCase; -use Symfony\Component\EventDispatcher\EventDispatcherInterface; +use Symfony\Component\EventDispatcher\EventDispatcher; use Symfony\Component\Form\ButtonBuilder; use Symfony\Component\Form\Exception\AlreadySubmittedException; use Symfony\Component\Form\FormBuilder; -use Symfony\Component\Form\FormFactoryInterface; +use Symfony\Component\Form\FormFactory; +use Symfony\Component\Form\FormRegistry; +use Symfony\Component\Form\ResolvedFormTypeFactory; /** * @author Bernhard Schussek */ class ButtonTest extends TestCase { - private $dispatcher; - - private $factory; - - protected function setUp(): void - { - $this->dispatcher = $this->createMock(EventDispatcherInterface::class); - $this->factory = $this->createMock(FormFactoryInterface::class); - } - public function testSetParentOnSubmittedButton() { $this->expectException(AlreadySubmittedException::class); @@ -83,6 +75,6 @@ private function getButtonBuilder($name) private function getFormBuilder() { - return new FormBuilder('form', null, $this->dispatcher, $this->factory); + return new FormBuilder('form', null, new EventDispatcher(), new FormFactory(new FormRegistry([], new ResolvedFormTypeFactory()))); } } diff --git a/src/Symfony/Component/Form/Tests/ChoiceList/Factory/CachingFactoryDecoratorTest.php b/src/Symfony/Component/Form/Tests/ChoiceList/Factory/CachingFactoryDecoratorTest.php index 38c4041bd74d7..de2a70efa8696 100644 --- a/src/Symfony/Component/Form/Tests/ChoiceList/Factory/CachingFactoryDecoratorTest.php +++ b/src/Symfony/Component/Form/Tests/ChoiceList/Factory/CachingFactoryDecoratorTest.php @@ -11,25 +11,18 @@ namespace Symfony\Component\Form\Tests\ChoiceList\Factory; -use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; use Symfony\Component\Form\ChoiceList\ArrayChoiceList; -use Symfony\Component\Form\ChoiceList\ChoiceListInterface; use Symfony\Component\Form\ChoiceList\Factory\CachingFactoryDecorator; -use Symfony\Component\Form\ChoiceList\Factory\ChoiceListFactoryInterface; -use Symfony\Component\Form\ChoiceList\Loader\ChoiceLoaderInterface; +use Symfony\Component\Form\ChoiceList\Factory\DefaultChoiceListFactory; use Symfony\Component\Form\ChoiceList\View\ChoiceListView; +use Symfony\Component\Form\Tests\Fixtures\ArrayChoiceLoader; /** * @author Bernhard Schussek */ class CachingFactoryDecoratorTest extends TestCase { - /** - * @var MockObject&ChoiceListFactoryInterface - */ - private $decoratedFactory; - /** * @var CachingFactoryDecorator */ @@ -37,21 +30,17 @@ class CachingFactoryDecoratorTest extends TestCase protected function setUp(): void { - $this->decoratedFactory = $this->createMock(ChoiceListFactoryInterface::class); - $this->factory = new CachingFactoryDecorator($this->decoratedFactory); + $this->factory = new CachingFactoryDecorator(new DefaultChoiceListFactory()); } public function testCreateFromChoicesEmpty() { - $list = new ArrayChoiceList([]); - - $this->decoratedFactory->expects($this->once()) - ->method('createListFromChoices') - ->with([]) - ->willReturn($list); + $list1 = $this->factory->createListFromChoices([]); + $list2 = $this->factory->createListFromChoices([]); - $this->assertSame($list, $this->factory->createListFromChoices([])); - $this->assertSame($list, $this->factory->createListFromChoices([])); + $this->assertSame($list1, $list2); + $this->assertEquals(new ArrayChoiceList([]), $list1); + $this->assertEquals(new ArrayChoiceList([]), $list2); } public function testCreateFromChoicesComparesTraversableChoicesAsArray() @@ -59,34 +48,25 @@ public function testCreateFromChoicesComparesTraversableChoicesAsArray() // The top-most traversable is converted to an array $choices1 = new \ArrayIterator(['A' => 'a']); $choices2 = ['A' => 'a']; - $list = new ArrayChoiceList([]); - $this->decoratedFactory->expects($this->once()) - ->method('createListFromChoices') - ->with($choices2) - ->willReturn($list); + $list1 = $this->factory->createListFromChoices($choices1); + $list2 = $this->factory->createListFromChoices($choices2); - $this->assertSame($list, $this->factory->createListFromChoices($choices1)); - $this->assertSame($list, $this->factory->createListFromChoices($choices2)); + $this->assertSame($list1, $list2); + $this->assertEquals(new ArrayChoiceList(['A' => 'a']), $list1); + $this->assertEquals(new ArrayChoiceList(['A' => 'a']), $list2); } public function testCreateFromChoicesGroupedChoices() { $choices1 = ['key' => ['A' => 'a']]; $choices2 = ['A' => 'a']; - $list1 = new ArrayChoiceList([]); - $list2 = new ArrayChoiceList([]); - - $this->decoratedFactory->expects($this->exactly(2)) - ->method('createListFromChoices') - ->withConsecutive( - [$choices1], - [$choices2] - ) - ->willReturnOnConsecutiveCalls($list1, $list2); - - $this->assertSame($list1, $this->factory->createListFromChoices($choices1)); - $this->assertSame($list2, $this->factory->createListFromChoices($choices2)); + $list1 = $this->factory->createListFromChoices($choices1); + $list2 = $this->factory->createListFromChoices($choices2); + + $this->assertNotSame($list1, $list2); + $this->assertEquals(new ArrayChoiceList(['key' => ['A' => 'a']]), $list1); + $this->assertEquals(new ArrayChoiceList(['A' => 'a']), $list2); } /** @@ -94,17 +74,12 @@ public function testCreateFromChoicesGroupedChoices() */ public function testCreateFromChoicesSameChoices($choice1, $choice2) { - $choices1 = [$choice1]; - $choices2 = [$choice2]; - $list = new ArrayChoiceList([]); - - $this->decoratedFactory->expects($this->once()) - ->method('createListFromChoices') - ->with($choices1) - ->willReturn($list); + $list1 = $this->factory->createListFromChoices([$choice1]); + $list2 = $this->factory->createListFromChoices([$choice2]); - $this->assertSame($list, $this->factory->createListFromChoices($choices1)); - $this->assertSame($list, $this->factory->createListFromChoices($choices2)); + $this->assertSame($list1, $list2); + $this->assertEquals(new ArrayChoiceList([$choice1]), $list1); + $this->assertEquals(new ArrayChoiceList([$choice2]), $list2); } /** @@ -112,369 +87,245 @@ public function testCreateFromChoicesSameChoices($choice1, $choice2) */ public function testCreateFromChoicesDifferentChoices($choice1, $choice2) { - $choices1 = [$choice1]; - $choices2 = [$choice2]; - $list1 = new ArrayChoiceList([]); - $list2 = new ArrayChoiceList([]); - - $this->decoratedFactory->expects($this->exactly(2)) - ->method('createListFromChoices') - ->withConsecutive( - [$choices1], - [$choices2] - ) - ->willReturnOnConsecutiveCalls($list1, $list2); - - $this->assertSame($list1, $this->factory->createListFromChoices($choices1)); - $this->assertSame($list2, $this->factory->createListFromChoices($choices2)); + $list1 = $this->factory->createListFromChoices([$choice1]); + $list2 = $this->factory->createListFromChoices([$choice2]); + + $this->assertNotSame($list1, $list2); + $this->assertEquals(new ArrayChoiceList([$choice1]), $list1); + $this->assertEquals(new ArrayChoiceList([$choice2]), $list2); } public function testCreateFromChoicesSameValueClosure() { $choices = [1]; - $list = new ArrayChoiceList([]); $closure = function () {}; - $this->decoratedFactory->expects($this->once()) - ->method('createListFromChoices') - ->with($choices, $closure) - ->willReturn($list); + $list1 = $this->factory->createListFromChoices($choices, $closure); + $list2 = $this->factory->createListFromChoices($choices, $closure); - $this->assertSame($list, $this->factory->createListFromChoices($choices, $closure)); - $this->assertSame($list, $this->factory->createListFromChoices($choices, $closure)); + $this->assertSame($list1, $list2); + $this->assertEquals(new ArrayChoiceList($choices, $closure), $list1); + $this->assertEquals(new ArrayChoiceList($choices, $closure), $list2); } public function testCreateFromChoicesDifferentValueClosure() { $choices = [1]; - $list1 = new ArrayChoiceList([]); - $list2 = new ArrayChoiceList([]); $closure1 = function () {}; $closure2 = function () {}; + $list1 = $this->factory->createListFromChoices($choices, $closure1); + $list2 = $this->factory->createListFromChoices($choices, $closure2); - $this->decoratedFactory->expects($this->exactly(2)) - ->method('createListFromChoices') - ->withConsecutive( - [$choices, $closure1], - [$choices, $closure2] - ) - ->willReturnOnConsecutiveCalls($list1, $list2); - - $this->assertSame($list1, $this->factory->createListFromChoices($choices, $closure1)); - $this->assertSame($list2, $this->factory->createListFromChoices($choices, $closure2)); + $this->assertNotSame($list1, $list2); + $this->assertEquals(new ArrayChoiceList($choices, $closure1), $list1); + $this->assertEquals(new ArrayChoiceList($choices, $closure2), $list2); } public function testCreateFromLoaderSameLoader() { - $loader = $this->createMock(ChoiceLoaderInterface::class); - $list = new ArrayChoiceList([]); - - $this->decoratedFactory->expects($this->once()) - ->method('createListFromLoader') - ->with($loader) - ->willReturn($list); + $loader = new ArrayChoiceLoader(); - $this->assertSame($list, $this->factory->createListFromLoader($loader)); - $this->assertSame($list, $this->factory->createListFromLoader($loader)); + $this->assertSame($this->factory->createListFromLoader($loader), $this->factory->createListFromLoader($loader)); } public function testCreateFromLoaderDifferentLoader() { - $loader1 = $this->createMock(ChoiceLoaderInterface::class); - $loader2 = $this->createMock(ChoiceLoaderInterface::class); - $list1 = new ArrayChoiceList([]); - $list2 = new ArrayChoiceList([]); - - $this->decoratedFactory->expects($this->exactly(2)) - ->method('createListFromLoader') - ->withConsecutive( - [$loader1], - [$loader2] - ) - ->willReturnOnConsecutiveCalls($list1, $list2); - - $this->assertSame($list1, $this->factory->createListFromLoader($loader1)); - $this->assertSame($list2, $this->factory->createListFromLoader($loader2)); + $this->assertNotSame($this->factory->createListFromLoader(new ArrayChoiceLoader()), $this->factory->createListFromLoader(new ArrayChoiceLoader())); } public function testCreateFromLoaderSameValueClosure() { - $loader = $this->createMock(ChoiceLoaderInterface::class); - $list = new ArrayChoiceList([]); + $loader = new ArrayChoiceLoader(); $closure = function () {}; - $this->decoratedFactory->expects($this->once()) - ->method('createListFromLoader') - ->with($loader, $closure) - ->willReturn($list); - - $this->assertSame($list, $this->factory->createListFromLoader($loader, $closure)); - $this->assertSame($list, $this->factory->createListFromLoader($loader, $closure)); + $this->assertSame($this->factory->createListFromLoader($loader, $closure), $this->factory->createListFromLoader($loader, $closure)); } public function testCreateFromLoaderDifferentValueClosure() { - $loader = $this->createMock(ChoiceLoaderInterface::class); - $list1 = new ArrayChoiceList([]); - $list2 = new ArrayChoiceList([]); + $loader = new ArrayChoiceLoader(); $closure1 = function () {}; $closure2 = function () {}; - $this->decoratedFactory->expects($this->exactly(2)) - ->method('createListFromLoader') - ->withConsecutive( - [$loader, $closure1], - [$loader, $closure2] - ) - ->willReturnOnConsecutiveCalls($list1, $list2); - - $this->assertSame($list1, $this->factory->createListFromLoader($loader, $closure1)); - $this->assertSame($list2, $this->factory->createListFromLoader($loader, $closure2)); + $this->assertNotSame($this->factory->createListFromLoader($loader, $closure1), $this->factory->createListFromLoader($loader, $closure2)); } public function testCreateViewSamePreferredChoices() { $preferred = ['a']; - $list = $this->createMock(ChoiceListInterface::class); - $view = new ChoiceListView(); - - $this->decoratedFactory->expects($this->once()) - ->method('createView') - ->with($list, $preferred) - ->willReturn($view); + $list = new ArrayChoiceList([]); + $view1 = $this->factory->createView($list, $preferred); + $view2 = $this->factory->createView($list, $preferred); - $this->assertSame($view, $this->factory->createView($list, $preferred)); - $this->assertSame($view, $this->factory->createView($list, $preferred)); + $this->assertSame($view1, $view2); + $this->assertEquals(new ChoiceListView(), $view1); + $this->assertEquals(new ChoiceListView(), $view2); } public function testCreateViewDifferentPreferredChoices() { $preferred1 = ['a']; $preferred2 = ['b']; - $list = $this->createMock(ChoiceListInterface::class); - $view1 = new ChoiceListView(); - $view2 = new ChoiceListView(); - - $this->decoratedFactory->expects($this->exactly(2)) - ->method('createView') - ->withConsecutive( - [$list, $preferred1], - [$list, $preferred2] - ) - ->willReturnOnConsecutiveCalls($view1, $view2); - - $this->assertSame($view1, $this->factory->createView($list, $preferred1)); - $this->assertSame($view2, $this->factory->createView($list, $preferred2)); + $list = new ArrayChoiceList([]); + $view1 = $this->factory->createView($list, $preferred1); + $view2 = $this->factory->createView($list, $preferred2); + + $this->assertNotSame($view1, $view2); + $this->assertEquals(new ChoiceListView(), $view1); + $this->assertEquals(new ChoiceListView(), $view2); } public function testCreateViewSamePreferredChoicesClosure() { $preferred = function () {}; - $list = $this->createMock(ChoiceListInterface::class); - $view = new ChoiceListView(); - - $this->decoratedFactory->expects($this->once()) - ->method('createView') - ->with($list, $preferred) - ->willReturn($view); + $list = new ArrayChoiceList([]); + $view1 = $this->factory->createView($list, $preferred); + $view2 = $this->factory->createView($list, $preferred); - $this->assertSame($view, $this->factory->createView($list, $preferred)); - $this->assertSame($view, $this->factory->createView($list, $preferred)); + $this->assertSame($view1, $view2); + $this->assertEquals(new ChoiceListView(), $view1); + $this->assertEquals(new ChoiceListView(), $view2); } public function testCreateViewDifferentPreferredChoicesClosure() { $preferred1 = function () {}; $preferred2 = function () {}; - $list = $this->createMock(ChoiceListInterface::class); - $view1 = new ChoiceListView(); - $view2 = new ChoiceListView(); - - $this->decoratedFactory->expects($this->exactly(2)) - ->method('createView') - ->withConsecutive( - [$list, $preferred1], - [$list, $preferred2] - ) - ->willReturnOnConsecutiveCalls($view1, $view2); - - $this->assertSame($view1, $this->factory->createView($list, $preferred1)); - $this->assertSame($view2, $this->factory->createView($list, $preferred2)); + $list = new ArrayChoiceList([]); + $view1 = $this->factory->createView($list, $preferred1); + $view2 = $this->factory->createView($list, $preferred2); + + $this->assertNotSame($view1, $view2); + $this->assertEquals(new ChoiceListView(), $view1); + $this->assertEquals(new ChoiceListView(), $view2); } public function testCreateViewSameLabelClosure() { $labels = function () {}; - $list = $this->createMock(ChoiceListInterface::class); - $view = new ChoiceListView(); - - $this->decoratedFactory->expects($this->once()) - ->method('createView') - ->with($list, null, $labels) - ->willReturn($view); + $list = new ArrayChoiceList([]); + $view1 = $this->factory->createView($list, null, $labels); + $view2 = $this->factory->createView($list, null, $labels); - $this->assertSame($view, $this->factory->createView($list, null, $labels)); - $this->assertSame($view, $this->factory->createView($list, null, $labels)); + $this->assertSame($view1, $view2); + $this->assertEquals(new ChoiceListView(), $view1); + $this->assertEquals(new ChoiceListView(), $view2); } public function testCreateViewDifferentLabelClosure() { $labels1 = function () {}; $labels2 = function () {}; - $list = $this->createMock(ChoiceListInterface::class); - $view1 = new ChoiceListView(); - $view2 = new ChoiceListView(); - - $this->decoratedFactory->expects($this->exactly(2)) - ->method('createView') - ->withConsecutive( - [$list, null, $labels1], - [$list, null, $labels2] - ) - ->willReturnOnConsecutiveCalls($view1, $view2); - - $this->assertSame($view1, $this->factory->createView($list, null, $labels1)); - $this->assertSame($view2, $this->factory->createView($list, null, $labels2)); + $list = new ArrayChoiceList([]); + $view1 = $this->factory->createView($list, null, $labels1); + $view2 = $this->factory->createView($list, null, $labels2); + + $this->assertNotSame($view1, $view2); + $this->assertEquals(new ChoiceListView(), $view1); + $this->assertEquals(new ChoiceListView(), $view2); } public function testCreateViewSameIndexClosure() { $index = function () {}; - $list = $this->createMock(ChoiceListInterface::class); - $view = new ChoiceListView(); - - $this->decoratedFactory->expects($this->once()) - ->method('createView') - ->with($list, null, null, $index) - ->willReturn($view); + $list = new ArrayChoiceList([]); + $view1 = $this->factory->createView($list, null, null, $index); + $view2 = $this->factory->createView($list, null, null, $index); - $this->assertSame($view, $this->factory->createView($list, null, null, $index)); - $this->assertSame($view, $this->factory->createView($list, null, null, $index)); + $this->assertSame($view1, $view2); + $this->assertEquals(new ChoiceListView(), $view1); + $this->assertEquals(new ChoiceListView(), $view2); } public function testCreateViewDifferentIndexClosure() { $index1 = function () {}; $index2 = function () {}; - $list = $this->createMock(ChoiceListInterface::class); - $view1 = new ChoiceListView(); - $view2 = new ChoiceListView(); - - $this->decoratedFactory->expects($this->exactly(2)) - ->method('createView') - ->withConsecutive( - [$list, null, null, $index1], - [$list, null, null, $index2] - ) - ->willReturnOnConsecutiveCalls($view1, $view2); - - $this->assertSame($view1, $this->factory->createView($list, null, null, $index1)); - $this->assertSame($view2, $this->factory->createView($list, null, null, $index2)); + $list = new ArrayChoiceList([]); + $view1 = $this->factory->createView($list, null, null, $index1); + $view2 = $this->factory->createView($list, null, null, $index2); + + $this->assertNotSame($view1, $view2); + $this->assertEquals(new ChoiceListView(), $view1); + $this->assertEquals(new ChoiceListView(), $view2); } public function testCreateViewSameGroupByClosure() { $groupBy = function () {}; - $list = $this->createMock(ChoiceListInterface::class); - $view = new ChoiceListView(); - - $this->decoratedFactory->expects($this->once()) - ->method('createView') - ->with($list, null, null, null, $groupBy) - ->willReturn($view); + $list = new ArrayChoiceList([]); + $view1 = $this->factory->createView($list, null, null, null, $groupBy); + $view2 = $this->factory->createView($list, null, null, null, $groupBy); - $this->assertSame($view, $this->factory->createView($list, null, null, null, $groupBy)); - $this->assertSame($view, $this->factory->createView($list, null, null, null, $groupBy)); + $this->assertSame($view1, $view2); + $this->assertEquals(new ChoiceListView(), $view1); + $this->assertEquals(new ChoiceListView(), $view2); } public function testCreateViewDifferentGroupByClosure() { $groupBy1 = function () {}; $groupBy2 = function () {}; - $list = $this->createMock(ChoiceListInterface::class); - $view1 = new ChoiceListView(); - $view2 = new ChoiceListView(); - - $this->decoratedFactory->expects($this->exactly(2)) - ->method('createView') - ->withConsecutive( - [$list, null, null, null, $groupBy1], - [$list, null, null, null, $groupBy2] - ) - ->willReturnOnConsecutiveCalls($view1, $view2); - - $this->assertSame($view1, $this->factory->createView($list, null, null, null, $groupBy1)); - $this->assertSame($view2, $this->factory->createView($list, null, null, null, $groupBy2)); + $list = new ArrayChoiceList([]); + $view1 = $this->factory->createView($list, null, null, null, $groupBy1); + $view2 = $this->factory->createView($list, null, null, null, $groupBy2); + + $this->assertNotSame($view1, $view2); + $this->assertEquals(new ChoiceListView(), $view1); + $this->assertEquals(new ChoiceListView(), $view2); } public function testCreateViewSameAttributes() { $attr = ['class' => 'foobar']; - $list = $this->createMock(ChoiceListInterface::class); - $view = new ChoiceListView(); + $list = new ArrayChoiceList([]); - $this->decoratedFactory->expects($this->once()) - ->method('createView') - ->with($list, null, null, null, null, $attr) - ->willReturn($view); + $view1 = $this->factory->createView($list, null, null, null, null, $attr); + $view2 = $this->factory->createView($list, null, null, null, null, $attr); - $this->assertSame($view, $this->factory->createView($list, null, null, null, null, $attr)); - $this->assertSame($view, $this->factory->createView($list, null, null, null, null, $attr)); + $this->assertSame($view1, $view2); + $this->assertEquals(new ChoiceListView(), $view1); + $this->assertEquals(new ChoiceListView(), $view2); } public function testCreateViewDifferentAttributes() { $attr1 = ['class' => 'foobar1']; $attr2 = ['class' => 'foobar2']; - $list = $this->createMock(ChoiceListInterface::class); - $view1 = new ChoiceListView(); - $view2 = new ChoiceListView(); - - $this->decoratedFactory->expects($this->exactly(2)) - ->method('createView') - ->withConsecutive( - [$list, null, null, null, null, $attr1], - [$list, null, null, null, null, $attr2] - ) - ->willReturnOnConsecutiveCalls($view1, $view2); - - $this->assertSame($view1, $this->factory->createView($list, null, null, null, null, $attr1)); - $this->assertSame($view2, $this->factory->createView($list, null, null, null, null, $attr2)); + $list = new ArrayChoiceList([]); + + $view1 = $this->factory->createView($list, null, null, null, null, $attr1); + $view2 = $this->factory->createView($list, null, null, null, null, $attr2); + + $this->assertNotSame($view1, $view2); + $this->assertEquals(new ChoiceListView(), $view1); + $this->assertEquals(new ChoiceListView(), $view2); } public function testCreateViewSameAttributesClosure() { $attr = function () {}; - $list = $this->createMock(ChoiceListInterface::class); - $view = new ChoiceListView(); - - $this->decoratedFactory->expects($this->once()) - ->method('createView') - ->with($list, null, null, null, null, $attr) - ->willReturn($view); + $list = new ArrayChoiceList([]); + $view1 = $this->factory->createView($list, null, null, null, null, $attr); + $view2 = $this->factory->createView($list, null, null, null, null, $attr); - $this->assertSame($view, $this->factory->createView($list, null, null, null, null, $attr)); - $this->assertSame($view, $this->factory->createView($list, null, null, null, null, $attr)); + $this->assertSame($view1, $view2); + $this->assertEquals(new ChoiceListView(), $view1); + $this->assertEquals(new ChoiceListView(), $view2); } public function testCreateViewDifferentAttributesClosure() { $attr1 = function () {}; $attr2 = function () {}; - $list = $this->createMock(ChoiceListInterface::class); - $view1 = new ChoiceListView(); - $view2 = new ChoiceListView(); - - $this->decoratedFactory->expects($this->exactly(2)) - ->method('createView') - ->withConsecutive( - [$list, null, null, null, null, $attr1], - [$list, null, null, null, null, $attr2] - ) - ->willReturnOnConsecutiveCalls($view1, $view2); - - $this->assertSame($view1, $this->factory->createView($list, null, null, null, null, $attr1)); - $this->assertSame($view2, $this->factory->createView($list, null, null, null, null, $attr2)); + $list = new ArrayChoiceList([]); + + $view1 = $this->factory->createView($list, null, null, null, null, $attr1); + $view2 = $this->factory->createView($list, null, null, null, null, $attr2); + + $this->assertNotSame($view1, $view2); + $this->assertEquals(new ChoiceListView(), $view1); + $this->assertEquals(new ChoiceListView(), $view2); } public function provideSameChoices() diff --git a/src/Symfony/Component/Form/Tests/ChoiceList/Factory/DefaultChoiceListFactoryTest.php b/src/Symfony/Component/Form/Tests/ChoiceList/Factory/DefaultChoiceListFactoryTest.php index 18cf4daa0cb35..25fb551df7ce8 100644 --- a/src/Symfony/Component/Form/Tests/ChoiceList/Factory/DefaultChoiceListFactoryTest.php +++ b/src/Symfony/Component/Form/Tests/ChoiceList/Factory/DefaultChoiceListFactoryTest.php @@ -16,10 +16,10 @@ use Symfony\Component\Form\ChoiceList\ChoiceListInterface; use Symfony\Component\Form\ChoiceList\Factory\DefaultChoiceListFactory; use Symfony\Component\Form\ChoiceList\LazyChoiceList; -use Symfony\Component\Form\ChoiceList\Loader\ChoiceLoaderInterface; use Symfony\Component\Form\ChoiceList\View\ChoiceGroupView; use Symfony\Component\Form\ChoiceList\View\ChoiceListView; use Symfony\Component\Form\ChoiceList\View\ChoiceView; +use Symfony\Component\Form\Tests\Fixtures\ArrayChoiceLoader; class DefaultChoiceListFactoryTest extends TestCase { @@ -194,7 +194,7 @@ function ($object) { return $object->value; } public function testCreateFromLoader() { - $loader = $this->createMock(ChoiceLoaderInterface::class); + $loader = new ArrayChoiceLoader(); $list = $this->factory->createListFromLoader($loader); @@ -203,7 +203,7 @@ public function testCreateFromLoader() public function testCreateFromLoaderWithValues() { - $loader = $this->createMock(ChoiceLoaderInterface::class); + $loader = new ArrayChoiceLoader(); $value = function () {}; $list = $this->factory->createListFromLoader($loader, $value); diff --git a/src/Symfony/Component/Form/Tests/ChoiceList/Factory/PropertyAccessDecoratorTest.php b/src/Symfony/Component/Form/Tests/ChoiceList/Factory/PropertyAccessDecoratorTest.php index 16969f3288f73..2a7884d0c59eb 100644 --- a/src/Symfony/Component/Form/Tests/ChoiceList/Factory/PropertyAccessDecoratorTest.php +++ b/src/Symfony/Component/Form/Tests/ChoiceList/Factory/PropertyAccessDecoratorTest.php @@ -11,14 +11,13 @@ namespace Symfony\Component\Form\Tests\ChoiceList\Factory; -use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; use Symfony\Component\Form\ChoiceList\ArrayChoiceList; -use Symfony\Component\Form\ChoiceList\ChoiceListInterface; -use Symfony\Component\Form\ChoiceList\Factory\ChoiceListFactoryInterface; +use Symfony\Component\Form\ChoiceList\Factory\DefaultChoiceListFactory; use Symfony\Component\Form\ChoiceList\Factory\PropertyAccessDecorator; -use Symfony\Component\Form\ChoiceList\Loader\ChoiceLoaderInterface; -use Symfony\Component\Form\ChoiceList\View\ChoiceListView; +use Symfony\Component\Form\ChoiceList\View\ChoiceGroupView; +use Symfony\Component\Form\ChoiceList\View\ChoiceView; +use Symfony\Component\Form\Tests\Fixtures\ArrayChoiceLoader; use Symfony\Component\PropertyAccess\PropertyPath; /** @@ -26,11 +25,6 @@ */ class PropertyAccessDecoratorTest extends TestCase { - /** - * @var MockObject&ChoiceListFactoryInterface - */ - private $decoratedFactory; - /** * @var PropertyAccessDecorator */ @@ -38,50 +32,29 @@ class PropertyAccessDecoratorTest extends TestCase protected function setUp(): void { - $this->decoratedFactory = $this->createMock(ChoiceListFactoryInterface::class); - $this->factory = new PropertyAccessDecorator($this->decoratedFactory); + $this->factory = new PropertyAccessDecorator(new DefaultChoiceListFactory()); } public function testCreateFromChoicesPropertyPath() { - $choices = [(object) ['property' => 'value']]; + $object = (object) ['property' => 'value']; - $this->decoratedFactory->expects($this->once()) - ->method('createListFromChoices') - ->with($choices, $this->isInstanceOf(\Closure::class)) - ->willReturnCallback(function ($choices, $callback) { - return new ArrayChoiceList(array_map($callback, $choices)); - }); - - $this->assertSame(['value' => 'value'], $this->factory->createListFromChoices($choices, 'property')->getChoices()); + $this->assertSame(['value' => $object], $this->factory->createListFromChoices([$object], 'property')->getChoices()); } public function testCreateFromChoicesPropertyPathInstance() { - $choices = [(object) ['property' => 'value']]; - - $this->decoratedFactory->expects($this->once()) - ->method('createListFromChoices') - ->with($choices, $this->isInstanceOf(\Closure::class)) - ->willReturnCallback(function ($choices, $callback) { - return new ArrayChoiceList(array_map($callback, $choices)); - }); + $object = (object) ['property' => 'value']; - $this->assertSame(['value' => 'value'], $this->factory->createListFromChoices($choices, new PropertyPath('property'))->getChoices()); + $this->assertSame(['value' => $object], $this->factory->createListFromChoices([$object], new PropertyPath('property'))->getChoices()); } public function testCreateFromLoaderPropertyPath() { - $loader = $this->createMock(ChoiceLoaderInterface::class); - - $this->decoratedFactory->expects($this->once()) - ->method('createListFromLoader') - ->with($loader, $this->isInstanceOf(\Closure::class)) - ->willReturnCallback(function ($loader, $callback) { - return new ArrayChoiceList((array) $callback((object) ['property' => 'value'])); - }); + $object = (object) ['property' => 'value']; + $loader = new ArrayChoiceLoader([$object]); - $this->assertSame(['value' => 'value'], $this->factory->createListFromLoader($loader, 'property')->getChoices()); + $this->assertSame(['value' => $object], $this->factory->createListFromLoader($loader, 'property')->getChoices()); } // https://github.com/symfony/symfony/issues/5494 @@ -89,212 +62,122 @@ public function testCreateFromChoicesAssumeNullIfValuePropertyPathUnreadable() { $choices = [null]; - $this->decoratedFactory->expects($this->once()) - ->method('createListFromChoices') - ->with($choices, $this->isInstanceOf(\Closure::class)) - ->willReturnCallback(function ($choices, $callback) { - return new ArrayChoiceList(array_map($callback, $choices)); - }); - - $this->assertSame([null], $this->factory->createListFromChoices($choices, 'property')->getChoices()); + $this->assertSame(['' => null], $this->factory->createListFromChoices($choices, 'property')->getChoices()); } // https://github.com/symfony/symfony/issues/5494 public function testCreateFromChoiceLoaderAssumeNullIfValuePropertyPathUnreadable() { - $loader = $this->createMock(ChoiceLoaderInterface::class); - - $this->decoratedFactory->expects($this->once()) - ->method('createListFromLoader') - ->with($loader, $this->isInstanceOf(\Closure::class)) - ->willReturnCallback(function ($loader, $callback) { - return new ArrayChoiceList((array) $callback(null)); - }); + $loader = new ArrayChoiceLoader([null]); - $this->assertSame([], $this->factory->createListFromLoader($loader, 'property')->getChoices()); + $this->assertSame(['' => null], $this->factory->createListFromLoader($loader, 'property')->getChoices()); } public function testCreateFromLoaderPropertyPathInstance() { - $loader = $this->createMock(ChoiceLoaderInterface::class); - - $this->decoratedFactory->expects($this->once()) - ->method('createListFromLoader') - ->with($loader, $this->isInstanceOf(\Closure::class)) - ->willReturnCallback(function ($loader, $callback) { - return new ArrayChoiceList((array) $callback((object) ['property' => 'value'])); - }); + $object = (object) ['property' => 'value']; + $loader = new ArrayChoiceLoader([$object]); - $this->assertSame(['value' => 'value'], $this->factory->createListFromLoader($loader, new PropertyPath('property'))->getChoices()); + $this->assertSame(['value' => $object], $this->factory->createListFromLoader($loader, new PropertyPath('property'))->getChoices()); } public function testCreateViewPreferredChoicesAsPropertyPath() { - $list = $this->createMock(ChoiceListInterface::class); + $object = (object) ['preferred_choice' => true, 'view_label' => 'foo', 'view_index' => 'key', 'view_group' => 'bar', 'view_attribute' => ['baz' => 'foobar']]; + $list = new ArrayChoiceList([$object]); - $this->decoratedFactory->expects($this->once()) - ->method('createView') - ->with($list, $this->isInstanceOf(\Closure::class)) - ->willReturnCallback(function ($list, $preferred) { - return new ChoiceListView((array) $preferred((object) ['property' => true])); - }); - - $this->assertSame([true], $this->factory->createView($list, 'property')->choices); + $this->assertEquals([new ChoiceView($object, '0', '0')], $this->factory->createView($list, 'preferred_choice')->choices); + $this->assertEquals([new ChoiceView($object, '0', '0')], $this->factory->createView($list, 'preferred_choice')->preferredChoices); } public function testCreateViewPreferredChoicesAsPropertyPathInstance() { - $list = $this->createMock(ChoiceListInterface::class); - - $this->decoratedFactory->expects($this->once()) - ->method('createView') - ->with($list, $this->isInstanceOf(\Closure::class)) - ->willReturnCallback(function ($list, $preferred) { - return new ChoiceListView((array) $preferred((object) ['property' => true])); - }); + $object = (object) ['preferred_choice' => true, 'view_label' => 'foo', 'view_index' => 'key', 'view_group' => 'bar', 'view_attribute' => ['baz' => 'foobar']]; + $list = new ArrayChoiceList([$object]); - $this->assertSame([true], $this->factory->createView($list, 'property')->choices); + $this->assertEquals([new ChoiceView($object, '0', '0')], $this->factory->createView($list, new PropertyPath('preferred_choice'))->choices); + $this->assertEquals([new ChoiceView($object, '0', '0')], $this->factory->createView($list, new PropertyPath('preferred_choice'))->preferredChoices); } // https://github.com/symfony/symfony/issues/5494 public function testCreateViewAssumeNullIfPreferredChoicesPropertyPathUnreadable() { - $list = $this->createMock(ChoiceListInterface::class); + $object = (object) ['preferred_choice' => true, 'view_label' => 'foo', 'view_index' => 'key', 'view_group' => 'bar', 'view_attribute' => ['baz' => 'foobar']]; + $list = new ArrayChoiceList([$object]); - $this->decoratedFactory->expects($this->once()) - ->method('createView') - ->with($list, $this->isInstanceOf(\Closure::class)) - ->willReturnCallback(function ($list, $preferred) { - return new ChoiceListView((array) $preferred((object) ['category' => null])); - }); - - $this->assertSame([false], $this->factory->createView($list, 'category.preferred')->choices); + $this->assertEquals([new ChoiceView($object, '0', '0')], $this->factory->createView($list, new PropertyPath('preferred_choice.property'))->choices); + $this->assertEquals([], $this->factory->createView($list, new PropertyPath('preferred_choice.property'))->preferredChoices); } public function testCreateViewLabelsAsPropertyPath() { - $list = $this->createMock(ChoiceListInterface::class); - - $this->decoratedFactory->expects($this->once()) - ->method('createView') - ->with($list, null, $this->isInstanceOf(\Closure::class)) - ->willReturnCallback(function ($list, $preferred, $label) { - return new ChoiceListView((array) $label((object) ['property' => 'label'])); - }); + $object = (object) ['preferred_choice' => true, 'view_label' => 'foo', 'view_index' => 'key', 'view_group' => 'bar', 'view_attribute' => ['baz' => 'foobar']]; + $list = new ArrayChoiceList([$object]); - $this->assertSame(['label'], $this->factory->createView($list, null, 'property')->choices); + $this->assertEquals([new ChoiceView($object, '0', 'foo')], $this->factory->createView($list, null, 'view_label')->choices); } public function testCreateViewLabelsAsPropertyPathInstance() { - $list = $this->createMock(ChoiceListInterface::class); - - $this->decoratedFactory->expects($this->once()) - ->method('createView') - ->with($list, null, $this->isInstanceOf(\Closure::class)) - ->willReturnCallback(function ($list, $preferred, $label) { - return new ChoiceListView((array) $label((object) ['property' => 'label'])); - }); + $object = (object) ['preferred_choice' => true, 'view_label' => 'foo', 'view_index' => 'key', 'view_group' => 'bar', 'view_attribute' => ['baz' => 'foobar']]; + $list = new ArrayChoiceList([$object]); - $this->assertSame(['label'], $this->factory->createView($list, null, new PropertyPath('property'))->choices); + $this->assertEquals([new ChoiceView($object, '0', 'foo')], $this->factory->createView($list, null, new PropertyPath('view_label'))->choices); } public function testCreateViewIndicesAsPropertyPath() { - $list = $this->createMock(ChoiceListInterface::class); + $object = (object) ['preferred_choice' => true, 'view_label' => 'foo', 'view_index' => 'key', 'view_group' => 'bar', 'view_attribute' => ['baz' => 'foobar']]; + $list = new ArrayChoiceList([$object]); - $this->decoratedFactory->expects($this->once()) - ->method('createView') - ->with($list, null, null, $this->isInstanceOf(\Closure::class)) - ->willReturnCallback(function ($list, $preferred, $label, $index) { - return new ChoiceListView((array) $index((object) ['property' => 'index'])); - }); - - $this->assertSame(['index'], $this->factory->createView($list, null, null, 'property')->choices); + $this->assertEquals(['key' => new ChoiceView($object, '0', '0')], $this->factory->createView($list, null, null, 'view_index')->choices); } public function testCreateViewIndicesAsPropertyPathInstance() { - $list = $this->createMock(ChoiceListInterface::class); - - $this->decoratedFactory->expects($this->once()) - ->method('createView') - ->with($list, null, null, $this->isInstanceOf(\Closure::class)) - ->willReturnCallback(function ($list, $preferred, $label, $index) { - return new ChoiceListView((array) $index((object) ['property' => 'index'])); - }); + $object = (object) ['preferred_choice' => true, 'view_label' => 'foo', 'view_index' => 'key', 'view_group' => 'bar', 'view_attribute' => ['baz' => 'foobar']]; + $list = new ArrayChoiceList([$object]); - $this->assertSame(['index'], $this->factory->createView($list, null, null, new PropertyPath('property'))->choices); + $this->assertEquals(['key' => new ChoiceView($object, '0', '0')], $this->factory->createView($list, null, null, new PropertyPath('view_index'))->choices); } public function testCreateViewGroupsAsPropertyPath() { - $list = $this->createMock(ChoiceListInterface::class); + $object = (object) ['preferred_choice' => true, 'view_label' => 'foo', 'view_index' => 'key', 'view_group' => 'bar', 'view_attribute' => ['baz' => 'foobar']]; + $list = new ArrayChoiceList([$object]); - $this->decoratedFactory->expects($this->once()) - ->method('createView') - ->with($list, null, null, null, $this->isInstanceOf(\Closure::class)) - ->willReturnCallback(function ($list, $preferred, $label, $index, $groupBy) { - return new ChoiceListView((array) $groupBy((object) ['property' => 'group'])); - }); - - $this->assertSame(['group'], $this->factory->createView($list, null, null, null, 'property')->choices); + $this->assertEquals(['bar' => new ChoiceGroupView('bar', [new ChoiceView($object, '0', '0')])], $this->factory->createView($list, null, null, null, 'view_group')->choices); } public function testCreateViewGroupsAsPropertyPathInstance() { - $list = $this->createMock(ChoiceListInterface::class); - - $this->decoratedFactory->expects($this->once()) - ->method('createView') - ->with($list, null, null, null, $this->isInstanceOf(\Closure::class)) - ->willReturnCallback(function ($list, $preferred, $label, $index, $groupBy) { - return new ChoiceListView((array) $groupBy((object) ['property' => 'group'])); - }); + $object = (object) ['preferred_choice' => true, 'view_label' => 'foo', 'view_index' => 'key', 'view_group' => 'bar', 'view_attribute' => ['baz' => 'foobar']]; + $list = new ArrayChoiceList([$object]); - $this->assertSame(['group'], $this->factory->createView($list, null, null, null, new PropertyPath('property'))->choices); + $this->assertEquals(['bar' => new ChoiceGroupView('bar', [new ChoiceView($object, '0', '0')])], $this->factory->createView($list, null, null, null, new PropertyPath('view_group'))->choices); } // https://github.com/symfony/symfony/issues/5494 public function testCreateViewAssumeNullIfGroupsPropertyPathUnreadable() { - $list = $this->createMock(ChoiceListInterface::class); - - $this->decoratedFactory->expects($this->once()) - ->method('createView') - ->with($list, null, null, null, $this->isInstanceOf(\Closure::class)) - ->willReturnCallback(function ($list, $preferred, $label, $index, $groupBy) { - return new ChoiceListView((array) $groupBy((object) ['group' => null])); - }); + $list = new ArrayChoiceList([]); $this->assertSame([], $this->factory->createView($list, null, null, null, 'group.name')->choices); } public function testCreateViewAttrAsPropertyPath() { - $list = $this->createMock(ChoiceListInterface::class); + $object = (object) ['preferred_choice' => true, 'view_label' => 'foo', 'view_index' => 'key', 'view_group' => 'bar', 'view_attribute' => ['baz' => 'foobar']]; + $list = new ArrayChoiceList([$object]); - $this->decoratedFactory->expects($this->once()) - ->method('createView') - ->with($list, null, null, null, null, $this->isInstanceOf(\Closure::class)) - ->willReturnCallback(function ($list, $preferred, $label, $index, $groupBy, $attr) { - return new ChoiceListView((array) $attr((object) ['property' => 'attr'])); - }); - - $this->assertSame(['attr'], $this->factory->createView($list, null, null, null, null, 'property')->choices); + $this->assertEquals([new ChoiceView($object, '0', '0', ['baz' => 'foobar'])], $this->factory->createView($list, null, null, null, null, 'view_attribute')->choices); } public function testCreateViewAttrAsPropertyPathInstance() { - $list = $this->createMock(ChoiceListInterface::class); - - $this->decoratedFactory->expects($this->once()) - ->method('createView') - ->with($list, null, null, null, null, $this->isInstanceOf(\Closure::class)) - ->willReturnCallback(function ($list, $preferred, $label, $index, $groupBy, $attr) { - return new ChoiceListView((array) $attr((object) ['property' => 'attr'])); - }); + $object = (object) ['preferred_choice' => true, 'view_label' => 'foo', 'view_index' => 'key', 'view_group' => 'bar', 'view_attribute' => ['baz' => 'foobar']]; + $list = new ArrayChoiceList([$object]); - $this->assertSame(['attr'], $this->factory->createView($list, null, null, null, null, new PropertyPath('property'))->choices); + $this->assertEquals([new ChoiceView($object, '0', '0', ['baz' => 'foobar'])], $this->factory->createView($list, null, null, null, null, new PropertyPath('view_attribute'))->choices); } } diff --git a/src/Symfony/Component/Form/Tests/ChoiceList/LazyChoiceListTest.php b/src/Symfony/Component/Form/Tests/ChoiceList/LazyChoiceListTest.php index 0c74ae1896d79..6f30d0896e1ba 100644 --- a/src/Symfony/Component/Form/Tests/ChoiceList/LazyChoiceListTest.php +++ b/src/Symfony/Component/Form/Tests/ChoiceList/LazyChoiceListTest.php @@ -11,155 +11,129 @@ namespace Symfony\Component\Form\Tests\ChoiceList; -use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; -use Symfony\Component\Form\ChoiceList\ChoiceListInterface; use Symfony\Component\Form\ChoiceList\LazyChoiceList; -use Symfony\Component\Form\ChoiceList\Loader\ChoiceLoaderInterface; +use Symfony\Component\Form\Tests\Fixtures\ArrayChoiceLoader; /** * @author Bernhard Schussek */ class LazyChoiceListTest extends TestCase { - /** - * @var LazyChoiceList - */ - private $list; - - /** - * @var MockObject&ChoiceListInterface - */ - private $loadedList; - - /** - * @var MockObject&ChoiceLoaderInterface - */ - private $loader; - - /** - * @var \Closure - */ - private $value; - - protected function setUp(): void - { - $this->loadedList = $this->createMock(ChoiceListInterface::class); - $this->loader = $this->createMock(ChoiceLoaderInterface::class); - $this->value = function () {}; - $this->list = new LazyChoiceList($this->loader, $this->value); - } - public function testGetChoiceLoadersLoadsLoadedListOnFirstCall() { - $this->loader->expects($this->exactly(2)) - ->method('loadChoiceList') - ->with($this->value) - ->willReturn($this->loadedList); - - // The same list is returned by the loader - $this->loadedList->expects($this->exactly(2)) - ->method('getChoices') - ->willReturn(['RESULT']); - - $this->assertSame(['RESULT'], $this->list->getChoices()); - $this->assertSame(['RESULT'], $this->list->getChoices()); + $choices = ['RESULT']; + $calls = 0; + $list = new LazyChoiceList(new ArrayChoiceLoader($choices), function ($choice) use ($choices, &$calls) { + ++$calls; + + return array_search($choice, $choices); + }); + + $this->assertSame(['RESULT'], $list->getChoices()); + $this->assertSame(['RESULT'], $list->getChoices()); + $this->assertSame(1, $calls); } public function testGetValuesLoadsLoadedListOnFirstCall() { - $this->loader->expects($this->exactly(2)) - ->method('loadChoiceList') - ->with($this->value) - ->willReturn($this->loadedList); - - // The same list is returned by the loader - $this->loadedList->expects($this->exactly(2)) - ->method('getValues') - ->willReturn(['RESULT']); - - $this->assertSame(['RESULT'], $this->list->getValues()); - $this->assertSame(['RESULT'], $this->list->getValues()); + $calls = 0; + $list = new LazyChoiceList(new ArrayChoiceLoader(['RESULT']), function ($choice) use (&$calls) { + ++$calls; + + return $choice; + }); + + $this->assertSame(['RESULT'], $list->getValues()); + $this->assertSame(['RESULT'], $list->getValues()); + $this->assertSame(1, $calls); } public function testGetStructuredValuesLoadsLoadedListOnFirstCall() { - $this->loader->expects($this->exactly(2)) - ->method('loadChoiceList') - ->with($this->value) - ->willReturn($this->loadedList); - - // The same list is returned by the loader - $this->loadedList->expects($this->exactly(2)) - ->method('getStructuredValues') - ->willReturn(['RESULT']); - - $this->assertSame(['RESULT'], $this->list->getStructuredValues()); - $this->assertSame(['RESULT'], $this->list->getStructuredValues()); + $calls = 0; + $list = new LazyChoiceList(new ArrayChoiceLoader(['RESULT']), function ($choice) use (&$calls) { + ++$calls; + + return $choice; + }); + + $this->assertSame(['RESULT'], $list->getStructuredValues()); + $this->assertSame(['RESULT'], $list->getStructuredValues()); + $this->assertSame(1, $calls); } public function testGetOriginalKeysLoadsLoadedListOnFirstCall() { - $this->loader->expects($this->exactly(2)) - ->method('loadChoiceList') - ->with($this->value) - ->willReturn($this->loadedList); - - // The same list is returned by the loader - $this->loadedList->expects($this->exactly(2)) - ->method('getOriginalKeys') - ->willReturn(['RESULT']); - - $this->assertSame(['RESULT'], $this->list->getOriginalKeys()); - $this->assertSame(['RESULT'], $this->list->getOriginalKeys()); + $calls = 0; + $choices = [ + 'a' => 'foo', + 'b' => 'bar', + 'c' => 'baz', + ]; + $list = new LazyChoiceList(new ArrayChoiceLoader($choices), function ($choice) use (&$calls) { + ++$calls; + + return $choice; + }); + + $this->assertSame(['foo' => 'a', 'bar' => 'b', 'baz' => 'c'], $list->getOriginalKeys()); + $this->assertSame(['foo' => 'a', 'bar' => 'b', 'baz' => 'c'], $list->getOriginalKeys()); + $this->assertSame(3, $calls); } public function testGetChoicesForValuesForwardsCallIfListNotLoaded() { - $this->loader->expects($this->exactly(2)) - ->method('loadChoicesForValues') - ->with(['a', 'b']) - ->willReturn(['RESULT']); - - $this->assertSame(['RESULT'], $this->list->getChoicesForValues(['a', 'b'])); - $this->assertSame(['RESULT'], $this->list->getChoicesForValues(['a', 'b'])); + $calls = 0; + $choices = [ + 'a' => 'foo', + 'b' => 'bar', + 'c' => 'baz', + ]; + $list = new LazyChoiceList(new ArrayChoiceLoader($choices), function ($choice) use ($choices, &$calls) { + ++$calls; + + return array_search($choice, $choices); + }); + + $this->assertSame(['foo', 'bar'], $list->getChoicesForValues(['a', 'b'])); + $this->assertSame(['foo', 'bar'], $list->getChoicesForValues(['a', 'b'])); + $this->assertSame(3, $calls); } public function testGetChoicesForValuesUsesLoadedList() { - $this->loader->expects($this->exactly(1)) - ->method('loadChoiceList') - ->with($this->value) - ->willReturn($this->loadedList); - - $this->loader->expects($this->exactly(2)) - ->method('loadChoicesForValues') - ->with(['a', 'b']) - ->willReturn(['RESULT']); + $choices = [ + 'a' => 'foo', + 'b' => 'bar', + 'c' => 'baz', + ]; + $list = new LazyChoiceList(new ArrayChoiceLoader($choices), function ($choice) use ($choices) { + return array_search($choice, $choices); + }); // load choice list - $this->list->getChoices(); + $list->getChoices(); - $this->assertSame(['RESULT'], $this->list->getChoicesForValues(['a', 'b'])); - $this->assertSame(['RESULT'], $this->list->getChoicesForValues(['a', 'b'])); + $this->assertSame(['foo', 'bar'], $list->getChoicesForValues(['a', 'b'])); + $this->assertSame(['foo', 'bar'], $list->getChoicesForValues(['a', 'b'])); } public function testGetValuesForChoicesUsesLoadedList() { - $this->loader->expects($this->exactly(1)) - ->method('loadChoiceList') - ->with($this->value) - ->willReturn($this->loadedList); - - $this->loader->expects($this->exactly(2)) - ->method('loadValuesForChoices') - ->with(['a', 'b']) - ->willReturn(['RESULT']); + $choices = [ + 'a' => 'foo', + 'b' => 'bar', + 'c' => 'baz', + ]; + $list = new LazyChoiceList(new ArrayChoiceLoader($choices), function ($choice) use ($choices) { + return array_search($choice, $choices); + }); // load choice list - $this->list->getChoices(); + $list->getChoices(); - $this->assertSame(['RESULT'], $this->list->getValuesForChoices(['a', 'b'])); - $this->assertSame(['RESULT'], $this->list->getValuesForChoices(['a', 'b'])); + $this->assertSame(['a', 'b'], $list->getValuesForChoices(['foo', 'bar'])); + $this->assertSame(['a', 'b'], $list->getValuesForChoices(['foo', 'bar'])); } } diff --git a/src/Symfony/Component/Form/Tests/CompoundFormTest.php b/src/Symfony/Component/Form/Tests/CompoundFormTest.php index a6fd1a1e93c75..7f8548e7a4158 100644 --- a/src/Symfony/Component/Form/Tests/CompoundFormTest.php +++ b/src/Symfony/Component/Form/Tests/CompoundFormTest.php @@ -11,28 +11,50 @@ namespace Symfony\Component\Form\Tests; +use PHPUnit\Framework\TestCase; use Symfony\Component\EventDispatcher\EventDispatcher; use Symfony\Component\Form\Exception\AlreadySubmittedException; use Symfony\Component\Form\Extension\Core\DataMapper\PropertyPathMapper; +use Symfony\Component\Form\Extension\Core\Type\SubmitType; +use Symfony\Component\Form\Extension\Core\Type\TextType; use Symfony\Component\Form\Extension\HttpFoundation\HttpFoundationRequestHandler; -use Symfony\Component\Form\Form; +use Symfony\Component\Form\FormBuilder; use Symfony\Component\Form\FormError; use Symfony\Component\Form\FormErrorIterator; use Symfony\Component\Form\FormEvent; use Symfony\Component\Form\FormEvents; +use Symfony\Component\Form\FormFactory; +use Symfony\Component\Form\FormFactoryInterface; use Symfony\Component\Form\FormInterface; +use Symfony\Component\Form\FormRegistry; use Symfony\Component\Form\Forms; use Symfony\Component\Form\FormView; +use Symfony\Component\Form\ResolvedFormTypeFactory; use Symfony\Component\Form\ResolvedFormTypeInterface; -use Symfony\Component\Form\SubmitButton; use Symfony\Component\Form\SubmitButtonBuilder; use Symfony\Component\Form\Tests\Fixtures\FixedDataTransformer; -use Symfony\Component\Form\Util\InheritDataAwareIterator; +use Symfony\Component\Form\Tests\Fixtures\Map; use Symfony\Component\HttpFoundation\File\UploadedFile; use Symfony\Component\HttpFoundation\Request; -class CompoundFormTest extends AbstractFormTest +class CompoundFormTest extends TestCase { + /** + * @var FormFactoryInterface + */ + private $factory; + + /** + * @var FormInterface + */ + private $form; + + protected function setUp(): void + { + $this->factory = new FormFactory(new FormRegistry([], new ResolvedFormTypeFactory())); + $this->form = $this->createForm(); + } + public function testValidIfAllChildrenAreValid() { $this->form->add($this->getBuilder('firstName')->getForm()); @@ -66,7 +88,7 @@ public function testDisabledFormsValidEvenIfChildrenInvalid() $form = $this->getBuilder('person') ->setDisabled(true) ->setCompound(true) - ->setDataMapper($this->getDataMapper()) + ->setDataMapper(new PropertyPathMapper()) ->add($this->getBuilder('name')) ->getForm(); @@ -131,10 +153,12 @@ public function testClearMissingFlagIsForwarded() $personForm->add($firstNameForm); $lastNameForm = $this->createForm('lastName', false); - $lastNameForm->setData('last name'); $personForm->add($lastNameForm); $this->form->add($personForm); + + $this->form->setData(['person' => ['lastName' => 'last name']]); + $this->form->submit(['person' => ['firstName' => 'foo']], false); $this->assertTrue($firstNameForm->isSubmitted()); @@ -158,10 +182,10 @@ public function testCloneChildren() public function testNotEmptyIfChildNotEmpty() { $child = $this->createForm('name', false); - $child->setData('foo'); $this->form->setData(null); $this->form->add($child); + $child->setData('foo'); $this->assertFalse($this->form->isEmpty()); } @@ -178,101 +202,72 @@ public function testAdd() public function testAddUsingNameAndType() { - $child = $this->getBuilder('foo')->getForm(); + $this->form->add('foo', TextType::class); - $this->factory->expects($this->once()) - ->method('createNamed') - ->with('foo', 'Symfony\Component\Form\Extension\Core\Type\TextType', null, [ - 'bar' => 'baz', - 'auto_initialize' => false, - ]) - ->willReturn($child); + $this->assertTrue($this->form->has('foo')); - $this->form->add('foo', 'Symfony\Component\Form\Extension\Core\Type\TextType', ['bar' => 'baz']); + $child = $this->form->get('foo'); - $this->assertTrue($this->form->has('foo')); - $this->assertSame($this->form, $child->getParent()); + $this->assertInstanceOf(TextType::class, $child->getConfig()->getType()->getInnerType()); $this->assertSame(['foo' => $child], $this->form->all()); } public function testAddUsingIntegerNameAndType() { - $child = $this->getBuilder('0')->getForm(); - - $this->factory->expects($this->once()) - ->method('createNamed') - ->with('0', 'Symfony\Component\Form\Extension\Core\Type\TextType', null, [ - 'bar' => 'baz', - 'auto_initialize' => false, - ]) - ->willReturn($child); - // in order to make casting unnecessary - $this->form->add(0, 'Symfony\Component\Form\Extension\Core\Type\TextType', ['bar' => 'baz']); + $this->form->add(0, TextType::class); $this->assertTrue($this->form->has(0)); - $this->assertSame($this->form, $child->getParent()); + + $child = $this->form->get(0); + + $this->assertInstanceOf(TextType::class, $child->getConfig()->getType()->getInnerType()); $this->assertSame([0 => $child], $this->form->all()); } public function testAddWithoutType() { - $child = $this->getBuilder('foo')->getForm(); - - $this->factory->expects($this->once()) - ->method('createNamed') - ->with('foo', 'Symfony\Component\Form\Extension\Core\Type\TextType') - ->willReturn($child); - $this->form->add('foo'); $this->assertTrue($this->form->has('foo')); - $this->assertSame($this->form, $child->getParent()); + + $child = $this->form->get('foo'); + + $this->assertInstanceOf(TextType::class, $child->getConfig()->getType()->getInnerType()); $this->assertSame(['foo' => $child], $this->form->all()); } public function testAddUsingNameButNoType() { - $this->form = $this->getBuilder('name', null, \stdClass::class) + $this->form = $this->getBuilder('name', \stdClass::class) ->setCompound(true) - ->setDataMapper($this->getDataMapper()) + ->setDataMapper(new PropertyPathMapper()) ->getForm(); - $child = $this->getBuilder('foo')->getForm(); - - $this->factory->expects($this->once()) - ->method('createForProperty') - ->with(\stdClass::class, 'foo') - ->willReturn($child); - $this->form->add('foo'); $this->assertTrue($this->form->has('foo')); - $this->assertSame($this->form, $child->getParent()); + + $child = $this->form->get('foo'); + + $this->assertInstanceOf(TextType::class, $child->getConfig()->getType()->getInnerType()); $this->assertSame(['foo' => $child], $this->form->all()); } public function testAddUsingNameButNoTypeAndOptions() { - $this->form = $this->getBuilder('name', null, \stdClass::class) + $this->form = $this->getBuilder('name', \stdClass::class) ->setCompound(true) - ->setDataMapper($this->getDataMapper()) + ->setDataMapper(new PropertyPathMapper()) ->getForm(); - $child = $this->getBuilder('foo')->getForm(); + $this->form->add('foo'); - $this->factory->expects($this->once()) - ->method('createForProperty') - ->with(\stdClass::class, 'foo', null, [ - 'bar' => 'baz', - 'auto_initialize' => false, - ]) - ->willReturn($child); + $this->assertTrue($this->form->has('foo')); - $this->form->add('foo', null, ['bar' => 'baz']); + $child = $this->form->get('foo'); - $this->assertTrue($this->form->has('foo')); - $this->assertSame($this->form, $child->getParent()); + $this->assertInstanceOf(TextType::class, $child->getConfig()->getType()->getInnerType()); $this->assertSame(['foo' => $child], $this->form->all()); } @@ -340,60 +335,55 @@ public function testIterator() public function testAddMapsViewDataToFormIfInitialized() { - $mapper = $this->getDataMapper(); $form = $this->getBuilder() ->setCompound(true) - ->setDataMapper($mapper) - ->addViewTransformer(new FixedDataTransformer([ - '' => '', - 'foo' => 'bar', - ])) - ->setData('foo') + ->setDataMapper(new PropertyPathMapper()) + ->setData(['child' => 'foo']) ->getForm(); - $child = $this->getBuilder()->getForm(); - $mapper->expects($this->once()) - ->method('mapDataToForms') - ->with('bar', $this->isInstanceOf(\RecursiveIteratorIterator::class)) - ->willReturnCallback(function ($data, \RecursiveIteratorIterator $iterator) use ($child) { - $this->assertInstanceOf(InheritDataAwareIterator::class, $iterator->getInnerIterator()); - $this->assertSame([$child->getName() => $child], iterator_to_array($iterator)); - }); + $child = $this->getBuilder('child')->getForm(); + + $this->assertNull($child->getData()); $form->initialize(); $form->add($child); + + $this->assertSame('foo', $child->getData()); } public function testAddDoesNotMapViewDataToFormIfNotInitialized() { - $mapper = $this->getDataMapper(); $form = $this->getBuilder() ->setCompound(true) - ->setDataMapper($mapper) + ->setDataMapper(new PropertyPathMapper()) ->getForm(); $child = $this->getBuilder()->getForm(); - $mapper->expects($this->never()) - ->method('mapDataToForms'); $form->add($child); + + $this->assertNull($form->getData()); + $this->assertNull($form->getNormData()); + $this->assertNull($form->getViewData()); } public function testAddDoesNotMapViewDataToFormIfInheritData() { - $mapper = $this->getDataMapper(); $form = $this->getBuilder() ->setCompound(true) - ->setDataMapper($mapper) - ->setInheritData(true) + ->setDataMapper(new PropertyPathMapper()) ->getForm(); - $child = $this->getBuilder()->getForm(); - $mapper->expects($this->never()) - ->method('mapDataToForms'); + $child = $this->getBuilder() + ->setInheritData(true) + ->getForm(); $form->initialize(); $form->add($child); + + $this->assertNull($form->getData()); + $this->assertNull($form->getNormData()); + $this->assertNull($form->getViewData()); } public function testSetDataSupportsDynamicAdditionAndRemovalOfChildren() @@ -408,7 +398,7 @@ public function testSetDataSupportsDynamicAdditionAndRemovalOfChildren() $childToBeRemoved = $this->createForm('removed', false); $childToBeAdded = $this->createForm('added', false); - $child = $this->getBuilder('child', new EventDispatcher()) + $child = $this->getBuilder('child') ->setCompound(true) ->setDataMapper(new PropertyPathMapper()) ->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event) use ($form, $childToBeAdded) { @@ -429,28 +419,24 @@ public function testSetDataSupportsDynamicAdditionAndRemovalOfChildren() public function testSetDataMapsViewDataToChildren() { - $mapper = $this->getDataMapper(); $form = $this->getBuilder() ->setCompound(true) - ->setDataMapper($mapper) - ->addViewTransformer(new FixedDataTransformer([ - '' => '', - 'foo' => 'bar', - ])) + ->setDataMapper(new PropertyPathMapper()) ->getForm(); $form->add($child1 = $this->getBuilder('firstName')->getForm()); $form->add($child2 = $this->getBuilder('lastName')->getForm()); - $mapper->expects($this->once()) - ->method('mapDataToForms') - ->with('bar', $this->isInstanceOf(\RecursiveIteratorIterator::class)) - ->willReturnCallback(function ($data, \RecursiveIteratorIterator $iterator) use ($child1, $child2) { - $this->assertInstanceOf(InheritDataAwareIterator::class, $iterator->getInnerIterator()); - $this->assertSame(['firstName' => $child1, 'lastName' => $child2], iterator_to_array($iterator)); - }); + $this->assertNull($child1->getData()); + $this->assertNull($child2->getData()); - $form->setData('foo'); + $form->setData([ + 'firstName' => 'foo', + 'lastName' => 'bar', + ]); + + $this->assertSame('foo', $child1->getData()); + $this->assertSame('bar', $child2->getData()); } public function testSetDataDoesNotMapViewDataToChildrenWithLockedSetData() @@ -503,59 +489,49 @@ public function testSubmitSupportsDynamicAdditionAndRemovalOfChildren() public function testSubmitMapsSubmittedChildrenOntoExistingViewData() { - $mapper = $this->getDataMapper(); $form = $this->getBuilder() ->setCompound(true) - ->setDataMapper($mapper) - ->addViewTransformer(new FixedDataTransformer([ - '' => '', - 'foo' => 'bar', - ])) - ->setData('foo') + ->setDataMapper(new PropertyPathMapper()) + ->setData([ + 'firstName' => null, + 'lastName' => null, + ]) ->getForm(); $form->add($child1 = $this->getBuilder('firstName')->setCompound(false)->getForm()); $form->add($child2 = $this->getBuilder('lastName')->setCompound(false)->getForm()); - $mapper->expects($this->once()) - ->method('mapFormsToData') - ->with($this->isInstanceOf(\RecursiveIteratorIterator::class), 'bar') - ->willReturnCallback(function (\RecursiveIteratorIterator $iterator) use ($child1, $child2) { - $this->assertInstanceOf(InheritDataAwareIterator::class, $iterator->getInnerIterator()); - $this->assertSame(['firstName' => $child1, 'lastName' => $child2], iterator_to_array($iterator)); - $this->assertEquals('Bernhard', $child1->getData()); - $this->assertEquals('Schussek', $child2->getData()); - }); + $this->assertSame(['firstName' => null, 'lastName' => null], $form->getData()); $form->submit([ 'firstName' => 'Bernhard', 'lastName' => 'Schussek', ]); + + $this->assertSame(['firstName' => 'Bernhard', 'lastName' => 'Schussek'], $form->getData()); } public function testMapFormsToDataIsNotInvokedIfInheritData() { - $mapper = $this->getDataMapper(); $form = $this->getBuilder() ->setCompound(true) - ->setDataMapper($mapper) - ->setInheritData(true) - ->addViewTransformer(new FixedDataTransformer([ - '' => '', - 'foo' => 'bar', - ])) + ->setDataMapper(new PropertyPathMapper()) ->getForm(); - $form->add($child1 = $this->getBuilder('firstName')->setCompound(false)->getForm()); - $form->add($child2 = $this->getBuilder('lastName')->setCompound(false)->getForm()); - - $mapper->expects($this->never()) - ->method('mapFormsToData'); + $form->add($child1 = $this->getBuilder('firstName')->setCompound(false)->setInheritData(true)->getForm()); + $form->add($child2 = $this->getBuilder('lastName')->setCompound(false)->setInheritData(true)->getForm()); $form->submit([ 'firstName' => 'Bernhard', 'lastName' => 'Schussek', ]); + + $this->assertNull($child1->getData()); + $this->assertNull($child1->getNormData()); + $this->assertNull($child1->getViewData()); + $this->assertNull($child2->getData()); + $this->assertNull($child2->getNormData()); + $this->assertNull($child2->getViewData()); } /* @@ -563,11 +539,10 @@ public function testMapFormsToDataIsNotInvokedIfInheritData() */ public function testSubmitRestoresViewDataIfCompoundAndEmpty() { - $mapper = $this->getDataMapper(); $object = new \stdClass(); - $form = $this->getBuilder('name', null, 'stdClass') + $form = $this->getBuilder('name', \stdClass::class) ->setCompound(true) - ->setDataMapper($mapper) + ->setDataMapper(new PropertyPathMapper()) ->setData($object) ->getForm(); @@ -578,28 +553,21 @@ public function testSubmitRestoresViewDataIfCompoundAndEmpty() public function testSubmitMapsSubmittedChildrenOntoEmptyData() { - $mapper = $this->getDataMapper(); - $object = new \stdClass(); + $object = new Map(); $form = $this->getBuilder() ->setCompound(true) - ->setDataMapper($mapper) + ->setDataMapper(new PropertyPathMapper()) ->setEmptyData($object) ->setData(null) ->getForm(); $form->add($child = $this->getBuilder('name')->setCompound(false)->getForm()); - $mapper->expects($this->once()) - ->method('mapFormsToData') - ->with($this->isInstanceOf(\RecursiveIteratorIterator::class), $object) - ->willReturnCallback(function (\RecursiveIteratorIterator $iterator) use ($child) { - $this->assertInstanceOf(InheritDataAwareIterator::class, $iterator->getInnerIterator()); - $this->assertSame(['name' => $child], iterator_to_array($iterator)); - }); - $form->submit([ 'name' => 'Bernhard', ]); + + $this->assertSame('Bernhard', $object['name']); } public function requestMethodProvider() @@ -644,7 +612,7 @@ public function testSubmitPostOrPutRequest($method) $form = $this->getBuilder('author') ->setMethod($method) ->setCompound(true) - ->setDataMapper($this->getDataMapper()) + ->setDataMapper(new PropertyPathMapper()) ->setRequestHandler(new HttpFoundationRequestHandler()) ->getForm(); $form->add($this->getBuilder('name')->getForm()); @@ -691,7 +659,7 @@ public function testSubmitPostOrPutRequestWithEmptyRootFormName($method) $form = $this->getBuilder('') ->setMethod($method) ->setCompound(true) - ->setDataMapper($this->getDataMapper()) + ->setDataMapper(new PropertyPathMapper()) ->setRequestHandler(new HttpFoundationRequestHandler()) ->getForm(); $form->add($this->getBuilder('name')->getForm()); @@ -731,7 +699,7 @@ public function testSubmitPostOrPutRequestWithSingleChildForm($method) 'REQUEST_METHOD' => $method, ]); - $form = $this->getBuilder('image', null, null, ['allow_file_upload' => true]) + $form = $this->getBuilder('image', null, ['allow_file_upload' => true]) ->setMethod($method) ->setRequestHandler(new HttpFoundationRequestHandler()) ->getForm(); @@ -790,7 +758,7 @@ public function testSubmitGetRequest() $form = $this->getBuilder('author') ->setMethod('GET') ->setCompound(true) - ->setDataMapper($this->getDataMapper()) + ->setDataMapper(new PropertyPathMapper()) ->setRequestHandler(new HttpFoundationRequestHandler()) ->getForm(); $form->add($this->getBuilder('firstName')->getForm()); @@ -817,7 +785,7 @@ public function testSubmitGetRequestWithEmptyRootFormName() $form = $this->getBuilder('') ->setMethod('GET') ->setCompound(true) - ->setDataMapper($this->getDataMapper()) + ->setDataMapper(new PropertyPathMapper()) ->setRequestHandler(new HttpFoundationRequestHandler()) ->getForm(); $form->add($this->getBuilder('firstName')->getForm()); @@ -966,9 +934,9 @@ public function testCreateViewWithChildren() ->method('createView') ->willReturn($field2View); - $this->form = $this->getBuilder('form', null, null, $options) + $this->form = $this->getBuilder('form', null, $options) ->setCompound(true) - ->setDataMapper($this->getDataMapper()) + ->setDataMapper(new PropertyPathMapper()) ->setType($type) ->getForm(); $this->form->add($field1); @@ -1002,20 +970,11 @@ public function testNoClickedButtonBeforeSubmission() public function testNoClickedButton() { - $button = $this->getMockBuilder(SubmitButton::class) - ->setConstructorArgs([new SubmitButtonBuilder('submit')]) - ->setMethods(['isClicked']) - ->getMock(); - - $button->expects($this->any()) - ->method('isClicked') - ->willReturn(false); - $parentForm = $this->getBuilder('parent')->getForm(); $nestedForm = $this->getBuilder('nested')->getForm(); $this->form->setParent($parentForm); - $this->form->add($button); + $this->form->add($this->factory->create(SubmitType::class)); $this->form->add($nestedForm); $this->form->submit([]); @@ -1024,55 +983,41 @@ public function testNoClickedButton() public function testClickedButton() { - $button = $this->getMockBuilder(SubmitButton::class) - ->setConstructorArgs([new SubmitButtonBuilder('submit')]) - ->setMethods(['isClicked']) - ->getMock(); - - $button->expects($this->any()) - ->method('isClicked') - ->willReturn(true); + $button = $this->factory->create(SubmitType::class); $this->form->add($button); - $this->form->submit([]); + $this->form->submit(['submit' => '']); $this->assertSame($button, $this->form->getClickedButton()); } public function testClickedButtonFromNestedForm() { - $button = $this->getBuilder('submit')->getForm(); - - $nestedForm = $this->getMockBuilder(Form::class) - ->setConstructorArgs([$this->getBuilder('nested')]) - ->setMethods(['getClickedButton']) - ->getMock(); + $button = $this->factory->create(SubmitType::class); - $nestedForm->expects($this->any()) - ->method('getClickedButton') - ->willReturn($button); + $nestedForm = $this->createForm('nested'); + $nestedForm->add($button); $this->form->add($nestedForm); - $this->form->submit([]); + $this->form->submit([ + 'nested' => [ + 'submit' => '', + ], + ]); $this->assertSame($button, $this->form->getClickedButton()); } public function testClickedButtonFromParentForm() { - $button = $this->getBuilder('submit')->getForm(); - - $parentForm = $this->getMockBuilder(Form::class) - ->setConstructorArgs([$this->getBuilder('parent')]) - ->setMethods(['getClickedButton']) - ->getMock(); - - $parentForm->expects($this->any()) - ->method('getClickedButton') - ->willReturn($button); + $button = $this->factory->create(SubmitType::class); - $this->form->setParent($parentForm); - $this->form->submit([]); + $parentForm = $this->createForm(''); + $parentForm->add($this->form); + $parentForm->add($button); + $parentForm->submit([ + 'submit' => '', + ]); $this->assertSame($button, $this->form->getClickedButton()); } @@ -1102,7 +1047,7 @@ public function testDisabledButtonIsNotSubmitted() public function testArrayTransformationFailureOnSubmit() { $this->form->add($this->getBuilder('foo')->setCompound(false)->getForm()); - $this->form->add($this->getBuilder('bar', null, null, ['multiple' => false])->setCompound(false)->getForm()); + $this->form->add($this->getBuilder('bar', null, ['multiple' => false])->setCompound(false)->getForm()); $this->form->submit([ 'foo' => ['foo'], @@ -1130,17 +1075,22 @@ public function testFileUpload() $this->assertNull($this->form->get('bar')->getData()); } - protected function createForm(string $name = 'name', bool $compound = true): FormInterface + private function createForm(string $name = 'name', bool $compound = true): FormInterface { $builder = $this->getBuilder($name); if ($compound) { $builder ->setCompound(true) - ->setDataMapper($this->getDataMapper()) + ->setDataMapper(new PropertyPathMapper()) ; } return $builder->getForm(); } + + private function getBuilder(string $name = 'name', string $dataClass = null, array $options = []): FormBuilder + { + return new FormBuilder($name, $dataClass, new EventDispatcher(), $this->factory, $options); + } } diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/BaseDateTimeTransformerTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/BaseDateTimeTransformerTest.php index f6d4226e5bef9..e3f101a8aac96 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/BaseDateTimeTransformerTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/BaseDateTimeTransformerTest.php @@ -15,19 +15,21 @@ use Symfony\Component\Form\Exception\InvalidArgumentException; use Symfony\Component\Form\Extension\Core\DataTransformer\BaseDateTimeTransformer; -class BaseDateTimeTransformerTest extends TestCase +abstract class BaseDateTimeTransformerTest extends TestCase { public function testConstructFailsIfInputTimezoneIsInvalid() { $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessage('this_timezone_does_not_exist'); - $this->getMockBuilder(BaseDateTimeTransformer::class)->setConstructorArgs(['this_timezone_does_not_exist'])->getMock(); + $this->createDateTimeTransformer('this_timezone_does_not_exist'); } public function testConstructFailsIfOutputTimezoneIsInvalid() { $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessage('that_timezone_does_not_exist'); - $this->getMockBuilder(BaseDateTimeTransformer::class)->setConstructorArgs([null, 'that_timezone_does_not_exist'])->getMock(); + $this->createDateTimeTransformer(null, 'that_timezone_does_not_exist'); } + + abstract protected function createDateTimeTransformer(string $inputTimezone = null, string $outputTimezone = null): BaseDateTimeTransformer; } diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DataTransformerChainTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DataTransformerChainTest.php index 307667b1f75f2..30be21e590dec 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DataTransformerChainTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DataTransformerChainTest.php @@ -12,43 +12,27 @@ namespace Symfony\Component\Form\Tests\Extension\Core\DataTransformer; use PHPUnit\Framework\TestCase; -use Symfony\Component\Form\DataTransformerInterface; use Symfony\Component\Form\Extension\Core\DataTransformer\DataTransformerChain; +use Symfony\Component\Form\Tests\Fixtures\FixedDataTransformer; class DataTransformerChainTest extends TestCase { public function testTransform() { - $transformer1 = $this->createMock(DataTransformerInterface::class); - $transformer1->expects($this->once()) - ->method('transform') - ->with($this->identicalTo('foo')) - ->willReturn('bar'); - $transformer2 = $this->createMock(DataTransformerInterface::class); - $transformer2->expects($this->once()) - ->method('transform') - ->with($this->identicalTo('bar')) - ->willReturn('baz'); - - $chain = new DataTransformerChain([$transformer1, $transformer2]); + $chain = new DataTransformerChain([ + new FixedDataTransformer(['foo' => 'bar']), + new FixedDataTransformer(['bar' => 'baz']), + ]); $this->assertEquals('baz', $chain->transform('foo')); } public function testReverseTransform() { - $transformer2 = $this->createMock(DataTransformerInterface::class); - $transformer2->expects($this->once()) - ->method('reverseTransform') - ->with($this->identicalTo('foo')) - ->willReturn('bar'); - $transformer1 = $this->createMock(DataTransformerInterface::class); - $transformer1->expects($this->once()) - ->method('reverseTransform') - ->with($this->identicalTo('bar')) - ->willReturn('baz'); - - $chain = new DataTransformerChain([$transformer1, $transformer2]); + $chain = new DataTransformerChain([ + new FixedDataTransformer(['baz' => 'bar']), + new FixedDataTransformer(['bar' => 'foo']), + ]); $this->assertEquals('baz', $chain->reverseTransform('foo')); } diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateTimeToArrayTransformerTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateTimeToArrayTransformerTest.php index 3ebfb9d1b51f8..3aafbec88a4ec 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateTimeToArrayTransformerTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateTimeToArrayTransformerTest.php @@ -11,11 +11,11 @@ namespace Symfony\Component\Form\Tests\Extension\Core\DataTransformer; -use PHPUnit\Framework\TestCase; use Symfony\Component\Form\Exception\TransformationFailedException; +use Symfony\Component\Form\Extension\Core\DataTransformer\BaseDateTimeTransformer; use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeToArrayTransformer; -class DateTimeToArrayTransformerTest extends TestCase +class DateTimeToArrayTransformerTest extends BaseDateTimeTransformerTest { public function testTransform() { @@ -535,4 +535,9 @@ public function testReverseTransformWithEmptyStringSecond() 'second' => '', ]); } + + protected function createDateTimeTransformer(string $inputTimezone = null, string $outputTimezone = null): BaseDateTimeTransformer + { + return new DateTimeToArrayTransformer($inputTimezone, $outputTimezone); + } } diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateTimeToHtml5LocalDateTimeTransformerTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateTimeToHtml5LocalDateTimeTransformerTest.php index 2e4b4ba7e696c..6e6e66afb1861 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateTimeToHtml5LocalDateTimeTransformerTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateTimeToHtml5LocalDateTimeTransformerTest.php @@ -11,12 +11,12 @@ namespace Symfony\Component\Form\Tests\Extension\Core\DataTransformer; -use PHPUnit\Framework\TestCase; use Symfony\Component\Form\Exception\TransformationFailedException; +use Symfony\Component\Form\Extension\Core\DataTransformer\BaseDateTimeTransformer; use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeToHtml5LocalDateTimeTransformer; use Symfony\Component\Form\Tests\Extension\Core\DataTransformer\Traits\DateTimeEqualsTrait; -class DateTimeToHtml5LocalDateTimeTransformerTest extends TestCase +class DateTimeToHtml5LocalDateTimeTransformerTest extends BaseDateTimeTransformerTest { use DateTimeEqualsTrait; @@ -115,4 +115,9 @@ public function testReverseTransformExpectsValidDateString() $transformer->reverseTransform('2010-2010-2010'); } + + protected function createDateTimeTransformer(string $inputTimezone = null, string $outputTimezone = null): BaseDateTimeTransformer + { + return new DateTimeToHtml5LocalDateTimeTransformer($inputTimezone, $outputTimezone); + } } diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateTimeToLocalizedStringTransformerTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateTimeToLocalizedStringTransformerTest.php index cde7cd531a892..ece8df76b2318 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateTimeToLocalizedStringTransformerTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateTimeToLocalizedStringTransformerTest.php @@ -11,13 +11,13 @@ namespace Symfony\Component\Form\Tests\Extension\Core\DataTransformer; -use PHPUnit\Framework\TestCase; use Symfony\Component\Form\Exception\TransformationFailedException; +use Symfony\Component\Form\Extension\Core\DataTransformer\BaseDateTimeTransformer; use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeToLocalizedStringTransformer; use Symfony\Component\Form\Tests\Extension\Core\DataTransformer\Traits\DateTimeEqualsTrait; use Symfony\Component\Intl\Util\IntlTestHelper; -class DateTimeToLocalizedStringTransformerTest extends TestCase +class DateTimeToLocalizedStringTransformerTest extends BaseDateTimeTransformerTest { use DateTimeEqualsTrait; @@ -372,4 +372,9 @@ public function testReverseTransformWrapsIntlErrorsWithExceptionsAndErrorLevel() $transformer = new DateTimeToLocalizedStringTransformer(); $transformer->reverseTransform('12345'); } + + protected function createDateTimeTransformer(string $inputTimezone = null, string $outputTimezone = null): BaseDateTimeTransformer + { + return new DateTimeToLocalizedStringTransformer($inputTimezone, $outputTimezone); + } } diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateTimeToRfc3339TransformerTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateTimeToRfc3339TransformerTest.php index 0c28ac50951cd..eccaa22a136f3 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateTimeToRfc3339TransformerTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateTimeToRfc3339TransformerTest.php @@ -11,12 +11,12 @@ namespace Symfony\Component\Form\Tests\Extension\Core\DataTransformer; -use PHPUnit\Framework\TestCase; use Symfony\Component\Form\Exception\TransformationFailedException; +use Symfony\Component\Form\Extension\Core\DataTransformer\BaseDateTimeTransformer; use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeToRfc3339Transformer; use Symfony\Component\Form\Tests\Extension\Core\DataTransformer\Traits\DateTimeEqualsTrait; -class DateTimeToRfc3339TransformerTest extends TestCase +class DateTimeToRfc3339TransformerTest extends BaseDateTimeTransformerTest { use DateTimeEqualsTrait; @@ -143,4 +143,9 @@ public function invalidDateStringProvider() 'RSS format' => ['Sat, 01 May 2010 04:05:00 +0000'], ]; } + + protected function createDateTimeTransformer(string $inputTimezone = null, string $outputTimezone = null): BaseDateTimeTransformer + { + return new DateTimeToRfc3339Transformer($inputTimezone, $outputTimezone); + } } diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateTimeToStringTransformerTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateTimeToStringTransformerTest.php index dc01ba15503d9..a7299e67ba237 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateTimeToStringTransformerTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateTimeToStringTransformerTest.php @@ -11,11 +11,11 @@ namespace Symfony\Component\Form\Tests\Extension\Core\DataTransformer; -use PHPUnit\Framework\TestCase; use Symfony\Component\Form\Exception\TransformationFailedException; +use Symfony\Component\Form\Extension\Core\DataTransformer\BaseDateTimeTransformer; use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeToStringTransformer; -class DateTimeToStringTransformerTest extends TestCase +class DateTimeToStringTransformerTest extends BaseDateTimeTransformerTest { public function dataProvider(): array { @@ -170,4 +170,9 @@ public function testReverseTransformWithNonExistingDate() $reverseTransformer->reverseTransform('2010-04-31'); } + + protected function createDateTimeTransformer(string $inputTimezone = null, string $outputTimezone = null): BaseDateTimeTransformer + { + return new DateTimeToStringTransformer($inputTimezone, $outputTimezone); + } } diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateTimeToTimestampTransformerTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateTimeToTimestampTransformerTest.php index b02be9a168b87..7a84153a73834 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateTimeToTimestampTransformerTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateTimeToTimestampTransformerTest.php @@ -11,11 +11,11 @@ namespace Symfony\Component\Form\Tests\Extension\Core\DataTransformer; -use PHPUnit\Framework\TestCase; use Symfony\Component\Form\Exception\TransformationFailedException; +use Symfony\Component\Form\Extension\Core\DataTransformer\BaseDateTimeTransformer; use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeToTimestampTransformer; -class DateTimeToTimestampTransformerTest extends TestCase +class DateTimeToTimestampTransformerTest extends BaseDateTimeTransformerTest { public function testTransform() { @@ -114,4 +114,9 @@ public function testReverseTransformExpectsValidTimestamp() $reverseTransformer->reverseTransform('2010-2010-2010'); } + + protected function createDateTimeTransformer(string $inputTimezone = null, string $outputTimezone = null): BaseDateTimeTransformer + { + return new DateTimeToTimestampTransformer($inputTimezone, $outputTimezone); + } } diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/PercentToLocalizedStringTransformerTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/PercentToLocalizedStringTransformerTest.php index c4817538d0737..95f1fe2db314f 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/PercentToLocalizedStringTransformerTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/PercentToLocalizedStringTransformerTest.php @@ -220,17 +220,7 @@ public function testDecimalSeparatorMayNotBeCommaIfGroupingSeparatorIsCommaWithN public function testDecimalSeparatorMayBeCommaIfGroupingSeparatorIsCommaButNoGroupingUsed() { - $formatter = new \NumberFormatter(\Locale::getDefault(), \NumberFormatter::DECIMAL); - $formatter->setAttribute(\NumberFormatter::FRACTION_DIGITS, 1); - $formatter->setAttribute(\NumberFormatter::GROUPING_USED, false); - - $transformer = $this->getMockBuilder(PercentToLocalizedStringTransformer::class) - ->setMethods(['getNumberFormatter']) - ->setConstructorArgs([1, 'integer']) - ->getMock(); - $transformer->expects($this->any()) - ->method('getNumberFormatter') - ->willReturn($formatter); + $transformer = new PercentToLocalizedStringTransformerWithoutGrouping(1, 'integer'); $this->assertEquals(1234.5, $transformer->reverseTransform('1234,5')); $this->assertEquals(1234.5, $transformer->reverseTransform('1234.5')); @@ -296,3 +286,14 @@ public function testReverseTransformDisallowsTrailingExtraCharactersMultibyte() $transformer->reverseTransform("12\xc2\xa0345,678foo"); } } + +class PercentToLocalizedStringTransformerWithoutGrouping extends PercentToLocalizedStringTransformer +{ + protected function getNumberFormatter(): \NumberFormatter + { + $formatter = parent::getNumberFormatter(); + $formatter->setAttribute(\NumberFormatter::GROUPING_USED, false); + + return $formatter; + } +} diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/Type/FileTypeTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/Type/FileTypeTest.php index 5db5e9e8ab92a..5ca5267430681 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Core/Type/FileTypeTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Core/Type/FileTypeTest.php @@ -17,7 +17,7 @@ use Symfony\Component\Form\RequestHandlerInterface; use Symfony\Component\HttpFoundation\File\File; use Symfony\Component\HttpFoundation\File\UploadedFile; -use Symfony\Contracts\Translation\TranslatorInterface; +use Symfony\Component\Translation\IdentityTranslator; class FileTypeTest extends BaseTypeTest { @@ -25,10 +25,7 @@ class FileTypeTest extends BaseTypeTest protected function getExtensions() { - $translator = $this->createMock(TranslatorInterface::class); - $translator->expects($this->any())->method('trans')->willReturnArgument(0); - - return array_merge(parent::getExtensions(), [new CoreExtension(null, null, $translator)]); + return array_merge(parent::getExtensions(), [new CoreExtension(null, null, new IdentityTranslator())]); } // https://github.com/symfony/symfony/pull/5028 @@ -210,7 +207,7 @@ public function testFailedFileUploadIsTurnedIntoFormErrorUsingHttpFoundationRequ $this->assertTrue($form->isValid()); } else { $this->assertFalse($form->isValid()); - $this->assertSame($expectedErrorMessage, $form->getErrors()[0]->getMessage()); + $this->assertMatchesRegularExpression($expectedErrorMessage, $form->getErrors()[0]->getMessage()); } } @@ -235,7 +232,7 @@ public function testFailedFileUploadIsTurnedIntoFormErrorUsingNativeRequestHandl $this->assertTrue($form->isValid()); } else { $this->assertFalse($form->isValid()); - $this->assertSame($expectedErrorMessage, $form->getErrors()[0]->getMessage()); + $this->assertMatchesRegularExpression($expectedErrorMessage, $form->getErrors()[0]->getMessage()); } } @@ -261,8 +258,8 @@ public function testMultipleSubmittedFailedFileUploadsAreTurnedIntoFormErrorUsin } else { $this->assertFalse($form->isValid()); $this->assertCount(2, $form->getErrors()); - $this->assertSame($expectedErrorMessage, $form->getErrors()[0]->getMessage()); - $this->assertSame($expectedErrorMessage, $form->getErrors()[1]->getMessage()); + $this->assertMatchesRegularExpression($expectedErrorMessage, $form->getErrors()[0]->getMessage()); + $this->assertMatchesRegularExpression($expectedErrorMessage, $form->getErrors()[1]->getMessage()); } } @@ -299,8 +296,8 @@ public function testMultipleSubmittedFailedFileUploadsAreTurnedIntoFormErrorUsin } else { $this->assertFalse($form->isValid()); $this->assertCount(2, $form->getErrors()); - $this->assertSame($expectedErrorMessage, $form->getErrors()[0]->getMessage()); - $this->assertSame($expectedErrorMessage, $form->getErrors()[1]->getMessage()); + $this->assertMatchesRegularExpression($expectedErrorMessage, $form->getErrors()[0]->getMessage()); + $this->assertMatchesRegularExpression($expectedErrorMessage, $form->getErrors()[1]->getMessage()); } } @@ -308,13 +305,13 @@ public function uploadFileErrorCodes() { return [ 'no error' => [\UPLOAD_ERR_OK, null], - 'upload_max_filesize ini directive' => [\UPLOAD_ERR_INI_SIZE, 'The file is too large. Allowed maximum size is {{ limit }} {{ suffix }}.'], - 'MAX_FILE_SIZE from form' => [\UPLOAD_ERR_FORM_SIZE, 'The file is too large.'], - 'partially uploaded' => [\UPLOAD_ERR_PARTIAL, 'The file could not be uploaded.'], - 'no file upload' => [\UPLOAD_ERR_NO_FILE, 'The file could not be uploaded.'], - 'missing temporary directory' => [\UPLOAD_ERR_NO_TMP_DIR, 'The file could not be uploaded.'], - 'write failure' => [\UPLOAD_ERR_CANT_WRITE, 'The file could not be uploaded.'], - 'stopped by extension' => [\UPLOAD_ERR_EXTENSION, 'The file could not be uploaded.'], + 'upload_max_filesize ini directive' => [\UPLOAD_ERR_INI_SIZE, '/The file is too large. Allowed maximum size is \d+ \S+\./'], + 'MAX_FILE_SIZE from form' => [\UPLOAD_ERR_FORM_SIZE, '/The file is too large\./'], + 'partially uploaded' => [\UPLOAD_ERR_PARTIAL, '/The file could not be uploaded\./'], + 'no file upload' => [\UPLOAD_ERR_NO_FILE, '/The file could not be uploaded\./'], + 'missing temporary directory' => [\UPLOAD_ERR_NO_TMP_DIR, '/The file could not be uploaded\./'], + 'write failure' => [\UPLOAD_ERR_CANT_WRITE, '/The file could not be uploaded\./'], + 'stopped by extension' => [\UPLOAD_ERR_EXTENSION, '/The file could not be uploaded\./'], ]; } diff --git a/src/Symfony/Component/Form/Tests/Extension/Csrf/EventListener/CsrfValidationListenerTest.php b/src/Symfony/Component/Form/Tests/Extension/Csrf/EventListener/CsrfValidationListenerTest.php index fc0ae8e45de83..43c94a329be9c 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Csrf/EventListener/CsrfValidationListenerTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Csrf/EventListener/CsrfValidationListenerTest.php @@ -76,17 +76,18 @@ public function testArrayCsrfToken() public function testMaxPostSizeExceeded() { - $serverParams = $this->createMock(ServerParams::class); - $serverParams - ->expects($this->once()) - ->method('hasPostMaxSizeBeenExceeded') - ->willReturn(true) - ; - $event = new FormEvent($this->form, ['csrf' => 'token']); - $validation = new CsrfValidationListener('csrf', $this->tokenManager, 'unknown', 'Error message', null, null, $serverParams); + $validation = new CsrfValidationListener('csrf', $this->tokenManager, 'unknown', 'Error message', null, null, new ServerParamsPostMaxSizeExceeded()); $validation->preSubmit($event); $this->assertEmpty($this->form->getErrors()); } } + +class ServerParamsPostMaxSizeExceeded extends ServerParams +{ + public function hasPostMaxSizeBeenExceeded(): bool + { + return true; + } +} diff --git a/src/Symfony/Component/Form/Tests/Extension/Csrf/Type/FormTypeCsrfExtensionTest.php b/src/Symfony/Component/Form/Tests/Extension/Csrf/Type/FormTypeCsrfExtensionTest.php index 0adaab003b290..b8e2cf7bcacc6 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Csrf/Type/FormTypeCsrfExtensionTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Csrf/Type/FormTypeCsrfExtensionTest.php @@ -19,7 +19,7 @@ use Symfony\Component\Form\Test\TypeTestCase; use Symfony\Component\Security\Csrf\CsrfToken; use Symfony\Component\Security\Csrf\CsrfTokenManagerInterface; -use Symfony\Contracts\Translation\TranslatorInterface; +use Symfony\Component\Translation\IdentityTranslator; class FormTypeCsrfExtensionTest_ChildType extends AbstractType { @@ -38,32 +38,17 @@ class FormTypeCsrfExtensionTest extends TypeTestCase */ protected $tokenManager; - /** - * @var MockObject&TranslatorInterface - */ - protected $translator; - protected function setUp(): void { $this->tokenManager = $this->createMock(CsrfTokenManagerInterface::class); - $this->translator = $this->createMock(TranslatorInterface::class); - $this->translator->expects($this->any())->method('trans')->willReturnArgument(0); parent::setUp(); } - protected function tearDown(): void - { - $this->tokenManager = null; - $this->translator = null; - - parent::tearDown(); - } - protected function getExtensions() { return array_merge(parent::getExtensions(), [ - new CsrfExtension($this->tokenManager, $this->translator), + new CsrfExtension($this->tokenManager, new IdentityTranslator()), ]); } diff --git a/src/Symfony/Component/Form/Tests/Extension/DataCollector/DataCollectorExtensionTest.php b/src/Symfony/Component/Form/Tests/Extension/DataCollector/DataCollectorExtensionTest.php index 9c02d2aff1d3f..0ae127d0775d1 100644 --- a/src/Symfony/Component/Form/Tests/Extension/DataCollector/DataCollectorExtensionTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/DataCollector/DataCollectorExtensionTest.php @@ -11,10 +11,10 @@ namespace Symfony\Component\Form\Tests\Extension\DataCollector; -use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; use Symfony\Component\Form\Extension\DataCollector\DataCollectorExtension; -use Symfony\Component\Form\Extension\DataCollector\FormDataCollectorInterface; +use Symfony\Component\Form\Extension\DataCollector\FormDataCollector; +use Symfony\Component\Form\Extension\DataCollector\FormDataExtractor; use Symfony\Component\Form\Extension\DataCollector\Type\DataCollectorTypeExtension; class DataCollectorExtensionTest extends TestCase @@ -24,15 +24,9 @@ class DataCollectorExtensionTest extends TestCase */ private $extension; - /** - * @var MockObject&FormDataCollectorInterface - */ - private $dataCollector; - protected function setUp(): void { - $this->dataCollector = $this->createMock(FormDataCollectorInterface::class); - $this->extension = new DataCollectorExtension($this->dataCollector); + $this->extension = new DataCollectorExtension(new FormDataCollector(new FormDataExtractor())); } public function testLoadTypeExtensions() diff --git a/src/Symfony/Component/Form/Tests/Extension/DataCollector/FormDataCollectorTest.php b/src/Symfony/Component/Form/Tests/Extension/DataCollector/FormDataCollectorTest.php index fd5ac459a6524..520f707f14df6 100644 --- a/src/Symfony/Component/Form/Tests/Extension/DataCollector/FormDataCollectorTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/DataCollector/FormDataCollectorTest.php @@ -11,18 +11,15 @@ namespace Symfony\Component\Form\Tests\Extension\DataCollector; -use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; -use Symfony\Component\EventDispatcher\EventDispatcher; use Symfony\Component\Form\Extension\Core\CoreExtension; -use Symfony\Component\Form\Extension\Core\DataMapper\PropertyPathMapper; use Symfony\Component\Form\Extension\Core\Type\CollectionType; use Symfony\Component\Form\Extension\Core\Type\FormType; use Symfony\Component\Form\Extension\Core\Type\TextType; use Symfony\Component\Form\Extension\DataCollector\FormDataCollector; -use Symfony\Component\Form\Extension\DataCollector\FormDataExtractorInterface; +use Symfony\Component\Form\Extension\DataCollector\FormDataExtractor; use Symfony\Component\Form\Form; -use Symfony\Component\Form\FormBuilder; +use Symfony\Component\Form\FormError; use Symfony\Component\Form\FormFactory; use Symfony\Component\Form\FormInterface; use Symfony\Component\Form\FormRegistry; @@ -31,31 +28,16 @@ class FormDataCollectorTest extends TestCase { - /** - * @var MockObject&FormDataExtractorInterface - */ - private $dataExtractor; - /** * @var FormDataCollector */ private $dataCollector; - /** - * @var EventDispatcher - */ - private $dispatcher; - /** * @var FormFactory */ private $factory; - /** - * @var PropertyPathMapper - */ - private $dataMapper; - /** * @var Form */ @@ -78,13 +60,10 @@ class FormDataCollectorTest extends TestCase protected function setUp(): void { - $this->dataExtractor = $this->createMock(FormDataExtractorInterface::class); - $this->dataCollector = new FormDataCollector($this->dataExtractor); - $this->dispatcher = new EventDispatcher(); + $this->dataCollector = new FormDataCollector(new FormDataExtractor()); $this->factory = new FormFactory(new FormRegistry([new CoreExtension()], new ResolvedFormTypeFactory())); - $this->dataMapper = new PropertyPathMapper(); $this->form = $this->createForm('name'); - $this->childForm = $this->createForm('child'); + $this->childForm = $this->createChildForm('child'); $this->view = new FormView(); $this->childView = new FormView(); } @@ -93,62 +72,51 @@ public function testBuildPreliminaryFormTree() { $this->form->add($this->childForm); - $this->dataExtractor->expects($this->exactly(2)) - ->method('extractConfiguration') - ->withConsecutive( - [$this->form], - [$this->childForm] - ) - ->willReturnOnConsecutiveCalls( - ['config' => 'foo'], - ['config' => 'bar'] - ); - - $this->dataExtractor->expects($this->exactly(2)) - ->method('extractDefaultData') - ->withConsecutive( - [$this->form], - [$this->childForm] - ) - ->willReturnOnConsecutiveCalls( - ['default_data' => 'foo'], - ['default_data' => 'bar'] - ); - - $this->dataExtractor->expects($this->exactly(2)) - ->method('extractSubmittedData') - ->withConsecutive( - [$this->form], - [$this->childForm] - ) - ->willReturnOnConsecutiveCalls( - ['submitted_data' => 'foo'], - ['submitted_data' => 'bar'] - ); - $this->dataCollector->collectConfiguration($this->form); $this->dataCollector->collectDefaultData($this->form); $this->dataCollector->collectSubmittedData($this->form); $this->dataCollector->buildPreliminaryFormTree($this->form); $childFormData = [ - 'config' => 'bar', - 'default_data' => 'bar', - 'submitted_data' => 'bar', - 'children' => [], + 'id' => 'name_child', + 'name' => 'child', + 'type_class' => FormType::class, + 'synchronized' => true, + 'passed_options' => [], + 'resolved_options' => $this->childForm->getConfig()->getOptions(), + 'default_data' => [ + 'norm' => null, + 'view' => '', + ], + 'submitted_data' => [ + 'norm' => null, + 'view' => '', + ], + 'errors' => [], + 'children' => [], ]; $formData = [ - 'config' => 'foo', - 'default_data' => 'foo', - 'submitted_data' => 'foo', + 'id' => 'name', + 'name' => 'name', + 'type_class' => FormType::class, + 'synchronized' => true, + 'passed_options' => [], + 'resolved_options' => $this->form->getConfig()->getOptions(), + 'default_data' => [ + 'norm' => null, + ], + 'submitted_data' => [ + 'norm' => null, + ], + 'errors' => [], 'has_children_error' => false, 'children' => [ 'child' => $childFormData, ], ]; - $this->assertSame([ + $this->assertEquals([ 'forms' => [ 'name' => $formData, ], @@ -165,27 +133,21 @@ public function testBuildMultiplePreliminaryFormTrees() $form1 = $this->createForm('form1'); $form2 = $this->createForm('form2'); - $this->dataExtractor->expects($this->exactly(2)) - ->method('extractConfiguration') - ->withConsecutive( - [$form1], - [$form2] - ) - ->willReturnOnConsecutiveCalls( - ['config' => 'foo'], - ['config' => 'bar'] - ); - $this->dataCollector->collectConfiguration($form1); $this->dataCollector->collectConfiguration($form2); $this->dataCollector->buildPreliminaryFormTree($form1); $form1Data = [ - 'config' => 'foo', + 'id' => 'form1', + 'name' => 'form1', + 'type_class' => FormType::class, + 'synchronized' => true, + 'passed_options' => [], + 'resolved_options' => $form1->getConfig()->getOptions(), 'children' => [], ]; - $this->assertSame([ + $this->assertEquals([ 'forms' => [ 'form1' => $form1Data, ], @@ -198,11 +160,16 @@ public function testBuildMultiplePreliminaryFormTrees() $this->dataCollector->buildPreliminaryFormTree($form2); $form2Data = [ - 'config' => 'bar', + 'id' => 'form2', + 'name' => 'form2', + 'type_class' => FormType::class, + 'synchronized' => true, + 'passed_options' => [], + 'resolved_options' => $form2->getConfig()->getOptions(), 'children' => [], ]; - $this->assertSame([ + $this->assertEquals([ 'forms' => [ 'form1' => $form1Data, 'form2' => $form2Data, @@ -217,25 +184,20 @@ public function testBuildMultiplePreliminaryFormTrees() public function testBuildSamePreliminaryFormTreeMultipleTimes() { - $this->dataExtractor - ->method('extractConfiguration') - ->with($this->form) - ->willReturn(['config' => 'foo']); - - $this->dataExtractor - ->method('extractDefaultData') - ->with($this->form) - ->willReturn(['default_data' => 'foo']); - $this->dataCollector->collectConfiguration($this->form); $this->dataCollector->buildPreliminaryFormTree($this->form); $formData = [ - 'config' => 'foo', + 'id' => 'name', + 'name' => 'name', + 'type_class' => FormType::class, + 'synchronized' => true, + 'passed_options' => [], + 'resolved_options' => $this->form->getConfig()->getOptions(), 'children' => [], ]; - $this->assertSame([ + $this->assertEquals([ 'forms' => [ 'name' => $formData, ], @@ -249,12 +211,20 @@ public function testBuildSamePreliminaryFormTreeMultipleTimes() $this->dataCollector->buildPreliminaryFormTree($this->form); $formData = [ - 'config' => 'foo', - 'default_data' => 'foo', + 'id' => 'name', + 'name' => 'name', + 'type_class' => FormType::class, + 'synchronized' => true, + 'passed_options' => [], + 'resolved_options' => $this->form->getConfig()->getOptions(), + 'default_data' => [ + 'norm' => null, + ], + 'submitted_data' => [], 'children' => [], ]; - $this->assertSame([ + $this->assertEquals([ 'forms' => [ 'name' => $formData, ], @@ -273,7 +243,7 @@ public function testBuildPreliminaryFormTreeWithoutCollectingAnyData() 'children' => [], ]; - $this->assertSame([ + $this->assertEquals([ 'forms' => [ 'name' => $formData, ], @@ -289,50 +259,6 @@ public function testBuildFinalFormTree() $this->form->add($this->childForm); $this->view->children['child'] = $this->childView; - $this->dataExtractor->expects($this->exactly(2)) - ->method('extractConfiguration') - ->withConsecutive( - [$this->form], - [$this->childForm] - ) - ->willReturnOnConsecutiveCalls( - ['config' => 'foo'], - ['config' => 'bar'] - ); - - $this->dataExtractor->expects($this->exactly(2)) - ->method('extractDefaultData') - ->withConsecutive( - [$this->form], - [$this->childForm] - ) - ->willReturnOnConsecutiveCalls( - ['default_data' => 'foo'], - ['default_data' => 'bar'] - ); - - $this->dataExtractor->expects($this->exactly(2)) - ->method('extractSubmittedData') - ->withConsecutive( - [$this->form], - [$this->childForm] - ) - ->willReturnOnConsecutiveCalls( - ['submitted_data' => 'foo'], - ['submitted_data' => 'bar'] - ); - - $this->dataExtractor->expects($this->exactly(2)) - ->method('extractViewVariables') - ->withConsecutive( - [$this->view], - [$this->childView] - ) - ->willReturnOnConsecutiveCalls( - ['view_vars' => 'foo'], - ['view_vars' => 'bar'] - ); - $this->dataCollector->collectConfiguration($this->form); $this->dataCollector->collectDefaultData($this->form); $this->dataCollector->collectSubmittedData($this->form); @@ -340,25 +266,53 @@ public function testBuildFinalFormTree() $this->dataCollector->buildFinalFormTree($this->form, $this->view); $childFormData = [ - 'view_vars' => 'bar', - 'config' => 'bar', - 'default_data' => 'bar', - 'submitted_data' => 'bar', + 'id' => 'name_child', + 'name' => 'child', + 'type_class' => FormType::class, + 'synchronized' => true, + 'passed_options' => [], + 'resolved_options' => $this->childForm->getConfig()->getOptions(), + 'default_data' => [ + 'norm' => null, + 'view' => '', + ], + 'submitted_data' => [ + 'norm' => null, + 'view' => '', + ], + 'errors' => [], + 'view_vars' => [ + 'attr' => [], + 'value' => null, + ], 'children' => [], ]; $formData = [ - 'view_vars' => 'foo', - 'config' => 'foo', - 'default_data' => 'foo', - 'submitted_data' => 'foo', + 'id' => 'name', + 'name' => 'name', + 'type_class' => FormType::class, + 'synchronized' => true, + 'passed_options' => [], + 'resolved_options' => $this->form->getConfig()->getOptions(), + 'default_data' => [ + 'norm' => null, + ], + 'submitted_data' => [ + 'norm' => null, + ], + 'errors' => [], + 'view_vars' => [ + 'attr' => [], + 'value' => null, + ], 'has_children_error' => false, 'children' => [ 'child' => $childFormData, ], ]; - $this->assertSame([ + $this->assertEquals([ 'forms' => [ 'name' => $formData, ], @@ -372,9 +326,11 @@ public function testBuildFinalFormTree() public function testSerializeWithFormAddedMultipleTimes() { + $this->expectNotToPerformAssertions(); + $form1 = $this->createForm('form1'); $form2 = $this->createForm('form2'); - $child1 = $this->createForm('child1'); + $child1 = $this->createChildForm('child1'); $form1View = new FormView(); $form2View = new FormView(); @@ -389,66 +345,6 @@ public function testSerializeWithFormAddedMultipleTimes() $form1View->children['child1'] = $child1View; $form2View->children['child1'] = $child1View; - $this->dataExtractor->expects($this->exactly(4)) - ->method('extractConfiguration') - ->withConsecutive( - [$form1], - [$child1], - [$form2], - [$child1] - ) - ->willReturnOnConsecutiveCalls( - ['config' => 'foo'], - ['config' => 'bar'], - ['config' => 'foo'], - ['config' => 'bar'] - ); - - $this->dataExtractor->expects($this->exactly(4)) - ->method('extractDefaultData') - ->withConsecutive( - [$form1], - [$child1], - [$form2], - [$child1] - ) - ->willReturnOnConsecutiveCalls( - ['default_data' => 'foo'], - ['default_data' => 'bar'], - ['default_data' => 'foo'], - ['default_data' => 'bar'] - ); - - $this->dataExtractor->expects($this->exactly(4)) - ->method('extractSubmittedData') - ->withConsecutive( - [$form1], - [$child1], - [$form2], - [$child1] - ) - ->willReturnOnConsecutiveCalls( - ['submitted_data' => 'foo'], - ['submitted_data' => 'bar'], - ['submitted_data' => 'foo'], - ['submitted_data' => 'bar'] - ); - - $this->dataExtractor->expects($this->exactly(4)) - ->method('extractViewVariables') - ->withConsecutive( - [$form1View], - [$child1View], - [$form2View], - [$child1View] - ) - ->willReturnOnConsecutiveCalls( - ['view_vars' => 'foo'], - ['view_vars' => $child1View->vars], - ['view_vars' => 'foo'], - ['view_vars' => $child1View->vars] - ); - $this->dataCollector->collectConfiguration($form1); $this->dataCollector->collectDefaultData($form1); $this->dataCollector->collectSubmittedData($form1); @@ -466,8 +362,8 @@ public function testSerializeWithFormAddedMultipleTimes() public function testFinalFormReliesOnFormViewStructure() { - $this->form->add($child1 = $this->createForm('first')); - $this->form->add($child2 = $this->createForm('second')); + $this->form->add($child1 = $this->createChildForm('first')); + $this->form->add($child2 = $this->createChildForm('second')); $this->view->children['second'] = $this->childView; @@ -488,7 +384,7 @@ public function testFinalFormReliesOnFormViewStructure() ], ]; - $this->assertSame([ + $this->assertEquals([ 'forms' => [ 'name' => $formData, ], @@ -509,7 +405,7 @@ public function testFinalFormReliesOnFormViewStructure() ], ]; - $this->assertSame([ + $this->assertEquals([ 'forms' => [ 'name' => $formData, ], @@ -528,17 +424,6 @@ public function testChildViewsCanBeWithoutCorrespondingChildForms() $this->view->children['child'] = $this->childView; - $this->dataExtractor->expects($this->exactly(2)) - ->method('extractConfiguration') - ->withConsecutive( - [$this->form], - [$this->childForm] - ) - ->willReturnOnConsecutiveCalls( - ['config' => 'foo'], - ['config' => 'bar'] - ); - // explicitly call collectConfiguration(), since $this->childForm is not // contained in the form tree $this->dataCollector->collectConfiguration($this->form); @@ -551,13 +436,18 @@ public function testChildViewsCanBeWithoutCorrespondingChildForms() ]; $formData = [ - 'config' => 'foo', + 'id' => 'name', + 'name' => 'name', + 'type_class' => FormType::class, + 'synchronized' => true, + 'passed_options' => [], + 'resolved_options' => $this->form->getConfig()->getOptions(), 'children' => [ 'child' => $childFormData, ], ]; - $this->assertSame([ + $this->assertEquals([ 'forms' => [ 'name' => $formData, ], @@ -578,17 +468,6 @@ public function testChildViewsWithoutCorrespondingChildFormsMayBeExplicitlyAssoc // but associate the two $this->dataCollector->associateFormWithView($this->childForm, $this->childView); - $this->dataExtractor->expects($this->exactly(2)) - ->method('extractConfiguration') - ->withConsecutive( - [$this->form], - [$this->childForm] - ) - ->willReturnOnConsecutiveCalls( - ['config' => 'foo'], - ['config' => 'bar'] - ); - // explicitly call collectConfiguration(), since $this->childForm is not // contained in the form tree $this->dataCollector->collectConfiguration($this->form); @@ -596,18 +475,28 @@ public function testChildViewsWithoutCorrespondingChildFormsMayBeExplicitlyAssoc $this->dataCollector->buildFinalFormTree($this->form, $this->view); $childFormData = [ - 'config' => 'bar', + 'id' => 'child', + 'name' => 'child', + 'type_class' => FormType::class, + 'synchronized' => true, + 'passed_options' => [], + 'resolved_options' => $this->childForm->getConfig()->getOptions(), 'children' => [], ]; $formData = [ - 'config' => 'foo', + 'id' => 'name', + 'name' => 'name', + 'type_class' => FormType::class, + 'synchronized' => true, + 'passed_options' => [], + 'resolved_options' => $this->form->getConfig()->getOptions(), 'children' => [ 'child' => $childFormData, ], ]; - $this->assertSame([ + $this->assertEquals([ 'forms' => [ 'name' => $formData, ], @@ -622,28 +511,15 @@ public function testChildViewsWithoutCorrespondingChildFormsMayBeExplicitlyAssoc public function testCollectSubmittedDataCountsErrors() { $form1 = $this->createForm('form1'); - $childForm1 = $this->createForm('child1'); + $childForm1 = $this->createChildForm('child1'); $form2 = $this->createForm('form2'); $form1->add($childForm1); - $this->dataExtractor - ->method('extractConfiguration') - ->willReturn([]); - $this->dataExtractor - ->method('extractDefaultData') - ->willReturn([]); - $this->dataExtractor->expects($this->exactly(3)) - ->method('extractSubmittedData') - ->withConsecutive( - [$form1], - [$childForm1], - [$form2] - ) - ->willReturnOnConsecutiveCalls( - ['errors' => ['foo']], - ['errors' => ['bar', 'bam']], - ['errors' => ['baz']] - ); + + $form1->addError(new FormError('foo')); + $childForm1->addError(new FormError('bar')); + $childForm1->addError(new FormError('bam')); + $form2->addError(new FormError('baz')); $this->dataCollector->collectSubmittedData($form1); @@ -658,38 +534,17 @@ public function testCollectSubmittedDataCountsErrors() public function testCollectSubmittedDataExpandedFormsErrors() { - $child1Form = $this->createForm('child1'); - $child11Form = $this->createForm('child11'); - $child2Form = $this->createForm('child2'); - $child21Form = $this->createForm('child21'); + $child1Form = $this->createChildForm('child1', true); + $child11Form = $this->createChildForm('child11'); + $child2Form = $this->createChildForm('child2', true); + $child21Form = $this->createChildForm('child21'); $child1Form->add($child11Form); $child2Form->add($child21Form); $this->form->add($child1Form); $this->form->add($child2Form); - $this->dataExtractor - ->method('extractConfiguration') - ->willReturn([]); - $this->dataExtractor - ->method('extractDefaultData') - ->willReturn([]); - $this->dataExtractor->expects($this->exactly(5)) - ->method('extractSubmittedData') - ->withConsecutive( - [$this->form], - [$child1Form], - [$child11Form], - [$child2Form], - [$child21Form] - ) - ->willReturnOnConsecutiveCalls( - ['errors' => []], - ['errors' => []], - ['errors' => ['foo']], - ['errors' => []], - ['errors' => []] - ); + $child11Form->addError(new FormError('foo')); $this->dataCollector->collectSubmittedData($this->form); $this->dataCollector->buildPreliminaryFormTree($this->form); @@ -712,20 +567,18 @@ public function testReset() { $form = $this->createForm('my_form'); - $this->dataExtractor->expects($this->any()) - ->method('extractConfiguration') - ->willReturn([]); - $this->dataExtractor->expects($this->any()) - ->method('extractDefaultData') - ->willReturn([]); - $this->dataExtractor->expects($this->any()) - ->method('extractSubmittedData') - ->with($form) - ->willReturn(['errors' => ['baz']]); - $this->dataCollector->buildPreliminaryFormTree($form); $this->dataCollector->collectSubmittedData($form); + $this->assertNotSame( + [ + 'forms' => [], + 'forms_by_hash' => [], + 'nb_errors' => 0, + ], + $this->dataCollector->getData() + ); + $this->dataCollector->reset(); $this->assertSame( @@ -753,47 +606,45 @@ public function testCollectMissingDataFromChildFormAddedOnFormEvents() ]) ->getForm() ; - $this->dataExtractor->expects($extractConfiguration = $this->exactly(4)) - ->method('extractConfiguration') - ->willReturn([]) - ; - $this->dataExtractor->expects($extractDefaultData = $this->exactly(4)) - ->method('extractDefaultData') - ->willReturnCallback(static function (FormInterface $form) { - // this simulate the call in extractDefaultData() method - // where (if defaultDataSet is false) it fires *_SET_DATA - // events, adding the form related to the configured data - $form->getNormData(); - - return []; - }) - ; - $this->dataExtractor->expects($this->exactly(4)) - ->method('extractSubmittedData') - ->willReturn([]) - ; $this->dataCollector->collectConfiguration($form); - $this->assertSame(2, $extractConfiguration->getInvocationCount(), 'only "root" and "items" forms were collected, the "items" children do not exist yet.'); + $this->dataCollector->buildPreliminaryFormTree($form); + $data = $this->dataCollector->getData(); + $this->assertCount(2, $data['forms_by_hash'], 'only "root" and "items" forms were collected, the "items" children do not exist yet.'); + + foreach ($data['forms_by_hash'] as $formData) { + $this->assertArrayNotHasKey('default_data', $formData); + } $this->dataCollector->collectDefaultData($form); - $this->assertSame(3, $extractConfiguration->getInvocationCount(), 'extracted missing configuration of the "items" children ["0" => foo].'); - $this->assertSame(3, $extractDefaultData->getInvocationCount()); + $this->dataCollector->buildPreliminaryFormTree($form); + $data = $this->dataCollector->getData(); + $this->assertCount(3, $data['forms_by_hash'], 'extracted missing configuration of the "items" children ["0" => foo].'); $this->assertSame(['foo'], $form->get('items')->getData()); + foreach ($data['forms_by_hash'] as $formData) { + $this->assertArrayHasKey('default_data', $formData); + } + $form->submit(['items' => ['foo', 'bar']]); $this->dataCollector->collectSubmittedData($form); - $this->assertSame(4, $extractConfiguration->getInvocationCount(), 'extracted missing configuration of the "items" children ["1" => bar].'); - $this->assertSame(4, $extractDefaultData->getInvocationCount(), 'extracted missing default data of the "items" children ["1" => bar].'); + $this->dataCollector->buildPreliminaryFormTree($form); + $data = $this->dataCollector->getData(); + $this->assertCount(4, $data['forms_by_hash'], 'extracted missing configuration of the "items" children ["1" => bar].'); $this->assertSame(['foo', 'bar'], $form->get('items')->getData()); + + foreach ($data['forms_by_hash'] as $formData) { + $this->assertArrayHasKey('default_data', $formData); + } } - private function createForm($name) + private function createForm(string $name): FormInterface { - $builder = new FormBuilder($name, null, $this->dispatcher, $this->factory); - $builder->setCompound(true); - $builder->setDataMapper($this->dataMapper); + return $this->factory->createNamedBuilder($name)->getForm(); + } - return $builder->getForm(); + private function createChildForm(string $name, bool $compound = false): FormInterface + { + return $this->factory->createNamedBuilder($name, FormType::class, null, ['auto_initialize' => false, 'compound' => $compound])->getForm(); } } diff --git a/src/Symfony/Component/Form/Tests/Extension/DataCollector/FormDataExtractorTest.php b/src/Symfony/Component/Form/Tests/Extension/DataCollector/FormDataExtractorTest.php index 10f624b1d823b..edbb185f6673f 100644 --- a/src/Symfony/Component/Form/Tests/Extension/DataCollector/FormDataExtractorTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/DataCollector/FormDataExtractorTest.php @@ -11,19 +11,20 @@ namespace Symfony\Component\Form\Tests\Extension\DataCollector; -use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; -use Symfony\Component\EventDispatcher\EventDispatcherInterface; +use Symfony\Component\EventDispatcher\EventDispatcher; use Symfony\Component\Form\CallbackTransformer; -use Symfony\Component\Form\DataMapperInterface; use Symfony\Component\Form\Exception\TransformationFailedException; +use Symfony\Component\Form\Extension\Core\DataMapper\PropertyPathMapper; use Symfony\Component\Form\Extension\Core\Type\HiddenType; use Symfony\Component\Form\Extension\DataCollector\FormDataExtractor; use Symfony\Component\Form\FormBuilder; use Symfony\Component\Form\FormError; -use Symfony\Component\Form\FormFactoryInterface; +use Symfony\Component\Form\FormFactory; +use Symfony\Component\Form\FormRegistry; use Symfony\Component\Form\FormView; -use Symfony\Component\Form\ResolvedFormTypeInterface; +use Symfony\Component\Form\ResolvedFormType; +use Symfony\Component\Form\ResolvedFormTypeFactory; use Symfony\Component\Form\Tests\Fixtures\FixedDataTransformer; use Symfony\Component\Validator\ConstraintViolation; use Symfony\Component\VarDumper\Test\VarDumperTestTrait; @@ -40,32 +41,15 @@ class FormDataExtractorTest extends TestCase */ private $dataExtractor; - /** - * @var MockObject&EventDispatcherInterface - */ - private $dispatcher; - - /** - * @var MockObject&FormFactoryInterface - */ - private $factory; - protected function setUp(): void { $this->dataExtractor = new FormDataExtractor(); - $this->dispatcher = $this->createMock(EventDispatcherInterface::class); - $this->factory = $this->createMock(FormFactoryInterface::class); } public function testExtractConfiguration() { - $type = $this->createMock(ResolvedFormTypeInterface::class); - $type->expects($this->any()) - ->method('getInnerType') - ->willReturn(new HiddenType()); - $form = $this->createBuilder('name') - ->setType($type) + ->setType(new ResolvedFormType(new HiddenType())) ->getForm(); $this->assertSame([ @@ -80,11 +64,6 @@ public function testExtractConfiguration() public function testExtractConfigurationSortsPassedOptions() { - $type = $this->createMock(ResolvedFormTypeInterface::class); - $type->expects($this->any()) - ->method('getInnerType') - ->willReturn(new HiddenType()); - $options = [ 'b' => 'foo', 'a' => 'bar', @@ -92,7 +71,7 @@ public function testExtractConfigurationSortsPassedOptions() ]; $form = $this->createBuilder('name') - ->setType($type) + ->setType(new ResolvedFormType(new HiddenType())) // passed options are stored in an attribute by // ResolvedTypeDataCollectorProxy ->setAttribute('data_collector/passed_options', $options) @@ -114,11 +93,6 @@ public function testExtractConfigurationSortsPassedOptions() public function testExtractConfigurationSortsResolvedOptions() { - $type = $this->createMock(ResolvedFormTypeInterface::class); - $type->expects($this->any()) - ->method('getInnerType') - ->willReturn(new HiddenType()); - $options = [ 'b' => 'foo', 'a' => 'bar', @@ -126,7 +100,7 @@ public function testExtractConfigurationSortsResolvedOptions() ]; $form = $this->createBuilder('name', $options) - ->setType($type) + ->setType(new ResolvedFormType(new HiddenType())) ->getForm(); $this->assertSame([ @@ -145,21 +119,16 @@ public function testExtractConfigurationSortsResolvedOptions() public function testExtractConfigurationBuildsIdRecursively() { - $type = $this->createMock(ResolvedFormTypeInterface::class); - $type->expects($this->any()) - ->method('getInnerType') - ->willReturn(new HiddenType()); - $grandParent = $this->createBuilder('grandParent') ->setCompound(true) - ->setDataMapper($this->createMock(DataMapperInterface::class)) + ->setDataMapper(new PropertyPathMapper()) ->getForm(); $parent = $this->createBuilder('parent') ->setCompound(true) - ->setDataMapper($this->createMock(DataMapperInterface::class)) + ->setDataMapper(new PropertyPathMapper()) ->getForm(); $form = $this->createBuilder('name') - ->setType($type) + ->setType(new ResolvedFormType(new HiddenType())) ->getForm(); $grandParent->add($parent); @@ -418,6 +387,6 @@ public function testExtractViewVariables() private function createBuilder(string $name, array $options = []): FormBuilder { - return new FormBuilder($name, null, $this->dispatcher, $this->factory, $options); + return new FormBuilder($name, null, new EventDispatcher(), new FormFactory(new FormRegistry([], new ResolvedFormTypeFactory())), $options); } } diff --git a/src/Symfony/Component/Form/Tests/Extension/DataCollector/Type/DataCollectorTypeExtensionTest.php b/src/Symfony/Component/Form/Tests/Extension/DataCollector/Type/DataCollectorTypeExtensionTest.php index 7c699f9498b50..13728988cac61 100644 --- a/src/Symfony/Component/Form/Tests/Extension/DataCollector/Type/DataCollectorTypeExtensionTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/DataCollector/Type/DataCollectorTypeExtensionTest.php @@ -11,12 +11,16 @@ namespace Symfony\Component\Form\Tests\Extension\DataCollector\Type; -use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; -use Symfony\Component\Form\Extension\DataCollector\EventListener\DataCollectorListener; -use Symfony\Component\Form\Extension\DataCollector\FormDataCollectorInterface; +use Symfony\Component\EventDispatcher\EventDispatcher; +use Symfony\Component\Form\Extension\DataCollector\FormDataCollector; +use Symfony\Component\Form\Extension\DataCollector\FormDataExtractor; use Symfony\Component\Form\Extension\DataCollector\Type\DataCollectorTypeExtension; -use Symfony\Component\Form\Test\FormBuilderInterface; +use Symfony\Component\Form\FormBuilder; +use Symfony\Component\Form\FormEvents; +use Symfony\Component\Form\FormFactory; +use Symfony\Component\Form\FormRegistry; +use Symfony\Component\Form\ResolvedFormTypeFactory; class DataCollectorTypeExtensionTest extends TestCase { @@ -25,15 +29,9 @@ class DataCollectorTypeExtensionTest extends TestCase */ private $extension; - /** - * @var MockObject&FormDataCollectorInterface - */ - private $dataCollector; - protected function setUp(): void { - $this->dataCollector = $this->createMock(FormDataCollectorInterface::class); - $this->extension = new DataCollectorTypeExtension($this->dataCollector); + $this->extension = new DataCollectorTypeExtension(new FormDataCollector(new FormDataExtractor())); } /** @@ -46,11 +44,19 @@ public function testGetExtendedType() public function testBuildForm() { - $builder = $this->createMock(FormBuilderInterface::class); - $builder->expects($this->atLeastOnce()) - ->method('addEventSubscriber') - ->with($this->isInstanceOf(DataCollectorListener::class)); - - $this->extension->buildForm($builder, []); + $eventDispatcher = new EventDispatcher(); + $this->assertFalse($eventDispatcher->hasListeners(FormEvents::PRE_SET_DATA)); + $this->assertFalse($eventDispatcher->hasListeners(FormEvents::POST_SET_DATA)); + $this->assertFalse($eventDispatcher->hasListeners(FormEvents::PRE_SUBMIT)); + $this->assertFalse($eventDispatcher->hasListeners(FormEvents::SUBMIT)); + $this->assertFalse($eventDispatcher->hasListeners(FormEvents::POST_SUBMIT)); + + $this->extension->buildForm(new FormBuilder(null, null, $eventDispatcher, new FormFactory(new FormRegistry([], new ResolvedFormTypeFactory()))), []); + + $this->assertFalse($eventDispatcher->hasListeners(FormEvents::PRE_SET_DATA)); + $this->assertTrue($eventDispatcher->hasListeners(FormEvents::POST_SET_DATA)); + $this->assertFalse($eventDispatcher->hasListeners(FormEvents::PRE_SUBMIT)); + $this->assertFalse($eventDispatcher->hasListeners(FormEvents::SUBMIT)); + $this->assertTrue($eventDispatcher->hasListeners(FormEvents::POST_SUBMIT)); } } diff --git a/src/Symfony/Component/Form/Tests/Extension/DependencyInjection/DependencyInjectionExtensionTest.php b/src/Symfony/Component/Form/Tests/Extension/DependencyInjection/DependencyInjectionExtensionTest.php index eb0a13c3334a6..b99240c8cb30f 100644 --- a/src/Symfony/Component/Form/Tests/Extension/DependencyInjection/DependencyInjectionExtensionTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/DependencyInjection/DependencyInjectionExtensionTest.php @@ -17,7 +17,6 @@ use Symfony\Component\Form\Exception\InvalidArgumentException; use Symfony\Component\Form\Extension\DependencyInjection\DependencyInjectionExtension; use Symfony\Component\Form\FormTypeGuesserChain; -use Symfony\Component\Form\FormTypeGuesserInterface; class DependencyInjectionExtensionTest extends TestCase { @@ -58,7 +57,7 @@ public function testThrowExceptionForInvalidExtendedType() public function testGetTypeGuesser() { - $extension = new DependencyInjectionExtension(new ContainerBuilder(), [], [$this->createMock(FormTypeGuesserInterface::class)]); + $extension = new DependencyInjectionExtension(new ContainerBuilder(), [], [new FormTypeGuesserChain([])]); $this->assertInstanceOf(FormTypeGuesserChain::class, $extension->getTypeGuesser()); } diff --git a/src/Symfony/Component/Form/Tests/Extension/Validator/Constraints/FormValidatorTest.php b/src/Symfony/Component/Form/Tests/Extension/Validator/Constraints/FormValidatorTest.php index a569a81c6e81b..58b8d4e05f892 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Validator/Constraints/FormValidatorTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Validator/Constraints/FormValidatorTest.php @@ -366,7 +366,7 @@ function () { throw new TransformationFailedException(); } public function testTransformationFailedExceptionInvalidMessageIsUsed() { - $object = $this->createMock('\stdClass'); + $object = new \stdClass(); $form = $this ->getBuilder('name', '\stdClass', [ diff --git a/src/Symfony/Component/Form/Tests/Fixtures/ArrayChoiceLoader.php b/src/Symfony/Component/Form/Tests/Fixtures/ArrayChoiceLoader.php new file mode 100644 index 0000000000000..7224d0e93639e --- /dev/null +++ b/src/Symfony/Component/Form/Tests/Fixtures/ArrayChoiceLoader.php @@ -0,0 +1,15 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Form\Tests\Fixtures; + +use Symfony\Component\Form\AbstractType; +use Symfony\Component\OptionsResolver\OptionsResolver; + +class ConfigurableFormType extends AbstractType +{ + public function configureOptions(OptionsResolver $resolver): void + { + $resolver->setDefined(['a', 'b']); + } + + public function getBlockPrefix(): string + { + return 'configurable_form_prefix'; + } +} diff --git a/src/Symfony/Component/Form/Tests/Fixtures/Map.php b/src/Symfony/Component/Form/Tests/Fixtures/Map.php new file mode 100644 index 0000000000000..3faa38cd4d3e6 --- /dev/null +++ b/src/Symfony/Component/Form/Tests/Fixtures/Map.php @@ -0,0 +1,38 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Form\Tests\Fixtures; + +class Map implements \ArrayAccess +{ + private $data = []; + + public function offsetExists($offset): bool + { + return isset($this->data[$offset]); + } + + #[\ReturnTypeWillChange] + public function offsetGet($offset) + { + return $this->data[$offset]; + } + + public function offsetSet($offset, $value): void + { + $this->data[$offset] = $value; + } + + public function offsetUnset($offset): void + { + unset($this->data[$offset]); + } +} diff --git a/src/Symfony/Component/Form/Tests/Fixtures/NullFormTypeGuesser.php b/src/Symfony/Component/Form/Tests/Fixtures/NullFormTypeGuesser.php new file mode 100644 index 0000000000000..81e728598083c --- /dev/null +++ b/src/Symfony/Component/Form/Tests/Fixtures/NullFormTypeGuesser.php @@ -0,0 +1,39 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Form\Tests\Fixtures; + +use Symfony\Component\Form\FormTypeGuesserInterface; +use Symfony\Component\Form\Guess\TypeGuess; +use Symfony\Component\Form\Guess\ValueGuess; + +class NullFormTypeGuesser implements FormTypeGuesserInterface +{ + public function guessType($class, $property): ?TypeGuess + { + return null; + } + + public function guessRequired($class, $property): ?ValueGuess + { + return null; + } + + public function guessMaxLength($class, $property): ?ValueGuess + { + return null; + } + + public function guessPattern($class, $property): ?ValueGuess + { + return null; + } +} diff --git a/src/Symfony/Component/Form/Tests/FormBuilderTest.php b/src/Symfony/Component/Form/Tests/FormBuilderTest.php index 878d527259036..d55f7733435f3 100644 --- a/src/Symfony/Component/Form/Tests/FormBuilderTest.php +++ b/src/Symfony/Component/Form/Tests/FormBuilderTest.php @@ -12,35 +12,29 @@ namespace Symfony\Component\Form\Tests; use PHPUnit\Framework\TestCase; -use Symfony\Component\EventDispatcher\EventDispatcherInterface; +use Symfony\Component\EventDispatcher\EventDispatcher; use Symfony\Component\Form\ButtonBuilder; use Symfony\Component\Form\Exception\InvalidArgumentException; use Symfony\Component\Form\Exception\UnexpectedTypeException; use Symfony\Component\Form\Extension\Core\Type\SubmitType; +use Symfony\Component\Form\Extension\Core\Type\TextType; use Symfony\Component\Form\Form; use Symfony\Component\Form\FormBuilder; +use Symfony\Component\Form\FormFactory; use Symfony\Component\Form\FormFactoryBuilder; -use Symfony\Component\Form\FormFactoryInterface; +use Symfony\Component\Form\FormRegistry; +use Symfony\Component\Form\ResolvedFormTypeFactory; use Symfony\Component\Form\SubmitButtonBuilder; class FormBuilderTest extends TestCase { - private $dispatcher; private $factory; private $builder; protected function setUp(): void { - $this->dispatcher = $this->createMock(EventDispatcherInterface::class); - $this->factory = $this->createMock(FormFactoryInterface::class); - $this->builder = new FormBuilder('name', null, $this->dispatcher, $this->factory); - } - - protected function tearDown(): void - { - $this->dispatcher = null; - $this->factory = null; - $this->builder = null; + $this->factory = new FormFactory(new FormRegistry([], new ResolvedFormTypeFactory())); + $this->builder = new FormBuilder('name', null, new EventDispatcher(), $this->factory); } /** @@ -68,9 +62,9 @@ public function testAddTypeNoString() public function testAddWithGuessFluent() { - $this->builder = new FormBuilder('name', 'stdClass', $this->dispatcher, $this->factory); - $builder = $this->builder->add('foo'); - $this->assertSame($builder, $this->builder); + $rootFormBuilder = new FormBuilder('name', 'stdClass', new EventDispatcher(), $this->factory); + $childFormBuilder = $rootFormBuilder->add('foo'); + $this->assertSame($childFormBuilder, $rootFormBuilder); } public function testAddIsFluent() @@ -95,11 +89,6 @@ public function testAddIntegerName() public function testAll() { - $this->factory->expects($this->once()) - ->method('createNamedBuilder') - ->with('foo', 'Symfony\Component\Form\Extension\Core\Type\TextType') - ->willReturn(new FormBuilder('foo', null, $this->dispatcher, $this->factory)); - $this->assertCount(0, $this->builder->all()); $this->assertFalse($this->builder->has('foo')); @@ -117,7 +106,7 @@ public function testAll() public function testMaintainOrderOfLazyAndExplicitChildren() { $this->builder->add('foo', 'Symfony\Component\Form\Extension\Core\Type\TextType'); - $this->builder->add($this->getFormBuilder('bar')); + $this->builder->add(new FormBuilder('bar', null, new EventDispatcher(), $this->factory)); $this->builder->add('baz', 'Symfony\Component\Form\Extension\Core\Type\TextType'); $children = $this->builder->all(); @@ -149,12 +138,9 @@ public function testRemoveAndGetForm() public function testCreateNoTypeNo() { - $this->factory->expects($this->once()) - ->method('createNamedBuilder') - ->with('foo', 'Symfony\Component\Form\Extension\Core\Type\TextType', null, []) - ; + $builder = $this->builder->create('foo'); - $this->builder->create('foo'); + $this->assertInstanceOf(TextType::class, $builder->getType()->getInnerType()); } public function testAddButton() @@ -175,42 +161,25 @@ public function testGetUnknown() public function testGetExplicitType() { - $expectedType = 'Symfony\Component\Form\Extension\Core\Type\TextType'; - $expectedName = 'foo'; - $expectedOptions = ['bar' => 'baz']; - - $this->factory->expects($this->once()) - ->method('createNamedBuilder') - ->with($expectedName, $expectedType, null, $expectedOptions) - ->willReturn($this->getFormBuilder()); - - $this->builder->add($expectedName, $expectedType, $expectedOptions); - $builder = $this->builder->get($expectedName); + $this->builder->add('foo', 'Symfony\Component\Form\Extension\Core\Type\TextType'); + $builder = $this->builder->get('foo'); $this->assertNotSame($builder, $this->builder); } public function testGetGuessedType() { - $expectedName = 'foo'; - $expectedOptions = ['bar' => 'baz']; + $rootFormBuilder = new FormBuilder('name', 'stdClass', new EventDispatcher(), $this->factory); + $rootFormBuilder->add('foo'); + $fooBuilder = $rootFormBuilder->get('foo'); - $this->factory->expects($this->once()) - ->method('createBuilderForProperty') - ->with('stdClass', $expectedName, null, $expectedOptions) - ->willReturn($this->getFormBuilder()); - - $this->builder = new FormBuilder('name', 'stdClass', $this->dispatcher, $this->factory); - $this->builder->add($expectedName, null, $expectedOptions); - $builder = $this->builder->get($expectedName); - - $this->assertNotSame($builder, $this->builder); + $this->assertNotSame($fooBuilder, $rootFormBuilder); } public function testGetFormConfigErasesReferences() { - $builder = new FormBuilder('name', null, $this->dispatcher, $this->factory); - $builder->add(new FormBuilder('child', null, $this->dispatcher, $this->factory)); + $builder = new FormBuilder('name', null, new EventDispatcher(), $this->factory); + $builder->add(new FormBuilder('child', null, new EventDispatcher(), $this->factory)); $config = $builder->getFormConfig(); $reflClass = new \ReflectionClass($config); @@ -226,19 +195,9 @@ public function testGetFormConfigErasesReferences() public function testGetButtonBuilderBeforeExplicitlyResolvingAllChildren() { - $builder = new FormBuilder('name', null, $this->dispatcher, (new FormFactoryBuilder())->getFormFactory()); + $builder = new FormBuilder('name', null, new EventDispatcher(), (new FormFactoryBuilder())->getFormFactory()); $builder->add('submit', SubmitType::class); $this->assertInstanceOf(ButtonBuilder::class, $builder->get('submit')); } - - private function getFormBuilder($name = 'name') - { - $mock = $this->createMock(FormBuilder::class); - $mock->expects($this->any()) - ->method('getName') - ->willReturn($name); - - return $mock; - } } diff --git a/src/Symfony/Component/Form/Tests/FormConfigTest.php b/src/Symfony/Component/Form/Tests/FormConfigTest.php index d1f1b9c3edadd..239ffbc99a611 100644 --- a/src/Symfony/Component/Form/Tests/FormConfigTest.php +++ b/src/Symfony/Component/Form/Tests/FormConfigTest.php @@ -12,7 +12,7 @@ namespace Symfony\Component\Form\Tests; use PHPUnit\Framework\TestCase; -use Symfony\Component\EventDispatcher\EventDispatcherInterface; +use Symfony\Component\EventDispatcher\EventDispatcher; use Symfony\Component\Form\FormConfigBuilder; use Symfony\Component\Form\NativeRequestHandler; @@ -67,13 +67,11 @@ public function getHtml4Ids() */ public function testNameAcceptsOnlyNamesValidAsIdsInHtml4($name, $expectedException = null) { - $dispatcher = $this->createMock(EventDispatcherInterface::class); - if (null !== $expectedException) { $this->expectException($expectedException); } - $formConfigBuilder = new FormConfigBuilder($name, null, $dispatcher); + $formConfigBuilder = new FormConfigBuilder($name, null, new EventDispatcher()); $this->assertSame((string) $name, $formConfigBuilder->getName()); } @@ -135,8 +133,6 @@ public function testSetMethodAllowsPatch() private function getConfigBuilder($name = 'name') { - $dispatcher = $this->createMock(EventDispatcherInterface::class); - - return new FormConfigBuilder($name, null, $dispatcher); + return new FormConfigBuilder($name, null, new EventDispatcher()); } } diff --git a/src/Symfony/Component/Form/Tests/FormErrorIteratorTest.php b/src/Symfony/Component/Form/Tests/FormErrorIteratorTest.php index b818dcd8c4872..44c304558b837 100644 --- a/src/Symfony/Component/Form/Tests/FormErrorIteratorTest.php +++ b/src/Symfony/Component/Form/Tests/FormErrorIteratorTest.php @@ -16,7 +16,9 @@ use Symfony\Component\Form\FormBuilder; use Symfony\Component\Form\FormError; use Symfony\Component\Form\FormErrorIterator; -use Symfony\Component\Form\FormFactoryInterface; +use Symfony\Component\Form\FormFactory; +use Symfony\Component\Form\FormRegistry; +use Symfony\Component\Form\ResolvedFormTypeFactory; use Symfony\Component\Validator\ConstraintViolation; class FormErrorIteratorTest extends TestCase @@ -34,7 +36,7 @@ public function testFindByCodes($code, $violationsCount) 'form', null, new EventDispatcher(), - $this->createMock(FormFactoryInterface::class), + new FormFactory(new FormRegistry([], new ResolvedFormTypeFactory())), [] ); diff --git a/src/Symfony/Component/Form/Tests/FormFactoryBuilderTest.php b/src/Symfony/Component/Form/Tests/FormFactoryBuilderTest.php index 9f4825e3fcdf7..fbabec1dd02c5 100644 --- a/src/Symfony/Component/Form/Tests/FormFactoryBuilderTest.php +++ b/src/Symfony/Component/Form/Tests/FormFactoryBuilderTest.php @@ -14,13 +14,12 @@ use PHPUnit\Framework\TestCase; use Symfony\Component\Form\FormFactory; use Symfony\Component\Form\FormFactoryBuilder; -use Symfony\Component\Form\FormTypeGuesserInterface; use Symfony\Component\Form\Tests\Fixtures\FooType; +use Symfony\Component\Form\Tests\Fixtures\NullFormTypeGuesser; class FormFactoryBuilderTest extends TestCase { private $registry; - private $guesser; private $type; protected function setUp(): void @@ -29,7 +28,6 @@ protected function setUp(): void $this->registry = $factory->getProperty('registry'); $this->registry->setAccessible(true); - $this->guesser = $this->createMock(FormTypeGuesserInterface::class); $this->type = new FooType(); } @@ -50,7 +48,7 @@ public function testAddType() public function testAddTypeGuesser() { $factoryBuilder = new FormFactoryBuilder(); - $factoryBuilder->addTypeGuesser($this->guesser); + $factoryBuilder->addTypeGuesser(new NullFormTypeGuesser()); $factory = $factoryBuilder->getFormFactory(); $registry = $this->registry->getValue($factory); diff --git a/src/Symfony/Component/Form/Tests/FormFactoryTest.php b/src/Symfony/Component/Form/Tests/FormFactoryTest.php index 2fa5e6d313e3e..8f7a03d0bc337 100644 --- a/src/Symfony/Component/Form/Tests/FormFactoryTest.php +++ b/src/Symfony/Component/Form/Tests/FormFactoryTest.php @@ -11,21 +11,21 @@ namespace Symfony\Component\Form\Tests; -use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; -use Symfony\Component\EventDispatcher\EventDispatcher; use Symfony\Component\Form\Exception\UnexpectedTypeException; -use Symfony\Component\Form\FormBuilder; +use Symfony\Component\Form\Extension\Core\Type\PasswordType; +use Symfony\Component\Form\Extension\Core\Type\TextType; use Symfony\Component\Form\FormFactory; +use Symfony\Component\Form\FormRegistry; use Symfony\Component\Form\FormRegistryInterface; use Symfony\Component\Form\FormTypeGuesserChain; use Symfony\Component\Form\FormTypeGuesserInterface; use Symfony\Component\Form\Guess\Guess; use Symfony\Component\Form\Guess\TypeGuess; use Symfony\Component\Form\Guess\ValueGuess; -use Symfony\Component\Form\ResolvedFormType; -use Symfony\Component\Form\ResolvedFormTypeInterface; -use Symfony\Component\Form\Test\FormBuilderInterface; +use Symfony\Component\Form\PreloadedExtension; +use Symfony\Component\Form\ResolvedFormTypeFactory; +use Symfony\Component\Form\Tests\Fixtures\ConfigurableFormType; /** * @author Bernhard Schussek @@ -33,25 +33,20 @@ class FormFactoryTest extends TestCase { /** - * @var MockObject&FormTypeGuesserInterface + * @var ConfigurableFormTypeGuesser */ private $guesser1; /** - * @var MockObject&FormTypeGuesserInterface + * @var ConfigurableFormTypeGuesser */ private $guesser2; /** - * @var MockObject&FormRegistryInterface + * @var FormRegistryInterface */ private $registry; - /** - * @var MockObject&FormBuilderInterface - */ - private $builder; - /** * @var FormFactory */ @@ -59,100 +54,36 @@ class FormFactoryTest extends TestCase protected function setUp(): void { - $this->guesser1 = $this->createMock(FormTypeGuesserInterface::class); - $this->guesser2 = $this->createMock(FormTypeGuesserInterface::class); - $this->registry = $this->createMock(FormRegistryInterface::class); - $this->builder = $this->createMock(FormBuilderInterface::class); + $this->guesser1 = new ConfigurableFormTypeGuesser(); + $this->guesser2 = new ConfigurableFormTypeGuesser(); + $this->registry = new FormRegistry([ + new PreloadedExtension([ + new ConfigurableFormType(), + ], [], new FormTypeGuesserChain([$this->guesser1, $this->guesser2])), + ], new ResolvedFormTypeFactory()); $this->factory = new FormFactory($this->registry); - - $this->registry->expects($this->any()) - ->method('getTypeGuesser') - ->willReturn(new FormTypeGuesserChain([ - $this->guesser1, - $this->guesser2, - ])); } public function testCreateNamedBuilderWithTypeName() { - $options = ['a' => '1', 'b' => '2']; - $resolvedOptions = ['a' => '2', 'b' => '3']; - $resolvedType = $this->createMock(ResolvedFormTypeInterface::class); - - $this->registry->expects($this->once()) - ->method('getType') - ->with('type') - ->willReturn($resolvedType); - - $resolvedType->expects($this->once()) - ->method('createBuilder') - ->with($this->factory, 'name', $options) - ->willReturn($this->builder); - - $this->builder->expects($this->any()) - ->method('getOptions') - ->willReturn($resolvedOptions); + $builder = $this->factory->createNamedBuilder('name', ConfigurableFormType::class, null, ['a' => '1', 'b' => '2']); - $resolvedType->expects($this->once()) - ->method('buildForm') - ->with($this->builder, $resolvedOptions); - - $this->assertSame($this->builder, $this->factory->createNamedBuilder('name', 'type', null, $options)); + $this->assertSame('1', $builder->getOption('a')); + $this->assertSame('2', $builder->getOption('b')); } public function testCreateNamedBuilderFillsDataOption() { - $givenOptions = ['a' => '1', 'b' => '2']; - $expectedOptions = array_merge($givenOptions, ['data' => 'DATA']); - $resolvedOptions = ['a' => '2', 'b' => '3', 'data' => 'DATA']; - $resolvedType = $this->createMock(ResolvedFormTypeInterface::class); - - $this->registry->expects($this->once()) - ->method('getType') - ->with('type') - ->willReturn($resolvedType); - - $resolvedType->expects($this->once()) - ->method('createBuilder') - ->with($this->factory, 'name', $expectedOptions) - ->willReturn($this->builder); - - $this->builder->expects($this->any()) - ->method('getOptions') - ->willReturn($resolvedOptions); - - $resolvedType->expects($this->once()) - ->method('buildForm') - ->with($this->builder, $resolvedOptions); - - $this->assertSame($this->builder, $this->factory->createNamedBuilder('name', 'type', 'DATA', $givenOptions)); + $builder = $this->factory->createNamedBuilder('name', ConfigurableFormType::class, 'DATA', ['a' => '1', 'b' => '2']); + + $this->assertSame('DATA', $builder->getOption('data')); } public function testCreateNamedBuilderDoesNotOverrideExistingDataOption() { - $options = ['a' => '1', 'b' => '2', 'data' => 'CUSTOM']; - $resolvedOptions = ['a' => '2', 'b' => '3', 'data' => 'CUSTOM']; - $resolvedType = $this->createMock(ResolvedFormTypeInterface::class); - - $this->registry->expects($this->once()) - ->method('getType') - ->with('type') - ->willReturn($resolvedType); - - $resolvedType->expects($this->once()) - ->method('createBuilder') - ->with($this->factory, 'name', $options) - ->willReturn($this->builder); - - $this->builder->expects($this->any()) - ->method('getOptions') - ->willReturn($resolvedOptions); - - $resolvedType->expects($this->once()) - ->method('buildForm') - ->with($this->builder, $resolvedOptions); + $builder = $this->factory->createNamedBuilder('name', ConfigurableFormType::class, 'DATA', ['a' => '1', 'b' => '2', 'data' => 'CUSTOM']); - $this->assertSame($this->builder, $this->factory->createNamedBuilder('name', 'type', 'DATA', $options)); + $this->assertSame('CUSTOM', $builder->getOption('data')); } public function testCreateNamedBuilderThrowsUnderstandableException() @@ -171,318 +102,150 @@ public function testCreateThrowsUnderstandableException() public function testCreateUsesBlockPrefixIfTypeGivenAsString() { - $options = ['a' => '1', 'b' => '2']; - $resolvedOptions = ['a' => '2', 'b' => '3']; + $form = $this->factory->create(ConfigurableFormType::class); - // the interface does not have the method, so use the real class - $resolvedType = $this->createMock(ResolvedFormType::class); - $resolvedType->expects($this->any()) - ->method('getBlockPrefix') - ->willReturn('TYPE_PREFIX'); + $this->assertSame('configurable_form_prefix', $form->getName()); + } - $this->registry->expects($this->any()) - ->method('getType') - ->with('TYPE') - ->willReturn($resolvedType); + public function testCreateNamed() + { + $form = $this->factory->createNamed('name', ConfigurableFormType::class, null, ['a' => '1', 'b' => '2']); - $resolvedType->expects($this->once()) - ->method('createBuilder') - ->with($this->factory, 'TYPE_PREFIX', $options) - ->willReturn($this->builder); + $this->assertSame('1', $form->getConfig()->getOption('a')); + $this->assertSame('2', $form->getConfig()->getOption('b')); + } - $this->builder->expects($this->any()) - ->method('getOptions') - ->willReturn($resolvedOptions); + public function testCreateBuilderForPropertyWithoutTypeGuesser() + { + $builder = $this->factory->createBuilderForProperty('Application\Author', 'firstName'); - $resolvedType->expects($this->once()) - ->method('buildForm') - ->with($this->builder, $resolvedOptions); + $this->assertSame('firstName', $builder->getName()); + } - $form = $this->createForm(); + public function testCreateBuilderForPropertyCreatesFormWithHighestConfidence() + { + $this->guesser1->configureTypeGuess(TextType::class, ['attr' => ['maxlength' => 10]], Guess::MEDIUM_CONFIDENCE); + $this->guesser2->configureTypeGuess(PasswordType::class, ['attr' => ['maxlength' => 7]], Guess::HIGH_CONFIDENCE); - $this->builder->expects($this->once()) - ->method('getForm') - ->willReturn($form); + $builder = $this->factory->createBuilderForProperty('Application\Author', 'firstName'); - $this->assertSame($form, $this->factory->create('TYPE', null, $options)); + $this->assertSame('firstName', $builder->getName()); + $this->assertSame(['maxlength' => 7], $builder->getOption('attr')); + $this->assertInstanceOf(PasswordType::class, $builder->getType()->getInnerType()); } - public function testCreateNamed() + public function testCreateBuilderCreatesTextFormIfNoGuess() { - $options = ['a' => '1', 'b' => '2']; - $resolvedOptions = ['a' => '2', 'b' => '3']; - $resolvedType = $this->createMock(ResolvedFormTypeInterface::class); + $builder = $this->factory->createBuilderForProperty('Application\Author', 'firstName'); - $this->registry->expects($this->once()) - ->method('getType') - ->with('type') - ->willReturn($resolvedType); + $this->assertSame('firstName', $builder->getName()); + $this->assertInstanceOf(TextType::class, $builder->getType()->getInnerType()); + } - $resolvedType->expects($this->once()) - ->method('createBuilder') - ->with($this->factory, 'name', $options) - ->willReturn($this->builder); + public function testOptionsCanBeOverridden() + { + $this->guesser1->configureTypeGuess(TextType::class, ['attr' => ['class' => 'foo', 'maxlength' => 10]], Guess::MEDIUM_CONFIDENCE); - $this->builder->expects($this->any()) - ->method('getOptions') - ->willReturn($resolvedOptions); + $builder = $this->factory->createBuilderForProperty('Application\Author', 'firstName', null, ['attr' => ['maxlength' => 11]]); - $resolvedType->expects($this->once()) - ->method('buildForm') - ->with($this->builder, $resolvedOptions); + $this->assertSame('firstName', $builder->getName()); + $this->assertSame(['class' => 'foo', 'maxlength' => 11], $builder->getOption('attr')); + $this->assertInstanceOf(TextType::class, $builder->getType()->getInnerType()); + } - $form = $this->createForm(); + public function testCreateBuilderUsesMaxLengthIfFound() + { + $this->guesser1->configureMaxLengthGuess(15, Guess::MEDIUM_CONFIDENCE); + $this->guesser2->configureMaxLengthGuess(20, Guess::HIGH_CONFIDENCE); - $this->builder->expects($this->once()) - ->method('getForm') - ->willReturn($form); + $builder = $this->factory->createBuilderForProperty('Application\Author', 'firstName'); - $this->assertSame($form, $this->factory->createNamed('name', 'type', null, $options)); + $this->assertSame('firstName', $builder->getName()); + $this->assertSame(['maxlength' => 20], $builder->getOption('attr')); + $this->assertInstanceOf(TextType::class, $builder->getType()->getInnerType()); } - public function testCreateBuilderForPropertyWithoutTypeGuesser() + public function testCreateBuilderUsesMaxLengthAndPattern() { - $registry = $this->createMock(FormRegistryInterface::class); - $factory = $this->getMockBuilder(FormFactory::class) - ->setMethods(['createNamedBuilder']) - ->setConstructorArgs([$registry]) - ->getMock(); - - $factory->expects($this->once()) - ->method('createNamedBuilder') - ->with('firstName', 'Symfony\Component\Form\Extension\Core\Type\TextType', null, []) - ->willReturn($this->builder); + $this->guesser1->configureMaxLengthGuess(20, Guess::HIGH_CONFIDENCE); + $this->guesser2->configurePatternGuess('.{5,}', Guess::HIGH_CONFIDENCE); - $this->builder = $factory->createBuilderForProperty('Application\Author', 'firstName'); + $builder = $this->factory->createBuilderForProperty('Application\Author', 'firstName', null, ['attr' => ['class' => 'tinymce']]); - $this->assertSame($this->builder, $this->builder); + $this->assertSame('firstName', $builder->getName()); + $this->assertSame(['maxlength' => 20, 'pattern' => '.{5,}', 'class' => 'tinymce'], $builder->getOption('attr')); + $this->assertInstanceOf(TextType::class, $builder->getType()->getInnerType()); } - public function testCreateBuilderForPropertyCreatesFormWithHighestConfidence() + public function testCreateBuilderUsesRequiredSettingWithHighestConfidence() { - $this->guesser1->expects($this->once()) - ->method('guessType') - ->with('Application\Author', 'firstName') - ->willReturn(new TypeGuess( - 'Symfony\Component\Form\Extension\Core\Type\TextType', - ['attr' => ['maxlength' => 10]], - Guess::MEDIUM_CONFIDENCE - )); - - $this->guesser2->expects($this->once()) - ->method('guessType') - ->with('Application\Author', 'firstName') - ->willReturn(new TypeGuess( - 'Symfony\Component\Form\Extension\Core\Type\PasswordType', - ['attr' => ['maxlength' => 7]], - Guess::HIGH_CONFIDENCE - )); - - $factory = $this->getMockFactory(['createNamedBuilder']); - - $factory->expects($this->once()) - ->method('createNamedBuilder') - ->with('firstName', 'Symfony\Component\Form\Extension\Core\Type\PasswordType', null, ['attr' => ['maxlength' => 7]]) - ->willReturn($this->builder); - - $this->builder = $factory->createBuilderForProperty('Application\Author', 'firstName'); - - $this->assertSame($this->builder, $this->builder); + $this->guesser1->configureRequiredGuess(true, Guess::MEDIUM_CONFIDENCE); + $this->guesser2->configureRequiredGuess(false, Guess::HIGH_CONFIDENCE); + + $builder = $this->factory->createBuilderForProperty('Application\Author', 'firstName'); + + $this->assertSame('firstName', $builder->getName()); + $this->assertFalse($builder->getOption('required')); + $this->assertInstanceOf(TextType::class, $builder->getType()->getInnerType()); } - public function testCreateBuilderCreatesTextFormIfNoGuess() + public function testCreateBuilderUsesPatternIfFound() { - $this->guesser1->expects($this->once()) - ->method('guessType') - ->with('Application\Author', 'firstName') - ->willReturn(null); + $this->guesser1->configurePatternGuess('[a-z]', Guess::MEDIUM_CONFIDENCE); + $this->guesser2->configurePatternGuess('[a-zA-Z]', Guess::HIGH_CONFIDENCE); - $factory = $this->getMockFactory(['createNamedBuilder']); + $builder = $this->factory->createBuilderForProperty('Application\Author', 'firstName'); - $factory->expects($this->once()) - ->method('createNamedBuilder') - ->with('firstName', 'Symfony\Component\Form\Extension\Core\Type\TextType') - ->willReturn($this->builder); + $this->assertSame('firstName', $builder->getName()); + $this->assertSame(['pattern' => '[a-zA-Z]'], $builder->getOption('attr')); + $this->assertInstanceOf(TextType::class, $builder->getType()->getInnerType()); + } +} - $this->builder = $factory->createBuilderForProperty('Application\Author', 'firstName'); +class ConfigurableFormTypeGuesser implements FormTypeGuesserInterface +{ + private $typeGuess; + private $requiredGuess; + private $maxLengthGuess; + private $patternGuess; - $this->assertSame($this->builder, $this->builder); + public function guessType($class, $property): ?TypeGuess + { + return $this->typeGuess; } - public function testOptionsCanBeOverridden() + public function guessRequired($class, $property): ?ValueGuess { - $this->guesser1->expects($this->once()) - ->method('guessType') - ->with('Application\Author', 'firstName') - ->willReturn(new TypeGuess( - 'Symfony\Component\Form\Extension\Core\Type\TextType', - ['attr' => ['class' => 'foo', 'maxlength' => 10]], - Guess::MEDIUM_CONFIDENCE - )); - - $factory = $this->getMockFactory(['createNamedBuilder']); - - $factory->expects($this->once()) - ->method('createNamedBuilder') - ->with('firstName', 'Symfony\Component\Form\Extension\Core\Type\TextType', null, ['attr' => ['class' => 'foo', 'maxlength' => 11]]) - ->willReturn($this->builder); - - $this->builder = $factory->createBuilderForProperty( - 'Application\Author', - 'firstName', - null, - ['attr' => ['maxlength' => 11]] - ); - - $this->assertSame($this->builder, $this->builder); + return $this->requiredGuess; } - public function testCreateBuilderUsesMaxLengthIfFound() + public function guessMaxLength($class, $property): ?ValueGuess { - $this->guesser1->expects($this->once()) - ->method('guessMaxLength') - ->with('Application\Author', 'firstName') - ->willReturn(new ValueGuess( - 15, - Guess::MEDIUM_CONFIDENCE - )); - - $this->guesser2->expects($this->once()) - ->method('guessMaxLength') - ->with('Application\Author', 'firstName') - ->willReturn(new ValueGuess( - 20, - Guess::HIGH_CONFIDENCE - )); - - $factory = $this->getMockFactory(['createNamedBuilder']); - - $factory->expects($this->once()) - ->method('createNamedBuilder') - ->with('firstName', 'Symfony\Component\Form\Extension\Core\Type\TextType', null, ['attr' => ['maxlength' => 20]]) - ->willReturn($this->builder); - - $this->builder = $factory->createBuilderForProperty( - 'Application\Author', - 'firstName' - ); - - $this->assertSame($this->builder, $this->builder); + return $this->maxLengthGuess; } - public function testCreateBuilderUsesMaxLengthAndPattern() + public function guessPattern($class, $property): ?ValueGuess { - $this->guesser1->expects($this->once()) - ->method('guessMaxLength') - ->with('Application\Author', 'firstName') - ->willReturn(new ValueGuess( - 20, - Guess::HIGH_CONFIDENCE - )); - - $this->guesser2->expects($this->once()) - ->method('guessPattern') - ->with('Application\Author', 'firstName') - ->willReturn(new ValueGuess( - '.{5,}', - Guess::HIGH_CONFIDENCE - )); - - $factory = $this->getMockFactory(['createNamedBuilder']); - - $factory->expects($this->once()) - ->method('createNamedBuilder') - ->with('firstName', 'Symfony\Component\Form\Extension\Core\Type\TextType', null, ['attr' => ['maxlength' => 20, 'pattern' => '.{5,}', 'class' => 'tinymce']]) - ->willReturn($this->builder); - - $this->builder = $factory->createBuilderForProperty( - 'Application\Author', - 'firstName', - null, - ['attr' => ['class' => 'tinymce']] - ); - - $this->assertSame($this->builder, $this->builder); + return $this->patternGuess; } - public function testCreateBuilderUsesRequiredSettingWithHighestConfidence() + public function configureTypeGuess(string $type, array $options, int $confidence): void { - $this->guesser1->expects($this->once()) - ->method('guessRequired') - ->with('Application\Author', 'firstName') - ->willReturn(new ValueGuess( - true, - Guess::MEDIUM_CONFIDENCE - )); - - $this->guesser2->expects($this->once()) - ->method('guessRequired') - ->with('Application\Author', 'firstName') - ->willReturn(new ValueGuess( - false, - Guess::HIGH_CONFIDENCE - )); - - $factory = $this->getMockFactory(['createNamedBuilder']); - - $factory->expects($this->once()) - ->method('createNamedBuilder') - ->with('firstName', 'Symfony\Component\Form\Extension\Core\Type\TextType', null, ['required' => false]) - ->willReturn($this->builder); - - $this->builder = $factory->createBuilderForProperty( - 'Application\Author', - 'firstName' - ); - - $this->assertSame($this->builder, $this->builder); + $this->typeGuess = new TypeGuess($type, $options, $confidence); } - public function testCreateBuilderUsesPatternIfFound() + public function configureRequiredGuess(bool $required, int $confidence): void { - $this->guesser1->expects($this->once()) - ->method('guessPattern') - ->with('Application\Author', 'firstName') - ->willReturn(new ValueGuess( - '[a-z]', - Guess::MEDIUM_CONFIDENCE - )); - - $this->guesser2->expects($this->once()) - ->method('guessPattern') - ->with('Application\Author', 'firstName') - ->willReturn(new ValueGuess( - '[a-zA-Z]', - Guess::HIGH_CONFIDENCE - )); - - $factory = $this->getMockFactory(['createNamedBuilder']); - - $factory->expects($this->once()) - ->method('createNamedBuilder') - ->with('firstName', 'Symfony\Component\Form\Extension\Core\Type\TextType', null, ['attr' => ['pattern' => '[a-zA-Z]']]) - ->willReturn($this->builder); - - $this->builder = $factory->createBuilderForProperty( - 'Application\Author', - 'firstName' - ); - - $this->assertSame($this->builder, $this->builder); + $this->requiredGuess = new ValueGuess($required, $confidence); } - protected function createForm() + public function configureMaxLengthGuess(int $maxLength, int $confidence): void { - $formBuilder = new FormBuilder('', null, new EventDispatcher(), $this->factory); - - return $formBuilder->getForm(); + $this->maxLengthGuess = new ValueGuess($maxLength, $confidence); } - private function getMockFactory(array $methods = []) + public function configurePatternGuess(string $pattern, int $confidence): void { - return $this->getMockBuilder(FormFactory::class) - ->setMethods($methods) - ->setConstructorArgs([$this->registry]) - ->getMock(); + $this->patternGuess = new ValueGuess($pattern, $confidence); } } diff --git a/src/Symfony/Component/Form/Tests/FormRegistryTest.php b/src/Symfony/Component/Form/Tests/FormRegistryTest.php index cdf8ea427ba1f..8cee7282a4de2 100644 --- a/src/Symfony/Component/Form/Tests/FormRegistryTest.php +++ b/src/Symfony/Component/Form/Tests/FormRegistryTest.php @@ -11,23 +11,20 @@ namespace Symfony\Component\Form\Tests; -use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; use Symfony\Component\Form\Exception\InvalidArgumentException; use Symfony\Component\Form\Exception\LogicException; -use Symfony\Component\Form\FormExtensionInterface; use Symfony\Component\Form\FormRegistry; use Symfony\Component\Form\FormTypeGuesserChain; -use Symfony\Component\Form\FormTypeGuesserInterface; +use Symfony\Component\Form\PreloadedExtension; use Symfony\Component\Form\ResolvedFormType; use Symfony\Component\Form\ResolvedFormTypeFactory; -use Symfony\Component\Form\ResolvedFormTypeFactoryInterface; -use Symfony\Component\Form\ResolvedFormTypeInterface; use Symfony\Component\Form\Tests\Fixtures\FooSubType; use Symfony\Component\Form\Tests\Fixtures\FooType; use Symfony\Component\Form\Tests\Fixtures\FooTypeBarExtension; use Symfony\Component\Form\Tests\Fixtures\FooTypeBazExtension; use Symfony\Component\Form\Tests\Fixtures\FormWithSameParentType; +use Symfony\Component\Form\Tests\Fixtures\NullFormTypeGuesser; use Symfony\Component\Form\Tests\Fixtures\RecursiveFormTypeBar; use Symfony\Component\Form\Tests\Fixtures\RecursiveFormTypeBaz; use Symfony\Component\Form\Tests\Fixtures\RecursiveFormTypeFoo; @@ -43,21 +40,6 @@ class FormRegistryTest extends TestCase */ private $registry; - /** - * @var MockObject&ResolvedFormTypeFactoryInterface - */ - private $resolvedTypeFactory; - - /** - * @var MockObject&FormTypeGuesserInterface - */ - private $guesser1; - - /** - * @var MockObject&FormTypeGuesserInterface - */ - private $guesser2; - /** * @var TestExtension */ @@ -70,43 +52,34 @@ class FormRegistryTest extends TestCase protected function setUp(): void { - $this->resolvedTypeFactory = $this->createMock(ResolvedFormTypeFactory::class); - $this->guesser1 = $this->createMock(FormTypeGuesserInterface::class); - $this->guesser2 = $this->createMock(FormTypeGuesserInterface::class); - $this->extension1 = new TestExtension($this->guesser1); - $this->extension2 = new TestExtension($this->guesser2); + $this->extension1 = new TestExtension(new NullFormTypeGuesser()); + $this->extension2 = new TestExtension(new NullFormTypeGuesser()); $this->registry = new FormRegistry([ $this->extension1, $this->extension2, - ], $this->resolvedTypeFactory); + ], new ResolvedFormTypeFactory()); } public function testGetTypeFromExtension() { $type = new FooType(); - $resolvedType = new ResolvedFormType($type); - $this->extension2->addType($type); - $this->resolvedTypeFactory->expects($this->once()) - ->method('createResolvedType') - ->with($type) - ->willReturn($resolvedType); + $resolvedFormType = $this->registry->getType(FooType::class); - $this->assertSame($resolvedType, $this->registry->getType(\get_class($type))); + $this->assertInstanceOf(ResolvedFormType::class, $resolvedFormType); + $this->assertSame($type, $resolvedFormType->getInnerType()); } public function testLoadUnregisteredType() { $type = new FooType(); - $resolvedType = new ResolvedFormType($type); - $this->resolvedTypeFactory->expects($this->once()) - ->method('createResolvedType') - ->with($type) - ->willReturn($resolvedType); + $resolvedFormType = $this->registry->getType(FooType::class); - $this->assertSame($resolvedType, $this->registry->getType('Symfony\Component\Form\Tests\Fixtures\FooType')); + $this->assertInstanceOf(ResolvedFormType::class, $resolvedFormType); + $this->assertInstanceOf(FooType::class, $resolvedFormType->getInnerType()); + $this->assertNotSame($type, $resolvedFormType->getInnerType()); } public function testFailIfUnregisteredTypeNoClass() @@ -126,39 +99,35 @@ public function testGetTypeWithTypeExtensions() $type = new FooType(); $ext1 = new FooTypeBarExtension(); $ext2 = new FooTypeBazExtension(); - $resolvedType = new ResolvedFormType($type, [$ext1, $ext2]); $this->extension2->addType($type); $this->extension1->addTypeExtension($ext1); $this->extension2->addTypeExtension($ext2); - $this->resolvedTypeFactory->expects($this->once()) - ->method('createResolvedType') - ->with($type, [$ext1, $ext2]) - ->willReturn($resolvedType); + $resolvedFormType = $this->registry->getType(FooType::class); - $this->assertSame($resolvedType, $this->registry->getType(\get_class($type))); + $this->assertInstanceOf(ResolvedFormType::class, $resolvedFormType); + $this->assertSame($type, $resolvedFormType->getInnerType()); + $this->assertSame([$ext1, $ext2], $resolvedFormType->getTypeExtensions()); } public function testGetTypeConnectsParent() { $parentType = new FooType(); $type = new FooSubType(); - $parentResolvedType = new ResolvedFormType($parentType); - $resolvedType = new ResolvedFormType($type); $this->extension1->addType($parentType); $this->extension2->addType($type); - $this->resolvedTypeFactory->expects($this->exactly(2)) - ->method('createResolvedType') - ->withConsecutive( - [$parentType], - [$type, [], $parentResolvedType] - ) - ->willReturnOnConsecutiveCalls($parentResolvedType, $resolvedType); + $resolvedFormType = $this->registry->getType(FooSubType::class); + + $this->assertInstanceOf(ResolvedFormType::class, $resolvedFormType); + $this->assertSame($type, $resolvedFormType->getInnerType()); + + $resolvedParentFormType = $resolvedFormType->getParent(); - $this->assertSame($resolvedType, $this->registry->getType(\get_class($type))); + $this->assertInstanceOf(ResolvedFormType::class, $resolvedParentFormType); + $this->assertSame($parentType, $resolvedParentFormType->getInnerType()); } public function testFormCannotHaveItselfAsAParent() @@ -196,26 +165,14 @@ public function testGetTypeThrowsExceptionIfTypeNotFound() public function testHasTypeAfterLoadingFromExtension() { $type = new FooType(); - $resolvedType = new ResolvedFormType($type); - - $this->resolvedTypeFactory->expects($this->once()) - ->method('createResolvedType') - ->with($type) - ->willReturn($resolvedType); - $this->extension2->addType($type); - $this->assertTrue($this->registry->hasType(\get_class($type))); + $this->assertTrue($this->registry->hasType(FooType::class)); } public function testHasTypeIfFQCN() { - $this->resolvedTypeFactory - ->expects($this->any()) - ->method('createResolvedType') - ->willReturn($this->createMock(ResolvedFormTypeInterface::class)); - - $this->assertTrue($this->registry->hasType('Symfony\Component\Form\Tests\Fixtures\FooType')); + $this->assertTrue($this->registry->hasType(FooType::class)); } public function testDoesNotHaveTypeIfNonExistingClass() @@ -230,14 +187,11 @@ public function testDoesNotHaveTypeIfNoFormType() public function testGetTypeGuesser() { - $expectedGuesser = new FormTypeGuesserChain([$this->guesser1, $this->guesser2]); + $expectedGuesser = new FormTypeGuesserChain([new NullFormTypeGuesser(), new NullFormTypeGuesser()]); $this->assertEquals($expectedGuesser, $this->registry->getTypeGuesser()); - $registry = new FormRegistry( - [$this->createMock(FormExtensionInterface::class)], - $this->resolvedTypeFactory - ); + $registry = new FormRegistry([new PreloadedExtension([], [])], new ResolvedFormTypeFactory()); $this->assertNull($registry->getTypeGuesser()); } diff --git a/src/Symfony/Component/Form/Tests/FormRendererTest.php b/src/Symfony/Component/Form/Tests/FormRendererTest.php index 00184ae2c5d68..9858fffadf472 100644 --- a/src/Symfony/Component/Form/Tests/FormRendererTest.php +++ b/src/Symfony/Component/Form/Tests/FormRendererTest.php @@ -12,19 +12,30 @@ namespace Symfony\Component\Form\Tests; use PHPUnit\Framework\TestCase; +use Symfony\Component\Form\AbstractRendererEngine; use Symfony\Component\Form\FormRenderer; +use Symfony\Component\Form\FormView; class FormRendererTest extends TestCase { public function testHumanize() { - $renderer = $this->getMockBuilder(FormRenderer::class) - ->setMethods(null) - ->disableOriginalConstructor() - ->getMock() - ; + $renderer = new FormRenderer(new DummyFormRendererEngine()); $this->assertEquals('Is active', $renderer->humanize('is_active')); $this->assertEquals('Is active', $renderer->humanize('isActive')); } } + +class DummyFormRendererEngine extends AbstractRendererEngine +{ + public function renderBlock(FormView $view, $resource, $blockName, array $variables = []): string + { + return ''; + } + + protected function loadResourceForBlockName($cacheKey, FormView $view, $blockName): bool + { + return true; + } +} diff --git a/src/Symfony/Component/Form/Tests/ResolvedFormTypeTest.php b/src/Symfony/Component/Form/Tests/ResolvedFormTypeTest.php index 931b98d144027..c841f505ac0ac 100644 --- a/src/Symfony/Component/Form/Tests/ResolvedFormTypeTest.php +++ b/src/Symfony/Component/Form/Tests/ResolvedFormTypeTest.php @@ -11,19 +11,23 @@ namespace Symfony\Component\Form\Tests; -use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; +use Symfony\Component\EventDispatcher\EventDispatcher; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\AbstractTypeExtension; -use Symfony\Component\Form\Extension\Core\Type\HiddenType; -use Symfony\Component\Form\Form; -use Symfony\Component\Form\FormConfigInterface; +use Symfony\Component\Form\Extension\Core\Type\FormType; +use Symfony\Component\Form\FormBuilder; +use Symfony\Component\Form\FormBuilderInterface; +use Symfony\Component\Form\FormFactory; use Symfony\Component\Form\FormFactoryInterface; +use Symfony\Component\Form\FormInterface; +use Symfony\Component\Form\FormRegistry; use Symfony\Component\Form\FormTypeExtensionInterface; use Symfony\Component\Form\FormTypeInterface; use Symfony\Component\Form\FormView; use Symfony\Component\Form\ResolvedFormType; -use Symfony\Component\Form\Test\FormBuilderInterface; +use Symfony\Component\Form\ResolvedFormTypeFactory; +use Symfony\Component\Form\Tests\Fixtures\ConfigurableFormType; use Symfony\Component\OptionsResolver\Exception\MissingOptionsException; use Symfony\Component\OptionsResolver\OptionsResolver; @@ -32,23 +36,25 @@ */ class ResolvedFormTypeTest extends TestCase { + private $calls; + /** - * @var MockObject&FormTypeInterface + * @var FormTypeInterface */ private $parentType; /** - * @var MockObject&FormTypeInterface + * @var FormTypeInterface */ private $type; /** - * @var MockObject&FormTypeExtensionInterface + * @var FormTypeExtensionInterface */ private $extension1; /** - * @var MockObject&FormTypeExtensionInterface + * @var FormTypeExtensionInterface */ private $extension2; @@ -62,51 +68,27 @@ class ResolvedFormTypeTest extends TestCase */ private $resolvedType; + /** + * @var FormFactoryInterface + */ + private $formFactory; + protected function setUp(): void { - $this->parentType = $this->getMockFormType(); - $this->type = $this->getMockFormType(); - $this->extension1 = $this->getMockFormTypeExtension(); - $this->extension2 = $this->getMockFormTypeExtension(); + $this->calls = []; + $this->parentType = new UsageTrackingParentFormType($this->calls); + $this->type = new UsageTrackingFormType($this->calls); + $this->extension1 = new UsageTrackingFormTypeExtension($this->calls, ['c' => 'c_default']); + $this->extension2 = new UsageTrackingFormTypeExtension($this->calls, ['d' => 'd_default']); $this->parentResolvedType = new ResolvedFormType($this->parentType); $this->resolvedType = new ResolvedFormType($this->type, [$this->extension1, $this->extension2], $this->parentResolvedType); + $this->formFactory = new FormFactory(new FormRegistry([], new ResolvedFormTypeFactory())); } public function testGetOptionsResolver() { - $i = 0; - - $assertIndexAndAddOption = function ($index, $option, $default) use (&$i) { - return function (OptionsResolver $resolver) use (&$i, $index, $option, $default) { - $this->assertEquals($index, $i, 'Executed at index '.$index); - - ++$i; - - $resolver->setDefaults([$option => $default]); - }; - }; - - // First the default options are generated for the super type - $this->parentType->expects($this->once()) - ->method('configureOptions') - ->willReturnCallback($assertIndexAndAddOption(0, 'a', 'a_default')); - - // The form type itself - $this->type->expects($this->once()) - ->method('configureOptions') - ->willReturnCallback($assertIndexAndAddOption(1, 'b', 'b_default')); - - // And its extensions - $this->extension1->expects($this->once()) - ->method('configureOptions') - ->willReturnCallback($assertIndexAndAddOption(2, 'c', 'c_default')); - - $this->extension2->expects($this->once()) - ->method('configureOptions') - ->willReturnCallback($assertIndexAndAddOption(3, 'd', 'd_default')); - - $givenOptions = ['a' => 'a_custom', 'c' => 'c_custom']; - $resolvedOptions = ['a' => 'a_custom', 'b' => 'b_default', 'c' => 'c_custom', 'd' => 'd_default']; + $givenOptions = ['a' => 'a_custom', 'c' => 'c_custom', 'foo' => 'bar']; + $resolvedOptions = ['a' => 'a_custom', 'b' => 'b_default', 'c' => 'c_custom', 'd' => 'd_default', 'foo' => 'bar']; $resolver = $this->resolvedType->getOptionsResolver(); @@ -115,26 +97,10 @@ public function testGetOptionsResolver() public function testCreateBuilder() { - $givenOptions = ['a' => 'a_custom', 'c' => 'c_custom']; - $resolvedOptions = ['a' => 'a_custom', 'b' => 'b_default', 'c' => 'c_custom', 'd' => 'd_default']; - $optionsResolver = $this->createMock(OptionsResolver::class); + $givenOptions = ['a' => 'a_custom', 'c' => 'c_custom', 'foo' => 'bar']; + $resolvedOptions = ['b' => 'b_default', 'd' => 'd_default', 'a' => 'a_custom', 'c' => 'c_custom', 'foo' => 'bar']; - $this->resolvedType = $this->getMockBuilder(ResolvedFormType::class) - ->setConstructorArgs([$this->type, [$this->extension1, $this->extension2], $this->parentResolvedType]) - ->setMethods(['getOptionsResolver']) - ->getMock(); - - $this->resolvedType->expects($this->once()) - ->method('getOptionsResolver') - ->willReturn($optionsResolver); - - $optionsResolver->expects($this->once()) - ->method('resolve') - ->with($givenOptions) - ->willReturn($resolvedOptions); - - $factory = $this->getMockFormFactory(); - $builder = $this->resolvedType->createBuilder($factory, 'name', $givenOptions); + $builder = $this->resolvedType->createBuilder($this->formFactory, 'name', $givenOptions); $this->assertSame($this->resolvedType, $builder->getType()); $this->assertSame($resolvedOptions, $builder->getOptions()); @@ -143,26 +109,19 @@ public function testCreateBuilder() public function testCreateBuilderWithDataClassOption() { - $givenOptions = ['data_class' => 'Foo']; - $resolvedOptions = ['data_class' => \stdClass::class]; - $optionsResolver = $this->createMock(OptionsResolver::class); - - $this->resolvedType = $this->getMockBuilder(ResolvedFormType::class) - ->setConstructorArgs([$this->type, [$this->extension1, $this->extension2], $this->parentResolvedType]) - ->setMethods(['getOptionsResolver']) - ->getMock(); - - $this->resolvedType->expects($this->once()) - ->method('getOptionsResolver') - ->willReturn($optionsResolver); - - $optionsResolver->expects($this->once()) - ->method('resolve') - ->with($givenOptions) - ->willReturn($resolvedOptions); + $resolvedOptions = [ + 'a' => 'a_default', + 'b' => 'b_default', + 'c' => 'c_default', + 'd' => 'd_default', + 'data_class' => \stdClass::class, + 'foo' => 'bar', + ]; - $factory = $this->getMockFormFactory(); - $builder = $this->resolvedType->createBuilder($factory, 'name', $givenOptions); + $builder = $this->resolvedType->createBuilder($this->formFactory, 'name', [ + 'data_class' => \stdClass::class, + 'foo' => 'bar', + ]); $this->assertSame($this->resolvedType, $builder->getType()); $this->assertSame($resolvedOptions, $builder->getOptions()); @@ -172,74 +131,21 @@ public function testCreateBuilderWithDataClassOption() public function testFailsCreateBuilderOnInvalidFormOptionsResolution() { $this->expectException(MissingOptionsException::class); - $this->expectExceptionMessage('An error has occurred resolving the options of the form "Symfony\Component\Form\Extension\Core\Type\HiddenType": The required option "foo" is missing.'); - $optionsResolver = (new OptionsResolver()) - ->setRequired('foo') - ; - $this->resolvedType = $this->getMockBuilder(ResolvedFormType::class) - ->setConstructorArgs([$this->type, [$this->extension1, $this->extension2], $this->parentResolvedType]) - ->setMethods(['getOptionsResolver', 'getInnerType']) - ->getMock() - ; - $this->resolvedType->expects($this->once()) - ->method('getOptionsResolver') - ->willReturn($optionsResolver) - ; - $this->resolvedType->expects($this->once()) - ->method('getInnerType') - ->willReturn(new HiddenType()) - ; - $factory = $this->getMockFormFactory(); - - $this->resolvedType->createBuilder($factory, 'name'); + $this->expectExceptionMessage(sprintf('An error has occurred resolving the options of the form "%s": The required option "foo" is missing.', UsageTrackingFormType::class)); + + $this->resolvedType->createBuilder($this->formFactory, 'name'); } public function testBuildForm() { - $i = 0; - - $assertIndex = function ($index) use (&$i) { - return function () use (&$i, $index) { - $this->assertEquals($index, $i, 'Executed at index '.$index); - - ++$i; - }; - }; - - $options = ['a' => 'Foo', 'b' => 'Bar']; - $builder = $this->createMock(FormBuilderInterface::class); - - // First the form is built for the super type - $this->parentType->expects($this->once()) - ->method('buildForm') - ->with($builder, $options) - ->willReturnCallback($assertIndex(0)); - - // Then the type itself - $this->type->expects($this->once()) - ->method('buildForm') - ->with($builder, $options) - ->willReturnCallback($assertIndex(1)); - - // Then its extensions - $this->extension1->expects($this->once()) - ->method('buildForm') - ->with($builder, $options) - ->willReturnCallback($assertIndex(2)); - - $this->extension2->expects($this->once()) - ->method('buildForm') - ->with($builder, $options) - ->willReturnCallback($assertIndex(3)); - - $this->resolvedType->buildForm($builder, $options); + $this->resolvedType->buildForm(new FormBuilder(null, null, new EventDispatcher(), $this->formFactory), []); + + $this->assertSame([$this->parentType, $this->type, $this->extension1, $this->extension2], $this->calls['buildForm']); } public function testCreateView() { - $form = $this->bootstrapForm(); - - $view = $this->resolvedType->createView($form); + $view = $this->resolvedType->createView($this->formFactory->create()); $this->assertInstanceOf(FormView::class, $view); $this->assertNull($view->parent); @@ -247,10 +153,9 @@ public function testCreateView() public function testCreateViewWithParent() { - $form = $this->bootstrapForm(); - $parentView = $this->createMock(FormView::class); + $parentView = new FormView(); - $view = $this->resolvedType->createView($form, $parentView); + $view = $this->resolvedType->createView($this->formFactory->create(), $parentView); $this->assertInstanceOf(FormView::class, $view); $this->assertSame($parentView, $view->parent); @@ -258,97 +163,23 @@ public function testCreateViewWithParent() public function testBuildView() { - $options = ['a' => '1', 'b' => '2']; - $form = $this->bootstrapForm(); - $view = $this->createMock(FormView::class); - - $i = 0; - - $assertIndex = function ($index) use (&$i) { - return function () use (&$i, $index) { - $this->assertEquals($index, $i, 'Executed at index '.$index); - - ++$i; - }; - }; - - // First the super type - $this->parentType->expects($this->once()) - ->method('buildView') - ->with($view, $form, $options) - ->willReturnCallback($assertIndex(0)); - - // Then the type itself - $this->type->expects($this->once()) - ->method('buildView') - ->with($view, $form, $options) - ->willReturnCallback($assertIndex(1)); - - // Then its extensions - $this->extension1->expects($this->once()) - ->method('buildView') - ->with($view, $form, $options) - ->willReturnCallback($assertIndex(2)); - - $this->extension2->expects($this->once()) - ->method('buildView') - ->with($view, $form, $options) - ->willReturnCallback($assertIndex(3)); - - $this->resolvedType->buildView($view, $form, $options); + $this->resolvedType->buildView(new FormView(), $this->formFactory->create(), []); + + $this->assertSame([$this->parentType, $this->type, $this->extension1, $this->extension2], $this->calls['buildView']); } public function testFinishView() { - $options = ['a' => '1', 'b' => '2']; - $form = $this->bootstrapForm(); - $view = $this->createMock(FormView::class); - - $i = 0; - - $assertIndex = function ($index) use (&$i) { - return function () use (&$i, $index) { - $this->assertEquals($index, $i, 'Executed at index '.$index); - - ++$i; - }; - }; - - // First the super type - $this->parentType->expects($this->once()) - ->method('finishView') - ->with($view, $form, $options) - ->willReturnCallback($assertIndex(0)); - - // Then the type itself - $this->type->expects($this->once()) - ->method('finishView') - ->with($view, $form, $options) - ->willReturnCallback($assertIndex(1)); - - // Then its extensions - $this->extension1->expects($this->once()) - ->method('finishView') - ->with($view, $form, $options) - ->willReturnCallback($assertIndex(2)); - - $this->extension2->expects($this->once()) - ->method('finishView') - ->with($view, $form, $options) - ->willReturnCallback($assertIndex(3)); - - $this->resolvedType->finishView($view, $form, $options); + $this->resolvedType->finishView(new FormView(), $this->formFactory->create(), []); + + $this->assertSame([$this->parentType, $this->type, $this->extension1, $this->extension2], $this->calls['finishView']); } public function testGetBlockPrefix() { - $this->type->expects($this->once()) - ->method('getBlockPrefix') - ->willReturn('my_prefix'); + $resolvedType = new ResolvedFormType(new ConfigurableFormType()); - $resolvedType = new ResolvedFormType($this->type); - - $this->assertSame('my_prefix', $resolvedType->getBlockPrefix()); + $this->assertSame('configurable_form_prefix', $resolvedType->getBlockPrefix()); } /** @@ -372,37 +203,84 @@ public function provideTypeClassBlockPrefixTuples() [Fixtures\FBooType::class, 'f_boo'], ]; } +} - /** - * @return MockObject&FormTypeInterface - */ - private function getMockFormType($typeClass = AbstractType::class): FormTypeInterface +class UsageTrackingFormType extends AbstractType +{ + use UsageTrackingTrait; + + public function __construct(array &$calls) { - return $this->getMockBuilder($typeClass)->setMethods(['getBlockPrefix', 'configureOptions', 'finishView', 'buildView', 'buildForm'])->getMock(); + $this->calls = &$calls; } - /** - * @return MockObject&FormTypeExtensionInterface - */ - private function getMockFormTypeExtension(): FormTypeExtensionInterface + public function getParent(): string { - return $this->getMockBuilder(AbstractTypeExtension::class)->setMethods(['getExtendedType', 'configureOptions', 'finishView', 'buildView', 'buildForm'])->getMock(); + return UsageTrackingParentFormType::class; } - /** - * @return MockObject&FormFactoryInterface - */ - private function getMockFormFactory(): FormFactoryInterface + public function configureOptions(OptionsResolver $resolver): void + { + $resolver->setDefault('b', 'b_default'); + $resolver->setDefined('data_class'); + $resolver->setRequired('foo'); + } +} + +class UsageTrackingParentFormType extends AbstractType +{ + use UsageTrackingTrait; + + public function __construct(array &$calls) + { + $this->calls = &$calls; + } + + public function configureOptions(OptionsResolver $resolver): void + { + $resolver->setDefault('a', 'a_default'); + } +} + +class UsageTrackingFormTypeExtension extends AbstractTypeExtension +{ + use UsageTrackingTrait; + + private $defaultOptions; + + public function __construct(array &$calls, array $defaultOptions) + { + $this->calls = &$calls; + $this->defaultOptions = $defaultOptions; + } + + public function configureOptions(OptionsResolver $resolver): void + { + $resolver->setDefaults($this->defaultOptions); + } + + public static function getExtendedTypes(): iterable { - return $this->createMock(FormFactoryInterface::class); + yield FormType::class; + } +} + +trait UsageTrackingTrait +{ + private $calls; + + public function buildForm(FormBuilderInterface $builder, array $options): void + { + $this->calls['buildForm'][] = $this; } - private function bootstrapForm(): Form + public function buildView(FormView $view, FormInterface $form, array $options): void { - $config = $this->createMock(FormConfigInterface::class); - $config->method('getInheritData')->willReturn(false); - $config->method('getName')->willReturn(''); + $this->calls['buildView'][] = $this; + } - return new Form($config); + public function finishView(FormView $view, FormInterface $form, array $options): void + { + $this->calls['finishView'][] = $this; } } diff --git a/src/Symfony/Component/Form/Tests/SimpleFormTest.php b/src/Symfony/Component/Form/Tests/SimpleFormTest.php index 8edfe15634f81..f1f6ce80a585a 100644 --- a/src/Symfony/Component/Form/Tests/SimpleFormTest.php +++ b/src/Symfony/Component/Form/Tests/SimpleFormTest.php @@ -11,22 +11,29 @@ namespace Symfony\Component\Form\Tests; +use PHPUnit\Framework\TestCase; use Symfony\Component\EventDispatcher\EventDispatcher; use Symfony\Component\Form\Exception\AlreadySubmittedException; use Symfony\Component\Form\Exception\LogicException; use Symfony\Component\Form\Exception\RuntimeException; use Symfony\Component\Form\Exception\TransformationFailedException; +use Symfony\Component\Form\Extension\Core\DataMapper\PropertyPathMapper; use Symfony\Component\Form\Form; +use Symfony\Component\Form\FormBuilder; use Symfony\Component\Form\FormConfigBuilder; use Symfony\Component\Form\FormError; use Symfony\Component\Form\FormEvent; use Symfony\Component\Form\FormEvents; +use Symfony\Component\Form\FormFactory; use Symfony\Component\Form\FormInterface; +use Symfony\Component\Form\FormRegistry; use Symfony\Component\Form\FormView; use Symfony\Component\Form\RequestHandlerInterface; +use Symfony\Component\Form\ResolvedFormTypeFactory; use Symfony\Component\Form\ResolvedFormTypeInterface; use Symfony\Component\Form\Tests\Fixtures\FixedDataTransformer; use Symfony\Component\Form\Tests\Fixtures\FixedFilterListener; +use Symfony\Component\Form\Tests\Fixtures\Map; use Symfony\Component\PropertyAccess\PropertyPath; class SimpleFormTest_Countable implements \Countable @@ -59,14 +66,21 @@ public function getIterator(): \Traversable } } -class SimpleFormTest extends AbstractFormTest +class SimpleFormTest extends TestCase { + private $form; + + protected function setUp(): void + { + $this->form = $this->createForm(); + } + /** * @dataProvider provideFormNames */ public function testGetPropertyPath($name, $propertyPath) { - $config = new FormConfigBuilder($name, null, $this->dispatcher); + $config = new FormConfigBuilder($name, null, new EventDispatcher()); $form = new Form($config); $this->assertEquals($propertyPath, $form->getPropertyPath()); @@ -90,7 +104,7 @@ public function testDataIsInitializedToConfiguredValue() 'foo' => 'bar', ]); - $config = new FormConfigBuilder('name', null, $this->dispatcher); + $config = new FormConfigBuilder('name', null, new EventDispatcher()); $config->addViewTransformer($view); $config->addModelTransformer($model); $config->setData('default'); @@ -112,7 +126,7 @@ public function testDataTransformationFailure() 'foo' => 'bar', ]); - $config = new FormConfigBuilder('name', null, $this->dispatcher); + $config = new FormConfigBuilder('name', null, new EventDispatcher()); $config->addViewTransformer($view); $config->addModelTransformer($model); $config->setData('arg'); @@ -127,53 +141,41 @@ public function testDataIsInitializedFromSubmit() $preSetData = false; $preSubmit = false; - $mock = $this->getMockBuilder(\stdClass::class) - ->setMethods(['preSetData', 'preSubmit']) - ->getMock(); - $mock->expects($this->once()) - ->method('preSetData') - ->with($this->callback(function () use (&$preSetData, $preSubmit) { - $preSetData = true; - - return false === $preSubmit; - })); - $mock->expects($this->once()) - ->method('preSubmit') - ->with($this->callback(function () use ($preSetData, &$preSubmit) { - $preSubmit = true; - - return false === $preSetData; - })); - - $config = new FormConfigBuilder('name', null, $this->dispatcher); - $config->addEventListener(FormEvents::PRE_SET_DATA, [$mock, 'preSetData']); - $config->addEventListener(FormEvents::PRE_SUBMIT, [$mock, 'preSubmit']); + $preSetDataListener = static function () use (&$preSetData, &$preSubmit): void { + $preSetData = !$preSubmit; + }; + $preSubmitListener = static function () use (&$preSetData, &$preSubmit): void { + $preSubmit = $preSetData; + }; + + $config = new FormConfigBuilder('name', null, new EventDispatcher()); + $config->addEventListener(FormEvents::PRE_SET_DATA, $preSetDataListener); + $config->addEventListener(FormEvents::PRE_SUBMIT, $preSubmitListener); $form = new Form($config); // no call to setData() or similar where the object would be // initialized otherwise $form->submit('foobar'); + + $this->assertTrue($preSetData); + $this->assertTrue($preSubmit); } // https://github.com/symfony/symfony/pull/7789 public function testFalseIsConvertedToNull() { - $mock = $this->getMockBuilder(\stdClass::class) - ->setMethods(['preSubmit']) - ->getMock(); - $mock->expects($this->once()) - ->method('preSubmit') - ->with($this->callback(function ($event) { - return null === $event->getData(); - })); - - $config = new FormConfigBuilder('name', null, $this->dispatcher); - $config->addEventListener(FormEvents::PRE_SUBMIT, [$mock, 'preSubmit']); + $passedDataIsNull = false; + + $config = new FormConfigBuilder('name', null, new EventDispatcher()); + $config->addEventListener(FormEvents::PRE_SUBMIT, static function (FormEvent $event) use (&$passedDataIsNull): void { + $passedDataIsNull = $event->getData() === null; + }); $form = new Form($config); $form->submit(false); + $this->assertTrue($passedDataIsNull); $this->assertTrue($form->isValid()); $this->assertNull($form->getData()); } @@ -278,7 +280,7 @@ public function testEmptyIfEmptyArray() public function testEmptyIfEmptyCountable() { - $this->form = new Form(new FormConfigBuilder('name', __NAMESPACE__.'\SimpleFormTest_Countable', $this->dispatcher)); + $this->form = new Form(new FormConfigBuilder('name', SimpleFormTest_Countable::class, new EventDispatcher())); $this->form->setData(new SimpleFormTest_Countable(0)); @@ -287,7 +289,7 @@ public function testEmptyIfEmptyCountable() public function testNotEmptyIfFilledCountable() { - $this->form = new Form(new FormConfigBuilder('name', __NAMESPACE__.'\SimpleFormTest_Countable', $this->dispatcher)); + $this->form = new Form(new FormConfigBuilder('name', SimpleFormTest_Countable::class, new EventDispatcher())); $this->form->setData(new SimpleFormTest_Countable(1)); @@ -296,7 +298,7 @@ public function testNotEmptyIfFilledCountable() public function testEmptyIfEmptyTraversable() { - $this->form = new Form(new FormConfigBuilder('name', __NAMESPACE__.'\SimpleFormTest_Traversable', $this->dispatcher)); + $this->form = new Form(new FormConfigBuilder('name', SimpleFormTest_Traversable::class, new EventDispatcher())); $this->form->setData(new SimpleFormTest_Traversable(0)); @@ -305,7 +307,7 @@ public function testEmptyIfEmptyTraversable() public function testNotEmptyIfFilledTraversable() { - $this->form = new Form(new FormConfigBuilder('name', __NAMESPACE__.'\SimpleFormTest_Traversable', $this->dispatcher)); + $this->form = new Form(new FormConfigBuilder('name', SimpleFormTest_Traversable::class, new EventDispatcher())); $this->form->setData(new SimpleFormTest_Traversable(1)); @@ -400,7 +402,7 @@ public function testSetDataThrowsExceptionIfAlreadySubmitted() public function testSetDataClonesObjectIfNotByReference() { $data = new \stdClass(); - $form = $this->getBuilder('name', null, \stdClass::class)->setByReference(false)->getForm(); + $form = $this->getBuilder('name', \stdClass::class)->setByReference(false)->getForm(); $form->setData($data); $this->assertNotSame($data, $form->getData()); @@ -410,7 +412,7 @@ public function testSetDataClonesObjectIfNotByReference() public function testSetDataDoesNotCloneObjectIfByReference() { $data = new \stdClass(); - $form = $this->getBuilder('name', null, \stdClass::class)->setByReference(true)->getForm(); + $form = $this->getBuilder('name', \stdClass::class)->setByReference(true)->getForm(); $form->setData($data); $this->assertSame($data, $form->getData()); @@ -419,7 +421,7 @@ public function testSetDataDoesNotCloneObjectIfByReference() public function testSetDataExecutesTransformationChain() { // use real event dispatcher now - $form = $this->getBuilder('name', new EventDispatcher()) + $form = $this->getBuilder('name') ->addEventSubscriber(new FixedFilterListener([ 'preSetData' => [ 'app' => 'filtered', @@ -542,7 +544,7 @@ public function testSetDataIsIgnoredIfDataIsLocked() public function testPreSetDataChangesDataIfDataIsLocked() { - $config = new FormConfigBuilder('name', null, $this->dispatcher); + $config = new FormConfigBuilder('name', null, new EventDispatcher()); $config ->setData('default') ->setDataLocked(true) @@ -570,7 +572,7 @@ public function testSubmitConvertsEmptyToNullIfNoTransformer() public function testSubmitExecutesTransformationChain() { // use real event dispatcher now - $form = $this->getBuilder('name', new EventDispatcher()) + $form = $this->getBuilder('name') ->addEventSubscriber(new FixedFilterListener([ 'preSubmit' => [ 'client' => 'filteredclient', @@ -649,13 +651,8 @@ public function testSynchronizedAfterSubmission() public function testNotSynchronizedIfViewReverseTransformationFailed() { - $transformer = $this->getDataTransformer(); - $transformer->expects($this->once()) - ->method('reverseTransform') - ->willThrowException(new TransformationFailedException()); - $form = $this->getBuilder() - ->addViewTransformer($transformer) + ->addViewTransformer(new FixedDataTransformer(['' => ''])) ->getForm(); $form->submit('foobar'); @@ -665,13 +662,8 @@ public function testNotSynchronizedIfViewReverseTransformationFailed() public function testNotSynchronizedIfModelReverseTransformationFailed() { - $transformer = $this->getDataTransformer(); - $transformer->expects($this->once()) - ->method('reverseTransform') - ->willThrowException(new TransformationFailedException()); - $form = $this->getBuilder() - ->addModelTransformer($transformer) + ->addModelTransformer(new FixedDataTransformer(['' => ''])) ->getForm(); $form->submit('foobar'); @@ -728,7 +720,7 @@ public function testSubmitResetsErrors() public function testCreateView() { $type = $this->createMock(ResolvedFormTypeInterface::class); - $view = $this->createMock(FormView::class); + $view = new FormView(); $form = $this->getBuilder()->setType($type)->getForm(); $type->expects($this->once()) @@ -742,10 +734,10 @@ public function testCreateView() public function testCreateViewWithParent() { $type = $this->createMock(ResolvedFormTypeInterface::class); - $view = $this->createMock(FormView::class); + $view = new FormView(); $parentType = $this->createMock(ResolvedFormTypeInterface::class); $parentForm = $this->getBuilder()->setType($parentType)->getForm(); - $parentView = $this->createMock(FormView::class); + $parentView = new FormView(); $form = $this->getBuilder()->setType($type)->getForm(); $form->setParent($parentForm); @@ -764,8 +756,8 @@ public function testCreateViewWithParent() public function testCreateViewWithExplicitParent() { $type = $this->createMock(ResolvedFormTypeInterface::class); - $view = $this->createMock(FormView::class); - $parentView = $this->createMock(FormView::class); + $view = new FormView(); + $parentView = new FormView(); $form = $this->getBuilder()->setType($type)->getForm(); $type->expects($this->once()) @@ -797,7 +789,7 @@ public function testFormCannotHaveEmptyNameNotInRootLevel() $this->expectExceptionMessage('A form with an empty name cannot have a parent form.'); $this->getBuilder() ->setCompound(true) - ->setDataMapper($this->getDataMapper()) + ->setDataMapper(new PropertyPathMapper()) ->add($this->getBuilder('')) ->getForm(); } @@ -812,9 +804,9 @@ public function testGetPropertyPathReturnsConfiguredPath() // see https://github.com/symfony/symfony/issues/3903 public function testGetPropertyPathDefaultsToNameIfParentHasDataClass() { - $parent = $this->getBuilder(null, null, 'stdClass') + $parent = $this->getBuilder(null, \stdClass::class) ->setCompound(true) - ->setDataMapper($this->getDataMapper()) + ->setDataMapper(new PropertyPathMapper()) ->getForm(); $form = $this->getBuilder('name')->getForm(); $parent->add($form); @@ -827,7 +819,7 @@ public function testGetPropertyPathDefaultsToIndexedNameIfParentDataClassIsNull( { $parent = $this->getBuilder() ->setCompound(true) - ->setDataMapper($this->getDataMapper()) + ->setDataMapper(new PropertyPathMapper()) ->getForm(); $form = $this->getBuilder('name')->getForm(); $parent->add($form); @@ -837,13 +829,13 @@ public function testGetPropertyPathDefaultsToIndexedNameIfParentDataClassIsNull( public function testGetPropertyPathDefaultsToNameIfFirstParentWithoutInheritDataHasDataClass() { - $grandParent = $this->getBuilder(null, null, 'stdClass') + $grandParent = $this->getBuilder(null, \stdClass::class) ->setCompound(true) - ->setDataMapper($this->getDataMapper()) + ->setDataMapper(new PropertyPathMapper()) ->getForm(); $parent = $this->getBuilder() ->setCompound(true) - ->setDataMapper($this->getDataMapper()) + ->setDataMapper(new PropertyPathMapper()) ->setInheritData(true) ->getForm(); $form = $this->getBuilder('name')->getForm(); @@ -857,11 +849,11 @@ public function testGetPropertyPathDefaultsToIndexedNameIfDataClassOfFirstParent { $grandParent = $this->getBuilder() ->setCompound(true) - ->setDataMapper($this->getDataMapper()) + ->setDataMapper(new PropertyPathMapper()) ->getForm(); $parent = $this->getBuilder() ->setCompound(true) - ->setDataMapper($this->getDataMapper()) + ->setDataMapper(new PropertyPathMapper()) ->setInheritData(true) ->getForm(); $form = $this->getBuilder('name')->getForm(); @@ -874,7 +866,7 @@ public function testGetPropertyPathDefaultsToIndexedNameIfDataClassOfFirstParent public function testViewDataMayBeObjectIfDataClassIsNull() { $object = new \stdClass(); - $config = new FormConfigBuilder('name', null, $this->dispatcher); + $config = new FormConfigBuilder('name', null, new EventDispatcher()); $config->addViewTransformer(new FixedDataTransformer([ '' => '', 'foo' => $object, @@ -888,8 +880,8 @@ public function testViewDataMayBeObjectIfDataClassIsNull() public function testViewDataMayBeArrayAccessIfDataClassIsNull() { - $arrayAccess = $this->createMock(\ArrayAccess::class); - $config = new FormConfigBuilder('name', null, $this->dispatcher); + $arrayAccess = new Map(); + $config = new FormConfigBuilder('name', null, new EventDispatcher()); $config->addViewTransformer(new FixedDataTransformer([ '' => '', 'foo' => $arrayAccess, @@ -904,7 +896,7 @@ public function testViewDataMayBeArrayAccessIfDataClassIsNull() public function testViewDataMustBeObjectIfDataClassIsSet() { $this->expectException(LogicException::class); - $config = new FormConfigBuilder('name', 'stdClass', $this->dispatcher); + $config = new FormConfigBuilder('name', 'stdClass', new EventDispatcher()); $config->addViewTransformer(new FixedDataTransformer([ '' => '', 'foo' => ['bar' => 'baz'], @@ -919,7 +911,7 @@ public function testSetDataCannotInvokeItself() $this->expectException(RuntimeException::class); $this->expectExceptionMessage('A cycle was detected. Listeners to the PRE_SET_DATA event must not call setData(). You should call setData() on the FormEvent object instead.'); // Cycle detection to prevent endless loops - $config = new FormConfigBuilder('name', 'stdClass', $this->dispatcher); + $config = new FormConfigBuilder('name', 'stdClass', new EventDispatcher()); $config->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event) { $event->getForm()->setData('bar'); }); @@ -932,14 +924,14 @@ public function testSubmittingWrongDataIsIgnored() { $called = 0; - $child = $this->getBuilder('child', $this->dispatcher); + $child = $this->getBuilder('child'); $child->addEventListener(FormEvents::PRE_SUBMIT, function () use (&$called) { ++$called; }); - $parent = $this->getBuilder('parent', new EventDispatcher()) + $parent = $this->getBuilder('parent') ->setCompound(true) - ->setDataMapper($this->getDataMapper()) + ->setDataMapper(new PropertyPathMapper()) ->add($child) ->getForm(); @@ -965,25 +957,27 @@ public function testHandleRequestForwardsToRequestHandler() public function testFormInheritsParentData() { - $child = $this->getBuilder('child') - ->setInheritData(true); + $nameForm = $this->getBuilder() + ->setCompound(true) + ->setDataMapper(new PropertyPathMapper()) + ->setInheritData(true) + ->getForm(); + $nameForm->add($firstNameForm = $this->getBuilder('firstName')->getForm()); + $nameForm->add($lastNameForm = $this->getBuilder('lastName')->getForm()); - $parent = $this->getBuilder('parent') + $rootForm = $this->getBuilder('') ->setCompound(true) - ->setDataMapper($this->getDataMapper()) - ->setData('foo') - ->addModelTransformer(new FixedDataTransformer([ - 'foo' => 'norm[foo]', - ])) - ->addViewTransformer(new FixedDataTransformer([ - 'norm[foo]' => 'view[foo]', - ])) - ->add($child) + ->setDataMapper(new PropertyPathMapper()) ->getForm(); + $rootForm->add($nameForm); + $rootForm->setData(['firstName' => 'Christian', 'lastName' => 'Flothmann']); - $this->assertSame('foo', $parent->get('child')->getData()); - $this->assertSame('norm[foo]', $parent->get('child')->getNormData()); - $this->assertSame('view[foo]', $parent->get('child')->getViewData()); + $this->assertSame('Christian', $firstNameForm->getData()); + $this->assertSame('Christian', $firstNameForm->getNormData()); + $this->assertSame('Christian', $firstNameForm->getViewData()); + $this->assertSame('Flothmann', $lastNameForm->getData()); + $this->assertSame('Flothmann', $lastNameForm->getNormData()); + $this->assertSame('Flothmann', $lastNameForm->getViewData()); } public function testInheritDataDisallowsSetData() @@ -1056,14 +1050,12 @@ public function testSubmitIsNeverFiredIfInheritData() public function testInitializeSetsDefaultData() { $config = $this->getBuilder()->setData('DEFAULT')->getFormConfig(); - $form = $this->getMockBuilder(Form::class)->setMethods(['setData'])->setConstructorArgs([$config])->getMock(); - - $form->expects($this->once()) - ->method('setData') - ->with($this->identicalTo('DEFAULT')); + $form = new Form($config); /* @var Form $form */ $form->initialize(); + + $this->assertSame('DEFAULT', $form->getData()); } public function testInitializeFailsIfParent() @@ -1081,7 +1073,7 @@ public function testCannotCallGetDataInPreSetDataListenerIfDataHasNotAlreadyBeen { $this->expectException(RuntimeException::class); $this->expectExceptionMessage('A cycle was detected. Listeners to the PRE_SET_DATA event must not call getData() if the form data has not already been set. You should call getData() on the FormEvent object instead.'); - $config = new FormConfigBuilder('name', 'stdClass', $this->dispatcher); + $config = new FormConfigBuilder('name', 'stdClass', new EventDispatcher()); $config->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event) { $event->getForm()->getData(); }); @@ -1094,7 +1086,7 @@ public function testCannotCallGetNormDataInPreSetDataListener() { $this->expectException(RuntimeException::class); $this->expectExceptionMessage('A cycle was detected. Listeners to the PRE_SET_DATA event must not call getNormData() if the form data has not already been set.'); - $config = new FormConfigBuilder('name', 'stdClass', $this->dispatcher); + $config = new FormConfigBuilder('name', 'stdClass', new EventDispatcher()); $config->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event) { $event->getForm()->getNormData(); }); @@ -1107,7 +1099,7 @@ public function testCannotCallGetViewDataInPreSetDataListener() { $this->expectException(RuntimeException::class); $this->expectExceptionMessage('A cycle was detected. Listeners to the PRE_SET_DATA event must not call getViewData() if the form data has not already been set.'); - $config = new FormConfigBuilder('name', 'stdClass', $this->dispatcher); + $config = new FormConfigBuilder('name', 'stdClass', new EventDispatcher()); $config->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event) { $event->getForm()->getViewData(); }); @@ -1116,8 +1108,13 @@ public function testCannotCallGetViewDataInPreSetDataListener() $form->setData('foo'); } - protected function createForm(): FormInterface + private function createForm(): FormInterface { return $this->getBuilder()->getForm(); } + + private function getBuilder(?string $name = 'name', string $dataClass = null, array $options = []): FormBuilder + { + return new FormBuilder($name, $dataClass, new EventDispatcher(), new FormFactory(new FormRegistry([], new ResolvedFormTypeFactory())), $options); + } }