From 8861dc2468d19d1a871553a6d0c6691c7ee341da Mon Sep 17 00:00:00 2001 From: Daniel Seifert Date: Tue, 7 Jan 2025 14:04:13 +0100 Subject: [PATCH] assert right return types in Account entity --- src/Entities/Account.php | 130 ++++++------- src/Entities/Entity.php | 87 +++++++++ tests/unit/Entities/AccountTest.php | 277 +++++++++++++++++++++++++++- 3 files changed, 423 insertions(+), 71 deletions(-) create mode 100644 src/Entities/Entity.php diff --git a/src/Entities/Account.php b/src/Entities/Account.php index 57f142b..bd8771d 100644 --- a/src/Entities/Account.php +++ b/src/Entities/Account.php @@ -18,10 +18,11 @@ declare(strict_types=1); namespace D3\KlicktippPhpClient\Entities; use D3\KlicktippPhpClient\Exceptions\BaseException; +use D3\KlicktippPhpClient\Exceptions\InvalidCredentialTypeException; use D3\KlicktippPhpClient\Resources\Account as AccountEndpoint; use Doctrine\Common\Collections\ArrayCollection; -class Account extends ArrayCollection +class Account extends Entity { private ?AccountEndpoint $endpoint; @@ -31,159 +32,162 @@ class Account extends ArrayCollection parent::__construct($elements); } - public function getId(): string + /** + * @throws InvalidCredentialTypeException + */ + public function getId(): ?string { - return $this->get(AccountEndpoint::UID); + return $this->getStringOrNullValue($this->get(AccountEndpoint::UID)); } - public function getStatus(): string + public function getStatus(): ?string { - return $this->get(AccountEndpoint::STATUS); + return $this->getStringOrNullValue($this->get(AccountEndpoint::STATUS)); } - public function getTier(): int + public function getTier(): ?int { - return (int) $this->get(AccountEndpoint::TIER); + return $this->getIntOrNullValue($this->get(AccountEndpoint::TIER)); } - public function getUsergroup(): string + public function getUsergroup(): ?string { - return $this->get(AccountEndpoint::USERGROUP); + return $this->getStringOrNullValue($this->get(AccountEndpoint::USERGROUP)); } - public function getEmail(): string + public function getEmail(): ?string { - return $this->get(AccountEndpoint::EMAIL); + return $this->getStringOrNullValue($this->get(AccountEndpoint::EMAIL)); } - public function getFirstname(): string + public function getFirstname(): ?string { - return $this->get(AccountEndpoint::FIRSTNAME); + return $this->getStringOrNullValue($this->get(AccountEndpoint::FIRSTNAME)); } - public function getLastname(): string + public function getLastname(): ?string { - return $this->get(AccountEndpoint::LASTNAME); + return $this->getStringOrNullValue($this->get(AccountEndpoint::LASTNAME)); } - public function getCompany(): string + public function getCompany(): ?string { - return $this->get(AccountEndpoint::COMPANY); + return $this->getStringOrNullValue($this->get(AccountEndpoint::COMPANY)); } - public function getWebsite(): string + public function getWebsite(): ?string { - return $this->get(AccountEndpoint::WEBSITE); + return $this->getStringOrNullValue($this->get(AccountEndpoint::WEBSITE)); } - public function getStreet(): string + public function getStreet(): ?string { - return $this->get(AccountEndpoint::STREET); + return $this->getStringOrNullValue($this->get(AccountEndpoint::STREET)); } - public function getCity(): string + public function getCity(): ?string { - return $this->get(AccountEndpoint::CITY); + return $this->getStringOrNullValue($this->get(AccountEndpoint::CITY)); } - public function getState(): string + public function getState(): ?string { - return $this->get(AccountEndpoint::STATE); + return $this->getStringOrNullValue($this->get(AccountEndpoint::STATE)); } - public function getZIP(): string + public function getZIP(): ?string { - return $this->get(AccountEndpoint::ZIP); + return $this->getStringOrNullValue($this->get(AccountEndpoint::ZIP)); } - public function getCountry(): string + public function getCountry(): ?string { - return $this->get(AccountEndpoint::COUNTRY); + return $this->getStringOrNullValue($this->get(AccountEndpoint::COUNTRY)); } - public function getPhone(): string + public function getPhone(): ?string { - return $this->get(AccountEndpoint::PHONE); + return $this->getStringOrNullValue($this->get(AccountEndpoint::PHONE)); } - public function getFax(): string + public function getFax(): ?string { - return $this->get(AccountEndpoint::FAX); + return $this->getStringOrNullValue($this->get(AccountEndpoint::FAX)); } - public function getAffiliateId(): string + public function getAffiliateId(): ?string { - return $this->get(AccountEndpoint::AFFILIATE_ID); + return $this->getStringOrNullValue($this->get(AccountEndpoint::AFFILIATE_ID)); } - public function getAccessRights(): ArrayCollection + public function getAccessRights(): ?ArrayCollection { - return new ArrayCollection($this->get(AccountEndpoint::ACCESS_RIGHTS)); + return $this->getArrayCollectionFromValue($this->get(AccountEndpoint::ACCESS_RIGHTS)); } - public function getSenders(): ArrayCollection + public function getSenders(): ?ArrayCollection { - return new ArrayCollection($this->get(AccountEndpoint::SENDERS)); + return $this->getArrayCollectionFromValue($this->get(AccountEndpoint::SENDERS)); } - public function getGmailPreview(): string + public function getGmailPreview(): ?string { - return $this->get(AccountEndpoint::GMAIL_PREVIEW); + return $this->getStringOrNullValue($this->get(AccountEndpoint::GMAIL_PREVIEW)); } - public function getLimits(): ArrayCollection + public function getLimits(): ?ArrayCollection { - return new ArrayCollection($this->get(AccountEndpoint::LIMITS)); + return $this->getArrayCollectionFromValue($this->get(AccountEndpoint::LIMITS)); } - public function getPreferences(): ArrayCollection + public function getPreferences(): ?ArrayCollection { - return new ArrayCollection($this->get(AccountEndpoint::PREFERENCES)); + return $this->getArrayCollectionFromValue($this->get(AccountEndpoint::PREFERENCES)); } - public function getSettings(): ArrayCollection + public function getSettings(): ?ArrayCollection { - return new ArrayCollection($this->get(AccountEndpoint::SETTINGS)); + return $this->getArrayCollectionFromValue($this->get(AccountEndpoint::SETTINGS)); } - public function canShowOtherAccountInfo(): bool + public function canShowOtherAccountInfo(): ?bool { - return (bool) $this->get(AccountEndpoint::SHOW_OTHER_ACCOUNT_INFO); + return $this->getBooleanOrNullValue($this->get(AccountEndpoint::SHOW_OTHER_ACCOUNT_INFO)); } - public function canShowSupportInfo(): bool + public function canShowSupportInfo(): ?bool { - return (bool) $this->get(AccountEndpoint::SHOW_SUPPORT_INFO); + return $this->getBooleanOrNullValue($this->get(AccountEndpoint::SHOW_SUPPORT_INFO)); } - public function getSupport(): ArrayCollection + public function getSupport(): ?ArrayCollection { - return new ArrayCollection($this->get(AccountEndpoint::SUPPORT)); + return $this->getArrayCollectionFromValue($this->get(AccountEndpoint::SUPPORT)); } - public function getLanguage(): string + public function getLanguage(): ?string { - return $this->get(AccountEndpoint::LANGUAGE); + return $this->getStringOrNullValue($this->get(AccountEndpoint::LANGUAGE)); } - public function getSegments(): ArrayCollection + public function getSegments(): ?ArrayCollection { - return new ArrayCollection($this->get(AccountEndpoint::SEGMENTS)); + return $this->getArrayCollectionFromValue($this->get(AccountEndpoint::SEGMENTS)); } - public function getCustomerData(): ArrayCollection + public function getCustomerData(): ?ArrayCollection { - return new ArrayCollection($this->get(AccountEndpoint::CUSTOMER_DATA)); + return $this->getArrayCollectionFromValue($this->get(AccountEndpoint::CUSTOMER_DATA)); } - public function getSubscriptionInfo(): ArrayCollection + public function getSubscriptionInfo(): ?ArrayCollection { - return new ArrayCollection($this->get(AccountEndpoint::SUBSCRIPTION_INFO)); + return $this->getArrayCollectionFromValue($this->get(AccountEndpoint::SUBSCRIPTION_INFO)); } - public function getActivePayments(): ArrayCollection + public function getActivePayments(): ?ArrayCollection { - return new ArrayCollection($this->get(AccountEndpoint::ACTIVE_PAYMENTS)); + return $this->getArrayCollectionFromValue($this->get(AccountEndpoint::ACTIVE_PAYMENTS)); } /** diff --git a/src/Entities/Entity.php b/src/Entities/Entity.php new file mode 100644 index 0000000..c1bc380 --- /dev/null +++ b/src/Entities/Entity.php @@ -0,0 +1,87 @@ + + * @link https://www.oxidmodule.com + */ + +declare(strict_types=1); + +namespace D3\KlicktippPhpClient\Entities; + +use Assert\Assert; +use D3\KlicktippPhpClient\Exceptions\InvalidCredentialTypeException; +use DateTime; +use Doctrine\Common\Collections\ArrayCollection; +use Exception; + +abstract class Entity extends ArrayCollection +{ + protected function getDateTimeFromValue($value): ?DateTime + { + $this->getStringOrNullValue($value); + + try { + return $value ? + new DateTime((string)$value) : + null; + } catch (Exception) { + return null; + } + } + + protected function getArrayCollectionFromValue($value): ?ArrayCollection + { + Assert::lazy() + ->setExceptionClass(InvalidCredentialTypeException::class) + ->that($value) + ->nullOr()->isArray($value) + ->verifyNow(); + + return is_array($value) ? new ArrayCollection($value) : null; + } + + /** + * @throws InvalidCredentialTypeException + */ + protected function getStringOrNullValue($value): ?string + { + Assert::lazy() + ->setExceptionClass(InvalidCredentialTypeException::class) + ->that($value) + ->nullOr()->string() + ->verifyNow(); + + return is_null($value) ? null : (string) $value; + } + + protected function getIntOrNullValue($value): ?int + { + Assert::lazy() + ->setExceptionClass(InvalidCredentialTypeException::class) + ->that($value) + ->nullOr()->integerish($value) + ->verifyNow(); + + return is_null($value) ? null : (int) $value; + } + + protected function getBooleanOrNullValue($value): ?bool + { + Assert::lazy() + ->setExceptionClass(InvalidCredentialTypeException::class) + ->that($value) + ->nullOr()->boolean($value) + ->verifyNow(); + + return is_null($value) ? null : (bool) $value; + } +} \ No newline at end of file diff --git a/tests/unit/Entities/AccountTest.php b/tests/unit/Entities/AccountTest.php index f6f5d8f..6b34964 100644 --- a/tests/unit/Entities/AccountTest.php +++ b/tests/unit/Entities/AccountTest.php @@ -18,6 +18,7 @@ declare(strict_types=1); namespace D3\KlicktippPhpClient\tests\unit\Entities; use D3\KlicktippPhpClient\Entities\Account; +use D3\KlicktippPhpClient\Exceptions\InvalidCredentialTypeException; use D3\KlicktippPhpClient\Resources\Account as AccountEndpoint; use D3\KlicktippPhpClient\tests\TestCase; use Doctrine\Common\Collections\ArrayCollection; @@ -26,7 +27,7 @@ use PHPUnit\Framework\MockObject\Rule\InvokedCount; use ReflectionException; /** - * @coversNothing + * @covers \D3\KlicktippPhpClient\Entities\Account */ class AccountTest extends TestCase { @@ -184,9 +185,61 @@ class AccountTest extends TestCase $elements, $sut->toArray() ); - $this->assertSame( - $endpoint, - $this->getValue($sut, 'endpoint') + } + + /** + * @test + * @throws ReflectionException + * @covers \D3\KlicktippPhpClient\Entities\Account::getId + * @covers \D3\KlicktippPhpClient\Entities\Account::getStatus + * @covers \D3\KlicktippPhpClient\Entities\Account::getTier + * @covers \D3\KlicktippPhpClient\Entities\Account::getUsergroup + * @covers \D3\KlicktippPhpClient\Entities\Account::getEmail + * @covers \D3\KlicktippPhpClient\Entities\Account::getFirstname + * @covers \D3\KlicktippPhpClient\Entities\Account::getLastname + * @covers \D3\KlicktippPhpClient\Entities\Account::getCompany + * @covers \D3\KlicktippPhpClient\Entities\Account::getWebsite + * @covers \D3\KlicktippPhpClient\Entities\Account::getStreet + * @covers \D3\KlicktippPhpClient\Entities\Account::getCity + * @covers \D3\KlicktippPhpClient\Entities\Account::getState + * @covers \D3\KlicktippPhpClient\Entities\Account::getZIP + * @covers \D3\KlicktippPhpClient\Entities\Account::getCountry + * @covers \D3\KlicktippPhpClient\Entities\Account::getPhone + * @covers \D3\KlicktippPhpClient\Entities\Account::getFax + * @covers \D3\KlicktippPhpClient\Entities\Account::getAffiliateId + * @covers \D3\KlicktippPhpClient\Entities\Account::getAccessRights + * @covers \D3\KlicktippPhpClient\Entities\Account::getSenders + * @covers \D3\KlicktippPhpClient\Entities\Account::getGmailPreview + * @covers \D3\KlicktippPhpClient\Entities\Account::getLimits + * @covers \D3\KlicktippPhpClient\Entities\Account::getPreferences + * @covers \D3\KlicktippPhpClient\Entities\Account::getSettings + * @covers \D3\KlicktippPhpClient\Entities\Account::canShowOtherAccountInfo + * @covers \D3\KlicktippPhpClient\Entities\Account::canShowSupportInfo + * @covers \D3\KlicktippPhpClient\Entities\Account::getSupport + * @covers \D3\KlicktippPhpClient\Entities\Account::getLanguage + * @covers \D3\KlicktippPhpClient\Entities\Account::getSegments + * @covers \D3\KlicktippPhpClient\Entities\Account::getCustomerData + * @covers \D3\KlicktippPhpClient\Entities\Account::getSubscriptionInfo + * @covers \D3\KlicktippPhpClient\Entities\Account::getActivePayments + * @dataProvider getDataProvider + */ + public function testGet(string $testMethod, $expected): void + { + $this->assertEquals( + $expected, + $this->callMethod( + $this->entity, + $testMethod, + ) + ); + + + $this->assertEquals( + $expected, + $this->callMethod( + $this->entity, + $testMethod, + ) ); } @@ -226,12 +279,103 @@ class AccountTest extends TestCase * @covers \D3\KlicktippPhpClient\Entities\Account::getActivePayments * @dataProvider getDataProvider */ - public function testGet(string $testMethod, $exepcted): void + public function testGetNull(string $testMethod): void { - $this->assertEquals( - $exepcted, + $nullProperties = []; + foreach (array_keys($this->entity->toArray()) as $key) { + $nullProperties[$key] = null; + } + + $sut = new Account($nullProperties); + + $this->assertNull( $this->callMethod( - $this->entity, + $sut, + $testMethod, + ) + ); + } + + /** + * @test + * @throws ReflectionException + * @covers \D3\KlicktippPhpClient\Entities\Account::getId + * @covers \D3\KlicktippPhpClient\Entities\Account::getStatus + * @covers \D3\KlicktippPhpClient\Entities\Account::getTier + * @covers \D3\KlicktippPhpClient\Entities\Account::getUsergroup + * @covers \D3\KlicktippPhpClient\Entities\Account::getEmail + * @covers \D3\KlicktippPhpClient\Entities\Account::getFirstname + * @covers \D3\KlicktippPhpClient\Entities\Account::getLastname + * @covers \D3\KlicktippPhpClient\Entities\Account::getCompany + * @covers \D3\KlicktippPhpClient\Entities\Account::getWebsite + * @covers \D3\KlicktippPhpClient\Entities\Account::getStreet + * @covers \D3\KlicktippPhpClient\Entities\Account::getCity + * @covers \D3\KlicktippPhpClient\Entities\Account::getState + * @covers \D3\KlicktippPhpClient\Entities\Account::getZIP + * @covers \D3\KlicktippPhpClient\Entities\Account::getCountry + * @covers \D3\KlicktippPhpClient\Entities\Account::getPhone + * @covers \D3\KlicktippPhpClient\Entities\Account::getFax + * @covers \D3\KlicktippPhpClient\Entities\Account::getAffiliateId + * @covers \D3\KlicktippPhpClient\Entities\Account::getAccessRights + * @covers \D3\KlicktippPhpClient\Entities\Account::getSenders + * @covers \D3\KlicktippPhpClient\Entities\Account::getGmailPreview + * @covers \D3\KlicktippPhpClient\Entities\Account::getLimits + * @covers \D3\KlicktippPhpClient\Entities\Account::getPreferences + * @covers \D3\KlicktippPhpClient\Entities\Account::getSettings + * @covers \D3\KlicktippPhpClient\Entities\Account::canShowOtherAccountInfo + * @covers \D3\KlicktippPhpClient\Entities\Account::canShowSupportInfo + * @covers \D3\KlicktippPhpClient\Entities\Account::getSupport + * @covers \D3\KlicktippPhpClient\Entities\Account::getLanguage + * @covers \D3\KlicktippPhpClient\Entities\Account::getSegments + * @covers \D3\KlicktippPhpClient\Entities\Account::getCustomerData + * @covers \D3\KlicktippPhpClient\Entities\Account::getSubscriptionInfo + * @covers \D3\KlicktippPhpClient\Entities\Account::getActivePayments + * @dataProvider getDataProvider + */ + public function testGetInvalidType(string $testMethod): void + { + $invalidProperties = [ + AccountEndpoint::UID => [], + AccountEndpoint::STATUS => [], + AccountEndpoint::TIER => [], + AccountEndpoint::USERGROUP => [], + AccountEndpoint::USERNAME => [], + AccountEndpoint::EMAIL => [], + AccountEndpoint::FIRSTNAME => [], + AccountEndpoint::LASTNAME => [], + AccountEndpoint::COMPANY => [], + AccountEndpoint::WEBSITE => [], + AccountEndpoint::STREET => [], + AccountEndpoint::CITY => [], + AccountEndpoint::STATE => [], + AccountEndpoint::ZIP => [], + AccountEndpoint::COUNTRY => [], + AccountEndpoint::PHONE => [], + AccountEndpoint::FAX => [], + AccountEndpoint::AFFILIATE_ID => [], + AccountEndpoint::ACCESS_RIGHTS => 'string', + AccountEndpoint::SENDERS => 'string', + AccountEndpoint::GMAIL_PREVIEW => [], + AccountEndpoint::LIMITS => 'string', + AccountEndpoint::PREFERENCES => 'string', + AccountEndpoint::SETTINGS => 'string', + AccountEndpoint::SHOW_OTHER_ACCOUNT_INFO => [], + AccountEndpoint::SHOW_SUPPORT_INFO => [], + AccountEndpoint::SUPPORT => 'string', + AccountEndpoint::LANGUAGE => [], + AccountEndpoint::SEGMENTS => 'string', + AccountEndpoint::CUSTOMER_DATA => 'string', + AccountEndpoint::SUBSCRIPTION_INFO => 'string', + AccountEndpoint::ACTIVE_PAYMENTS => 'string', + ]; + + $sut = new Account($invalidProperties); + + $this->expectException(InvalidCredentialTypeException::class); + + $this->assertNull( + $this->callMethod( + $sut, $testMethod, ) ); @@ -396,4 +540,121 @@ class AccountTest extends TestCase yield 'has endpoint' => [true, self::once(), true]; yield 'has no endpoint' => [false, self::never(), null]; } + + /** + * @test + * @throws ReflectionException + * @covers \D3\KlicktippPhpClient\Entities\Entity::getArrayCollectionFromValue + * @dataProvider getArrayCollectionFromValueDataProvider + */ + public function testGetArrayCollectionFromValue($value, ?ArrayCollection $expected, bool $expectException): void + { + if ($expectException) { + $this->expectException( InvalidCredentialTypeException::class ); + } + + $this->assertEquals( + $expected, + $this->callMethod( + $this->entity, + 'getArrayCollectionFromValue', + [$value] + ) + ); + } + + public static function getArrayCollectionFromValueDataProvider(): Generator + { + yield 'ArrayCollection' => [['foo' => 'bar'], new ArrayCollection(['foo' => 'bar']), false]; + yield 'null' => [null, null, false]; + yield 'wrong type' => ['string', null, true]; + } + + /** + * @test + * @throws ReflectionException + * @covers \D3\KlicktippPhpClient\Entities\Entity::getStringOrNullValue + * @dataProvider getStringOrNullValueDataProvider + */ + public function testGetStringOrNullValue($value, ?string $expected, bool $expectException): void + { + if ($expectException) { + $this->expectException( InvalidCredentialTypeException::class ); + } + + $this->assertEquals( + $expected, + $this->callMethod( + $this->entity, + 'getStringOrNullValue', + [$value] + ) + ); + } + + public static function getStringOrNullValueDataProvider(): Generator + { + yield 'string' => ['foobar', "foobar", false]; + yield 'null' => [null, null, false]; + yield 'wrong type' => [[], null, true]; + } + + /** + * @test + * @throws ReflectionException + * @covers \D3\KlicktippPhpClient\Entities\Entity::getIntOrNullValue + * @dataProvider getIntOrNullValueDataProvider + */ + public function testGetIntOrNullValue($value, ?int $expected, bool $expectException): void + { + if ($expectException) { + $this->expectException( InvalidCredentialTypeException::class ); + } + + $this->assertEquals( + $expected, + $this->callMethod( + $this->entity, + 'getIntOrNullValue', + [$value] + ) + ); + } + + public static function getIntOrNullValueDataProvider(): Generator + { + yield 'int' => [10000, 10000, false]; + yield 'null' => [null, null, false]; + yield 'wrong type' => [[], null, true]; + } + + /** + * @test + * @throws ReflectionException + * @covers \D3\KlicktippPhpClient\Entities\Entity::getBooleanOrNullValue + * @dataProvider getBooleanOrNullValueDataProvider + */ + public function testGetBooleanOrNullValue($value, ?bool $expected, bool $expectException): void + { + if ($expectException) { + $this->expectException( InvalidCredentialTypeException::class ); + } + + $this->assertEquals( + $expected, + $this->callMethod( + $this->entity, + 'getBooleanOrNullValue', + [$value] + ) + ); + } + + public static function getBooleanOrNullValueDataProvider(): Generator + { + yield 'true' => [true, true, false]; + yield 'false' => [false, false, false]; + yield 'null' => [null, null, false]; + yield 'wrong type' => [[], null, true]; + } }