mirror of
https://code.mensbeam.com/MensBeam/Arsse.git
synced 2024-12-22 13:12:41 +00:00
More binding tests and related changes
- Introduced abstract Statement class to hold common methods - Common methods currently consist of a date formatter and type caster - Moved binding tests to a trait for reuse with future drivers
This commit is contained in:
parent
1529fc367a
commit
0c410fcf50
8 changed files with 369 additions and 159 deletions
|
@ -291,16 +291,14 @@ class Database {
|
|||
throw new Feed\Exception($url, $e);
|
||||
}
|
||||
|
||||
$this->db->prepare("INSERT INTO newssync_feeds(url,title,favicon,source,updated,modified,etag,username,password) values(?,?,?)", "str", "str", "str", "str", "str", "str", "str", "str", "str")->run(
|
||||
$this->db->prepare("INSERT INTO newssync_feeds(url,title,favicon,source,updated,modified,etag,username,password) values(?,?,?,?,?,?,?,?,?)", "str", "str", "str", "str", "datetime", "datetime", "str", "str", "str")->run(
|
||||
$url,
|
||||
$feed->title,
|
||||
// Grab the favicon for the Goodfeed; returns an empty string if it cannot find one.
|
||||
(new PicoFeed\Reader\Favicon)->find($url),
|
||||
$feed->siteUrl,
|
||||
// Convert the date formats to SQL date format before inserting.
|
||||
// FIXME: Dates should be formatted transparently by the driver's Statement wrapper, not here
|
||||
$this->driver::formatDate($feed->date),
|
||||
$this->driver::formatDate($resource->getLastModified()),
|
||||
$feed->date,
|
||||
$resource->getLastModified(),
|
||||
$resource->getEtag(),
|
||||
$fetchUser,
|
||||
$fetchPassword
|
||||
|
|
89
lib/Db/AbstractStatement.php
Normal file
89
lib/Db/AbstractStatement.php
Normal file
|
@ -0,0 +1,89 @@
|
|||
<?php
|
||||
declare(strict_types=1);
|
||||
namespace JKingWeb\NewsSync\Db;
|
||||
|
||||
abstract class AbstractStatement implements Statement {
|
||||
|
||||
abstract function runArray(array $values): Result;
|
||||
abstract static function dateFormat(int $part = self::TS_BOTH): string;
|
||||
|
||||
public function run(...$values): Result {
|
||||
return $this->runArray($values);
|
||||
}
|
||||
|
||||
public function rebind(...$bindings): bool {
|
||||
return $this->rebindArray($bindings);
|
||||
}
|
||||
|
||||
public function rebindArray(array $bindings): bool {
|
||||
$this->types = [];
|
||||
foreach($bindings as $binding) {
|
||||
$binding = trim(strtolower($binding));
|
||||
if(!array_key_exists($binding, self::TYPES)) throw new Exception("paramTypeInvalid", $binding);
|
||||
$this->types[] = self::TYPES[$binding];
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
protected function cast($v, string $t) {
|
||||
switch($t) {
|
||||
case "date":
|
||||
return $this->formatDate($v, self::TS_DATE);
|
||||
case "time":
|
||||
return $this->formatDate($v, self::TS_TIME);
|
||||
case "datetime":
|
||||
return $this->formatDate($v, self::TS_BOTH);
|
||||
case "null":
|
||||
case "integer":
|
||||
case "float":
|
||||
case "binary":
|
||||
case "string":
|
||||
case "boolean":
|
||||
if($t=="binary") $t = "string";
|
||||
$value = $v;
|
||||
try{
|
||||
settype($value, $t);
|
||||
} catch(\Throwable $e) {
|
||||
// handle objects
|
||||
$value = $v;
|
||||
if($value instanceof \DateTimeInterface) {
|
||||
$value = $value->getTimestamp();
|
||||
if($t=="string") $value = $this->formatDate($value, self::TS_BOTH);
|
||||
settype($value, $t);
|
||||
} else {
|
||||
$value = null;
|
||||
settype($value, $t);
|
||||
}
|
||||
}
|
||||
return $value;
|
||||
default:
|
||||
throw new Exception("paramTypeUnknown", $type);
|
||||
}
|
||||
}
|
||||
|
||||
protected function formatDate($date, int $part = self::TS_BOTH) {
|
||||
// Force UTC.
|
||||
$timezone = date_default_timezone_get();
|
||||
date_default_timezone_set('UTC');
|
||||
// convert input to a Unix timestamp
|
||||
// FIXME: there are more kinds of date representations
|
||||
if($date instanceof \DateTimeInterface) {
|
||||
$time = $date->getTimestamp();
|
||||
} else if(is_numeric($date)) {
|
||||
$time = (int) $date;
|
||||
} else if($date===null) {
|
||||
return null;
|
||||
} else if(is_string($date)) {
|
||||
$time = strtotime($date);
|
||||
if($time===false) return null;
|
||||
} else if (is_bool($date)) {
|
||||
return null;
|
||||
} else {
|
||||
$time = (int) $date;
|
||||
}
|
||||
// ISO 8601 with space in the middle instead of T.
|
||||
$date = date($this->dateFormat($part), $time);
|
||||
date_default_timezone_set($timezone);
|
||||
return $date;
|
||||
}
|
||||
}
|
|
@ -69,23 +69,4 @@ Trait Common {
|
|||
public function prepare(string $query, string ...$paramType): Statement {
|
||||
return $this->prepareArray($query, $paramType);
|
||||
}
|
||||
|
||||
public static function formatDate($date, int $precision = self::TS_BOTH): string {
|
||||
// Force UTC.
|
||||
$timezone = date_default_timezone_get();
|
||||
date_default_timezone_set('UTC');
|
||||
// convert input to a Unix timestamp
|
||||
// FIXME: there are more kinds of date representations
|
||||
if(is_int($date)) {
|
||||
$time = $date;
|
||||
} else if($date===null) {
|
||||
$time = 0;
|
||||
} else {
|
||||
$time = strtotime($date);
|
||||
}
|
||||
// ISO 8601 with space in the middle instead of T.
|
||||
$date = date(self::TS_FORMAT[$precision], $time);
|
||||
date_default_timezone_set($timezone);
|
||||
return $date;
|
||||
}
|
||||
}
|
|
@ -3,16 +3,6 @@ declare(strict_types=1);
|
|||
namespace JKingWeb\NewsSync\Db;
|
||||
|
||||
interface Driver {
|
||||
const TS_TIME = -1;
|
||||
const TS_DATE = 0;
|
||||
const TS_BOTH = 1;
|
||||
|
||||
const TS_FORMAT = [
|
||||
self::TS_TIME => 'h:i:sP',
|
||||
self::TS_DATE => 'Y-m-d',
|
||||
self::TS_BOTH => 'Y-m-d h:i:sP',
|
||||
];
|
||||
|
||||
function __construct(\JKingWeb\NewsSync\RuntimeData $data, bool $install = false);
|
||||
// returns a human-friendly name for the driver (for display in installer, for example)
|
||||
static function driverName(): string;
|
||||
|
|
|
@ -3,7 +3,9 @@ declare(strict_types=1);
|
|||
namespace JKingWeb\NewsSync\Db;
|
||||
|
||||
interface Statement {
|
||||
|
||||
const TS_TIME = -1;
|
||||
const TS_DATE = 0;
|
||||
const TS_BOTH = 1;
|
||||
const TYPES = [
|
||||
"null" => "null",
|
||||
"nil" => "null",
|
||||
|
@ -20,14 +22,16 @@ interface Statement {
|
|||
"blob" => "binary",
|
||||
"bin" => "binary",
|
||||
"binary" => "binary",
|
||||
"text" => "text",
|
||||
"string" => "text",
|
||||
"str" => "text",
|
||||
"text" => "string",
|
||||
"string" => "string",
|
||||
"str" => "string",
|
||||
"bool" => "boolean",
|
||||
"boolean" => "boolean",
|
||||
"bit" => "boolean",
|
||||
];
|
||||
|
||||
static function dateFormat(int $part = self::TS_BOTH): string;
|
||||
|
||||
function run(...$values): Result;
|
||||
function runArray(array $values): Result;
|
||||
function rebind(...$bindings): bool;
|
||||
|
|
|
@ -1,9 +1,20 @@
|
|||
<?php
|
||||
declare(strict_types=1);
|
||||
namespace JKingWeb\NewsSync\Db;
|
||||
use JKingWeb\NewsSync\Db\DriverSQLite3 as Driver;
|
||||
|
||||
class StatementSQLite3 implements Statement {
|
||||
class StatementSQLite3 extends AbstractStatement {
|
||||
const BINDINGS = [
|
||||
"null" => \SQLITE3_NULL,
|
||||
"integer" => \SQLITE3_INTEGER,
|
||||
"float" => \SQLITE3_FLOAT,
|
||||
"date" => \SQLITE3_TEXT,
|
||||
"time" => \SQLITE3_TEXT,
|
||||
"datetime" => \SQLITE3_TEXT,
|
||||
"binary" => \SQLITE3_BLOB,
|
||||
"string" => \SQLITE3_TEXT,
|
||||
"boolean" => \SQLITE3_INTEGER,
|
||||
];
|
||||
|
||||
protected $db;
|
||||
protected $st;
|
||||
protected $types;
|
||||
|
@ -19,8 +30,12 @@ class StatementSQLite3 implements Statement {
|
|||
unset($this->st);
|
||||
}
|
||||
|
||||
public function run(...$values): Result {
|
||||
return $this->runArray($values);
|
||||
public static function dateFormat(int $part = self::TS_BOTH): string {
|
||||
return ([
|
||||
self::TS_TIME => 'h:i:sP',
|
||||
self::TS_DATE => 'Y-m-d',
|
||||
self::TS_BOTH => 'Y-m-d h:i:sP',
|
||||
])[$part];
|
||||
}
|
||||
|
||||
public function runArray(array $values = null): Result {
|
||||
|
@ -28,80 +43,21 @@ class StatementSQLite3 implements Statement {
|
|||
$l = sizeof($values);
|
||||
for($a = 0; $a < $l; $a++) {
|
||||
// find the right SQLite binding type for the value/specified type
|
||||
$type = null;
|
||||
if($values[$a]===null) {
|
||||
$type = \SQLITE3_NULL;
|
||||
} else if(array_key_exists($a,$this->types)) {
|
||||
$type = $this->translateType($this->types[$a]);
|
||||
if(!array_key_exists($this->types[$a], self::BINDINGS)) throw new Exception("paramTypeUnknown", $this->types[$a]);
|
||||
$type = self::BINDINGS[$this->types[$a]];
|
||||
} else {
|
||||
$type = \SQLITE3_TEXT;
|
||||
}
|
||||
// cast values if necessary
|
||||
switch($this->types[$a]) {
|
||||
case "null":
|
||||
$value = null; break;
|
||||
case "integer":
|
||||
$value = (int) $values[$a]; break;
|
||||
case "float":
|
||||
$value = (float) $values[$a]; break;
|
||||
case "date":
|
||||
$value = Driver::formatDate($values[$a], Driver::TS_DATE); break;
|
||||
case "time":
|
||||
$value = Driver::formatDate($values[$a], Driver::TS_TIME); break;
|
||||
case "datetime":
|
||||
$value = Driver::formatDate($values[$a], Driver::TS_BOTH); break;
|
||||
case "binary":
|
||||
$value = (string) $values[$a]; break;
|
||||
case "text":
|
||||
$value = $values[$a]; break;
|
||||
case "boolean":
|
||||
$value = (bool) $values[$a]; break;
|
||||
default:
|
||||
throw new Exception("paramTypeUnknown", $type);
|
||||
}
|
||||
if($type===null) {
|
||||
$this->st->bindParam($a+1, $value);
|
||||
} else {
|
||||
$this->st->bindParam($a+1, $value, $type);
|
||||
}
|
||||
// cast value if necessary
|
||||
$value = $this->cast($values[$a], $this->types[$a]);
|
||||
// re-adjust for null casts
|
||||
if($value===null) $type = \SQLITE3_NULL;
|
||||
// perform binding
|
||||
$this->st->bindParam($a+1, $value, $type);
|
||||
}
|
||||
return new ResultSQLite3($this->st->execute(), $this->db->changes(), $this);
|
||||
}
|
||||
|
||||
public function rebind(...$bindings): bool {
|
||||
return $this->rebindArray($bindings);
|
||||
}
|
||||
|
||||
protected function translateType(string $type) {
|
||||
switch($type) {
|
||||
case "null":
|
||||
return \SQLITE3_NULL;
|
||||
case "integer":
|
||||
return \SQLITE3_INTEGER;
|
||||
case "float":
|
||||
return \SQLITE3_FLOAT;
|
||||
case "date":
|
||||
case "time":
|
||||
case "datetime":
|
||||
return \SQLITE3_TEXT;
|
||||
case "binary":
|
||||
return \SQLITE3_BLOB;
|
||||
case "text":
|
||||
return \SQLITE3_TEXT;
|
||||
case "boolean":
|
||||
return \SQLITE3_INTEGER;
|
||||
default:
|
||||
throw new Db\Exception("paramTypeUnknown", $binding);
|
||||
}
|
||||
}
|
||||
|
||||
public function rebindArray(array $bindings): bool {
|
||||
$this->types = [];
|
||||
foreach($bindings as $binding) {
|
||||
$binding = trim(strtolower($binding));
|
||||
if(!array_key_exists($binding, self::TYPES)) throw new Db\Exception("paramTypeInvalid", $binding);
|
||||
$this->types[] = self::TYPES[$binding];
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -4,10 +4,11 @@ namespace JKingWeb\NewsSync;
|
|||
|
||||
|
||||
class TestDbStatementSQLite3 extends \PHPUnit\Framework\TestCase {
|
||||
use Test\Tools;
|
||||
use Test\Tools, Test\Db\BindingTests;
|
||||
|
||||
protected $c;
|
||||
protected $s;
|
||||
static protected $imp = Db\StatementSQLite3::class;
|
||||
|
||||
function setUp() {
|
||||
date_default_timezone_set("UTC");
|
||||
|
@ -28,53 +29,4 @@ class TestDbStatementSQLite3 extends \PHPUnit\Framework\TestCase {
|
|||
function testConstructStatement() {
|
||||
$this->assertInstanceOf(Db\StatementSQLite3::class, new Db\StatementSQLite3($this->c, $this->s));
|
||||
}
|
||||
|
||||
function testBindMissingValue() {
|
||||
$s = new Db\StatementSQLite3($this->c, $this->s);
|
||||
$val = $s->runArray()->get()['value'];
|
||||
$this->assertSame(null, $val);
|
||||
}
|
||||
|
||||
function testBindNull() {
|
||||
$exp = [
|
||||
"null" => null,
|
||||
"integer" => null,
|
||||
"float" => null,
|
||||
"date" => null,
|
||||
"time" => null,
|
||||
"datetime" => null,
|
||||
"binary" => null,
|
||||
"text" => null,
|
||||
"boolean" => null,
|
||||
];
|
||||
$s = new Db\StatementSQLite3($this->c, $this->s);
|
||||
$types = array_unique(Db\Statement::TYPES);
|
||||
foreach($types as $type) {
|
||||
$s->rebindArray([$type]);
|
||||
$val = $s->runArray([null])->get()['value'];
|
||||
$this->assertSame($exp[$type], $val);
|
||||
}
|
||||
}
|
||||
|
||||
function testBindInteger() {
|
||||
$exp = [
|
||||
"null" => null,
|
||||
"integer" => 2112,
|
||||
"float" => 2112.0,
|
||||
"date" => date('Y-m-d', 2112),
|
||||
"time" => date('h:i:sP', 2112),
|
||||
"datetime" => date('Y-m-d h:i:sP', 2112),
|
||||
"binary" => "2112",
|
||||
"text" => "2112",
|
||||
"boolean" => 1,
|
||||
];
|
||||
$s = new Db\StatementSQLite3($this->c, $this->s);
|
||||
$types = array_unique(Db\Statement::TYPES);
|
||||
foreach($types as $type) {
|
||||
$s->rebindArray([$type]);
|
||||
$val = $s->runArray([2112])->get()['value'];
|
||||
$this->assertSame($exp[$type], $val, "Type $type failed comparison.");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
240
tests/lib/Db/BindingTests.php
Normal file
240
tests/lib/Db/BindingTests.php
Normal file
|
@ -0,0 +1,240 @@
|
|||
<?php
|
||||
declare(strict_types=1);
|
||||
namespace JKingWeb\NewsSync\Test\Db;
|
||||
use JKingWeb\NewsSync\Db\Statement;
|
||||
use JKingWeb\NewsSync\Db\Driver;
|
||||
|
||||
trait BindingTests {
|
||||
|
||||
function testBindMissingValue() {
|
||||
$s = new self::$imp($this->c, $this->s);
|
||||
$val = $s->runArray()->get()['value'];
|
||||
$this->assertSame(null, $val);
|
||||
}
|
||||
|
||||
function testBindNull() {
|
||||
$input = null;
|
||||
$exp = [
|
||||
"null" => null,
|
||||
"integer" => null,
|
||||
"float" => null,
|
||||
"date" => null,
|
||||
"time" => null,
|
||||
"datetime" => null,
|
||||
"binary" => null,
|
||||
"string" => null,
|
||||
"boolean" => null,
|
||||
];
|
||||
$this->checkBinding($input, $exp);
|
||||
}
|
||||
|
||||
function testBindTrue() {
|
||||
$input = true;
|
||||
$exp = [
|
||||
"null" => null,
|
||||
"integer" => 1,
|
||||
"float" => 1.0,
|
||||
"date" => null,
|
||||
"time" => null,
|
||||
"datetime" => null,
|
||||
"binary" => "1",
|
||||
"string" => "1",
|
||||
"boolean" => 1,
|
||||
];
|
||||
$this->checkBinding($input, $exp);
|
||||
}
|
||||
|
||||
function testBindFalse() {
|
||||
$input = false;
|
||||
$exp = [
|
||||
"null" => null,
|
||||
"integer" => 0,
|
||||
"float" => 0.0,
|
||||
"date" => null,
|
||||
"time" => null,
|
||||
"datetime" => null,
|
||||
"binary" => "",
|
||||
"string" => "",
|
||||
"boolean" => 0,
|
||||
];
|
||||
$this->checkBinding($input, $exp);
|
||||
}
|
||||
|
||||
function testBindInteger() {
|
||||
$input = 2112;
|
||||
$exp = [
|
||||
"null" => null,
|
||||
"integer" => 2112,
|
||||
"float" => 2112.0,
|
||||
"date" => date(self::$imp::dateFormat(Statement::TS_DATE), 2112),
|
||||
"time" => date(self::$imp::dateFormat(Statement::TS_TIME), 2112),
|
||||
"datetime" => date(self::$imp::dateFormat(Statement::TS_BOTH), 2112),
|
||||
"binary" => "2112",
|
||||
"string" => "2112",
|
||||
"boolean" => 1,
|
||||
];
|
||||
$this->checkBinding($input, $exp);
|
||||
}
|
||||
|
||||
function testBindIntegerZero() {
|
||||
$input = 0;
|
||||
$exp = [
|
||||
"null" => null,
|
||||
"integer" => 0,
|
||||
"float" => 0.0,
|
||||
"date" => date(self::$imp::dateFormat(Statement::TS_DATE), 0),
|
||||
"time" => date(self::$imp::dateFormat(Statement::TS_TIME), 0),
|
||||
"datetime" => date(self::$imp::dateFormat(Statement::TS_BOTH), 0),
|
||||
"binary" => "0",
|
||||
"string" => "0",
|
||||
"boolean" => 0,
|
||||
];
|
||||
$this->checkBinding($input, $exp);
|
||||
}
|
||||
|
||||
function testBindFloat() {
|
||||
$input = 2112.0;
|
||||
$exp = [
|
||||
"null" => null,
|
||||
"integer" => 2112,
|
||||
"float" => 2112.0,
|
||||
"date" => date(self::$imp::dateFormat(Statement::TS_DATE), 2112),
|
||||
"time" => date(self::$imp::dateFormat(Statement::TS_TIME), 2112),
|
||||
"datetime" => date(self::$imp::dateFormat(Statement::TS_BOTH), 2112),
|
||||
"binary" => "2112",
|
||||
"string" => "2112",
|
||||
"boolean" => 1,
|
||||
];
|
||||
$this->checkBinding($input, $exp);
|
||||
}
|
||||
|
||||
function testBindFloatZero() {
|
||||
$input = 0.0;
|
||||
$exp = [
|
||||
"null" => null,
|
||||
"integer" => 0,
|
||||
"float" => 0.0,
|
||||
"date" => date(self::$imp::dateFormat(Statement::TS_DATE), 0),
|
||||
"time" => date(self::$imp::dateFormat(Statement::TS_TIME), 0),
|
||||
"datetime" => date(self::$imp::dateFormat(Statement::TS_BOTH), 0),
|
||||
"binary" => "0",
|
||||
"string" => "0",
|
||||
"boolean" => 0,
|
||||
];
|
||||
$this->checkBinding($input, $exp);
|
||||
}
|
||||
|
||||
function testBindAsciiString() {
|
||||
$input = "Random string";
|
||||
$exp = [
|
||||
"null" => null,
|
||||
"integer" => 0,
|
||||
"float" => 0.0,
|
||||
"date" => null,
|
||||
"time" => null,
|
||||
"datetime" => null,
|
||||
"binary" => $input,
|
||||
"string" => $input,
|
||||
"boolean" => 1,
|
||||
];
|
||||
$this->checkBinding($input, $exp);
|
||||
}
|
||||
|
||||
function testBindUtf8String() {
|
||||
$input = "é";
|
||||
$exp = [
|
||||
"null" => null,
|
||||
"integer" => 0,
|
||||
"float" => 0.0,
|
||||
"date" => null,
|
||||
"time" => null,
|
||||
"datetime" => null,
|
||||
"binary" => $input,
|
||||
"string" => $input,
|
||||
"boolean" => 1,
|
||||
];
|
||||
$this->checkBinding($input, $exp);
|
||||
}
|
||||
|
||||
function testBindBinaryString() {
|
||||
// FIXME: This test may be unreliable; SQLite happily stores invalid UTF-8 text as bytes untouched, but other engines probably don't do this
|
||||
$input = chr(233);
|
||||
$exp = [
|
||||
"null" => null,
|
||||
"integer" => 0,
|
||||
"float" => 0.0,
|
||||
"date" => null,
|
||||
"time" => null,
|
||||
"datetime" => null,
|
||||
"binary" => $input,
|
||||
"string" => $input,
|
||||
"boolean" => 1,
|
||||
];
|
||||
$this->checkBinding($input, $exp);
|
||||
}
|
||||
|
||||
function testBindIso8601DateString() {
|
||||
$input = "2017-01-09T13:11:17";
|
||||
$time = strtotime($input);
|
||||
$exp = [
|
||||
"null" => null,
|
||||
"integer" => 2017,
|
||||
"float" => 2017.0,
|
||||
"date" => date(self::$imp::dateFormat(Statement::TS_DATE), $time),
|
||||
"time" => date(self::$imp::dateFormat(Statement::TS_TIME), $time),
|
||||
"datetime" => date(self::$imp::dateFormat(Statement::TS_BOTH), $time),
|
||||
"binary" => $input,
|
||||
"string" => $input,
|
||||
"boolean" => 1,
|
||||
];
|
||||
$this->checkBinding($input, $exp);
|
||||
}
|
||||
|
||||
function testBindArbitraryDateString() {
|
||||
$input = "Today";
|
||||
$time = strtotime($input);
|
||||
$exp = [
|
||||
"null" => null,
|
||||
"integer" => 0,
|
||||
"float" => 0.0,
|
||||
"date" => date(self::$imp::dateFormat(Statement::TS_DATE), $time),
|
||||
"time" => date(self::$imp::dateFormat(Statement::TS_TIME), $time),
|
||||
"datetime" => date(self::$imp::dateFormat(Statement::TS_BOTH), $time),
|
||||
"binary" => $input,
|
||||
"string" => $input,
|
||||
"boolean" => 1,
|
||||
];
|
||||
$this->checkBinding($input, $exp);
|
||||
}
|
||||
|
||||
function testBindMutableDateObject($class = '\DateTime') {
|
||||
$input = new $class("Noon Today");
|
||||
$time = $input->getTimestamp();
|
||||
$exp = [
|
||||
"null" => null,
|
||||
"integer" => $time,
|
||||
"float" => (float) $time,
|
||||
"date" => date(self::$imp::dateFormat(Statement::TS_DATE), $time),
|
||||
"time" => date(self::$imp::dateFormat(Statement::TS_TIME), $time),
|
||||
"datetime" => date(self::$imp::dateFormat(Statement::TS_BOTH), $time),
|
||||
"binary" => date(self::$imp::dateFormat(Statement::TS_BOTH), $time),
|
||||
"string" => date(self::$imp::dateFormat(Statement::TS_BOTH), $time),
|
||||
"boolean" => 1,
|
||||
];
|
||||
$this->checkBinding($input, $exp);
|
||||
}
|
||||
|
||||
function testBindImmutableDateObject() {
|
||||
$this->testBindMutableDateObject('\DateTimeImmutable');
|
||||
}
|
||||
|
||||
protected function checkBinding($input, array $expectations) {
|
||||
$s = new self::$imp($this->c, $this->s);
|
||||
$types = array_unique(Statement::TYPES);
|
||||
foreach($types as $type) {
|
||||
$s->rebindArray([$type]);
|
||||
$val = $s->runArray([$input])->get()['value'];
|
||||
$this->assertSame($expectations[$type], $val, "Type $type failed comparison.");
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue