148 lines
5.1 KiB
PHP
148 lines
5.1 KiB
PHP
<?php
|
|
|
|
namespace Tests\Unit;
|
|
|
|
use App\Repositories\AccountRateRepository;
|
|
use PHPUnit\Framework\TestCase;
|
|
use ReflectionClass;
|
|
use Services\Database;
|
|
use Services\DataBase\Classes\PdoConnection;
|
|
use Services\DataBase\Classes\Profiler;
|
|
use System\Classes\Config;
|
|
use System\Classes\MyException;
|
|
use System\Classes\Repository;
|
|
|
|
/**
|
|
* AccountRateRepository жёстко привязан к боевой таблице account_rates конструктором — для
|
|
* тестов подменяем её на временную (тот же приём, что и в BudgetRepositoryTest/CategoryRepositoryTest:
|
|
* прямой вызов Repository::__construct(), минуя AccountRateRepository::__construct()).
|
|
*/
|
|
class AccountRateRepositoryTestDouble extends AccountRateRepository
|
|
{
|
|
public function __construct(?string $connection = null)
|
|
{
|
|
Repository::__construct('account_rate_repository_test_rates', connection: $connection);
|
|
}
|
|
}
|
|
|
|
class AccountRateRepositoryTest extends TestCase
|
|
{
|
|
private PdoConnection $connection;
|
|
private AccountRateRepositoryTestDouble $repository;
|
|
|
|
protected function setUp(): void
|
|
{
|
|
$config = Config::get('db', 'default') ?? [];
|
|
$this->connection = new PdoConnection($config);
|
|
|
|
try {
|
|
$this->connection->pdo();
|
|
} catch (MyException $e) {
|
|
$this->markTestSkipped('Нет живого подключения к MariaDB (заполните App/config/config.local.php): ' . $e->getMessage());
|
|
}
|
|
|
|
$this->connection->exec('DROP TABLE IF EXISTS account_rate_repository_test_rates');
|
|
|
|
$this->connection->exec(
|
|
'CREATE TABLE account_rate_repository_test_rates (
|
|
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
|
|
account_id INT UNSIGNED NOT NULL,
|
|
rate_percent DECIMAL(5,2) NOT NULL,
|
|
valid_from DATE NOT NULL,
|
|
valid_to DATE NULL
|
|
)'
|
|
);
|
|
|
|
$this->repository = new AccountRateRepositoryTestDouble();
|
|
}
|
|
|
|
protected function tearDown(): void
|
|
{
|
|
Profiler::reset();
|
|
|
|
if (isset($this->connection)) {
|
|
try {
|
|
$this->connection->exec('DROP TABLE IF EXISTS account_rate_repository_test_rates');
|
|
} catch (MyException) {
|
|
}
|
|
}
|
|
|
|
// Database::instance() кэширует подключение статически — сбрасываем между тестами
|
|
$ref = new ReflectionClass(Database::class);
|
|
$prop = $ref->getProperty('_instances');
|
|
$prop->setAccessible(true);
|
|
$prop->setValue(null, []);
|
|
}
|
|
|
|
public function testSetRateWithNoCurrentRateJustCreates(): void
|
|
{
|
|
$this->repository->setRate(1, 5.5, '2026-01-01');
|
|
|
|
$current = $this->repository->getCurrentRate(1);
|
|
|
|
$this->assertNotFalse($current);
|
|
$this->assertSame('5.50', $current->rate_percent);
|
|
$this->assertSame('2026-01-01', $current->valid_from);
|
|
$this->assertNull($current->valid_to);
|
|
}
|
|
|
|
public function testSetRateClosesPreviousAndOpensNew(): void
|
|
{
|
|
$this->repository->setRate(1, 5.5, '2026-01-01');
|
|
$this->repository->setRate(1, 6.0, '2026-03-01');
|
|
|
|
$rows = $this->repository->getList('*', ['account_id' => 1], 'id');
|
|
|
|
$this->assertCount(2, $rows);
|
|
|
|
$this->assertSame('2026-01-01', $rows[0]->valid_from);
|
|
$this->assertSame('2026-02-28', $rows[0]->valid_to);
|
|
|
|
$this->assertSame('2026-03-01', $rows[1]->valid_from);
|
|
$this->assertNull($rows[1]->valid_to);
|
|
|
|
$current = $this->repository->getCurrentRate(1);
|
|
$this->assertSame('6.00', $current->rate_percent);
|
|
}
|
|
|
|
public function testSetRateRejectsDateNotAfterCurrentValidFrom(): void
|
|
{
|
|
$this->repository->setRate(1, 5.5, '2026-03-01');
|
|
|
|
$this->expectException(MyException::class);
|
|
$this->repository->setRate(1, 6.0, '2026-03-01');
|
|
}
|
|
|
|
public function testSetRateRejectsDateBeforeCurrentValidFrom(): void
|
|
{
|
|
$this->repository->setRate(1, 5.5, '2026-03-01');
|
|
|
|
$this->expectException(MyException::class);
|
|
$this->repository->setRate(1, 6.0, '2026-01-01');
|
|
}
|
|
|
|
public function testSetRateIsolatedPerAccount(): void
|
|
{
|
|
$this->repository->setRate(1, 5.5, '2026-01-01');
|
|
$this->repository->setRate(2, 4.0, '2026-01-01');
|
|
|
|
$this->assertSame('5.50', $this->repository->getCurrentRate(1)->rate_percent);
|
|
$this->assertSame('4.00', $this->repository->getCurrentRate(2)->rate_percent);
|
|
}
|
|
|
|
public function testSetRateRollsBackOnRejectedDate(): void
|
|
{
|
|
$this->repository->setRate(1, 5.5, '2026-03-01');
|
|
|
|
try {
|
|
$this->repository->setRate(1, 6.0, '2026-01-01');
|
|
} catch (MyException) {
|
|
}
|
|
|
|
// Отклонённая правка не должна была ни закрыть текущую строку, ни создать новую.
|
|
$rows = $this->repository->getList('*', ['account_id' => 1], 'id');
|
|
$this->assertCount(1, $rows);
|
|
$this->assertNull($rows[0]->valid_to);
|
|
}
|
|
}
|