262 lines
8.5 KiB
PHP
262 lines
8.5 KiB
PHP
<?php
|
|
|
|
namespace Tests\Feature\Element;
|
|
|
|
use App\Element\CreateElementDto;
|
|
use App\Element\ElementRepository;
|
|
use App\Set\CreateSetDto;
|
|
use App\Set\CreateSetLevelDto;
|
|
use App\Set\Set;
|
|
use App\Set\SetLevel;
|
|
use App\Set\SetLevelRepository;
|
|
use App\Set\SetRepository;
|
|
use App\Shared\ValueObject\EmailAddress;
|
|
use App\User\CreateUserDto;
|
|
use App\User\UserRepository;
|
|
use DomainException;
|
|
use Illuminate\Foundation\Testing\RefreshDatabase;
|
|
use Tests\TestCase;
|
|
|
|
class EloquentElementRepositoryTest extends TestCase
|
|
{
|
|
use RefreshDatabase;
|
|
|
|
public function testItPersistsNestedElementsInSiblingOrder(): void
|
|
{
|
|
$set = $this->createSet('Bible');
|
|
$repository = app(ElementRepository::class);
|
|
$bookLevel = $this->createLevel($set, 'book');
|
|
$portionLevel = $this->createLevel($set, 'portion');
|
|
$genesisBook = $repository->create(new CreateElementDto(
|
|
name: 'Genesis',
|
|
level: $bookLevel,
|
|
parentElement: null,
|
|
));
|
|
$exodusBook = $repository->create(new CreateElementDto(
|
|
name: 'Exodus',
|
|
level: $bookLevel,
|
|
parentElement: null,
|
|
));
|
|
$genesisPortion = $repository->create(new CreateElementDto(
|
|
name: 'Genesis',
|
|
level: $portionLevel,
|
|
parentElement: $genesisBook,
|
|
));
|
|
$noahPortion = $repository->create(new CreateElementDto(
|
|
name: 'Noah',
|
|
level: $portionLevel,
|
|
parentElement: $genesisBook,
|
|
));
|
|
|
|
$this->assertSame(1, $genesisBook->getPosition());
|
|
$this->assertSame(2, $exodusBook->getPosition());
|
|
$this->assertSame(1, $genesisPortion->getPosition());
|
|
$this->assertSame(2, $noahPortion->getPosition());
|
|
$this->assertDatabaseHas('elements', [
|
|
'id' => $genesisPortion->getId(),
|
|
'set_level_id' => $portionLevel->getId(),
|
|
'name' => 'Genesis',
|
|
'parent_element_id' => $genesisBook->getId(),
|
|
'position' => 1,
|
|
]);
|
|
|
|
$foundElement = $repository->find($noahPortion->getId());
|
|
|
|
$this->assertNotNull($foundElement);
|
|
$this->assertSame('Noah', $foundElement->getName());
|
|
$this->assertSame('portion', $foundElement->getKind());
|
|
$this->assertSame(
|
|
$portionLevel->getId(),
|
|
$foundElement->getLevel()->getId(),
|
|
);
|
|
$this->assertSame($set->getId(), $foundElement->getSet()->getId());
|
|
$this->assertSame(
|
|
$genesisBook->getId(),
|
|
$foundElement->getParentElement()?->getId(),
|
|
);
|
|
}
|
|
|
|
public function testItRejectsAParentFromAnotherSet(): void
|
|
{
|
|
$bible = $this->createSet('Bible');
|
|
$course = $this->createSet('Course');
|
|
$repository = app(ElementRepository::class);
|
|
$bookLevel = $this->createLevel($bible, 'book');
|
|
$moduleLevel = $this->createLevel($course, 'module');
|
|
$book = $repository->create(new CreateElementDto(
|
|
name: 'Genesis',
|
|
level: $bookLevel,
|
|
parentElement: null,
|
|
));
|
|
|
|
$this->expectException(DomainException::class);
|
|
$this->expectExceptionMessage(
|
|
'parent element must belong to the same set',
|
|
);
|
|
|
|
$repository->create(new CreateElementDto(
|
|
name: 'Invalid lesson',
|
|
level: $moduleLevel,
|
|
parentElement: $book,
|
|
));
|
|
}
|
|
|
|
public function testItRejectsARootOutsideTheFirstLevel(): void
|
|
{
|
|
$set = $this->createSet('Bible');
|
|
$this->createLevel($set, 'book');
|
|
$portionLevel = $this->createLevel($set, 'portion');
|
|
|
|
$this->expectException(DomainException::class);
|
|
$this->expectExceptionMessage(
|
|
'root element must use the first set level',
|
|
);
|
|
|
|
app(ElementRepository::class)->create(new CreateElementDto(
|
|
name: 'Creation',
|
|
level: $portionLevel,
|
|
parentElement: null,
|
|
));
|
|
}
|
|
|
|
public function testItRejectsAChildOutsideTheNextLevel(): void
|
|
{
|
|
$set = $this->createSet('Bible');
|
|
$bookLevel = $this->createLevel($set, 'book');
|
|
$this->createLevel($set, 'portion');
|
|
$chapterLevel = $this->createLevel($set, 'chapter');
|
|
$repository = app(ElementRepository::class);
|
|
$book = $repository->create(new CreateElementDto(
|
|
name: 'Genesis',
|
|
level: $bookLevel,
|
|
parentElement: null,
|
|
));
|
|
|
|
$this->expectException(DomainException::class);
|
|
$this->expectExceptionMessage(
|
|
'child element must use the next set level',
|
|
);
|
|
|
|
$repository->create(new CreateElementDto(
|
|
name: 'Chapter 1',
|
|
level: $chapterLevel,
|
|
parentElement: $book,
|
|
));
|
|
}
|
|
|
|
public function testItListsOrderedElementsWithinTheirTreeScope(): void
|
|
{
|
|
$bible = $this->createSet('Bible');
|
|
$course = $this->createSet('Course');
|
|
$repository = app(ElementRepository::class);
|
|
$bookLevel = $this->createLevel($bible, 'book');
|
|
$portionLevel = $this->createLevel($bible, 'portion');
|
|
$moduleLevel = $this->createLevel($course, 'module');
|
|
$genesisBook = $repository->create(new CreateElementDto(
|
|
name: 'Genesis',
|
|
level: $bookLevel,
|
|
parentElement: null,
|
|
));
|
|
$exodusBook = $repository->create(new CreateElementDto(
|
|
name: 'Exodus',
|
|
level: $bookLevel,
|
|
parentElement: null,
|
|
));
|
|
$repository->create(new CreateElementDto(
|
|
name: 'Module 1',
|
|
level: $moduleLevel,
|
|
parentElement: null,
|
|
));
|
|
$repository->create(new CreateElementDto(
|
|
name: 'Genesis',
|
|
level: $portionLevel,
|
|
parentElement: $genesisBook,
|
|
));
|
|
$repository->create(new CreateElementDto(
|
|
name: 'Noah',
|
|
level: $portionLevel,
|
|
parentElement: $genesisBook,
|
|
));
|
|
$repository->create(new CreateElementDto(
|
|
name: 'Shemot',
|
|
level: $portionLevel,
|
|
parentElement: $exodusBook,
|
|
));
|
|
|
|
$topLevelElements = $repository->findTopLevelBySet($bible);
|
|
$childElements = $repository->findByParentElement($genesisBook);
|
|
|
|
$this->assertSame(
|
|
['Genesis', 'Exodus'],
|
|
array_map(function ($element): string {
|
|
return $element->getName();
|
|
}, $topLevelElements),
|
|
);
|
|
$this->assertSame(
|
|
['Genesis', 'Noah'],
|
|
array_map(function ($element): string {
|
|
return $element->getName();
|
|
}, $childElements),
|
|
);
|
|
}
|
|
|
|
public function testItListsEveryElementForASet(): void
|
|
{
|
|
$bible = $this->createSet('Bible');
|
|
$course = $this->createSet('Course');
|
|
$repository = app(ElementRepository::class);
|
|
$bookLevel = $this->createLevel($bible, 'book');
|
|
$portionLevel = $this->createLevel($bible, 'portion');
|
|
$moduleLevel = $this->createLevel($course, 'module');
|
|
$genesis = $repository->create(new CreateElementDto(
|
|
name: 'Genesis',
|
|
level: $bookLevel,
|
|
parentElement: null,
|
|
));
|
|
$repository->create(new CreateElementDto(
|
|
name: 'Creation',
|
|
level: $portionLevel,
|
|
parentElement: $genesis,
|
|
));
|
|
$repository->create(new CreateElementDto(
|
|
name: 'Foundations',
|
|
level: $moduleLevel,
|
|
parentElement: null,
|
|
));
|
|
|
|
$elements = $repository->findBySet($bible);
|
|
|
|
$this->assertSame(
|
|
['Genesis', 'Creation'],
|
|
array_map(function ($element): string {
|
|
return $element->getName();
|
|
}, $elements),
|
|
);
|
|
$this->assertNull($elements[0]->getParentElement());
|
|
$this->assertSame(
|
|
$genesis->getId(),
|
|
$elements[1]->getParentElement()?->getId(),
|
|
);
|
|
}
|
|
|
|
private function createSet(string $name): Set
|
|
{
|
|
$creator = app(UserRepository::class)->create(new CreateUserDto(
|
|
email: new EmailAddress(strtolower($name) . '@example.com'),
|
|
passwordHash: 'hashed-password',
|
|
));
|
|
|
|
return app(SetRepository::class)->create(new CreateSetDto(
|
|
name: $name,
|
|
creator: $creator,
|
|
));
|
|
}
|
|
|
|
private function createLevel(Set $set, string $kind): SetLevel
|
|
{
|
|
return app(SetLevelRepository::class)->create(new CreateSetLevelDto(
|
|
set: $set,
|
|
kind: $kind,
|
|
));
|
|
}
|
|
}
|