From 5f1a2abaa953795d0387c5d86a488c32ca0be8e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20=C5=A0pa=C4=8Dek?= Date: Sat, 30 Nov 2024 06:49:04 +0100 Subject: [PATCH] Add assert()s and tests to test those assert()s --- app/psalm-baseline.xml | 87 ------------- app/src/Application/Routing/BlogPostRoute.php | 2 +- app/src/EasterEgg/NetteCve202015227.php | 9 +- .../EasterEgg/Presenters/NettePresenter.php | 2 +- app/src/Form/InterviewFormFactory.php | 3 - app/src/Form/TalkFormFactory.php | 3 - app/src/Form/TalkSlidesFormFactory.php | 5 +- ...iningApplicationPreliminaryFormFactory.php | 4 +- app/src/Form/TrainingReviewFormFactory.php | 24 ++-- app/src/Media/VideoThumbnails.php | 15 +-- app/src/Net/DnsResolver.php | 7 +- app/src/Talks/Slides/TalkSlides.php | 13 +- .../TrainingApplicationFormDataLogger.php | 8 +- .../TrainingApplicationFormSpam.php | 16 +-- .../TrainingApplicationFormSuccess.php | 27 ++-- app/src/Training/Reviews/TrainingReviews.php | 5 +- .../EasterEgg/NetteCve202015227Test.phpt | 27 ++-- .../Form/TrainingReviewFormFactoryTest.phpt | 119 ++++++++++++++++++ app/tests/Net/DnsResolverTest.phpt | 34 +++++ ...TrainingApplicationFormDataLoggerTest.phpt | 26 ++-- .../TrainingApplicationFormSpamTest.phpt | 98 ++++++++++----- 21 files changed, 341 insertions(+), 193 deletions(-) create mode 100644 app/tests/Form/TrainingReviewFormFactoryTest.phpt create mode 100644 app/tests/Net/DnsResolverTest.phpt diff --git a/app/psalm-baseline.xml b/app/psalm-baseline.xml index e41232884..6cb0b3179 100644 --- a/app/psalm-baseline.xml +++ b/app/psalm-baseline.xml @@ -117,11 +117,6 @@ videoHref]]> - - - deleteReplaced]]> - - @@ -161,12 +156,6 @@ status]]> - - - email]]> - name]]> - - @@ -226,26 +215,6 @@ - - - company]]> - company]]> - hidden]]> - hidden]]> - href ?: null]]> - href ?: null]]> - jobTitle ?: null]]> - jobTitle ?: null]]> - name]]> - name]]> - note ?: null]]> - note ?: null]]> - ranking ?: null]]> - ranking ?: null]]> - review]]> - review]]> - - @@ -254,21 +223,9 @@ videoThumbnail]]> - videoThumbnail]]> - videoThumbnailAlternative]]> videoThumbnailAlternative]]> - - - - - - - - - - @@ -278,15 +235,6 @@ filename ?? '']]> filenameAlternative ?? '']]> - alias]]> - number]]> - number]]> - replace]]> - replace]]> - replaceAlternative]]> - replaceAlternative]]> - speakerNotes]]> - title]]> @@ -294,41 +242,6 @@ - - - city]]> - city]]> - city]]> - company]]> - company]]> - company]]> - companyId]]> - companyId]]> - companyId]]> - companyTaxId]]> - companyTaxId]]> - companyTaxId]]> - country]]> - country]]> - country]]> - email]]> - email]]> - email]]> - name]]> - name]]> - name]]> - note]]> - note]]> - note]]> - street]]> - street]]> - street]]> - trainingId]]> - zip]]> - zip]]> - zip]]> - - ranking]]> diff --git a/app/src/Application/Routing/BlogPostRoute.php b/app/src/Application/Routing/BlogPostRoute.php index daf0afa86..21c1addf0 100644 --- a/app/src/Application/Routing/BlogPostRoute.php +++ b/app/src/Application/Routing/BlogPostRoute.php @@ -31,7 +31,7 @@ public function __construct( * Maps HTTP request to a Request object. * * @param IRequest $httpRequest - * @return array|null + * @return array|null */ #[Override] public function match(IRequest $httpRequest): ?array diff --git a/app/src/EasterEgg/NetteCve202015227.php b/app/src/EasterEgg/NetteCve202015227.php index 124130ac5..490589f23 100644 --- a/app/src/EasterEgg/NetteCve202015227.php +++ b/app/src/EasterEgg/NetteCve202015227.php @@ -5,6 +5,7 @@ use Nette\Application\BadRequestException; use Nette\Application\Routers\RouteList; +use Nette\Application\UI\Component; /** * Nette CVE-2020-15227, here to easter-egg some bots @@ -19,10 +20,7 @@ class NetteCve202015227 { - /** - * @param array $params - */ - public function rce(string $callback, array $params): NetteCve202015227Rce + public function rce(string $callback, Component $component): NetteCve202015227Rce { $callback = strtolower($callback); $paramNames = [ @@ -40,7 +38,8 @@ public function rce(string $callback, array $params): NetteCve202015227Rce $data = []; - $param = $params[$paramNames[$callback]] ?? null; + $param = $component->getParameters()[$paramNames[$callback]] ?? null; + assert(is_string($param) || $param === null); if ($param === null) { throw new BadRequestException(sprintf("[%s] Empty param '%s' for callback '%s'", __CLASS__, $paramNames[$callback], $callback)); } diff --git a/app/src/EasterEgg/Presenters/NettePresenter.php b/app/src/EasterEgg/Presenters/NettePresenter.php index 2d000de53..2ef6f7288 100644 --- a/app/src/EasterEgg/Presenters/NettePresenter.php +++ b/app/src/EasterEgg/Presenters/NettePresenter.php @@ -23,7 +23,7 @@ public function __construct( public function actionMicro(string $callback): void { sleep(random_int(5, 20)); - $rce = $this->cve202015227->rce($callback, $this->getParameters()); + $rce = $this->cve202015227->rce($callback, $this); $this->setView($rce->view->value); $this->template->eth0RxPackets = $rce->eth0RxPackets; $this->template->eth1RxPackets = $rce->eth1RxPackets; diff --git a/app/src/Form/InterviewFormFactory.php b/app/src/Form/InterviewFormFactory.php index 43ddba884..370895ac9 100644 --- a/app/src/Form/InterviewFormFactory.php +++ b/app/src/Form/InterviewFormFactory.php @@ -121,9 +121,6 @@ public function create(callable $onSuccess, ?Interview $interview = null): UiFor } $onSuccess(); }; - - $this->videoThumbnails->addOnValidateUploads($form, $videoThumbnailFormFields); - return $form; } diff --git a/app/src/Form/TalkFormFactory.php b/app/src/Form/TalkFormFactory.php index a024d855a..e1cfd53ba 100644 --- a/app/src/Form/TalkFormFactory.php +++ b/app/src/Form/TalkFormFactory.php @@ -182,9 +182,6 @@ public function create(callable $onSuccess, ?Talk $talk = null): UiForm $message->addHtml(Html::el('a')->href($this->linkGenerator->link('Www:Talks:talk', [$values->action]))->setText('Zobrazit')); $onSuccess($message); }; - - $this->videoThumbnails->addOnValidateUploads($form, $videoThumbnailFormFields); - return $form; } diff --git a/app/src/Form/TalkSlidesFormFactory.php b/app/src/Form/TalkSlidesFormFactory.php index ad3c4c0a8..12bb0e9d7 100644 --- a/app/src/Form/TalkSlidesFormFactory.php +++ b/app/src/Form/TalkSlidesFormFactory.php @@ -11,6 +11,7 @@ use Nette\Application\Request; use Nette\Forms\Container; use Nette\Forms\Form; +use Nette\Utils\ArrayHash; use Nette\Utils\Html; readonly class TalkSlidesFormFactory @@ -61,6 +62,9 @@ public function create(callable $onSuccess, int $talkId, TalkSlideCollection $sl $form->onSuccess[] = function (UiForm $form) use ($slides, $onSuccess, $talkId): void { try { $values = $form->getFormValues(); + assert($values->slides instanceof ArrayHash); + assert($values->new instanceof ArrayHash); + assert(is_bool($values->deleteReplaced)); $this->talkSlides->saveSlides($talkId, $slides, (array)$values->slides, array_values((array)$values->new), $values->deleteReplaced); $message = $this->texyFormatter->translate('messages.talks.admin.slideadded'); $type = 'info'; @@ -96,7 +100,6 @@ private function addSlideFields(UiForm $form, Container $container, ?int $filena ->setRequired('Zadejte prosím alias') ->addRule(Form::Pattern, 'Alias musí být ve formátu [_.,a-z0-9-]+', '[_.,a-z0-9-]+'); $container->addInteger('number', 'Slajd:') - ->setHtmlType('number') ->setDefaultValue(1) ->setHtmlAttribute('class', 'right slide-nr') ->setRequired('Zadejte prosím číslo slajdu'); diff --git a/app/src/Form/TrainingApplicationPreliminaryFormFactory.php b/app/src/Form/TrainingApplicationPreliminaryFormFactory.php index 2c2d8342b..b302c98c2 100644 --- a/app/src/Form/TrainingApplicationPreliminaryFormFactory.php +++ b/app/src/Form/TrainingApplicationPreliminaryFormFactory.php @@ -27,8 +27,10 @@ public function create(callable $onSuccess, callable $onError, int $trainingId, $form->addSubmit('signUp', 'Odeslat'); $form->onSuccess[] = function (UiForm $form) use ($onSuccess, $onError, $trainingId, $action): void { $values = $form->getFormValues(); + assert(is_string($values->name)); + assert(is_string($values->email)); try { - $this->formSpam->check($values); + $this->formSpam->check($values->name); $this->trainingApplicationStorage->addPreliminaryInvitation($trainingId, $values->name, $values->email); $onSuccess($action); } catch (SpammyApplicationException) { diff --git a/app/src/Form/TrainingReviewFormFactory.php b/app/src/Form/TrainingReviewFormFactory.php index 22d1c6ce6..379d7b67b 100644 --- a/app/src/Form/TrainingReviewFormFactory.php +++ b/app/src/Form/TrainingReviewFormFactory.php @@ -51,9 +51,9 @@ public function create(callable $onSuccess, int $dateId, ?TrainingReview $review ->setRequired(false) ->addRule(Form::MaxLength, 'Maximální délka odkazu je %d znaků', 200); $form->addCheckbox('hidden', 'Skrýt:'); - $form->addText('ranking', 'Pořadí:') + $form->addInteger('ranking', 'Pořadí:') ->setRequired(false) - ->setHtmlType('number'); + ->addRule(Form::Min, 'Minimální hodnota pořadí je %d', 0); $form->addText('note', 'Poznámka:') ->setRequired(false) ->addRule(Form::MaxLength, 'Maximální délka poznámky je %d znaků', 2000); @@ -64,17 +64,25 @@ public function create(callable $onSuccess, int $dateId, ?TrainingReview $review $form->onSuccess[] = function (UiForm $form) use ($onSuccess, $review, $dateId): void { $values = $form->getFormValues(); + assert(is_string($values->name)); + assert(is_string($values->company)); + assert(is_string($values->jobTitle)); + assert(is_string($values->review)); + assert(is_string($values->href)); + assert(is_bool($values->hidden)); + assert(is_int($values->ranking) || $values->ranking === null); + assert(is_string($values->note)); if ($review) { $this->trainingReviews->updateReview( $review->getId(), $dateId, $values->name, $values->company, - $values->jobTitle ?: null, + $values->jobTitle !== '' ? $values->jobTitle : null, $values->review, - $values->href ?: null, + $values->href !== '' ? $values->href : null, $values->hidden, - $values->ranking ?: null, + $values->ranking !== 0 ? $values->ranking : null, $values->note ?: null, ); } else { @@ -82,11 +90,11 @@ public function create(callable $onSuccess, int $dateId, ?TrainingReview $review $dateId, $values->name, $values->company, - $values->jobTitle ?: null, + $values->jobTitle !== '' ? $values->jobTitle : null, $values->review, - $values->href ?: null, + $values->href !== '' ? $values->href : null, $values->hidden, - $values->ranking ?: null, + $values->ranking !== 0 ? $values->ranking : null, $values->note ?: null, ); } diff --git a/app/src/Media/VideoThumbnails.php b/app/src/Media/VideoThumbnails.php index ec2b2b7fb..c01237e1d 100644 --- a/app/src/Media/VideoThumbnails.php +++ b/app/src/Media/VideoThumbnails.php @@ -71,17 +71,14 @@ public function addFormFields(UiForm $form, bool $hasMainVideoThumbnail, bool $h $videoThumbnailAlternative->addCondition(Form::Filled, true) ->toggle('#currentVideoThumbnailAlternative', false); } - return new VideoThumbnailFileUploads($videoThumbnail, $videoThumbnailAlternative, $hasMainVideoThumbnail, $hasAlternativeVideoThumbnail); - } - - - public function addOnValidateUploads(UiForm $form, VideoThumbnailFileUploads $formFields): void - { - $form->onValidate[] = function (UiForm $form) use ($formFields): void { + $form->onValidate[] = function (UiForm $form) use ($videoThumbnail, $videoThumbnailAlternative): void { $values = $form->getFormValues(); - $this->validateUpload($values->videoThumbnail, $formFields->getVideoThumbnail()); - $this->validateUpload($values->videoThumbnailAlternative, $formFields->getVideoThumbnailAlternative()); + assert($values->videoThumbnail instanceof FileUpload); + assert($values->videoThumbnailAlternative instanceof FileUpload); + $this->validateUpload($values->videoThumbnail, $videoThumbnail); + $this->validateUpload($values->videoThumbnailAlternative, $videoThumbnailAlternative); }; + return new VideoThumbnailFileUploads($videoThumbnail, $videoThumbnailAlternative, $hasMainVideoThumbnail, $hasAlternativeVideoThumbnail); } diff --git a/app/src/Net/DnsResolver.php b/app/src/Net/DnsResolver.php index f2a7b1f8f..675ec74d5 100644 --- a/app/src/Net/DnsResolver.php +++ b/app/src/Net/DnsResolver.php @@ -23,7 +23,12 @@ public function getRecords(string $hostname, int $type): array } $result = []; foreach ($records as $record) { - $result[] = new DnsRecord(...$record); + assert(is_string($record['host'])); + assert(is_string($record['class'])); + assert(is_int($record['ttl'])); + assert(is_string($record['type'])); + assert(is_string($record['ip'])); + $result[] = new DnsRecord($record['host'], $record['class'], $record['ttl'], $record['type'], $record['ip']); } return $result; } diff --git a/app/src/Talks/Slides/TalkSlides.php b/app/src/Talks/Slides/TalkSlides.php index 7dda00862..5d90d4f6d 100644 --- a/app/src/Talks/Slides/TalkSlides.php +++ b/app/src/Talks/Slides/TalkSlides.php @@ -217,11 +217,14 @@ private function addSlides(int $talkId, array $slides): void $lastNumber = 0; try { foreach ($slides as $slide) { + assert($slide->replace instanceof FileUpload); + assert($slide->replaceAlternative instanceof FileUpload); + assert(is_int($slide->number)); $width = self::SLIDE_MAX_WIDTH; $height = self::SLIDE_MAX_HEIGHT; $replace = $this->replaceSlideImage($talkId, $slide->replace, $this->supportedImageFileFormats->getMainExtensionByContentType(...), false, null, $width, $height); $replaceAlternative = $this->replaceSlideImage($talkId, $slide->replaceAlternative, $this->supportedImageFileFormats->getAlternativeExtensionByContentType(...), false, null, $width, $height); - $lastNumber = (int)$slide->number; + $lastNumber = $slide->number; $this->database->query( 'INSERT INTO talk_slides', [ @@ -259,6 +262,14 @@ private function updateSlides(int $talkId, TalkSlideCollection $originalSlides, } } foreach ($slides as $id => $slide) { + assert($slide->replace instanceof FileUpload || $slide->replace === null); + assert($slide->replaceAlternative instanceof FileUpload || $slide->replaceAlternative === null); + assert(is_string($slide->alias)); + assert(is_int($slide->number)); + assert(is_string($slide->filename)); + assert(is_string($slide->filenameAlternative)); + assert(is_string($slide->title)); + assert(is_string($slide->speakerNotes)); $width = self::SLIDE_MAX_WIDTH; $height = self::SLIDE_MAX_HEIGHT; diff --git a/app/src/Training/ApplicationForm/TrainingApplicationFormDataLogger.php b/app/src/Training/ApplicationForm/TrainingApplicationFormDataLogger.php index ab8548a54..ca5c94e23 100644 --- a/app/src/Training/ApplicationForm/TrainingApplicationFormDataLogger.php +++ b/app/src/Training/ApplicationForm/TrainingApplicationFormDataLogger.php @@ -4,18 +4,20 @@ namespace MichalSpacekCz\Training\ApplicationForm; use MichalSpacekCz\Training\Applications\TrainingApplicationSessionSection; -use stdClass; use Tracy\Debugger; class TrainingApplicationFormDataLogger { - public function log(stdClass $values, string $name, int $dateId, ?TrainingApplicationSessionSection $sessionSection): void + /** + * @param array $values + */ + public function log(array $values, string $name, int $dateId, ?TrainingApplicationSessionSection $sessionSection): void { $applicationId = $sessionSection?->getApplicationIdByDateId($name, $dateId); $logSession = $applicationId !== null ? "id => '{$applicationId}', dateId => '{$dateId}'" : null; $logValues = []; - foreach ((array)$values as $key => $value) { + foreach ($values as $key => $value) { $logValues[] = sprintf('%s => %s', $key, is_string($value) ? "'{$value}'" : get_debug_type($value)); } $message = sprintf( diff --git a/app/src/Training/ApplicationForm/TrainingApplicationFormSpam.php b/app/src/Training/ApplicationForm/TrainingApplicationFormSpam.php index 953658619..8c4ff3115 100644 --- a/app/src/Training/ApplicationForm/TrainingApplicationFormSpam.php +++ b/app/src/Training/ApplicationForm/TrainingApplicationFormSpam.php @@ -5,7 +5,6 @@ use Composer\Pcre\Regex; use MichalSpacekCz\Training\Exceptions\SpammyApplicationException; -use stdClass; class TrainingApplicationFormSpam { @@ -16,15 +15,18 @@ class TrainingApplicationFormSpam private const string FIELD_MISSING_VALUE = 'missing'; - public function check(stdClass $values): void + /** + * @throws SpammyApplicationException + */ + public function check(string $name, ?string $company = null, ?string $companyId = null, ?string $companyTaxId = null, ?string $note = null): void { - if (Regex::isMatch('~\s+href="\s*https?://~', $values->note ?? '')) { + if (Regex::isMatch('~\s+href="\s*https?://~', $note ?? self::FIELD_MISSING_VALUE)) { throw new SpammyApplicationException(); } elseif ( - ctype_lower($values->name ?? self::FIELD_MISSING_VALUE) - && ctype_lower($values->company ?? self::FIELD_MISSING_VALUE) - && ctype_lower($values->companyId ?? self::FIELD_MISSING_VALUE) - && ctype_lower($values->companyTaxId ?? self::FIELD_MISSING_VALUE) + ctype_lower($name) + && ctype_lower($company ?? self::FIELD_MISSING_VALUE) + && ctype_lower($companyId ?? self::FIELD_MISSING_VALUE) + && ctype_lower($companyTaxId ?? self::FIELD_MISSING_VALUE) ) { throw new SpammyApplicationException(); } diff --git a/app/src/Training/ApplicationForm/TrainingApplicationFormSuccess.php b/app/src/Training/ApplicationForm/TrainingApplicationFormSuccess.php index a853595ad..1bd19f185 100644 --- a/app/src/Training/ApplicationForm/TrainingApplicationFormSuccess.php +++ b/app/src/Training/ApplicationForm/TrainingApplicationFormSuccess.php @@ -21,7 +21,6 @@ use ParagonIE\Halite\Alerts\HaliteAlert; use PDOException; use SodiumException; -use stdClass; use Tracy\Debugger; readonly class TrainingApplicationFormSuccess @@ -57,11 +56,22 @@ public function success( TrainingApplicationSessionSection $sessionSection, ): void { $values = $form->getFormValues(); + assert(is_string($values->name)); + assert(is_string($values->email)); + assert(is_string($values->company)); + assert(is_string($values->street)); + assert(is_string($values->city)); + assert(is_string($values->zip)); + assert(is_string($values->country)); + assert(is_string($values->companyId)); + assert(is_string($values->companyTaxId)); + assert(is_string($values->note)); try { - $this->formSpam->check($values); + $this->formSpam->check($values->name, $values->company, $values->companyId, $values->companyTaxId, $values->note); if ($multipleDates) { - $this->checkTrainingDate($values, $action, $dates, $sessionSection); - $date = $dates[$values->trainingId] ?? false; + assert(is_int($values->trainingId)); + $this->checkTrainingDate((array)$values, $action, $values->trainingId, $dates, $sessionSection); + $date = $dates[$values->trainingId]; } else { $date = reset($dates); } @@ -153,14 +163,15 @@ public function success( /** + * @param array $values * @param array $dates * @throws TrainingDateNotUpcomingException */ - private function checkTrainingDate(stdClass $values, string $name, array $dates, TrainingApplicationSessionSection $sessionSection): void + private function checkTrainingDate(array $values, string $name, int $dateId, array $dates, TrainingApplicationSessionSection $sessionSection): void { - if (!isset($dates[$values->trainingId])) { - $this->formDataLogger->log($values, $name, $values->trainingId, $sessionSection); - throw new TrainingDateNotUpcomingException($values->trainingId, $dates); + if (!isset($dates[$dateId])) { + $this->formDataLogger->log($values, $name, $dateId, $sessionSection); + throw new TrainingDateNotUpcomingException($dateId, $dates); } } diff --git a/app/src/Training/Reviews/TrainingReviews.php b/app/src/Training/Reviews/TrainingReviews.php index ced5fd2a6..a2e3fa675 100644 --- a/app/src/Training/Reviews/TrainingReviews.php +++ b/app/src/Training/Reviews/TrainingReviews.php @@ -3,8 +3,8 @@ namespace MichalSpacekCz\Training\Reviews; -use DateTime; use MichalSpacekCz\Database\TypedDatabase; +use MichalSpacekCz\DateTime\DateTimeFactory; use MichalSpacekCz\Formatter\TexyFormatter; use MichalSpacekCz\Training\Exceptions\TrainingReviewNotFoundException; use Nette\Database\Explorer; @@ -17,6 +17,7 @@ public function __construct( private Explorer $database, private TypedDatabase $typedDatabase, private TexyFormatter $texyFormatter, + private DateTimeFactory $dateTimeFactory, ) { } @@ -176,7 +177,7 @@ public function updateReview(int $reviewId, int $dateId, string $name, string $c public function addReview(int $dateId, string $name, string $company, ?string $jobTitle, string $review, ?string $href, bool $hidden, ?int $ranking, ?string $note): void { - $datetime = new DateTime(); + $datetime = $this->dateTimeFactory->create(); $timeZone = $datetime->getTimezone()->getName(); $this->database->query( 'INSERT INTO training_reviews ?', diff --git a/app/tests/EasterEgg/NetteCve202015227Test.phpt b/app/tests/EasterEgg/NetteCve202015227Test.phpt index 51258e996..adad7d089 100644 --- a/app/tests/EasterEgg/NetteCve202015227Test.phpt +++ b/app/tests/EasterEgg/NetteCve202015227Test.phpt @@ -7,6 +7,7 @@ use MichalSpacekCz\Test\TestCaseRunner; use Nette\Application\BadRequestException; use Nette\Application\Routers\Route; use Nette\Application\Routers\RouteList; +use Nette\Application\UI\Component; use Tester\Assert; use Tester\TestCase; @@ -25,7 +26,7 @@ class NetteCve202015227Test extends TestCase public function testRceUnknownCallback(): void { Assert::exception(function (): void { - $this->cve202015227->rce('foo', ['bar' => 'baz']); + $this->cve202015227->rce('foo', $this->createComponent(['bar' => 'baz'])); }, BadRequestException::class, "[MichalSpacekCz\EasterEgg\NetteCve202015227] Unknown callback 'foo'"); } @@ -33,7 +34,7 @@ class NetteCve202015227Test extends TestCase public function testRceEmptyParam(): void { Assert::exception(function (): void { - $this->cve202015227->rce('exec', ['bar' => 'baz']); + $this->cve202015227->rce('exec', $this->createComponent(['bar' => 'baz'])); }, BadRequestException::class, "[MichalSpacekCz\EasterEgg\NetteCve202015227] Empty param 'command' for callback 'exec'"); } @@ -41,21 +42,21 @@ class NetteCve202015227Test extends TestCase public function testRceUnknownValue(): void { Assert::exception(function (): void { - $this->cve202015227->rce('exec', ['command' => 'baz']); + $this->cve202015227->rce('exec', $this->createComponent(['command' => 'baz'])); }, BadRequestException::class, "[MichalSpacekCz\EasterEgg\NetteCve202015227] Unknown value 'baz' for callback 'exec' and param 'command'"); } public function testRceLs(): void { - $rce = $this->cve202015227->rce('exec', ['command' => 'ls foo']); + $rce = $this->cve202015227->rce('exec', $this->createComponent(['command' => 'ls foo'])); Assert::same(NetteCve202015227View::Ls, $rce->view); } public function testRceIfconfig(): void { - $rce = $this->cve202015227->rce('exec', ['command' => 'ifconfig bar']); + $rce = $this->cve202015227->rce('exec', $this->createComponent(['command' => 'ifconfig bar'])); Assert::same(NetteCve202015227View::Ifconfig, $rce->view); Assert::type('string', $rce->eth0RxPackets); Assert::type('string', $rce->eth1RxPackets); @@ -74,7 +75,7 @@ class NetteCve202015227Test extends TestCase public function testRceWget(): void { - $rce = $this->cve202015227->rce('shell_exec', ['cmd' => 'wget example.com']); + $rce = $this->cve202015227->rce('shell_exec', $this->createComponent(['cmd' => 'wget example.com'])); Assert::same(NetteCve202015227View::Wget, $rce->view); } @@ -82,7 +83,7 @@ class NetteCve202015227Test extends TestCase /** @dataProvider getCommands */ public function testRceNotFound(NetteCve202015227View $view, string $command, string $cmd): void { - $rce = $this->cve202015227->rce('shell_exec', ['cmd' => $cmd]); + $rce = $this->cve202015227->rce('shell_exec', $this->createComponent(['cmd' => $cmd])); Assert::same($view, $rce->view); Assert::same($command, $rce->command); } @@ -141,6 +142,18 @@ class NetteCve202015227Test extends TestCase ]; } + + /** + * @param array $params + */ + private function createComponent(array $params): Component + { + $component = new class extends Component { + }; + $component->loadState($params); + return $component; + } + } TestCaseRunner::run(NetteCve202015227Test::class); diff --git a/app/tests/Form/TrainingReviewFormFactoryTest.phpt b/app/tests/Form/TrainingReviewFormFactoryTest.phpt new file mode 100644 index 000000000..d97968f7c --- /dev/null +++ b/app/tests/Form/TrainingReviewFormFactoryTest.phpt @@ -0,0 +1,119 @@ +setDateTime(new DateTimeImmutable('2020-01-01 12:34:56')); + } + + + #[Override] + protected function tearDown(): void + { + $this->database->reset(); + $this->resultDateId = null; + } + + + public function testCreateOnSuccessAdd(): void + { + $form = $this->formFactory->create( + function (int $dateId): void { + $this->resultDateId = $dateId; + }, + self::DATE_ID, + null, + ); + $this->applicationPresenter->anchorForm($form); + Arrays::invoke($form->onSuccess, $form); + Assert::same(self::DATE_ID, $this->resultDateId); + Assert::same([ + [ + 'key_date' => self::DATE_ID, + 'name' => '', + 'company' => '', + 'job_title' => null, + 'review' => '', + 'href' => null, + 'added' => '2020-01-01 12:34:56', + 'added_timezone' => 'Europe/Prague', + 'hidden' => false, + 'ranking' => null, + 'note' => null, + ], + ], $this->database->getParamsArrayForQuery('INSERT INTO training_reviews ?')); + } + + + public function testCreateOnSuccessEdit(): void + { + $form = $this->formFactory->create( + function (int $dateId): void { + $this->resultDateId = $dateId; + }, + self::DATE_ID, + new TrainingReview( + 303, + 'John Deere', + 'Comp Any', + 'Team Le-ad', + Html::fromHtml('foo'), + '**foo**', + 'https://example.com', + false, + 3, + 'No tea', + self::DATE_ID, + ), + ); + $this->applicationPresenter->anchorForm($form); + Arrays::invoke($form->onSuccess, $form); + Assert::same(self::DATE_ID, $this->resultDateId); + Assert::same([ + [ + 'key_date' => self::DATE_ID, + 'name' => 'John Deere', + 'company' => 'Comp Any', + 'job_title' => 'Team Le-ad', + 'review' => '**foo**', + 'href' => 'https://example.com', + 'hidden' => false, + 'ranking' => 3, + 'note' => 'No tea', + ], + ], $this->database->getParamsArrayForQuery('UPDATE training_reviews SET ? WHERE id_review = ?')); + } + +} + +TestCaseRunner::run(TrainingReviewFormFactoryTest::class); diff --git a/app/tests/Net/DnsResolverTest.phpt b/app/tests/Net/DnsResolverTest.phpt new file mode 100644 index 000000000..48f744da8 --- /dev/null +++ b/app/tests/Net/DnsResolverTest.phpt @@ -0,0 +1,34 @@ +dnsResolver->getRecords('one.one.one.one', DNS_A); + $ips = array_map(fn(DnsRecord $dnsRecord): ?string => $dnsRecord->getIp(), $records); + sort($ips); + Assert::same(['1.0.0.1', '1.1.1.1'], $ips); + } + +} + +TestCaseRunner::run(DnsResolverTest::class); diff --git a/app/tests/Training/ApplicationForm/TrainingApplicationFormDataLoggerTest.phpt b/app/tests/Training/ApplicationForm/TrainingApplicationFormDataLoggerTest.phpt index 0b4b25a66..bc6708e8e 100644 --- a/app/tests/Training/ApplicationForm/TrainingApplicationFormDataLoggerTest.phpt +++ b/app/tests/Training/ApplicationForm/TrainingApplicationFormDataLoggerTest.phpt @@ -15,7 +15,6 @@ use MichalSpacekCz\Training\Files\TrainingFiles; use MichalSpacekCz\Training\Mails\TrainingMailMessageFactory; use Nette\Utils\Html; use Override; -use stdClass; use Tester\Assert; use Tester\TestCase; @@ -50,16 +49,17 @@ class TrainingApplicationFormDataLoggerTest extends TestCase public function testLogNoValuesNoSession(): void { - $this->formDataLogger->log(new stdClass(), 'foo', self::DATE_ID, null); + $this->formDataLogger->log([], 'foo', self::DATE_ID, null); Assert::same(['Application session data for foo: undefined, form values: empty'], $this->logger->getLogged()); } public function testLogNoSession(): void { - $values = new stdClass(); - $values->key1 = 'value1'; - $values->key2 = 'value2'; + $values = [ + 'key1' => 'value1', + 'key2' => 'value2', + ]; $this->formDataLogger->log($values, 'foo', self::DATE_ID, null); Assert::same(["Application session data for foo: undefined, form values: key1 => 'value1', key2 => 'value2'"], $this->logger->getLogged()); } @@ -67,9 +67,10 @@ class TrainingApplicationFormDataLoggerTest extends TestCase public function testLogEmptySession(): void { - $values = new stdClass(); - $values->key1 = 'value1'; - $values->key2 = 'value2'; + $values = [ + 'key1' => 'value1', + 'key2' => 'value2', + ]; $this->formDataLogger->log($values, 'foo', self::DATE_ID, $this->getTrainingSessionSection()); Assert::same(["Application session data for foo: empty, form values: key1 => 'value1', key2 => 'value2'"], $this->logger->getLogged()); } @@ -77,10 +78,11 @@ class TrainingApplicationFormDataLoggerTest extends TestCase public function testLog(): void { - $values = new stdClass(); - $values->key1 = 'value1'; - $values->key2 = 'value2'; - $values->key3 = 1336; + $values = [ + 'key1' => 'value1', + 'key2' => 'value2', + 'key3' => 1336, + ]; $trainingName = 'foo'; $session = $this->getTrainingSessionSection(); diff --git a/app/tests/Training/ApplicationForm/TrainingApplicationFormSpamTest.phpt b/app/tests/Training/ApplicationForm/TrainingApplicationFormSpamTest.phpt index da7ceb0fa..15edab45c 100644 --- a/app/tests/Training/ApplicationForm/TrainingApplicationFormSpamTest.phpt +++ b/app/tests/Training/ApplicationForm/TrainingApplicationFormSpamTest.phpt @@ -5,11 +5,9 @@ declare(strict_types = 1); namespace MichalSpacekCz\Training\ApplicationForm; -use Generator; use MichalSpacekCz\Test\NullLogger; use MichalSpacekCz\Test\TestCaseRunner; use MichalSpacekCz\Training\Exceptions\SpammyApplicationException; -use stdClass; use Tester\Assert; use Tester\TestCase; @@ -26,45 +24,79 @@ class TrainingApplicationFormSpamTest extends TestCase } - public function getValues(): Generator + /** + * @return list + */ + public function getValues(): array { - $values = new stdClass(); - $values->note = 'foo href="https:// example" bar baz'; - yield [$values, false]; - - $values = new stdClass(); - $values->name = 'zggnbijhah'; - $values->companyId = 'vwetyeofcx'; - $values->companyTaxId = 'tyqvukaims'; - $values->company = 'qzpormrfcq'; - yield [$values, false]; - - $values = new stdClass(); - $values->name = 'zggnbijhah'; - yield [$values, false]; - - yield [new stdClass(), false]; - $values = new stdClass(); - $values->name = 'foo bar'; - yield [$values, true]; - - $values = new stdClass(); - $values->companyId = 'foobar1'; - yield [$values, true]; - - $values = new stdClass(); - $values->companyTaxId = 'foobar1'; - yield [$values, true]; + return [ + [ + 'name' => 'foo bar', + 'companyId' => null, + 'companyTaxId' => null, + 'company' => null, + 'note' => 'foo href="https:// example" bar baz', + 'isNice' => false, + ], + [ + 'name' => 'zggnbijhah', + 'companyId' => 'vwetyeofcx', + 'companyTaxId' => 'tyqvukaims', + 'company' => 'qzpormrfcq', + 'note' => null, + 'isNice' => false, + ], + [ + 'name' => 'zggnbijhah', + 'companyId' => null, + 'companyTaxId' => null, + 'company' => null, + 'note' => null, + 'isNice' => false, + ], + [ + 'name' => 'foo bar', + 'companyId' => null, + 'companyTaxId' => null, + 'company' => null, + 'note' => null, + 'isNice' => true, + ], + [ + 'name' => '', + 'companyId' => 'foobar1', + 'companyTaxId' => null, + 'company' => null, + 'note' => null, + 'isNice' => true, + ], + [ + 'name' => '', + 'companyId' => null, + 'companyTaxId' => 'foobar1', + 'company' => null, + 'note' => null, + 'isNice' => true, + ], + [ + 'name' => '', + 'companyId' => null, + 'companyTaxId' => null, + 'company' => 'comp any', + 'note' => null, + 'isNice' => true, + ], + ]; } /** * @dataProvider getValues */ - public function testIsSpam(stdClass $values, bool $isNice): void + public function testIsSpam(string $name, ?string $companyId, ?string $companyTaxId, ?string $company, ?string $note, bool $isNice): void { - $check = function () use ($values): void { - $this->formSpam->check($values); + $check = function () use ($name, $company, $companyId, $companyTaxId, $note): void { + $this->formSpam->check($name, $company, $companyId, $companyTaxId, $note); }; if ($isNice) { Assert::noError($check);