Туча доработок

- класс `PayingAgent`, покрытый тестами
- новые константы для тегов ФФД 1.05 `Ffd105Tags`
- `Entity::jsonSerialize()` object -> array (again)
- `TooManyException::$max` int -> float
- тесты по psr-4, потому что почему бы и нет
- некоторые провайдеры вынесены в `BasicTestCase`
- улучшен тест покупателя
This commit is contained in:
2021-11-24 01:30:54 +08:00
parent b5a01debd2
commit 42d194116f
40 changed files with 622 additions and 192 deletions

View File

@@ -0,0 +1,344 @@
<?php
/*
* Copyright (c) 2020-2021 Антон Аксенов (Anthony Axenov)
*
* This code is licensed under MIT.
* Этот код распространяется по лицензии MIT.
* https://github.com/anthonyaxenov/atol-online/blob/master/LICENSE
*/
namespace AtolOnline\Tests\Api;
use AtolOnline\Api\AtolClient;
use AtolOnline\Api\KktMonitor;
use AtolOnline\Api\KktResponse;
use AtolOnline\Entities\Kkt;
use AtolOnline\Exceptions\AuthFailedException;
use AtolOnline\Exceptions\EmptyLoginException;
use AtolOnline\Exceptions\EmptyMonitorDataException;
use AtolOnline\Exceptions\EmptyPasswordException;
use AtolOnline\Exceptions\NotEnoughMonitorDataException;
use AtolOnline\Exceptions\TooLongLoginException;
use AtolOnline\Exceptions\TooLongPasswordException;
use AtolOnline\Helpers;
use AtolOnline\TestEnvParams;
use AtolOnline\Tests\BasicTestCase;
use GuzzleHttp\Exception\GuzzleException;
/**
* Набор тестов для проверки работы API-клиента на примере монитора ККТ
*/
class KktMonitorTest extends BasicTestCase
{
/**
* Возвращает объект клиента для тестирования с тестовым API АТОЛ
*
* @return KktMonitor
* @throws EmptyLoginException
* @throws EmptyPasswordException
* @throws TooLongLoginException
* @throws TooLongPasswordException
*/
private function newTestClient(): KktMonitor
{
$credentials = TestEnvParams::FFD105();
return (new KktMonitor(true))
->setLogin($credentials['login'])
->setPassword($credentials['password']);
}
/**
* Тестирует успешное создание объекта монитора без аргументов конструктора
*
* @covers \AtolOnline\Api\KktMonitor::__construct
*/
public function testConstructorWithoutArgs(): void
{
$client = new KktMonitor();
$this->assertIsObject($client);
$this->assertIsSameClass(KktMonitor::class, $client);
$this->assertExtendsClasses($client, [AtolClient::class]);
}
/**
* Тестирует успешное создание объекта монитора с аргументами конструктора
*
* @covers \AtolOnline\Api\KktMonitor::__construct
* @covers \AtolOnline\Api\KktMonitor::setLogin
* @covers \AtolOnline\Api\KktMonitor::getLogin
* @covers \AtolOnline\Api\KktMonitor::setPassword
* @covers \AtolOnline\Api\KktMonitor::getPassword
* @throws EmptyLoginException
* @throws EmptyPasswordException
* @throws TooLongLoginException
* @throws TooLongPasswordException
*/
public function testConstructorWithArgs(): void
{
$client = new KktMonitor(false, 'login', 'password', []);
$this->assertIsObject($client);
$this->assertIsSameClass($client, KktMonitor::class);
$this->assertExtendsClasses($client, [AtolClient::class]);
}
/**
* Тестирует установку и возврат логина
*
* @covers \AtolOnline\Api\KktMonitor::__construct
* @covers \AtolOnline\Api\KktMonitor::getLogin
* @covers \AtolOnline\Api\KktMonitor::setLogin
* @throws EmptyLoginException
* @throws TooLongLoginException
*/
public function testLogin(): void
{
$client = new KktMonitor(login: 'login');
$this->assertEquals('login', $client->getLogin());
$client = new KktMonitor();
$this->assertNull($client->getLogin());
$client->setLogin('login');
$this->assertEquals('login', $client->getLogin());
}
/**
* Тестирует исключение при попытке передать пустой логин в конструктор
*
* @covers \AtolOnline\Api\KktMonitor::__construct
* @covers \AtolOnline\Api\KktMonitor::setLogin
* @covers \AtolOnline\Exceptions\EmptyLoginException
*/
public function testEmptyLoginException(): void
{
$this->expectException(EmptyLoginException::class);
new KktMonitor(login: '');
}
/**
* Тестирует исключение при попытке передать слишком длинный логин в конструктор
*
* @covers \AtolOnline\Api\KktMonitor::__construct
* @covers \AtolOnline\Api\KktMonitor::setLogin
* @covers \AtolOnline\Exceptions\TooLongLoginException
* @throws EmptyLoginException
* @throws EmptyPasswordException
* @throws TooLongLoginException
* @throws TooLongPasswordException
*/
public function testTooLongLoginException(): void
{
$this->expectException(TooLongLoginException::class);
new KktMonitor(login: Helpers::randomStr(101));
}
/**
* Тестирует установку и возврат пароля
*
* @covers \AtolOnline\Api\KktMonitor::__construct
* @covers \AtolOnline\Api\KktMonitor::getPassword
* @covers \AtolOnline\Api\KktMonitor::setPassword
* @throws EmptyPasswordException
* @throws TooLongPasswordException
*/
public function testPassword(): void
{
$client = new KktMonitor(password: 'password');
$this->assertEquals('password', $client->getPassword());
$client = new KktMonitor();
$this->assertNull($client->getPassword());
$client->setPassword('password');
$this->assertEquals('password', $client->getPassword());
}
/**
* Тестирует исключение при попытке передать пустой пароль в конструктор
*
* @covers \AtolOnline\Api\KktMonitor::__construct
* @covers \AtolOnline\Api\KktMonitor::setPassword
* @covers \AtolOnline\Exceptions\EmptyPasswordException
*/
public function testEmptyPasswordException(): void
{
$this->expectException(EmptyPasswordException::class);
new KktMonitor(password: '');
}
/**
* Тестирует исключение при попытке передать слишком длинный пароль в конструктор
*
* @covers \AtolOnline\Api\KktMonitor::__construct
* @covers \AtolOnline\Api\KktMonitor::setPassword
* @throws EmptyLoginException
* @throws EmptyPasswordException
* @throws TooLongLoginException
* @throws TooLongPasswordException
*/
public function testConstructorWithLongPassword(): void
{
$this->expectException(TooLongPasswordException::class);
new KktMonitor(password: Helpers::randomStr(101));
}
/**
* Тестирует установку тестового режима
*
* @covers \AtolOnline\Api\KktMonitor::__construct
* @covers \AtolOnline\Api\KktMonitor::isTestMode
* @covers \AtolOnline\Api\KktMonitor::setTestMode
*/
public function testTestMode(): void
{
$client = new KktMonitor();
$this->assertTrue($client->isTestMode());
$client = new KktMonitor(true);
$this->assertTrue($client->isTestMode());
$client = new KktMonitor(false);
$this->assertFalse($client->isTestMode());
$client = (new KktMonitor())->setTestMode();
$this->assertTrue($client->isTestMode());
$client = (new KktMonitor())->setTestMode(true);
$this->assertTrue($client->isTestMode());
$client = (new KktMonitor())->setTestMode(false);
$this->assertFalse($client->isTestMode());
}
/**
* Тестирует авторизацию
*
* @covers \AtolOnline\Api\AtolClient::getHeaders
* @covers \AtolOnline\Api\KktMonitor::sendRequest
* @covers \AtolOnline\Api\KktMonitor::getAuthEndpoint
* @covers \AtolOnline\Api\KktMonitor::doAuth
* @covers \AtolOnline\Api\KktMonitor::auth
* @covers \AtolOnline\Exceptions\AuthFailedException
* @throws EmptyLoginException
* @throws EmptyPasswordException
* @throws TooLongLoginException
* @throws TooLongPasswordException
* @throws AuthFailedException
* @throws GuzzleException
*/
public function testAuth(): void
{
$this->skipIfMonitoringIsOffline();
$result = $this->newTestClient()->auth();
$this->assertTrue($result);
}
/**
* Тестирует возврат токена после авторизации
*
* @depends testAuth
* @covers \AtolOnline\Api\KktMonitor::setToken
* @covers \AtolOnline\Api\KktMonitor::getToken
* @covers \AtolOnline\Exceptions\AuthFailedException
* @throws AuthFailedException
* @throws EmptyLoginException
* @throws EmptyPasswordException
* @throws GuzzleException
* @throws TooLongLoginException
* @throws TooLongPasswordException
*/
public function testGetToken(): void
{
$client = new KktMonitor();
$this->assertNull($client->getToken());
$this->skipIfMonitoringIsOffline();
$client = $this->newTestClient();
$client->auth();
$this->assertIsString($client->getToken());
}
/**
* Тестирует возврат объекта последнего ответа от API
*
* @depends testAuth
* @covers \AtolOnline\Api\KktMonitor::getResponse
* @covers \AtolOnline\Exceptions\AuthFailedException
* @throws AuthFailedException
* @throws EmptyLoginException
* @throws EmptyPasswordException
* @throws GuzzleException
* @throws TooLongLoginException
* @throws TooLongPasswordException
*/
public function testGetResponse(): void
{
$this->skipIfMonitoringIsOffline();
$client = $this->newTestClient();
$client->auth();
$this->assertIsSameClass(KktResponse::class, $client->getResponse());
}
/**
* [Мониторинг] Тестирует получение данных о всех ККТ
*
* @depends testAuth
* @covers \AtolOnline\Api\KktMonitor::getMainEndpoint
* @covers \AtolOnline\Api\AtolClient::getUrlToMethod
* @covers \AtolOnline\Api\KktMonitor::fetchAll
* @covers \AtolOnline\Api\KktMonitor::getAll
* @covers \AtolOnline\Exceptions\AuthFailedException
* @throws AuthFailedException
* @throws EmptyLoginException
* @throws EmptyPasswordException
* @throws GuzzleException
* @throws TooLongLoginException
* @throws TooLongPasswordException
*/
public function testMonitorGetAll(): void
{
$this->skipIfMonitoringIsOffline();
$client = $this->newTestClient();
$client->auth();
$kkts = $client->getAll();
$this->assertNotEmpty($client->getResponse()->getContent());
$this->assertIsCollection($kkts);
$this->assertTrue($kkts->count() > 0);
$this->assertIsSameClass(Kkt::class, $kkts->random());
}
/**
* [Мониторинг] Тестирует получение данных о конкретной ККТ
*
* @depends testAuth
* @covers \AtolOnline\Api\KktMonitor::getMainEndpoint
* @covers \AtolOnline\Api\AtolClient::getUrlToMethod
* @covers \AtolOnline\Api\KktMonitor::fetchOne
* @covers \AtolOnline\Api\KktMonitor::getOne
* @covers \AtolOnline\Entities\Kkt::__construct
* @covers \AtolOnline\Entities\Kkt::__get
* @covers \AtolOnline\Entities\Kkt::jsonSerialize
* @covers \AtolOnline\Entities\Kkt::__toString
* @throws AuthFailedException
* @throws EmptyLoginException
* @throws EmptyPasswordException
* @throws GuzzleException
* @throws TooLongLoginException
* @throws TooLongPasswordException
* @throws EmptyMonitorDataException
* @throws NotEnoughMonitorDataException
*/
public function testMonitorGetOne(): void
{
$this->skipIfMonitoringIsOffline();
$client = $this->newTestClient();
$client->auth();
$serial_number = $client->getAll()->first()->serialNumber;
$kkt = $client->getOne($serial_number);
$this->assertNotEmpty($client->getResponse());
$this->assertIsSameClass(Kkt::class, $kkt);
$this->assertAtolable($kkt);
$this->assertNotNull($kkt->serialNumber);
$this->assertEquals($serial_number, $kkt->serialNumber);
}
}

View File

@@ -0,0 +1,225 @@
<?php
/*
* Copyright (c) 2020-2021 Антон Аксенов (Anthony Axenov)
*
* This code is licensed under MIT.
* Этот код распространяется по лицензии MIT.
* https://github.com/anthonyaxenov/atol-online/blob/master/LICENSE
*/
declare(strict_types = 1);
namespace AtolOnline\Tests;
use AtolOnline\Entities\Entity;
use AtolOnline\Helpers;
use GuzzleHttp\Client;
use GuzzleHttp\Exception\GuzzleException;
use Illuminate\Support\Collection;
use PHPUnit\Framework\TestCase;
/**
* Базовый класс для тестов
*/
class BasicTestCase extends TestCase
{
/**
* Проверяет наличие подключения к ресурсу по URL
*
* @param string $url
* @param int $code
* @return bool
*/
protected function ping(string $url, int $code): bool
{
try {
$result = (new Client([
'http_errors' => false,
'timeout' => 3,
]))->request('GET', $url);
} catch (GuzzleException) {
return false;
}
return $result->getStatusCode() === $code;
}
/**
* Проверяет доступность API мониторинга
*
* @return bool
*/
protected function isMonitoringOnline(): bool
{
return $this->ping('https://testonline.atol.ru/api/auth/v1/gettoken', 400);
}
/**
* Пропускает текущий тест если API мониторинга недоступен
*/
protected function skipIfMonitoringIsOffline(): void
{
if (!$this->isMonitoringOnline()) {
$this->markTestSkipped($this->getName() . ': Monitoring API is inaccessible. Skipping test.');
}
}
/**
* Тестирует является ли объект приводимым к json-строке согласно схеме АТОЛ Онлайн
*
* @param Entity $entity
* @param array $json_structure
* @covers \AtolOnline\Entities\Entity::jsonSerialize
* @covers \AtolOnline\Entities\Entity::__toString
*/
public function assertAtolable(Entity $entity, array $json_structure = []): void
{
$this->assertIsArray($entity->jsonSerialize());
$this->assertIsString((string)$entity);
$this->assertJson((string)$entity);
if ($json_structure) {
$this->assertEquals(json_encode($json_structure), (string)$entity);
}
}
/**
* Тестирует идентичность двух классов
*
* @param object|string $expected
* @param object|string $actual
*/
public function assertIsSameClass(object|string $expected, object|string $actual): void
{
$this->assertTrue(Helpers::isSameClass($expected, $actual));
}
/**
* Тестирует наследование класса (объекта) от указанных классов
*
* @param object|string $class
* @param string[] $parents
*/
public function assertExtendsClasses(object|string $class, array $parents): void
{
$this->assertTrue(Helpers::checkExtendsClasses($class, $parents));
}
/**
* Тестирует имплементацию классом (объектом) указанных интерфейсов
*
* @param object|string $class
* @param string[] $interfaces
*/
public function assertImplementsInterfaces(object|string $class, array $interfaces): void
{
$this->assertTrue(Helpers::checkImplementsInterfaces($class, $interfaces));
}
/**
* Тестирует использование классом (объектом) указанных трейтов
*
* @param object|string $class
* @param string[] $traits
*/
public function assertUsesTraits(object|string $class, array $traits): void
{
$this->assertTrue(Helpers::checkUsesTraits($traits, $class));
}
/**
* Тестирует, является ли объект коллекцией
*
* @param mixed $expected
*/
public function assertIsCollection(mixed $expected): void
{
$this->assertIsObject($expected);
$this->assertIsIterable($expected);
$this->assertIsSameClass($expected, Collection::class);
}
//------------------------------------------------------------------------------------------------------------------
/**
* Провайдер строк, которые приводятся к null
*
* @return array<array<string|null>>
*/
public function providerNullableStrings(): array
{
return [
[''],
[' '],
[null],
["\n\r\t"],
];
}
/**
* Провайдер валидных телефонов
*
* @return array<array<string, string>>
*/
public function providerValidPhones(): array
{
return [
['+79991234567', '+79991234567'],
['79991234567', '+79991234567'],
['89991234567', '+89991234567'],
['+7 999 123 45 67', '+79991234567'],
['+7 (999) 123-45-67', '+79991234567'],
["+7 %(?9:9\"9')abc\r123\n45\t67\0", '+79991234567'],
];
}
/**
* Провайдер телефонов, которые приводятся к null
*
* @return array<array<string>>
*/
public function providerNullablePhones(): array
{
return array_merge(
$this->providerNullableStrings(),
[
[Helpers::randomStr(10, false)],
["asdfgvs \n\rtt\t*/(*&%^*$%"],
]
);
}
/**
* Провайдер валидных email-ов
*
* @return array<array<string>>
*/
public function providerValidEmails(): array
{
return [
['abc@mail.com'],
['abc-d@mail.com'],
['abc.def@mail.com'],
['abc.def@mail.org'],
['abc.def@mail-archive.com'],
];
}
/**
* Провайдер невалидных email-ов
*
* @return array<array<string>>
*/
public function providerInvalidEmails(): array
{
return [
['@example'],
[Helpers::randomStr(15)],
['@example.com'],
['abc.def@mail'],
['.abc@mail.com'],
['example@example'],
['abc..def@mail.com'],
['abc.def@mail..com'],
['abc.def@mail#archive.com'],
];
}
}

View File

@@ -0,0 +1,254 @@
<?php
/*
* Copyright (c) 2020-2021 Антон Аксенов (Anthony Axenov)
*
* This code is licensed under MIT.
* Этот код распространяется по лицензии MIT.
* https://github.com/anthonyaxenov/atol-online/blob/master/LICENSE
*/
namespace AtolOnline\Tests\Entities;
use AtolOnline\{
Entities\Client,
Exceptions\InvalidEmailException,
Exceptions\InvalidInnLengthException,
Exceptions\TooLongClientContactException,
Exceptions\TooLongClientNameException,
Exceptions\TooLongEmailException,
Helpers,
Tests\BasicTestCase
};
/**
* Набор тестов для проверки работы класса покупателя
*/
class ClientTest extends BasicTestCase
{
/**
* Тестирует конструктор без передачи значений и приведение к json
*
* @covers \AtolOnline\Entities\Client
* @covers \AtolOnline\Entities\Client::jsonSerialize
*/
public function testConstructorWithoutArgs(): void
{
$this->assertEquals('[]', (string)(new Client()));
}
/**
* Тестирует конструктор с передачей значений и приведение к json
*
* @covers \AtolOnline\Entities\Client
* @covers \AtolOnline\Entities\Client::jsonSerialize
* @covers \AtolOnline\Entities\Client::setName
* @covers \AtolOnline\Entities\Client::setPhone
* @covers \AtolOnline\Entities\Client::setEmail
* @covers \AtolOnline\Entities\Client::setInn
* @covers \AtolOnline\Entities\Client::getName
* @covers \AtolOnline\Entities\Client::getPhone
* @covers \AtolOnline\Entities\Client::getEmail
* @covers \AtolOnline\Entities\Client::getInn
*/
public function testConstructorWithArgs(): void
{
$this->assertAtolable(new Client('John Doe'), ['name' => 'John Doe']);
$this->assertAtolable(new Client(email: 'john@example.com'), ['email' => 'john@example.com']);
$this->assertAtolable(new Client(phone: '+1/22/99*73s dsdas654 5s6'), ['phone' => '+122997365456']);
$this->assertAtolable(new Client(inn: '+fasd3\qe3fs_=nac99013928czc'), ['inn' => '3399013928']);
$this->assertAtolable(new Client(
'John Doe',
'john@example.com',
'+1/22/99*73s dsdas654 5s6', // +122997365456
'+fasd3\qe3fs_=nac99013928czc' // 3399013928
), [
'name' => 'John Doe',
'email' => 'john@example.com',
'phone' => '+122997365456',
'inn' => '3399013928',
]);
}
/**
* Тестирует установку имён, которые приводятся к null
*
* @param mixed $name
* @dataProvider providerNullableStrings
* @covers \AtolOnline\Entities\Client
* @covers \AtolOnline\Entities\Client::setName
* @covers \AtolOnline\Entities\Client::getName
* @throws TooLongClientNameException
*/
public function testNullableNames(mixed $name): void
{
$this->assertNull((new Client())->setName($name)->getName());
}
/**
* Тестирует установку валидного имени
*
* @covers \AtolOnline\Entities\Client
* @covers \AtolOnline\Entities\Client::setName
* @covers \AtolOnline\Entities\Client::getName
* @throws TooLongClientNameException
*/
public function testValidName(): void
{
$name = Helpers::randomStr();
$this->assertEquals($name, (new Client())->setName($name)->getName());
}
/**
* Тестирует установку невалидного имени
*
* @covers \AtolOnline\Entities\Client
* @covers \AtolOnline\Entities\Client::setName
* @covers \AtolOnline\Exceptions\TooLongClientNameException
*/
public function testInvalidName(): void
{
$this->expectException(TooLongClientNameException::class);
(new Client())->setName(Helpers::randomStr(400));
}
//------------------------------------------------------------------------------------------------------------------
/**
* Тестирует установку телефонов, которые приводятся к null
*
* @param mixed $phone
* @dataProvider providerNullablePhones
* @covers \AtolOnline\Entities\Client
* @covers \AtolOnline\Entities\Client::setPhone
* @covers \AtolOnline\Entities\Client::getPhone
* @throws TooLongClientContactException
*/
public function testNullablePhones(mixed $phone): void
{
$this->assertNull((new Client())->setPhone($phone)->getPhone());
}
/**
* Тестирует установку валидного телефона
*
* @todo актуализировать при доработатанной валидации
* @dataProvider providerValidPhones
* @covers \AtolOnline\Entities\Client
* @covers \AtolOnline\Entities\Client::setPhone
* @covers \AtolOnline\Entities\Client::getPhone
* @throws TooLongClientContactException
*/
public function testValidPhone(string $input, string $output): void
{
$this->assertEquals($output, (new Client())->setPhone($input)->getPhone());
}
/**
* Тестирует установку невалидного телефона
*
* @todo актуализировать при доработатанной валидации
* @covers \AtolOnline\Entities\Client
* @covers \AtolOnline\Entities\Client::setPhone
* @covers \AtolOnline\Exceptions\TooLongClientContactException
* @throws TooLongClientContactException
*/
public function testTooLongClientPhone(): void
{
$this->expectException(TooLongClientContactException::class);
(new Client())->setPhone('99999999999999999999999999999999999999999999999999999999999999999999999999');
}
//------------------------------------------------------------------------------------------------------------------
/**
* Тестирует установку валидных email-ов
*
* @param mixed $email
* @dataProvider providerValidEmails
* @covers \AtolOnline\Entities\Client
* @covers \AtolOnline\Entities\Client::setEmail
* @covers \AtolOnline\Entities\Client::getEmail
* @throws TooLongEmailException
* @throws InvalidEmailException
*/
public function testValidEmails(mixed $email): void
{
$this->assertEquals($email, (new Client())->setEmail($email)->getEmail());
}
/**
* Тестирует установку слишком длинного email
*
* @covers \AtolOnline\Entities\Client
* @covers \AtolOnline\Entities\Client::setEmail
* @covers \AtolOnline\Exceptions\TooLongEmailException
* @throws TooLongEmailException
* @throws InvalidEmailException
*/
public function testTooLongEmail(): void
{
$this->expectException(TooLongEmailException::class);
(new Client())->setEmail(Helpers::randomStr(65));
}
/**
* Тестирует установку невалидного email
*
* @param mixed $email
* @dataProvider providerInvalidEmails
* @covers \AtolOnline\Entities\Client
* @covers \AtolOnline\Entities\Client::setEmail
* @covers \AtolOnline\Exceptions\InvalidEmailException
* @throws TooLongEmailException
* @throws InvalidEmailException
*/
public function testInvalidEmail(mixed $email): void
{
$this->expectException(InvalidEmailException::class);
(new Client())->setEmail($email);
}
//------------------------------------------------------------------------------------------------------------------
/**
* Тестирует исключение о корректной длине ИНН
*
* @covers \AtolOnline\Entities\Client
* @covers \AtolOnline\Entities\Client::setInn
* @covers \AtolOnline\Entities\Client::getInn
* @throws InvalidInnLengthException
*/
public function testValidInn(): void
{
$this->assertEquals('1234567890', (new Client())->setInn('1234567890')->getInn());
$this->assertEquals('123456789012', (new Client())->setInn('123456789012')->getInn());
}
/**
* Тестирует исключение о некорректной длине ИНН (10 цифр)
*
* @covers \AtolOnline\Entities\Client
* @covers \AtolOnline\Entities\Client::setInn
* @covers \AtolOnline\Exceptions\InvalidInnLengthException
* @throws InvalidInnLengthException
*/
public function testInvalidInn10(): void
{
$this->expectException(InvalidInnLengthException::class);
(new Client())->setInn('12345678901');
}
/**
* Тестирует исключение о некорректной длине ИНН (12 цифр)
*
* @covers \AtolOnline\Entities\Client
* @covers \AtolOnline\Entities\Client::setInn
* @covers \AtolOnline\Exceptions\InvalidInnLengthException
* @throws InvalidInnLengthException
*/
public function testInvalidInn12(): void
{
$this->expectException(InvalidInnLengthException::class);
(new Client())->setInn('1234567890123');
}
}

