CollectionValidatorTest.php 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357
  1. <?php
  2. /*
  3. * This file is part of the Symfony package.
  4. *
  5. * (c) Fabien Potencier <fabien@symfony.com>
  6. *
  7. * For the full copyright and license information, please view the LICENSE
  8. * file that was distributed with this source code.
  9. */
  10. namespace Symfony\Tests\Component\Validator\Constraints;
  11. use Symfony\Component\Validator\ExecutionContext;
  12. use Symfony\Component\Validator\Constraints\Min;
  13. use Symfony\Component\Validator\Constraints\NotBlank;
  14. use Symfony\Component\Validator\Constraints\NotNull;
  15. use Symfony\Component\Validator\Constraints\Collection;
  16. use Symfony\Component\Validator\Constraints\CollectionValidator;
  17. /**
  18. * This class is a hand written simplified version of PHP native `ArrayObject`
  19. * class, to show that it behaves different than PHP native implementation.
  20. */
  21. class TestArrayObject implements \ArrayAccess, \IteratorAggregate, \Countable, \Serializable
  22. {
  23. private $array;
  24. public function __construct(array $array = null)
  25. {
  26. $this->array = (array) ($array ?: array());
  27. }
  28. public function offsetExists($offset)
  29. {
  30. return array_key_exists($offset, $this->array);
  31. }
  32. public function offsetGet($offset)
  33. {
  34. return $this->array[$offset];
  35. }
  36. public function offsetSet($offset, $value)
  37. {
  38. if (null === $offset) {
  39. $this->array[] = $value;
  40. } else {
  41. $this->array[$offset] = $value;
  42. }
  43. }
  44. public function offsetUnset($offset)
  45. {
  46. if (array_key_exists($offset, $this->array)) {
  47. unset($this->array[$offset]);
  48. }
  49. }
  50. public function getIterator()
  51. {
  52. return new \ArrayIterator($this->array);
  53. }
  54. public function count()
  55. {
  56. return count($this->array);
  57. }
  58. public function serialize()
  59. {
  60. return serialize($this->array);
  61. }
  62. public function unserialize($serialized)
  63. {
  64. $this->array = (array) unserialize((string) $serialized);
  65. }
  66. }
  67. class CollectionValidatorTest extends \PHPUnit_Framework_TestCase
  68. {
  69. protected $validator;
  70. protected $walker;
  71. protected $context;
  72. protected function setUp()
  73. {
  74. $this->walker = $this->getMock('Symfony\Component\Validator\GraphWalker', array(), array(), '', false);
  75. $metadataFactory = $this->getMock('Symfony\Component\Validator\Mapping\ClassMetadataFactoryInterface');
  76. $this->context = new ExecutionContext('Root', $this->walker, $metadataFactory);
  77. $this->validator = new CollectionValidator();
  78. $this->validator->initialize($this->context);
  79. }
  80. protected function tearDown()
  81. {
  82. $this->validator = null;
  83. $this->walker = null;
  84. $this->context = null;
  85. }
  86. public function testNullIsValid()
  87. {
  88. $this->assertTrue($this->validator->isValid(null, new Collection(array('fields' => array(
  89. 'foo' => new Min(4),
  90. )))));
  91. }
  92. public function testFieldsAsDefaultOption()
  93. {
  94. $this->assertTrue($this->validator->isValid(array('foo' => 'foobar'), new Collection(array(
  95. 'foo' => new Min(4),
  96. ))));
  97. $this->assertTrue($this->validator->isValid(new \ArrayObject(array('foo' => 'foobar')), new Collection(array(
  98. 'foo' => new Min(4),
  99. ))));
  100. $this->assertTrue($this->validator->isValid(new TestArrayObject(array('foo' => 'foobar')), new Collection(array(
  101. 'foo' => new Min(4),
  102. ))));
  103. }
  104. /**
  105. * @expectedException Symfony\Component\Validator\Exception\UnexpectedTypeException
  106. */
  107. public function testThrowsExceptionIfNotTraversable()
  108. {
  109. $this->validator->isValid('foobar', new Collection(array('fields' => array(
  110. 'foo' => new Min(4),
  111. ))));
  112. }
  113. /**
  114. * @dataProvider getValidArguments
  115. */
  116. public function testWalkSingleConstraint($array)
  117. {
  118. $this->context->setGroup('MyGroup');
  119. $this->context->setPropertyPath('foo');
  120. $constraint = new Min(4);
  121. foreach ($array as $key => $value) {
  122. $this->walker->expects($this->once())
  123. ->method('walkConstraint')
  124. ->with($this->equalTo($constraint), $this->equalTo($value), $this->equalTo('MyGroup'), $this->equalTo('foo['.$key.']'));
  125. }
  126. $this->assertTrue($this->validator->isValid($array, new Collection(array(
  127. 'fields' => array(
  128. 'foo' => $constraint,
  129. ),
  130. ))));
  131. }
  132. /**
  133. * @dataProvider getValidArguments
  134. */
  135. public function testWalkMultipleConstraints($array)
  136. {
  137. $this->context->setGroup('MyGroup');
  138. $this->context->setPropertyPath('foo');
  139. $constraint = new Min(4);
  140. // can only test for twice the same constraint because PHPUnits mocking
  141. // can't test method calls with different arguments
  142. $constraints = array($constraint, $constraint);
  143. foreach ($array as $key => $value) {
  144. $this->walker->expects($this->exactly(2))
  145. ->method('walkConstraint')
  146. ->with($this->equalTo($constraint), $this->equalTo($value), $this->equalTo('MyGroup'), $this->equalTo('foo['.$key.']'));
  147. }
  148. $this->assertTrue($this->validator->isValid($array, new Collection(array(
  149. 'fields' => array(
  150. 'foo' => $constraints,
  151. )
  152. ))));
  153. }
  154. /**
  155. * @dataProvider getArgumentsWithExtraFields
  156. */
  157. public function testExtraFieldsDisallowed($array)
  158. {
  159. $this->assertFalse($this->validator->isValid($array, new Collection(array(
  160. 'fields' => array(
  161. 'foo' => new Min(4),
  162. ),
  163. ))));
  164. }
  165. // bug fix
  166. public function testNullNotConsideredExtraField()
  167. {
  168. $array = array(
  169. 'foo' => null,
  170. );
  171. $collection = new Collection(array(
  172. 'fields' => array(
  173. 'foo' => new Min(4),
  174. ),
  175. ));
  176. $this->assertTrue($this->validator->isValid($array, $collection));
  177. $this->assertTrue($this->validator->isValid(new \ArrayObject($array), $collection));
  178. $this->assertTrue($this->validator->isValid(new TestArrayObject($array), $collection));
  179. }
  180. public function testExtraFieldsAllowed()
  181. {
  182. $array = array(
  183. 'foo' => 5,
  184. 'bar' => 6,
  185. );
  186. $collection = new Collection(array(
  187. 'fields' => array(
  188. 'foo' => new Min(4),
  189. ),
  190. 'allowExtraFields' => true,
  191. ));
  192. $this->assertTrue($this->validator->isValid($array, $collection));
  193. $this->assertTrue($this->validator->isValid(new \ArrayObject($array), $collection));
  194. $this->assertTrue($this->validator->isValid(new TestArrayObject($array), $collection));
  195. }
  196. public function testMissingFieldsDisallowed()
  197. {
  198. $this->assertFalse($this->validator->isValid(array(), new Collection(array(
  199. 'fields' => array(
  200. 'foo' => new Min(4),
  201. ),
  202. ))));
  203. $this->assertFalse($this->validator->isValid(new \ArrayObject(array()), new Collection(array(
  204. 'fields' => array(
  205. 'foo' => new Min(4),
  206. ),
  207. ))));
  208. $this->assertFalse($this->validator->isValid(new TestArrayObject(array()), new Collection(array(
  209. 'fields' => array(
  210. 'foo' => new Min(4),
  211. ),
  212. ))));
  213. }
  214. public function testMissingFieldsAllowed()
  215. {
  216. $this->assertTrue($this->validator->isValid(array(), new Collection(array(
  217. 'fields' => array(
  218. 'foo' => new Min(4),
  219. ),
  220. 'allowMissingFields' => true,
  221. ))));
  222. $this->assertTrue($this->validator->isValid(new \ArrayObject(array()), new Collection(array(
  223. 'fields' => array(
  224. 'foo' => new Min(4),
  225. ),
  226. 'allowMissingFields' => true,
  227. ))));
  228. $this->assertTrue($this->validator->isValid(new TestArrayObject(array()), new Collection(array(
  229. 'fields' => array(
  230. 'foo' => new Min(4),
  231. ),
  232. 'allowMissingFields' => true,
  233. ))));
  234. }
  235. public function testArrayAccessObject() {
  236. $value = new TestArrayObject();
  237. $value['foo'] = 12;
  238. $value['asdf'] = 'asdfaf';
  239. $this->assertTrue(isset($value['asdf']));
  240. $this->assertTrue(isset($value['foo']));
  241. $this->assertFalse(empty($value['asdf']));
  242. $this->assertFalse(empty($value['foo']));
  243. $result = $this->validator->isValid($value, new Collection(array(
  244. 'fields' => array(
  245. 'foo' => new NotBlank(),
  246. 'asdf' => new NotBlank()
  247. )
  248. )));
  249. $this->assertTrue($result);
  250. }
  251. public function testArrayObject() {
  252. $value = new \ArrayObject(array());
  253. $value['foo'] = 12;
  254. $value['asdf'] = 'asdfaf';
  255. $this->assertTrue(isset($value['asdf']));
  256. $this->assertTrue(isset($value['foo']));
  257. $this->assertFalse(empty($value['asdf']));
  258. $this->assertFalse(empty($value['foo']));
  259. $result = $this->validator->isValid($value, new Collection(array(
  260. 'fields' => array(
  261. 'foo' => new NotBlank(),
  262. 'asdf' => new NotBlank()
  263. )
  264. )));
  265. $this->assertTrue($result);
  266. }
  267. public function testObjectShouldBeLeftUnchanged()
  268. {
  269. $value = new \ArrayObject(array(
  270. 'foo' => 3
  271. ));
  272. $this->validator->isValid($value, new Collection(array(
  273. 'fields' => array(
  274. 'foo' => new Min(2),
  275. )
  276. )));
  277. $this->assertEquals(array(
  278. 'foo' => 3
  279. ), (array) $value);
  280. }
  281. public function getValidArguments()
  282. {
  283. return array(
  284. // can only test for one entry, because PHPUnits mocking does not allow
  285. // to expect multiple method calls with different arguments
  286. array(array('foo' => 3)),
  287. array(new \ArrayObject(array('foo' => 3))),
  288. array(new TestArrayObject(array('foo' => 3))),
  289. );
  290. }
  291. public function getArgumentsWithExtraFields()
  292. {
  293. return array(
  294. array(array(
  295. 'foo' => 5,
  296. 'bar' => 6,
  297. )),
  298. array(new \ArrayObject(array(
  299. 'foo' => 5,
  300. 'bar' => 6,
  301. ))),
  302. array(new TestArrayObject(array(
  303. 'foo' => 5,
  304. 'bar' => 6,
  305. )))
  306. );
  307. }
  308. }