Merge branch 'NewFeatures' into phpstan-strict

This commit is contained in:
Clemens Schwaighofer
2024-10-18 09:16:05 +09:00
3459 changed files with 22055 additions and 423696 deletions

43
.eslintrc.js Normal file
View File

@@ -0,0 +1,43 @@
module.exports = {
'env': {
'browser': true,
'es6': true,
'commonjs': true,
'jquery': true
},
'extends': 'eslint:recommended',
'parserOptions': {
'ecmaVersion': 6
},
'rules': {
'indent': [
'error',
'tab',
{
'SwitchCase': 1
}
],
'linebreak-style': [
'error',
'unix'
],
'quotes': [
'error',
'single'
],
'semi': [
'error',
'always'
],
'no-console': 'off',
'no-unused-vars': [
'error', {
'vars': 'all',
'args': 'after-used',
'ignoreRestSiblings': false
}
],
// Requires eslint >= v8.14.0
'no-constant-binary-expression': 'error'
}
};

5
.gitignore vendored
View File

@@ -0,0 +1,5 @@
.libs
node_modules/
composer.lock
vendor/
tools/

View File

@@ -27,6 +27,7 @@ use Phan\Config;
return [ return [
// "target_php_version" => "8.2", // "target_php_version" => "8.2",
"minimum_target_php_version" => "8.1",
// turn color on (-C) // turn color on (-C)
"color_issue_messages_if_supported" => true, "color_issue_messages_if_supported" => true,
// If true, missing properties will be created when // If true, missing properties will be created when
@@ -95,8 +96,6 @@ return [
"exclude_analysis_directory_list" => [ "exclude_analysis_directory_list" => [
'www/vendor', 'www/vendor',
'www/tests', 'www/tests',
'www/lib/Smarty',
'www/lib/smarty-4.3.0',
'www/templates_c', 'www/templates_c',
'www/log', 'www/log',
'www/tmp', 'www/tmp',
@@ -117,10 +116,6 @@ return [
// ignore the old qq tests // ignore the old qq tests
'www/admin/qq_file_upload_front.php', 'www/admin/qq_file_upload_front.php',
'www/admin/qq_file_upload_ajax.php', 'www/admin/qq_file_upload_ajax.php',
// symlink ignore
'www/lib/smarty-4.3.0/libs/Smarty.class.php',
// legacy edit base (until removal)
'www/includes/edit_base.LEGACY.php'
], ],
// what not to show as problem // what not to show as problem
@@ -133,7 +128,12 @@ return [
'PhanWriteOnlyPublicProperty', 'PhanWriteOnlyPublicProperty',
'PhanUnreferencedConstant', 'PhanUnreferencedConstant',
'PhanWriteOnlyPublicProperty', 'PhanWriteOnlyPublicProperty',
'PhanReadOnlyPublicProperty' 'PhanReadOnlyPublicProperty',
// start ignore annotations
'PhanUnextractableAnnotationElementName',
'PhanUnextractableAnnotationSuffix',
// enum problems in comments
'PhanCommentObjectInClassConstantType'
], ],
// Override to hardcode existence and types of (non-builtin) globals in the global scope. // Override to hardcode existence and types of (non-builtin) globals in the global scope.

12
.phive/phars.xml Normal file
View File

@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<phive xmlns="https://phar.io/phive">
<phar name="phpunit" version="^9.6" installed="9.6.21" location="./tools/phpunit" copy="false"/>
<phar name="phpcbf" version="^3.7.2" installed="3.10.3" location="./tools/phpcbf" copy="false"/>
<phar name="phpcs" version="^3.7.2" installed="3.10.3" location="./tools/phpcs" copy="false"/>
<phar name="phpstan" version="^1.10.37" installed="1.12.4" location="./tools/phpstan" copy="false"/>
<phar name="phan" version="^5.4.2" installed="5.4.3" location="./tools/phan" copy="false"/>
<phar name="psalm" version="^5.15.0" installed="5.24.0" location="./tools/psalm" copy="false"/>
<phar name="phpdox" version="^0.12.0" installed="0.12.0" location="./tools/phpdox" copy="false"/>
<phar name="phpdocumentor" version="^3.4.2" installed="3.4.3" location="./tools/phpDocumentor" copy="false"/>
<phar name="php-cs-fixer" version="^3.34.1" installed="3.57.2" location="./tools/php-cs-fixer" copy="false"/>
</phive>

2
.shellcheckrc Normal file
View File

@@ -0,0 +1,2 @@
shell=bash
external-sources=true

View File

@@ -1,19 +1,20 @@
#!/usr/bin/env bash #!/usr/bin/env bash
BASE_FOLDER=$(dirname $(readlink -f $0))"/"; BASE_FOLDER=$(dirname "$(readlink -f "$0")")"/";
# Assume script is in 4dev/bin # Assume script is in 4dev/bin
base_folder="${BASE_FOLDER}../../www/"; base_folder="${BASE_FOLDER}../../www/";
# locale gettext po to mo translator master # locale gettext po to mo translator master
for file in $(ls -1 ${base_folder}../4dev/locale/*.po); do for file in "${base_folder}"../4dev/locale/*.po; do
file=$(basename $file .po); [[ -e "$file" ]] || break
file=$(basename "$file" .po);
locale=$(echo "${file}" | cut -d "-" -f 1); locale=$(echo "${file}" | cut -d "-" -f 1);
domain=$(echo "${file}" | cut -d "-" -f 2); domain=$(echo "${file}" | cut -d "-" -f 2);
echo "- Translate language file '${file}' for locale '${locale}' and domain '${domain}':"; echo "- Translate language file '${file}' for locale '${locale}' and domain '${domain}':";
if [ ! -d "${base_folder}/includes/locale/${locale}/LC_MESSAGES/" ]; then if [ ! -d "${base_folder}/includes/locale/${locale}/LC_MESSAGES/" ]; then
mkdir -p "${base_folder}/includes/locale/${locale}/LC_MESSAGES/"; mkdir -p "${base_folder}/includes/locale/${locale}/LC_MESSAGES/";
fi; fi;
msgfmt -o ${base_folder}/includes/locale/${locale}/LC_MESSAGES/${domain}.mo ${base_folder}../4dev/locale/${locale}-${domain}.po; msgfmt -o "${base_folder}/includes/locale/${locale}/LC_MESSAGES/${domain}.mo" "${base_folder}../4dev/locale/${locale}-${domain}.po";
done; done;
# __END__ # __END__

View File

@@ -2,16 +2,18 @@
# read source mo files and writes target js files in object form # read source mo files and writes target js files in object form
# check for ARG 1 is "mv" # check for ARG 1 is "no-move"
# then move the files directly and don't do manual check (don't create temp files) # then do not move the files directly for manual check
FILE_MOVE=0;
if [ "${1}" = "mv" ]; then
echo "*** Direct write ***";
FILE_MOVE=1; FILE_MOVE=1;
if [ "${1}" = "no-move" ]; then
echo "+++ CREATE TEMPORARY FILES +++";
FILE_MOVE=0;
else
echo "*** Direct write ***";
fi; fi;
target=''; target='';
BASE_FOLDER=$(dirname $(readlink -f $0))"/"; BASE_FOLDER=$(dirname "$(readlink -f "$0")")"/";
# Assume script is in 4dev/bin # Assume script is in 4dev/bin
base_folder="${BASE_FOLDER}../../www/"; base_folder="${BASE_FOLDER}../../www/";
po_folder='../4dev/locale/' po_folder='../4dev/locale/'
@@ -26,9 +28,9 @@ if [ "${target}" == '' ]; then
echo "*** Non smarty ***"; echo "*** Non smarty ***";
TEXTDOMAINDIR=${base_folder}${mo_folder}. TEXTDOMAINDIR=${base_folder}${mo_folder}.
# default is admin # default is admin
TEXTDOMAIN=admin; TEXTDOMAIN="admin";
fi; fi;
js_folder="layout/${TEXTDOMAIN}/javascript/"; js_folder="${TEXTDOMAIN}/layout/javascript/";
error=0; error=0;
# this checks if the TEXTDOMAIN target actually exists # this checks if the TEXTDOMAIN target actually exists
@@ -44,15 +46,16 @@ if [ ${error} -eq 1 ]; then
fi; fi;
# locale gettext po to mo translator master # locale gettext po to mo translator master
for file in $(ls -1 ${base_folder}../4dev/locale/*.po); do for file in "${base_folder}"../4dev/locale/*.po; do
file=$(basename $file .po); [[ -e "$file" ]] || break
echo "Translate language ${file}"; file=$(basename "$file" .po);
locale=$(echo "${file}" | cut -d "-" -f 1); locale=$(echo "${file}" | cut -d "-" -f 1);
domain=$(echo "${file}" | cut -d "-" -f 2); domain=$(echo "${file}" | cut -d "-" -f 2);
echo "- Translate language file '${file}' for locale '${locale}' and domain '${domain}':";
if [ ! -d "${base_folder}/includes/locale/${locale}/LC_MESSAGES/" ]; then if [ ! -d "${base_folder}/includes/locale/${locale}/LC_MESSAGES/" ]; then
mkdir -p "${base_folder}/includes/locale/${locale}/LC_MESSAGES/"; mkdir -p "${base_folder}/includes/locale/${locale}/LC_MESSAGES/";
fi; fi;
msgfmt -o ${base_folder}/includes/locale/${locale}/LC_MESSAGES/${domain}.mo ${base_folder}${po_folder}${locale}-${domain}.po; msgfmt -o "${base_folder}/includes/locale/${locale}/LC_MESSAGES/${domain}.mo" "${base_folder}${po_folder}${locale}-${domain}.po";
done; done;
rx_msgid_empty="^msgid \"\""; rx_msgid_empty="^msgid \"\"";
@@ -62,7 +65,7 @@ rx_msgstr="^msgstr \""
# quick copy string at the end # quick copy string at the end
quick_copy=''; quick_copy='';
for language in ${language_list[*]}; do for language in "${language_list[@]}"; do
# I don't know which one must be set, but I think at least LANGUAGE # I don't know which one must be set, but I think at least LANGUAGE
case ${language} in case ${language} in
ja) ja)
@@ -79,7 +82,8 @@ for language in ${language_list[*]}; do
esac; esac;
# write only one for language and then symlink files # write only one for language and then symlink files
template_file=$(echo ${template_file_stump} | sed -e "s/##SUFFIX##//" | sed -e "s/##LANGUAGE##/${LANG}/"); template_file=$(echo ${template_file_stump} | sed -e "s/##SUFFIX##//" | sed -e "s/##LANGUAGE##/${LANG}/");
original_file=$(echo ${template_file} | sed -e 's/\.TMP//g'); # original_file=$(echo ${template_file} | sed -e 's/\.TMP//g');
original_file=${template_file//.TMP/};
if [ "${FILE_MOVE}" -eq 0 ]; then if [ "${FILE_MOVE}" -eq 0 ]; then
file=${target_folder}${template_file}; file=${target_folder}${template_file};
else else
@@ -88,16 +92,18 @@ for language in ${language_list[*]}; do
echo "===> Write translation file ${file}"; echo "===> Write translation file ${file}";
echo ". = normal, : = escape, x = skip"; echo ". = normal, : = escape, x = skip";
# init line [aka don't touch this file] # init line [aka don't touch this file]
echo "// AUTO FILL, changes will be overwritten" > $file; echo "// AUTO FILL, changes will be overwritten" > "$file";
echo "// source: ${suffix}, language: ${language}" >> $file; {
echo "// Translation strings in the format" >> $file; echo "// source: ${suffix}, language: ${language}";
echo "// \"Original\":\"Translated\""$'\n' >> $file; echo "// Translation strings in the format";
echo "var i18n = {" >> $file; echo "// \"Original\":\"Translated\""$'\n'
echo "var i18n = {"
} >> "$file"
# translations stuff # translations stuff
# read the po file # read the po file
pos=0; # do we add a , for the next line pos=0; # do we add a , for the next line
cat "${base_folder}${po_folder}${language}-${TEXTDOMAIN}.po" | cat "${base_folder}${po_folder}${language}-${TEXTDOMAIN}.po" |
while read str; do while read -r str; do
# echo "S: ${str}"; # echo "S: ${str}";
# skip empty # skip empty
if [[ "${str}" =~ ${rx_msgid_empty} ]]; then if [[ "${str}" =~ ${rx_msgid_empty} ]]; then
@@ -112,12 +118,13 @@ for language in ${language_list[*]}; do
str_source=$(echo "${str}" | sed -e "s/^msgid \"//" | sed -e "s/\"$//"); str_source=$(echo "${str}" | sed -e "s/^msgid \"//" | sed -e "s/\"$//");
# close right side, if not last add , # close right side, if not last add ,
if [ "${pos}" -eq 1 ]; then if [ "${pos}" -eq 1 ]; then
echo -n "," >> $file; echo -n "," >> "$file";
fi; fi;
# all " inside string need to be escaped # all " inside string need to be escaped
str_source=$(echo "${str_source}" | sed -e 's/"/\\"/g'); # str_source=$(echo "${str_source}" | sed -e 's/"/\\"/g');
str_source=${str_source//\"/\\\"}
# fix with proper layout # fix with proper layout
echo -n "\"$str_source\":\"$(TEXTDOMAINDIR=${TEXTDOMAINDIR} LANGUAGE=${language} LANG=${LANG} gettext ${TEXTDOMAIN} "${str_source}")\"" >> $file; echo -n "\"$str_source\":\"$(TEXTDOMAINDIR=${TEXTDOMAINDIR} LANGUAGE=${language} LANG=${LANG} gettext "${TEXTDOMAIN}" "${str_source}")\"" >> "$file";
pos=1; pos=1;
elif [[ "${str}" =~ ${rx_msgstr} ]]; then elif [[ "${str}" =~ ${rx_msgstr} ]]; then
# open right side (ignore) # open right side (ignore)
@@ -128,8 +135,8 @@ for language in ${language_list[*]}; do
fi; fi;
done; done;
echo "" >> $file; echo "" >> "$file";
echo "};" >> $file; echo "};" >> "$file";
echo " [DONE]"; echo " [DONE]";
# on no move # on no move
@@ -140,19 +147,19 @@ for language in ${language_list[*]}; do
fi; fi;
# symlink to master file # symlink to master file
for suffix in ${source_list[*]}; do for suffix in "${source_list[@]}"; do
# symlink with full lang name # symlink with full lang name
symlink_file[0]=$(echo ${template_file_stump} | sed -e "s/##SUFFIX##/${suffix}_/" | sed -e "s/##LANGUAGE##/${LANG}/" | sed -e 's/\.TMP//g'); symlink_file[0]=$(echo ${template_file_stump} | sed -e "s/##SUFFIX##/${suffix}_/" | sed -e "s/##LANGUAGE##/${LANG}/" | sed -e 's/\.TMP//g');
# create second one with lang (no country) + encoding # create second one with lang (no country) + encoding
symlink_file[1]=$(echo ${template_file_stump} | sed -e "s/##SUFFIX##/${suffix}_/" | sed -e "s/##LANGUAGE##/${LANGUAGE}\.${ENCODING}/" | sed -e 's/\.TMP//g'); symlink_file[1]=$(echo ${template_file_stump} | sed -e "s/##SUFFIX##/${suffix}_/" | sed -e "s/##LANGUAGE##/${LANGUAGE}\.${ENCODING}/" | sed -e 's/\.TMP//g');
for template_file in ${symlink_file[@]}; do for template_file in "${symlink_file[@]}"; do
# if this is not symlink, create them # if this is not symlink, create them
if [ ! -h "${template_file}" ]; then if [ ! -h "${template_file}" ]; then
echo "Create symlink: ${template_file}"; echo "Create symlink: ${template_file}";
# symlik to original # symlik to original
cd "${target_folder}"; cd "${target_folder}" || exit;
ln -sf "${original_file}" "${template_file}"; ln -sf "${original_file}" "${template_file}";
cd - >/dev/null; cd - >/dev/null || exit;
fi; fi;
done; done;
done; done;

View File

@@ -1,3 +1,5 @@
base="/storage/var/www/html/developers/clemens/core_data/php_libraries/trunk/"; base="/storage/var/www/html/developers/clemens/core_data/php_libraries/trunk/";
# must be run in ${base}www/ # must be run in ${base}
phan --progress-bar -C --analyze-twice cd $base;
${base}tools/phan --progress-bar -C --analyze-twice;
cd ~;

View File

@@ -1,3 +1,5 @@
base="/storage/var/www/html/developers/clemens/core_data/php_libraries/trunk/"; base="/storage/var/www/html/developers/clemens/core_data/php_libraries/trunk/";
# must be run in ${base}www/ # must be run in ${base}
phpstan cd $base;
${base}tools/phpstan;
cd ~;

View File

@@ -12,28 +12,31 @@ if [ "${1}" = "t" ] || [ "${2}" = "t" ]; then
opt_testdox="--testdox"; opt_testdox="--testdox";
fi; fi;
php_bin=""; php_bin="";
if [ ! -z "${1}" ]; then if [ -n "${1}" ]; then
case "${1}" in case "${1}" in
# "7.3") php_bin="/usr/bin/php7.3 "; ;; # "7.3") php_bin="/usr/bin/php7.3 "; ;;
"7.4") php_bin="/usr/bin/php7.4 "; ;; # "7.4") php_bin="/usr/bin/php7.4 "; ;;
"8.0") php_bin="/usr/bin/php8.0 "; ;; # "8.0") php_bin="/usr/bin/php8.0 "; ;;
"8.1") php_bin="/usr/bin/php8.1 "; ;; # "8.1") php_bin="/usr/bin/php8.1 "; ;;
"8.2") php_bin="/usr/bin/php8.2 "; ;; "8.2") php_bin="/usr/bin/php8.2 "; ;;
"8.3") php_bin="/usr/bin/php8.4 "; ;;
*) echo "Not support PHP: ${1}"; exit; ;; *) echo "Not support PHP: ${1}"; exit; ;;
esac; esac;
fi; fi;
if [ ! -z "${2}" ] && [ -z "${php_bin}" ]; then if [ -n "${2}" ] && [ -z "${php_bin}" ]; then
case "${2}" in case "${2}" in
# "7.3") php_bin="/usr/bin/php7.3 "; ;; # "7.3") php_bin="/usr/bin/php7.3 "; ;;
"7.4") php_bin="/usr/bin/php7.4 "; ;; # "7.4") php_bin="/usr/bin/php7.4 "; ;;
"8.0") php_bin="/usr/bin/php8.0 "; ;; # "8.0") php_bin="/usr/bin/php8.0 "; ;;
"8.1") php_bin="/usr/bin/php8.1 "; ;; # "8.1") php_bin="/usr/bin/php8.1 "; ;;
"8.2") php_bin="/usr/bin/php8.2 "; ;; "8.2") php_bin="/usr/bin/php8.2 "; ;;
"8.3") php_bin="/usr/bin/php8.3 "; ;;
*) echo "Not support PHP: ${1}"; exit; ;; *) echo "Not support PHP: ${1}"; exit; ;;
esac; esac;
fi; fi;
phpunit_call="${php_bin}${base}www/vendor/bin/phpunit ${opt_testdox} -c ${base}phpunit.xml ${base}4dev/tests/"; # Note 4dev/tests/bootstrap.php has to be set as bootstrap file in phpunit.xml
phpunit_call="${php_bin}${base}tools/phpunit ${opt_testdox} -c ${base}phpunit.xml ${base}4dev/tests/";
${phpunit_call}; ${phpunit_call};

View File

@@ -0,0 +1,22 @@
#!/bin/env bash
# syncs
# 4dev/tests/
# www/lib/CoreLibs/
#
# to the composer corelibs all repo
GO="${1}";
DRY_RUN="";
if [ "${GO}" != "go" ]; then
DRY_RUN="-n ";
fi;
BASE="/storage/var/www/html/developers/clemens/core_data/";
SOURCE="${BASE}php_libraries/trunk/"
TARGET="${BASE}composer-packages/CoreLibs-Composer-All/"
rsync ${DRY_RUN}-Plzvrupt --stats --delete ${SOURCE}4dev/tests/ ${TARGET}test/phpunit/
rsync ${DRY_RUN}-Plzvrupt --stats --delete ${SOURCE}www/lib/CoreLibs/ ${TARGET}src/
# __END__

View File

@@ -0,0 +1,31 @@
# DB Query Params ? and : to $
dbReturn*
dbExec
keep
->query
->params
for reference
## : named params
in order for each named found replace with order number:
```txt
:name, :foo, :bar, :name =>
$1, $2, $3, $1
```
```php
$query = str_replace(
[':name', ':foo', ':bar'],
['$1', '$2', '$3'],
$query
);
```
## ? Params
Foreach ? set $1 to $n and store that in new params array
in QUERY for each ? replace with matching $n

View File

@@ -1,4 +1,4 @@
#!/bin/bash #!/usr/bin/env bash
# create path # create path
path=$(pwd)"/"$0; path=$(pwd)"/"$0;
@@ -10,6 +10,11 @@ TARGET_HOST_WEB="<user>@<host>";
TMP_DIR=$LOCAL_BASE_DIR"/4dev/tmp/"; TMP_DIR=$LOCAL_BASE_DIR"/4dev/tmp/";
tmpf_web=$TMP_DIR"sync.exclude.tmp"; tmpf_web=$TMP_DIR"sync.exclude.tmp";
if [ ! -d "$LOCAL_BASE_DIR" ]; then
echo "Folder: $LOCAL_BASE_DIR not found";
exit;
fi;
# if vendor be sure group folder is +x # if vendor be sure group folder is +x
chmod -R ug+rX ${LOCAL_DIR}/vender/ chmod -R ug+rX ${LOCAL_DIR}/vender/

View File

@@ -0,0 +1,40 @@
<?php
declare(strict_types=1);
namespace tests;
use PHPUnit\Framework\TestCase;
/**
* Test base setup
* @testdox AAASetupData\AAASetupDataTest just setup BASE
*/
final class CoreLibsAAASetupDataTest extends TestCase
{
/**
* Covers nothing
*
* @testdox Just setup BASE
*
* @return void
*/
public function testSetupData(): void
{
if (!defined('BASE')) {
define(
'BASE',
str_replace('/configs', '', __DIR__)
. DIRECTORY_SEPARATOR
);
}
$this->assertEquals(
str_replace('/configs', '', __DIR__)
. DIRECTORY_SEPARATOR,
BASE,
'BASE Path set check'
);
}
}
// __END__

View File

@@ -0,0 +1 @@
../Language/includes/

1
4dev/tests/AAASetupData/log Symbolic link
View File

@@ -0,0 +1 @@
../Debug/log/

View File

@@ -7,6 +7,14 @@ namespace tests;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\MockObject\MockObject;
/*
Not yet covered tests:
- loginGetLocale
- loginGetHeaderColor
- loginGetPages
- loginGetEuid
*/
/** /**
* Test class for ACL\Login * Test class for ACL\Login
* @coversDefaultClass \CoreLibs\ACL\Login * @coversDefaultClass \CoreLibs\ACL\Login
@@ -60,13 +68,10 @@ final class CoreLibsACLLoginTest extends TestCase
// logger is always needed // logger is always needed
// define basic connection set valid and one invalid // define basic connection set valid and one invalid
self::$log = new \CoreLibs\Debug\Logging([ self::$log = new \CoreLibs\Logging\Logging([
// 'log_folder' => __DIR__ . DIRECTORY_SEPARATOR . 'log', // 'log_folder' => __DIR__ . DIRECTORY_SEPARATOR . 'log',
'log_folder' => DIRECTORY_SEPARATOR . 'tmp', 'log_folder' => DIRECTORY_SEPARATOR . 'tmp',
'file_id' => 'CoreLibs-ACL-Login-Test', 'log_file_id' => 'CoreLibs-ACL-Login-Test',
'debug_all' => true,
'echo_all' => false,
'print_all' => true,
]); ]);
// test database we need to connect do, if not possible this test is skipped // test database we need to connect do, if not possible this test is skipped
self::$db = new \CoreLibs\DB\IO( self::$db = new \CoreLibs\DB\IO(
@@ -120,8 +125,6 @@ final class CoreLibsACLLoginTest extends TestCase
// define('LOGIN_DB_SCHEMA', ''); // define('LOGIN_DB_SCHEMA', '');
// SHOULD SET // SHOULD SET
// PASSWORD_MIN_LENGTH (d9)
// PASSWORD_MAX_LENGTH (d255)
// DEFAULT_ACL_LEVEL (d80) // DEFAULT_ACL_LEVEL (d80)
// OPT: // OPT:
@@ -164,8 +167,10 @@ final class CoreLibsACLLoginTest extends TestCase
// change_password, pw_username, pw_old_password, pw_new_password, // change_password, pw_username, pw_old_password, pw_new_password,
// pw_new_password_confirm // pw_new_password_confirm
// 3[session]: override session set // 3[session]: override session set
// 4[error] : expected error code, 0 for all ok, 3000 for login page view // 4[error] : expected error code, 0 for all ok, 100 for login page view
// note that 1000 (no db), 2000 (no session) must be tested too // note that 1000 (no db), 2000 (no session), 3000 (options set error)
// must be tested too
// <1000 info, >=1000 critical error
// 5[return] : expected return array, eg login_error code, // 5[return] : expected return array, eg login_error code,
// or other info data to match // or other info data to match
$tests = [ $tests = [
@@ -177,7 +182,7 @@ final class CoreLibsACLLoginTest extends TestCase
[], [],
[], [],
[], [],
3000, 100,
[ [
'login_error' => 0, 'login_error' => 0,
'error_string' => 'Success: <b>No error</b>', 'error_string' => 'Success: <b>No error</b>',
@@ -195,7 +200,7 @@ final class CoreLibsACLLoginTest extends TestCase
[], [],
[], [],
[], [],
3000, 100,
[ [
'login_error' => 0, 'login_error' => 0,
'error_string' => 'Success: <b>No error</b>', 'error_string' => 'Success: <b>No error</b>',
@@ -218,7 +223,7 @@ final class CoreLibsACLLoginTest extends TestCase
[], [],
[], [],
[], [],
3000, 100,
[ [
'login_error' => 0, 'login_error' => 0,
'error_string' => 'Success: <b>No error</b>', 'error_string' => 'Success: <b>No error</b>',
@@ -261,6 +266,8 @@ final class CoreLibsACLLoginTest extends TestCase
'GROUP_ACL_LEVEL' => -1, 'GROUP_ACL_LEVEL' => -1,
'PAGES_ACL_LEVEL' => [], 'PAGES_ACL_LEVEL' => [],
'USER_ACL_LEVEL' => -1, 'USER_ACL_LEVEL' => -1,
'USER_ADDITIONAL_ACL' => [],
'GROUP_ADDITIONAL_ACL' => [],
'UNIT_UID' => [ 'UNIT_UID' => [
'AdminAccess' => 1, 'AdminAccess' => 1,
], ],
@@ -274,6 +281,7 @@ final class CoreLibsACLLoginTest extends TestCase
'data' => [ 'data' => [
'test' => 'value', 'test' => 'value',
], ],
'additional_acl' => []
], ],
], ],
// 'UNIT_DEFAULT' => '', // 'UNIT_DEFAULT' => '',
@@ -302,7 +310,7 @@ final class CoreLibsACLLoginTest extends TestCase
'login_password' => '', 'login_password' => '',
], ],
[], [],
3000, 100,
[ [
'login_error' => 102, 'login_error' => 102,
'error_string' => '<span style="color: red;">Fatal Error:</span> ' 'error_string' => '<span style="color: red;">Fatal Error:</span> '
@@ -323,7 +331,7 @@ final class CoreLibsACLLoginTest extends TestCase
'login_password' => 'abc', 'login_password' => 'abc',
], ],
[], [],
3000, 100,
[ [
'login_error' => 102, 'login_error' => 102,
'error_string' => '<span style="color: red;">Fatal Error:</span> ' 'error_string' => '<span style="color: red;">Fatal Error:</span> '
@@ -344,7 +352,7 @@ final class CoreLibsACLLoginTest extends TestCase
'login_password' => '', 'login_password' => '',
], ],
[], [],
3000, 100,
[ [
'login_error' => 102, 'login_error' => 102,
'error_string' => '<span style="color: red;">Fatal Error:</span> ' 'error_string' => '<span style="color: red;">Fatal Error:</span> '
@@ -365,7 +373,7 @@ final class CoreLibsACLLoginTest extends TestCase
'login_password' => 'abc', 'login_password' => 'abc',
], ],
[], [],
3000, 100,
[ [
'login_error' => 1010, 'login_error' => 1010,
'error_string' => '<span style="color: red;">Fatal Error:</span> ' 'error_string' => '<span style="color: red;">Fatal Error:</span> '
@@ -389,7 +397,7 @@ final class CoreLibsACLLoginTest extends TestCase
'login_password' => 'abc', 'login_password' => 'abc',
], ],
[], [],
3000, 100,
[ [
// default password is plain text // default password is plain text
'login_error' => 1012, 'login_error' => 1012,
@@ -415,7 +423,7 @@ final class CoreLibsACLLoginTest extends TestCase
'login_password' => 'admin', 'login_password' => 'admin',
], ],
[], [],
3000, 100,
[ [
'login_error' => 106, 'login_error' => 106,
'error_string' => '<span style="color: red;">Fatal Error:</span> ' 'error_string' => '<span style="color: red;">Fatal Error:</span> '
@@ -440,7 +448,7 @@ final class CoreLibsACLLoginTest extends TestCase
'login_password' => 'admin', 'login_password' => 'admin',
], ],
[], [],
3000, 100,
[ [
'login_error' => 104, 'login_error' => 104,
'error_string' => '<span style="color: red;">Fatal Error:</span> ' 'error_string' => '<span style="color: red;">Fatal Error:</span> '
@@ -465,7 +473,7 @@ final class CoreLibsACLLoginTest extends TestCase
'login_password' => 'admin', 'login_password' => 'admin',
], ],
[], [],
3000, 100,
[ [
'login_error' => 105, 'login_error' => 105,
'error_string' => '<span style="color: red;">Fatal Error:</span> ' 'error_string' => '<span style="color: red;">Fatal Error:</span> '
@@ -514,7 +522,7 @@ final class CoreLibsACLLoginTest extends TestCase
'login_password' => 'admin', 'login_password' => 'admin',
], ],
[], [],
3000, 100,
[ [
'login_error' => 107, 'login_error' => 107,
'error_string' => '<span style="color: red;">Fatal Error:</span> ' 'error_string' => '<span style="color: red;">Fatal Error:</span> '
@@ -568,7 +576,7 @@ final class CoreLibsACLLoginTest extends TestCase
'login_password' => 'admin', 'login_password' => 'admin',
], ],
[], [],
3000, 100,
[ [
'login_error' => 107, 'login_error' => 107,
'error_string' => '<span style="color: red;">Fatal Error:</span> ' 'error_string' => '<span style="color: red;">Fatal Error:</span> '
@@ -594,7 +602,7 @@ final class CoreLibsACLLoginTest extends TestCase
'login_password' => 'admin', 'login_password' => 'admin',
], ],
[], [],
3000, 100,
[ [
'login_error' => 107, 'login_error' => 107,
'error_string' => '<span style="color: red;">Fatal Error:</span> ' 'error_string' => '<span style="color: red;">Fatal Error:</span> '
@@ -619,7 +627,7 @@ final class CoreLibsACLLoginTest extends TestCase
'login_password' => 'admin', 'login_password' => 'admin',
], ],
[], [],
3000, 100,
[ [
'login_error' => 108, 'login_error' => 108,
'error_string' => '<span style="color: red;">Fatal Error:</span> ' 'error_string' => '<span style="color: red;">Fatal Error:</span> '
@@ -755,7 +763,7 @@ final class CoreLibsACLLoginTest extends TestCase
], ],
[], [],
[], [],
3000, 100,
[ [
'login_error' => 1010, 'login_error' => 1010,
'error_string' => '<span style="color: red;">Fatal Error:</span> ' 'error_string' => '<span style="color: red;">Fatal Error:</span> '
@@ -847,7 +855,7 @@ final class CoreLibsACLLoginTest extends TestCase
], ],
[], [],
[], [],
3000, 100,
[ [
'login_error' => 1101, 'login_error' => 1101,
'error_string' => '<span style="color: red;">Fatal Error:</span> ' 'error_string' => '<span style="color: red;">Fatal Error:</span> '
@@ -903,7 +911,7 @@ final class CoreLibsACLLoginTest extends TestCase
], ],
[], [],
[], [],
3000, 100,
[ [
'login_error' => 1102, 'login_error' => 1102,
'error_string' => '<span style="color: red;">Fatal Error:</span> ' 'error_string' => '<span style="color: red;">Fatal Error:</span> '
@@ -959,7 +967,7 @@ final class CoreLibsACLLoginTest extends TestCase
], ],
[], [],
[], [],
3000, 100,
[ [
'login_error' => 1102, 'login_error' => 1102,
'error_string' => '<span style="color: red;">Fatal Error:</span> ' 'error_string' => '<span style="color: red;">Fatal Error:</span> '
@@ -986,7 +994,7 @@ final class CoreLibsACLLoginTest extends TestCase
], ],
[], [],
[], [],
3000, 100,
[ [
'login_error' => 1102, 'login_error' => 1102,
'error_string' => '<span style="color: red;">Fatal Error:</span> ' 'error_string' => '<span style="color: red;">Fatal Error:</span> '
@@ -1106,13 +1114,28 @@ final class CoreLibsACLLoginTest extends TestCase
/** @var \CoreLibs\ACL\Login&MockObject */ /** @var \CoreLibs\ACL\Login&MockObject */
$login_mock = $this->getMockBuilder(\CoreLibs\ACL\Login::class) $login_mock = $this->getMockBuilder(\CoreLibs\ACL\Login::class)
->setConstructorArgs([self::$db, self::$log, $session_mock, false]) ->setConstructorArgs([
self::$db,
self::$log,
$session_mock,
[
'auto_login' => false,
'default_acl_level' => 80,
'logout_target' => '',
'site_locale' => 'en_US.UTF-8',
'site_domain' => 'admin',
'site_encoding' => 'UTF-8',
'locale_path' => __DIR__ . DIRECTORY_SEPARATOR
. 'includes' . DIRECTORY_SEPARATOR
. 'locale' . DIRECTORY_SEPARATOR,
]
])
->onlyMethods(['loginTerminate', 'loginReadPageName', 'loginPrintLogin']) ->onlyMethods(['loginTerminate', 'loginReadPageName', 'loginPrintLogin'])
->getMock(); ->getMock();
$login_mock->expects($this->any()) $login_mock->expects($this->any())
->method('loginTerminate') ->method('loginTerminate')
->will( ->will(
$this->returnCallback(function ($code) { $this->returnCallback(function ($message, $code) {
throw new \Exception('', $code); throw new \Exception('', $code);
}) })
); );
@@ -1206,7 +1229,11 @@ final class CoreLibsACLLoginTest extends TestCase
$login_mock->loginSetMaxLoginErrorCount($mock_settings['max_login_error_count']); $login_mock->loginSetMaxLoginErrorCount($mock_settings['max_login_error_count']);
// temporary wrong password // temporary wrong password
$_POST['login_password'] = 'wrong'; $_POST['login_password'] = 'wrong';
for ($run = 1, $max_run = $login_mock->loginGetMaxLoginErrorCount(); $run <= $max_run; $run++) { for (
$run = 1, $max_run = $login_mock->loginGetMaxLoginErrorCount();
$run <= $max_run;
$run++
) {
try { try {
$login_mock->loginMainCall(); $login_mock->loginMainCall();
} catch (\Exception $e) { } catch (\Exception $e) {
@@ -1454,10 +1481,10 @@ final class CoreLibsACLLoginTest extends TestCase
// print "AJAX: " . $login_mock->loginGetAjaxFlag() . "\n"; // print "AJAX: " . $login_mock->loginGetAjaxFlag() . "\n";
// print "AJAX GLOBAL: " . ($GLOBALS['AJAX_PAGE'] ?? '{f}') . "\n"; // print "AJAX GLOBAL: " . ($GLOBALS['AJAX_PAGE'] ?? '{f}') . "\n";
// print "Login error expext: " . ($expected['login_error'] ?? '{0}') . "\n"; // print "Login error expext: " . ($expected['login_error'] ?? '{0}') . "\n";
// if this is 3000, then we do further error checks // if this is 100, then we do further error checks
if ( if (
$e->getCode() == 3000 || $e->getCode() == 100 ||
!empty($_POST['login_exit']) && $_POST['login_exit'] == 3000 !empty($_POST['login_exit']) && $_POST['login_exit'] == 100
) { ) {
$this->assertEquals( $this->assertEquals(
$expected['login_error'], $expected['login_error'],
@@ -1729,7 +1756,7 @@ final class CoreLibsACLLoginTest extends TestCase
], ],
20 20
], ],
'invalud search' => [ 'invalid search' => [
12, 12,
'foo', 'foo',
[], [],
@@ -1774,13 +1801,28 @@ final class CoreLibsACLLoginTest extends TestCase
); );
/** @var \CoreLibs\ACL\Login&MockObject */ /** @var \CoreLibs\ACL\Login&MockObject */
$login_mock = $this->getMockBuilder(\CoreLibs\ACL\Login::class) $login_mock = $this->getMockBuilder(\CoreLibs\ACL\Login::class)
->setConstructorArgs([self::$db, self::$log, $session_mock, false]) ->setConstructorArgs([
self::$db,
self::$log,
$session_mock,
[
'auto_login' => false,
'default_acl_level' => 80,
'logout_target' => '',
'site_locale' => 'en_US.UTF-8',
'site_domain' => 'admin',
'site_encoding' => 'UTF-8',
'locale_path' => __DIR__ . DIRECTORY_SEPARATOR
. 'includes' . DIRECTORY_SEPARATOR
. 'locale' . DIRECTORY_SEPARATOR,
]
])
->onlyMethods(['loginTerminate']) ->onlyMethods(['loginTerminate'])
->getMock(); ->getMock();
$login_mock->expects($this->any()) $login_mock->expects($this->any())
->method('loginTerminate') ->method('loginTerminate')
->will( ->will(
$this->returnCallback(function ($code) { $this->returnCallback(function ($message, $code) {
throw new \Exception('', $code); throw new \Exception('', $code);
}) })
); );
@@ -1873,13 +1915,28 @@ final class CoreLibsACLLoginTest extends TestCase
); );
/** @var \CoreLibs\ACL\Login&MockObject */ /** @var \CoreLibs\ACL\Login&MockObject */
$login_mock = $this->getMockBuilder(\CoreLibs\ACL\Login::class) $login_mock = $this->getMockBuilder(\CoreLibs\ACL\Login::class)
->setConstructorArgs([self::$db, self::$log, $session_mock, false]) ->setConstructorArgs([
self::$db,
self::$log,
$session_mock,
[
'auto_login' => false,
'default_acl_level' => 80,
'logout_target' => '',
'site_locale' => 'en_US.UTF-8',
'site_domain' => 'admin',
'site_encoding' => 'UTF-8',
'locale_path' => __DIR__ . DIRECTORY_SEPARATOR
. 'includes' . DIRECTORY_SEPARATOR
. 'locale' . DIRECTORY_SEPARATOR,
]
])
->onlyMethods(['loginTerminate']) ->onlyMethods(['loginTerminate'])
->getMock(); ->getMock();
$login_mock->expects($this->any()) $login_mock->expects($this->any())
->method('loginTerminate') ->method('loginTerminate')
->will( ->will(
$this->returnCallback(function ($code) { $this->returnCallback(function ($message, $code) {
throw new \Exception('', $code); throw new \Exception('', $code);
}) })
); );
@@ -1946,13 +2003,28 @@ final class CoreLibsACLLoginTest extends TestCase
); );
/** @var \CoreLibs\ACL\Login&MockObject */ /** @var \CoreLibs\ACL\Login&MockObject */
$login_mock = $this->getMockBuilder(\CoreLibs\ACL\Login::class) $login_mock = $this->getMockBuilder(\CoreLibs\ACL\Login::class)
->setConstructorArgs([self::$db, self::$log, $session_mock, false]) ->setConstructorArgs([
self::$db,
self::$log,
$session_mock,
[
'auto_login' => false,
'default_acl_level' => 80,
'logout_target' => '',
'site_locale' => 'en_US.UTF-8',
'site_domain' => 'admin',
'site_encoding' => 'UTF-8',
'locale_path' => __DIR__ . DIRECTORY_SEPARATOR
. 'includes' . DIRECTORY_SEPARATOR
. 'locale' . DIRECTORY_SEPARATOR,
]
])
->onlyMethods(['loginTerminate']) ->onlyMethods(['loginTerminate'])
->getMock(); ->getMock();
$login_mock->expects($this->any()) $login_mock->expects($this->any())
->method('loginTerminate') ->method('loginTerminate')
->will( ->will(
$this->returnCallback(function ($code) { $this->returnCallback(function ($message, $code) {
throw new \Exception('', $code); throw new \Exception('', $code);
}) })
); );
@@ -2027,13 +2099,28 @@ final class CoreLibsACLLoginTest extends TestCase
); );
/** @var \CoreLibs\ACL\Login&MockObject */ /** @var \CoreLibs\ACL\Login&MockObject */
$login_mock = $this->getMockBuilder(\CoreLibs\ACL\Login::class) $login_mock = $this->getMockBuilder(\CoreLibs\ACL\Login::class)
->setConstructorArgs([self::$db, self::$log, $session_mock, false]) ->setConstructorArgs([
self::$db,
self::$log,
$session_mock,
[
'auto_login' => false,
'default_acl_level' => 80,
'logout_target' => '',
'site_locale' => 'en_US.UTF-8',
'site_domain' => 'admin',
'site_encoding' => 'UTF-8',
'locale_path' => __DIR__ . DIRECTORY_SEPARATOR
. 'includes' . DIRECTORY_SEPARATOR
. 'locale' . DIRECTORY_SEPARATOR,
]
])
->onlyMethods(['loginTerminate']) ->onlyMethods(['loginTerminate'])
->getMock(); ->getMock();
$login_mock->expects($this->any()) $login_mock->expects($this->any())
->method('loginTerminate') ->method('loginTerminate')
->will( ->will(
$this->returnCallback(function ($code) { $this->returnCallback(function ($message, $code) {
throw new \Exception('', $code); throw new \Exception('', $code);
}) })
); );

1
4dev/tests/ACL/includes Symbolic link
View File

@@ -0,0 +1 @@
../AAASetupData/includes

View File

@@ -13,6 +13,11 @@ use PHPUnit\Framework\TestCase;
*/ */
final class CoreLibsCheckColorsTest extends TestCase final class CoreLibsCheckColorsTest extends TestCase
{ {
/**
* Undocumented function
*
* @return array<mixed>
*/
public function validateColorProvider(): array public function validateColorProvider(): array
{ {
/* /*
@@ -321,7 +326,7 @@ final class CoreLibsCheckColorsTest extends TestCase
*/ */
public function testValidateColorException(int $flag): void public function testValidateColorException(int $flag): void
{ {
$this->expectException(\Exception::class); $this->expectException(\UnexpectedValueException::class);
\CoreLibs\Check\Colors::validateColor('#ffffff', $flag); \CoreLibs\Check\Colors::validateColor('#ffffff', $flag);
} }
} }

View File

@@ -28,10 +28,10 @@ final class CoreLibsCheckFileTest extends TestCase
public function filesList(): array public function filesList(): array
{ {
return [ return [
['filename.txt', 'txt', 5], ['filename.txt', 'txt', 5, 'text/plain'],
['filename.csv', 'csv', 15], ['filename.csv', 'csv', 15, 'text/csv'],
['filename.tsv', 'tsv', 0], ['filename.tsv', 'tsv', 0, 'text/plain'],
['file_does_not_exits', '', -1], ['file_does_not_exits', '', -1, ''],
]; ];
} }
@@ -63,6 +63,15 @@ final class CoreLibsCheckFileTest extends TestCase
return $list; return $list;
} }
public function mimeTypeProvider(): array
{
$list = [];
foreach ($this->filesList() as $row) {
$list[$row[0] . ' must be mime type ' . $row[3]] = [$row[0], $row[3]];
}
return $list;
}
/** /**
* Tests if file extension matches * Tests if file extension matches
* *
@@ -115,6 +124,51 @@ final class CoreLibsCheckFileTest extends TestCase
unlink($this->base_folder . $input); unlink($this->base_folder . $input);
} }
} }
/**
* Undocumented function
*
* @covers ::getMimeType
* @dataProvider mimeTypeProvider
* @testdox getMimeType $input must be mime type $expected [$_dataName]
*
* @param string $input
* @param string $expected
* @return void
*/
public function testGetMimeType(string $input, string $expected): void
{
if (!empty($expected)) {
$file = $this->base_folder . $input;
$fp = fopen($file, 'w');
switch ($expected) {
case 'text/csv':
for ($i = 1; $i <= 10; $i++) {
fwrite($fp, '"This is row","' . $expected . '",' . $i . PHP_EOL);
}
break;
case 'text/tsv':
for ($i = 1; $i <= 10; $i++) {
fwrite($fp, "\"This is row\"\t\"" . $expected . "\"\t\"" . $i . PHP_EOL);
}
break;
case 'text/plain':
fwrite($fp, 'This is mime type: ' . $expected . PHP_EOL);
break;
}
fclose($fp);
} else {
$this->expectException(\UnexpectedValueException::class);
}
$this->assertEquals(
$expected,
\CoreLibs\Check\File::getMimeType($this->base_folder . $input)
);
// unlink file
if (is_file($this->base_folder . $input)) {
unlink($this->base_folder . $input);
}
}
} }
// __END__ // __END__