View File

@@ -0,0 +1,136 @@
<?php
/*
* Copyright (c) 2020-2021 Антон Аксенов (Anthony Axenov)
*
* This code is licensed under MIT.
* Этот код распространяется по лицензии MIT.
* https://github.com/anthonyaxenov/atol-online/blob/master/LICENSE
*/
namespace AtolOnline\Tests\Entities;
use AtolOnline\{
Entities\Company,
Enums\SnoTypes,
Exceptions\InvalidEmailException,
Exceptions\InvalidEnumValueException,
Exceptions\InvalidInnLengthException,
Exceptions\InvalidPaymentAddressException,
Exceptions\TooLongEmailException,
Exceptions\TooLongPaymentAddressException,
Helpers,
Tests\BasicTestCase
};
/**
* Набор тестов для проверки работы класс продавца
*/
class CompanyTest extends BasicTestCase
{
/**
* Тестирует конструктор с сеттерами и приведение к json с геттерами
*
* @covers \AtolOnline\Entities\Company
* @covers \AtolOnline\Entities\Company::jsonSerialize
* @covers \AtolOnline\Entities\Company::setEmail
* @covers \AtolOnline\Entities\Company::setSno
* @covers \AtolOnline\Entities\Company::setInn
* @covers \AtolOnline\Entities\Company::setPaymentAddress
* @covers \AtolOnline\Entities\Company::getEmail
* @covers \AtolOnline\Entities\Company::getSno
* @covers \AtolOnline\Entities\Company::getInn
* @covers \AtolOnline\Entities\Company::getPaymentAddress
*/
public function testConstructor()
{
$this->assertAtolable(new Company(
$email = 'company@example.com',
$sno = SnoTypes::OSN,
$inn = '1234567890',
$payment_address = 'https://example.com',
), [
'email' => $email,
'sno' => $sno,
'inn' => $inn,
'payment_address' => $payment_address,
]);
}
/**
* Тестирует исключение о слишком длинном email
*
* @covers \AtolOnline\Entities\Company
* @covers \AtolOnline\Entities\Company::setEmail
* @covers \AtolOnline\Exceptions\TooLongEmailException
*/
public function testEmailTooLongException()
{
$this->expectException(TooLongEmailException::class);
new Company(Helpers::randomStr(65), SnoTypes::OSN, '1234567890', 'https://example.com');
}
/**
* Тестирует исключение о невалидном email
*
* @covers \AtolOnline\Entities\Company
* @covers \AtolOnline\Entities\Company::setEmail
* @covers \AtolOnline\Exceptions\InvalidEmailException
*/
public function testInvalidEmailException()
{
$this->expectException(InvalidEmailException::class);
new Company('company@examas%^*.com', SnoTypes::OSN, '1234567890', 'https://example.com');
}
/**
* Тестирует исключение о слишком длинном платёжном адресе
*
* @covers \AtolOnline\Entities\Company
* @covers \AtolOnline\Entities\Company::setSno
* @covers \AtolOnline\Exceptions\InvalidEnumValueException
*/
public function testInvalidSnoException()
{
$this->expectException(InvalidEnumValueException::class);
new Company('company@example.com', 'test', '1234567890', 'https://example.com');
}
/**
* Тестирует исключение о слишком длинном платёжном адресе
*
* @covers \AtolOnline\Entities\Company
* @covers \AtolOnline\Entities\Company::setInn
* @covers \AtolOnline\Exceptions\InvalidInnLengthException
*/
public function testInvalidInnLengthException()
{
$this->expectException(InvalidInnLengthException::class);
new Company('company@example.com', SnoTypes::OSN, Helpers::randomStr(13), 'https://example.com');
}
/**
* Тестирует исключение о слишком длинном платёжном адресе
*
* @covers \AtolOnline\Entities\Company
* @covers \AtolOnline\Entities\Company::setPaymentAddress
* @covers \AtolOnline\Exceptions\TooLongPaymentAddressException
*/
public function testTooLongPaymentAddressException()
{
$this->expectException(TooLongPaymentAddressException::class);
new Company('company@example.com', SnoTypes::OSN, '1234567890', Helpers::randomStr(257));
}
/**
* Тестирует исключение о невалидном платёжном адресе
*
* @covers \AtolOnline\Entities\Company
* @covers \AtolOnline\Entities\Company::setPaymentAddress
* @covers \AtolOnline\Exceptions\InvalidPaymentAddressException
*/
public function testInvalidPaymentAddressException()
{
$this->expectException(InvalidPaymentAddressException::class);
new Company('company@example.com', SnoTypes::OSN, '1234567890', '');
}
}

