diff --git a/src/Bitwise.php b/src/Bitwise.php new file mode 100644 index 000000000..7ccdc5c1d --- /dev/null +++ b/src/Bitwise.php @@ -0,0 +1,192 @@ +<?php +/** + * Zend Framework (http://framework.zend.com/) + * + * @link http://github.com/zendframework/zf2 for the canonical source repository + * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ + +namespace Zend\Validator; + +use Traversable; + +class Bitwise extends AbstractValidator +{ + const OP_AND = 'and'; + const OP_XOR = 'xor'; + + const NOT_AND = 'notAnd'; + const NOT_AND_STRICT = 'notAndStrict'; + const NOT_XOR = 'notXor'; + + /** + * @var integer + */ + protected $control; + + /** + * Validation failure message template definitions + * + * @var array + */ + protected $messageTemplates = array( + self::NOT_AND => "The input has no common bit set with '%control%'", + self::NOT_AND_STRICT => "The input doesn't have the same bits set as '%control%'", + self::NOT_XOR => "The input has common bit set with '%control%'", + ); + + /** + * Additional variables available for validation failure messages + * + * @var array + */ + protected $messageVariables = array( + 'control' => 'control', + ); + + /** + * @var integer + */ + protected $operator; + + /** + * @var boolean + */ + protected $strict = false; + + /** + * Sets validator options + * Accepts the following option keys: + * 'control' => integer + * 'operator' => + * 'strict' => boolean + * + * @param array|Traversable $options + */ + public function __construct($options = null) + { + if ($options instanceof Traversable) { + $options = iterator_to_array($options); + } + + if (!is_array($options)) { + $options = func_get_args(); + + $temp['control'] = array_shift($options); + + if (!empty($options)) { + $temp['operator'] = array_shift($options); + } + + if (!empty($options)) { + $temp['strict'] = array_shift($options); + } + + $options = $temp; + } + + parent::__construct($options); + } + + /** + * Returns the control parameter. + * + * @return integer + */ + public function getControl() + { + return $this->control; + } + + /** + * Returns the operator parameter. + * + * @return string + */ + public function getOperator() + { + return $this->operator; + } + + /** + * Returns the strict parameter. + * + * @return boolean + */ + public function getStrict() + { + return $this->strict; + } + + /** + * Returns true if and only if $value is between min and max options, inclusively + * if inclusive option is true. + * + * @param mixed $value + * @return bool + */ + public function isValid($value) + { + $this->setValue($value); + + if (self::OP_AND === $this->operator) { + if ($this->strict) { + // All the bits set in value must be set in control + $this->error(self::NOT_AND_STRICT); + + return (bool) (($this->control & $value) == $value); + } else { + // At least one of the bits must be common between value and control + $this->error(self::NOT_AND); + + return (bool) ($this->control & $value); + } + } elseif (self::OP_XOR === $this->operator) { + $this->error(self::NOT_XOR); + + return (bool) (($this->control ^ $value) === ($this->control | $value)); + } + + return false; + } + + /** + * Sets the control parameter. + * + * @param integer $control + * @return Bitwise + */ + public function setControl($control) + { + $this->control = (int) $control; + + return $this; + } + + /** + * Sets the operator parameter. + * + * @param string $operator + * @return Bitwise + */ + public function setOperator($operator) + { + $this->operator = $operator; + + return $this; + } + + /** + * Sets the strict parameter. + * + * @param boolean $strict + * @return Bitwise + */ + public function setStrict($strict) + { + $this->strict = (bool) $strict; + + return $this; + } +} diff --git a/test/BitwiseTest.php b/test/BitwiseTest.php new file mode 100644 index 000000000..da93ef82b --- /dev/null +++ b/test/BitwiseTest.php @@ -0,0 +1,181 @@ +<?php +/** + * Zend Framework (http://framework.zend.com/) + * + * @link http://github.com/zendframework/zf2 for the canonical source repository + * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com) + * @license http://framework.zend.com/license/new-bsd New BSD License + */ + +namespace ZendTest\Validator; + +use Zend\Validator\Bitwise; + +class BitwiseTest extends \PHPUnit_Framework_TestCase +{ + /** + * @var \Zend\Validator\Bitwise + */ + public $validator; + + public function setUp() + { + $this->validator = new Bitwise(); + } + + /** + * @covers \Zend\Validator\Bitwise::__construct() + * @dataProvider constructDataProvider + * + * @param array $args + * @param array $options + */ + public function testConstruct(array $args, array $options) + { + $validator = new Bitwise($args); + + $this->assertSame($options['control'], $validator->getControl()); + $this->assertSame($options['operator'], $validator->getOperator()); + $this->assertSame($options['strict'], $validator->getStrict()); + } + + public function constructDataProvider() + { + return array( + array( + array(), + array('control' => null, 'operator' => null, 'strict' => false), + ), + array( + array('control' => 0x1), + array('control' => 0x1, 'operator' => null, 'strict' => false), + ), + array( + array('control' => 0x1, 'operator' => Bitwise::OP_AND), + array('control' => 0x1, 'operator' => Bitwise::OP_AND, 'strict' => false), + ), + array( + array('control' => 0x1, 'operator' => Bitwise::OP_AND, 'strict' => true), + array('control' => 0x1, 'operator' => Bitwise::OP_AND, 'strict' => true), + ), + ); + + } + + /** + * @covers \Zend\Validator\Bitwise::isvalid() + */ + public function testBitwiseAndNotStrict() + { + $controlSum = 0x7; // (0x1 | 0x2 | 0x4) === 0x7 + + $validator = new Bitwise(); + $validator->setControl($controlSum); + $validator->setOperator(Bitwise::OP_AND); + + $this->assertTrue($validator->isValid(0x1)); + $this->assertTrue($validator->isValid(0x2)); + $this->assertTrue($validator->isValid(0x4)); + $this->assertFalse($validator->isValid(0x8)); + + $validator->isValid(0x8); + $messages = $validator->getMessages(); + $this->assertArrayHasKey($validator::NOT_AND, $messages); + $this->assertSame("The input has no common bit set with '$controlSum'", $messages[$validator::NOT_AND]); + + $this->assertTrue($validator->isValid(0x1 | 0x2)); + $this->assertTrue($validator->isValid(0x1 | 0x2 | 0x4)); + $this->assertTrue($validator->isValid(0x1 | 0x8)); + } + + /** + * @covers \Zend\Validator\Bitwise::isvalid() + */ + public function testBitwiseAndStrict() + { + $controlSum = 0x7; // (0x1 | 0x2 | 0x4) === 0x7 + + $validator = new Bitwise(); + $validator->setControl($controlSum); + $validator->setOperator(Bitwise::OP_AND); + $validator->setStrict(true); + + $this->assertTrue($validator->isValid(0x1)); + $this->assertTrue($validator->isValid(0x2)); + $this->assertTrue($validator->isValid(0x4)); + $this->assertFalse($validator->isValid(0x8)); + + $validator->isValid(0x8); + $messages = $validator->getMessages(); + $this->assertArrayHasKey($validator::NOT_AND_STRICT, $messages); + $this->assertSame("The input doesn't have the same bits set as '$controlSum'", $messages[$validator::NOT_AND_STRICT]); + + $this->assertTrue($validator->isValid(0x1 | 0x2)); + $this->assertTrue($validator->isValid(0x1 | 0x2 | 0x4)); + $this->assertFalse($validator->isValid(0x1 | 0x8)); + } + + /** + * @covers \Zend\Validator\Bitwise::isvalid() + */ + public function testBitwiseXor() + { + $controlSum = 0x5; // (0x1 | 0x4) === 0x5 + + $validator = new Bitwise(); + $validator->setControl($controlSum); + $validator->setOperator(Bitwise::OP_XOR); + + $this->assertTrue($validator->isValid(0x2)); + $this->assertTrue($validator->isValid(0x8)); + $this->assertTrue($validator->isValid(0x10)); + $this->assertFalse($validator->isValid(0x1)); + $this->assertFalse($validator->isValid(0x4)); + + $validator->isValid(0x4); + $messages = $validator->getMessages(); + $this->assertArrayHasKey($validator::NOT_XOR, $messages); + $this->assertSame("The input has common bit set with '$controlSum'", $messages[$validator::NOT_XOR]); + + $this->assertTrue($validator->isValid(0x8 | 0x10)); + $this->assertFalse($validator->isValid(0x1 | 0x4)); + $this->assertFalse($validator->isValid(0x1 | 0x8)); + $this->assertFalse($validator->isValid(0x4 | 0x8)); + } + + /** + * @covers \Zend\Validator\Bitwise::setOperator() + */ + public function testSetOperator() + { + $validator = new Bitwise(); + + $validator->setOperator(Bitwise::OP_AND); + $this->assertSame(Bitwise::OP_AND, $validator->getOperator()); + + $validator->setOperator(Bitwise::OP_XOR); + $this->assertSame(Bitwise::OP_XOR, $validator->getOperator()); + } + + /** + * @covers \Zend\Validator\Bitwise::setStrict() + */ + public function testSetStrict() + { + $validator = new Bitwise(); + + $this->assertFalse($validator->getStrict(), 'Strict false by default'); + + $validator->setStrict(false); + $this->assertFalse($validator->getStrict()); + + $validator->setStrict(true); + $this->assertTrue($validator->getStrict()); + + $validator = new Bitwise(0x1, Bitwise::OP_AND, false); + $this->assertFalse($validator->getStrict()); + + $validator = new Bitwise(0x1, Bitwise::OP_AND, true); + $this->assertTrue($validator->getStrict()); + } +}