diff --git a/.github/workflows/on-pull-request.yml b/.github/workflows/on-pull-request.yml index 4375b3d..fac84f4 100644 --- a/.github/workflows/on-pull-request.yml +++ b/.github/workflows/on-pull-request.yml @@ -31,6 +31,8 @@ jobs: run: composer install --no-progress --no-dev --prefer-dist --optimize-autoloader - name: Composer install with dev run: composer install --no-progress --prefer-dist --optimize-autoloader + - name: phpcs + run: composer phpcs - name: PHPUnit run: composer test diff --git a/composer.json b/composer.json index 7a6abe7..53c52ac 100644 --- a/composer.json +++ b/composer.json @@ -8,7 +8,8 @@ ], "type": "library", "require-dev": { - "phpunit/phpunit": "^12.0" + "phpunit/phpunit": "^12.0", + "squizlabs/php_codesniffer": "^3.9" }, "require": { "ext-json": "*", @@ -32,6 +33,8 @@ } }, "scripts": { - "test": "phpunit" + "test": "phpunit", + "phpcs": "phpcs", + "phpcbf": "phpcbf" } } diff --git a/phpcs.xml b/phpcs.xml new file mode 100644 index 0000000..88ed800 --- /dev/null +++ b/phpcs.xml @@ -0,0 +1,7 @@ + + + PHP_CodeSniffer configuration for ObjectErrors using PSR-12 + + src + tests + diff --git a/src/ErrorsCollection.php b/src/ErrorsCollection.php index b51271e..8c389e8 100644 --- a/src/ErrorsCollection.php +++ b/src/ErrorsCollection.php @@ -24,9 +24,8 @@ class ErrorsCollection implements ArrayAccess, Countable, JsonSerializable, Stri * @param ParamsMode $mode Mode how this errors collection works */ public function __construct( - public readonly ParamsMode $mode = ParamsMode::Mode1 - ) - { + public readonly ParamsMode $mode = ParamsMode::Mode1 + ) { } /** @@ -116,8 +115,8 @@ public function __toString(): string return ''; } - return implode(PHP_EOL, $this->errors); - } + return implode(PHP_EOL, $this->errors); + } /** * Adds an @@ -188,14 +187,13 @@ public function toArray(): array return $this->errors; } - /** - * Export data to json - * - * @throws JsonException - */ + /** + * Export data to json + * + * @throws JsonException + */ public function toJson(): string { return json_encode($this, JSON_THROW_ON_ERROR); } - -} \ No newline at end of file +} diff --git a/src/ErrorsTrait.php b/src/ErrorsTrait.php index 0ff9620..340770f 100644 --- a/src/ErrorsTrait.php +++ b/src/ErrorsTrait.php @@ -8,56 +8,54 @@ */ trait ErrorsTrait { - - /** - * Errors collection - */ - protected ErrorsCollection $errors; - - /** - * ErrorsTrait constructor. - */ - public function __construct() - { - $this->errors = new ErrorsCollection(); - } - - /** - * return the errors for this object as an array - * - * @param bool $asHTML Format using HTML? - * - * @return array|string an array of errors - */ - public function getErrors(bool $asHTML = true): array|string - { - return $asHTML ? $this->getHtmlErrors() : $this->errors->toArray(); - } - - /** - * add an error - * - * @param string $err_str error to add - */ - public function setErrors(string $err_str): void - { - call_user_func_array([$this->errors, 'add'], func_get_args()); - } - - /** - * Returns the errors for this object as html - */ - public function getHtmlErrors(): string - { - return $this->errors->getHtml(); - } - - /** - * Has some errors? - */ - public function hasError(): bool - { - return !$this->errors->isEmpty(); - } - -} \ No newline at end of file + /** + * Errors collection + */ + protected ErrorsCollection $errors; + + /** + * ErrorsTrait constructor. + */ + public function __construct() + { + $this->errors = new ErrorsCollection(); + } + + /** + * return the errors for this object as an array + * + * @param bool $asHTML Format using HTML? + * + * @return array|string an array of errors + */ + public function getErrors(bool $asHTML = true): array|string + { + return $asHTML ? $this->getHtmlErrors() : $this->errors->toArray(); + } + + /** + * add an error + * + * @param string $err_str error to add + */ + public function setErrors(string $err_str): void + { + call_user_func_array([$this->errors, 'add'], func_get_args()); + } + + /** + * Returns the errors for this object as html + */ + public function getHtmlErrors(): string + { + return $this->errors->getHtml(); + } + + /** + * Has some errors? + */ + public function hasError(): bool + { + return !$this->errors->isEmpty(); + } +} diff --git a/src/ParamsMode.php b/src/ParamsMode.php index 13b10a6..85e4611 100644 --- a/src/ParamsMode.php +++ b/src/ParamsMode.php @@ -6,20 +6,18 @@ enum ParamsMode: int { + /** + * Mode that says that only one param for adding is used + */ + case Mode1 = 0; - /** - * Mode that says that only one param for adding is used - */ - case Mode1 = 0; - - /** - * Mode that says two params are used - */ - case Mode2 = 1; - - /** - * Mode that says that 2nd param is a used as prefix - */ - case Mode2AsPrefix = 2; + /** + * Mode that says two params are used + */ + case Mode2 = 1; + /** + * Mode that says that 2nd param is a used as prefix + */ + case Mode2AsPrefix = 2; } diff --git a/src/UnsetErrorException.php b/src/UnsetErrorException.php index d2735dc..7c855d6 100644 --- a/src/UnsetErrorException.php +++ b/src/UnsetErrorException.php @@ -6,5 +6,4 @@ class UnsetErrorException extends Exception { - -} \ No newline at end of file +} diff --git a/tests/ErrorsCollectionTest.php b/tests/ErrorsCollectionTest.php index 9682c54..074fadb 100644 --- a/tests/ErrorsCollectionTest.php +++ b/tests/ErrorsCollectionTest.php @@ -12,202 +12,227 @@ class ErrorsCollectionTest extends TestCase { - - public function testDefaultConstructorParams(): void - { - $instance = new ErrorsCollection(); - $this->assertSame( - ParamsMode::Mode1, - $instance->mode, - message: 'When creating ErrorsCollection instance default mode should be MODE_1_PARAM, but isn\'t' - ); - } - - #[DataProvider('provideConstructorParams')] - public function testConstructorParams(ParamsMode $mode): void - { - $instance = new ErrorsCollection($mode); - $this->assertSame( - $mode, - $instance->mode, - message: 'Mode ' . $mode->name . ' is different after creating instance' - ); - } - - public function testOffsetExists(): void - { - $instance = new ErrorsCollection(ParamsMode::Mode2); - $key = crc32(time()); - $this->assertArrayNotHasKey( - $key, - $instance, - message: 'Random key already exists in array but shouldn\'t' - ); - $instance->add($key, crc32(time())); - $this->assertArrayHasKey( - $key, - $instance, - message: 'Random key was not found but it should' - ); - } - - public function testOffsetGet(): void - { - $offset = crc32(time()); - $data = sha1(time()); - - $instance = new ErrorsCollection(ParamsMode::Mode2); - $instance->add($offset, $data); - $this->assertSame($instance[$offset], $data, message: 'Data is not same #1'); - $this->assertSame($instance->offsetGet($offset), $data, message: 'Data is not same #2'); - $this->assertNotNull($instance[$offset], message: 'Data is not same #3'); - $this->assertNotNull($instance->offsetGet($offset), message: 'Data is not same #4'); - } - - public function testOffsetSet(): void - { - $offset = crc32(time()); - $data = sha1(time()); - - $instance = new ErrorsCollection(ParamsMode::Mode2); - $instance->add($offset, $data); - - $ndata = md5(time()); - $instance[$offset] = $ndata; - $this->assertSame($instance[$offset], $ndata, message: 'Changed data is not same as readed one #1'); - - $ndata = soundex($ndata); - $instance->offsetSet($offset, $ndata); - $this->assertSame($instance[$offset], $ndata, message: 'Changed data is not same as readed one #2'); - - $offset = md5(microtime(true)); - - $ndata = metaphone($ndata); - $instance[$offset] = $ndata; - $this->assertSame($instance[$offset], $ndata, message: 'Changed data is not same as readed one #3'); - - $ndata = soundex($ndata); - $instance->offsetSet($offset, $ndata); - $this->assertSame($instance[$offset], $ndata, message: 'Changed data is not same as readed one #4'); - } - - public function testOffsetUnset(): void - { - $offset = crc32(time()); - - $instance = new ErrorsCollection(ParamsMode::Mode2); - - $this->expectException(UnsetErrorException::class); - $instance->offsetUnset($offset); - } - - public function testIsEmpty(): void - { - $instance = new ErrorsCollection(); - $this->assertTrue($instance->isEmpty(), message: 'Is not empty after creation'); - - $instance->add(crc32(time())); - $this->assertNotTrue($instance->isEmpty(), message: 'Is still empty after one element was added'); - } - - public function testClear(): void - { - $instance = new ErrorsCollection(); - $instance->add(crc32(time())); - $instance->clear(); - $this->assertEmpty($instance, message: 'Clear() must clear'); - } - - public function testStringConversion(): void - { - $instance = new ErrorsCollection(); - - $this->assertEmpty((string)$instance, message: 'Converted to string empty ErrorsCollection must be empty'); - $this->assertEmpty($instance->getHtml(), message: 'Converted to HTML empty ErrorsCollection must be empty'); - - $instance->add(crc32(time())); - - $this->assertNotEmpty((string)$instance, message: 'Converted to string not empty ErrorsCollection must be not empty'); - $this->assertNotEmpty($instance->getHtml(), message: 'Converted to HTML not empty ErrorsCollection must be not empty'); - - $this->assertIsString($instance->getHtml(), message: 'getHTML must generate strings'); - } - - public function testCount(): void - { - $instance = new ErrorsCollection(); - $this->assertCount(0, $instance, message: 'Count is not 0 when collection was just created'); - - $instance->add(crc32(time())); - $this->assertSame(1, $instance->count(), message: 'Count must be 1 after one element was added'); - - $this->assertCount(1, $instance, message: 'Count function doesn\'t work'); - } - - public static function provideTestAddData(): Generator - { - yield 'mode1' => [ - 'mode' => ParamsMode::Mode1, - 'addParams' => [ - md5(time()) - ], - 'expectedKey' => 0 - ]; - - yield 'mode2asprefix' => [ - 'mode' => ParamsMode::Mode2AsPrefix, - 'addParams' => [ - md5(time()) - ], - 'expectedKey' => 0 - ]; - - $key = crc32(time()); - yield 'mode2' => [ - 'mode' => ParamsMode::Mode2, - 'addParams' => [ - $key, - md5(time()) - ], - 'expectedKey' => $key - ]; - } - - #[DataProvider('provideTestAddData')] - public function testAdd(ParamsMode $mode, array $addParams, int|string $expectedKey): void - { - $instance = new ErrorsCollection($mode); - call_user_func_array([$instance, 'add'], $addParams); - $this->assertArrayHasKey($expectedKey, $instance); - } - - /** - * @throws JsonException - */ - public function testSerialization(): void - { - $instance = new ErrorsCollection(ParamsMode::Mode2); - - $instance->add(md5(time()), sha1(time())); - $instance->add(crc32(time()), soundex(time())); - - $serialized = serialize($instance); - $unserialized = unserialize($serialized); - $this->assertInstanceOf(ErrorsCollection::class, $unserialized, message: 'Unserialized data is not ErrorsCollection class type but it should be #1'); - $this->assertSame($instance->mode, $unserialized->mode, message: 'Serialization-unserialization fails #1'); - $this->assertSame($instance->toArray(), $unserialized->toArray(), message: 'Serialization-unserialization fails #2'); - - $this->assertIsArray($instance->toArray(), message: 'toArray doesn\'t makes an array'); - $this->assertIsString($instance->toJson(), message: 'toJSON doesn\'t makes a string'); - } - - public static function provideConstructorParams(): Generator - { - foreach (ParamsMode::cases() as $mode) { - yield $mode->name => [ - 'mode' => $mode, - ]; - } - } - -} \ No newline at end of file + public function testDefaultConstructorParams(): void + { + $instance = new ErrorsCollection(); + $this->assertSame( + ParamsMode::Mode1, + $instance->mode, + message: 'When creating ErrorsCollection instance default mode should be MODE_1_PARAM, but isn\'t' + ); + } + + #[DataProvider('provideConstructorParams')] + public function testConstructorParams(ParamsMode $mode): void + { + $instance = new ErrorsCollection($mode); + $this->assertSame( + $mode, + $instance->mode, + message: 'Mode ' . $mode->name . ' is different after creating instance' + ); + } + + public function testOffsetExists(): void + { + $instance = new ErrorsCollection(ParamsMode::Mode2); + $key = crc32(time()); + $this->assertArrayNotHasKey( + $key, + $instance, + message: 'Random key already exists in array but shouldn\'t' + ); + $instance->add($key, crc32(time())); + $this->assertArrayHasKey( + $key, + $instance, + message: 'Random key was not found but it should' + ); + } + + public function testOffsetGet(): void + { + $offset = crc32(time()); + $data = sha1(time()); + + $instance = new ErrorsCollection(ParamsMode::Mode2); + $instance->add($offset, $data); + $this->assertSame($instance[$offset], $data, message: 'Data is not same #1'); + $this->assertSame($instance->offsetGet($offset), $data, message: 'Data is not same #2'); + $this->assertNotNull($instance[$offset], message: 'Data is not same #3'); + $this->assertNotNull($instance->offsetGet($offset), message: 'Data is not same #4'); + } + + public function testOffsetSet(): void + { + $offset = crc32(time()); + $data = sha1(time()); + + $instance = new ErrorsCollection(ParamsMode::Mode2); + $instance->add($offset, $data); + + $ndata = md5(time()); + $instance[$offset] = $ndata; + $this->assertSame($instance[$offset], $ndata, message: 'Changed data is not same as readed one #1'); + + $ndata = soundex($ndata); + $instance->offsetSet($offset, $ndata); + $this->assertSame($instance[$offset], $ndata, message: 'Changed data is not same as readed one #2'); + + $offset = md5(microtime(true)); + + $ndata = metaphone($ndata); + $instance[$offset] = $ndata; + $this->assertSame($instance[$offset], $ndata, message: 'Changed data is not same as readed one #3'); + + $ndata = soundex($ndata); + $instance->offsetSet($offset, $ndata); + $this->assertSame($instance[$offset], $ndata, message: 'Changed data is not same as readed one #4'); + } + + public function testOffsetUnset(): void + { + $offset = crc32(time()); + + $instance = new ErrorsCollection(ParamsMode::Mode2); + + $this->expectException(UnsetErrorException::class); + $instance->offsetUnset($offset); + } + + public function testIsEmpty(): void + { + $instance = new ErrorsCollection(); + $this->assertTrue($instance->isEmpty(), message: 'Is not empty after creation'); + + $instance->add(crc32(time())); + $this->assertNotTrue($instance->isEmpty(), message: 'Is still empty after one element was added'); + } + + public function testClear(): void + { + $instance = new ErrorsCollection(); + $instance->add(crc32(time())); + $instance->clear(); + $this->assertEmpty($instance, message: 'Clear() must clear'); + } + + public function testStringConversion(): void + { + $instance = new ErrorsCollection(); + + $this->assertEmpty( + (string)$instance, + message: 'Converted to string empty ErrorsCollection must be empty' + ); + $this->assertEmpty( + $instance->getHtml(), + message: 'Converted to HTML empty ErrorsCollection must be empty' + ); + + $instance->add(crc32(time())); + + $this->assertNotEmpty( + (string)$instance, + message: 'Converted to string not empty ErrorsCollection must be not empty' + ); + $this->assertNotEmpty( + $instance->getHtml(), + message: 'Converted to HTML not empty ErrorsCollection must be not empty' + ); + + $this->assertIsString( + $instance->getHtml(), + message: 'getHTML must generate strings' + ); + } + + public function testCount(): void + { + $instance = new ErrorsCollection(); + $this->assertCount(0, $instance, message: 'Count is not 0 when collection was just created'); + + $instance->add(crc32(time())); + $this->assertSame(1, $instance->count(), message: 'Count must be 1 after one element was added'); + + $this->assertCount(1, $instance, message: 'Count function doesn\'t work'); + } + + public static function provideTestAddData(): Generator + { + yield 'mode1' => [ + 'mode' => ParamsMode::Mode1, + 'addParams' => [ + md5(time()) + ], + 'expectedKey' => 0 + ]; + + yield 'mode2asprefix' => [ + 'mode' => ParamsMode::Mode2AsPrefix, + 'addParams' => [ + md5(time()) + ], + 'expectedKey' => 0 + ]; + + $key = crc32(time()); + yield 'mode2' => [ + 'mode' => ParamsMode::Mode2, + 'addParams' => [ + $key, + md5(time()) + ], + 'expectedKey' => $key + ]; + } + + #[DataProvider('provideTestAddData')] + public function testAdd(ParamsMode $mode, array $addParams, int|string $expectedKey): void + { + $instance = new ErrorsCollection($mode); + call_user_func_array([$instance, 'add'], $addParams); + $this->assertArrayHasKey($expectedKey, $instance); + } + + /** + * @throws JsonException + */ + public function testSerialization(): void + { + $instance = new ErrorsCollection(ParamsMode::Mode2); + + $instance->add(md5(time()), sha1(time())); + $instance->add(crc32(time()), soundex(time())); + + $serialized = serialize($instance); + $unserialized = unserialize($serialized); + $this->assertInstanceOf( + ErrorsCollection::class, + $unserialized, + message: 'Unserialized data is not ErrorsCollection class type but it should be #1' + ); + $this->assertSame( + $instance->mode, + $unserialized->mode, + message: 'Serialization-unserialization fails #1' + ); + $this->assertSame( + $instance->toArray(), + $unserialized->toArray(), + message: 'Serialization-unserialization fails #2' + ); + + $this->assertIsArray($instance->toArray(), message: 'toArray doesn\'t makes an array'); + $this->assertIsString($instance->toJson(), message: 'toJSON doesn\'t makes a string'); + } + + public static function provideConstructorParams(): Generator + { + foreach (ParamsMode::cases() as $mode) { + yield $mode->name => [ + 'mode' => $mode, + ]; + } + } +} diff --git a/tests/ErrorsTraitTest.php b/tests/ErrorsTraitTest.php index 4f6a11c..f4c3f85 100644 --- a/tests/ErrorsTraitTest.php +++ b/tests/ErrorsTraitTest.php @@ -7,39 +7,37 @@ class ErrorsTraitTest extends TestCase { + private function createFakeInstance(): object + { + return new class { + use ErrorsTrait; + }; + } - private function createFakeInstance(): object - { - return new class { - use ErrorsTrait; - }; - } + public function testGetErrors(): void + { + $mock = $this->createFakeInstance(); - public function testGetErrors(): void - { - $mock = $this->createFakeInstance(); + $this->assertIsArray($mock->getErrors(false)); + $this->assertIsString($mock->getErrors(true)); + } - $this->assertIsArray($mock->getErrors(false)); - $this->assertIsString($mock->getErrors(true)); - } + public function testGetHtmlErrors(): void + { + $mock = $this->createFakeInstance(); - public function testGetHtmlErrors(): void - { - $mock = $this->createFakeInstance(); + $this->assertIsString($mock->getHtmlErrors()); + } - $this->assertIsString($mock->getHtmlErrors()); - } + public function testHasAndSetError(): void + { + $mock = $this->createFakeInstance(); - public function testHasAndSetError(): void - { - $mock = $this->createFakeInstance(); + $this->assertIsBool($mock->hasError()); - $this->assertIsBool($mock->hasError()); + $this->assertFalse($mock->hasError()); - $this->assertFalse($mock->hasError()); - - $mock->setErrors("some errors"); - $this->assertTrue($mock->hasError()); - } - -} \ No newline at end of file + $mock->setErrors("some errors"); + $this->assertTrue($mock->hasError()); + } +}