View File

@@ -0,0 +1,137 @@
<?php
/*
* Copyright (c) 2020-2021 Антон Аксенов (Anthony Axenov)
*
* This code is licensed under MIT.
* Этот код распространяется по лицензии MIT.
* https://github.com/anthonyaxenov/atol-online/blob/master/LICENSE
*/
declare(strict_types = 1);
namespace AtolOnline\Tests\Entities;
use AtolOnline\Entities\Kkt;
use AtolOnline\Exceptions\EmptyMonitorDataException;
use AtolOnline\Exceptions\NotEnoughMonitorDataException;
use AtolOnline\Tests\BasicTestCase;
use DateTime;
use Exception;
class KktEntityTest extends BasicTestCase
{
/**
* @var array Данные для создания объекта ККТ
*/
private array $sample_data = [
'serialNumber' => '00107703864827',
'registrationNumber' => '0000000003027865',
'deviceNumber' => 'KKT024219',
'fiscalizationDate' => '2019-07-22T14:03:00+00:00',
'fiscalStorageExpiration' => '2020-11-02T21:00:00+00:00',
'signedDocuments' => 213350,
'fiscalStoragePercentageUse' => 85.34,
'fiscalStorageINN' => '3026455760',
'fiscalStorageSerialNumber' => '9999078902004339',
'fiscalStoragePaymentAddress' => 'test.qa.ru',
'groupCode' => 'test-qa-ru_14605',
'timestamp' => '2019-12-05T10:45:30+00:00',
'isShiftOpened' => true,
'shiftNumber' => 126,
'shiftReceipt' => 2278,
//'unsentDocs' => 123,
'firstUnsetDocTimestamp' => 'there must be timestamp, but we want to get exception here to get string',
'networkErrorCode' => 2,
];
/**
* Тестирует создание объекта ККТ с валидными данными
*
* @covers \AtolOnline\Entities\Kkt::__construct
* @covers \AtolOnline\Entities\Kkt::__get
* @covers \AtolOnline\Entities\Kkt::jsonSerialize
* @covers \AtolOnline\Entities\Kkt::__toString
* @throws Exception
*/
public function testConstructor(): void
{
$kkt = new Kkt((object)$this->sample_data);
$this->assertIsSameClass(Kkt::class, $kkt);
$this->assertAtolable($kkt);
}
/**
* Тестирует исключение при попытке создать объект ККТ без данных от монитора
*
* @covers \AtolOnline\Entities\Kkt::__construct
* @covers \AtolOnline\Exceptions\EmptyMonitorDataException
* @throws EmptyMonitorDataException
* @throws NotEnoughMonitorDataException
*/
public function testEmptyMonitorDataException(): void
{
$this->expectException(EmptyMonitorDataException::class);
new Kkt((object)[]);
}
/**
* Тестирует исключение при попытке создать объект ККТ без данных от монитора
*
* @covers \AtolOnline\Entities\Kkt::__construct
* @covers \AtolOnline\Exceptions\NotEnoughMonitorDataException
* @throws EmptyMonitorDataException
* @throws NotEnoughMonitorDataException
*/
public function testNotEnoughMonitorDataException(): void
{
$this->expectException(NotEnoughMonitorDataException::class);
new Kkt((object)[
'fiscalizationDate' => '2021-11-20T10:21:00+00:00',
]);
}
/**
* Тестирует получение атрибутов через магический геттер
*
* @covers \AtolOnline\Entities\Kkt::__get
* @throws EmptyMonitorDataException
* @throws NotEnoughMonitorDataException
*/
public function testMagicGetter(): void
{
$kkt = new Kkt((object)$this->sample_data);
// string
$this->assertNotNull($kkt->serialNumber);
$this->assertIsString($kkt->serialNumber);
$this->assertEquals($this->sample_data['serialNumber'], $kkt->serialNumber);
// int
$this->assertNotNull($kkt->signedDocuments);
$this->assertIsInt($kkt->signedDocuments);
// float
$this->assertNotNull($kkt->signedDocuments);
$this->assertIsFloat($kkt->fiscalStoragePercentageUse);
// null
$this->assertNull($kkt->unsentDocs);
// DateTime
$this->assertNotNull($kkt->fiscalizationDate);
$this->assertIsSameClass(DateTime::class, $kkt->fiscalizationDate);
}
/**
* Тестирует исключение при попытке получить некорректный DateTime через магический геттер
*
* @covers \AtolOnline\Entities\Kkt::__get
* @throws EmptyMonitorDataException
* @throws NotEnoughMonitorDataException
*/
public function testDateTimeException(): void
{
$this->expectException(Exception::class);
(new Kkt((object)$this->sample_data))->firstUnsetDocTimestamp;
}
}

