160 lines
5.6 KiB
PHP
160 lines
5.6 KiB
PHP
<?php
|
||
|
||
namespace Tests\Unit;
|
||
|
||
use App\Repositories\BudgetRepository;
|
||
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;
|
||
|
||
/**
|
||
* BudgetRepository жёстко привязан к боевой таблице budgets конструктором, а getYear() делает
|
||
* JOIN к categories — для тестов подменяем обе таблицы на временные (тот же приём, что и в
|
||
* CategoryRepositoryTest: прямой вызов Repository::__construct(), минуя BudgetRepository::__construct()).
|
||
*/
|
||
class BudgetRepositoryTestDouble extends BudgetRepository
|
||
{
|
||
public function __construct(?string $connection = null)
|
||
{
|
||
Repository::__construct('budget_repository_test_budgets', connection: $connection);
|
||
$this->categories_table = 'budget_repository_test_categories';
|
||
}
|
||
}
|
||
|
||
class BudgetRepositoryTest extends TestCase
|
||
{
|
||
private PdoConnection $connection;
|
||
private BudgetRepositoryTestDouble $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 budget_repository_test_budgets');
|
||
$this->connection->exec('DROP TABLE IF EXISTS budget_repository_test_categories');
|
||
|
||
$this->connection->exec(
|
||
'CREATE TABLE budget_repository_test_categories (
|
||
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
|
||
user_id INT UNSIGNED NOT NULL
|
||
)'
|
||
);
|
||
|
||
$this->connection->exec(
|
||
'CREATE TABLE budget_repository_test_budgets (
|
||
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
|
||
categorie_id INT UNSIGNED NOT NULL,
|
||
plan_summ DECIMAL(15,2) NOT NULL,
|
||
year SMALLINT UNSIGNED NOT NULL,
|
||
month TINYINT UNSIGNED NOT NULL,
|
||
type ENUM(\'income\',\'expense\') NOT NULL,
|
||
formula_pct_used DECIMAL(5,2) NULL,
|
||
UNIQUE KEY uq_period (categorie_id, year, month)
|
||
)'
|
||
);
|
||
|
||
$this->repository = new BudgetRepositoryTestDouble();
|
||
}
|
||
|
||
protected function tearDown(): void
|
||
{
|
||
Profiler::reset();
|
||
|
||
if (isset($this->connection)) {
|
||
try {
|
||
$this->connection->exec('DROP TABLE IF EXISTS budget_repository_test_budgets');
|
||
$this->connection->exec('DROP TABLE IF EXISTS budget_repository_test_categories');
|
||
} catch (MyException) {
|
||
}
|
||
}
|
||
|
||
$ref = new ReflectionClass(Database::class);
|
||
$prop = $ref->getProperty('_instances');
|
||
$prop->setAccessible(true);
|
||
$prop->setValue(null, []);
|
||
}
|
||
|
||
private function createCategory(int $user_id): int
|
||
{
|
||
$stmt = $this->connection->prepare('INSERT INTO budget_repository_test_categories (user_id) VALUES (:user_id)');
|
||
$stmt->execute(['user_id' => $user_id]);
|
||
|
||
return (int)$this->connection->lastInsertId();
|
||
}
|
||
|
||
public function testUpsertCreatesRow(): void
|
||
{
|
||
$categorie_id = $this->createCategory(1);
|
||
|
||
$this->repository->upsert($categorie_id, 2027, 3, 1000.50, 'expense');
|
||
|
||
$row = $this->repository->getItemWhere("categorie_id = $categorie_id AND year = 2027 AND month = 3");
|
||
|
||
$this->assertSame('1000.50', $row->plan_summ);
|
||
}
|
||
|
||
public function testUpsertUpdatesExistingRow(): void
|
||
{
|
||
$categorie_id = $this->createCategory(1);
|
||
|
||
$this->repository->upsert($categorie_id, 2027, 3, 1000, 'expense');
|
||
$this->repository->upsert($categorie_id, 2027, 3, 2500, 'expense');
|
||
|
||
$rows = $this->repository->getList('*', ['categorie_id' => $categorie_id]);
|
||
|
||
$this->assertCount(1, $rows);
|
||
$this->assertSame('2500.00', $rows[0]->plan_summ);
|
||
}
|
||
|
||
public function testUpsertStoresFormulaPctUsed(): void
|
||
{
|
||
$categorie_id = $this->createCategory(1);
|
||
|
||
$this->repository->upsert($categorie_id, 2027, 5, 300, 'expense', 30.5);
|
||
|
||
$row = $this->repository->getItemWhere("categorie_id = $categorie_id AND year = 2027 AND month = 5");
|
||
|
||
$this->assertSame('30.50', $row->formula_pct_used);
|
||
}
|
||
|
||
public function testGetYearReturnsOnlyUsersCategories(): void
|
||
{
|
||
$my_categorie_id = $this->createCategory(1);
|
||
$foreign_categorie_id = $this->createCategory(2);
|
||
|
||
$this->repository->upsert($my_categorie_id, 2027, 1, 100, 'income');
|
||
$this->repository->upsert($foreign_categorie_id, 2027, 1, 999, 'income');
|
||
|
||
$plan = $this->repository->getYear(1, 2027);
|
||
|
||
$this->assertArrayHasKey($my_categorie_id, $plan);
|
||
$this->assertArrayNotHasKey($foreign_categorie_id, $plan);
|
||
$this->assertSame(100.0, $plan[$my_categorie_id][1]['plan_summ']);
|
||
}
|
||
|
||
public function testGetYearFiltersByYear(): void
|
||
{
|
||
$categorie_id = $this->createCategory(1);
|
||
|
||
$this->repository->upsert($categorie_id, 2026, 1, 100, 'income');
|
||
$this->repository->upsert($categorie_id, 2027, 1, 200, 'income');
|
||
|
||
$plan = $this->repository->getYear(1, 2027);
|
||
|
||
$this->assertSame(200.0, $plan[$categorie_id][1]['plan_summ']);
|
||
$this->assertCount(1, $plan[$categorie_id]);
|
||
}
|
||
}
|