diff --git a/public/index.php b/public/index.php index 79964f681d..3137f33047 100644 --- a/public/index.php +++ b/public/index.php @@ -25,7 +25,7 @@ $paths = new Config\Paths(); // Location of the framework bootstrap file. // This is the second of two lines that might need to be changed, depending on your folder structure. -$app = require FCPATH . '../system//bootstrap.php'; +$app = require FCPATH . '../system/bootstrap.php'; /* *--------------------------------------------------------------- diff --git a/system/CLI/Exceptions/CLIException.php b/system/CLI/Exceptions/CLIException.php index 3e330f088b..6e2477faa7 100644 --- a/system/CLI/Exceptions/CLIException.php +++ b/system/CLI/Exceptions/CLIException.php @@ -10,6 +10,6 @@ class CLIException extends \RuntimeException */ public static function forInvalidColor(string $type, string $color) { - return new self(lang('CLI.invalidColor', [$type, $color])); + return new static(lang('CLI.invalidColor', [$type, $color])); } } diff --git a/system/Cache/Exceptions/CacheException.php b/system/Cache/Exceptions/CacheException.php index b5385313b5..538d470d33 100644 --- a/system/Cache/Exceptions/CacheException.php +++ b/system/Cache/Exceptions/CacheException.php @@ -7,7 +7,7 @@ class CacheException extends \RuntimeException implements ExceptionInterface */ public static function forInvalidHandlers() { - return new self(lang('Cache.invalidHandlers')); + return new static(lang('Cache.invalidHandlers')); } /** @@ -15,7 +15,7 @@ class CacheException extends \RuntimeException implements ExceptionInterface */ public static function forNoBackup() { - return new self(lang('Cache.noBackup')); + return new static(lang('Cache.noBackup')); } /** @@ -23,6 +23,6 @@ class CacheException extends \RuntimeException implements ExceptionInterface */ public static function forHandlerNotFound() { - return new self(lang('Cache.handlerNotFound')); + return new static(lang('Cache.handlerNotFound')); } } diff --git a/system/Config/AutoloadConfig.php b/system/Config/AutoloadConfig.php index b75ac52424..96b2787809 100644 --- a/system/Config/AutoloadConfig.php +++ b/system/Config/AutoloadConfig.php @@ -143,10 +143,6 @@ class AutoloadConfig 'CodeIgniter\Debug\Exceptions' => BASEPATH . 'Debug/Exceptions.php', 'CodeIgniter\Debug\Timer' => BASEPATH . 'Debug/Timer.php', 'CodeIgniter\Debug\Iterator' => BASEPATH . 'Debug/Iterator.php', - 'CodeIgniter\Encryption\Encryption' => BASEPATH . 'Encryption/Encryption.php', - 'CodeIgniter\Encryption\EncrypterInterface' => BASEPATH . 'Encryption/EncrypterInterface.php', - 'CodeIgniter\Encryption\Handlers\BaseHandler' => BASEPATH . 'Encryption/Handlers/BaseHandler.php', - 'CodeIgniter\Encryption\Handlers\OpenSSLHandler' => BASEPATH . 'Encryption/Handlers/OpenSSLHandler.php', 'CodeIgniter\Events\Events' => BASEPATH . 'Events/Events.php', 'CodeIgniter\HTTP\CLIRequest' => BASEPATH . 'HTTP/CLIRequest.php', 'CodeIgniter\HTTP\ContentSecurityPolicy' => BASEPATH . 'HTTP/ContentSecurityPolicy.php', diff --git a/system/Database/Exceptions/DataException.php b/system/Database/Exceptions/DataException.php index 65a55dd82b..806139211e 100644 --- a/system/Database/Exceptions/DataException.php +++ b/system/Database/Exceptions/DataException.php @@ -11,7 +11,7 @@ class DataException extends \RuntimeException implements ExceptionInterface */ public static function forInvalidMethodTriggered(string $method) { - return new self(lang('Database.invalidEvent', [$method])); + return new static(lang('Database.invalidEvent', [$method])); } /** @@ -24,7 +24,7 @@ class DataException extends \RuntimeException implements ExceptionInterface */ public static function forEmptyDataset(string $mode) { - return new self(lang('Database.emptyDataset', [$mode])); + return new static(lang('Database.emptyDataset', [$mode])); } /** @@ -38,11 +38,11 @@ class DataException extends \RuntimeException implements ExceptionInterface */ public static function forInvalidArgument(string $argument) { - return new self(lang('Database.invalidArgument', [$argument])); + return new static(lang('Database.invalidArgument', [$argument])); } public static function forInvalidAllowedFields(string $model) { - return new self(lang('Database.invalidAllowedFields', [$model])); + return new static(lang('Database.invalidAllowedFields', [$model])); } } diff --git a/system/Exceptions/ConfigException.php b/system/Exceptions/ConfigException.php index b41bca365f..038a7b52fe 100644 --- a/system/Exceptions/ConfigException.php +++ b/system/Exceptions/ConfigException.php @@ -14,16 +14,16 @@ class ConfigException extends CriticalError public static function forMissingMigrationsTable() { - throw new self(lang('Migrations.missingTable')); + throw new static(lang('Migrations.missingTable')); } public static function forInvalidMigrationType(string $type = null) { - throw new self(lang('Migrations.invalidType', [$type])); + throw new static(lang('Migrations.invalidType', [$type])); } public static function forDisabledMigrations() { - throw new self(lang('Migrations.disabled')); + throw new static(lang('Migrations.disabled')); } } diff --git a/system/Exceptions/FrameworkException.php b/system/Exceptions/FrameworkException.php index 8dd95a4ab3..f3ceb9ad47 100644 --- a/system/Exceptions/FrameworkException.php +++ b/system/Exceptions/FrameworkException.php @@ -12,26 +12,26 @@ class FrameworkException extends \RuntimeException implements ExceptionInterface { public static function forEmptyBaseURL(): self { - return new self('You have an empty or invalid base URL. The baseURL value must be set in Config\App.php, or through the .env file.'); + return new static('You have an empty or invalid base URL. The baseURL value must be set in Config\App.php, or through the .env file.'); } public static function forInvalidFile(string $path) { - return new self(lang('Core.invalidFile', [$path])); + return new static(lang('Core.invalidFile', [$path])); } public static function forCopyError() { - return new self(lang('Core.copyError')); + return new static(lang('Core.copyError')); } public static function forMissingExtension(string $extension) { - return new self(lang('Core.missingExtension', [$extension])); + return new static(lang('Core.missingExtension', [$extension])); } public static function forNoHandlers(string $class) { - return new self(lang('Core.noHandlers', [$class])); + return new static(lang('Core.noHandlers', [$class])); } } diff --git a/system/Exceptions/PageNotFoundException.php b/system/Exceptions/PageNotFoundException.php index 32f282a856..8e6807f341 100644 --- a/system/Exceptions/PageNotFoundException.php +++ b/system/Exceptions/PageNotFoundException.php @@ -10,21 +10,21 @@ class PageNotFoundException extends \OutOfBoundsException implements ExceptionIn public static function forPageNotFound() { - return new self(lang('HTTP.pageNotFound')); + return new static(lang('HTTP.pageNotFound')); } public static function forEmptyController() { - return new self(lang('HTTP.emptyController')); + return new static(lang('HTTP.emptyController')); } public static function forControllerNotFound(string $controller, string $method) { - return new self(lang('HTTP.controllerNotFound', [$controller, $method])); + return new static(lang('HTTP.controllerNotFound', [$controller, $method])); } public static function forMethodNotFound(string $method) { - return new self(lang('HTTP.methodNotFound', [$method])); + return new static(lang('HTTP.methodNotFound', [$method])); } } diff --git a/system/Files/Exceptions/FileException.php b/system/Files/Exceptions/FileException.php index 31c46d690f..e8950abc16 100644 --- a/system/Files/Exceptions/FileException.php +++ b/system/Files/Exceptions/FileException.php @@ -7,7 +7,7 @@ class FileException extends \RuntimeException implements ExceptionInterface public static function forUnableToMove(string $from = null, string $to = null, string $error = null) { - return new self(lang('Files.cannotMove', [$from, $to, $error])); + return new static(lang('Files.cannotMove', [$from, $to, $error])); } } diff --git a/system/Files/Exceptions/FileNotFoundException.php b/system/Files/Exceptions/FileNotFoundException.php index b13f7f5009..987bf52b9d 100644 --- a/system/Files/Exceptions/FileNotFoundException.php +++ b/system/Files/Exceptions/FileNotFoundException.php @@ -6,6 +6,6 @@ class FileNotFoundException extends \RuntimeException implements ExceptionInterf { public static function forFileNotFound(string $path) { - return new self(lang('Files.fileNotFound', [$path])); + return new static(lang('Files.fileNotFound', [$path])); } } diff --git a/system/Files/File.php b/system/Files/File.php index ed98e97968..43a2d2f514 100644 --- a/system/Files/File.php +++ b/system/Files/File.php @@ -99,7 +99,7 @@ class File extends SplFileInfo return number_format(($this->size / 1024) / 1024, 3); } - return $this->size; + return (int) $this->size; } //-------------------------------------------------------------------- diff --git a/system/Filters/Exceptions/FilterException.php b/system/Filters/Exceptions/FilterException.php index 3805633a60..b2aba94bf6 100644 --- a/system/Filters/Exceptions/FilterException.php +++ b/system/Filters/Exceptions/FilterException.php @@ -7,11 +7,11 @@ class FilterException extends ConfigException implements ExceptionInterface { public static function forNoAlias(string $alias) { - return new self(lang('Filters.noFilter', [$alias])); + return new static(lang('Filters.noFilter', [$alias])); } public static function forIncorrectInterface(string $class) { - return new self(lang('Filters.incorrectInterface', [$class])); + return new static(lang('Filters.incorrectInterface', [$class])); } } diff --git a/system/Format/Exceptions/FormatException.php b/system/Format/Exceptions/FormatException.php index 636ee60dd3..442be8f3e2 100644 --- a/system/Format/Exceptions/FormatException.php +++ b/system/Format/Exceptions/FormatException.php @@ -6,12 +6,12 @@ class FormatException extends \RuntimeException implements ExceptionInterface { public static function forInvalidJSON(string $error = null) { - return new self(lang('Format.invalidJSON', [$error])); + return new static(lang('Format.invalidJSON', [$error])); } public static function forMissingExtension() { - return new self(lang('Format.missingExtension')); + return new static(lang('Format.missingExtension')); } } diff --git a/system/HTTP/Exceptions/HTTPException.php b/system/HTTP/Exceptions/HTTPException.php index f0b0b2e6b8..a8f2ae4642 100644 --- a/system/HTTP/Exceptions/HTTPException.php +++ b/system/HTTP/Exceptions/HTTPException.php @@ -12,7 +12,7 @@ class HTTPException extends FrameworkException implements ExceptionInterface */ public static function forMissingCurl() { - return new self(lang('HTTP.missingCurl')); + return new static(lang('HTTP.missingCurl')); } /** @@ -24,7 +24,7 @@ class HTTPException extends FrameworkException implements ExceptionInterface */ public static function forSSLCertNotFound(string $cert) { - return new self(lang('HTTP.sslCertNotFound', [$cert])); + return new static(lang('HTTP.sslCertNotFound', [$cert])); } /** @@ -36,7 +36,7 @@ class HTTPException extends FrameworkException implements ExceptionInterface */ public static function forInvalidSSLKey(string $key) { - return new self(lang('HTTP.invalidSSLKey', [$key])); + return new static(lang('HTTP.invalidSSLKey', [$key])); } /** @@ -49,7 +49,7 @@ class HTTPException extends FrameworkException implements ExceptionInterface */ public static function forCurlError(string $errorNum, string $error) { - return new self(lang('HTTP.curlError', [$errorNum, $error])); + return new static(lang('HTTP.curlError', [$errorNum, $error])); } /** @@ -61,7 +61,7 @@ class HTTPException extends FrameworkException implements ExceptionInterface */ public static function forInvalidNegotiationType(string $type) { - return new self(lang('HTTP.invalidNegotiationType', [$type])); + return new static(lang('HTTP.invalidNegotiationType', [$type])); } /** @@ -73,7 +73,7 @@ class HTTPException extends FrameworkException implements ExceptionInterface */ public static function forInvalidHTTPProtocol(string $protocols) { - return new self(lang('HTTP.invalidHTTPProtocol', [$protocols])); + return new static(lang('HTTP.invalidHTTPProtocol', [$protocols])); } /** @@ -83,7 +83,7 @@ class HTTPException extends FrameworkException implements ExceptionInterface */ public static function forEmptySupportedNegotiations() { - return new self(lang('HTTP.emptySupportedNegotiations')); + return new static(lang('HTTP.emptySupportedNegotiations')); } /** @@ -95,7 +95,7 @@ class HTTPException extends FrameworkException implements ExceptionInterface */ public static function forInvalidRedirectRoute(string $route) { - return new self(lang('HTTP.invalidRoute', [$route])); + return new static(lang('HTTP.invalidRoute', [$route])); } /** @@ -105,7 +105,7 @@ class HTTPException extends FrameworkException implements ExceptionInterface */ public static function forMissingResponseStatus() { - return new self(lang('HTTP.missingResponseStatus')); + return new static(lang('HTTP.missingResponseStatus')); } /** @@ -117,7 +117,7 @@ class HTTPException extends FrameworkException implements ExceptionInterface */ public static function forInvalidStatusCode(int $code) { - return new self(lang('HTTP.invalidStatusCode', [$code])); + return new static(lang('HTTP.invalidStatusCode', [$code])); } /** @@ -129,7 +129,7 @@ class HTTPException extends FrameworkException implements ExceptionInterface */ public static function forUnkownStatusCode(int $code) { - return new self(lang('HTTP.unknownStatusCode', [$code])); + return new static(lang('HTTP.unknownStatusCode', [$code])); } /** @@ -141,7 +141,7 @@ class HTTPException extends FrameworkException implements ExceptionInterface */ public static function forUnableToParseURI(string $uri) { - return new self(lang('HTTP.cannotParseURI', [$uri])); + return new static(lang('HTTP.cannotParseURI', [$uri])); } /** @@ -153,7 +153,7 @@ class HTTPException extends FrameworkException implements ExceptionInterface */ public static function forURISegmentOutOfRange(int $segment) { - return new self(lang('HTTP.segmentOutOfRange', [$segment])); + return new static(lang('HTTP.segmentOutOfRange', [$segment])); } /** @@ -165,7 +165,7 @@ class HTTPException extends FrameworkException implements ExceptionInterface */ public static function forInvalidPort(int $port) { - return new self(lang('HTTP.invalidPort', [$port])); + return new static(lang('HTTP.invalidPort', [$port])); } /** @@ -175,6 +175,6 @@ class HTTPException extends FrameworkException implements ExceptionInterface */ public static function forMalformedQueryString() { - return new self(lang('HTTP.malformedQueryString')); + return new static(lang('HTTP.malformedQueryString')); } } diff --git a/system/I18n/Exceptions/I18nException.php b/system/I18n/Exceptions/I18nException.php index 0056ac6e4c..2c50055170 100644 --- a/system/I18n/Exceptions/I18nException.php +++ b/system/I18n/Exceptions/I18nException.php @@ -7,26 +7,26 @@ class I18nException extends FrameworkException implements ExceptionInterface { public static function forInvalidMonth(string $month) { - return new self(lang('Time.invalidMonth', [$month])); + return new static(lang('Time.invalidMonth', [$month])); } public static function forInvalidDay(string $day) { - return new self(lang('Time.invalidDay', [$day])); + return new static(lang('Time.invalidDay', [$day])); } public static function forInvalidHour(string $hour) { - return new self(lang('Time.invalidHour', [$hour])); + return new static(lang('Time.invalidHour', [$hour])); } public static function forInvalidMinutes(string $minutes) { - return new self(lang('Time.invalidMinutes', [$minutes])); + return new static(lang('Time.invalidMinutes', [$minutes])); } public static function forInvalidSeconds(string $seconds) { - return new self(lang('Time.invalidSeconds', [$seconds])); + return new static(lang('Time.invalidSeconds', [$seconds])); } } diff --git a/system/Images/Exceptions/ImageException.php b/system/Images/Exceptions/ImageException.php index 583e80b1a2..cf8d355d24 100644 --- a/system/Images/Exceptions/ImageException.php +++ b/system/Images/Exceptions/ImageException.php @@ -7,36 +7,36 @@ class ImageException extends FrameworkException implements ExceptionInterface { public static function forMissingAngle() { - return new self(lang('Images.rotationAngleRequired')); + return new static(lang('Images.rotationAngleRequired')); } public static function forInvalidDirection(string $dir = null) { - return new self(lang('Images.invalidDirection', [$dir])); + return new static(lang('Images.invalidDirection', [$dir])); } public static function forEXIFUnsupported() { - return new self(lang('Images.exifNotSupported')); + return new static(lang('Images.exifNotSupported')); } public static function forInvalidImageCreate(string $extra = null) { - return new self(lang('Images.unsupportedImagecreate').' '.$extra); + return new static(lang('Images.unsupportedImagecreate').' '.$extra); } public static function forSaveFailed() { - return new self(lang('Images.saveFailed')); + return new static(lang('Images.saveFailed')); } public static function forInvalidImageLibraryPath(string $path = null) { - return new self(lang('Images.libPathInvalid', [$path])); + return new static(lang('Images.libPathInvalid', [$path])); } public static function forImageProcessFailed() { - return new self(lang('Images.imageProcessFailed')); + return new static(lang('Images.imageProcessFailed')); } } diff --git a/system/Log/Exceptions/LogException.php b/system/Log/Exceptions/LogException.php index e32419e8c6..1768efd76e 100644 --- a/system/Log/Exceptions/LogException.php +++ b/system/Log/Exceptions/LogException.php @@ -7,7 +7,7 @@ class LogException extends FrameworkException implements ExceptionInterface { public static function forInvalidLogLevel(string $level) { - return new self(lang('Log.invalidLogLevel', [$level])); + return new static(lang('Log.invalidLogLevel', [$level])); } diff --git a/system/Log/Handlers/ChromeLoggerHandler.php b/system/Log/Handlers/ChromeLoggerHandler.php index 98cf26e215..ebf94723f4 100644 --- a/system/Log/Handlers/ChromeLoggerHandler.php +++ b/system/Log/Handlers/ChromeLoggerHandler.php @@ -149,7 +149,7 @@ class ChromeLoggerHandler extends BaseHandler implements HandlerInterface // Default to 'log' type. $type = ''; - if (in_array($level, $this->levels)) + if (array_key_exists($level, $this->levels)) { $type = $this->levels[$level]; } diff --git a/system/Pager/Exceptions/PagerException.php b/system/Pager/Exceptions/PagerException.php index 55689dfad9..239d7939e9 100644 --- a/system/Pager/Exceptions/PagerException.php +++ b/system/Pager/Exceptions/PagerException.php @@ -7,11 +7,11 @@ class PagerException extends FrameworkException implements ExceptionInterface { public static function forInvalidTemplate(string $template=null) { - return new self(lang('Pager.invalidTemplate', [$template])); + return new static(lang('Pager.invalidTemplate', [$template])); } public static function forInvalidPaginationGroup(string $group = null) { - return new self(lang('Pager.invalidPaginationGroup', [$group])); + return new static(lang('Pager.invalidPaginationGroup', [$group])); } } diff --git a/system/Router/Exceptions/RouterException.php b/system/Router/Exceptions/RouterException.php index 0a18400398..7117c55f8f 100644 --- a/system/Router/Exceptions/RouterException.php +++ b/system/Router/Exceptions/RouterException.php @@ -7,11 +7,11 @@ class RouterException extends FrameworkException implements ExceptionInterface { public static function forInvalidParameterType() { - return new self(lang('Router.invalidParameterType')); + return new static(lang('Router.invalidParameterType')); } public static function forMissingDefaultRoute() { - return new self(lang('Router.missingDefaultRoute')); + return new static(lang('Router.missingDefaultRoute')); } } diff --git a/system/Security/Exceptions/SecurityException.php b/system/Security/Exceptions/SecurityException.php index 80a70e9164..dda6a9d5da 100644 --- a/system/Security/Exceptions/SecurityException.php +++ b/system/Security/Exceptions/SecurityException.php @@ -7,6 +7,6 @@ class SecurityException extends FrameworkException implements ExceptionInterface { public static function forDisallowedAction() { - return new self(lang('HTTP.disallowedAction'), 403); + return new static(lang('HTTP.disallowedAction'), 403); } } diff --git a/system/Session/Exceptions/SessionException.php b/system/Session/Exceptions/SessionException.php index 00b92d6f83..f4733c0ef7 100644 --- a/system/Session/Exceptions/SessionException.php +++ b/system/Session/Exceptions/SessionException.php @@ -7,26 +7,26 @@ class SessionException extends FrameworkException implements ExceptionInterface { public static function forMissingDatabaseTable() { - return new self(lang('Session.missingDatabaseTable')); + return new static(lang('Session.missingDatabaseTable')); } public static function forInvalidSavePath(string $path = null) { - return new self(lang('Session.invalidSavePath', [$path])); + return new static(lang('Session.invalidSavePath', [$path])); } public static function forWriteProtectedSavePath(string $path = null) { - return new self(lang('Session.writeProtectedSavePath', [$path])); + return new static(lang('Session.writeProtectedSavePath', [$path])); } public static function forEmptySavepath() { - return new self(lang('Session.emptySavePath')); + return new static(lang('Session.emptySavePath')); } public static function forInvalidSavePathFormat(string $path) { - return new self(lang('Session.invalidSavePathFormat', [$path])); + return new static(lang('Session.invalidSavePathFormat', [$path])); } } diff --git a/system/Validation/Exceptions/ValidationException.php b/system/Validation/Exceptions/ValidationException.php index f014fdc9c0..0bb6c1ad96 100644 --- a/system/Validation/Exceptions/ValidationException.php +++ b/system/Validation/Exceptions/ValidationException.php @@ -7,26 +7,26 @@ class ValidationException extends FrameworkException implements ExceptionInterfa { public static function forRuleNotFound(string $rule = null) { - return new self(lang('Validation.ruleNotFound', [$rule])); + return new static(lang('Validation.ruleNotFound', [$rule])); } public static function forGroupNotFound(string $group = null) { - return new self(lang('Validation.groupNotFound', [$group])); + return new static(lang('Validation.groupNotFound', [$group])); } public static function forGroupNotArray(string $group = null) { - return new self(lang('Validation.groupNotArray', [$group])); + return new static(lang('Validation.groupNotArray', [$group])); } public static function forInvalidTemplate(string $template = null) { - return new self(lang('Validation.invalidTemplate', [$template])); + return new static(lang('Validation.invalidTemplate', [$template])); } public static function forNoRuleSets() { - return new self(lang('Validation.noRuleSets')); + return new static(lang('Validation.noRuleSets')); } } diff --git a/system/Validation/FileRules.php b/system/Validation/FileRules.php index 4ae268d2ba..543ff363ee 100644 --- a/system/Validation/FileRules.php +++ b/system/Validation/FileRules.php @@ -85,13 +85,16 @@ class FileRules return $file->getError() === 0; } + // Note: cannot unit test this; no way to over-ride ENVIRONMENT? + // @codeCoverageIgnoreStart return $file->isValid(); + // @codeCoverageIgnoreEnd } //-------------------------------------------------------------------- /** - * Verifies if the file's size in Kilobytes is larger than the parameter. + * Verifies if the file's size in Kilobytes is no larger than the parameter. * * @param string|null $blank * @param string $params @@ -112,8 +115,7 @@ class FileRules { return false; } - - return $params[0] > $file->getSize('kb'); + return $params[0] >= $file->getSize('kb'); } //-------------------------------------------------------------------- @@ -174,7 +176,7 @@ class FileRules return false; } - return in_array($file->getType(), $params); + return in_array($file->getMimeType(), $params); } //-------------------------------------------------------------------- diff --git a/system/Validation/FormatRules.php b/system/Validation/FormatRules.php index ca2e854e38..4b5fea2dce 100644 --- a/system/Validation/FormatRules.php +++ b/system/Validation/FormatRules.php @@ -334,11 +334,7 @@ class FormatRules } elseif (preg_match('/^(?:([^:]*)\:)?\/\/(.+)$/', $str, $matches)) { - if (empty($matches[2])) - { - return false; - } - elseif ( ! in_array($matches[1], ['http', 'https'], true)) + if ( ! in_array($matches[1], ['http', 'https'], true)) { return false; } @@ -370,8 +366,7 @@ class FormatRules $date = \DateTime::createFromFormat($format, $str); - return (bool) $date && \DateTime::getLastErrors()['warning_count'] === 0 - && \DateTime::getLastErrors()['error_count'] === 0; + return (bool) $date && \DateTime::getLastErrors()['warning_count'] === 0 && \DateTime::getLastErrors()['error_count'] === 0; } //-------------------------------------------------------------------- diff --git a/system/Validation/Validation.php b/system/Validation/Validation.php index 2608d2933e..a2b4659fb9 100644 --- a/system/Validation/Validation.php +++ b/system/Validation/Validation.php @@ -204,7 +204,7 @@ class Validation implements ValidationInterface { // and the current field does not exists in the input data // we can return true. Ignoring all other rules to this field. - if (! array_key_exists($field, $data)) + if ( ! array_key_exists($field, $data)) { return true; } @@ -214,7 +214,7 @@ class Validation implements ValidationInterface if (in_array('permit_empty', $rules)) { - if (! in_array('required', $rules) && (is_array($value) ? empty($value) : (trim($value) === ''))) + if ( ! in_array('required', $rules) && (is_array($value) ? empty($value) : (trim($value) === ''))) { return true; } @@ -332,8 +332,8 @@ class Validation implements ValidationInterface public function setRule(string $field, string $label = null, string $rules, array $errors = []) { $this->rules[$field] = [ - 'label' => $label, - 'rules' => $rules, + 'label' => $label, + 'rules' => $rules, ]; $this->customErrors = array_merge($this->customErrors, [ $field => $errors @@ -615,6 +615,11 @@ class Validation implements ValidationInterface * ] * * @return array + * + * Excluded from code coverage because that it always run as cli + * + * @codeCoverageIgnore + * */ public function getErrors(): array { diff --git a/system/View/Exceptions/ViewException.php b/system/View/Exceptions/ViewException.php index cdba67111b..d5d57f5278 100644 --- a/system/View/Exceptions/ViewException.php +++ b/system/View/Exceptions/ViewException.php @@ -7,31 +7,31 @@ class ViewException extends FrameworkException implements ExceptionInterface { public static function forInvalidCellMethod(string $class, string $method) { - return new self(lang('View.invalidCellMethod', ['class' => $class, 'method' => $method])); + return new static(lang('View.invalidCellMethod', ['class' => $class, 'method' => $method])); } public static function forMissingCellParameters(string $class, string $method) { - return new self(lang('View.missingCellParameters', ['class' => $class, 'method' => $method])); + return new static(lang('View.missingCellParameters', ['class' => $class, 'method' => $method])); } public static function forInvalidCellParameter(string $key) { - return new self(lang('View.invalidCellParameter', [$key])); + return new static(lang('View.invalidCellParameter', [$key])); } public static function forNoCellClass() { - return new self(lang('View.noCellClass')); + return new static(lang('View.noCellClass')); } public static function forInvalidCellClass(string $class = null) { - return new self(lang('View.invalidCellClass', [$class])); + return new static(lang('View.invalidCellClass', [$class])); } public static function forTagSyntaxError(string $output) { - return new self(lang('View.tagSyntaxError', [$output])); + return new static(lang('View.tagSyntaxError', [$output])); } } diff --git a/tests/_support/Config/MockLogger.php b/tests/_support/Config/MockLogger.php index 7517ce35a6..793362d881 100644 --- a/tests/_support/Config/MockLogger.php +++ b/tests/_support/Config/MockLogger.php @@ -3,94 +3,94 @@ class MockLogger { /* - |-------------------------------------------------------------------------- - | Error Logging Threshold - |-------------------------------------------------------------------------- - | - | You can enable error logging by setting a threshold over zero. The - | threshold determines what gets logged. Any values below or equal to the - | threshold will be logged. Threshold options are: - | - | 0 = Disables logging, Error logging TURNED OFF - | 1 = Emergency Messages - System is unusable - | 2 = Alert Messages - Action Must Be Taken Immediately - | 3 = Critical Messages - Application component unavailable, unexpected exception. - | 4 = Runtime Errors - Don't need immediate action, but should be monitored. - | 5 = Warnings - Exceptional occurrences that are not errors. - | 6 = Notices - Normal but significant events. - | 7 = Info - Interesting events, like user logging in, etc. - | 8 = Debug - Detailed debug information. - | 9 = All Messages - | - | You can also pass an array with threshold levels to show individual error types - | - | array(1, 2, 3, 8) = Emergency, Alert, Critical, and Debug messages - | - | For a live site you'll usually enable Critical or higher (3) to be logged otherwise - | your log files will fill up very fast. - | - */ + |-------------------------------------------------------------------------- + | Error Logging Threshold + |-------------------------------------------------------------------------- + | + | You can enable error logging by setting a threshold over zero. The + | threshold determines what gets logged. Any values below or equal to the + | threshold will be logged. Threshold options are: + | + | 0 = Disables logging, Error logging TURNED OFF + | 1 = Emergency Messages - System is unusable + | 2 = Alert Messages - Action Must Be Taken Immediately + | 3 = Critical Messages - Application component unavailable, unexpected exception. + | 4 = Runtime Errors - Don't need immediate action, but should be monitored. + | 5 = Warnings - Exceptional occurrences that are not errors. + | 6 = Notices - Normal but significant events. + | 7 = Info - Interesting events, like user logging in, etc. + | 8 = Debug - Detailed debug information. + | 9 = All Messages + | + | You can also pass an array with threshold levels to show individual error types + | + | array(1, 2, 3, 8) = Emergency, Alert, Critical, and Debug messages + | + | For a live site you'll usually enable Critical or higher (3) to be logged otherwise + | your log files will fill up very fast. + | + */ + public $threshold = 9; /* - |-------------------------------------------------------------------------- - | Error Logging Directory Path - |-------------------------------------------------------------------------- - | - | - | - */ + |-------------------------------------------------------------------------- + | Error Logging Directory Path + |-------------------------------------------------------------------------- + | + | + | + */ public $path = ''; /* - |-------------------------------------------------------------------------- - | Date Format for Logs - |-------------------------------------------------------------------------- - | - | Each item that is logged has an associated date. You can use PHP date - | codes to set your own date formatting - | - */ + |-------------------------------------------------------------------------- + | Date Format for Logs + |-------------------------------------------------------------------------- + | + | Each item that is logged has an associated date. You can use PHP date + | codes to set your own date formatting + | + */ public $dateFormat = 'Y-m-d'; /* - |-------------------------------------------------------------------------- - | Log Handlers - |-------------------------------------------------------------------------- - | - | The logging system supports multiple actions to be taken when something - | is logged. This is done by allowing for multiple Handlers, special classes - | designed to write the log to their chosen destinations, whether that is - | a file on the getServer, a cloud-based service, or even taking actions such - | as emailing the dev team. - | - | Each handler is defined by the class name used for that handler, and it - | MUST implement the CodeIgniter\Log\Handlers\HandlerInterface interface. - | - | The value of each key is an array of configuration items that are sent - | to the constructor of each handler. The only required configuration item - | is the 'handles' element, which must be an array of integer log levels. - | This is most easily handled by using the constants defined in the - | Psr\Log\LogLevel class. - | - | Handlers are executed in the order defined in this array, starting with - | the handler on top and continuing down. - | - */ + |-------------------------------------------------------------------------- + | Log Handlers + |-------------------------------------------------------------------------- + | + | The logging system supports multiple actions to be taken when something + | is logged. This is done by allowing for multiple Handlers, special classes + | designed to write the log to their chosen destinations, whether that is + | a file on the getServer, a cloud-based service, or even taking actions such + | as emailing the dev team. + | + | Each handler is defined by the class name used for that handler, and it + | MUST implement the CodeIgniter\Log\Handlers\HandlerInterface interface. + | + | The value of each key is an array of configuration items that are sent + | to the constructor of each handler. The only required configuration item + | is the 'handles' element, which must be an array of integer log levels. + | This is most easily handled by using the constants defined in the + | Psr\Log\LogLevel class. + | + | Handlers are executed in the order defined in this array, starting with + | the handler on top and continuing down. + | + */ public $handlers = [ - //-------------------------------------------------------------------- // File Handler //-------------------------------------------------------------------- 'Tests\Support\Log\Handlers\TestHandler' => [ - /* * The log levels that this handler will handle. */ 'handles' => ['critical', 'alert', 'emergency', 'debug', - 'error', 'info', 'notice', 'warning'], + 'error', 'info', 'notice', 'warning'], ] ]; + } diff --git a/tests/_support/Log/Handlers/MockChromeHandler.php b/tests/_support/Log/Handlers/MockChromeHandler.php new file mode 100644 index 0000000000..7164e324c1 --- /dev/null +++ b/tests/_support/Log/Handlers/MockChromeHandler.php @@ -0,0 +1,24 @@ +json['rows'][0]; + } + +} diff --git a/tests/_support/Log/Handlers/MockFileHandler.php b/tests/_support/Log/Handlers/MockFileHandler.php new file mode 100644 index 0000000000..b674d175e7 --- /dev/null +++ b/tests/_support/Log/Handlers/MockFileHandler.php @@ -0,0 +1,25 @@ +handles = $config['handles'] ?? []; + $this->destination = $this->path . 'log-' . date('Y-m-d') . '.' . $this->fileExtension; + } + +} \ No newline at end of file diff --git a/tests/_support/Log/Handlers/TestHandler.php b/tests/_support/Log/Handlers/TestHandler.php index 17e6f7375a..b62b47830f 100644 --- a/tests/_support/Log/Handlers/TestHandler.php +++ b/tests/_support/Log/Handlers/TestHandler.php @@ -8,17 +8,8 @@ use CodeIgniter\Log\Handlers\HandlerInterface; * A simple LogHandler that stores the logs in memory. * Only used for testing purposes. */ -class TestHandler implements HandlerInterface +class TestHandler extends \CodeIgniter\Log\Handlers\FileHandler { - /** - * @var array - */ - protected $handles; - - /** - * @var string - */ - protected $dateFormat = 'Y-m-d H:i:s'; /** * Local storage for logs. @@ -26,48 +17,22 @@ class TestHandler implements HandlerInterface */ protected static $logs = []; + /** + * Where would the log be written? + */ //-------------------------------------------------------------------- public function __construct(array $config) { + parent::__construct($config); $this->handles = $config['handles'] ?? []; + $this->destination = $this->path . 'log-' . date('Y-m-d') . '.' . $this->fileExtension; self::$logs = []; } //-------------------------------------------------------------------- - /** - * Checks whether the Handler will handle logging items of this - * log Level. - * - * @param $level - * - * @return bool - */ - public function canHandle(string $level): bool - { - return in_array($level, $this->handles); - } - - //-------------------------------------------------------------------- - - /** - * Stores the date format to use while logging messages. - * - * @param string $format - * - * @return HandlerInterface - */ - public function setDateFormat(string $format) - { - $this->dateFormat = $format; - - return $this; - } - - //-------------------------------------------------------------------- - /** * Handles logging the message. * If the handler returns false, then execution of handlers @@ -83,7 +48,7 @@ class TestHandler implements HandlerInterface { $date = date($this->dateFormat); - self::$logs[] = strtoupper($level).' - '.$date.' --> '.$message; + self::$logs[] = strtoupper($level) . ' - ' . $date . ' --> ' . $message; return true; } @@ -92,10 +57,8 @@ class TestHandler implements HandlerInterface public static function getLogs() { - return self::$logs; + return self::$logs; } //-------------------------------------------------------------------- - - } diff --git a/tests/_support/Log/TestLogger.php b/tests/_support/Log/TestLogger.php index 0c34411109..613398222a 100644 --- a/tests/_support/Log/TestLogger.php +++ b/tests/_support/Log/TestLogger.php @@ -32,7 +32,7 @@ class TestLogger extends Logger foreach ($trace as $row) { - if (! in_array($row['function'], ['log', 'log_message'])) + if ( ! in_array($row['function'], ['log', 'log_message'])) { $file = basename($row['file'] ?? ''); break; @@ -40,9 +40,9 @@ class TestLogger extends Logger } self::$op_logs[] = [ - 'level' => $level, - 'message' => $log_message, - 'file' => $file, + 'level' => $level, + 'message' => $log_message, + 'file' => $file, ]; // Let the parent do it's thing. @@ -63,8 +63,7 @@ class TestLogger extends Logger { foreach (self::$op_logs as $log) { - if (strtolower($log['level']) == strtolower($level) - && $message == $log['message']) + if (strtolower($log['level']) == strtolower($level) && $message == $log['message']) { return true; } @@ -74,5 +73,10 @@ class TestLogger extends Logger } //-------------------------------------------------------------------- + // Expose cleanFileNames() + public function cleanup($file) + { + return $this->cleanFileNames($file); + } } diff --git a/tests/_support/Validation/uploads/phpUxc0ty b/tests/_support/Validation/uploads/phpUxc0ty new file mode 100644 index 0000000000..b2b46dadae Binary files /dev/null and b/tests/_support/Validation/uploads/phpUxc0ty differ diff --git a/tests/feature/HomeTest.php b/tests/feature/HomeTest.php index 46a4ffcc9e..d9ec362632 100644 --- a/tests/feature/HomeTest.php +++ b/tests/feature/HomeTest.php @@ -3,9 +3,7 @@ use CodeIgniter\Test\FeatureTestCase; /** - * This relies on a database connection - * - * @codeCoverageIgnore + * @group DatabaseLive */ class HomeTest extends FeatureTestCase { diff --git a/tests/system/Log/ChromeLoggerHandlerTest.php b/tests/system/Log/ChromeLoggerHandlerTest.php index 49140029b4..e48e286ec3 100644 --- a/tests/system/Log/ChromeLoggerHandlerTest.php +++ b/tests/system/Log/ChromeLoggerHandlerTest.php @@ -1,56 +1,78 @@ handlers['CodeIgniter\Log\Handlers\TestHandler']['handles'] = ['critical']; + $config->handlers['CodeIgniter\Log\Handlers\TestHandler']['handles'] = ['critical']; $logger = new ChromeLoggerHandler($config->handlers['CodeIgniter\Log\Handlers\TestHandler']); - $this->assertFalse($logger->canHandle('foo')); + $this->assertFalse($logger->canHandle('foo')); } - //-------------------------------------------------------------------- + //-------------------------------------------------------------------- - public function testHandle() - { - $config = new LoggerConfig(); - $config->handlers['CodeIgniter\Log\Handlers\TestHandler']['handles'] = ['critical']; + public function testHandle() + { + $config = new LoggerConfig(); + $config->handlers['CodeIgniter\Log\Handlers\TestHandler']['handles'] = ['critical']; $logger = new ChromeLoggerHandler($config->handlers['CodeIgniter\Log\Handlers\TestHandler']); - $this->assertTrue($logger->handle("warning", "This a log test") ); - } + $this->assertTrue($logger->handle("warning", "This a log test")); + } - //-------------------------------------------------------------------- + //-------------------------------------------------------------------- - public function testSendLogs() - { - $config = new LoggerConfig(); - $config->handlers['CodeIgniter\Log\Handlers\TestHandler']['handles'] = ['critical']; + public function testSendLogs() + { + $config = new LoggerConfig(); + $config->handlers['CodeIgniter\Log\Handlers\TestHandler']['handles'] = ['critical']; $logger = new ChromeLoggerHandler($config->handlers['CodeIgniter\Log\Handlers\TestHandler']); - $logger->sendLogs(); + $logger->sendLogs(); - $response = Services::response(null, true); + $response = Services::response(null, true); - $this->assertTrue($response->hasHeader('X-ChromeLogger-Data')); - } + $this->assertTrue($response->hasHeader('X-ChromeLogger-Data')); + } - //-------------------------------------------------------------------- + //-------------------------------------------------------------------- - public function testSetDateFormat() - { - $config = new LoggerConfig(); - $config->handlers['CodeIgniter\Log\Handlers\TestHandler']['handles'] = ['critical']; + public function testSetDateFormat() + { + $config = new LoggerConfig(); + $config->handlers['CodeIgniter\Log\Handlers\TestHandler']['handles'] = ['critical']; $logger = new ChromeLoggerHandler($config->handlers['CodeIgniter\Log\Handlers\TestHandler']); - $result = $logger->setDateFormat('F j, Y'); + $result = $logger->setDateFormat('F j, Y'); + + $this->assertObjectHasAttribute('dateFormat', $result); + $this->assertObjectHasAttribute('dateFormat', $logger); + } + + //-------------------------------------------------------------------- + + public function testObjectMessage() + { + $config = new LoggerConfig(); + $config->handlers['CodeIgniter\Log\Handlers\TestHandler']['handles'] = ['critical']; + + $logger = new MockChromeHandler($config->handlers['CodeIgniter\Log\Handlers\TestHandler']); + $data = new \stdClass(); + $data->code = 123; + $data->explanation = "That's no moon, it's a pumpkin"; + $result = $logger->setDateFormat('F j, Y'); + + $logger->handle('debug', $data); + $peek = $logger->peekaboo(); + + $this->assertEquals($data->explanation, $peek[0]['explanation']); + } - $this->assertObjectHasAttribute('dateFormat', $result); - $this->assertObjectHasAttribute('dateFormat', $logger); - } } diff --git a/tests/system/Log/FileHandlerTest.php b/tests/system/Log/FileHandlerTest.php index d9fb2e8703..f93c289170 100644 --- a/tests/system/Log/FileHandlerTest.php +++ b/tests/system/Log/FileHandlerTest.php @@ -1,17 +1,81 @@ handlers['CodeIgniter\Log\Handlers\TestHandler']['handles'] = ['critical']; + public function setUp() + { + $this->root = vfsStream::setup('root'); + $this->start = $this->root->url() . '/'; + } + + public function testHandle() + { + $config = new LoggerConfig(); + $config->handlers['Tests\Support\Log\Handlers\TestHandler']['handles'] = ['critical']; + + $logger = new FileHandler($config->handlers['Tests\Support\Log\Handlers\TestHandler']); + $logger->setDateFormat("Y-m-d H:i:s:u"); + $this->assertTrue($logger->handle("warning", "This is a test log")); + } + + //-------------------------------------------------------------------- + + public function testBasicHandle() + { + $config = new LoggerConfig(); + $config->path = $this->start . 'charlie/'; + $config->handlers['Tests\Support\Log\Handlers\TestHandler']['handles'] = ['critical']; + $logger = new MockFileHandler($config->handlers['Tests\Support\Log\Handlers\TestHandler']); + $logger->setDateFormat("Y-m-d H:i:s:u"); + $this->assertTrue($logger->handle("warning", "This is a test log")); + } + + public function testHandleCreateFile() + { + $config = new LoggerConfig(); + $config->path = $this->start; + $logger = new MockFileHandler((array) $config); + + $logger->setDateFormat("Y-m-d H:i:s:u"); + $logger->handle("warning", "This is a test log"); + + $expected = 'log-' . date('Y-m-d') . '.php'; + $fp = fopen($config->path . $expected, 'r'); + $line = fgets($fp); + fclose($fp); + + // did the log file get created? + $expectedResult = "\n"; + $this->assertEquals($expectedResult, $line); + } + + public function testHandleDateTimeCorrectly() + { + $config = new LoggerConfig(); + $config->path = $this->start; + $logger = new MockFileHandler((array) $config); + + $logger->setDateFormat('Y-m-d'); + $expected = 'log-' . date('Y-m-d') . '.php'; + + $logger->handle('debug', 'Test message'); + + $fp = fopen($config->path . $expected, 'r'); + $line = fgets($fp); // skip opening PHP tag + $line = fgets($fp); // skip blank line + $line = fgets($fp); // and get the second line + fclose($fp); + + $expectedResult = 'DEBUG - ' . date('Y-m-d') . ' --> Test message'; + $this->assertEquals($expectedResult, substr($line, 0, strlen($expectedResult))); + } - $logger = new FileHandler($config->handlers['CodeIgniter\Log\Handlers\TestHandler']); - $logger->setDateFormat("Y-m-d H:i:s:u"); - $this->assertTrue($logger->handle("warning", "This is a test log") ); - } } diff --git a/tests/system/Log/LoggerTest.php b/tests/system/Log/LoggerTest.php index 9d07a9ea70..da8de297fa 100644 --- a/tests/system/Log/LoggerTest.php +++ b/tests/system/Log/LoggerTest.php @@ -8,6 +8,7 @@ use Tests\Support\Log\Handlers\TestHandler; class LoggerTest extends \CIUnitTestCase { + public function testThrowsExceptionWithBadHandlerSettings() { $config = new LoggerConfig(); @@ -54,7 +55,7 @@ class LoggerTest extends \CIUnitTestCase $logger = new Logger($config); - $expected = 'DEBUG - '.date('Y-m-d').' --> Test message'; + $expected = 'DEBUG - ' . date('Y-m-d') . ' --> Test message'; $logger->log('debug', 'Test message'); @@ -69,7 +70,7 @@ class LoggerTest extends \CIUnitTestCase public function testLogDoesnotLogUnhandledLevels() { $config = new LoggerConfig(); - $config->handlers['Tests\Support\Log\Handlers\TestHandler']['handles'] = ['critical']; + $config->handlers['Tests\Support\Log\Handlers\TestHandler']['handles'] = ['critical']; $logger = new Logger($config); @@ -88,7 +89,7 @@ class LoggerTest extends \CIUnitTestCase $logger = new Logger($config); - $expected = 'DEBUG - '.date('Y-m-d').' --> Test message bar baz'; + $expected = 'DEBUG - ' . date('Y-m-d') . ' --> Test message bar baz'; $logger->log('debug', 'Test message {foo} {bar}', ['foo' => 'bar', 'bar' => 'baz']); @@ -107,7 +108,7 @@ class LoggerTest extends \CIUnitTestCase $logger = new Logger($config); $_POST = ['foo' => 'bar']; - $expected = 'DEBUG - '.date('Y-m-d').' --> Test message $_POST: '. print_r($_POST, true); + $expected = 'DEBUG - ' . date('Y-m-d') . ' --> Test message $_POST: ' . print_r($_POST, true); $logger->log('debug', 'Test message {post_vars}'); @@ -126,7 +127,7 @@ class LoggerTest extends \CIUnitTestCase $logger = new Logger($config); $_GET = ['bar' => 'baz']; - $expected = 'DEBUG - '.date('Y-m-d').' --> Test message $_GET: '. print_r($_GET, true); + $expected = 'DEBUG - ' . date('Y-m-d') . ' --> Test message $_GET: ' . print_r($_GET, true); $logger->log('debug', 'Test message {get_vars}'); @@ -145,7 +146,7 @@ class LoggerTest extends \CIUnitTestCase $logger = new Logger($config); $_SESSION = ['xxx' => 'yyy']; - $expected = 'DEBUG - '.date('Y-m-d').' --> Test message $_SESSION: '. print_r($_SESSION, true); + $expected = 'DEBUG - ' . date('Y-m-d') . ' --> Test message $_SESSION: ' . print_r($_SESSION, true); $logger->log('debug', 'Test message {session_vars}'); @@ -163,7 +164,7 @@ class LoggerTest extends \CIUnitTestCase $logger = new Logger($config); - $expected = 'DEBUG - '.date('Y-m-d').' --> Test message '. ENVIRONMENT; + $expected = 'DEBUG - ' . date('Y-m-d') . ' --> Test message ' . ENVIRONMENT; $logger->log('debug', 'Test message {env}'); @@ -183,7 +184,7 @@ class LoggerTest extends \CIUnitTestCase $_ENV['foo'] = 'bar'; - $expected = 'DEBUG - '.date('Y-m-d').' --> Test message bar'; + $expected = 'DEBUG - ' . date('Y-m-d') . ' --> Test message bar'; $logger->log('debug', 'Test message {env:foo}'); @@ -205,7 +206,7 @@ class LoggerTest extends \CIUnitTestCase // For whatever reason, this will often be the class/function instead of file and line. // Other times it actually returns the line number, so don't look for either - $expected = 'DEBUG - '.date('Y-m-d').' --> Test message LoggerTest'; + $expected = 'DEBUG - ' . date('Y-m-d') . ' --> Test message LoggerTest'; $logger->log('debug', 'Test message {file} {line}'); @@ -217,12 +218,35 @@ class LoggerTest extends \CIUnitTestCase //-------------------------------------------------------------------- + public function testLogInterpolatesExceptions() + { + $config = new LoggerConfig(); + $logger = new Logger($config); + + $expected = 'ERROR - ' . date('Y-m-d') . ' --> [ERROR] These are not the droids you are looking for'; + + try + { + throw new Exception('These are not the droids you are looking for'); + } catch (\Exception $e) + { + $logger->log('error', '[ERROR] {exception}', ['exception' => $e]); + } + + $logs = TestHandler::getLogs(); + + $this->assertCount(1, $logs); + $this->assertTrue(strpos($logs[0], $expected) === 0); + } + + //-------------------------------------------------------------------- + public function testEmergencyLogsCorrectly() { $config = new LoggerConfig(); $logger = new Logger($config); - $expected = 'EMERGENCY - '.date('Y-m-d').' --> Test message'; + $expected = 'EMERGENCY - ' . date('Y-m-d') . ' --> Test message'; $logger->emergency('Test message'); @@ -239,7 +263,7 @@ class LoggerTest extends \CIUnitTestCase $config = new LoggerConfig(); $logger = new Logger($config); - $expected = 'ALERT - '.date('Y-m-d').' --> Test message'; + $expected = 'ALERT - ' . date('Y-m-d') . ' --> Test message'; $logger->alert('Test message'); @@ -256,7 +280,7 @@ class LoggerTest extends \CIUnitTestCase $config = new LoggerConfig(); $logger = new Logger($config); - $expected = 'CRITICAL - '.date('Y-m-d').' --> Test message'; + $expected = 'CRITICAL - ' . date('Y-m-d') . ' --> Test message'; $logger->critical('Test message'); @@ -273,7 +297,7 @@ class LoggerTest extends \CIUnitTestCase $config = new LoggerConfig(); $logger = new Logger($config); - $expected = 'ERROR - '.date('Y-m-d').' --> Test message'; + $expected = 'ERROR - ' . date('Y-m-d') . ' --> Test message'; $logger->error('Test message'); @@ -290,7 +314,7 @@ class LoggerTest extends \CIUnitTestCase $config = new LoggerConfig(); $logger = new Logger($config); - $expected = 'WARNING - '.date('Y-m-d').' --> Test message'; + $expected = 'WARNING - ' . date('Y-m-d') . ' --> Test message'; $logger->warning('Test message'); @@ -307,7 +331,7 @@ class LoggerTest extends \CIUnitTestCase $config = new LoggerConfig(); $logger = new Logger($config); - $expected = 'NOTICE - '.date('Y-m-d').' --> Test message'; + $expected = 'NOTICE - ' . date('Y-m-d') . ' --> Test message'; $logger->notice('Test message'); @@ -324,7 +348,7 @@ class LoggerTest extends \CIUnitTestCase $config = new LoggerConfig(); $logger = new Logger($config); - $expected = 'INFO - '.date('Y-m-d').' --> Test message'; + $expected = 'INFO - ' . date('Y-m-d') . ' --> Test message'; $logger->info('Test message'); @@ -341,7 +365,7 @@ class LoggerTest extends \CIUnitTestCase $config = new LoggerConfig(); $logger = new Logger($config); - $expected = 'DEBUG - '.date('Y-m-d').' --> Test message'; + $expected = 'DEBUG - ' . date('Y-m-d') . ' --> Test message'; $logger->debug('Test message'); @@ -350,4 +374,51 @@ class LoggerTest extends \CIUnitTestCase $this->assertCount(1, $logs); $this->assertEquals($expected, $logs[0]); } + + //-------------------------------------------------------------------- + + public function testLogLevels() + { + $config = new LoggerConfig(); + $logger = new Logger($config); + + $expected = 'DEBUG - ' . date('Y-m-d') . ' --> Test message'; + + $logger->log(5, 'Test message'); + + $logs = TestHandler::getLogs(); + + $this->assertCount(1, $logs); + $this->assertEquals($expected, $logs[0]); + } + + //-------------------------------------------------------------------- + + public function testNonStringMessage() + { + $config = new LoggerConfig(); + $logger = new Logger($config); + + $expected = '[Tests\Support\Log\Handlers\TestHandler]'; + $logger->log(5, $config); + + $logs = TestHandler::getLogs(); + + $this->assertCount(1, $logs); + $this->assertContains($expected, $logs[0]); + } + + //-------------------------------------------------------------------- + + public function testFilenameCleaning() + { + $config = new LoggerConfig(); + $logger = new \Tests\Support\Log\TestLogger($config); + + $ohoh = APPPATH . 'LoggerTest'; + $expected = 'APPPATH/LoggerTest'; + + $this->assertEquals($expected, $logger->cleanup($ohoh)); + } + } diff --git a/tests/system/Validation/CreditCardRulesTest.php b/tests/system/Validation/CreditCardRulesTest.php new file mode 100644 index 0000000000..34a443f397 --- /dev/null +++ b/tests/system/Validation/CreditCardRulesTest.php @@ -0,0 +1,363 @@ + [ + \CodeIgniter\Validation\Rules::class, + \CodeIgniter\Validation\FormatRules::class, + \CodeIgniter\Validation\FileRules::class, + \CodeIgniter\Validation\CreditCardRules::class, + \Tests\Support\Validation\TestRules::class, + ], + 'groupA' => [ + 'foo' => 'required|min_length[5]', + ], + 'groupA_errors' => [ + 'foo' => [ + 'min_length' => 'Shame, shame. Too short.', + ], + ], + ]; + + //-------------------------------------------------------------------- + + public function setUp() + { + parent::setUp(); + $this->validation = new Validation((object) $this->config, \Config\Services::renderer()); + $this->validation->reset(); + + $_FILES = []; + } + + //-------------------------------------------------------------------- + // Credit Card Rules + //-------------------------------------------------------------------- + + /** + * @dataProvider creditCardProvider + * + * @param $type + * @param $number + * @param bool $expected + */ + public function testValidCCNumber($type, $number, $expected = false) + { + $data = [ + 'cc' => $number, + ]; + + $this->validation->setRules([ + 'cc' => "valid_cc_number[{$type}]", + ]); + + $this->assertEquals($expected, $this->validation->run($data)); + } + + //-------------------------------------------------------------------- + + /** + * Cards shown are test cards found around the web. + * + * @see https://www.paypalobjects.com/en_US/vhelp/paypalmanager_help/credit_card_numbers.htm + * + * @return array + */ + public function creditCardProvider() + { + return [ + 'null_test' => ['amex', null, false], + 'random_test' => ['amex', $this->generateCardNum('37', 16), false], + 'invalid_type' => ['shorty', '1111 1111 1111 1111', false], + 'invalid_length' => ['amex', '', false], + 'not_numeric' => ['amex', 'abcd efgh ijkl mnop', false], + 'bad_length' => ['amex', '3782 8224 6310 0051', false], + 'bad_prefix' => ['amex', '3582 8224 6310 0051', false], + 'amex1' => ['amex', '3782 8224 6310 005', true], + 'amex2' => ['amex', '3714 4963 5398 431', true], + 'dinersclub1' => ['dinersclub', '3056 9309 0259 04', true], + 'dinersculb2' => ['dinersclub', '3852 0000 0232 37', true], + 'discover1' => ['discover', '6011 1111 1111 1117', true], + 'discover2' => ['discover', '6011 0009 9013 9424', true], + 'jcb1' => ['jcb', '3530 1113 3330 0000', true], + 'jcb2' => ['jcb', '3566 0020 2036 0505', true], + 'mastercard1' => ['mastercard', '5555 5555 5555 4444', true], + 'mastercard2' => ['mastercard', '5105 1051 0510 5100', true], + 'visa1' => ['visa', '4111 1111 1111 1111', true], + 'visa2' => ['visa', '4012 8888 8888 1881', true], + 'visa3' => ['visa', '4222 2222 2222 2', true], + 'dankort1' => ['dankort', '5019 7170 1010 3742', true], + 'unionpay1' => ['unionpay', $this->generateCardNum(62, 16), true], + 'unionpay2' => ['unionpay', $this->generateCardNum(62, 17), true], + 'unionpay3' => ['unionpay', $this->generateCardNum(62, 18), true], + 'unionpay4' => ['unionpay', $this->generateCardNum(62, 19), true], + 'unionpay5' => ['unionpay', $this->generateCardNum(63, 19), false], + 'carteblanche1' => ['carteblanche', $this->generateCardNum(300, 14), true], + 'carteblanche2' => ['carteblanche', $this->generateCardNum(301, 14), true], + 'carteblanche3' => ['carteblanche', $this->generateCardNum(302, 14), true], + 'carteblanche4' => ['carteblanche', $this->generateCardNum(303, 14), true], + 'carteblanche5' => ['carteblanche', $this->generateCardNum(304, 14), true], + 'carteblanche6' => ['carteblanche', $this->generateCardNum(305, 14), true], + 'carteblanche7' => ['carteblanche', $this->generateCardNum(306, 14), false], + 'dinersclub3' => ['dinersclub', $this->generateCardNum(300, 14), true], + 'dinersclub4' => ['dinersclub', $this->generateCardNum(301, 14), true], + 'dinersclub5' => ['dinersclub', $this->generateCardNum(302, 14), true], + 'dinersclub6' => ['dinersclub', $this->generateCardNum(303, 14), true], + 'dinersclub7' => ['dinersclub', $this->generateCardNum(304, 14), true], + 'dinersclub8' => ['dinersclub', $this->generateCardNum(305, 14), true], + 'dinersclub9' => ['dinersclub', $this->generateCardNum(309, 14), true], + 'dinersclub10' => ['dinersclub', $this->generateCardNum(36, 14), true], + 'dinersclub11' => ['dinersclub', $this->generateCardNum(38, 14), true], + 'dinersclub12' => ['dinersclub', $this->generateCardNum(39, 14), true], + 'dinersclub13' => ['dinersclub', $this->generateCardNum(54, 14), true], + 'dinersclub14' => ['dinersclub', $this->generateCardNum(55, 14), true], + 'dinersclub15' => ['dinersclub', $this->generateCardNum(300, 16), true], + 'dinersclub16' => ['dinersclub', $this->generateCardNum(301, 16), true], + 'dinersclub17' => ['dinersclub', $this->generateCardNum(302, 16), true], + 'dinersclub18' => ['dinersclub', $this->generateCardNum(303, 16), true], + 'dinersclub19' => ['dinersclub', $this->generateCardNum(304, 16), true], + 'dinersclub20' => ['dinersclub', $this->generateCardNum(305, 16), true], + 'dinersclub21' => ['dinersclub', $this->generateCardNum(309, 16), true], + 'dinersclub22' => ['dinersclub', $this->generateCardNum(36, 16), true], + 'dinersclub23' => ['dinersclub', $this->generateCardNum(38, 16), true], + 'dinersclub24' => ['dinersclub', $this->generateCardNum(39, 16), true], + 'dinersclub25' => ['dinersclub', $this->generateCardNum(54, 16), true], + 'dinersclub26' => ['dinersclub', $this->generateCardNum(55, 16), true], + 'discover3' => ['discover', $this->generateCardNum(6011, 16), true], + 'discover4' => ['discover', $this->generateCardNum(622, 16), true], + 'discover5' => ['discover', $this->generateCardNum(644, 16), true], + 'discover6' => ['discover', $this->generateCardNum(645, 16), true], + 'discover7' => ['discover', $this->generateCardNum(656, 16), true], + 'discover8' => ['discover', $this->generateCardNum(647, 16), true], + 'discover9' => ['discover', $this->generateCardNum(648, 16), true], + 'discover10' => ['discover', $this->generateCardNum(649, 16), true], + 'discover11' => ['discover', $this->generateCardNum(65, 16), true], + 'discover12' => ['discover', $this->generateCardNum(6011, 19), true], + 'discover13' => ['discover', $this->generateCardNum(622, 19), true], + 'discover14' => ['discover', $this->generateCardNum(644, 19), true], + 'discover15' => ['discover', $this->generateCardNum(645, 19), true], + 'discover16' => ['discover', $this->generateCardNum(656, 19), true], + 'discover17' => ['discover', $this->generateCardNum(647, 19), true], + 'discover18' => ['discover', $this->generateCardNum(648, 19), true], + 'discover19' => ['discover', $this->generateCardNum(649, 19), true], + 'discover20' => ['discover', $this->generateCardNum(65, 19), true], + 'interpayment1' => ['interpayment', $this->generateCardNum(4, 16), true], + 'interpayment2' => ['interpayment', $this->generateCardNum(4, 17), true], + 'interpayment3' => ['interpayment', $this->generateCardNum(4, 18), true], + 'interpayment4' => ['interpayment', $this->generateCardNum(4, 19), true], + 'jcb1' => ['jcb', $this->generateCardNum(352, 16), true], + 'jcb2' => ['jcb', $this->generateCardNum(353, 16), true], + 'jcb3' => ['jcb', $this->generateCardNum(354, 16), true], + 'jcb4' => ['jcb', $this->generateCardNum(355, 16), true], + 'jcb5' => ['jcb', $this->generateCardNum(356, 16), true], + 'jcb6' => ['jcb', $this->generateCardNum(357, 16), true], + 'jcb7' => ['jcb', $this->generateCardNum(358, 16), true], + 'maestro1' => ['maestro', $this->generateCardNum(50, 12), true], + 'maestro2' => ['maestro', $this->generateCardNum(56, 12), true], + 'maestro3' => ['maestro', $this->generateCardNum(57, 12), true], + 'maestro4' => ['maestro', $this->generateCardNum(58, 12), true], + 'maestro5' => ['maestro', $this->generateCardNum(59, 12), true], + 'maestro6' => ['maestro', $this->generateCardNum(60, 12), true], + 'maestro7' => ['maestro', $this->generateCardNum(61, 12), true], + 'maestro8' => ['maestro', $this->generateCardNum(62, 12), true], + 'maestro9' => ['maestro', $this->generateCardNum(63, 12), true], + 'maestro10' => ['maestro', $this->generateCardNum(64, 12), true], + 'maestro11' => ['maestro', $this->generateCardNum(65, 12), true], + 'maestro12' => ['maestro', $this->generateCardNum(66, 12), true], + 'maestro13' => ['maestro', $this->generateCardNum(67, 12), true], + 'maestro14' => ['maestro', $this->generateCardNum(68, 12), true], + 'maestro15' => ['maestro', $this->generateCardNum(69, 12), true], + 'maestro16' => ['maestro', $this->generateCardNum(50, 13), true], + 'maestro17' => ['maestro', $this->generateCardNum(56, 13), true], + 'maestro18' => ['maestro', $this->generateCardNum(57, 13), true], + 'maestro19' => ['maestro', $this->generateCardNum(58, 13), true], + 'maestro20' => ['maestro', $this->generateCardNum(59, 13), true], + 'maestro21' => ['maestro', $this->generateCardNum(60, 13), true], + 'maestro22' => ['maestro', $this->generateCardNum(61, 13), true], + 'maestro23' => ['maestro', $this->generateCardNum(62, 13), true], + 'maestro24' => ['maestro', $this->generateCardNum(63, 13), true], + 'maestro25' => ['maestro', $this->generateCardNum(64, 13), true], + 'maestro26' => ['maestro', $this->generateCardNum(65, 13), true], + 'maestro27' => ['maestro', $this->generateCardNum(66, 13), true], + 'maestro28' => ['maestro', $this->generateCardNum(67, 13), true], + 'maestro29' => ['maestro', $this->generateCardNum(68, 13), true], + 'maestro30' => ['maestro', $this->generateCardNum(69, 13), true], + 'maestro31' => ['maestro', $this->generateCardNum(50, 14), true], + 'maestro32' => ['maestro', $this->generateCardNum(56, 14), true], + 'maestro33' => ['maestro', $this->generateCardNum(57, 14), true], + 'maestro34' => ['maestro', $this->generateCardNum(58, 14), true], + 'maestro35' => ['maestro', $this->generateCardNum(59, 14), true], + 'maestro36' => ['maestro', $this->generateCardNum(60, 14), true], + 'maestro37' => ['maestro', $this->generateCardNum(61, 14), true], + 'maestro38' => ['maestro', $this->generateCardNum(62, 14), true], + 'maestro39' => ['maestro', $this->generateCardNum(63, 14), true], + 'maestro40' => ['maestro', $this->generateCardNum(64, 14), true], + 'maestro41' => ['maestro', $this->generateCardNum(65, 14), true], + 'maestro42' => ['maestro', $this->generateCardNum(66, 14), true], + 'maestro43' => ['maestro', $this->generateCardNum(67, 14), true], + 'maestro44' => ['maestro', $this->generateCardNum(68, 14), true], + 'maestro45' => ['maestro', $this->generateCardNum(69, 14), true], + 'maestro46' => ['maestro', $this->generateCardNum(50, 15), true], + 'maestro47' => ['maestro', $this->generateCardNum(56, 15), true], + 'maestro48' => ['maestro', $this->generateCardNum(57, 15), true], + 'maestro49' => ['maestro', $this->generateCardNum(58, 15), true], + 'maestro50' => ['maestro', $this->generateCardNum(59, 15), true], + 'maestro51' => ['maestro', $this->generateCardNum(60, 15), true], + 'maestro52' => ['maestro', $this->generateCardNum(61, 15), true], + 'maestro53' => ['maestro', $this->generateCardNum(62, 15), true], + 'maestro54' => ['maestro', $this->generateCardNum(63, 15), true], + 'maestro55' => ['maestro', $this->generateCardNum(64, 15), true], + 'maestro56' => ['maestro', $this->generateCardNum(65, 15), true], + 'maestro57' => ['maestro', $this->generateCardNum(66, 15), true], + 'maestro58' => ['maestro', $this->generateCardNum(67, 15), true], + 'maestro59' => ['maestro', $this->generateCardNum(68, 15), true], + 'maestro60' => ['maestro', $this->generateCardNum(69, 15), true], + 'maestro61' => ['maestro', $this->generateCardNum(50, 16), true], + 'maestro62' => ['maestro', $this->generateCardNum(56, 16), true], + 'maestro63' => ['maestro', $this->generateCardNum(57, 16), true], + 'maestro64' => ['maestro', $this->generateCardNum(58, 16), true], + 'maestro65' => ['maestro', $this->generateCardNum(59, 16), true], + 'maestro66' => ['maestro', $this->generateCardNum(60, 16), true], + 'maestro67' => ['maestro', $this->generateCardNum(61, 16), true], + 'maestro68' => ['maestro', $this->generateCardNum(62, 16), true], + 'maestro69' => ['maestro', $this->generateCardNum(63, 16), true], + 'maestro70' => ['maestro', $this->generateCardNum(64, 16), true], + 'maestro71' => ['maestro', $this->generateCardNum(65, 16), true], + 'maestro72' => ['maestro', $this->generateCardNum(66, 16), true], + 'maestro73' => ['maestro', $this->generateCardNum(67, 16), true], + 'maestro74' => ['maestro', $this->generateCardNum(68, 16), true], + 'maestro75' => ['maestro', $this->generateCardNum(69, 16), true], + 'maestro91' => ['maestro', $this->generateCardNum(50, 18), true], + 'maestro92' => ['maestro', $this->generateCardNum(56, 18), true], + 'maestro93' => ['maestro', $this->generateCardNum(57, 18), true], + 'maestro94' => ['maestro', $this->generateCardNum(58, 18), true], + 'maestro95' => ['maestro', $this->generateCardNum(59, 18), true], + 'maestro96' => ['maestro', $this->generateCardNum(60, 18), true], + 'maestro97' => ['maestro', $this->generateCardNum(61, 18), true], + 'maestro98' => ['maestro', $this->generateCardNum(62, 18), true], + 'maestro99' => ['maestro', $this->generateCardNum(63, 18), true], + 'maestro100' => ['maestro', $this->generateCardNum(64, 18), true], + 'maestro101' => ['maestro', $this->generateCardNum(65, 18), true], + 'maestro102' => ['maestro', $this->generateCardNum(66, 18), true], + 'maestro103' => ['maestro', $this->generateCardNum(67, 18), true], + 'maestro104' => ['maestro', $this->generateCardNum(68, 18), true], + 'maestro105' => ['maestro', $this->generateCardNum(69, 18), true], + 'maestro106' => ['maestro', $this->generateCardNum(50, 19), true], + 'maestro107' => ['maestro', $this->generateCardNum(56, 19), true], + 'maestro108' => ['maestro', $this->generateCardNum(57, 19), true], + 'maestro109' => ['maestro', $this->generateCardNum(58, 19), true], + 'maestro110' => ['maestro', $this->generateCardNum(59, 19), true], + 'maestro111' => ['maestro', $this->generateCardNum(60, 19), true], + 'maestro112' => ['maestro', $this->generateCardNum(61, 19), true], + 'maestro113' => ['maestro', $this->generateCardNum(62, 19), true], + 'maestro114' => ['maestro', $this->generateCardNum(63, 19), true], + 'maestro115' => ['maestro', $this->generateCardNum(64, 19), true], + 'maestro116' => ['maestro', $this->generateCardNum(65, 19), true], + 'maestro117' => ['maestro', $this->generateCardNum(66, 19), true], + 'maestro118' => ['maestro', $this->generateCardNum(67, 19), true], + 'maestro119' => ['maestro', $this->generateCardNum(68, 19), true], + 'maestro120' => ['maestro', $this->generateCardNum(69, 19), true], + 'dankort1' => ['dankort', $this->generateCardNum(5019, 16), true], + 'dankort2' => ['dankort', $this->generateCardNum(4175, 16), true], + 'dankort3' => ['dankort', $this->generateCardNum(4571, 16), true], + 'dankort4' => ['dankort', $this->generateCardNum(4, 16), true], + 'mir1' => ['mir', $this->generateCardNum(2200, 16), true], + 'mir2' => ['mir', $this->generateCardNum(2201, 16), true], + 'mir3' => ['mir', $this->generateCardNum(2202, 16), true], + 'mir4' => ['mir', $this->generateCardNum(2203, 16), true], + 'mir5' => ['mir', $this->generateCardNum(2204, 16), true], + 'mastercard1' => ['mastercard', $this->generateCardNum(51, 16), true], + 'mastercard2' => ['mastercard', $this->generateCardNum(52, 16), true], + 'mastercard3' => ['mastercard', $this->generateCardNum(53, 16), true], + 'mastercard4' => ['mastercard', $this->generateCardNum(54, 16), true], + 'mastercard5' => ['mastercard', $this->generateCardNum(55, 16), true], + 'mastercard6' => ['mastercard', $this->generateCardNum(22, 16), true], + 'mastercard7' => ['mastercard', $this->generateCardNum(23, 16), true], + 'mastercard8' => ['mastercard', $this->generateCardNum(24, 16), true], + 'mastercard9' => ['mastercard', $this->generateCardNum(25, 16), true], + 'mastercard10' => ['mastercard', $this->generateCardNum(26, 16), true], + 'mastercard11' => ['mastercard', $this->generateCardNum(27, 16), true], + 'visa1' => ['visa', $this->generateCardNum(4, 13), true], + 'visa2' => ['visa', $this->generateCardNum(4, 16), true], + 'visa3' => ['visa', $this->generateCardNum(4, 19), true], + 'uatp' => ['uatp', $this->generateCardNum(1, 15), true], + 'verve1' => ['verve', $this->generateCardNum(506, 16), true], + 'verve2' => ['verve', $this->generateCardNum(650, 16), true], + 'verve3' => ['verve', $this->generateCardNum(506, 19), true], + 'verve4' => ['verve', $this->generateCardNum(650, 19), true], + 'cibc1' => ['cibc', $this->generateCardNum(4506, 16), true], + 'rbc1' => ['rbc', $this->generateCardNum(45, 16), true], + 'tdtrust' => ['tdtrust', $this->generateCardNum(589297, 16), true], + 'scotia1' => ['scotia', $this->generateCardNum(4536, 16), true], + 'bmoabm1' => ['bmoabm', $this->generateCardNum(500, 16), true], + 'hsbc' => ['hsbc', $this->generateCardNum(56, 16), true], + 'hsbc' => ['hsbc', $this->generateCardNum(57, 16), false], + ]; + } + + //-------------------------------------------------------------------- + + /** + * Used to generate fake credit card numbers that will still pass the Luhn + * check used to validate the card so we can be sure the cards are recognized correctly. + * + * @param int $prefix + * @param int $length + * + * @return string + */ + protected function generateCardNum(int $prefix, int $length) + { + $pos = mb_strlen($prefix); + $finalDigit = 0; + $sum = 0; + + // Fill in the first values of the string based on $prefix + $string = str_split($prefix); + + // Pad out the array to the appropriate length + $string = array_pad($string, $length, 0); + + // Fill all of the remaining values with random numbers, except the last one. + while ($pos < $length - 1) + { + $string[$pos ++] = random_int(0, 9); + } + + // Calculate the Luhn checksum of the current values. + $lenOffset = ($length + 1) % 2; + for ($pos = 0; $pos < $length - 1; $pos ++ ) + { + if (($pos + $lenOffset) % 2) + { + $temp = $string[$pos] * 2; + if ($temp > 9) + { + $temp -= 9; + } + + $sum += $temp; + } + else + { + $sum += $string[$pos]; + } + } + + // Make the last number whatever would cause the entire number to pass the checksum + $finalDigit = (10 - ($sum % 10)) % 10; + $string[$length - 1] = $finalDigit; + + return implode('', $string); + } + + //-------------------------------------------------------------------- +} diff --git a/tests/system/Validation/FileRulesTest.php b/tests/system/Validation/FileRulesTest.php new file mode 100644 index 0000000000..c292dbbe56 --- /dev/null +++ b/tests/system/Validation/FileRulesTest.php @@ -0,0 +1,209 @@ + [ + \CodeIgniter\Validation\Rules::class, + \CodeIgniter\Validation\FormatRules::class, + \CodeIgniter\Validation\FileRules::class, + \CodeIgniter\Validation\CreditCardRules::class, + \Tests\Support\Validation\TestRules::class, + ], + 'groupA' => [ + 'foo' => 'required|min_length[5]', + ], + 'groupA_errors' => [ + 'foo' => [ + 'min_length' => 'Shame, shame. Too short.', + ], + ], + ]; + + //-------------------------------------------------------------------- + + public function setUp() + { + parent::setUp(); + $this->validation = new Validation((object) $this->config, \Config\Services::renderer()); + $this->validation->reset(); + + $_FILES = [ + 'avatar' => [ + 'tmp_name' => TESTPATH . '_support/Validation/uploads/phpUxc0ty', + 'name' => 'my-avatar.png', + 'size' => 4614, + 'type' => 'image/png', + 'error' => 0, + 'width' => 640, + 'height' => 400, + ] + ]; + } + + //-------------------------------------------------------------------- + + public function testUploadedTrue() + { + $this->validation->setRules([ + 'avatar' => "uploaded[avatar]", + ]); + + $this->assertTrue($this->validation->run([])); + } + + public function testUploadedFalse() + { + $this->validation->setRules([ + 'avatar' => "uploaded[userfile]", + ]); + + $this->assertFalse($this->validation->run([])); + } + + //-------------------------------------------------------------------- + + public function testMaxSize() + { + $this->validation->setRules([ + 'avatar' => "max_size[avatar,100]", + ]); + + $this->assertTrue($this->validation->run([])); + } + + public function testMaxSizeFail() + { + $this->validation->setRules([ + 'avatar' => "max_size[avatar,4]", + ]); + $this->assertFalse($this->validation->run([])); + } + + public function testMaxSizeBad() + { + $this->validation->setRules([ + 'avatar' => "max_size[userfile,50]", + ]); + $this->assertFalse($this->validation->run([])); + } + + //-------------------------------------------------------------------- + + public function testMaxDims() + { + $this->validation->setRules([ + 'avatar' => "max_dims[avatar,640,480]", + ]); + $this->assertTrue($this->validation->run([])); + } + + public function testMaxDimsFail() + { + $this->validation->setRules([ + 'avatar' => "max_dims[avatar,600,480]", + ]); + $this->assertFalse($this->validation->run([])); + } + + public function testMaxDimsBad() + { + $this->validation->setRules([ + 'avatar' => "max_dims[unknown,640,480]", + ]); + $this->assertFalse($this->validation->run([])); + } + + //-------------------------------------------------------------------- + + public function testIsImage() + { + $this->validation->setRules([ + 'avatar' => "is_image[avatar]", + ]); + $this->assertTrue($this->validation->run([])); + } + + public function testIsntImage() + { + $_FILES['stuff'] = [ + 'tmp_name' => TESTPATH . '_support/Validation/uploads/abc77tz', + 'name' => 'address.book', + 'size' => 12345, + 'type' => 'application/address', + 'error' => 0, + ]; + $this->validation->setRules([ + 'avatar' => "is_image[stuff]", + ]); + $this->assertFalse($this->validation->run([])); + } + + public function testAlsoIsntImage() + { + $this->validation->setRules([ + 'avatar' => "is_image[unknown]", + ]); + $this->assertFalse($this->validation->run([])); + } + + //-------------------------------------------------------------------- + + public function testMimeTypeOk() + { + $this->validation->setRules([ + 'avatar' => "mime_in[avatar,image/jpg,image/jpeg,image/gif,image/png]", + ]); + $this->assertTrue($this->validation->run([])); + } + + public function testMimeTypeNotOk() + { + $this->validation->setRules([ + 'avatar' => "mime_in[avatar,application/xls,application/doc,application/ppt]", + ]); + $this->assertFalse($this->validation->run([])); + } + + public function testMimeTypeImpossible() + { + $this->validation->setRules([ + 'avatar' => "mime_in[unknown,application/xls,application/doc,application/ppt]", + ]); + $this->assertFalse($this->validation->run([])); + } + + //-------------------------------------------------------------------- + + public function testExtensionOk() + { + $this->validation->setRules([ + 'avatar' => "ext_in[avatar,jpg,jpeg,gif,png]", + ]); + $this->assertTrue($this->validation->run([])); + } + + public function testExtensionNotOk() + { + $this->validation->setRules([ + 'avatar' => "ext_in[avatar,xls,doc,ppt]", + ]); + $this->assertFalse($this->validation->run([])); + } + + public function testExtensionImpossible() + { + $this->validation->setRules([ + 'avatar' => "ext_in[unknown,xls,doc,ppt]", + ]); + $this->assertFalse($this->validation->run([])); + } + +} diff --git a/tests/system/Validation/FormatRulesTest.php b/tests/system/Validation/FormatRulesTest.php new file mode 100644 index 0000000000..c7e4c1ab46 --- /dev/null +++ b/tests/system/Validation/FormatRulesTest.php @@ -0,0 +1,689 @@ + [ + \CodeIgniter\Validation\Rules::class, + \CodeIgniter\Validation\FormatRules::class, + \CodeIgniter\Validation\FileRules::class, + \CodeIgniter\Validation\CreditCardRules::class, + \Tests\Support\Validation\TestRules::class, + ], + 'groupA' => [ + 'foo' => 'required|min_length[5]', + ], + 'groupA_errors' => [ + 'foo' => [ + 'min_length' => 'Shame, shame. Too short.', + ], + ], + ]; + + //-------------------------------------------------------------------- + + public function setUp() + { + parent::setUp(); + $this->validation = new Validation((object) $this->config, \Config\Services::renderer()); + $this->validation->reset(); + + $_FILES = []; + } + + //-------------------------------------------------------------------- + + public function testRegexMatch() + { + $data = [ + 'foo' => 'abcde', + ]; + + $this->validation->setRules([ + 'foo' => 'regex_match[/[a-z]/]', + ]); + + $this->assertTrue($this->validation->run($data)); + } + + //-------------------------------------------------------------------- + + public function testRegexMatchFalse() + { + $data = [ + 'foo' => 'abcde', + ]; + + $this->validation->setRules([ + 'foo' => 'regex_match[\d]', + ]); + + $this->assertFalse($this->validation->run($data)); + } + + //-------------------------------------------------------------------- + + /** + * @dataProvider urlProvider + */ + public function testValidURL(string $url = null, bool $expected) + { + $data = [ + 'foo' => $url, + ]; + + $this->validation->setRules([ + 'foo' => 'valid_url', + ]); + + $this->assertEquals($expected, $this->validation->run($data)); + } + + //-------------------------------------------------------------------- + + public function urlProvider() + { + return [ + ['www.codeigniter.com', true], + ['http://codeigniter.com', true], + //https://bugs.php.net/bug.php?id=51192 + ['http://accept-dashes.tld', true], + ['http://reject_underscores', false], + // https://github.com/bcit-ci/CodeIgniter/issues/4415 + ['http://[::1]/ipv6', true], + ['htt://www.codeigniter.com', false], + ['', false], + ['code igniter', false], + [null, false], + ['http://', true], // this is apparently valid! + ['http:///oops.com', false], + ['123.com', true], + ['abc.123', true], + ['http:8080//abc.com', true], + ]; + } + + //-------------------------------------------------------------------- + + /** + * @dataProvider emailProviderSingle + * + * @param $email + * @param $expected + */ + public function testValidEmail($email, $expected) + { + $data = [ + 'foo' => $email, + ]; + + $this->validation->setRules([ + 'foo' => 'valid_email', + ]); + + $this->assertEquals($expected, $this->validation->run($data)); + } + + //-------------------------------------------------------------------- + + /** + * @dataProvider emailsProvider + * + * @param $email + * @param $expected + */ + public function testValidEmails($email, $expected) + { + $data = [ + 'foo' => $email, + ]; + + $this->validation->setRules([ + 'foo' => 'valid_emails', + ]); + + $this->assertEquals($expected, $this->validation->run($data)); + } + + //-------------------------------------------------------------------- + + public function emailProviderSingle() + { + return [ + ['email@sample.com', true], + ['valid_email', false], + [null, false], + ]; + } + + //-------------------------------------------------------------------- + + public function emailsProvider() + { + return [ + ['1@sample.com,2@sample.com', true], + ['1@sample.com, 2@sample.com', true], + ['email@sample.com', true], + ['@sample.com,2@sample.com,validemail@email.ca', false], + [null, false] + ]; + } + + //-------------------------------------------------------------------- + + /** + * @dataProvider ipProvider + * + * @param $ip + * @param $which + * @param $expected + */ + public function testValidIP($ip, $which, $expected) + { + $data = [ + 'foo' => $ip, + ]; + + $this->validation->setRules([ + 'foo' => "valid_ip[{$which}]", + ]); + + $this->assertEquals($expected, $this->validation->run($data)); + } + + //-------------------------------------------------------------------- + + public function ipProvider() + { + return [ + ['127.0.0.1', null, true], + ['127.0.0.1', 'ipv4', true], + ['2001:0db8:85a3:0000:0000:8a2e:0370:7334', null, true], + ['2001:0db8:85a3:0000:0000:8a2e:0370:7334', 'ipv6', true], + ['2001:0db8:85a3:0000:0000:8a2e:0370:7334', 'ipv4', false], + ['127.0.0.1', 'ipv6', false], + ['H001:0db8:85a3:0000:0000:8a2e:0370:7334', null, false], + ['127.0.0.259', null, false], + [null, null, false] + ]; + } + + //-------------------------------------------------------------------- + + /** + * @dataProvider alphaProvider + * + * @param $str + * @param $expected + */ + public function testAlpha($str, $expected) + { + $data = [ + 'foo' => $str, + ]; + + $this->validation->setRules([ + 'foo' => "alpha", + ]); + + $this->assertEquals($expected, $this->validation->run($data)); + } + + //-------------------------------------------------------------------- + + public function alphaProvider() + { + return [ + ['abcdefghijklmnopqrstuvwxyzABCDEFGHLIJKLMNOPQRSTUVWXYZ', true], + ['abcdefghijklmnopqrstuvwxyzABCDEFGHLIJKLMNOPQRSTUVWXYZ ', false], + ['abcdefghijklmnopqrstuvwxyzABCDEFGHLIJKLMNOPQRSTUVWXYZ1', false], + ['abcdefghijklmnopqrstuvwxyzABCDEFGHLIJKLMNOPQRSTUVWXYZ*', false], + [null, false], + ]; + } + + //-------------------------------------------------------------------- + + /** + * Test alpha with spaces. + * + * @param mixed $value Value. + * @param bool $expected Expected. + * + * @dataProvider alphaSpaceProvider + */ + public function testAlphaSpace($value, $expected) + { + $data = [ + 'foo' => $value + ]; + + $this->validation->setRules([ + 'foo' => 'alpha_space' + ]); + + $this->assertEquals($expected, $this->validation->run($data)); + } + + //-------------------------------------------------------------------- + + public function alphaSpaceProvider() + { + return [ + [null, true], + ['abcdefghijklmnopqrstuvwxyzABCDEFGHLIJKLMNOPQRSTUVWXYZ', true], + ['abcdefghijklmnopqrstuvwxyzABCDEFGHLIJKLMNOPQRSTUVWXYZ ', true], + ['abcdefghijklmnopqrstuvwxyzABCDEFGHLIJKLMNOPQRSTUVWXYZ1', false], + ['abcdefghijklmnopqrstuvwxyzABCDEFGHLIJKLMNOPQRSTUVWXYZ*', false], + ]; + } + + //-------------------------------------------------------------------- + + /** + * @dataProvider alphaNumericProvider + * + * @param $str + * @param $expected + */ + public function testAlphaNumeric($str, $expected) + { + $data = [ + 'foo' => $str, + ]; + + $this->validation->setRules([ + 'foo' => "alpha_numeric", + ]); + + $this->assertEquals($expected, $this->validation->run($data)); + } + + //-------------------------------------------------------------------- + + public function alphaNumericProvider() + { + return [ + ['abcdefghijklmnopqrstuvwxyzABCDEFGHLIJKLMNOPQRSTUVWXYZ0123456789', true], + ['abcdefghijklmnopqrstuvwxyzABCDEFGHLIJKLMNOPQRSTUVWXYZ0123456789\ ', false], + ['abcdefghijklmnopqrstuvwxyzABCDEFGHLIJKLMNOPQRSTUVWXYZ0123456789_', false], + [null, false], + ]; + } + + //-------------------------------------------------------------------- + + /** + * @dataProvider alphaNumericProvider + * + * @param $str + * @param $expected + */ + public function testAlphaNumericSpace($str, $expected) + { + $data = [ + 'foo' => $str, + ]; + + $this->validation->setRules([ + 'foo' => "alpha_numeric_space", + ]); + + $this->assertEquals($expected, $this->validation->run($data)); + } + + //-------------------------------------------------------------------- + + public function alphaNumericSpaceProvider() + { + return [ + [' abcdefghijklmnopqrstuvwxyzABCDEFGHLIJKLMNOPQRSTUVWXYZ0123456789', true], + [' abcdefghijklmnopqrstuvwxyzABCDEFGHLIJKLMNOPQRSTUVWXYZ0123456789-', false], + [null, false], + ]; + } + + //-------------------------------------------------------------------- + + /** + * @dataProvider alphaDashProvider + * + * @param $str + * @param $expected + */ + public function testAlphaDash($str, $expected) + { + $data = [ + 'foo' => $str, + ]; + + $this->validation->setRules([ + 'foo' => "alpha_dash", + ]); + + $this->assertEquals($expected, $this->validation->run($data)); + } + + //-------------------------------------------------------------------- + + public function alphaDashProvider() + { + return [ + ['abcdefghijklmnopqrstuvwxyzABCDEFGHLIJKLMNOPQRSTUVWXYZ0123456789-', true], + ['abcdefghijklmnopqrstuvwxyzABCDEFGHLIJKLMNOPQRSTUVWXYZ0123456789-\ ', false], + [null, false], + ]; + } + + //-------------------------------------------------------------------- + + /** + * @dataProvider numericProvider + * + * @param $str + * @param $expected + */ + public function testNumeric($str, $expected) + { + $data = [ + 'foo' => $str, + ]; + + $this->validation->setRules([ + 'foo' => "numeric", + ]); + + $this->assertEquals($expected, $this->validation->run($data)); + } + + //-------------------------------------------------------------------- + + public function numericProvider() + { + return [ + ['0', true], + ['12314', true], + ['-42', true], + ['+42', true], + ['123a', false], + ['--1', false], + [null, false] + ]; + } + + //------------------------------------------------------------------- + + /** + * @dataProvider integerProvider + * + * @param $str + * @param $expected + */ + public function testInteger($str, $expected) + { + $data = [ + 'foo' => $str, + ]; + + $this->validation->setRules([ + 'foo' => "integer", + ]); + + $this->assertEquals($expected, $this->validation->run($data)); + } + + //-------------------------------------------------------------------- + + public function integerProvider() + { + return [ + ['0', true], + ['42', true], + ['-1', true], + ['123a', false], + ['1.9', false], + ['--1', false], + [null, false], + ]; + } + + //------------------------------------------------------------------- + + /** + * @dataProvider decimalProvider + * + * @param $str + * @param $expected + */ + public function testDecimal($str, $expected) + { + $data = [ + 'foo' => $str, + ]; + + $this->validation->setRules([ + 'foo' => "decimal", + ]); + + $this->assertEquals($expected, $this->validation->run($data)); + } + + //-------------------------------------------------------------------- + + public function decimalProvider() + { + return [ + ['1.0', true], + ['-0.98', true], + ['0', false], + ['1.0a', false], + ['-i', false], + ['--1', false], + [null, false] + ]; + } + + //------------------------------------------------------------------- + + /** + * @dataProvider naturalProvider + * + * @param $str + * @param $expected + */ + public function testNatural($first, $expected) + { + $data = [ + 'foo' => $first, + ]; + + $this->validation->setRules([ + 'foo' => "is_natural", + ]); + + $this->assertEquals($expected, $this->validation->run($data)); + } + + //-------------------------------------------------------------------- + + public function naturalProvider() + { + return [ + ['0', true], + ['12', true], + ['42a', false], + ['-1', false], + [null, false] + ]; + } + + //------------------------------------------------------------------- + + /** + * @dataProvider naturalZeroProvider + * + * @param $str + * @param $expected + */ + public function testNaturalNoZero($first, $expected) + { + $data = [ + 'foo' => $first, + ]; + + $this->validation->setRules([ + 'foo' => "is_natural_no_zero", + ]); + + $this->assertEquals($expected, $this->validation->run($data)); + } + + //-------------------------------------------------------------------- + + public function naturalZeroProvider() + { + return [ + ['0', false], + ['12', true], + ['42a', false], + ['-1', false], + [null, false] + ]; + } + + //------------------------------------------------------------------- + + /** + * @dataProvider base64Provider + * + * @param $str + * @param $expected + */ + public function testBase64($first, $expected) + { + $data = [ + 'foo' => $first, + ]; + + $this->validation->setRules([ + 'foo' => "valid_base64", + ]); + + $this->assertEquals($expected, $this->validation->run($data)); + } + + //-------------------------------------------------------------------- + + public function base64Provider() + { + return [ + [base64_encode('string'), true], + ['FA08GG', false], + [null, false] + ]; + } + + //------------------------------------------------------------------- + + /** + * @dataProvider timezoneProvider + * + * @param $value + * @param $expected + */ + public function testTimeZone($value, $expected) + { + $data = [ + 'foo' => $value, + ]; + + $this->validation->setRules([ + 'foo' => "timezone", + ]); + + $this->assertEquals($expected, $this->validation->run($data)); + } + + //-------------------------------------------------------------------- + + public function timezoneProvider() + { + return [ + ['America/Chicago', true], + ['america/chicago', false], + ['foo/bar', false], + [null, false] + ]; + } + + //-------------------------------------------------------------------- + + /** + * @dataProvider validDateProvider + * + * @param $str + * @param $format + * @param $expected + */ + public function testValidDate($str, $format, $expected) + { + $data = [ + 'foo' => $str, + ]; + + $this->validation->setRules([ + 'foo' => "valid_date[{$format}]", + ]); + + $this->assertEquals($expected, $this->validation->run($data)); + } + + //-------------------------------------------------------------------- + + public function validDateProvider() + { + return [ + ['Sun', 'D', true], + ['Sun', 'd', false], + ['Sun', null, true], + ['1500', 'Y', true], + ['1500', 'y', false], + ['1500', null, true], + ['09:26:05', 'H:i:s', true], + ['09:26:5', 'H:i:s', false], + ['1992-02-29', 'Y-m-d', true], + ['1991-02-29', 'Y-m-d', false], + ['1718-05-10 15:25:59', 'Y-m-d H:i:s', true], + ['1718-05-10 15:5:59', 'Y-m-d H:i:s', false], + ['Thu, 31 Oct 2013 13:31:00', 'D, d M Y H:i:s', true], + ['Thu, 31 Jun 2013 13:31:00', 'D, d M Y H:i:s', false], + ['Thu, 31 Jun 2013 13:31:00', null, true], + ['07.05.03', 'm.d.y', true], + ['07.05.1803', 'm.d.y', false], + ['19890109', 'Ymd', true], + ['198919', 'Ymd', false], + ['2, 7, 2001', 'j, n, Y', true], + ['2, 17, 2001', 'j, n, Y', false], + ['09-42-25, 12-11-17', 'h-i-s, j-m-y', true], + ['09-42-25, 12-00-17', 'h-i-s, j-m-y', false], + ['09-42-25, 12-00-17', null, false], + ['November 12, 2017, 9:42 am', 'F j, Y, g:i a', true], + ['November 12, 2017, 19:42 am', 'F j, Y, g:i a', false], + ['November 12, 2017, 9:42 am', null, true], + ['Monday 8th of August 2005 03:12:46 PM', 'l jS \of F Y h:i:s A', true], + ['Monday 8th of August 2005 13:12:46 PM', 'l jS \of F Y h:i:s A', false], + ['23:01:59 is now', 'H:m:s \i\s \n\o\w', true], + ['23:01:59 is now', 'H:m:s is now', false], + ['12/11/2017', 'd/m/Y', true], + ]; + } + + //-------------------------------------------------------------------- +} diff --git a/tests/system/Validation/RulesTest.php b/tests/system/Validation/RulesTest.php index 4f8d459f81..414249867f 100644 --- a/tests/system/Validation/RulesTest.php +++ b/tests/system/Validation/RulesTest.php @@ -10,19 +10,18 @@ class RulesTest extends \CIUnitTestCase * @var Validation */ protected $validation; - protected $config = [ - 'ruleSets' => [ + 'ruleSets' => [ \CodeIgniter\Validation\Rules::class, \CodeIgniter\Validation\FormatRules::class, \CodeIgniter\Validation\FileRules::class, \CodeIgniter\Validation\CreditCardRules::class, \Tests\Support\Validation\TestRules::class, ], - 'groupA' => [ + 'groupA' => [ 'foo' => 'required|min_length[5]', ], - 'groupA_errors' => [ + 'groupA_errors' => [ 'foo' => [ 'min_length' => 'Shame, shame. Too short.', ], @@ -189,18 +188,14 @@ class RulesTest extends \CIUnitTestCase [['foo' => 'permit_empty'], ['foo' => 0.0], true], [['foo' => 'permit_empty'], ['foo' => null], true], [['foo' => 'permit_empty'], ['foo' => false], true], - [['foo' => 'permit_empty|valid_email'], ['foo' => ''], true], [['foo' => 'permit_empty|valid_email'], ['foo' => 'user@domain.tld'], true], [['foo' => 'permit_empty|valid_email'], ['foo' => 'invalid'], false], - // Required has more priority [['foo' => 'permit_empty|required|valid_email'], ['foo' => ''], false], - [['foo' => 'permit_empty|required'], ['foo' => ''], false], [['foo' => 'permit_empty|required'], ['foo' => null], false], [['foo' => 'permit_empty|required'], ['foo' => false], false], - // This tests will return true because the input data is trimmed [['foo' => 'permit_empty|required'], ['foo' => '0'], true], [['foo' => 'permit_empty|required'], ['foo' => 0], true], @@ -210,41 +205,11 @@ class RulesTest extends \CIUnitTestCase //-------------------------------------------------------------------- - public function testRegexMatch() - { - $data = [ - 'foo' => 'abcde', - ]; - - $this->validation->setRules([ - 'foo' => 'regex_match[/[a-z]/]', - ]); - - $this->assertTrue($this->validation->run($data)); - } - - //-------------------------------------------------------------------- - - public function testRegexMatchFalse() - { - $data = [ - 'foo' => 'abcde', - ]; - - $this->validation->setRules([ - 'foo' => 'regex_match[\d]', - ]); - - $this->assertFalse($this->validation->run($data)); - } - - //-------------------------------------------------------------------- - public function testMatchesNull() { $data = [ - 'foo' => null, - 'bar' => null, + 'foo' => null, + 'bar' => null, ]; $this->validation->setRules([ @@ -259,8 +224,8 @@ class RulesTest extends \CIUnitTestCase public function testMatchesTrue() { $data = [ - 'foo' => 'match', - 'bar' => 'match', + 'foo' => 'match', + 'bar' => 'match', ]; $this->validation->setRules([ @@ -275,8 +240,8 @@ class RulesTest extends \CIUnitTestCase public function testMatchesFalse() { $data = [ - 'foo' => 'match', - 'bar' => 'nope', + 'foo' => 'match', + 'bar' => 'nope', ]; $this->validation->setRules([ @@ -291,8 +256,8 @@ class RulesTest extends \CIUnitTestCase public function testDiffersNull() { $data = [ - 'foo' => null, - 'bar' => null, + 'foo' => null, + 'bar' => null, ]; $this->validation->setRules([ @@ -307,8 +272,8 @@ class RulesTest extends \CIUnitTestCase public function testDiffersTrue() { $data = [ - 'foo' => 'match', - 'bar' => 'nope', + 'foo' => 'match', + 'bar' => 'nope', ]; $this->validation->setRules([ @@ -323,8 +288,8 @@ class RulesTest extends \CIUnitTestCase public function testDiffersFalse() { $data = [ - 'foo' => 'match', - 'bar' => 'match', + 'foo' => 'match', + 'bar' => 'match', ]; $this->validation->setRules([ @@ -390,9 +355,9 @@ class RulesTest extends \CIUnitTestCase 'email' => 'deva@example.com', ]); $row = $db->table('user') - ->limit(1) - ->get() - ->getRow(); + ->limit(1) + ->get() + ->getRow(); $data = [ 'email' => 'derek@world.co.uk', @@ -587,6 +552,21 @@ class RulesTest extends \CIUnitTestCase //-------------------------------------------------------------------- + public function testExactLengthDetectsBadLength() + { + $data = [ + 'foo' => 'bar', + ]; + + $this->validation->setRules([ + 'foo' => 'exact_length[abc]', + ]); + + $this->assertFalse($this->validation->run($data)); + } + + //-------------------------------------------------------------------- + public function testExactLengthReturnsFalseWhenShort() { $data = [ @@ -615,423 +595,6 @@ class RulesTest extends \CIUnitTestCase $this->assertFalse($this->validation->run($data)); } - //-------------------------------------------------------------------- - - /** - * @dataProvider urlProvider - */ - public function testValidURL(string $url=null, bool $expected) - { - $data = [ - 'foo' => $url, - ]; - - $this->validation->setRules([ - 'foo' => 'valid_url', - ]); - - $this->assertEquals($expected, $this->validation->run($data)); - } - - //-------------------------------------------------------------------- - - public function urlProvider() - { - return [ - ['www.codeigniter.com', true], - ['http://codeigniter.com', true], - //https://bugs.php.net/bug.php?id=51192 - ['http://accept-dashes.tld', true], - ['http://reject_underscores', false], - // https://github.com/bcit-ci/CodeIgniter/issues/4415 - ['http://[::1]/ipv6', true], - ['htt://www.codeigniter.com', false], - ['', false], - ['code igniter', false], - [null, false], - ]; - } - - //-------------------------------------------------------------------- - - /** - * @dataProvider emailProviderSingle - * - * @param $email - * @param $expected - */ - public function testValidEmail($email, $expected) - { - $data = [ - 'foo' => $email, - ]; - - $this->validation->setRules([ - 'foo' => 'valid_email', - ]); - - $this->assertEquals($expected, $this->validation->run($data)); - } - - //-------------------------------------------------------------------- - - /** - * @dataProvider emailProviderSingle - * - * @param $email - * @param $expected - */ - public function testValidEmails($email, $expected) - { - $data = [ - 'foo' => $email, - ]; - - $this->validation->setRules([ - 'foo' => 'valid_emails', - ]); - - $this->assertEquals($expected, $this->validation->run($data)); - } - - //-------------------------------------------------------------------- - - public function emailProviderSingle() - { - return [ - ['email@sample.com', true], - ['valid_email', false], - [null, false], - ]; - } - - //-------------------------------------------------------------------- - - public function emailsProvider() - { - return [ - ['1@sample.com,2@sample.com', true], - ['1@sample.com, 2@sample.com', true], - ['email@sample.com', true], - ['@sample.com,2@sample.com,validemail@email.ca', false], - [null, false] - ]; - } - - //-------------------------------------------------------------------- - - /** - * @dataProvider ipProvider - * - * @param $ip - * @param $which - * @param $expected - */ - public function testValidIP($ip, $which, $expected) - { - $data = [ - 'foo' => $ip, - ]; - - $this->validation->setRules([ - 'foo' => "valid_ip[{$which}]", - ]); - - $this->assertEquals($expected, $this->validation->run($data)); - } - - //-------------------------------------------------------------------- - - public function ipProvider() - { - return [ - ['127.0.0.1', null, true], - ['127.0.0.1', 'ipv4', true], - ['2001:0db8:85a3:0000:0000:8a2e:0370:7334', null, true], - ['2001:0db8:85a3:0000:0000:8a2e:0370:7334', 'ipv6', true], - ['2001:0db8:85a3:0000:0000:8a2e:0370:7334', 'ipv4', false], - ['127.0.0.1', 'ipv6', false], - ['H001:0db8:85a3:0000:0000:8a2e:0370:7334', null, false], - ['127.0.0.259', null, false], - [null, null, false] - ]; - } - - //-------------------------------------------------------------------- - - /** - * @dataProvider alphaProvider - * - * @param $str - * @param $expected - */ - public function testAlpha($str, $expected) - { - $data = [ - 'foo' => $str, - ]; - - $this->validation->setRules([ - 'foo' => "alpha", - ]); - - $this->assertEquals($expected, $this->validation->run($data)); - } - - //-------------------------------------------------------------------- - - public function alphaProvider() - { - return [ - ['abcdefghijklmnopqrstuvwxyzABCDEFGHLIJKLMNOPQRSTUVWXYZ', true], - ['abcdefghijklmnopqrstuvwxyzABCDEFGHLIJKLMNOPQRSTUVWXYZ ', false], - ['abcdefghijklmnopqrstuvwxyzABCDEFGHLIJKLMNOPQRSTUVWXYZ1', false], - ['abcdefghijklmnopqrstuvwxyzABCDEFGHLIJKLMNOPQRSTUVWXYZ*', false], - [null, false], - ]; - } - - //-------------------------------------------------------------------- - - /** - * Test alpha with spaces. - * - * @param mixed $value Value. - * @param bool $expected Expected. - * - * @dataProvider alphaSpaceProvider - */ - public function testAlphaSpace($value, $expected) - { - $data = [ - 'foo' => $value - ]; - - $this->validation->setRules([ - 'foo' => 'alpha_space' - ]); - - $this->assertEquals($expected, $this->validation->run($data)); - } - - //-------------------------------------------------------------------- - - public function alphaSpaceProvider() - { - return [ - [null, true], - ['abcdefghijklmnopqrstuvwxyzABCDEFGHLIJKLMNOPQRSTUVWXYZ', true], - ['abcdefghijklmnopqrstuvwxyzABCDEFGHLIJKLMNOPQRSTUVWXYZ ', true], - ['abcdefghijklmnopqrstuvwxyzABCDEFGHLIJKLMNOPQRSTUVWXYZ1', false], - ['abcdefghijklmnopqrstuvwxyzABCDEFGHLIJKLMNOPQRSTUVWXYZ*', false], - ]; - } - - //-------------------------------------------------------------------- - - /** - * @dataProvider alphaNumericProvider - * - * @param $str - * @param $expected - */ - public function testAlphaNumeric($str, $expected) - { - $data = [ - 'foo' => $str, - ]; - - $this->validation->setRules([ - 'foo' => "alpha_numeric", - ]); - - $this->assertEquals($expected, $this->validation->run($data)); - } - - //-------------------------------------------------------------------- - - public function alphaNumericProvider() - { - return [ - ['abcdefghijklmnopqrstuvwxyzABCDEFGHLIJKLMNOPQRSTUVWXYZ0123456789', true], - ['abcdefghijklmnopqrstuvwxyzABCDEFGHLIJKLMNOPQRSTUVWXYZ0123456789\ ', false], - ['abcdefghijklmnopqrstuvwxyzABCDEFGHLIJKLMNOPQRSTUVWXYZ0123456789_', false], - [null, false], - ]; - } - - //-------------------------------------------------------------------- - - /** - * @dataProvider alphaNumericProvider - * - * @param $str - * @param $expected - */ - public function testAlphaNumericSpace($str, $expected) - { - $data = [ - 'foo' => $str, - ]; - - $this->validation->setRules([ - 'foo' => "alpha_numeric_space", - ]); - - $this->assertEquals($expected, $this->validation->run($data)); - } - - //-------------------------------------------------------------------- - - public function alphaNumericSpaceProvider() - { - return [ - [' abcdefghijklmnopqrstuvwxyzABCDEFGHLIJKLMNOPQRSTUVWXYZ0123456789', true], - [' abcdefghijklmnopqrstuvwxyzABCDEFGHLIJKLMNOPQRSTUVWXYZ0123456789-', false], - [null, false], - ]; - } - - //-------------------------------------------------------------------- - - /** - * @dataProvider alphaDashProvider - * - * @param $str - * @param $expected - */ - public function testAlphaDash($str, $expected) - { - $data = [ - 'foo' => $str, - ]; - - $this->validation->setRules([ - 'foo' => "alpha_dash", - ]); - - $this->assertEquals($expected, $this->validation->run($data)); - } - - //-------------------------------------------------------------------- - - public function alphaDashProvider() - { - return [ - ['abcdefghijklmnopqrstuvwxyzABCDEFGHLIJKLMNOPQRSTUVWXYZ0123456789-', true], - ['abcdefghijklmnopqrstuvwxyzABCDEFGHLIJKLMNOPQRSTUVWXYZ0123456789-\ ', false], - [null, false], - ]; - } - - //-------------------------------------------------------------------- - - /** - * @dataProvider numericProvider - * - * @param $str - * @param $expected - */ - public function testNumeric($str, $expected) - { - $data = [ - 'foo' => $str, - ]; - - $this->validation->setRules([ - 'foo' => "numeric", - ]); - - $this->assertEquals($expected, $this->validation->run($data)); - } - - //-------------------------------------------------------------------- - - public function numericProvider() - { - return [ - ['0', true], - ['12314', true], - ['-42', true], - ['+42', true], - ['123a', false], - ['--1', false], - [null, false] - ]; - } - - //------------------------------------------------------------------- - - /** - * @dataProvider integerProvider - * - * @param $str - * @param $expected - */ - public function testInteger($str, $expected) - { - $data = [ - 'foo' => $str, - ]; - - $this->validation->setRules([ - 'foo' => "integer", - ]); - - $this->assertEquals($expected, $this->validation->run($data)); - } - - //-------------------------------------------------------------------- - - public function integerProvider() - { - return [ - ['0', true], - ['42', true], - ['-1', true], - ['123a', false], - ['1.9', false], - ['--1', false], - [null, false], - ]; - } - - //------------------------------------------------------------------- - - /** - * @dataProvider decimalProvider - * - * @param $str - * @param $expected - */ - public function testDecimal($str, $expected) - { - $data = [ - 'foo' => $str, - ]; - - $this->validation->setRules([ - 'foo' => "decimal", - ]); - - $this->assertEquals($expected, $this->validation->run($data)); - } - - //-------------------------------------------------------------------- - - public function decimalProvider() - { - return [ - ['1.0', true], - ['-0.98', true], - ['0', false], - ['1.0a', false], - ['-i', false], - ['--1', false], - [null, false] - ]; - } - //------------------------------------------------------------------- /** @@ -1214,139 +777,6 @@ class RulesTest extends \CIUnitTestCase ]; } - //------------------------------------------------------------------- - - /** - * @dataProvider naturalProvider - * - * @param $str - * @param $expected - */ - public function testNatural($first, $expected) - { - $data = [ - 'foo' => $first, - ]; - - $this->validation->setRules([ - 'foo' => "is_natural", - ]); - - $this->assertEquals($expected, $this->validation->run($data)); - } - - //-------------------------------------------------------------------- - - public function naturalProvider() - { - return [ - ['0', true], - ['12', true], - ['42a', false], - ['-1', false], - [null, false] - ]; - } - - //------------------------------------------------------------------- - - /** - * @dataProvider naturalZeroProvider - * - * @param $str - * @param $expected - */ - public function testNaturalNoZero($first, $expected) - { - $data = [ - 'foo' => $first, - ]; - - $this->validation->setRules([ - 'foo' => "is_natural_no_zero", - ]); - - $this->assertEquals($expected, $this->validation->run($data)); - } - - //-------------------------------------------------------------------- - - public function naturalZeroProvider() - { - return [ - ['0', false], - ['12', true], - ['42a', false], - ['-1', false], - [null, false] - ]; - } - - //------------------------------------------------------------------- - - /** - * @dataProvider base64Provider - * - * @param $str - * @param $expected - */ - public function testBase64($first, $expected) - { - $data = [ - 'foo' => $first, - ]; - - $this->validation->setRules([ - 'foo' => "valid_base64", - ]); - - $this->assertEquals($expected, $this->validation->run($data)); - } - - //-------------------------------------------------------------------- - - public function base64Provider() - { - return [ - [base64_encode('string'), true], - ['FA08GG', false], - [null, false] - ]; - } - - //------------------------------------------------------------------- - - /** - * @dataProvider timezoneProvider - * - * @param $value - * @param $expected - */ - public function testTimeZone($value, $expected) - { - $data = [ - 'foo' => $value, - ]; - - $this->validation->setRules([ - 'foo' => "timezone", - ]); - - $this->assertEquals($expected, $this->validation->run($data)); - } - - //-------------------------------------------------------------------- - - public function timezoneProvider() - { - return [ - ['America/Chicago', true], - ['america/chicago', false], - ['foo/bar', false], - [null, false] - ]; - } - //-------------------------------------------------------------------- /** @@ -1358,10 +788,10 @@ class RulesTest extends \CIUnitTestCase public function testRequiredWith($field, $check, $expected = false) { $data = [ - 'foo' => 'bar', - 'bar' => 'something', - 'baz' => null, - 'ar' => [] // Was running into issues with array values + 'foo' => 'bar', + 'bar' => 'something', + 'baz' => null, + 'ar' => [] // Was running into issues with array values ]; $this->validation->setRules([ @@ -1396,9 +826,9 @@ class RulesTest extends \CIUnitTestCase public function testRequiredWithout($field, $check, $expected = false) { $data = [ - 'foo' => 'bar', - 'bar' => 'something', - 'baz' => null, + 'foo' => 'bar', + 'bar' => 'something', + 'baz' => null, ]; $this->validation->setRules([ @@ -1423,426 +853,4 @@ class RulesTest extends \CIUnitTestCase //-------------------------------------------------------------------- - //-------------------------------------------------------------------- - // Credit Card Rules - //-------------------------------------------------------------------- - - /** - * @dataProvider creditCardProvider - * - * @param $type - * @param $number - * @param bool $expected - */ - public function testValidCCNumber($type, $number, $expected = false) - { - $data = [ - 'cc' => $number, - ]; - - $this->validation->setRules([ - 'cc' => "valid_cc_number[{$type}]", - ]); - - $this->assertEquals($expected, $this->validation->run($data)); - } - - //-------------------------------------------------------------------- - - /** - * Cards shown are test cards found around the web. - * - * @see https://www.paypalobjects.com/en_US/vhelp/paypalmanager_help/credit_card_numbers.htm - * - * @return array - */ - public function creditCardProvider() - { - return [ - 'null_test' => ['amex', null, false], - 'random_test' => ['amex', $this->generateCardNum('37', 16), false], - 'invalid_type' => ['shorty', '1111 1111 1111 1111', false], - 'invalid_length' => ['amex', '', false], - 'not_numeric' => ['amex', 'abcd efgh ijkl mnop', false], - 'bad_length' => ['amex', '3782 8224 6310 0051', false], - 'bad_prefix' => ['amex', '3582 8224 6310 0051', false], - 'amex1' => ['amex', '3782 8224 6310 005', true], - 'amex2' => ['amex', '3714 4963 5398 431', true], - 'dinersclub1' => ['dinersclub', '3056 9309 0259 04', true], - 'dinersculb2' => ['dinersclub', '3852 0000 0232 37', true], - 'discover1' => ['discover', '6011 1111 1111 1117', true], - 'discover2' => ['discover', '6011 0009 9013 9424', true], - 'jcb1' => ['jcb', '3530 1113 3330 0000', true], - 'jcb2' => ['jcb', '3566 0020 2036 0505', true], - 'mastercard1' => ['mastercard', '5555 5555 5555 4444', true], - 'mastercard2' => ['mastercard', '5105 1051 0510 5100', true], - 'visa1' => ['visa', '4111 1111 1111 1111', true], - 'visa2' => ['visa', '4012 8888 8888 1881', true], - 'visa3' => ['visa', '4222 2222 2222 2', true], - 'dankort1' => ['dankort', '5019 7170 1010 3742', true], - 'unionpay1' => ['unionpay', $this->generateCardNum(62, 16), true], - 'unionpay2' => ['unionpay', $this->generateCardNum(62, 17), true], - 'unionpay3' => ['unionpay', $this->generateCardNum(62, 18), true], - 'unionpay4' => ['unionpay', $this->generateCardNum(62, 19), true], - 'unionpay5' => ['unionpay', $this->generateCardNum(63, 19), false], - 'carteblanche1' => ['carteblanche', $this->generateCardNum(300, 14), true], - 'carteblanche2' => ['carteblanche', $this->generateCardNum(301, 14), true], - 'carteblanche3' => ['carteblanche', $this->generateCardNum(302, 14), true], - 'carteblanche4' => ['carteblanche', $this->generateCardNum(303, 14), true], - 'carteblanche5' => ['carteblanche', $this->generateCardNum(304, 14), true], - 'carteblanche6' => ['carteblanche', $this->generateCardNum(305, 14), true], - 'carteblanche7' => ['carteblanche', $this->generateCardNum(306, 14), false], - 'dinersclub3' => ['dinersclub', $this->generateCardNum(300, 14), true], - 'dinersclub4' => ['dinersclub', $this->generateCardNum(301, 14), true], - 'dinersclub5' => ['dinersclub', $this->generateCardNum(302, 14), true], - 'dinersclub6' => ['dinersclub', $this->generateCardNum(303, 14), true], - 'dinersclub7' => ['dinersclub', $this->generateCardNum(304, 14), true], - 'dinersclub8' => ['dinersclub', $this->generateCardNum(305, 14), true], - 'dinersclub9' => ['dinersclub', $this->generateCardNum(309, 14), true], - 'dinersclub10' => ['dinersclub', $this->generateCardNum(36, 14), true], - 'dinersclub11' => ['dinersclub', $this->generateCardNum(38, 14), true], - 'dinersclub12' => ['dinersclub', $this->generateCardNum(39, 14), true], - 'dinersclub13' => ['dinersclub', $this->generateCardNum(54, 14), true], - 'dinersclub14' => ['dinersclub', $this->generateCardNum(55, 14), true], - 'dinersclub15' => ['dinersclub', $this->generateCardNum(300, 16), true], - 'dinersclub16' => ['dinersclub', $this->generateCardNum(301, 16), true], - 'dinersclub17' => ['dinersclub', $this->generateCardNum(302, 16), true], - 'dinersclub18' => ['dinersclub', $this->generateCardNum(303, 16), true], - 'dinersclub19' => ['dinersclub', $this->generateCardNum(304, 16), true], - 'dinersclub20' => ['dinersclub', $this->generateCardNum(305, 16), true], - 'dinersclub21' => ['dinersclub', $this->generateCardNum(309, 16), true], - 'dinersclub22' => ['dinersclub', $this->generateCardNum(36, 16), true], - 'dinersclub23' => ['dinersclub', $this->generateCardNum(38, 16), true], - 'dinersclub24' => ['dinersclub', $this->generateCardNum(39, 16), true], - 'dinersclub25' => ['dinersclub', $this->generateCardNum(54, 16), true], - 'dinersclub26' => ['dinersclub', $this->generateCardNum(55, 16), true], - 'discover3' => ['discover', $this->generateCardNum(6011, 16), true], - 'discover4' => ['discover', $this->generateCardNum(622, 16), true], - 'discover5' => ['discover', $this->generateCardNum(644, 16), true], - 'discover6' => ['discover', $this->generateCardNum(645, 16), true], - 'discover7' => ['discover', $this->generateCardNum(656, 16), true], - 'discover8' => ['discover', $this->generateCardNum(647, 16), true], - 'discover9' => ['discover', $this->generateCardNum(648, 16), true], - 'discover10' => ['discover', $this->generateCardNum(649, 16), true], - 'discover11' => ['discover', $this->generateCardNum(65, 16), true], - 'discover12' => ['discover', $this->generateCardNum(6011, 19), true], - 'discover13' => ['discover', $this->generateCardNum(622, 19), true], - 'discover14' => ['discover', $this->generateCardNum(644, 19), true], - 'discover15' => ['discover', $this->generateCardNum(645, 19), true], - 'discover16' => ['discover', $this->generateCardNum(656, 19), true], - 'discover17' => ['discover', $this->generateCardNum(647, 19), true], - 'discover18' => ['discover', $this->generateCardNum(648, 19), true], - 'discover19' => ['discover', $this->generateCardNum(649, 19), true], - 'discover20' => ['discover', $this->generateCardNum(65, 19), true], - 'interpayment1' => ['interpayment', $this->generateCardNum(4, 16), true], - 'interpayment2' => ['interpayment', $this->generateCardNum(4, 17), true], - 'interpayment3' => ['interpayment', $this->generateCardNum(4, 18), true], - 'interpayment4' => ['interpayment', $this->generateCardNum(4, 19), true], - 'jcb1' => ['jcb', $this->generateCardNum(352, 16), true], - 'jcb2' => ['jcb', $this->generateCardNum(353, 16), true], - 'jcb3' => ['jcb', $this->generateCardNum(354, 16), true], - 'jcb4' => ['jcb', $this->generateCardNum(355, 16), true], - 'jcb5' => ['jcb', $this->generateCardNum(356, 16), true], - 'jcb6' => ['jcb', $this->generateCardNum(357, 16), true], - 'jcb7' => ['jcb', $this->generateCardNum(358, 16), true], - 'maestro1' => ['maestro', $this->generateCardNum(50, 12), true], - 'maestro2' => ['maestro', $this->generateCardNum(56, 12), true], - 'maestro3' => ['maestro', $this->generateCardNum(57, 12), true], - 'maestro4' => ['maestro', $this->generateCardNum(58, 12), true], - 'maestro5' => ['maestro', $this->generateCardNum(59, 12), true], - 'maestro6' => ['maestro', $this->generateCardNum(60, 12), true], - 'maestro7' => ['maestro', $this->generateCardNum(61, 12), true], - 'maestro8' => ['maestro', $this->generateCardNum(62, 12), true], - 'maestro9' => ['maestro', $this->generateCardNum(63, 12), true], - 'maestro10' => ['maestro', $this->generateCardNum(64, 12), true], - 'maestro11' => ['maestro', $this->generateCardNum(65, 12), true], - 'maestro12' => ['maestro', $this->generateCardNum(66, 12), true], - 'maestro13' => ['maestro', $this->generateCardNum(67, 12), true], - 'maestro14' => ['maestro', $this->generateCardNum(68, 12), true], - 'maestro15' => ['maestro', $this->generateCardNum(69, 12), true], - 'maestro16' => ['maestro', $this->generateCardNum(50, 13), true], - 'maestro17' => ['maestro', $this->generateCardNum(56, 13), true], - 'maestro18' => ['maestro', $this->generateCardNum(57, 13), true], - 'maestro19' => ['maestro', $this->generateCardNum(58, 13), true], - 'maestro20' => ['maestro', $this->generateCardNum(59, 13), true], - 'maestro21' => ['maestro', $this->generateCardNum(60, 13), true], - 'maestro22' => ['maestro', $this->generateCardNum(61, 13), true], - 'maestro23' => ['maestro', $this->generateCardNum(62, 13), true], - 'maestro24' => ['maestro', $this->generateCardNum(63, 13), true], - 'maestro25' => ['maestro', $this->generateCardNum(64, 13), true], - 'maestro26' => ['maestro', $this->generateCardNum(65, 13), true], - 'maestro27' => ['maestro', $this->generateCardNum(66, 13), true], - 'maestro28' => ['maestro', $this->generateCardNum(67, 13), true], - 'maestro29' => ['maestro', $this->generateCardNum(68, 13), true], - 'maestro30' => ['maestro', $this->generateCardNum(69, 13), true], - 'maestro31' => ['maestro', $this->generateCardNum(50, 14), true], - 'maestro32' => ['maestro', $this->generateCardNum(56, 14), true], - 'maestro33' => ['maestro', $this->generateCardNum(57, 14), true], - 'maestro34' => ['maestro', $this->generateCardNum(58, 14), true], - 'maestro35' => ['maestro', $this->generateCardNum(59, 14), true], - 'maestro36' => ['maestro', $this->generateCardNum(60, 14), true], - 'maestro37' => ['maestro', $this->generateCardNum(61, 14), true], - 'maestro38' => ['maestro', $this->generateCardNum(62, 14), true], - 'maestro39' => ['maestro', $this->generateCardNum(63, 14), true], - 'maestro40' => ['maestro', $this->generateCardNum(64, 14), true], - 'maestro41' => ['maestro', $this->generateCardNum(65, 14), true], - 'maestro42' => ['maestro', $this->generateCardNum(66, 14), true], - 'maestro43' => ['maestro', $this->generateCardNum(67, 14), true], - 'maestro44' => ['maestro', $this->generateCardNum(68, 14), true], - 'maestro45' => ['maestro', $this->generateCardNum(69, 14), true], - 'maestro46' => ['maestro', $this->generateCardNum(50, 15), true], - 'maestro47' => ['maestro', $this->generateCardNum(56, 15), true], - 'maestro48' => ['maestro', $this->generateCardNum(57, 15), true], - 'maestro49' => ['maestro', $this->generateCardNum(58, 15), true], - 'maestro50' => ['maestro', $this->generateCardNum(59, 15), true], - 'maestro51' => ['maestro', $this->generateCardNum(60, 15), true], - 'maestro52' => ['maestro', $this->generateCardNum(61, 15), true], - 'maestro53' => ['maestro', $this->generateCardNum(62, 15), true], - 'maestro54' => ['maestro', $this->generateCardNum(63, 15), true], - 'maestro55' => ['maestro', $this->generateCardNum(64, 15), true], - 'maestro56' => ['maestro', $this->generateCardNum(65, 15), true], - 'maestro57' => ['maestro', $this->generateCardNum(66, 15), true], - 'maestro58' => ['maestro', $this->generateCardNum(67, 15), true], - 'maestro59' => ['maestro', $this->generateCardNum(68, 15), true], - 'maestro60' => ['maestro', $this->generateCardNum(69, 15), true], - 'maestro61' => ['maestro', $this->generateCardNum(50, 16), true], - 'maestro62' => ['maestro', $this->generateCardNum(56, 16), true], - 'maestro63' => ['maestro', $this->generateCardNum(57, 16), true], - 'maestro64' => ['maestro', $this->generateCardNum(58, 16), true], - 'maestro65' => ['maestro', $this->generateCardNum(59, 16), true], - 'maestro66' => ['maestro', $this->generateCardNum(60, 16), true], - 'maestro67' => ['maestro', $this->generateCardNum(61, 16), true], - 'maestro68' => ['maestro', $this->generateCardNum(62, 16), true], - 'maestro69' => ['maestro', $this->generateCardNum(63, 16), true], - 'maestro70' => ['maestro', $this->generateCardNum(64, 16), true], - 'maestro71' => ['maestro', $this->generateCardNum(65, 16), true], - 'maestro72' => ['maestro', $this->generateCardNum(66, 16), true], - 'maestro73' => ['maestro', $this->generateCardNum(67, 16), true], - 'maestro74' => ['maestro', $this->generateCardNum(68, 16), true], - 'maestro75' => ['maestro', $this->generateCardNum(69, 16), true], - 'maestro91' => ['maestro', $this->generateCardNum(50, 18), true], - 'maestro92' => ['maestro', $this->generateCardNum(56, 18), true], - 'maestro93' => ['maestro', $this->generateCardNum(57, 18), true], - 'maestro94' => ['maestro', $this->generateCardNum(58, 18), true], - 'maestro95' => ['maestro', $this->generateCardNum(59, 18), true], - 'maestro96' => ['maestro', $this->generateCardNum(60, 18), true], - 'maestro97' => ['maestro', $this->generateCardNum(61, 18), true], - 'maestro98' => ['maestro', $this->generateCardNum(62, 18), true], - 'maestro99' => ['maestro', $this->generateCardNum(63, 18), true], - 'maestro100' => ['maestro', $this->generateCardNum(64, 18), true], - 'maestro101' => ['maestro', $this->generateCardNum(65, 18), true], - 'maestro102' => ['maestro', $this->generateCardNum(66, 18), true], - 'maestro103' => ['maestro', $this->generateCardNum(67, 18), true], - 'maestro104' => ['maestro', $this->generateCardNum(68, 18), true], - 'maestro105' => ['maestro', $this->generateCardNum(69, 18), true], - 'maestro106' => ['maestro', $this->generateCardNum(50, 19), true], - 'maestro107' => ['maestro', $this->generateCardNum(56, 19), true], - 'maestro108' => ['maestro', $this->generateCardNum(57, 19), true], - 'maestro109' => ['maestro', $this->generateCardNum(58, 19), true], - 'maestro110' => ['maestro', $this->generateCardNum(59, 19), true], - 'maestro111' => ['maestro', $this->generateCardNum(60, 19), true], - 'maestro112' => ['maestro', $this->generateCardNum(61, 19), true], - 'maestro113' => ['maestro', $this->generateCardNum(62, 19), true], - 'maestro114' => ['maestro', $this->generateCardNum(63, 19), true], - 'maestro115' => ['maestro', $this->generateCardNum(64, 19), true], - 'maestro116' => ['maestro', $this->generateCardNum(65, 19), true], - 'maestro117' => ['maestro', $this->generateCardNum(66, 19), true], - 'maestro118' => ['maestro', $this->generateCardNum(67, 19), true], - 'maestro119' => ['maestro', $this->generateCardNum(68, 19), true], - 'maestro120' => ['maestro', $this->generateCardNum(69, 19), true], - 'dankort1' => ['dankort', $this->generateCardNum(5019, 16), true], - 'dankort2' => ['dankort', $this->generateCardNum(4175, 16), true], - 'dankort3' => ['dankort', $this->generateCardNum(4571, 16), true], - 'dankort4' => ['dankort', $this->generateCardNum(4, 16), true], - 'mir1' => ['mir', $this->generateCardNum(2200, 16), true], - 'mir2' => ['mir', $this->generateCardNum(2201, 16), true], - 'mir3' => ['mir', $this->generateCardNum(2202, 16), true], - 'mir4' => ['mir', $this->generateCardNum(2203, 16), true], - 'mir5' => ['mir', $this->generateCardNum(2204, 16), true], - 'mastercard1' => ['mastercard', $this->generateCardNum(51, 16), true], - 'mastercard2' => ['mastercard', $this->generateCardNum(52, 16), true], - 'mastercard3' => ['mastercard', $this->generateCardNum(53, 16), true], - 'mastercard4' => ['mastercard', $this->generateCardNum(54, 16), true], - 'mastercard5' => ['mastercard', $this->generateCardNum(55, 16), true], - 'mastercard6' => ['mastercard', $this->generateCardNum(22, 16), true], - 'mastercard7' => ['mastercard', $this->generateCardNum(23, 16), true], - 'mastercard8' => ['mastercard', $this->generateCardNum(24, 16), true], - 'mastercard9' => ['mastercard', $this->generateCardNum(25, 16), true], - 'mastercard10' => ['mastercard', $this->generateCardNum(26, 16), true], - 'mastercard11' => ['mastercard', $this->generateCardNum(27, 16), true], - 'visa1' => ['visa', $this->generateCardNum(4, 13), true], - 'visa2' => ['visa', $this->generateCardNum(4, 16), true], - 'visa3' => ['visa', $this->generateCardNum(4, 19), true], - 'uatp' => ['uatp', $this->generateCardNum(1, 15), true], - 'verve1' => ['verve', $this->generateCardNum(506, 16), true], - 'verve2' => ['verve', $this->generateCardNum(650, 16), true], - 'verve3' => ['verve', $this->generateCardNum(506, 19), true], - 'verve4' => ['verve', $this->generateCardNum(650, 19), true], - 'cibc1' => ['cibc', $this->generateCardNum(4506, 16), true], - 'rbc1' => ['rbc', $this->generateCardNum(45, 16), true], - 'tdtrust' => ['tdtrust', $this->generateCardNum(589297, 16), true], - 'scotia1' => ['scotia', $this->generateCardNum(4536, 16), true], - 'bmoabm1' => ['bmoabm', $this->generateCardNum(500, 16), true], - 'hsbc' => ['hsbc', $this->generateCardNum(56, 16), true], - 'hsbc' => ['hsbc', $this->generateCardNum(57, 16), false], - ]; - } - - //-------------------------------------------------------------------- - - /** - * Used to generate fake credit card numbers that will still pass the Luhn - * check used to validate the card so we can be sure the cards are recognized correctly. - * - * @param int $prefix - * @param int $length - * - * @return string - */ - protected function generateCardNum(int $prefix, int $length) - { - $pos = mb_strlen($prefix); - $finalDigit = 0; - $sum = 0; - - // Fill in the first values of the string based on $prefix - $string = str_split($prefix); - - // Pad out the array to the appropriate length - $string = array_pad($string, $length, 0); - - // Fill all of the remaining values with random numbers, except the last one. - while ($pos < $length-1) { - $string[$pos++] = random_int(0, 9); - } - - // Calculate the Luhn checksum of the current values. - $lenOffset = ($length+1)%2; - for ($pos = 0; $pos < $length-1; $pos++) { - if (($pos+$lenOffset)%2) { - $temp = $string[$pos]*2; - if ($temp > 9) { - $temp -= 9; - } - - $sum += $temp; - } else { - $sum += $string[$pos]; - } - } - - // Make the last number whatever would cause the entire number to pass the checksum - $finalDigit = (10-($sum%10))%10; - $string[$length-1] = $finalDigit; - - return implode('', $string); - } - - //-------------------------------------------------------------------- - - public function testUploadedTrue() - { - $_FILES = [ - 'avatar' => [ - 'tmp_name' => 'phpUxcOty', - 'name' => 'my-avatar.png', - 'size' => 90996, - 'type' => 'image/png', - 'error' => 0, - ] - ]; - - $this->validation->setRules([ - 'avatar' => "uploaded[avatar]", - ]); - - $this->assertTrue($this->validation->run([])); - - } - - //-------------------------------------------------------------------- - - public function testUploadedFalse() - { - $_FILES = [ - 'avatar' => [ - 'tmp_name' => 'phpUxcOty', - 'name' => 'my-avatar.png', - 'size' => 90996, - 'type' => 'image/png', - 'error' => 0, - ] - ]; - - $this->validation->setRules([ - 'avatar' => "uploaded[userfile]", - ]); - - $this->assertFalse($this->validation->run([])); - - } - - //-------------------------------------------------------------------- - - /** - * @dataProvider validDateProvider - * - * @param $str - * @param $format - * @param $expected - */ - public function testValidDate($str, $format, $expected) - { - $data = [ - 'foo' => $str, - ]; - - $this->validation->setRules([ - 'foo' => "valid_date[{$format}]", - ]); - - $this->assertEquals($expected, $this->validation->run($data)); - } - - //-------------------------------------------------------------------- - - public function validDateProvider() - { - return [ - ['Sun', 'D', true], - ['Sun', 'd', false], - ['Sun', null, true], - ['1500', 'Y', true], - ['1500', 'y', false], - ['1500', null, true], - ['09:26:05', 'H:i:s', true], - ['09:26:5', 'H:i:s', false], - ['1992-02-29', 'Y-m-d', true], - ['1991-02-29', 'Y-m-d', false], - ['1718-05-10 15:25:59', 'Y-m-d H:i:s', true], - ['1718-05-10 15:5:59', 'Y-m-d H:i:s', false], - ['Thu, 31 Oct 2013 13:31:00', 'D, d M Y H:i:s', true], - ['Thu, 31 Jun 2013 13:31:00', 'D, d M Y H:i:s', false], - ['Thu, 31 Jun 2013 13:31:00', null, true], - ['07.05.03', 'm.d.y', true], - ['07.05.1803', 'm.d.y', false], - ['19890109', 'Ymd', true], - ['198919', 'Ymd', false], - ['2, 7, 2001', 'j, n, Y', true], - ['2, 17, 2001', 'j, n, Y', false], - ['09-42-25, 12-11-17', 'h-i-s, j-m-y', true], - ['09-42-25, 12-00-17', 'h-i-s, j-m-y', false], - ['09-42-25, 12-00-17', null, false], - ['November 12, 2017, 9:42 am', 'F j, Y, g:i a', true], - ['November 12, 2017, 19:42 am', 'F j, Y, g:i a', false], - ['November 12, 2017, 9:42 am', null, true], - ['Monday 8th of August 2005 03:12:46 PM', 'l jS \of F Y h:i:s A', true], - ['Monday 8th of August 2005 13:12:46 PM', 'l jS \of F Y h:i:s A', false], - ['23:01:59 is now', 'H:m:s \i\s \n\o\w', true], - ['23:01:59 is now', 'H:m:s is now', false], - ['12/11/2017', 'd/m/Y', true], - ]; - } - - //-------------------------------------------------------------------- } diff --git a/tests/system/Validation/ValidationTest.php b/tests/system/Validation/ValidationTest.php index 0ac66c2fb7..52573a9504 100644 --- a/tests/system/Validation/ValidationTest.php +++ b/tests/system/Validation/ValidationTest.php @@ -1,35 +1,43 @@ [ + 'ruleSets' => [ \CodeIgniter\Validation\Rules::class, \CodeIgniter\Validation\FormatRules::class, \CodeIgniter\Validation\FileRules::class, \CodeIgniter\Validation\CreditCardRules::class, \Tests\Support\Validation\TestRules::class, ], - 'groupA' => [ + 'groupA' => [ 'foo' => 'required|min_length[5]', ], - 'groupA_errors' => [ + 'groupA_errors' => [ 'foo' => [ 'min_length' => 'Shame, shame. Too short.', ], ], + 'groupX' => 'Not an array, so not a real group', + 'templates' => [ + 'list' => 'CodeIgniter\Validation\Views\list', + 'single' => 'CodeIgniter\Validation\Views\single' + ], ]; - //-------------------------------------------------------------------- +//-------------------------------------------------------------------- public function setUp() { @@ -37,19 +45,19 @@ class ValidationTest extends \CIUnitTestCase Services::reset(); - $this->validation = new Validation((object)$this->config, \Config\Services::renderer()); + $this->validation = new Validation((object) $this->config, \Config\Services::renderer()); $this->validation->reset(); $_FILES = []; } - //-------------------------------------------------------------------- +//-------------------------------------------------------------------- public function testSetRulesStoresRules() { $rules = [ - 'foo' => 'bar|baz', - 'bar' => 'baz|belch', + 'foo' => 'bar|baz', + 'bar' => 'baz|belch', ]; $this->validation->setRules($rules); @@ -57,7 +65,7 @@ class ValidationTest extends \CIUnitTestCase $this->assertEquals($rules, $this->validation->getRules()); } - //-------------------------------------------------------------------- +//-------------------------------------------------------------------- public function testRunReturnsFalseWithNothingToDo() { @@ -66,7 +74,7 @@ class ValidationTest extends \CIUnitTestCase $this->assertFalse($this->validation->run([])); } - //-------------------------------------------------------------------- +//-------------------------------------------------------------------- public function testRunDoesTheBasics() { @@ -75,13 +83,13 @@ class ValidationTest extends \CIUnitTestCase ]; $this->validation->setRules([ - 'foo' => 'is_numeric', + 'foo' => 'is_numeric', ]); $this->assertFalse($this->validation->run($data)); } - //-------------------------------------------------------------------- +//-------------------------------------------------------------------- public function testRunReturnsLocalizedErrors() { @@ -90,14 +98,14 @@ class ValidationTest extends \CIUnitTestCase ]; $this->validation->setRules([ - 'foo' => 'is_numeric', + 'foo' => 'is_numeric', ]); $this->assertFalse($this->validation->run($data)); $this->assertEquals('Validation.is_numeric', $this->validation->getError('foo')); } - //-------------------------------------------------------------------- +//-------------------------------------------------------------------- public function testRunWithCustomErrors() { @@ -112,21 +120,21 @@ class ValidationTest extends \CIUnitTestCase ]; $this->validation->setRules([ - 'foo' => 'is_numeric', - ], $messages); + 'foo' => 'is_numeric', + ], $messages); $this->validation->run($data); $this->assertEquals('Nope. Not a number.', $this->validation->getError('foo')); } - //-------------------------------------------------------------------- +//-------------------------------------------------------------------- public function testCheck() { $this->assertFalse($this->validation->check('notanumber', 'is_numeric')); } - //-------------------------------------------------------------------- +//-------------------------------------------------------------------- public function testCheckLocalizedError() { @@ -134,17 +142,17 @@ class ValidationTest extends \CIUnitTestCase $this->assertEquals('Validation.is_numeric', $this->validation->getError()); } - //-------------------------------------------------------------------- +//-------------------------------------------------------------------- public function testCheckCustomError() { $this->validation->check('notanumber', 'is_numeric', [ - 'is_numeric' => 'Nope. Not a number.' + 'is_numeric' => 'Nope. Not a number.' ]); $this->assertEquals('Nope. Not a number.', $this->validation->getError()); } - //-------------------------------------------------------------------- +//-------------------------------------------------------------------- public function testGetErrors() { @@ -153,7 +161,7 @@ class ValidationTest extends \CIUnitTestCase ]; $this->validation->setRules([ - 'foo' => 'is_numeric', + 'foo' => 'is_numeric', ]); $this->validation->run($data); @@ -161,7 +169,7 @@ class ValidationTest extends \CIUnitTestCase $this->assertEquals(['foo' => 'Validation.is_numeric'], $this->validation->getErrors()); } - //-------------------------------------------------------------------- +//-------------------------------------------------------------------- public function testGetErrorsWhenNone() { @@ -172,7 +180,7 @@ class ValidationTest extends \CIUnitTestCase ]; $this->validation->setRules([ - 'foo' => 'is_numeric', + 'foo' => 'is_numeric', ]); $this->validation->run($data); @@ -180,12 +188,12 @@ class ValidationTest extends \CIUnitTestCase $this->assertEquals([], $this->validation->getErrors()); } - //-------------------------------------------------------------------- +//-------------------------------------------------------------------- public function testSetErrors() { $this->validation->setRules([ - 'foo' => 'is_numeric', + 'foo' => 'is_numeric', ]); $this->validation->setError('foo', 'Nadda'); @@ -193,12 +201,12 @@ class ValidationTest extends \CIUnitTestCase $this->assertEquals(['foo' => 'Nadda'], $this->validation->getErrors()); } - //-------------------------------------------------------------------- +//-------------------------------------------------------------------- public function testRulesReturnErrors() { $this->validation->setRules([ - 'foo' => 'customError' + 'foo' => 'customError' ]); $this->validation->run(['foo' => 'bar']); @@ -206,7 +214,7 @@ class ValidationTest extends \CIUnitTestCase $this->assertEquals(['foo' => 'My lovely error'], $this->validation->getErrors()); } - //-------------------------------------------------------------------- +//-------------------------------------------------------------------- public function testGroupsReadFromConfig() { @@ -218,7 +226,7 @@ class ValidationTest extends \CIUnitTestCase $this->assertEquals('Shame, shame. Too short.', $this->validation->getError('foo')); } - //-------------------------------------------------------------------- +//-------------------------------------------------------------------- public function testGroupsReadFromConfigValid() { @@ -229,16 +237,16 @@ class ValidationTest extends \CIUnitTestCase $this->assertTrue($this->validation->run($data, 'groupA')); } - //-------------------------------------------------------------------- +//-------------------------------------------------------------------- public function testGetRuleGroup() { $this->assertEquals([ - 'foo' => 'required|min_length[5]', - ], $this->validation->getRuleGroup('groupA')); + 'foo' => 'required|min_length[5]', + ], $this->validation->getRuleGroup('groupA')); } - //-------------------------------------------------------------------- +//-------------------------------------------------------------------- public function testGetRuleGroupException() { @@ -246,18 +254,18 @@ class ValidationTest extends \CIUnitTestCase $this->validation->getRuleGroup('groupZ'); } - //-------------------------------------------------------------------- +//-------------------------------------------------------------------- public function testSetRuleGroup() { $this->validation->setRuleGroup('groupA'); $this->assertEquals([ - 'foo' => 'required|min_length[5]', - ], $this->validation->getRules()); + 'foo' => 'required|min_length[5]', + ], $this->validation->getRules()); } - //-------------------------------------------------------------------- +//-------------------------------------------------------------------- public function testSetRuleGroupException() { @@ -266,6 +274,8 @@ class ValidationTest extends \CIUnitTestCase $this->validation->setRuleGroup('groupZ'); } +//-------------------------------------------------------------------- + /** * @dataProvider rulesSetupProvider */ @@ -276,15 +286,15 @@ class ValidationTest extends \CIUnitTestCase ]; $this->validation->setRules([ - 'foo' => $rules, - ], $errors); + 'foo' => $rules, + ], $errors); $this->validation->run($data); $this->assertEquals($expected, $this->validation->getError('foo')); } - //-------------------------------------------------------------------- +//-------------------------------------------------------------------- public function rulesSetupProvider() { @@ -322,8 +332,8 @@ class ValidationTest extends \CIUnitTestCase ], [ [ - 'label' => 'Foo Bar', - 'rules' => 'min_length[10]', + 'label' => 'Foo Bar', + 'rules' => 'min_length[10]', 'errors' => ['min_length' => 'The {field} field is very short.'] ], 'The Foo Bar field is very short.', @@ -331,5 +341,164 @@ class ValidationTest extends \CIUnitTestCase ]; } - //-------------------------------------------------------------------- +//-------------------------------------------------------------------- + + public function testInvalidRule() + { + $this->expectException(ValidationException::class); + + $rules = [ + 'foo' => 'bar|baz', + 'bar' => 'baz|belch', + ]; + $this->validation->setRules($rules); + + $data = [ + 'foo' => '', + ]; + $this->validation->run($data); + } + +//-------------------------------------------------------------------- + + public function testRawInput() + { + $rawstring = 'username=admin001&role=administrator&usepass=0'; + + $data = [ + 'username' => 'admin001', + 'role' => 'administrator', + 'usepass' => 0 + ]; + + $config = new App(); + $config->baseURL = 'http://example.com'; + + $request = new IncomingRequest($config, new URI(), $rawstring, new UserAgent()); + $request->setMethod('patch'); + + $rules = [ + 'role' => 'required|min_length[5]', + ]; + $this->validation->withRequest($request) + ->run($data); + + $this->assertEquals([], $this->validation->getErrors()); + } + +//-------------------------------------------------------------------- + + public function testHasRule() + { + $this->validation->setRuleGroup('groupA'); + + $this->assertTrue($this->validation->hasRule('foo')); + } + +//-------------------------------------------------------------------- + + public function testNotARealGroup() + { + $this->expectException(ValidationException::class); + $this->validation->setRuleGroup('groupX'); + $this->validation->getRuleGroup('groupX'); + } + +//-------------------------------------------------------------------- + + public function testBadTemplate() + { + $this->expectException(ValidationException::class); + $this->validation->listErrors('obviouslyBadTemplate'); + } + +//-------------------------------------------------------------------- + + public function testShowNonError() + { + $this->validation->setRules([ + 'foo' => 'is_numeric', + ]); + + $this->validation->setError('foo', 'Nadda'); + + $this->assertEquals('', $this->validation->showError('bogus')); + } + +//-------------------------------------------------------------------- + + public function testShowBadTemplate() + { + $this->expectException(ValidationException::class); + + $this->validation->setRules([ + 'foo' => 'is_numeric', + ]); + $this->validation->setError('foo', 'Nadda'); + + $this->assertEquals('We should never get here', $this->validation->showError('foo','bogus_template')); + } + +//-------------------------------------------------------------------- + + public function testNoRuleSetsSetup() + { + $this->expectException(ValidationException::class); + + $this->config['ruleSets'] = null; + $this->validation = new Validation((object) $this->config, \Config\Services::renderer()); + $this->validation->reset(); + + $data = [ + 'foo' => '', + ]; + + $this->validation->run($data); + } + +//-------------------------------------------------------------------- + + public function testNotCustomRuleGroup() + { + $this->expectException(ValidationException::class); + + + $data = [ + 'foo' => '', + ]; + + $this->validation->run($data, 'GeorgeRules'); + } + +//-------------------------------------------------------------------- + + public function testNotRealCustomRule() + { + $this->expectException(ValidationException::class); + + + $data = [ + 'foo' => '', + ]; + + $this->validation->run($data, 'groupX'); + } + +//-------------------------------------------------------------------- + + public function testHasError() + { + $data = [ + 'foo' => 'notanumber', + ]; + + $this->validation->setRules([ + 'foo' => 'is_numeric', + ]); + + $this->validation->run($data); + + $this->assertTrue($this->validation->hasError('foo')); + } + } diff --git a/user_guide_src/source/general/logging.rst b/user_guide_src/source/general/logging.rst index 1faf14e053..0cdf55e7dd 100644 --- a/user_guide_src/source/general/logging.rst +++ b/user_guide_src/source/general/logging.rst @@ -105,7 +105,7 @@ file name and line number. You must still provide the exception placeholder in { ... Something throws error here } - catch (\Exception #e) + catch (\Exception $e) { log_message('error', '[ERROR] {exception}', ['exception' => $e]); } diff --git a/user_guide_src/source/libraries/validation.rst b/user_guide_src/source/libraries/validation.rst index d2d697c913..8d600e0b4e 100644 --- a/user_guide_src/source/libraries/validation.rst +++ b/user_guide_src/source/libraries/validation.rst @@ -709,11 +709,11 @@ Rule Parameter Description uploaded Yes Fails if the name of the parameter does not match the name of any uploaded files. uploaded[field_name] max_size Yes Fails if the uploaded file named in the parameter is larger than the second parameter in max_size[field_name,2048] kilobytes (kb). -max_dims Yes Files if the maximum width and height of an uploaded image exceeds values. The first parameter max_dims[field_name,300,150] +max_dims Yes Fails if the maximum width and height of an uploaded image exceed values. The first parameter max_dims[field_name,300,150] is the field name. The second is the width, and the third is the height. Will also fail if the file cannot be determined to be an image. -mime_in Yes Fails if the file's mime type is not one listed in the parameter. mime_in[field_name,image/png,image/jpg] -ext_in Yes Fails if the file's extension is not one listed in the parameter. ext_in[field_name,png,jpg,gif] +mime_in Yes Fails if the file's mime type is not one listed in the parameters. mime_in[field_name,image/png,image/jpg] +ext_in Yes Fails if the file's extension is not one listed in the parameters. ext_in[field_name,png,jpg,gif] is_image Yes Fails if the file cannot be determined to be an image based on the mime type. is_image[field_name] ======================= =========== =============================================================================================== ========================================