From aa5247141076718704641d500ce09e3098ad200f Mon Sep 17 00:00:00 2001 From: Anton Popov Date: Fri, 22 Jan 2021 14:39:16 +0700 Subject: [PATCH 1/9] feature/PLU-2760-create-invalid-data-generator - created InvalidDataMaker --- packages/EasySecurity/composer.json | 4 +- .../AbstractInvalidDataMaker.php | 240 ++++++++++++++ .../src/InvalidDataMaker/InvalidDataMaker.php | 293 ++++++++++++++++++ 3 files changed, 536 insertions(+), 1 deletion(-) create mode 100644 packages/EasyTest/src/InvalidDataMaker/AbstractInvalidDataMaker.php create mode 100644 packages/EasyTest/src/InvalidDataMaker/InvalidDataMaker.php diff --git a/packages/EasySecurity/composer.json b/packages/EasySecurity/composer.json index d256e880f..93d1b7e6f 100644 --- a/packages/EasySecurity/composer.json +++ b/packages/EasySecurity/composer.json @@ -12,9 +12,11 @@ }, "require-dev": { "eonx-com/easy-bugsnag": "^3.0", + "nesbot/carbon": "^2.3", "phpunit/phpunit": "^8.4 || ^9.5", "laravel/lumen-framework": "^5.5", - "symfony/symfony": "^4.4 || ^5.1.5" + "symfony/symfony": "^4.4 || ^5.1.5", + "symfony/intl": "^4.4 || ^5.1.5", }, "autoload": { "psr-4": { diff --git a/packages/EasyTest/src/InvalidDataMaker/AbstractInvalidDataMaker.php b/packages/EasyTest/src/InvalidDataMaker/AbstractInvalidDataMaker.php new file mode 100644 index 000000000..98074c986 --- /dev/null +++ b/packages/EasyTest/src/InvalidDataMaker/AbstractInvalidDataMaker.php @@ -0,0 +1,240 @@ +property = $property; + } + + final public static function addTranslations(string $translations): void + { + self::$translations[] = $translations; + } + + final public static function make(string $property): self + { + return new static($property); + } + + /** + * @param mixed $value + * + * @return mixed[] + */ + final protected function create($caseName, $value, ?string $message = null): array + { + if ($this->asString === true) { + $value = (string)$value; + } + + if ($this->asArrayElement === true) { + $value = [$value]; + } + + $invalidData = [ + $this->property => $value, + ]; + + $data = [ + $caseName => [ + 'data' => $invalidData, + 'message' => (string)($this->message ?? $message), + 'propertyPath' => $this->resolvePropertyPath($invalidData), + ] + ]; + + if ($this->wrapWith !== null) { + $data = $this->applyWrapWith($data); + } + + return $data; + } + + /** + * @param mixed[]|null $params + */ + final protected function translateMessage(string $messageKey, ?array $params = null, ?int $plural = null): string + { + $params[self::PLURAL_INDEX] = $plural; + + return self::$translator->trans($messageKey, $params); + } + + private static function createTranslationLoader(string $extension): LoaderInterface + { + if (\in_array($extension, ['yaml', 'yml'], true)) { + return new YamlFileLoader(); + } + + if ($extension === 'xlf') { + return new XliffFileLoader(); + } + + throw new LogicException('For now allowed translations in formats [yaml, xlf]'); + } + + private static function initTranslator(): void + { + if (self::$translator !== null) { + return; + } + + $locale = 'en'; + $translator = new Translator($locale); + + foreach (self::$translations as $translation) { + $extension = \strtolower(\pathinfo($translation, \PATHINFO_EXTENSION)); + $translator->addLoader($extension, self::createTranslationLoader($extension)); + $translator->addResource($extension, $translation, $locale); + } + + self::$translator = $translator; + } + + /** + * @param mixed[] $data + * + * @return mixed[] + */ + private function applyWrapWith(array $data): array + { + $caseName = \current(\array_keys($data)); + $caseData = $data[$caseName]['data']; + + /** @var string $newCaseName */ + $newCaseName = \str_replace($this->property, "{$this->wrapWith}.{$this->property}", $caseName); + + return [ + $newCaseName => [ + 'data' => [ + $this->wrapWith => $caseData, + ], + 'message' => $data[$caseName]['message'], + 'propertyPath' => "{$this->wrapWith}.{$this->property}", + ] + ]; + } + + /** + * @param mixed[] $invalidData + * + * @noinspection MultipleReturnStatementsInspection + */ + private function resolvePropertyPath(array $invalidData): string + { + if ($this->propertyPath !== null) { + return $this->propertyPath; + } + + $propertyName = (string)\array_key_first($invalidData); + + if (\is_array($invalidData[$propertyName]) && \count($invalidData[$propertyName]) > 0) { + // The case of stubs collection ('prop' => [ [], [], [], [] ]) + if (($invalidData[$propertyName][0] ?? null) === []) { + return $propertyName; + } + + $currentProperty = \current(\array_keys($invalidData[$propertyName])); + + if ($currentProperty === 0) { + return $propertyName . '[0]'; + } + + return $propertyName . '.' . $this->resolvePropertyPath($invalidData[$propertyName]); + } + + return $propertyName; + } + + final public function asArrayElement(): self + { + $this->asArrayElement = true; + + return $this; + } + + final public function asString(): self + { + $this->asString = true; + + return $this; + } + + final public function message(string $message): self + { + $this->message = $message; + + return $this; + } + + final public function propertyPath(string $propertyPath): self + { + $this->propertyPath = $propertyPath; + + return $this; + } + + final public function wrapWith(string $wrapWith): self + { + $this->wrapWith = $wrapWith; + + return $this; + } +} diff --git a/packages/EasyTest/src/InvalidDataMaker/InvalidDataMaker.php b/packages/EasyTest/src/InvalidDataMaker/InvalidDataMaker.php new file mode 100644 index 000000000..f3874bdce --- /dev/null +++ b/packages/EasyTest/src/InvalidDataMaker/InvalidDataMaker.php @@ -0,0 +1,293 @@ +translateMessage( + (new Count(['min' => $minElements]))->minMessage, + ['{{ limit }}' => $minElements], + $minElements + ); + + yield from $this->create("{$this->property} has too few elements in the collection is blank", $value, $message); + } + + public function yieldArrayCollectionWithMoreItems(int $maxElements): iterable + { + $value = new ArrayCollection(\array_fill(0, $maxElements - 1, null)); + $message = $this->translateMessage( + (new Count(['max' => $maxElements]))->maxMessage, + ['{{ limit }}' => $maxElements], + $maxElements + ); + + yield from $this->create("{$this->property} has too more elements in the collection", $value, $message); + } + + public function yieldArrayWithFewerItems(int $minElements): iterable + { + $value = \array_fill(0, $minElements - 1, null); + $message = $this->translateMessage( + (new Count(['min' => $minElements]))->minMessage, + ['{{ limit }}' => $minElements], + $minElements + ); + + yield from $this->create("{$this->property} has too few elements in the array", $value, $message); + } + + public function yieldArrayWithMoreItems(int $maxElements): iterable + { + $value = \array_fill(0, $maxElements + 1, null); + $message = $this->translateMessage( + (new Count(['max' => $maxElements]))->maxMessage, + ['{{ limit }}' => $maxElements], + $maxElements + ); + + yield from $this->create("{$this->property} has too many elements in the collection", $value, $message); + } + + public function yieldBlankString(): iterable + { + $value = ''; + $message = $this->translateMessage((new NotBlank())->message); + + yield from $this->create("{$this->property} is blank", $value, $message); + } + + public function yieldDateTimeLessThanOrEqualToNow(): iterable + { + $dateTime = Carbon::now(); + $message = $this->translateMessage((new GreaterThan(['value' => 'now']))->message, [ + '{{ compared_value }}' => 'now', + ]); + + $value = $dateTime->clone()->subSecond()->toAtomString(); + yield from $this->create("{$this->property} has less datetime", $value, $message); + + $value = $dateTime->toAtomString(); + yield from $this->create("{$this->property} has equal datetime", $value, $message); + } + + public function yieldEmptyArrayCollection(int $minElements): iterable + { + $value = new ArrayCollection(); + $message = $this->translateMessage( + (new Count(['min' => $minElements]))->minMessage, + ['{{ limit }}' => $minElements], + $minElements + ); + + yield from $this->create("{$this->property} has too few elements in the collection", $value, $message); + } + + public function yieldIntegerGreaterThanGiven(int $lessThanOrEqualValue): iterable + { + $value = $lessThanOrEqualValue + 1; + $message = $this->translateMessage((new LessThanOrEqual(['value' => $value]))->message, [ + '{{ compared_value }}' => $lessThanOrEqualValue, + ]); + + yield from $this->create("{$this->property} has greater value", $value, $message); + } + + public function yieldIntegerGreaterThanOrEqualToGiven(int $lessThanValue): iterable + { + $value = $lessThanValue + 1; + $message = $this->translateMessage((new LessThan(['value' => $value]))->message, [ + '{{ compared_value }}' => $lessThanValue, + ]); + yield from $this->create("{$this->property} has greater value", $value, $message); + + $value = $lessThanValue; + $message = $this->translateMessage((new LessThan(['value' => $value]))->message, [ + '{{ compared_value }}' => $lessThanValue, + ]); + yield from $this->create("{$this->property} has equal value", $value, $message); + } + + public function yieldInvalidChoice(): iterable + { + $value = 'invalid-choice'; + $message = $this->translateMessage((new Choice())->message); + + yield from $this->create("{$this->property} is not a valid choice", $value, $message); + } + + public function yieldInvalidCreditCardNumber(): iterable + { + $value = '1111222233334444'; + $message = $this->translateMessage((new CardScheme(['schemes' => null]))->message); + + yield from $this->create("{$this->property} is not a valid credit card number", $value, $message); + } + + public function yieldInvalidCurrencyCode(): iterable + { + $value = 'invalid-currency-code'; + $message = $this->translateMessage((new Currency())->message); + + yield from $this->create("{$this->property} is invalid currency", $value, $message); + } + + public function yieldInvalidEmail(): iterable + { + $value = 'invalid-email'; + $message = $this->translateMessage((new Email())->message); + + yield from $this->create("{$this->property} is invalid email", $value, $message); + } + + public function yieldInvalidExactLengthString(int $exactLength): iterable + { + $message = $this->translateMessage( + (new Length(['max' => $exactLength, 'min' => $exactLength]))->exactMessage, + ['{{ limit }}' => $exactLength], + $exactLength + ); + + $value = \str_pad('1', $exactLength + 1, '1'); + yield from $this->create("{$this->property} has length more than expected", $value, $message); + + $value = \str_pad('', $exactLength - 1, '1'); + yield from $this->create("{$this->property} has length less than expected", $value, $message); + } + + public function yieldInvalidFloat(int $precision, ?int $integerPart = null): iterable + { + $value = ($integerPart ?? 0) + \round(1 / 3, $precision + 1); + yield from $this->create("{$this->property} has invalid precision", $value); + + $value = 'abc'; + yield from $this->create("{$this->property} is a string", $value); + + $value = 10; + yield from $this->create("{$this->property} is an integer", $value); + } + + public function yieldInvalidTimezone(): iterable + { + $value = 'invalid-timezone'; + $message = $this->translateMessage((new Timezone())->message); + + yield from $this->create("{$this->property} is invalid timezone", $value, $message); + } + + public function yieldInvalidUrl(): iterable + { + $value = 'invalid-url'; + $message = $this->translateMessage((new Url())->message); + + yield from $this->create("{$this->property} is invalid url", $value, $message); + } + + public function yieldInvalidUuid(): iterable + { + $value = 'some-invalid-uuid'; + $message = $this->translateMessage((new Uuid())->message); + + yield from $this->create("{$this->property} is invalid uuid", $value, $message); + } + + public function yieldNegativeNumber(): iterable + { + $value = -1; + $message = $this->translateMessage((new PositiveOrZero())->message); + + yield from $this->create("{$this->property} has negative value", $value, $message); + } + + public function yieldNegativeOrZeroNumber(): iterable + { + $message = $this->translateMessage((new Positive())->message); + + $value = -1; + yield from $this->create("{$this->property} has negative value", $value, $message); + + $value = 0; + yield from $this->create("{$this->property} has zero value", $value, $message); + } + + public function yieldNonDigitSymbols(): iterable + { + $value = '111-aaa'; + $message = $this->translateMessage((new Type(['type' => 'digit']))->message, [ + '{{ type }}' => 'digit', + ]); + + yield from $this->create("{$this->property} has non-digit symbols", $value, $message); + } + + public function yieldNonLuhnCreditCardNumber(): iterable + { + $value = '4388576018402626'; + $message = $this->translateMessage((new Luhn())->message); + + yield from $this->create("{$this->property} do not pass the Luhn algorithm", $value, $message); + } + + public function yieldOutOfRangeNumber(int $min, int $max): iterable + { + $message = $this->translateMessage((new Range(\compact('min', 'max')))->notInRangeMessage, [ + '{{ min }}' => $min, + '{{ max }}' => $max, + ]); + + $value = $max + 1; + yield from $this->create("{$this->property} is out of range (above)", $value, $message); + + $value = $min - 1; + yield from $this->create("{$this->property} is out of range (below)", $value, $message); + } + + public function yieldTooLongString(int $maxLength): iterable + { + $value = \str_pad('g', $maxLength + 1, 'g'); + $message = $this->translateMessage( + (new Length(['max' => $maxLength]))->maxMessage, + ['{{ limit }}' => $maxLength], + $maxLength + ); + + yield from $this->create("{$this->property} is too long", $value, $message); + } + + public function yieldTooShortString(int $minLength): iterable + { + $value = $minLength > 1 ? \str_pad('g', $minLength - 1, 'g') : ''; + $message = $this->translateMessage( + (new Length(['min' => $minLength]))->minMessage, + ['{{ limit }}' => $minLength], + $minLength + ); + + yield from $this->create("{$this->property} is too short", $value, $message); + } +} From da3ab76ad39053f80efe2548a033083f922f1593 Mon Sep 17 00:00:00 2001 From: Anton Popov Date: Fri, 22 Jan 2021 15:23:18 +0700 Subject: [PATCH 2/9] feature/PLU-2760-create-invalid-data-generator - ecs fixes --- .../AbstractInvalidDataMaker.php | 5 +- .../src/InvalidDataMaker/InvalidDataMaker.php | 139 +++++++++++++----- 2 files changed, 104 insertions(+), 40 deletions(-) diff --git a/packages/EasyTest/src/InvalidDataMaker/AbstractInvalidDataMaker.php b/packages/EasyTest/src/InvalidDataMaker/AbstractInvalidDataMaker.php index 98074c986..ac5087d07 100644 --- a/packages/EasyTest/src/InvalidDataMaker/AbstractInvalidDataMaker.php +++ b/packages/EasyTest/src/InvalidDataMaker/AbstractInvalidDataMaker.php @@ -1,4 +1,5 @@ $invalidData, 'message' => (string)($this->message ?? $message), 'propertyPath' => $this->resolvePropertyPath($invalidData), - ] + ], ]; if ($this->wrapWith !== null) { @@ -168,7 +169,7 @@ private function applyWrapWith(array $data): array ], 'message' => $data[$caseName]['message'], 'propertyPath' => "{$this->wrapWith}.{$this->property}", - ] + ], ]; } diff --git a/packages/EasyTest/src/InvalidDataMaker/InvalidDataMaker.php b/packages/EasyTest/src/InvalidDataMaker/InvalidDataMaker.php index f3874bdce..96babffdc 100644 --- a/packages/EasyTest/src/InvalidDataMaker/InvalidDataMaker.php +++ b/packages/EasyTest/src/InvalidDataMaker/InvalidDataMaker.php @@ -30,8 +30,12 @@ public function yieldArrayCollectionWithFewerItems(int $minElements): iterable { $value = new ArrayCollection(\array_fill(0, $minElements - 1, null)); $message = $this->translateMessage( - (new Count(['min' => $minElements]))->minMessage, - ['{{ limit }}' => $minElements], + (new Count([ + 'min' => $minElements, + ]))->minMessage, + [ + '{{ limit }}' => $minElements, + ], $minElements ); @@ -42,8 +46,12 @@ public function yieldArrayCollectionWithMoreItems(int $maxElements): iterable { $value = new ArrayCollection(\array_fill(0, $maxElements - 1, null)); $message = $this->translateMessage( - (new Count(['max' => $maxElements]))->maxMessage, - ['{{ limit }}' => $maxElements], + (new Count([ + 'max' => $maxElements, + ]))->maxMessage, + [ + '{{ limit }}' => $maxElements, + ], $maxElements ); @@ -54,8 +62,12 @@ public function yieldArrayWithFewerItems(int $minElements): iterable { $value = \array_fill(0, $minElements - 1, null); $message = $this->translateMessage( - (new Count(['min' => $minElements]))->minMessage, - ['{{ limit }}' => $minElements], + (new Count([ + 'min' => $minElements, + ]))->minMessage, + [ + '{{ limit }}' => $minElements, + ], $minElements ); @@ -66,8 +78,12 @@ public function yieldArrayWithMoreItems(int $maxElements): iterable { $value = \array_fill(0, $maxElements + 1, null); $message = $this->translateMessage( - (new Count(['max' => $maxElements]))->maxMessage, - ['{{ limit }}' => $maxElements], + (new Count([ + 'max' => $maxElements, + ]))->maxMessage, + [ + '{{ limit }}' => $maxElements, + ], $maxElements ); @@ -85,9 +101,14 @@ public function yieldBlankString(): iterable public function yieldDateTimeLessThanOrEqualToNow(): iterable { $dateTime = Carbon::now(); - $message = $this->translateMessage((new GreaterThan(['value' => 'now']))->message, [ - '{{ compared_value }}' => 'now', - ]); + $message = $this->translateMessage( + (new GreaterThan([ + 'value' => 'now', + ]))->message, + [ + '{{ compared_value }}' => 'now', + ] + ); $value = $dateTime->clone()->subSecond()->toAtomString(); yield from $this->create("{$this->property} has less datetime", $value, $message); @@ -100,8 +121,12 @@ public function yieldEmptyArrayCollection(int $minElements): iterable { $value = new ArrayCollection(); $message = $this->translateMessage( - (new Count(['min' => $minElements]))->minMessage, - ['{{ limit }}' => $minElements], + (new Count([ + 'min' => $minElements, + ]))->minMessage, + [ + '{{ limit }}' => $minElements, + ], $minElements ); @@ -111,9 +136,14 @@ public function yieldEmptyArrayCollection(int $minElements): iterable public function yieldIntegerGreaterThanGiven(int $lessThanOrEqualValue): iterable { $value = $lessThanOrEqualValue + 1; - $message = $this->translateMessage((new LessThanOrEqual(['value' => $value]))->message, [ - '{{ compared_value }}' => $lessThanOrEqualValue, - ]); + $message = $this->translateMessage( + (new LessThanOrEqual([ + 'value' => $value, + ]))->message, + [ + '{{ compared_value }}' => $lessThanOrEqualValue, + ] + ); yield from $this->create("{$this->property} has greater value", $value, $message); } @@ -121,15 +151,25 @@ public function yieldIntegerGreaterThanGiven(int $lessThanOrEqualValue): iterabl public function yieldIntegerGreaterThanOrEqualToGiven(int $lessThanValue): iterable { $value = $lessThanValue + 1; - $message = $this->translateMessage((new LessThan(['value' => $value]))->message, [ - '{{ compared_value }}' => $lessThanValue, - ]); + $message = $this->translateMessage( + (new LessThan([ + 'value' => $value, + ]))->message, + [ + '{{ compared_value }}' => $lessThanValue, + ] + ); yield from $this->create("{$this->property} has greater value", $value, $message); $value = $lessThanValue; - $message = $this->translateMessage((new LessThan(['value' => $value]))->message, [ - '{{ compared_value }}' => $lessThanValue, - ]); + $message = $this->translateMessage( + (new LessThan([ + 'value' => $value, + ]))->message, + [ + '{{ compared_value }}' => $lessThanValue, + ] + ); yield from $this->create("{$this->property} has equal value", $value, $message); } @@ -144,7 +184,9 @@ public function yieldInvalidChoice(): iterable public function yieldInvalidCreditCardNumber(): iterable { $value = '1111222233334444'; - $message = $this->translateMessage((new CardScheme(['schemes' => null]))->message); + $message = $this->translateMessage((new CardScheme([ + 'schemes' => null, + ]))->message); yield from $this->create("{$this->property} is not a valid credit card number", $value, $message); } @@ -168,8 +210,13 @@ public function yieldInvalidEmail(): iterable public function yieldInvalidExactLengthString(int $exactLength): iterable { $message = $this->translateMessage( - (new Length(['max' => $exactLength, 'min' => $exactLength]))->exactMessage, - ['{{ limit }}' => $exactLength], + (new Length([ + 'max' => $exactLength, + 'min' => $exactLength, + ]))->exactMessage, + [ + '{{ limit }}' => $exactLength, + ], $exactLength ); @@ -197,7 +244,7 @@ public function yieldInvalidTimezone(): iterable $value = 'invalid-timezone'; $message = $this->translateMessage((new Timezone())->message); - yield from $this->create("{$this->property} is invalid timezone", $value, $message); + yield from $this->create("{$this->property} is invalid timezone", $value, $message); } public function yieldInvalidUrl(): iterable @@ -229,7 +276,7 @@ public function yieldNegativeOrZeroNumber(): iterable $message = $this->translateMessage((new Positive())->message); $value = -1; - yield from $this->create("{$this->property} has negative value", $value, $message); + yield from $this->create("{$this->property} has negative value", $value, $message); $value = 0; yield from $this->create("{$this->property} has zero value", $value, $message); @@ -238,9 +285,14 @@ public function yieldNegativeOrZeroNumber(): iterable public function yieldNonDigitSymbols(): iterable { $value = '111-aaa'; - $message = $this->translateMessage((new Type(['type' => 'digit']))->message, [ - '{{ type }}' => 'digit', - ]); + $message = $this->translateMessage( + (new Type([ + 'type' => 'digit', + ]))->message, + [ + '{{ type }}' => 'digit', + ] + ); yield from $this->create("{$this->property} has non-digit symbols", $value, $message); } @@ -255,10 +307,13 @@ public function yieldNonLuhnCreditCardNumber(): iterable public function yieldOutOfRangeNumber(int $min, int $max): iterable { - $message = $this->translateMessage((new Range(\compact('min', 'max')))->notInRangeMessage, [ - '{{ min }}' => $min, - '{{ max }}' => $max, - ]); + $message = $this->translateMessage( + (new Range(\compact('min', 'max')))->notInRangeMessage, + [ + '{{ min }}' => $min, + '{{ max }}' => $max, + ] + ); $value = $max + 1; yield from $this->create("{$this->property} is out of range (above)", $value, $message); @@ -271,8 +326,12 @@ public function yieldTooLongString(int $maxLength): iterable { $value = \str_pad('g', $maxLength + 1, 'g'); $message = $this->translateMessage( - (new Length(['max' => $maxLength]))->maxMessage, - ['{{ limit }}' => $maxLength], + (new Length([ + 'max' => $maxLength, + ]))->maxMessage, + [ + '{{ limit }}' => $maxLength, + ], $maxLength ); @@ -283,8 +342,12 @@ public function yieldTooShortString(int $minLength): iterable { $value = $minLength > 1 ? \str_pad('g', $minLength - 1, 'g') : ''; $message = $this->translateMessage( - (new Length(['min' => $minLength]))->minMessage, - ['{{ limit }}' => $minLength], + (new Length([ + 'min' => $minLength, + ]))->minMessage, + [ + '{{ limit }}' => $minLength, + ], $minLength ); From 56e35ad89e160f685187cdf6138e0121100e0684 Mon Sep 17 00:00:00 2001 From: Anton Popov Date: Fri, 22 Jan 2021 15:43:11 +0700 Subject: [PATCH 3/9] feature/PLU-2760-create-invalid-data-generator - phpstan fixes --- packages/EasySecurity/composer.json | 4 +- packages/EasyTest/composer.json | 3 + .../src/InvalidDataMaker/InvalidDataMaker.php | 80 ++++++++++++++++++- 3 files changed, 83 insertions(+), 4 deletions(-) diff --git a/packages/EasySecurity/composer.json b/packages/EasySecurity/composer.json index 93d1b7e6f..d256e880f 100644 --- a/packages/EasySecurity/composer.json +++ b/packages/EasySecurity/composer.json @@ -12,11 +12,9 @@ }, "require-dev": { "eonx-com/easy-bugsnag": "^3.0", - "nesbot/carbon": "^2.3", "phpunit/phpunit": "^8.4 || ^9.5", "laravel/lumen-framework": "^5.5", - "symfony/symfony": "^4.4 || ^5.1.5", - "symfony/intl": "^4.4 || ^5.1.5", + "symfony/symfony": "^4.4 || ^5.1.5" }, "autoload": { "psr-4": { diff --git a/packages/EasyTest/composer.json b/packages/EasyTest/composer.json index ac5def85f..f965063e6 100644 --- a/packages/EasyTest/composer.json +++ b/packages/EasyTest/composer.json @@ -6,8 +6,11 @@ "require": { "php": "^7.2", "symfony/console": "^4.4 || ^5.1.5", + "nesbot/carbon": "^2.3", "nette/utils": "^3.1", + "symfony/intl": "^4.4 || ^5.1.5", "symfony/http-kernel": "^4.4 || ^5.1.5", + "symfony/validator": "^4.4 || ^5.1.5", "symplify/autowire-array-parameter": "^8.3.41" }, "require-dev": { diff --git a/packages/EasyTest/src/InvalidDataMaker/InvalidDataMaker.php b/packages/EasyTest/src/InvalidDataMaker/InvalidDataMaker.php index 96babffdc..8fa7b8f0b 100644 --- a/packages/EasyTest/src/InvalidDataMaker/InvalidDataMaker.php +++ b/packages/EasyTest/src/InvalidDataMaker/InvalidDataMaker.php @@ -1,4 +1,5 @@ + */ public function yieldArrayCollectionWithFewerItems(int $minElements): iterable { $value = new ArrayCollection(\array_fill(0, $minElements - 1, null)); @@ -42,6 +46,9 @@ public function yieldArrayCollectionWithFewerItems(int $minElements): iterable yield from $this->create("{$this->property} has too few elements in the collection is blank", $value, $message); } + /** + * @return iterable + */ public function yieldArrayCollectionWithMoreItems(int $maxElements): iterable { $value = new ArrayCollection(\array_fill(0, $maxElements - 1, null)); @@ -58,6 +65,9 @@ public function yieldArrayCollectionWithMoreItems(int $maxElements): iterable yield from $this->create("{$this->property} has too more elements in the collection", $value, $message); } + /** + * @return iterable + */ public function yieldArrayWithFewerItems(int $minElements): iterable { $value = \array_fill(0, $minElements - 1, null); @@ -74,6 +84,9 @@ public function yieldArrayWithFewerItems(int $minElements): iterable yield from $this->create("{$this->property} has too few elements in the array", $value, $message); } + /** + * @return iterable + */ public function yieldArrayWithMoreItems(int $maxElements): iterable { $value = \array_fill(0, $maxElements + 1, null); @@ -90,6 +103,9 @@ public function yieldArrayWithMoreItems(int $maxElements): iterable yield from $this->create("{$this->property} has too many elements in the collection", $value, $message); } + /** + * @return iterable + */ public function yieldBlankString(): iterable { $value = ''; @@ -98,6 +114,9 @@ public function yieldBlankString(): iterable yield from $this->create("{$this->property} is blank", $value, $message); } + /** + * @return iterable + */ public function yieldDateTimeLessThanOrEqualToNow(): iterable { $dateTime = Carbon::now(); @@ -110,13 +129,18 @@ public function yieldDateTimeLessThanOrEqualToNow(): iterable ] ); - $value = $dateTime->clone()->subSecond()->toAtomString(); + $value = $dateTime->clone() + ->subSecond() + ->toAtomString(); yield from $this->create("{$this->property} has less datetime", $value, $message); $value = $dateTime->toAtomString(); yield from $this->create("{$this->property} has equal datetime", $value, $message); } + /** + * @return iterable + */ public function yieldEmptyArrayCollection(int $minElements): iterable { $value = new ArrayCollection(); @@ -133,6 +157,9 @@ public function yieldEmptyArrayCollection(int $minElements): iterable yield from $this->create("{$this->property} has too few elements in the collection", $value, $message); } + /** + * @return iterable + */ public function yieldIntegerGreaterThanGiven(int $lessThanOrEqualValue): iterable { $value = $lessThanOrEqualValue + 1; @@ -148,6 +175,9 @@ public function yieldIntegerGreaterThanGiven(int $lessThanOrEqualValue): iterabl yield from $this->create("{$this->property} has greater value", $value, $message); } + /** + * @return iterable + */ public function yieldIntegerGreaterThanOrEqualToGiven(int $lessThanValue): iterable { $value = $lessThanValue + 1; @@ -173,6 +203,9 @@ public function yieldIntegerGreaterThanOrEqualToGiven(int $lessThanValue): itera yield from $this->create("{$this->property} has equal value", $value, $message); } + /** + * @return iterable + */ public function yieldInvalidChoice(): iterable { $value = 'invalid-choice'; @@ -181,6 +214,9 @@ public function yieldInvalidChoice(): iterable yield from $this->create("{$this->property} is not a valid choice", $value, $message); } + /** + * @return iterable + */ public function yieldInvalidCreditCardNumber(): iterable { $value = '1111222233334444'; @@ -191,6 +227,9 @@ public function yieldInvalidCreditCardNumber(): iterable yield from $this->create("{$this->property} is not a valid credit card number", $value, $message); } + /** + * @return iterable + */ public function yieldInvalidCurrencyCode(): iterable { $value = 'invalid-currency-code'; @@ -199,6 +238,9 @@ public function yieldInvalidCurrencyCode(): iterable yield from $this->create("{$this->property} is invalid currency", $value, $message); } + /** + * @return iterable + */ public function yieldInvalidEmail(): iterable { $value = 'invalid-email'; @@ -207,6 +249,9 @@ public function yieldInvalidEmail(): iterable yield from $this->create("{$this->property} is invalid email", $value, $message); } + /** + * @return iterable + */ public function yieldInvalidExactLengthString(int $exactLength): iterable { $message = $this->translateMessage( @@ -227,6 +272,9 @@ public function yieldInvalidExactLengthString(int $exactLength): iterable yield from $this->create("{$this->property} has length less than expected", $value, $message); } + /** + * @return iterable + */ public function yieldInvalidFloat(int $precision, ?int $integerPart = null): iterable { $value = ($integerPart ?? 0) + \round(1 / 3, $precision + 1); @@ -239,6 +287,9 @@ public function yieldInvalidFloat(int $precision, ?int $integerPart = null): ite yield from $this->create("{$this->property} is an integer", $value); } + /** + * @return iterable + */ public function yieldInvalidTimezone(): iterable { $value = 'invalid-timezone'; @@ -247,6 +298,9 @@ public function yieldInvalidTimezone(): iterable yield from $this->create("{$this->property} is invalid timezone", $value, $message); } + /** + * @return iterable + */ public function yieldInvalidUrl(): iterable { $value = 'invalid-url'; @@ -255,6 +309,9 @@ public function yieldInvalidUrl(): iterable yield from $this->create("{$this->property} is invalid url", $value, $message); } + /** + * @return iterable + */ public function yieldInvalidUuid(): iterable { $value = 'some-invalid-uuid'; @@ -263,6 +320,9 @@ public function yieldInvalidUuid(): iterable yield from $this->create("{$this->property} is invalid uuid", $value, $message); } + /** + * @return iterable + */ public function yieldNegativeNumber(): iterable { $value = -1; @@ -271,6 +331,9 @@ public function yieldNegativeNumber(): iterable yield from $this->create("{$this->property} has negative value", $value, $message); } + /** + * @return iterable + */ public function yieldNegativeOrZeroNumber(): iterable { $message = $this->translateMessage((new Positive())->message); @@ -282,6 +345,9 @@ public function yieldNegativeOrZeroNumber(): iterable yield from $this->create("{$this->property} has zero value", $value, $message); } + /** + * @return iterable + */ public function yieldNonDigitSymbols(): iterable { $value = '111-aaa'; @@ -297,6 +363,9 @@ public function yieldNonDigitSymbols(): iterable yield from $this->create("{$this->property} has non-digit symbols", $value, $message); } + /** + * @return iterable + */ public function yieldNonLuhnCreditCardNumber(): iterable { $value = '4388576018402626'; @@ -305,6 +374,9 @@ public function yieldNonLuhnCreditCardNumber(): iterable yield from $this->create("{$this->property} do not pass the Luhn algorithm", $value, $message); } + /** + * @return iterable + */ public function yieldOutOfRangeNumber(int $min, int $max): iterable { $message = $this->translateMessage( @@ -322,6 +394,9 @@ public function yieldOutOfRangeNumber(int $min, int $max): iterable yield from $this->create("{$this->property} is out of range (below)", $value, $message); } + /** + * @return iterable + */ public function yieldTooLongString(int $maxLength): iterable { $value = \str_pad('g', $maxLength + 1, 'g'); @@ -338,6 +413,9 @@ public function yieldTooLongString(int $maxLength): iterable yield from $this->create("{$this->property} is too long", $value, $message); } + /** + * @return iterable + */ public function yieldTooShortString(int $minLength): iterable { $value = $minLength > 1 ? \str_pad('g', $minLength - 1, 'g') : ''; From 8bed49e72987d00fadb56e11ea3ed62a9496d39b Mon Sep 17 00:00:00 2001 From: Anton Popov Date: Fri, 22 Jan 2021 15:47:19 +0700 Subject: [PATCH 4/9] feature/PLU-2760-create-invalid-data-generator - phpstan fixes - dependencies fixes --- packages/EasyTest/composer.json | 2 +- .../EasyTest/src/InvalidDataMaker/AbstractInvalidDataMaker.php | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/EasyTest/composer.json b/packages/EasyTest/composer.json index f965063e6..fa0063a5d 100644 --- a/packages/EasyTest/composer.json +++ b/packages/EasyTest/composer.json @@ -6,7 +6,7 @@ "require": { "php": "^7.2", "symfony/console": "^4.4 || ^5.1.5", - "nesbot/carbon": "^2.3", + "nesbot/carbon": "^2.22", "nette/utils": "^3.1", "symfony/intl": "^4.4 || ^5.1.5", "symfony/http-kernel": "^4.4 || ^5.1.5", diff --git a/packages/EasyTest/src/InvalidDataMaker/AbstractInvalidDataMaker.php b/packages/EasyTest/src/InvalidDataMaker/AbstractInvalidDataMaker.php index ac5087d07..615dc4c5c 100644 --- a/packages/EasyTest/src/InvalidDataMaker/AbstractInvalidDataMaker.php +++ b/packages/EasyTest/src/InvalidDataMaker/AbstractInvalidDataMaker.php @@ -79,7 +79,7 @@ final public static function make(string $property): self * * @return mixed[] */ - final protected function create($caseName, $value, ?string $message = null): array + final protected function create(string $caseName, $value, ?string $message = null): array { if ($this->asString === true) { $value = (string)$value; @@ -156,6 +156,7 @@ private static function initTranslator(): void */ private function applyWrapWith(array $data): array { + /** @var string $caseName */ $caseName = \current(\array_keys($data)); $caseData = $data[$caseName]['data']; From 4f61e405f8a03d9cc84c14a93ef6e1aadfd5a6a3 Mon Sep 17 00:00:00 2001 From: Anton Popov Date: Fri, 22 Jan 2021 15:58:46 +0700 Subject: [PATCH 5/9] feature/PLU-2760-create-invalid-data-generator - added coverage ignore annotations --- .../EasyTest/src/InvalidDataMaker/AbstractInvalidDataMaker.php | 3 +++ packages/EasyTest/src/InvalidDataMaker/InvalidDataMaker.php | 3 +++ 2 files changed, 6 insertions(+) diff --git a/packages/EasyTest/src/InvalidDataMaker/AbstractInvalidDataMaker.php b/packages/EasyTest/src/InvalidDataMaker/AbstractInvalidDataMaker.php index 615dc4c5c..880c80a12 100644 --- a/packages/EasyTest/src/InvalidDataMaker/AbstractInvalidDataMaker.php +++ b/packages/EasyTest/src/InvalidDataMaker/AbstractInvalidDataMaker.php @@ -10,6 +10,9 @@ use Symfony\Component\Translation\Loader\YamlFileLoader; use Symfony\Component\Translation\Translator; +/** + * @codeCoverageIgnore + */ abstract class AbstractInvalidDataMaker { /** diff --git a/packages/EasyTest/src/InvalidDataMaker/InvalidDataMaker.php b/packages/EasyTest/src/InvalidDataMaker/InvalidDataMaker.php index 8fa7b8f0b..56d4cef2b 100644 --- a/packages/EasyTest/src/InvalidDataMaker/InvalidDataMaker.php +++ b/packages/EasyTest/src/InvalidDataMaker/InvalidDataMaker.php @@ -25,6 +25,9 @@ use Symfony\Component\Validator\Constraints\Url; use Symfony\Component\Validator\Constraints\Uuid; +/** + * @codeCoverageIgnore + */ class InvalidDataMaker extends AbstractInvalidDataMaker { /** From 4f9c13cf66b0350e5521aba835eb6831ea361d54 Mon Sep 17 00:00:00 2001 From: Anton Popov Date: Fri, 22 Jan 2021 23:46:37 +0700 Subject: [PATCH 6/9] feature/PLU-2760-create-invalid-data-generator - fixed GH actions --- packages/EasyTest/config/services.yaml | 1 + phpstan.neon | 3 +++ 2 files changed, 4 insertions(+) diff --git a/packages/EasyTest/config/services.yaml b/packages/EasyTest/config/services.yaml index b538dad92..2d4450bbf 100644 --- a/packages/EasyTest/config/services.yaml +++ b/packages/EasyTest/config/services.yaml @@ -8,3 +8,4 @@ services: resource: '../src' exclude: - '../src/HttpKernel/*' + - '../src/InvalidDataMaker/*' diff --git a/phpstan.neon b/phpstan.neon index 64216c942..fe11645de 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -210,6 +210,9 @@ parameters: - message: '#Cannot cast array\|string\|null to string.#' path: packages/EasyTest/src/Console/Commands + - message: '#Unsafe usage of new static\(\)#' + path: packages/EasyTest/src/InvalidDataMaker/AbstractInvalidDataMaker.php + # ---- EasyWebhook ---- - message: '#Unsafe usage of new static\(\)#' # Until we find a better design path: packages/EasyWebhook/src/AbstractWebhook.php From 8e587374bbe098ae0e820bb6b57f2f7ff5dbca5c Mon Sep 17 00:00:00 2001 From: Anton Popov Date: Tue, 26 Jan 2021 12:19:20 +0700 Subject: [PATCH 7/9] feature/PLU-2760-create-invalid-data-generator - changes according review --- .../InvalidDataMaker/AbstractInvalidDataMaker.php | 15 +++++++++------ .../src/InvalidDataMaker/InvalidDataMaker.php | 11 ++++++++--- 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/packages/EasyTest/src/InvalidDataMaker/AbstractInvalidDataMaker.php b/packages/EasyTest/src/InvalidDataMaker/AbstractInvalidDataMaker.php index 880c80a12..9f42c0d61 100644 --- a/packages/EasyTest/src/InvalidDataMaker/AbstractInvalidDataMaker.php +++ b/packages/EasyTest/src/InvalidDataMaker/AbstractInvalidDataMaker.php @@ -18,7 +18,7 @@ abstract class AbstractInvalidDataMaker /** * @var string */ - private const PLURAL_INDEX = '%count%'; + private const PLURAL_PARAM = '%count%'; /** * @var string @@ -28,7 +28,9 @@ abstract class AbstractInvalidDataMaker /** * @var string[] */ - private static $translations = []; + protected static $translations = [ + 'vendor/symfony/validator/Resources/translations/validators.en.xlf', + ]; /** * @var \Symfony\Contracts\Translation\TranslatorInterface @@ -116,7 +118,7 @@ final protected function create(string $caseName, $value, ?string $message = nul */ final protected function translateMessage(string $messageKey, ?array $params = null, ?int $plural = null): string { - $params[self::PLURAL_INDEX] = $plural; + $params[self::PLURAL_PARAM] = $plural; return self::$translator->trans($messageKey, $params); } @@ -131,7 +133,7 @@ private static function createTranslationLoader(string $extension): LoaderInterf return new XliffFileLoader(); } - throw new LogicException('For now allowed translations in formats [yaml, xlf]'); + throw new LogicException('Only YAML and XLF translation formats are supported.'); } private static function initTranslator(): void @@ -163,8 +165,9 @@ private function applyWrapWith(array $data): array $caseName = \current(\array_keys($data)); $caseData = $data[$caseName]['data']; + $wrappedPropertyPath = "{$this->wrapWith}.{$this->property}"; /** @var string $newCaseName */ - $newCaseName = \str_replace($this->property, "{$this->wrapWith}.{$this->property}", $caseName); + $newCaseName = \str_replace($this->property, $wrappedPropertyPath, $caseName); return [ $newCaseName => [ @@ -172,7 +175,7 @@ private function applyWrapWith(array $data): array $this->wrapWith => $caseData, ], 'message' => $data[$caseName]['message'], - 'propertyPath' => "{$this->wrapWith}.{$this->property}", + 'propertyPath' => $wrappedPropertyPath, ], ]; } diff --git a/packages/EasyTest/src/InvalidDataMaker/InvalidDataMaker.php b/packages/EasyTest/src/InvalidDataMaker/InvalidDataMaker.php index 56d4cef2b..1f0836bf0 100644 --- a/packages/EasyTest/src/InvalidDataMaker/InvalidDataMaker.php +++ b/packages/EasyTest/src/InvalidDataMaker/InvalidDataMaker.php @@ -46,7 +46,7 @@ public function yieldArrayCollectionWithFewerItems(int $minElements): iterable $minElements ); - yield from $this->create("{$this->property} has too few elements in the collection is blank", $value, $message); + yield from $this->create("{$this->property} has too few elements in the collection", $value, $message); } /** @@ -65,7 +65,7 @@ public function yieldArrayCollectionWithMoreItems(int $maxElements): iterable $maxElements ); - yield from $this->create("{$this->property} has too more elements in the collection", $value, $message); + yield from $this->create("{$this->property} has too many elements in the collection", $value, $message); } /** @@ -103,7 +103,7 @@ public function yieldArrayWithMoreItems(int $maxElements): iterable $maxElements ); - yield from $this->create("{$this->property} has too many elements in the collection", $value, $message); + yield from $this->create("{$this->property} has too many elements in the array", $value, $message); } /** @@ -276,6 +276,11 @@ public function yieldInvalidExactLengthString(int $exactLength): iterable } /** + * This method is intended to be used with a custom constraint, so a custom message should be passed, e.g.: + * InvalidDataMaker::make('amount') + * ->message('This value is not a valid decimal number or has more than 3 digits in a precision.') + * ->yieldInvalidFloat(3); + * * @return iterable */ public function yieldInvalidFloat(int $precision, ?int $integerPart = null): iterable From 3fa6fdb8cad4856bc27a91229ac498cea5d26b05 Mon Sep 17 00:00:00 2001 From: Anton Popov Date: Tue, 26 Jan 2021 12:23:46 +0700 Subject: [PATCH 8/9] feature/PLU-2760-create-invalid-data-generator - ecs fixed --- .../src/InvalidDataMaker/AbstractInvalidDataMaker.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/EasyTest/src/InvalidDataMaker/AbstractInvalidDataMaker.php b/packages/EasyTest/src/InvalidDataMaker/AbstractInvalidDataMaker.php index 9f42c0d61..454b4bda8 100644 --- a/packages/EasyTest/src/InvalidDataMaker/AbstractInvalidDataMaker.php +++ b/packages/EasyTest/src/InvalidDataMaker/AbstractInvalidDataMaker.php @@ -28,9 +28,7 @@ abstract class AbstractInvalidDataMaker /** * @var string[] */ - protected static $translations = [ - 'vendor/symfony/validator/Resources/translations/validators.en.xlf', - ]; + protected static $translations = ['vendor/symfony/validator/Resources/translations/validators.en.xlf']; /** * @var \Symfony\Contracts\Translation\TranslatorInterface From 633e3fdce348e8b8e9fc5c36cb586105e419f110 Mon Sep 17 00:00:00 2001 From: Anton Popov Date: Tue, 26 Jan 2021 14:08:06 +0700 Subject: [PATCH 9/9] feature/PLU-2760-create-invalid-data-generator - changes according review --- .../src/InvalidDataMaker/InvalidDataMaker.php | 21 ++++++++----------- 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/packages/EasyTest/src/InvalidDataMaker/InvalidDataMaker.php b/packages/EasyTest/src/InvalidDataMaker/InvalidDataMaker.php index 1f0836bf0..61ed26371 100644 --- a/packages/EasyTest/src/InvalidDataMaker/InvalidDataMaker.php +++ b/packages/EasyTest/src/InvalidDataMaker/InvalidDataMaker.php @@ -144,20 +144,17 @@ public function yieldDateTimeLessThanOrEqualToNow(): iterable /** * @return iterable */ - public function yieldEmptyArrayCollection(int $minElements): iterable + public function yieldEmptyArray(): iterable { - $value = new ArrayCollection(); - $message = $this->translateMessage( - (new Count([ - 'min' => $minElements, - ]))->minMessage, - [ - '{{ limit }}' => $minElements, - ], - $minElements - ); + yield from $this->yieldArrayWithFewerItems(1); + } - yield from $this->create("{$this->property} has too few elements in the collection", $value, $message); + /** + * @return iterable + */ + public function yieldEmptyArrayCollection(): iterable + { + yield from $this->yieldArrayCollectionWithFewerItems(1); } /**