{JSON results of applicable inspection}
<?php
$inspect('Example Inspection', function () {
// Try changing this to: contains('example.org')
$this->assert('bob.smith@example.com')->contains('example.com');
});
{JSON results of applicable inspection}
<?php
/**
* This inspection is still under construction.
* ---
* @todo
*/
$inspect('Tell_Message', function() {
$this->try('_()', function() {
// @todo
});
});
{JSON results of applicable inspection}
<?php
/**
* This inspection is still under construction.
* ---
* @todo
*/
// ---------------------------------------------------------------------------------------------
$inspect('Tell_Bridge_Card', function() {
// @todo
});
{JSON results of applicable inspection}
<?php
// -------------------------------------------------------------------------------------------------
class Inspect_Test_Auth_Bearer extends Tell_Auth_Bearer
{
public function authenticate()
{
if ('rkbsRv9iVvla2unTCXkwNdRTWxZrfRmA' === $this->token()) {
return [
'first_name' => 'Bob',
'last_name' => 'Smith',
'email' => 'bob@example.com',
];
}
return FALSE;
}
public $test = [
'onAuthenticate' => [],
'onAuthenticateSuccess' => [],
'onAuthenticateFailure' => [],
'onAuthenticateRevoke' => [],
'onPersist' => [],
'onPersistSuccess' => [],
'onPersistFailure' => [],
'onAuthorize' => [],
'onAuthorizeSuccess' => [],
];
public function onAuthenticate(...$args)
{
$this->test['onAuthenticate'] = $args;
}
public function onAuthenticateSuccess(...$args)
{
$this->test['onAuthenticateSuccess'] = $args;
}
public function onAuthenticateFailure(...$args)
{
$this->test['onAuthenticateFailure'] = $args;
}
public function onAuthenticateRevoke(...$args)
{
$this->test['onAuthenticateRevoke'] = $args;
}
public function onPersist(...$args)
{
$this->test['onPersist'] = $args;
}
public function onPersistSuccess(...$args)
{
$this->test['onPersistSuccess'] = $args;
}
public function onPersistFailure(...$args)
{
$this->test['onPersistFailure'] = $args;
}
public function onAuthorize(...$args)
{
$this->test['onAuthorize'] = $args;
}
public function onAuthorizeSuccess(...$args)
{
$this->test['onAuthorizeSuccess'] = $args;
}
}
// -------------------------------------------------------------------------------------------------
$inspect('Tell_Auth_Bearer >> Instantiate', function(Inspect_Test_Auth_Bearer $auth) {
$this->assert($auth->test['onAuthenticate'])->array()->empty();
$this->assert($auth->test['onAuthenticateSuccess'])->array()->empty();
$this->assert($auth->test['onAuthenticateFailure'])->array()->hasKey(0)->hasKey(1);
$this->assert($auth->test['onAuthenticateFailure'][0])->false();
$this->assert($auth->test['onAuthenticateFailure'][1])->instanceOf($auth);
$this->assert($auth->test['onPersist'])->array()->empty();
$this->assert($auth->test['onPersistSuccess'])->array()->empty();
$this->assert($auth->test['onPersistFailure'])->array()->empty();
$this->assert($auth->test['onAuthorize'])->array()->empty();
$this->assert($auth->test['onAuthorizeSuccess'])->array()->empty();
});
// -------------------------------------------------------------------------------------------------
$inspect('Tell_Auth_Bearer >> Valid Bearer', function(Inspect_Test_Auth_Bearer $auth) {
$this->assert($auth->test['onAuthenticate'])->array()->hasKey(0)->hasKey(1);
$this->assert($auth->test['onAuthenticate'][0])->equals([
'first_name' => 'Bob',
'last_name' => 'Smith',
'email' => 'bob@example.com',
]);
$this->assert($auth->test['onAuthenticate'][1])->instanceOf($auth);
$this->assert($auth->test['onAuthenticateSuccess'])->equals($auth->test['onAuthenticate']);
$this->assert($auth->test['onAuthenticateFailure'])->array()->empty();
$this->assert($auth->test['onPersist'])->array()->empty();
$this->assert($auth->test['onPersistSuccess'])->array()->empty();
$this->assert($auth->test['onPersistFailure'])->array()->empty();
$this->assert($auth->test['onAuthorize'])->array()->empty();
$this->assert($auth->test['onAuthorizeSuccess'])->array()->empty();
})->request([
'method' => 'GET',
'server' => [
'PHP_AUTH_TOKEN' => 'rkbsRv9iVvla2unTCXkwNdRTWxZrfRmA',
],
]);
// -------------------------------------------------------------------------------------------------
{JSON results of applicable inspection}
<?php
$inspect('Tell_Jwt', function() {
$alive = [
'exp' => strtotime('+5 minutes', strtotime($this->date)),
'data' => [
'user_id' => 123,
'first_name' => 'Çelik',
'last_name' => 'Gonçalves',
],
];
$expired = [
'exp' => strtotime('-1 minute', strtotime($this->date)),
'data' => [
'user_id' => 123,
'first_name' => 'Çelik',
'last_name' => 'Gonçalves',
],
];
$tests = [
[
'throw' => NULL,
'payload' => $alive,
'alg' => 'HS256',
'jwt' => 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE2NDQ2MzUxMDAsImRhdGEiOnsidXNlcl9pZCI6MTIzLCJmaXJzdF9uYW1lIjoiXHUwMGM3ZWxpayIsImxhc3RfbmFtZSI6Ikdvblx1MDBlN2FsdmVzIn19.ky0_9EMJiR0VG0KGfNzZktYAw1itplhWB0ADL93F0cw',
],
[
'throw' => NULL,
'payload' => $alive,
'alg' => 'HS384',
'jwt' => 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzM4NCJ9.eyJleHAiOjE2NDQ2MzUxMDAsImRhdGEiOnsidXNlcl9pZCI6MTIzLCJmaXJzdF9uYW1lIjoiXHUwMGM3ZWxpayIsImxhc3RfbmFtZSI6Ikdvblx1MDBlN2FsdmVzIn19.JXG8ZDtnqAo8CB-1-lbIOqynrkQke7Qu4o_9dFZ9c_K_x-PUIQNAeVOYBZegen1z',
],
[
'throw' => NULL,
'payload' => $alive,
'alg' => 'HS512',
'jwt' => 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzUxMiJ9.eyJleHAiOjE2NDQ2MzUxMDAsImRhdGEiOnsidXNlcl9pZCI6MTIzLCJmaXJzdF9uYW1lIjoiXHUwMGM3ZWxpayIsImxhc3RfbmFtZSI6Ikdvblx1MDBlN2FsdmVzIn19.-WtrSAKiq7v3IS2baU57tSw-dMsQokuvf0-2tT8mq1EgGb485P0I1LQR4j8w5Z-QmNjziBZMa8r705JNEmT9Xw',
],
[
'throw' => Tell_Jwt_Exception_Expired::class, // Token expired 1 minute ago
'payload' => $expired,
'alg' => 'HS256',
'jwt' => 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE2NDQ2MzQ3NDAsImRhdGEiOnsidXNlcl9pZCI6MTIzLCJmaXJzdF9uYW1lIjoiXHUwMGM3ZWxpayIsImxhc3RfbmFtZSI6Ikdvblx1MDBlN2FsdmVzIn19.avmYNA3BqlSPDwgonooqGpQCmOTtJcLyqUNyUmDH6Lk',
],
[
'throw' => Tell_Jwt_Exception_Invalid::class, // Messed up header segment
'payload' => $alive,
'alg' => 'HS256',
'jwt' => 'AAAAAAAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE2NDQ2MzUxMDAsImRhdGEiOnsidXNlcl9pZCI6MTIzLCJmaXJzdF9uYW1lIjoiXHUwMGM3ZWxpayIsImxhc3RfbmFtZSI6Ikdvblx1MDBlN2FsdmVzIn19.ky0_9EMJiR0VG0KGfNzZktYAw1itplhWB0ADL93F0cw',
],
[
'throw' => Tell_Jwt_Exception_Invalid::class, // Missing segment
'payload' => $alive,
'alg' => 'HS256',
'jwt' => 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9eyJleHAiOjE2NDQ2MzUxMDAsImRhdGEiOnsidXNlcl9pZCI6MTIzLCJmaXJzdF9uYW1lIjoiXHUwMGM3ZWxpayIsImxhc3RfbmFtZSI6Ikdvblx1MDBlN2FsdmVzIn19.ky0_9EMJiR0VG0KGfNzZktYAw1itplhWB0ADL93F0cw',
],
[
'throw' => NULL,
'payload' => $alive,
'alg' => 'RS256',
'jwt' => 'eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJleHAiOjE2NDQ2MzUxMDAsImRhdGEiOnsidXNlcl9pZCI6MTIzLCJmaXJzdF9uYW1lIjoiXHUwMGM3ZWxpayIsImxhc3RfbmFtZSI6Ikdvblx1MDBlN2FsdmVzIn19.O-jfcjL01JOzdzgjP35oduD_k5dR62X_jhTm2I29ORq7mBqFhouNdl1CuIblNmnyw_X5TALSsFxrPWmGXQZ1xID4CP3l0lJAWTl--KzKbVOlN3jTv6b-Jgu9nRzojXEroZScxtrZnIS2wdGnkcs7jY65NujA5ttR4wHpjJ-eoCZ5QQo3D6tFlo-8tXsWeXt_p0yD8BmKnaekhKBDRrrPxFdMPX6ziQAx-Q_isJey-Q1l-q7H0JsGVKRw96a1h_NRArHRSNqQvZ1exuzLM5-RPG-iBarMfrWIY44kDIJ5TlIcnuSArNn95XlxxzP7ugfkcLSixH7WRvikbnvp7H0dGg',
],
[
'throw' => NULL,
'payload' => $alive,
'alg' => 'RS384',
'jwt' => 'eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzM4NCJ9.eyJleHAiOjE2NDQ2MzUxMDAsImRhdGEiOnsidXNlcl9pZCI6MTIzLCJmaXJzdF9uYW1lIjoiXHUwMGM3ZWxpayIsImxhc3RfbmFtZSI6Ikdvblx1MDBlN2FsdmVzIn19.buNeUn__x4tkRouBc5AAh5X0e5rZeY8JRd4kC2Npt9oLkEIqH4cv4lPDEakN5HWhxEd68LQ1S8O488bY1a25_qfXP3P7yZo9i1XSelcGwMSIYwqzg4raYB7G2Nmfo0lTueNJdAHH4um2JSljJbjJh6PUAwMNOTNErfvb7lpVMCEs6Bty_nAuZ5ZX5rfndnyXSK5GmzToYAvtLvYtY_GExkrQOQCg24Xnar9HHiVn2O3EIM2g1ywSp0wzm2b67nq8nf6Girv5F_hsdDEtcVukechhDYm66wuhSGXGp4Hmi-GMo04_ovGBKMTP0-s7MHdkGhjIYHL9qTpk945D5cioDA',
],
[
'throw' => NULL,
'payload' => $alive,
'alg' => 'RS512',
'jwt' => 'eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzUxMiJ9.eyJleHAiOjE2NDQ2MzUxMDAsImRhdGEiOnsidXNlcl9pZCI6MTIzLCJmaXJzdF9uYW1lIjoiXHUwMGM3ZWxpayIsImxhc3RfbmFtZSI6Ikdvblx1MDBlN2FsdmVzIn19.DRcP3-cr5WmTN-gF_8xCJi7t2qA8pq4q4O-1gJQTqAkwiWDvdcFdipyAdtar5jkOHtultyKOCaWdq-HFdJP0NzkSmT2HXZQ7Ex56lXUBt2vD0Rmj1kx4iGjuY3ZnpSmHd8Z9MElj78Ru2eeMoCC5Aq4Nvzz29bso7jsk5TM0B6ncvT4Xn-06kUe_fZ9gZ1Nr1hvFmkCZ3UZCG9o6ivPt63uonLV3gJsnwsxgumuGRikdzBAZ6mv1sfSyE3m9cIvyep4h2jyIu3lxu84BjUxzsaASjoQa7ecxdANbyL8gD_-AHKL55kSSJrKMLrdXuWOCSh_RCYYGYzJnWDOGQ38R6w',
],
];
Tell_Jwt::time(strtotime($this->date));
Tell_Jwt::leeway(0);
$this->try('encode()', function() use ($tests) {
foreach ($tests as $t) {
if ($t['throw']) {
continue;
}
$key = $t['alg'][0] === 'H' ? $this->hash_key : $this->private_key;
$jwt = Tell_Jwt::encode($t['payload'], $key, $t['alg']);
$bad = function() use ($t, $key) {
return Tell_Jwt::encode($t['payload'], $key, 'HS9999');
};
$this->assert($jwt)->equals($t['jwt']);
$this->assert($bad)->exception(Tell_Jwt_Exception::class);
}
})->then('decode()', function() use ($tests) {
foreach ($tests as $t) {
$key = $t['alg'][0] === 'H' ? $this->hash_key : $this->public_key;
if ($t['throw']) {
$run = function() use ($t, $key) {
return Tell_Jwt::decode($t['jwt'], $key);
};
$this->assert($run)->exception($t['throw']);
} else {
$this->assert(Tell_Jwt::decode($t['jwt'], $key))->equals($t['payload']);
}
}
});
})->vars([
'date' => '2022-02-12 03:00:00',
'hash_key' => 'XM4bXpjk6hiqZ8HxtswBgIIBK7L7qjHM',
'private_key' => file_get_contents(__DIR__ . '/../keep/private.pem'),
'public_key' => file_get_contents(__DIR__ . '/../keep/public.pem'),
]);
{JSON results of applicable inspection}
<?php
/**
* This inspection is still under construction.
* ---
* @todo
*/
$inspect('Tell_Image_Info', function() {
$this->try('isGif()', function() {
$this->assert((new Tell_Image_Info($this->path_gif))->isGif())->true();
$this->assert((new Tell_Image_Info($this->path_jpg))->isGif())->false();
$this->assert((new Tell_Image_Info($this->path_jpeg))->isGif())->false();
$this->assert((new Tell_Image_Info($this->path_png))->isGif())->false();
$this->assert($this->path_gif)->imageGif();
});
$this->try('isJpeg()', function() {
$this->assert((new Tell_Image_Info($this->path_gif))->isJpeg())->false();
$this->assert((new Tell_Image_Info($this->path_jpg))->isJpg())->true();
$this->assert((new Tell_Image_Info($this->path_jpg))->isJpeg())->true();
$this->assert((new Tell_Image_Info($this->path_jpeg))->isJpg())->true();
$this->assert((new Tell_Image_Info($this->path_jpeg))->isJpeg())->true();
$this->assert((new Tell_Image_Info($this->path_png))->isJpeg())->false();
$this->assert($this->path_jpg)->imageJpg();
$this->assert($this->path_jpg)->imageJpeg();
$this->assert($this->path_jpeg)->imageJpg();
$this->assert($this->path_jpeg)->imageJpeg();
});
$this->try('isPng()', function() {
$this->assert((new Tell_Image_Info($this->path_gif))->isPng())->false();
$this->assert((new Tell_Image_Info($this->path_jpg))->isPng())->false();
$this->assert((new Tell_Image_Info($this->path_jpeg))->isPng())->false();
$this->assert((new Tell_Image_Info($this->path_png))->isPng())->true();
$this->assert($this->path_png)->imagePng();
});
$this->try('isImage()', function() {
$this->assert((new Tell_Image_Info($this->path_gif))->isImage())->true();
$this->assert((new Tell_Image_Info($this->path_jpg))->isImage())->true();
$this->assert((new Tell_Image_Info($this->path_jpeg))->isImage())->true();
$this->assert((new Tell_Image_Info($this->path_png))->isImage())->true();
$this->assert($this->path_gif)->image();
$this->assert($this->path_jpg)->image();
$this->assert($this->path_jpeg)->image();
$this->assert($this->path_png)->image();
});
})->vars([
'path_png' => Tell_Asset::path('images/blossoms.png'),
'path_gif' => Tell_Asset::path('images/dolphins.gif'),
'path_jpeg' => Tell_Asset::path('images/shark.jpeg'),
'path_jpg' => Tell_Asset::path('images/whale.jpg'),
'path_txt' => Tell_Asset::path('docs/ipsum.txt'),
'path_pdf' => Tell_Asset::path('docs/skookum.pdf'),
]);
{JSON results of applicable inspection}
<?php
$inspect('Tell_File', function() {
$shark = $this->path_shark;
$whale = $this->path_whale;
$vscode = $this->path_vscode;
$sqlite = $this->path_sqlite3;
$base = $this->path_cache;
$dA = 'test_dir_a' . DS;
$dB = 'test_dir_b' . DS;
$dC = 'test_dir_c' . DS;
$fA = 'test_file_a.txt';
$fB = 'test_file_b.md';
$fC = 'test_file_c';
$fD = basename($shark);
$this->try('buffer()', function() {
$this->assert(Tell_File::buffer($this->path_buffer, [
'name' => 'Bob',
'active' => TRUE,
]))->equals('Hello, Bob! Your account is active.');
$this->assert(Tell_File::buffer($this->path_buffer, [
'name' => 'Jane',
'active' => FALSE,
]))->equals('Hello, Jane! Your account is not active.');
});
$this->try('newDirectory()', function() use ($base, $dA, $dB) {
$this->assert(Tell_File::newDirectory($base . $dA))->true();
$this->assert(Tell_File::newDirectory($base . $dB . $dA))->true();
$this->assert($base . $dA)->notFile()->directory();
$this->assert($base . $dB)->notFile()->directory();
$this->assert($base . $dB . $dA)->notFile()->directory();
})->then('newFile()', function() use ($base, $dA, $dB, $fA, $fB, $fC) {
$this->assert(Tell_File::newFile($base . $dA . $fA, 'hello world'))->true();
$this->assert(Tell_File::newFile($base . $dB . $dA . $fB, 'hello again'))->true();
$this->assert(Tell_File::newFile($base . $dA . $fC, 'foobar'))->true();
$this->assert($base . $dA . $fA)->notDirectory()->file();
$this->assert($base . $dB . $dA . $fB)->notDirectory()->file();
$this->assert($base . $dA . $fC)->notDirectory()->file();
})->then('copy()', function() use ($shark, $base, $dA, $dB, $dC, $fA, $fB) {
$this->assert(Tell_File::copy($base . $dA . $fA, /**/ $base . $dB . $dA . $fA))->true();
$this->assert(Tell_File::copy($base . $dB . $dA . $fB, /**/ $base . $dA . $fB))->true();
$this->assert(Tell_File::copy($base . $dB, /**/ $base . $dC))->true();
$this->assert(Tell_File::copy($shark, /**/ $base . $dC))->true();
})->then('extension()', function() use ($whale, $shark, $base, $dA, $dC, $fA, $fB, $fC, $fD) {
$this->validate($whale)->extensions('jpg')->assert();
$this->validate($shark)->extensions('jpg')->assert();
$this->validate($base . $dA . $fA)->extensions('txt')->assert();
$this->validate($base . $dA . $fB)->extensions('md')->assert();
$this->validate($base . $dA . $fC)->extensions('')->assert();
$this->validate($base . $dC . $fD)->extensions('jpg')->assert();
})->then('mime()', function() use ($whale, $shark, $vscode, $sqlite, $base, $dA, $dC, $fA, $fB, $fC, $fD) {
$mimes = [
'*' => 'application/octet-stream',
'ico' => 'image/x-icon',
'jpg' => 'image/jpeg',
'jpeg' => 'image/jpeg',
'md' => 'text/markdown',
'mp4' => 'video/mp4',
'pdf' => 'application/pdf',
'sqlite3' => 'application/vnd.sqlite3',
'txt' => 'text/plain',
];
$this->validate($whale)->mimes($mimes['jpeg'])->assert();
$this->validate($whale)->mimes($mimes['jpeg'])->assert();
$this->validate($shark)->mimes($mimes['jpg'])->assert();
$this->validate($vscode)->mimes($mimes['ico'])->assert();
$this->validate($sqlite)->mimes($mimes['sqlite3'])->assert();
$this->validate($base . $dA . $fA)->mimes($mimes['txt'])->assert();
$this->validate($base . $dA . $fB)->mimes($mimes['md'])->assert();
$this->validate($base . $dA . $fC)->mimes($mimes['*'])->assert();
$this->validate($base . $dC . $fD)->mimes($mimes['jpg'])->assert();
})->then('sha256()', function() use ($shark, $base, $dC, $fD) {
$hashA = Tell_File::sha256($shark);
$hashB = Tell_File::sha256($base . $dC . $fD);
$this->assert($hashA)->equals($hashB);
})->then('sha512()', function() use ($shark, $base, $dC, $fD) {
$hashA = Tell_File::sha512($shark);
$hashB = Tell_File::sha512($base . $dC . $fD);
$this->assert($hashA)->equals($hashB);
})->then('delete()', function() use ($base, $dA, $dB, $dC, $fA, $fB, $fC) {
$this->assert(Tell_File::delete($base . $fA))->true();
$this->assert(Tell_File::delete($base . $fB))->true();
$this->assert(Tell_File::delete($base . $fC))->true();
$this->assert($base . $fA)->notFile()->notDirectory();
$this->assert($base . $fA)->notFile()->notDirectory();
$this->assert($base . $fC)->notFile()->notDirectory();
$this->assert(Tell_File::delete($base . $dA))->true();
$this->assert(Tell_File::delete($base . $dB))->true();
$this->assert(Tell_File::delete($base . $dC . $dA))->true();
$this->assert($base . $dA)->notDirectory()->notFile();
$this->assert($base . $dB)->notDirectory()->notFile();
$this->assert($base . $dC . $dA)->notDirectory()->notFile();
$this->assert($base . $dC)->directory()->notFile();
$this->assert(Tell_File::delete($base . $dC))->true();
$this->assert($base . $dC)->notDirectory()->notFile();
});
})->vars([
'path_buffer' => Tell_Asset::path('scripts/buffer.php'),
'path_whale' => Tell_Asset::path('images/whale.jpg'),
'path_shark' => Tell_Asset::path('images/shark.jpeg'),
'path_skookum' => Tell_Asset::path('docs/skookum.pdf'),
'path_vscode' => Tell_Asset::path('images/vscode.ico'),
'path_ipsum' => Tell_Asset::path('docs/ipsum.txt'),
'path_sqlite3' => Tell_Asset::path('sql/tell_php_test.sqlite3'),
'path_video' => Tell_Asset::path('videos/volcano.mp4'),
'path_cache' => CACHE_PATH . DS . 'inspect' . DS,
]);
$inspect('Tell_File_Search', function() {
// logger($this->path_asset);
// (new Tell_File_Search())
// ->directories()
// ->inside($this->path_asset)
// ->depth(0)
// ->results();
})->vars([
'path_asset' => Tell_Asset::directory(),
]);
{JSON results of applicable inspection}
<?php
// -------------------------------------------------------------------------------------------------
class Inspect_Test_Auth_Digest extends Tell_Auth_Digest
{
public function authenticate()
{
if ($this->validate()) {
return [
'first_name' => 'Bob',
'last_name' => 'Smith',
'email' => 'bob@example.com',
];
}
return FALSE;
}
public function findPassword(string $username)
: ? string
{
if ($username === 'bob@example.com') {
return 'testing';
}
return NULL;
}
public $test = [
'onAuthenticate' => [],
'onAuthenticateSuccess' => [],
'onAuthenticateFailure' => [],
'onAuthenticateRevoke' => [],
'onPersist' => [],
'onPersistSuccess' => [],
'onPersistFailure' => [],
'onAuthorize' => [],
'onAuthorizeSuccess' => [],
];
public function onAuthenticate(...$args)
{
$this->test['onAuthenticate'] = $args;
}
public function onAuthenticateSuccess(...$args)
{
$this->test['onAuthenticateSuccess'] = $args;
}
public function onAuthenticateFailure(...$args)
{
$this->test['onAuthenticateFailure'] = $args;
}
public function onAuthenticateRevoke(...$args)
{
$this->test['onAuthenticateRevoke'] = $args;
}
public function onPersist(...$args)
{
$this->test['onPersist'] = $args;
}
public function onPersistSuccess(...$args)
{
$this->test['onPersistSuccess'] = $args;
}
public function onPersistFailure(...$args)
{
$this->test['onPersistFailure'] = $args;
}
public function onAuthorize(...$args)
{
$this->test['onAuthorize'] = $args;
}
public function onAuthorizeSuccess(...$args)
{
$this->test['onAuthorizeSuccess'] = $args;
}
}
// -------------------------------------------------------------------------------------------------
$inspect('Tell_Auth_Digest >> Instantiate', function(Inspect_Test_Auth_Digest $auth) {
$this->assert($auth->test['onAuthenticate'])->array()->empty();
$this->assert($auth->test['onAuthenticateSuccess'])->array()->empty();
$this->assert($auth->test['onAuthenticateFailure'])->array()->hasKey(0)->hasKey(1);
$this->assert($auth->test['onAuthenticateFailure'][0])->false();
$this->assert($auth->test['onAuthenticateFailure'][1])->instanceOf($auth);
$this->assert($auth->test['onPersist'])->array()->empty();
$this->assert($auth->test['onPersistSuccess'])->array()->empty();
$this->assert($auth->test['onPersistFailure'])->array()->empty();
$this->assert($auth->test['onAuthorize'])->array()->empty();
$this->assert($auth->test['onAuthorizeSuccess'])->array()->empty();
});
// -------------------------------------------------------------------------------------------------
$inspect('Tell_Auth_Jwt >> Valid Digest', function(Inspect_Test_Auth_Digest $auth) {
$this->assert($auth->test['onAuthenticate'])->array()->hasKey(0)->hasKey(1);
$this->assert($auth->test['onAuthenticate'][0])->equals([
'first_name' => 'Bob',
'last_name' => 'Smith',
'email' => 'bob@example.com',
]);
$this->assert($auth->test['onAuthenticate'][1])->instanceOf($auth);
$this->assert($auth->test['onAuthenticateSuccess'])->equals($auth->test['onAuthenticate']);
$this->assert($auth->test['onAuthenticateFailure'])->array()->empty();
$this->assert($auth->test['onPersist'])->array()->empty();
$this->assert($auth->test['onPersistSuccess'])->array()->empty();
$this->assert($auth->test['onPersistFailure'])->array()->empty();
$this->assert($auth->test['onAuthorize'])->array()->empty();
$this->assert($auth->test['onAuthorizeSuccess'])->array()->empty();
})->request([
'method' => 'GET',
'server' => [
'PHP_AUTH_DIGEST' => 'username="bob@example.com", realm="Protected Area", nonce="gf8RcDCkvNvODtyDRw56KAlcO0dm3x0v", uri="/test/auth/middleware/digest", algorithm=MD5, response="ca175b73ced4115be91847e5ceb9aff1", opaque="2929b8e007e9c3edd69d915068815d71", qop=auth, nc=00000003, cnonce="0c4ce06db26f3f58"',
],
]);
// -------------------------------------------------------------------------------------------------
{JSON results of applicable inspection}
<?php
$inspect('Tell_Inspect_Suite_Client', function() {
$this->try('An HTTP request with an expectation')->client(function() {
$this->post('test/webhook/post', function(Tell_Request $input) {
$client = new Tell_Client_Request();
$client->header('Authorization', $input->post('code'));
$client->query([
'status' => 'Active',
'account' => 12,
]);
$client->data([
'first_name' => $input->post('first_name'),
'last_name' => $input->post('last_name'),
'email' => $input->post('email'),
'country' => 'US',
]);
return $client;
})->expecting(function($response) {
$this->assert($response)->instanceOf(Tell_Client_Response::class);
$this->assert($response->code())->equals(200);
$this->assert($response->isJson())->true();
$this->assert($response->header('authorization'))->equals('feVUrB4f0j5ScMd3');
$this->assert($response->header('Authorization'))->equals('feVUrB4f0j5ScMd3');
$this->assert($response->body())->iterable();
$this->assert($response->body('query.account'))->equals('12');
$this->assert($response->body('input.email'))->equals('bob-smith@foobar.com');
$this->assert($response->body('input.country'))->equals('US');
$this->assert($response->body('input.Country'))->empty();
return TRUE;
})->then('An HTTP request after the expectation')->client(function() {
$response = $this->get('test/webhook/get/' . Tell_Request::post('code'))->result;
$this->assert($response)->instanceOf(Tell_Client_Response::class);
$this->assert($response->code())->equals(200);
$this->assert($response->isJson())->true();
$this->assert($response->body())->arr();
});
})->then('An isolated HTTP request', function() {
$response = $this->client()->post('test/webhook/broke')->result;
$this->assert($response)->instanceOf(Tell_Client_Response::class);
$this->assert($response->code())->equals(200);
$this->assert($response->header('authorization'))->notEquals('feVUrB4f0j5ScMd3');
$this->assert($response->isJson());
$this->assert($response->body())->array();
});
})->request([
'post' => [
'code' => 'feVUrB4f0j5ScMd3',
'first_name' => 'Bob',
'last_name' => 'Smith',
'email' => 'bob-smith@foobar.com',
],
])->onlyWhen(function() {
return ! Tell_Request::isCli();
});
{JSON results of applicable inspection}
<?php
/**
* This inspection is still under construction.
* ---
* @todo
*/
$inspect('Tell_Mutate', function() {
$this->try('Closures', function() {
// @todo
});
});
{JSON results of applicable inspection}
<?php
$inspect('Tell_Mutate_Response >> Normalizer Methods', function() {
$request = Mockery::mock(Tell_Request::class);
$mutate = new Tell_Mutate_Response($request, [], []);
$rawCorsValues = [ // value, expect
[['abc', 123], 'abc, 123'],
[['abc, 123'], 'abc, 123'],
[['abc', 123, '*'], '*'],
[0, NULL],
['0', NULL],
[FALSE, NULL],
[NULL, NULL],
[TRUE, '1'],
];
$pathRules = [ // path, rule, expect
['/', '*', TRUE],
['/foo/123', '*', TRUE],
['/foo/123/bar', '*', TRUE],
['/foo/123/bar/doe', '/foo/**', TRUE],
['/foo/123/bar/doe', '/foo/*', FALSE],
['/foo/123/bar', '/foo/*/doe', FALSE],
['/foo/123/bar', '/foo/*/bar', TRUE],
['/foo/123/bar/doe', '/foo/*/bar', FALSE],
['/foo/123/bar/doe', '/foo/*/doe', FALSE],
['/foo/123/bar/doe', '/foo/**/doe', TRUE],
['/foo/123/bar/doe.png', '/foo/**/*.png', TRUE],
['/foo/123/bar/doe.png', '/foo/**/*.jpg', FALSE],
];
$this->try('normalizeCorsValue()')->many($rawCorsValues, function($test) use ($mutate) {
list($value, $expect) = $test;
return $expect === $mutate->normalizeCorsValue($value, TRUE);
})->then('normalizeCorsPolicy()', function() use ($mutate) {
$this->assert($mutate->normalizeCorsPolicy([
'access-control-allow-credentials' => TRUE,
]))->equals([
'Access-Control-Allow-Credentials' => 'true',
'Access-Control-Allow-Headers' => NULL,
'Access-Control-Allow-Methods' => NULL,
'Access-Control-Expose-Headers' => NULL,
'Access-Control-Max-Age' => '0',
]);
$this->assert($mutate->normalizeCorsPolicy([
'Access-Control-Expose-Headers' => 'Content-Encoding',
]))->equals([
'Access-Control-Allow-Credentials' => NULL,
'Access-Control-Allow-Headers' => NULL,
'Access-Control-Allow-Methods' => NULL,
'Access-Control-Expose-Headers' => 'Content-Encoding',
'Access-Control-Max-Age' => '0',
]);
$this->assert($mutate->normalizeCorsPolicy([
'Access-Control-Expose-Headers' => ['Content-Encoding', 'Kuma-Revision'],
'access-control-max-age' => 600,
]))->equals([
'Access-Control-Allow-Credentials' => NULL,
'Access-Control-Allow-Headers' => NULL,
'Access-Control-Allow-Methods' => NULL,
'Access-Control-Expose-Headers' => 'Content-Encoding, Kuma-Revision',
'Access-Control-Max-Age' => '600',
]);
})->then('pathRule()')->many($pathRules, function($test) use ($mutate) {
list($path, $rule, $expect) = $test;
return $expect === $mutate->pathRule($path, $rule);
})->then('appendVaryHeader()', function() use ($mutate) {
$response = new Tell_Response_Plain("I'm just a big nothin!");
$response = $mutate->appendVaryHeader($response, 'Origin');
$response = $mutate->appendVaryHeader($response, 'Access-Control-Request-Method');
$response = $mutate->appendVaryHeader($response, 'Access-Control-Request-Headers');
$vary = $response->header('Vary');
$this->assert($vary)->equals('Origin, Access-Control-Request-Method, Access-Control-Request-Headers');
})->then('pickHeaderPolicy()', function() use ($mutate) {
$policies = [
[
'paths' => ['/dist/*.js', '/assets/**/.jsx', '/assets/**/*.js'],
'headers' => [
'Content-Type' => 'text/javascript',
'X-Powered-By' => 'tell-php',
],
],
[
'paths' => ['/widgets/**'],
'headers' => [
'X-Powered-By' => FALSE,
'X-Frame-Options' => 'SAMEORIGIN',
],
],
[
'paths' => ['/users/**'],
'headers' => [
'X-Powered-By' => FALSE,
'X-Frame-Options' => 'DENY',
],
],
];
$this->assert($mutate->pickHeaderPolicy('/assets/js/main.js', $policies))->equals([
'Content-Type' => 'text/javascript',
'X-Powered-By' => 'tell-php',
]);
$this->assert($mutate->pickHeaderPolicy('/dist/app.js', $policies))->equals([
'Content-Type' => 'text/javascript',
'X-Powered-By' => 'tell-php',
]);
$this->assert($mutate->pickHeaderPolicy('/widgets/form/survey/food', $policies))->equals([
'X-Powered-By' => FALSE,
'X-Frame-Options' => 'SAMEORIGIN',
]);
$this->assert($mutate->pickHeaderPolicy('/users/123/notes', $policies))->equals([
'X-Powered-By' => FALSE,
'X-Frame-Options' => 'DENY',
]);
$this->assert($mutate->pickHeaderPolicy('/admin', $policies))->equals($mutate->defaultHeaderPolicy());
})->then('pickCorsPolicy()', function() use ($mutate) {
$origin = 'https://dashboard.example.com:8087';
$path = '/auth/refresh/jwt';
$empty = [
[
'paths' => [],
'origins' => [],
'headers' => [],
],
];
$rightOriginWrongPathDepth = [
[
'paths' => ['/auth/*'],
'origins' => ['*.example.com:*'],
'headers' => [],
],
];
$rightOriginRightPathDepth = [
[
'paths' => ['/auth/**'], // matches
'origins' => ['*.example.com'], // no-match
'headers' => [],
],
[
'paths' => ['/foo/**'], // no-match
'origins' => ['*.example.com:*'], // matches
'headers' => [],
],
[
'paths' => ['/auth/**'], // matches
'origins' => ['*.example.com:*'], // matches
'headers' => [
'Access-Control-Allow-Credentials' => TRUE,
'Access-Control-Allow-Methods' => ['GET', 'POST', 'PUT', 'DELETE'],
],
],
];
$this->assert($mutate->pickCorsPolicy($origin, $path, $empty))->null();
$this->assert($mutate->pickCorsPolicy($origin, $path, $rightOriginWrongPathDepth))->null();
$policy = $mutate->pickCorsPolicy($origin, $path, $rightOriginRightPathDepth);
$this->assert($policy)->array()->equals([
'Access-Control-Allow-Credentials' => TRUE,
'Access-Control-Allow-Headers' => NULL,
'Access-Control-Allow-Methods' => ['GET', 'POST', 'PUT', 'DELETE'],
'Access-Control-Expose-Headers' => NULL,
'Access-Control-Max-Age' => '0',
]);
});
});
$inspect('Tell_Mutate_Response >> Standard Request', function() {
$this->try('headerMutation()', function(Tell_Request $request) {
$mutate = new Tell_Mutate_Response($request, [], []);
$response = new Tell_Response_Plain("I'm just a big nothin!");
$headerPolicy = [
'content-type' => 'text/plain',
'upgrade-insecure-requests' => TRUE,
'x-powered-by' => 'tell-php',
];
$response = $mutate->headerMutation($response, $headerPolicy);
$this->assert($response)->instanceOf(Tell_Response_Plain::class);
$this->assert($response->header('Content-Type'))->equals('text/plain');
$this->assert($response->header('Upgrade-Insecure-Requests'))->equals('1');
$this->assert($response->header('X-Powered-By'))->equals('tell-php');
});
});
$inspect('Tell_Mutate_Response >> CORS Preflight Request', function() {
$this->try('corsMutation()', function(Tell_Request $request) {
$mutate = new Tell_Mutate_Response($request, [], []);
$response = new Tell_Response_Plain("I'm just a big nothin!");
$corsPolicy = $mutate->normalizeCorsPolicy([
'Access-Control-Allow-Credentials' => 'true',
'Access-Control-Allow-Headers' => ['Content-Type', 'X-Requested-With'],
'Access-Control-Allow-Methods' => NULL,
'Access-Control-Expose-Headers' => 'Content-Encoding, Kuma-Revision',
'Access-Control-Max-Age' => '600',
]);
$response = $mutate->corsMutation($response, $corsPolicy);
$this->assert($response)->instanceOf(Tell_Response_Empty::class);
$this->assert($response->header('Access-Control-Allow-Headers'))->equals('Content-Type, X-Requested-With');
$this->assert($response->header('Access-Control-Max-Age'))->equals('600');
$this->assert($response->header('Access-Control-Allow-Origin'))->equals('https://dashboard.example.com:8087');
$this->assert($response->header('Access-Control-Allow-Credentials'))->equals('true');
$headerPolicy = [ // should not apply to CORS preflight requests
'content-type' => 'text/plain',
'upgrade-insecure-requests' => TRUE,
'x-powered-by' => 'tell-php',
];
$response = $mutate->headerMutation($response, $headerPolicy);
$this->assert($response)->instanceOf(Tell_Response_Empty::class);
$this->assert($response->header('Content-Type'))->equals('text/plain');
})->then('__invoke()', function(Tell_Request $request) {
$corsPolicies = [
[
'paths' => ['/auth/**'],
'origins' => ['dashboard.example.com:*'],
'headers' => [
'Access-Control-Allow-Credentials' => TRUE,
'Access-Control-Allow-Headers' => '*',
'Access-Control-Allow-Methods' => '*',
'Access-Control-Expose-Headers' => '*',
'Access-Control-Max-Age' => 600,
],
],
];
$headerPolicies = [ // none should apply to CORS preflight requests
[
'paths' => ['/auth/**'],
'headers' => [
'X-Powered-By' => 'tell-php-auth-areas',
],
],
[
'paths' => '*',
'headers' => [
'X-Powered-By' => 'tell-php-everywhere-else',
],
],
];
$mutate = new Tell_Mutate_Response($request, $corsPolicies, $headerPolicies);
$response = $mutate->__invoke(new Tell_Response_Plain("I'm just a big nothin!"));
$this->assert($response)->instanceOf(Tell_Response_Empty::class);
$this->assert($response->header('Access-Control-Allow-Origin'))->equals('https://dashboard.example.com:8087');
$this->assert($response->header('Access-Control-Allow-Methods'))->equals('POST');
$this->assert($response->header('Access-Control-Allow-Headers'))->equals('Authorization, X-Requested-With, Content-Type');
$this->assert($response->header('Access-Control-Allow-Credentials'))->equals('true');
$this->assert($response->header('Access-Control-Max-Age'))->equals('600');
$this->assert($response->header('Vary'))->equals('Access-Control-Allow-Headers, Access-Control-Allow-Methods, Origin');
});
})->request([
'method' => 'OPTIONS',
'uri' => '/auth/refresh/jwt',
'headers' => [
'Access-Control-Request-Headers' => 'Authorization, X-Requested-With, Content-Type',
'Access-Control-Request-Method' => 'POST',
'Origin' => 'https://dashboard.example.com:8087',
],
]);
$inspect('Tell_Mutate_Response >> CORS Request', function() {
$this->try('__invoke()', function(Tell_Request $request) {
$corsPolicies = [
[
'paths' => ['/auth/**'], // matches
'origins' => ['*.example.com'], // no-match
'headers' => [],
],
[
'paths' => ['/foo/**'], // no-match
'origins' => ['*.example.com:*'], // matches
'headers' => [],
],
[
'paths' => ['/auth/**'], // matches
'origins' => ['example.com', 'dashboard.example.com:*'], // matches
'headers' => [
'Access-Control-Allow-Credentials' => TRUE,
'Access-Control-Allow-Headers' => '*',
'Access-Control-Allow-Methods' => '*',
'Access-Control-Expose-Headers' => 'Content-Encoding, Kuma-Revision',
'Access-Control-Max-Age' => 600,
],
],
];
$headerPolicies = [
[
'paths' => ['/foo/**'], // no-match
'headers' => [],
],
[
'paths' => ['/auth/**'], // matches
'headers' => [
'X-Powered-By' => 'tell-php-auth-areas',
],
],
[
'paths' => '*', // also matches, but first match in policy list is always chosen
'headers' => [
'X-Powered-By' => 'tell-php-everywhere-else',
],
],
];
$mutate = new Tell_Mutate_Response($request, $corsPolicies, $headerPolicies);
$response = $mutate->__invoke(new Tell_Response_Plain("I'm just a big nothin!"));
$this->assert($response)->instanceOf(Tell_Response_Plain::class);
$this->assert($response->header('Access-Control-Allow-Origin'))->equals('https://dashboard.example.com:8087');
$this->assert($response->header('Access-Control-Expose-Headers'))->equals('Content-Encoding, Kuma-Revision');
$this->assert($response->header('Access-Control-Allow-Credentials'))->equals('true');
$this->assert($response->header('Vary'))->equals('Origin');
$this->assert($response->header('X-Powered-By'))->equals('tell-php-auth-areas');
});
})->request([
'method' => 'POST',
'uri' => '/auth/refresh/jwt',
'headers' => [
'Access-Control-Request-Headers' => 'Authorization, X-Requested-With, Content-Type',
'Access-Control-Request-Method' => 'POST',
'Origin' => 'https://dashboard.example.com:8087',
],
]);
{JSON results of applicable inspection}
<?php
/**
* This inspection is still under construction.
* ---
* @todo
*/
$inspect('Tell_Assert', function() {
$this->try('instanceOf(), notInstanceOf()', function() {
$db = new TestDb($this->config);
$user = new TestUser($db);
$order = new TestOrder($db);
$online = new TestOnlineOrder($db, $user);
$this->assert($db)
->instanceOf(TestDb::class)
->notInstanceOf(TestUser::class)
->notInstanceOf($user);
$this->assert($user)
->instanceOf(TestUser::class)
->notInstanceOf(TestDb::class)
->notInstanceOf($db);
$this->assert($order)
->instanceOf(TestOrder::class)
->notInstanceOf(TestOnlineOrder::class)
->notInstanceOf($online);
$this->assert($online)
->instanceOf(TestOrder::class)
->instanceOf(TestOnlineOrder::class)
->notInstanceOf(TestUser::class)
->notInstanceOf($user);
});
})->vars([
'config' => [
'driver' => 'mysql',
'database' => 'foobar',
'host' => 'localhost',
'port' => NULL,
'socket' => NULL,
'username' => 'foobar_admin',
'password' => 'i-am-a-nice-shark-not-a-mindless-eating-machine...',
],
]);
class TestDb
{
protected $config = [];
public function __construct(array $config)
{
$this->config = $config;
}
}
class TestUser
{
protected $db = NULL;
public function __construct(TestDb $db)
{
$this->db = $db;
}
}
class TestOrder
{
protected $db = NULL;
public function __construct(TestDb $db)
{
$this->db = $db;
}
}
class TestOnlineOrder extends TestOrder
{
protected $user = NULL;
public function __construct(TestDb $db, TestUser $user)
{
parent::__construct($db);
$this->user = $user;
}
}
{JSON results of applicable inspection}
<?php
$inspect('Tell_Uuid', function() {
$this->try('generate(), binToUuid(), uuidToBin()')->many(5000, function() {
$uuid = Tell_Uuid::generate();
if ( ! (bool) preg_match('/^[0-9A-F]{8}-[0-9A-F]{4}-[4][0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$/i', $uuid)) {
return FALSE;
}
$bin = Tell_Uuid::uuidToBin($uuid);
$undo = Tell_Uuid::binToUuid($bin);
return strlen($bin) === 16 && $uuid === $undo;
});
});
{JSON results of applicable inspection}
<?php
/**
* This inspection is still under construction.
* ---
* @todo
*/
// ---------------------------------------------------------------------------------------------
$inspect('Tell_Bridge_Contact', function() {
// @todo
});
{JSON results of applicable inspection}
<?php
Tell_Jwt::time(1677126824);
// -------------------------------------------------------------------------------------------------
class Inspect_Test_Auth_Jwt extends Tell_Auth_Jwt
{
const RECORD_TABLE = '_test_users';
const FIELD_ID = 'id';
const FIELD_PASSWORD = 'password';
const SECRET_JWT = 'U2Fv3HJKpfMuVTkyXM2LxclDudAyjyvD';
const SECRET_PERSIST = 'nP7NnrM6Fk4Y3PMLVdIuznoDNQZIVMbT';
public function jwtPayload(array $data)
: array
{
return [
'sub' => $data['id'],
];
}
public function findById($id)
: ? array
{
if (123 !== (int) $id) {
return NULL;
}
return [
'id' => 123,
'first_name' => 'Bob',
'last_name' => 'Smith',
'email' => 'bob@example.com',
'password' => Tell_Password::hash('testing'),
];
}
public function findByUser($user)
: ? array
{
if ('bob@example.com' !== $user) {
return NULL;
}
return [
'id' => 123,
'first_name' => 'Bob',
'last_name' => 'Smith',
'email' => 'bob@example.com',
'password' => Tell_Password::hash('testing'),
];
}
protected function persistHashKey()
: string
{
return self::SECRET_PERSIST;
}
protected function jwtDecode(string $jwt)
: array
{
return Tell_Jwt::decode($jwt, self::SECRET_JWT);
}
protected function jwtEncode(array $payload)
: string
{
return Tell_Jwt::encode($payload, self::SECRET_JWT);
}
public $test = [
'onAuthenticate' => [],
'onAuthenticateSuccess' => [],
'onAuthenticateFailure' => [],
'onAuthenticateRevoke' => [],
'onPersist' => [],
'onPersistSuccess' => [],
'onPersistFailure' => [],
'onAuthorize' => [],
'onAuthorizeSuccess' => [],
];
public function onAuthenticate(...$args)
{
$this->test['onAuthenticate'] = $args;
}
public function onAuthenticateSuccess(...$args)
{
$this->test['onAuthenticateSuccess'] = $args;
}
public function onAuthenticateFailure(...$args)
{
$this->test['onAuthenticateFailure'] = $args;
}
public function onAuthenticateRevoke(...$args)
{
$this->test['onAuthenticateRevoke'] = $args;
}
public function onPersist(...$args)
{
$this->test['onPersist'] = $args;
}
public function onPersistSuccess(...$args)
{
$this->test['onPersistSuccess'] = $args;
}
public function onPersistFailure(...$args)
{
$this->test['onPersistFailure'] = $args;
}
public function onAuthorize(...$args)
{
$this->test['onAuthorize'] = $args;
}
public function onAuthorizeSuccess(...$args)
{
$this->test['onAuthorizeSuccess'] = $args;
}
}
// -------------------------------------------------------------------------------------------------
$inspect('Tell_Auth_Jwt >> Instantiate', function(Inspect_Test_Auth_Jwt $auth) {
$this->assert($auth->test['onAuthenticate'])->array()->empty();
$this->assert($auth->test['onAuthenticateSuccess'])->array()->empty();
$this->assert($auth->test['onAuthenticateFailure'])->array()
->hasKey(0)
->hasKey(1)
->hasKey(2)
->hasKey(3);
$this->assert($auth->test['onAuthenticateFailure'][0])->false();
$this->assert($auth->test['onAuthenticateFailure'][1])->equals('jwt_invalid');
$this->assert($auth->test['onAuthenticateFailure'][2])->null();
$this->assert($auth->test['onAuthenticateFailure'][3])->instanceOf($auth);
$this->assert($auth->test['onAuthenticateRevoke'])->array()->empty();
$this->assert($auth->test['onPersist'])->array()->empty();
$this->assert($auth->test['onPersistSuccess'])->array()->empty();
$this->assert($auth->test['onPersistFailure'])->array()->empty();
$this->assert($auth->test['onAuthorize'])->array()->empty();
$this->assert($auth->test['onAuthorizeSuccess'])->array()->empty();
})->swap(function() {
$db = Mockery::mock(Tell_Db::class);
$persist = Mockery::mock(Tell_Auth_Persist::class);
$persist->shouldReceive('hashKey')->andReturnSelf();
$persist->shouldReceive('graft')->andReturn(NULL);
return [
'Tell_Db' => $db,
'Tell_Auth_Persist' => $persist,
];
});
// -------------------------------------------------------------------------------------------------
$inspect('Tell_Auth_Jwt >> Valid Access Token', function(Inspect_Test_Auth_Jwt $auth) {
$payload = [
'sub' => 123,
'iss' => 'dbaf009e4e3a94c648b37a2a789c0e6e',
'exp' => 1677127124,
];
$storage = [
'sub' => 123,
'iss' => 'dbaf009e4e3a94c648b37a2a789c0e6e',
'exp' => 1677127124,
];
$this->assert($auth->test['onAuthenticate'])->array()
->hasKey(0)
->hasKey(1);
$this->assert($auth->test['onAuthenticateSuccess'])->array()
->hasKey(0)
->hasKey(1);
$this->assert($auth->test['onAuthenticate'][0])->equals($payload);
$this->assert($auth->test['onAuthenticateSuccess'][0])->equals($payload);
$this->assert($auth->isAuthenticated())->true();
$this->assert($auth->get())->equals($storage);
})->request([
'server' => [
'PHP_AUTH_TOKEN' => 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOjEyMywiaXNzIjoiZGJhZjAwOWU0ZTNhOTRjNjQ4YjM3YTJhNzg5YzBlNmUiLCJleHAiOjE2NzcxMjcxMjR9.0Za23rAIRVTDTpgmM-Op8MbYGwS1BYyKfF1xtGuHwm4',
],
])->swap(function() {
$db = Mockery::mock(Tell_Db::class);
$persist = Mockery::mock(Tell_Auth_Persist::class);
$persist->shouldReceive('hashKey')->andReturnSelf();
$persist->shouldReceive('graft')->andReturn(NULL);
return [
'Tell_Db' => $db,
'Tell_Auth_Persist' => $persist,
];
});
// -------------------------------------------------------------------------------------------------
$inspect('Tell_Auth_Jwt >> Valid Simulated Refresh Cycle', function(Inspect_Test_Auth_Jwt $auth) {
$this->assert($auth->test['onAuthenticate'])->array()->empty();
$this->assert($auth->test['onAuthenticateSuccess'])->array()->empty();
$this->assert($auth->test['onAuthenticateFailure'])->array()->empty();
$this->assert($auth->test['onAuthenticateRevoke'])->array()->empty();
$this->assert($auth->test['onPersist'])->array()->empty();
$this->assert($auth->test['onPersistSuccess'])->array()->empty();
$this->assert($auth->test['onPersistFailure'])->array()->empty();
$this->assert($auth->test['onAuthorize'])->array()->empty();
$this->assert($auth->test['onAuthorizeSuccess'])->array()->empty();
$refresh = $auth->refreshCycle();
$this->assert($refresh)->instanceOf(Tell_Response_Json::class);
$this->assert($refresh->json)->string();
$json = Tell_Json::decode($refresh->json, TRUE);
$this->assert($json)->array()
->hasKey('status')
->hasKey('access_token')
->hasKey('access_expires')
->hasKey('refresh_token')
->hasKey('refresh_expires');
})->request([
'server' => [
'PHP_AUTH_TOKEN' => 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE2NzgzMzY0MjQsImp0aSI6IjRaMW5lQ1JzamtoZ0lNdEZLWUh4NTE5VWVGa1dzandmIiwic3ViIjoiOGxvOHpQV0NuQmVkMmsxNWZhNGhkdUhIVGNGWEF0b3UiLCJpc3MiOiJkYmFmMDA5ZTRlM2E5NGM2NDhiMzdhMmE3ODljMGU2ZSJ9.3n9NQFQFPEdniOVsEfLcb9ylWs9taQk9KQqk9Ryy-SE',
],
])->swap(function() {
$record = [
'id' => 1,
'parent_table' => '_test_users',
'parent_record' => 123,
'access_selector' => '8lo8zPWCnBed2k15fa4hduHHTcFXAtou',
'access_token' => 'ef783f86600c2dcab429b3e11778ddd924a0929449279b3a827eb871a1ecd72e',
'class_name' => 'Inspect_Test_Auth_Jwt',
'last_ip' => '172.16.238.1',
'created' => '2023-02-23 04:33:44',
'expires' => '2023-03-09 04:33:44',
];
$refresh = [
Tell_Security::random(32),
Tell_Security::random(32),
1678300000,
];
$db = Mockery::mock(Tell_Db::class);
$persist = Mockery::mock(Tell_Auth_Persist::class);
$persist->shouldReceive('hashKey')->andReturnSelf();
$persist->shouldReceive('graft')->andReturn(NULL);
$persist->shouldReceive('load')->andReturn($record);
$persist->shouldReceive('delete')->andReturn(TRUE);
$persist->shouldReceive('create')->andReturn($refresh);
return [
'Tell_Db' => $db,
'Tell_Auth_Persist' => $persist,
];
});
// -------------------------------------------------------------------------------------------------
$inspect('Tell_Auth_Jwt >> Valid Simulated Refresh Delete', function(Inspect_Test_Auth_Jwt $auth) {
$this->assert($auth->test['onAuthenticate'])->array()->empty();
$this->assert($auth->test['onAuthenticateSuccess'])->array()->empty();
$this->assert($auth->test['onAuthenticateFailure'])->array()->empty();
$this->assert($auth->test['onAuthenticateRevoke'])->array()->empty();
$this->assert($auth->test['onPersist'])->array()->empty();
$this->assert($auth->test['onPersistSuccess'])->array()->empty();
$this->assert($auth->test['onPersistFailure'])->array()->empty();
$this->assert($auth->test['onAuthorize'])->array()->empty();
$this->assert($auth->test['onAuthorizeSuccess'])->array()->empty();
$delete = $auth->refreshDelete();
$this->assert($delete)->instanceOf(Tell_Response_Empty::class);
Tell_Jwt::time(NULL);
})->request([
'server' => [
'PHP_AUTH_TOKEN' => 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE2NzgzMzY0MjQsImp0aSI6IjRaMW5lQ1JzamtoZ0lNdEZLWUh4NTE5VWVGa1dzandmIiwic3ViIjoiOGxvOHpQV0NuQmVkMmsxNWZhNGhkdUhIVGNGWEF0b3UiLCJpc3MiOiJkYmFmMDA5ZTRlM2E5NGM2NDhiMzdhMmE3ODljMGU2ZSJ9.3n9NQFQFPEdniOVsEfLcb9ylWs9taQk9KQqk9Ryy-SE',
],
])->swap(function() {
$db = Mockery::mock(Tell_Db::class);
$persist = Mockery::mock(Tell_Auth_Persist::class);
$persist->shouldReceive('hashKey')->andReturnSelf();
$persist->shouldReceive('graft')->andReturn(NULL);
$persist->shouldReceive('delete')->andReturn(TRUE);
return [
'Tell_Db' => $db,
'Tell_Auth_Persist' => $persist,
];
});
// -------------------------------------------------------------------------------------------------
{JSON results of applicable inspection}
<?php
class Inspect_Cron_Schedule extends Tell_Cron_Schedule
{
public function __call($name, $arguments)
{
return $this->$name(...$arguments);
}
}
$inspect('Tell_Cron_Schedule', function() {
$tab = function(string $schedule, $now) {
return new Inspect_Cron_Schedule($schedule, $now);
};
$bad = function(string $schedule, $now, $method = NULL) {
return function() use ($schedule, $now, $method) {
return $method
? (new Inspect_Cron_Schedule($schedule, $now))->$method()
: new Inspect_Cron_Schedule($schedule, $now);
};
};
$this->assert($bad('5 4 * *', time()))->exception(Tell_Cron_Exception::class);
$this->try('matchMinute()', function() use ($tab, $bad) {
// Every 59 minutes
$this->assert($tab('*/59 * * * *', '2023-02-27 02:58:10')->matchMinute())->false();
$this->assert($tab('*/59 * * * *', '2023-02-27 02:59:10')->matchMinute())->true();
$this->assert($tab('*/59 * * * *', '2023-02-27 03:00:05')->matchMinute())->true();
$this->assert($tab('*/59 * * * *', '2023-02-27 03:01:00')->matchMinute())->false();
// At 5 minutes past the hour
$this->assert($tab('5 * * * *', '2023-02-27 00:04:59')->matchMinute())->false();
$this->assert($tab('5 * * * *', '2023-02-27 00:05:10')->matchMinute())->true();
$this->assert($tab('5 * * * *', '2023-02-27 00:06:00')->matchMinute())->false();
$this->assert($tab('5 * * * *', '2023-02-27 12:05:59')->matchMinute())->true();
// At 5, 25, and 45 minutes past the hour
$this->assert($tab('5,25,45 * * * *', '2023-02-27 12:05:59')->matchMinute())->true();
$this->assert($tab('5,25,45 * * * *', '2023-02-27 12:06:01')->matchMinute())->false();
$this->assert($tab('5,25,45 * * * *', '2023-02-27 12:24:30')->matchMinute())->false();
$this->assert($tab('5,25,45 * * * *', '2023-02-27 12:25:00')->matchMinute())->true();
$this->assert($tab('5,25,45 * * * *', '2023-02-27 12:45:10')->matchMinute())->true();
$this->assert($tab('5,25,45 * * * *', '2023-02-27 12:46:10')->matchMinute())->false();
// Every minute
$this->assert($tab('* * * * *', '2023-02-16 12:10:00')->matchMinute())->true();
// 0-59 max range
$this->assert($bad('*/60 * * * *', '2023-02-20 02:59:59', 'matchMinute'))->exception(Tell_Cron_Exception::class);
$this->assert($bad('0-60 * * * *', '2023-02-20 02:59:59', 'matchMinute'))->exception(Tell_Cron_Exception::class);
$this->assert($bad('60 * * * *', '2023-02-20 02:59:59', 'matchMinute'))->exception(Tell_Cron_Exception::class);
$this->assert($bad('abc * * * *', '2023-02-20 02:59:59', 'matchMinute'))->exception(Tell_Cron_Exception::class);
})->then('matchHour()', function() use ($tab, $bad) {
// Every minute, every 2 hours, between 12:00 AM and 05:59 AM
$this->assert($tab('* 0-5/2 * * *', '2023-02-27 00:00:00')->matchHour())->true();
$this->assert($tab('* 0-5/2 * * *', '2023-02-27 00:30:07')->matchHour())->true();
$this->assert($tab('* 0-5/2 * * *', '2023-02-27 01:30:07')->matchHour())->false();
$this->assert($tab('* 0-5/2 * * *', '2023-02-27 02:30:30')->matchHour())->true();
$this->assert($tab('* 0-5/2 * * *', '2023-02-27 04:59:00')->matchHour())->true();
$this->assert($tab('* 0-5/2 * * *', '2023-02-27 05:59:00')->matchHour())->false();
$this->assert($tab('* 0-5/2 * * *', '2023-02-27 06:00:00')->matchHour())->false();
$this->assert($tab('* 0-5/2 * * *', '2023-02-27 23:59:59')->matchHour())->false();
// Every minute, between 05:00 AM and 05:59 AM
$this->assert($tab('* 5 * * *', '2023-02-20 04:59:02')->matchHour())->false();
$this->assert($tab('* 5 * * *', '2023-02-20 05:00:02')->matchHour())->true();
$this->assert($tab('* 5 * * *', '2023-02-20 05:59:02')->matchHour())->true();
$this->assert($tab('* 5 * * *', '2023-02-20 06:00:02')->matchHour())->false();
// Every minute, between 12:00 PM and 02:59 PM
$this->assert($tab('* 12-14 * * *', '2023-02-20 11:59:59')->matchHour())->false();
$this->assert($tab('* 12-14 * * *', '2023-02-20 12:00:00')->matchHour())->true();
$this->assert($tab('* 12-14 * * *', '2023-02-20 13:30:00')->matchHour())->true();
$this->assert($tab('* 12-14 * * *', '2023-02-20 14:59:59')->matchHour())->true();
$this->assert($tab('* 12-14 * * *', '2023-02-20 15:00:00')->matchHour())->false();
// Every minute
$this->assert($tab('* * * * *', '2023-02-16 12:10:00')->matchHour())->true();
// 0-23 max range
$this->assert($bad('* 12-24 * * *', '2023-02-20 02:59:59', 'matchHour'))->exception(Tell_Cron_Exception::class);
$this->assert($bad('* 24 * * *', '2023-02-20 02:59:59', 'matchHour'))->exception(Tell_Cron_Exception::class);
})->then('matchDayMonth()', function() use ($tab, $bad) {
// Every minute, on day 2 of the month
$this->assert($tab('* * 2 * *', '2023-02-01 23:59:00')->matchDayMonth())->false();
$this->assert($tab('* * 2 * *', '2023-02-02 00:00:00')->matchDayMonth())->true();
$this->assert($tab('* * 2 * *', '2023-02-02 00:01:10')->matchDayMonth())->true();
$this->assert($tab('* * 2 * *', '2023-02-02 00:02:03')->matchDayMonth())->true();
$this->assert($tab('* * 2 * *', '2023-02-02 23:59:00')->matchDayMonth())->true();
$this->assert($tab('* * 2 * *', '2023-02-03 00:00:00')->matchDayMonth())->false();
// Every minute, every 3 days, between day 2 and 15 of the month
$this->assert($tab('* * 2-15/3 * *', '2023-03-01 23:59:00')->matchDayMonth())->false();
$this->assert($tab('* * 2-15/3 * *', '2023-03-02 00:00:00')->matchDayMonth())->true();
$this->assert($tab('* * 2-15/3 * *', '2023-03-03 12:10:00')->matchDayMonth())->false();
$this->assert($tab('* * 2-15/3 * *', '2023-03-04 12:10:00')->matchDayMonth())->false();
$this->assert($tab('* * 2-15/3 * *', '2023-03-05 12:10:00')->matchDayMonth())->true();
$this->assert($tab('* * 2-15/3 * *', '2023-03-14 12:10:00')->matchDayMonth())->true();
$this->assert($tab('* * 2-15/3 * *', '2023-03-15 12:10:00')->matchDayMonth())->false();
// Every minute, on day 5, 15, and 31 of the month
$this->assert($tab('* * 5,15,31 * *', '2023-02-04 12:10:00')->matchDayMonth())->false();
$this->assert($tab('* * 5,15,31 * *', '2023-02-05 12:10:00')->matchDayMonth())->true();
$this->assert($tab('* * 5,15,31 * *', '2023-02-06 12:10:00')->matchDayMonth())->false();
$this->assert($tab('* * 5,15,31 * *', '2023-02-14 12:10:00')->matchDayMonth())->false();
$this->assert($tab('* * 5,15,31 * *', '2023-02-15 12:10:00')->matchDayMonth())->true();
$this->assert($tab('* * 5,15,31 * *', '2023-02-16 12:10:00')->matchDayMonth())->false();
$this->assert($tab('* * 5,15,31 * *', '2023-02-31 12:10:00')->matchDayMonth())->false();
// Every minute
$this->assert($tab('* * * * *', '2023-02-16 12:10:00')->matchDayMonth())->true();
// 1-31 max range
$this->assert($bad('* * 0-31 * *', '2023-02-20 02:59:59', 'matchDayMonth'))->exception(Tell_Cron_Exception::class);
$this->assert($bad('* * 1-32 * *', '2023-02-20 02:59:59', 'matchDayMonth'))->exception(Tell_Cron_Exception::class);
$this->assert($bad('* * 0 * *', '2023-02-20 02:59:59', 'matchDayMonth'))->exception(Tell_Cron_Exception::class);
$this->assert($bad('* * 32 * *', '2023-02-20 02:59:59', 'matchDayMonth'))->exception(Tell_Cron_Exception::class);
})->then('matchMonth()', function() use ($tab, $bad) {
// Every minute, January through March
$this->assert($tab('* * * jan-mar *', '2022-12-31 23:59:59')->matchMonth())->false();
$this->assert($tab('* * * jan-mar *', '2023-01-01 00:00:00')->matchMonth())->true();
$this->assert($tab('* * * jan-mar *', '2023-01-15 10:05:13')->matchMonth())->true();
$this->assert($tab('* * * jan-mar *', '2023-01-31 10:05:13')->matchMonth())->true();
$this->assert($tab('* * * jan-mar *', '2023-02-10 10:05:13')->matchMonth())->true();
$this->assert($tab('* * * jan-mar *', '2023-02-28 10:05:13')->matchMonth())->true();
$this->assert($tab('* * * jan-mar *', '2023-03-31 23:59:59')->matchMonth())->true();
$this->assert($tab('* * * jan-mar *', '2023-04-01 00:00:00')->matchMonth())->false();
$this->assert($tab('* * * 1-3 *', '2022-12-31 23:59:59')->matchMonth())->false();
$this->assert($tab('* * * 1-3 *', '2023-01-01 00:00:00')->matchMonth())->true();
$this->assert($tab('* * * 1-3 *', '2023-01-15 10:05:13')->matchMonth())->true();
$this->assert($tab('* * * 1-3 *', '2023-01-31 10:05:13')->matchMonth())->true();
$this->assert($tab('* * * 1-3 *', '2023-02-10 10:05:13')->matchMonth())->true();
$this->assert($tab('* * * 1-3 *', '2023-02-28 10:05:13')->matchMonth())->true();
$this->assert($tab('* * * 1-3 *', '2023-03-31 23:59:59')->matchMonth())->true();
$this->assert($tab('* * * 1-3 *', '2023-04-01 00:00:00')->matchMonth())->false();
// Every minute, only in January, March, and August
$this->assert($tab('* * * jan,mar,aug *', '2023-01-02 13:35:02')->matchMonth())->true();
$this->assert($tab('* * * jan,mar,aug *', '2023-02-02 13:35:02')->matchMonth())->false();
$this->assert($tab('* * * jan,mar,aug *', '2023-03-02 13:35:02')->matchMonth())->true();
$this->assert($tab('* * * jan,mar,aug *', '2023-07-02 13:35:02')->matchMonth())->false();
$this->assert($tab('* * * jan,mar,aug *', '2023-08-02 13:35:02')->matchMonth())->true();
$this->assert($tab('* * * jan,mar,aug *', '2023-09-02 13:35:02')->matchMonth())->false();
$this->assert($tab('* * * 1,3,8 *', '2023-01-02 13:35:02')->matchMonth())->true();
$this->assert($tab('* * * 1,3,8 *', '2023-02-02 13:35:02')->matchMonth())->false();
$this->assert($tab('* * * 1,3,8 *', '2023-03-02 13:35:02')->matchMonth())->true();
$this->assert($tab('* * * 1,3,8 *', '2023-07-02 13:35:02')->matchMonth())->false();
$this->assert($tab('* * * 1,3,8 *', '2023-08-02 13:35:02')->matchMonth())->true();
$this->assert($tab('* * * 1,3,8 *', '2023-09-02 13:35:02')->matchMonth())->false();
// Every minute
$this->assert($tab('* * * * *', '2023-09-02 13:35:02')->matchMonth())->true();
// 1-12 max range
$this->assert($bad('* * * 0 *', '2023-02-20 02:59:59', 'matchMonth'))->exception(Tell_Cron_Exception::class);
$this->assert($bad('* * * 13 *', '2023-02-20 02:59:59', 'matchMonth'))->exception(Tell_Cron_Exception::class);
$this->assert($bad('* * * 0-12 *', '2023-02-20 02:59:59', 'matchMonth'))->exception(Tell_Cron_Exception::class);
$this->assert($bad('* * * 5-3 *', '2023-02-20 02:59:59', 'matchMonth'))->exception(Tell_Cron_Exception::class);
$this->assert($bad('* * * jan-foo *', '2023-02-20 02:59:59', 'matchMonth'))->exception(Tell_Cron_Exception::class);
$this->assert($bad('* * * may-jan *', '2023-02-20 02:59:59', 'matchMonth'))->exception(Tell_Cron_Exception::class);
})->then('matchDayWeek()', function() use ($tab, $bad) {
// Every minute, Monday through Friday
$this->assert($tab('* * * * mon-fri', '2023-02-26 23:59:59')->matchDayWeek())->false(); // sun
$this->assert($tab('* * * * mon-fri', '2023-02-27 14:10:30')->matchDayWeek())->true(); // mon
$this->assert($tab('* * * * mon-fri', '2023-02-28 14:10:30')->matchDayWeek())->true(); // tue
$this->assert($tab('* * * * mon-fri', '2023-03-01 14:10:30')->matchDayWeek())->true(); // wed
$this->assert($tab('* * * * mon-fri', '2023-03-02 14:10:30')->matchDayWeek())->true(); // thu
$this->assert($tab('* * * * mon-fri', '2023-03-03 23:59:59')->matchDayWeek())->true(); // fri
$this->assert($tab('* * * * mon-fri', '2023-03-04 00:00:00')->matchDayWeek())->false(); // sat
$this->assert($tab('* * * * 1-5', '2023-02-26 23:59:59')->matchDayWeek())->false(); // sun
$this->assert($tab('* * * * 1-5', '2023-02-27 14:10:30')->matchDayWeek())->true(); // mon
$this->assert($tab('* * * * 1-5', '2023-02-28 14:10:30')->matchDayWeek())->true(); // tue
$this->assert($tab('* * * * 1-5', '2023-03-01 14:10:30')->matchDayWeek())->true(); // wed
$this->assert($tab('* * * * 1-5', '2023-03-02 14:10:30')->matchDayWeek())->true(); // thu
$this->assert($tab('* * * * 1-5', '2023-03-03 23:59:59')->matchDayWeek())->true(); // fri
$this->assert($tab('* * * * 1-5', '2023-03-04 00:00:00')->matchDayWeek())->false(); // sat
// Every minute, every 2 days of the week, Monday through Friday
$this->assert($tab('* * * * 1-5/2', '2023-02-28 10:05:00')->matchDayWeek())->false(); // tue
$this->assert($tab('* * * * 1-5/2', '2023-03-01 10:05:00')->matchDayWeek())->true(); // wed
$this->assert($tab('* * * * 1-5/2', '2023-03-02 10:05:00')->matchDayWeek())->false(); // thu
$this->assert($tab('* * * * 1-5/2', '2023-03-03 10:05:00')->matchDayWeek())->true(); // fri
$this->assert($tab('* * * * 1-5/2', '2023-03-04 10:05:00')->matchDayWeek())->false(); // sat
$this->assert($tab('* * * * 1-5/2', '2023-03-05 10:05:00')->matchDayWeek())->false(); // sun
$this->assert($tab('* * * * 1-5/2', '2023-03-06 10:05:00')->matchDayWeek())->true(); // mon
// Every minute, only on Tuesday and Thursday
$this->assert($tab('* * * * tue,thu', '2023-02-28 12:00:00')->matchDayWeek())->true(); // tue
$this->assert($tab('* * * * tue,thu', '2023-03-01 12:00:00')->matchDayWeek())->false(); // wed
$this->assert($tab('* * * * tue,thu', '2023-03-02 12:00:00')->matchDayWeek())->true(); // thu
$this->assert($tab('* * * * tue,thu', '2023-03-03 12:00:00')->matchDayWeek())->false(); // fri
$this->assert($tab('* * * * 2,4', '2023-02-28 12:00:00')->matchDayWeek())->true(); // tue
$this->assert($tab('* * * * 2,4', '2023-03-01 12:00:00')->matchDayWeek())->false(); // wed
$this->assert($tab('* * * * 2,4', '2023-03-02 12:00:00')->matchDayWeek())->true(); // thu
$this->assert($tab('* * * * 2,4', '2023-03-03 12:00:00')->matchDayWeek())->false(); // fri
// Every minute
$this->assert($tab('* * * * *', '2023-03-06 10:05:00')->matchDayWeek())->true();
// 0-6 max range
$this->assert($bad('* * * * 7', '2023-02-28 12:30:00', 'matchDayWeek'))->exception(Tell_Cron_Exception::class);
$this->assert($bad('* * * * 0-7', '2023-02-28 12:30:00', 'matchDayWeek'))->exception(Tell_Cron_Exception::class);
$this->assert($bad('* * * * 5-3', '2023-02-28 12:30:00', 'matchDayWeek'))->exception(Tell_Cron_Exception::class);
$this->assert($bad('* * * * 0-foo', '2023-02-28 12:30:00', 'matchDayWeek'))->exception(Tell_Cron_Exception::class);
$this->assert($bad('* * * * foo', '2023-02-28 12:30:00', 'matchDayWeek'))->exception(Tell_Cron_Exception::class);
})->then('matches()', function() use ($tab, $bad) {
// Every 5 minutes
$this->assert($tab('*/5 * * * *', '2023-03-06 10:05:03')->matches())->true();
$this->assert($tab('*/5 * * * *', '2023-03-06 10:06:03')->matches())->false();
$this->assert($tab('*/5 * * * *', '2023-03-06 10:10:53')->matches())->true();
// At 04:15 PM, Monday through Friday
$this->assert($tab('15 16 * * mon-fri', '2023-03-06 16:14:59')->matches())->false(); // mon
$this->assert($tab('15 16 * * mon-fri', '2023-03-06 16:15:06')->matches())->true(); // mon
$this->assert($tab('15 16 * * mon-fri', '2023-03-07 16:15:00')->matches())->true(); // tue
$this->assert($tab('15 16 * * mon-fri', '2023-03-08 16:15:03')->matches())->true(); // wed
$this->assert($tab('15 16 * * mon-fri', '2023-03-09 16:15:01')->matches())->true(); // thu
$this->assert($tab('15 16 * * mon-fri', '2023-03-10 16:15:00')->matches())->true(); // fri
$this->assert($tab('15 16 * * mon-fri', '2023-03-11 16:15:00')->matches())->false(); // sat
$this->assert($tab('15 16 * * 1-5', '2023-03-06 16:14:59')->matches())->false(); // mon
$this->assert($tab('15 16 * * 1-5', '2023-03-06 16:15:06')->matches())->true(); // mon
$this->assert($tab('15 16 * * 1-5', '2023-03-07 16:15:00')->matches())->true(); // tue
$this->assert($tab('15 16 * * 1-5', '2023-03-08 16:15:03')->matches())->true(); // wed
$this->assert($tab('15 16 * * 1-5', '2023-03-09 16:15:01')->matches())->true(); // thu
$this->assert($tab('15 16 * * 1-5', '2023-03-10 16:15:00')->matches())->true(); // fri
$this->assert($tab('15 16 * * 1-5', '2023-03-11 16:15:00')->matches())->false(); // sat
// At 7, 27, and 47 minutes past the hour, between 09:00 AM and 04:59 PM, Monday through Friday
$this->assert($tab('7,27,47 9-16 * * mon-fri', '2023-02-26 09:07:00')->matches())->false(); // sun
$this->assert($tab('7,27,47 9-16 * * mon-fri', '2023-02-26 14:27:01')->matches())->false(); // sun
$this->assert($tab('7,27,47 9-16 * * mon-fri', '2023-02-26 16:47:01')->matches())->false(); // sun
$this->assert($tab('7,27,47 9-16 * * mon-fri', '2023-02-27 09:07:00')->matches())->true(); // mon
$this->assert($tab('7,27,47 9-16 * * mon-fri', '2023-02-27 14:27:01')->matches())->true(); // mon
$this->assert($tab('7,27,47 9-16 * * mon-fri', '2023-02-27 16:47:01')->matches())->true(); // mon
$this->assert($tab('7,27,47 9-16 * * mon-fri', '2023-02-27 17:47:01')->matches())->false(); // mon
$this->assert($tab('7,27,47 9-16 * * mon-fri', '2023-02-27 08:07:01')->matches())->false(); // mon
$this->assert($tab('7,27,47 9-16 * * 1-5', '2023-02-26 09:07:00')->matches())->false(); // sun
$this->assert($tab('7,27,47 9-16 * * 1-5', '2023-02-26 14:27:01')->matches())->false(); // sun
$this->assert($tab('7,27,47 9-16 * * 1-5', '2023-02-26 16:47:01')->matches())->false(); // sun
$this->assert($tab('7,27,47 9-16 * * 1-5', '2023-02-27 09:07:00')->matches())->true(); // mon
$this->assert($tab('7,27,47 9-16 * * 1-5', '2023-02-27 14:27:01')->matches())->true(); // mon
$this->assert($tab('7,27,47 9-16 * * 1-5', '2023-02-27 16:47:01')->matches())->true(); // mon
$this->assert($tab('7,27,47 9-16 * * 1-5', '2023-02-27 17:47:01')->matches())->false(); // mon
$this->assert($tab('7,27,47 9-16 * * 1-5', '2023-02-27 08:07:01')->matches())->false(); // mon
});
});
{JSON results of applicable inspection}
<?php
/**
* This inspection is still under construction.
* ---
* @todo
*/
$inspect('Tell_Uri', function() {
$this->try('_()', function() {
// @todo
});
});
{JSON results of applicable inspection}
<?php
// ---------------------------------------------------------------------------------------------
$inspect('Tell_Client - Parameters', function() {
$good = function($request, $response, $method, Closure $extra = NULL) {
$data = function($key) use ($request) {
return Tell_Arr::get($request->toArr(), $key);
};
$this->assert($request)->instanceOf(Tell_Client_Request::class);
$this->assert($response)->instanceOf(Tell_Client_Response::class);
$this->assert($response->code())->equals(200);
$this->assert($response->body('method'))->equals($method);
$this->assert($response->isJson())->true();
$this->assert($response->header('Authorization'))->equals($data('headers.authorization.1'));
$this->assert($response->body())->iterable();
$this->assert($response->body('query.account'))->equals((string) $data('query.account'));
$this->assert($response->body('input.email'))->equals($data('data.email'));
$this->assert($response->body('input.country'))->equals($data('data.country'));
$this->assert($response->body('input.Country'))->empty();
if ($extra) {
$extra->bindTo($this)->__invoke($data, $response);
}
};
$bad = function($request, $response) {
$this->assert($request)->instanceOf(Tell_Client_Request::class);
$this->assert($response)->instanceOf(Tell_Client_Response::class);
$this->assert($response->code())->equals(404);
};
$emptyBody = function($request, $response) {
$this->assert($request)->instanceOf(Closure::class);
$this->assert($response)->instanceOf(Tell_Client_Response::class);
$this->assert($response->body('body'))->equals('');
};
$postBody = function($request, $response) {
$this->assert($request)->instanceOf(Closure::class);
$this->assert($response)->instanceOf(Tell_Client_Response::class);
$this->assert($response->body('body'))->equals('first_name=Bob&last_name=Smith&email=bob-smith%40foobar.com&country=US');
$this->assert($response->body('headers.Content-Type'))->equals('application/x-www-form-urlencoded');
};
$data = (new Tell_Client_Request())
->header('Authorization', $this->code)
->query(['status' => 'Active', 'account' => 12])
->data([
'first_name' => $this->first_name,
'last_name' => $this->last_name,
'email' => $this->email,
'country' => 'US',
]);
$this->try('cURL Driver', function() use ($data, $good, $bad, $emptyBody, $postBody) {
$config = ['driver' => 'curl'];
$good($data, (new Tell_Client($config))->get('test/webhook/get/123', $data), 'GET', $emptyBody);
$bad($data, (new Tell_Client($config))->get('test/webhook/post', $data), 'GET');
$good($data, (new Tell_Client($config))->post('test/webhook/post', $data), 'POST', $postBody);
});
$this->try('Socket Driver', function() use ($data, $good, $bad, $emptyBody, $postBody) {
$config = ['driver' => 'socket'];
$good($data, (new Tell_Client($config))->get('test/webhook/get/123', $data), 'GET', $emptyBody);
$bad($data, (new Tell_Client($config))->get('test/webhook/post', $data), 'GET');
$good($data, (new Tell_Client($config))->post('test/webhook/post', $data), 'POST', $postBody);
});
})->vars([
'code' => 'feVUrB4f0j5ScMd3',
'first_name' => 'Bob',
'last_name' => 'Smith',
'email' => 'bob-smith@foobar.com',
])->onlyWhen(function() {
return ! Tell_Request::isCli();
});
// ---------------------------------------------------------------------------------------------
$inspect('Tell_Client - JSON', function() {
$good = function($request, $response, $method, Closure $extra = NULL) {
$data = function($key) use ($request) {
return Tell_Arr::get($request->toArr(), $key);
};
$this->assert($request)->instanceOf(Tell_Client_Request::class);
$this->assert($response)->instanceOf(Tell_Client_Response::class);
$this->assert($response->code())->equals(200);
$this->assert($response->body('method'))->equals($method);
$this->assert($response->isJson())->true();
$this->assert($response->header('Authorization'))->equals($data('headers.authorization.1'));
$this->assert($response->body())->iterable();
$this->assert($response->body('query.account'))->equals((string) $data('query.account'));
$this->assert($response->body('input.email'))->equals($data('data.email'));
$this->assert($response->body('input.country'))->equals($data('data.country'));
$this->assert($response->body('input.Country'))->empty();
if ($extra) {
$extra->bindTo($this)->__invoke($data, $response);
}
};
$emptyBody = function($request, $response) {
$this->assert($request)->instanceOf(Closure::class);
$this->assert($response)->instanceOf(Tell_Client_Response::class);
$this->assert($response->body('body'))->equals('');
};
$jsonBody = function($request, $response) {
$this->assert($request)->instanceOf(Closure::class);
$this->assert($response)->instanceOf(Tell_Client_Response::class);
$this->assert($response->body('body'))->equals('{"first_name":"Bob","last_name":"Smith","email":"bob-smith@foobar.com","country":"CA"}');
$this->assert($response->body('headers.Content-Type'))->equals('application/json');
};
$json = (new Tell_Client_Request())
->header('Authorization', $this->code)
->query(['status' => 'Disabled', 'account' => 65])
->json([
'first_name' => $this->first_name,
'last_name' => $this->last_name,
'email' => $this->email,
'country' => 'CA',
]);
$this->try('cURL Driver', function() use ($json, $good, $emptyBody, $jsonBody) {
$config = ['driver' => 'curl'];
$good($json, (new Tell_Client($config))->get('test/webhook/json', $json), 'GET', $emptyBody);
$good($json, (new Tell_Client($config))->post('test/webhook/json', $json), 'POST', $jsonBody);
});
$this->try('Socket Driver', function() use ($json, $good, $emptyBody, $jsonBody) {
$config = ['driver' => 'socket'];
$good($json, (new Tell_Client($config))->get('test/webhook/json', $json), 'GET', $emptyBody);
$good($json, (new Tell_Client($config))->post('test/webhook/json', $json), 'POST', $jsonBody);
});
})->vars([
'code' => 'feVUrB4f0j5ScMd3',
'first_name' => 'Bob',
'last_name' => 'Smith',
'email' => 'bob-smith@foobar.com',
])->onlyWhen(function() {
return ! Tell_Request::isCli();
});
// ---------------------------------------------------------------------------------------------
$inspect('Tell_Client - Binary', function() {
$good = function($request, $response, $method) {
$this->assert($request)->instanceOf(Tell_Client_Request::class);
$this->assert($response)->instanceOf(Tell_Client_Response::class);
$this->assert($response->code())->equals(200);
$this->assert($response->body('method'))->equals($method);
$this->assert(base64_decode($response->body('body')))->equals($this->image);
};
$data = (new Tell_Client_Request())
->header('Authorization', $this->code)
->query(['status' => 'Active', 'account' => 15])
->data($this->image);
$this->try('cURL Driver', function() use ($data, $good) {
$config = ['driver' => 'curl'];
$good($data, (new Tell_Client($config))->post('test/webhook/binary', $data), 'POST');
$good($data, (new Tell_Client($config))->put('test/webhook/binary', $data), 'PUT');
$good($data, (new Tell_Client($config))->delete('test/webhook/binary', $data), 'DELETE');
$good($data, (new Tell_Client($config))->patch('test/webhook/binary', $data), 'PATCH');
});
$this->try('Socket Driver', function() use ($data, $good) {
$config = ['driver' => 'socket'];
$good($data, (new Tell_Client($config))->post('test/webhook/binary', $data), 'POST');
$good($data, (new Tell_Client($config))->put('test/webhook/binary', $data), 'PUT');
$good($data, (new Tell_Client($config))->delete('test/webhook/binary', $data), 'DELETE');
$good($data, (new Tell_Client($config))->patch('test/webhook/binary', $data), 'PATCH');
});
})->vars([
'code' => 'kRPlYbudWQ7gd79v',
'image' => file_get_contents(__DIR__ . '/../assets/images/shark.jpeg'),
])->onlyWhen(function() {
return ! Tell_Request::isCli();
});
// ---------------------------------------------------------------------------------------------
$inspect('Tell_Client - Empty', function() {
$good = function($request, $response, $method) {
$this->assert($request)->instanceOf(Tell_Client_Request::class);
$this->assert($response)->instanceOf(Tell_Client_Response::class);
$this->assert($response->code())->equals(200);
$this->assert($response->header('authorization'))->equals($this->code);
$this->assert($response->header('x-request-method'))->equals($method);
$this->assert($response->body('body'))->null();
};
$data = (new Tell_Client_Request())
->header('Authorization', $this->code)
->query(['status' => 'Active', 'account' => 15]);
$this->try('cURL Driver', function() use ($data, $good) {
$config = ['driver' => 'curl'];
$good($data, (new Tell_Client($config))->head('test/webhook/empty', $data), 'HEAD');
$good($data, (new Tell_Client($config))->delete('test/webhook/empty', $data), 'DELETE');
});
$this->try('Socket Driver', function() use ($data, $good) {
$config = ['driver' => 'socket'];
$good($data, (new Tell_Client($config))->head('test/webhook/empty', $data), 'HEAD');
$good($data, (new Tell_Client($config))->delete('test/webhook/empty', $data), 'DELETE');
});
})->vars([
'code' => 'kRPlYbudWQ7gd79v',
])->onlyWhen(function() {
return ! Tell_Request::isCli();
});
// ---------------------------------------------------------------------------------------------
{JSON results of applicable inspection}
<?php
$inspect('Tell_Cookie', function() {
$this->try('Tell_Cookie_Write', function() {
$cookie = new Tell_Cookie_Write($this->name, $this->value, [
'expires' => 0,
'path' => '',
'domain' => '',
'secure' => FALSE,
'httponly' => FALSE,
'maxage' => NULL,
'samesite' => 'Lax',
], $this->hash_key);
$this->assert($cookie->sign())->equals($this->signed);
$this->assert($cookie->unsign())->equals($this->value);
$this->assert($cookie->options())
->arr()
->hasKey('expires')
->hasKey('path')
->hasKey('domain')
->hasKey('secure')
->hasKey('httponly')
->hasKey('samesite')
->contains('Lax')
->contains('/');
});
$this->try('Tell_Cookie_Read', function() {
$cookie = new Tell_Cookie_Read($this->name, $this->signed, $this->hash_key);
$this->assert($cookie->__toString())->equals($this->value);
$this->assert($cookie->unsign())->equals($this->value);
$this->assert($cookie->sign())->equals($this->signed);
});
})->vars([
'name' => 'TestTellCookie',
'value' => 'hello world',
'hash_key' => 'test-hash-key-123',
'signed' => '79a6a3b9474ba9874f903be5e19abf13df051b32_hello world',
'signature' => '79a6a3b9474ba9874f903be5e19abf13df051b32',
]);
{JSON results of applicable inspection}
<?php
// -------------------------------------------------------------------------------------------------
class Inspect_Test_Auth_Session extends Tell_Auth_Session
{
const RECORD_TABLE = '_test_users';
const FIELD_ID = 'id';
const FIELD_PASSWORD = 'password';
const SECRET_COOKIE = 'DQ89eTd2uueXWuzgDif9vgEKTEIJAO1g';
const SECRET_PERSIST = 'WwZtarOG03HpjjYYZ3ZIllmTxoYJrvUE';
public function isActive()
: bool
{
return 'Active' === $this->get('status');
}
public function findById($id)
: ? array
{
if (123 !== (int) $id) {
return NULL;
}
return [
'id' => 123,
'first_name' => 'Bob',
'last_name' => 'Smith',
'email' => 'bob@example.com',
'password' => '$2y$12$6xVfIWPWnxSa789yxPhvVeAkPtEOiL95jFkDyCUXvAW2hVfPmTyBO', // testing
];
}
public function findByUser($user)
: ? array
{
if ('bob@example.com' !== $user) {
return NULL;
}
return [
'id' => 123,
'first_name' => 'Bob',
'last_name' => 'Smith',
'email' => 'bob@example.com',
'password' => '$2y$12$6xVfIWPWnxSa789yxPhvVeAkPtEOiL95jFkDyCUXvAW2hVfPmTyBO', // testing
];
}
protected function persistHashKey()
: string
{
return self::SECRET_PERSIST;
}
protected function cookieHashKey()
: string
{
return self::SECRET_COOKIE;
}
public $test = [
'onAuthenticate' => [],
'onAuthenticateSuccess' => [],
'onAuthenticateFailure' => [],
'onAuthenticateRevoke' => [],
'onPersist' => [],
'onPersistSuccess' => [],
'onPersistFailure' => [],
'onAuthorize' => [],
'onAuthorizeSuccess' => [],
];
public function onAuthenticate(...$args)
{
$this->test['onAuthenticate'] = $args;
}
public function onAuthenticateSuccess(...$args)
{
$this->test['onAuthenticateSuccess'] = $args;
}
public function onAuthenticateFailure(...$args)
{
$this->test['onAuthenticateFailure'] = $args;
}
public function onAuthenticateRevoke(...$args)
{
$this->test['onAuthenticateRevoke'] = $args;
}
public function onPersist(...$args)
{
$this->test['onPersist'] = $args;
}
public function onPersistSuccess(...$args)
{
$this->test['onPersistSuccess'] = $args;
}
public function onPersistFailure(...$args)
{
$this->test['onPersistFailure'] = $args;
}
public function onAuthorize(...$args)
{
$this->test['onAuthorize'] = $args;
}
public function onAuthorizeSuccess(...$args)
{
$this->test['onAuthorizeSuccess'] = $args;
}
}
// -------------------------------------------------------------------------------------------------
$inspect('Tell_Auth_Session >> Instantiate', function(Inspect_Test_Auth_Session $auth) {
$this->assert($auth->test['onAuthenticate'])->array()->empty();
$this->assert($auth->test['onAuthenticateSuccess'])->array()->empty();
$this->assert($auth->test['onAuthenticateFailure'])->array()->empty();
$this->assert($auth->test['onPersist'])->array()->empty();
$this->assert($auth->test['onPersistSuccess'])->array()->empty();
$this->assert($auth->test['onPersistFailure'])->array()->empty();
$this->assert($auth->test['onAuthorize'])->array()->empty();
$this->assert($auth->test['onAuthorizeSuccess'])->array()->empty();
})->swap(function() {
$db = Mockery::mock(Tell_Db::class);
$persist = Mockery::mock(Tell_Auth_Persist::class);
$persist->shouldReceive('hashKey')->andReturnSelf();
$persist->shouldReceive('graft')->andReturn(NULL);
return [
'Tell_Db' => $db,
'Tell_Auth_Persist' => $persist,
];
});
// -------------------------------------------------------------------------------------------------
$inspect('Tell_Auth_Session >> Login & Logout', function(Inspect_Test_Auth_Session $auth) {
$this->assert($auth->login('bob@example.com', 'testing', TRUE))->true();
$this->assert($auth->test['onAuthenticate'][0])->equals([
'id' => 123,
'first_name' => 'Bob',
'last_name' => 'Smith',
'email' => 'bob@example.com',
'password' => '$2y$12$6xVfIWPWnxSa789yxPhvVeAkPtEOiL95jFkDyCUXvAW2hVfPmTyBO',
]);
$this->assert($auth->test['onAuthenticate'][1])->instanceOf($auth);
$this->assert($auth->test['onAuthenticateSuccess'])->array()->hasKey(0)->hasKey(1);
$this->assert($auth->test['onAuthenticateFailure'])->array()->empty();
$this->assert($auth->test['onAuthenticateRevoke'])->array()->empty();
$this->assert($auth->test['onPersist'])->array()->empty();
$this->assert($auth->test['onPersistSuccess'])->array()->empty();
$this->assert($auth->test['onPersistFailure'])->array()->empty();
$this->assert($auth->test['onAuthorize'])->array()->empty();
$this->assert($auth->test['onAuthorizeSuccess'])->array()->empty();
$this->assert($auth->isAuthenticated())->true();
$this->assert($auth->logout())->true();
$this->assert($auth->test['onAuthenticateRevoke'])->array()->hasKey(0)->hasKey(1);
$this->assert($auth->isAuthenticated())->false();
})->swap(function() {
$db = Mockery::mock(Tell_Db::class);
$refresh = [
Tell_Security::random(32),
Tell_Security::random(32),
1678300000,
];
$persist = Mockery::mock(Tell_Auth_Persist::class);
$persist->shouldReceive('hashKey')->andReturnSelf();
$persist->shouldReceive('graft')->andReturn(NULL);
$persist->shouldReceive('create')->andReturn($refresh);
$persist->shouldReceive('delete')->andReturn(TRUE);
return [
'Tell_Db' => $db,
'Tell_Auth_Persist' => $persist,
];
});
// -------------------------------------------------------------------------------------------------
$inspect('Tell_Auth_Session >> Valid Persistent Cookie', function(Inspect_Test_Auth_Session $auth) {
$this->assert($auth->test['onAuthenticate'])->array()
->hasKey(0)
->hasKey(1)
->hasKey(2)
->hasKey(3);
$this->assert($auth->test['onAuthenticate'][0])->equals([
'id' => 123,
'first_name' => 'Bob',
'last_name' => 'Smith',
'email' => 'bob@example.com',
'password' => '$2y$12$6xVfIWPWnxSa789yxPhvVeAkPtEOiL95jFkDyCUXvAW2hVfPmTyBO',
]);
$this->assert($auth->test['onAuthenticate'][1])->equals([
'id' => 1,
'parent_table' => '_test_users',
'parent_record' => 123,
'access_selector' => 'd5HwgHaB9AK0ZhaW9ZXxiMNBQVYg8tGw',
'access_token' => 'f7dd5af516104c5815f5cfd95497d9bdb1bab68d9c9f63f9b9bc52bbe9df6b9f',
'class_name' => 'Inspect_Test_Auth_Session',
'last_ip' => '172.16.238.1',
'created' => '2023-02-26 02:35:21',
'expires' => '2023-03-12 02:35:21',
]);
$this->assert($auth->test['onAuthenticate'][2])->equals([
'data' => 'JbhhPAvb2GHMab7UHgSuMoOSnW3I46n5_ets84uaemGgnT9VZdVurMgPN7sAlg0GT',
'select' => 'JbhhPAvb2GHMab7UHgSuMoOSnW3I46n5',
'token' => 'ets84uaemGgnT9VZdVurMgPN7sAlg0GT',
]);
$this->assert($auth->test['onAuthenticate'][3])->instanceOf($auth);
$this->assert($auth->test['onAuthenticateFailure'])->array()->empty();
$this->assert($auth->test['onAuthenticateRevoke'])->array()->empty();
$this->assert($auth->test['onPersist'])->equals($auth->test['onAuthenticate']);
$this->assert($auth->test['onPersistSuccess'])->equals($auth->test['onAuthenticateSuccess']);
$this->assert($auth->test['onPersistFailure'])->array()->empty();
$this->assert($auth->test['onAuthorize'])->array()->empty();
$this->assert($auth->test['onAuthorizeSuccess'])->array()->empty();
$this->assert($auth->isAuthenticated())->true();
})->request(function() {
$cookie = new Tell_Cookie_Read('_tell_auths__Inspect_Test_Auth_Session', '760418426d3517c7323d6328acbd49241f7b0215_JbhhPAvb2GHMab7UHgSuMoOSnW3I46n5_ets84uaemGgnT9VZdVurMgPN7sAlg0GT');
return [
'method' => 'GET',
'cookie' => [
'_tell_auths__Inspect_Test_Auth_Session' => $cookie,
],
];
})->swap(function() {
$record = [
'id' => 1,
'parent_table' => '_test_users',
'parent_record' => 123,
'access_selector' => 'd5HwgHaB9AK0ZhaW9ZXxiMNBQVYg8tGw',
'access_token' => 'f7dd5af516104c5815f5cfd95497d9bdb1bab68d9c9f63f9b9bc52bbe9df6b9f',
'class_name' => 'Inspect_Test_Auth_Session',
'last_ip' => '172.16.238.1',
'created' => '2023-02-26 02:35:21',
'expires' => '2023-03-12 02:35:21',
];
$db = Mockery::mock(Tell_Db::class);
$persist = Mockery::mock(Tell_Auth_Persist::class);
$persist->shouldReceive('hashKey')->andReturnSelf();
$persist->shouldReceive('graft')->andReturn(NULL);
$persist->shouldReceive('load')->andReturn($record);
return [
'Tell_Db' => $db,
'Tell_Auth_Persist' => $persist,
];
});
// -------------------------------------------------------------------------------------------------
{JSON results of applicable inspection}
<?php
function eventFoo(Tell_Bridge_Event $e, $true, $false, $int, $float, $hello, $world)
{
affirm($true)->true();
affirm($false)->false();
affirm($int)->equals(3);
affirm($float)->equals(1.5);
affirm($hello)->equals('hello');
affirm($world)->equals('world');
return __FUNCTION__;
}
function eventBarDoe($a, $female, $deer, $true, $float, $e)
{
affirm($a)->equals('a');
affirm($female)->equals('female');
affirm($deer)->equals('deer');
affirm($true)->true();
affirm($float)->equals(2.5);
affirm($e)->instanceOf(Tell_Bridge_Event::class);
return __FUNCTION__;
}
function eventBarRei(Tell_Bridge_Event $e, $a, $drop, $of, $golden, $sun, $true, $float)
{
affirm($a)->equals('a');
affirm($drop)->equals('drop');
affirm($of)->equals('of');
affirm($golden)->equals('golden');
affirm($sun)->equals('sun');
affirm($true)->true();
affirm($float)->equals(2.5);
return __FUNCTION__;
}
function eventBarMei($a, $name, $i, $call, $myself, $true, $float, $e)
{
affirm($a)->equals('a');
affirm($name)->equals('name');
affirm($i)->equals('I');
affirm($call)->equals('call');
affirm($myself)->equals('myself');
affirm($true)->true();
affirm($float)->equals(2.5);
affirm($e)->instanceOf(Tell_Bridge_Event::class);
return __FUNCTION__;
}
class Event_Foo
{
public function __invoke(Tell_Bridge_Event $e, $true, $false, $int, $float, $hello, $world)
{
affirm(eventFoo(...func_get_args()))->equals('eventFoo');
return __METHOD__;
}
}
class Event_Bar
{
public function doe($a, $female, $deer, $true, $float, $e)
{
affirm(eventBarDoe(...func_get_args()))->equals('eventBarDoe');
return __METHOD__;
}
public function rei(Tell_Bridge_Event $e, $a, $drop, $of, $golden, $sun, $true, $float)
{
affirm(eventBarRei(...func_get_args()))->equals('eventBarRei');
return __METHOD__;
}
public function mei($a, $name, $i, $call, $myself, $true, $float, $e)
{
affirm(eventBarMei(...func_get_args()))->equals('eventBarMei');
return __METHOD__;
}
}
$inspect('Tell_Event', function() {
$this->try('Closures', function() {
$event = new Tell_Event(new Tell_Container());
$affirms = function($i, $am, $a, $nice, $shark, $false, $ten, $e) {
affirm($e)->instanceOf(Tell_Bridge_Event::class);
affirm(['foo', 'bar', 'fubar'])->contains($e->name);
affirm($i)->equals('I');
affirm($am)->equals('am');
affirm($a)->equals('a');
affirm($nice)->equals('nice');
affirm($shark)->equals('shark');
affirm($false)->false();
affirm($ten)->equals(10);
};
$event->register('foo;bar', function($i, $am, $a, $nice, $shark, $false, $ten, $e) use ($affirms) {
$affirms($i, $am, $a, $nice, $shark, $false, $ten, $e);
return 'Listener A';
});
$event->register(['foo', 'fubar'], function(Tell_Bridge_Event $be, $i, $am, $a, $nice, $shark, $false, $ten, $e) use ($affirms) {
affirm($be)->instanceOf(Tell_Bridge_Event::class);
$affirms($i, $am, $a, $nice, $shark, $false, $ten, $e);
return 'Listener B';
});
$event->register('foo', function($i, $am, $a, $nice, $shark, $false, $ten, $e) use ($affirms) {
$affirms($i, $am, $a, $nice, $shark, $false, $ten, $e);
$e->stop();
return 'Listener C';
});
$event->register('foo', function($i, $am, $a, $nice, $shark, $false, $ten, $e) use ($affirms) {
$affirms($i, $am, $a, $nice, $shark, $false, $ten, $e);
return 'Listener Never Invoked';
});
$event->register('bar', function($i, $am, $a, $nice, $shark, $false, $ten, $e) use ($affirms) {
$affirms($i, $am, $a, $nice, $shark, $false, $ten, $e);
return 'Listener Priority';
}, 9);
if ($foo = $event->trigger('foo', 'I', 'am', 'a', 'nice', 'shark', FALSE, 10)) {
$this->assert($foo)->instanceOf(Tell_Bridge_Event::class);
$this->assert($foo->result())->equals('Listener C');
}
if ($bar = $event->trigger('bar', 'I', 'am', 'a', 'nice', 'shark', FALSE, 10)) {
$this->assert($bar)->instanceOf(Tell_Bridge_Event::class);
$this->assert($bar->result())->equals('Listener A');
$this->assert($bar->result->pop())->equals('Listener A');
$this->assert($bar->result->pop())->equals('Listener Priority');
}
if ($fubar = $event->trigger('fubar', 'I', 'am', 'a', 'nice', 'shark', FALSE, 10)) {
$this->assert($fubar)->instanceOf(Tell_Bridge_Event::class);
$this->assert($fubar->result())->equals('Listener B');
}
});
$this->try('Functions', function() {
$event = new Tell_Event(new Tell_Container());
$event->register('foo', 'eventFoo');
$event->register('doe', 'eventBarDoe');
$event->register('rei', 'eventBarRei');
$event->register('mei', 'eventBarMei');
if ($foo = $event->trigger('foo', TRUE, FALSE, 3, 1.5, 'hello', 'world')) {
$this->assert($foo)->instanceOf(Tell_Bridge_Event::class);
$this->assert($foo->result())->equals('eventFoo');
}
if ($doe = $event->trigger('doe', 'a', 'female', 'deer', TRUE, 2.5)) {
$this->assert($doe)->instanceOf(Tell_Bridge_Event::class);
$this->assert($doe->result())->equals('eventBarDoe');
}
if ($rei = $event->trigger('rei', 'a', 'drop', 'of', 'golden', 'sun', TRUE, 2.5)) {
$this->assert($rei)->instanceOf(Tell_Bridge_Event::class);
$this->assert($rei->result())->equals('eventBarRei');
}
if ($mei = $event->trigger('mei', 'a', 'name', 'I', 'call', 'myself', TRUE, 2.5)) {
$this->assert($mei)->instanceOf(Tell_Bridge_Event::class);
$this->assert($mei->result())->equals('eventBarMei');
}
$event->remove('mei');
if ($mei = $event->trigger('mei', 'a', 'name', 'I', 'call', 'myself', TRUE, 2.5)) {
$this->assert($mei)->instanceOf(Tell_Bridge_Event::class);
$this->assert($mei->result())->null();
}
});
$this->try('Classes', function() {
$event = new Tell_Event(new Tell_Container());
$event->register('foo', Event_Foo::class);
$event->register('bar', Event_Bar::class);
$event->register('bar.doe', Event_Bar::class);
$event->register('bar.rei', Event_Bar::class);
$event->register('bar.mei', Event_Bar::class);
if ($foo = $event->trigger('foo', TRUE, FALSE, 3, 1.5, 'hello', 'world')) {
$this->assert($foo)->instanceOf(Tell_Bridge_Event::class);
$this->assert($foo->result())->equals('Event_Foo::__invoke');
}
if ($bar = $event->trigger('bar', 'hello', 'world')) {
$this->assert($bar)->instanceOf(Tell_Bridge_Event::class);
$this->assert($bar->result())->instanceOf(Event_Bar::class);
}
if ($doe = $event->trigger('bar.doe', 'a', 'female', 'deer', TRUE, 2.5)) {
$this->assert($doe)->instanceOf(Tell_Bridge_Event::class);
$this->assert($doe->result())->equals('Event_Bar::doe');
}
if ($rei = $event->trigger('bar.rei', 'a', 'drop', 'of', 'golden', 'sun', TRUE, 2.5)) {
$this->assert($rei)->instanceOf(Tell_Bridge_Event::class);
$this->assert($rei->result())->equals('Event_Bar::rei');
}
if ($mei = $event->trigger('bar.mei', 'a', 'name', 'I', 'call', 'myself', TRUE, 2.5)) {
$this->assert($mei)->instanceOf(Tell_Bridge_Event::class);
$this->assert($mei->result())->equals('Event_Bar::mei');
}
});
});
{JSON results of applicable inspection}
<?php
/**
* This inspection is still under construction.
* ---
* @todo
*/
$inspect('Tell_Translate', function() {
$this->try('_()', function() {
// @todo
});
});
{JSON results of applicable inspection}
<?php
/**
* This inspection is still under construction.
* ---
* @todo
*/
$inspect('Tell_Password', function() {
$this->try('_()', function() {
// @todo
});
});
{JSON results of applicable inspection}
<?php
/**
* This inspection is still under construction.
* ---
* @todo
*/
// ---------------------------------------------------------------------------------------------
$inspect('Tell_Bridge_Currency', function() {
// @todo
});
{JSON results of applicable inspection}
<?php
/**
* This inspection is still under construction.
* ---
* @todo
*/
$inspect('Tell_Log', function() {
$this->try('_()', function() {
// @todo
});
});
{JSON results of applicable inspection}
<?php
/**
* This inspection is still under construction.
* ---
* @todo
*/
$inspect('Tell_Schema_Table_Sqlite', function(Tell_Db $db) {
// @todo [once SQLite driver is finished]
})->swap(function(Tell_Event $event) {
return [
'Tell_Db' => new Tell_Db([
'driver' => 'sqlite',
'database' => __DIR__ . '/../assets/sql/tell_php_test.sqlite3',
'elevate_exceptions' => TRUE,
'log_failed' => TRUE,
'log_success' => FALSE,
'log_limit' => 1000,
], $event),
];
})->onlyWhen(function() {
return extension_loaded('pdo_sqlite') && env('TELL_PHP_DEV');
});
{JSON results of applicable inspection}
<?php
/**
* This inspection is still under construction.
* ---
* @todo
*/
$inspect('Tell_Asset', function() {
// @todo
});
{JSON results of applicable inspection}
<?php
/**
* This inspection is still under construction.
* ---
* @todo
*/
$inspect('Tell_Crypt', function() {
$this->try('__()', function() {
// @todo
});
});
{JSON results of applicable inspection}
<?php
$inspect('Tell_Str', function() {
$this->try('flatten()', function() {
$before = "The quick brown fox\n"
. "jumps over\r\n"
. "the lazy\n\n\n\n"
. "dog.";
$after = "The quick brown fox jumps over the lazy dog.";
$this->assert(Tell_Str::flatten($before))->equals($after);
});
$this->try('isRightToLeft()', function() {
$english = $this->langs['en'];
$russian = $this->langs['ru'];
$hebrew = $this->langs['iw'];
$this->assert(Tell_Str::isRightToLeft($english))->false();
$this->assert(Tell_Str::isRightToLeft($russian))->false();
$this->assert(Tell_Str::isRightToLeft($hebrew))->true();
});
$this->try('isAscii()', function() {
$tests = [
$this->hebrew_cp1255 => FALSE,
$this->hebrew_utf8 => FALSE,
$this->windows_1252 => FALSE,
'žščř' => FALSE,
'hëllo-world-123' => FALSE,
'hšello-world' => FALSE,
"hëllowo'rld" => FALSE,
'(123ľ' => FALSE,
'HelloW.orld FooBar' => TRUE,
'Hello$WorldFooBar' => TRUE,
"hello-world\tfoo" => TRUE,
'$Hello World_Foo_123' => TRUE,
"Hello\tWorld\t_Foo_123" => TRUE,
];
foreach ($tests as $str => $expect) {
$this->assert(Tell_Str::isAscii($str))->equals($expect);
}
});
$this->try('toAscii()', function() {
$before = "El pingüino Wenceslao hizo kilómetros bajo exhaustiva lluvia y frío, añoraba a su querido cachorro.";
$after = "El pinguino Wenceslao hizo kilometros bajo exhaustiva lluvia y frio, anoraba a su querido cachorro.";
$this->assert(Tell_Str::toAscii($before))->equals($after);
$this->assert(Tell_Str::toAscii("hëllo wφrld!"))->equals('hello world!');
$this->assert(Tell_Str::toAscii("Hοω arε yoυ?"))->equals('How are you?');
$this->assert(Tell_Str::toAscii("I'm not féélíng wéll."))->equals("I'm not feeling well.");
});
$this->try('toUtf8()', function() {
$before = $this->hebrew_cp1255;
$after = $this->hebrew_utf8;
try {
$this->assert(Tell_Str::toUtf8($before, 'CP1255'))->equals($after);
} catch (DomainException $e) {
// iconv() not installed, and mb_* functions don't support CP1255
}
$before = $this->windows_1252;
$after = "äöüßéèâ";
$this->assert(Tell_Str::toUtf8($before, 'WINDOWS-1252'))->equals($after);
});
$this->try('ltrim()', function() {
$good = [
["aaabbbccc", "ac", 2, "abbbccc"],
["aaabbbccc", "ac", 3, "bbbccc"],
["aaabbbccc", "ab", 4, "bbccc"],
["aaabbbccc", "ab", 5, "bccc"],
["aaabbbccc", "ab", 6, "ccc"],
["aaabbbccc", "abc", 7, "cc"],
["aaabbbccc", "abc", 8, "c"],
["aaabbbccc", "abc", 9, ""],
["aaabbbccc", "a", 0, "bbbccc"],
["aaabbbccc", "ab", 0, "ccc"],
];
foreach ($good as list($before, $chars, $limit, $after)) {
$this->assert(Tell_Str::ltrim($before, $chars, $limit))->equals($after);
}
$bad = [
["äöüßéèâ", "ä", 0, "öüßéèâ"], // No multibyte support at this time (@todo?)
];
foreach ($bad as list($before, $chars, $limit, $after)) {
$this->assert(Tell_Str::ltrim($before, $chars, $limit))->notEquals($after);
}
});
$this->try('rtrim()', function() {
$good = [
["aaabbbccc", "ca", 2, "aaabbbc"],
["aaabbbccc", "ca", 3, "aaabbb"],
["aaabbbccc", "ca", 4, "aaabbb"],
["aaabbbccc", "ab", 5, "aaabbbccc"],
["aaabbbccc", "abc", 0, ""],
];
foreach ($good as list($before, $chars, $limit, $after)) {
$this->assert(Tell_Str::rtrim($before, $chars, $limit))->equals($after);
}
$bad = [
["äöüßéèâ", "ä", 0, "äöüßéè"], // No multibyte support at this time (@todo?)
];
foreach ($bad as list($before, $chars, $limit, $after)) {
$this->assert(Tell_Str::ltrim($before, $chars, $limit))->notEquals($after);
}
});
$this->try('trim()', function() {
$good = [
["aaabbbccc", "ac", 1, "aabbbcc"],
["aaabbbccc", "ac", 2, "abbbc"],
["aaabbbccc", "ac", 3, "bbb"],
["aaabbbccc", "ab", 4, "bbccc"],
["aaabbbccc", "ab", 5, "bccc"],
["aaabbbccc", "ab", 6, "ccc"],
["aaabbbccc", "abc", 7, ""],
["aaabbbccc", "abc", 8, ""],
["aaabbbccc", "abc", 9, ""],
["aaabbbccc", "a", 0, "bbbccc"],
["aaabbbccc", "ab", 0, "ccc"],
];
foreach ($good as list($before, $chars, $limit, $after)) {
$this->assert(Tell_Str::trim($before, $chars, $limit))->equals($after);
}
$bad = [
["äöüßéèâ", "ä", 0, "öüßéè"], // No multibyte support at this time (@todo?)
];
foreach ($bad as list($before, $chars, $limit, $after)) {
$this->assert(Tell_Str::trim($before, $chars, $limit))->notEquals($after);
}
});
$this->try('sanitize()', function() {
$byte4 = '𠜎 𠜱 𠝹 𠱓 𠱸 𠲖 𠳏 𠳕 𠴕 𠵼 𠵿 𠸎 𠸏 𠹷 𠺝 𠺢 𠻗 𠻹 𠻺 𠼭 𠼮 𠽌 𠾴 𠾼 𠿪 𡁜 𡁯 𡁵 '
. '𡁶 𡁻 𡃁 𡃉 𡇙 𢃇 𢞵 𢫕 𢭃 𢯊 𢱑 𢱕 𢳂 𢴈 𢵌 𢵧 𢺳 𣲷 𤓓 𤶸 𤷪 𥄫 𦉘 𦟌 𦧲 𦧺 𧨾 𨅝 '
. '𨈇 𨋢 𨳊 𨳍 𨳒 𩶘';
$this->assert(strlen($byte4))->equals(309);
$this->assert(strlen(Tell_Str::sanitize($byte4)))->equals(123);
$arrByte4 = [
'',
'𡁵',
'𠸎 𠸏',
'𠜎 𠜱 𠝹',
'𢺳 𣲷 𤓓 𤶸',
'𢞵 𢫕 𢭃 𢯊 𢱑',
'𨈇 𨋢 𨳊 𨳍 𨳒 𩶘',
];
foreach ($arrByte4 as $chars => $str) {
$this->assert(strlen($str))->equals(($chars * 4) + max($chars - 1, 0));
$this->assert(strlen(Tell_Str::sanitize($str)))->equals($chars + max($chars - 1, 0));
}
$cleanArrByte4 = Tell_Str::sanitize($arrByte4);
foreach ($cleanArrByte4 as $chars => $str) {
$this->assert(strlen($str))->equals($chars + max($chars - 1, 0));
}
});
$this->try('truncate()', function() {
$fr = "
Portez ce vieux whisky au juge blond qui fume sur son île intérieure, à
côté de l'alcôve ovoïde, où les bûches se consument dans l'âtre, ce
qui lui permet de penser à la cænogenèse de l'être dont il est question
dans la cause ambiguë entendue à Moÿ, dans un capharnaüm qui,
pense-t-il, diminue çà et là la qualité de son œuvre."
;
$langs = $this->langs;
});
})->vars([
'hebrew_cp1255' => Tell_Asset::contents('docs/hebrew-cp1255'),
'hebrew_utf8' => Tell_Asset::contents('docs/hebrew-utf-8'),
'windows_1252' => Tell_Asset::contents('docs/windows-1252'),
'langs' => [
'da' => /* Danish */ "Quizdeltagerne spiste jordbær med fløde, mens cirkusklovnen Wolther spillede på xylofon.",
'en' => /* English */ "The quick brown fox jumps over the lazy dog",
'fr' => /* French */ "Le cœur déçu mais l'âme plutôt naïve, Louÿs rêva de crapaüter en canoë au delà des îles, près du mälström où brûlent les novæ.",
'de' => /* German */ "Falsches Üben von Xylophonmusik quält jeden größeren Zwerg",
'el' => /* Greek */ "Γαζέες καὶ μυρτιὲς δὲν θὰ βρῶ πιὰ στὸ χρυσαφὶ ξέφωτο",
'iw' => /* Hebrew */ "? דג סקרן שט בים מאוכזב ולפתע מצא לו חברה איך הקליטה",
'jp' => /* Japanese */ "イロハニホヘト チリヌルヲ ワカヨタレソ ツネナラム ウヰノオクヤマ ケフコエテ アサキユメミシ ヱヒモセスン",
'ru' => /* Russian */ "В чащах юга жил бы цитрус? Да, но фальшивый экземпляр! Съешь же ещё этих мягких французских булок да выпей чаю",
'es' => /* Spanish */ "El pingüino Wenceslao hizo kilómetros bajo exhaustiva lluvia y frío, añoraba a su querido cachorro.",
],
]);
{JSON results of applicable inspection}
<?php
// -------------------------------------------------------------------------------------------------
class Inspect_Test_Auth_Basic extends Tell_Auth_Basic
{
public function authenticate()
{
if ('bob@example.com' === $this->username() && 'testing' === $this->password()) {
return [
'first_name' => 'Bob',
'last_name' => 'Smith',
'email' => 'bob@example.com',
];
}
return FALSE;
}
public $test = [
'onAuthenticate' => [],
'onAuthenticateSuccess' => [],
'onAuthenticateFailure' => [],
'onAuthenticateRevoke' => [],
'onPersist' => [],
'onPersistSuccess' => [],
'onPersistFailure' => [],
'onAuthorize' => [],
'onAuthorizeSuccess' => [],
];
public function onAuthenticate(...$args)
{
$this->test['onAuthenticate'] = $args;
}
public function onAuthenticateSuccess(...$args)
{
$this->test['onAuthenticateSuccess'] = $args;
}
public function onAuthenticateFailure(...$args)
{
$this->test['onAuthenticateFailure'] = $args;
}
public function onAuthenticateRevoke(...$args)
{
$this->test['onAuthenticateRevoke'] = $args;
}
public function onPersist(...$args)
{
$this->test['onPersist'] = $args;
}
public function onPersistSuccess(...$args)
{
$this->test['onPersistSuccess'] = $args;
}
public function onPersistFailure(...$args)
{
$this->test['onPersistFailure'] = $args;
}
public function onAuthorize(...$args)
{
$this->test['onAuthorize'] = $args;
}
public function onAuthorizeSuccess(...$args)
{
$this->test['onAuthorizeSuccess'] = $args;
}
}
// -------------------------------------------------------------------------------------------------
$inspect('Tell_Auth_Basic >> Instantiate', function(Inspect_Test_Auth_Basic $auth) {
$this->assert($auth->test['onAuthenticate'])->array()->empty();
$this->assert($auth->test['onAuthenticateSuccess'])->array()->empty();
$this->assert($auth->test['onAuthenticateFailure'])->array()->hasKey(0)->hasKey(1);
$this->assert($auth->test['onAuthenticateFailure'][0])->false();
$this->assert($auth->test['onAuthenticateFailure'][1])->instanceOf($auth);
$this->assert($auth->test['onPersist'])->array()->empty();
$this->assert($auth->test['onPersistSuccess'])->array()->empty();
$this->assert($auth->test['onPersistFailure'])->array()->empty();
$this->assert($auth->test['onAuthorize'])->array()->empty();
$this->assert($auth->test['onAuthorizeSuccess'])->array()->empty();
});
// -------------------------------------------------------------------------------------------------
$inspect('Tell_Auth_Basic >> Valid Basic Credentials', function(Inspect_Test_Auth_Basic $auth) {
$this->assert($auth->test['onAuthenticate'])->array()->hasKey(0)->hasKey(1);
$this->assert($auth->test['onAuthenticate'][0])->equals([
'first_name' => 'Bob',
'last_name' => 'Smith',
'email' => 'bob@example.com',
]);
$this->assert($auth->test['onAuthenticate'][1])->instanceOf($auth);
$this->assert($auth->test['onAuthenticateSuccess'])->equals($auth->test['onAuthenticate']);
$this->assert($auth->test['onAuthenticateFailure'])->array()->empty();
$this->assert($auth->test['onPersist'])->array()->empty();
$this->assert($auth->test['onPersistSuccess'])->array()->empty();
$this->assert($auth->test['onPersistFailure'])->array()->empty();
$this->assert($auth->test['onAuthorize'])->array()->empty();
$this->assert($auth->test['onAuthorizeSuccess'])->array()->empty();
})->request([
'method' => 'GET',
'server' => [
'PHP_AUTH_USER' => 'bob@example.com',
'PHP_AUTH_PW' => 'testing',
],
]);
// -------------------------------------------------------------------------------------------------
{JSON results of applicable inspection}
<?php
$inspect('Tell_Arr', function() {
$this->try('get()', function() {
$a = $this->a;
$this->assert(Tell_Arr::get($a, 'item_name'))
->equals($a['item_name']);
$this->assert(Tell_Arr::get($a, 'attachments'))
->equals($a['attachments']);
$this->assert(Tell_Arr::get($a, 'attachments.images'))
->equals($a['attachments']['images']);
$this->assert(Tell_Arr::get($a, 'attachments.images.2'))
->equals($a['attachments']['images'][2]);
$this->assert(Tell_Arr::get($a, 'attachments.images.4'))
->equals($a['attachments']['images'][4]);
$this->assert(Tell_Arr::get($a, 'attachments.images.5'))
->equals($a['attachments']['images'][5]);
})->then('delete()', function() {
$a = $this->a;
Tell_Arr::delete($a, 'item_name');
Tell_Arr::delete($a, 'attachments.images.2');
Tell_Arr::delete($a, 'attachments.images.4');
Tell_Arr::delete($a, 'attachments.images.5');
$this->assert(Tell_Arr::get($a, 'item_name'))
->null();
$this->assert(Tell_Arr::get($a, 'attachments.images.2'))
->null();
$this->assert(Tell_Arr::get($a, 'attachments.images.4'))
->null();
$this->assert(Tell_Arr::get($a, 'attachments.images.5'))
->null();
})->then('set()', function() {
$a = $this->a;
Tell_Arr::set($a, FALSE, 'foobar.jpg');
Tell_Arr::set($a, 'attachments.images.4', 'dolphins.jpg');
Tell_Arr::set($a, 'attachments.images.5', 'cats.jpg');
Tell_Arr::set($a, 'attachments.images.2', 'cats.jpg');
Tell_Arr::set($a, 'attachments.files', [
0 => 'trex-700.pdf',
1 => 'blade-600x.pdf',
]);
$this->assert(Tell_Arr::get($a, FALSE))
->equals('foobar.jpg');
$this->assert(Tell_Arr::get($a, 0))
->equals('foobar.jpg');
$this->assert(Tell_Arr::get($a, 'attachments.images.4'))
->equals('dolphins.jpg');
$this->assert(Tell_Arr::get($a, 'attachments.images.5'))
->equals('cats.jpg');
$this->assert(Tell_Arr::get($a, 'attachments.images.2'))
->equals('cats.jpg');
$this->assert(Tell_Arr::get($a, 'attachments.files.0'))
->equals('trex-700.pdf');
$this->assert(Tell_Arr::get($a, 'attachments.files.1'))
->equals('blade-600x.pdf');
});
$this->try('isAssociative()', function() {
$a = $this->a;
$d = $this->d;
$this->assert(Tell_Arr::isAssociative($a))->true();
$this->assert(Tell_Arr::isAssociative($a['attachments']))->true();
$this->assert(Tell_Arr::isAssociative($a['attachments']['images']))->false();
$this->assert(Tell_Arr::isAssociative($d))->false();
});
$this->try('isIndexed()', function() {
$a = $this->a;
$d = $this->d;
$this->assert(Tell_Arr::isIndexed($a))->false();
$this->assert(Tell_Arr::isIndexed($a['attachments']))->false();
$this->assert(Tell_Arr::isIndexed($a['attachments']['images']))->true();
$this->assert(Tell_Arr::isIndexed($d))->true();
});
$this->try('isMultiDimensional()', function() {
$this->assert(Tell_Arr::isMultiDimensional([
'a' => 'foo',
'b' => ['bar'],
'c' => 'doe',
]))->true();
$this->assert(Tell_Arr::isMultiDimensional([
'a' => 'foo',
'b' => 'bar',
'c' => 'doe',
]))->false();
});
$this->try('coalesce()', function() {
$a = [
'attachments' => [
'avatar' => NULL,
'resume' => 'bob-cv.pdf',
'images' => [
0 => 'whales.jpg',
1 => 'horses.jpg',
2 => 'flowers.jpg',
3 => 'dogs.jpg',
4 => 'dolphins.jpg',
5 => 'cats.jpg',
],
],
];
$b = [
'first_name' => 'Bob',
'last_name' => 'Smith',
'attachments' => [
'avatar' => 'gravatar.png',
'resume' => 'bob-updated-cv.pdf',
'images' => [
0 => 'whales.jpg',
1 => 'sharks.jpg',
2 => 'flowers.jpg',
3 => 'dogs.jpg',
4 => 'dolphins.jpg',
5 => 'cats.jpg',
],
],
];
$c = Tell_Arr::coalesce($a, $b);
$this->assert($c['first_name'] ?? NULL)->equals('Bob');
$this->assert($c['last_name'] ?? NULL)->equals('Smith');
$this->assert($c['attachments']['avatar'] ?? NULL)->equals('gravatar.png');
$this->assert($c['attachments']['resume'] ?? NULL)->equals('bob-updated-cv.pdf');
$this->assert($c['attachments']['images'][0] ?? NULL)->equals('whales.jpg');
$this->assert($c['attachments']['images'][1] ?? NULL)->equals('sharks.jpg');
});
$this->try('diff()', function() {
$a = [
'attachments' => [
'avatar' => NULL,
'resume' => 'bob-cv.pdf',
'images' => [
0 => 'whales.jpg',
1 => 'horses.jpg',
2 => 'flowers.jpg',
3 => 'dogs.jpg',
4 => 'dolphins.jpg',
5 => 'cats.jpg',
],
],
];
$b = [
'first_name' => 'Bob',
'last_name' => 'Smith',
'attachments' => [
'avatar' => 'gravatar.png',
'resume' => 'bob-updated-cv.pdf',
'images' => [
0 => 'whales.jpg',
1 => 'sharks.jpg',
2 => 'flowers.jpg',
3 => 'dogs.jpg',
4 => 'dolphins.jpg',
5 => 'cats.jpg',
],
],
];
$c = Tell_Arr::diff($a, $b);
$this->assert($c)->hasKey('attachments.avatar');
$this->assert($c['attachments']['resume'] ?? NULL)->equals('bob-cv.pdf');
$this->assert($c['attachments']['images'][1] ?? NULL)->equals('horses.jpg');
});
$this->try('flatten()', function() {
$a = [
'first_name' => 'Bob',
'last_name' => 'Smith',
'attachments' => [
'avatar' => 'gravatar.png',
'resume' => 'bob-updated-cv.pdf',
'images' => [
0 => 'whales.jpg',
1 => 'sharks.jpg',
2 => 'flowers.jpg',
3 => 'dogs.jpg',
4 => 'dolphins.jpg',
5 => 'cats.jpg',
],
],
];
$b = Tell_Arr::flatten($a, TRUE);
$c = Tell_Arr::flatten($a, FALSE);
$this->assert($b['first_name'] ?? NULL)->equals('Bob');
$this->assert($b[5] ?? NULL)->equals('cats.jpg');
$this->assert($c[0] ?? NULL)->equals('Bob');
$this->assert($c[9] ?? NULL)->equals('cats.jpg');
});
$this->try('merge()', function() {
$b = $this->b;
$c = $this->c;
$d = Tell_Arr::merge($b, $c);
$this->assert(Tell_Arr::get($d, 'images.aa_samples'))
->equals(4);
$this->assert(Tell_Arr::get($d, 'i18n.currency'))
->equals('CAD');
$this->assert(Tell_Arr::get($d, 'i18n.translate.domain'))
->equals('api');
$this->assert(count(Tell_Arr::get($d, 'i18n.locales')))
->equals(4);
$this->assert(count(Tell_Arr::merge($b['i18n']['locales'], $c['i18n']['locales'])))
->equals(4);
$a = [
'attachments' => [
'avatar' => NULL,
'resume' => 'bob-cv.pdf',
'images' => [
0 => 'whales.jpg',
1 => 'horses.jpg',
2 => 'flowers.jpg',
3 => 'dogs.jpg',
4 => 'dolphins.jpg',
5 => 'cats.jpg',
],
],
];
$b = [
'first_name' => 'Bob',
'last_name' => 'Smith',
'attachments' => [
'avatar' => 'gravatar.png',
'resume' => 'bob-updated-cv.pdf',
'images' => [
0 => 'whales.jpg',
1 => 'sharks.jpg',
2 => 'flowers.jpg',
3 => 'dogs.jpg',
4 => 'dolphins.jpg',
5 => 'cats.jpg',
],
],
];
$c = Tell_Arr::merge($a, $b);
$this->assert($c['first_name'] ?? NULL)->equals('Bob');
$this->assert($c['last_name'] ?? NULL)->equals('Smith');
$this->assert($c['attachments']['avatar'] ?? NULL)->equals('gravatar.png');
$this->assert($c['attachments']['resume'] ?? NULL)->equals('bob-updated-cv.pdf');
$this->assert($c['attachments']['images'][0] ?? NULL)->equals('whales.jpg');
$this->assert($c['attachments']['images'][1] ?? NULL)->equals('horses.jpg');
$this->assert($c['attachments']['images'][11] ?? NULL)->equals('cats.jpg');
});
$this->try('trim()', function() {
$d = $this->d;
$this->assert(strlen($d[3]))
->equals(26);
$this->assert(strlen(Tell_Arr::trim($d)[3]))
->equals(23);
$this->assert(strlen(explode(', ', 'hello, world, how, are, you')[4]))
->equals(4);
$this->assert(strlen(Tell_Arr::trim('hello, world, how, are, you')[4]))
->equals(3);
});
})->vars([
'a' => [
'item_name' => 'Crucio Fero Quam',
'item_status' => 'Active',
'category_id' => 7,
'attachments' => [
'resume' => 'bob-cv.pdf',
'images' => [
0 => 'whales.jpg',
1 => 'horses.jpg',
2 => 'flowers.jpg',
3 => 'dogs.jpg',
4 => 'dolphins.jpg',
5 => 'cats.jpg',
],
],
],
'b' => [
'images' => [
'driver' => 'gd',
'aa_samples' => 2,
],
'i18n' => [
'timezone' => 'UTC',
'currency' => 'USD',
'locales' => [
'en_US',
'en',
],
'translate' => [
'domain' => 'app',
'paths' => [],
],
],
],
'c' => [
'images' => [
'driver' => 'gd',
'aa_samples' => 4,
],
'i18n' => [
'timezone' => 'UTC',
'currency' => 'CAD',
'locales' => [
'en_CA',
'en',
],
'translate' => [
'domain' => 'api',
'paths' => [],
],
],
],
'd' => [
' Vires Solium ',
' Super ',
' Parens ',
' Tutaminis Vorago Relevo ',
' Infeci Munus Renuntio ',
' Mores Postpono Illa ',
' Defaeco Progressus Recognosco ',
],
]);
{JSON results of applicable inspection}
<?php
/**
* This inspection is still under construction.
* ---
* @todo
*/
$inspect('Tell_Format', function() {
$this->try('_()', function() {
// @todo
});
});
{JSON results of applicable inspection}
<?php
$inspect('Tell_Schema_Table_Pgsql', function() {
$this->try('Creating example tables from SQL file', function(Tell_Db $db) {
if ($db->pdo instanceof Closure) {
$db->pdo->__invoke();
}
$this->assert($db->pdo->exec($this->ddl))->int()->equals(0);
})->then('Validate the DDL without schema in cache', function(Tell_Schema $schema) {
$this->assert($schema->incrementColumn('example'))->equals('id');
$this->assert($schema->primaryKey('example'))->equals('id');
$this->assert($schema->hasTable('example'))->true();
$this->assert($schema->hasTable('example2'))->false();
$this->assert($schema->rename('example', 'example2'))->true();
$this->assert($schema->hasTable('example'))->false();
$this->assert($schema->hasTable('example2'))->true();
$this->assert($schema->hasColumn('example2', 'id'))->true();
$this->assert($schema->hasColumn('example2', 'id2'))->false();
$this->assert($schema->hasColumn('example', 'id'))->false();
$this->assert($schema->hasIndex('example2', 'id'))->false();
$this->assert($schema->hasIndex('example2', 'bill_first_name, bill_last_name'))->true();
$this->assert($schema->incrementColumn('example2'))->equals('id');
$this->assert($schema->primaryKey('example2'))->equals('id');
$this->assert($schema->dropColumn('example2', 'order_number'))->true();
})->then('Validate the DDL with schema in cache', function(Tell_Schema $schema) {
$schema('example2'); // puts schema in cache
$this->assert($schema->incrementColumn('example2'))->equals('id');
$this->assert($schema->primaryKey('example2'))->equals('id');
$this->assert($schema->hasTable('example2'))->true();
$this->assert($schema->hasTable('example'))->false();
$this->assert($schema->hasColumn('example2', 'id'))->true();
$this->assert($schema->hasColumn('example2', 'id2'))->false();
$this->assert($schema->hasColumn('example', 'id'))->false();
$this->assert($schema->hasIndex('example2', 'id'))->false();
$this->assert($schema->hasIndex('example2', 'bill_first_name, bill_last_name'))->true();
$this->assert($schema->incrementColumn('example2'))->equals('id');
$this->assert($schema->primaryKey('example2'))->equals('id');
$this->assert($schema->dropColumn('example2', 'order_number'))->true();
$this->assert($schema->drop('example2'))->true();
$this->assert($schema->hasTable('example2'))->false();
})->then('Create and alter a table', function(Tell_Schema $schema, Tell_Db $db) {
$this->assert($schema->drop('items'))->true();
$this->assert($schema->create('items', function(Tell_Schema_Column $column) {
$column->serial('id')->primary();
$column->int('category_id');
$column->enum('listing_status', ['Active', 'Backordered', 'Discontinued', 'Unlisted']);
$column->varchar('item_name');
$column->currency('price');
$column->dateTime('modified');
$column->dateTime('created');
$column->index('id, category_id');
$column->index('listing_status');
}))->true();
$this->assert($schema->hasTable('items'))->true();
$this->assert($schema->hasColumn('items', 'id'))->true();
$this->assert($schema->hasColumn('items', 'category_id'))->true();
$this->assert($schema->hasColumn('items', 'listing_status'))->true();
$this->assert($schema->hasColumn('items', 'item_name'))->true();
$this->assert($schema->hasColumn('items', 'price'))->true();
$this->assert($schema->hasColumn('items', 'modified'))->true();
$this->assert($schema->hasColumn('items', 'created'))->true();
$this->assert($schema->hasColumn('items', 'something_else'))->false();
$this->assert($schema->incrementColumn('items'))->equals('id');
$this->assert($schema->primaryKey('items'))->equals('id');
$this->assert($schema->hasIndex('items', 'id, category_id'))->true();
$this->assert($schema->hasIndex('items', 'listing_status'))->true();
$table = $schema->schema('items', TRUE);
$this->assert($table)->instanceOf(Tell_Schema_Schema_Bridge::class);
$columns = $table->columns;
$this->assert($columns)->arr();
$this->assert($columns['item_name'] ?? NULL)->instanceOf(Tell_Schema_Column_Bridge::class);
$this->assert($columns['item_name']->length)->int()->equals(255);
for ($i = 0; $i < 5; $i++) {
$this->assert($db("INSERT INTO items")->data(Test_Schema::rowIpsumItem())->run())
->int()
->equals($i + 1);
}
$this->assert($schema->alter('items', function(Tell_Schema_Column $column) {
$column->rename('id', 'item_id');
$column->rename('listing_status', 'status');
$column->enum('status', ['Active', 'Preordered', 'Backordered', 'Discontinued', 'Unlisted']);
$column->varchar('item_name', 128);
$column->dropIndex(['id', 'category_id']);
}))->true();
$this->assert($schema->incrementColumn('items'))->equals('item_id');
$this->assert($schema->primaryKey('items'))->equals('item_id');
$this->assert($schema->hasColumn('items', 'listing_status'))->false();
$this->assert($schema->hasColumn('items', 'status'))->true();
$this->assert($schema->hasIndex('items', 'id, category_id'))->false();
$this->assert($schema->hasIndex('items', 'listing_status'))->false();
$this->assert($schema->hasIndex('items', 'status'))->true();
$columns = $schema->schema('items', TRUE)->columns;
$this->assert($columns['item_name']->length)->int()->equals(128);
$this->assert($db("INSERT INTO items")->data(Test_Schema::rowItemAfterAltered())->run())
->int()
->equals($i + 1);
$this->assert($schema->drop('items'))->true();
$this->assert($schema->hasTable('items'))->false();
});
})->swap(function(Tell_Event $event) {
return [
'Tell_Db' => new Tell_Db([
'driver' => 'pgsql',
'database' => 'tell_php_test',
'host' => '127.0.0.1',
'port' => NULL,
'socket' => NULL,
'username' => 'postgres',
'password' => '',
'elevate_exceptions' => TRUE,
'log_failed' => TRUE,
'log_success' => FALSE,
'log_limit' => 1000,
], $event),
];
})->vars([
'ddl' => file_get_contents(__DIR__ . '/../assets/sql/table.pgsql.sql'),
])->onlyWhen(function() {
return extension_loaded('pdo_pgsql') && env('TELL_PHP_DEV');
});
{JSON results of applicable inspection}
<?php
/**
* This inspection is still under construction.
* ---
* @todo
*/
$inspect('Tell_Html', function() {
$this->try('_()', function() {
// @todo
});
});
{JSON results of applicable inspection}
<?php
/**
* This inspection is still under construction.
* ---
* @todo
*/
$inspect('Tell_Locale', function() {
$this->try('_()', function() {
// @todo
});
});
{JSON results of applicable inspection}
<?php
$inspect('Tell_Security', function() {
$this->try('originRule()')->many($this->rules, function($test) {
list($desc, $rule, $origin, $expected) = $test;
return $expected === Tell_Security::originRule($origin, $rule);
})->then('isOriginAllowed()')->many($this->origins, function($test) {
list($origin, $expected) = $test;
return $expected === Tell_Security::isOriginAllowed($origin, $this->whitelist);
});
$this->try('fileExistsIn()', function() {
$unlockedDir = realpath(__DIR__ . '/../bridge');
$lockedDir = realpath(CORE_PATH . '/classes/auth');
$this->assert($unlockedDir)->directory();
$this->assert($lockedDir)->directory();
$goodUserInput = '/auth/Jwt.php';
$badUserInput = '/../../../classes/auth/Jwt.php';
$this->assert($unlockedDir . $goodUserInput)->file();
$this->assert($unlockedDir . $badUserInput)->file();
$this->assert(Tell_Security::fileExistsIn($goodUserInput, $unlockedDir))->true();
$this->assert(Tell_Security::fileExistsIn($badUserInput, $unlockedDir))->false();
});
$this->try('random(0)', function() {
$this->assert(function() {
Tell_Security::random(0);
})->exception(Error::class);
})->then('random(#)')->many(50, function($i) {
return $i ? strlen(Tell_Security::random($i)) === $i : TRUE; // skip 0
})->then('csrfToken()', function() {
$this->validate(Tell_Security::csrfToken())->lengthFixed(40)->assert();
});
})->vars([
// description, allowed, origin, expected
'rules' => [
['Allow domain', 'foo.com', 'foo.com', TRUE],
['Disallow subdomain on domain', 'foo.com', 'www.foo.com', FALSE],
['Allow subdomain', 'www.foo.com', 'www.foo.com', TRUE],
['Disallow wrong subdomain', 'www.foo.com', 'ws.foo.com', FALSE],
['Allow All', '*', 'ws.foo.com', TRUE],
['Allow subdomain wildcard', '*.foo.com', 'ws.foo.com', TRUE],
['Disallow lacks subdomain', '*.foo.com', 'foo.com', FALSE],
['Allow double subdomain', '*.foo.com', 'a.b.foo.com', TRUE],
['Disallow incorrect position', '*.foo.com', 'a.foo.com.evil.com', FALSE],
['Allow subdomain in the middle', 'a.*.foo.com', 'a.bc.foo.com', TRUE],
['Disallow wrong subdomain', 'a.*.foo.com', 'b.bc.foo.com', FALSE],
['Disallow missing TLD', 'foo.com', 'fooXcom', FALSE],
['Allow port on domain', 'foo.com:2087', 'foo.com:2087', TRUE],
['Disallow port on domain', 'foo.com', 'foo.com:2087', FALSE],
['Disallow wrong port on domain', 'foo.com:2087', 'foo.com:2088', FALSE],
['Disallow HTTP on HTTPS', 'https://foo.com', 'http://foo.com', FALSE],
['Disallow HTTPS on HTTP', 'http://foo.com', 'https://foo.com', FALSE],
['Disallow HTTPS w/ port', 'https://foo.com:2087', 'https://foo.com', FALSE],
['Allow HTTPS w/ subdomain + port', 'https://*.foo.com:2087', 'https://ws.foo.com:2087', TRUE],
],
// origin, expected
'origins' => [
['http://foo.io', FALSE],
['https://foo.io', TRUE],
['https://www.foo.io', TRUE],
['https://users.foo.io', TRUE],
['https://admin.bar.dev', FALSE],
['https://admin.bar.dev:8080', TRUE],
['http://doe.com', TRUE],
['https://doe.com:2087', FALSE],
['http://yay.doe.com', TRUE],
['http://yay.me.doe.com', TRUE],
['https://yay.doe.com:2087', FALSE],
],
'whitelist' => [
'https://foo.io',
'https://www.foo.io',
'https://users.foo.io',
'https://admin.bar.dev:8080',
'doe.com',
'*.doe.com',
],
]);
{JSON results of applicable inspection}
<?php
// ---------------------------------------------------------------------------------------------
$inspect('Tell_Validate_Card', function() {
$this->try('luhn(loose)')->many($this->loose, function(bool $expect, $card) {
return $expect === (new Tell_Validate_Card())->luhn($card, FALSE);
});
$this->try('luhn(strict)')->many($this->strict, function(bool $expect, $card) {
return $expect === (new Tell_Validate_Card())->luhn($card, TRUE);
});
})->vars([
'loose' => [ // [value => expect, ...]
'49927398716' => TRUE,
'49927398717' => TRUE,
'1234567812345678' => TRUE,
'1234567812345670' => TRUE,
'99927398716' => TRUE,
'40927398717' => TRUE,
'1234567812345778' => TRUE,
'1234567812345679' => TRUE,
],
'strict' => [ // [value => expect, ...]
'49927398716' => TRUE,
'49927398717' => FALSE,
'1234567812345678' => FALSE,
'1234567812345670' => TRUE,
'99927398716' => FALSE,
'40927398717' => FALSE,
'1234567812345778' => FALSE,
'1234567812345679' => FALSE,
],
]);
// ---------------------------------------------------------------------------------------------
$inspect('Tell_Validate_Color', function() {
$this->try('hex()')->many($this->hex, function(bool $expect, $color) {
return $expect === (new Tell_Validate_Color())->hex($color);
});
$this->try('rgb()')->many($this->rgb, function(bool $expect, $color) {
return $expect === (new Tell_Validate_Color())->rgb($color);
});
})->vars([
'hex' => [ // [value => expect, ...]
'32C0DF' => TRUE,
'32c0df' => TRUE,
'#32C0DF' => TRUE,
'#32c0df' => TRUE,
'#32c0dg' => FALSE,
'#2c0df' => FALSE,
"# 32c0df" => FALSE, // ... ...
"\x0D#32c0df" => FALSE, // \n...
"\x0A\x0D#32c0df" => FALSE, // \r\n...
"#32c0df\x0D" => FALSE, // ...\n
"#32c0df\x0A\x0D" => FALSE, // ...\r\n
"\x0032c0df" => FALSE, // NULL...
"#32c0df\x00" => FALSE, // ...NULL
"#32\x00c0df" => FALSE, // ...NULL...
"\x04#32c0df" => FALSE, // EOL...
"#32c0df\x04" => FALSE, // ...EOL
"32\x04c0df" => FALSE, // ...EOL...
],
'rgb' => [ // [value => expect, ...]
'(0,0,0)' => TRUE,
'(255,255,255)' => TRUE,
'50, 192, 223' => TRUE,
'50,192,223' => TRUE,
'(50, 192, 223)' => TRUE,
'(50,192,223)' => TRUE,
'(50,192223)' => FALSE,
'50,192,223)' => FALSE,
'(50,192,223' => FALSE,
'(5a,192,223)' => FALSE,
'256,255,200' => FALSE,
'128,128,-1' => FALSE,
'128,299,127' => FALSE,
"50, 192,223" => TRUE, // ... ...
"\x0D50,192,223" => FALSE, // \n...
"\x0A\x0D50,192,223" => FALSE, // \r\n...
"50,192,223\x0D" => FALSE, // ...\n
"50,192,223\x0A\x0D" => FALSE, // ...\r\n
"\x0050,192,223" => FALSE, // NULL...
"50,192,223\x00" => FALSE, // ...NULL
"50,192\x00,223" => FALSE, // ...NULL...
"\x0450,192,223" => FALSE, // EOL...
"50,192,223\x04" => FALSE, // ...EOL
"50,192\x04,223" => FALSE, // ...EOL...
],
]);
// ---------------------------------------------------------------------------------------------
$inspect('Tell_Validate_Country', function() {
$this->try('validate()')->many($this->countries, function(bool $expect, $code) {
return $expect === (new Tell_Validate_Country())->validate($code);
});
})->vars([
'countries' => [ // [value => expect, ...]
0 => FALSE,
1 => FALSE,
'US' => TRUE,
'CA' => TRUE,
'GB' => TRUE,
'us' => FALSE,
'Us' => FALSE,
'uS' => FALSE,
'ca' => FALSE,
'Ca' => FALSE,
'cA' => FALSE,
'gb' => FALSE,
'Gb' => FALSE,
'gB' => FALSE,
'USA' => FALSE,
'UK' => FALSE, // UK should be GB (Great Britain), UK not valid
"U S" => FALSE, // ... ...
"\x0DUS" => FALSE, // \n...
"\x0A\x0DUS" => FALSE, // \r\n...
"GB\x0D" => FALSE, // ...\n
"GB\x0A\x0D" => FALSE, // ...\r\n
"\x00CA" => FALSE, // NULL...
"CA\x00" => FALSE, // ...NULL
"C\x00A" => FALSE, // ...NULL...
"\x04FR" => FALSE, // EOL...
"FR\x04" => FALSE, // ...EOL
"F\x04R" => FALSE, // ...EOL...
],
]);
// ---------------------------------------------------------------------------------------------
$inspect('Tell_Validate_Date', function() {
$this->try('clock()')->many($this->clocks['*'], function(bool $expect, $clock) {
return $expect === (new Tell_Validate_Date())->clock($clock);
})->then('am()')->many($this->clocks['am'], function(bool $expect, $clock) {
return $expect === (new Tell_Validate_Date())->am($clock);
})->then('pm()')->many($this->clocks['pm'], function(bool $expect, $clock) {
return $expect === (new Tell_Validate_Date())->pm($clock);
})->then('date()')->many($this->dates, function(bool $expect, $date) {
return $expect === (new Tell_Validate_Date())->date($date);
})->then('dateTime()')->many($this->dateTimes, function(bool $expect, $stamp) {
return $expect === (new Tell_Validate_Date())->dateTime($stamp);
});
// @todo currently returns erroneous results
// $this->try('expiration()')->many($this->expirations, function(bool $expect, $expires) {
// return $expect === (new Tell_Validate_Date())->expiration($expires)
// && $expect === (new Tell_Validate_Date())->expiration($expires, $this->now_a)
// && $expect === (new Tell_Validate_Date())->expiration($expires, $this->now_b);
// });
$this->try('day()')->many($this->days, function(bool $expect, $day) {
return $expect === (new Tell_Validate_Date())->day($day);
});
$this->try('month()')->many($this->months, function(bool $expect, $day) {
return $expect === (new Tell_Validate_Date())->month($day);
});
$this->try('weekday()')->many($this->weekdays, function(bool $expect, $day) {
return $expect === (new Tell_Validate_Date())->weekday($day);
});
$this->try('format(...)')->many($this->formats, function(array $tests, $fmt) {
return $this->try("format($fmt)")->many($tests, function(bool $expect, $date) use ($fmt) {
return $expect === (new Tell_Validate_Date())->format($date, $fmt);
});
});
$this->try('before()')->many($this->before, function(array $range) {
list($date, $max, $expect) = $range;
return $expect === (new Tell_Validate_Date())->before($date, $max);
});
$this->try('after()')->many($this->after, function(array $range) {
list($date, $min, $expect) = $range;
return $expect === (new Tell_Validate_Date())->after($date, $min);
});
})->vars([
'now_a' => '2021-05-31 04:18:20',
'now_b' => '2021-06-01 19:59:21',
'clocks' => [ // [value => expect, ...]
'*' => [
0 => FALSE,
'1' => FALSE, // Too vague (easily mistaken for boolean instead of 1 AM)
'6' => FALSE,
'01' => FALSE,
'1am' => TRUE,
'1a.m.' => TRUE,
'1 am' => TRUE,
'1 a.m.' => TRUE,
'1AM' => TRUE,
'1 AM' => TRUE,
'1 A.M.' => TRUE,
'1:32' => TRUE,
'1:32am' => TRUE,
'1:32a.m.' => TRUE,
'1:32 am' => TRUE,
'1:32 a.m.' => TRUE,
'1:33AM' => TRUE,
'1:33A.M.' => TRUE,
'1:33 AM' => TRUE,
'1:33 A.M.' => TRUE,
'133' => FALSE,
'133AM' => FALSE,
'15:35' => TRUE,
'15:35am' => FALSE,
'15:35AM' => FALSE,
'15:35 AM' => FALSE,
'23:59' => TRUE,
'23: 59' => FALSE,
'23 : 59' => FALSE,
'23 :59' => FALSE,
'23:60' => FALSE,
'1:13pm' => TRUE,
'1:13PM' => TRUE,
'1:13p.m.' => TRUE,
'7:47 P.M.' => TRUE,
],
'am' => [ // [value => expect, ...]
0 => FALSE,
'1' => FALSE, // Too vague (easily mistaken for boolean instead of 1 AM)
'1am' => TRUE,
'1a.m.' => TRUE,
'1 am' => TRUE,
'1 a.m.' => TRUE,
'1AM' => TRUE,
'1 AM' => TRUE,
'1 A.M.' => TRUE,
'1:32' => TRUE,
'1:32am' => TRUE,
'1:32a.m.' => TRUE,
'1:32 am' => TRUE,
'1:32 a.m.' => TRUE,
'1:33AM' => TRUE,
'1:33A.M.' => TRUE,
'1:33 AM' => TRUE,
'1:33 A.M.' => TRUE,
'12:59' => TRUE,
'15:35' => FALSE,
'23:59' => FALSE,
],
'pm' => [ // [value => expect, ...]
0 => FALSE,
'1' => FALSE, // Too vague (easily mistaken for boolean instead of 1 AM)
'1pm' => TRUE,
'1p.m.' => TRUE,
'1 pm' => TRUE,
'1 p.m.' => TRUE,
'1PM' => TRUE,
'1 PM' => TRUE,
'1 P.M.' => TRUE,
'1:32' => FALSE,
'1:32pm' => TRUE,
'1:32p.m.' => TRUE,
'1:32 pm' => TRUE,
'1:32 p.m.' => TRUE,
'1:33PM' => TRUE,
'1:33P.M.' => TRUE,
'1:33 PM' => TRUE,
'1:33 P.M.' => TRUE,
'7:47AM' => FALSE,
'7:47PM' => TRUE,
'7:47 AM' => FALSE,
'7:47 PM' => TRUE,
'12:59' => FALSE,
'15:35' => TRUE,
'23:59' => TRUE,
],
],
'dates' => [ // [value => expect, ...]
0 => FALSE,
'1' => FALSE,
'1967-07-14' => TRUE,
'07/14/1967' => TRUE,
'1967/14/07' => FALSE,
'1967-14-07' => FALSE,
'1967 14 07' => FALSE,
'1969-12-31' => TRUE,
'12/31/1969' => TRUE,
'1969/31/12' => FALSE,
'1969-31-12' => FALSE,
'1969 12 31' => FALSE,
'1970-01-01' => TRUE,
'01/01/1970' => TRUE,
'1970/01/01' => TRUE,
'1970 01 01' => FALSE,
'2000-01-01' => TRUE,
'01/01/2000' => TRUE,
'2000/01/01' => TRUE,
'2000 01 01' => FALSE,
'2016-02-01' => TRUE,
'02/01/2016' => TRUE,
'2016 02 01' => FALSE,
'16-03-02' => FALSE,
'2016-03-02' => TRUE,
'03/02/2016' => TRUE,
'2016/02/03' => TRUE,
'2016/03/02' => TRUE,
'2016-02-03' => TRUE,
'2016 02 03' => FALSE,
'2016 03 02' => FALSE,
'2006-13-07' => FALSE,
'2006-07-13' => TRUE,
'07/13/2006' => TRUE,
'13/07/2006' => FALSE,
'2006 13 07' => FALSE, // ... ...
'2006 07 13' => FALSE, // ... ...
"\x0D12/15/2021" => FALSE, // \n...
"\x0A\x0D2021-07-09" => FALSE, // \r\n...
"03/24/2019\x0D" => FALSE, // ...\n
"1994/09/17\x0A\x0D" => FALSE, // ...\r\n
"\x002021-05-11" => FALSE, // NULL...
"07/24/2019\x00" => FALSE, // ...NULL
"07/24\x00/2019" => FALSE, // ...NULL...
"\x042020-01-20" => FALSE, // EOL...
"2020-02-24\x04" => FALSE, // ...EOL
"2021-03-\x0415" => FALSE, // ...EOL...
],
'dateTimes' => [ // [value => expect, ...]
'2005-08-15T15:52:01+00:00' => TRUE,
'Monday, 15-Aug-2005 15:52:01 UTC' => TRUE,
'2005-08-15T15:52:01+0000' => TRUE,
'Mon, 15 Aug 05 15:52:01 +0000' => TRUE,
'Monday, 15-Aug-05 15:52:01 UTC' => TRUE,
'Mon, 15 Aug 2005 15:52:01 +0000' => TRUE,
'Sat, 30 Apr 2016 17:52:13 GMT' => TRUE,
'2005-08-15T15:52:01.000+00:00' => TRUE,
'1970-01-01 06:46:13' => TRUE,
'1970-01-91 06:46:13' => FALSE,
'1970-01-91 Z:46:13' => FALSE,
'01/01/1970 07:19:23' => FALSE,
'01/01-1970 07:19:23' => FALSE,
'1970/01/01 12:10:05' => FALSE,
'1969-12-31 1:32 AM' => FALSE,
'1969-12-31 1:32AM' => FALSE,
'1969-12/31 1:32AM' => FALSE,
'12/31/1969 1:32' => FALSE,
'12/31/1969 01:32' => FALSE,
'12/31/1969 01' => FALSE,
'2016-02-03 3:14 PM' => FALSE,
'2016-02-03 3:14PM' => FALSE,
'2016-02-03 3:14' => FALSE,
'2016-02-03 03:14' => FALSE,
'2016-02-03 314' => FALSE,
'2021-05-16 13:27:14' => TRUE,
'2021-05-16 00:00:00' => TRUE,
'2021-05-16 00:00' => FALSE,
'2021-05-16 08:00' => FALSE,
'2021-05-16 0' => FALSE,
'2021-07-19 12:31:14' => TRUE,
"\x0D1970-01-01 06:46:13" => FALSE, // \n...
"\x0A\x0D1970-01-01 06:46:13" => FALSE, // \r\n...
"1970-01-01 06:46:13\x0D" => FALSE, // ...\n
"1970-01-01 06:46:13\x0A\x0D" => FALSE, // ...\r\n
"\x002021-05-16 13:28:14" => FALSE, // NULL...
"2021-05-16 13:27:14\x00" => FALSE, // ...NULL
"2021-05-16 \x0013:38:14" => FALSE, // ...NULL...
"\x042021-07-19 12:31:14" => FALSE, // EOL...
"2021-07-19 12:31:14\x04" => FALSE, // ...EOL
"2021-07-19 \x0412:31:14" => FALSE, // ...EOL...
],
'formats' => [ // [format => [value => expect, ...], ...]
'Y-m-d' => [
'2012-12-31' => TRUE,
'1967-07-14' => TRUE,
'2000-01-01' => TRUE,
'2016-02-03' => TRUE,
'2012/12/31' => FALSE,
'2016/02/03' => FALSE,
'2000-01-00' => FALSE,
'2012-12-32' => FALSE,
'2012-31-12' => FALSE,
'212-12-31' => FALSE,
'2012-12' => FALSE,
'12-07-13' => FALSE,
// ... @todo ...
],
'y-m-d' => [
'2012-12-31' => TRUE,
'1967-07-14' => TRUE,
'2000-01-01' => TRUE,
'2016-02-03' => TRUE,
'2012/12/31' => FALSE,
'2016/02/03' => FALSE,
'2000-01-00' => FALSE,
'2012-12-32' => FALSE,
'2012-31-12' => FALSE,
'212-12-31' => FALSE,
'2012-12' => FALSE,
'12-07-13' => FALSE,
// ... @todo ...
],
'y/m/d' => [
'2017/01/10' => TRUE,
'2017/07/12' => TRUE,
'2017/12/31' => TRUE,
'2001/12/32' => FALSE,
'17/12/31' => FALSE,
'2017/13/10' => FALSE,
'2017/1/10' => FALSE,
'2017/10/1' => FALSE,
// ... @todo ...
],
'm/d/Y' => [
'12/31/2016' => TRUE,
'01/01/2016' => TRUE,
'07/14/2016' => TRUE,
'13/12/2016' => FALSE,
'07/32/2016' => FALSE,
'1/12/2016' => FALSE,
'12/31/16' => FALSE,
'07/7/2016' => FALSE,
// ... @todo ...
],
'm/d/y' => [
'12/31/2016' => TRUE,
'01/01/2016' => TRUE,
'07/14/2016' => TRUE,
'13/12/2016' => FALSE,
'07/32/2016' => FALSE,
'1/12/2016' => FALSE,
'12/31/16' => FALSE,
'07/7/2016' => FALSE,
// ... @todo ...
],
'm/d' => [
'07/13' => TRUE,
'12/31' => TRUE,
'01/01' => TRUE,
'13/10' => FALSE,
'7/13' => FALSE,
'07/3' => FALSE,
'7/3' => FALSE,
// ... @todo ...
],
'm/y' => [
'12/2012' => TRUE,
'07/2016' => TRUE,
'01/2016' => TRUE,
'01/2000' => TRUE,
'12/2000' => TRUE,
'01/12' => FALSE,
'00/12' => FALSE,
'00/2016' => FALSE,
'1/2016' => FALSE,
'12/12' => FALSE,
'12/3' => FALSE,
// ... @todo ...
],
'my' => [
'102013' => TRUE,
'122013' => TRUE,
'012013' => TRUE,
'122000' => TRUE,
'002013' => FALSE,
'12013' => FALSE,
'1012' => FALSE,
'12201' => FALSE,
// ... @todo ...
],
],
'expirations' => [ // [value => expect, ...]
date('my', strtotime('-' . date('t') . ' days')) => TRUE, // MMYY
date('my', strtotime('-32 days')) => FALSE, // MMYY
date('my', strtotime('-28 days')) => TRUE, // MMYY
date('my', strtotime('-1 year')) => FALSE, // MMYY
date('my', strtotime('+1 year')) => TRUE, // MMYY
date('m/y', strtotime('-1 year')) => FALSE, // MM/YY
date('m/y', strtotime('+1 year')) => TRUE, // MM/YY
date('mY', strtotime('-1 year')) => FALSE, // MMYYYY
date('mY', strtotime('+1 year')) => TRUE, // MMYYYY
date('m/Y', strtotime('-1 year')) => FALSE, // MM/YYYY
date('m/Y', strtotime('+1 year')) => TRUE, // MM/YYYY
date('my', strtotime('-1 month')) => TRUE, // MMYY
date('my', strtotime('+1 month')) => TRUE, // MMYY
date('m/y', strtotime('-1 month')) => TRUE, // MM/YY
date('m/y', strtotime('+1 month')) => TRUE, // MM/YY
date('mY', strtotime('-1 month')) => TRUE, // MMYYYY
date('mY', strtotime('+1 month')) => TRUE, // MMYYYY
date('m/Y', strtotime('-1 month')) => TRUE, // MM/YYYY
date('m/Y', strtotime('+1 month')) => TRUE, // MM/YYYY
],
'before' => [ // [[value 1, value 2, expect], ...]
['2016-03-02', '2016-02-01', FALSE],
['2016-03-02', '2016-03-02', TRUE],
['2016-02-01', '2016-03-02', TRUE],
['07/13/2006', '2006-07-12', FALSE],
['07/13/2006', '2006/07/14', TRUE],
['07/13/2006', '2006-07-14', TRUE],
['2006-07-13', '2006/07/14', TRUE],
['2006-07-13', '2005-07-14', FALSE],
],
'after' => [ // [[value 1, value 2, expect], ...]
['2016-03-02', '2016-02-01', TRUE],
['2016-03-02', '2016-03-02', TRUE],
['2016-02-01', '2016-03-02', FALSE],
['07/13/2006', '2006-07-12', TRUE],
['07/13/2006', '2006/07/14', FALSE],
['07/13/2006', '2006-07-14', FALSE],
['2006-07-13', '2006/07/14', FALSE],
['2006-07-13', '2005-07-14', TRUE],
],
'days' => [ // [value => expect, ...]
0 => FALSE,
'1' => TRUE,
'1st' => TRUE,
'14th' => TRUE,
28 => TRUE,
'31' => TRUE,
'31st' => TRUE,
'32' => FALSE,
'32nd' => FALSE,
],
'months' => [ // [value => expect, ...]
'Jan' => TRUE,
'JaN' => TRUE,
'Feb' => TRUE,
'March' => TRUE,
'April' => TRUE,
'Sep' => TRUE,
'SEPT' => TRUE,
'NOVEMBER' => TRUE,
'Decem' => FALSE,
'December' => TRUE,
],
'weekdays' => [ // [value => expect, ...]
'mo' => TRUE,
'Mo' => TRUE,
'MO' => TRUE,
'mon' => TRUE,
'Mon' => TRUE,
'MON' => TRUE,
'monday' => TRUE,
'Monday' => TRUE,
'MONDAY' => TRUE,
'th' => TRUE,
'TH' => TRUE,
'Thu' => TRUE,
'Thur' => TRUE,
'THURS' => TRUE,
'Thursday' => TRUE,
],
]);
// ---------------------------------------------------------------------------------------------
$inspect('Tell_Validate_File', function() {
$this->assert($this->path_gif)->imageGif();
$this->assert($this->path_jpeg)->imageJpg();
$this->assert($this->path_jpg)->imageJpeg();
$this->assert($this->path_png)->imagePng();
$this->try('extensions()', function() {
$this->assert((new Tell_Validate_File())->extensions($this->path_gif, ['bmp', 'exe']))->false();
$this->assert((new Tell_Validate_File())->extensions($this->path_gif, ['gif', 'bmp', 'exe']))->true();
$this->assert((new Tell_Validate_File())->extensions($this->path_jpg, ['gif', 'jpg', 'png']))->true();
$this->assert((new Tell_Validate_File())->extensions($this->path_jpeg, 'gif', 'jpg', 'png'))->true();
});
$this->try('mimes()', function() {
$images = ['image/gif', 'image/jpeg', 'image/png'];
$this->assert((new Tell_Validate_File())->mimes($this->path_gif, $images))->true();
$this->assert((new Tell_Validate_File())->mimes($this->path_jpg, $images))->true();
$this->assert((new Tell_Validate_File())->mimes($this->path_jpeg, $images))->true();
$this->assert((new Tell_Validate_File())->mimes($this->path_txt, $images))->false();
$this->assert((new Tell_Validate_File())->mimes($this->path_pdf, $images))->false();
});
$this->try('image()', function() {
if ( ! extension_loaded('gd')) return;
$this->assert((new Tell_Validate_File())->image($this->path_gif))->true();
$this->assert((new Tell_Validate_File())->image($this->path_jpg))->true();
$this->assert((new Tell_Validate_File())->image($this->path_jpeg))->true();
$this->assert((new Tell_Validate_File())->image($this->path_png))->true();
$this->assert((new Tell_Validate_File())->image($this->path_txt))->false();
$this->assert((new Tell_Validate_File())->image($this->path_pdf))->false();
});
$this->try('heightBetween()', function() {
if ( ! extension_loaded('gd')) return;
$this->assert((new Tell_Validate_File())
->heightBetween($this->path_gif, 1000, 1800))
->true();
$this->assert((new Tell_Validate_File())
->heightBetween($this->path_gif, 600, 1600))
->false();
$this->assert((new Tell_Validate_File())
->heightBetween($this->path_jpg, 3000, 3800))
->true();
$this->assert((new Tell_Validate_File())
->heightBetween($this->path_jpg, 3700, 4700))
->false();
$this->assert((new Tell_Validate_File())
->heightBetween($this->path_jpeg, 2000, 2300))
->true();
$this->assert((new Tell_Validate_File())
->heightBetween($this->path_jpeg, 2300, 2500))
->false();
$this->assert((new Tell_Validate_File())
->heightBetween($this->path_png, 800, 1100))
->true();
$this->assert((new Tell_Validate_File())
->heightBetween($this->path_png, 800, 900))
->false();
});
$this->try('heightMin()', function() {
if ( ! extension_loaded('gd')) return;
$this->assert((new Tell_Validate_File())
->heightMin($this->path_gif, 1500))
->true();
$this->assert((new Tell_Validate_File())
->heightMin($this->path_gif, 1800))
->false();
$this->assert((new Tell_Validate_File())
->heightMin($this->path_jpg, 3500))
->true();
$this->assert((new Tell_Validate_File())
->heightMin($this->path_jpg, 3700))
->false();
$this->assert((new Tell_Validate_File())
->heightMin($this->path_jpeg, 2200))
->true();
$this->assert((new Tell_Validate_File())
->heightMin($this->path_jpeg, 2300))
->false();
$this->assert((new Tell_Validate_File())
->heightMin($this->path_png, 800))
->true();
$this->assert((new Tell_Validate_File())
->heightMin($this->path_png, 1000))
->false();
});
$this->try('heightMax()', function() {
if ( ! extension_loaded('gd')) return;
$this->assert((new Tell_Validate_File())
->heightMax($this->path_gif, 1500))
->false();
$this->assert((new Tell_Validate_File())
->heightMax($this->path_gif, 1800))
->true();
$this->assert((new Tell_Validate_File())
->heightMax($this->path_jpg, 3500))
->false();
$this->assert((new Tell_Validate_File())
->heightMax($this->path_jpg, 3700))
->true();
$this->assert((new Tell_Validate_File())
->heightMax($this->path_jpeg, 2200))
->false();
$this->assert((new Tell_Validate_File())
->heightMax($this->path_jpeg, 2300))
->true();
$this->assert((new Tell_Validate_File())
->heightMax($this->path_png, 800))
->false();
$this->assert((new Tell_Validate_File())
->heightMax($this->path_png, 1000))
->true();
});
$this->try('widthBetween()', function() {
if ( ! extension_loaded('gd')) return;
$this->assert((new Tell_Validate_File())
->widthBetween($this->path_gif, 1000, 1200))
->true();
$this->assert((new Tell_Validate_File())
->widthBetween($this->path_gif, 600, 1000))
->false();
$this->assert((new Tell_Validate_File())
->widthBetween($this->path_jpg, 3000, 6000))
->true();
$this->assert((new Tell_Validate_File())
->widthBetween($this->path_jpg, 1000, 3000))
->false();
$this->assert((new Tell_Validate_File())
->widthBetween($this->path_jpeg, 1500, 3000))
->true();
$this->assert((new Tell_Validate_File())
->widthBetween($this->path_jpeg, 800, 1500))
->false();
$this->assert((new Tell_Validate_File())
->widthBetween($this->path_png, 800, 2000))
->true();
$this->assert((new Tell_Validate_File())
->widthBetween($this->path_png, 500, 1200))
->false();
});
$this->try('widthMin()', function() {
if ( ! extension_loaded('gd')) return;
$this->assert((new Tell_Validate_File())
->widthMin($this->path_gif, 1000))
->true();
$this->assert((new Tell_Validate_File())
->widthMin($this->path_gif, 1200))
->false();
$this->assert((new Tell_Validate_File())
->widthMin($this->path_jpg, 5000))
->true();
$this->assert((new Tell_Validate_File())
->widthMin($this->path_jpg, 6000))
->false();
$this->assert((new Tell_Validate_File())
->widthMin($this->path_jpeg, 1500))
->true();
$this->assert((new Tell_Validate_File())
->widthMin($this->path_jpeg, 2000))
->false();
$this->assert((new Tell_Validate_File())
->widthMin($this->path_png, 1300))
->true();
$this->assert((new Tell_Validate_File())
->widthMin($this->path_png, 1600))
->false();
});
$this->try('widthMax()', function() {
if ( ! extension_loaded('gd')) return;
$this->assert((new Tell_Validate_File())
->widthMax($this->path_gif, 1000))
->false();
$this->assert((new Tell_Validate_File())
->widthMax($this->path_gif, 1200))
->true();
$this->assert((new Tell_Validate_File())
->widthMax($this->path_jpg, 5000))
->false();
$this->assert((new Tell_Validate_File())
->widthMax($this->path_jpg, 6000))
->true();
$this->assert((new Tell_Validate_File())
->widthMax($this->path_jpeg, 1500))
->false();
$this->assert((new Tell_Validate_File())
->widthMax($this->path_jpeg, 2000))
->true();
$this->assert((new Tell_Validate_File())
->widthMax($this->path_png, 1300))
->false();
$this->assert((new Tell_Validate_File())
->widthMax($this->path_png, 1600))
->true();
});
$this->try('sizeBetween()', function() {
$this->assert((new Tell_Validate_File())
->sizeBetween($this->path_gif, '100kb', '0.5mb'))
->true();
$this->assert((new Tell_Validate_File())
->sizeBetween($this->path_gif, '300kb', '2mb'))
->false();
$this->assert((new Tell_Validate_File())
->sizeBetween($this->path_jpg, '100kb', '1.5mb'))
->true();
$this->assert((new Tell_Validate_File())
->sizeBetween($this->path_jpg, '100kb', '1mb'))
->false();
$this->assert((new Tell_Validate_File())
->sizeBetween($this->path_jpeg, '100kb', '300kib'))
->true();
$this->assert((new Tell_Validate_File())
->sizeBetween($this->path_jpeg, '50kib', '230kib'))
->false();
$this->assert((new Tell_Validate_File())
->sizeBetween($this->path_png, '1.0mb', '2mb'))
->true();
$this->assert((new Tell_Validate_File())
->sizeBetween($this->path_png, '10 bytes', '1000kb'))
->false();
});
$this->try('sizeMin()', function() {
$this->assert((new Tell_Validate_File())
->sizeMin($this->path_jpeg, '225kib'))
->true();
$this->assert((new Tell_Validate_File())
->sizeMin($this->path_jpeg, '0.25mb'))
->false();
});
$this->try('sizeMax()', function() {
$this->assert((new Tell_Validate_File())
->sizeMax($this->path_jpeg, '225kib'))
->false();
$this->assert((new Tell_Validate_File())
->sizeMax($this->path_jpeg, '0.25mb'))
->true();
});
})->vars([
'path_png' => Tell_Asset::path('images/blossoms.png'),
'path_gif' => Tell_Asset::path('images/dolphins.gif'),
'path_jpeg' => Tell_Asset::path('images/shark.jpeg'),
'path_jpg' => Tell_Asset::path('images/whale.jpg'),
'path_txt' => Tell_Asset::path('docs/ipsum.txt'),
'path_pdf' => Tell_Asset::path('docs/skookum.pdf'),
]);
// ---------------------------------------------------------------------------------------------
$inspect('Tell_Validate_List', function() {
$this->try('blacklist()', function() {
$list = ['pooh', 'doo', 69, 666];
$this->assert((new Tell_Validate_List())->blacklist('red', ...$list))->true();
$this->assert((new Tell_Validate_List())->blacklist('red', $list))->true();
$this->assert((new Tell_Validate_List())->blacklist('pooh', ...$list))->false();
$this->assert((new Tell_Validate_List())->blacklist('pooh', $list))->false();
$this->assert((new Tell_Validate_List())->blacklist(69, ...$list))->false();
});
$this->try('whitelist()', function() {
$list = ['Visa', 'MasterCard', 'Discover', 'American Express', 'Diners Club', 'JCB'];
$this->assert((new Tell_Validate_List())->whitelist('Amex', ...$list))->false();
$this->assert((new Tell_Validate_List())->whitelist('American Express', $list))->true();
$this->assert((new Tell_Validate_List())->whitelist('visa', $list))->false();
$this->assert((new Tell_Validate_List())->whitelist('Visa', $list))->true();
$this->assert((new Tell_Validate_List())->whitelist('Diners Club', ...$list))->true();
$this->assert((new Tell_Validate_List())->whitelist('Diners Club', $list))->true();
});
});
$inspect('Tell_Validate_Number', function() {
$this->try('digit()', function() {
$this->assert((new Tell_Validate_Number())->digit('a'))->false();
$this->assert((new Tell_Validate_Number())->digit(1))->true();
$this->assert((new Tell_Validate_Number())->digit('1'))->true();
$this->assert((new Tell_Validate_Number())->digit(0))->true();
$this->assert((new Tell_Validate_Number())->digit('0'))->true();
$this->assert((new Tell_Validate_Number())->digit(-1))->true();
$this->assert((new Tell_Validate_Number())->digit('-1'))->true();
$this->assert((new Tell_Validate_Number())->digit('-1'))->true();
$this->assert((new Tell_Validate_Number())->digit(-1000))->true();
$this->assert((new Tell_Validate_Number())->digit('-1000'))->true();
$this->assert((new Tell_Validate_Number())->digit(1259))->true();
$this->assert((new Tell_Validate_Number())->digit('1259'))->true();
$this->assert((new Tell_Validate_Number())->digit('125,900'))->false();
$this->assert((new Tell_Validate_Number())->digit(TRUE))->false();
$this->assert((new Tell_Validate_Number())->digit(FALSE))->false();
$this->assert((new Tell_Validate_Number())->digit(NULL))->false();
$this->assert((new Tell_Validate_Number())->digit([]))->false();
$this->assert((new Tell_Validate_Number())->digit(new stdClass))->false();
});
$this->try('negative()', function() {
$this->assert((new Tell_Validate_Number())->negative('0'))->false();
$this->assert((new Tell_Validate_Number())->negative('0', TRUE))->true();
$this->assert((new Tell_Validate_Number())->negative('-0'))->false();
$this->assert((new Tell_Validate_Number())->negative('-1'))->true();
$this->assert((new Tell_Validate_Number())->negative(-1))->true();
$this->assert((new Tell_Validate_Number())->negative(-0.01))->true();
$this->assert((new Tell_Validate_Number())->negative('-0.01'))->true();
$this->assert((new Tell_Validate_Number())->negative(-0.5))->true();
$this->assert((new Tell_Validate_Number())->negative(0.01))->false();
$this->assert((new Tell_Validate_Number())->negative('0.01'))->false();
$this->assert((new Tell_Validate_Number())->negative(1.00))->false();
$this->assert((new Tell_Validate_Number())->negative('1.00'))->false();
$this->assert((new Tell_Validate_Number())->negative('a'))->false();
$this->assert((new Tell_Validate_Number())->negative('+'))->false();
$this->assert((new Tell_Validate_Number())->negative('-'))->false();
$this->assert((new Tell_Validate_Number())->negative('.'))->false();
$this->assert((new Tell_Validate_Number())->negative(' '))->false();
$this->assert((new Tell_Validate_Number())->negative(TRUE))->false();
$this->assert((new Tell_Validate_Number())->negative(FALSE))->false();
$this->assert((new Tell_Validate_Number())->negative(NULL))->false();
$this->assert((new Tell_Validate_Number())->negative([]))->false();
$this->assert((new Tell_Validate_Number())->negative(new stdClass))->false();
});
$this->try('numeric()', function() {
$this->assert((new Tell_Validate_Number())->numeric(1337e0))->true(); // 1337
$this->assert((new Tell_Validate_Number())->numeric('1337e0'))->false();
$this->assert((new Tell_Validate_Number())->numeric(' 42'))->false();
$this->assert((new Tell_Validate_Number())->numeric('42 '))->false();
$this->assert((new Tell_Validate_Number())->numeric('42'))->true();
$this->assert((new Tell_Validate_Number())->numeric('0.01'))->true();
$this->assert((new Tell_Validate_Number())->numeric(0.01))->true();
$this->assert((new Tell_Validate_Number())->numeric(-0.01))->true();
});
$this->try('numericBetween()', function() {
$this->assert((new Tell_Validate_Number())->numericBetween(-1, -2, -1))->true();
$this->assert((new Tell_Validate_Number())->numericBetween(1, 1, 2))->true();
$this->assert((new Tell_Validate_Number())->numericBetween('59.50', '50', 100))->true();
$this->assert((new Tell_Validate_Number())->numericBetween(10.001, 5, 10))->false();
});
$this->try('numericMin()', function() {
$this->assert((new Tell_Validate_Number())->numericMin('-1.01', -1))->false();
$this->assert((new Tell_Validate_Number())->numericMin('-0.002', -0.001))->false();
$this->assert((new Tell_Validate_Number())->numericMin(-0.002, -0.002))->true();
$this->assert((new Tell_Validate_Number())->numericMin(0, 0))->true();
$this->assert((new Tell_Validate_Number())->numericMin('0', '0'))->true();
$this->assert((new Tell_Validate_Number())->numericMin(0, '0'))->true();
$this->assert((new Tell_Validate_Number())->numericMin(1.001, 1))->true();
$this->assert((new Tell_Validate_Number())->numericMin(10, '5'))->true();
});
$this->try('numericMax()', function() {
$this->assert((new Tell_Validate_Number())->numericMax('0', -1))->false();
$this->assert((new Tell_Validate_Number())->numericMax('0', -0.01))->false();
$this->assert((new Tell_Validate_Number())->numericMax(0, '-0.01'))->false();
$this->assert((new Tell_Validate_Number())->numericMax(-0.01, '-0.01'))->true();
$this->assert((new Tell_Validate_Number())->numericMax(-5, -10))->false();
$this->assert((new Tell_Validate_Number())->numericMax(5, 10))->true();
$this->assert((new Tell_Validate_Number())->numericMax(5, 3))->false();
$this->assert((new Tell_Validate_Number())->numericMax('0.01', 0.02))->true();
$this->assert((new Tell_Validate_Number())->numericMax(1000, 1001))->true();
});
$this->try('positive()', function() {
$this->assert((new Tell_Validate_Number())->positive('0'))->false();
$this->assert((new Tell_Validate_Number())->positive('0', TRUE))->true();
$this->assert((new Tell_Validate_Number())->positive('-0'))->false();
$this->assert((new Tell_Validate_Number())->positive('-1'))->false();
$this->assert((new Tell_Validate_Number())->positive(-1))->false();
$this->assert((new Tell_Validate_Number())->positive(-0.01))->false();
$this->assert((new Tell_Validate_Number())->positive('-0.01'))->false();
$this->assert((new Tell_Validate_Number())->positive(-0.5))->false();
$this->assert((new Tell_Validate_Number())->positive(0.01))->true();
$this->assert((new Tell_Validate_Number())->positive('0.01'))->true();
$this->assert((new Tell_Validate_Number())->positive(1.00))->true();
$this->assert((new Tell_Validate_Number())->positive('1.00'))->true();
$this->assert((new Tell_Validate_Number())->positive('a'))->false();
$this->assert((new Tell_Validate_Number())->positive('+'))->false();
$this->assert((new Tell_Validate_Number())->positive('-'))->false();
$this->assert((new Tell_Validate_Number())->positive('.'))->false();
$this->assert((new Tell_Validate_Number())->positive(' '))->false();
$this->assert((new Tell_Validate_Number())->positive(TRUE))->false();
$this->assert((new Tell_Validate_Number())->positive(FALSE))->false();
$this->assert((new Tell_Validate_Number())->positive(NULL))->false();
$this->assert((new Tell_Validate_Number())->positive([]))->false();
$this->assert((new Tell_Validate_Number())->positive(new stdClass))->false();
});
});
// ---------------------------------------------------------------------------------------------
$inspect('Tell_Validate_Phone', function() {
$this->try('format()')->many($this->phones, function(bool $expect, $number) {
return $expect === (new Tell_Validate_Phone())->format($number);
});
})->vars([
'phones' => [ // [value => expect, ...]
'123-456-7890' => TRUE,
'(0555) 1234 5678' => TRUE,
'+86 155 5555 5432' => TRUE,
'+86 13888889999 extension 12345' => TRUE,
'1-123-456-7890 *5214' => TRUE,
'(123) 456-7890 x 1234' => TRUE,
'+1.123-456-7890/1234' => TRUE,
'555-555-5555' => TRUE,
'+123.555123456' => TRUE,
'+1.123.555.1234' => TRUE,
'555-555-5555 or 123-456-7890' => FALSE,
'mobile 555-555-5555' => FALSE,
'call Bob at 555-555-5555' => FALSE,
'1.1234x123' => FALSE,
"I am a nice shark" => FALSE,
],
]);
// ---------------------------------------------------------------------------------------------
$inspect('Tell_Validate_Str', function() {
$this->try('alpha()')->many($this->alpha, function(array $rules, $str) {
list($spaces, $expect) = $rules;
return $expect === (new Tell_Validate_Str())->alpha($str, $spaces);
});
$this->try('alphaDash()')->many($this->alpha_dash, function(array $rules, $str) {
list($spaces, $expect) = $rules;
return $expect === (new Tell_Validate_Str())->alphaDash($str, $spaces);
});
$this->try('alphaNumeric()')->many($this->alpha_numeric, function(array $rules, $str) {
list($spaces, $expect) = $rules;
return $expect === (new Tell_Validate_Str())->alphaNumeric($str, $spaces);
});
$this->try('ascii()')->many($this->ascii, function(bool $expect, $str) {
return $expect === (new Tell_Validate_Str())->ascii($str);
});
$this->try('length*(ascii)')->many($this->ascii_tests, function(array $rules) {
list($method, $args, $expect) = $rules;
return $expect === (new Tell_Validate_Str())->$method($this->ascii_value, ...$args);
});
$this->try('length*(utf8)')->many($this->utf8_tests, function(array $rules) {
list($method, $args, $expect) = $rules;
return $expect === (new Tell_Validate_Str())->$method($this->utf8_value, ...$args);
});
$this->try('noWhiteSpace()')->many($this->no_whitespace, function(bool $expect, $str) {
return $expect === (new Tell_Validate_Str())->noWhiteSpace($str);
});
$this->try('words()')->many($this->words, function(bool $expect, $str) {
return $expect === (new Tell_Validate_Str())->words($str);
});
})->vars([
'ascii_value' => 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.',
'ascii_tests' => [ // [[method, [args], expect], ...]
['lengthFixed', [56], TRUE],
['lengthFixed', [55], FALSE],
['lengthBetween', [50, 60], TRUE],
['lengthBetween', [56, 57], TRUE],
['lengthBetween', [57, 60], FALSE],
['lengthMin', [60], FALSE],
['lengthMin', [56], TRUE],
['lengthMin', [50], TRUE],
['lengthMin', [57], FALSE],
['lengthMax', [60], TRUE],
['lengthMax', [56], TRUE],
['lengthMax', [50], FALSE],
['lengthMax', [57], TRUE],
],
'utf8_value' => 'žščř',
'utf8_tests' => [ // [[method, [args], expect], ...]
['lengthFixed', [4], TRUE],
['lengthFixed', [8], FALSE],
['lengthFixed', [3], FALSE],
['lengthFixed', [5], FALSE],
['lengthBetween', [2, 6], TRUE],
['lengthBetween', [4, 5], TRUE],
['lengthBetween', [4, 8], TRUE],
['lengthBetween', [5, 8], FALSE],
['lengthBetween', [2, 4], TRUE],
['lengthBetween', [2, 3], FALSE],
['lengthMin', [5], FALSE],
['lengthMin', [4], TRUE],
['lengthMin', [2], TRUE],
['lengthMin', [3], TRUE],
['lengthMin', [6], FALSE],
['lengthMin', [8], FALSE],
['lengthMax', [5], TRUE],
['lengthMax', [4], TRUE],
['lengthMax', [2], FALSE],
['lengthMax', [3], FALSE],
['lengthMax', [6], TRUE],
['lengthMax', [8], TRUE],
],
'alpha' => [ // [value => [allow/disallow-spaces, expect], ...]
'hello-world-123' => [FALSE, FALSE],
'hello-world' => [FALSE, FALSE],
'helloworld' => [FALSE, TRUE],
'123' => [FALSE, FALSE],
'HelloWorldFooBar' => [FALSE, TRUE],
'Hello WorldFooBar' => [FALSE, FALSE],
'hello-world foo' => [FALSE, FALSE],
'Hello World_Foo_123' => [FALSE, FALSE],
'ahello-world-123' => [TRUE, FALSE],
'ahello-world' => [TRUE, FALSE],
'ahelloworld' => [TRUE, TRUE],
'a123' => [TRUE, FALSE],
'aHelloWorldFooBar' => [TRUE, TRUE],
'aHello WorldFooBar' => [TRUE, TRUE],
'ahello-world foo' => [TRUE, FALSE],
'aHello World_Foo_123' => [TRUE, FALSE],
],
'alpha_dash' => [ // [value => [allow/disallow spaces, expect], ...]
'hello-world-123' => [FALSE, TRUE],
'hello-world' => [FALSE, TRUE],
'helloworld' => [FALSE, TRUE],
'123' => [FALSE, TRUE],
'HelloWorldFooBar' => [FALSE, TRUE],
'Hello WorldFooBar' => [FALSE, FALSE],
'hello-world foo' => [FALSE, FALSE],
'Hello World_Foo_123' => [FALSE, FALSE],
'ahello-world-123' => [TRUE, TRUE],
'ahello-world' => [TRUE, TRUE],
'ahelloworld' => [TRUE, TRUE],
'a123' => [TRUE, TRUE],
'aHelloWorldFooBar' => [TRUE, TRUE],
'aHello WorldFooBar' => [TRUE, TRUE],
'ahello-world foo' => [TRUE, TRUE],
'aHello World_Foo_123' => [TRUE, FALSE],
],
'alpha_numeric' => [ // [value => [allow/disallow spaces, expect], ...]
'hello-world-123' => [FALSE, FALSE],
'hello-world' => [FALSE, FALSE],
'helloworld' => [FALSE, TRUE],
'123' => [FALSE, TRUE],
'HelloWorldFooBar' => [FALSE, TRUE],
'Hello WorldFooBar' => [FALSE, FALSE],
'hello-world foo' => [FALSE, FALSE],
'Hello World_Foo_123' => [FALSE, FALSE],
'ahello-world-123' => [TRUE, FALSE],
'ahello-world' => [TRUE, FALSE],
'ahelloworld' => [TRUE, TRUE],
'a123' => [TRUE, TRUE],
'aHelloWorldFooBar' => [TRUE, TRUE],
'aHello WorldFooBar' => [TRUE, TRUE],
'ahello-world foo' => [TRUE, FALSE],
'aHello World_Foo_123' => [TRUE, FALSE],
],
'ascii' => [ // [value => expect, ...]
'žščř' => FALSE,
'hëllo-world-123' => FALSE,
'hšello-world' => FALSE,
"hëllowo'rld" => FALSE,
'(123ľ' => FALSE,
'HelloW.orld FooBar' => TRUE,
'Hello$WorldFooBar' => TRUE,
"hello-world\tfoo" => TRUE,
'$Hello World_Foo_123' => TRUE,
"Hello\tWorld\t_Foo_123" => TRUE,
],
'no_whitespace' => [ // [value => expect, ...]
'hello-world-123' => TRUE,
'hello-world' => TRUE,
'helloworld' => TRUE,
'123' => TRUE,
'HelloWorldFooBar' => TRUE,
'Hello WorldFooBar' => FALSE,
'hello-world foo' => FALSE,
'Hello World_Foo_123' => FALSE,
'hello-world-123[' => TRUE,
'hello-;world' => TRUE,
"hellowo'rld" => TRUE,
'(123' => TRUE,
'HelloW.orld FooBar' => FALSE,
'Hello=WorldFooBar' => TRUE,
"hello-world\tfoo" => FALSE,
"Hello World_Foo_123\n" => FALSE,
"Hello World\n_Foo_123" => FALSE,
],
'words' => [ // [value => expect, ...]
'hello-world-123' => TRUE,
'hello-world' => TRUE,
'helloworld' => TRUE,
'123' => TRUE,
'HelloWorldFooBar' => TRUE,
'Hello WorldFooBar' => TRUE,
'hello-world foo' => TRUE,
'Hello World_Foo_123' => TRUE,
'hello-world-123[' => FALSE,
'hello-;world' => FALSE,
"hellowo'rld" => FALSE,
'(123' => FALSE,
'HelloW.orldFooBar' => FALSE,
'Hello=WorldFooBar' => FALSE,
"hello-world\tfoo" => FALSE,
"Hello World_Foo_123\n" => FALSE,
"Hello World\n_Foo_123" => FALSE,
],
]);
// ---------------------------------------------------------------------------------------------
$inspect('Tell_Validate_Vin', function() {
// @todo this validator is not working for some reason (it used to?)
// $this->try('validate()')->many($this->vins, function($expect, $vin) {
// return $expect === (new Tell_Validate_Vin())->validate($vin);
// });
})->vars([
'vins' => [ // [value => expect, ...]
'3MZBM1V73FM144590' => TRUE,
'JYA2JU007HA058976' => TRUE,
'3VWTL81K39M389565' => TRUE,
'1FAHP34N65W153563' => TRUE,
'4T1GK12E3SU265462' => TRUE,
'JHBFA1536P1S10176' => TRUE,
'1N6BA0CA5BN390204' => TRUE,
'JHMCP2F36BC075467' => TRUE,
'1GDM7T1J7RJ574782' => TRUE,
'1GCEK14T05E276540' => TRUE,
'1GDM7T1J7ZJ574782' => TRUE,
'MZBM1V73FM144590' => FALSE,
'JYA2JU007HA0589767' => FALSE,
'3VXTL81K39M389565' => FALSE,
'1FCHP34N65W153563' => FALSE,
'4T4GK12E3SU265462' => FALSE,
'JHDFA1536P1S10176' => FALSE,
'1N6BB0CA5BN390204' => FALSE,
'JHMCP5F36BC075467' => FALSE,
'1GCEK14T09E276540' => FALSE,
],
]);
// ---------------------------------------------------------------------------------------------
$inspect('Tell_Validate_Web', function() {
$this->try('domain()')->many($this->domains, function(bool $expect, $domain) {
return $expect === (new Tell_Validate_Web())->domain($domain);
});
$this->try('email()')->many($this->emails, function(bool $expect, $email) {
return $expect === (new Tell_Validate_Web())->email($email);
});
$this->try('ip()')->many($this->ip_addresses, function(bool $expect, $ip) {
return $expect === (new Tell_Validate_Web())->ip($ip, TRUE, TRUE);
});
$this->try('ipv4Range()')->many($this->ipv4_ranges, function($value) {
list($input, $cidr, $expect) = $value;
return $expect === (new Tell_Validate_Web())->ipv4Range($input, $cidr);
});
$this->try('url()')->many($this->urls, function(bool $expect, $url) {
return $expect === (new Tell_Validate_Web())->url($url);
});
})->vars([
'domains' => [ // [value => expect, ...]
// 'foo.-google.com' => FALSE, // needs fixed
// 'foo.google.-co.uk' => FALSE, // needs fixed
'google.com' => TRUE,
'go--gle.com' => TRUE,
'google-.com' => FALSE,
'foo.google.com' => TRUE,
'foo.google.com/bar' => FALSE,
'http://google.com' => FALSE,
'https://google.com' => FALSE,
'google.co.uk' => TRUE,
'foo.google.co.uk' => TRUE,
"\x0Dgoogle.com" => FALSE, // \n...
"goo\x0Dgle.com" => FALSE, // ...\n...
"google.com\x0D" => FALSE, // ...\n
"\x00google.com" => FALSE, // NULL...
"goo\x00gle.com" => FALSE, // ...NULL...
"google.com\x00" => FALSE, // ...NULL
"\x04google.com" => FALSE, // EOL...
"goo\x04gle.com" => FALSE, // ...EOL...
"google.com\x04" => FALSE, // ...EOL
],
'emails' => [ // [value => expect, ...]
0 => FALSE,
1 => FALSE,
'bartle.doo@foo.com' => TRUE,
'bobbie@templeton.co.uk' => TRUE,
'@foo.com' => FALSE,
"bartle.doo@foo..com" => FALSE,
'bartle.doo@.com' => FALSE,
"bartle.doo@foo" => FALSE,
'omer asaf.lang@quies.co.il' => FALSE, // ... ...
"bartle.doo @foo.com" => FALSE, // ... ...
"bartle.doo@ foo.com" => FALSE, // ... ...
"\x0Dbartle.doo@foo.com" => FALSE, // \n...
"\x0A\x0Dbartle.doo@foo.com" => FALSE, // \r\n...
"bartle.doo@foo.com\x0D" => FALSE, // ...\n
"bartle.doo@foo.com\x0A\x0D" => FALSE, // ...\r\n
"\x00bartle.doo@foo.com" => FALSE, // NULL...
"bartle.doo@foo.com\x00" => FALSE, // ...NULL
"bartle.doo\x00doo@foo.com" => FALSE, // ...NULL...
"\x04bartledoo@foo.com" => FALSE, // EOL...
"bartle.doo@foo.com\x04" => FALSE, // ...EOL
"bartle.doo\x04@foo.com" => FALSE, // ...EOL...
],
'ip_addresses' => [ // [value => expect, ...]
'123.169.23.16' => TRUE,
'44.213.46.223' => TRUE,
'178.208.44.81' => TRUE,
'16.195.168.77' => TRUE,
'206.0.47.20' => TRUE,
'218.117.101.145' => TRUE,
'152.154.100.99' => TRUE,
'30.184.54.80' => TRUE,
'51.228.94.171' => TRUE,
'254.159.129.88' => TRUE, // reserved range
'16.195.168.77 ' => FALSE,
'16.195.16877' => FALSE,
"16.195.168\x00.77" => FALSE, // NULL
'a0af:5637:1cbb:e389:a0d9:e226:b2cd:59df' => TRUE,
'fbc9:1ec2:529b:2790:4fd6:ded8:a5ad:389c' => TRUE,
'825b:d227:2397:50f2:b4d3:5a21:a183:2034' => TRUE,
'dcb7:60a7:66c0:b5a6:418b:5b23:e080:3c2c' => TRUE,
'5e2f:ff97:c3cc:9c6c:9091:debc:4e8b:481f' => TRUE,
'939d:d5a6:2761:8091:814b:91e2:925b:0261' => TRUE,
'c712:ba91:6d99:73ba:aec8:e477:0cb2:eb33' => TRUE,
'da3f:75c7:d6d6:7c88:473a:c00b:61e7:bcbf' => TRUE,
'1839:30cc:8126:23a0:eb32:aae0:ab73:b7f6' => TRUE,
'bfb0:15f7:0557:51cd:1e0a:db6a:0281:b630' => TRUE,
'bfb0:15f7:0557:51cd:1e0a:db6a:0281b630' => FALSE,
],
// Values from Symfony HTTP Foundation Tests/IPUtilsTest.php
// (c) Fabien Potencier <fabien@symfony.com>
'ipv4_ranges' => [ // [[value, cidr notation(s), expect], ...]
['192.168.1.1', '192.168.1.1', TRUE],
['192.168.1.1', '192.168.1.1/1', TRUE],
['192.168.1.1', '192.168.1.0/24', TRUE],
['192.168.1.1', '1.2.3.4/1', FALSE],
['192.168.1.1', '192.168.1.0/a', FALSE], // Invalid subnet
['192.168.1.1', '192.168.1.1/33', FALSE], // Invalid subnet
['192.168.1.1', ['1.2.3.4/1', '192.168.1.0/24'], TRUE],
['192.168.1.1', ['192.168.1.0/24', '1.2.3.4/1'], TRUE],
['192.168.1.1', ['1.2.3.4/1', '4.3.2.1/1'], FALSE],
['1.2.3.4', '0.0.0.0/0', TRUE],
['1.2.3.4', '192.168.1.0/0', TRUE],
['1.2.3.4', '256.256.256/0', FALSE], // Invalid CIDR notation
['an_invalid_ip', '192.168.1.0/24', FALSE],
['', '1.2.3.4/1', FALSE],
],
'urls' => [ // [value => expect, ...]
'https://example.com/believe/authority.html' => TRUE,
'example.com/believe/authority.html' => FALSE,
'http://example.org/' => TRUE,
'http://apparel.example.com/' => TRUE,
'https://www.example.com/border?advice=action' => TRUE,
'http://www.example.com/bomb.html' => TRUE,
'http://army.example.com/birthday/addition' => TRUE,
'https://www.example.com' => TRUE,
'https://example.com/boundary/anger.php' => TRUE,
'https://www.example.com/afternoon.php' => TRUE,
'https://belief.example.com/aunt/brass.php?balance=boy&board=action' => TRUE,
'http://pt.wikipedia.org/wiki/Guimarães' => TRUE,
"https://www.example.com/hello\x00world" => FALSE, // NULL
"https://www.example.com/hello\x0Dworld" => FALSE, // \n
],
]);
// ---------------------------------------------------------------------------------------------
{JSON results of applicable inspection}
<?php
/**
* This inspection is still under construction.
* ---
* @todo
*/
$inspect('Tell_Ipsum', function() {
$this->try('Tell_Ipsum_Card', function() {
$this->try('number()')->many(50, function(Tell_Ipsum_Card $card) {
return $this->assert($card->number())->string();
})->then('factory()', function(Tell_Ipsum_Card $card) {
return $this->assert($card->factory())->instanceOf(Tell_Bridge_Card::class);
});
});
$this->try('Tell_Ipsum_Contact', function() {
// @todo
});
$this->try('Tell_Ipsum_Record', function() {
// @todo
});
$this->try('Tell_Ipsum_Text', function() {
// @todo
});
});
{JSON results of applicable inspection}
<?php
/**
* This inspection is still under construction.
* ---
* @todo
*/
$inspect('Tell_Session', function() {
$this->try('_()', function() {
// @todo
});
});
{JSON results of applicable inspection}
<?php
/**
* This inspection is still under construction.
* ---
* @todo
*/
$inspect('Tell_Str_Obj', function() {
$tests = [
'el' => /* Greek */ "Γαζέες καὶ μυρτιὲς δὲν θὰ βρῶ πιὰ στὸ χρυσαφὶ ξέφωτο",
'en' => /* English */ "The quick brown fox jumps over the lazy dog",
'de' => /* German */ "Falsches Üben von Xylophonmusik quält jeden größeren Zwerg",
'es' => /* Spanish */ "El pingüino Wenceslao hizo kilómetros bajo exhaustiva lluvia y frío, añoraba a su querido cachorro.",
'fr' => /* French */ "Le cœur déçu mais l'âme plutôt naïve, Louÿs rêva de crapaüter en canoë au delà des îles, près du mälström où brûlent les novæ.",
];
$greek = new Tell_Str_Obj($tests['el']);
$english = new Tell_Str_Obj($tests['en']);
$german = new Tell_Str_Obj($tests['de']);
$spanish = new Tell_Str_Obj($tests['es']);
$french = new Tell_Str_Obj($tests['fr']);
$this->assert($greek->__toString())->equals($tests['el']);
$this->assert($greek[0])->equals('Γ');
$this->assert($greek[26])->equals('β');
$this->assert($greek[51])->equals('ο');
$this->assert($english->__toString())->equals($tests['en']);
$this->assert($english[0])->equals('T');
$this->assert($english[27])->equals('v');
$this->assert($english[42])->equals('g');
$this->assert($german->__toString())->equals($tests['de']);
$this->assert($german[0])->equals('F');
$this->assert($german[46])->equals('ö');
$this->assert($german[57])->equals('g');
$this->assert($spanish->__toString())->equals($tests['es']);
$this->assert($spanish[0])->equals('E');
$this->assert($spanish[7])->equals('ü');
$this->assert($spanish[98])->equals('.');
$this->assert($french->__toString())->equals($tests['fr']);
$this->assert($french[0])->equals('L');
$this->assert($french[41])->equals('ÿ');
$this->assert($french[125])->equals('.');
});
{JSON results of applicable inspection}
<?php
/**
* This inspection is still under construction.
* ---
* @todo
*/
$inspect('Tell_Env', function() {
$this->try('get()', function() {
// @todo
});
});
{JSON results of applicable inspection}
<?php
$inspect('Tell_Date_Epoch', function() {
$props = [
'years',
'months',
'weeks',
'days',
'hours',
'minutes',
'seconds',
];
$epochs = [
new Tell_Date_Epoch(
new DateTime('2000-01-01 00:00:00'),
new DateTime('2001-01-01 00:00:00')
),
new Tell_Date_Epoch(
new DateTime('2001-01-01 00:00:00'),
new DateTime('2002-01-01 00:00:00')
),
new Tell_Date_Epoch(
new DateTime('2020-01-10 00:00:00'),
new DateTime('2020-01-20 00:00:00')
),
new Tell_Date_Epoch(
new DateTime('2020-01-10 09:15:00'),
new DateTime('2020-01-11 10:15:00')
),
new Tell_Date_Epoch(
new DateTime('2020-03-10 09:15:25'),
new DateTime('2021-03-09 09:15:25')
),
new Tell_Date_Epoch(
new DateTime('1962-03-10 12:30:00'),
new DateTime('1964-03-11 12:30:00')
),
new Tell_Date_Epoch(
new DateTime('1970-01-01 00:01:00'),
new DateTime('1971-01-01 00:01:30')
),
];
foreach ($epochs as $epoch) {
foreach ($props as $prop) {
$lt = '+' . ($epoch->$prop) . ' ' . $prop;
$gt = '+' . ($epoch->$prop + 1) . ' ' . $prop;
$this->assert((clone $epoch->from)->modify($lt))->lessThanOrEqualTo($epoch->to);
$this->assert((clone $epoch->from)->modify($gt))->greaterThanOrEqualTo($epoch->to);
}
}
});
$inspect('Tell_Date_Unit', function() {
$base = [
'isIncremental' => FALSE,
'isDateTime' => FALSE,
'isDate' => FALSE,
'isTime' => FALSE,
'isYear' => FALSE,
'isMonth' => FALSE,
'isWeek' => FALSE,
'isWeekday' => FALSE,
'isDay' => FALSE,
'isHour' => FALSE,
'isMinute' => FALSE,
'isSecond' => FALSE,
];
$tests = [
// ------------------------------
[
'value' => '1970-01-01 06:46:13',
'isDateTime' => TRUE,
],
[
'value' => '01/01/1970 07:19:23',
'isDateTime' => TRUE,
],
[
'value' => '2016-02-03 3:14 PM',
'isDateTime' => TRUE,
],
[
'value' => '2016-02-03 3:14PM',
'isDateTime' => TRUE,
],
[
'value' => '2021-05-16 13:27:14',
'isDateTime' => TRUE,
],
[
'value' => '2021-05-16 00:00:00',
'isDateTime' => TRUE,
],
[
'value' => '2021-05-16 00:00',
'isDateTime' => TRUE,
],
[
'value' => '2021-07-19 12:31:14',
'isDateTime' => TRUE,
],
// ------------------------------
[
'value' => '2020-09-14',
'isDate' => TRUE,
],
[
'value' => '2000-01-01',
'isDate' => TRUE,
],
[
'value' => '2016/02/03',
'isDate' => TRUE,
],
[
'value' => '07/13/2006',
'isDate' => TRUE,
],
// ------------------------------
[
'value' => '9am',
'isTime' => TRUE,
],
[
'value' => '9 am',
'isTime' => TRUE,
],
[
'value' => '9AM',
'isTime' => TRUE,
],
[
'value' => '9 AM',
'isTime' => TRUE,
],
[
'value' => '9:00',
'isTime' => TRUE,
],
[
'value' => '09:00',
'isTime' => TRUE,
],
[
'value' => '9:15am',
'isTime' => TRUE,
],
[
'value' => '9:15 am',
'isTime' => TRUE,
],
[
'value' => '9:15AM',
'isTime' => TRUE,
],
[
'value' => '9:15 AM',
'isTime' => TRUE,
],
[
'value' => '09:15 AM',
'isTime' => TRUE,
],
[
'value' => '1230',
'isTime' => TRUE,
],
[
'value' => '1800',
'isTime' => TRUE,
],
[
'value' => '2359',
'isTime' => TRUE,
],
// ------------------------------
[
'value' => 'sep',
'isMonth' => TRUE,
],
[
'value' => 'sept',
'isMonth' => TRUE,
],
[
'value' => 'September',
'isMonth' => TRUE,
],
[
'value' => 'SEPTEMBER',
'isMonth' => TRUE,
],
[
'value' => 'Jul',
'isMonth' => TRUE,
],
[
'value' => 'JUL',
'isMonth' => TRUE,
],
[
'value' => 'July',
'isMonth' => TRUE,
],
// ------------------------------
[
'value' => 'Month',
'isIncremental' => TRUE,
'isMonth' => TRUE,
],
[
'value' => '1 month',
'isIncremental' => TRUE,
'isMonth' => TRUE,
],
[
'value' => '2 mths',
'isIncremental' => TRUE,
'isMonth' => TRUE,
],
[
'value' => '6 months',
'isIncremental' => TRUE,
'isMonth' => TRUE,
],
[
'value' => '2 MONTHS',
'isIncremental' => TRUE,
'isMonth' => TRUE,
],
[
'value' => '48 MONTHS',
'isIncremental' => TRUE,
'isMonth' => TRUE,
],
// ------------------------------
[
'value' => 'we',
'isWeekday' => TRUE,
],
[
'value' => 'wed',
'isWeekday' => TRUE,
],
[
'value' => 'WED',
'isWeekday' => TRUE,
],
[
'value' => 'wednesday',
'isWeekday' => TRUE,
],
[
'value' => 'Friday',
'isWeekday' => TRUE,
],
[
'value' => 'FRIDAY',
'isWeekday' => TRUE,
],
// ------------------------------
[
'value' => 'day',
'isIncremental' => TRUE,
'isDay' => TRUE,
],
[
'value' => '1 day',
'isIncremental' => TRUE,
'isDay' => TRUE,
],
[
'value' => '3 DAYS',
'isIncremental' => TRUE,
'isDay' => TRUE,
],
[
'value' => '60 DAYS',
'isIncremental' => TRUE,
'isDay' => TRUE,
],
// ------------------------------
[
'value' => 'hr',
'isIncremental' => TRUE,
'isHour' => TRUE,
],
[
'value' => 'hour',
'isIncremental' => TRUE,
'isHour' => TRUE,
],
[
'value' => '1 hour',
'isIncremental' => TRUE,
'isHour' => TRUE,
],
[
'value' => '3 HOURS',
'isIncremental' => TRUE,
'isHour' => TRUE,
],
[
'value' => '4 hr',
'isIncremental' => TRUE,
'isHour' => TRUE,
],
[
'value' => '4 hrs',
'isIncremental' => TRUE,
'isHour' => TRUE,
],
// ------------------------------
[
'value' => '15 minutes',
'isIncremental' => TRUE,
'isMinute' => TRUE,
],
[
'value' => '15 MINUTES',
'isIncremental' => TRUE,
'isMinute' => TRUE,
],
[
'value' => '15 mins',
'isIncremental' => TRUE,
'isMinute' => TRUE,
],
[
'value' => '15 min',
'isIncremental' => TRUE,
'isMinute' => TRUE,
],
[
'value' => '60 min',
'isIncremental' => TRUE,
'isMinute' => TRUE,
],
// ------------------------------
[
'value' => '30 sec',
'isIncremental' => TRUE,
'isSecond' => TRUE,
],
[
'value' => '35 secs',
'isIncremental' => TRUE,
'isSecond' => TRUE,
],
[
'value' => '45 seconds',
'isIncremental' => TRUE,
'isSecond' => TRUE,
],
[
'value' => '120 SECONDS',
'isIncremental' => TRUE,
'isSecond' => TRUE,
],
// ------------------------------
];
foreach ($tests as $k => $test) {
$tests[$k] = array_merge($base, $test);
}
foreach (array_keys($base) as $method) {
$this->try($method . '()')->many($tests, function($t) use ($method) {
return $t[$method] === (new Tell_Date_Unit($t['value']))->$method();
});
}
// $this->assert(function() { new Tell_Date_Unit('Dec 32nd'); })
// ->exception(Tell_Exception_Type::class);
// $this->assert(function() { new Tell_Date_Unit('Dec abc'); })
// ->exception(Tell_Exception_Type::class);
// $this->assert(function() { new Tell_Date_Unit('1 March'); })
// ->exception(Tell_Exception_Type::class);
// $this->assert(function() { logger(new Tell_Date_Unit('32 Monday')); })
// ->exception(Tell_Exception_Type::class);
// $this->assert(function() { new Tell_Date_Unit('March 32'); })
// ->exception(Tell_Exception_Type::class);
});
{JSON results of applicable inspection}
<?php
class Inspect_Cron_Job extends Tell_Cron_Job
{
public function __call($name, $arguments)
{
return $this->$name(...$arguments);
}
}
class GoodCronJob
{
public function __invoke()
{
return 'OK';
}
}
class BadCronJob {}
$inspect('Tell_Cron_Job', function(Tell_Container $ioc) {
$event = $ioc->pull(Tell_Event::class);
$evFailure = $evSuccess = [];
$event->register(Tell::EVENT_JOB_FAILURE, function($ev) use (&$evFailure) {
$evFailure[] = $ev;
});
$event->register(Tell::EVENT_JOB_SUCCESS, function($ev) use (&$evSuccess) {
$evSuccess[] = $ev;
});
$reset = function() use (&$evFailure, &$evSuccess) {
$evFailure = $evSuccess = [];
};
$cron = function(string $schedule, $now) use ($ioc) {
return new Inspect_Cron_Job($schedule, $ioc, __DIR__ . '/../job', $now);
};
$assertEvent = function($event) {
$this->assert($event)->array()
->hasKey('schedule')
->hasKey('type')
->hasKey('input')
->hasKey('output')
->hasKey('result');
};
$this->try('runCommand() - failure event', function() use ($cron, &$evFailure, $reset, $assertEvent) {
$job = $cron('*/5 * * * *', '2023-03-06 10:10:53');
$this->assert($job->shouldRun())->true();
ob_start();
$job->runCommand('cd /foo/bar/not/exist');
$this->assert(strlen(trim(ob_get_clean())))->greaterThan(3);
$assertEvent($evFailure[0] ?? NULL);
$this->assert($evFailure[0]['input'])->equals('cd /foo/bar/not/exist');
$this->assert($evFailure[0]['result'])->array()
->hasKey('stdout')
->hasKey('stderr')
->hasKey('return');
$reset();
})->then('runCommand() - success event', function() use ($cron, &$evSuccess, $reset, $assertEvent) {
$job = $cron('*/5 * * * *', '2023-03-06 10:10:53');
$this->assert($job->shouldRun())->true();
ob_start();
$job->runCommand('echo OK');
$this->assert(trim(ob_get_clean()))->equals('OK');
$assertEvent($evSuccess[0] ?? NULL);
$this->assert($evSuccess[0]['input'])->equals('echo OK');
$this->assert($evSuccess[0]['result'])->array()
->hasKey('stdout')
->hasKey('stderr')
->hasKey('return');
$this->assert(trim($evSuccess[0]['result']['stdout']))->equals('OK');
$this->assert($evSuccess[0]['result']['return'])->equals(0);
$reset();
})->then('runJob() - failure event', function() use ($cron, &$evFailure, $reset, $assertEvent) {
$job = $cron('*/5 * * * *', '2023-03-06 10:10:53');
$this->assert($job->shouldRun())->true();
ob_start();
$job->runJob('invalid.job');
$this->assert(trim(ob_get_clean()))->equals('"invalid.job" does not resolve to a valid job script.');
$assertEvent($evFailure[0] ?? NULL);
$this->assert($evFailure[0]['input'])->equals('invalid.job');
$this->assert($evFailure[0]['output'])->equals('"invalid.job" does not resolve to a valid job script.');
$reset();
})->then('runJob() - success event', function() use ($cron, &$evSuccess, $reset, $assertEvent) {
$job = $cron('*/5 * * * *', '2023-03-06 10:10:53');
$this->assert($job->shouldRun())->true();
ob_start();
$job->runJob('test');
$this->assert(trim(ob_get_clean()))->equals('OK');
$assertEvent($evSuccess[0] ?? NULL);
$this->assert($evSuccess[0]['input'])->equals('test');
$this->assert($evSuccess[0]['output'])->equals('OK');
$reset();
})->then('runResolve() - failure event', function() use ($cron, &$evFailure, $reset, $assertEvent) {
$job = $cron('*/5 * * * *', '2023-03-06 10:10:53');
$this->assert($job->shouldRun())->true();
ob_start();
$job->runResolve(BadCronJob::class);
$this->assert(trim(ob_get_clean()))->equals('BadCronJob must have an __invoke() method to be used as a cron job.');
$assertEvent($evFailure[0] ?? NULL);
$this->assert($evFailure[0]['input'])->equals(BadCronJob::class);
$reset();
})->then('runResolve() - success event', function() use ($cron, &$evSuccess, $reset, $assertEvent) {
$job = $cron('*/5 * * * *', '2023-03-06 10:10:53');
$this->assert($job->shouldRun())->true();
ob_start();
$job->runResolve(GoodCronJob::class);
$this->assert(trim(ob_get_clean()))->equals('OK');
$assertEvent($evSuccess[0] ?? NULL);
$this->assert($evSuccess[0]['input'])->equals(GoodCronJob::class);
$this->assert($evSuccess[0]['output'])->equals('OK');
$reset();
})->then('__invoke()', function() use ($cron, &$evSuccess, $reset, $assertEvent) {
$job = $cron('*/5 * * * *', '2023-03-06 10:10:53')
->command('echo OK')
->job('test')
->resolve(GoodCronJob::class);
$this->assert($job->shouldRun())->true();
ob_start();
$job->__invoke();
$this->assert(trim(ob_get_clean()))->equals("OK\nOK\nOK");
$assertEvent($evSuccess[0] ?? NULL);
$assertEvent($evSuccess[1] ?? NULL);
$assertEvent($evSuccess[2] ?? NULL);
$reset();
});
});
{JSON results of applicable inspection}
<?php
/**
* This inspection is still under construction.
* ---
* @todo
*/
$inspect('Tell_Reflect', function() {
$this->try('_()', function() {
// @todo
});
});
{JSON results of applicable inspection}
<?php
/**
* This inspection is still under construction.
* ---
* @todo
*/
$inspect('Tell_Email', function() {
$this->try('__()', function() {
// @todo
});
});
{JSON results of applicable inspection}
<?php
/**
* This inspection is still under construction.
* ---
* @todo
*/
$inspect('Tell_Request', function() {
$this->try('_()', function() {
// @todo
});
});
{JSON results of applicable inspection}
<?php
/**
* This inspection is still under construction.
* ---
* @todo
*/
$inspect('Tell_Json', function() {
$this->try('_()', function() {
// @todo
});
});
{JSON results of applicable inspection}
<?php
$inspect('Tell_Schema_Table_Mysql', function() {
$this->try('Creating example tables from SQL file', function(Tell_Db $db) {
if ($db->pdo instanceof Closure) {
$db->pdo->__invoke();
}
$this->assert($db->pdo->exec($this->ddl))->int()->equals(0);
})->then('Validate the DDL without schema in cache', function(Tell_Schema $schema) {
$this->assert($schema->incrementColumn('example'))->equals('id');
$this->assert($schema->primaryKey('example'))->equals('id');
$this->assert($schema->hasTable('example'))->true();
$this->assert($schema->hasTable('example2'))->false();
$this->assert($schema->rename('example', 'example2'))->true();
$this->assert($schema->hasTable('example'))->false();
$this->assert($schema->hasTable('example2'))->true();
$this->assert($schema->hasColumn('example2', 'id'))->true();
$this->assert($schema->hasColumn('example2', 'id2'))->false();
$this->assert($schema->hasColumn('example', 'id'))->false();
$this->assert($schema->hasIndex('example2', 'id'))->false();
$this->assert($schema->hasIndex('example2', 'bill_first_name, bill_last_name'))->true();
$this->assert($schema->incrementColumn('example2'))->equals('id');
$this->assert($schema->primaryKey('example2'))->equals('id');
$this->assert($schema->dropColumn('example2', 'order_number'))->true();
})->then('Validate the DDL with schema in cache', function(Tell_Schema $schema) {
$schema('example2'); // puts schema in cache
$this->assert($schema->incrementColumn('example2'))->equals('id');
$this->assert($schema->primaryKey('example2'))->equals('id');
$this->assert($schema->hasTable('example2'))->true();
$this->assert($schema->hasTable('example'))->false();
$this->assert($schema->hasColumn('example2', 'id'))->true();
$this->assert($schema->hasColumn('example2', 'id2'))->false();
$this->assert($schema->hasColumn('example', 'id'))->false();
$this->assert($schema->hasIndex('example2', 'id'))->false();
$this->assert($schema->hasIndex('example2', 'bill_first_name, bill_last_name'))->true();
$this->assert($schema->incrementColumn('example2'))->equals('id');
$this->assert($schema->primaryKey('example2'))->equals('id');
$this->assert($schema->dropColumn('example2', 'order_number'))->true();
$this->assert($schema->drop('example2'))->true();
$this->assert($schema->hasTable('example2'))->false();
})->then('Create and alter a table', function(Tell_Schema $schema, Tell_Db $db) {
$this->assert($schema->drop('items'))->true();
$this->assert($schema->create('items', function(Tell_Schema_Column $column) {
$column->serial('id')->primary();
$column->int('category_id');
$column->enum('listing_status', ['Active', 'Backordered', 'Discontinued', 'Unlisted']);
$column->varchar('item_name');
$column->currency('price');
$column->dateTime('modified');
$column->dateTime('created');
$column->index('id, category_id');
$column->index('listing_status');
}))->true();
$this->assert($schema->hasTable('items'))->true();
$this->assert($schema->hasColumn('items', 'id'))->true();
$this->assert($schema->hasColumn('items', 'category_id'))->true();
$this->assert($schema->hasColumn('items', 'listing_status'))->true();
$this->assert($schema->hasColumn('items', 'item_name'))->true();
$this->assert($schema->hasColumn('items', 'price'))->true();
$this->assert($schema->hasColumn('items', 'modified'))->true();
$this->assert($schema->hasColumn('items', 'created'))->true();
$this->assert($schema->hasColumn('items', 'something_else'))->false();
$this->assert($schema->incrementColumn('items'))->equals('id');
$this->assert($schema->primaryKey('items'))->equals('id');
$this->assert($schema->hasIndex('items', 'id, category_id'))->true();
$this->assert($schema->hasIndex('items', 'listing_status'))->true();
$table = $schema->schema('items', TRUE);
$this->assert($table)->instanceOf(Tell_Schema_Schema_Bridge::class);
$columns = $table->columns;
$this->assert($columns)->arr();
$this->assert($columns['item_name'] ?? NULL)->instanceOf(Tell_Schema_Column_Bridge::class);
$this->assert($columns['item_name']->length)->int()->equals(255);
for ($i = 0; $i < 5; $i++) {
$this->assert($db("INSERT INTO items")->data(Test_Schema::rowIpsumItem())->run())
->int()
->equals($i + 1);
}
$this->assert($schema->alter('items', function(Tell_Schema_Column $column) {
$column->rename('id', 'item_id');
$column->rename('listing_status', 'status');
$column->enum('status', ['Active', 'Preordered', 'Backordered', 'Discontinued', 'Unlisted']);
$column->varchar('item_name', 128);
$column->dropIndex(['id', 'category_id']);
}))->true();
$this->assert($schema->incrementColumn('items'))->equals('item_id');
$this->assert($schema->primaryKey('items'))->equals('item_id');
$this->assert($schema->hasColumn('items', 'listing_status'))->false();
$this->assert($schema->hasColumn('items', 'status'))->true();
$this->assert($schema->hasIndex('items', 'id, category_id'))->false();
$this->assert($schema->hasIndex('items', 'listing_status'))->false();
$this->assert($schema->hasIndex('items', 'status'))->true();
$columns = $schema->schema('items', TRUE)->columns;
$this->assert($columns['item_name']->length)->int()->equals(128);
$this->assert($db("INSERT INTO items")->data(Test_Schema::rowItemAfterAltered())->run())
->int()
->equals($i + 1);
$this->assert($schema->drop('items'))->true();
$this->assert($schema->hasTable('items'))->false();
});
})->swap(function(Tell_Event $event) {
return [
'Tell_Db' => new Tell_Db([
'driver' => 'mysql',
'database' => 'tell_php_test',
'host' => '127.0.0.1',
'port' => NULL,
'socket' => NULL,
'username' => 'tell_php_test',
'password' => 'testing',
'elevate_exceptions' => TRUE,
'log_failed' => TRUE,
'log_success' => FALSE,
'log_limit' => 1000,
], $event),
];
})->vars([
'ddl' => file_get_contents(__DIR__ . '/../assets/sql/table.mysql.sql'),
])->onlyWhen(function() {
return extension_loaded('pdo_mysql') && env('TELL_PHP_DEV');
});
{JSON results of applicable inspection}
<?php
/**
* This inspection is still under construction.
* ---
* @todo
*/
$inspect('Tell_Exception_File', function() {
$this->try('Granular Methods', function() {
$this->try('__construct()', function() {
// @todo
});
$this->try('toArr()', function() {
// @todo
});
$this->try('operation()', function() {
// @todo
});
$this->try('path()', function() {
// @todo
});
$this->try('reason()', function() {
// @todo
});
})->then('Shorthand Methods', function() {
$this->try('notEmpty()', function() {
// @todo
});
$this->try('notExecutable()', function() {
// @todo
});
$this->try('notDirectory()', function() {
// @todo
});
$this->try('notEmptyDirectory()', function() {
// @todo
});
$this->try('notExecutable()', function() {
// @todo
});
$this->try('notFile()', function() {
// @todo
});
$this->try('notFound()', function() {
// @todo
});
$this->try('notReadable()', function() {
// @todo
});
$this->try('notWritable()', function() {
// @todo
});
$this->try('failedDeleteDirectory()', function() {
// @todo
});
$this->try('failedDeleteFile()', function() {
// @todo
});
$this->try('failedCreateDirectory()', function() {
// @todo
});
$this->try('failedCreateFile()', function() {
// @todo
});
$this->try('failedUpdateFile()', function() {
// @todo
});
});
});
$inspect('Tell_Exception_Path', function() {
$this->try('_()', function() {
// @todo
});
});
$inspect('Tell_Exception_Type', function() {
$this->try('_()', function() {
// @todo
});
});
{JSON results of applicable inspection}
<?php
/**
* This inspection is still under construction.
* ---
* @todo
*/
// ---------------------------------------------------------------------------------------------
$inspect('Tell_Inflect_Pluralize', function() {
$this->try('isPlural()', function() {
// @todo
})->then('plural()', function() {
// @todo
});
$this->try('isSingular()', function() {
// @todo
})->then('singular()', function() {
// @todo
});
});
// ---------------------------------------------------------------------------------------------
$inspect('Tell_Inflect_Variadic - Lists', function() {
$this->try('isListable()', function() {
// @todo
})->then('toList()', function() {
// @todo
});
})->vars([
'args' => [
0 => new stdClass(),
1 => [new stdClass()],
2 => 'dory',
3 => ['dory'],
4 => ['foo', 'I', 'am', 'a', 'nice', 'shark'],
5 => ['foo', 'I', 'am', 'a', new stdClass(), 'shark'],
],
]);
// ---------------------------------------------------------------------------------------------
$inspect('Tell_Inflect_Variadic - Parameters', function() {
$this->try('isParamable()', function() {
// @todo
})->then('toParams()', function() {
// @todo
});
})->vars([
'good' => [
0 => ['first_name', 'Bob'],
1 => [
'first_name' => 'Bob',
'last_name' => 'Smith',
],
],
'bad' => [
0 => 'Bob',
1 => ['Bob'],
2 => ['first_name', 'Bob', 'last_name', 'Smith'],
],
]);
// ---------------------------------------------------------------------------------------------
$inspect('Tell_Inflect_Variadic - Rows', function() {
$this->try('isRowable()', function() {
foreach ($this->good as $val) {
$inflect = new Tell_Inflect_Variadic([], $val);
$this->assert($inflect->isRowable())->true();
}
foreach ($this->bad as $val) {
$inflect = new Tell_Inflect_Variadic([], $val);
$this->assert($inflect->isRowable())->false();
}
})->then('toRows()', function() {
foreach ($this->good as $val) {
$inflect = new Tell_Inflect_Variadic([], $val);
$this->assert($inflect->toRows())->arr();
}
foreach ($this->bad as $val) {
$inflect = new Tell_Inflect_Variadic([], $val);
$this->assert($inflect->toRows())->null();
}
});
})->vars([
'good' => [
0 => [[
'first_name' => 'Johnny',
'last_name' => 'Raincloud',
'billing_id' => NULL,
]],
1 => [[
[
'first_name' => 'Johnny',
'last_name' => 'Raincloud',
],
[
'first_name' => 'Negative',
'last_name' => 'Nancy'
],
[
'first_name' => 'Starvin',
'last_name' => 'Marvin',
],
]],
],
'bad' => [
0 => [['Positive', 'Pedro']],
1 => [[
[
'first_name' => 'Johnny',
'last_name' => 'Raincloud',
],
'Negative Nancy',
[
'first_name' => 'Starvin',
'last_name' => 'Marvin',
],
]],
],
]);
// ---------------------------------------------------------------------------------------------
$inspect('Tell_Inflect', function() {
$this->try('plural()', function() {
// @todo
});
$this->try('singular()', function() {
// @todo
});
$this->try('bytes()', function() {
// @todo
});
$this->try('kilobytes()', function() {
// @todo
});
$this->try('megabytes()', function() {
// @todo
});
$this->try('gigabytes()', function() {
// @todo
});
$this->try('terabytes()', function() {
// @todo
});
$this->try('filesize()', function() {
// @todo
});
$this->try('unitMultiplier()', function() {
// @todo
});
$this->try('bool()', function() {
// @todo
});
$this->try('enum()', function() {
// @todo
});
$this->try('humanize()', function() {
// @todo
});
$this->try('int()', function() {
// @todo
});
$this->try('ordinal()', function() {
// @todo
});
$this->try('slugify()', function() {
// @todo
});
$this->try('time()', function() {
// @todo
});
$this->try('unaccent()', function() {
// @todo
});
});
// ---------------------------------------------------------------------------------------------
{JSON results of applicable inspection}
<?php
$inspect('Action', function() {
$db = Mockery::mock(Tell_Db::class);
$db->shouldReceive('query->data->run')->andReturn(1);
$action = new Test_Action_UserCreate();
$action::inject('ioc', $this->ioc);
$action::inject('db', $db);
$this->try('Creating user')->action(Test_Action_UserCreate::class)->assert();
})->request(function(Tell_Ipsum_Contact $ipsum) {
$contact = $ipsum->contact();
$password = $ipsum->password();
return [
'method' => 'POST',
'post' => [
'first_name' => $contact->first_name,
'last_name' => $contact->last_name,
'address1' => $contact->address1,
'address2' => $contact->address2,
'city' => $contact->city,
'province' => $contact->province,
'postal' => $contact->postal,
'country' => $contact->country,
'email' => $contact->email,
'password' => $password,
'password_confirm' => $password,
'status' => $ipsum->random(['Active', 'Disabled']),
],
];
});