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 category_repository_test_categories'); $this->connection->exec( 'CREATE TABLE category_repository_test_categories ( id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY, user_id INT UNSIGNED NOT NULL, parent_id INT UNSIGNED NULL, title VARCHAR(128) NOT NULL, type ENUM(\'income\',\'expense\') NOT NULL, is_delete TINYINT(1) NOT NULL DEFAULT 0, `order` INT NOT NULL DEFAULT 0, linked_expense_categorie_id INT UNSIGNED NULL, formula_pct DECIMAL(5,2) NULL )' ); $this->repository = new CategoryRepositoryTestDouble(); } protected function tearDown(): void { Profiler::reset(); if (isset($this->connection)) { try { $this->connection->exec('DROP TABLE IF EXISTS category_repository_test_categories'); } catch (MyException) { } } $ref = new ReflectionClass(Database::class); $prop = $ref->getProperty('_instances'); $prop->setAccessible(true); $prop->setValue(null, []); } public function testFindActiveDuplicateFindsSameTitleTypeParent(): void { $this->repository->create([ 'user_id' => 1, 'parent_id' => null, 'title' => 'Зарплата', 'type' => 'income', 'is_delete' => false, 'order' => 0, ]); $duplicate = $this->repository->findActiveDuplicate(1, 'income', null, 'Зарплата'); $this->assertNotFalse($duplicate); $this->assertSame('Зарплата', $duplicate->title); } public function testFindActiveDuplicateIgnoresDifferentType(): void { $this->repository->create([ 'user_id' => 1, 'parent_id' => null, 'title' => 'Прочее', 'type' => 'income', 'is_delete' => false, 'order' => 0, ]); $this->assertFalse($this->repository->findActiveDuplicate(1, 'expense', null, 'Прочее')); } public function testFindActiveDuplicateExcludesGivenId(): void { $id = $this->repository->create([ 'user_id' => 1, 'parent_id' => null, 'title' => 'Транспорт', 'type' => 'expense', 'is_delete' => false, 'order' => 0, ]); $this->assertFalse($this->repository->findActiveDuplicate(1, 'expense', null, 'Транспорт', $id)); } public function testFindArchivedDuplicateOnlyMatchesArchived(): void { $this->repository->create([ 'user_id' => 1, 'parent_id' => null, 'title' => 'Такси', 'type' => 'expense', 'is_delete' => true, 'order' => 0, ]); $this->assertFalse($this->repository->findActiveDuplicate(1, 'expense', null, 'Такси')); $archived = $this->repository->findArchivedDuplicate(1, 'expense', null, 'Такси'); $this->assertNotFalse($archived); $this->assertSame('Такси', $archived->title); } public function testGetTreeGroupsByParentId(): void { $group_id = $this->repository->create([ 'user_id' => 1, 'parent_id' => null, 'title' => 'Транспорт', 'type' => 'expense', 'is_delete' => false, 'order' => 0, ]); $this->repository->create([ 'user_id' => 1, 'parent_id' => $group_id, 'title' => 'Такси', 'type' => 'expense', 'is_delete' => false, 'order' => 0, ]); // архивная — не должна попасть в дерево $this->repository->create([ 'user_id' => 1, 'parent_id' => $group_id, 'title' => 'Метро', 'type' => 'expense', 'is_delete' => true, 'order' => 0, ]); $tree = $this->repository->getTree(1); $this->assertCount(1, $tree[0]); $this->assertSame('Транспорт', $tree[0][0]->title); $this->assertCount(1, $tree[$group_id]); $this->assertSame('Такси', $tree[$group_id][0]->title); } public function testGetTreeScopedByUser(): void { $this->repository->create([ 'user_id' => 1, 'parent_id' => null, 'title' => 'Моя статья', 'type' => 'expense', 'is_delete' => false, 'order' => 0, ]); $this->repository->create([ 'user_id' => 2, 'parent_id' => null, 'title' => 'Чужая статья', 'type' => 'expense', 'is_delete' => false, 'order' => 0, ]); $tree = $this->repository->getTree(1); $this->assertCount(1, $tree[0]); $this->assertSame('Моя статья', $tree[0][0]->title); } }