Attainly/backend/tests/Feature/Element/EloquentElementRepositoryTest.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,
));
}
}