View File

@@ -31,6 +31,7 @@ final class CoreLibsCombinedArrayHandlerTest extends TestCase
4, 4,
'b', 'b',
'c' => 'test', 'c' => 'test',
'single' => 'single',
'same' => 'same', 'same' => 'same',
'deep' => [ 'deep' => [
'sub' => [ 'sub' => [
@@ -107,6 +108,13 @@ final class CoreLibsCombinedArrayHandlerTest extends TestCase
*/ */
public function arraySearchRecursiveAllProvider(): array public function arraySearchRecursiveAllProvider(): array
{ {
/*
0: $needle,
1: array $input,
2: ?string $key_search_for,
3: bool $flag,
4: array $expected
*/
return [ return [
'find value' => [ 'find value' => [
0 => 'bar', 0 => 'bar',
@@ -172,6 +180,13 @@ final class CoreLibsCombinedArrayHandlerTest extends TestCase
*/ */
public function arraySearchSimpleProvider(): array public function arraySearchSimpleProvider(): array
{ {
/*
0: array $input,
1: $key,
2: $value,
3: bool $flag,
4: bool $expected
*/
return [ return [
'key/value exist' => [ 'key/value exist' => [
0 => self::$array, 0 => self::$array,
@@ -274,6 +289,188 @@ final class CoreLibsCombinedArrayHandlerTest extends TestCase
]; ];
} }
/**
* Undocumented function
*
* @return array
*/
public function arraySearchKeyProvider(): array
{
/*
0: search in array
1: search keys
2: flat flag
3: prefix flag
4: expected array
*/
return [
// single
'find single, standard' => [
0 => self::$array,
1 => ['single'],
2 => null,
3 => null,
4 => [
0 => [
'value' => 'single',
'path' => ['single'],
],
],
],
'find single, prefix' => [
0 => self::$array,
1 => ['single'],
2 => null,
3 => true,
4 => [
'single' => [
0 => [
'value' => 'single',
'path' => ['single'],
],
],
],
],
'find single, flat' => [
0 => self::$array,
1 => ['single'],
2 => true,
3 => null,
4 => [
'single',
],
],
'find single, flat, prefix' => [
0 => self::$array,
1 => ['single'],
2 => true,
3 => true,
4 => [
'single' => [
'single',
],
],
],
// not found
'not found, standard' => [
0 => self::$array,
1 => ['NOT FOUND'],
2 => null,
3 => null,
4 => [],
],
'not found, standard, prefix' => [
0 => self::$array,
1 => ['NOT FOUND'],
2 => null,
3 => true,
4 => [
'NOT FOUND' => [],
],
],
'not found, flat' => [
0 => self::$array,
1 => ['NOT FOUND'],
2 => true,
3 => null,
4 => [],
],
'not found, flat, prefix' => [
0 => self::$array,
1 => ['NOT FOUND'],
2 => true,
3 => true,
4 => [
'NOT FOUND' => [],
],
],
// multi
'multiple found, standard' => [
0 => self::$array,
1 => ['same'],
2 => null,
3 => null,
4 => [
[
'value' => 'same',
'path' => ['a', 'same', ],
],
[
'value' => 'same',
'path' => ['same', ],
],
[
'value' => 'same',
'path' => ['deep', 'sub', 'same', ],
],
]
],
'multiple found, flat' => [
0 => self::$array,
1 => ['same'],
2 => true,
3 => null,
4 => ['same', 'same', 'same', ],
],
// search with multiple
'search multiple, standard' => [
0 => self::$array,
1 => ['single', 'nested'],
2 => null,
3 => null,
4 => [
[
'value' => 'single',
'path' => ['single'],
],
[
'value' => 'bar',
'path' => ['deep', 'sub', 'nested', ],
],
],
],
'search multiple, prefix' => [
0 => self::$array,
1 => ['single', 'nested'],
2 => null,
3 => true,
4 => [
'single' => [
[
'value' => 'single',
'path' => ['single'],
],
],
'nested' => [
[
'value' => 'bar',
'path' => ['deep', 'sub', 'nested', ],
],
],
],
],
'search multiple, flat' => [
0 => self::$array,
1 => ['single', 'nested'],
2 => true,
3 => null,
4 => [
'single', 'bar',
],
],
'search multiple, flat, prefix' => [
0 => self::$array,
1 => ['single', 'nested'],
2 => true,
3 => true,
4 => [
'single' => ['single', ],
'nested' => ['bar', ],
],
],
];
}
/** /**
* provides array listing for the merge test * provides array listing for the merge test
* *
@@ -321,17 +518,20 @@ final class CoreLibsCombinedArrayHandlerTest extends TestCase
return [ return [
// error <2 arguments // error <2 arguments
'too view arguments' => [ 'too view arguments' => [
'ArgumentCountError',
'arrayMergeRecursive needs two or more array arguments', 'arrayMergeRecursive needs two or more array arguments',
[1] [1]
], ],
// error <2 arrays // error <2 arrays
'only one array' => [ 'only one array' => [
'ArgumentCountError',
'arrayMergeRecursive needs two or more array arguments', 'arrayMergeRecursive needs two or more array arguments',
[1], [1],
true, true,
], ],
// error element is not array // error element is not array
'non array between array' => [ 'non array between array' => [
'TypeError',
'arrayMergeRecursive encountered a non array argument', 'arrayMergeRecursive encountered a non array argument',
[1], [1],
'string', 'string',
@@ -665,7 +865,7 @@ final class CoreLibsCombinedArrayHandlerTest extends TestCase
* *
* @param array $input * @param array $input
* @param string|int $key * @param string|int $key
* @param string|int $value * @param string|int|bool $value
* @param bool $expected * @param bool $expected
* @return void * @return void
*/ */
@@ -677,6 +877,44 @@ final class CoreLibsCombinedArrayHandlerTest extends TestCase
); );
} }
/**
* Undocumented function
*
* @covers::arraySearchKey
* @dataProvider arraySearchKeyProvider
* @testdox arraySearchKey Search array with keys and flat: $flat, prefix: $prefix [$_dataName]
*
* @param array $input
* @param array $needles
* @param bool|null $flat
* @param bool|null $prefix
* @param array $expected
* @return void
*/
public function testArraySearchKey(
array $input,
array $needles,
?bool $flat,
?bool $prefix,
array $expected
): void {
if ($flat === null && $prefix === null) {
$result = \CoreLibs\Combined\ArrayHandler::arraySearchKey($input, $needles);
} elseif ($flat === null) {
$result = \CoreLibs\Combined\ArrayHandler::arraySearchKey($input, $needles, prefix: $prefix);
} elseif ($prefix === null) {
$result = \CoreLibs\Combined\ArrayHandler::arraySearchKey($input, $needles, flat: $flat);
} else {
$result = \CoreLibs\Combined\ArrayHandler::arraySearchKey($input, $needles, $flat, $prefix);
}
// print "E: " . print_r($expected, true) . "\n";
// print "R: " . print_r($result, true) . "\n";
$this->assertEquals(
$expected,
$result
);
}
/** /**
* Undocumented function * Undocumented function
* *
@@ -712,19 +950,21 @@ final class CoreLibsCombinedArrayHandlerTest extends TestCase
*/ */
public function testArrayMergeRecursiveWarningA(): void public function testArrayMergeRecursiveWarningA(): void
{ {
set_error_handler( // set_error_handler(
static function (int $errno, string $errstr): never { // static function (int $errno, string $errstr): never {
throw new Exception($errstr, $errno); // throw new Exception($errstr, $errno);
}, // },
E_USER_WARNING // E_USER_WARNING
); // );
$arrays = func_get_args(); $arrays = func_get_args();
// first is expected warning // first is expected warning
$exception = array_shift($arrays);
$warning = array_shift($arrays); $warning = array_shift($arrays);
// phpunit 10.0 compatible // phpunit 10.0 compatible
$this->expectExceptionMessage(($warning)); $this->expectException($exception);
$this->expectExceptionMessage($warning);
\CoreLibs\Combined\ArrayHandler::arrayMergeRecursive(...$arrays); \CoreLibs\Combined\ArrayHandler::arrayMergeRecursive(...$arrays);
@@ -858,16 +1098,109 @@ final class CoreLibsCombinedArrayHandlerTest extends TestCase
* @testdox arrayFlatForKey array $input will be $expected [$_dataName] * @testdox arrayFlatForKey array $input will be $expected [$_dataName]
* *
* @param array $input * @param array $input
* @param string $search
* @param array $expected * @param array $expected
* @return void * @return void
*/ */
public function testArrayFlatForKey(array $input, $search, array $expected): void public function testArrayFlatForKey(array $input, string $search, array $expected): void
{ {
$this->assertEquals( $this->assertEquals(
$expected, $expected,
\CoreLibs\Combined\ArrayHandler::arrayFlatForKey($input, $search) \CoreLibs\Combined\ArrayHandler::arrayFlatForKey($input, $search)
); );
} }
/**
* Undocumented function
*
* @return array
*/
public function providerArrayGetNextPrevKey(): array
{
return [
'find, ok' => [
'input' => [
'a' => 'First',
'b' => 'Second',
'c' => 'Third',
],
'b',
'a',
'c'
],
'find, first' => [
'input' => [
'a' => 'First',
'b' => 'Second',
'c' => 'Third',
],
'a',
null,
'b'
],
'find, last' => [
'input' => [
'a' => 'First',
'b' => 'Second',
'c' => 'Third',
],
'c',
'b',
null
],
'find, not found' => [
'input' => [
'a' => 'First',
'b' => 'Second',
'c' => 'Third',
],
'z',
null,
null
],
'int, index' => [
'input' => [
'a',
'b',
'c'
],
1,
0,
2
]
];
}
/**
* Undocumented function
*
* @covers ::arrayGetPrevKey, ::arrayGetNextKey
* @dataProvider providerArrayGetNextPrevKey
* @testdox arrayGetNextPrevKey get next/prev key for $search wtih $expected_prev/$expected_next [$_dataName]
*
* @param array $input
* @param int|string $search
* @param int|string|null $expected_prev
* @param int|string|null $expected_next
* @return void
*/
public function testArrayGetNextPrevKey(
array $input,
int|string $search,
int|string|null $expected_prev,
int|string|null $expected_next
): void {
$this->assertEquals(
$expected_prev,
\CoreLibs\Combined\ArrayHandler::arrayGetPrevKey($input, $search),
'Find prev key in array'
);
$this->assertEquals(
$expected_next,
\CoreLibs\Combined\ArrayHandler::arrayGetNextKey($input, $search),
'Find next key in array'
);
}
} }
// __END__ // __END__

View File

@@ -66,6 +66,34 @@ final class CoreLibsCombinedDateTimeTest extends TestCase
]; ];
} }
/**
* date string convert test
*
* @covers ::dateStringFormat
* @dataProvider timestampProvider
* @testdox dateStringFormat $input (microtime $flag) will be $expected [$_dataName]
*
* @param int|float $input
* @param bool $flag
* @param string $expected
* @return void
*/
public function testDateStringFormat(
$input,
bool $flag_show_micro,
bool $flag_micro_as_float,
string $expected
): void {
$this->assertEquals(
$expected,
\CoreLibs\Combined\DateTime::dateStringFormat(
$input,
$flag_show_micro,
$flag_micro_as_float
)
);
}
/** /**
* interval for both directions * interval for both directions
* *
@@ -74,6 +102,11 @@ final class CoreLibsCombinedDateTimeTest extends TestCase
public function intervalProvider(): array public function intervalProvider(): array
{ {
return [ return [
'on hour' => [
3600,
false,
'1h 0m 0s'
],
'interval no microtime' => [ 'interval no microtime' => [
1641515890, 1641515890,
false, false,
@@ -82,7 +115,7 @@ final class CoreLibsCombinedDateTimeTest extends TestCase
'interval with microtime' => [ 'interval with microtime' => [
1641515890, 1641515890,
true, true,
'18999d 0h 38m 10s', '18999d 0h 38m 10s 0ms',
], ],
'micro interval no microtime' => [ 'micro interval no microtime' => [
1641515890.123456, 1641515890.123456,
@@ -92,7 +125,7 @@ final class CoreLibsCombinedDateTimeTest extends TestCase
'micro interval with microtime' => [ 'micro interval with microtime' => [
1641515890.123456, 1641515890.123456,
true, true,
'18999d 0h 38m 10s 1235ms', '18999d 0h 38m 10s 124ms',
], ],
'negative interval no microtime' => [ 'negative interval no microtime' => [
-1641515890, -1641515890,
@@ -103,27 +136,27 @@ final class CoreLibsCombinedDateTimeTest extends TestCase
'microtime only' => [ 'microtime only' => [
0.123456, 0.123456,
true, true,
'0s 1235ms', '0s 123ms',
], ],
'seconds only' => [ 'seconds only' => [
30.123456, 30.123456,
true, true,
'30s 1235ms', '30s 123ms',
], ],
'minutes only' => [ 'minutes only' => [
90.123456, 90.123456,
true, true,
'1m 30s 1235ms', '1m 30s 123ms',
], ],
'hours only' => [ 'hours only' => [
3690.123456, 3690.123456,
true, true,
'1h 1m 30s 1235ms', '1h 1m 30s 123ms',
], ],
'days only' => [ 'days only' => [
90090.123456, 90090.123456,
true, true,
'1d 1h 1m 30s 1235ms', '1d 1h 1m 30s 123ms',
], ],
'already set' => [ 'already set' => [
'1d 1h 1m 30s 1235ms', '1d 1h 1m 30s 1235ms',
@@ -143,6 +176,306 @@ final class CoreLibsCombinedDateTimeTest extends TestCase
]; ];
} }
/**
* time seconds convert test
*
* @covers ::timeStringFormat
* @dataProvider intervalProvider
* @testdox timeStringFormat $input (microtime $flag) will be $expected [$_dataName]
*
* @param string|int|float $input
* @param bool $flag
* @param string $expected
* @return void
*/
public function testTimeStringFormat(string|int|float $input, bool $flag, string $expected): void
{
$this->assertEquals(
$expected,
\CoreLibs\Combined\DateTime::timeStringFormat($input, $flag)
);
}
/**
* interval seconds convert
*
* @covers ::intervalStringFormat
* @dataProvider intervalProvider
* @testdox intervalStringFormat $input (microtime $show_micro) will be $expected [$_dataName]
*
* @param string|int|float $input
* @param bool $show_micro
* @param string $expected
* @return void
*/
public function testIntervalStringFormat(string|int|float $input, bool $show_micro, string $expected): void
{
// we skip string input, that is not allowed
if (is_string($input)) {
$this->assertTrue(true, 'Skip strings');
return;
}
// invalid values throw exception in default
if ($input == 999999999999999) {
$this->expectException(\LengthException::class);
}
// below is equal to timeStringFormat
$this->assertEquals(
$expected,
\CoreLibs\Combined\DateTime::intervalStringFormat(
$input,
show_microseconds: $show_micro,
show_only_days: true,
skip_zero: false,
skip_last_zero: false,
truncate_nanoseconds: true,
truncate_zero_seconds_if_microseconds: false
)
);
}
/**
* Undocumented function
*
* @return array
*/
public function intervalExtendedProvider(): array
{
return [
// A
'(60) default value' => [
[
'seconds' => 60,
],
'expected' => '1m',
'exception' => null
],
'(60) default value, skip_last_zero:false' => [
[
'seconds' => 60,
'skip_last_zero' => false,
],
'expected' => '1m 0s 0ms',
'exception' => null
],
// B
'(120.1) default value' => [
[
'seconds' => 120.1,
],
'expected' => '2m 100ms',
'exception' => null
],
'(120.1) default value, skip_zero:false' => [
[
'seconds' => 120.1,
'skip_zero' => false,
],
'expected' => '2m 0s 100ms',
'exception' => null
],
'(120.1) default value, skip_last_zero:false' => [
[
'seconds' => 120.1,
'skip_last_zero' => false,
],
'expected' => '2m 100ms',
'exception' => null
],
// C
'(3601) default value' => [
[
'seconds' => 3601,
],
'expected' => '1h 1s',
'exception' => null
],
'(3601) default value, skip_zero:false' => [
[
'seconds' => 3601,
'skip_zero' => false,
],
'expected' => '1h 0m 1s',
'exception' => null
],
'(3601) default value, skip_last_zero:false' => [
[
'seconds' => 3601,
'skip_last_zero' => false,
],
'expected' => '1h 1s 0ms',
'exception' => null
],
// TODO create unit tests for ALL edge cases
// CREATE abort tests, simple, all others are handled in exception tests
'exception: \UnexpectedValueException:1' => [
[
'seconds' => 99999999999999999999999
],
'expected' => null,
'exception' => [
'class' => \UnexpectedValueException::class,
'code' => 1,
],
]
];
}
/**
* test all options for interval conversion
*
* @covers ::intervalStringFormat
* @dataProvider intervalExtendedProvider
* @testdox intervalStringFormat $input will be $expected / $exception [$_dataName]
*
* @param array<string,null|int|float|bool> $parameter_list
* @param string $expected
* @param array<string,mixed> $exception
* @return void
*/
public function testExtendedIntervalStringFormat(
array $parameter_list,
?string $expected,
?array $exception
): void {
if ($expected === null && $exception === null) {
$this->assertFalse(true, 'Cannot have expected and exception null in test data');
}
$parameters = [];
foreach (
[
'seconds' => null,
'truncate_after' => '',
'natural_seperator' => false,
'name_space_seperator' => false,
'show_microseconds' => true,
'short_time_name' => true,
'skip_last_zero' => true,
'skip_zero' => true,
'show_only_days' => false,
'auto_fix_microseconds' => false,
'truncate_nanoseconds' => false,
'truncate_zero_seconds_if_microseconds' => true,
] as $param => $default
) {
if (empty($parameter_list[$param]) && $default === null) {
$this->assertFalse(true, 'Parameter ' . $param . ' is mandatory ');
} elseif (!isset($parameter_list[$param]) || $parameter_list[$param] === null) {
$parameters[] = $default;
} else {
$parameters[] = $parameter_list[$param];
}
}
if ($expected !== null) {
$this->assertEquals(
$expected,
call_user_func_array('CoreLibs\Combined\DateTime::intervalStringFormat', $parameters)
);
} else {
if (empty($exception['class']) || empty($exception['code'])) {
$this->assertFalse(true, 'Exception tests need Exception name and Code');
}
$this->expectException($exception['class']);
$this->expectExceptionCode($exception['code']);
// if we have a message, must be regex
if (!empty($exception['message'])) {
$this->expectExceptionMessageMatches($exception['message']);
}
call_user_func_array('CoreLibs\Combined\DateTime::intervalStringFormat', $parameters);
}
}
/**
* Undocumented function
*
* @return array<mixed>
*/
public function exceptionsIntervalProvider(): array
{
return [
'UnexpectedValueException: 1 A' => [
'seconds' => 99999999999999999999999,
'params' => [],
'exception' => \UnexpectedValueException::class,
'exception_message' => "/^Seconds value is invalid, too large or more than six decimals: /",
'excpetion_code' => 1,
],
'UnexpectedValueException: 1 B' => [
'seconds' => 123.1234567,
'params' => [],
'exception' => \UnexpectedValueException::class,
'exception_message' => "/^Seconds value is invalid, too large or more than six decimals: /",
'excpetion_code' => 1,
],
// exception 2 is very likely covered by exception 1
'LengthException: 3' => [
'seconds' => 999999999999999999,
'params' => [
'show_only_days',
],
'exception' => \LengthException::class,
'exception_message' => "/^Input seconds value is too large for days output: /",
'excpetion_code' => 3,
],
'UnexpectedValueException: 4' => [
'seconds' => 1234567,
'params' => [
'truncate_after'
],
'exception' => \UnexpectedValueException::class,
'exception_message' => "/^truncate_after has an invalid value: /",
'excpetion_code' => 4,
],
'UnexpectedValueException: 5' => [
'seconds' => 1234567,
'params' => [
'show_only_days:truncate_after'
],
'exception' => \UnexpectedValueException::class,
'exception_message' =>
"/^If show_only_days is turned on, the truncate_after cannot be years or months: /",
'excpetion_code' => 5,
]
];
}
/**
* Test all exceptions
*
* @covers ::intervalStringFormat
* @dataProvider exceptionsIntervalProvider
* @testdox intervalStringFormat: test Exceptions
*
* @param int|float $seconds
* @param array<string> $params
* @param string $exception
* @param string $exception_message
* @param int $excpetion_code
* @return void
*/
public function testExceptionsIntervalStringFormat(
int|float $seconds,
array $params,
string $exception,
string $exception_message,
int $excpetion_code,
): void {
$this->expectException($exception);
$this->expectExceptionMessageMatches($exception_message);
$this->expectExceptionCode($excpetion_code);
if (empty($params)) {
\CoreLibs\Combined\DateTime::intervalStringFormat($seconds);
} else {
if (in_array('show_only_days', $params)) {
\CoreLibs\Combined\DateTime::intervalStringFormat($seconds, show_only_days:true);
} elseif (in_array('truncate_after', $params)) {
\CoreLibs\Combined\DateTime::intervalStringFormat($seconds, truncate_after: 'v');
} elseif (in_array('show_only_days:truncate_after', $params)) {
\CoreLibs\Combined\DateTime::intervalStringFormat($seconds, show_only_days:true, truncate_after: 'y');
}
}
}
/** /**
* Undocumented function * Undocumented function
* *
@@ -203,6 +536,25 @@ final class CoreLibsCombinedDateTimeTest extends TestCase
]; ];
} }
/**
* Undocumented function
*
* @covers ::stringToTime
* @dataProvider reverseIntervalProvider
* @testdox stringToTime $input will be $expected [$_dataName]
*
* @param string|int|float $input
* @param string|int|float $expected
* @return void
*/
public function testStringToTime($input, $expected): void
{
$this->assertEquals(
$expected,
\CoreLibs\Combined\DateTime::stringToTime($input)
);
}
/** /**
* Undocumented function * Undocumented function
* *
@@ -238,6 +590,25 @@ final class CoreLibsCombinedDateTimeTest extends TestCase
]; ];
} }
/**
* Undocumented function
*
* @covers ::checkDate
* @dataProvider dateProvider
* @testdox checkDate $input will be $expected [$_dataName]
*
* @param string $input
* @param bool $expected
* @return void
*/
public function testCheckDate(string $input, bool $expected): void
{
$this->assertEquals(
$expected,
\CoreLibs\Combined\DateTime::checkDate($input)
);
}
/** /**
* Undocumented function * Undocumented function
* *
@@ -297,6 +668,25 @@ final class CoreLibsCombinedDateTimeTest extends TestCase
]; ];
} }
/**
* Undocumented function
*
* @covers ::checkDateTime
* @dataProvider dateTimeProvider
* @testdox checkDateTime $input will be $expected [$_dataName]
*
* @param string $input
* @param bool $expected
* @return void
*/
public function testCheckDateTime(string $input, bool $expected): void
{
$this->assertEquals(
$expected,
\CoreLibs\Combined\DateTime::checkDateTime($input)
);
}
/** /**
* Undocumented function * Undocumented function
* *
@@ -309,45 +699,104 @@ final class CoreLibsCombinedDateTimeTest extends TestCase
'2020-12-12', '2020-12-12',
'2021-12-12', '2021-12-12',
-1, -1,
null,
null,
], ],
'dates equal' => [ 'dates equal' => [
'2020-12-12', '2020-12-12',
'2020-12-12', '2020-12-12',
0, 0,
null,
null,
], ],
'second date smaller' => [ 'second date smaller' => [
'2021-12-12', '2021-12-12',
'2020-12-12', '2020-12-12',
1 1,
null,
null,
], ],
'dates equal with different time' => [ 'dates equal with different time' => [
'2020-12-12 12:12:12', '2020-12-12 12:12:12',
'2020-12-12 13:13:13', '2020-12-12 13:13:13',
0, 0,
null,
null,
], ],
'invalid dates --' => [ 'invalid dates --' => [
'--', '--',
'--', '--',
false false,
'UnexpectedValueException',
1,
], ],
'empty dates' => [ 'empty dates' => [
'', '',
'', '',
false false,
'UnexpectedValueException',
1
], ],
'invalid dates' => [ 'invalid dates' => [
'not a date', 'not a date',
'not a date either', 'not a date either',
false, false,
'UnexpectedValueException',
2
],
'invalid end date' => [
'1990-01-01',
'not a date either',
false,
'UnexpectedValueException',
3
], ],
'out of bound dates' => [ 'out of bound dates' => [
'1900-1-1', '1900-1-1',
'9999-12-31', '9999-12-31',
-1 -1,
null,
null,
] ]
]; ];
} }
/**
* Undocumented function
*
* @covers ::compareDate
* @dataProvider dateCompareProvider
* @testdox compareDate $input_a compared to $input_b will be $expected [$_dataName]
*
* @param string $input_a
* @param string $input_b
* @param int|bool $expected
* @param string|null $exception
* @param int|null $exception_code
* @return void
*/
public function testCompareDate(
string $input_a,
string $input_b,
int|bool $expected,
?string $exception,
?int $exception_code
): void {
if ($expected === false) {
$this->expectException($exception);
$this->expectExceptionCode($exception_code);
}
$this->assertEquals(
$expected,
\CoreLibs\Combined\DateTime::compareDate($input_a, $input_b)
);
}
/**
* Undocumented function
*
* @return array<mixed>
*/
public function dateTimeCompareProvider(): array public function dateTimeCompareProvider(): array
{ {
return [ return [
@@ -355,55 +804,120 @@ final class CoreLibsCombinedDateTimeTest extends TestCase
'2020-12-12', '2020-12-12',
'2021-12-12', '2021-12-12',
-1, -1,
null,
null,
], ],
'dates equal no timestamp' => [ 'dates equal no timestamp' => [
'2020-12-12', '2020-12-12',
'2020-12-12', '2020-12-12',
0, 0,
null,
null,
], ],
'second date smaller no timestamp' => [ 'second date smaller no timestamp' => [
'2021-12-12', '2021-12-12',
'2020-12-12', '2020-12-12',
1 1,
null,
null,
], ],
'date equal first time smaller' => [ 'date equal first time smaller' => [
'2020-12-12 12:12:12', '2020-12-12 12:12:12',
'2020-12-12 13:13:13', '2020-12-12 13:13:13',
-1, -1,
null,
null,
], ],
'date equal time equal' => [ 'date equal time equal' => [
'2020-12-12 12:12:12', '2020-12-12 12:12:12',
'2020-12-12 12:12:12', '2020-12-12 12:12:12',
0, 0,
null,
null,
], ],
'date equal second time smaller' => [ 'date equal second time smaller' => [
'2020-12-12 13:13:13', '2020-12-12 13:13:13',
'2020-12-12 12:12:12', '2020-12-12 12:12:12',
1, 1,
null,
null,
], ],
'valid date invalid time' => [ 'valid date invalid time' => [
'2020-12-12 13:99:13', '2020-12-12 13:99:13',
'2020-12-12 12:12:99', '2020-12-12 12:12:99',
false, false,
'UnexpectedValueException',
2
],
'valid date invalid end time' => [
'2020-12-12 13:12:13',
'2020-12-12 12:12:99',
false,
'UnexpectedValueException',
3
], ],
'invalid datetimes --' => [ 'invalid datetimes --' => [
'--', '--',
'--', '--',
false, false,
'UnexpectedValueException',
1
], ],
'empty datetimess' => [ 'empty datetimess' => [
'', '',
'', '',
false, false,
'UnexpectedValueException',
1
], ],
'invalid date times' => [ 'invalid date times' => [
'not a date', 'not a date',
'not a date either', 'not a date either',
false, false,
'UnexpectedValueException',
2
],
'invalid end date time' => [
'1990-01-01 12:12:12',
'not a date either',
false,
'UnexpectedValueException',
3
], ],
]; ];
} }
/**
* Undocumented function
*
* @covers ::compareDateTime
* @dataProvider dateTimeCompareProvider
* @testdox compareDateTime $input_a compared to $input_b will be $expected [$_dataName]
*
* @param string $input_a
* @param string $input_b
* @param int|bool $expected
* @param string|null $exception
* @param int|null $exception_code
* @return void
*/
public function testCompareDateTime(
string $input_a,
string $input_b,
int|bool $expected,
?string $exception,
?int $exception_code
): void {
if ($expected === false) {
$this->expectException($exception);
$this->expectExceptionCode($exception_code);
}
$this->assertEquals(
$expected,
\CoreLibs\Combined\DateTime::compareDateTime($input_a, $input_b)
);
}
/** /**
* Undocumented function * Undocumented function
* *
@@ -458,151 +972,6 @@ final class CoreLibsCombinedDateTimeTest extends TestCase
]; ];
} }
/**
* date string convert test
*
* @covers ::dateStringFormat
* @dataProvider timestampProvider
* @testdox dateStringFormat $input (microtime $flag) will be $expected [$_dataName]
*
* @param int|float $input
* @param bool $flag
* @param string $expected
* @return void
*/
public function testDateStringFormat(
$input,
bool $flag_show_micro,
bool $flag_micro_as_float,
string $expected
): void {
$this->assertEquals(
$expected,
\CoreLibs\Combined\DateTime::dateStringFormat(
$input,
$flag_show_micro,
$flag_micro_as_float
)
);
}
/**
* interval convert test
*
* @covers ::timeStringFormat
* @dataProvider intervalProvider
* @testdox timeStringFormat $input (microtime $flag) will be $expected [$_dataName]
*
* @param int|float $input
* @param bool $flag
* @param string $expected
* @return void
*/
public function testTimeStringFormat($input, bool $flag, string $expected): void
{
$this->assertEquals(
$expected,
\CoreLibs\Combined\DateTime::timeStringFormat($input, $flag)
);
}
/**
* Undocumented function
*
* @covers ::stringToTime
* @dataProvider reverseIntervalProvider
* @testdox stringToTime $input will be $expected [$_dataName]
*
* @param string|int|float $input
* @param string|int|float $expected
* @return void
*/
public function testStringToTime($input, $expected): void
{
$this->assertEquals(
$expected,
\CoreLibs\Combined\DateTime::stringToTime($input)
);
}
/**
* Undocumented function
*
* @covers ::checkDate
* @dataProvider dateProvider
* @testdox checkDate $input will be $expected [$_dataName]
*
* @param string $input
* @param bool $expected
* @return void
*/
public function testCheckDate(string $input, bool $expected): void
{
$this->assertEquals(
$expected,
\CoreLibs\Combined\DateTime::checkDate($input)
);
}
/**
* Undocumented function
*
* @covers ::checkDateTime
* @dataProvider dateTimeProvider
* @testdox checkDateTime $input will be $expected [$_dataName]
*
* @param string $input
* @param bool $expected
* @return void
*/
public function testCheckDateTime(string $input, bool $expected): void
{
$this->assertEquals(
$expected,
\CoreLibs\Combined\DateTime::checkDateTime($input)
);
}
/**
* Undocumented function
*
* @covers ::compareDate
* @dataProvider dateCompareProvider
* @testdox compareDate $input_a compared to $input_b will be $expected [$_dataName]
*
* @param string $input_a
* @param string $input_b
* @param int|bool $expected
* @return void
*/
public function testCompareDate(string $input_a, string $input_b, $expected): void
{
$this->assertEquals(
$expected,
\CoreLibs\Combined\DateTime::compareDate($input_a, $input_b)
);
}
/**
* Undocumented function
*
* @covers ::compareDateTime
* @dataProvider dateTimeCompareProvider
* @testdox compareDateTime $input_a compared to $input_b will be $expected [$_dataName]
*
* @param string $input_a
* @param string $input_b
* @param int|bool $expected
* @return void
*/
public function testCompareDateTime(string $input_a, string $input_b, $expected): void
{
$this->assertEquals(
$expected,
\CoreLibs\Combined\DateTime::compareDateTime($input_a, $input_b)
);
}
/** /**
* Undocumented function * Undocumented function
* *
@@ -780,6 +1149,70 @@ final class CoreLibsCombinedDateTimeTest extends TestCase
$output $output
); );
} }
/**
* Undocumented function
*
* @return array
*/
public function dateRangeHasWeekendProvider(): array
{
return [
'no weekend' => [
'2023-07-03',
'2023-07-04',
false
],
'start weekend sat' => [
'2023-07-01',
'2023-07-04',
true
],
'start weekend sun' => [
'2023-07-02',
'2023-07-04',
true
],
'end weekend sat' => [
'2023-07-03',
'2023-07-08',
true
],
'end weekend sun' => [
'2023-07-03',
'2023-07-09',
true
],
'long period > 6 days' => [
'2023-07-03',
'2023-07-27',
true
]
];
}
/**
* Undocumented function
*
* @covers ::dateRangeHasWeekend
* @dataProvider dateRangeHasWeekendProvider
* @testdox dateRangeHasWeekend $start_date and $end_date are expected weekend $expected [$_dataName]
*
* @param string $start_date
* @param string $end_date
* @param bool $expected
* @return void
*/
public function testDateRangeHasWeekend(
string $start_date,
string $end_date,
bool $expected
): void {
$this->assertEquals(
$expected,
\CoreLibs\Combined\DateTime::dateRangeHasWeekend($start_date, $end_date)
);
}
} }
// __END__ // __END__

