"
+ * their tag such as "[[_toc_]]".
+ *
+ * @param string $text Tag text to encode
+ *
+ * @return string
+ *
+ * @since 1.0.0
*/
- protected function encodeTagToHash($text)
+ protected function encodeToCTagToHash(string $text) : string
{
- $salt = $this->getSalt();
- $tagOrigin = $this->getTagToC();
+ $salt = \bin2hex(\random_bytes(4));
+ $tagOrigin = $this->options['toc']['set_toc_tag'] ?? '[toc]';
if (\strpos($text, $tagOrigin) === false) {
return $text;
}
- $tagHashed = \hash('sha256', $salt.$tagOrigin);
+ $tagHashed = \hash('sha256', $salt . $tagOrigin);
return \str_replace($tagOrigin, $tagHashed, $text);
}
@@ -1583,14 +2999,19 @@ class Markdown
* Decodes the hashed ToC tag to an original tag and replaces.
*
* This is used to avoid parsing user defined ToC tag which includes "_" in
- * their tag such as "[[_toc_]]". Unless it will be parsed as:
- * "
');
foreach ($oShape->getShapeCollection() as $oShapeChild) {
$this->displayShape($oShapeChild);
}
diff --git a/Utils/Parser/Spreadsheet/SpreadsheetParser.php b/Utils/Parser/Spreadsheet/SpreadsheetParser.php
index 07847522b..b85fc0f4c 100755
--- a/Utils/Parser/Spreadsheet/SpreadsheetParser.php
+++ b/Utils/Parser/Spreadsheet/SpreadsheetParser.php
@@ -25,8 +25,18 @@ use PhpOffice\PhpSpreadsheet\Worksheet\PageSetup;
* @link https://jingga.app
* @since 1.0.0
*/
-class SpreadsheetParser
+final class SpreadsheetParser
{
+ /**
+ * Constructor.
+ *
+ * @since 1.0.0
+ * @codeCoverageIgnore
+ */
+ private function __construct()
+ {
+ }
+
/**
* Spreadsheet to string
*
@@ -38,9 +48,9 @@ class SpreadsheetParser
*/
public static function parseSpreadsheet(string $path, string $output = 'json') : string
{
- if ($output === 'json') {
- $spreadsheet = IOFactory::load($path);
+ $spreadsheet = IOFactory::load($path);
+ if ($output === 'json') {
$sheetCount = $spreadsheet->getSheetCount();
$csv = [];
@@ -52,8 +62,6 @@ class SpreadsheetParser
return $json === false ? '' : $json;
} elseif ($output === 'pdf') {
- $spreadsheet = IOFactory::load($path);
-
$spreadsheet->getActiveSheet()->setShowGridLines(false);
$spreadsheet->getActiveSheet()->getPageSetup()->setOrientation(PageSetup::ORIENTATION_LANDSCAPE);
@@ -64,13 +72,31 @@ class SpreadsheetParser
return $writer->toPdfString();
} elseif ($output === 'html') {
- $spreadsheet = IOFactory::load($path);
-
IOFactory::registerWriter('custom', \phpOMS\Utils\Parser\Spreadsheet\SpreadsheetWriter::class);
/** @var \phpOMS\Utils\Parser\Spreadsheet\SpreadsheetWriter $writer */
$writer = IOFactory::createWriter($spreadsheet, 'custom');
return $writer->generateHtmlAll();
+ } elseif ($output === 'txt') {
+ IOFactory::registerWriter('custom', \phpOMS\Utils\Parser\Spreadsheet\SpreadsheetWriter::class);
+
+ /** @var \phpOMS\Utils\Parser\Spreadsheet\SpreadsheetWriter $writer */
+ $writer = IOFactory::createWriter($spreadsheet, 'custom');
+ $html = $writer->generateHtmlAll();
+
+ $doc = new \DOMDocument();
+ $html = \preg_replace(
+ ['~~', '~~'],
+ ['', ''],
+ $html
+ );
+
+ $doc->loadHTMLFile($path);
+
+ $body = $doc->getElementsByTagName('body');
+ $node = $body->item(0);
+
+ return empty($node->textContent) ? '' : $node->textContent;
}
return '';
diff --git a/Utils/Parser/Xml/XmlParser.php b/Utils/Parser/Xml/XmlParser.php
new file mode 100644
index 000000000..3c772a652
--- /dev/null
+++ b/Utils/Parser/Xml/XmlParser.php
@@ -0,0 +1,96 @@
+preserveWhiteSpace = true;
+ $doc->formatOutput = true;
+
+ $xml = \file_get_contents($path);
+ if ($xml === false || $xml === null) {
+ return '';
+ }
+
+ $xml = \preg_replace(
+ ['~~', '~~'],
+ ['', ''],
+ $xml
+ );
+
+ if ($xml === null) {
+ return '';
+ }
+
+ $result = $doc->loadXML($xml);
+ if ($result === false) {
+ return '';
+ }
+
+ if (empty($xpath)) {
+ $result = $doc->saveHTML();
+
+ return $result === false ? '' : $result;
+ }
+
+ $content = '';
+ $xNode = new \DOMXpath($doc);
+ $elements = $xNode->query($xpath);
+
+ if ($elements === false) {
+ return $content;
+ }
+
+ foreach ($elements as $element) {
+ $nodes = $element->childNodes;
+
+ foreach ($nodes as $node) {
+ $content .= $node->textContent . "\n";
+ }
+ }
+
+ return $content;
+ }
+}
diff --git a/Utils/Permutation.php b/Utils/Permutation.php
index 6f4bc3532..d2f62106e 100755
--- a/Utils/Permutation.php
+++ b/Utils/Permutation.php
@@ -37,14 +37,14 @@ final class Permutation
/**
* Create all permutations.
*
- * @param array $toPermute data to permutate
+ * @param array $toPermute data to permute
* @param array $result existing permutations
*
* @return array
*
* @since 1.0.0
*/
- public static function permut(array $toPermute, array $result = [], bool $concat = true) : array
+ public static function permuteAll(array $toPermute, array $result = [], bool $concat = true) : array
{
$permutations = [];
@@ -58,7 +58,7 @@ final class Permutation
unset($newArr[$key]);
- $permutations = \array_merge($permutations, self::permut($newArr, $newres, $concat));
+ $permutations = \array_merge($permutations, self::permuteAll($newArr, $newres, $concat));
}
}
@@ -98,9 +98,9 @@ final class Permutation
}
/**
- * Permutate based on transposition key.
+ * Permute based on transposition key.
*
- * @param array|string $toPermute To permutate
+ * @param array|string $toPermute To permute
* @param int[] $key Permutation keys
*
* @return string|array
@@ -109,7 +109,7 @@ final class Permutation
*
* @since 1.0.0
*/
- public static function permutate(string | array $toPermute, array $key) : string | array
+ public static function permuteByKey(string | array $toPermute, array $key) : string | array
{
$length = \is_array($toPermute) ? \count($toPermute) : \strlen($toPermute);
diff --git a/Utils/RnG/ArrayRandomize.php b/Utils/RnG/ArrayRandomize.php
index adfb5fbda..6619e3b11 100755
--- a/Utils/RnG/ArrayRandomize.php
+++ b/Utils/RnG/ArrayRandomize.php
@@ -22,8 +22,18 @@ namespace phpOMS\Utils\RnG;
* @link https://jingga.app
* @since 1.0.0
*/
-class ArrayRandomize
+final class ArrayRandomize
{
+ /**
+ * Constructor.
+ *
+ * @since 1.0.0
+ * @codeCoverageIgnore
+ */
+ private function __construct()
+ {
+ }
+
/**
* Yates array shuffler.
*
diff --git a/Utils/RnG/DateTime.php b/Utils/RnG/DateTime.php
index c288b10ff..704a8e39f 100755
--- a/Utils/RnG/DateTime.php
+++ b/Utils/RnG/DateTime.php
@@ -22,8 +22,18 @@ namespace phpOMS\Utils\RnG;
* @link https://jingga.app
* @since 1.0.0
*/
-class DateTime
+final class DateTime
{
+ /**
+ * Constructor.
+ *
+ * @since 1.0.0
+ * @codeCoverageIgnore
+ */
+ private function __construct()
+ {
+ }
+
/**
* Get a random \DateTime.
*
diff --git a/Utils/RnG/Email.php b/Utils/RnG/Email.php
index 4ae5ab4cf..50a71dcca 100755
--- a/Utils/RnG/Email.php
+++ b/Utils/RnG/Email.php
@@ -22,8 +22,18 @@ namespace phpOMS\Utils\RnG;
* @link https://jingga.app
* @since 1.0.0
*/
-class Email
+final class Email
{
+ /**
+ * Constructor.
+ *
+ * @since 1.0.0
+ * @codeCoverageIgnore
+ */
+ private function __construct()
+ {
+ }
+
/**
* Get a random email.
*
diff --git a/Utils/RnG/File.php b/Utils/RnG/File.php
index 22b951659..87288bf29 100755
--- a/Utils/RnG/File.php
+++ b/Utils/RnG/File.php
@@ -22,7 +22,7 @@ namespace phpOMS\Utils\RnG;
* @link https://jingga.app
* @since 1.0.0
*/
-class File
+final class File
{
/**
* Extensions.
@@ -44,6 +44,16 @@ class File
['flv'], ['fla'], ['deb'], ['py'], ['pl'],
];
+ /**
+ * Constructor.
+ *
+ * @since 1.0.0
+ * @codeCoverageIgnore
+ */
+ private function __construct()
+ {
+ }
+
/**
* Get a random file extension.
*
@@ -53,11 +63,9 @@ class File
*
* @since 1.0.0
*/
- public static function generateExtension(array $source = null) : string
+ public static function generateExtension(?array $source = null) : string
{
- if ($source === null) {
- $source = self::$extensions;
- }
+ $source ??= self::$extensions;
$key = \array_rand($source, 1);
diff --git a/Utils/RnG/LinearCongruentialGenerator.php b/Utils/RnG/LinearCongruentialGenerator.php
index bfc60986e..c10e42258 100755
--- a/Utils/RnG/LinearCongruentialGenerator.php
+++ b/Utils/RnG/LinearCongruentialGenerator.php
@@ -22,7 +22,7 @@ namespace phpOMS\Utils\RnG;
* @link https://jingga.app
* @since 1.0.0
*/
-class LinearCongruentialGenerator
+final class LinearCongruentialGenerator
{
/**
* BSD seed value.
@@ -40,6 +40,16 @@ class LinearCongruentialGenerator
*/
private static $msvcrtSeed = 0;
+ /**
+ * Constructor.
+ *
+ * @since 1.0.0
+ * @codeCoverageIgnore
+ */
+ private function __construct()
+ {
+ }
+
/**
* BSD random number
*
diff --git a/Utils/RnG/Name.php b/Utils/RnG/Name.php
index f02a9faec..dff549c46 100755
--- a/Utils/RnG/Name.php
+++ b/Utils/RnG/Name.php
@@ -22,7 +22,7 @@ namespace phpOMS\Utils\RnG;
* @link https://jingga.app
* @since 1.0.0
*/
-class Name
+final class Name
{
private static array $names = [
'western' => [
@@ -216,7 +216,7 @@ class Name
'Zula', 'Catrina', 'Hazeline', 'Lillian', 'Reanne', 'Zuri', 'Catriona', 'Heather', 'Lillie', 'Rebecca',
'Zyana', 'Cayla', 'Heaven',
],
- 'male' => [
+ 'male' => [
'Aaron', 'Clay', 'Gino', 'Laurie', 'Richard', 'Abdul', 'Clayton', 'Giorgio', 'Lawrence', 'Richie',
'Abdullah', 'Clement', 'Giovanni', 'Lawson', 'Rick', 'Abe', 'Cliff', 'Glen', 'Layne', 'Rickey', 'Abel',
'Clifford', 'Glenn', 'Layton', 'Rickie', 'Abraham', 'Clifton', 'Glyndwr', 'Leaf', 'Ricky', 'Abram',
@@ -481,6 +481,16 @@ class Name
],
];
+ /**
+ * Constructor.
+ *
+ * @since 1.0.0
+ * @codeCoverageIgnore
+ */
+ private function __construct()
+ {
+ }
+
/**
* Get a random string.
*
diff --git a/Utils/RnG/Number.php b/Utils/RnG/Number.php
new file mode 100644
index 000000000..3bc1a7c47
--- /dev/null
+++ b/Utils/RnG/Number.php
@@ -0,0 +1,71 @@
+ 49, 'us' => 1];
- }
+ $countries ??= ['de' => 49, 'us' => 1];
$numberString = \str_replace(
'$1',
diff --git a/Utils/RnG/StringUtils.php b/Utils/RnG/StringUtils.php
index 55e67dd6b..1cc6c73d0 100755
--- a/Utils/RnG/StringUtils.php
+++ b/Utils/RnG/StringUtils.php
@@ -22,8 +22,18 @@ namespace phpOMS\Utils\RnG;
* @link https://jingga.app
* @since 1.0.0
*/
-class StringUtils
+final class StringUtils
{
+ /**
+ * Constructor.
+ *
+ * @since 1.0.0
+ * @codeCoverageIgnore
+ */
+ private function __construct()
+ {
+ }
+
/**
* Get a random string.
*
diff --git a/Utils/RnG/Text.php b/Utils/RnG/Text.php
index 2b8b8a87b..d07cc0236 100755
--- a/Utils/RnG/Text.php
+++ b/Utils/RnG/Text.php
@@ -22,7 +22,7 @@ namespace phpOMS\Utils\RnG;
* @link https://jingga.app
* @since 1.0.0
*/
-class Text
+final class Text
{
/**
* Vocabulary.
@@ -97,15 +97,13 @@ class Text
*
* @since 1.0.0
*/
- public function generateText(int $length, array $words = null) : string
+ public function generateText(int $length, ?array $words = null) : string
{
if ($length === 0) {
return '';
}
- if ($words === null) {
- $words = self::LOREM_IPSUM;
- }
+ $words ??= self::LOREM_IPSUM;
$punctuation = $this->generatePunctuation($length);
$punctuationCount = \array_count_values(
@@ -249,7 +247,7 @@ class Text
$paragraphLength = $length - $i;
}
- $i += $paragraphLength;
+ $i += $paragraphLength;
$paragraph[] = $i;
}
diff --git a/Utils/RnG/UUID.php b/Utils/RnG/UUID.php
index 3dcf94611..a7661145f 100755
--- a/Utils/RnG/UUID.php
+++ b/Utils/RnG/UUID.php
@@ -24,6 +24,16 @@ namespace phpOMS\Utils\RnG;
*/
final class UUID
{
+ /**
+ * Constructor.
+ *
+ * @since 1.0.0
+ * @codeCoverageIgnore
+ */
+ private function __construct()
+ {
+ }
+
/**
* Get default random UUID
*
diff --git a/Utils/StringUtils.php b/Utils/StringUtils.php
index 31d23d291..e82295714 100755
--- a/Utils/StringUtils.php
+++ b/Utils/StringUtils.php
@@ -131,7 +131,7 @@ final class StringUtils
}
/**
- * Count occurences of character at the beginning of a string.
+ * Count occurrences of character at the beginning of a string.
*
* @param string $string string to analyze
* @param string $character character to count at the beginning of the string
@@ -139,7 +139,7 @@ final class StringUtils
* @example StringUtils::countCharacterFromStart(' Test string', ' '); // 4
* @example StringUtils::countCharacterFromStart(' Test string', 's'); // 0
*
- * @return int the amount of repeating occurences at the beginning of the string
+ * @return int the amount of repeating occurrences at the beginning of the string
*
* @since 1.0.0
*/
@@ -178,7 +178,7 @@ final class StringUtils
/** @var int $v */
foreach ($countChars as $v) {
- $p = $v / $size;
+ $p = $v / $size;
$entropy -= $p * \log($p) / \log(2);
}
@@ -265,37 +265,30 @@ final class StringUtils
for ($i = 0; $i < $n; ++$i) {
$mc = $diff['mask'][$i];
- if ($mc !== 0) {
- switch ($mc) {
- case -1:
- $result .= '' . $diff['values'][$i] . '' . $delim;
- break;
- case 1:
- $result .= '' . $diff['values'][$i] . '' . $delim;
- break;
- }
- } else {
- $result .= $diff['values'][$i] . $delim;
+ $previousMC = $diff['mask'][$i - 1] ?? 0;
+ $nextMC = $diff['mask'][$i + 1] ?? 0;
+
+ switch ($mc) {
+ case -1:
+ $result .= ($previousMC === -1 ? '' : '')
+ . $diff['values'][$i]
+ . ($nextMC === -1 ? '' : '')
+ . $delim;
+
+ break;
+ case 1:
+ $result .= ($previousMC === 1 ? '' : '')
+ . $diff['values'][$i]
+ . ($nextMC === 1 ? '' : '')
+ . $delim;
+
+ break;
+ default:
+ $result .= $diff['values'][$i] . $delim;
}
}
- $result = \rtrim($result, $delim);
-
- switch ($mc) {
- case -1:
- $result .= '';
- break;
- case 1:
- $result .= '';
- break;
- }
-
- // @todo: This should not be necessary but the algorithm above allows for weird combinations.
- return \str_replace(
- ['', '', '', '', '', '', '', ' '],
- ['', '', '', '', '', '', '', ''],
- $result
- );
+ return \rtrim($result, $delim);
}
/**
@@ -389,36 +382,6 @@ final class StringUtils
return (int) $res;
}
- /**
- * Fix CVE-2016-10033 and CVE-2016-10045 by disallowing potentially unsafe shell characters.
- *
- * @param string $string String to check
- *
- * @return bool
- *
- * @since 1.0.0
- */
- public static function isShellSafe(string $string) : bool
- {
- if (\escapeshellcmd($string) !== $string
- || !\in_array(\escapeshellarg($string), ["'{$string}'", "\"{$string}\""])
- ) {
- return false;
- }
-
- $length = \strlen($string);
-
- for ($i = 0; $i < $length; ++$i) {
- $c = $string[$i];
-
- if (!\ctype_alnum($c) && \strpos('@_-.', $c) === false) {
- return false;
- }
- }
-
- return true;
- }
-
/**
* Turn ints into spreadsheet column names
*
diff --git a/Utils/TaskSchedule/Cron.php b/Utils/TaskSchedule/Cron.php
index 13c2ad9b1..e3b98a063 100755
--- a/Utils/TaskSchedule/Cron.php
+++ b/Utils/TaskSchedule/Cron.php
@@ -206,8 +206,10 @@ class Cron extends SchedulerAbstract
$elements = \array_merge($elements, $interval);
$elements[] = \trim(\substr($line, $len = (\strlen(\implode(' ', $interval)) + 1), $comment - $len - 1));
- $jobs[] = $job = CronJob::createWith($elements);
- $job->setStatus($line[0] === '#' ? TaskStatus::INACTIVE : TaskStatus::ACTIVE);
+ $job = CronJob::createWith($elements);
+ $job->status = $line[0] === '#' ? TaskStatus::INACTIVE : TaskStatus::ACTIVE;
+
+ $jobs[] = $job;
}
$line = \fgets($fp);
diff --git a/Utils/TaskSchedule/Interval.php b/Utils/TaskSchedule/Interval.php
index c7f5f0e70..775f061f4 100755
--- a/Utils/TaskSchedule/Interval.php
+++ b/Utils/TaskSchedule/Interval.php
@@ -110,7 +110,7 @@ class Interval implements SerializableInterface
*
* @since 1.0.0
*/
- public function __construct(\DateTime $start = null, string $interval = null)
+ public function __construct(?\DateTime $start = null, ?string $interval = null)
{
$this->start = $start ?? new \DateTime('now');
@@ -225,7 +225,7 @@ class Interval implements SerializableInterface
*
* @since 1.0.0
*/
- public function setMinute(int $index, int $start = null, int $end = null, int $step = null) : void
+ public function setMinute(int $index, ?int $start = null, ?int $end = null, ?int $step = null) : void
{
$this->minute[$index] = [
'start' => $start,
@@ -245,7 +245,7 @@ class Interval implements SerializableInterface
*
* @since 1.0.0
*/
- public function addMinute(int $start = null, int $end = null, int $step = null) : void
+ public function addMinute(?int $start = null, ?int $end = null, ?int $step = null) : void
{
$this->minute[] = [
'start' => $start,
@@ -278,7 +278,7 @@ class Interval implements SerializableInterface
*
* @since 1.0.0
*/
- public function setHour(int $index, int $start = null, int $end = null, int $step = null) : void
+ public function setHour(int $index, ?int $start = null, ?int $end = null, ?int $step = null) : void
{
$this->hour[$index] = [
'start' => $start,
@@ -298,7 +298,7 @@ class Interval implements SerializableInterface
*
* @since 1.0.0
*/
- public function addHour(int $start = null, int $end = null, int $step = null) : void
+ public function addHour(?int $start = null, ?int $end = null, ?int $step = null) : void
{
$this->hour[] = [
'start' => $start,
@@ -331,7 +331,7 @@ class Interval implements SerializableInterface
*
* @since 1.0.0
*/
- public function setDayOfMonth(int $index, int $start = null, int $end = null, int $step = null) : void
+ public function setDayOfMonth(int $index, ?int $start = null, ?int $end = null, ?int $step = null) : void
{
$this->dayOfMonth[$index] = [
'start' => $start,
@@ -351,7 +351,7 @@ class Interval implements SerializableInterface
*
* @since 1.0.0
*/
- public function addDayOfMonth(int $start = null, int $end = null, int $step = null) : void
+ public function addDayOfMonth(?int $start = null, ?int $end = null, ?int $step = null) : void
{
$this->dayOfMonth[] = [
'start' => $start,
@@ -384,7 +384,7 @@ class Interval implements SerializableInterface
*
* @since 1.0.0
*/
- public function setDayOfWeek(int $index, int $start = null, int $end = null, int $step = null) : void
+ public function setDayOfWeek(int $index, ?int $start = null, ?int $end = null, ?int $step = null) : void
{
$this->dayOfWeek[$index] = [
'start' => $start,
@@ -404,7 +404,7 @@ class Interval implements SerializableInterface
*
* @since 1.0.0
*/
- public function addDayOfWeek(int $start = null, int $end = null, int $step = null) : void
+ public function addDayOfWeek(?int $start = null, ?int $end = null, ?int $step = null) : void
{
$this->dayOfWeek[] = [
'start' => $start,
@@ -437,7 +437,7 @@ class Interval implements SerializableInterface
*
* @since 1.0.0
*/
- public function setMonth(int $index, int $start = null, int $end = null, int $step = null) : void
+ public function setMonth(int $index, ?int $start = null, ?int $end = null, ?int $step = null) : void
{
$this->month[$index] = [
'start' => $start,
@@ -457,7 +457,7 @@ class Interval implements SerializableInterface
*
* @since 1.0.0
*/
- public function addMonth(int $start = null, int $end = null, int $step = null) : void
+ public function addMonth(?int $start = null, ?int $end = null, ?int $step = null) : void
{
$this->month[] = [
'start' => $start,
@@ -490,7 +490,7 @@ class Interval implements SerializableInterface
*
* @since 1.0.0
*/
- public function setYear(int $index, int $start = null, int $end = null, int $step = null) : void
+ public function setYear(int $index, ?int $start = null, ?int $end = null, ?int $step = null) : void
{
$this->year[$index] = [
'start' => $start,
@@ -510,7 +510,7 @@ class Interval implements SerializableInterface
*
* @since 1.0.0
*/
- public function addYear(int $start = null, int $end = null, int $step = null) : void
+ public function addYear(?int $start = null, ?int $end = null, ?int $step = null) : void
{
$this->year[] = [
'start' => $start,
diff --git a/Utils/TaskSchedule/Schedule.php b/Utils/TaskSchedule/Schedule.php
index b00f6b7e5..9991020d8 100755
--- a/Utils/TaskSchedule/Schedule.php
+++ b/Utils/TaskSchedule/Schedule.php
@@ -23,6 +23,9 @@ use phpOMS\Validation\Base\DateTime;
* @license OMS License 2.0
* @link https://jingga.app
* @since 1.0.0
+ *
+ * @todo Use `Interval` for scheduler instead of string etc.
+ * https://github.com/Karaka-Management/phpOMS/issues/257
*/
class Schedule extends TaskAbstract
{
@@ -39,13 +42,9 @@ class Schedule extends TaskAbstract
*/
public static function createWith(array $jobData) : TaskAbstract
{
- /**
- * @todo Karaka/phpOMS#231
- * Use the interval for generating a schedule
- */
$job = new self($jobData[1], $jobData[8], $jobData[7]);
- $job->setStatus((int) $jobData[3]);
+ $job->status = (int) $jobData[3];
if (DateTime::isValid($jobData[2])) {
$job->setNextRunTime(new \DateTime($jobData[2]));
diff --git a/Utils/TaskSchedule/TaskAbstract.php b/Utils/TaskSchedule/TaskAbstract.php
index e1dc82ff2..586720f0b 100755
--- a/Utils/TaskSchedule/TaskAbstract.php
+++ b/Utils/TaskSchedule/TaskAbstract.php
@@ -54,7 +54,7 @@ abstract class TaskAbstract
* @var int
* @since 1.0.0
*/
- protected int $status = TaskStatus::ACTIVE;
+ public int $status = TaskStatus::ACTIVE;
/**
* Next runtime
@@ -170,32 +170,6 @@ abstract class TaskAbstract
$this->interval = $interval;
}
- /**
- * Get status.
- *
- * @return int
- *
- * @since 1.0.0
- */
- public function getStatus() : int
- {
- return $this->status;
- }
-
- /**
- * Set status.
- *
- * @param int $status Status
- *
- * @return void
- *
- * @since 1.0.0
- */
- public function setStatus(int $status) : void
- {
- $this->status = $status;
- }
-
/**
* Get next run time.
*
diff --git a/Validation/Base/DateTime.php b/Validation/Base/DateTime.php
index b0f656058..38ddbcfc9 100755
--- a/Validation/Base/DateTime.php
+++ b/Validation/Base/DateTime.php
@@ -29,7 +29,7 @@ abstract class DateTime extends ValidatorAbstract
/**
* {@inheritdoc}
*/
- public static function isValid(mixed $value, array $constraints = null) : bool
+ public static function isValid(mixed $value, ?array $constraints = null) : bool
{
if (!\is_string($value)) {
return false;
diff --git a/Validation/Base/Json.php b/Validation/Base/Json.php
index c0f4d375a..78e285cec 100755
--- a/Validation/Base/Json.php
+++ b/Validation/Base/Json.php
@@ -30,7 +30,7 @@ abstract class Json extends ValidatorAbstract
/**
* {@inheritdoc}
*/
- public static function isValid(mixed $value, array $constraints = null) : bool
+ public static function isValid(mixed $value, ?array $constraints = null) : bool
{
if (!\is_string($value)) {
return false;
diff --git a/Validation/Finance/BIC.php b/Validation/Finance/BIC.php
index 986ad0645..d63dc9004 100755
--- a/Validation/Finance/BIC.php
+++ b/Validation/Finance/BIC.php
@@ -29,7 +29,7 @@ final class BIC extends ValidatorAbstract
/**
* {@inheritdoc}
*/
- public static function isValid(mixed $value, array $constraints = null) : bool
+ public static function isValid(mixed $value, ?array $constraints = null) : bool
{
if (!\is_string($value)) {
return false;
diff --git a/Validation/Finance/CreditCard.php b/Validation/Finance/CreditCard.php
index 19c5ee050..05a292010 100755
--- a/Validation/Finance/CreditCard.php
+++ b/Validation/Finance/CreditCard.php
@@ -29,7 +29,7 @@ final class CreditCard extends ValidatorAbstract
/**
* {@inheritdoc}
*/
- public static function isValid($value, array $constraints = null) : bool
+ public static function isValid($value, ?array $constraints = null) : bool
{
if (!\is_string($value)) {
return false;
diff --git a/Validation/Finance/EUVat.php b/Validation/Finance/EUVat.php
index 1d86aa38b..92e1776e3 100644
--- a/Validation/Finance/EUVat.php
+++ b/Validation/Finance/EUVat.php
@@ -63,7 +63,7 @@ final class EUVat extends ValidatorAbstract
/**
* {@inheritdoc}
*/
- public static function isValid(mixed $value, array $constraints = null) : bool
+ public static function isValid(mixed $value, ?array $constraints = null) : bool
{
if (!\is_string($value)) {
return false;
diff --git a/Validation/Finance/Iban.php b/Validation/Finance/Iban.php
index c905bbebf..e30f2b803 100755
--- a/Validation/Finance/Iban.php
+++ b/Validation/Finance/Iban.php
@@ -29,7 +29,7 @@ final class Iban extends ValidatorAbstract
/**
* {@inheritdoc}
*/
- public static function isValid(mixed $value, array $constraints = null) : bool
+ public static function isValid(mixed $value, ?array $constraints = null) : bool
{
if (!\is_string($value)) {
return false;
@@ -42,7 +42,7 @@ final class Iban extends ValidatorAbstract
return false; // @codeCoverageIgnore
}
- $enumName = 'C_' . \strtoupper($temp);
+ $enumName = '_' . \strtoupper($temp);
if (!IbanEnum::isValidName($enumName)) {
self::$error = IbanErrorType::INVALID_COUNTRY;
@@ -148,14 +148,16 @@ final class Iban extends ValidatorAbstract
*/
private static function validateChecksum(string $iban) : bool
{
- $chars = ['a' => 10, 'b' => 11, 'c' => 12, 'd' => 13, 'e' => 14, 'f' => 15, 'g' => 16, 'h' => 17, 'i' => 18,
- 'j' => 19, 'k' => 20, 'l' => 21, 'm' => 22, 'n' => 23, 'o' => 24, 'p' => 25, 'q' => 26, 'r' => 27,
- 's' => 28, 't' => 29, 'u' => 30, 'v' => 31, 'w' => 32, 'x' => 33, 'y' => 34, 'z' => 35,];
+ $chars = [
+ 'a' => 10, 'b' => 11, 'c' => 12, 'd' => 13, 'e' => 14, 'f' => 15, 'g' => 16, 'h' => 17, 'i' => 18,
+ 'j' => 19, 'k' => 20, 'l' => 21, 'm' => 22, 'n' => 23, 'o' => 24, 'p' => 25, 'q' => 26, 'r' => 27,
+ 's' => 28, 't' => 29, 'u' => 30, 'v' => 31, 'w' => 32, 'x' => 33, 'y' => 34, 'z' => 35,
+ ];
$moved = \substr($iban, 4) . \substr($iban, 0, 4);
$movedArray = (array) \str_split($moved);
$new = '';
- foreach ($movedArray as $key => $value) {
+ foreach ($movedArray as $key => $_) {
if (!\is_numeric($movedArray[$key])) {
$movedArray[$key] = $chars[$movedArray[$key]];
}
diff --git a/Validation/Finance/IbanEnum.php b/Validation/Finance/IbanEnum.php
index 50e0bdf16..31c7ec98e 100755
--- a/Validation/Finance/IbanEnum.php
+++ b/Validation/Finance/IbanEnum.php
@@ -26,167 +26,167 @@ use phpOMS\Stdlib\Base\Enum;
*/
class IbanEnum extends Enum
{
- public const C_AL = 'ALkk bbbs sssx cccc cccc cccc cccc';
+ public const _AL = 'ALkk bbbs sssx cccc cccc cccc cccc';
- public const C_AD = 'ADkk bbbb ssss cccc cccc cccc';
+ public const _AD = 'ADkk bbbb ssss cccc cccc cccc';
- public const C_AT = 'ATkk bbbb bccc cccc cccc';
+ public const _AT = 'ATkk bbbb bccc cccc cccc';
- public const C_AZ = 'AZkk bbbb cccc cccc cccc cccc cccc ';
+ public const _AZ = 'AZkk bbbb cccc cccc cccc cccc cccc ';
- public const C_BH = 'BHkk bbbb cccc cccc cccc cc';
+ public const _BH = 'BHkk bbbb cccc cccc cccc cc';
- public const C_BE = 'BEkk bbbc cccc ccxx';
+ public const _BE = 'BEkk bbbc cccc ccxx';
- public const C_BA = 'BAkk bbbs sscc cccc ccxx';
+ public const _BA = 'BAkk bbbs sscc cccc ccxx';
- public const C_BR = 'BRkk bbbb bbbb ssss sccc cccc ccct n';
+ public const _BR = 'BRkk bbbb bbbb ssss sccc cccc ccct n';
- public const C_BG = 'BGkk bbbb ssss ttcc cccc cc';
+ public const _BG = 'BGkk bbbb ssss ttcc cccc cc';
- public const C_CR = 'CRkk bbbc cccc cccc cccc c';
+ public const _CR = 'CRkk bbbc cccc cccc cccc c';
- public const C_HR = 'HRkk bbbb bbbc cccc cccc c';
+ public const _HR = 'HRkk bbbb bbbc cccc cccc c';
- public const C_CY = 'CYkk bbbs ssss cccc cccc cccc cccc';
+ public const _CY = 'CYkk bbbs ssss cccc cccc cccc cccc';
- public const C_CZ = 'CZkk bbbb ssss sscc cccc cccc';
+ public const _CZ = 'CZkk bbbb ssss sscc cccc cccc';
- public const C_DK = 'DKkk bbbb cccc cccc cc';
+ public const _DK = 'DKkk bbbb cccc cccc cc';
- public const C_DO = 'DOkk bbbb cccc cccc cccc cccc cccc';
+ public const _DO = 'DOkk bbbb cccc cccc cccc cccc cccc';
- public const C_TL = 'TLkk bbbc cccc cccc cccc cxx';
+ public const _TL = 'TLkk bbbc cccc cccc cccc cxx';
- public const C_EE = 'EEkk bbss cccc cccc cccx';
+ public const _EE = 'EEkk bbss cccc cccc cccx';
- public const C_FO = 'FOkk bbbb cccc cccc cx';
+ public const _FO = 'FOkk bbbb cccc cccc cx';
- public const C_FI = 'FIkk bbbb bbcc cccc cx';
+ public const _FI = 'FIkk bbbb bbcc cccc cx';
- public const C_FR = 'FRkk bbbb bsss sscc cccc cccc cxx';
+ public const _FR = 'FRkk bbbb bsss sscc cccc cccc cxx';
- public const C_GE = 'GEkk bbcc cccc cccc cccc cc';
+ public const _GE = 'GEkk bbcc cccc cccc cccc cc';
- public const C_DE = 'DEkk bbbb bbbb cccc cccc cc';
+ public const _DE = 'DEkk bbbb bbbb cccc cccc cc';
- public const C_GI = 'GIkk bbbb cccc cccc cccc ccc';
+ public const _GI = 'GIkk bbbb cccc cccc cccc ccc';
- public const C_GR = 'GRkk bbbs sssc cccc cccc cccc ccc';
+ public const _GR = 'GRkk bbbs sssc cccc cccc cccc ccc';
- public const C_GL = 'GLkk bbbb cccc cccc cc';
+ public const _GL = 'GLkk bbbb cccc cccc cc';
- public const C_GT = 'GTkk bbbb mmtt cccc cccc cccc cccc';
+ public const _GT = 'GTkk bbbb mmtt cccc cccc cccc cccc';
- public const C_HU = 'HUkk bbbs sssx cccc cccc cccc cccx';
+ public const _HU = 'HUkk bbbs sssx cccc cccc cccc cccx';
- public const C_IS = 'ISkk bbbb sscc cccc iiii iiii ii';
+ public const _IS = 'ISkk bbbb sscc cccc iiii iiii ii';
- public const C_IE = 'IEkk aaaa bbbb bbcc cccc cc';
+ public const _IE = 'IEkk aaaa bbbb bbcc cccc cc';
- public const C_IL = 'ILkk bbbn nncc cccc cccc ccc';
+ public const _IL = 'ILkk bbbn nncc cccc cccc ccc';
- public const C_IT = 'ITkk xbbb bbss sssc cccc cccc ccc';
+ public const _IT = 'ITkk xbbb bbss sssc cccc cccc ccc';
- public const C_JO = 'JOkk bbbb ssss cccc cccc cccc cccc cc';
+ public const _JO = 'JOkk bbbb ssss cccc cccc cccc cccc cc';
- public const C_KZ = 'KZkk bbbc cccc cccc cccc';
+ public const _KZ = 'KZkk bbbc cccc cccc cccc';
- public const C_XK = 'XKkk bbbb cccc cccc cccc';
+ public const _XK = 'XKkk bbbb cccc cccc cccc';
- public const C_KW = 'KWkk bbbb cccc cccc cccc cccc cccc cc';
+ public const _KW = 'KWkk bbbb cccc cccc cccc cccc cccc cc';
- public const C_LV = 'LVkk bbbb cccc cccc cccc c';
+ public const _LV = 'LVkk bbbb cccc cccc cccc c';
- public const C_LB = 'LBkk bbbb cccc cccc cccc cccc cccc';
+ public const _LB = 'LBkk bbbb cccc cccc cccc cccc cccc';
- public const C_LI = 'LIkk bbbb bccc cccc cccc c';
+ public const _LI = 'LIkk bbbb bccc cccc cccc c';
- public const C_LT = 'LTkk bbbb bccc cccc cccc';
+ public const _LT = 'LTkk bbbb bccc cccc cccc';
- public const C_LU = 'LUkk bbbc cccc cccc cccc';
+ public const _LU = 'LUkk bbbc cccc cccc cccc';
- public const C_MK = 'MKkk bbbc cccc cccc cxx';
+ public const _MK = 'MKkk bbbc cccc cccc cxx';
- public const C_MT = 'MTkk bbbb ssss sccc cccc cccc cccc ccc';
+ public const _MT = 'MTkk bbbb ssss sccc cccc cccc cccc ccc';
- public const C_MR = 'MRkk bbbb bsss sscc cccc cccc cxx';
+ public const _MR = 'MRkk bbbb bsss sscc cccc cccc cxx';
- public const C_MU = 'MUkk bbbb bbss cccc cccc cccc 000m mm';
+ public const _MU = 'MUkk bbbb bbss cccc cccc cccc 000m mm';
- public const C_MC = 'MCkk bbbb bsss sscc cccc cccc cxx';
+ public const _MC = 'MCkk bbbb bsss sscc cccc cccc cxx';
- public const C_MD = 'MDkk bbcc cccc cccc cccc cccc';
+ public const _MD = 'MDkk bbcc cccc cccc cccc cccc';
- public const C_ME = 'MEkk bbbc cccc cccc cccc xx';
+ public const _ME = 'MEkk bbbc cccc cccc cccc xx';
- public const C_NL = 'NLkk bbbb cccc cccc cc';
+ public const _NL = 'NLkk bbbb cccc cccc cc';
- public const C_NO = 'NOkk bbbb cccc ccx';
+ public const _NO = 'NOkk bbbb cccc ccx';
- public const C_PK = 'PKkk bbbb cccc cccc cccc cccc';
+ public const _PK = 'PKkk bbbb cccc cccc cccc cccc';
- public const C_PS = 'PSkk bbbb xxxx xxxx xccc cccc cccc c';
+ public const _PS = 'PSkk bbbb xxxx xxxx xccc cccc cccc c';
- public const C_PL = 'PLkk bbbs sssx cccc cccc cccc cccc';
+ public const _PL = 'PLkk bbbs sssx cccc cccc cccc cccc';
- public const C_PT = 'PTkk bbbb ssss cccc cccc cccx x';
+ public const _PT = 'PTkk bbbb ssss cccc cccc cccx x';
- public const C_QA = 'QAkk bbbb cccc cccc cccc cccc cccc c';
+ public const _QA = 'QAkk bbbb cccc cccc cccc cccc cccc c';
- public const C_RO = 'ROkk bbbb cccc cccc cccc cccc';
+ public const _RO = 'ROkk bbbb cccc cccc cccc cccc';
- public const C_SM = 'SMkk xbbb bbss sssc cccc cccc ccc';
+ public const _SM = 'SMkk xbbb bbss sssc cccc cccc ccc';
- public const C_SA = 'SAkk bbcc cccc cccc cccc cccc';
+ public const _SA = 'SAkk bbcc cccc cccc cccc cccc';
- public const C_RS = 'RSkk bbbc cccc cccc cccc xx';
+ public const _RS = 'RSkk bbbc cccc cccc cccc xx';
- public const C_SK = 'SKkk bbbb ssss sscc cccc cccc';
+ public const _SK = 'SKkk bbbb ssss sscc cccc cccc';
- public const C_SI = 'SIkk bbss sccc cccc cxx';
+ public const _SI = 'SIkk bbss sccc cccc cxx';
- public const C_ES = 'ESkk bbbb ssss xxcc cccc cccc';
+ public const _ES = 'ESkk bbbb ssss xxcc cccc cccc';
- public const C_SE = 'SEkk bbbc cccc cccc cccc cccc';
+ public const _SE = 'SEkk bbbc cccc cccc cccc cccc';
- public const C_CH = 'CHkk bbbb bccc cccc cccc c';
+ public const _CH = 'CHkk bbbb bccc cccc cccc c';
- public const C_TN = 'TNkk bbss sccc cccc cccc cccc';
+ public const _TN = 'TNkk bbss sccc cccc cccc cccc';
- public const C_TR = 'TRkk bbbb bxcc cccc cccc cccc cc';
+ public const _TR = 'TRkk bbbb bxcc cccc cccc cccc cc';
- public const C_UA = 'UAkk bbbb bbcc cccc cccc cccc cccc c';
+ public const _UA = 'UAkk bbbb bbcc cccc cccc cccc cccc c';
- public const C_AE = 'AEkk bbbc cccc cccc cccc ccc';
+ public const _AE = 'AEkk bbbc cccc cccc cccc ccc';
- public const C_GB = 'GBkk bbbb ssss sscc cccc cc';
+ public const _GB = 'GBkk bbbb ssss sscc cccc cc';
- public const C_VG = 'VGkk bbbb cccc cccc cccc cccc';
+ public const _VG = 'VGkk bbbb cccc cccc cccc cccc';
- public const C_SN = 'SNkk annn nnnn nnnn nnnn nnnn nnnn';
+ public const _SN = 'SNkk annn nnnn nnnn nnnn nnnn nnnn';
- public const C_MZ = 'MZkk nnnn nnnn nnnn nnnn nnnn n';
+ public const _MZ = 'MZkk nnnn nnnn nnnn nnnn nnnn n';
- public const C_ML = 'MLkk annn nnnn nnnn nnnn nnnn nnnn';
+ public const _ML = 'MLkk annn nnnn nnnn nnnn nnnn nnnn';
- public const C_MG = 'MGkk nnnn nnnn nnnn nnnn nnnn nnn';
+ public const _MG = 'MGkk nnnn nnnn nnnn nnnn nnnn nnn';
- public const C_CI = 'CIkk annn nnnn nnnn nnnn nnnn nnnn';
+ public const _CI = 'CIkk annn nnnn nnnn nnnn nnnn nnnn';
- public const C_IR = 'IRkk nnnn nnnn nnnn nnnn nnnn nn';
+ public const _IR = 'IRkk nnnn nnnn nnnn nnnn nnnn nn';
- public const C_CV = 'CVkk nnnn nnnn nnnn nnnn nnnn n';
+ public const _CV = 'CVkk nnnn nnnn nnnn nnnn nnnn n';
- public const C_CM = 'CMkk nnnn nnnn nnnn nnnn nnnn nnn';
+ public const _CM = 'CMkk nnnn nnnn nnnn nnnn nnnn nnn';
- public const C_BI = 'BIkk nnnn nnnn nnnn';
+ public const _BI = 'BIkk nnnn nnnn nnnn';
- public const C_BF = 'BFkk nnnn nnnn nnnn nnnn nnnn nnn';
+ public const _BF = 'BFkk nnnn nnnn nnnn nnnn nnnn nnn';
- public const C_BJ = 'BJkk annn nnnn nnnn nnnn nnnn nnnn';
+ public const _BJ = 'BJkk annn nnnn nnnn nnnn nnnn nnnn';
- public const C_AO = 'AOkk nnnn nnnn nnnn nnnn nnnn n';
+ public const _AO = 'AOkk nnnn nnnn nnnn nnnn nnnn n';
- public const C_DZ = 'DZkk nnnn nnnn nnnn nnnn nnnn';
+ public const _DZ = 'DZkk nnnn nnnn nnnn nnnn nnnn';
}
diff --git a/Validation/Network/Email.php b/Validation/Network/Email.php
index edb68fb2f..81a6dc209 100755
--- a/Validation/Network/Email.php
+++ b/Validation/Network/Email.php
@@ -39,7 +39,7 @@ abstract class Email extends ValidatorAbstract
/**
* {@inheritdoc}
*/
- public static function isValid(mixed $value, array $constraints = null) : bool
+ public static function isValid(mixed $value, ?array $constraints = null) : bool
{
if (\filter_var($value, \FILTER_VALIDATE_EMAIL) === false) {
self::$msg = 'Invalid Email by filter_var standards';
diff --git a/Validation/Network/Hostname.php b/Validation/Network/Hostname.php
index 215c7bdc7..7b6aa25a5 100755
--- a/Validation/Network/Hostname.php
+++ b/Validation/Network/Hostname.php
@@ -39,9 +39,9 @@ abstract class Hostname extends ValidatorAbstract
/**
* {@inheritdoc}
*
- * A IPv6 string MUST be in [...] to be sucessfully validated
+ * A IPv6 string MUST be in [...] to be successfully validated
*/
- public static function isValid(mixed $value, array $constraints = null) : bool
+ public static function isValid(mixed $value, ?array $constraints = null) : bool
{
//return \filter_var(\gethostbyname($value), \FILTER_VALIDATE_IP) !== false;
diff --git a/Validation/Network/Ip.php b/Validation/Network/Ip.php
index b8a358f53..dafffce06 100755
--- a/Validation/Network/Ip.php
+++ b/Validation/Network/Ip.php
@@ -39,7 +39,7 @@ abstract class Ip extends ValidatorAbstract
/**
* {@inheritdoc}
*/
- public static function isValid(mixed $value, array $constraints = null) : bool
+ public static function isValid(mixed $value, ?array $constraints = null) : bool
{
return \filter_var($value, \FILTER_VALIDATE_IP) !== false;
}
diff --git a/Validation/Validator.php b/Validation/Validator.php
index bbc88455a..80d879cf7 100755
--- a/Validation/Validator.php
+++ b/Validation/Validator.php
@@ -38,7 +38,7 @@ final class Validator extends ValidatorAbstract
*
* @since 1.0.0
*/
- public static function isValid(mixed $var, array $constraints = null) : bool
+ public static function isValid(mixed $var, ?array $constraints = null) : bool
{
if ($constraints === null) {
return true;
diff --git a/Validation/ValidatorInterface.php b/Validation/ValidatorInterface.php
index 955cfa258..48b419fab 100755
--- a/Validation/ValidatorInterface.php
+++ b/Validation/ValidatorInterface.php
@@ -34,7 +34,7 @@ interface ValidatorInterface
*
* @since 1.0.0
*/
- public static function isValid(mixed $value, array $constraints = null) : bool;
+ public static function isValid(mixed $value, ?array $constraints = null) : bool;
/**
* Get most recent error string.
diff --git a/Views/View.php b/Views/View.php
index f9b743c0a..15863d165 100755
--- a/Views/View.php
+++ b/Views/View.php
@@ -98,7 +98,7 @@ class View extends ViewAbstract
*
* @since 1.0.0
*/
- public function __construct(L11nManager $l11n = null, RequestAbstract $request = null, ResponseAbstract $response = null)
+ public function __construct(?L11nManager $l11n = null, ?RequestAbstract $request = null, ?ResponseAbstract $response = null)
{
$this->l11nManager = $l11n ?? new L11nManager();
$this->request = $request;
@@ -201,7 +201,7 @@ class View extends ViewAbstract
*
* @since 1.0.0
*/
- public function getText(string $translation, string $module = null, string $theme = null) : string
+ public function getText(string $translation, ?string $module = null, ?string $theme = null) : string
{
if ($module === null && $this->module === null) {
$this->setModuleDynamically();
@@ -302,7 +302,7 @@ class View extends ViewAbstract
*
* @since 1.0.0
*/
- public function getHtml(string $translation, string $module = null, string $theme = null) : string
+ public function getHtml(string $translation, ?string $module = null, ?string $theme = null) : string
{
return \htmlspecialchars($this->getText($translation, $module, $theme));
}
@@ -317,7 +317,7 @@ class View extends ViewAbstract
*
* @since 1.0.0
*/
- public function getNumeric(int | float | FloatInt $numeric, string $format = null) : string
+ public function getNumeric(int | float | FloatInt $numeric, ?string $format = null) : string
{
return $this->l11nManager->getNumeric($this->l11n, $numeric, $format);
}
@@ -325,14 +325,14 @@ class View extends ViewAbstract
/**
* Print a percentage value
*
- * @param float $percentage Percentage value to print
- * @param null|string $format Format type to use
+ * @param float|FloatInt $percentage Percentage value to print
+ * @param null|string $format Format type to use
*
* @return string
*
* @since 1.0.0
*/
- public function getPercentage(float $percentage, string $format = null) : string
+ public function getPercentage(float | FloatInt $percentage, ?string $format = null) : string
{
return $this->l11nManager->getPercentage($this->l11n, $percentage, $format);
}
@@ -351,8 +351,8 @@ class View extends ViewAbstract
*/
public function getCurrency(
int | float | Money | FloatInt $currency,
- string $symbol = null,
- string $format = null,
+ ?string $symbol = null,
+ ?string $format = null,
int $divide = 1
) : string
{
@@ -369,7 +369,7 @@ class View extends ViewAbstract
*
* @since 1.0.0
*/
- public function getDateTime(\DateTimeInterface $datetime = null, string $format = null) : string
+ public function getDateTime(?\DateTimeInterface $datetime = null, ?string $format = null) : string
{
return $this->l11nManager->getDateTime($this->l11n, $datetime, $format);
}
diff --git a/Views/ViewAbstract.php b/Views/ViewAbstract.php
index d39ca6b64..f218c0274 100755
--- a/Views/ViewAbstract.php
+++ b/Views/ViewAbstract.php
@@ -32,7 +32,7 @@ abstract class ViewAbstract implements RenderableInterface
* @var string
* @since 1.0.0
*/
- protected const BASE_PATH = __DIR__ . '/../..';
+ public const BASE_PATH = __DIR__ . '/../..';
/**
* Output is buffered
@@ -230,7 +230,7 @@ abstract class ViewAbstract implements RenderableInterface
}
/**
- * Arrayify view and it's subviews.
+ * Arrayify view and it's sub-views.
*
* @return array
*
diff --git a/preload.php b/preload.php
index 6f719dcad..9d94e5a8e 100755
--- a/preload.php
+++ b/preload.php
@@ -4,7 +4,7 @@
*
* PHP Version 8.1
*
- * @package Karaka
+ * @package Jingga
* @copyright Dennis Eichhorn
* @license OMS License 2.0
* @version 1.0.0
diff --git a/tests/Account/AccountManagerTest.php b/tests/Account/AccountManagerTest.php
index bc1e19090..63c6ea074 100755
--- a/tests/Account/AccountManagerTest.php
+++ b/tests/Account/AccountManagerTest.php
@@ -73,7 +73,7 @@ final class AccountManagerTest extends \PHPUnit\Framework\TestCase
public function testRetrieveAccount() : void
{
$this->manager->add($this->account);
- self::assertEquals($this->account, $this->manager->get($this->account->getId()));
+ self::assertEquals($this->account, $this->manager->get($this->account->id));
}
/**
@@ -87,7 +87,7 @@ final class AccountManagerTest extends \PHPUnit\Framework\TestCase
$added = $this->manager->add($this->account);
self::assertFalse($added);
- self::assertTrue($this->manager->remove($this->account->getId()));
+ self::assertTrue($this->manager->remove($this->account->id));
self::assertFalse($this->manager->remove(-1));
self::assertEquals(0, $this->manager->count());
}
@@ -100,7 +100,7 @@ final class AccountManagerTest extends \PHPUnit\Framework\TestCase
public function testRemoveAccount() : void
{
$this->manager->add($this->account);
- self::assertTrue($this->manager->remove($this->account->getId()));
+ self::assertTrue($this->manager->remove($this->account->id));
self::assertEquals(0, $this->manager->count());
self::assertFalse($this->manager->remove(-1));
}
@@ -115,7 +115,7 @@ final class AccountManagerTest extends \PHPUnit\Framework\TestCase
$this->manager->add($this->account);
self::assertFalse($this->manager->remove(-1));
self::assertEquals(1, $this->manager->count());
- self::assertTrue($this->manager->remove($this->account->getId()));
+ self::assertTrue($this->manager->remove($this->account->id));
self::assertEquals(0, $this->manager->count());
}
}
diff --git a/tests/Account/AccountTest.php b/tests/Account/AccountTest.php
index 130d2c571..99891fb9e 100755
--- a/tests/Account/AccountTest.php
+++ b/tests/Account/AccountTest.php
@@ -53,8 +53,8 @@ final class AccountTest extends \PHPUnit\Framework\TestCase
$account = new Account();
/* Testing default values */
- self::assertIsInt($account->getId());
- self::assertEquals(0, $account->getId());
+ self::assertIsInt($account->id);
+ self::assertEquals(0, $account->id);
self::assertInstanceOf('\phpOMS\Localization\Localization', $account->l11n);
@@ -74,11 +74,11 @@ final class AccountTest extends \PHPUnit\Framework\TestCase
self::assertIsString($account->getEmail());
self::assertEquals('', $account->getEmail());
- self::assertIsInt($account->getStatus());
- self::assertEquals(AccountStatus::INACTIVE, $account->getStatus());
+ self::assertIsInt($account->status);
+ self::assertEquals(AccountStatus::INACTIVE, $account->status);
- self::assertIsInt($account->getType());
- self::assertEquals(AccountType::USER, $account->getType());
+ self::assertIsInt($account->type);
+ self::assertEquals(AccountType::USER, $account->type);
self::assertEquals([], $account->getPermissions());
self::assertFalse($account->hasGroup(2));
@@ -145,34 +145,6 @@ final class AccountTest extends \PHPUnit\Framework\TestCase
self::assertEquals('d.duck@duckburg.com', $account->getEmail());
}
- /**
- * @testdox The default status of the account can be changed to a different valid status
- * @covers phpOMS\Account\Account
- * @group framework
- */
- public function testChangeStatus() : void
- {
- $account = new Account();
- $account->generatePassword('abcd');
-
- $account->setStatus(AccountStatus::ACTIVE);
- self::assertEquals(AccountStatus::ACTIVE, $account->getStatus());
- }
-
- /**
- * @testdox The default type of the account can be changed to a different valid type
- * @covers phpOMS\Account\Account
- * @group framework
- */
- public function testChangeType() : void
- {
- $account = new Account();
- $account->generatePassword('abcd');
-
- $account->setType(AccountType::GROUP);
- self::assertEquals(AccountType::GROUP, $account->getType());
- }
-
/**
* @testdox Account permissions can be added
* @covers phpOMS\Account\Account
@@ -293,40 +265,4 @@ final class AccountTest extends \PHPUnit\Framework\TestCase
$account = new Account();
$account->setEmail('d.duck!@#%@duckburg');
}
-
- /**
- * @testdox An account can only have valid account status
- * @group framework
- */
- public function testStatusException() : void
- {
- $this->expectException(\phpOMS\Stdlib\Base\Exception\InvalidEnumValue::class);
-
- $account = new Account();
-
- $rand = 0;
- do {
- $rand = \mt_rand(\PHP_INT_MIN, \PHP_INT_MAX);
- } while (AccountStatus::isValidValue($rand));
-
- $account->setStatus($rand);
- }
-
- /**
- * @testdox An account can only have valid account types
- * @group framework
- */
- public function testTypeException() : void
- {
- $this->expectException(\phpOMS\Stdlib\Base\Exception\InvalidEnumValue::class);
-
- $account = new Account();
-
- $rand = 0;
- do {
- $rand = \mt_rand(\PHP_INT_MIN, \PHP_INT_MAX);
- } while (AccountType::isValidValue($rand));
-
- $account->setType($rand);
- }
}
diff --git a/tests/Account/GroupTest.php b/tests/Account/GroupTest.php
index f55bbd427..a6d4c36c7 100755
--- a/tests/Account/GroupTest.php
+++ b/tests/Account/GroupTest.php
@@ -38,14 +38,14 @@ final class GroupTest extends \PHPUnit\Framework\TestCase
$group = new Group();
/* Testing default values */
- self::assertIsInt($group->getId());
- self::assertEquals(0, $group->getId());
+ self::assertIsInt($group->id);
+ self::assertEquals(0, $group->id);
self::assertIsString($group->name);
self::assertEquals('', $group->name);
- self::assertIsInt($group->getStatus());
- self::assertEquals(GroupStatus::INACTIVE, $group->getStatus());
+ self::assertIsInt($group->status);
+ self::assertEquals(GroupStatus::INACTIVE, $group->status);
self::assertIsString($group->description);
self::assertEquals('', $group->description);
@@ -138,36 +138,4 @@ final class GroupTest extends \PHPUnit\Framework\TestCase
$group->removePermission($perm);
self::assertCount(0, $group->getPermissions());
}
-
- /**
- * @testdox The default status of the group can be changed to a different valid status
- * @covers phpOMS\Account\Group
- * @group framework
- */
- public function testChangeStatus() : void
- {
- $group = new Group();
-
- $group->setStatus(GroupStatus::ACTIVE);
- self::assertEquals(GroupStatus::ACTIVE, $group->getStatus());
- }
-
- /**
- * @testdox A group can only have valid group status
- * @covers phpOMS\Account\Group
- * @group framework
- */
- public function testStatusException() : void
- {
- $this->expectException(\phpOMS\Stdlib\Base\Exception\InvalidEnumValue::class);
-
- $group = new Group();
-
- $rand = 0;
- do {
- $rand = \mt_rand(\PHP_INT_MIN, \PHP_INT_MAX);
- } while (GroupStatus::isValidValue($rand));
-
- $group->setStatus($rand);
- }
}
diff --git a/tests/Account/NullAccountTest.php b/tests/Account/NullAccountTest.php
index f3c5e5470..e08f6c07e 100755
--- a/tests/Account/NullAccountTest.php
+++ b/tests/Account/NullAccountTest.php
@@ -42,7 +42,7 @@ final class NullAccountTest extends \PHPUnit\Framework\TestCase
public function testId() : void
{
$null = new NullAccount(2);
- self::assertEquals(2, $null->getId());
+ self::assertEquals(2, $null->id);
}
public function testJsonSerialization() : void
diff --git a/tests/Account/NullGroupTest.php b/tests/Account/NullGroupTest.php
index 39694ba93..03e4738e3 100755
--- a/tests/Account/NullGroupTest.php
+++ b/tests/Account/NullGroupTest.php
@@ -42,7 +42,7 @@ final class NullGroupTest extends \PHPUnit\Framework\TestCase
public function testId() : void
{
$null = new NullGroup(2);
- self::assertEquals(2, $null->getId());
+ self::assertEquals(2, $null->id);
}
public function testJsonSerialization() : void
diff --git a/tests/Algorithm/Frequency/AprioriTest.php b/tests/Algorithm/Frequency/AprioriTest.php
new file mode 100644
index 000000000..fe998058b
--- /dev/null
+++ b/tests/Algorithm/Frequency/AprioriTest.php
@@ -0,0 +1,115 @@
+ 2,
+ 'epsilon' => 2,
+ 'epsilon:theta' => 0,
+ 'beta' => 4,
+ 'beta:theta' => 2,
+ 'beta:epsilon' => 2,
+ 'beta:epsilon:theta' => 0,
+ 'alpha' => 4,
+ 'alpha:theta' => 2,
+ 'alpha:epsilon' => 2,
+ 'alpha:epsilon:theta' => 0,
+ 'alpha:beta' => 4,
+ 'alpha:beta:theta' => 2,
+ 'alpha:beta:epsilon' => 2,
+ 'alpha:beta:epsilon:theta' => 0,
+ ],
+ Apriori::apriori([
+ ['alpha', 'beta', 'epsilon'],
+ ['alpha', 'beta', 'theta'],
+ ['alpha', 'beta', 'epsilon'],
+ ['alpha', 'beta', 'theta'],
+ ])
+ );
+
+ self::assertEquals(
+ [
+ '4' => 5,
+ '3' => 3,
+ '3:4' => 3,
+ '2' => 5,
+ '2:4' => 4,
+ '2:3' => 2,
+ '2:3:4' => 2,
+ '1' => 3,
+ '1:4' => 2,
+ '1:3' => 1,
+ '1:3:4' => 1,
+ '1:2' => 3,
+ '1:2:4' => 2,
+ '1:2:3' => 1,
+ '1:2:3:4' => 1,
+ ],
+ Apriori::apriori([
+ ['1', '2', '3', '4'],
+ ['1', '2', '4'],
+ ['1', '2'],
+ ['2', '3', '4'],
+ ['3', '4'],
+ ['2', '4'],
+ ])
+ );
+ }
+
+ public function testAprioriSubset() : void
+ {
+ self::assertEquals(
+ ['beta:theta' => 2],
+ Apriori::apriori(
+ [
+ ['alpha', 'beta', 'epsilon'],
+ ['alpha', 'beta', 'theta'],
+ ['alpha', 'beta', 'epsilon'],
+ ['alpha', 'beta', 'theta'],
+ ],
+ ['beta', 'theta']
+ )
+ );
+
+ self::assertEquals(
+ ['2:3' => 2],
+ Apriori::apriori(
+ [
+ ['1', '2', '3', '4'],
+ ['1', '2', '4'],
+ ['1', '2'],
+ ['2', '3', '4'],
+ ['3', '4'],
+ ['2', '4'],
+ ],
+ ['2', '3']
+ )
+ );
+ }
+}
diff --git a/tests/Algorithm/Graph/DependencyResolverTest.php b/tests/Algorithm/Graph/DependencyResolverTest.php
new file mode 100644
index 000000000..eeab355b6
--- /dev/null
+++ b/tests/Algorithm/Graph/DependencyResolverTest.php
@@ -0,0 +1,50 @@
+ [1, 2], 1 => [0, 2], 2 => []])
+ );
+ }
+
+ /**
+ * @covers phpOMS\Algorithm\Graph\DependencyResolver
+ * @group framework
+ */
+ public function testResolve() : void
+ {
+ self::assertEquals(
+ [2, 3, 1, 0],
+ DependencyResolver::resolve([0 => [1, 2], 1 => [2, 3], 2 => [], 3 => []])
+ );
+ }
+}
diff --git a/tests/Algorithm/Graph/MarkovChainTest.php b/tests/Algorithm/Graph/MarkovChainTest.php
new file mode 100644
index 000000000..0521dc2d5
--- /dev/null
+++ b/tests/Algorithm/Graph/MarkovChainTest.php
@@ -0,0 +1,105 @@
+setTraining(
+ [
+ 'A' => ['A' => 0.1, 'C' => 0.6, 'E' => 0.3],
+ 'C' => ['A' => 0.25, 'C' => 0.05, 'E' => 0.7],
+ 'E' => ['A' => 0.7, 'C' => 0.3, 'E' => 0.0],
+ ]
+ );
+
+ self::assertEquals(3, \count($markov->generate(3, ['A'])));
+ }
+
+ /**
+ * @covers phpOMS\Algorithm\Graph\MarkovChain
+ * @group framework
+ */
+ public function testTrainingGenerate() : void
+ {
+ $markov = new MarkovChain();
+ $markov->train(['A', 'C', 'E', 'A', 'C', 'E', 'E', 'C', 'A', 'A', 'E', 'A']);
+
+ self::assertEquals(5, \count($markov->generate(5, ['A'])));
+ }
+
+ /**
+ * @covers phpOMS\Algorithm\Graph\MarkovChain
+ * @group framework
+ */
+ public function testStepProbability() : void
+ {
+ $markov = new MarkovChain(2);
+ $markov->setTraining(
+ [
+ 'A A' => ['A' => 0.18, 'D' => 0.6, 'G' => 0.22],
+ 'A D' => ['A' => 0.5, 'D' => 0.5, 'G' => 0.0],
+ 'A G' => ['A' => 0.15, 'D' => 0.75, 'G' => 0.1],
+ 'D D' => ['A' => 0.0, 'D' => 0.0, 'G' => 1.0],
+ 'D A' => ['A' => 0.25, 'D' => 0.0, 'G' => 0.75],
+ 'D G' => ['A' => 0.9, 'D' => 0.1, 'G' => 0.0],
+ 'G G' => ['A' => 0.4, 'D' => 0.4, 'G' => 0.2],
+ 'G A' => ['A' => 0.5, 'D' => 0.25, 'G' => 0.25],
+ 'G D' => ['A' => 1.0, 'D' => 0.0, 'G' => 0.0],
+ ]
+ );
+
+ self::assertEquals(0.1, $markov->stepProbability(['D', 'G'], 'D'));
+ }
+
+ /**
+ * @covers phpOMS\Algorithm\Graph\MarkovChain
+ * @group framework
+ */
+ public function testPathProbability() : void
+ {
+ $markov = new MarkovChain(2);
+ $markov->setTraining(
+ [
+ 'A A' => ['A' => 0.18, 'D' => 0.6, 'G' => 0.22],
+ 'A D' => ['A' => 0.5, 'D' => 0.5, 'G' => 0.0],
+ 'A G' => ['A' => 0.15, 'D' => 0.75, 'G' => 0.1],
+ 'D D' => ['A' => 0.0, 'D' => 0.0, 'G' => 1.0],
+ 'D A' => ['A' => 0.25, 'D' => 0.0, 'G' => 0.75],
+ 'D G' => ['A' => 0.9, 'D' => 0.1, 'G' => 0.0],
+ 'G G' => ['A' => 0.4, 'D' => 0.4, 'G' => 0.2],
+ 'G A' => ['A' => 0.5, 'D' => 0.25, 'G' => 0.25],
+ 'G D' => ['A' => 1.0, 'D' => 0.0, 'G' => 0.0],
+ ]
+ );
+
+ self::assertEquals(0.9 * 0.5 * 0.6, $markov->pathProbability(['D', 'G', 'A', 'A', 'D']));
+ }
+}
diff --git a/tests/Algorithm/JobScheduling/WeightedTest.php b/tests/Algorithm/JobScheduling/WeightedTest.php
index fa7bd0412..69ce8908f 100755
--- a/tests/Algorithm/JobScheduling/WeightedTest.php
+++ b/tests/Algorithm/JobScheduling/WeightedTest.php
@@ -46,7 +46,7 @@ final class WeightedTest extends \PHPUnit\Framework\TestCase
$names = [];
foreach ($filtered as $job) {
- $value += $job->getValue();
+ $value += $job->getValue();
$names[] = $job->name;
}
diff --git a/tests/Api/Geocoding/NominatimTest.php b/tests/Api/Geocoding/NominatimTest.php
new file mode 100644
index 000000000..2d12e42fc
--- /dev/null
+++ b/tests/Api/Geocoding/NominatimTest.php
@@ -0,0 +1,46 @@
+ 50.3050738,
+ 'lon' => 8.688465172531158,
+ ],
+ Nominatim::geocoding('de', 'Rosbach', 'Kirchstraße 33'),
+ 0.01
+ );
+
+ self::assertEqualsWithDelta(
+ [
+ 'lat' => 50.3050738,
+ 'lon' => 8.688465172531158,
+ ],
+ Nominatim::geocoding('de', 'Rosbach', 'Kirchstraße 33', '61191'),
+ 0.01
+ );
+ }
+}
diff --git a/tests/Application/ApplicationInfoTest.php b/tests/Application/ApplicationInfoTest.php
index 427fe5a3e..6af83db67 100755
--- a/tests/Application/ApplicationInfoTest.php
+++ b/tests/Application/ApplicationInfoTest.php
@@ -111,7 +111,7 @@ final class ApplicationInfoTest extends \PHPUnit\Framework\TestCase
$info = new ApplicationInfo(__DIR__ . '/info-test.json');
$info->load();
- $testObj = new class() {
+ $testObj = new class() {
public $test = 1;
public function test() : void
diff --git a/tests/Application/ApplicationManagerTest.php b/tests/Application/ApplicationManagerTest.php
index 6c594c4e1..aac7e3318 100755
--- a/tests/Application/ApplicationManagerTest.php
+++ b/tests/Application/ApplicationManagerTest.php
@@ -49,7 +49,7 @@ final class ApplicationManagerTest extends \PHPUnit\Framework\TestCase
*/
protected function setUp() : void
{
- $app = new class() extends ApplicationAbstract {
+ $app = new class() extends ApplicationAbstract {
protected string $appName = 'Api';
};
@@ -62,12 +62,12 @@ final class ApplicationManagerTest extends \PHPUnit\Framework\TestCase
public function get(
mixed $ids = null,
- string | array $names = null,
- int $unit = null,
- int $app = null,
- string $module = null,
- int $group = null,
- int $account = null
+ string | array|null $names = null,
+ ?int $unit = null,
+ ?int $app = null,
+ ?string $module = null,
+ ?int $group = null,
+ ?int $account = null
) : mixed {
return '';
}
@@ -172,7 +172,7 @@ final class ApplicationManagerTest extends \PHPUnit\Framework\TestCase
}
/**
- * @testdox A invalid application path results in no uninstallation
+ * @testdox A invalid application path results in no uninstall
* @covers phpOMS\Application\ApplicationManager
* @group framework
*/
@@ -183,7 +183,7 @@ final class ApplicationManagerTest extends \PHPUnit\Framework\TestCase
}
/**
- * @testdox A missing uninstallation file results in no uninstallation
+ * @testdox A missing uninstall file results in no uninstall
* @covers phpOMS\Application\ApplicationManager
* @group framework
*/
diff --git a/tests/Application/InstallerAbstractTest.php b/tests/Application/InstallerAbstractTest.php
index d06211f77..0cdba868d 100755
--- a/tests/Application/InstallerAbstractTest.php
+++ b/tests/Application/InstallerAbstractTest.php
@@ -32,7 +32,7 @@ final class InstallerAbstractTest extends \PHPUnit\Framework\TestCase
*/
protected function setUp() : void
{
- $this->installer = new class() extends InstallerAbstract {
+ $this->installer = new class() extends InstallerAbstract {
public const PATH = __DIR__ . '/Invalid';
};
}
diff --git a/tests/Application/Testapp/Admin/Install/Application/Routes.php b/tests/Application/Testapp/Admin/Install/Application/Routes.php
index 8bfccbeab..8ca42bfe7 100755
--- a/tests/Application/Testapp/Admin/Install/Application/Routes.php
+++ b/tests/Application/Testapp/Admin/Install/Application/Routes.php
@@ -15,13 +15,13 @@ declare(strict_types=1);
use phpOMS\Router\RouteVerb;
return [
- '^.*/testapp.*$' => [
+ '^.*/testapp(\?.*$|$)' => [
[
'dest' => '\phpOMS\tess\Application\Apps\Testapp\Controller\Controller:testEndpoint',
'verb' => RouteVerb::GET,
'permission' => [
- 'type' => 1,
- 'state' => 2,
+ 'type' => 1,
+ 'state' => 2,
],
],
],
diff --git a/tests/Application/Testapp/info.json b/tests/Application/Testapp/info.json
index d079e1e00..96bc7c4f2 100755
--- a/tests/Application/Testapp/info.json
+++ b/tests/Application/Testapp/info.json
@@ -14,7 +14,6 @@
"name": "Jingga",
"website": "jingga.app"
},
- "description": "The administration module.",
"directory": "Admin",
"providing": {
"Navigation": "*",
diff --git a/tests/Application/info-test.json b/tests/Application/info-test.json
index bb4cc9cba..8b8fe302f 100755
--- a/tests/Application/info-test.json
+++ b/tests/Application/info-test.json
@@ -14,7 +14,6 @@
"name": "Jingga",
"website": "jingga.app"
},
- "description": "The administration module.",
"directory": "Admin",
"providing": {
"Navigation": "*"
diff --git a/tests/Autoloader.php b/tests/Autoloader.php
index 6e249662d..95dd1b74c 100755
--- a/tests/Autoloader.php
+++ b/tests/Autoloader.php
@@ -75,8 +75,8 @@ class Autoloader
*/
public static function defaultAutoloader(string $class) : void
{
- $class = \ltrim($class, '\\');
- $class = \strtr($class, '_\\', '//');
+ $class = \ltrim($class, '\\');
+ $class = \strtr($class, '_\\', '//');
if (\stripos($class, 'Web/Backend') !== false || \stripos($class, 'Web/Api') !== false) {
$class = \is_dir(__DIR__ . '/Web') ? $class : \str_replace('Web/', 'MainRepository/Web/', $class);
diff --git a/tests/Bootstrap.php b/tests/Bootstrap.php
index 1b48ed57b..44c8a78a9 100755
--- a/tests/Bootstrap.php
+++ b/tests/Bootstrap.php
@@ -1,4 +1,15 @@
[
+ 'db' => [
'core' => [
'masters' => [
- 'admin' => [
+ 'admin' => [
'db' => 'mysql', /* db type */
'host' => '127.0.0.1', /* db host address */
'port' => '3306', /* db host port */
@@ -80,7 +91,7 @@ $CONFIG = [
'weight' => 1000, /* db table prefix */
'datetimeformat' => 'Y-m-d H:i:s',
],
- 'insert' => [
+ 'insert' => [
'db' => 'mysql', /* db type */
'host' => '127.0.0.1', /* db host address */
'port' => '3306', /* db host port */
@@ -90,7 +101,7 @@ $CONFIG = [
'weight' => 1000, /* db table prefix */
'datetimeformat' => 'Y-m-d H:i:s',
],
- 'select' => [
+ 'select' => [
'db' => 'mysql', /* db type */
'host' => '127.0.0.1', /* db host address */
'port' => '3306', /* db host port */
@@ -100,7 +111,7 @@ $CONFIG = [
'weight' => 1000, /* db table prefix */
'datetimeformat' => 'Y-m-d H:i:s',
],
- 'update' => [
+ 'update' => [
'db' => 'mysql', /* db type */
'host' => '127.0.0.1', /* db host address */
'port' => '3306', /* db host port */
@@ -110,7 +121,7 @@ $CONFIG = [
'weight' => 1000, /* db table prefix */
'datetimeformat' => 'Y-m-d H:i:s',
],
- 'delete' => [
+ 'delete' => [
'db' => 'mysql', /* db type */
'host' => '127.0.0.1', /* db host address */
'port' => '3306', /* db host port */
@@ -120,7 +131,7 @@ $CONFIG = [
'weight' => 1000, /* db table prefix */
'datetimeformat' => 'Y-m-d H:i:s',
],
- 'schema' => [
+ 'schema' => [
'db' => 'mysql', /* db type */
'host' => '127.0.0.1', /* db host address */
'port' => '3306', /* db host port */
@@ -132,7 +143,7 @@ $CONFIG = [
],
],
'postgresql' => [
- 'admin' => [
+ 'admin' => [
'db' => 'pgsql', /* db type */
'host' => '127.0.0.1', /* db host address */
'port' => '5432', /* db host port */
@@ -142,7 +153,7 @@ $CONFIG = [
'weight' => 1000, /* db table prefix */
'datetimeformat' => 'Y-m-d H:i:s',
],
- 'insert' => [
+ 'insert' => [
'db' => 'pgsql', /* db type */
'host' => '127.0.0.1', /* db host address */
'port' => '5432', /* db host port */
@@ -152,7 +163,7 @@ $CONFIG = [
'weight' => 1000, /* db table prefix */
'datetimeformat' => 'Y-m-d H:i:s',
],
- 'select' => [
+ 'select' => [
'db' => 'pgsql', /* db type */
'host' => '127.0.0.1', /* db host address */
'port' => '5432', /* db host port */
@@ -162,7 +173,7 @@ $CONFIG = [
'weight' => 1000, /* db table prefix */
'datetimeformat' => 'Y-m-d H:i:s',
],
- 'update' => [
+ 'update' => [
'db' => 'pgsql', /* db type */
'host' => '127.0.0.1', /* db host address */
'port' => '5432', /* db host port */
@@ -172,7 +183,7 @@ $CONFIG = [
'weight' => 1000, /* db table prefix */
'datetimeformat' => 'Y-m-d H:i:s',
],
- 'delete' => [
+ 'delete' => [
'db' => 'pgsql', /* db type */
'host' => '127.0.0.1', /* db host address */
'port' => '5432', /* db host port */
@@ -182,7 +193,7 @@ $CONFIG = [
'weight' => 1000, /* db table prefix */
'datetimeformat' => 'Y-m-d H:i:s',
],
- 'schema' => [
+ 'schema' => [
'db' => 'pgsql', /* db type */
'host' => '127.0.0.1', /* db host address */
'port' => '5432', /* db host port */
@@ -194,37 +205,37 @@ $CONFIG = [
],
],
'sqlite' => [
- 'admin' => [
+ 'admin' => [
'db' => 'sqlite', /* db type */
'database' => __DIR__ . '/../Localization/Defaults/localization.sqlite', /* db name */
'weight' => 1000, /* db table prefix */
'datetimeformat' => 'Y-m-d H:i:s',
],
- 'insert' => [
+ 'insert' => [
'db' => 'sqlite', /* db type */
'database' => __DIR__ . '/../Localization/Defaults/localization.sqlite', /* db name */
'weight' => 1000, /* db table prefix */
'datetimeformat' => 'Y-m-d H:i:s',
],
- 'select' => [
+ 'select' => [
'db' => 'sqlite', /* db type */
'database' => __DIR__ . '/../Localization/Defaults/localization.sqlite', /* db name */
'weight' => 1000, /* db table prefix */
'datetimeformat' => 'Y-m-d H:i:s',
],
- 'update' => [
+ 'update' => [
'db' => 'sqlite', /* db type */
'database' => __DIR__ . '/../Localization/Defaults/localization.sqlite', /* db name */
'weight' => 1000, /* db table prefix */
'datetimeformat' => 'Y-m-d H:i:s',
],
- 'delete' => [
+ 'delete' => [
'db' => 'sqlite', /* db type */
'database' => __DIR__ . '/../Localization/Defaults/localization.sqlite', /* db name */
'weight' => 1000, /* db table prefix */
'datetimeformat' => 'Y-m-d H:i:s',
],
- 'schema' => [
+ 'schema' => [
'db' => 'sqlite', /* db type */
'database' => __DIR__ . '/../Localization/Defaults/localization.sqlite', /* db name */
'weight' => 1000, /* db table prefix */
@@ -232,7 +243,7 @@ $CONFIG = [
],
],
'mssql' => [
- 'admin' => [
+ 'admin' => [
'db' => 'mssql', /* db type */
'host' => 'localhost', /* db host address */
'port' => '1433', /* db host port */
@@ -242,7 +253,7 @@ $CONFIG = [
'weight' => 1000, /* db table prefix */
'datetimeformat' => 'Y-m-d H:i:s',
],
- 'insert' => [
+ 'insert' => [
'db' => 'mssql', /* db type */
'host' => 'localhost', /* db host address */
'port' => '1433', /* db host port */
@@ -252,7 +263,7 @@ $CONFIG = [
'weight' => 1000, /* db table prefix */
'datetimeformat' => 'Y-m-d H:i:s',
],
- 'select' => [
+ 'select' => [
'db' => 'mssql', /* db type */
'host' => 'localhost', /* db host address */
'port' => '1433', /* db host port */
@@ -262,7 +273,7 @@ $CONFIG = [
'weight' => 1000, /* db table prefix */
'datetimeformat' => 'Y-m-d H:i:s',
],
- 'update' => [
+ 'update' => [
'db' => 'mssql', /* db type */
'host' => 'localhost', /* db host address */
'port' => '1433', /* db host port */
@@ -272,7 +283,7 @@ $CONFIG = [
'weight' => 1000, /* db table prefix */
'datetimeformat' => 'Y-m-d H:i:s',
],
- 'delete' => [
+ 'delete' => [
'db' => 'mssql', /* db type */
'host' => 'localhost', /* db host address */
'port' => '1433', /* db host port */
@@ -282,7 +293,7 @@ $CONFIG = [
'weight' => 1000, /* db table prefix */
'datetimeformat' => 'Y-m-d H:i:s',
],
- 'schema' => [
+ 'schema' => [
'db' => 'mssql', /* db type */
'host' => 'localhost', /* db host address */
'port' => '1433', /* db host port */
@@ -322,16 +333,16 @@ $CONFIG = [
'password' => '123456',
],
],
- 'log' => [
+ 'log' => [
'file' => [
'path' => __DIR__ . '/Logs',
],
],
- 'page' => [
+ 'page' => [
'root' => '/',
'https' => false,
],
- 'app' => [
+ 'app' => [
'path' => __DIR__,
'default' => [
'app' => 'Backend',
@@ -350,7 +361,7 @@ $CONFIG = [
],
],
],
- 'socket' => [
+ 'socket' => [
'master' => [
'host' => '127.0.0.1',
'limit' => 300,
@@ -360,7 +371,7 @@ $CONFIG = [
'language' => [
'en',
],
- 'apis' => [
+ 'apis' => [
],
];
diff --git a/tests/Business/Finance/FinanceFormulasTest.php b/tests/Business/Finance/FinanceFormulasTest.php
index 54d2b1b59..dcf12e886 100755
--- a/tests/Business/Finance/FinanceFormulasTest.php
+++ b/tests/Business/Finance/FinanceFormulasTest.php
@@ -121,13 +121,13 @@ final class FinanceFormulasTest extends \PHPUnit\Framework\TestCase
* @covers phpOMS\Business\Finance\FinanceFormulas
* @group framework
*/
- public function testAnnutiyPaymentFactorPV() : void
+ public function testAnnuityPaymentFactorPV() : void
{
$expected = 0.21216;
$r = 0.02;
$n = 5;
- $p = FinanceFormulas::getAnnutiyPaymentFactorPV($r, $n);
+ $p = FinanceFormulas::getAnnuityPaymentFactorPV($r, $n);
self::assertEqualsWithDelta(\round($expected, 5), \round($p, 5), 0.01);
self::assertEqualsWithDelta($n, FinanceFormulas::getNumberOfAPFPV($p, $r), 0.01);
@@ -314,8 +314,8 @@ final class FinanceFormulasTest extends \PHPUnit\Framework\TestCase
$C = \round(FinanceFormulas::getCompoundInterest($P, $r, $t), 2);
self::assertEqualsWithDelta(\round($expected, 2), $C, 0.01);
- self::assertEqualsWithDelta($P, FinanceFormulas::getPrincipalOfCompundInterest($C, $r, $t), 0.1);
- self::assertEqualsWithDelta($t, (int) \round(FinanceFormulas::getPeriodsOfCompundInterest($P, $C, $r), 0), 0.01);
+ self::assertEqualsWithDelta($P, FinanceFormulas::getPrincipalOfCompoundInterest($C, $r, $t), 0.1);
+ self::assertEqualsWithDelta($t, (int) \round(FinanceFormulas::getPeriodsOfCompoundInterest($P, $C, $r), 0), 0.01);
}
/**
diff --git a/tests/Business/Recommendation/BayesianPersonalizedRankingTest.php b/tests/Business/Recommendation/BayesianPersonalizedRankingTest.php
new file mode 100644
index 000000000..f8ed76a2e
--- /dev/null
+++ b/tests/Business/Recommendation/BayesianPersonalizedRankingTest.php
@@ -0,0 +1,24 @@
+ [1.0, 2.0],
+ 'B' => [2.0, 4.0],
+ 'C' => [2.5, 4.0],
+ 'D' => [4.5, 5.0],
+ ]);
+
+ self::assertEquals(
+ ['B', 'C'],
+ $memory->bestMatch([2.2, 4.1], 2)
+ );
+ }
+}
diff --git a/tests/Business/Recommendation/ModelCFTest.php b/tests/Business/Recommendation/ModelCFTest.php
new file mode 100644
index 000000000..4e10ac810
--- /dev/null
+++ b/tests/Business/Recommendation/ModelCFTest.php
@@ -0,0 +1,48 @@
+cache->get('test'));
self::assertEquals(
[
- 'status' => CacheStatus::OK,
- 'count' => 0,
- 'size' => 0,
+ 'status' => CacheStatus::OK,
+ 'count' => 0,
+ 'size' => 0,
],
$this->cache->stats()
);
@@ -237,7 +237,7 @@ final class FileCacheTest extends \PHPUnit\Framework\TestCase
self::assertEquals([], $this->cache->getLike('key\d'));
}
- public function testExpiredDelteLike() : void
+ public function testExpiredDeleteLike() : void
{
$this->cache->set('key1', 'testVal1', 2);
$this->cache->set('key2', 'testVal2', 2);
@@ -339,9 +339,9 @@ final class FileCacheTest extends \PHPUnit\Framework\TestCase
self::assertEquals(
[
- 'status' => CacheStatus::OK,
- 'count' => 2,
- 'size' => 17,
+ 'status' => CacheStatus::OK,
+ 'count' => 2,
+ 'size' => 17,
],
$this->cache->stats()
);
@@ -365,9 +365,9 @@ final class FileCacheTest extends \PHPUnit\Framework\TestCase
self::assertEquals(
[
- 'status' => CacheStatus::OK,
- 'count' => 0,
- 'size' => 0,
+ 'status' => CacheStatus::OK,
+ 'count' => 0,
+ 'size' => 0,
],
$this->cache->stats()
);
diff --git a/tests/DataStorage/Cache/Connection/MemCachedTest.php b/tests/DataStorage/Cache/Connection/MemCachedTest.php
index fe8614030..db3ff6c14 100755
--- a/tests/DataStorage/Cache/Connection/MemCachedTest.php
+++ b/tests/DataStorage/Cache/Connection/MemCachedTest.php
@@ -63,9 +63,9 @@ final class MemCachedTest extends \PHPUnit\Framework\TestCase
self::assertEquals(11211, $this->cache->getPort());
self::assertEquals(
[
- 'status' => CacheStatus::OK,
- 'count' => 0,
- 'size' => 0,
+ 'status' => CacheStatus::OK,
+ 'count' => 0,
+ 'size' => 0,
],
$this->cache->stats()
);
@@ -321,7 +321,7 @@ final class MemCachedTest extends \PHPUnit\Framework\TestCase
self::assertTrue($this->cache->flushAll());
self::assertNull($this->cache->get('key5'));
- // Carefull memcached is dumb and keeps expired elements which were not acessed after flushing in stat
+ // Careful memcached is dumb and keeps expired elements which were not acessed after flushing in stat
self::assertGreaterThanOrEqual(0, $this->cache->stats()['count']);
self::assertGreaterThanOrEqual(0, $this->cache->stats()['size']);
}
diff --git a/tests/DataStorage/Database/DataMapperAbstractTest.php b/tests/DataStorage/Database/DataMapperAbstractTest.php
index 1e34165fd..ceb2b0873 100755
--- a/tests/DataStorage/Database/DataMapperAbstractTest.php
+++ b/tests/DataStorage/Database/DataMapperAbstractTest.php
@@ -14,6 +14,8 @@ declare(strict_types=1);
namespace phpOMS\tests\DataStorage\Database;
+include_once __DIR__ . '/../../Autoloader.php';
+
use phpOMS\DataStorage\Database\Query\OrderType;
use phpOMS\tests\DataStorage\Database\TestModel\BaseModel;
use phpOMS\tests\DataStorage\Database\TestModel\BaseModelMapper;
@@ -42,21 +44,27 @@ final class DataMapperAbstractTest extends \PHPUnit\Framework\TestCase
{
$this->model = new BaseModel();
+ \phpOMS\Log\FileLogger::getInstance()->verbose = true;
+
$GLOBALS['dbpool']->get()->con->prepare(
'CREATE TABLE `test_base` (
`test_base_id` int(11) NOT NULL AUTO_INCREMENT,
`test_base_string` varchar(254) NOT NULL,
+ `test_base_compress` BLOB NOT NULL,
+ `test_base_pstring` varchar(254) NOT NULL,
`test_base_int` int(11) NOT NULL,
`test_base_bool` tinyint(1) DEFAULT NULL,
`test_base_null` int(11) DEFAULT NULL,
`test_base_float` decimal(5, 4) DEFAULT NULL,
`test_base_belongs_to_one` int(11) DEFAULT NULL,
+ `test_base_belongs_top_one` int(11) DEFAULT NULL,
`test_base_owns_one_self` int(11) DEFAULT NULL,
+ `test_base_owns_onep_self` int(11) DEFAULT NULL,
`test_base_json` varchar(254) DEFAULT NULL,
`test_base_json_serializable` varchar(254) DEFAULT NULL,
`test_base_serializable` varchar(254) DEFAULT NULL,
`test_base_datetime` datetime DEFAULT NULL,
- `test_base_datetime_null` datetime DEFAULT NULL, /* There was a bug where it returned the current date because new \DateTime(null) === current date which is wrong, we want null as value! */
+ `test_base_datetime_null` datetime DEFAULT NULL,
PRIMARY KEY (`test_base_id`)
)ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 AUTO_INCREMENT=1;'
)->execute();
@@ -112,6 +120,49 @@ final class DataMapperAbstractTest extends \PHPUnit\Framework\TestCase
PRIMARY KEY (`test_has_many_rel_relations_id`)
)ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 AUTO_INCREMENT=1;'
)->execute();
+
+ // private
+ $GLOBALS['dbpool']->get()->con->prepare(
+ 'CREATE TABLE `test_has_many_directp` (
+ `test_has_many_directp_id` int(11) NOT NULL AUTO_INCREMENT,
+ `test_has_many_directp_string` varchar(254) NOT NULL,
+ `test_has_many_directp_to` int(11) NOT NULL,
+ PRIMARY KEY (`test_has_many_directp_id`)
+ )ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 AUTO_INCREMENT=1;'
+ )->execute();
+
+ $GLOBALS['dbpool']->get()->con->prepare(
+ 'CREATE TABLE `test_has_many_relp` (
+ `test_has_many_relp_id` int(11) NOT NULL AUTO_INCREMENT,
+ `test_has_many_relp_string` varchar(254) NOT NULL,
+ PRIMARY KEY (`test_has_many_relp_id`)
+ )ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 AUTO_INCREMENT=1;'
+ )->execute();
+
+ $GLOBALS['dbpool']->get()->con->prepare(
+ 'CREATE TABLE `test_has_many_rel_relationsp` (
+ `test_has_many_rel_relationsp_id` int(11) NOT NULL AUTO_INCREMENT,
+ `test_has_many_rel_relationsp_src` int(11) NOT NULL,
+ `test_has_many_rel_relationsp_dest` int(11) NOT NULL,
+ PRIMARY KEY (`test_has_many_rel_relationsp_id`)
+ )ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 AUTO_INCREMENT=1;'
+ )->execute();
+
+ $GLOBALS['dbpool']->get()->con->prepare(
+ 'CREATE TABLE `test_belongs_to_onep` (
+ `test_belongs_to_onep_id` int(11) NOT NULL AUTO_INCREMENT,
+ `test_belongs_to_onep_string` varchar(254) NOT NULL,
+ PRIMARY KEY (`test_belongs_to_onep_id`)
+ )ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 AUTO_INCREMENT=1;'
+ )->execute();
+
+ $GLOBALS['dbpool']->get()->con->prepare(
+ 'CREATE TABLE `test_owns_onep` (
+ `test_owns_onep_id` int(11) NOT NULL AUTO_INCREMENT,
+ `test_owns_onep_string` varchar(254) NOT NULL,
+ PRIMARY KEY (`test_owns_onep_id`)
+ )ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 AUTO_INCREMENT=1;'
+ )->execute();
}
protected function tearDown() : void
@@ -123,6 +174,14 @@ final class DataMapperAbstractTest extends \PHPUnit\Framework\TestCase
$GLOBALS['dbpool']->get()->con->prepare('DROP TABLE test_has_many_direct')->execute();
$GLOBALS['dbpool']->get()->con->prepare('DROP TABLE test_has_many_rel')->execute();
$GLOBALS['dbpool']->get()->con->prepare('DROP TABLE test_has_many_rel_relations')->execute();
+
+ $GLOBALS['dbpool']->get()->con->prepare('DROP TABLE test_has_many_directp')->execute();
+ $GLOBALS['dbpool']->get()->con->prepare('DROP TABLE test_has_many_relp')->execute();
+ $GLOBALS['dbpool']->get()->con->prepare('DROP TABLE test_has_many_rel_relationsp')->execute();
+ $GLOBALS['dbpool']->get()->con->prepare('DROP TABLE test_belongs_to_onep')->execute();
+ $GLOBALS['dbpool']->get()->con->prepare('DROP TABLE test_owns_onep')->execute();
+
+ \phpOMS\Log\FileLogger::getInstance()->verbose = false;
}
/**
@@ -138,7 +197,7 @@ final class DataMapperAbstractTest extends \PHPUnit\Framework\TestCase
public function testCreate() : void
{
self::assertGreaterThan(0, BaseModelMapper::create()->execute($this->model));
- self::assertGreaterThan(0, $this->model->getId());
+ self::assertGreaterThan(0, $this->model->id);
}
public function testCreateNullModel() : void
@@ -153,9 +212,9 @@ final class DataMapperAbstractTest extends \PHPUnit\Framework\TestCase
public function testCreateAlreadyCreatedModel() : void
{
self::assertGreaterThan(0, $id = BaseModelMapper::create()->execute($this->model));
- self::assertGreaterThan(0, $this->model->getId());
+ self::assertGreaterThan(0, $this->model->id);
self::assertEquals($id, BaseModelMapper::create()->execute($this->model));
- self::assertEquals($id, $this->model->getId());
+ self::assertEquals($id, $this->model->id);
}
public function testCreateHasManyRelation() : void
@@ -197,8 +256,10 @@ final class DataMapperAbstractTest extends \PHPUnit\Framework\TestCase
->where('id', $id)
->execute();
- self::assertEquals($this->model->getId(), $modelR->getId());
+ self::assertEquals($this->model->id, $modelR->id);
self::assertEquals($this->model->string, $modelR->string);
+ self::assertEquals($this->model->compress, $modelR->compress);
+ self::assertEquals($this->model->getPString(), $modelR->getPString());
self::assertEquals($this->model->int, $modelR->int);
self::assertEquals($this->model->bool, $modelR->bool);
self::assertEquals($this->model->float, $modelR->float);
@@ -218,12 +279,38 @@ final class DataMapperAbstractTest extends \PHPUnit\Framework\TestCase
self::assertEquals($this->model->belongsToOne->string, $modelR->belongsToOne->string);
}
+ public function testGetRaw() : void
+ {
+ $id = BaseModelMapper::create()->execute($this->model);
+
+ /** @var BaseModel $modelR */
+ $modelR = BaseModelMapper::getRaw()
+ ->with('belongsToOne')
+ ->with('ownsOneSelf')
+ ->with('hasManyDirect')
+ ->with('hasMnayRelations')
+ ->with('conditional')
+ ->where('id', $id)
+ ->execute();
+
+ self::assertTrue(\is_array($modelR));
+ }
+
public function testGetAll() : void
{
BaseModelMapper::create()->execute($this->model);
self::assertCount(1, BaseModelMapper::getAll()->execute());
}
+ public function testGetYield() : void
+ {
+ BaseModelMapper::create()->execute($this->model);
+
+ foreach (BaseModelMapper::yield()->execute() as $model) {
+ self::assertGreaterThan(0, $model->id);
+ }
+ }
+
public function testGetFor() : void
{
$id = BaseModelMapper::create()->execute($this->model);
@@ -247,7 +334,7 @@ final class DataMapperAbstractTest extends \PHPUnit\Framework\TestCase
$id2 = BaseModelMapper::create()->execute($model2);
$by = BaseModelMapper::get()->where('string', '456')->execute();
- self::assertEquals($model2->getId(), $by->getId());
+ self::assertEquals($model2->id, $by->id);
}
public function testGetNewest() : void
@@ -255,13 +342,14 @@ final class DataMapperAbstractTest extends \PHPUnit\Framework\TestCase
$model1 = new BaseModel();
$model1->datetime = new \DateTime('now');
$id1 = BaseModelMapper::create()->execute($model1);
+
\sleep(1);
$model2 = new BaseModel();
$model2->datetime = new \DateTime('now');
$id2 = BaseModelMapper::create()->execute($model2);
$newest = BaseModelMapper::getAll()->sort('id', OrderType::DESC)->limit(1)->execute();
- self::assertEquals($id2, \reset($newest)->getId());
+ self::assertEquals($id2, \reset($newest)->id);
}
public function testGetNullModel() : void
@@ -269,6 +357,38 @@ final class DataMapperAbstractTest extends \PHPUnit\Framework\TestCase
self::assertEquals(NullBaseModel::class, \get_class(BaseModelMapper::get()->where('id', 99)->execute()));
}
+ public function testCount() : void
+ {
+ BaseModelMapper::create()->execute($this->model);
+ self::assertEquals(1, BaseModelMapper::count()->execute());
+ }
+
+ public function testSum() : void
+ {
+ BaseModelMapper::create()->execute($this->model);
+ self::assertEquals(11, BaseModelMapper::sum()->columns(['test_base_int'])->execute());
+ }
+
+ public function testExists() : void
+ {
+ $id = BaseModelMapper::create()->execute($this->model);
+ self::assertTrue(BaseModelMApper::exists()->where('id', $id)->execute());
+ self::assertFalse(BaseModelMApper::exists()->where('id', $id + 1)->execute());
+ }
+
+ public function testHas() : void
+ {
+ $id = BaseModelMapper::create()->execute($this->model);
+ self::assertTrue(BaseModelMApper::has()->with('hasManyRelations')->where('id', $id)->execute());
+ self::assertTrue(BaseModelMApper::has()->with('hasManyDirect')->where('id', $id)->execute());
+ }
+
+ public function testRandom() : void
+ {
+ $id = BaseModelMapper::create()->execute($this->model);
+ self::assertEquals($id, BaseModelMApper::getRandom()->limit(1)->execute()->id);
+ }
+
/**
* @covers phpOMS\DataStorage\Database\Mapper\DataMapperAbstract
* @covers phpOMS\DataStorage\Database\Mapper\DataMapperFactory
diff --git a/tests/DataStorage/Database/Query/BuilderTest.php b/tests/DataStorage/Database/Query/BuilderTest.php
index fb61096a5..0defa7035 100755
--- a/tests/DataStorage/Database/Query/BuilderTest.php
+++ b/tests/DataStorage/Database/Query/BuilderTest.php
@@ -85,7 +85,7 @@ final class BuilderTest extends \PHPUnit\Framework\TestCase
$datetime = new \DateTime('now');
$sql = 'SELECT [a].[test], [b].[test] FROM [a], [b] WHERE [a].[test] = \'' . $datetime->format('Y-m-d H:i:s')
. '\';';
- $sql = \strtr($sql, '[]', $iS . $iE);
+ $sql = \strtr($sql, '[]', $iS . $iE);
self::assertEquals($sql, $query->select('a.test', 'b.test')->from('a', 'b')->where('a.test', '=', $datetime)->toSql());
$query = new Builder($con);
@@ -121,7 +121,7 @@ final class BuilderTest extends \PHPUnit\Framework\TestCase
$iE = $con->getGrammar()->systemIdentifierEnd;
$query = new Builder($con);
- $sql = 'SELECT [a].[test] FROM [a] as b WHERE [a].[test] = 1 ORDER BY \rand() LIMIT 1;';
+ $sql = 'SELECT [a].[test] FROM [a] as b WHERE [a].[test] = 1 ORDER BY RAND() LIMIT 1;';
$sql = \strtr($sql, '[]', $iS . $iE);
self::assertEquals($sql, $query->random('a.test')->fromAs('a', 'b')->where('a.test', '=', 1)->toSql());
}
@@ -535,19 +535,19 @@ final class BuilderTest extends \PHPUnit\Framework\TestCase
$iE = $con->getGrammar()->systemIdentifierEnd;
$query = new Builder($con);
- $sql = 'UPDATE [a] SET [a].[test] = 1, [a].[test2] = 2 WHERE [a].[test] = 1;';
+ $sql = 'UPDATE [a] SET [test] = 1, [test2] = 2 WHERE [a].[test] = 1;';
$sql = \strtr($sql, '[]', $iS . $iE);
- self::assertEquals($sql, $query->update('a')->set(['a.test' => 1])->set(['a.test2' => 2])->where('a.test', '=', 1)->toSql());
+ self::assertEquals($sql, $query->update('a')->set(['test' => 1])->set(['test2' => 2])->where('a.test', '=', 1)->toSql());
$query = new Builder($con);
- $sql = 'UPDATE [a] SET [a].[test] = 1, [a].[test2] = 2 WHERE [a].[test] = 1;';
+ $sql = 'UPDATE [a] SET [test] = 1, [test2] = 2 WHERE [a].[test] = 1;';
$sql = \strtr($sql, '[]', $iS . $iE);
- self::assertEquals($sql, $query->update('a')->sets('a.test', 1)->sets('a.test2', 2)->where('a.test', '=', 1)->toSql());
+ self::assertEquals($sql, $query->update('a')->sets('test', 1)->sets('test2', 2)->where('a.test', '=', 1)->toSql());
$query = new Builder($con);
- $sql = 'UPDATE [a] SET [a].[test] = 1, [a].[test2] = :test2 WHERE [a].[test] = :test3;';
+ $sql = 'UPDATE [a] SET [test] = 1, [test2] = :test2 WHERE [a].[test] = :test3;';
$sql = \strtr($sql, '[]', $iS . $iE);
- self::assertEquals($sql, $query->update('a')->set(['a.test' => 1])->set(['a.test2' => new Parameter('test2')])->where('a.test', '=', new Parameter('test3'))->toSql());
+ self::assertEquals($sql, $query->update('a')->set(['test' => 1])->set(['test2' => new Parameter('test2')])->where('a.test', '=', new Parameter('test3'))->toSql());
}
/**
@@ -744,28 +744,6 @@ final class BuilderTest extends \PHPUnit\Framework\TestCase
$query->delete();
}
- /**
- * @testdox Invalid select types throw a InvalidArgumentException
- * @group framework
- * @dataProvider dbConnectionProvider
- */
- public function testInvalidSelectParameter($con) : void
- {
- if (!$con->isInitialized()) {
- self::markTestSkipped();
-
- return;
- }
-
- $iS = $con->getGrammar()->systemIdentifierStart;
- $iE = $con->getGrammar()->systemIdentifierEnd;
-
- $this->expectException(\InvalidArgumentException::class);
-
- $query = new Builder($con, true);
- $query->select(false);
- }
-
/**
* @testdox Invalid from types throw a InvalidArgumentException
* @group framework
diff --git a/tests/DataStorage/Database/Query/ColumnTest.php b/tests/DataStorage/Database/Query/ColumnTest.php
deleted file mode 100755
index 51a14aa20..000000000
--- a/tests/DataStorage/Database/Query/ColumnTest.php
+++ /dev/null
@@ -1,32 +0,0 @@
-get()));
- }
-}
diff --git a/tests/DataStorage/Database/Query/CountTest.php b/tests/DataStorage/Database/Query/CountTest.php
deleted file mode 100755
index d13cfd7a8..000000000
--- a/tests/DataStorage/Database/Query/CountTest.php
+++ /dev/null
@@ -1,32 +0,0 @@
-get()));
- }
-}
diff --git a/tests/DataStorage/Database/Query/ExpressionTest.php b/tests/DataStorage/Database/Query/ExpressionTest.php
deleted file mode 100755
index 0743230fc..000000000
--- a/tests/DataStorage/Database/Query/ExpressionTest.php
+++ /dev/null
@@ -1,32 +0,0 @@
-get()));
- }
-}
diff --git a/tests/DataStorage/Database/Query/FromTest.php b/tests/DataStorage/Database/Query/FromTest.php
deleted file mode 100755
index f1a7111d9..000000000
--- a/tests/DataStorage/Database/Query/FromTest.php
+++ /dev/null
@@ -1,32 +0,0 @@
-get()));
- }
-}
diff --git a/tests/DataStorage/Database/Query/IntoTest.php b/tests/DataStorage/Database/Query/IntoTest.php
deleted file mode 100755
index fd3daafaa..000000000
--- a/tests/DataStorage/Database/Query/IntoTest.php
+++ /dev/null
@@ -1,32 +0,0 @@
-get()));
- }
-}
diff --git a/tests/DataStorage/Database/Query/SelectTest.php b/tests/DataStorage/Database/Query/SelectTest.php
deleted file mode 100755
index 83a46661e..000000000
--- a/tests/DataStorage/Database/Query/SelectTest.php
+++ /dev/null
@@ -1,32 +0,0 @@
-get()));
- }
-}
diff --git a/tests/DataStorage/Database/Schema/BuilderTest.php b/tests/DataStorage/Database/Schema/BuilderTest.php
index b988c99c0..f5a70693e 100755
--- a/tests/DataStorage/Database/Schema/BuilderTest.php
+++ b/tests/DataStorage/Database/Schema/BuilderTest.php
@@ -170,7 +170,6 @@ final class BuilderTest extends \PHPUnit\Framework\TestCase
$iS = $con->getGrammar()->systemIdentifierStart;
$iE = $con->getGrammar()->systemIdentifierEnd;
- // @todo: fix, this is not correct for sqlite
$query = new Builder($con);
$sql = '';
@@ -181,7 +180,7 @@ final class BuilderTest extends \PHPUnit\Framework\TestCase
} elseif ($con instanceof SqlServerConnection) {
$sql = 'CREATE TABLE IF NOT EXISTS [user_roles] ([user_id] INT AUTO_INCREMENT, [role_id] VARCHAR(10) DEFAULT \'1\' NULL, PRIMARY KEY ([user_id]), FOREIGN KEY ([user_id]) REFERENCES [users] ([ext1_id]), FOREIGN KEY ([role_id]) REFERENCES [roles] ([ext2_id]));';
} elseif ($con instanceof SQLiteConnection) {
- $sql = 'CREATE TABLE IF NOT EXISTS [user_roles] ([user_id] INT AUTO_INCREMENT, [role_id] VARCHAR(10) DEFAULT \'1\' NULL, PRIMARY KEY ([user_id]), FOREIGN KEY ([user_id]) REFERENCES [users] ([ext1_id]), FOREIGN KEY ([role_id]) REFERENCES [roles] ([ext2_id]));';
+ $sql = 'CREATE TABLE [user_roles] ([user_id] INTEGER PRIMARY KEY AUTOINCREMENT, [role_id] TEXT DEFAULT \'1\' NULL, PRIMARY KEY ([user_id]), FOREIGN KEY ([user_id]) REFERENCES [users] ([ext1_id]), FOREIGN KEY ([role_id]) REFERENCES [roles] ([ext2_id]));';
}
$sql = \strtr($sql, '[]', $iS . $iE);
diff --git a/tests/DataStorage/Database/Schema/Grammar/MysqlGrammarTest.php b/tests/DataStorage/Database/Schema/Grammar/MysqlGrammarTest.php
index dc43f93ef..bc1315f34 100755
--- a/tests/DataStorage/Database/Schema/Grammar/MysqlGrammarTest.php
+++ b/tests/DataStorage/Database/Schema/Grammar/MysqlGrammarTest.php
@@ -78,7 +78,7 @@ final class MysqlGrammarTest extends \PHPUnit\Framework\TestCase
);
}
- $delete = new Builder($this->con);
+ $delete = new Builder($this->con);
$delete->dropTable('test')
->dropTable('test_foreign')
->execute();
@@ -101,7 +101,7 @@ final class MysqlGrammarTest extends \PHPUnit\Framework\TestCase
self::assertContains('test', $tables);
self::assertContains('test_foreign', $tables);
- $delete = new Builder($this->con);
+ $delete = new Builder($this->con);
$delete->dropTable('test')
->dropTable('test_foreign')
->execute();
diff --git a/tests/DataStorage/Database/TestModel/BaseModel.php b/tests/DataStorage/Database/TestModel/BaseModel.php
index 24b892d34..7c6a6c117 100755
--- a/tests/DataStorage/Database/TestModel/BaseModel.php
+++ b/tests/DataStorage/Database/TestModel/BaseModel.php
@@ -22,6 +22,10 @@ class BaseModel
public string $string = 'Base';
+ public string $compress = 'Uncompressed';
+
+ private string $pstring = 'Private';
+
public string $conditional = '';
public int $int = 11;
@@ -40,10 +44,18 @@ class BaseModel
public array $hasManyRelations = [];
+ private array $hasManyDirectPrivate = [];
+
+ private array $hasManyRelationsPrivate = [];
+
public $ownsOneSelf = 0;
public $belongsToOne = 0;
+ private $ownsOneSelfPrivate = 0;
+
+ private $belongsToOnePrivate = 0;
+
public ?object $serializable = null;
public array $json = [1, 2, 3];
@@ -64,11 +76,21 @@ class BaseModel
new ManyToManyRelModel(),
];
+ $this->hasManyDirectPrivate = [
+ new ManyToManyDirectModel(),
+ new ManyToManyDirectModel(),
+ ];
+
+ $this->hasManyRelationsPrivate = [
+ new ManyToManyRelModel(),
+ new ManyToManyRelModel(),
+ ];
+
$this->ownsOneSelf = new OwnsOneModel();
$this->belongsToOne = new BelongsToModel();
$this->serializable = new class() implements SerializableInterface {
- public $value = '';
+ public $value = '';
public function serialize() : string
{
@@ -89,6 +111,11 @@ class BaseModel
};
}
+ public function getPString() : string
+ {
+ return $this->pstring;
+ }
+
public function getId() : int
{
return $this->id;
diff --git a/tests/DataStorage/Database/TestModel/BaseModelMapper.php b/tests/DataStorage/Database/TestModel/BaseModelMapper.php
index 37d2146fe..6809192b3 100755
--- a/tests/DataStorage/Database/TestModel/BaseModelMapper.php
+++ b/tests/DataStorage/Database/TestModel/BaseModelMapper.php
@@ -27,6 +27,8 @@ class BaseModelMapper extends DataMapperFactory
public const COLUMNS = [
'test_base_id' => ['name' => 'test_base_id', 'type' => 'int', 'internal' => 'id'],
'test_base_string' => ['name' => 'test_base_string', 'type' => 'string', 'internal' => 'string', 'autocomplete' => true],
+ 'test_base_compress' => ['name' => 'test_base_compress', 'type' => 'compress', 'internal' => 'compress',],
+ 'test_base_pstring' => ['name' => 'test_base_pstring', 'type' => 'pstring', 'internal' => 'pstring', 'private' => true],
'test_base_int' => ['name' => 'test_base_int', 'type' => 'int', 'internal' => 'int'],
'test_base_bool' => ['name' => 'test_base_bool', 'type' => 'bool', 'internal' => 'bool'],
'test_base_null' => ['name' => 'test_base_null', 'type' => 'int', 'internal' => 'null'],
@@ -38,6 +40,8 @@ class BaseModelMapper extends DataMapperFactory
'test_base_datetime_null' => ['name' => 'test_base_datetime_null', 'type' => 'DateTime', 'internal' => 'datetime_null'],
'test_base_owns_one_self' => ['name' => 'test_base_owns_one_self', 'type' => 'int', 'internal' => 'ownsOneSelf'],
'test_base_belongs_to_one' => ['name' => 'test_base_belongs_to_one', 'type' => 'int', 'internal' => 'belongsToOne'],
+ 'test_base_owns_onep_self' => ['name' => 'test_base_owns_onep_self', 'type' => 'int', 'internal' => 'ownsOneSelfPrivate', 'private' => true],
+ 'test_base_belongs_top_one' => ['name' => 'test_base_belongs_top_one', 'type' => 'int', 'internal' => 'belongsToOnePrivate', 'private' => true],
];
/**
@@ -50,6 +54,12 @@ class BaseModelMapper extends DataMapperFactory
'belongsToOne' => [
'mapper' => BelongsToModelMapper::class,
'external' => 'test_base_belongs_to_one',
+ 'private' => true,
+ ],
+ 'belongsToOnePrivate' => [
+ 'mapper' => BelongsToModelPrivateMapper::class,
+ 'external' => 'test_base_belongs_top_one',
+ 'private' => true,
],
];
@@ -58,6 +68,10 @@ class BaseModelMapper extends DataMapperFactory
'mapper' => OwnsOneModelMapper::class,
'external' => 'test_base_owns_one_self',
],
+ 'ownsOneSelfPrivate' => [
+ 'mapper' => OwnsOneModelPrivateMapper::class,
+ 'external' => 'test_base_owns_onep_self',
+ ],
];
/**
@@ -86,6 +100,20 @@ class BaseModelMapper extends DataMapperFactory
'column' => 'title',
'external' => null,
],
+ 'hasManyDirectPrivate' => [
+ 'mapper' => ManyToManyDirectModelPrivateMapper::class,
+ 'table' => 'test_has_many_directp',
+ 'self' => 'test_has_many_directp_to',
+ 'external' => null,
+ 'private' => true,
+ ],
+ 'hasManyRelationsPrivate' => [
+ 'mapper' => ManyToManyRelModelPrivateMapper::class,
+ 'table' => 'test_has_many_rel_relationsp',
+ 'external' => 'test_has_many_rel_relationsp_src',
+ 'self' => 'test_has_many_rel_relationsp_dest',
+ 'private' => true,
+ ],
];
/**
diff --git a/tests/DataStorage/Database/TestModel/BelongsToModelPrivateMapper.php b/tests/DataStorage/Database/TestModel/BelongsToModelPrivateMapper.php
new file mode 100644
index 000000000..4ed89646e
--- /dev/null
+++ b/tests/DataStorage/Database/TestModel/BelongsToModelPrivateMapper.php
@@ -0,0 +1,49 @@
+
+ * @since 1.0.0
+ */
+ public const COLUMNS = [
+ 'test_belongs_to_onep_id' => ['name' => 'test_belongs_to_onep_id', 'type' => 'int', 'internal' => 'id'],
+ 'test_belongs_to_onep_string' => ['name' => 'test_belongs_to_onep_string', 'type' => 'string', 'internal' => 'string'],
+ ];
+
+ /**
+ * Primary table.
+ *
+ * @var string
+ * @since 1.0.0
+ */
+ public const TABLE = 'test_belongs_to_onep';
+
+ /**
+ * Primary field name.
+ *
+ * @var string
+ * @since 1.0.0
+ */
+ public const PRIMARYFIELD = 'test_belongs_to_onep_id';
+
+ public const MODEL = BelongsToModel::class;
+}
diff --git a/tests/DataStorage/Database/TestModel/ManyToManyDirectModelPrivateMapper.php b/tests/DataStorage/Database/TestModel/ManyToManyDirectModelPrivateMapper.php
new file mode 100644
index 000000000..e1de0fd8a
--- /dev/null
+++ b/tests/DataStorage/Database/TestModel/ManyToManyDirectModelPrivateMapper.php
@@ -0,0 +1,50 @@
+
+ * @since 1.0.0
+ */
+ public const COLUMNS = [
+ 'test_has_many_directp_id' => ['name' => 'test_has_many_directp_id', 'type' => 'int', 'internal' => 'id'],
+ 'test_has_many_directp_string' => ['name' => 'test_has_many_directp_string', 'type' => 'string', 'internal' => 'string'],
+ 'test_has_many_directp_to' => ['name' => 'test_has_many_directp_to', 'type' => 'int', 'internal' => 'to'],
+ ];
+
+ /**
+ * Primary table.
+ *
+ * @var string
+ * @since 1.0.0
+ */
+ public const TABLE = 'test_has_many_directp';
+
+ /**
+ * Primary field name.
+ *
+ * @var string
+ * @since 1.0.0
+ */
+ public const PRIMARYFIELD = 'test_has_many_directp_id';
+
+ public const MODEL = ManyToManyDirectModel::class;
+}
diff --git a/tests/DataStorage/Database/TestModel/ManyToManyRelModelPrivateMapper.php b/tests/DataStorage/Database/TestModel/ManyToManyRelModelPrivateMapper.php
new file mode 100644
index 000000000..e7df8b66d
--- /dev/null
+++ b/tests/DataStorage/Database/TestModel/ManyToManyRelModelPrivateMapper.php
@@ -0,0 +1,49 @@
+
+ * @since 1.0.0
+ */
+ public const COLUMNS = [
+ 'test_has_many_relp_id' => ['name' => 'test_has_many_relp_id', 'type' => 'int', 'internal' => 'id'],
+ 'test_has_many_relp_string' => ['name' => 'test_has_many_relp_string', 'type' => 'string', 'internal' => 'string'],
+ ];
+
+ /**
+ * Primary table.
+ *
+ * @var string
+ * @since 1.0.0
+ */
+ public const TABLE = 'test_has_many_relp';
+
+ /**
+ * Primary field name.
+ *
+ * @var string
+ * @since 1.0.0
+ */
+ public const PRIMARYFIELD = 'test_has_many_relp_id';
+
+ public const MODEL = ManyToManyRelModel::class;
+}
diff --git a/tests/DataStorage/Database/TestModel/OwnsOneModelPrivateMapper.php b/tests/DataStorage/Database/TestModel/OwnsOneModelPrivateMapper.php
new file mode 100644
index 000000000..08511b3aa
--- /dev/null
+++ b/tests/DataStorage/Database/TestModel/OwnsOneModelPrivateMapper.php
@@ -0,0 +1,49 @@
+
+ * @since 1.0.0
+ */
+ public const COLUMNS = [
+ 'test_owns_onep_id' => ['name' => 'test_owns_onep_id', 'type' => 'int', 'internal' => 'id'],
+ 'test_owns_onep_string' => ['name' => 'test_owns_onep_string', 'type' => 'string', 'internal' => 'string'],
+ ];
+
+ /**
+ * Primary table.
+ *
+ * @var string
+ * @since 1.0.0
+ */
+ public const TABLE = 'test_owns_onep';
+
+ /**
+ * Primary field name.
+ *
+ * @var string
+ * @since 1.0.0
+ */
+ public const PRIMARYFIELD = 'test_owns_onep_id';
+
+ public const MODEL = OwnsOneModel::class;
+}
diff --git a/tests/Dispatcher/DispatcherTest.php b/tests/Dispatcher/DispatcherTest.php
index 9d9937d12..2af67ec07 100755
--- a/tests/Dispatcher/DispatcherTest.php
+++ b/tests/Dispatcher/DispatcherTest.php
@@ -39,7 +39,7 @@ final class DispatcherTest extends \PHPUnit\Framework\TestCase
*/
protected function setUp() : void
{
- $this->app = new class() extends ApplicationAbstract {
+ $this->app = new class() extends ApplicationAbstract {
protected string $appName = 'Api';
};
diff --git a/tests/Localization/Defaults/CityMapperTest.php b/tests/Localization/Defaults/CityMapperTest.php
index 647170efb..cf9cb420d 100755
--- a/tests/Localization/Defaults/CityMapperTest.php
+++ b/tests/Localization/Defaults/CityMapperTest.php
@@ -33,8 +33,8 @@ final class CityMapperTest extends \PHPUnit\Framework\TestCase
public static function setUpBeforeClass() : void
{
self::$con = new SqliteConnection([
- 'db' => 'sqlite',
- 'database' => \realpath(__DIR__ . '/../../../Localization/Defaults/localization.sqlite'),
+ 'db' => 'sqlite',
+ 'database' => \realpath(__DIR__ . '/../../../Localization/Defaults/localization.sqlite'),
]);
self::$con->connect();
diff --git a/tests/Localization/Defaults/CountryMapperTest.php b/tests/Localization/Defaults/CountryMapperTest.php
index 403bfdc65..9ea15f43f 100755
--- a/tests/Localization/Defaults/CountryMapperTest.php
+++ b/tests/Localization/Defaults/CountryMapperTest.php
@@ -33,8 +33,8 @@ final class CountryMapperTest extends \PHPUnit\Framework\TestCase
public static function setUpBeforeClass() : void
{
self::$con = new SqliteConnection([
- 'db' => 'sqlite',
- 'database' => \realpath(__DIR__ . '/../../../Localization/Defaults/localization.sqlite'),
+ 'db' => 'sqlite',
+ 'database' => \realpath(__DIR__ . '/../../../Localization/Defaults/localization.sqlite'),
]);
self::$con->connect();
diff --git a/tests/Localization/Defaults/CountryTest.php b/tests/Localization/Defaults/CountryTest.php
index 2d678bfb9..ee5c76381 100755
--- a/tests/Localization/Defaults/CountryTest.php
+++ b/tests/Localization/Defaults/CountryTest.php
@@ -33,7 +33,7 @@ final class CountryTest extends \PHPUnit\Framework\TestCase
public function testDefaults() : void
{
$obj = new Country();
- self::assertEquals(0, $obj->getId());
+ self::assertEquals(0, $obj->id);
self::assertEquals('', $obj->getName());
self::assertEquals('', $obj->getCode2());
self::assertEquals('', $obj->getCode3());
diff --git a/tests/Localization/Defaults/CurrencyMapperTest.php b/tests/Localization/Defaults/CurrencyMapperTest.php
index ce42e7c81..6c576276c 100755
--- a/tests/Localization/Defaults/CurrencyMapperTest.php
+++ b/tests/Localization/Defaults/CurrencyMapperTest.php
@@ -33,8 +33,8 @@ final class CurrencyMapperTest extends \PHPUnit\Framework\TestCase
public static function setUpBeforeClass() : void
{
self::$con = new SqliteConnection([
- 'db' => 'sqlite',
- 'database' => \realpath(__DIR__ . '/../../../Localization/Defaults/localization.sqlite'),
+ 'db' => 'sqlite',
+ 'database' => \realpath(__DIR__ . '/../../../Localization/Defaults/localization.sqlite'),
]);
self::$con->connect();
diff --git a/tests/Localization/Defaults/IbanMapperTest.php b/tests/Localization/Defaults/IbanMapperTest.php
index 477dcb63d..f4dcecd3b 100755
--- a/tests/Localization/Defaults/IbanMapperTest.php
+++ b/tests/Localization/Defaults/IbanMapperTest.php
@@ -33,8 +33,8 @@ final class IbanMapperTest extends \PHPUnit\Framework\TestCase
public static function setUpBeforeClass() : void
{
self::$con = new SqliteConnection([
- 'db' => 'sqlite',
- 'database' => \realpath(__DIR__ . '/../../../Localization/Defaults/localization.sqlite'),
+ 'db' => 'sqlite',
+ 'database' => \realpath(__DIR__ . '/../../../Localization/Defaults/localization.sqlite'),
]);
self::$con->connect();
@@ -51,7 +51,7 @@ final class IbanMapperTest extends \PHPUnit\Framework\TestCase
{
/** @var Iban $obj */
$obj = IbanMapper::get()->where('id', 22)->execute();
- self::assertEquals('DE', $obj->getCountry());
+ self::assertEquals('DE', $obj->country);
self::assertEquals(22, $obj->getChars());
self::assertEquals('18n', $obj->getBban());
self::assertEquals('DEkk bbbb bbbb cccc cccc cc', $obj->getFields());
diff --git a/tests/Localization/Defaults/IbanTest.php b/tests/Localization/Defaults/IbanTest.php
index 041247d79..bbf92365f 100755
--- a/tests/Localization/Defaults/IbanTest.php
+++ b/tests/Localization/Defaults/IbanTest.php
@@ -33,7 +33,7 @@ final class IbanTest extends \PHPUnit\Framework\TestCase
public function testDefaults() : void
{
$obj = new Iban();
- self::assertEquals('', $obj->getCountry());
+ self::assertEquals('', $obj->country);
self::assertEquals(2, $obj->getChars());
self::assertEquals('', $obj->getBban());
self::assertEquals('', $obj->getFields());
diff --git a/tests/Localization/Defaults/LanguageMapperTest.php b/tests/Localization/Defaults/LanguageMapperTest.php
index 0b9758858..fd96411f2 100755
--- a/tests/Localization/Defaults/LanguageMapperTest.php
+++ b/tests/Localization/Defaults/LanguageMapperTest.php
@@ -33,8 +33,8 @@ final class LanguageMapperTest extends \PHPUnit\Framework\TestCase
public static function setUpBeforeClass() : void
{
self::$con = new SqliteConnection([
- 'db' => 'sqlite',
- 'database' => \realpath(__DIR__ . '/../../../Localization/Defaults/localization.sqlite'),
+ 'db' => 'sqlite',
+ 'database' => \realpath(__DIR__ . '/../../../Localization/Defaults/localization.sqlite'),
]);
self::$con->connect();
diff --git a/tests/Localization/Defaults/LanguageTest.php b/tests/Localization/Defaults/LanguageTest.php
index 000d36ac4..bfafe2464 100755
--- a/tests/Localization/Defaults/LanguageTest.php
+++ b/tests/Localization/Defaults/LanguageTest.php
@@ -33,7 +33,7 @@ final class LanguageTest extends \PHPUnit\Framework\TestCase
public function testDefaults() : void
{
$obj = new Language();
- self::assertEquals(0, $obj->getId());
+ self::assertEquals(0, $obj->id);
self::assertEquals('', $obj->getName());
self::assertEquals('', $obj->getNative());
self::assertEquals('', $obj->getCode2());
diff --git a/tests/Localization/LocalizationTest.php b/tests/Localization/LocalizationTest.php
index 980f0e9a5..1e670bec7 100755
--- a/tests/Localization/LocalizationTest.php
+++ b/tests/Localization/LocalizationTest.php
@@ -48,11 +48,11 @@ final class LocalizationTest extends \PHPUnit\Framework\TestCase
*/
public function testDefault() : void
{
- self::assertEquals(0, $this->localization->getId());
+ self::assertEquals(0, $this->localization->id);
self::assertTrue(ISO3166TwoEnum::isValidValue($this->localization->country));
self::assertTrue(TimeZoneEnumArray::isValidValue($this->localization->getTimezone()));
self::assertTrue(ISO639x1Enum::isValidValue($this->localization->language));
- self::assertTrue(ISO4217CharEnum::isValidValue($this->localization->getCurrency()));
+ self::assertTrue(ISO4217CharEnum::isValidValue($this->localization->currency));
self::assertEquals('0', $this->localization->getCurrencyFormat());
self::assertEquals('.', $this->localization->getDecimal());
self::assertEquals(',', $this->localization->getThousands());
@@ -66,18 +66,6 @@ final class LocalizationTest extends \PHPUnit\Framework\TestCase
self::assertEquals([], $this->localization->getVolume());
}
- /**
- * @testdox Setting a invalid language code throws InvalidEnumValue
- * @covers phpOMS\Localization\Localization
- * @group framework
- */
- public function testInvalidLanguage() : void
- {
- $this->expectException(\phpOMS\Stdlib\Base\Exception\InvalidEnumValue::class);
-
- $this->localization->setLanguage('abc');
- }
-
/**
* @testdox Setting a invalid country code throws InvalidEnumValue
* @covers phpOMS\Localization\Localization
@@ -102,18 +90,6 @@ final class LocalizationTest extends \PHPUnit\Framework\TestCase
$this->localization->setTimezone('abc');
}
- /**
- * @testdox Setting a invalid currency code throws InvalidEnumValue
- * @covers phpOMS\Localization\Localization
- * @group framework
- */
- public function testInvalidCurrency() : void
- {
- $this->expectException(\phpOMS\Stdlib\Base\Exception\InvalidEnumValue::class);
-
- $this->localization->setCurrency('abc');
- }
-
/**
* @testdox Setting a invalid angle throws InvalidEnumValue
* @covers phpOMS\Localization\Localization
@@ -160,28 +136,6 @@ final class LocalizationTest extends \PHPUnit\Framework\TestCase
self::assertEquals(TimeZoneEnumArray::get(315), $this->localization->getTimezone());
}
- /**
- * @testdox The language can be set and returned
- * @covers phpOMS\Localization\Localization
- * @group framework
- */
- public function testLanguageInputOutput() : void
- {
- $this->localization->setLanguage(ISO639x1Enum::_DE);
- self::assertEquals(ISO639x1Enum::_DE, $this->localization->language);
- }
-
- /**
- * @testdox The currency can be set and returned
- * @covers phpOMS\Localization\Localization
- * @group framework
- */
- public function testCurrencyInputOutput() : void
- {
- $this->localization->setCurrency(ISO4217CharEnum::_EUR);
- self::assertEquals(ISO4217CharEnum::_EUR, $this->localization->getCurrency());
- }
-
/**
* @testdox The datetime can be set and returned
* @covers phpOMS\Localization\Localization
@@ -322,7 +276,7 @@ final class LocalizationTest extends \PHPUnit\Framework\TestCase
public function testLocalizationFromLanguageCode() : void
{
$l11n = Localization::fromLanguage(ISO639x1Enum::_DE);
- self::assertEquals(ISO4217CharEnum::_EUR, $l11n->getCurrency());
+ self::assertEquals(ISO4217CharEnum::_EUR, $l11n->currency);
}
/**
@@ -333,7 +287,7 @@ final class LocalizationTest extends \PHPUnit\Framework\TestCase
public function testLocalizationLoading() : void
{
$this->localization->loadFromLanguage(ISO639x1Enum::_DE);
- self::assertEquals(ISO4217CharEnum::_EUR, $this->localization->getCurrency());
+ self::assertEquals(ISO4217CharEnum::_EUR, $this->localization->currency);
}
/**
@@ -360,7 +314,7 @@ final class LocalizationTest extends \PHPUnit\Framework\TestCase
public function testInvalidCountryLocalizationLoading() : void
{
$this->localization->loadFromLanguage(ISO639x1Enum::_DE, 'ABC');
- self::assertEquals(ISO4217CharEnum::_EUR, $this->localization->getCurrency());
+ self::assertEquals(ISO4217CharEnum::_EUR, $this->localization->currency);
}
/**
@@ -371,6 +325,6 @@ final class LocalizationTest extends \PHPUnit\Framework\TestCase
public function testMissingLocalizationLoading() : void
{
$this->localization->loadFromLanguage(ISO639x1Enum::_AA);
- self::assertEquals(ISO4217CharEnum::_USD, $this->localization->getCurrency());
+ self::assertEquals(ISO4217CharEnum::_USD, $this->localization->currency);
}
}
diff --git a/tests/Math/Functions/AlgebraTest.php b/tests/Math/Functions/AlgebraTest.php
new file mode 100644
index 000000000..7455ea3fe
--- /dev/null
+++ b/tests/Math/Functions/AlgebraTest.php
@@ -0,0 +1,91 @@
+ 9, 'y' => 0]], GrahamScan::createConvexHull([['x' => 9, 'y' => 0]]));
+
+ $points = [];
+ for ($i = 0; $i < 10; ++$i) {
+ for ($j = 0; $j < 10; ++$j) {
+ $points[] = ['x' => $i, 'y' => $j];
+ }
+ }
+
+ self::assertEquals([
+ ['x' => 0, 'y' => 0],
+ ['x' => 9, 'y' => 0],
+ ['x' => 9, 'y' => 9],
+ ['x' => 0, 'y' => 9],
+ ],
+ GrahamScan::createConvexHull($points)
+ );
+ }
+}
diff --git a/tests/Math/Matrix/MatrixTest.php b/tests/Math/Matrix/MatrixTest.php
index f418c5790..276867ec5 100755
--- a/tests/Math/Matrix/MatrixTest.php
+++ b/tests/Math/Matrix/MatrixTest.php
@@ -69,7 +69,7 @@ final class MatrixTest extends \PHPUnit\Framework\TestCase
*/
public function testMultMatrix() : void
{
- self::assertEquals([[0, -5], [-6, -7]], $this->C->getMatrix());
+ self::assertEquals([[0, -5], [-6, -7]], $this->C->toArray());
}
/**
@@ -79,7 +79,7 @@ final class MatrixTest extends \PHPUnit\Framework\TestCase
*/
public function testMultMatrixScalar() : void
{
- self::assertEquals([[0, -10], [-12, -14]], $this->C->mult(2)->getMatrix());
+ self::assertEquals([[0, -10], [-12, -14]], $this->C->mult(2)->toArray());
}
/**
@@ -291,7 +291,7 @@ final class MatrixTest extends \PHPUnit\Framework\TestCase
*/
public function testUpperTriangular() : void
{
- self::assertEquals([[-6, -7], [0, -5]], $this->C->upperTriangular()->getMatrix());
+ self::assertEquals([[-6, -7], [0, -5]], $this->C->upperTriangular()->toArray());
}
/**
@@ -301,8 +301,8 @@ final class MatrixTest extends \PHPUnit\Framework\TestCase
public function testLowerTriangular() : void
{
self::markTestIncomplete();
- //self::assertEquals([], $this->C->lowerTriangular()->getMatrix());
- //self::assertEquals([], $this->C->diagonalize()->getMatrix());
+ //self::assertEquals([], $this->C->lowerTriangular()->toArray());
+ //self::assertEquals([], $this->C->diagonalize()->toArray());
}
/**
@@ -492,4 +492,134 @@ final class MatrixTest extends \PHPUnit\Framework\TestCase
$A->mult($B);
}
+
+ public function testSumAll() : void
+ {
+ $m = Matrix::fromArray([
+ [1, 2, 3],
+ [4, 5, 6],
+ [7, 8, 9],
+ ]);
+
+ self::assertEquals(
+ 45,
+ $m->sum(-1)
+ );
+ }
+
+ public function testSumColumns() : void
+ {
+ $m = Matrix::fromArray([
+ [1, 2, 3],
+ [4, 5, 6],
+ [7, 8, 9],
+ ]);
+
+ self::assertEquals(
+ [12, 15, 18],
+ $m->sum(0)->toVectorArray()
+ );
+ }
+
+ public function testSumRows() : void
+ {
+ $m = Matrix::fromArray([
+ [1, 2, 3],
+ [4, 5, 6],
+ [7, 8, 9],
+ ]);
+
+ self::assertEquals(
+ [6, 15, 24],
+ $m->sum(1)->toVectorArray()
+ );
+ }
+
+ public function testDiaglonal() : void
+ {
+ $m = Matrix::fromArray([
+ [1, 2, 3],
+ [4, 5, 6],
+ [7, 8, 9],
+ ]);
+
+ self::assertFalse($m->isDiagonal());
+
+ $m = Matrix::fromArray([
+ [1, 0, 0],
+ [0, 5, 0],
+ [0, 0, -8],
+ ]);
+
+ self::assertTrue($m->isDiagonal());
+ }
+
+ public function testPow() : void
+ {
+ $m = Matrix::fromArray([
+ [1, 2, 3],
+ [4, 5, 6],
+ [7, 8, 9],
+ ]);
+
+ self::assertEquals(
+ [
+ [30, 36, 42],
+ [66, 81, 96],
+ [102, 126, 150],
+ ],
+ $m->pow(2)->toArray()
+ );
+
+ $m = Matrix::fromArray([
+ [1.5, 2.5, 3.5],
+ [4.5, 5.5, 6.5],
+ [7.5, 8.5, 9.5],
+ ]);
+
+ self::assertEqualsWithDelta(
+ [
+ [39.75, 47.25, 54.75],
+ [80.25, 96.75, 113.25],
+ [120.75, 146.25, 171.75],
+ ],
+ $m->pow(2)->toArray(),
+ 0.1
+ );
+
+ $m = Matrix::fromArray([
+ [1, 1, 1],
+ [1, 2, 3],
+ [1, 3, 6],
+ ]);
+
+ self::assertEqualsWithDelta(
+ [
+ [0.8901, 0.5882, 0.3684],
+ [0.5882, 1.2035, 1.3799],
+ [0.3684, 1.3799, 3.1167],
+ ],
+ $m->pow(2 / 3)->toArray(),
+ 0.01
+ );
+ }
+
+ public function testExp() : void
+ {
+ $m = Matrix::fromArray([
+ [1, 2, 3],
+ [4, 5, 6],
+ [7, 8, 9],
+ ]);
+
+ self::assertEqualsWithDelta(
+ [
+ [1118906.6994131860386, 1374815.062935806540981, 1630724.426458427043361],
+ [2533881.041898971697907, 3113415.03138055427637, 3692947.020862136854833],
+ [3948856.384384757357213, 4852012.999825302011759, 5755170.615265846666304],
+ ],
+ $m->exp(12)->toArray(),
+ 0.1
+ );
+ }
}
diff --git a/tests/Math/Matrix/VectorTest.php b/tests/Math/Matrix/VectorTest.php
index afc52c23c..70200aa89 100755
--- a/tests/Math/Matrix/VectorTest.php
+++ b/tests/Math/Matrix/VectorTest.php
@@ -65,4 +65,20 @@ final class VectorTest extends \PHPUnit\Framework\TestCase
self::assertEquals(5, $vec->getM());
}
+
+ public function testCosine() : void
+ {
+ $v1 = Vector::fromArray([3, 4, 0]);
+ $v2 = Vector::fromArray([4, 4, 2]);
+
+ self::assertEqualsWithDelta(14 / 15, $v1->cosine($v2), 0.1);
+ }
+
+ public function testCross3() : void
+ {
+ self::assertEquals(
+ [-15, -2, 39],
+ Vector::fromArray([3, -3, 1])->cross3(Vector::fromArray([4, 9, 2]))->toVectorArray()
+ );
+ }
}
diff --git a/tests/Math/Optimization/SimplexTest.php b/tests/Math/Optimization/SimplexTest.php
new file mode 100644
index 000000000..ca9c1be16
--- /dev/null
+++ b/tests/Math/Optimization/SimplexTest.php
@@ -0,0 +1,108 @@
+solve(
+ [
+ [-1, 1],
+ [1, 1],
+ [1, -4],
+ ],
+ [8, -3, 2],
+ [1, 3]
+ ),
+ 0.01
+ );
+ }
+
+ public function testSimplexBasicFeasible() : void
+ {
+ $simplex = new Simplex();
+ self::assertEqualsWithDelta(
+ [
+ [1.0, 0.0, 0.0, 0.0],
+ 5.0,
+ ],
+ $simplex->solve(
+ [
+ [-1, 1],
+ [-2, -1],
+ ],
+ [1, 2],
+ [5, -3]
+ ),
+ 0.0
+ );
+ }
+
+ public function testSimplexLPInfeasible() : void
+ {
+ $simplex = new Simplex();
+ self::assertEquals(
+ [
+ [-2, -2, -2, -2, -2],
+ \INF,
+ ],
+ $simplex->solve(
+ [
+ [-1, -1],
+ [2, 2],
+ ],
+ [2, -10],
+ [3, -2]
+ )
+ );
+ }
+
+ public function testSimplexLPUnbound() : void
+ {
+ $simplex = new Simplex();
+ self::assertEqualsWithDelta(
+ [
+ [-1, -1, -1, -1],
+ \INF,
+ ],
+ $simplex->solve(
+ [
+ [2, -1],
+ [1, 2],
+ ],
+ [-1, -2],
+ [1, -1]
+ ),
+ 0.01
+ );
+ }
+}
diff --git a/tests/Math/Solver/Root/BisectionTest.php b/tests/Math/Solver/Root/BisectionTest.php
new file mode 100644
index 000000000..830452251
--- /dev/null
+++ b/tests/Math/Solver/Root/BisectionTest.php
@@ -0,0 +1,34 @@
+ 3, 'y' => 4, 'z' => 0], ['x' => 4, 'y' => 4, 'z' => 2]),
+ 0.1
+ );
+ }
+
/**
* @testdox The bray-curtis distance can be calculated
* @covers phpOMS\Math\Topology\MetricsND
@@ -193,6 +207,18 @@ final class MetricsNDTest extends \PHPUnit\Framework\TestCase
MetricsND::canberra([3, 6, 4], [4, 6, 8, 3]);
}
+ /**
+ * @testdox Different dimension sizes for the coordinates in the cosine metric throw a InvalidDimensionException
+ * @covers phpOMS\Math\Topology\MetricsND
+ * @group framework
+ */
+ public function testInvalidCosineDimension() : void
+ {
+ $this->expectException(\phpOMS\Math\Matrix\Exception\InvalidDimensionException::class);
+
+ MetricsND::cosine([3, 6, 4], [4, 6, 8, 3]);
+ }
+
/**
* @testdox Different dimension sizes for the coordinates in the Bray Curtis metric throw a InvalidDimensionException
* @covers phpOMS\Math\Topology\MetricsND
diff --git a/tests/Message/HeaderAbstractTest.php b/tests/Message/HeaderAbstractTest.php
index f2f3c9ea3..c303e4100 100755
--- a/tests/Message/HeaderAbstractTest.php
+++ b/tests/Message/HeaderAbstractTest.php
@@ -48,7 +48,7 @@ final class HeaderAbstractTest extends \PHPUnit\Framework\TestCase
return true;
}
- public function get(string $key = null) : array
+ public function get(?string $key = null) : array
{
return [];
}
diff --git a/tests/Message/Http/HttpRequestTest.php b/tests/Message/Http/HttpRequestTest.php
index f62d2f485..b90fb5d4b 100755
--- a/tests/Message/Http/HttpRequestTest.php
+++ b/tests/Message/Http/HttpRequestTest.php
@@ -14,7 +14,6 @@ declare(strict_types=1);
namespace phpOMS\tests\Message\Http;
-use phpOMS\Localization\ISO639x1Enum;
use phpOMS\Localization\Localization;
use phpOMS\Message\Http\BrowserType;
use phpOMS\Message\Http\HttpRequest;
@@ -150,21 +149,6 @@ final class HttpRequestTest extends \PHPUnit\Framework\TestCase
self::assertEquals('http://www.google.com/test/path', $request->__toString());
}
- /**
- * @testdox The request langauge can be returned
- * @covers phpOMS\Message\Http\HttpRequest
- * @group framework
- */
- public function testLangaugeOutput() : void
- {
- $request = new HttpRequest(new HttpUri('http://www.google.com/test/path'), $l11n = new Localization());
-
- $request->header->l11n = new Localization();
- $request->header->l11n->setLanguage(ISO639x1Enum::_DE);
-
- self::assertEquals(ISO639x1Enum::_DE, $request->header->l11n->language);
- }
-
/**
* @testdox The url hashes for the different paths get correctly generated
* @covers phpOMS\Message\Http\HttpRequest
@@ -231,7 +215,7 @@ final class HttpRequestTest extends \PHPUnit\Framework\TestCase
*/
public function testDataJsonRead() : void
{
- $request = new HttpRequest(new HttpUri(''));
+ $request = new HttpRequest();
$data = [
1, 2, 3,
@@ -250,7 +234,7 @@ final class HttpRequestTest extends \PHPUnit\Framework\TestCase
*/
public function testEmptyDataJsonRead() : void
{
- $request = new HttpRequest(new HttpUri(''));
+ $request = new HttpRequest();
self::assertEquals([], $request->getDataJson('def'));
}
@@ -262,7 +246,7 @@ final class HttpRequestTest extends \PHPUnit\Framework\TestCase
*/
public function testInvalidDataJsonRead() : void
{
- $request = new HttpRequest(new HttpUri(''));
+ $request = new HttpRequest();
$data = [
"0" => 1, "1" => 2, "2" => 3,
@@ -281,7 +265,7 @@ final class HttpRequestTest extends \PHPUnit\Framework\TestCase
*/
public function testDataList() : void
{
- $request = new HttpRequest(new HttpUri(''));
+ $request = new HttpRequest();
$data = [
1, 2, 3,
@@ -299,7 +283,7 @@ final class HttpRequestTest extends \PHPUnit\Framework\TestCase
*/
public function testEmptyDataList() : void
{
- $request = new HttpRequest(new HttpUri(''));
+ $request = new HttpRequest();
self::assertEquals([], $request->getDataList('def'));
}
@@ -311,7 +295,7 @@ final class HttpRequestTest extends \PHPUnit\Framework\TestCase
*/
public function testDataLike() : void
{
- $request = new HttpRequest(new HttpUri(''));
+ $request = new HttpRequest();
$data = 'this is a test';
@@ -327,7 +311,7 @@ final class HttpRequestTest extends \PHPUnit\Framework\TestCase
*/
public function testInvalidDataLikeMatch() : void
{
- $request = new HttpRequest(new HttpUri(''));
+ $request = new HttpRequest();
$data = 'this is a test';
diff --git a/tests/Message/Http/HttpResponseTest.php b/tests/Message/Http/HttpResponseTest.php
index 571c327ad..0352ccf50 100755
--- a/tests/Message/Http/HttpResponseTest.php
+++ b/tests/Message/Http/HttpResponseTest.php
@@ -14,8 +14,6 @@ declare(strict_types=1);
namespace phpOMS\tests\Message\Http;
-use phpOMS\Localization\ISO639x1Enum;
-use phpOMS\Localization\Localization;
use phpOMS\Message\Http\HttpResponse;
use phpOMS\System\MimeType;
@@ -105,19 +103,6 @@ final class HttpResponseTest extends \PHPUnit\Framework\TestCase
self::assertEquals($start, \ob_get_level());
}
- /**
- * @testdox The response langauge can be returned
- * @covers phpOMS\Message\Http\HttpResponse
- * @group framework
- */
- public function testLangaugeOutput() : void
- {
- $this->response->header->l11n = new Localization();
- $this->response->header->l11n->setLanguage(ISO639x1Enum::_DE);
-
- self::assertEquals(ISO639x1Enum::_DE, $this->response->header->l11n->language);
- }
-
/**
* @testdox Response data can be turned into an array
* @covers phpOMS\Message\Http\HttpResponse
diff --git a/tests/Message/Mail/MailHandlerMailTrait.php b/tests/Message/Mail/MailHandlerMailTrait.php
index 81b554660..d49c729c3 100755
--- a/tests/Message/Mail/MailHandlerMailTrait.php
+++ b/tests/Message/Mail/MailHandlerMailTrait.php
@@ -308,10 +308,10 @@ trait MailHandlerMailTrait
$mail->confirmationAddress = 'test1@jingga.app';
$mail->setFrom('test1@jingga.app', 'Dennis Eichhorn');
$mail->addTo('test@jingga.app', 'Dennis Eichhorn');
- $mail->subject = 'testSendICalAltWithMail';
- $mail->body = 'Ical test';
- $mail->bodyAlt = 'Ical test';
- $mail->ical = 'BEGIN:VCALENDAR'
+ $mail->subject = 'testSendICalAltWithMail';
+ $mail->body = 'Ical test';
+ $mail->bodyAlt = 'Ical test';
+ $mail->ical = 'BEGIN:VCALENDAR'
. "\r\nVERSION:2.0"
. "\r\nPRODID:-//phpOMS//Karaka Calendar//EN"
. $methodLine
@@ -366,10 +366,10 @@ trait MailHandlerMailTrait
$mail->setFrom('test1@jingga.app', 'Dennis Eichhorn');
$mail->addTo('test@jingga.app', 'Dennis Eichhorn');
$mail->addAttachment(__DIR__ . '/files/logo.png', 'logo');
- $mail->subject = 'testSendICalAltAttachmentWithMail';
- $mail->body = 'Ical test';
- $mail->bodyAlt = 'Ical test';
- $mail->ical = 'BEGIN:VCALENDAR'
+ $mail->subject = 'testSendICalAltAttachmentWithMail';
+ $mail->body = 'Ical test';
+ $mail->bodyAlt = 'Ical test';
+ $mail->ical = 'BEGIN:VCALENDAR'
. "\r\nVERSION:2.0"
. "\r\nPRODID:-//phpOMS//Karaka Calendar//EN"
. $methodLine
diff --git a/tests/Message/Mail/MailHandlerSendmailTrait.php b/tests/Message/Mail/MailHandlerSendmailTrait.php
index 9e07c1481..737e33bdf 100755
--- a/tests/Message/Mail/MailHandlerSendmailTrait.php
+++ b/tests/Message/Mail/MailHandlerSendmailTrait.php
@@ -282,10 +282,10 @@ trait MailHandlerSendmailTrait
$mail->confirmationAddress = 'test1@jingga.app';
$mail->setFrom('test1@jingga.app', 'Dennis Eichhorn');
$mail->addTo('test@jingga.app', 'Dennis Eichhorn');
- $mail->subject = 'testSendICalAltWithSendmail';
- $mail->body = 'Ical test';
- $mail->bodyAlt = 'Ical test';
- $mail->ical = 'BEGIN:VCALENDAR'
+ $mail->subject = 'testSendICalAltWithSendmail';
+ $mail->body = 'Ical test';
+ $mail->bodyAlt = 'Ical test';
+ $mail->ical = 'BEGIN:VCALENDAR'
. "\r\nVERSION:2.0"
. "\r\nPRODID:-//phpOMS//Karaka Calendar//EN"
. $methodLine
@@ -338,10 +338,10 @@ trait MailHandlerSendmailTrait
$mail->setFrom('test1@jingga.app', 'Dennis Eichhorn');
$mail->addTo('test@jingga.app', 'Dennis Eichhorn');
$mail->addAttachment(__DIR__ . '/files/logo.png', 'logo');
- $mail->subject = 'testSendICalAltAttachmentWithSendmail';
- $mail->body = 'Ical test';
- $mail->bodyAlt = 'Ical test';
- $mail->ical = 'BEGIN:VCALENDAR'
+ $mail->subject = 'testSendICalAltAttachmentWithSendmail';
+ $mail->body = 'Ical test';
+ $mail->bodyAlt = 'Ical test';
+ $mail->ical = 'BEGIN:VCALENDAR'
. "\r\nVERSION:2.0"
. "\r\nPRODID:-//phpOMS//Karaka Calendar//EN"
. $methodLine
diff --git a/tests/Message/Mail/MailHandlerSmtpTrait.php b/tests/Message/Mail/MailHandlerSmtpTrait.php
index e14d2cff2..5a3e516c4 100755
--- a/tests/Message/Mail/MailHandlerSmtpTrait.php
+++ b/tests/Message/Mail/MailHandlerSmtpTrait.php
@@ -391,10 +391,10 @@ trait MailHandlerSmtpTrait
$mail->confirmationAddress = 'test1@jingga.app';
$mail->setFrom('test1@jingga.app', 'Dennis Eichhorn');
$mail->addTo('test@jingga.app', 'Dennis Eichhorn');
- $mail->subject = 'testSendICalAltWithSmtp';
- $mail->body = 'Ical test';
- $mail->bodyAlt = 'Ical test';
- $mail->ical = 'BEGIN:VCALENDAR'
+ $mail->subject = 'testSendICalAltWithSmtp';
+ $mail->body = 'Ical test';
+ $mail->bodyAlt = 'Ical test';
+ $mail->ical = 'BEGIN:VCALENDAR'
. "\r\nVERSION:2.0"
. "\r\nPRODID:-//phpOMS//Karaka Calendar//EN"
. $methodLine
@@ -456,10 +456,10 @@ trait MailHandlerSmtpTrait
$mail->setFrom('test1@jingga.app', 'Dennis Eichhorn');
$mail->addTo('test@jingga.app', 'Dennis Eichhorn');
$mail->addAttachment(__DIR__ . '/files/logo.png', 'logo');
- $mail->subject = 'testSendICalAltAttachmentWithSmtp';
- $mail->body = 'Ical test';
- $mail->bodyAlt = 'Ical test';
- $mail->ical = 'BEGIN:VCALENDAR'
+ $mail->subject = 'testSendICalAltAttachmentWithSmtp';
+ $mail->body = 'Ical test';
+ $mail->bodyAlt = 'Ical test';
+ $mail->ical = 'BEGIN:VCALENDAR'
. "\r\nVERSION:2.0"
. "\r\nPRODID:-//phpOMS//Karaka Calendar//EN"
. $methodLine
diff --git a/tests/Message/Mail/MailHandlerTest.php b/tests/Message/Mail/MailHandlerTest.php
index 0e5f40a7d..540ea0c68 100755
--- a/tests/Message/Mail/MailHandlerTest.php
+++ b/tests/Message/Mail/MailHandlerTest.php
@@ -42,9 +42,9 @@ final class MailHandlerTest extends \PHPUnit\Framework\TestCase
'countryName' => 'DE',
'stateOrProvinceName' => 'Hesse',
'localityName' => 'Frankfurt',
- 'organizationName' => 'Karaka',
+ 'organizationName' => 'Jingga',
'organizationalUnitName' => 'Framework',
- 'commonName' => 'Karaka Test',
+ 'commonName' => 'Jingga Test',
'emailAddress' => 'test@jingga.app',
];
$keyconfig = [
diff --git a/tests/Message/RequestAbstractTest.php b/tests/Message/RequestAbstractTest.php
index 7c6fd82fa..79c996aa7 100755
--- a/tests/Message/RequestAbstractTest.php
+++ b/tests/Message/RequestAbstractTest.php
@@ -96,4 +96,77 @@ final class RequestAbstractTest extends \PHPUnit\Framework\TestCase
$this->request->setData('key5', 1);
self::assertEquals(1, $this->request->getData('key5', 'invalid'));
}
+
+ public function testDataAllInputOutput() : void
+ {
+ $this->request->setData('asdf', false);
+ self::assertEquals(['asdf' => false], $this->request->getData());
+ }
+
+ /**
+ * @group framework
+ */
+ public function testDataJsonInputOutput() : void
+ {
+ $this->request->setData('asdf', '[1,2,3]');
+ self::assertEquals([1,2,3], $this->request->getDataJson('asdf'));
+ }
+
+ /**
+ * @group framework
+ */
+ public function testDataStringInputOutput() : void
+ {
+ $this->request->setData('asdf', 1);
+ self::assertEquals('1', $this->request->getDataString('asdf'));
+ self::assertEquals('1', $this->request->getData('asdf', 'string'));
+ }
+
+ /**
+ * @group framework
+ */
+ public function testDataBoolInputOutput() : void
+ {
+ $this->request->setData('asdf', 1);
+ self::assertTrue($this->request->getDataBool('asdf'));
+ self::assertTrue($this->request->getData('asdf', 'bool'));
+ }
+
+ /**
+ * @group framework
+ */
+ public function testDataFloatInputOutput() : void
+ {
+ $this->request->setData('asdf', 1);
+ self::assertEquals(1.0, $this->request->getDataFloat('asdf'));
+ self::assertEquals(1.0, $this->request->getData('asdf', 'float'));
+ }
+
+ /**
+ * @group framework
+ */
+ public function testDataDateTimeInputOutput() : void
+ {
+ $this->request->setData('asdf', '2023-01-01');
+ self::assertEquals((new \DateTime('2023-01-01'))->format('Y-m-d'), $this->request->getDataDateTime('asdf')->format('Y-m-d'));
+ self::assertEquals((new \DateTime('2023-01-01'))->format('Y-m-d'), $this->request->getData('asdf', 'DateTime')->format('Y-m-d'));
+ }
+
+ public function testDataInvalidTypeInputOutput() : void
+ {
+ $this->request->setData('asdf', 1);
+ self::assertEquals(1, $this->request->getData('asdf', 'invalid'));
+ }
+
+ /**
+ * @group framework
+ */
+ public function testInvalidDataTypeInputOutput() : void
+ {
+ self::assertNull($this->request->getDataString('a'));
+ self::assertNull($this->request->getDataBool('a'));
+ self::assertNull($this->request->getDataInt('a'));
+ self::assertNull($this->request->getDataFloat('a'));
+ self::assertNull($this->request->getDataDateTime('a'));
+ }
}
diff --git a/tests/Message/ResponseAbstractTest.php b/tests/Message/ResponseAbstractTest.php
index f4df8aab2..87530523b 100755
--- a/tests/Message/ResponseAbstractTest.php
+++ b/tests/Message/ResponseAbstractTest.php
@@ -67,6 +67,12 @@ final class ResponseAbstractTest extends \PHPUnit\Framework\TestCase
self::assertEquals([1], $this->response->jsonSerialize());
}
+ public function testDataAllInputOutput() : void
+ {
+ $this->response->set('asdf', false);
+ self::assertEquals(['asdf' => false], $this->response->getData());
+ }
+
/**
* @testdox Data can be set and returned for the response
* @covers phpOMS\Message\ResponseAbstract
@@ -77,4 +83,81 @@ final class ResponseAbstractTest extends \PHPUnit\Framework\TestCase
$this->response->set('asdf', false);
self::assertFalse($this->response->getData('asdf'));
}
+
+ /**
+ * @testdox Data can be set and returned for the response
+ * @covers phpOMS\Message\ResponseAbstract
+ * @group framework
+ */
+ public function testDataStringInputOutput() : void
+ {
+ $this->response->set('asdf', 1);
+ self::assertEquals('1', $this->response->getDataString('asdf'));
+ self::assertEquals('1', $this->response->getData('asdf', 'string'));
+ }
+
+ /**
+ * @testdox Data can be set and returned for the response
+ * @covers phpOMS\Message\ResponseAbstract
+ * @group framework
+ */
+ public function testDataBoolInputOutput() : void
+ {
+ $this->response->set('asdf', 1);
+ self::assertTrue($this->response->getDataBool('asdf'));
+ self::assertTrue($this->response->getData('asdf', 'bool'));
+ }
+
+ /**
+ * @testdox Data can be set and returned for the response
+ * @covers phpOMS\Message\ResponseAbstract
+ * @group framework
+ */
+ public function testDataFloatInputOutput() : void
+ {
+ $this->response->set('asdf', 1);
+ self::assertEquals(1.0, $this->response->getDataFloat('asdf'));
+ self::assertEquals(1.0, $this->response->getData('asdf', 'float'));
+ }
+
+ /**
+ * @group framework
+ */
+ public function testDataJsonInputOutput() : void
+ {
+ $this->response->set('asdf', '[1,2,3]');
+ self::assertEquals([1,2,3], $this->response->getDataJson('asdf'));
+ }
+
+ /**
+ * @testdox Data can be set and returned for the response
+ * @covers phpOMS\Message\ResponseAbstract
+ * @group framework
+ */
+ public function testDataDateTimeInputOutput() : void
+ {
+ $this->response->set('asdf', '2023-01-01');
+ self::assertEquals((new \DateTime('2023-01-01'))->format('Y-m-d'), $this->response->getDataDateTime('asdf')->format('Y-m-d'));
+ self::assertEquals((new \DateTime('2023-01-01'))->format('Y-m-d'), $this->response->getData('asdf', 'DateTime')->format('Y-m-d'));
+ }
+
+ public function testDataInvalidTypeInputOutput() : void
+ {
+ $this->response->set('asdf', 1);
+ self::assertEquals(1, $this->response->getData('asdf', 'invalid'));
+ }
+
+ /**
+ * @testdox Data can be set and returned for the response
+ * @covers phpOMS\Message\ResponseAbstract
+ * @group framework
+ */
+ public function testInvalidDataTypeInputOutput() : void
+ {
+ self::assertNull($this->response->getDataString('a'));
+ self::assertNull($this->response->getDataBool('a'));
+ self::assertNull($this->response->getDataInt('a'));
+ self::assertNull($this->response->getDataFloat('a'));
+ self::assertNull($this->response->getDataDateTime('a'));
+ }
}
diff --git a/tests/Model/Html/HeadTest.php b/tests/Model/Html/HeadTest.php
index 1639c91b1..4aea21376 100755
--- a/tests/Model/Html/HeadTest.php
+++ b/tests/Model/Html/HeadTest.php
@@ -43,7 +43,7 @@ final class HeadTest extends \PHPUnit\Framework\TestCase
{
self::assertInstanceOf('\phpOMS\Model\Html\Meta', $this->head->meta);
self::assertEquals('', $this->head->title);
- self::assertEquals('en', $this->head->getLanguage());
+ self::assertEquals('en', $this->head->language);
self::assertEquals([], $this->head->getStyleAll());
self::assertEquals([], $this->head->getScriptAll());
self::assertEquals('', $this->head->renderStyle());
@@ -86,17 +86,6 @@ final class HeadTest extends \PHPUnit\Framework\TestCase
self::assertEquals(['key' => 'console.log("msg");'], $this->head->getScriptAll());
}
- /**
- * @testdox The language can be set and returned
- * @covers phpOMS\Model\Html\Head
- * @group framework
- */
- public function testLanguageInputOutput() : void
- {
- $this->head->setLanguage('en');
- self::assertEquals('en', $this->head->getLanguage());
- }
-
/**
* @testdox The assets can be set and rendered
* @covers phpOMS\Model\Html\Head
diff --git a/tests/Model/Message/NotifyTest.php b/tests/Model/Message/NotifyTest.php
index b6335f910..40a17e6ab 100755
--- a/tests/Model/Message/NotifyTest.php
+++ b/tests/Model/Message/NotifyTest.php
@@ -48,7 +48,7 @@ final class NotifyTest extends \PHPUnit\Framework\TestCase
$obj->delay = 3;
$obj->stay = 5;
$obj->level = NotificationLevel::ERROR;
- $obj->message ='msg';
+ $obj->message = 'msg';
$obj->title = 'title';
self::assertEquals([
diff --git a/tests/Module/InstallerAbstractTest.php b/tests/Module/InstallerAbstractTest.php
index d66f88ab9..d3e1c4e02 100755
--- a/tests/Module/InstallerAbstractTest.php
+++ b/tests/Module/InstallerAbstractTest.php
@@ -61,12 +61,12 @@ final class InstallerAbstractTest extends \PHPUnit\Framework\TestCase
public function get(
mixed $ids = null,
- string | array $names = null,
- int $unit = null,
- int $app = null,
- string $module = null,
- int $group = null,
- int $account = null
+ string | array|null $names = null,
+ ?int $unit = null,
+ ?int $app = null,
+ ?string $module = null,
+ ?int $group = null,
+ ?int $account = null
) : mixed
{
return null;
diff --git a/tests/Module/ModuleAbstractTest.php b/tests/Module/ModuleAbstractTest.php
index c586e79bd..063e11a4d 100755
--- a/tests/Module/ModuleAbstractTest.php
+++ b/tests/Module/ModuleAbstractTest.php
@@ -26,7 +26,6 @@ use phpOMS\tests\DataStorage\Database\TestModel\BaseModel;
use phpOMS\tests\DataStorage\Database\TestModel\BaseModelMapper;
use phpOMS\tests\DataStorage\Database\TestModel\ManyToManyRelModel;
use phpOMS\tests\DataStorage\Database\TestModel\ManyToManyRelModelMapper;
-use phpOMS\Uri\HttpUri;
/**
* @testdox phpOMS\tests\Module\ModuleAbstractTest: Abstract module
@@ -102,7 +101,7 @@ final class ModuleAbstractTest extends \PHPUnit\Framework\TestCase
$model1 = BaseModelMapper::get()->where('id', 1)->execute();
$model2 = ManyToManyRelModelMapper::get()->where('id', 1)->execute();
- $this->createModelRelation(1, $model1->getId(), $model2->id, BaseModelMapper::class, 'hasManyRelations', '', '127.0.0.1');
+ $this->createModelRelation(1, $model1->id, $model2->id, BaseModelMapper::class, 'hasManyRelations', '', '127.0.0.1');
}
public function deleteRelationDB() : void
@@ -110,7 +109,7 @@ final class ModuleAbstractTest extends \PHPUnit\Framework\TestCase
$model1 = BaseModelMapper::get()->where('id', 1)->execute();
$model2 = ManyToManyRelModelMapper::get()->where('id', 1)->execute();
- $this->deleteModelRelation(1, $model1->getId(), $model2->id, BaseModelMapper::class, 'hasManyRelations', '', '127.0.0.1');
+ $this->deleteModelRelation(1, $model1->id, $model2->id, BaseModelMapper::class, 'hasManyRelations', '', '127.0.0.1');
}
public function creates() : void
@@ -246,7 +245,7 @@ final class ModuleAbstractTest extends \PHPUnit\Framework\TestCase
*/
public function testFillJson() : void
{
- $request = new HttpRequest(new HttpUri(''));
+ $request = new HttpRequest();
$response = new HttpResponse();
$this->module->fillJson($request, $response, 'OK', 'Test Title', 'Test Message!', [1, 'test string', 'bool' => true]);
@@ -269,7 +268,7 @@ final class ModuleAbstractTest extends \PHPUnit\Framework\TestCase
*/
public function testFillJsonRaw() : void
{
- $request = new HttpRequest(new HttpUri(''));
+ $request = new HttpRequest();
$response = new HttpResponse();
$this->module->fillJsonRaw($request, $response, [1, 'test string', 'bool' => true]);
@@ -285,21 +284,27 @@ final class ModuleAbstractTest extends \PHPUnit\Framework\TestCase
*/
private function dbSetup() : void
{
+ \phpOMS\Log\FileLogger::getInstance()->verbose = true;
+
$GLOBALS['dbpool']->get()->con->prepare(
'CREATE TABLE `test_base` (
`test_base_id` int(11) NOT NULL AUTO_INCREMENT,
`test_base_string` varchar(254) NOT NULL,
+ `test_base_compress` BLOB NOT NULL,
+ `test_base_pstring` varchar(254) NOT NULL,
`test_base_int` int(11) NOT NULL,
`test_base_bool` tinyint(1) DEFAULT NULL,
`test_base_null` int(11) DEFAULT NULL,
`test_base_float` decimal(5, 4) DEFAULT NULL,
`test_base_belongs_to_one` int(11) DEFAULT NULL,
+ `test_base_belongs_top_one` int(11) DEFAULT NULL,
`test_base_owns_one_self` int(11) DEFAULT NULL,
+ `test_base_owns_onep_self` int(11) DEFAULT NULL,
`test_base_json` varchar(254) DEFAULT NULL,
`test_base_json_serializable` varchar(254) DEFAULT NULL,
`test_base_serializable` varchar(254) DEFAULT NULL,
`test_base_datetime` datetime DEFAULT NULL,
- `test_base_datetime_null` datetime DEFAULT NULL, /* There was a bug where it returned the current date because new \DateTime(null) === current date which is wrong, we want null as value! */
+ `test_base_datetime_null` datetime DEFAULT NULL,
PRIMARY KEY (`test_base_id`)
)ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 AUTO_INCREMENT=1;'
)->execute();
@@ -355,6 +360,49 @@ final class ModuleAbstractTest extends \PHPUnit\Framework\TestCase
PRIMARY KEY (`test_has_many_rel_relations_id`)
)ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 AUTO_INCREMENT=1;'
)->execute();
+
+ // private
+ $GLOBALS['dbpool']->get()->con->prepare(
+ 'CREATE TABLE `test_has_many_directp` (
+ `test_has_many_directp_id` int(11) NOT NULL AUTO_INCREMENT,
+ `test_has_many_directp_string` varchar(254) NOT NULL,
+ `test_has_many_directp_to` int(11) NOT NULL,
+ PRIMARY KEY (`test_has_many_directp_id`)
+ )ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 AUTO_INCREMENT=1;'
+ )->execute();
+
+ $GLOBALS['dbpool']->get()->con->prepare(
+ 'CREATE TABLE `test_has_many_relp` (
+ `test_has_many_relp_id` int(11) NOT NULL AUTO_INCREMENT,
+ `test_has_many_relp_string` varchar(254) NOT NULL,
+ PRIMARY KEY (`test_has_many_relp_id`)
+ )ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 AUTO_INCREMENT=1;'
+ )->execute();
+
+ $GLOBALS['dbpool']->get()->con->prepare(
+ 'CREATE TABLE `test_has_many_rel_relationsp` (
+ `test_has_many_rel_relationsp_id` int(11) NOT NULL AUTO_INCREMENT,
+ `test_has_many_rel_relationsp_src` int(11) NOT NULL,
+ `test_has_many_rel_relationsp_dest` int(11) NOT NULL,
+ PRIMARY KEY (`test_has_many_rel_relationsp_id`)
+ )ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 AUTO_INCREMENT=1;'
+ )->execute();
+
+ $GLOBALS['dbpool']->get()->con->prepare(
+ 'CREATE TABLE `test_belongs_to_onep` (
+ `test_belongs_to_onep_id` int(11) NOT NULL AUTO_INCREMENT,
+ `test_belongs_to_onep_string` varchar(254) NOT NULL,
+ PRIMARY KEY (`test_belongs_to_onep_id`)
+ )ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 AUTO_INCREMENT=1;'
+ )->execute();
+
+ $GLOBALS['dbpool']->get()->con->prepare(
+ 'CREATE TABLE `test_owns_onep` (
+ `test_owns_onep_id` int(11) NOT NULL AUTO_INCREMENT,
+ `test_owns_onep_string` varchar(254) NOT NULL,
+ PRIMARY KEY (`test_owns_onep_id`)
+ )ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 AUTO_INCREMENT=1;'
+ )->execute();
}
/**
@@ -369,6 +417,14 @@ final class ModuleAbstractTest extends \PHPUnit\Framework\TestCase
$GLOBALS['dbpool']->get()->con->prepare('DROP TABLE test_has_many_direct')->execute();
$GLOBALS['dbpool']->get()->con->prepare('DROP TABLE test_has_many_rel')->execute();
$GLOBALS['dbpool']->get()->con->prepare('DROP TABLE test_has_many_rel_relations')->execute();
+
+ $GLOBALS['dbpool']->get()->con->prepare('DROP TABLE test_has_many_directp')->execute();
+ $GLOBALS['dbpool']->get()->con->prepare('DROP TABLE test_has_many_relp')->execute();
+ $GLOBALS['dbpool']->get()->con->prepare('DROP TABLE test_has_many_rel_relationsp')->execute();
+ $GLOBALS['dbpool']->get()->con->prepare('DROP TABLE test_belongs_to_onep')->execute();
+ $GLOBALS['dbpool']->get()->con->prepare('DROP TABLE test_owns_onep')->execute();
+
+ \phpOMS\Log\FileLogger::getInstance()->verbose = false;
}
/**
diff --git a/tests/Module/ModuleInfoTest.php b/tests/Module/ModuleInfoTest.php
index 23964bfe3..0b749a749 100755
--- a/tests/Module/ModuleInfoTest.php
+++ b/tests/Module/ModuleInfoTest.php
@@ -112,7 +112,7 @@ final class ModuleInfoTest extends \PHPUnit\Framework\TestCase
$info = new ModuleInfo(__DIR__ . '/info-test.json');
$info->load();
- $testObj = new class() {
+ $testObj = new class() {
public $test = 1;
public function test() : void
diff --git a/tests/Module/ModuleManagerTest.php b/tests/Module/ModuleManagerTest.php
index 60adacf9c..79776bf28 100755
--- a/tests/Module/ModuleManagerTest.php
+++ b/tests/Module/ModuleManagerTest.php
@@ -45,7 +45,7 @@ final class ModuleManagerTest extends \PHPUnit\Framework\TestCase
*/
protected function setUp() : void
{
- $this->app = new class() extends ApplicationAbstract {
+ $this->app = new class() extends ApplicationAbstract {
protected string $appName = 'Api';
};
@@ -153,7 +153,7 @@ final class ModuleManagerTest extends \PHPUnit\Framework\TestCase
self::assertTrue($this->moduleManager->activate('TestModule'));
// this is normally done in the ApiController
- $module->setStatus(ModuleStatus::ACTIVE);
+ $module->status = ModuleStatus::ACTIVE;
ModuleMapper::update()->execute($module);
$queryLoad = new Builder($this->app->dbPool->get('insert'));
diff --git a/tests/Module/info-test.json b/tests/Module/info-test.json
index daf851593..92998de85 100755
--- a/tests/Module/info-test.json
+++ b/tests/Module/info-test.json
@@ -14,7 +14,6 @@
"name": "Jingga",
"website": "jingga.app"
},
- "description": "The administration module.",
"directory": "Admin",
"dependencies": [],
"providing": {
diff --git a/tests/Router/SocketRouterTest.php b/tests/Router/SocketRouterTest.php
index 72d7ebcdb..6d29465b9 100755
--- a/tests/Router/SocketRouterTest.php
+++ b/tests/Router/SocketRouterTest.php
@@ -108,7 +108,7 @@ final class SocketRouterTest extends \PHPUnit\Framework\TestCase
*/
public function testDynamicRouteAdding() : void
{
- $this->router->add('^.*backends_admin -settings=general.*$', 'Controller:test');
+ $this->router->add('^.*backends_admin -settings=general(\?.*$|$)', 'Controller:test');
self::assertEquals(
[['dest' => 'Controller:test']],
$this->router->route('backends_admin -settings=general -t 123')
@@ -219,7 +219,7 @@ final class SocketRouterTest extends \PHPUnit\Framework\TestCase
public function testDataValidation() : void
{
$this->router->add(
- '^.*backends_admin -settings=general.*$',
+ '^.*backends_admin -settings=general(\?.*$|$)',
'Controller:test',
validation: ['test_pattern' => '/^[a-z]*$/']
);
@@ -238,7 +238,7 @@ final class SocketRouterTest extends \PHPUnit\Framework\TestCase
public function testInvalidDataValidation() : void
{
$this->router->add(
- '^.*backends_admin -settings=general.*$',
+ '^.*backends_admin -settings=general(\?.*$|$)',
'Controller:test',
validation: ['test_pattern' => '/^[a-z]*$/']
);
@@ -257,7 +257,7 @@ final class SocketRouterTest extends \PHPUnit\Framework\TestCase
public function testDataFromPattern() : void
{
$this->router->add(
- '^.*-settings=general.*$',
+ '^.*-settings=general(\?.*$|$)',
'Controller:test',
dataPattern: '/^.*?(settings)=([a-z]*).*?$/'
);
diff --git a/tests/Router/WebRouterTest.php b/tests/Router/WebRouterTest.php
index ebe3ac000..041d1bd03 100755
--- a/tests/Router/WebRouterTest.php
+++ b/tests/Router/WebRouterTest.php
@@ -53,7 +53,7 @@ final class WebRouterTest extends \PHPUnit\Framework\TestCase
{
self::assertEmpty(
$this->router->route(
- (new HttpRequest(new HttpUri('')))->uri->getRoute()
+ (new HttpRequest())->uri->getRoute()
)
);
}
@@ -142,7 +142,7 @@ final class WebRouterTest extends \PHPUnit\Framework\TestCase
*/
public function testDynamicRouteAdding() : void
{
- $this->router->add('^.*/backends/admin/settings/general.*$', 'Controller:test', RouteVerb::GET | RouteVerb::SET);
+ $this->router->add('^.*/backends/admin/settings/general(\?.*$|$)', 'Controller:test', RouteVerb::GET | RouteVerb::SET);
self::assertEquals(
[['dest' => 'Controller:test']],
$this->router->route(
@@ -318,7 +318,7 @@ final class WebRouterTest extends \PHPUnit\Framework\TestCase
public function testDataValidation() : void
{
$this->router->add(
- '^.*/backends/admin/settings/general.*$',
+ '^.*/backends/admin/settings/general(\?.*$|$)',
'Controller:test',
RouteVerb::GET | RouteVerb::SET,
false,
@@ -335,14 +335,14 @@ final class WebRouterTest extends \PHPUnit\Framework\TestCase
}
/**
- * @testdox A data validation pattern invalidates missmatches
+ * @testdox A data validation pattern invalidates miss-matches
* @covers phpOMS\Router\WebRouter
* @group framework
*/
public function testInvalidDataValidation() : void
{
$this->router->add(
- '^.*/backends/admin/settings/general.*$',
+ '^.*/backends/admin/settings/general(\?.*$|$)',
'Controller:test',
RouteVerb::GET | RouteVerb::SET,
false,
@@ -366,7 +366,7 @@ final class WebRouterTest extends \PHPUnit\Framework\TestCase
public function testDataFromPattern() : void
{
$this->router->add(
- '^.*/backends/admin.*$',
+ '^.*/backends/admin(\?.*$|$)',
'Controller:test',
RouteVerb::GET | RouteVerb::SET,
false,
diff --git a/tests/Router/socketRouterTestFile.php b/tests/Router/socketRouterTestFile.php
index 9fb5e48d0..3a4b22f4e 100755
--- a/tests/Router/socketRouterTestFile.php
+++ b/tests/Router/socketRouterTestFile.php
@@ -1,7 +1,7 @@
[
+ '^.*backend_admin -settings=general(\?.*$|$)' => [
0 => [
'dest' => '\Modules\Admin\Controller:viewSettingsGeneral',
],
diff --git a/tests/Router/socketRouterTestFilePermission.php b/tests/Router/socketRouterTestFilePermission.php
index 359f24003..6e33a2e90 100755
--- a/tests/Router/socketRouterTestFilePermission.php
+++ b/tests/Router/socketRouterTestFilePermission.php
@@ -4,13 +4,13 @@ declare(strict_types=1);
use phpOMS\Account\PermissionType;
return [
- '^.*backend_admin -settings=general.*$' => [
+ '^.*backend_admin -settings=general(\?.*$|$)' => [
0 => [
'dest' => '\Modules\Admin\Controller:viewSettingsGeneral',
'permission' => [
- 'module' => 'TEST',
- 'type' => PermissionType::READ,
- 'category' => 1,
+ 'module' => 'TEST',
+ 'type' => PermissionType::READ,
+ 'category' => 1,
],
],
],
diff --git a/tests/Router/webRouteTestCsrf.php b/tests/Router/webRouteTestCsrf.php
index 693807819..43edd600e 100755
--- a/tests/Router/webRouteTestCsrf.php
+++ b/tests/Router/webRouteTestCsrf.php
@@ -1,7 +1,7 @@
[
+ '^.*/backend/admin/settings/csrf(\?.*$|$)' => [
0 => [
'dest' => '\Modules\Admin\Controller:viewCsrf',
'verb' => 1,
diff --git a/tests/Router/webRouterTestFile.php b/tests/Router/webRouterTestFile.php
index a6945522a..7f4fb925c 100755
--- a/tests/Router/webRouterTestFile.php
+++ b/tests/Router/webRouterTestFile.php
@@ -1,7 +1,7 @@
[
+ '^.*/backend/admin/settings/general(\?.*$|$)' => [
0 => [
'dest' => '\Modules\Admin\Controller:viewSettingsGeneral',
'verb' => 1,
diff --git a/tests/Router/webRouterTestFilePermission.php b/tests/Router/webRouterTestFilePermission.php
index b44c375c5..5441e72bf 100755
--- a/tests/Router/webRouterTestFilePermission.php
+++ b/tests/Router/webRouterTestFilePermission.php
@@ -5,14 +5,14 @@ use phpOMS\Account\PermissionType;
use phpOMS\Router\RouteVerb;
return [
- '^.*/backend/admin/settings/general.*$' => [
+ '^.*/backend/admin/settings/general(\?.*$|$)' => [
0 => [
'dest' => '\Modules\Admin\Controller:viewSettingsGeneral',
'verb' => RouteVerb::GET,
'permission' => [
- 'module' => 'TEST',
- 'type' => PermissionType::READ,
- 'category' => 1,
+ 'module' => 'TEST',
+ 'type' => PermissionType::READ,
+ 'category' => 1,
],
],
],
diff --git a/tests/Security/EncryptionHelperTest.php b/tests/Security/EncryptionHelperTest.php
index c3c82bc05..017dbb862 100644
--- a/tests/Security/EncryptionHelperTest.php
+++ b/tests/Security/EncryptionHelperTest.php
@@ -49,8 +49,8 @@ final class EncryptionHelperTest extends \PHPUnit\Framework\TestCase
public function testFileEncryption() : void
{
- if (\is_file(__DIR__ . '/encrytped.txt')) {
- \unlink(__DIR__ . '/encrytped.txt');
+ if (\is_file(__DIR__ . '/encrypted.txt')) {
+ \unlink(__DIR__ . '/encrypted.txt');
}
if (\is_file(__DIR__ . '/decrypted.txt')) {
@@ -58,22 +58,22 @@ final class EncryptionHelperTest extends \PHPUnit\Framework\TestCase
}
$key = EncryptionHelper::createSharedKey();
- self::assertTrue(EncryptionHelper::encryptFile(__DIR__ . '/plain.txt', __DIR__ . '/encrytped.txt', $key));
+ self::assertTrue(EncryptionHelper::encryptFile(__DIR__ . '/plain.txt', __DIR__ . '/encrypted.txt', $key));
self::assertNotEquals(
\file_get_contents(__DIR__ . '/plain.txt'),
- \file_get_contents(__DIR__ . '/encrytped.txt')
+ \file_get_contents(__DIR__ . '/encrypted.txt')
);
- self::assertTrue(EncryptionHelper::decryptFile(__DIR__ . '/encrytped.txt', __DIR__ . '/decrypted.txt', $key));
+ self::assertTrue(EncryptionHelper::decryptFile(__DIR__ . '/encrypted.txt', __DIR__ . '/decrypted.txt', $key));
self::assertEquals(
\file_get_contents(__DIR__ . '/plain.txt'),
\file_get_contents(__DIR__ . '/decrypted.txt')
);
- if (\is_file(__DIR__ . '/encrytped.txt')) {
- \unlink(__DIR__ . '/encrytped.txt');
+ if (\is_file(__DIR__ . '/encrypted.txt')) {
+ \unlink(__DIR__ . '/encrypted.txt');
}
if (\is_file(__DIR__ . '/decrypted.txt')) {
diff --git a/tests/Security/GuardTest.php b/tests/Security/GuardTest.php
index 89b80078f..8bac47439 100644
--- a/tests/Security/GuardTest.php
+++ b/tests/Security/GuardTest.php
@@ -56,4 +56,16 @@ final class GuardTest extends \PHPUnit\Framework\TestCase
)
);
}
+
+ /**
+ * @testdox A string can be validated for shell safety
+ * @covers phpOMS\Security\Guard
+ * @group framework
+ */
+ public function testIsShellSafe() : void
+ {
+ self::assertTrue(Guard::isShellSafe('asdf'));
+ self::assertFalse(Guard::isShellSafe('`|*?~<>^()[]{}$\\'));
+ self::assertFalse(Guard::isShellSafe('™'));
+ }
}
diff --git a/tests/Socket/Client/ClientTest.php b/tests/Socket/Client/ClientTest.php
index 719c3cfc1..c850dee93 100755
--- a/tests/Socket/Client/ClientTest.php
+++ b/tests/Socket/Client/ClientTest.php
@@ -59,18 +59,18 @@ final class ClientTest extends \PHPUnit\Framework\TestCase
protected string $appName = 'Socket';
};
- $this->app->logger = new FileLogger(__DIR__ . '/client.log', false);
- $this->app->dbPool = $GLOBALS['dbpool'];
- $this->app->unitId = 1;
- $this->app->cachePool = new CachePool($this->app->dbPool);
- $this->app->accountManager = new AccountManager($GLOBALS['session']);
- $this->app->appSettings = new CoreSettings();
- $this->app->moduleManager = new ModuleManager($this->app, __DIR__ . '/../../../../Modules/');
- $this->app->dispatcher = new Dispatcher($this->app);
- $this->app->eventManager = new EventManager($this->app->dispatcher);
+ $this->app->logger = new FileLogger(__DIR__ . '/client.log', false);
+ $this->app->dbPool = $GLOBALS['dbpool'];
+ $this->app->unitId = 1;
+ $this->app->cachePool = new CachePool($this->app->dbPool);
+ $this->app->accountManager = new AccountManager($GLOBALS['session']);
+ $this->app->appSettings = new CoreSettings();
+ $this->app->moduleManager = new ModuleManager($this->app, __DIR__ . '/../../../../Modules/');
+ $this->app->dispatcher = new Dispatcher($this->app);
+ $this->app->eventManager = new EventManager($this->app->dispatcher);
$this->app->eventManager->importFromFile(__DIR__ . '/../../../Socket/Hooks.php');
- $this->app->l11nManager = new L11nManager();
- $this->app->router = new SocketRouter();
+ $this->app->l11nManager = new L11nManager();
+ $this->app->router = new SocketRouter();
}
protected function tearDown() : void
diff --git a/tests/Socket/Client/ClientTestHelper.php b/tests/Socket/Client/ClientTestHelper.php
index 84700ab90..1728af467 100755
--- a/tests/Socket/Client/ClientTestHelper.php
+++ b/tests/Socket/Client/ClientTestHelper.php
@@ -49,18 +49,18 @@ $app = new class() extends ApplicationAbstract
protected string $appName = 'Socket';
};
-$app->logger = FileLogger::getInstance(__DIR__ . '/server.log', true);
-$app->dbPool = $GLOBALS['dbpool'];
-$app->unitId = 1;
-$app->cachePool = new CachePool($app->dbPool);
-$app->accountManager = new AccountManager($GLOBALS['session']);
-$app->appSettings = new CoreSettings($app->dbPool->get());
-$app->moduleManager = new ModuleManager($app, __DIR__ . '/../../../../Modules/');
-$app->dispatcher = new Dispatcher($app);
-$app->eventManager = new EventManager($app->dispatcher);
+$app->logger = FileLogger::getInstance(__DIR__ . '/server.log', true);
+$app->dbPool = $GLOBALS['dbpool'];
+$app->unitId = 1;
+$app->cachePool = new CachePool($app->dbPool);
+$app->accountManager = new AccountManager($GLOBALS['session']);
+$app->appSettings = new CoreSettings($app->dbPool->get());
+$app->moduleManager = new ModuleManager($app, __DIR__ . '/../../../../Modules/');
+$app->dispatcher = new Dispatcher($app);
+$app->eventManager = new EventManager($app->dispatcher);
$app->eventManager->importFromFile(__DIR__ . '/../../../Socket/Hooks.php');
-$app->l11nManager = new L11nManager();
-$app->router = new SocketRouter();
+$app->l11nManager = new L11nManager();
+$app->router = new SocketRouter();
$socket = new Server($app);
$socket->create('127.0.0.1', $config['socket']['master']['port']);
diff --git a/tests/Socket/Server/ServerTest.php b/tests/Socket/Server/ServerTest.php
index 247415a4e..a44349699 100755
--- a/tests/Socket/Server/ServerTest.php
+++ b/tests/Socket/Server/ServerTest.php
@@ -59,18 +59,18 @@ final class ServerTest extends \PHPUnit\Framework\TestCase
protected string $appName = 'Socket';
};
- $this->app->logger = new FileLogger(__DIR__ . '/server.log', false);
- $this->app->dbPool = $GLOBALS['dbpool'];
- $this->app->unitId = 1;
- $this->app->cachePool = new CachePool($this->app->dbPool);
- $this->app->accountManager = new AccountManager($GLOBALS['session']);
- $this->app->appSettings = new CoreSettings();
- $this->app->moduleManager = new ModuleManager($this->app, __DIR__ . '/../../../../Modules/');
- $this->app->dispatcher = new Dispatcher($this->app);
- $this->app->eventManager = new EventManager($this->app->dispatcher);
+ $this->app->logger = new FileLogger(__DIR__ . '/server.log', false);
+ $this->app->dbPool = $GLOBALS['dbpool'];
+ $this->app->unitId = 1;
+ $this->app->cachePool = new CachePool($this->app->dbPool);
+ $this->app->accountManager = new AccountManager($GLOBALS['session']);
+ $this->app->appSettings = new CoreSettings();
+ $this->app->moduleManager = new ModuleManager($this->app, __DIR__ . '/../../../../Modules/');
+ $this->app->dispatcher = new Dispatcher($this->app);
+ $this->app->eventManager = new EventManager($this->app->dispatcher);
$this->app->eventManager->importFromFile(__DIR__ . '/../../../Socket/Hooks.php');
- $this->app->l11nManager = new L11nManager();
- $this->app->router = new SocketRouter();
+ $this->app->l11nManager = new L11nManager();
+ $this->app->router = new SocketRouter();
}
protected function tearDown() : void
diff --git a/tests/Stdlib/Base/AddressTypeTest.php b/tests/Stdlib/Base/AddressTypeTest.php
index f1e89e61e..931513cf3 100755
--- a/tests/Stdlib/Base/AddressTypeTest.php
+++ b/tests/Stdlib/Base/AddressTypeTest.php
@@ -27,7 +27,7 @@ final class AddressTypeTest extends \PHPUnit\Framework\TestCase
*/
public function testEnumCount() : void
{
- self::assertCount(8, AddressType::getconstants());
+ self::assertCount(8, AddressType::getConstants());
}
/**
@@ -50,7 +50,6 @@ final class AddressTypeTest extends \PHPUnit\Framework\TestCase
self::assertEquals(3, AddressType::SHIPPING);
self::assertEquals(4, AddressType::BILLING);
self::assertEquals(5, AddressType::WORK);
- self::assertEquals(6, AddressType::CONTRACT);
self::assertEquals(7, AddressType::OTHER);
self::assertEquals(8, AddressType::EDUCATION);
}
diff --git a/tests/Stdlib/Base/LocationTest.php b/tests/Stdlib/Base/LocationTest.php
index 08bd21eb1..d5e4dd2f3 100755
--- a/tests/Stdlib/Base/LocationTest.php
+++ b/tests/Stdlib/Base/LocationTest.php
@@ -53,11 +53,11 @@ final class LocationTest extends \PHPUnit\Framework\TestCase
self::assertEquals('', $this->location->postal);
self::assertEquals('', $this->location->city);
- self::assertEquals('XX', $this->location->getCountry());
+ self::assertEquals('XX', $this->location->country);
self::assertEquals('', $this->location->address);
self::assertEquals('', $this->location->state);
- self::assertEquals(0, $this->location->getId());
- self::assertEquals(AddressType::HOME, $this->location->getType());
+ self::assertEquals(0, $this->location->id);
+ self::assertEquals(AddressType::HOME, $this->location->type);
self::assertEquals($expected, $this->location->toArray());
self::assertEquals($expected, $this->location->jsonSerialize());
}
@@ -73,17 +73,6 @@ final class LocationTest extends \PHPUnit\Framework\TestCase
self::assertEquals('0123456789', $this->location->postal);
}
- /**
- * @testdox The type can be set and returned
- * @covers phpOMS\Stdlib\Base\Location
- * @group framework
- */
- public function testTypeInputOutput() : void
- {
- $this->location->setType(AddressType::BUSINESS);
- self::assertEquals(AddressType::BUSINESS, $this->location->getType());
- }
-
/**
* @testdox The city can be set and returned
* @covers phpOMS\Stdlib\Base\Location
@@ -103,7 +92,7 @@ final class LocationTest extends \PHPUnit\Framework\TestCase
public function testCountryInputOutput() : void
{
$this->location->setCountry('Country');
- self::assertEquals('Country', $this->location->getCountry());
+ self::assertEquals('Country', $this->location->country);
}
/**
@@ -145,8 +134,8 @@ final class LocationTest extends \PHPUnit\Framework\TestCase
'lon' => 11.2,
];
- $this->location->postal = '0123456789';
- $this->location->setType(AddressType::BUSINESS);
+ $this->location->postal = '0123456789';
+ $this->location->type = AddressType::BUSINESS;
$this->location->city = 'city';
$this->location->address = 'Some address here';
$this->location->state = 'This is a state 123';
@@ -174,8 +163,8 @@ final class LocationTest extends \PHPUnit\Framework\TestCase
'lon' => 11.2,
];
- $this->location->postal = '0123456789';
- $this->location->setType(AddressType::BUSINESS);
+ $this->location->postal = '0123456789';
+ $this->location->type = AddressType::BUSINESS;
$this->location->city = 'city';
$this->location->address = 'Some address here';
$this->location->state = 'This is a state 123';
diff --git a/tests/Stdlib/Graph/NodeTest.php b/tests/Stdlib/Graph/NodeTest.php
index 953f19610..a399d7706 100755
--- a/tests/Stdlib/Graph/NodeTest.php
+++ b/tests/Stdlib/Graph/NodeTest.php
@@ -143,7 +143,8 @@ final class NodeTest extends \PHPUnit\Framework\TestCase
* @covers phpOMS\Stdlib\Graph\Node
* @group framework
*
- * @todo: is there bug where directed graphs return invalid neighbors?
+ * @bug Directed graphs may return invalid neighbors
+ * https://github.com/Karaka-Management/phpOMS/issues/366
*/
public function testNeighborsInputOutput() : void
{
diff --git a/tests/Stdlib/Tree/BinarySearchTreeTest.php b/tests/Stdlib/Tree/BinarySearchTreeTest.php
new file mode 100644
index 000000000..73276be49
--- /dev/null
+++ b/tests/Stdlib/Tree/BinarySearchTreeTest.php
@@ -0,0 +1,149 @@
+insert(new Node('D', 'D'));
+ $bst->insert(new Node('I', 'I'));
+ $bst->insert(new Node('N', 'N'));
+ $bst->insert(new Node('O', 'O'));
+ $bst->insert(new Node('S', 'S'));
+ $bst->insert(new Node('A', 'A'));
+ $bst->insert(new Node('U', 'U'));
+ $bst->insert(new Node('R', 'R'));
+
+ self::assertEquals(
+ [
+ 'key' => 'D',
+ 0 => [
+ 'key' => 'A',
+ 0 => null,
+ 1 => null,
+ ],
+ 1 => [
+ 'key' => 'I',
+ 0 => null,
+ 1 => [
+ 'key' => 'N',
+ 0 => null,
+ 1 => [
+ 'key' => 'O',
+ 0 => null,
+ 1 => [
+ 'key' => 'S',
+ 0 => [
+ 'key' => 'R',
+ 0 => null,
+ 1 => null,
+ ],
+ 1 => [
+ 'key' => 'U',
+ 0 => null,
+ 1 => null,
+ ],
+ ],
+ ],
+ ],
+ ],
+ ],
+ $bst->toArray()
+ );
+ }
+
+ public function testSearch() : void
+ {
+ $bst = new BinarySearchTree();
+ $bst->insert(new Node('D', 'D'));
+ $bst->insert(new Node('I', 'I'));
+ $bst->insert(new Node('N', 'N'));
+ $bst->insert(new Node('O', 'O'));
+ $bst->insert(new Node('S', 'S'));
+ $bst->insert(new Node('A', 'A'));
+ $bst->insert(new Node('U', 'U'));
+ $bst->insert(new Node('R', 'R'));
+
+ self::assertEquals('S', $bst->search('S')->key);
+ self::assertEquals('U', $bst->search('U')->key);
+ self::assertEquals('R', $bst->search('R')->key);
+ }
+
+ public function testDelete() : void
+ {
+ $bst = new BinarySearchTree();
+ $bst->insert(new Node('D', 'D'));
+ $bst->insert(new Node('I', 'I'));
+ $bst->insert(new Node('N', 'N'));
+ $bst->insert(new Node('O', 'O'));
+ $bst->insert(new Node('S', 'S'));
+ $bst->insert(new Node('A', 'A'));
+ $bst->insert(new Node('U', 'U'));
+ $bst->insert(new Node('R', 'R'));
+ $bst->delete($bst->search('I'));
+ $bst->insert(new Node('Z', 'Z'));
+ $bst->delete($bst->search('S'));
+ $bst->insert(new Node('T', 'T'));
+
+ self::assertEquals(
+ [
+ 'key' => 'D',
+ 0 => [
+ 'key' => 'A',
+ 0 => null,
+ 1 => null,
+ ],
+ 1 => [
+ 'key' => 'N',
+ 0 => null,
+ 1 => [
+ 'key' => 'O',
+ 0 => null,
+ 1 => [
+ 'key' => 'U',
+ 0 => [
+ 'key' => 'R',
+ 0 => null,
+ 1 => [
+ 'key' => 'T',
+ 0 => null,
+ 1 => null,
+ ],
+ ],
+ 1 => [
+ 'key' => 'Z',
+ 0 => null,
+ 1 => null,
+ ],
+ ],
+ ],
+ ],
+ ],
+ $bst->toArray()
+ );
+ }
+}
diff --git a/tests/System/File/Local/FileTest.php b/tests/System/File/Local/FileTest.php
index b7b2fd361..47a0b6c23 100755
--- a/tests/System/File/Local/FileTest.php
+++ b/tests/System/File/Local/FileTest.php
@@ -562,7 +562,7 @@ final class FileTest extends \PHPUnit\Framework\TestCase
\unlink($testFile);
}
- $newPath = __DIR__ . '/test2.txt';
+ $newPath = __DIR__ . '/test2.txt';
if (\is_file($newPath)) {
\unlink($newPath);
}
diff --git a/tests/System/SystemUtilsTest.php b/tests/System/SystemUtilsTest.php
index c9edcaf14..61750bee2 100755
--- a/tests/System/SystemUtilsTest.php
+++ b/tests/System/SystemUtilsTest.php
@@ -52,4 +52,9 @@ final class SystemUtilsTest extends \PHPUnit\Framework\TestCase
{
self::assertGreaterThan(0, SystemUtils::getCpuUsage());
}
+
+ public function testHostname() : void
+ {
+ self::assertGreaterThan(0, \strlen(SystemUtils::getHostname()));
+ }
}
diff --git a/tests/Utils/Converter/EnergyPowerTypeTest.php b/tests/Utils/Converter/EnergyPowerTypeTest.php
index 708e36149..e8b3106e0 100755
--- a/tests/Utils/Converter/EnergyPowerTypeTest.php
+++ b/tests/Utils/Converter/EnergyPowerTypeTest.php
@@ -45,13 +45,13 @@ final class EnergyPowerTypeTest extends \PHPUnit\Framework\TestCase
*/
public function testEnums() : void
{
- self::assertEquals('kWh', EnergyPowerType::KILOWATT_HOUERS);
- self::assertEquals('MWh', EnergyPowerType::MEGAWATT_HOUERS);
+ self::assertEquals('kWh', EnergyPowerType::KILOWATT_HOURS);
+ self::assertEquals('MWh', EnergyPowerType::MEGAWATT_HOURS);
self::assertEquals('kt', EnergyPowerType::KILOTONS);
- self::assertEquals('J', EnergyPowerType::JOULS);
+ self::assertEquals('J', EnergyPowerType::JOULES);
self::assertEquals('Cal', EnergyPowerType::CALORIES);
self::assertEquals('BTU', EnergyPowerType::BTU);
- self::assertEquals('kJ', EnergyPowerType::KILOJOULS);
+ self::assertEquals('kJ', EnergyPowerType::KILOJOULES);
self::assertEquals('thmEC', EnergyPowerType::THERMEC);
self::assertEquals('Nm', EnergyPowerType::NEWTON_METERS);
}
diff --git a/tests/Utils/Converter/MeasurementTest.php b/tests/Utils/Converter/MeasurementTest.php
index 9523eca04..5b49243cf 100755
--- a/tests/Utils/Converter/MeasurementTest.php
+++ b/tests/Utils/Converter/MeasurementTest.php
@@ -245,7 +245,7 @@ final class MeasurementTest extends \PHPUnit\Framework\TestCase
}
/**
- * @testdox Filesizes can be converted
+ * @testdox File sizes can be converted
* @covers phpOMS\Utils\Converter\Measurement
* @group framework
*/
@@ -490,7 +490,7 @@ final class MeasurementTest extends \PHPUnit\Framework\TestCase
{
$this->expectException(\InvalidArgumentException::class);
- Measurement::convertEnergy(1.1, 'invalid', EnergyPowerType::JOULS);
+ Measurement::convertEnergy(1.1, 'invalid', EnergyPowerType::JOULES);
}
/**
@@ -502,7 +502,7 @@ final class MeasurementTest extends \PHPUnit\Framework\TestCase
{
$this->expectException(\InvalidArgumentException::class);
- Measurement::convertEnergy(1.1, EnergyPowerType::JOULS, 'invalid');
+ Measurement::convertEnergy(1.1, EnergyPowerType::JOULES, 'invalid');
}
/**
diff --git a/tests/Utils/IO/Spreadsheet/SpreadsheetDatabaseMapperTest.php b/tests/Utils/IO/Spreadsheet/SpreadsheetDatabaseMapperTest.php
index b30db62f7..ceb645d00 100755
--- a/tests/Utils/IO/Spreadsheet/SpreadsheetDatabaseMapperTest.php
+++ b/tests/Utils/IO/Spreadsheet/SpreadsheetDatabaseMapperTest.php
@@ -14,9 +14,9 @@ declare(strict_types=1);
namespace phpOMS\tests\Utils\IO\Spreadsheet;
-use phpOMS\tests\Autoloader;
use phpOMS\DataStorage\Database\Connection\SQLiteConnection;
use phpOMS\DataStorage\Database\Query\Builder;
+use phpOMS\tests\Autoloader;
use phpOMS\Utils\IO\Spreadsheet\SpreadsheetDatabaseMapper;
use phpOMS\Utils\StringUtils;
@@ -79,7 +79,7 @@ final class SpreadsheetDatabaseMapperTest extends \PHPUnit\Framework\TestCase
$mapper->insert();
$builder = new Builder($this->sqlite, true);
- $data = $builder->select('insert_1.*')->from('insert_1')->execute()->fetchAll(\PDO::FETCH_ASSOC);
+ $data = $builder->select('insert_1.*')->from('insert_1')->execute()?->fetchAll(\PDO::FETCH_ASSOC) ?? [];
self::assertEquals(
[
['id' => 1, 'int' => 2, 'decimal' => 2.0, 'bool' => 1, 'varchar' => 'Line 1', 'datetime' => '43631'],
@@ -91,7 +91,7 @@ final class SpreadsheetDatabaseMapperTest extends \PHPUnit\Framework\TestCase
);
$builder = new Builder($this->sqlite, true);
- $data = $builder->select('insert_2.*')->from('insert_2')->execute()->fetchAll(\PDO::FETCH_ASSOC);
+ $data = $builder->select('insert_2.*')->from('insert_2')->execute()?->fetchAll(\PDO::FETCH_ASSOC) ?? [];
self::assertEquals(
[
['id' => 1, 'int' => 2, 'decimal' => 2.0, 'bool' => 1, 'varchar' => 'Line 1', 'datetime' => '43631'],
@@ -114,7 +114,7 @@ final class SpreadsheetDatabaseMapperTest extends \PHPUnit\Framework\TestCase
$mapper->insert();
$builder = new Builder($this->sqlite, true);
- $data = $builder->select('insert_1.*')->from('insert_1')->execute()->fetchAll(\PDO::FETCH_ASSOC);
+ $data = $builder->select('insert_1.*')->from('insert_1')->execute()?->fetchAll(\PDO::FETCH_ASSOC) ?? [];
self::assertEquals(
[
['id' => 1, 'int' => 2, 'decimal' => 2.0, 'bool' => 1, 'varchar' => 'Line 1', 'datetime' => '43631'],
@@ -126,7 +126,7 @@ final class SpreadsheetDatabaseMapperTest extends \PHPUnit\Framework\TestCase
);
$builder = new Builder($this->sqlite, true);
- $data = $builder->select('insert_2.*')->from('insert_2')->execute()->fetchAll(\PDO::FETCH_ASSOC);
+ $data = $builder->select('insert_2.*')->from('insert_2')->execute()?->fetchAll(\PDO::FETCH_ASSOC) ?? [];
self::assertEquals(
[
['id' => 1, 'int' => 2, 'decimal' => 2.0, 'bool' => 1, 'varchar' => 'Line 1', 'datetime' => '43631'],
@@ -149,7 +149,7 @@ final class SpreadsheetDatabaseMapperTest extends \PHPUnit\Framework\TestCase
$mapper->insert();
$builder = new Builder($this->sqlite, true);
- $data = $builder->select('insert_1.*')->from('insert_1')->execute()->fetchAll(\PDO::FETCH_ASSOC);
+ $data = $builder->select('insert_1.*')->from('insert_1')->execute()?->fetchAll(\PDO::FETCH_ASSOC) ?? [];
self::assertEquals(
[
['id' => 1, 'int' => 2, 'decimal' => 2.0, 'bool' => 1, 'varchar' => 'Line 1', 'datetime' => '43631'],
@@ -161,7 +161,7 @@ final class SpreadsheetDatabaseMapperTest extends \PHPUnit\Framework\TestCase
);
$builder = new Builder($this->sqlite, true);
- $data = $builder->select('insert_2.*')->from('insert_2')->execute()->fetchAll(\PDO::FETCH_ASSOC);
+ $data = $builder->select('insert_2.*')->from('insert_2')->execute()?->fetchAll(\PDO::FETCH_ASSOC) ?? [];
self::assertEquals(
[
['id' => 1, 'int' => 2, 'decimal' => 2.0, 'bool' => 1, 'varchar' => 'Line 1', 'datetime' => '43631'],
@@ -184,7 +184,7 @@ final class SpreadsheetDatabaseMapperTest extends \PHPUnit\Framework\TestCase
$mapper->insert();
$builder = new Builder($this->sqlite, true);
- $data = $builder->select('insert_1.*')->from('insert_1')->execute()->fetchAll(\PDO::FETCH_ASSOC);
+ $data = $builder->select('insert_1.*')->from('insert_1')->execute()?->fetchAll(\PDO::FETCH_ASSOC) ?? [];
self::assertEquals(
[
['id' => 1, 'int' => 2, 'decimal' => 2.0, 'bool' => 1, 'varchar' => 'Line 1', 'datetime' => '43631'],
@@ -196,7 +196,7 @@ final class SpreadsheetDatabaseMapperTest extends \PHPUnit\Framework\TestCase
);
$builder = new Builder($this->sqlite, true);
- $data = $builder->select('insert_2.*')->from('insert_2')->execute()->fetchAll(\PDO::FETCH_ASSOC);
+ $data = $builder->select('insert_2.*')->from('insert_2')->execute()?->fetchAll(\PDO::FETCH_ASSOC) ?? [];
self::assertEquals(
[
['id' => 1, 'int' => 2, 'decimal' => 2.0, 'bool' => 1, 'varchar' => 'Line 1', 'datetime' => '43631'],
@@ -211,7 +211,7 @@ final class SpreadsheetDatabaseMapperTest extends \PHPUnit\Framework\TestCase
$mapper->update();
$builder = new Builder($this->sqlite, true);
- $data = $builder->select('insert_1.*')->from('insert_1')->execute()->fetchAll(\PDO::FETCH_ASSOC);
+ $data = $builder->select('insert_1.*')->from('insert_1')->execute()?->fetchAll(\PDO::FETCH_ASSOC) ?? [];
self::assertEquals(
[
['id' => 1, 'int' => 2, 'decimal' => 2.0, 'bool' => 1, 'varchar' => 'Line 1', 'datetime' => '43631'],
@@ -223,7 +223,7 @@ final class SpreadsheetDatabaseMapperTest extends \PHPUnit\Framework\TestCase
);
$builder = new Builder($this->sqlite, true);
- $data = $builder->select('insert_2.*')->from('insert_2')->execute()->fetchAll(\PDO::FETCH_ASSOC);
+ $data = $builder->select('insert_2.*')->from('insert_2')->execute()?->fetchAll(\PDO::FETCH_ASSOC) ?? [];
self::assertEquals(
[
['id' => 1, 'int' => 2, 'decimal' => 2.0, 'bool' => 1, 'varchar' => 'Line 1', 'datetime' => '43631'],
@@ -246,7 +246,7 @@ final class SpreadsheetDatabaseMapperTest extends \PHPUnit\Framework\TestCase
$mapper->insert();
$builder = new Builder($this->sqlite, true);
- $data = $builder->select('insert_1.*')->from('insert_1')->execute()->fetchAll(\PDO::FETCH_ASSOC);
+ $data = $builder->select('insert_1.*')->from('insert_1')->execute()?->fetchAll(\PDO::FETCH_ASSOC) ?? [];
self::assertEquals(
[
['id' => 1, 'int' => 2, 'decimal' => 2.0, 'bool' => 1, 'varchar' => 'Line 1', 'datetime' => '43631'],
@@ -258,7 +258,7 @@ final class SpreadsheetDatabaseMapperTest extends \PHPUnit\Framework\TestCase
);
$builder = new Builder($this->sqlite, true);
- $data = $builder->select('insert_2.*')->from('insert_2')->execute()->fetchAll(\PDO::FETCH_ASSOC);
+ $data = $builder->select('insert_2.*')->from('insert_2')->execute()?->fetchAll(\PDO::FETCH_ASSOC) ?? [];
self::assertEquals(
[
['id' => 1, 'int' => 2, 'decimal' => 2.0, 'bool' => 1, 'varchar' => 'Line 1', 'datetime' => '43631'],
@@ -273,7 +273,7 @@ final class SpreadsheetDatabaseMapperTest extends \PHPUnit\Framework\TestCase
$mapper->update();
$builder = new Builder($this->sqlite, true);
- $data = $builder->select('insert_1.*')->from('insert_1')->execute()->fetchAll(\PDO::FETCH_ASSOC);
+ $data = $builder->select('insert_1.*')->from('insert_1')->execute()?->fetchAll(\PDO::FETCH_ASSOC) ?? [];
self::assertEquals(
[
['id' => 1, 'int' => 2, 'decimal' => 2.0, 'bool' => 1, 'varchar' => 'Line 1', 'datetime' => '43631'],
@@ -285,7 +285,7 @@ final class SpreadsheetDatabaseMapperTest extends \PHPUnit\Framework\TestCase
);
$builder = new Builder($this->sqlite, true);
- $data = $builder->select('insert_2.*')->from('insert_2')->execute()->fetchAll(\PDO::FETCH_ASSOC);
+ $data = $builder->select('insert_2.*')->from('insert_2')->execute()?->fetchAll(\PDO::FETCH_ASSOC) ?? [];
self::assertEquals(
[
['id' => 1, 'int' => 2, 'decimal' => 2.0, 'bool' => 1, 'varchar' => 'Line 1', 'datetime' => '43631'],
@@ -308,7 +308,7 @@ final class SpreadsheetDatabaseMapperTest extends \PHPUnit\Framework\TestCase
$mapper->insert();
$builder = new Builder($this->sqlite, true);
- $data = $builder->select('insert_1.*')->from('insert_1')->execute()->fetchAll(\PDO::FETCH_ASSOC);
+ $data = $builder->select('insert_1.*')->from('insert_1')->execute()?->fetchAll(\PDO::FETCH_ASSOC) ?? [];
self::assertEquals(
[
['id' => 1, 'int' => 2, 'decimal' => 2.0, 'bool' => 1, 'varchar' => 'Line 1', 'datetime' => '43631'],
@@ -320,7 +320,7 @@ final class SpreadsheetDatabaseMapperTest extends \PHPUnit\Framework\TestCase
);
$builder = new Builder($this->sqlite, true);
- $data = $builder->select('insert_2.*')->from('insert_2')->execute()->fetchAll(\PDO::FETCH_ASSOC);
+ $data = $builder->select('insert_2.*')->from('insert_2')->execute()?->fetchAll(\PDO::FETCH_ASSOC) ?? [];
self::assertEquals(
[
['id' => 1, 'int' => 2, 'decimal' => 2.0, 'bool' => 1, 'varchar' => 'Line 1', 'datetime' => '43631'],
@@ -335,7 +335,7 @@ final class SpreadsheetDatabaseMapperTest extends \PHPUnit\Framework\TestCase
$mapper->update();
$builder = new Builder($this->sqlite, true);
- $data = $builder->select('insert_1.*')->from('insert_1')->execute()->fetchAll(\PDO::FETCH_ASSOC);
+ $data = $builder->select('insert_1.*')->from('insert_1')->execute()?->fetchAll(\PDO::FETCH_ASSOC) ?? [];
self::assertEquals(
[
['id' => 1, 'int' => 2, 'decimal' => 2.0, 'bool' => 1, 'varchar' => 'Line 1', 'datetime' => '43631'],
@@ -347,7 +347,7 @@ final class SpreadsheetDatabaseMapperTest extends \PHPUnit\Framework\TestCase
);
$builder = new Builder($this->sqlite, true);
- $data = $builder->select('insert_2.*')->from('insert_2')->execute()->fetchAll(\PDO::FETCH_ASSOC);
+ $data = $builder->select('insert_2.*')->from('insert_2')->execute()?->fetchAll(\PDO::FETCH_ASSOC) ?? [];
self::assertEquals(
[
['id' => 1, 'int' => 2, 'decimal' => 2.0, 'bool' => 1, 'varchar' => 'Line 1', 'datetime' => '43631'],
@@ -374,7 +374,7 @@ final class SpreadsheetDatabaseMapperTest extends \PHPUnit\Framework\TestCase
$mapper->insert();
$builder = new Builder($this->sqlite, true);
- $data = $builder->select('insert_1.*')->from('insert_1')->execute()->fetchAll(\PDO::FETCH_ASSOC);
+ $data = $builder->select('insert_1.*')->from('insert_1')->execute()?->fetchAll(\PDO::FETCH_ASSOC) ?? [];
self::assertEquals(
[
['id' => 1, 'int' => 2, 'decimal' => 2.0, 'bool' => 1, 'varchar' => 'Line 1', 'datetime' => '43631'],
@@ -386,7 +386,7 @@ final class SpreadsheetDatabaseMapperTest extends \PHPUnit\Framework\TestCase
);
$builder = new Builder($this->sqlite, true);
- $data = $builder->select('insert_2.*')->from('insert_2')->execute()->fetchAll(\PDO::FETCH_ASSOC);
+ $data = $builder->select('insert_2.*')->from('insert_2')->execute()?->fetchAll(\PDO::FETCH_ASSOC) ?? [];
self::assertEquals(
[
['id' => 1, 'int' => 2, 'decimal' => 2.0, 'bool' => 1, 'varchar' => 'Line 1', 'datetime' => '43631'],
@@ -426,7 +426,7 @@ final class SpreadsheetDatabaseMapperTest extends \PHPUnit\Framework\TestCase
$mapper->insert();
$builder = new Builder($this->sqlite, true);
- $data = $builder->select('insert_1.*')->from('insert_1')->execute()->fetchAll(\PDO::FETCH_ASSOC);
+ $data = $builder->select('insert_1.*')->from('insert_1')->execute()?->fetchAll(\PDO::FETCH_ASSOC) ?? [];
self::assertEquals(
[
['id' => 1, 'int' => 2, 'decimal' => 2.0, 'bool' => 1, 'varchar' => 'Line 1', 'datetime' => '43631'],
@@ -438,7 +438,7 @@ final class SpreadsheetDatabaseMapperTest extends \PHPUnit\Framework\TestCase
);
$builder = new Builder($this->sqlite, true);
- $data = $builder->select('insert_2.*')->from('insert_2')->execute()->fetchAll(\PDO::FETCH_ASSOC);
+ $data = $builder->select('insert_2.*')->from('insert_2')->execute()?->fetchAll(\PDO::FETCH_ASSOC) ?? [];
self::assertEquals(
[
['id' => 1, 'int' => 2, 'decimal' => 2.0, 'bool' => 1, 'varchar' => 'Line 1', 'datetime' => '43631'],
@@ -478,7 +478,7 @@ final class SpreadsheetDatabaseMapperTest extends \PHPUnit\Framework\TestCase
$mapper->insert();
$builder = new Builder($this->sqlite, true);
- $data = $builder->select('insert_1.*')->from('insert_1')->execute()->fetchAll(\PDO::FETCH_ASSOC);
+ $data = $builder->select('insert_1.*')->from('insert_1')->execute()?->fetchAll(\PDO::FETCH_ASSOC) ?? [];
self::assertEquals(
[
['id' => 1, 'int' => 2, 'decimal' => 2.0, 'bool' => 1, 'varchar' => 'Line 1', 'datetime' => '43631'],
@@ -490,7 +490,7 @@ final class SpreadsheetDatabaseMapperTest extends \PHPUnit\Framework\TestCase
);
$builder = new Builder($this->sqlite, true);
- $data = $builder->select('insert_2.*')->from('insert_2')->execute()->fetchAll(\PDO::FETCH_ASSOC);
+ $data = $builder->select('insert_2.*')->from('insert_2')->execute()?->fetchAll(\PDO::FETCH_ASSOC) ?? [];
self::assertEquals(
[
['id' => 1, 'int' => 2, 'decimal' => 2.0, 'bool' => 1, 'varchar' => 'Line 1', 'datetime' => '43631'],
diff --git a/tests/Utils/ImageUtilsTest.php b/tests/Utils/ImageUtilsTest.php
index 84eed2dc2..7d4aec704 100755
--- a/tests/Utils/ImageUtilsTest.php
+++ b/tests/Utils/ImageUtilsTest.php
@@ -39,16 +39,18 @@ final class ImageUtilsTest extends \PHPUnit\Framework\TestCase
public function testResize() : void
{
- ImageUtils::resize(__DIR__ . '/logo.png', __DIR__ . '/logo_resized.png', 256, 256);
- self::assertTrue(\is_file(__DIR__ . '/logo_resized.png'));
+ ImageUtils::resize(__DIR__ . '/img/logo.png', __DIR__ . '/img/logo_resized.png', 256, 256);
+ self::assertTrue(\is_file(__DIR__ . '/img/logo_resized.png'));
}
public function testDifference() : void
{
- $diff = ImageUtils::difference(__DIR__ . '/img1.png', __DIR__ . '/img2.png', __DIR__ . '/diff1.png', 0);
- $diff = ImageUtils::difference(__DIR__ . '/img1.png', __DIR__ . '/img2.png', __DIR__ . '/diff2.png', 1);
+ foreach (['png', 'gif'] as $type) {
+ $diff = ImageUtils::difference(__DIR__ . '/img/img1.' . $type, __DIR__ . '/img/img2.' . $type, __DIR__ . '/img/diff1.' . $type, 0);
+ $diff = ImageUtils::difference(__DIR__ . '/img/img1.' . $type, __DIR__ . '/img/img2.' . $type, __DIR__ . '/img/diff2.' . $type, 1);
- self::assertGreaterThan(0, $diff);
+ self::assertGreaterThan(0, $diff);
+ }
}
/**
@@ -59,7 +61,7 @@ final class ImageUtilsTest extends \PHPUnit\Framework\TestCase
public function testImage() : void
{
self::assertEquals(
- \file_get_contents(__DIR__ . '/logo.png'),
+ \file_get_contents(__DIR__ . '/img/logo.png'),
ImageUtils::decodeBase64Image(
'data:image/png;base64,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'
)
diff --git a/tests/Utils/Parser/Calendar/ICalParserTest.php b/tests/Utils/Parser/Calendar/ICalParserTest.php
new file mode 100644
index 000000000..64ddafac2
--- /dev/null
+++ b/tests/Utils/Parser/Calendar/ICalParserTest.php
@@ -0,0 +1,42 @@
+toPdfString(__DIR__ . '/data/WordMpdf.pdf');
+ self::assertFalse(\is_file(__DIR__ . '/data/WordMpdf.pdf'));
+
+ \file_put_contents(__DIR__ . '/data/WordMpdf.pdf', $pdf);
+ self::assertTrue(\is_file(__DIR__ . '/data/WordMpdf.pdf'));
+ self::assertGreaterThan(100, \strlen(\file_get_contents(__DIR__ . '/data/WordMpdf.pdf')));
+ }
+}
diff --git a/tests/Utils/Parser/Document/data/Word.docx b/tests/Utils/Parser/Document/data/Word.docx
new file mode 100644
index 000000000..811baba61
Binary files /dev/null and b/tests/Utils/Parser/Document/data/Word.docx differ
diff --git a/tests/Utils/Parser/Document/data/Word.html b/tests/Utils/Parser/Document/data/Word.html
new file mode 100644
index 000000000..e69de29bb
diff --git a/tests/Utils/Parser/Markdown/MarkdownTest.php b/tests/Utils/Parser/Markdown/MarkdownTest.php
index 87fc643fb..50db61079 100755
--- a/tests/Utils/Parser/Markdown/MarkdownTest.php
+++ b/tests/Utils/Parser/Markdown/MarkdownTest.php
@@ -47,9 +47,142 @@ final class MarkdownTest extends \PHPUnit\Framework\TestCase
public function testSafeMode() : void
{
- $parser = new Markdown();
- $parser->setSafeMode(true);
+ $parser = new Markdown();
+ $parser->safeMode = true;
- self::assertTrue(\file_get_contents(__DIR__ . '/manualdata/xss_bad_url.html') === ($parsed = $parser->text(\file_get_contents(__DIR__ . '/manualdata/xss_bad_url.md'))), $parsed);
+ self::assertEquals(
+ \file_get_contents(__DIR__ . '/manualdata/xss_bad_url.html'),
+ $parser->text(\file_get_contents(__DIR__ . '/manualdata/xss_bad_url.md'))
+ );
+ }
+
+ public function testTablespan() : void
+ {
+ $parser = new Markdown([
+ 'tables' => [
+ 'tablespan' => true,
+ ],
+ ]);
+
+ self::assertEquals(
+ \file_get_contents(__DIR__ . '/manualdata/tablespan.html'),
+ $parser->text(\file_get_contents(__DIR__ . '/manualdata/tablespan.md'))
+ );
+ }
+
+ public function testMap() : void
+ {
+ $parser = new Markdown([
+ 'map' => true,
+ ]);
+
+ self::assertLessThan(9,
+ \levenshtein(
+ \file_get_contents(__DIR__ . '/manualdata/map.html'),
+ $parser->text(\file_get_contents(__DIR__ . '/manualdata/map.md'))
+ )
+ );
+ }
+
+ public function testContact() : void
+ {
+ $parser = new Markdown([
+ 'contact' => true,
+ ]);
+
+ self::assertEquals(
+ \file_get_contents(__DIR__ . '/manualdata/contact.html'),
+ $parser->text(\file_get_contents(__DIR__ . '/manualdata/contact.md'))
+ );
+ }
+
+ public function testTypographer() : void
+ {
+ $parser = new Markdown([
+ 'typographer' => true,
+ ]);
+
+ self::assertEquals(
+ \file_get_contents(__DIR__ . '/manualdata/typographer.html'),
+ $parser->text(\file_get_contents(__DIR__ . '/manualdata/typographer.md'))
+ );
+ }
+
+ public function testAddress() : void
+ {
+ $parser = new Markdown([
+ 'address' => true,
+ ]);
+
+ self::assertEquals(
+ \file_get_contents(__DIR__ . '/manualdata/address.html'),
+ $parser->text(\file_get_contents(__DIR__ . '/manualdata/address.md'))
+ );
+ }
+
+ public function testProgress() : void
+ {
+ $parser = new Markdown([
+ 'progress' => true,
+ ]);
+
+ self::assertEquals(
+ \file_get_contents(__DIR__ . '/manualdata/progress.html'),
+ $parser->text(\file_get_contents(__DIR__ . '/manualdata/progress.md'))
+ );
+ }
+
+ public function testEmbed() : void
+ {
+ $parser = new Markdown([
+ 'embeding' => true,
+ ]);
+
+ self::assertEquals(
+ \file_get_contents(__DIR__ . '/manualdata/embed.html'),
+ $parser->text(\file_get_contents(__DIR__ . '/manualdata/embed.md'))
+ );
+ }
+
+ public function testMath() : void
+ {
+ $parser = new Markdown([
+ 'math' => true,
+ ]);
+
+ self::assertEquals(
+ \file_get_contents(__DIR__ . '/manualdata/katex.html'),
+ $parser->text(\file_get_contents(__DIR__ . '/manualdata/katex.md'))
+ );
+ }
+
+ public function testTOC() : void
+ {
+ $parser = new Markdown([
+ 'toc' => true,
+ ]);
+ $parser->text(\file_get_contents(__DIR__ . '/manualdata/toc.md'));
+
+ self::assertEquals(
+ \file_get_contents(__DIR__ . '/manualdata/toc.html'),
+ $parser->contentsList()
+ );
+ }
+
+ public function testSpoiler() : void
+ {
+ $parser = new Markdown([
+ 'spoiler' => true,
+ ]);
+
+ self::assertEquals(
+ \file_get_contents(__DIR__ . '/manualdata/spoiler.html'),
+ $parser->text(\file_get_contents(__DIR__ . '/manualdata/spoiler.md'))
+ );
+
+ self::assertEquals(
+ \file_get_contents(__DIR__ . '/manualdata/spoiler_block.html'),
+ $parser->text(\file_get_contents(__DIR__ . '/manualdata/spoiler_block.md'))
+ );
}
}
diff --git a/tests/Utils/Parser/Markdown/data/chartjs.html b/tests/Utils/Parser/Markdown/data/chartjs.html
new file mode 100644
index 000000000..c173ca4d7
--- /dev/null
+++ b/tests/Utils/Parser/Markdown/data/chartjs.html
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/tests/Utils/Parser/Markdown/data/chartjs.md b/tests/Utils/Parser/Markdown/data/chartjs.md
new file mode 100644
index 000000000..6ff76ccd9
--- /dev/null
+++ b/tests/Utils/Parser/Markdown/data/chartjs.md
@@ -0,0 +1,2 @@
+```chart
+```
\ No newline at end of file
diff --git a/tests/Utils/Parser/Markdown/data/checkbox.html b/tests/Utils/Parser/Markdown/data/checkbox.html
new file mode 100644
index 000000000..2fe532fb7
--- /dev/null
+++ b/tests/Utils/Parser/Markdown/data/checkbox.html
@@ -0,0 +1,4 @@
+
+
Unchecked
+
Checked
+
\ No newline at end of file
diff --git a/tests/Utils/Parser/Markdown/data/checkbox.md b/tests/Utils/Parser/Markdown/data/checkbox.md
new file mode 100644
index 000000000..1949d401f
--- /dev/null
+++ b/tests/Utils/Parser/Markdown/data/checkbox.md
@@ -0,0 +1,2 @@
+- [ ] Unchecked
+- [x] Checked
\ No newline at end of file
diff --git a/tests/Utils/Parser/Markdown/data/em_strong.html b/tests/Utils/Parser/Markdown/data/em_strong.html
index c2cddc0fc..d16606cd8 100755
--- a/tests/Utils/Parser/Markdown/data/em_strong.html
+++ b/tests/Utils/Parser/Markdown/data/em_strong.html
@@ -1,8 +1,4 @@
-
em strong
-
em strong strong
-
strong em strong
-
strong em strong strong
-
em strong
-
em strong strong
-
strong em strong
-
strong em strong strong
\ No newline at end of file
+
em underline
+
underline em
+
strong em
+
strong em
\ No newline at end of file
diff --git a/tests/Utils/Parser/Markdown/data/em_strong.md b/tests/Utils/Parser/Markdown/data/em_strong.md
index 9abeb3fd4..224cf308d 100755
--- a/tests/Utils/Parser/Markdown/data/em_strong.md
+++ b/tests/Utils/Parser/Markdown/data/em_strong.md
@@ -1,15 +1,7 @@
-___em strong___
+___em underline___
-___em strong_ strong__
+__*underline em*__
-__strong _em strong___
+***strong em***
-__strong _em strong_ strong__
-
-***em strong***
-
-***em strong* strong**
-
-**strong *em strong***
-
-**strong *em strong* strong**
\ No newline at end of file
+**_strong em_**
\ No newline at end of file
diff --git a/tests/Utils/Parser/Markdown/data/emoji.html b/tests/Utils/Parser/Markdown/data/emoji.html
new file mode 100644
index 000000000..d4de04c55
--- /dev/null
+++ b/tests/Utils/Parser/Markdown/data/emoji.html
@@ -0,0 +1 @@
+
📹
\ No newline at end of file
diff --git a/tests/Utils/Parser/Markdown/data/emoji.md b/tests/Utils/Parser/Markdown/data/emoji.md
new file mode 100644
index 000000000..914af9824
--- /dev/null
+++ b/tests/Utils/Parser/Markdown/data/emoji.md
@@ -0,0 +1 @@
+:video_camera:
\ No newline at end of file
diff --git a/tests/Utils/Parser/Markdown/data/emphasis.html b/tests/Utils/Parser/Markdown/data/emphasis.html
index 60ff4bd8b..4571c85f8 100755
--- a/tests/Utils/Parser/Markdown/data/emphasis.html
+++ b/tests/Utils/Parser/Markdown/data/emphasis.html
@@ -1,4 +1,4 @@
-
underscore, asterisk, one two, three four, a, b
+
underscore, asterisk, one two, three four, a, b
strong and em and strong and em
line
line
diff --git a/tests/Utils/Parser/Markdown/data/emphasis.md b/tests/Utils/Parser/Markdown/data/emphasis.md
index 85b9d2299..99073ae5c 100755
--- a/tests/Utils/Parser/Markdown/data/emphasis.md
+++ b/tests/Utils/Parser/Markdown/data/emphasis.md
@@ -1,10 +1,10 @@
-_underscore_, *asterisk*, _one two_, *three four*, _a_, *b*
+__underscore__, *asterisk*, _one two_, *three four*, _a_, *b*
**strong** and *em* and **strong** and *em*
-_line
+*line
line
-line_
+line*
this_is_not_an_emphasis
diff --git a/tests/Utils/Parser/Markdown/data/keystroke.html b/tests/Utils/Parser/Markdown/data/keystroke.html
new file mode 100644
index 000000000..8e6d5ca4d
--- /dev/null
+++ b/tests/Utils/Parser/Markdown/data/keystroke.html
@@ -0,0 +1 @@
+
ctrl + shift + A
\ No newline at end of file
diff --git a/tests/Utils/Parser/Markdown/data/keystroke.md b/tests/Utils/Parser/Markdown/data/keystroke.md
new file mode 100644
index 000000000..281e60490
--- /dev/null
+++ b/tests/Utils/Parser/Markdown/data/keystroke.md
@@ -0,0 +1 @@
+[[ctrl]] + [[shift]] + [[A]]
\ No newline at end of file
diff --git a/tests/Utils/Parser/Markdown/data/mark.html b/tests/Utils/Parser/Markdown/data/mark.html
new file mode 100644
index 000000000..2b6624130
--- /dev/null
+++ b/tests/Utils/Parser/Markdown/data/mark.html
@@ -0,0 +1 @@
+
Text with Mark test inline.
\ No newline at end of file
diff --git a/tests/Utils/Parser/Markdown/data/mark.md b/tests/Utils/Parser/Markdown/data/mark.md
new file mode 100644
index 000000000..efefef266
--- /dev/null
+++ b/tests/Utils/Parser/Markdown/data/mark.md
@@ -0,0 +1 @@
+Text with ==Mark test== inline.
\ No newline at end of file
diff --git a/tests/Utils/Parser/Markdown/data/mermaidjs.html b/tests/Utils/Parser/Markdown/data/mermaidjs.html
new file mode 100644
index 000000000..a49f1d1b3
--- /dev/null
+++ b/tests/Utils/Parser/Markdown/data/mermaidjs.html
@@ -0,0 +1,11 @@
+
sequenceDiagram
+ participant Alice
+ participant Bob
+ Alice->>John: Hello John, how are you?
+ loop Healthcheck
+ John->>John: Fight against hypochondria
+ end
+ Note right of John: Rational thoughts<br/>prevail...
+ John-->>Alice: Great!
+ John->>Bob: How about you?
+ Bob-->>John: Jolly good!
\ No newline at end of file
diff --git a/tests/Utils/Parser/Markdown/data/mermaidjs.md b/tests/Utils/Parser/Markdown/data/mermaidjs.md
new file mode 100644
index 000000000..b9c32ff04
--- /dev/null
+++ b/tests/Utils/Parser/Markdown/data/mermaidjs.md
@@ -0,0 +1,13 @@
+```mermaid
+sequenceDiagram
+ participant Alice
+ participant Bob
+ Alice->>John: Hello John, how are you?
+ loop Healthcheck
+ John->>John: Fight against hypochondria
+ end
+ Note right of John: Rational thoughts prevail...
+ John-->>Alice: Great!
+ John->>Bob: How about you?
+ Bob-->>John: Jolly good!
+```
\ No newline at end of file
diff --git a/tests/Utils/Parser/Markdown/manualdata/address.html b/tests/Utils/Parser/Markdown/manualdata/address.html
new file mode 100644
index 000000000..7a6a79b3b
--- /dev/null
+++ b/tests/Utils/Parser/Markdown/manualdata/address.html
@@ -0,0 +1,7 @@
+
+AddrName
+Addr
+AddrZip
+AddrCity
+AddrCoutry
+
\ No newline at end of file
diff --git a/tests/Utils/Parser/Markdown/manualdata/address.md b/tests/Utils/Parser/Markdown/manualdata/address.md
new file mode 100644
index 000000000..ed1c1e308
--- /dev/null
+++ b/tests/Utils/Parser/Markdown/manualdata/address.md
@@ -0,0 +1 @@
+[addr name="AddrName" address="Addr" city="AddrCity" country="AddrCoutry" zip="AddrZip"]
\ No newline at end of file
diff --git a/tests/Utils/Parser/Markdown/manualdata/contact.html b/tests/Utils/Parser/Markdown/manualdata/contact.html
new file mode 100644
index 000000000..92760f913
--- /dev/null
+++ b/tests/Utils/Parser/Markdown/manualdata/contact.html
@@ -0,0 +1,36 @@
+
\ No newline at end of file
diff --git a/tests/Utils/Parser/Markdown/manualdata/contact.md b/tests/Utils/Parser/Markdown/manualdata/contact.md
new file mode 100644
index 000000000..3b56536b9
--- /dev/null
+++ b/tests/Utils/Parser/Markdown/manualdata/contact.md
@@ -0,0 +1,9 @@
+[contact phone="+49 123 456 789"]
+[contact facebook="@jinggaApp"]
+[contact discord="jingga"]
+[contact email="test@email.com"]
+[contact twitter="@jinggaApp"]
+[contact youtube="@jinggaApp"]
+[contact instagram="jinggaApp"]
+[contact slack="jinggaApp"]
+[contact teams="jinggaApp"]
\ No newline at end of file
diff --git a/tests/Utils/Parser/Markdown/manualdata/embed.html b/tests/Utils/Parser/Markdown/manualdata/embed.html
new file mode 100644
index 000000000..d30d6762c
--- /dev/null
+++ b/tests/Utils/Parser/Markdown/manualdata/embed.html
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/tests/Utils/Parser/Markdown/manualdata/embed.md b/tests/Utils/Parser/Markdown/manualdata/embed.md
new file mode 100644
index 000000000..58e47889a
--- /dev/null
+++ b/tests/Utils/Parser/Markdown/manualdata/embed.md
@@ -0,0 +1,5 @@
+[video src="https://www.youtube.com/watch?v=dQw4w9WgXcQ&ab_channel=RickAstley"]
+[video src="https://vimeo.com/874474957"]
+[video src="https://www.dailymotion.com/video/x3w7rss"]
+[video src="test.mp4"]
+[audio src="test.mp3"]
\ No newline at end of file
diff --git a/tests/Utils/Parser/Markdown/manualdata/katex.html b/tests/Utils/Parser/Markdown/manualdata/katex.html
new file mode 100644
index 000000000..4df09dc60
--- /dev/null
+++ b/tests/Utils/Parser/Markdown/manualdata/katex.html
@@ -0,0 +1,2 @@
+$$
+ x = {-b \pm \sqrt{b^2-4ac} \over 2a}.$$
\ No newline at end of file
diff --git a/tests/Utils/Parser/Markdown/manualdata/katex.md b/tests/Utils/Parser/Markdown/manualdata/katex.md
new file mode 100644
index 000000000..2c583e1c0
--- /dev/null
+++ b/tests/Utils/Parser/Markdown/manualdata/katex.md
@@ -0,0 +1,3 @@
+$$
+ x = {-b \pm \sqrt{b^2-4ac} \over 2a}.
+$$
\ No newline at end of file
diff --git a/tests/Utils/Parser/Markdown/manualdata/map.html b/tests/Utils/Parser/Markdown/manualdata/map.html
new file mode 100644
index 000000000..c6f54ef15
--- /dev/null
+++ b/tests/Utils/Parser/Markdown/manualdata/map.html
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/tests/Utils/Parser/Markdown/manualdata/map.md b/tests/Utils/Parser/Markdown/manualdata/map.md
new file mode 100644
index 000000000..a7963e89a
--- /dev/null
+++ b/tests/Utils/Parser/Markdown/manualdata/map.md
@@ -0,0 +1 @@
+[map lat="1.0" lon="1.0"]
\ No newline at end of file
diff --git a/tests/Utils/Parser/Markdown/manualdata/progress.html b/tests/Utils/Parser/Markdown/manualdata/progress.html
new file mode 100644
index 000000000..24ae75383
--- /dev/null
+++ b/tests/Utils/Parser/Markdown/manualdata/progress.html
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/tests/Utils/Parser/Markdown/manualdata/progress.md b/tests/Utils/Parser/Markdown/manualdata/progress.md
new file mode 100644
index 000000000..579e077e5
--- /dev/null
+++ b/tests/Utils/Parser/Markdown/manualdata/progress.md
@@ -0,0 +1 @@
+[progress value="33"]
\ No newline at end of file
diff --git a/tests/Utils/Parser/Markdown/manualdata/spoiler.html b/tests/Utils/Parser/Markdown/manualdata/spoiler.html
new file mode 100644
index 000000000..2085a4d8e
--- /dev/null
+++ b/tests/Utils/Parser/Markdown/manualdata/spoiler.html
@@ -0,0 +1,4 @@
+
This is a
+
+test spoiler
+ in text.
\ No newline at end of file
diff --git a/tests/Utils/Parser/Markdown/manualdata/spoiler.md b/tests/Utils/Parser/Markdown/manualdata/spoiler.md
new file mode 100644
index 000000000..011c08b14
--- /dev/null
+++ b/tests/Utils/Parser/Markdown/manualdata/spoiler.md
@@ -0,0 +1 @@
+This is a >!test spoiler!< in text.
\ No newline at end of file
diff --git a/tests/Utils/Parser/Markdown/manualdata/spoiler_block.html b/tests/Utils/Parser/Markdown/manualdata/spoiler_block.html
new file mode 100644
index 000000000..067b6cdb3
--- /dev/null
+++ b/tests/Utils/Parser/Markdown/manualdata/spoiler_block.html
@@ -0,0 +1,5 @@
+
+Test summary
+
+This is a test spoiler.
+
\ No newline at end of file
diff --git a/tests/Utils/Parser/Markdown/manualdata/spoiler_block.md b/tests/Utils/Parser/Markdown/manualdata/spoiler_block.md
new file mode 100644
index 000000000..f855f1231
--- /dev/null
+++ b/tests/Utils/Parser/Markdown/manualdata/spoiler_block.md
@@ -0,0 +1,3 @@
+???Test summary
+This is a test spoiler.
+???
\ No newline at end of file
diff --git a/tests/Utils/Parser/Markdown/manualdata/tablespan.html b/tests/Utils/Parser/Markdown/manualdata/tablespan.html
new file mode 100644
index 000000000..83d411ac2
--- /dev/null
+++ b/tests/Utils/Parser/Markdown/manualdata/tablespan.html
@@ -0,0 +1,36 @@
+
+
+
+
Colspan
+
for thead
+
+
+
+
+
Lorem
+
ipsum
+
dolor
+
sit
+
amet
+
+
+
-
+
right align
+
.
+
+
+
,
+
center align
+
2x2 cell
+
+
+
another 2x2
+
+
+
+
+
+
+
!
+
+
+
\ No newline at end of file
diff --git a/tests/Utils/Parser/Markdown/manualdata/tablespan.md b/tests/Utils/Parser/Markdown/manualdata/tablespan.md
new file mode 100644
index 000000000..3b35723eb
--- /dev/null
+++ b/tests/Utils/Parser/Markdown/manualdata/tablespan.md
@@ -0,0 +1,7 @@
+| > | > | Colspan | > | for thead |
+| ----- | :---------: | -----------: | ----------- | --------- |
+| Lorem | ipsum | dolor | sit | amet |
+| ^ | - | > | right align | . |
+| , | > | center align | > | 2x2 cell |
+| > | another 2x2 | + | > | ^ |
+| > | ^ | | | ! |
\ No newline at end of file
diff --git a/tests/Utils/Parser/Markdown/manualdata/toc.html b/tests/Utils/Parser/Markdown/manualdata/toc.html
new file mode 100644
index 000000000..b7951fe2c
--- /dev/null
+++ b/tests/Utils/Parser/Markdown/manualdata/toc.html
@@ -0,0 +1,10 @@
+
\ No newline at end of file
diff --git a/tests/Utils/Parser/Markdown/manualdata/toc.md b/tests/Utils/Parser/Markdown/manualdata/toc.md
new file mode 100644
index 000000000..156f263f0
--- /dev/null
+++ b/tests/Utils/Parser/Markdown/manualdata/toc.md
@@ -0,0 +1,7 @@
+# A
+
+## 1
+
+### i
+
+# B
diff --git a/tests/Utils/Parser/Markdown/manualdata/typographer.html b/tests/Utils/Parser/Markdown/manualdata/typographer.html
new file mode 100644
index 000000000..ea5570267
--- /dev/null
+++ b/tests/Utils/Parser/Markdown/manualdata/typographer.html
@@ -0,0 +1 @@
+