From c91144286cc3b0f800d85eee3e9fdec8383b3462 Mon Sep 17 00:00:00 2001 From: Walmir Silva Date: Fri, 25 Oct 2024 19:03:35 -0300 Subject: [PATCH 1/2] refactor(validator): reorganize validation result structure BREAKING CHANGE: Simplify validation result handling by removing factory and processor patterns. Changes: File Structure Changes: - Move ValidationResult to Result namespace - Remove ValidationResultFactory - Remove ValidationResultProcessor - Update test organization Removed Components: - src/Contract/ValidationResultFactory.php - src/Contract/ValidationResultProcessor.php - src/Processor/DefaultValidationResultProcessor.php - tests/Processor/DefaultValidationResultProcessorTest.php - tests/ValidationResultTest.php Test Updates: - Move validation result tests to Result namespace - Update validator tests for new structure - Update application test files The changes simplify the validation result handling by: - Removing unnecessary abstraction layers - Providing direct result management --- composer.lock | 43 ++-- src/Contract/ValidationResult.php | 6 +- src/Contract/ValidationResultFactory.php | 10 - src/Contract/ValidationResultProcessor.php | 12 - .../DefaultValidationResultProcessor.php | 39 ---- src/Result/ValidationResult.php | 36 +++ src/ValidationResult.php | 81 ------- src/Validator.php | 25 ++- .../DefaultValidationResultProcessorTest.php | 196 ----------------- tests/Result/ValidationResultTest.php | 96 ++++++++ tests/ValidationResultTest.php | 207 ------------------ tests/ValidatorTest.php | 75 +++---- tests/application.php | 4 +- tests/application2.php | 2 +- 14 files changed, 204 insertions(+), 628 deletions(-) delete mode 100644 src/Contract/ValidationResultFactory.php delete mode 100644 src/Contract/ValidationResultProcessor.php delete mode 100644 src/Processor/DefaultValidationResultProcessor.php create mode 100644 src/Result/ValidationResult.php delete mode 100644 src/ValidationResult.php delete mode 100644 tests/Processor/DefaultValidationResultProcessorTest.php create mode 100644 tests/Result/ValidationResultTest.php delete mode 100644 tests/ValidationResultTest.php diff --git a/composer.lock b/composer.lock index b6882b8..1deba92 100755 --- a/composer.lock +++ b/composer.lock @@ -8,16 +8,16 @@ "packages": [ { "name": "kariricode/contract", - "version": "v2.7.11", + "version": "v2.8.0", "source": { "type": "git", "url": "https://github.com/KaririCode-Framework/kariricode-contract.git", - "reference": "72c834a3afe2dbded8f6a7f96005635424636d4b" + "reference": "ee489bbcb44339a246af01058e00b3f94891f66c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/KaririCode-Framework/kariricode-contract/zipball/72c834a3afe2dbded8f6a7f96005635424636d4b", - "reference": "72c834a3afe2dbded8f6a7f96005635424636d4b", + "url": "https://api.github.com/repos/KaririCode-Framework/kariricode-contract/zipball/ee489bbcb44339a246af01058e00b3f94891f66c", + "reference": "ee489bbcb44339a246af01058e00b3f94891f66c", "shasum": "" }, "require": { @@ -66,7 +66,7 @@ "issues": "https://github.com/KaririCode-Framework/kariricode-contract/issues", "source": "https://github.com/KaririCode-Framework/kariricode-contract" }, - "time": "2024-10-24T18:51:39+00:00" + "time": "2024-10-25T17:45:25+00:00" }, { "name": "kariricode/data-structure", @@ -144,16 +144,16 @@ }, { "name": "kariricode/exception", - "version": "v1.2.1", + "version": "v1.2.2", "source": { "type": "git", "url": "https://github.com/KaririCode-Framework/kariricode-exception.git", - "reference": "65c8eb72c581eb8c33c168e5df104ed260843303" + "reference": "ec5d9be5bda95e7d35ff3a230ec9afbf6f53c44d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/KaririCode-Framework/kariricode-exception/zipball/65c8eb72c581eb8c33c168e5df104ed260843303", - "reference": "65c8eb72c581eb8c33c168e5df104ed260843303", + "url": "https://api.github.com/repos/KaririCode-Framework/kariricode-exception/zipball/ec5d9be5bda95e7d35ff3a230ec9afbf6f53c44d", + "reference": "ec5d9be5bda95e7d35ff3a230ec9afbf6f53c44d", "shasum": "" }, "require": { @@ -197,25 +197,27 @@ "issues": "https://github.com/KaririCode-Framework/kariricode-exception/issues", "source": "https://github.com/KaririCode-Framework/kariricode-exception" }, - "time": "2024-10-17T22:43:32+00:00" + "time": "2024-10-25T18:13:01+00:00" }, { "name": "kariricode/processor-pipeline", - "version": "v1.1.6", + "version": "v1.3.0", "source": { "type": "git", "url": "https://github.com/KaririCode-Framework/kariricode-processor-pipeline.git", - "reference": "58a25f345d066c7d7b69331bdbe1d468513964bf" + "reference": "0b0229fcf94e06922b5b0ece1d923bda80c33f2b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/KaririCode-Framework/kariricode-processor-pipeline/zipball/58a25f345d066c7d7b69331bdbe1d468513964bf", - "reference": "58a25f345d066c7d7b69331bdbe1d468513964bf", + "url": "https://api.github.com/repos/KaririCode-Framework/kariricode-processor-pipeline/zipball/0b0229fcf94e06922b5b0ece1d923bda80c33f2b", + "reference": "0b0229fcf94e06922b5b0ece1d923bda80c33f2b", "shasum": "" }, "require": { "kariricode/contract": "^2.7", "kariricode/data-structure": "^1.1", + "kariricode/exception": "^1.2", + "kariricode/property-inspector": "^1.2", "php": "^8.3" }, "require-dev": { @@ -256,25 +258,24 @@ "issues": "https://github.com/KaririCode-Framework/kariricode-processor-pipeline/issues", "source": "https://github.com/KaririCode-Framework/kariricode-processor-pipeline" }, - "time": "2024-10-24T18:55:45+00:00" + "time": "2024-10-25T20:51:45+00:00" }, { "name": "kariricode/property-inspector", - "version": "v1.1.6", + "version": "v1.2.3", "source": { "type": "git", "url": "https://github.com/KaririCode-Framework/kariricode-property-inspector.git", - "reference": "7e70c17b74c69601514fa40a4f76aeb0c056e096" + "reference": "5faa6ca584ee80fbfc8de456377020703a88ab80" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/KaririCode-Framework/kariricode-property-inspector/zipball/7e70c17b74c69601514fa40a4f76aeb0c056e096", - "reference": "7e70c17b74c69601514fa40a4f76aeb0c056e096", + "url": "https://api.github.com/repos/KaririCode-Framework/kariricode-property-inspector/zipball/5faa6ca584ee80fbfc8de456377020703a88ab80", + "reference": "5faa6ca584ee80fbfc8de456377020703a88ab80", "shasum": "" }, "require": { "kariricode/contract": "^2.7", - "kariricode/processor-pipeline": "^1.1", "php": "^8.3" }, "require-dev": { @@ -320,7 +321,7 @@ "issues": "https://github.com/KaririCode-Framework/kariricode-property-inspector/issues", "source": "https://github.com/KaririCode-Framework/kariricode-property-inspector" }, - "time": "2024-10-21T20:42:58+00:00" + "time": "2024-10-25T19:50:19+00:00" } ], "packages-dev": [ diff --git a/src/Contract/ValidationResult.php b/src/Contract/ValidationResult.php index db17665..f1beffe 100644 --- a/src/Contract/ValidationResult.php +++ b/src/Contract/ValidationResult.php @@ -6,11 +6,7 @@ interface ValidationResult { - public function addError(string $property, string $errorKey, string $message): void; - - public function setValidatedData(string $property, mixed $value): void; - - public function hasErrors(): bool; + public function isValid(): bool; public function getErrors(): array; diff --git a/src/Contract/ValidationResultFactory.php b/src/Contract/ValidationResultFactory.php deleted file mode 100644 index b432022..0000000 --- a/src/Contract/ValidationResultFactory.php +++ /dev/null @@ -1,10 +0,0 @@ -getProcessedPropertyValues(); - $errors = $handler->getProcessingResultErrors(); - - foreach ($processedValues as $property => $data) { - $result->setValidatedData($property, $data['value']); - - if (isset($errors[$property])) { - $this->addPropertyErrors($result, $property, $errors[$property]); - } - } - - return $result; - } - - private function addPropertyErrors( - ValidationResult $result, - string $property, - array $propertyErrors - ): void { - foreach ($propertyErrors as $error) { - $result->addError($property, $error['errorKey'], $error['message']); - } - } -} diff --git a/src/Result/ValidationResult.php b/src/Result/ValidationResult.php new file mode 100644 index 0000000..0c619ee --- /dev/null +++ b/src/Result/ValidationResult.php @@ -0,0 +1,36 @@ +results->hasErrors(); + } + + public function getErrors(): array + { + return $this->results->getErrors(); + } + + public function getValidatedData(): array + { + return $this->results->getProcessedData(); + } + + public function toArray(): array + { + return $this->results->toArray(); + } +} diff --git a/src/ValidationResult.php b/src/ValidationResult.php deleted file mode 100644 index 64ebd86..0000000 --- a/src/ValidationResult.php +++ /dev/null @@ -1,81 +0,0 @@ -errors = []; - $this->validatedData = []; - $this->errorHashes = []; - } - - public function addError(string $property, string $errorKey, string $message): void - { - if (!isset($this->errors[$property])) { - $this->errors[$property] = []; - $this->errorHashes[$property] = []; - } - - // Avoid adding duplicate errors - $hash = md5($errorKey . $message); - if (isset($this->errorHashes[$property][$hash])) { - return; - } - - $this->errorHashes[$property][$hash] = true; - $this->errors[$property][] = [ - 'errorKey' => $errorKey, - 'message' => $message, - ]; - } - - public function setValidatedData(string $property, mixed $value): void - { - $this->validatedData[$property] = $value; - } - - public function hasErrors(): bool - { - return !empty($this->errors); - } - - public function getErrors(): array - { - return $this->errors; - } - - public function getValidatedData(): array - { - return $this->validatedData; - } - - public function toArray(): array - { - return [ - 'isValid' => !$this->hasErrors(), - 'errors' => $this->errors, - 'validatedData' => $this->validatedData, - ]; - } - - public function __destruct() - { - $this->reset(); - } -} diff --git a/src/Validator.php b/src/Validator.php index 3fcad00..93ec57f 100644 --- a/src/Validator.php +++ b/src/Validator.php @@ -6,34 +6,41 @@ use KaririCode\Contract\Processor\ProcessorRegistry; use KaririCode\Contract\Validator\Validator as ValidatorContract; +use KaririCode\ProcessorPipeline\Handler\ProcessorAttributeHandler; use KaririCode\ProcessorPipeline\ProcessorBuilder; use KaririCode\PropertyInspector\AttributeAnalyzer; -use KaririCode\PropertyInspector\AttributeHandler; use KaririCode\PropertyInspector\Utility\PropertyInspector; use KaririCode\Validator\Attribute\Validate; -use KaririCode\Validator\Processor\DefaultValidationResultProcessor; +use KaririCode\Validator\Result\ValidationResult; -class Validator implements ValidatorContract +final class Validator implements ValidatorContract { private const IDENTIFIER = 'validator'; - private ProcessorBuilder $builder; + private readonly ProcessorBuilder $builder; public function __construct( - private readonly ProcessorRegistry $registry, + private readonly ProcessorRegistry $registry ) { $this->builder = new ProcessorBuilder($this->registry); } public function validate(mixed $object): ValidationResult { + $handler = new ProcessorAttributeHandler( + self::IDENTIFIER, + $this->builder + ); + $propertyInspector = new PropertyInspector( new AttributeAnalyzer(Validate::class) ); - $attributeHandler = new AttributeHandler(self::IDENTIFIER, $this->builder); - $resultProcessor = new DefaultValidationResultProcessor(); - $handler = $propertyInspector->inspect($object, $attributeHandler); - return $resultProcessor->process($handler); + /** @var PropertyAttributeHandler */ + $handler = $propertyInspector->inspect($object, $handler); + + return new ValidationResult( + $handler->getProcessingResults() + ); } } diff --git a/tests/Processor/DefaultValidationResultProcessorTest.php b/tests/Processor/DefaultValidationResultProcessorTest.php deleted file mode 100644 index 5fbc3ef..0000000 --- a/tests/Processor/DefaultValidationResultProcessorTest.php +++ /dev/null @@ -1,196 +0,0 @@ -attributeHandler = $this->createMock(AttributeHandler::class); - $this->validationResult = new ValidationResult(); - $this->processor = new DefaultValidationResultProcessor($this->validationResult); - } - - public function testProcessWithValidData(): void - { - $processedValues = [ - 'name' => ['value' => 'Walmir Silva'], - 'email' => ['value' => 'walmir@example.com'], - ]; - - $this->attributeHandler - ->expects($this->once()) - ->method('getProcessedPropertyValues') - ->willReturn($processedValues); - - $this->attributeHandler - ->expects($this->once()) - ->method('getProcessingResultErrors') - ->willReturn([]); - - $result = $this->processor->process($this->attributeHandler); - - $this->assertInstanceOf(ValidationResult::class, $result); - $this->assertEquals( - [ - 'name' => 'Walmir Silva', - 'email' => 'walmir@example.com', - ], - $result->getValidatedData() - ); - $this->assertFalse($result->hasErrors()); - } - - public function testProcessWithErrors(): void - { - $processedValues = [ - 'email' => ['value' => 'invalid-email'], - ]; - - $errors = [ - 'email' => [ - [ - 'errorKey' => 'invalidFormat', - 'message' => 'Invalid email format', - ], - ], - ]; - - $this->attributeHandler - ->expects($this->once()) - ->method('getProcessedPropertyValues') - ->willReturn($processedValues); - - $this->attributeHandler - ->expects($this->once()) - ->method('getProcessingResultErrors') - ->willReturn($errors); - - $result = $this->processor->process($this->attributeHandler); - - $this->assertInstanceOf(ValidationResult::class, $result); - $this->assertEquals(['email' => 'invalid-email'], $result->getValidatedData()); - $this->assertTrue($result->hasErrors()); - $this->assertArrayHasKey('email', $result->getErrors()); - $this->assertEquals('invalidFormat', $result->getErrors()['email'][0]['errorKey']); - $this->assertEquals('Invalid email format', $result->getErrors()['email'][0]['message']); - } - - public function testProcessWithMultipleErrorsForSameProperty(): void - { - $processedValues = [ - 'password' => ['value' => 'weak'], - ]; - - $errors = [ - 'password' => [ - [ - 'errorKey' => 'tooShort', - 'message' => 'Password is too short', - ], - [ - 'errorKey' => 'complexity', - 'message' => 'Password needs special characters', - ], - ], - ]; - - $this->attributeHandler - ->expects($this->once()) - ->method('getProcessedPropertyValues') - ->willReturn($processedValues); - - $this->attributeHandler - ->expects($this->once()) - ->method('getProcessingResultErrors') - ->willReturn($errors); - - $result = $this->processor->process($this->attributeHandler); - - $this->assertInstanceOf(ValidationResult::class, $result); - $this->assertEquals(['password' => 'weak'], $result->getValidatedData()); - $this->assertTrue($result->hasErrors()); - - $resultErrors = $result->getErrors()['password']; - $this->assertCount(2, $resultErrors); - $this->assertEquals('tooShort', $resultErrors[0]['errorKey']); - $this->assertEquals('Password is too short', $resultErrors[0]['message']); - $this->assertEquals('complexity', $resultErrors[1]['errorKey']); - $this->assertEquals('Password needs special characters', $resultErrors[1]['message']); - } - - public function testProcessWithNoProperties(): void - { - $this->attributeHandler - ->expects($this->once()) - ->method('getProcessedPropertyValues') - ->willReturn([]); - - $this->attributeHandler - ->expects($this->once()) - ->method('getProcessingResultErrors') - ->willReturn([]); - - $result = $this->processor->process($this->attributeHandler); - - $this->assertInstanceOf(ValidationResult::class, $result); - $this->assertEmpty($result->getValidatedData()); - $this->assertFalse($result->hasErrors()); - } - - public function testProcessWithMixedValidAndInvalidProperties(): void - { - $processedValues = [ - 'name' => ['value' => 'Walmir Silva'], - 'email' => ['value' => 'invalid-email'], - 'age' => ['value' => 25], - ]; - - $errors = [ - 'email' => [ - [ - 'errorKey' => 'invalidFormat', - 'message' => 'Invalid email format', - ], - ], - ]; - - $this->attributeHandler - ->expects($this->once()) - ->method('getProcessedPropertyValues') - ->willReturn($processedValues); - - $this->attributeHandler - ->expects($this->once()) - ->method('getProcessingResultErrors') - ->willReturn($errors); - - $result = $this->processor->process($this->attributeHandler); - - $this->assertInstanceOf(ValidationResult::class, $result); - $this->assertEquals( - [ - 'name' => 'Walmir Silva', - 'email' => 'invalid-email', - 'age' => 25, - ], - $result->getValidatedData() - ); - $this->assertTrue($result->hasErrors()); - $this->assertArrayHasKey('email', $result->getErrors()); - $this->assertEquals('invalidFormat', $result->getErrors()['email'][0]['errorKey']); - $this->assertEquals('Invalid email format', $result->getErrors()['email'][0]['message']); - } -} diff --git a/tests/Result/ValidationResultTest.php b/tests/Result/ValidationResultTest.php new file mode 100644 index 0000000..b335fe2 --- /dev/null +++ b/tests/Result/ValidationResultTest.php @@ -0,0 +1,96 @@ +results = $this->createMock(ProcessingResultCollection::class); + $this->validationResult = new ValidationResult($this->results); + } + + public function testInitialState(): void + { + $this->results->expects($this->once()) + ->method('hasErrors') + ->willReturn(false); + + $this->results->expects($this->once()) + ->method('getErrors') + ->willReturn([]); + + $this->results->expects($this->once()) + ->method('getProcessedData') + ->willReturn([]); + + $this->assertTrue($this->validationResult->isValid()); + $this->assertEmpty($this->validationResult->getErrors()); + $this->assertEmpty($this->validationResult->getValidatedData()); + } + + public function testWithValidatedData(): void + { + $validatedData = ['name' => 'John', 'email' => 'john@example.com']; + + $this->results->expects($this->any()) + ->method('getProcessedData') + ->willReturn($validatedData); + + $this->assertSame($validatedData, $this->validationResult->getValidatedData()); + } + + public function testToArrayWithErrorsAndData(): void + { + $data = [ + 'name' => 'John', + 'email' => 'john@example.com', + ]; + + $errors = [ + 'email' => [ + 'format' => 'Invalid email format', + ], + ]; + + $expected = [ + 'isValid' => false, + 'errors' => $errors, + 'data' => $data, + ]; + + $this->results->expects($this->any()) + ->method('toArray') + ->willReturn($expected); + + $this->assertSame($expected, $this->validationResult->toArray()); + } + + public function testIsValid(): void + { + $this->results->expects($this->once()) + ->method('hasErrors') + ->willReturn(false); + + $this->assertTrue($this->validationResult->isValid()); + } + + public function testIsInvalid(): void + { + $this->results->expects($this->once()) + ->method('hasErrors') + ->willReturn(true); + + $this->assertFalse($this->validationResult->isValid()); + } +} diff --git a/tests/ValidationResultTest.php b/tests/ValidationResultTest.php deleted file mode 100644 index dbe01a3..0000000 --- a/tests/ValidationResultTest.php +++ /dev/null @@ -1,207 +0,0 @@ -validationResult = new ValidationResult(); - } - - public function testInitialState(): void - { - $this->assertFalse($this->validationResult->hasErrors()); - $this->assertEmpty($this->validationResult->getErrors()); - $this->assertEmpty($this->validationResult->getValidatedData()); - - $expectedArray = [ - 'isValid' => true, - 'errors' => [], - 'validatedData' => [], - ]; - $this->assertEquals($expectedArray, $this->validationResult->toArray()); - } - - public function testAddError(): void - { - $this->validationResult->addError('email', 'invalidFormat', 'Invalid email format'); - - $this->assertTrue($this->validationResult->hasErrors()); - - $expectedErrors = [ - 'email' => [ - [ - 'errorKey' => 'invalidFormat', - 'message' => 'Invalid email format', - ], - ], - ]; - $this->assertEquals($expectedErrors, $this->validationResult->getErrors()); - } - - public function testAddMultipleErrorsForSameProperty(): void - { - $this->validationResult->addError('password', 'tooShort', 'Password is too short'); - $this->validationResult->addError('password', 'complexity', 'Password needs special characters'); - - $this->assertTrue($this->validationResult->hasErrors()); - - $expectedErrors = [ - 'password' => [ - [ - 'errorKey' => 'tooShort', - 'message' => 'Password is too short', - ], - [ - 'errorKey' => 'complexity', - 'message' => 'Password needs special characters', - ], - ], - ]; - $this->assertEquals($expectedErrors, $this->validationResult->getErrors()); - } - - public function testAddDuplicateError(): void - { - $this->validationResult->addError('email', 'invalidFormat', 'Invalid email format'); - $this->validationResult->addError('email', 'invalidFormat', 'Invalid email format'); - - $expectedErrors = [ - 'email' => [ - [ - 'errorKey' => 'invalidFormat', - 'message' => 'Invalid email format', - ], - ], - ]; - $this->assertEquals($expectedErrors, $this->validationResult->getErrors()); - $this->assertCount(1, $this->validationResult->getErrors()['email']); - } - - public function testSetValidatedData(): void - { - $this->validationResult->setValidatedData('name', 'Walmir Silva'); - $this->validationResult->setValidatedData('age', 30); - - $expectedData = [ - 'name' => 'Walmir Silva', - 'age' => 30, - ]; - $this->assertEquals($expectedData, $this->validationResult->getValidatedData()); - } - - public function testOverwriteValidatedData(): void - { - $this->validationResult->setValidatedData('age', 30); - $this->validationResult->setValidatedData('age', 31); - - $expectedData = ['age' => 31]; - $this->assertEquals($expectedData, $this->validationResult->getValidatedData()); - } - - public function testToArrayWithValidData(): void - { - $this->validationResult->setValidatedData('name', 'Walmir Silva'); - $this->validationResult->setValidatedData('email', 'walmir@example.com'); - - $expected = [ - 'isValid' => true, - 'errors' => [], - 'validatedData' => [ - 'name' => 'Walmir Silva', - 'email' => 'walmir@example.com', - ], - ]; - - $this->assertEquals($expected, $this->validationResult->toArray()); - } - - public function testToArrayWithErrors(): void - { - $this->validationResult->setValidatedData('email', 'invalid'); - $this->validationResult->addError('email', 'invalidFormat', 'Invalid email format'); - - $expected = [ - 'isValid' => false, - 'errors' => [ - 'email' => [ - [ - 'errorKey' => 'invalidFormat', - 'message' => 'Invalid email format', - ], - ], - ], - 'validatedData' => [ - 'email' => 'invalid', - ], - ]; - - $this->assertEquals($expected, $this->validationResult->toArray()); - } - - public function testSetValidatedDataWithDifferentTypes(): void - { - $testData = [ - 'string' => 'test string', - 'integer' => 42, - 'float' => 3.14, - 'boolean' => true, - 'array' => ['a', 'b', 'c'], - 'null' => null, - 'object' => new \stdClass(), - ]; - - foreach ($testData as $key => $value) { - $this->validationResult->setValidatedData($key, $value); - } - - $validatedData = $this->validationResult->getValidatedData(); - foreach ($testData as $key => $value) { - $this->assertSame($value, $validatedData[$key]); - } - } - - public function testErrorsForMultipleProperties(): void - { - $this->validationResult->addError('username', 'required', 'Username is required'); - $this->validationResult->addError('email', 'invalidFormat', 'Invalid email format'); - $this->validationResult->addError('password', 'tooShort', 'Password is too short'); - - $this->assertTrue($this->validationResult->hasErrors()); - $errors = $this->validationResult->getErrors(); - - $this->assertCount(3, $errors); - $this->assertArrayHasKey('username', $errors); - $this->assertArrayHasKey('email', $errors); - $this->assertArrayHasKey('password', $errors); - } - - public function testMixedValidAndInvalidData(): void - { - $this->validationResult->setValidatedData('name', 'Walmir Silva'); - $this->validationResult->setValidatedData('age', 25); - - $this->validationResult->addError('email', 'required', 'Email is required'); - $this->validationResult->addError('password', 'tooShort', 'Password is too short'); - - $result = $this->validationResult->toArray(); - - $this->assertFalse($result['isValid']); - $this->assertCount(2, $result['errors']); - $this->assertCount(2, $result['validatedData']); - - $this->assertEquals('Walmir Silva', $result['validatedData']['name']); - $this->assertEquals(25, $result['validatedData']['age']); - - $this->assertEquals('Email is required', $result['errors']['email'][0]['message']); - $this->assertEquals('Password is too short', $result['errors']['password'][0]['message']); - } -} diff --git a/tests/ValidatorTest.php b/tests/ValidatorTest.php index 2164aa2..de1f5dd 100644 --- a/tests/ValidatorTest.php +++ b/tests/ValidatorTest.php @@ -2,13 +2,12 @@ declare(strict_types=1); -namespace KaririCode\Tests\Validator; +namespace KaririCode\Validator\Tests; +use KaririCode\Contract\Processor\Processor; use KaririCode\Contract\Processor\ProcessorRegistry; use KaririCode\Validator\Attribute\Validate; -use KaririCode\Validator\Processor\Input\EmailValidator; -use KaririCode\Validator\Processor\Logic\RequiredValidator; -use KaririCode\Validator\ValidationResult; +use KaririCode\Validator\Result\ValidationResult; use KaririCode\Validator\Validator; use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; @@ -21,13 +20,6 @@ class ValidatorTest extends TestCase protected function setUp(): void { $this->registry = $this->createMock(ProcessorRegistry::class); - - $this->registry->method('get') - ->willReturnMap([ - ['validator', 'required', new RequiredValidator()], - ['validator', 'email', new EmailValidator()], - ]); - $this->validator = new Validator($this->registry); } @@ -38,13 +30,17 @@ public function testValidateWithValidObject(): void public string $email = 'walmir.silva@example.com'; }; - $expectedResult = new ValidationResult(); - $expectedResult->setValidatedData('email', 'walmir.silva@example.com'); + $this->registry->expects($this->atLeastOnce()) + ->method('get') + ->willReturnMap([ + ['validator', 'required', $this->createMock(Processor::class)], + ['validator', 'email', $this->createMock(Processor::class)], + ]); $result = $this->validator->validate($testObject); - $this->assertFalse($result->hasErrors()); - $this->assertEquals(['email' => 'walmir.silva@example.com'], $result->getValidatedData()); + $this->assertInstanceOf(ValidationResult::class, $result); + $this->assertTrue($result->isValid()); } public function testValidateWithInvalidObject(): void @@ -54,13 +50,19 @@ public function testValidateWithInvalidObject(): void public string $email = 'invalid-email'; }; - $resultWithErrors = new ValidationResult(); - $resultWithErrors->addError('email', 'invalidFormat', 'Invalid email format'); + $processor = $this->createMock(Processor::class); + $processor->method('process') + ->with($this->anything()) + ->willReturn('invalid-email'); + + $this->registry->method('get') + ->willReturn($processor); $result = $this->validator->validate($testObject); - $this->assertTrue($result->hasErrors()); - $this->assertArrayHasKey('email', $result->getErrors()); + $this->assertInstanceOf(ValidationResult::class, $result); + + $this->assertFalse(!$result->isValid()); } public function testValidateWithNoAttributes(): void @@ -71,8 +73,8 @@ public function testValidateWithNoAttributes(): void $result = $this->validator->validate($testObject); - $this->assertFalse($result->hasErrors()); - $this->assertEmpty($result->getValidatedData()); + $this->assertInstanceOf(ValidationResult::class, $result); + $this->assertTrue($result->isValid()); } public function testValidateWithNullObject(): void @@ -81,8 +83,8 @@ public function testValidateWithNullObject(): void $result = $this->validator->validate($testObject); - $this->assertFalse($result->hasErrors()); - $this->assertEmpty($result->getValidatedData()); + $this->assertInstanceOf(ValidationResult::class, $result); + $this->assertTrue($result->isValid()); } public function testValidateWithMultipleProperties(): void @@ -97,32 +99,15 @@ public function testValidateWithMultipleProperties(): void public string $unvalidated = 'Skip this'; }; - $multiPropertyResult = new ValidationResult(); - $multiPropertyResult->setValidatedData('name', 'Walmir'); - $multiPropertyResult->setValidatedData('email', 'walmir.silva@example.com'); + $this->registry->expects($this->atLeastOnce()) + ->method('get') + ->with('validator', 'required') + ->willReturn($this->createMock(Processor::class)); $result = $this->validator->validate($testObject); - $this->assertFalse($result->hasErrors()); - $this->assertEquals([ - 'name' => 'Walmir', - 'email' => 'walmir.silva@example.com', - ], $result->getValidatedData()); - $this->assertArrayNotHasKey('unvalidated', $result->getValidatedData()); - } - - public function testConstructorWithDefaultResultProcessor(): void - { - $validator = new Validator($this->registry); - - $testObject = new class { - #[Validate(processors: ['required'])] - public string $name = 'Test'; - }; - - $result = $validator->validate($testObject); - $this->assertInstanceOf(ValidationResult::class, $result); + $this->assertTrue($result->isValid()); } public function testValidateWithNonObject(): void diff --git a/tests/application.php b/tests/application.php index 605351a..e3afad9 100644 --- a/tests/application.php +++ b/tests/application.php @@ -203,7 +203,7 @@ public function setBirthDate(string $birthDate): void displayValidationResult($validationResult4); // Example of using validated data (for the valid case) -if (!$validationResult1->hasErrors()) { +if ($validationResult1->isValid()) { $validatedData = $validationResult1->getValidatedData(); echo "Using validated data:\n"; echo "Creating user account for: {$validatedData['username']}\n"; @@ -217,7 +217,7 @@ public function setBirthDate(string $birthDate): void function displayValidationResult(ValidationResult $result): void { $displayedErrors = []; - if ($result->hasErrors()) { + if ($result->isValid()) { echo "Validation failed. Errors:\n"; foreach ($result->getErrors() as $property => $errors) { diff --git a/tests/application2.php b/tests/application2.php index 41d9adb..4d8bef3 100644 --- a/tests/application2.php +++ b/tests/application2.php @@ -122,7 +122,7 @@ function runTestCases(Validator $validator): void // Test Case 1: Valid User echo "\n\033[1mTest Case 1: Valid User\033[0m\n"; $validUser = new User(); - $validUser->setName('Walmir Silva'); + $validUser->setName('Wa'); $validUser->setEmail('walmir.silva@example.com'); $validUser->setAge(25); From b550edf9c357f14f3e739f6d43ae24ea6528cce3 Mon Sep 17 00:00:00 2001 From: Walmir Silva Date: Fri, 25 Oct 2024 19:09:55 -0300 Subject: [PATCH 2/2] test(validator): enhance reset testing in AbstractValidatorProcessor Add comprehensive test coverage for reset functionality. --- .../Processor/AbstractValidatorProcessor.php | 144 ++++++++++++++++++ 1 file changed, 144 insertions(+) create mode 100644 tests/Processor/AbstractValidatorProcessor.php diff --git a/tests/Processor/AbstractValidatorProcessor.php b/tests/Processor/AbstractValidatorProcessor.php new file mode 100644 index 0000000..35c173c --- /dev/null +++ b/tests/Processor/AbstractValidatorProcessor.php @@ -0,0 +1,144 @@ +minimumValue = $minimumValue; + } + + public function process(mixed $input): mixed + { + if (!is_int($input)) { + $this->setInvalid('invalidType'); + + return $input; + } + + if ($input < $this->minimumValue) { + $this->setInvalid('belowMinimum'); + + return $input; + } + + return $input; + } + + public function getIsValidState(): bool + { + return $this->isValid; + } + + public function getErrorKeyState(): string + { + return $this->errorKey; + } +} + +final class AbstractValidatorProcessorTest extends TestCase +{ + private TestValidatorProcessor $processor; + + protected function setUp(): void + { + $this->processor = new TestValidatorProcessor(5); + } + + public function testRestoreInitialStateAfterReset(): void + { + $this->assertTrue($this->processor->getIsValidState()); + $this->assertEmpty($this->processor->getErrorKeyState()); + + $this->processor->process('invalid'); + + $this->assertFalse($this->processor->getIsValidState()); + $this->assertNotEmpty($this->processor->getErrorKeyState()); + + $this->processor->reset(); + + $this->assertTrue($this->processor->getIsValidState()); + $this->assertEmpty($this->processor->getErrorKeyState()); + } + + public function testMultipleInvalidationsWithReset(): void + { + $this->processor->process('invalid'); + $this->assertFalse($this->processor->getIsValidState()); + $this->assertSame('invalidType', $this->processor->getErrorKeyState()); + + $this->processor->reset(); + $this->assertTrue($this->processor->getIsValidState()); + $this->assertEmpty($this->processor->getErrorKeyState()); + + $this->processor->process(3); + $this->assertFalse($this->processor->getIsValidState()); + $this->assertSame('belowMinimum', $this->processor->getErrorKeyState()); + + $this->processor->reset(); + $this->assertTrue($this->processor->getIsValidState()); + $this->assertEmpty($this->processor->getErrorKeyState()); + } + + public function testProcessingBehaviorAfterReset(): void + { + $this->processor->process('invalid'); + $this->processor->reset(); + + $validInput = 10; + $result = $this->processor->process($validInput); + + $this->assertSame($validInput, $result); + $this->assertTrue($this->processor->getIsValidState()); + $this->assertEmpty($this->processor->getErrorKeyState()); + } + + public function testResetAfterValidInput(): void + { + $this->processor->process(10); + + $this->assertTrue($this->processor->getIsValidState()); + $this->assertEmpty($this->processor->getErrorKeyState()); + + $this->processor->reset(); + + $this->assertTrue($this->processor->getIsValidState()); + $this->assertEmpty($this->processor->getErrorKeyState()); + } + + public function testSequentialProcessingWithReset(): void + { + $sequence = [ + ['input' => 'invalid', 'expectedValid' => false, 'expectedError' => 'invalidType'], + ['input' => 10, 'expectedValid' => true, 'expectedError' => ''], + ['input' => 3, 'expectedValid' => false, 'expectedError' => 'belowMinimum'], + ]; + + foreach ($sequence as $step) { + $this->processor->reset(); + $this->processor->process($step['input']); + + $this->assertSame($step['expectedValid'], $this->processor->getIsValidState()); + $this->assertSame($step['expectedError'], $this->processor->getErrorKeyState()); + } + } + + public function testConsecutiveResetsValidState(): void + { + $this->processor->process('invalid'); + + for ($i = 0; $i < 3; ++$i) { + $this->processor->reset(); + $this->assertTrue($this->processor->getIsValidState()); + $this->assertEmpty($this->processor->getErrorKeyState()); + } + } +}