View File

@@ -253,7 +253,8 @@ final class CoreLibsConvertByteTest extends TestCase
*/ */
public function testHumanReadableByteFormatException(int $flag): void public function testHumanReadableByteFormatException(int $flag): void
{ {
$this->expectException(\Exception::class); $this->expectException(\InvalidArgumentException::class);
$this->expectExceptionCode(1);
\CoreLibs\Convert\Byte::humanReadableByteFormat(12, $flag); \CoreLibs\Convert\Byte::humanReadableByteFormat(12, $flag);
} }
@@ -272,7 +273,8 @@ final class CoreLibsConvertByteTest extends TestCase
*/ */
public function testStringByteFormatException(int $flag): void public function testStringByteFormatException(int $flag): void
{ {
$this->expectException(\Exception::class); $this->expectException(\InvalidArgumentException::class);
$this->expectExceptionCode(1);
\CoreLibs\Convert\Byte::stringByteFormat(12, $flag); \CoreLibs\Convert\Byte::stringByteFormat(12, $flag);
} }
} }

View File

@@ -59,6 +59,27 @@ final class CoreLibsConvertColorsTest extends TestCase
3 => false, 3 => false,
4 => false 4 => false
], ],
'invalid color red ' => [
0 => -12,
1 => 12,
2 => 12,
3 => false,
4 => false
],
'invalid color green ' => [
0 => 12,
1 => -12,
2 => 12,
3 => false,
4 => false
],
'invalid color blue ' => [
0 => 12,
1 => 12,
2 => -12,
3 => false,
4 => false
],
]; ];
} }
@@ -150,10 +171,40 @@ final class CoreLibsConvertColorsTest extends TestCase
'valid' => true, 'valid' => true,
], ],
// invalid values // invalid values
'invalid color' => [ 'invalid color r/h/h low' => [
'rgb' => [-12, 300, 12], 'rgb' => [-1, 12, 12],
'hsb' => [-12, 300, 12], 'hsb' => [-1, 50, 50],
'hsl' => [-12, 300, 12], 'hsl' => [-1, 50, 50],
'valid' => false,
],
'invalid color r/h/h high' => [
'rgb' => [256, 12, 12],
'hsb' => [361, 50, 50],
'hsl' => [361, 50, 50],
'valid' => false,
],
'invalid color g/s/s low' => [
'rgb' => [12, -1, 12],
'hsb' => [1, -1, 50],
'hsl' => [1, -1, 50],
'valid' => false,
],
'invalid color g/s/s high' => [
'rgb' => [12, 256, 12],
'hsb' => [1, 101, 50],
'hsl' => [1, 101, 50],
'valid' => false,
],
'invalid color b/b/l low' => [
'rgb' => [12, 12, -1],
'hsb' => [1, 50, -1],
'hsl' => [1, 50, -1],
'valid' => false,
],
'invalid color b/b/l high' => [
'rgb' => [12, 12, 256],
'hsb' => [1, 50, 101],
'hsl' => [1, 50, 101],
'valid' => false, 'valid' => false,
], ],
]; ];
@@ -246,11 +297,22 @@ final class CoreLibsConvertColorsTest extends TestCase
* @param int $input_r * @param int $input_r
* @param int $input_g * @param int $input_g
* @param int $input_b * @param int $input_b
* @param string|bool $expected_hash
* @param string|bool $expected * @param string|bool $expected
* @return void * @return void
*/ */
public function testRgb2hex(int $input_r, int $input_g, int $input_b, $expected_hash, $expected) public function testRgb2hex(
{ int $input_r,
int $input_g,
int $input_b,
string|bool $expected_hash,
string|bool $expected
) {
// if expected hash is or expected is false, we need to check for
// LengthException
if ($expected_hash === false || $expected === false) {
$this->expectException(\LengthException::class);
}
// with # // with #
$this->assertEquals( $this->assertEquals(
$expected_hash, $expected_hash,
@@ -292,11 +354,19 @@ final class CoreLibsConvertColorsTest extends TestCase
*/ */
public function testHex2rgb( public function testHex2rgb(
string $input, string $input,
$expected, array|bool $expected,
$expected_str, string|bool $expected_str,
string $separator, string $separator,
$expected_str_sep string|bool $expected_str_sep
): void { ): void {
if ($expected === false || $expected_str === false || $expected_str_sep === false) {
$hex_string = preg_replace("/[^0-9A-Fa-f]/", '', $input);
if (!is_string($hex_string)) {
$this->expectException(\InvalidArgumentException::class);
} else {
$this->expectException(\UnexpectedValueException::class);
}
}
$this->assertEquals( $this->assertEquals(
$expected, $expected,
\CoreLibs\Convert\Colors::hex2rgb($input) \CoreLibs\Convert\Colors::hex2rgb($input)
@@ -324,8 +394,11 @@ final class CoreLibsConvertColorsTest extends TestCase
* @param array|bool $expected * @param array|bool $expected
* @return void * @return void
*/ */
public function testRgb2hsb(int $input_r, int $input_g, int $input_b, $expected): void public function testRgb2hsb(int $input_r, int $input_g, int $input_b, array|bool $expected): void
{ {
if ($expected === false) {
$this->expectException(\LengthException::class);
}
$this->assertEquals( $this->assertEquals(
$expected, $expected,
\CoreLibs\Convert\Colors::rgb2hsb($input_r, $input_g, $input_b) \CoreLibs\Convert\Colors::rgb2hsb($input_r, $input_g, $input_b)
@@ -345,8 +418,12 @@ final class CoreLibsConvertColorsTest extends TestCase
* @param array|bool $expected * @param array|bool $expected
* @return void * @return void
*/ */
public function testHsb2rgb(float $input_h, float $input_s, float $input_b, $expected): void public function testHsb2rgb(float $input_h, float $input_s, float $input_b, array|bool $expected): void
{ {
if ($expected === false) {
$this->expectException(\LengthException::class);
$expected = [];
}
$this->assertEquals( $this->assertEquals(
$expected, $expected,
\CoreLibs\Convert\Colors::hsb2rgb($input_h, $input_s, $input_b) \CoreLibs\Convert\Colors::hsb2rgb($input_h, $input_s, $input_b)
@@ -366,8 +443,11 @@ final class CoreLibsConvertColorsTest extends TestCase
* @param array|bool $expected * @param array|bool $expected
* @return void * @return void
*/ */
public function testRgb2hsl(int $input_r, int $input_g, int $input_b, $expected): void public function testRgb2hsl(int $input_r, int $input_g, int $input_b, array|bool $expected): void
{ {
if ($expected === false) {
$this->expectException(\LengthException::class);
}
$this->assertEquals( $this->assertEquals(
$expected, $expected,
\CoreLibs\Convert\Colors::rgb2hsl($input_r, $input_g, $input_b) \CoreLibs\Convert\Colors::rgb2hsl($input_r, $input_g, $input_b)
@@ -387,8 +467,11 @@ final class CoreLibsConvertColorsTest extends TestCase
* @param array|bool $expected * @param array|bool $expected
* @return void * @return void
*/ */
public function testHsl2rgb($input_h, float $input_s, float $input_l, $expected): void public function testHsl2rgb(int|float $input_h, float $input_s, float $input_l, array|bool $expected): void
{ {
if ($expected === false) {
$this->expectException(\LengthException::class);
}
$this->assertEquals( $this->assertEquals(
$expected, $expected,
\CoreLibs\Convert\Colors::hsl2rgb($input_h, $input_s, $input_l) \CoreLibs\Convert\Colors::hsl2rgb($input_h, $input_s, $input_l)
@@ -406,11 +489,11 @@ final class CoreLibsConvertColorsTest extends TestCase
*/ */
public function testHslHsb360hue(): void public function testHslHsb360hue(): void
{ {
$this->assertNotFalse( $this->assertIsArray(
\CoreLibs\Convert\Colors::hsl2rgb(360.0, 90.5, 41.2), \CoreLibs\Convert\Colors::hsl2rgb(360.0, 90.5, 41.2),
'HSL to RGB with 360 hue' 'HSL to RGB with 360 hue'
); );
$this->assertNotFalse( $this->assertIsArray(
\CoreLibs\Convert\Colors::hsb2rgb(360, 95, 78.0), \CoreLibs\Convert\Colors::hsb2rgb(360, 95, 78.0),
'HSB to RGB with 360 hue' 'HSB to RGB with 360 hue'
); );

View File

@@ -16,7 +16,7 @@ final class CoreLibsConvertJsonTest extends TestCase
/** /**
* test list for json convert tests * test list for json convert tests
* *
* @return array * @return array<mixed>
*/ */
public function jsonProvider(): array public function jsonProvider(): array
{ {
@@ -54,10 +54,36 @@ final class CoreLibsConvertJsonTest extends TestCase
]; ];
} }
/**
* Undocumented function
*
* @return array<mixed>
*/
public function jsonArrayProvider(): array
{
return [
'valid json' => [
[
'm' => 2,
'f' => 'sub_2'
],
'{"m":2,"f":"sub_2"}',
],
'empty json array' => [
[],
'[]'
],
'empty json hash' => [
['' => ''],
'{"":""}'
]
];
}
/** /**
* json error list * json error list
* *
* @return array JSON error list * @return array<mixed> JSON error list
*/ */
public function jsonErrorProvider(): array public function jsonErrorProvider(): array
{ {
@@ -127,7 +153,7 @@ final class CoreLibsConvertJsonTest extends TestCase
* *
* @param string|null $input * @param string|null $input
* @param bool $flag * @param bool $flag
* @param array $expected * @param array<mixed> $expected
* @return void * @return void
*/ */
public function testJsonConvertToArray(?string $input, bool $flag, array $expected): void public function testJsonConvertToArray(?string $input, bool $flag, array $expected): void
@@ -146,7 +172,8 @@ final class CoreLibsConvertJsonTest extends TestCase
* @testdox jsonGetLastError $input will be $expected_i/$expected_s [$_dataName] * @testdox jsonGetLastError $input will be $expected_i/$expected_s [$_dataName]
* *
* @param string|null $input * @param string|null $input
* @param string $expected * @param int $expected_i
* @param string $expected_s
* @return void * @return void
*/ */
public function testJsonGetLastError(?string $input, int $expected_i, string $expected_s): void public function testJsonGetLastError(?string $input, int $expected_i, string $expected_s): void
@@ -161,6 +188,25 @@ final class CoreLibsConvertJsonTest extends TestCase
\CoreLibs\Convert\Json::jsonGetLastError(true) \CoreLibs\Convert\Json::jsonGetLastError(true)
); );
} }
/**
* Undocumented function
*
* @covers ::jsonConvertArrayTo
* @dataProvider jsonArrayProvider
* @testdox jsonConvertArrayTo $input (Override: $flag) will be $expected [$_dataName]
*
* @param array<mixed> $input
* @param string $expected
* @return void
*/
public function testJsonConvertArrayto(array $input, string $expected): void
{
$this->assertEquals(
$expected,
\CoreLibs\Convert\Json::jsonConvertArrayTo($input)
);
}
} }
// __END__ // __END__

View File

@@ -33,15 +33,14 @@ final class CoreLibsConvertMimeEncodeTest extends TestCase
'The quick brown fox jumps over the lazy sheep that sleeps in the ravine ' 'The quick brown fox jumps over the lazy sheep that sleeps in the ravine '
. 'and has no idea what is going on here', . 'and has no idea what is going on here',
'UTF-8', 'UTF-8',
'The quick brown fox jumps over the lazy sheep that sleeps in the ravine ' "The quick brown fox jumps over the lazy sheep that sleeps in the ravine and\r\n"
. 'and has no idea what is going on here' . ' has no idea what is going on here'
], ],
'standard with special chars UTF-8' => [ 'standard with special chars UTF-8' => [
'This is ümläßtと漢字もカタカナ!^$%&', 'This is ümläßtと漢字もカタカナ!^$%&',
'UTF-8', 'UTF-8',
'This is =?UTF-8?B?w7xtbMOkw59044Go5ryi5a2X44KC44Kr44K/44Kr44OK77yBIV4k?=' "This is =?UTF-8?B?w7xtbMOkw59044Go5ryi5a2X44KC44Kr44K/44Kr44OK77yBIV4k?=\r\n"
. "\r\n" . ' =?UTF-8?B?JSY=?='
. ' =?UTF-8?B?JQ==?=&'
], ],
'35 chars and space at the end UTF-8' => [ '35 chars and space at the end UTF-8' => [
'12345678901234567890123456789012345 ' '12345678901234567890123456789012345 '
@@ -62,9 +61,8 @@ final class CoreLibsConvertMimeEncodeTest extends TestCase
. 'is there a space?', . 'is there a space?',
'UTF-8', 'UTF-8',
"=?UTF-8?B?44Kr44K/44Kr44OK44Kr44K/44Kr44OK44GL44Gq44Kr44K/44Kr44OK44Kr?=\r\n" "=?UTF-8?B?44Kr44K/44Kr44OK44Kr44K/44Kr44OK44GL44Gq44Kr44K/44Kr44OK44Kr?=\r\n"
. " =?UTF-8?B?44K/44Kr44OK?=\r\n" . " =?UTF-8?B?44K/44Kr44OK44GL44Gq44Kr44K/44Kr44OK44Kr44K/44Kr44OK44GL44Gq?=\r\n"
. " =?UTF-8?B?44GL44Gq44Kr44K/44Kr44OK44Kr44K/44Kr44OK44GL44Gq44Kr44K/44Kr?=\r\n" . " =?UTF-8?B?44Kr44K/44Kr44OK44Kr44K/IGlzIHRoZXJlIGEgc3BhY2U/?="
. " =?UTF-8?B?44OK44Kr44K/?= is there a =?UTF-8?B?c3BhY2U/?="
] ]
]; ];
} }
@@ -85,16 +83,28 @@ final class CoreLibsConvertMimeEncodeTest extends TestCase
// print "MIME: -" . $encoded . "-\n"; // print "MIME: -" . $encoded . "-\n";
$this->assertEquals( $this->assertEquals(
$expected, $expected,
$encoded $encoded,
"__mbMimeEncode"
); );
$decoded = mb_decode_mimeheader($encoded); $decoded = mb_decode_mimeheader($encoded);
// print "INPUT : " . $input . "\n"; // print "ENCODED: " . $encoded . "\n";
// print "DECODED: " . $decoded . "\n"; // print "INPUT : " . $input . " | " . mb_strlen($input) . "\n";
// print "DECODED: " . $decoded . " | " . mb_strlen($decoded) . "\n";
// $test_enc = mb_encode_mimeheader($input, $encoding);
// $test_dec = mb_decode_mimeheader($test_enc);
// print "TEST ENC: " . $test_enc . "\n";
// back compare decoded // back compare decoded
$this->assertEquals( $this->assertEquals(
$input, $input,
$decoded $decoded,
"mb_decode_mimeheader"
); );
// $this->assertEquals(
// $input,
// $test_dec,
// 'mb_encode_to_decode'
// );
} }
} }

View File

@@ -43,12 +43,17 @@ final class CoreLibsConvertSetVarTypeNullTest extends TestCase
'int, no override' => [ 'int, no override' => [
1, 1,
null, null,
null '1'
], ],
'int, override set' => [ 'int, override set' => [
1, 1,
'not int', 'not int',
'not int' '1'
],
'array, override set' => [
[1, 2],
null,
null
] ]
]; ];
} }
@@ -201,7 +206,7 @@ final class CoreLibsConvertSetVarTypeNullTest extends TestCase
'float' => [ 'float' => [
1.5, 1.5,
null, null,
null 1
] ]
]; ];
} }
@@ -349,7 +354,7 @@ final class CoreLibsConvertSetVarTypeNullTest extends TestCase
'int' => [ 'int' => [
1, 1,
null, null,
null 1.0
] ]
]; ];
} }

View File

@@ -43,11 +43,16 @@ final class CoreLibsConvertSetVarTypeTest extends TestCase
'int, no override' => [ 'int, no override' => [
1, 1,
null, null,
'' '1'
], ],
'int, override set' => [ 'int, override set' => [
1, 1,
'not int', 'not int',
'1'
],
'array, override set' => [
[1, 2],
'not int',
'not int' 'not int'
] ]
]; ];
@@ -189,7 +194,7 @@ final class CoreLibsConvertSetVarTypeTest extends TestCase
'float' => [ 'float' => [
1.5, 1.5,
null, null,
0 1
] ]
]; ];
} }
@@ -330,7 +335,7 @@ final class CoreLibsConvertSetVarTypeTest extends TestCase
'int' => [ 'int' => [
1, 1,
null, null,
0.0 1.0
] ]
]; ];
} }

View File

@@ -13,6 +13,8 @@ use PHPUnit\Framework\TestCase;
*/ */
final class CoreLibsConvertStringsTest extends TestCase final class CoreLibsConvertStringsTest extends TestCase
{ {
private const DATA_FOLDER = __DIR__ . DIRECTORY_SEPARATOR . 'data' . DIRECTORY_SEPARATOR;
/** /**
* Undocumented function * Undocumented function
* *
@@ -256,6 +258,126 @@ final class CoreLibsConvertStringsTest extends TestCase
$output $output
); );
} }
/**
* provider for testStripMultiplePathSlashes
*
* @return array<mixed>
*/
public function stripMultiplePathSlashesProvider(): array
{
return [
'no slahses' => [
'input' => 'string_abc',
'expected' => 'string_abc',
],
'one slash' => [
'input' => 'some/foo',
'expected' => 'some/foo',
],
'two slashes' => [
'input' => 'some//foo',
'expected' => 'some/foo',
],
'three slashes' => [
'input' => 'some///foo',
'expected' => 'some/foo',
],
'slashes in front' => [
'input' => '/foo',
'expected' => '/foo',
],
'two slashes in front' => [
'input' => '//foo',
'expected' => '/foo',
],
'thee slashes in front' => [
'input' => '///foo',
'expected' => '/foo',
],
'slashes in back' => [
'input' => 'foo/',
'expected' => 'foo/',
],
'two slashes in back' => [
'input' => 'foo//',
'expected' => 'foo/',
],
'thee slashes in back' => [
'input' => 'foo///',
'expected' => 'foo/',
],
'multiple slashes' => [
'input' => '/foo//bar///string/end_times',
'expected' => '/foo/bar/string/end_times',
]
];
}
/**
* test multiple slashes clean up
*
* @covers ::stripMultiplePathSlashes
* @dataProvider stripMultiplePathSlashesProvider
* @testdox stripMultiplePathSlashes $input will be $expected [$_dataName]
*
* @param string $input
* @param string $expected
* @return void
*/
public function testStripMultiplePathSlashes(string $input, string $expected): void
{
$this->assertEquals(
$expected,
\CoreLibs\Convert\Strings::stripMultiplePathSlashes($input)
);
}
/**
* Undocumented function
*
* @return array
*/
public function providerStripUTF8BomBytes(): array
{
return [
"utf8-bom" => [
"file" => "UTF8BOM.csv",
"expect" => "Asset Type,Epic,File Name\n",
],
"utf8" => [
"file" => "UTF8.csv",
"expect" => "Asset Type,Epic,File Name\n",
],
];
}
/**
* test utf8 bom remove
*
* @covers ::stripUTF8BomBytes
* @dataProvider providerStripUTF8BomBytes
* @testdox stripUTF8BomBytes $file will be $expected [$_dataName]
*
* @param string $file
* @param string $expected
* @return void
*/
public function testStripUTF8BomBytes(string $file, string $expected): void
{
// load sample file
if (!is_file(self::DATA_FOLDER . $file)) {
$this->markTestSkipped('File: ' . $file . ' could not be opened');
}
$file = file_get_contents(self::DATA_FOLDER . $file);
if ($file === false) {
$this->markTestSkipped('File: ' . $file . ' could not be read');
}
$this->assertEquals(
$expected,
\CoreLibs\Convert\Strings::stripUTF8BomBytes($file)
);
}
} }
// __END__ // __END__

View File

@@ -0,0 +1 @@
Asset Type,Epic,File Name
1 Asset Type Epic File Name

View File

@@ -0,0 +1 @@
Asset Type,Epic,File Name
1 Asset Type Epic File Name

View File