View File

@@ -0,0 +1,145 @@
<?php
/*
* Copyright (c) 2020-2021 Антон Аксенов (Anthony Axenov)
*
* This code is licensed under MIT.
* Этот код распространяется по лицензии MIT.
* https://github.com/anthonyaxenov/atol-online/blob/master/LICENSE
*/
namespace AtolOnline\Tests\Entities;
use AtolOnline\{
Entities\PayingAgent,
Exceptions\InvalidPhoneException,
Exceptions\TooLongPayingAgentOperationException,
Helpers,
Tests\BasicTestCase
};
/**
* Набор тестов для проверки работы класса платёжного агента
*/
class PayingAgentTest extends BasicTestCase
{
/**
* Тестирует конструктор без передачи значений и корректное приведение к json
*
* @covers \AtolOnline\Entities\PayingAgent
* @covers \AtolOnline\Entities\PayingAgent::jsonSerialize
*/
public function testConstructorWithoutArgs(): void
{
$this->assertEquals('[]', (string)(new PayingAgent()));
}
/**
* Тестирует конструктор с передачей значений и корректное приведение к json
*
* @covers \AtolOnline\Entities\PayingAgent
* @covers \AtolOnline\Entities\PayingAgent::jsonSerialize
* @covers \AtolOnline\Entities\PayingAgent::setOperation
* @covers \AtolOnline\Entities\PayingAgent::setPhones
* @covers \AtolOnline\Entities\PayingAgent::getOperation
* @covers \AtolOnline\Entities\PayingAgent::getPhones
* @throws InvalidPhoneException
* @throws TooLongPayingAgentOperationException
*/
public function testConstructorWithArgs(): void
{
$operation = Helpers::randomStr();
$this->assertAtolable(new PayingAgent(
$operation,
['+122997365456'],
), [
'operation' => $operation,
'phones' => ['+122997365456'],
]);
$this->assertAtolable(
new PayingAgent($operation),
['operation' => $operation]
);
$this->assertAtolable(
new PayingAgent(phones: ['+122997365456']),
['phones' => ['+122997365456']]
);
}
/**
* Тестирует установку операций, которые приводятся к null
*
* @param mixed $name
* @dataProvider providerNullableStrings
* @covers \AtolOnline\Entities\PayingAgent
* @covers \AtolOnline\Entities\PayingAgent::setOperation
* @covers \AtolOnline\Entities\PayingAgent::getOperation
* @throws TooLongPayingAgentOperationException
*/
public function testNullableOperations(mixed $name): void
{
$this->assertNull((new PayingAgent())->setOperation($name)->getOperation());
}
/**
* Тестирует установку невалидного имени покупателя
*
* @covers \AtolOnline\Entities\PayingAgent
* @covers \AtolOnline\Entities\PayingAgent::setOperation
* @covers \AtolOnline\Exceptions\TooLongPayingAgentOperationException
*/
public function testTooLongPayingAgentOperationException(): void
{
$this->expectException(TooLongPayingAgentOperationException::class);
(new PayingAgent())->setOperation(Helpers::randomStr(25));
}
/**
* Провайдер массивов телефонов, которые приводятся к null
*
* @return array<array<mixed>>
*/
public function providerNullablePhonesArrays(): array
{
return [
[[]],
[null],
[collect()],
];
}
/**
* Тестирует установку пустых телефонов
*
* @dataProvider providerNullablePhonesArrays
* @covers \AtolOnline\Entities\PayingAgent
* @covers \AtolOnline\Entities\PayingAgent::setPhones
* @covers \AtolOnline\Entities\PayingAgent::getPhones
* @throws InvalidPhoneException
* @throws TooLongPayingAgentOperationException
*/
public function testNullablePhones(mixed $phones): void
{
$agent = new PayingAgent(phones: $phones);
$this->assertIsCollection($agent->getPhones());
$this->assertTrue($agent->getPhones()->isEmpty());
}
/**
* Тестирует установку невалидных телефонов
*
* @covers \AtolOnline\Entities\PayingAgent
* @covers \AtolOnline\Entities\PayingAgent::setPhones
* @covers \AtolOnline\Exceptions\InvalidPhoneException
* @throws InvalidPhoneException
*/
public function testInvalidPhoneException(): void
{
$this->expectException(InvalidPhoneException::class);
(new PayingAgent())->setPhones([
'12345678901234567', // good
'+123456789012345678', // good
'12345678901234567890', // bad
'+12345678901234567890', // bad
]);
}
}

