em->getRepository(Specialty::class); } /** @return array{0: Specialty, 1: Specialty, 2: Specialty} ریشه و دو فرزندش */ private function newTree(): array { $suffix = uniqid(); $root = new Specialty('ریشهٔ ' . $suffix, 'root-' . $suffix); $this->em->persist($root); $this->em->flush(); $childA = new Specialty('فرزند الف ' . $suffix, 'child-a-' . $suffix, $root); $childB = new Specialty('فرزند ب ' . $suffix, 'child-b-' . $suffix, $root); $this->em->persist($childA); $this->em->persist($childB); $this->em->flush(); return [$root, $childA, $childB]; } public function testRootExpandsToItselfAndEveryChild(): void { [$root, $childA, $childB] = $this->newTree(); $out = $this->repo()->expandWithDescendants([$root->getId()]); self::assertContains($root->getId(), $out); self::assertContains($childA->getId(), $out); self::assertContains($childB->getId(), $out); } public function testLeafExpandsToItselfOnly(): void { [$root, $childA, $childB] = $this->newTree(); $out = $this->repo()->expandWithDescendants([$childA->getId()]); self::assertSame([$childA->getId()], $out); self::assertNotContains($root->getId(), $out); self::assertNotContains($childB->getId(), $out); } public function testUnknownIdIsKeptSoTheFilterMatchesNothing(): void { // حذفش می‌کرد، خروجی خالی می‌شد و `IN ()` فیلتر را خنثی می‌کرد. self::assertSame([999_999_999], $this->repo()->expandWithDescendants([999_999_999])); } public function testEmptyInputGivesEmptyOutput(): void { self::assertSame([], $this->repo()->expandWithDescendants([])); } public function testDuplicateAndStringIdsAreNormalised(): void { [$root] = $this->newTree(); $id = $root->getId(); $out = $this->repo()->expandWithDescendants([$id, (string) $id, $id]); self::assertSame(count($out), count(array_unique($out))); self::assertContains($id, $out); } public function testOutputIsSortedAscending(): void { [$root] = $this->newTree(); $out = $this->repo()->expandWithDescendants([$root->getId()]); $sorted = $out; sort($sorted); self::assertSame($sorted, $out); } public function testAncestorExpansionIsUnaffected(): void { // دو تابع دو جهت‌اند؛ این تست تثبیت می‌کند که قرینهٔ قدیمی دست‌نخورده مانده. [$root, $childA] = $this->newTree(); $out = $this->repo()->expandWithAncestors([$childA->getId()]); self::assertContains($childA->getId(), $out); self::assertContains($root->getId(), $out); } }