@@ -1,310 +0,0 @@
<?php // phpcs:disable Generic.Files.LineLength
declare(strict_types=1);
namespace tests;
use PHPUnit\Framework\TestCase;
/**
* Test class for Language\GetLocale
*
* @coversDefaultClass \CoreLibs\Language\GetLocale
* @testdox \CoreLibs\Language\GetLocale method tests
*/
final class CoreLibsLanguageGetLocaleTest extends TestCase
{
/**
* set all constant variables that must be set before call
*
* @return void
*/
public static function setUpBeforeClass(): void
{
// default web page encoding setting
if (!defined('DEFAULT_ENCODING')) {
define('DEFAULT_ENCODING', 'UTF-8');
}
if (!defined('DEFAULT_LOCALE')) {
// default lang + encoding
define('DEFAULT_LOCALE', 'en_US.UTF-8');
}
// site
if (!defined('SITE_ENCODING')) {
define('SITE_ENCODING', DEFAULT_ENCODING);
}
if (!defined('SITE_LOCALE')) {
define('SITE_LOCALE', DEFAULT_LOCALE);
}
// just set
if (!defined('BASE')) {
define('BASE', str_replace('/configs', '', __DIR__) . DIRECTORY_SEPARATOR);
}
if (!defined('INCLUDES')) {
define('INCLUDES', 'includes' . DIRECTORY_SEPARATOR);
}
if (!defined('LANG')) {
define('LANG', 'lang' . DIRECTORY_SEPARATOR);
}
if (!defined('LOCALE')) {
define('LOCALE', 'locale' . DIRECTORY_SEPARATOR);
}
if (!defined('CONTENT_PATH')) {
define('CONTENT_PATH', 'frontend' . DIRECTORY_SEPARATOR);
}
// array session
$_SESSION = [];
global $_SESSION;
}
/**
* all the test data
*
* @return array
*/
public function setLocaleProvider(): array
{
return [
// 0: locale
// 1: domain
// 2: encoding
// 3: path
// 4: SESSION: DEFAULT_LOCALE
// 5: SESSION: DEFAULT_CHARSET
// 6: expected array
'no params, all default constants' => [
// lang, domain, encoding, path
null, null, null, null,
// SESSION DEFAULT_LOCALE, SESSION: DEFAULT_CHARSET
null, null,
// return array
[
'locale' => 'en_US.UTF-8',
'lang' => 'en_US',
'domain' => 'frontend',
'encoding' => 'UTF-8',
'path' => "/^\/(.*\/)?includes\/locale\/$/",
],
],
'no params, session charset and lang' => [
// lang, domain, encoding, path
null, null, null, null,
// SESSION DEFAULT_LOCALE, SESSION: DEFAULT_CHARSET
'ja_JP', 'UTF-8',
// return array
[
'locale' => 'ja_JP',
'lang' => 'ja_JP',
'domain' => 'frontend',
'encoding' => 'UTF-8',
'path' => "/^\/(.*\/)?includes\/locale\/$/",
],
],
'no params, session charset and lang short' => [
// lang, domain, encoding, path
null, null, null, null,
// SESSION DEFAULT_LOCALE, SESSION: DEFAULT_CHARSET
'ja', 'UTF-8',
// return array
[
'locale' => 'ja',
'lang' => 'ja',
'domain' => 'frontend',
'encoding' => 'UTF-8',
'path' => "/^\/(.*\/)?includes\/locale\/$/",
],
],
// param lang (no sessions)
'locale param only, no sessions' => [
// lang, domain, encoding, path
'ja.UTF-8', null, null, null,
// SESSION DEFAULT_LOCALE, SESSION: DEFAULT_CHARSET
null, null,
// return array
[
'locale' => 'ja.UTF-8',
'lang' => 'ja',
'domain' => 'frontend',
'encoding' => 'UTF-8',
'path' => "/^\/(.*\/)?includes\/locale\/$/",
],
],
// different locale setting
'locale complex param only, no sessions' => [
// lang, domain, encoding, path
'ja_JP.SJIS', null, null, null,
// SESSION DEFAULT_LOCALE, SESSION: DEFAULT_CHARSET
null, null,
// return array
[
'locale' => 'ja_JP.SJIS',
'lang' => 'ja_JP',
'domain' => 'frontend',
'encoding' => 'SJIS',
'path' => "/^\/(.*\/)?includes\/locale\/$/",
],
],
// param lang and domain (no override)
'locale, domain params, no sessions' => [
// lang, domain, encoding, path
'ja.UTF-8', 'admin', null, null,
// SESSION DEFAULT_LOCALE, SESSION: DEFAULT_CHARSET
null, null,
// return array
[
'locale' => 'ja.UTF-8',
'lang' => 'ja',
'domain' => 'admin',
'encoding' => 'UTF-8',
'path' => "/^\/(.*\/)?includes\/locale\/$/",
],
],
// param lang and domain (no override)
'locale, domain, encoding params, no sessions' => [
// lang, domain, encoding, path
'ja.UTF-8', 'admin', 'UTF-8', null,
// SESSION DEFAULT_LOCALE, SESSION: DEFAULT_CHARSET
null, null,
// return array
[
'locale' => 'ja.UTF-8',
'lang' => 'ja',
'domain' => 'admin',
'encoding' => 'UTF-8',
'path' => "/^\/(.*\/)?includes\/locale\/$/",
],
],
// lang, domain, path (no override)
'locale, domain and path, no sessions' => [
// lang, domain, encoding, path
'ja.UTF-8', 'admin', '', __DIR__ . '/locale_other/',
// SESSION DEFAULT_LOCALE, SESSION: DEFAULT_CHARSET
null, null,
// return array
[
'locale' => 'ja.UTF-8',
'lang' => 'ja',
'domain' => 'admin',
'encoding' => 'UTF-8',
'path' => "/^\/(.*\/)?locale_other\/$/",
],
],
// all params set (no override)
'all parameter, no sessions' => [
// lang, domain, encoding, path
'ja', 'admin', 'UTF-8', __DIR__ . '/locale_other/',
// SESSION DEFAULT_LOCALE, SESSION: DEFAULT_CHARSET
null, null,
// return array
[
'locale' => 'ja',
'lang' => 'ja',
'domain' => 'admin',
'encoding' => 'UTF-8',
'path' => "/^\/(.*\/)?locale_other\/$/",
],
],
// param lang and domain (no override)
'long locale, domain, encoding params, no sessions' => [
// lang, domain, encoding, path
'de_CH.UTF-8@euro', 'admin', 'UTF-8', null,
// SESSION DEFAULT_LOCALE, SESSION: DEFAULT_CHARSET
null, null,
// return array
[
'locale' => 'de_CH.UTF-8@euro',
'lang' => 'de_CH',
'domain' => 'admin',
'encoding' => 'UTF-8',
'path' => "/^\/(.*\/)?includes\/locale\/$/",
],
],
// TODO invalid params (bad path) (no override)
// TODO param calls, but with override set
];
}
/**
* Undocumented function
*
* @covers ::setLocale
* @dataProvider setLocaleProvider
* @testdox lang settings lang $language, domain $domain, encoding $encoding, path $path; session lang: $SESSION_DEFAULT_LOCALE, session char: $SESSION_DEFAULT_CHARSET [$_dataName]
*
* @return void
*/
public function testsetLocale(
?string $language,
?string $domain,
?string $encoding,
?string $path,
?string $SESSION_DEFAULT_LOCALE,
?string $SESSION_DEFAULT_CHARSET,
array $expected
): void {
$return_lang_settings = [];
global $_SESSION;
// set override
if ($SESSION_DEFAULT_LOCALE !== null) {
$_SESSION['DEFAULT_LOCALE'] = $SESSION_DEFAULT_LOCALE;
}
if ($SESSION_DEFAULT_CHARSET !== null) {
$_SESSION['DEFAULT_CHARSET'] = $SESSION_DEFAULT_CHARSET;
}
// function call
if ($language === null && $domain === null && $encoding === null && $path === null) {
$return_lang_settings = \CoreLibs\Language\GetLocale::setLocale();
} elseif ($language !== null && $domain === null && $encoding === null && $path === null) {
$return_lang_settings = \CoreLibs\Language\GetLocale::setLocale(
$language
);
} elseif ($language !== null && $domain !== null && $encoding === null && $path === null) {
$return_lang_settings = \CoreLibs\Language\GetLocale::setLocale(
$language,
$domain
);
} elseif ($language !== null && $domain !== null && $encoding !== null && $path === null) {
$return_lang_settings = \CoreLibs\Language\GetLocale::setLocale(
$language,
$domain,
$encoding
);
} else {
$return_lang_settings = \CoreLibs\Language\GetLocale::setLocale(
$language,
$domain,
$encoding,
$path
);
}
// print "RETURN: " . print_r($return_lang_settings, true) . "\n";
foreach (
[
'locale', 'lang', 'domain', 'encoding', 'path'
] as $key
) {
$value = $expected[$key];
if (strpos($value, "/") === 0) {
// this is regex
$this->assertMatchesRegularExpression(
$value,
$return_lang_settings[$key],
'assert regex failed for ' . $key
);
} else {
// assert equal
$this->assertEquals(
$value,
$return_lang_settings[$key],
'assert equal failed for ' . $key
);
}
}
// unset all vars
$_SESSION = [];
unset($GLOBALS['OVERRIDE_LANG']);
}
}
// __END__

View File

@@ -1,33 +0,0 @@
<?php
declare(strict_types=1);
namespace tests;
use PHPUnit\Framework\TestCase;
/**
* Test class for Output\Image
* @coversDefaultClass \CoreLibs\Output\Image
* @testdox \CoreLibs\Output\Image method tests
*/
final class CoreLibsOutputImageTest extends TestCase
{
/**
* Undocumented function
*
* @testdox Output\Image Class tests
*
* @return void
*/
public function testOutputImage()
{
// $this->assertTrue(true, 'Output Image Tests not implemented');
$this->markTestIncomplete(
'Output\Image Tests have not yet been implemented'
);
// $this->markTestSkipped('No implementation for Output\Image at the moment');
}
}
// __END__

View File

@@ -22,12 +22,9 @@ final class CoreLibsCreateEmailTest extends TestCase
*/ */
public static function setUpBeforeClass(): void public static function setUpBeforeClass(): void
{ {
self::$log = new \CoreLibs\Debug\Logging([ self::$log = new \CoreLibs\Logging\Logging([
'log_folder' => DIRECTORY_SEPARATOR . 'tmp', 'log_folder' => DIRECTORY_SEPARATOR . 'tmp',
'file_id' => 'CoreLibs-Create-Email-Test', 'log_file_id' => 'CoreLibs-Create-Email-Test',
'debug_all' => true,
'echo_all' => false,
'print_all' => true,
]); ]);
} }
@@ -624,7 +621,7 @@ final class CoreLibsCreateEmailTest extends TestCase
// force new set for each run // force new set for each run
self::$log->setLogUniqueId(true); self::$log->setLogUniqueId(true);
// set on of unique log id // set on of unique log id
self::$log->setLogPer('run', true); self::$log->setLogFlag(\CoreLibs\Logging\Logger\Flag::per_run);
// init logger // init logger
$status = \CoreLibs\Create\Email::sendEmail( $status = \CoreLibs\Create\Email::sendEmail(
$subject, $subject,
@@ -646,7 +643,9 @@ final class CoreLibsCreateEmailTest extends TestCase
// assert content: must load JSON from log file // assert content: must load JSON from log file
if ($status == 2) { if ($status == 2) {
// open file, get last entry with 'SEND EMAIL JSON' key // open file, get last entry with 'SEND EMAIL JSON' key
$file = file_get_contents(self::$log->getLogFileName()); $file = file_get_contents(
self::$log->getLogFolder() . self::$log->getLogFile()
);
if ($file !== false) { if ($file !== false) {
// extract SEND EMAIL JSON line // extract SEND EMAIL JSON line
$found = preg_match_all("/^.* <SEND EMAIL JSON> - (.*)$/m", $file, $matches); $found = preg_match_all("/^.* <SEND EMAIL JSON> - (.*)$/m", $file, $matches);

View File

@@ -30,8 +30,10 @@ final class CoreLibsCreateSessionTest extends TestCase
// setSessionName: true/false, // setSessionName: true/false,
// checkActiveSession: true/false, [1st call, 2nd call] // checkActiveSession: true/false, [1st call, 2nd call]
// getSessionId: string or false // getSessionId: string or false
// 3: exepcted name (session) // 3: exepcted name (session)]
// 4: expected error string // 4: Exception thrown on error
// 5: exception code, null for none
// 6: expected error string
return [ return [
'session parameter' => [ 'session parameter' => [
'sessionNameParameter', 'sessionNameParameter',
@@ -44,7 +46,9 @@ final class CoreLibsCreateSessionTest extends TestCase
'getSessionId' => '1234abcd4567' 'getSessionId' => '1234abcd4567'
], ],
'sessionNameParameter', 'sessionNameParameter',
'' null,
null,
'',
], ],
'session globals' => [ 'session globals' => [
'sessionNameGlobals', 'sessionNameGlobals',
@@ -57,7 +61,9 @@ final class CoreLibsCreateSessionTest extends TestCase
'getSessionId' => '1234abcd4567' 'getSessionId' => '1234abcd4567'
], ],
'sessionNameGlobals', 'sessionNameGlobals',
'' null,
null,
'',
], ],
'session name default' => [ 'session name default' => [
'', '',
@@ -70,7 +76,9 @@ final class CoreLibsCreateSessionTest extends TestCase
'getSessionId' => '1234abcd4567' 'getSessionId' => '1234abcd4567'
], ],
'', '',
'' null,
null,
'',
], ],
// error checks // error checks
// 1: we are in cli // 1: we are in cli
@@ -85,6 +93,8 @@ final class CoreLibsCreateSessionTest extends TestCase
'getSessionId' => '1234abcd4567' 'getSessionId' => '1234abcd4567'
], ],
'', '',
'RuntimeException',
1,
'[SESSION] No sessions in php cli' '[SESSION] No sessions in php cli'
], ],
// 2: session disabled // 2: session disabled
@@ -99,6 +109,8 @@ final class CoreLibsCreateSessionTest extends TestCase
'getSessionId' => '1234abcd4567' 'getSessionId' => '1234abcd4567'
], ],
'', '',
'RuntimeException',
2,
'[SESSION] Sessions are disabled' '[SESSION] Sessions are disabled'
], ],
// 3: invalid session name: string // 3: invalid session name: string
@@ -113,6 +125,8 @@ final class CoreLibsCreateSessionTest extends TestCase
'getSessionId' => '1234abcd4567' 'getSessionId' => '1234abcd4567'
], ],
'', '',
'UnexpectedValueException',
3,
'[SESSION] Invalid session name: 1invalid$session#;' '[SESSION] Invalid session name: 1invalid$session#;'
], ],
// 3: invalid session name: only numbers // 3: invalid session name: only numbers
@@ -127,6 +141,8 @@ final class CoreLibsCreateSessionTest extends TestCase
'getSessionId' => '1234abcd4567' 'getSessionId' => '1234abcd4567'
], ],
'', '',
'UnexpectedValueException',
3,
'[SESSION] Invalid session name: 123' '[SESSION] Invalid session name: 123'
], ],
// 3: invalid session name: invalid name short // 3: invalid session name: invalid name short
@@ -143,6 +159,8 @@ final class CoreLibsCreateSessionTest extends TestCase
'getSessionId' => '1234abcd4567' 'getSessionId' => '1234abcd4567'
], ],
'', '',
'RuntimeException',
4,
'[SESSION] Failed to activate session' '[SESSION] Failed to activate session'
], ],
// 5: get session id return false // 5: get session id return false
@@ -157,6 +175,8 @@ final class CoreLibsCreateSessionTest extends TestCase
'getSessionId' => false 'getSessionId' => false
], ],
'', '',
'UnexpectedValueException',
5,
'[SESSION] getSessionId did not return a session id' '[SESSION] getSessionId did not return a session id'
], ],
]; ];
@@ -173,6 +193,7 @@ final class CoreLibsCreateSessionTest extends TestCase
* @param string $type * @param string $type
* @param array<mixed> $mock_data * @param array<mixed> $mock_data
* @param string $expected * @param string $expected
* @param string|null $exception
* @param string $expected_error * @param string $expected_error
* @return void * @return void
*/ */
@@ -181,6 +202,8 @@ final class CoreLibsCreateSessionTest extends TestCase
string $type, string $type,
array $mock_data, array $mock_data,
string $expected, string $expected,
?string $exception,
?int $exception_code,
string $expected_error string $expected_error
): void { ): void {
// override expected // override expected
@@ -224,6 +247,11 @@ final class CoreLibsCreateSessionTest extends TestCase
// regex for session id // regex for session id
$ression_id_regex = "/^\w+$/"; $ression_id_regex = "/^\w+$/";
if ($exception !== null) {
$this->expectException($exception);
$this->expectExceptionCode($exception_code);
}
unset($GLOBALS['SET_SESSION_NAME']); unset($GLOBALS['SET_SESSION_NAME']);
$session_id = ''; $session_id = '';
switch ($type) { switch ($type) {
@@ -253,13 +281,6 @@ final class CoreLibsCreateSessionTest extends TestCase
$expected, $expected,
$session_mock->getSessionName() $session_mock->getSessionName()
); );
} else {
// false checks
$this->assertEquals(
$expected_error,
$session_mock->getErrorStr(),
'error assert'
);
} }
} }

View File