View File

@@ -0,0 +1,123 @@
<?php
/*
* Copyright (c) 2020-2021 Антон Аксенов (Anthony Axenov)
*
* This code is licensed under MIT.
* Этот код распространяется по лицензии MIT.
* https://github.com/anthonyaxenov/atol-online/blob/master/LICENSE
*/
namespace AtolOnline\Tests;
use AtolOnline\Helpers;
/**
* Набор тестов для проверки работы функций-хелперов
*/
class HelpersTest extends BasicTestCase
{
/**
* Провайдер копеек для перевода в рубли
*
* @return array<array<int|null, float>>
*/
public function providerKopeksToRubles(): array
{
return [
[null, 0],
[0, 0],
[1, 0.01],
[12, 0.12],
[123, 1.23],
[1234, 12.34],
[12345, 123.45],
[-1, 0.01],
[-12, 0.12],
[-123, 1.23],
[-1234, 12.34],
[-12345, 123.45],
];
}
/**
* Провайдер рублей для перевода в копейки
*
* @return array<array<float|null, int>>
*/
public function providerRublesToKopeks(): array
{
return [
[null, 0],
[0, 0],
[0.01, 1],
[0.12, 12],
[1.23, 123],
[12.34, 1234],
[123.45, 12345],
[-0.01, 1],
[-0.12, 12],
[-1.23, 123],
[-12.34, 1234],
[-123.45, 12345],
];
}
/**
* Провайдер для тестирования генерации рандомной строки
*
* @return array<array<int, int>>
*/
public function providerRandomStr(): array
{
return [
[0, 0],
[1, 1],
[5, 5],
[-1, 1],
[-5, 5],
];
}
//------------------------------------------------------------------------------------------------------------------
/**
* Тестирует перевод копеек в рубли
*
* @dataProvider providerKopeksToRubles
* @covers \AtolOnline\Helpers::KopToRub
*/
public function testKopeksToRubles(?int $kopeks, float $rubles): void
{
$result = Helpers::KopToRub($kopeks);
$this->assertIsFloat($result);
$this->assertEquals($result, $rubles);
}
/**
* Тестирует перевод копеек в рубли
*
* @dataProvider providerRublesToKopeks
* @covers \AtolOnline\Helpers::RubToKop
*/
public function testRublesToKopeks(?float $rubles, int $kopeks): void
{
$result = Helpers::RubToKop($rubles);
$this->assertIsInt($result);
$this->assertEquals($result, $kopeks);
}
/**
* Тестирует длину рандомной строки
*
* @param int $input
* @param int $output
* @dataProvider providerRandomStr
*/
public function testRandomString(int $input, int $output): void
{
$result = Helpers::randomStr($input);
$this->assertIsString($result);
$this->assertEquals($output, strlen($result));
// тестировать на наличие цифр быссмысленно
}
}