diff --git a/src/Query.php b/src/Query.php index 5e58032..3c23e58 100644 --- a/src/Query.php +++ b/src/Query.php @@ -90,22 +90,23 @@ protected static function replaceHolder($pdo, $key, $type, $value, &$bind_values } if ($type === '@int') { + if (is_int($value)) { + return $value; + } + if (!is_numeric($value)) { throw new \DomainException(sprintf('param "%s" must be numeric', $key)); } - $s = (string)$value; - if ($s < self::INT64_MIN || self::INT64_MAX < $s) { + if ($value < self::INT64_MIN || self::INT64_MAX < $value) { throw new \DomainException(sprintf('param "%s" is integer out of range.', $key)); } - $is_zero = $s === 0 || $s === '0'; - - if (!$is_zero && !preg_match('/\A-?[1-9][0-9]*\z/', $s)) { - throw new \DomainException(); + if ($value !== '0' && !preg_match('/\A-?[1-9][0-9]*\z/', $value)) { + throw new \DomainException(sprintf('param "%s" is unexpected integer notation.', $key)); } - return (int)$s; + return (int)$value; } if ($type === '@int[]') { @@ -128,7 +129,7 @@ protected static function replaceHolder($pdo, $key, $type, $value, &$bind_values throw new \LogicException('Validation Error.'); } - if (!preg_match('/\A(?:-?[1-9][0-9]*)(?:,-?[1-9][0-9]*)*\z/', $valuesString)) { + if ($value !== '0' && !preg_match('/\A(?:-?[1-9][0-9]*)(?:,-?[1-9][0-9]*)*\z/', $valuesString)) { throw new \DomainException(sprintf('param "%s[%]"')); } @@ -168,7 +169,7 @@ protected static function replaceHolder($pdo, $key, $type, $value, &$bind_values return $key; } - if ($type === '') { + if ($type === '' || $type === '@') { throw new \DomainException(sprintf('type specifier for param "%s" not found', $key)); } else { throw new \DomainException(sprintf('unexpected type "%s"', $type)); diff --git a/tests/Query/ReplaceHolderTest.php b/tests/Query/ReplaceHolderTest.php new file mode 100644 index 0000000..229c2e3 --- /dev/null +++ b/tests/Query/ReplaceHolderTest.php @@ -0,0 +1,89 @@ + + * @copyright 2019 USAMI Kenta + * @license https://github.com/BaguettePHP/TetoSQL/blob/master/LICENSE MPL-2.0 + */ +final class ReplaceHolderTest extends \PHPUnit\Framework\TestCase +{ + /** + * @dataProvider acceptDataProvider + */ + public function test_accept($type, $input, $expected) + { + $pdo = new DummyPDO(); + + $actual = call_user_func(\Closure::bind(function () use ($pdo, $type, $input) { + return Query::replaceHolder($pdo, ':key', "@{$type}", $input, $bind_values); + }, null, Query::class)); + + $this->assertSame($expected, $actual); + } + + public function acceptDataProvider() + { + return [ + ['ascdesc', 'ASC', 'ASC'], + ['ascdesc', 'DESC', 'DESC'], + ['ascdesc', 'asc', 'asc'], + ['ascdesc', 'desc', 'desc'], + ['int', 1, 1], + ['int', '1', 1], + ['int', 0, 0], + ['int', '0', 0], + ['int', '9223372036854775807', 9223372036854775807], + ['int', '-9223372036854775808', (int)'-9223372036854775808'], + ['int[]', [1, 2, 3], '1,2,3'], + ['int[]', ['1', '2', '3'], '1,2,3'], + ['int[]', + ['9223372036854775807', '-9223372036854775808'], + '9223372036854775807,-9223372036854775808', + ], + ['string', 0, '@0@'], + ['string', '0', '@0@'], + ['string', '', '@@'], + ['string[]', ['', ''], '@@,@@'], + ]; + } + + /** + * @dataProvider rejeceptDataProvider + */ + public function test_raise_exception($type, $input, $expected_message) + { + $pdo = new DummyPDO(); + + $this->expectException(\DomainException::class); + $this->expectExceptionMessage($expected_message); + + call_user_func(\Closure::bind(function () use ($pdo, $type, $input) { + return Query::replaceHolder($pdo, ':key', $type, $input, $bind_values); + }, null, Query::class)); + } + + public function rejeceptDataProvider() + { + return [ + ['', null, 'type specifier for param ":key" not found'], + ['@', null, 'type specifier for param ":key" not found'], + ['@piyo', null, 'unexpected type "@piyo"'], + ['@ascdesc', 'foo', 'param ":key" must be "ASC", "DESC", "asc" or "desc"'], + ['@int', '-0', 'param ":key" is unexpected integer notation'], + ['@int', '9223372036854775808', 'param ":key" is integer out of range.'], + ['@int', '-9223372036854775809', 'param ":key" is integer out of range.'], + ['@int[]', 0, 'param ":key" must be int array'], + ['@int[]', [], 'param ":key" must be not empty int array'], + ['@int[]', ['1', 'a', '3'], 'param ":key[]" is integer out of range.'], + ['@string', [], 'param ":key" must be string or numeric'], + ['@string[]', '', 'param ":key" must be string array'], + ['@string[]', [], 'param ":key" must be not empty string array'], + ['@string[]', ['', null], 'element of param ":key" must be string or numeric'], + ]; + } +} diff --git a/tests/SQLite/QueryTest.php b/tests/SQLite/QueryTest.php index bfbbc39..b3f74bd 100644 --- a/tests/SQLite/QueryTest.php +++ b/tests/SQLite/QueryTest.php @@ -27,7 +27,7 @@ public function setUp() public function getPDO() { - if (is_null($this->pdo)) { + if ($this->pdo === null) { $dsn = 'sqlite:/' . __DIR__ . '/db.sq3'; $this->pdo = new \PDO($dsn, null, null, [\PDO::ATTR_PERSISTENT => true]); }