@@ -21,45 +21,83 @@ final class CoreLibsCreateUidsTest extends TestCase
public function uniqIdProvider(): array public function uniqIdProvider(): array
{ {
return [ return [
// number length
'too short' => [
0 => 1,
1 => 4,
2 => null
],
'valid length: 10' => [
0 => 10,
1 => 10,
2 => null
],
'valid length: 9, auto length' => [
0 => 9,
1 => 8,
2 => null
],
'valid length: 9, force length' => [
0 => 9,
1 => 9,
2 => true,
],
'very long: 512' => [
0 => 512,
1 => 512,
2 => null
],
// below is all legacy
'md5 hash' => [ 'md5 hash' => [
0 => 'md5', 0 => 'md5',
1 => 32, 1 => 32,
2 => null
], ],
'sha256 hash' => [ 'sha256 hash' => [
0 => 'sha256', 0 => 'sha256',
1 => 64 1 => 64,
2 => null
], ],
'ripemd160 hash' => [ 'ripemd160 hash' => [
0 => 'ripemd160', 0 => 'ripemd160',
1 => 40 1 => 40,
2 => null
], ],
'adler32 hash' => [ 'adler32 hash' => [
0 => 'adler32', 0 => 'adler32',
1 => 8 1 => 8,
2 => null
], ],
'not in list hash but valid' => [ 'not in list, set default length' => [
0 => 'sha3-512', 0 => 'sha3-512',
1 => strlen(hash('sha3-512', 'A')) 1 => 64,
2 => null
], ],
'default hash not set' => [ 'default hash not set' => [
0 => null, 0 => null,
1 => 64, 1 => 64,
2 => null
], ],
'invalid name' => [ 'invalid name' => [
0 => 'iamnotavalidhash', 0 => 'iamnotavalidhash',
1 => 64, 1 => 64,
2 => null
], ],
'auto: ' . \CoreLibs\Create\Uids::DEFAULT_HASH => [ // auto calls
0 => \CoreLibs\Create\Uids::DEFAULT_HASH, 'auto: ' . \CoreLibs\Create\Uids::DEFAULT_UNNIQ_ID_LENGTH => [
1 => strlen(hash(\CoreLibs\Create\Uids::DEFAULT_HASH, 'A')) 0 => \CoreLibs\Create\Uids::DEFAULT_UNNIQ_ID_LENGTH,
1 => 64,
2 => null
], ],
'auto: ' . \CoreLibs\Create\Uids::STANDARD_HASH_LONG => [ 'auto: ' . \CoreLibs\Create\Uids::STANDARD_HASH_LONG => [
0 => \CoreLibs\Create\Uids::STANDARD_HASH_LONG, 0 => \CoreLibs\Create\Uids::STANDARD_HASH_LONG,
1 => strlen(hash(\CoreLibs\Create\Uids::STANDARD_HASH_LONG, 'A')) 1 => strlen(hash(\CoreLibs\Create\Uids::STANDARD_HASH_LONG, 'A')),
2 => null
], ],
'auto: ' . \CoreLibs\Create\Uids::STANDARD_HASH_SHORT => [ 'auto: ' . \CoreLibs\Create\Uids::STANDARD_HASH_SHORT => [
0 => \CoreLibs\Create\Uids::STANDARD_HASH_SHORT, 0 => \CoreLibs\Create\Uids::STANDARD_HASH_SHORT,
1 => strlen(hash(\CoreLibs\Create\Uids::STANDARD_HASH_SHORT, 'A')) 1 => strlen(hash(\CoreLibs\Create\Uids::STANDARD_HASH_SHORT, 'A')),
2 => null
], ],
]; ];
} }
@@ -105,26 +143,27 @@ final class CoreLibsCreateUidsTest extends TestCase
* *
* @covers ::uniqId * @covers ::uniqId
* @dataProvider uniqIdProvider * @dataProvider uniqIdProvider
* @testdox uniqId $input will be length $expected [$_dataName] * @testdox uniqId $input will be length $expected (Force $flag) [$_dataName]
* *
* @param string|null $input * @param int|string|null $input
* @param string $expected * @param string $expected
* @param bool|null $flag
* @return void * @return void
*/ */
public function testUniqId(?string $input, int $expected): void public function testUniqId(int|string|null $input, int $expected, ?bool $flag): void
{ {
if ($input === null) { if ($input === null) {
$this->assertEquals( $uniq_id_length = strlen(\CoreLibs\Create\Uids::uniqId());
$expected, } elseif ($flag === null) {
strlen(\CoreLibs\Create\Uids::uniqId()) $uniq_id_length = strlen(\CoreLibs\Create\Uids::uniqId($input));
);
} else { } else {
$uniq_id_length = strlen(\CoreLibs\Create\Uids::uniqId($input, $flag));
}
$this->assertEquals( $this->assertEquals(
$expected, $expected,
strlen(\CoreLibs\Create\Uids::uniqId($input)) $uniq_id_length
); );
} }
}
/** /**
* Because we set a constant here, we can only run one test * Because we set a constant here, we can only run one test

View File

@@ -10,11 +10,13 @@ use PHPUnit\Framework\TestCase;
/** /**
* Test class for Debug\Logging * Test class for Debug\Logging
* @coversDefaultClass \CoreLibs\Debug\Logging * @coversDefaultClass \CoreLibs\Debug\LoggingLegacy
* @testdox \CoreLibs\Debug\Logging method tests * @testdox \CoreLibs\Debug\LoggingLegacy method tests
*/ */
final class CoreLibsDebugLoggingTest extends TestCase final class CoreLibsDebugLoggingLegacyTest extends TestCase
{ {
private const LOG_FOLDER = __DIR__ . DIRECTORY_SEPARATOR . 'log' . DIRECTORY_SEPARATOR;
/** /**
* test set for options BASIC * test set for options BASIC
* *
@@ -23,7 +25,7 @@ final class CoreLibsDebugLoggingTest extends TestCase
* 1: expected * 1: expected
* 2: override * 2: override
* override: * override:
* - constant for COSNTANTS * - constant for CONSTANTS
* - global for _GLOBALS * - global for _GLOBALS
* *
* @return array * @return array
@@ -33,17 +35,20 @@ final class CoreLibsDebugLoggingTest extends TestCase
return [ return [
'log folder set' => [ 'log folder set' => [
[ [
'log_folder' => '/tmp' 'log_folder' => DIRECTORY_SEPARATOR . 'tmp',
'file_id' => 'testClassInit'
], ],
[ [
'log_folder' => '/tmp/', 'log_folder' => DIRECTORY_SEPARATOR . 'tmp' . DIRECTORY_SEPARATOR,
'debug_all' => false, 'debug_all' => false,
'print_all' => false, 'print_all' => false,
], ],
[] []
], ],
'nothing set' => [ 'nothing set' => [
null, [
'file_id' => 'testClassInit'
],
[ [
'log_folder' => getcwd() . DIRECTORY_SEPARATOR, 'log_folder' => getcwd() . DIRECTORY_SEPARATOR,
'debug_all' => false, 'debug_all' => false,
@@ -51,30 +56,33 @@ final class CoreLibsDebugLoggingTest extends TestCase
], ],
[] []
], ],
'no options set, constant set' => [ 'no options set, constant set [DEPRECATED]' => [
null,
[ [
'log_folder' => str_replace('/configs', '', __DIR__) 'file_id' => 'testClassInit'
. DIRECTORY_SEPARATOR . 'log/', ],
[
'log_folder' => str_replace(DIRECTORY_SEPARATOR . 'configs', '', __DIR__)
. DIRECTORY_SEPARATOR . 'log' . DIRECTORY_SEPARATOR,
'debug_all' => false, 'debug_all' => false,
'print_all' => false, 'print_all' => false,
], ],
[ [
'constant' => [ 'constant' => [
'BASE' => str_replace('/configs', '', __DIR__) 'BASE' => str_replace(DIRECTORY_SEPARATOR . 'configs', '', __DIR__)
. DIRECTORY_SEPARATOR, . DIRECTORY_SEPARATOR,
'LOG' => 'log/' 'LOG' => 'log' . DIRECTORY_SEPARATOR
] ]
] ]
], ],
'standard test set' => [ 'standard test set' => [
[ [
'log_folder' => '/tmp', 'log_folder' => DIRECTORY_SEPARATOR . 'tmp',
'file_id' => 'testClassInit',
'debug_all' => true, 'debug_all' => true,
'print_all' => true, 'print_all' => true,
], ],
[ [
'log_folder' => '/tmp/', 'log_folder' => DIRECTORY_SEPARATOR . 'tmp' . DIRECTORY_SEPARATOR,
'debug_all' => true, 'debug_all' => true,
'print_all' => true, 'print_all' => true,
], ],
@@ -89,35 +97,66 @@ final class CoreLibsDebugLoggingTest extends TestCase
* @dataProvider optionsProvider * @dataProvider optionsProvider
* @testdox init test [$_dataName] * @testdox init test [$_dataName]
* *
* @param array|null $options * @param array $options
* @param array $expected * @param array $expected
* @param array $override * @param array $override
* @return void * @return void
*/ */
public function testClassInit(?array $options, array $expected, array $override): void public function testClassInit(array $options, array $expected, array $override): void
{ {
if (!empty($override['constant'])) { if (!empty($override['constant'])) {
foreach ($override['constant'] as $var => $value) { foreach ($override['constant'] as $var => $value) {
if (!defined($var)) {
define($var, $value); define($var, $value);
} }
} }
if ($options === null) { // for deprecated no log_folder set
$log = new \CoreLibs\Debug\Logging(); // if base is defined and it does have AAASetupData set
} else { // change the log_folder "Debug" to "AAASetupData"
$log = new \CoreLibs\Debug\Logging($options); if (
defined('BASE') &&
strpos(BASE, DIRECTORY_SEPARATOR . 'AAASetupData') !== false
) {
$expected['log_folder'] = str_replace(
DIRECTORY_SEPARATOR . 'Debug',
DIRECTORY_SEPARATOR . 'AAASetupData',
$expected['log_folder']
);
} }
}
// if not log folder and constant set -> expect E_USER_DEPRECATION
if (!empty($override['constant']) && empty($options['log_folder'])) {
// the deprecation message
$deprecation_message = 'options: log_folder must be set. '
. 'Setting via BASE and LOG constants is deprecated';
// convert E_USER_DEPRECATED to a exception
set_error_handler(
static function (int $errno, string $errstr): never {
throw new \Exception($errstr, $errno);
},
E_USER_DEPRECATED
);
// catch this with the message
$this->expectExceptionMessage($deprecation_message);
}
$log = new \CoreLibs\Debug\LoggingLegacy($options);
// reset error handler
restore_error_handler();
// check that settings match // check that settings match
$this->assertEquals( $this->assertEquals(
$expected['log_folder'], $expected['log_folder'],
$log->getSetting('log_folder') $log->getSetting('log_folder'),
'log folder not matching'
); );
$this->assertEquals( $this->assertEquals(
$expected['debug_all'], $expected['debug_all'],
$log->getSetting('debug_output_all') $log->getSetting('debug_output_all'),
'debug all flag not matching'
); );
$this->assertEquals( $this->assertEquals(
$expected['print_all'], $expected['print_all'],
$log->getSetting('print_output_all') $log->getSetting('print_output_all'),
'print all flag not matching'
); );
// print "LOG: " . $log->getSetting('log_folder') . "\n"; // print "LOG: " . $log->getSetting('log_folder') . "\n";
// print "DEBUG: " . $log->getSetting('debug_output_all') . "\n"; // print "DEBUG: " . $log->getSetting('debug_output_all') . "\n";
@@ -134,17 +173,23 @@ final class CoreLibsDebugLoggingTest extends TestCase
// 0: options // 0: options
// 1: expected // 1: expected
// 2: override // 2: override
// 3: exception message
return [ return [
'no log id set' => [ 'no log id set' => [
null, [
'log_folder' => self::LOG_FOLDER,
],
[ [
'log_file_id' => '' 'log_file_id' => ''
], ],
[] [],
null
], ],
// set log id manually afterwards // set log id manually afterwards
'set log id manually' => [ 'set log id manually' => [
null, [
'log_folder' => self::LOG_FOLDER,
],
[ [
'log_file_id' => '', 'log_file_id' => '',
'set_log_file_id' => 'abc123', 'set_log_file_id' => 'abc123',
@@ -154,21 +199,26 @@ final class CoreLibsDebugLoggingTest extends TestCase
'values' => [ 'values' => [
'log_file_id' => 'abc123' 'log_file_id' => 'abc123'
] ]
] ],
null
], ],
// set log id from options // set log id from options
'set log id via options' => [ 'set log id via options' => [
[ [
'file_id' => 'abc456', 'file_id' => 'abc456',
'log_folder' => self::LOG_FOLDER,
], ],
[ [
'log_file_id' => 'abc456' 'log_file_id' => 'abc456'
], ],
[] [],
null
], ],
// set log id from GLOBALS [DEPRECATED] // set log id from GLOBALS [DEPRECATED]
'set log id via globals' => [ 'set log id via globals [DEPRECATED]' => [
null, [
'log_folder' => self::LOG_FOLDER,
],
[ [
'log_file_id' => 'def123' 'log_file_id' => 'def123'
], ],
@@ -176,11 +226,14 @@ final class CoreLibsDebugLoggingTest extends TestCase
'globals' => [ 'globals' => [
'LOG_FILE_ID' => 'def123' 'LOG_FILE_ID' => 'def123'
] ]
] ],
'options: file_id must be set. Setting via LOG_FILE_ID global variable is deprecated'
], ],
// set log id from CONSTANT [DEPRECATED] // set log id from CONSTANT [DEPRECATED]
'set log id via constant' => [ 'set log id via constant [DEPRECATED]' => [
null, [
'log_folder' => self::LOG_FOLDER,
],
[ [
'log_file_id' => 'ghi123' 'log_file_id' => 'ghi123'
], ],
@@ -192,12 +245,14 @@ final class CoreLibsDebugLoggingTest extends TestCase
'constant' => [ 'constant' => [
'LOG_FILE_ID' => 'ghi123' 'LOG_FILE_ID' => 'ghi123'
] ]
] ],
'options: file_id must be set. Setting via LOG_FILE_ID constant is deprecated'
], ],
// invalid, keep previous set // invalid, keep previous set
'invalid log id' => [ 'invalid log id' => [
[ [
'file_id' => 'jkl456' 'file_id' => 'jkl456',
'log_folder' => self::LOG_FOLDER,
], ],
[ [
'log_file_id' => 'jkl456', 'log_file_id' => 'jkl456',
@@ -207,7 +262,8 @@ final class CoreLibsDebugLoggingTest extends TestCase
'values' => [ 'values' => [
'log_file_id' => './#' 'log_file_id' => './#'
] ]
] ],
null
] ]
]; ];
} }
@@ -219,13 +275,18 @@ final class CoreLibsDebugLoggingTest extends TestCase
* @dataProvider logIdOptionsProvider * @dataProvider logIdOptionsProvider
* @testdox log id set/get tests [$_dataName] * @testdox log id set/get tests [$_dataName]
* *
* @param array|null $options * @param array $options
* @param array $expected * @param array $expected
* @param array $override * @param array $override
* @param string|null $deprecation_message until we remove the old code
* @return void * @return void
*/ */
public function testLogId(?array $options, array $expected, array $override): void public function testLogId(
{ array $options,
array $expected,
array $override,
?string $deprecation_message
): void {
// we need to set with file_id option, globals LOG_FILE_ID, constant LOG_FILE_ID // we need to set with file_id option, globals LOG_FILE_ID, constant LOG_FILE_ID
if (!empty($override['constant'])) { if (!empty($override['constant'])) {
foreach ($override['constant'] as $var => $value) { foreach ($override['constant'] as $var => $value) {
@@ -237,11 +298,20 @@ final class CoreLibsDebugLoggingTest extends TestCase
$GLOBALS[$var] = $value; $GLOBALS[$var] = $value;
} }
} }
if ($options === null) { if (!empty($override['constant']) || !empty($override['globals'])) {
$log = new \CoreLibs\Debug\Logging(); // convert E_USER_DEPRECATED to a exception
} else { set_error_handler(
$log = new \CoreLibs\Debug\Logging($options); static function (int $errno, string $errstr): never {
throw new \Exception($errstr, $errno);
},
E_USER_DEPRECATED
);
// catch this with the message
$this->expectExceptionMessage($deprecation_message);
} }
$log = new \CoreLibs\Debug\LoggingLegacy($options);
// reset error handler
restore_error_handler();
// check current // check current
$this->assertEquals( $this->assertEquals(
$log->getLogId(), $log->getLogId(),
@@ -316,7 +386,10 @@ final class CoreLibsDebugLoggingTest extends TestCase
bool $expected_get bool $expected_get
): void { ): void {
// neutral start with default // neutral start with default
$log = new \CoreLibs\Debug\Logging(); $log = new \CoreLibs\Debug\LoggingLegacy([
'file_id' => 'testSetGetLogLevelAll',
'log_folder' => self::LOG_FOLDER
]);
// set and check // set and check
$this->assertEquals( $this->assertEquals(
$log->setLogLevelAll($type, $flag), $log->setLogLevelAll($type, $flag),
@@ -438,7 +511,10 @@ final class CoreLibsDebugLoggingTest extends TestCase
$expected_get $expected_get
): void { ): void {
// neutral start with default // neutral start with default
$log = new \CoreLibs\Debug\Logging(); $log = new \CoreLibs\Debug\LoggingLegacy([
'file_id' => 'testSetGetLogLevel',
'log_folder' => self::LOG_FOLDER
]);
// set // set
$this->assertEquals( $this->assertEquals(
$log->setLogLevel($type, $flag, $debug_on), $log->setLogLevel($type, $flag, $debug_on),
@@ -517,7 +593,10 @@ final class CoreLibsDebugLoggingTest extends TestCase
bool $expected_get bool $expected_get
): void { ): void {
// neutral start with default // neutral start with default
$log = new \CoreLibs\Debug\Logging(); $log = new \CoreLibs\Debug\LoggingLegacy([
'file_id' => 'testSetGetLogPer',
'log_folder' => self::LOG_FOLDER
]);
// set and check // set and check
$this->assertEquals( $this->assertEquals(
$log->setLogPer($type, $set), $log->setLogPer($type, $set),
@@ -546,7 +625,10 @@ final class CoreLibsDebugLoggingTest extends TestCase
public function testSetGetLogPrintFileDate(bool $input, bool $expected_set, bool $expected_get): void public function testSetGetLogPrintFileDate(bool $input, bool $expected_set, bool $expected_get): void
{ {
// neutral start with default // neutral start with default
$log = new \CoreLibs\Debug\Logging(); $log = new \CoreLibs\Debug\LoggingLegacy([
'file_id' => 'testSetGetLogPrintFileDate',
'log_folder' => self::LOG_FOLDER
]);
// set and check // set and check
$this->assertEquals( $this->assertEquals(
$log->setGetLogPrintFileDate($input), $log->setGetLogPrintFileDate($input),
@@ -612,7 +694,10 @@ final class CoreLibsDebugLoggingTest extends TestCase
*/ */
public function testPrAr(array $input, string $expected): void public function testPrAr(array $input, string $expected): void
{ {
$log = new \CoreLibs\Debug\Logging(); $log = new \CoreLibs\Debug\LoggingLegacy([
'file_id' => 'testPrAr',
'log_folder' => self::LOG_FOLDER
]);
$this->assertEquals( $this->assertEquals(
$log->prAr($input), $log->prAr($input),
$expected $expected
@@ -673,7 +758,10 @@ final class CoreLibsDebugLoggingTest extends TestCase
*/ */
public function testPrBl(bool $input, ?string $true, ?string $false, string $expected): void public function testPrBl(bool $input, ?string $true, ?string $false, string $expected): void
{ {
$log = new \CoreLibs\Debug\Logging(); $log = new \CoreLibs\Debug\LoggingLegacy([
'file_id' => 'testPrBl',
'log_folder' => self::LOG_FOLDER
]);
$return = ''; $return = '';
if ($true === null && $false === null) { if ($true === null && $false === null) {
$return = $log->prBl($input); $return = $log->prBl($input);
@@ -845,7 +933,7 @@ final class CoreLibsDebugLoggingTest extends TestCase
// remove any files named /tmp/error_log_TestDebug*.log // remove any files named /tmp/error_log_TestDebug*.log
array_map('unlink', glob($options['log_folder'] . 'error_msg_' . $options['file_id'] . '*.log')); array_map('unlink', glob($options['log_folder'] . 'error_msg_' . $options['file_id'] . '*.log'));
// init logger // init logger
$log = new \CoreLibs\Debug\Logging($options); $log = new \CoreLibs\Debug\LoggingLegacy($options);
// * debug (A/B) // * debug (A/B)
// NULL check for strip/prefix // NULL check for strip/prefix
$this->assertEquals( $this->assertEquals(
@@ -959,9 +1047,16 @@ final class CoreLibsDebugLoggingTest extends TestCase
public function testLogUniqueId(bool $option, bool $override): void public function testLogUniqueId(bool $option, bool $override): void
{ {
if ($option === true) { if ($option === true) {
$log = new \CoreLibs\Debug\Logging(['per_run' => $option]); $log = new \CoreLibs\Debug\LoggingLegacy([
'file_id' => 'testLogUniqueId',
'log_folder' => self::LOG_FOLDER,
'per_run' => $option
]);
} else { } else {
$log = new \CoreLibs\Debug\Logging(); $log = new \CoreLibs\Debug\LoggingLegacy([
'file_id' => 'testLogUniqueId',
'log_folder' => self::LOG_FOLDER
]);
$log->setLogUniqueId(); $log->setLogUniqueId();
} }
$per_run_id = $log->getLogUniqueId(); $per_run_id = $log->getLogUniqueId();

View File

@@ -5,6 +5,7 @@ declare(strict_types=1);
namespace tests; namespace tests;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use CoreLibs\Debug\Support;
/** /**
* Test class for Debug\Support * Test class for Debug\Support
@@ -40,6 +41,32 @@ final class CoreLibsDebugSupportTest extends TestCase
]; ];
} }
/**
* Undocumented function
*
* @cover ::printTime
* @dataProvider printTimeProvider
* @testdox printTime test with $microtime and match to regex [$_dataName]
*
* @param int|null $mircrotime
* @param string $expected
* @return void
*/
public function testPrintTime(?int $microtime, string $regex): void
{
if ($microtime === null) {
$this->assertMatchesRegularExpression(
$regex,
Support::printTime()
);
} else {
$this->assertMatchesRegularExpression(
$regex,
Support::printTime($microtime)
);
}
}
/** /**
* Undocumented function * Undocumented function
* *
@@ -50,18 +77,55 @@ final class CoreLibsDebugSupportTest extends TestCase
return [ return [
'empty array' => [ 'empty array' => [
0 => [], 0 => [],
1 => "<pre>Array\n(\n)\n</pre>" 1 => "<pre>Array\n(\n)\n</pre>",
2 => "Array\n(\n)\n",
], ],
'simple array' => [ 'simple array' => [
0 => ['a', 'b'], 0 => ['a', 'b'],
1 => "<pre>Array\n(\n" 1 => "<pre>Array\n(\n"
. " [0] => a\n" . " [0] => a\n"
. " [1] => b\n" . " [1] => b\n"
. ")\n</pre>" . ")\n</pre>",
2 => "Array\n(\n"
. " [0] => a\n"
. " [1] => b\n"
. ")\n",
], ],
]; ];
} }
/**
* Undocumented function
*
* @cover ::printAr
* @cover ::printArray
* @dataProvider printArrayProvider
* @testdox printAr/printArray $input will be $expected [$_dataName]
*
* @param array $input
* @param string $expected
* @param string $expected_strip
* @return void
*/
public function testPrintAr(array $input, string $expected, string $expected_strip): void
{
$this->assertEquals(
$expected,
Support::printAr($input),
'assert printAr'
);
$this->assertEquals(
$expected,
Support::printArray($input),
'assert printArray'
);
$this->assertEquals(
$expected_strip,
Support::prAr($input),
'assert prAr'
);
}
/** /**
* Undocumented function * Undocumented function
* *
@@ -73,27 +137,31 @@ final class CoreLibsDebugSupportTest extends TestCase
'true input default' => [ 'true input default' => [
0 => true, 0 => true,
1 => [], 1 => [],
2 => 'true' 2 => 'true',
3 => 'true',
], ],
'false input default' => [ 'false input default' => [
0 => false, 0 => false,
1 => [], 1 => [],
2 => 'false' 2 => 'false',
3 => 'false'
], ],
'false input param name' => [ 'false input param name' => [
0 => false, 0 => false,
1 => [ 1 => [
'name' => 'param test' 'name' => 'param test'
], ],
2 => '<b>param test</b>: false' 2 => '<b>param test</b>: false',
3 => 'false'
], ],
'true input param name, true override' => [ 'true input param name, true override' => [
0 => true, 0 => true,
1 => [ 1 => [
'name' => 'param test', 'name' => 'param test',
'true' => 'ok' 'true' => 'ok',
], ],
2 => '<b>param test</b>: ok' 2 => '<b>param test</b>: ok',
3 => 'ok',
], ],
'false input param name, true override, false override' => [ 'false input param name, true override, false override' => [
0 => false, 0 => false,
@@ -102,11 +170,77 @@ final class CoreLibsDebugSupportTest extends TestCase
'true' => 'ok', 'true' => 'ok',
'false' => 'not', 'false' => 'not',
], ],
2 => '<b>param test</b>: not' 2 => '<b>param test</b>: not',
3 => 'not'
], ],
]; ];
} }
/**
* Undocumented function
*
* @cover ::printBool
* @dataProvider printBoolProvider
* @testdox printBool $input will be $expected [$_dataName]
*
* @param bool $input
* @param array $params
* @param string $expected
* @param string $expected_strip
* @return void
*/
public function testPrintBool(bool $input, array $params, string $expected, string $expected_strip): void
{
if (
isset($params['name']) &&
isset($params['true']) &&
isset($params['false'])
) {
$string = Support::printBool(
$input,
$params['name'],
$params['true'],
$params['false']
);
$string_strip = Support::prBl(
$input,
$params['true'],
$params['false']
);
} elseif (isset($params['name']) && isset($params['true'])) {
$string = Support::printBool(
$input,
$params['name'],
$params['true']
);
$string_strip = Support::prBl(
$input,
$params['true'],
);
} elseif (isset($params['name'])) {
$string = Support::printBool(
$input,
$params['name']
);
$string_strip = Support::prBl(
$input
);
} else {
$string = Support::printBool($input);
$string_strip = Support::prBl($input);
}
$this->assertEquals(
$expected,
$string,
'assert printBool'
);
$this->assertEquals(
$expected_strip,
$string_strip,
'assert prBl'
);
}
/** /**
* Undocumented function * Undocumented function
* *
@@ -169,12 +303,10 @@ final class CoreLibsDebugSupportTest extends TestCase
'an array, no html' => [ 'an array, no html' => [
['a', 'b'], ['a', 'b'],
true, true,
"##HTMLPRE##" "Array\n(\n"
. "Array\n(\n"
. " [0] => a\n" . " [0] => a\n"
. " [1] => b\n" . " [1] => b\n"
. ")\n" . ")\n",
. "##/HTMLPRE##",
], ],
// resource // resource
'a resource' => [ 'a resource' => [
@@ -191,6 +323,330 @@ final class CoreLibsDebugSupportTest extends TestCase
]; ];
} }
/**
* Undocumented function
*
* @cover ::printToString
* @dataProvider printToStringProvider
* @testdox printToString $input with $flag will be $expected [$_dataName]
*
* @param mixed $input anything
* @param boolean|null $flag html flag, only for string and array
* @param string $expected always string
* @return void
*/
public function testPrintToString(mixed $input, ?bool $flag, string $expected): void
{
if ($flag === null) {
// if expected starts with / and ends with / then this is a regex compare
if (
substr($expected, 0, 1) == '/' &&
substr($expected, -1, 1) == '/'
) {
$this->assertMatchesRegularExpression(
$expected,
Support::printToString($input)
);
} else {
$this->assertEquals(
$expected,
Support::printToString($input)
);
}
} else {
$this->assertEquals(
$expected,
Support::printToString($input, $flag)
);
}
}
/**
* Undocumented function
*
* @return array
*/
public function providerDumpExportVar(): array
{
return [
'string' => [
'input' => 'string',
'flag' => null,
'expected_dump' => 'string(6) "string"' . "\n",
'expected_export' => "<pre>'string'</pre>",
],
'string, no html' => [
'input' => 'string',
'flag' => true,
'expected_dump' => 'string(6) "string"' . "\n",
'expected_export' => "'string'",
],
// int
'int' => [
'input' => 6,
'flag' => null,
'expected_dump' => 'int(6)' . "\n",
'expected_export' => "<pre>6</pre>",
],
// float
'float' => [
'input' => 1.6,
'flag' => null,
'expected_dump' => 'float(1.6)' . "\n",
'expected_export' => "<pre>1.6</pre>",
],
// bool
'bool' => [
'input' => true,
'flag' => null,
'expected_dump' => 'bool(true)' . "\n",
'expected_export' => "<pre>true</pre>",
],
// array
'array' => [
'input' => ['string', true],
'flag' => null,
'expected_dump' => "array(2) {\n"
. " [0]=>\n"
. " string(6) \"string\"\n"
. " [1]=>\n"
. " bool(true)\n"
. "}\n",
'expected_export' => "<pre>array (\n"
. " 0 => 'string',\n"
. " 1 => true,\n"
. ")</pre>",
],
// more
];
}
/**
* Undocumented function
*
* @cover ::dumpVar
* @cover ::exportVar
* @dataProvider providerDumpExportVar
* @testdox dump/exportVar $input with $flag will be $expected_dump / $expected_export [$_dataName]
*
* @param mixed $input
* @param bool|null $flag
* @param string $expected_dump
* @param string $expected_export
* @return void
*/
public function testDumpExportVar(mixed $input, ?bool $flag, string $expected_dump, string $expected_export): void
{
if ($flag === null) {
$dump = Support::dumpVar($input);
$export = Support::exportVar($input);
} else {
$dump = Support::dumpVar($input, $flag);
$export = Support::exportVar($input, $flag);
}
$this->assertEquals(
$expected_dump,
$dump,
'assert dumpVar'
);
$this->assertEquals(
$expected_export,
$export,
'assert dumpVar'
);
}
/**
* Undocumented function
*
* @cover ::getCallerFileLine
* @testWith ["vendor/phpunit/phpunit/src/Framework/TestCase.php:6434","phar:///home/clemens/.phive/phars/phpunit-9.6.13.phar/phpunit/Framework/TestCase.php:6434"]
* @testdox getCallerFileLine check based on regex .../Framework/TestCase.php:\d+ [$_dataName]
*
* @param string $expected
* @return void
*/
public function testGetCallerFileLine(): void
{
// regex prefix with path "/../" and then fixed vendor + \d+
// or phar start if phiev installed
// phar:///home/clemens/.phive/phars/phpunit-9.6.13.phar/phpunit/Framework/TestCase.php
$regex = "/^("
. "\/.*\/vendor\/phpunit\/phpunit\/src"
. "|"
. "phar:\/\/\/.*\.phive\/phars\/phpunit-\d+\.\d+\.\d+\.phar\/phpunit"
. ")"
. "\/Framework\/TestCase.php:\d+$/";
$this->assertMatchesRegularExpression(
$regex,
Support::getCallerFileLine()
);
}
/**
* Undocumented function
*
* @cover ::getCallerMethod
* @testWith ["testGetCallerMethod"]
* @testdox getCallerMethod check if it returns $expected [$_dataName]
*
* @return void
*/
public function testGetCallerMethod(string $expected): void
{
$this->assertEquals(
$expected,
Support::getCallerMethod()
);
}
/**
* Undocumented function
*
* @cover ::getCallerMethodList
* @testWith [["main", "run", "run", "run", "run", "run", "run", "runBare", "runTest", "testGetCallerMethodList"]]
* @testdox getCallerMethodList check if it returns $expected [$_dataName]
*
* @param array $expected
* @return void
*/
public function testGetCallerMethodList(array $expected): void
{
$compare = Support::getCallerMethodList();
// 10: legacy
// 11: direct
// 12: full call
switch (count($compare)) {
case 10:
// add nothing
$this->assertEquals(
$expected,
$compare,
'assert expected 10'
);
break;
case 11:
if ($compare[0] == 'include') {
// add include at first
array_splice(
$expected,
0,
0,
['include']
);
} else {
array_splice(
$expected,
6,
0,
['run']
);
}
$this->assertEquals(
$expected,
$compare,
'assert expected 11'
);
break;
case 12:
// add two "run" before "runBare"
array_splice(
$expected,
7,
0,
['run']
);
array_splice(
$expected,
0,
0,
['include']
);
$this->assertEquals(
$expected,
$compare,
'assert expected 12'
);
break;
}
}
/**
* Undocumented function
*
* @cover ::getCallStack
* @testdox getCallStack check if it returns data [$_dataName]
*
* @return void
*/
public function testGetCallStack(): void
{
$call_stack = Support::getCallStack();
// print "Get CALL: " . print_r(Support::getCallStack(), true) . "\n";
if ($call_stack < 8) {
$this->assertFalse(true, 'getCallStack too low: 8');
} else {
$this->assertTrue(true, 'getCallSteck ok');
}
// just test top entry
$first = array_shift($call_stack);
$this->assertStringEndsWith(
':tests\CoreLibsDebugSupportTest->testGetCallStack',
$first,
);
}
/**
* test the lowest one (one above base)
*
* @cover ::getCallerClass
* @testWith ["tests\\CoreLibsDebugSupportTest"]
* @testdox getCallerClass check if it returns $expected [$_dataName]
*
* @return void
*/
public function testGetCallerClass(string $expected): void
{
$this->assertEquals(
$expected,
Support::getCallerClass()
);
}
/**
* test highest return (top level)
*
* @cover ::getCallerTopLevelClass
* @testWith ["PHPUnit\\TextUI\\Command"]
* @testdox getCallerTopLevelClass check if it returns $expected [$_dataName]
*
* @return void
*/
public function testGetCallerTopLevelClass(string $expected): void
{
$this->assertEquals(
$expected,
Support::getCallerTopLevelClass()
);
}
/**
* test highest return (top level)
*
* @cover ::getCallerClassMethod
* @testWith ["tests\\CoreLibsDebugSupportTest->testGetCallerClassMethod"]
* @testdox getCallerClassMethod check if it returns $expected [$_dataName]
*
* @return void
*/
public function testGetCallerClassMethod(string $expected): void
{
$this->assertEquals(
$expected,
Support::getCallerClassMethod()
);
}
/** /**
* Undocumented function * Undocumented function
* *
@@ -236,205 +692,6 @@ final class CoreLibsDebugSupportTest extends TestCase
]; ];
} }
/**
* Undocumented function
*
* @cover ::printTime
* @dataProvider printTimeProvider
* @testdox printTime test with $microtime and match to regex [$_dataName]
*
* @param int|null $mircrotime
* @param string $expected
* @return void
*/
public function testPrintTime(?int $microtime, string $regex): void
{
if ($microtime === null) {
$this->assertMatchesRegularExpression(
$regex,
\CoreLibs\Debug\Support::printTime()
);
} else {
$this->assertMatchesRegularExpression(
$regex,
\CoreLibs\Debug\Support::printTime($microtime)
);
}
}
/**
* Undocumented function
*
* @cover ::printAr
* @cover ::printArray
* @dataProvider printArrayProvider
* @testdox printAr/printArray $input will be $expected [$_dataName]
*
* @param array $input
* @param string $expected
* @return void
*/
public function testPrintAr(array $input, string $expected): void
{
$this->assertEquals(
$expected,
\CoreLibs\Debug\Support::printAr($input),
'assert printAr'
);
$this->assertEquals(
$expected,
\CoreLibs\Debug\Support::printArray($input),
'assert printArray'
);
}
/**
* Undocumented function
*
* @cover ::printBool
* @dataProvider printBoolProvider
* @testdox printBool $input will be $expected [$_dataName]
*
* @param bool $input
* @param array $params
* @param string $expected
* @return void
*/
public function testPrintBool(bool $input, array $params, string $expected): void
{
if (
isset($params['name']) &&
isset($params['true']) &&
isset($params['false'])
) {
$string = \CoreLibs\Debug\Support::printBool(
$input,
$params['name'],
$params['true'],
$params['false']
);
} elseif (isset($params['name']) && isset($params['true'])) {
$string = \CoreLibs\Debug\Support::printBool(
$input,
$params['name'],
$params['true']
);
} elseif (isset($params['name'])) {
$string = \CoreLibs\Debug\Support::printBool(
$input,
$params['name']
);
} else {
$string = \CoreLibs\Debug\Support::printBool($input);
}
$this->assertEquals(
$expected,
$string,
'assert printBool'
);
}
/**
* Undocumented function
*
* @cover ::printToString
* @dataProvider printToStringProvider
* @testdox printToString $input with $flag will be $expected [$_dataName]
*
* @param mixed $input anything
* @param boolean|null $flag html flag, only for string and array
* @param string $expected always string
* @return void
*/
public function testPrintToString(mixed $input, ?bool $flag, string $expected): void
{
if ($flag === null) {
// if expected starts with / and ends with / then this is a regex compare
if (
substr($expected, 0, 1) == '/' &&
substr($expected, -1, 1) == '/'
) {
$this->assertMatchesRegularExpression(
$expected,
\CoreLibs\Debug\Support::printToString($input)
);
} else {
$this->assertEquals(
$expected,
\CoreLibs\Debug\Support::printToString($input)
);
}
} else {
$this->assertEquals(
$expected,
\CoreLibs\Debug\Support::printToString($input, $flag)
);
}
}
/**
* Undocumented function
*
* @cover ::getCallerMethod
* @testWith ["testGetCallerMethod"]
* @testdox getCallerMethod check if it returns $expected [$_dataName]
*
* @return void
*/
public function testGetCallerMethod(string $expected): void
{
$this->assertEquals(
$expected,
\CoreLibs\Debug\Support::getCallerMethod()
);
}
/**
* Undocumented function
*
* @cover ::getCallerMethodList
* @testWith [["main", "run", "run", "run", "run", "run", "run", "runBare", "runTest", "testGetCallerMethodList"],["include", "main", "run", "run", "run", "run", "run", "run", "run", "runBare", "runTest", "testGetCallerMethodList"]]
* @testdox getCallerMethodList check if it returns $expected [$_dataName]
*
* @param array $expected
* @return void
*/
public function testGetCallerMethodList(array $expected, array $expected_group): void
{
$compare = \CoreLibs\Debug\Support::getCallerMethodList();
// if we direct call we have 10, if we call as folder we get 11
if (count($compare) == 10) {
$this->assertEquals(
$expected,
\CoreLibs\Debug\Support::getCallerMethodList(),
'assert expected 10'
);
} else {
$this->assertEquals(
$expected_group,
\CoreLibs\Debug\Support::getCallerMethodList(),
'assert expected group'
);
}
}
/**
* Undocumented function
*
* @cover ::getCallerClass
* @testWith ["PHPUnit\\TextUI\\Command"]
* @testdox getCallerClass check if it returns $expected [$_dataName]
*
* @return void
*/
public function testGetCallerClass(string $expected): void
{
$this->assertEquals(
$expected,
\CoreLibs\Debug\Support::getCallerClass()
);
}
/** /**
* Undocumented function * Undocumented function
* *
@@ -453,19 +710,19 @@ final class CoreLibsDebugSupportTest extends TestCase
if ($replace === null && $flag === null) { if ($replace === null && $flag === null) {
$this->assertEquals( $this->assertEquals(
$expected, $expected,
\CoreLibs\Debug\Support::debugString($input), Support::debugString($input),
'assert all default' 'assert all default'
); );
} elseif ($flag === null) { } elseif ($flag === null) {
$this->assertEquals( $this->assertEquals(
$expected, $expected,
\CoreLibs\Debug\Support::debugString($input, $replace), Support::debugString($input, $replace),
'assert flag default' 'assert flag default'
); );
} else { } else {
$this->assertEquals( $this->assertEquals(
$expected, $expected,
\CoreLibs\Debug\Support::debugString($input, $replace, $flag), Support::debugString($input, $replace, $flag),
'assert all set' 'assert all set'
); );
} }

View File

@@ -1,2 +1,3 @@
* *log
*LOG
!.gitignore !.gitignore

View File

@@ -77,21 +77,24 @@ final class CoreLibsGetDotEnvTest extends TestCase
'file' => 'cannot_read.env', 'file' => 'cannot_read.env',
'status' => 2, 'status' => 2,
'content' => [], 'content' => [],
'chmod' => '000', // 0000
'chmod' => '100000',
], ],
'empty file' => [ 'empty file' => [
'folder' => __DIR__ . DIRECTORY_SEPARATOR . 'dotenv', 'folder' => __DIR__ . DIRECTORY_SEPARATOR . 'dotenv',
'file' => 'empty.env', 'file' => 'empty.env',
'status' => 1, 'status' => 1,
'content' => [], 'content' => [],
'chmod' => null, // 0664
'chmod' => '100664',
], ],
'override all' => [ 'override all' => [
'folder' => __DIR__ . DIRECTORY_SEPARATOR . 'dotenv', 'folder' => __DIR__ . DIRECTORY_SEPARATOR . 'dotenv',
'file' => 'test.env', 'file' => 'test.env',
'status' => 0, 'status' => 0,
'content' => $dot_env_content, 'content' => $dot_env_content,
'chmod' => null, // 0664
'chmod' => '100664',
], ],
'override directory' => [ 'override directory' => [
'folder' => __DIR__ . DIRECTORY_SEPARATOR . 'dotenv', 'folder' => __DIR__ . DIRECTORY_SEPARATOR . 'dotenv',
@@ -124,6 +127,16 @@ final class CoreLibsGetDotEnvTest extends TestCase
array $expected_env, array $expected_env,
?string $chmod ?string $chmod
): void { ): void {
if (
!empty($chmod) &&
$chmod == '100000' &&
getmyuid() == 0
) {
$this->markTestSkipped(
"Skip cannot read file test because run user is root"
);
return;
}
// if we have file + chmod set // if we have file + chmod set
$old_chmod = null; $old_chmod = null;
if ( if (
@@ -134,6 +147,20 @@ final class CoreLibsGetDotEnvTest extends TestCase
$old_chmod = fileperms($folder . DIRECTORY_SEPARATOR . $file); $old_chmod = fileperms($folder . DIRECTORY_SEPARATOR . $file);
chmod($folder . DIRECTORY_SEPARATOR . $file, octdec($chmod)); chmod($folder . DIRECTORY_SEPARATOR . $file, octdec($chmod));
} }
$message = '\CoreLibs\Get\DotEnv is deprecated in favor for '
. 'composer package gullevek\dotenv which is a copy of this';
// convert E_USER_DEPRECATED to a exception
set_error_handler(
static function (int $errno, string $errstr): never {
throw new \Exception($errstr, $errno);
},
E_USER_DEPRECATED
);
// tests are never run -> deprecated
if (is_file($folder . DIRECTORY_SEPARATOR . $file)) {
chmod($folder . DIRECTORY_SEPARATOR . $file, 0664);
}
$this->expectExceptionMessage($message);
if ($folder !== null && $file !== null) { if ($folder !== null && $file !== null) {
$status = DotEnv::readEnvFile($folder, $file); $status = DotEnv::readEnvFile($folder, $file);
} elseif ($folder !== null) { } elseif ($folder !== null) {
@@ -141,6 +168,7 @@ final class CoreLibsGetDotEnvTest extends TestCase
} else { } else {
$status = DotEnv::readEnvFile(); $status = DotEnv::readEnvFile();
} }
restore_error_handler();
$this->assertEquals( $this->assertEquals(
$status, $status,
$expected_status, $expected_status,
@@ -153,8 +181,9 @@ final class CoreLibsGetDotEnvTest extends TestCase
'Assert _ENV correct' 'Assert _ENV correct'
); );
// if we have file and chmod unset // if we have file and chmod unset
if ($old_chmod !== null) { print "Write mode: $old_chmod\n";
chmod($folder . DIRECTORY_SEPARATOR . $file, $old_chmod); if ($old_chmod !== null && $chmod == '100000') {
chmod($folder . DIRECTORY_SEPARATOR . $file, 0664);
} }
} }
} }

View File

@@ -67,17 +67,17 @@ final class CoreLibsGetSystemTest extends TestCase
'original set' => [ 'original set' => [
0 => null, 0 => null,
1 => 'NOHOST', 1 => 'NOHOST',
2 => 'NOPORT', 2 => 0,
], ],
'override set no port' => [ 'override set no port' => [
0 => 'foo.org', 0 => 'foo.org',
1 => 'foo.org', 1 => 'foo.org',
2 => '80' 2 => 80
], ],
'override set with port' => [ 'override set with port' => [
0 => 'foo.org:443', 0 => 'foo.org:443',
1 => 'foo.org', 1 => 'foo.org',
2 => '443' 2 => 443
] ]
]; ];
} }
@@ -99,7 +99,7 @@ final class CoreLibsGetSystemTest extends TestCase
1 => 'phpunit', 1 => 'phpunit',
2 => 'phpunit', 2 => 'phpunit',
// NOTE: this can change, so it is a regex check // NOTE: this can change, so it is a regex check
3 => "/^(\/?.*\/?)?vendor\/bin\/phpunit$/", 3 => "/^(\/?.*\/?)?(vendor\/bin|tools)\/phpunit$/",
], ],
'some path with extension' => [ 'some path with extension' => [
0 => '/some/path/to/file.txt', 0 => '/some/path/to/file.txt',
@@ -138,10 +138,10 @@ final class CoreLibsGetSystemTest extends TestCase
* *
* @param string|null $input * @param string|null $input
* @param string $expected_host * @param string $expected_host
* @param string $expected_port * @param int $expected_port
* @return void * @return void
*/ */
public function testGetHostNanme(?string $input, string $expected_host, string $expected_port): void public function testGetHostNanme(?string $input, string $expected_host, int $expected_port): void
{ {
// print "HOSTNAME: " . $_SERVER['HTTP_HOST'] . "<br>"; // print "HOSTNAME: " . $_SERVER['HTTP_HOST'] . "<br>";
// print "SERVER: " . print_r($_SERVER, true) . "\n"; // print "SERVER: " . print_r($_SERVER, true) . "\n";
@@ -216,6 +216,29 @@ final class CoreLibsGetSystemTest extends TestCase
); );
} }
} }
/**
* Undocumented function
*
* @covers ::getIpAddresses
* @testdox getIpAddresses check
*
* @return void
*/
public function testGetIpAddresses()
{
// response must have "REMOTE_ADDR" entry, others are optional
// NOTE: we have no IP addresses on command line
$this->assertTrue(
true,
"We do not have REMOTE_ADDR on command line"
);
// $this->assertContains(
// 'REMOTE_ADDR',
// array_keys(\CoreLibs\Get\System::getIpAddresses()),
// 'failed REMOTE_ADDR assert'
// );
}
} }
// __END__ // __END__

View File

@@ -0,0 +1,568 @@
<?php // phpcs:disable Generic.Files.LineLength
declare(strict_types=1);
namespace tests;
use PHPUnit\Framework\TestCase;
/**
* Test class for Language\GetLocale
*
* @coversDefaultClass \CoreLibs\Language\GetLocale
* @testdox \CoreLibs\Language\GetLocale method tests
*/
final class CoreLibsLanguageGetLocaleTest extends TestCase
{
public const SITE_ENCODING = 'UTF-8';
public const SITE_LOCALE = 'en_US.UTF-8';
public const SITE_DOMAIN = 'admin';
public const LOCALE_PATH = __DIR__ . DIRECTORY_SEPARATOR
. 'includes' . DIRECTORY_SEPARATOR
. 'locale' . DIRECTORY_SEPARATOR;
/**
* set all constant variables that must be set before call
*
* @return void
*/
public static function setUpBeforeClass(): void
{
// default web page encoding setting
/* if (!defined('DEFAULT_ENCODING')) {
define('DEFAULT_ENCODING', 'UTF-8');
}
if (!defined('DEFAULT_LOCALE')) {
// default lang + encoding
define('DEFAULT_LOCALE', 'en_US.UTF-8');
}
// site
if (!defined('SITE_ENCODING')) {
define('SITE_ENCODING', DEFAULT_ENCODING);
}
if (!defined('SITE_LOCALE')) {
define('SITE_LOCALE', DEFAULT_LOCALE);
} */
// just set
/* if (!defined('BASE')) {
define('BASE', str_replace('/configs', '', __DIR__) . DIRECTORY_SEPARATOR);
}
if (!defined('INCLUDES')) {
define('INCLUDES', 'includes' . DIRECTORY_SEPARATOR);
}
if (!defined('LANG')) {
define('LANG', 'lang' . DIRECTORY_SEPARATOR);
}
if (!defined('LOCALE')) {
define('LOCALE', 'locale' . DIRECTORY_SEPARATOR);
}
if (!defined('CONTENT_PATH')) {
define('CONTENT_PATH', 'frontend' . DIRECTORY_SEPARATOR);
} */
// array session
$_SESSION = [];
global $_SESSION;
}
/**
* all the test data
*
* @return array<mixed>
*/
/* public function setLocaleProvider(): array
{
return [
// 0: locale
// 1: domain
// 2: encoding
// 3: path
// 4: SESSION: DEFAULT_LOCALE
// 5: SESSION: DEFAULT_CHARSET
// 6: expected array
// 7: deprecation message
'no params, all default constants' => [
// lang, domain, encoding, path
null, null, null, null,
// SESSION DEFAULT_LOCALE, SESSION: DEFAULT_CHARSET
null, null,
// return array
[
'locale' => 'en_US.UTF-8',
'lang' => 'en_US',
'domain' => 'frontend',
'encoding' => 'UTF-8',
'path' => "/^\/(.*\/)?includes\/locale\/$/",
],
'setLocale: Unset $locale or unset SESSION locale is deprecated',
],
'no params, session charset and lang' => [
// lang, domain, encoding, path
null, null, null, null,
// SESSION DEFAULT_LOCALE, SESSION: DEFAULT_CHARSET
'ja_JP', 'UTF-8',
// return array
[
'locale' => 'ja_JP',
'lang' => 'ja_JP',
'domain' => 'frontend',
'encoding' => 'UTF-8',
'path' => "/^\/(.*\/)?includes\/locale\/$/",
],
'setLocale: Unset $domain is deprecated'
],
'no params, session charset and lang short' => [
// lang, domain, encoding, path
null, null, null, null,
// SESSION DEFAULT_LOCALE, SESSION: DEFAULT_CHARSET
'ja', 'UTF-8',
// return array
[
'locale' => 'ja',
'lang' => 'ja',
'domain' => 'frontend',
'encoding' => 'UTF-8',
'path' => "/^\/(.*\/)?includes\/locale\/$/",
],
'setLocale: Unset $domain is deprecated',
],
// param lang (no sessions)
'locale param only, no sessions' => [
// lang, domain, encoding, path
'ja.UTF-8', null, null, null,
// SESSION DEFAULT_LOCALE, SESSION: DEFAULT_CHARSET
null, null,
// return array
[
'locale' => 'ja.UTF-8',
'lang' => 'ja',
'domain' => 'frontend',
'encoding' => 'UTF-8',
'path' => "/^\/(.*\/)?includes\/locale\/$/",
],
'setLocale: Unset $domain is deprecated',
],
// different locale setting
'locale complex param only, no sessions' => [
// lang, domain, encoding, path
'ja_JP.SJIS', null, null, null,
// SESSION DEFAULT_LOCALE, SESSION: DEFAULT_CHARSET
null, null,
// return array
[
'locale' => 'ja_JP.SJIS',
'lang' => 'ja_JP',
'domain' => 'frontend',
'encoding' => 'SJIS',
'path' => "/^\/(.*\/)?includes\/locale\/$/",
],
'setLocale: Unset $domain is deprecated',
],
// param lang and domain (no override)
'locale, domain params, no sessions' => [
// lang, domain, encoding, path
'ja.UTF-8', 'admin', null, null,
// SESSION DEFAULT_LOCALE, SESSION: DEFAULT_CHARSET
null, null,
// return array
[
'locale' => 'ja.UTF-8',
'lang' => 'ja',
'domain' => 'admin',
'encoding' => 'UTF-8',
'path' => "/^\/(.*\/)?includes\/locale\/$/",
],
'setLocale: Unset $path is deprecated',
],
// param lang and domain (no override)
'locale, domain, encoding params, no sessions' => [
// lang, domain, encoding, path
'ja.UTF-8', 'admin', 'UTF-8', null,
// SESSION DEFAULT_LOCALE, SESSION: DEFAULT_CHARSET
null, null,
// return array
[
'locale' => 'ja.UTF-8',
'lang' => 'ja',
'domain' => 'admin',
'encoding' => 'UTF-8',
'path' => "/^\/(.*\/)?includes\/locale\/$/",
],
'setLocale: Unset $path is deprecated'
],
// lang, domain, path (no override)
'locale, domain and path, no sessions' => [
// lang, domain, encoding, path
'ja.UTF-8', 'admin', '', __DIR__ . '/locale_other/',
// SESSION DEFAULT_LOCALE, SESSION: DEFAULT_CHARSET
null, null,
// return array
[
'locale' => 'ja.UTF-8',
'lang' => 'ja',
'domain' => 'admin',
'encoding' => 'UTF-8',
'path' => "/^\/(.*\/)?locale_other\/$/",
],
null
],
// all params set (no override)
'all parameter, no sessions' => [
// lang, domain, encoding, path
'ja', 'admin', 'UTF-8', __DIR__ . '/locale_other/',
// SESSION DEFAULT_LOCALE, SESSION: DEFAULT_CHARSET
null, null,
// return array
[
'locale' => 'ja',
'lang' => 'ja',
'domain' => 'admin',
'encoding' => 'UTF-8',
'path' => "/^\/(.*\/)?locale_other\/$/",
],
null
],
// param lang and domain (no override)
'long locale, domain, encoding params, no sessions' => [
// lang, domain, encoding, path
'de_CH.UTF-8@euro', 'admin', 'UTF-8', null,
// SESSION DEFAULT_LOCALE, SESSION: DEFAULT_CHARSET
null, null,
// return array
[
'locale' => 'de_CH.UTF-8@euro',
'lang' => 'de_CH',
'domain' => 'admin',
'encoding' => 'UTF-8',
'path' => "/^\/(.*\/)?includes\/locale\/$/",
],
'setLocale: Unset $path is deprecated',
],
// TODO invalid params (bad path) (no override)
// TODO param calls, but with override set
];
} */
/**
* Undocumented function
*
* @covers ::setLocale
* @dataProvider setLocaleProvider
* @testdox lang settings lang $language, domain $domain, encoding $encoding, path $path; session lang: $SESSION_DEFAULT_LOCALE, session char: $SESSION_DEFAULT_CHARSET [$_dataName]
*
* @param string|null $language
* @param string|null $domain
* @param string|null $encoding
* @param string|null $path
* @param string|null $SESSION_DEFAULT_LOCALE
* @param string|null $SESSION_DEFAULT_CHARSET
* @param array<mixed> $expected
* @param string|null $deprecation_message
* @return void
*/
/* public function testsetLocale(
?string $language,
?string $domain,
?string $encoding,
?string $path,
?string $SESSION_DEFAULT_LOCALE,
?string $SESSION_DEFAULT_CHARSET,
array $expected,
?string $deprecation_message
): void {
$return_lang_settings = [];
global $_SESSION;
// set override
if ($SESSION_DEFAULT_LOCALE !== null) {
$_SESSION['DEFAULT_LOCALE'] = $SESSION_DEFAULT_LOCALE;
}
if ($SESSION_DEFAULT_CHARSET !== null) {
$_SESSION['DEFAULT_CHARSET'] = $SESSION_DEFAULT_CHARSET;
}
if ($deprecation_message !== null) {
set_error_handler(
static function (int $errno, string $errstr): never {
throw new \Exception($errstr, $errno);
},
E_USER_DEPRECATED
);
// catch this with the message
$this->expectExceptionMessage($deprecation_message);
}
// function call
if (
$language === null && $domain === null &&
$encoding === null && $path === null
) {
$return_lang_settings = \CoreLibs\Language\GetLocale::setLocale();
} elseif (
$language !== null && $domain === null &&
$encoding === null && $path === null
) {
$return_lang_settings = \CoreLibs\Language\GetLocale::setLocale(
$language
);
} elseif (
$language !== null && $domain !== null &&
$encoding === null && $path === null
) {
$return_lang_settings = \CoreLibs\Language\GetLocale::setLocale(
$language,
$domain
);
} elseif (
$language !== null && $domain !== null &&
$encoding !== null && $path === null
) {
$return_lang_settings = \CoreLibs\Language\GetLocale::setLocale(
$language,
$domain,
$encoding
);
} else {
$return_lang_settings = \CoreLibs\Language\GetLocale::setLocale(
$language,
$domain,
$encoding,
$path
);
}
restore_error_handler();
// print "RETURN: " . print_r($return_lang_settings, true) . "\n";
foreach (
[
'locale', 'lang', 'domain', 'encoding', 'path'
] as $key
) {
$value = $expected[$key];
if (strpos($value, "/") === 0) {
// this is regex
$this->assertMatchesRegularExpression(
$value,
$return_lang_settings[$key],
'assert regex failed for ' . $key
);
} else {
// assert equal
$this->assertEquals(
$value,
$return_lang_settings[$key],
'assert equal failed for ' . $key
);
}
}
// unset all vars
$_SESSION = [];
unset($GLOBALS['OVERRIDE_LANG']);
} */
/**
* all the test data
*
* @return array<mixed>
*/
public function setLocaleFromSessionProvider(): array
{
return [
// 0: locale
// 1: domain
// 2: encoding
// 3: path
// 4: SESSION: DEFAULT_LOCALE
// 5: SESSION: DEFAULT_CHARSET
// 5: SESSION: DEFAULT_DOMAIN
// 6: SESSION: LOCALE_PATH
// 6: expected array
// 7: deprecation message
'all session vars set' => [
// lang, domain, encoding, path
self::SITE_LOCALE, self::SITE_DOMAIN, self::SITE_ENCODING, self::LOCALE_PATH,
// SESSION SETTINGS: locale, charset, domain, path
'ja_JP.UTF-8', 'UTF-8', 'admin', __DIR__ . '/locale_other/',
// return array
[
'locale' => 'ja_JP.UTF-8',
'lang' => 'ja_JP',
'domain' => 'admin',
'encoding' => 'UTF-8',
'path' => "/^\/(.*\/)?locale_other\/$/",
],
],
// param lang and domain (no override)
'no session set, only parameters' => [
// lang, domain, encoding, path
self::SITE_LOCALE, self::SITE_DOMAIN, self::SITE_ENCODING, self::LOCALE_PATH,
// SESSION SETTINGS: locale, charset, domain, path
null, null, null, null,
// return array
[
'locale' => 'en_US.UTF-8',
'lang' => 'en_US',
'domain' => 'admin',
'encoding' => 'UTF-8',
'path' => "/^\/(.*\/)?includes\/locale\/$/",
],
],
// special parse session check for locales
'all session vars set, short lang' => [
// lang, domain, encoding, path
self::SITE_LOCALE, self::SITE_DOMAIN, self::SITE_ENCODING, self::LOCALE_PATH,
// SESSION SETTINGS: locale, charset, domain, path
'ja', 'UTF-8', 'admin', __DIR__ . '/locale_other/',
// return array
[
'locale' => 'ja',
'lang' => 'ja',
'domain' => 'admin',
'encoding' => 'UTF-8',
'path' => "/^\/(.*\/)?locale_other\/$/",
],
],
// lang with modifier
// param lang and domain (no override)
'long locale, domain, encoding params, no sessions' => [
// lang, domain, encoding, path
self::SITE_LOCALE, self::SITE_DOMAIN, self::SITE_ENCODING, self::LOCALE_PATH,
// SESSION SETTINGS: locale, charset, domain, path
'de_CH.UTF-8@euro', 'admin', 'UTF-8', __DIR__ . '/includes/locale/',
// return array
[
'locale' => 'de_CH.UTF-8@euro',
'lang' => 'de_CH',
'domain' => 'admin',
'encoding' => 'UTF-8',
'path' => "/^\/(.*\/)?includes\/locale\/$/",
],
],
// missing session values check
// special parse session check for locales
'session missing encoding, set from parameters' => [
// lang, domain, encoding, path
self::SITE_LOCALE, self::SITE_DOMAIN, self::SITE_ENCODING, self::LOCALE_PATH,
// SESSION SETTINGS: locale, charset, domain, path
'ja', null, 'admin', __DIR__ . '/locale_other/',
// return array
[
'locale' => 'ja',
'lang' => 'ja',
'domain' => 'admin',
'encoding' => 'UTF-8',
'path' => "/^\/(.*\/)?locale_other\/$/",
],
],
// null return check for invalid entries
'no session set, only parameters, all invalid' => [
// lang, domain, encoding, path
'###', '&&&&', '$$$$', 'foo_bar_path',
// SESSION SETTINGS: locale, charset, domain, path
null, null, null, null,
// return array
[
'locale' => null,
'lang' => null,
'domain' => null,
'encoding' => null,
'path' => null,
],
],
// invalid session names, fall backup
'all session vars are invalid, fallback' => [
// lang, domain, encoding, path
self::SITE_LOCALE, self::SITE_DOMAIN, self::SITE_ENCODING, self::LOCALE_PATH,
// SESSION SETTINGS: locale, charset, domain, path
'###', '&&&&', '$$$$', 'foo_bar_path',
// return array
[
'locale' => 'en_US.UTF-8',
'lang' => 'en_US',
'domain' => 'admin',
'encoding' => 'UTF-8',
'path' => "/^\/(.*\/)?includes\/locale\/$/",
],
],
];
}
/**
* Undocumented function
*
* @covers ::setLocale
* @dataProvider setLocaleFromSessionProvider
* @testdox lang settings lang $language, domain $domain, encoding $encoding, path $path; session lang: $SESSION_DEFAULT_LOCALE, session char: $SESSION_DEFAULT_CHARSET [$_dataName]
*
* @param string| $language
* @param string| $domain
* @param string| $encoding
* @param string| $path
* @param string|null $SESSION_DEFAULT_LOCALE
* @param string|null $SESSION_DEFAULT_CHARSET
* @param string|null $SESSION_DEFAULT_DOMAIN
* @param string|null $SESSION_LOCALE_PATH
* @param array<mixed> $expected
* @return void
*/
public function testsetLocaleFromSession(
string $language,
string $domain,
string $encoding,
string $path,
?string $SESSION_DEFAULT_LOCALE,
?string $SESSION_DEFAULT_CHARSET,
?string $SESSION_DEFAULT_DOMAIN,
?string $SESSION_LOCALE_PATH,
array $expected,
): void {
$return_lang_settings = [];
global $_SESSION;
// set override
if ($SESSION_DEFAULT_LOCALE !== null) {
$_SESSION['DEFAULT_LOCALE'] = $SESSION_DEFAULT_LOCALE;
}
if ($SESSION_DEFAULT_CHARSET !== null) {
$_SESSION['DEFAULT_CHARSET'] = $SESSION_DEFAULT_CHARSET;
}
if ($SESSION_DEFAULT_DOMAIN !== null) {
$_SESSION['DEFAULT_DOMAIN'] = $SESSION_DEFAULT_DOMAIN;
}
if ($SESSION_LOCALE_PATH !== null) {
$_SESSION['LOCALE_PATH'] = $SESSION_LOCALE_PATH;
}
$return_lang_settings = \CoreLibs\Language\GetLocale::setLocaleFromSession(
$language,
$domain,
$encoding,
$path
);
// print "RETURN: " . print_r($return_lang_settings, true) . "\n";
foreach (
[
'locale', 'lang', 'domain', 'encoding', 'path'
] as $key
) {
$value = $expected[$key];
if (
!empty($value) &&
strpos($value, "/") === 0
) {
// this is regex
$this->assertMatchesRegularExpression(
$value,
$return_lang_settings[$key] ?? '',
'assert regex failed for ' . $key
);
} else {
// assert equal
$this->assertEquals(
$value,
$return_lang_settings[$key],
'assert equal failed for ' . $key
);
}
}
// unset all vars
$_SESSION = [];
unset($GLOBALS['OVERRIDE_LANG']);
}
}
// __END__

View File

@@ -22,37 +22,16 @@ final class CoreLibsLanguageL10nTest extends TestCase
*/ */
public static function setUpBeforeClass(): void public static function setUpBeforeClass(): void
{ {
// default web page encoding setting // for deprecation test only, will be removed
if (!defined('DEFAULT_ENCODING')) {
define('DEFAULT_ENCODING', 'UTF-8');
}
if (!defined('DEFAULT_LOCALE')) {
// default lang + encoding
define('DEFAULT_LOCALE', 'en_US.UTF-8');
}
// site
if (!defined('SITE_ENCODING')) {
define('SITE_ENCODING', DEFAULT_ENCODING);
}
if (!defined('SITE_LOCALE')) {
define('SITE_LOCALE', DEFAULT_LOCALE);
}
// just set
if (!defined('BASE')) { if (!defined('BASE')) {
define('BASE', str_replace('/configs', '', __DIR__) . DIRECTORY_SEPARATOR); define('BASE', str_replace(DIRECTORY_SEPARATOR . 'configs', '', __DIR__) . DIRECTORY_SEPARATOR);
} }
if (!defined('INCLUDES')) { if (!defined('INCLUDES')) {
define('INCLUDES', 'includes' . DIRECTORY_SEPARATOR); define('INCLUDES', 'includes' . DIRECTORY_SEPARATOR);
} }
if (!defined('LANG')) {
define('LANG', 'lang' . DIRECTORY_SEPARATOR);
}
if (!defined('LOCALE')) { if (!defined('LOCALE')) {
define('LOCALE', 'locale' . DIRECTORY_SEPARATOR); define('LOCALE', 'locale' . DIRECTORY_SEPARATOR);
} }
if (!defined('CONTENT_PATH')) {
define('CONTENT_PATH', 'frontend' . DIRECTORY_SEPARATOR);
}
} }
/** /**
@@ -105,77 +84,163 @@ final class CoreLibsLanguageL10nTest extends TestCase
{ {
return [ return [
// 0: locale // 0: locale
// 1: domain // 1: encoding
// 2: encoding // 2: domain
// 3: path // 3: path
// 4: locale expected // 4: locale expected
// 5: locale set expected // 5: locale set expected
// 6: domain exepcted // 6: lang expected
// 7: context (null for none) // 7: lang short expected
// 8: test string in // 8: encoding expected
// 9: test translated // 9: domain exepcted
// 10: context (null for none)
// 11: test string in
// 12: test translated
// 13: deprecation message (until removed)
// new style load // new style load
'gettext load en' => [ 'gettext load en' => [
'en_US.UTF-8', 'en_US.UTF-8',
'UTF-8',
'frontend', 'frontend',
__DIR__ . 'includes/locale/', __DIR__ . DIRECTORY_SEPARATOR . 'includes' . DIRECTORY_SEPARATOR . 'locale' . DIRECTORY_SEPARATOR,
// // 4, 5, 6, 7, 8, 9
'en_US.UTF-8', 'en_US.UTF-8',
'en_US', 'en_US',
'en_US',
'en',
'UTF-8',
'frontend', 'frontend',
// 10
null, null,
// 11, 12
'Original', 'Original',
'Translated frontend en_US', 'Translated frontend en_US',
// 13
null,
], ],
'gettext load en' => [ 'gettext load en' => [
'en_US.UTF-8', 'en_US.UTF-8',
'UTF-8',
'frontend', 'frontend',
__DIR__ . 'includes/locale/', __DIR__ . DIRECTORY_SEPARATOR . 'includes' . DIRECTORY_SEPARATOR . 'locale' . DIRECTORY_SEPARATOR,
// //
'en_US.UTF-8', 'en_US.UTF-8',
'en_US', 'en_US',
'en_US',
'en',
'UTF-8',
'frontend', 'frontend',
//
'context', 'context',
//
'Original', 'Original',
'Original context frontend en_US', 'Original context frontend en_US',
//
null,
], ],
'gettext load ja' => [ 'gettext load ja' => [
'ja_JP.UTF-8', 'ja_JP.UTF-8',
'UTF-8',
'admin', 'admin',
__DIR__ . 'includes/locale/', __DIR__ . DIRECTORY_SEPARATOR . 'includes' . DIRECTORY_SEPARATOR . 'locale' . DIRECTORY_SEPARATOR,
// //
'ja_JP.UTF-8', 'ja_JP.UTF-8',
'ja_JP', 'ja_JP',
'ja_JP',
'ja',
'UTF-8',
'admin', 'admin',
//
null, null,
//
'Original', 'Original',
'Translated admin ja_JP', 'Translated admin ja_JP',
//
null,
], ],
// mixed path and domain // load short locale with different encoding
'mixed path and domain' => [ 'gettext load short ja no encoding' => [
'ja',
'SJIS',
'admin',
__DIR__ . DIRECTORY_SEPARATOR . 'includes' . DIRECTORY_SEPARATOR . 'locale' . DIRECTORY_SEPARATOR,
//
'ja',
'ja',
'ja',
'ja',
'SJIS',
'admin',
//
null,
//
'Original',
'Translated admin ja_JP',
//
null,
],
// mixed path and domain [DEPRECATED]
'mixed path and domain [DEPRECATED]' => [
'en_US.UTF-8', 'en_US.UTF-8',
__DIR__ . 'includes/locale/', 'UTF-8',
__DIR__ . DIRECTORY_SEPARATOR . 'includes' . DIRECTORY_SEPARATOR . 'locale' . DIRECTORY_SEPARATOR,
'frontend', 'frontend',
// //
'en_US.UTF-8', 'en_US.UTF-8',
'en_US', 'en_US',
'en_US',
'en',
'UTF-8',
'frontend', 'frontend',
//
'context', 'context',
//
'Original', 'Original',
'Original context frontend en_US', 'Original context frontend en_US',
//
'L10n constructor parameter switch is no longer supported. domain is 2nd, path is 3rd parameter'
],
// unset path
'unset path with locale and domain [DEPRECATED]' => [
'ja_JP.UTF-8',
'UTF-8',
'admin',
null,
//
'ja_JP.UTF-8',
'ja_JP',
'ja_JP',
'ja',
'UTF-8',
'admin',
//
null,
//
'Original',
'Translated admin ja_JP',
//
'Empty path parameter is no longer allowed if locale and domain are set',
], ],
// null set // null set
'empty load new ' => [ 'empty load new ' => [
'', '',
'', '',
'', '',
'',
// //
'', '',
'', '',
'', '',
'',
'', // unset on empty call
'',
//
null, null,
//
'Original', 'Original',
'Original', 'Original',
//
null,
] ]
]; ];
} }
@@ -188,37 +253,62 @@ final class CoreLibsLanguageL10nTest extends TestCase
* @testdox check l10n init with Locale $locale, Path $path, Domain $domain, Legacy: $legacy with $context [$_dataName] * @testdox check l10n init with Locale $locale, Path $path, Domain $domain, Legacy: $legacy with $context [$_dataName]
* *
* @param string|null $locale * @param string|null $locale
* @param string|null $encoding
* @param string|null $domain * @param string|null $domain
* @param string|null $path * @param string|null $path
* @param string $locale_expected * @param string $locale_expected
* @param string $locale_set_expected * @param string $locale_set_expected
* @param string $lang_expected
* @param string $lang_short_expected
* @param string $encoding_expected
* @param string $domain_expected * @param string $domain_expected
* @param ?string $context * @param string|null $context
* @param string $original * @param string $original
* @param string $translated * @param string $translated
* @param string|null $deprecation_message
* @return void * @return void
*/ */
public function testL10nObject( public function testL10nObject(
?string $locale, ?string $locale,
?string $encoding,
?string $domain, ?string $domain,
?string $path, ?string $path,
string $locale_expected, string $locale_expected,
string $locale_set_expected, string $locale_set_expected,
string $lang_expected,
string $lang_short_expected,
string $encoding_expected,
string $domain_expected, string $domain_expected,
?string $context, ?string $context,
string $original, string $original,
string $translated string $translated,
?string $deprecation_message
): void { ): void {
if ($deprecation_message !== null) {
set_error_handler(
static function (int $errno, string $errstr): never {
throw new \Exception($errstr, $errno);
},
E_USER_DEPRECATED
);
// catch this with the message
$this->expectExceptionMessage($deprecation_message);
}
if ($locale === null) { if ($locale === null) {
$l10n = new \CoreLibs\Language\L10n(); $l10n = new \CoreLibs\Language\L10n();
} elseif ($domain === null) { } elseif ($domain === null) {
// deprecated, locale + domain must be set, handled like empty calls
$l10n = new \CoreLibs\Language\L10n($locale); $l10n = new \CoreLibs\Language\L10n($locale);
} elseif ($path === null) { } elseif ($path === null) {
// deprecated, path must be set, will thow DEPRECATION error, handled like empty
$l10n = new \CoreLibs\Language\L10n($locale, $domain); $l10n = new \CoreLibs\Language\L10n($locale, $domain);
} else { } elseif ($encoding === null) {
// if encoding not found will be UTF-8
$l10n = new \CoreLibs\Language\L10n($locale, $domain, $path); $l10n = new \CoreLibs\Language\L10n($locale, $domain, $path);
} else {
$l10n = new \CoreLibs\Language\L10n($locale, $domain, $path, $encoding);
} }
// print "LOC: " . $locale . ", " . $l10n->getLocale() . ", " . $locale_expected . "\n"; restore_error_handler();
// print "MO: " . $l10n->getMoFile() . "\n"; // print "MO: " . $l10n->getMoFile() . "\n";
$this->assertEquals( $this->assertEquals(
$locale_expected, $locale_expected,
@@ -248,6 +338,20 @@ final class CoreLibsLanguageL10nTest extends TestCase
'Translated string assert failed in context: ' . $context 'Translated string assert failed in context: ' . $context
); );
} }
// test get locel as array
$locale = $l10n->getLocaleAsArray();
$this->assertEquals(
[
'locale' => $locale_expected,
'lang' => $lang_expected,
'lang_short' => $lang_short_expected,
'domain' => $domain_expected,
'encoding' => $encoding_expected,
'path' => $path
],
$locale,
'getLocaleAsArray mismatch'
);
} }
// l10nReloadMOfile and getTranslator // l10nReloadMOfile and getTranslator
@@ -283,7 +387,7 @@ final class CoreLibsLanguageL10nTest extends TestCase
// set 0-2 // set 0-2
'en_US.UTF-8', 'en_US.UTF-8',
'frontend', 'frontend',
__DIR__ . 'includes/locale/', __DIR__ . DIRECTORY_SEPARATOR . 'includes' . DIRECTORY_SEPARATOR . 'locale' . DIRECTORY_SEPARATOR,
// status 3 // status 3
false, false,
// to translate 4 // to translate 4
@@ -296,7 +400,7 @@ final class CoreLibsLanguageL10nTest extends TestCase
// set new 8-10 // set new 8-10
'ja_JP.UTF-8', 'ja_JP.UTF-8',
'frontend', 'frontend',
__DIR__ . 'includes/locale/', __DIR__ . DIRECTORY_SEPARATOR . 'includes' . DIRECTORY_SEPARATOR . 'locale' . DIRECTORY_SEPARATOR,
// status new 11 // status new 11
false, false,
// check new setter 12-14 // check new setter 12-14
@@ -322,7 +426,7 @@ final class CoreLibsLanguageL10nTest extends TestCase
// set new 8-10 // set new 8-10
'en_US.UTF-8', 'en_US.UTF-8',
'frontend', 'frontend',
__DIR__ . 'includes/locale/', __DIR__ . DIRECTORY_SEPARATOR . 'includes' . DIRECTORY_SEPARATOR . 'locale' . DIRECTORY_SEPARATOR,
// status new 11 // status new 11
false, false,
// check new setter 12-14 // check new setter 12-14
@@ -387,12 +491,8 @@ final class CoreLibsLanguageL10nTest extends TestCase
string $domain_expected_b, string $domain_expected_b,
string $translated_b string $translated_b
): void { ): void {
if ($locale === null) { if ($locale === null || $domain === null || $path === null) {
$l10n = new \CoreLibs\Language\L10n(); $l10n = new \CoreLibs\Language\L10n();
} elseif ($domain === null) {
$l10n = new \CoreLibs\Language\L10n($locale);
} elseif ($path === null) {
$l10n = new \CoreLibs\Language\L10n($locale, $domain);
} else { } else {
$l10n = new \CoreLibs\Language\L10n($locale, $domain, $path); $l10n = new \CoreLibs\Language\L10n($locale, $domain, $path);
} }
@@ -494,16 +594,16 @@ final class CoreLibsLanguageL10nTest extends TestCase
{ {
return [ return [
// 0: locale // 0: locale
// 1: path // 1: domain
// 2: domain // 2: path
// 3: context (null for none) // 3: context (null for none)
// 4: single string // 4: single string
// 5: plural string // 5: plural string
// 6: array for each n value expected string // 6: array for each n value expected string
'plural text en' => [ 'plural text en' => [
'en_US', 'en_US',
__DIR__ . 'includes/locale/',
'admin', 'admin',
__DIR__ . DIRECTORY_SEPARATOR . 'includes' . DIRECTORY_SEPARATOR . 'locale' . DIRECTORY_SEPARATOR,
// context // context
null, null,
// text single/multi in // text single/multi in
@@ -518,8 +618,8 @@ final class CoreLibsLanguageL10nTest extends TestCase
], ],
'plural text context en' => [ 'plural text context en' => [
'en_US', 'en_US',
__DIR__ . 'includes/locale/',
'admin', 'admin',
__DIR__ . DIRECTORY_SEPARATOR . 'includes' . DIRECTORY_SEPARATOR . 'locale' . DIRECTORY_SEPARATOR,
// context // context
'context', 'context',
// text single/multi in // text single/multi in
@@ -544,8 +644,8 @@ final class CoreLibsLanguageL10nTest extends TestCase
* @testdox plural string test for locale $locale and domain $domain with $context [$_dataName] * @testdox plural string test for locale $locale and domain $domain with $context [$_dataName]
* *
* @param string $locale * @param string $locale
* @param string $path
* @param string $domain * @param string $domain
* @param string $path
* @param ?string $context * @param ?string $context
* @param string $original_single * @param string $original_single
* @param string $original_plural * @param string $original_plural
@@ -555,8 +655,8 @@ final class CoreLibsLanguageL10nTest extends TestCase
public function testNgettext( public function testNgettext(
// config 0-3 // config 0-3
string $locale, string $locale,
string $path,
string $domain, string $domain,
string $path,
// context string // context string
?string $context, ?string $context,
// input strings // input strings
@@ -565,7 +665,7 @@ final class CoreLibsLanguageL10nTest extends TestCase
// expected // expected
array $expected_strings array $expected_strings
): void { ): void {
$l10n = new \CoreLibs\Language\L10n($locale, $path, $domain, false); $l10n = new \CoreLibs\Language\L10n($locale, $domain, $path);
foreach ($expected_strings as $n => $expected) { foreach ($expected_strings as $n => $expected) {
if (empty($context)) { if (empty($context)) {
@@ -981,7 +1081,7 @@ final class CoreLibsLanguageL10nTest extends TestCase
'standard en' => [ 'standard en' => [
'en_US.UTF-8', 'en_US.UTF-8',
'frontend', 'frontend',
__DIR__ . 'includes/locale/', __DIR__ . DIRECTORY_SEPARATOR . 'includes' . DIRECTORY_SEPARATOR . 'locale' . DIRECTORY_SEPARATOR,
'UTF-8', 'UTF-8',
'Original', 'Original',
'Translated frontend en_US', 'Translated frontend en_US',
@@ -989,7 +1089,7 @@ final class CoreLibsLanguageL10nTest extends TestCase
'standard ja' => [ 'standard ja' => [
'ja_JP.UTF-8', 'ja_JP.UTF-8',
'admin', 'admin',
__DIR__ . 'includes/locale/', __DIR__ . DIRECTORY_SEPARATOR . 'includes' . DIRECTORY_SEPARATOR . 'locale' . DIRECTORY_SEPARATOR,
'UTF-8', 'UTF-8',
'Original', 'Original',
'Translated admin ja_JP', 'Translated admin ja_JP',
@@ -1030,6 +1130,7 @@ final class CoreLibsLanguageL10nTest extends TestCase
_textdomain($domain); _textdomain($domain);
_bindtextdomain($domain, $path); _bindtextdomain($domain, $path);
_bind_textdomain_codeset($domain, $encoding); _bind_textdomain_codeset($domain, $encoding);
$this->assertEquals( $this->assertEquals(
$translated, $translated,
__($original), __($original),

View File

@@ -0,0 +1 @@
ja_JP

View File

@@ -0,0 +1,563 @@
<?php
declare(strict_types=1);
namespace tests;
use PHPUnit\Framework\TestCase;
use CoreLibs\Logging\Logger\Level;
/**
* Test class for Logging
* @coversDefaultClass \CoreLibs\Logging\ErrorMessages
* @testdox \CoreLibs\Logging\ErrorMEssages method tests
*/
final class CoreLibsLoggingErrorMessagesTest extends TestCase
{
private const LOG_FOLDER = __DIR__ . DIRECTORY_SEPARATOR . 'log' . DIRECTORY_SEPARATOR;
/**
* tear down and remove log data
*
* @return void
*/
public static function tearDownAfterClass(): void
{
array_map('unlink', glob(self::LOG_FOLDER . '*.log'));
}
/**
* for checking level only
*
* @return array
*/
public function providerErrorMessageLevel(): array
{
return [
'ok' => [
'level' => 'ok',
'str' => 'OK',
'expected' => 'ok',
],
'success' => [
'level' => 'success',
'str' => 'SUCCESS',
'expected' => 'success',
],
'info' => [
'level' => 'info',
'str' => 'INFO',
'expected' => 'info',
],
'notice' => [
'level' => 'notice',
'str' => 'NOTICE',
'expected' => 'notice',
],
'warn' => [
'level' => 'warn',
'str' => 'WARN',
'expected' => 'warn'
],
'warning' => [
'level' => 'warning',
'str' => 'WARN',
'expected' => 'warn'
],
'error' => [
'level' => 'error',
'str' => 'ERROR',
'expected' => 'error'
],
'abort' => [
'level' => 'abort',
'str' => 'ABORT',
'expected' => 'abort'
],
'crash' => [
'level' => 'crash',
'str' => 'CRASH',
'expected' => 'crash'
],
'wrong level' => [
'level' => 'wrong',
'str' => 'WRONG',
'expected' => 'unknown'
]
];
}
/**
* Undocumented function
*
* @dataProvider providerErrorMessageLevel
* @testdox error message level: $level will be $expected [$_dataName]
*
* @param string $level
* @param string $str
* @param string $expected
* @return void
*/
public function testErrorMessageLevelOk(string $level, string $str, string $expected): void
{
$log = new \CoreLibs\Logging\Logging([
'log_file_id' => 'testErrorMessagesLevelOk',
'log_folder' => self::LOG_FOLDER,
'log_level' => Level::Error,
]);
$em = new \CoreLibs\Logging\ErrorMessage($log);
$em->setMessage(
$level,
$str
);
$this->assertEquals(
[
'level' => $expected,
'str' => $str,
'id' => '',
'target' => '',
'target_style' => '',
'highlight' => [],
],
$em->getLastErrorMsg()
);
}
/**
* Undocumented function
*
* @testdox Test of all methods for n messages [$_dataName]
*
* @return void
*/
public function testErrorMessageOk(): void
{
$log = new \CoreLibs\Logging\Logging([
'log_file_id' => 'testErrorMessagesOk',
'log_folder' => self::LOG_FOLDER,
'log_level' => Level::Error
]);
$em = new \CoreLibs\Logging\ErrorMessage($log);
$em->setErrorMsg(
'100',
'info',
'INFO MESSAGE'
);
$this->assertEquals(
[
'id' => '100',
'level' => 'info',
'str' => 'INFO MESSAGE',
'target' => '',
'target_style' => '',
'highlight' => [],
],
$em->getLastErrorMsg()
);
$this->assertEquals(
['100'],
$em->getErrorIds()
);
$this->assertEquals(
[
[
'id' => '100',
'level' => 'info',
'str' => 'INFO MESSAGE',
'target' => '',
'target_style' => '',
'highlight' => [],
]
],
$em->getErrorMsg()
);
$em->setErrorMsg(
'200',
'error',
'ERROR MESSAGE'
);
$this->assertEquals(
[
'id' => '200',
'level' => 'error',
'str' => 'ERROR MESSAGE',
'target' => '',
'target_style' => '',
'highlight' => [],
],
$em->getLastErrorMsg()
);
$this->assertEquals(
['100', '200'],
$em->getErrorIds()
);
$this->assertEquals(
[
[
'id' => '100',
'level' => 'info',
'str' => 'INFO MESSAGE',
'target' => '',
'target_style' => '',
'highlight' => [],
],
[
'id' => '200',
'level' => 'error',
'str' => 'ERROR MESSAGE',
'target' => '',
'target_style' => '',
'highlight' => [],
]
],
$em->getErrorMsg()
);
}
/**
* Undocumented function
*
* @return array
*/
public function providerErrorMessageLog(): array
{
return [
'error, not logged' => [
'id' => '200',
'level' => 'error',
'str' => 'ERROR MESSAGE',
'message' => null,
'log_error' => null,
'log_warning' => null,
'expected' => '<ERROR> ERROR MESSAGE',
],
'error, logged' => [
'id' => '200',
'level' => 'error',
'str' => 'ERROR MESSAGE',
'message' => null,
'log_error' => true,
'log_warning' => null,
'expected' => '<ERROR> ERROR MESSAGE',
],
'error, logged, message' => [
'id' => '200',
'level' => 'error',
'str' => 'ERROR MESSAGE',
'message' => 'OTHER ERROR MESSAGE',
'log_error' => true,
'log_warning' => null,
'expected' => '<ERROR> OTHER ERROR MESSAGE',
],
'warn, not logged' => [
'id' => '300',
'level' => 'warn',
'str' => 'WARNING MESSAGE',
'message' => null,
'log_error' => null,
'log_warning' => null,
'expected' => '<WARNING> WARNING MESSAGE',
],
'warn, logged' => [
'id' => '300',
'level' => 'warn',
'str' => 'WARNING MESSAGE',
'message' => null,
'log_error' => null,
'log_warning' => true,
'expected' => '<WARNING> WARNING MESSAGE',
],
'warn, logged, message' => [
'id' => '300',
'level' => 'warn',
'str' => 'WARNING MESSAGE',
'message' => 'OTHER WARNING MESSAGE',
'log_error' => null,
'log_warning' => true,
'expected' => '<WARNING> OTHER WARNING MESSAGE',
],
'notice' => [
'id' => '100',
'level' => 'notice',
'str' => 'NOTICE MESSAGE',
'message' => null,
'log_error' => null,
'log_warning' => null,
'expected' => '<NOTICE> NOTICE MESSAGE',
],
'notice, message' => [
'id' => '100',
'level' => 'notice',
'str' => 'NOTICE MESSAGE',
'message' => 'OTHER NOTICE MESSAGE',
'log_error' => null,
'log_warning' => null,
'expected' => '<NOTICE> OTHER NOTICE MESSAGE',
],
'crash' => [
'id' => '300',
'level' => 'crash',
'str' => 'CRASH MESSAGE',
'message' => null,
'log_error' => null,
'log_warning' => null,
'expected' => '<ALERT> CRASH MESSAGE',
],
'crash, message' => [
'id' => '300',
'level' => 'crash',
'str' => 'CRASH MESSAGE',
'message' => 'OTHER CRASH MESSAGE',
'log_error' => null,
'log_warning' => null,
'expected' => '<ALERT> OTHER CRASH MESSAGE',
],
'abort' => [
'id' => '200',
'level' => 'abort',
'str' => 'ABORT MESSAGE',
'message' => null,
'log_error' => null,
'log_warning' => null,
'expected' => '<CRITICAL> ABORT MESSAGE',
],
'abort, message' => [
'id' => '200',
'level' => 'abort',
'str' => 'ABORT MESSAGE',
'message' => 'OTHER ABORT MESSAGE',
'log_error' => null,
'log_warning' => null,
'expected' => '<CRITICAL> OTHER ABORT MESSAGE',
],
'unknown' => [
'id' => '400',
'level' => 'wrong level',
'str' => 'WRONG LEVEL MESSAGE',
'message' => null,
'log_error' => null,
'log_warning' => null,
'expected' => '<EMERGENCY> WRONG LEVEL MESSAGE',
],
'unknown, message' => [
'id' => '400',
'level' => 'wrong level',
'str' => 'WRONG LEVEL MESSAGE',
'message' => 'OTHER WRONG LEVEL MESSAGE',
'log_error' => null,
'log_warning' => null,
'expected' => '<EMERGENCY> OTHER WRONG LEVEL MESSAGE',
],
];
}
/**
* Undocumented function
*
* @dataProvider providerErrorMessageLog
* @testdox Test Log writing with log level Error [$_dataName]
*
* @param string $id
* @param string $level
* @param string $str
* @param string|null $message
* @param bool|null $log_error
* @param bool|null $log_warning
* @param string $expected
* @return void
*/
public function testErrorMessageLogErrorLevel(
string $id,
string $level,
string $str,
?string $message,
?bool $log_error,
?bool $log_warning,
string $expected
): void {
$log = new \CoreLibs\Logging\Logging([
'log_file_id' => 'testErrorMessagesLogError',
'log_folder' => self::LOG_FOLDER,
'log_level' => Level::Notice,
'log_per_run' => true
]);
$em = new \CoreLibs\Logging\ErrorMessage($log);
$em->setErrorMsg(
$id,
$level,
$str,
message: $message,
log_error: $log_error,
log_warning: $log_warning
);
$file_content = '';
if (is_file($log->getLogFolder() . $log->getLogFile())) {
$file_content = file_get_contents(
$log->getLogFolder() . $log->getLogFile()
) ?: '';
}
// if error, if null or false, it will not be logged
if ($level == 'error' && ($log_error === null || $log_error === false)) {
$this->assertStringNotContainsString(
$expected,
$file_content
);
} elseif ($level == 'warn' && ($log_warning === null || $log_warning === false)) {
$this->assertStringNotContainsString(
$expected,
$file_content
);
} else {
$this->assertStringContainsString(
$expected,
$file_content
);
}
}
/**
* Undocumented function
*
* @dataProvider providerErrorMessageLog
* @testdox Test Log writing with log Level Debug [$_dataName]
*
* @param string $id
* @param string $level
* @param string $str
* @param string|null $message
* @param bool|null $log_error
* @param bool|null $log_warning
* @param string $expected
* @return void
*/
public function testErrorMessageLogErrorDebug(
string $id,
string $level,
string $str,
?string $message,
?bool $log_error,
?bool $log_warning,
string $expected
): void {
$log = new \CoreLibs\Logging\Logging([
'log_file_id' => 'testErrorMessagesLogDebug',
'log_folder' => self::LOG_FOLDER,
'log_level' => Level::Debug,
'log_per_run' => true
]);
$em = new \CoreLibs\Logging\ErrorMessage($log);
$em->setErrorMsg(
$id,
$level,
$str,
message: $message,
log_error: $log_error,
log_warning: $log_warning
);
$file_content = '';
if (is_file($log->getLogFolder() . $log->getLogFile())) {
$file_content = file_get_contents(
$log->getLogFolder() . $log->getLogFile()
) ?: '';
}
// if error, and log is debug level, only explicit false are not logged
if ($level == 'error' && $log_error === false) {
$this->assertStringNotContainsString(
$expected,
$file_content
);
} elseif ($level == 'warn' && $log_warning === false) {
$this->assertStringNotContainsString(
$expected,
$file_content
);
} else {
$this->assertStringContainsString(
$expected,
$file_content
);
}
}
/**
* Undocumented function
*
* @testdox Test jump target set and reporting
*
* @return void
*/
public function testJumpTarget(): void
{
$log = new \CoreLibs\Logging\Logging([
'log_file_id' => 'testErrorMessagesLogDebug',
'log_folder' => self::LOG_FOLDER,
'log_level' => Level::Debug,
'log_per_run' => true
]);
$em = new \CoreLibs\Logging\ErrorMessage($log);
$em->setJumpTarget(
'target-f',
'Target text'
);
$this->assertEquals(
[
['target' => 'target-f', 'info' => 'Target text', 'level' => 'error']
],
$em->getJumpTarget()
);
// set same target, keep as before
$em->setJumpTarget(
'target-f',
'Other text'
);
$this->assertEquals(
[
['target' => 'target-f', 'info' => 'Target text', 'level' => 'error']
],
$em->getJumpTarget()
);
// add new now two messages
$em->setJumpTarget(
'target-s',
'More text'
);
$this->assertEquals(
[
['target' => 'target-f', 'info' => 'Target text', 'level' => 'error'],
['target' => 'target-s', 'info' => 'More text', 'level' => 'error'],
],
$em->getJumpTarget()
);
// add empty info
$em->setJumpTarget(
'target-e',
''
);
$this->assertEquals(
[
['target' => 'target-f', 'info' => 'Target text', 'level' => 'error'],
['target' => 'target-s', 'info' => 'More text', 'level' => 'error'],
['target' => 'target-e', 'info' => 'Jump to: target-e', 'level' => 'error'],
],
$em->getJumpTarget()
);
// add through message
$em->setErrorMsg('E-101', 'abort', 'Abort message', jump_target:[
'target' => 'abort-target',
'info' => 'Abort error'
]);
$this->assertEquals(
[
['target' => 'target-f', 'info' => 'Target text', 'level' => 'error'],
['target' => 'target-s', 'info' => 'More text', 'level' => 'error'],
['target' => 'target-e', 'info' => 'Jump to: target-e', 'level' => 'error'],
['target' => 'abort-target', 'info' => 'Abort error', 'level' => 'abort'],
],
$em->getJumpTarget()
);
}
}
// __END__

View File

@@ -0,0 +1,847 @@
<?php
declare(strict_types=1);
namespace tests;
use PHPUnit\Framework\TestCase;
use CoreLibs\Logging\Logger\Level;
use CoreLibs\Logging\Logger\Flag;
// TODO: setLogPer test log file written matches pattern
/**
* Test class for Logging
* @coversDefaultClass \CoreLibs\Logging\Logging
* @testdox \CoreLibs\Logging\Logging method tests
*/
final class CoreLibsLoggingLoggingTest extends TestCase
{
private const LOG_FOLDER = __DIR__ . DIRECTORY_SEPARATOR . 'log' . DIRECTORY_SEPARATOR;
private const REGEX_BASE = "\[[\d\-\s\.:]+\]\s{1}" // date
. "\[[\w\.]+(:\d+)?\]\s{1}" // host:port
. "\[(phar:\/\/)?[\w\-\.\/]+:\d+\]\s{1}" // folder/file [note phar:// is for phpunit]
. "\[\w+\]\s{1}" // run id
. "{[\w\\\\]+((::|->)\w+)?}\s{1}"; // class
public static function tearDownAfterClass(): void
{
array_map('unlink', glob(self::LOG_FOLDER . '*.log'));
}
/**
* test set for options BASIC
*
* 0: options
* - null for NOT set
* 1: expected
* 2: override
* override:
* - constant for COSNTANTS
* - global for _GLOBALS
*
* @return array
*/
public function optionsProvider(): array
{
return [
'log folder set' => [
'options' => [
'log_folder' => DIRECTORY_SEPARATOR . 'tmp',
'log_file_id' => 'testClassInit',
],
'expected' => [
'log_folder' => DIRECTORY_SEPARATOR . 'tmp' . DIRECTORY_SEPARATOR,
'log_level' => Level::Debug,
'log_file_id' => 'testClassInit',
],
'override' => [],
],
// -> deprecation warning, log_folder must be set
'no log folder set' => [
'options' => [
'log_file_id' => 'testClassInit'
],
'expected' => [
'log_folder' => getcwd() . DIRECTORY_SEPARATOR,
'log_level' => Level::Debug,
'log_file_id' => 'testClassInit',
],
'override' => []
],
// -> upcoming deprecated
'file_id set but not log_file_id' => [
'options' => [
'log_folder' => DIRECTORY_SEPARATOR . 'tmp' . DIRECTORY_SEPARATOR,
'file_id' => 'testClassInit',
],
'expected' => [
'log_folder' => DIRECTORY_SEPARATOR . 'tmp' . DIRECTORY_SEPARATOR,
'log_level' => Level::Debug,
'log_file_id' => 'testClassInit',
],
'override' => [],
],
// both file_id and log_file_id set -> WARNING
'file_id and log_file_id set' => [
'options' => [
'log_folder' => DIRECTORY_SEPARATOR . 'tmp' . DIRECTORY_SEPARATOR,
'file_id' => 'testClassInit',
'log_file_id' => 'testClassInit',
],
'expected' => [
'log_folder' => DIRECTORY_SEPARATOR . 'tmp' . DIRECTORY_SEPARATOR,
'log_level' => Level::Debug,
'log_file_id' => 'testClassInit',
],
'override' => [],
],
// no log file id set -> error,
'nothing set' => [
'options' => [],
'expected' => [
'log_folder' => getcwd() . DIRECTORY_SEPARATOR,
'log_level' => Level::Debug,
'log_file_id' => 'NOHOST-0_PHPUnit-TextUI-Command',
],
'override' => []
]
];
}
/**
* init logging class
*
* @dataProvider optionsProvider
* @testdox init test [$_dataName]
*
* @param array $options
* @param array $expected
* @param array $override
* @return void
*/
public function testClassInit(array $options, array $expected, array $override): void
{
if (!empty($override['constant'])) {
foreach ($override['constant'] as $var => $value) {
if (!defined($var)) {
define($var, $value);
}
}
// for deprecated no log_folder set
// if base is defined and it does have AAASetupData set
// change the log_folder "Debug" to "AAASetupData"
if (
defined('BASE') &&
strpos(BASE, DIRECTORY_SEPARATOR . 'AAASetupData') !== false
) {
$expected['log_folder'] = str_replace(
DIRECTORY_SEPARATOR . 'Debug',
DIRECTORY_SEPARATOR . 'AAASetupData',
$expected['log_folder']
);
}
}
// if not log folder and constant set -> expect E_USER_DEPRECATION
if (!empty($override['constant']) && empty($options['log_folder'])) {
// the deprecation message
$deprecation_message = 'options: log_folder must be set. '
. 'Setting via BASE and LOG constants is deprecated';
// convert E_USER_DEPRECATED to a exception
set_error_handler(
static function (int $errno, string $errstr): never {
throw new \Exception($errstr, $errno);
},
E_USER_DEPRECATED
);
// catch this with the message
$this->expectExceptionMessage($deprecation_message);
}
// alert for log file id with globals
if (!empty($override['constant']) && empty($options['log_file_id'])) {
//
}
// alert for log file id and file id set
if (
!empty($options['log_file_id']) &&
!empty($options['file_id'])
) {
set_error_handler(
static function (int $errno, string $errstr): never {
throw new \InvalidArgumentException($errstr, $errno);
},
E_USER_WARNING
);
$error_message = 'options: "file_id" is deprecated use: "log_file_id".';
$this->expectExceptionMessage($error_message);
$this->expectException(\InvalidArgumentException::class);
set_error_handler(
static function (int $errno, string $errstr): never {
throw new \Exception($errstr, $errno);
},
E_USER_DEPRECATED
);
$this->expectException(\Exception::class);
// $error_message = 'options: both log_file_id and log_id are set at the same time, will use log_file_id';
// $this->expectExceptionMessage($error_message);
}
// empty log folder
if (empty($override['constant']) && empty($options['log_folder'])) {
$this->expectException(\InvalidArgumentException::class);
$this->expectExceptionMessageMatches("/^Missing mandatory option: \"/");
} elseif (empty($options['log_file_id']) && !empty($options['file_id'])) {
// the deprecation message
$deprecation_message = 'options: "file_id" is deprecated use: "log_file_id".';
// convert E_USER_DEPRECATED to a exception
set_error_handler(
static function (int $errno, string $errstr): never {
throw new \Exception($errstr, $errno);
},
E_USER_DEPRECATED
);
// catch this with the message
$this->expectExceptionMessage($deprecation_message);
}
$log = new \CoreLibs\Logging\Logging($options);
// reset error handler
restore_error_handler();
// check that settings match
$this->assertEquals(
$expected['log_folder'],
$log->getLogFolder(),
'log folder not matching'
);
$this->assertEquals(
$expected['log_file_id'],
$log->getLogFileId(),
'log file id not matching'
);
}
// test all setters/getters
// setLoggingLevel
// getLoggingLevel
// loggingLevelIsDebug
/**
* Undocumented function
*
* @covers ::setLoggingLevel
* @covers ::getLoggingLevel
* @covers ::loggingLevelIsDebug
* @testdox setLoggingLevel set/get checks
*
* @return void
*/
public function testSetLoggingLevel(): void
{
// valid that is not Debug
$log = new \CoreLibs\Logging\Logging([
'log_file_id' => 'testSetLoggingLevel',
'log_folder' => self::LOG_FOLDER,
'log_level' => Level::Info
]);
$this->assertEquals(
Level::Info,
$log->getLoggingLevel()
);
$this->assertFalse(
$log->loggingLevelIsDebug()
);
// not set, should be debug]
$log = new \CoreLibs\Logging\Logging([
'log_file_id' => 'testSetLoggingLevel',
'log_folder' => self::LOG_FOLDER,
]);
$this->assertEquals(
Level::Debug,
$log->getLoggingLevel()
);
$this->assertTrue(
$log->loggingLevelIsDebug()
);
// invalid, should be debug, will throw excpetion too
$this->expectException(\InvalidArgumentException::class);
$this->expectExceptionMessage('Option: "log_level" is not of instance \CoreLibs\Logging\Logger\Level');
$log = new \CoreLibs\Logging\Logging([
'log_file_id' => 'testSetLoggingLevel',
'log_folder' => self::LOG_FOLDER,
'log_level' => 'I'
]);
$this->assertEquals(
Level::Debug,
$log->getLoggingLevel()
);
$this->assertTrue(
$log->loggingLevelIsDebug()
);
// set valid, then change
$log = new \CoreLibs\Logging\Logging([
'log_file_id' => 'testSetLoggingLevel',
'log_folder' => self::LOG_FOLDER,
'log_level' => Level::Info
]);
$this->assertEquals(
Level::Info,
$log->getLoggingLevel()
);
$log->setLoggingLevel(Level::Notice);
$this->assertEquals(
Level::Notice,
$log->getLoggingLevel()
);
// illegal logging level
$this->expectException(\Psr\Log\InvalidArgumentException::class);
$this->expectExceptionMessageMatches("/^Level \"NotGood\" is not defined, use one of: /");
$log->setLoggingLevel('NotGood');
}
// setLogFileId
// getLogFileId
/**
* Undocumented function
*
* @covers ::setLogFileId
* @covers ::getLogFileId
* @testdox setLogFileId set/get checks
*
* @return void
*/
public function testLogFileId(): void
{
$log = new \CoreLibs\Logging\Logging([
'log_file_id' => 'testLogFileId',
'log_folder' => self::LOG_FOLDER
]);
// bad, keep same
$log->setLogFileId('$$##$%#$%&');
$this->assertEquals(
'testLogFileId',
$log->getLogFileId()
);
// good, change
$log->setLogFileId('validID');
$this->assertEquals(
'validID',
$log->getLogFileId()
);
// invalid on init
$this->expectException(\Psr\Log\InvalidArgumentException::class);
$this->expectExceptionMessage('LogFileId: no log file id set');
$log = new \CoreLibs\Logging\Logging([
'log_file_id' => '$$$"#"#$"#$',
'log_folder' => self::LOG_FOLDER
]);
}
// setLogUniqueId
// getLogUniqueId
/**
* Undocumented function
*
* @return array
*/
public function logUniqueIdProvider(): array
{
return [
'option set' => [
'option' => true,
'override' => false,
],
'direct set' => [
'option' => false,
'override' => false,
],
'override set' => [
'option' => false,
'override' => true,
],
'option and override set' => [
'option' => false,
'override' => true,
],
];
}
/**
* Undocumented function
*
* @covers ::setLogUniqueId
* @covers ::getLogUniqueId
* @dataProvider logUniqueIdProvider
* @testdox per run log id set test: option: $option, override: $override [$_dataName]
*
* @param bool $option
* @param bool $override
* @return void
*/
public function testLogUniqueId(bool $option, bool $override): void
{
if ($option === true) {
$log = new \CoreLibs\Logging\Logging([
'log_file_id' => 'testLogUniqueId',
'log_folder' => self::LOG_FOLDER,
'log_per_run' => $option
]);
} else {
$log = new \CoreLibs\Logging\Logging([
'log_file_id' => 'testLogUniqueId',
'log_folder' => self::LOG_FOLDER
]);
$log->setLogUniqueId();
}
$per_run_id = $log->getLogUniqueId();
$this->assertMatchesRegularExpression(
"/^\d{4}-\d{2}-\d{2}_\d{6}_U_[a-z0-9]{8}$/",
$per_run_id,
'assert per log run id 1st'
);
if ($override === true) {
$log->setLogUniqueId(true);
$per_run_id_2nd = $log->getLogUniqueId();
$this->assertMatchesRegularExpression(
"/^\d{4}-\d{2}-\d{2}_\d{6}_U_[a-z0-9]{8}$/",
$per_run_id_2nd,
'assert per log run id 2nd'
);
$this->assertNotEquals(
$per_run_id,
$per_run_id_2nd,
'1st and 2nd don\'t match'
);
}
}
// setLogDate
// getLogDate
/**
* Undocumented function
*
* @covers ::setLogDate
* @covers ::getLogDate
* @testdox setLogDate set/get checks
*
* @return void
*/
public function testSetLogDate(): void
{
$log = new \CoreLibs\Logging\Logging([
'log_file_id' => 'testLogFileId',
'log_folder' => self::LOG_FOLDER,
'log_per_date' => true,
]);
$this->assertEquals(
date('Y-m-d'),
$log->getLogDate()
);
}
// setLogFlag
// getLogFlag
// unsetLogFlag
// getLogFlags
// Logger\Flag
/**
* Undocumented function
*
* @covers Logger\Flag
* @testdox Logger\Flag enum test
*
* @return void
*/
public function testLoggerFlag(): void
{
// logger flags to check that they exist
$flags = [
'all_off' => 0,
'per_run' => 1,
'per_date' => 2,
'per_group' => 4,
'per_page' => 8,
'per_class' => 16,
'per_level' => 32,
];
// from int -> return value
foreach ($flags as $name => $value) {
$this->assertEquals(
Flag::fromName($name),
Flag::fromValue($value)
);
}
}
/**
* Undocumented function
*
* @covers ::setLogFlag
* @covers ::getLogFlag
* @covers ::unsetLogFlag
* @covers ::getLogFlags
* @testdox setLogDate set/get checks
*
* @return void
*/
public function testSetLogFlag(): void
{
$log = new \CoreLibs\Logging\Logging([
'log_file_id' => 'testSetLogFlag',
'log_folder' => self::LOG_FOLDER,
]);
// set valid log flag
$log->setLogFlag(Flag::per_run);
$this->assertTrue(
$log->getLogFlag(Flag::per_run)
);
// flags seum
$this->assertEquals(
Flag::per_run->value,
$log->getLogFlags(),
);
// unset valid log flag
$log->unsetLogFlag(Flag::per_run);
$this->assertFalse(
$log->getLogFlag(Flag::per_run)
);
// illegal Flags cannot be set, they will throw eerros onrun
// test multi set and sum is equals set
$log->setLogFlag(Flag::per_date);
$log->setLogFlag(Flag::per_group);
$this->assertEquals(
Flag::per_date->value + Flag::per_group->value,
$log->getLogFlags()
);
}
// setLogFolder
// getLogFolder
/**
* Undocumented function
*
* @covers ::setLogFolder
* @covers ::getLogFolder
* @testdox setLogFolder set/get checks, init check
*
* @return void
*/
public function testSetLogFolder(): void
{
// set to good folder
$log = new \CoreLibs\Logging\Logging([
'log_file_id' => 'testSetLogFolder',
'log_folder' => self::LOG_FOLDER,
]);
$this->assertEquals(
self::LOG_FOLDER,
$log->getLogFolder()
);
// set to a good other folder
$log->setLogFolder(DIRECTORY_SEPARATOR . 'tmp' . DIRECTORY_SEPARATOR);
$this->assertEquals(
DIRECTORY_SEPARATOR . 'tmp' . DIRECTORY_SEPARATOR,
$log->getLogFolder()
);
// good other folder with missing trailing slash
$log->setLogFolder(DIRECTORY_SEPARATOR . 'tmp');
$this->assertEquals(
DIRECTORY_SEPARATOR . 'tmp' . DIRECTORY_SEPARATOR,
$log->getLogFolder()
);
// a bad folder -> last good folder
$log->setLogFolder('I-am-not existing');
$this->assertEquals(
DIRECTORY_SEPARATOR . 'tmp' . DIRECTORY_SEPARATOR,
$log->getLogFolder()
);
// init with a bad folder
$this->expectException(\Psr\Log\InvalidArgumentException::class);
$this->expectExceptionMessage('Folder: "I-am-bad" is not writeable for logging');
$log = new \CoreLibs\Logging\Logging([
'log_file_id' => 'testSetLogFolderInvalid',
'log_folder' => 'I-am-bad',
]);
}
// getLogFile (no set, only correct after log run)
// setLogMaxFileSize
// getLogMaxFileSize
/**
* Undocumented function
*
* @covers ::setLogMaxFileSize
* @covers ::getLogMaxFileSize
* @testdox setLogMaxFileSize set/get checks, init check
*
* @return void
*/
public function testSetLogMaxFileSize(): void
{
// init set to 0
$log = new \CoreLibs\Logging\Logging([
'log_file_id' => 'testSetLogMaxFileSize',
'log_folder' => self::LOG_FOLDER,
]);
$this->assertEquals(
0,
$log->getLogMaxFileSize()
);
// set to new, valid size
$file_size = 200 * 1024;
$valid = $log->setLogMaxFileSize($file_size);
$this->assertTrue($valid);
$this->assertEquals(
$file_size,
$log->getLogMaxFileSize()
);
// invalid size, < 0, will be last and return false
$valid = $log->setLogMaxFileSize(-1);
$this->assertFalse($valid);
$this->assertEquals(
$file_size,
$log->getLogMaxFileSize()
);
// too small (< MIN_LOG_MAX_FILESIZE)
$valid = $log->setLogMaxFileSize($log::MIN_LOG_MAX_FILESIZE - 1);
$this->assertFalse($valid);
$this->assertEquals(
$file_size,
$log->getLogMaxFileSize()
);
}
// getOption (option params)
/**
* Undocumented function
*
* @covers ::getOption
* @testdox getOption checks
*
* @return void
*/
public function testGetOption(): void
{
$log = new \CoreLibs\Logging\Logging([
'log_file_id' => 'testGetOption',
'log_folder' => self::LOG_FOLDER,
]);
$this->assertEquals(
self::LOG_FOLDER,
$log->getOption('log_folder')
);
// not found
$this->assertNull(
$log->getOption('I_do not exist')
);
}
// test all logger functions
// debug (special)
// info
// notice
// warning
// error
// critical
// alert
// emergency
/**
* Undocumented function
*
* @covers ::debug
* @testdox debug checks
*
* @return void
*/
public function testDebug(): void
{
// init logger
$log = new \CoreLibs\Logging\Logging([
'log_file_id' => 'testDebug',
'log_folder' => self::LOG_FOLDER,
]);
// clean all data in folder first
array_map('unlink', glob($log->getLogFolder() . $log->getLogFileId() . '*.log'));
$group_id = 'G';
$message = 'D';
$log_status = $log->debug($group_id, $message);
$this->assertTrue($log_status, 'debug write successful');
$file_content = file_get_contents(
$log->getLogFolder() . $log->getLogFile()
) ?: '';
$log_level = $log->getLoggingLevel()->getName();
// [2023-05-30 15:51:39.36128800] [NOHOST:0]
// [www/vendor/bin/phpunit] [7b9d0747] {PHPUnit\TextUI\Command}
// <DEBUG:G> D
$this->assertMatchesRegularExpression(
"/" . self::REGEX_BASE
. "<$log_level:$group_id>\s{1}" // log level / group id
. "$message" // message
. "/",
$file_content
);
}
/**
* Undocumented function
*
* @return array
*/
public function providerLoggingLevelWrite(): array
{
return [
'info' => [
'message' => 'I',
'file_id' => Level::Info->name,
'level' => Level::Info
],
'notice' => [
'message' => 'N',
'file_id' => Level::Notice->name,
'level' => Level::Notice
],
'warning' => [
'message' => 'W',
'file_id' => Level::Warning->name,
'level' => Level::Warning
],
'error' => [
'message' => 'E',
'file_id' => Level::Error->name,
'level' => Level::Error
],
'crticial' => [
'message' => 'C',
'file_id' => Level::Critical->name,
'level' => Level::Critical
],
'alert' => [
'message' => 'A',
'file_id' => Level::Alert->name,
'level' => Level::Alert
],
'emergency' => [
'message' => 'Em',
'file_id' => Level::Emergency->name,
'level' => Level::Emergency
],
];
}
/**
* Undocumented function
*
* @covers ::info
* @covers ::notice
* @covers ::warning
* @covers ::error
* @covers ::critical
* @covers ::alert
* @covers ::emergency
* @dataProvider providerLoggingLevelWrite
* @testdox logging level write checks for $level [$_dataName]
*
* @return void
*/
public function testLoggingLevelWrite(string $message, string $file_id, Level $level): void
{
// init logger
$log = new \CoreLibs\Logging\Logging([
'log_file_id' => 'test' . $file_id,
'log_folder' => self::LOG_FOLDER,
'log_level' => $level,
]);
// clean all data in folder first
array_map('unlink', glob($log->getLogFolder() . $log->getLogFileId() . '*.log'));
switch ($level->value) {
case 200:
$log_status = $log->info($message);
break;
case 250:
$log_status = $log->notice($message);
break;
case 300:
$log_status = $log->warning($message);
break;
case 400:
$log_status = $log->error($message);
break;
case 500:
$log_status = $log->critical($message);
break;
case 550:
$log_status = $log->alert($message);
break;
case 600:
$log_status = $log->emergency($message);
break;
}
$this->assertTrue($log_status, 'log write successful');
$file_content = file_get_contents(
$log->getLogFolder() . $log->getLogFile()
) ?: '';
$log_level = $log->getLoggingLevel()->getName();
$this->assertMatchesRegularExpression(
"/" . self::REGEX_BASE
. "<$log_level>\s{1}" // log level / group id
. "$message" // message
. "/",
$file_content,
'log message regex'
);
}
// check log level that writer writes in correct level
// also that non debug ignores prefix/group
/**
* Undocumented function
*
* @covers ::log
* @testdox log() general call test
*
* @return void
*/
public function testLoggingLog(): void
{
// init logger
$log = new \CoreLibs\Logging\Logging([
'log_file_id' => 'testLoggingLog',
'log_folder' => self::LOG_FOLDER,
'log_per_level' => true,
]);
$log_ok = $log->log(Level::Debug, 'DEBUG', group_id: 'GROUP_ID', prefix: 'PREFIX:');
$this->assertTrue($log_ok, 'assert ::log (debug) OK');
$this->assertEquals(
$log->getLogFile(),
$log->getLogFileId() . '_DEBUG.log'
);
$log_ok = $log->log(Level::Info, 'INFO', group_id: 'GROUP_ID', prefix: 'PREFIX:');
$this->assertTrue($log_ok, 'assert ::log (info) OK');
$this->assertEquals(
$log->getLogFile(),
$log->getLogFileId() . '_INFO.log'
);
}
// must test flow:
// init normal
// log -> check file name
// set per date
// log -> check file name
// and same for per_run
// deprecated calls check?
}
// __END__

3
4dev/tests/Logging/log/.gitignore vendored Normal file
View File

@@ -0,0 +1,3 @@
*log
*LOG
!.gitignore

View File

@@ -0,0 +1,105 @@
<?php
declare(strict_types=1);
namespace tests;
use PHPUnit\Framework\TestCase;
/**
* Test class for Output\Image
* @coversDefaultClass \CoreLibs\Output\Image
* @testdox \CoreLibs\Output\Image method tests
*/
final class CoreLibsOutputImageTest extends TestCase
{
/**
* Undocumented function
*
* @covers ::createThumbnail
* @testdox createThumbnail checks
*
* @return void
*/
public function testCreateThumbnail(): void
{
// CONVERT does not exist
$this->expectException(\RuntimeException::class);
\CoreLibs\Output\Image::createThumbnail('do_not_exist.png', 200, 200);
// set convert
$paths = [
'/bin',
'/usr/bin',
'/usr/local/bin',
];
// find convert
foreach ($paths as $path) {
if (
file_exists($path . DIRECTORY_SEPARATOR . 'convert') &&
is_file($path . DIRECTORY_SEPARATOR . 'convert')
) {
// image magick convert location
define('CONVERT', $path . DIRECTORY_SEPARATOR . 'convert');
break;
}
}
unset($paths);
// cannot set dummy file
$this->expectException(\Exception::class);
\CoreLibs\Output\Image::createThumbnail('do_not_exist.png', 200, 200);
}
/**
* Undocumented function
*
* @covers ::createThumbnailSimple
* @testdox createThumbnailSimple checks
*
* @return void
*/
public function testCreateThumbnailSimple(): void
{
// file does not exist
$this->expectException(\UnexpectedValueException::class);
\CoreLibs\Output\Image::createThumbnailSimple(
'do_not_exist.png',
200,
200,
cache_folder: '/tmp/',
web_folder: '/tmp/'
);
// cache folder is not dir
$this->expectException(\UnexpectedValueException::class);
\CoreLibs\Output\Image::createThumbnailSimple(
'do_not_exist.png',
200,
200,
cache_folder: '/foo/bar/',
web_folder: '/tmp/'
);
// target cache folder is not writeable
// RuntimeException: imagecreatetruecolor failed
// RuntimeException: imagecolorallocatealpha failed
}
/**
* Undocumented function
*
* @covers ::correctImageOrientation
* @testdox correctImageOrientation checks
*
* @return void
*/
public function testCorrectImageOrientation(): void
{
// test file does not exist
$this->expectException(\UnexpectedValueException::class);
\CoreLibs\Output\Image::correctImageOrientation('do_not_exist.png');
// test folder not writeable
// test exit_read_data not present (how)?
// test image rotate
}
}
// __END__

View File

@@ -7,11 +7,11 @@ namespace tests;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
/** /**
* Test class for Check\Password * Test class for Security\Password
* @coversDefaultClass \CoreLibs\Check\Password * @coversDefaultClass \CoreLibs\Security\Password
* @testdox \CoreLibs\Check\Password method tests * @testdox \CoreLibs\Security\Password method tests
*/ */
final class CoreLibsCheckPasswordTest extends TestCase final class CoreLibsSecurityPasswordTest extends TestCase
{ {
public function passwordProvider(): array public function passwordProvider(): array
{ {
@@ -46,7 +46,7 @@ final class CoreLibsCheckPasswordTest extends TestCase
{ {
$this->assertEquals( $this->assertEquals(
$expected, $expected,
\CoreLibs\Check\Password::passwordVerify($input, \CoreLibs\Check\Password::passwordSet($input_hash)) \CoreLibs\Security\Password::passwordVerify($input, \CoreLibs\Security\Password::passwordSet($input_hash))
); );
} }
@@ -65,7 +65,7 @@ final class CoreLibsCheckPasswordTest extends TestCase
{ {
$this->assertEquals( $this->assertEquals(
$expected, $expected,
\CoreLibs\Check\Password::passwordRehashCheck($input) \CoreLibs\Security\Password::passwordRehashCheck($input)
); );
} }
} }

View File

@@ -0,0 +1,237 @@
<?php
declare(strict_types=1);
namespace tests;
use PHPUnit\Framework\TestCase;
use CoreLibs\Security\CreateKey;
use CoreLibs\Security\SymmetricEncryption;
/**
* Test class for Security\SymmetricEncryption and Security\CreateKey
* @coversDefaultClass \CoreLibs\Security\SymmetricEncryption
* @testdox \CoreLibs\Security\SymmetricEncryption method tests
*/
final class CoreLibsSecuritySymmetricEncryptionTest extends TestCase
{
/**
* Undocumented function
*
* @return array
*/
public function providerEncryptDecryptSuccess(): array
{
return [
'valid string' => [
'input' => 'I am a secret',
'expected' => 'I am a secret',
],
];
}
/**
* test encrypt/decrypt produce correct output
*
* @covers ::generateRandomKey
* @covers ::encrypt
* @covers ::decrypt
* @dataProvider providerEncryptDecryptSuccess
* @testdox encrypt/decrypt $input must be $expected [$_dataName]
*
* @param string $input
* @param string $expected
* @return void
*/
public function testEncryptDecryptSuccess(string $input, string $expected): void
{
$key = CreateKey::generateRandomKey();
// test class
$crypt = new SymmetricEncryption($key);
$encrypted = $crypt->encrypt($input);
$decrypted = $crypt->decrypt($encrypted);
$this->assertEquals(
$expected,
$decrypted,
'Class call',
);
// test indirect
$encrypted = SymmetricEncryption::getInstance($key)->encrypt($input);
$decrypted = SymmetricEncryption::getInstance($key)->decrypt($encrypted);
$this->assertEquals(
$expected,
$decrypted,
'Class Instance call',
);
// test static
$encrypted = SymmetricEncryption::encryptKey($input, $key);
$decrypted = SymmetricEncryption::decryptKey($encrypted, $key);
$this->assertEquals(
$expected,
$decrypted,
'Static call',
);
}
/**
* Undocumented function
*
* @return array
*/
public function providerEncryptFailed(): array
{
return [
'wrong decryption key' => [
'input' => 'I am a secret',
'excpetion_message' => 'Invalid Key'
],
];
}
/**
* Test decryption with wrong key
*
* @covers ::generateRandomKey
* @covers ::encrypt
* @covers ::decrypt
* @dataProvider providerEncryptFailed
* @testdox decrypt with wrong key $input throws $exception_message [$_dataName]
*
* @param string $input
* @param string $exception_message
* @return void
*/
public function testEncryptFailed(string $input, string $exception_message): void
{
$key = CreateKey::generateRandomKey();
$wrong_key = CreateKey::generateRandomKey();
// wrong key in class call
$crypt = new SymmetricEncryption($key);
$encrypted = $crypt->encrypt($input);
$this->expectExceptionMessage($exception_message);
$crypt->setKey($key);
$crypt->decrypt($encrypted);
// class instance
$encrypted = SymmetricEncryption::getInstance($key)->encrypt($input);
$this->expectExceptionMessage($exception_message);
SymmetricEncryption::getInstance($wrong_key)->decrypt($encrypted);
// class static
$encrypted = SymmetricEncryption::encryptKey($input, $key);
$this->expectExceptionMessage($exception_message);
SymmetricEncryption::decryptKey($encrypted, $wrong_key);
}
/**
* Undocumented function
*
* @return array
*/
public function providerWrongKey(): array
{
return [
'not hex key' => [
'key' => 'not_a_hex_key',
'exception_message' => 'Invalid hex key'
],
'too short hex key' => [
'key' => '1cabd5cba9e042f12522f4ff2de5c31d233b',
'excpetion_message' => 'Key is not the correct size (must be '
],
];
}
/**
* test invalid key provided to decrypt or encrypt
*
* @covers ::encrypt
* @covers ::decrypt
* @dataProvider providerWrongKey
* @testdox wrong key $key throws $exception_message [$_dataName]
*
* @param string $key
* @param string $exception_message
* @return void
*/
public function testWrongKey(string $key, string $exception_message): void
{
$enc_key = CreateKey::generateRandomKey();
// class
$crypt = new SymmetricEncryption($key);
$this->expectExceptionMessage($exception_message);
$crypt->encrypt('test');
$crypt->setKey($enc_key);
$encrypted = $crypt->encrypt('test');
$this->expectExceptionMessage($exception_message);
$crypt->setKey($key);
$crypt->decrypt($encrypted);
// class instance
$this->expectExceptionMessage($exception_message);
SymmetricEncryption::getInstance($key)->encrypt('test');
// we must encrypt valid thing first so we can fail with the wrong key
$encrypted = SymmetricEncryption::getInstance($enc_key)->encrypt('test');
$this->expectExceptionMessage($exception_message);
SymmetricEncryption::getInstance($key)->decrypt($encrypted);
// class static
$this->expectExceptionMessage($exception_message);
SymmetricEncryption::encryptKey('test', $key);
// we must encrypt valid thing first so we can fail with the wrong key
$encrypted = SymmetricEncryption::encryptKey('test', $enc_key);
$this->expectExceptionMessage($exception_message);
SymmetricEncryption::decryptKey($encrypted, $key);
}
/**
* Undocumented function
*
* @return array
*/
public function providerWrongCiphertext(): array
{
return [
'too short ciphertext' => [
'input' => 'short',
'exception_message' => 'Decipher message failed: '
],
];
}
/**
* Undocumented function
*
* @covers ::decrypt
* @dataProvider providerWrongCiphertext
* @testdox too short ciphertext $input throws $exception_message [$_dataName]
*
* @param string $input
* @param string $exception_message
* @return void
*/
public function testWrongCiphertext(string $input, string $exception_message): void
{
$key = CreateKey::generateRandomKey();
// class
$crypt = new SymmetricEncryption($key);
$this->expectExceptionMessage($exception_message);
$crypt->decrypt($input);
// class instance
$this->expectExceptionMessage($exception_message);
SymmetricEncryption::getInstance($key)->decrypt($input);
// class static
$this->expectExceptionMessage($exception_message);
SymmetricEncryption::decryptKey($input, $key);
}
}
// __END__

View File

@@ -0,0 +1,34 @@
<?php
declare(strict_types=1);
namespace tests;
use PHPUnit\Framework\TestCase;
use CoreLibs\Template\HtmlBuilder\Block;
/**
* Test class for Template\HtmlBuilder\Block
* @coversDefaultClass \CoreLibs\Template\HtmlBuilder\Block
* @testdox \CoreLibs\Template\HtmlBuilder\Block method tests
*/
final class CoreLibsTemplateHtmlBuilderBlockTest extends TestCase
{
public function testCreateBlock(): void
{
$el = Block::cel('div', 'id', 'content', ['css'], ['onclick' => 'foo();']);
$this->assertEquals(
'<div id="id" class="css" onclick="foo();">content</div>',
Block::buildHtml($el)
);
}
// ael
// aelx|addSub
// resetSub
// acssel/rcssel/scssel
// buildHtml
// buildHtmlFromList|printHtmlFromArray
}
// __END__

View File

@@ -0,0 +1,546 @@
<?php
declare(strict_types=1);
namespace tests;
use PHPUnit\Framework\TestCase;
use CoreLibs\Template\HtmlBuilder\Element;
use CoreLibs\Template\HtmlBuilder\General\Error;
use CoreLibs\Template\HtmlBuilder\General\HtmlBuilderExcpetion;
/**
* Test class for Template\HtmlBuilder\Element
* @coversDefaultClass \CoreLibs\Template\HtmlBuilder\Element
* @testdox \CoreLibs\Template\HtmlBuilder\Element method tests
*/
final class CoreLibsTemplateHtmlBuilderElementTest extends TestCase
{
public function providerCreateElements(): array
{
return [
'simple div' => [
'tag' => 'div',
'id' => 'id',
'content' => 'content',
'css' => ['css'],
'options' => ['onclick' => 'foo();'],
'expected' => '<div id="id" class="css" onclick="foo();">content</div>'
],
'simple input' => [
'tag' => 'input',
'id' => 'id',
'content' => null,
'css' => ['css'],
'options' => ['name' => 'name', 'onclick' => 'foo();'],
'expected' => '<input id="id" name="name" class="css" onclick="foo();">'
]
];
}
/**
* Undocumented function
*
* @covers ::Element
* @covers ::buildHtml
* @covers ::getTag
* @covers ::getId
* @covers ::getContent
* @covers ::getOptions
* @covers ::getCss
* @dataProvider providerCreateElements
* @testdox create single new Element test [$_dataName]
*
* @param string $tag
* @param string|null $id
* @param string|null $content
* @param array|null $css
* @param array|null $options
* @param string $expected
* @return void
*/
public function testCreateElement(
string $tag,
?string $id,
?string $content,
?array $css,
?array $options,
string $expected
): void {
$el = new Element($tag, $id ?? '', $content ?? '', $css ?? [], $options ?? []);
$this->assertEquals(
$expected,
$el->buildHtml(),
'element creation failed'
);
$this->assertEquals(
$tag,
$el->getTag(),
'get tag failed'
);
if ($id !== null) {
$this->assertEquals(
$id,
$el->getId(),
'get id failed'
);
}
if ($content !== null) {
$this->assertEquals(
$content,
$el->getContent(),
'get content failed'
);
}
if ($css !== null) {
$this->assertEquals(
$css,
$el->getCss(),
'get css failed'
);
}
if ($options !== null) {
$this->assertEquals(
$options,
$el->getOptions(),
'get options failed'
);
}
if (!empty($options['name'])) {
$this->assertEquals(
$options['name'],
$el->getName(),
'get name failed'
);
}
}
/**
* css add/remove
*
* @cover ::getCss
* @cover ::addCss
* @cover ::removeCss
* @testdox test handling of adding and removing css classes
*
* @return void
*/
public function testCssHandling(): void
{
$el = new Element('div', 'css-test', 'CSS content');
$this->assertEqualsCanonicalizing(
[],
$el->getCss(),
'check empty css'
);
$el->addCss('foo');
$this->assertEqualsCanonicalizing(
['foo'],
$el->getCss(),
'check added one css'
);
$el->removeCss('foo');
$this->assertEqualsCanonicalizing(
[],
$el->getCss(),
'check remove added css'
);
// add serveral
// remove some of them
$el->addCss('a', 'b', 'c');
$this->assertEqualsCanonicalizing(
['a', 'b', 'c'],
$el->getCss(),
'check added some css'
);
$el->removeCss('a', 'c');
// $this->assertArray
$this->assertEqualsCanonicalizing(
['b'],
$el->getCss(),
'check remove some css'
);
// chained add and remove
$el->addCss('a', 'b', 'c', 'd')->removeCss('b', 'd');
$this->assertEqualsCanonicalizing(
['a', 'c'],
$el->getCss(),
'check chain add remove some css'
);
$el->resetCss();
$this->assertEqualsCanonicalizing(
[],
$el->getCss(),
'check reset css'
);
// remove something that does not eixst
$el->addCss('exists');
$el->removeCss('not');
$this->assertEqualsCanonicalizing(
['exists'],
$el->getCss(),
'check remove not exitsing'
);
}
/**
* nested test
*
* @testdox nested test and loop assign detection
*
* @return void
*/
public function testBuildNested(): void
{
Error::resetMessages();
$el = new Element('div', 'build-test');
$el_sub = new Element('div', 'sub-1');
$el->addSub($el_sub);
$this->assertEquals(
'<div id="build-test"><div id="sub-1"></div></div>',
$el->buildHtml(),
'nested build failed'
);
// this would create a loop, throws error
$this->expectException(HtmlBuilderExcpetion::class);
$this->expectExceptionMessage("Cannot assign Element to itself, this would create an infinite loop");
$el_sub->addSub($el_sub);
$this->assertEquals(
'<div id="sub-1"></div>',
$el_sub->buildHtml(),
'loop detection failed'
);
$this->assertTrue(
Error::hasError(),
'failed to throw error post loop detection'
);
$this->assertEquals(
[[
'level' => 'Error',
'id' => '100',
'message' => 'Cannot assign Element to itself, this would create an infinite loop',
'context' => ['tag' => 'div', 'id' => 'sub-1']
]],
Error::getMessages(),
'check error is 100 failed'
);
// get sub
$this->assertEquals(
[$el_sub],
$el->getSub(),
'get sub failed'
);
// reset sub
$el->resetSub();
$this->assertEquals(
[],
$el->getSub(),
'reset sub failed'
);
}
/**
* Undocumented function
*
* @testdox updated nested connection
*
* @return void
*/
public function testNestedChangeContent(): void
{
$el = new Element('div', 'build-test');
$el_s_1 = new Element('div', 'sub-1');
$el_s_2 = new Element('div', 'sub-2');
$el_s_3 = new Element('div', 'sub-3');
$el_s_4 = new Element('div', 'sub-4');
$el->addSub($el_s_1, $el_s_2);
// only sub -1, -2
$this->assertEquals(
'<div id="build-test"><div id="sub-1"></div><div id="sub-2"></div></div>',
$el->buildHtml(),
'check basic nested'
);
// now add -3, -4 to both -1 and -2
$el_s_1->addSub($el_s_3, $el_s_4);
$el_s_2->addSub($el_s_3, $el_s_4);
$this->assertEquals(
'<div id="build-test"><div id="sub-1"><div id="sub-3"></div><div id="sub-4">'
. '</div></div><div id="sub-2"><div id="sub-3"></div><div id="sub-4"></div>'
. '</div></div>',
$el->buildHtml(),
'check nested added'
);
// now add some css to el_s_3, will update in both sets
$el_s_3->addCss('red');
$this->assertEquals(
'<div id="build-test"><div id="sub-1"><div id="sub-3" class="red"></div><div id="sub-4">'
. '</div></div><div id="sub-2"><div id="sub-3" class="red"></div><div id="sub-4"></div>'
. '</div></div>',
$el->buildHtml(),
'check nested u@dated'
);
}
/**
* Undocumented function
*
* @testdox test change tag/id/content
*
* @return void
*/
public function testChangeElementData(): void
{
$el = new Element('div', 'id', 'Content');
// content change
$this->assertEquals(
'Content',
$el->getContent(),
'set content'
);
$el->setContent('New Content');
$this->assertEquals(
'New Content',
$el->getContent(),
'changed content'
);
$this->assertEquals(
'div',
$el->getTag(),
'set tag'
);
$el->setTag('span');
$this->assertEquals(
'span',
$el->getTag(),
'changed tag'
);
$this->assertEquals(
'id',
$el->getId(),
'set id'
);
$el->setId('id-2');
$this->assertEquals(
'id-2',
$el->getId(),
'changed id'
);
}
/**
* Undocumented function
*
* @testdox test change options
*
* @return void
*/
public function testChangeOptions(): void
{
$el = new Element('button', 'id', 'Action', ['css'], ['value' => '3']);
$this->assertEquals(
['value' => '3'],
$el->getOptions(),
'set option'
);
$el->setOptions([
'value' => '2'
]);
$this->assertEquals(
['value' => '2'],
$el->getOptions(),
'changed option'
);
// add a new one
$el->setOptions([
'Foo' => 'bar',
'Moo' => 'cow'
]);
$this->assertEquals(
[
'value' => '2',
'Foo' => 'bar',
'Moo' => 'cow'
],
$el->getOptions(),
'changed option'
);
}
// build output
// build from array list
/**
* Undocumented function
*
* @testdox build element tree from object
*
* @return void
*/
public function testBuildHtmlObject(): void
{
// build a simple block
// div -> div -> button
// -> div -> span
// -> div -> input
$el = new Element('div', 'master', '', ['master']);
$el->addSub(
Element::addElement(
new Element('div', 'div-button', '', ['dv-bt']),
new Element('button', 'button-id', 'Click me', ['bt-red'], [
'OnClick' => 'action();',
'value' => 'click',
'type' => 'button'
]),
),
Element::addElement(
new Element('div', 'div-span', '', ['dv-sp']),
new Element('span', 'span-id', 'Big important message<br>other', ['red']),
),
Element::addElement(
new Element('div', 'div-input', '', ['dv-in']),
new Element('input', 'input-id', '', ['in-blue'], [
'OnClick' => 'otherAction();',
'value' => 'Touch',
'type' => 'button'
]),
),
);
$this->assertEquals(
'<div id="master" class="master">'
. '<div id="div-button" class="dv-bt">'
. '<button id="button-id" name="button-id" class="bt-red" OnClick="action();" '
. 'value="click" type="button">Click me</button>'
. '</div>'
. '<div id="div-span" class="dv-sp">'
. '<span id="span-id" class="red">Big important message<br>other</span>'
. '</div>'
. '<div id="div-input" class="dv-in">'
. '<input id="input-id" name="input-id" '
. 'class="in-blue" OnClick="otherAction();" value="Touch" type="button">'
. '</div>'
. '</div>',
$el->buildHtml()
);
}
/**
* Undocumented function
*
* @testdox build elements from array list
*
* @return void
*/
public function testbuildHtmlArray(): void
{
$this->assertEquals(
'<div id="id-1">A</div>'
. '<div id="id-2">B</div>'
. '<div id="id-3">C</div>',
Element::buildHtmlFromList([
new Element('div', 'id-1', 'A'),
new Element('div', 'id-2', 'B'),
new Element('div', 'id-3', 'C'),
])
);
}
/**
* Undocumented function
*
* @testdox check for invalid tag detection, possible invalid id, possible invalid css
*
* @return void
*/
public function testInvalidElement(): void
{
Error::resetMessages();
$this->expectException(HtmlBuilderExcpetion::class);
$this->expectExceptionMessage("Could not create Element");
$el = new Element('');
$this->assertTrue(
Error::hasError(),
'failed to set error invalid tag detection'
);
$this->assertEquals(
[[
'level' => 'Error',
'id' => '201',
'message' => 'invalid or empty tag',
'context' => ['tag' => '']
]],
Error::getMessages(),
'check error message failed'
);
// if we set invalid tag
$el = new Element('div');
$this->expectException(HtmlBuilderExcpetion::class);
$this->expectExceptionMessageMatches("/^Invalid or empty tag: /");
$this->expectExceptionMessage("Invalid or empty tag: 123123");
$el->setTag('123123');
$this->assertTrue(
Error::hasError(),
'failed to set error invalid tag detection'
);
$this->assertEquals(
[[
'level' => 'Error',
'id' => '201',
'message' => 'invalid or empty tag',
'context' => ['tag' => '']
]],
Error::getMessages(),
'check error message failed'
);
// invalid id (warning)
Error::resetMessages();
$el = new Element('div', '-$a15');
$this->assertTrue(
Error::hasWarning(),
'failed to set warning invalid id detection'
);
$this->assertEquals(
[[
'level' => 'Warning',
'id' => '202',
'message' => 'possible invalid id',
'context' => ['id' => '-$a15', 'tag' => 'div']
]],
Error::getMessages(),
'check error message failed'
);
// invalid name
Error::resetMessages();
$el = new Element('div', 'valid', '', [], ['name' => '-$asdf&']);
$this->assertTrue(
Error::hasWarning(),
'failed to set warning invalid name detection'
);
$this->assertEquals(
[[
'level' => 'Warning',
'id' => '203',
'message' => 'possible invalid name',
'context' => ['name' => '-$asdf&', 'id' => 'valid', 'tag' => 'div']
]],
Error::getMessages(),
'check error message failed'
);
}
// static add element
// print object/array
}
// __END__

View File

@@ -0,0 +1,65 @@
<?php
declare(strict_types=1);
namespace tests;
use PHPUnit\Framework\TestCase;
use CoreLibs\Template\HtmlBuilder\StringReplace;
/**
* Test class for Template\HtmlBuilder\StringReplace
* @coversDefaultClass \CoreLibs\Template\HtmlBuilder\StringReplace
* @testdox \CoreLibs\Template\HtmlBuilder\StringReplace method tests
*/
final class CoreLibsTemplateHtmlBuilderStringReplaceTest extends TestCase
{
/**
* Undocumented function
*
* @covers ::replaceData
* @testdox test basic replaceData
*
* @return void
*/
public function testReplaceData(): void
{
$html_block = <<<HTML
<div id="{ID}" class="{CSS}">
{CONTENT}
</div>
HTML;
$this->assertEquals(
<<<HTML
<div id="block-id" class="blue,red">
Some content here<br>with bla bla inside
</div>
HTML,
StringReplace::replaceData(
$html_block,
[
'ID' => 'block-id',
'CSS' => join(',', ['blue', 'red']),
'{CONTENT}' => 'Some content here<br>with bla bla inside',
]
)
);
}
/**
* Undocumented function
*
* @testdox replaceData error
*
* @return void
*/
/* public function testReplaceDataErrors(): void
{
$this->expectException(HtmlBuilderExcpetion::class);
$this->expectExceptionMessage("Replace and content array count differ");
StringReplace::replaceData('<span>{FOO}</span>', ['{FOO}', '{BAR}'], ['foo']);
} */
}
// __END__

15
4dev/tests/bootstrap.php Normal file
View File

@@ -0,0 +1,15 @@
<?php
$set = 0;
foreach (['/../../www', '/../www', '/../..', '/..', '/../../src', '/../src'] as $src) {
if (is_file(dirname(__DIR__) . $src . '/vendor/autoload.php')) {
require dirname(__DIR__) . $src . '/vendor/autoload.php';
$set = 1;
break;
}
}
if (!$set) {
die("Cannot find /vendor/autoload.php in reference to: " . dirname(__DIR__));
}
// __END__

View File

@@ -1 +0,0 @@
test.env

43
README.Exceptions.md Normal file
View File

@@ -0,0 +1,43 @@
# Exception rules
What exceptions to use for what
NOTE: There will be custom Excpetions creaed and so some rules will change
NOTE: For catching: always catch \Exception at the end to avoid missing some changed exceptions
NOTE: Changed exceptions will have marked as critical API change
## \Exception
if there is nothing else matching, use this one
## \InvalidArgumentException
if argument to a function is not expected type
## \UnexpectedValueException
If the value is not matching to what we expect
## \LengthException
Given value is out of range
## \RuntimeException
Missing php modules or external programs
## \OutOfRangeException
Not in range of given expression (array or other)
## Below are ERRORs
### \ArgumentCountError [ERROR]
If we have dynamic argument methods and we are missing a certain arguemnt count
### \TypeError
Invalid type

View File

@@ -4,7 +4,6 @@
* Uses PSR-12 * Uses PSR-12
* tab indent instead of 4 spaces indent * tab indent instead of 4 spaces indent
* Warning at 120 character length, error at 240 character length
## General information ## General information
@@ -24,9 +23,9 @@ There are three branches:
### master ### master
The active branch, which is the namespace branch. The active branch, which is the namespace branch.
Currently compatible with PHP 7.4 and 8.0 Compatible with PHP 8.1 or higher
### legacy ### legacy (deprecated)
The old non namepsace format layout. The old non namepsace format layout.
This is fully deprecated and will no longer be maintaned. This is fully deprecated and will no longer be maintaned.
@@ -39,17 +38,17 @@ Any current development is done here
## Static checks ## Static checks
With phpstan (`4dev/checking/phpstan.sh`) With phpstan (`4dev/checking/phpstan.sh`)
`phpstan` `vendor/bin/phpstan`
With phan (`4dev/checking/phan.sh`) With phan (`4dev/checking/phan.sh`)
`phan --progress-bar -C --analyze-twice` `vendor/bin/phan --progress-bar -C --analyze-twice`
pslam is setup but not configured pslam is setup but not configured
## Unit tests ## Unit tests
With phpunit (`4dev/checking/phpunit.sh`) With phpunit (`4dev/checking/phpunit.sh`)
`phpunit -c $phpunit.xml 4dev/tests/` `www/vendor/bin/phpunit -c $phpunit.xml 4dev/tests/`
## Other Notes ## Other Notes
@@ -93,3 +92,25 @@ Loads classes internal (not passed in, not extend)
* \CoreLibs\Admin\EditBase loads \CoreLibs\Template\SmartyExtend, \CoreLibs\Output\Form\Generate * \CoreLibs\Admin\EditBase loads \CoreLibs\Template\SmartyExtend, \CoreLibs\Output\Form\Generate
* \CoreLibs\Output\From\Generate loads \CoreLibs\Debug\Logging, \CoreLibs\Language\L10n if not passed on * \CoreLibs\Output\From\Generate loads \CoreLibs\Debug\Logging, \CoreLibs\Language\L10n if not passed on
* \CoreLibs\Output\From\Generate loads \CoreLibs\Output\From\TableArrays * \CoreLibs\Output\From\Generate loads \CoreLibs\Output\From\TableArrays
## PHP unit testing and Intelephense
Intelephense can not directly read phar files so we do the following
In the workspace root we have `.libs/`, be in the workspace folder not the `.libs/` folder
`php -r "(new Phar('/path/to/.phive/phars/phpunit-9.6.13.phar'))->extractTo('.libs/phpunit/');"`
andd add in vscode Intelephense > Enviroment: Include Paths (intelephense.environment.includePaths)
```json
"intelephense.environment.includePaths": [
"/.libs/phpunit/"
]
```
Add `.libs` to the master .gitingore
### Update phpunit
On a version update the old phpunit folder in .libs has to be removed and the new version extracted again

View File

@@ -9,13 +9,8 @@
- run phan/phpstan/phpunit tests in composer branch - run phan/phpstan/phpunit tests in composer branch
- commit and sync to master - commit and sync to master
- create the same version tag as before in the trunk/master - create the same version tag as before in the trunk/master
- GITEA - GITEA and GITLAB:
- download ZIP file from TAG - Run `publish/publish.sh` script to create composer packages
- `curl --user clemens.schwaighofer:KEY \
--upload-file ~/Documents/Composer/CoreLibs-Composer-All-vX.Y.Z.zip \
https://git.egplusww.jp/api/packages/Composer/composer?version=X.Y.Z`
- GitLab
- `curl --data tag=vX-Y-Z --header "Deploy-Token: TOKENr" "https://gitlab-na.factory.tools/api/v4/projects/950/packages/composer"`
- Composer Packagest local - Composer Packagest local
- update pacakges.json file with new version and commit - update pacakges.json file with new version and commit
- `git pull egra-gitea master` - run `git pull egra-gitea master` on udon-core in `/var/www/html/composer/www`

View File

@@ -1,4 +1,12 @@
{ {
"name": "egrajp/development-corelibs-dev",
"version": "dev-master",
"description": "CoreLibs: Development package",
"type": "library",
"config": {
},
"require": {
"php": ">=8.1"
"require-dev": { "require-dev": {
"phpstan/phpstan": "^1.10", "phpstan/phpstan": "^1.10",
"phan/phan": "^5.4", "phan/phan": "^5.4",

1810
composer.lock generated

File diff suppressed because it is too large Load Diff

15
jsconfig.json Normal file
View File

@@ -0,0 +1,15 @@
{
"compilerOptions": {
"module": "ESNext",
"moduleResolution": "Node",
"target": "ES2020",
"jsx": "react",
"allowImportingTsExtensions": true,
"strictNullChecks": true,
"strictFunctionTypes": true
},
"exclude": [
"node_modules",
"**/node_modules/*"
]
}

18
phpcs.xml Normal file
View File

@@ -0,0 +1,18 @@
<?xml version="1.0"?>
<ruleset name="MyStandard">
<description>PSR12 override rules (strict, standard). Switch spaces indent to tab.</description>
<arg name="tab-width" value="4"/>
<rule ref="PSR1"/>
<rule ref="PSR12">
<!-- turn off white space check for tab -->
<exclude name="Generic.WhiteSpace.DisallowTabIndent"/>
</rule>
<!-- no space indent, must be tab, 4 is tab iwdth -->
<rule ref="Generic.WhiteSpace.DisallowSpaceIndent"/>
<rule ref="Generic.WhiteSpace.ScopeIndent">
<properties>
<property name="indent" value="4"/>
<property name="tabIndent" value="true"/>
</properties>
</rule>
</ruleset>

View File

@@ -1,47 +0,0 @@
parameters:
ignoreErrors:
-
message: "#^Parameter \\#1 \\$connection of function pg_escape_bytea expects PgSql\\\\Connection\\|string, object\\|resource given\\.$#"
count: 1
path: www/lib/CoreLibs/DB/SQL/PgSQL.php
-
message: "#^Parameter \\#1 \\$connection of function pg_escape_identifier expects PgSql\\\\Connection\\|string, object\\|resource given\\.$#"
count: 1
path: www/lib/CoreLibs/DB/SQL/PgSQL.php
-
message: "#^Parameter \\#1 \\$connection of function pg_escape_literal expects PgSql\\\\Connection\\|string, object\\|resource given\\.$#"
count: 1
path: www/lib/CoreLibs/DB/SQL/PgSQL.php
-
message: "#^Parameter \\#1 \\$connection of function pg_escape_string expects PgSql\\\\Connection\\|string, object\\|resource given\\.$#"
count: 1
path: www/lib/CoreLibs/DB/SQL/PgSQL.php
-
message: "#^Parameter \\#1 \\$connection of function pg_execute expects PgSql\\\\Connection\\|string, object\\|resource given\\.$#"
count: 1
path: www/lib/CoreLibs/DB/SQL/PgSQL.php
-
message: "#^Parameter \\#1 \\$connection of function pg_parameter_status expects PgSql\\\\Connection\\|string, object\\|resource given\\.$#"
count: 1
path: www/lib/CoreLibs/DB/SQL/PgSQL.php
-
message: "#^Parameter \\#1 \\$connection of function pg_prepare expects PgSql\\\\Connection\\|string, object\\|resource given\\.$#"
count: 1
path: www/lib/CoreLibs/DB/SQL/PgSQL.php
-
message: "#^Parameter \\#1 \\$connection of function pg_query expects PgSql\\\\Connection\\|string, object\\|resource given\\.$#"
count: 1
path: www/lib/CoreLibs/DB/SQL/PgSQL.php
-
message: "#^Parameter \\#1 \\$connection of function pg_query_params expects PgSql\\\\Connection\\|string, object\\|resource given\\.$#"
count: 1
path: www/lib/CoreLibs/DB/SQL/PgSQL.php

View File

@@ -8,5 +8,7 @@ $_SERVER['HTTP_HOST'] = 'soba.tokyo.tequila.jp';
// for whatever reason it does not load that from the confing.master.php // for whatever reason it does not load that from the confing.master.php
// for includes/admin_header.php // for includes/admin_header.php
define('BASE_NAME', ''); define('BASE_NAME', '');
define('SITE_DOMAIN', '');
define('HOST_NAME', 'soba.tokyo.tequila.jp');
// __END__ // __END__

View File

@@ -2,7 +2,7 @@
includes: includes:
- phpstan-conditional.php - phpstan-conditional.php
parameters: parameters:
tmpDir: /tmp/phpstan-corelibs tmpDir: %currentWorkingDirectory%/tmp/phpstan-corelibs
level: 8 # max is now 9 level: 8 # max is now 9
checkMissingCallableSignature: true checkMissingCallableSignature: true
treatPhpDocTypesAsCertain: false treatPhpDocTypesAsCertain: false
@@ -24,36 +24,25 @@ parameters:
- %currentWorkingDirectory%/www - %currentWorkingDirectory%/www
bootstrapFiles: bootstrapFiles:
- %currentWorkingDirectory%/phpstan-bootstrap.php - %currentWorkingDirectory%/phpstan-bootstrap.php
# - %currentWorkingDirectory%/www/lib/autoloader.php
- %currentWorkingDirectory%/www/vendor/autoload.php - %currentWorkingDirectory%/www/vendor/autoload.php
scanDirectories: scanDirectories:
- www/vendor - www/vendor
scanFiles: scanFiles:
- www/configs/config.php - www/configs/config.php
- www/configs/config.master.php - www/configs/config.master.php
# if composer.json autoloader defined, this is not needed
# - www/lib/autoloader.php
- www/vendor/autoload.php
excludePaths: excludePaths:
# do not check old qq file uploader tests # do not check old qq file uploader tests
- www/admin/qq_file_upload_*.php - www/admin/qq_file_upload_*.php
# ignore all test files
- www/admin/class_test*.php
# extra in sub folder
- www/admin/subfolder/class_test*.php
- www/admin/error_test.php - www/admin/error_test.php
# admin synlink files # admin synlink files
- www/admin/edit_*.php - www/admin/edit_*.php
# config symlinks
- www/admin/config.php - www/admin/config.php
# frotend symlink - www/frontend/config.php
- www/frontend/*config.php - www/frontend/*/config.php
# ignore admin header stuff # ignore admin header stuff
# - www/includes/admin_header.php # ignore the admin include stuff # - www/includes/admin_header.php # ignore the admin include stuff
- www/includes/admin_footer.php # ignore the admin include stuff - www/includes/admin_footer.php # ignore the admin include stuff
# deprecated files
- www/includes/admin_set_paths.php # ignore the admin include stuff
- www/includes/admin_smarty.php # ignore the admin include stuff
- www/includes/edit_base.LEGACY.php # old style
# folders with data no check needed # folders with data no check needed
- www/templates_c - www/templates_c
- www/cache - www/cache
@@ -66,13 +55,9 @@ parameters:
- www/vendor - www/vendor
# ignore errores with # ignore errores with
ignoreErrors: ignoreErrors:
#- # this error is ignore because of the PHP 8.0 to 8.1 change for pg_*, only for 8.0 or lower # - # in the class_test tree we allow deprecated calls
# message: "#^Parameter \\#1 \\$(result|connection) of function pg_\\w+ expects resource(\\|null)?, object\\|resource(\\|bool)? given\\.$#" # message: "#^Call to deprecated method #"
# path: %currentWorkingDirectory%/www/lib/CoreLibs/DB/SQL/PgSQL.php # path: %currentWorkingDirectory%/www/admin/class_test.*.php
- # this is for 8.1 or newer
message: "#^Parameter \\#1 \\$(result|connection) of function pg_\\w+ expects PgSql\\\\(Result|Connection(\\|string)?(\\|null)?), object\\|resource given\\.$#"
path: %currentWorkingDirectory%/www/lib/CoreLibs/DB/SQL/PgSQL.php
# this is ignored for now
# - '#Expression in empty\(\) is always falsy.#' # - '#Expression in empty\(\) is always falsy.#'
# - # -
# message: '#Reflection error: [a-zA-Z0-9\\_]+ not found.#' # message: '#Reflection error: [a-zA-Z0-9\\_]+ not found.#'
@@ -84,3 +69,6 @@ parameters:
# paths: # paths:
# - ... # - ...
# - ... # - ...
#-
# message: "#^Call to deprecated method #"
# path: www/admin/class_test*.php

Some files were not shown because too many files have changed in this diff Show More