outline-8.x-1.x-dev/tests/src/Kernel/EntryHierarchyValidationTest.php
tests/src/Kernel/EntryHierarchyValidationTest.php
<?php
namespace Drupal\Tests\outline\Kernel;
use Drupal\KernelTests\Core\Entity\EntityKernelTestBase;
use Drupal\outline\Entity\Outline;
/**
* Tests handling of pending revisions.
*
* @coversDefaultClass \Drupal\outline\Plugin\Validation\Constraint\OutlineEntryHierarchyConstraintValidator
*
* @group outline
*/
class EntryHierarchyValidationTest extends EntityKernelTestBase {
/**
* {@inheritdoc}
*/
protected static $modules = ['outline'];
/**
* {@inheritdoc}
*/
protected function setUp(): void {
parent::setUp();
$this->installEntitySchema('outline_entry');
}
/**
* Tests the entry hierarchy validation with re-parenting in pending
* revisions.
*
* @throws \Drupal\Core\Entity\EntityStorageException
*/
public function testEntryHierarchyValidation() {
$outline_id = mb_strtolower($this->randomMachineName());
$outline = Outline::create([
'name' => $outline_id,
'oid' => $outline_id,
]);
$outline->save();
// Create a simple hierarchy in the outline, a root entry and three parent
// entries.
/** @var \Drupal\Core\Entity\RevisionableStorageInterface $entry_storage */
$entry_storage = \Drupal::entityTypeManager()->getStorage('outline_entry');
$root = $entry_storage->create([
'name' => $this->randomMachineName(),
'oid' => $outline_id,
]);
$root->save();
$parent1 = $entry_storage->create([
'name' => $this->randomMachineName(),
'oid' => $outline_id,
'parent' => $root->id(),
]);
$parent1->save();
$parent2 = $entry_storage->create([
'name' => $this->randomMachineName(),
'oid' => $outline_id,
'parent' => $root->id(),
]);
$parent2->save();
$parent3 = $entry_storage->create([
'name' => $this->randomMachineName(),
'oid' => $outline_id,
'parent' => $root->id(),
]);
$parent3->save();
// Create a child entry and assign one of the parents above.
$child1 = $entry_storage->create([
'name' => $this->randomMachineName(),
'oid' => $outline_id,
'parent' => $parent1->id(),
]);
$violations = $child1->validate();
$this->assertEmpty($violations);
$child1->save();
$validation_message = 'You can only change the hierarchy for the <em>published</em> version of this entry.';
// Add a pending revision without changing the entry parent.
$pending_name = $this->randomMachineName();
$child_pending = $entry_storage->createRevision($child1, FALSE);
$child_pending->name = $pending_name;
$violations = $child_pending->validate();
$this->assertEmpty($violations);
// Add a pending revision and change the parent.
$child_pending = $entry_storage->createRevision($child1, FALSE);
$child_pending->parent = $parent2;
$violations = $child_pending->validate();
$this->assertCount(1, $violations);
$this->assertEquals($validation_message, $violations[0]->getMessage());
$this->assertEquals('parent', $violations[0]->getPropertyPath());
// Add a pending revision and add a new parent.
$child_pending = $entry_storage->createRevision($child1, FALSE);
$child_pending->parent[0] = $parent1;
$child_pending->parent[1] = $parent3;
$violations = $child_pending->validate();
$this->assertCount(1, $violations);
$this->assertEquals($validation_message, $violations[0]->getMessage());
$this->assertEquals('parent', $violations[0]->getPropertyPath());
// Add a pending revision and use the root entry as a parent.
$child_pending = $entry_storage->createRevision($child1, FALSE);
$child_pending->parent[0] = $root;
$violations = $child_pending->validate();
$this->assertCount(1, $violations);
$this->assertEquals($validation_message, $violations[0]->getMessage());
$this->assertEquals('parent', $violations[0]->getPropertyPath());
// Add a pending revision and remove the parent.
$child_pending = $entry_storage->createRevision($child1, FALSE);
$child_pending->parent[0] = NULL;
$violations = $child_pending->validate();
$this->assertCount(1, $violations);
$this->assertEquals($validation_message, $violations[0]->getMessage());
$this->assertEquals('parent', $violations[0]->getPropertyPath());
// Add a pending revision and change the weight.
$child_pending = $entry_storage->createRevision($child1, FALSE);
$child_pending->weight = 10;
$violations = $child_pending->validate();
$this->assertCount(1, $violations);
$this->assertEquals($validation_message, $violations[0]->getMessage());
$this->assertEquals('weight', $violations[0]->getPropertyPath());
// Add a pending revision and change both the parent and the weight.
$child_pending = $entry_storage->createRevision($child1, FALSE);
$child_pending->parent = $parent2;
$child_pending->weight = 10;
$violations = $child_pending->validate();
$this->assertCount(2, $violations);
$this->assertEquals($validation_message, $violations[0]->getMessage());
$this->assertEquals($validation_message, $violations[1]->getMessage());
$this->assertEquals('parent', $violations[0]->getPropertyPath());
$this->assertEquals('weight', $violations[1]->getPropertyPath());
// Add a published revision and change the parent.
$child_pending = $entry_storage->createRevision($child1, TRUE);
$child_pending->parent[0] = $parent2;
$violations = $child_pending->validate();
$this->assertEmpty($violations);
// Add a new entry as a third-level child.
// The outline tree structure ends up as follows:
// root
// - parent1
// - parent2
// -- child1 <- this will be a entry with a pending revision
// --- child2
// - parent3
$child2 = $entry_storage->create([
'name' => $this->randomMachineName(),
'oid' => $outline_id,
'parent' => $child1->id(),
]);
$child2->save();
// Change 'child1' to be a pending revision.
$child1 = $entry_storage->createRevision($child1, FALSE);
$child1->save();
// Check that a child of a pending entry can not be re-parented.
$child2_pending = $entry_storage->createRevision($child2, FALSE);
$child2_pending->parent = $parent3;
$violations = $child2_pending->validate();
$this->assertCount(1, $violations);
$this->assertEquals($validation_message, $violations[0]->getMessage());
$this->assertEquals('parent', $violations[0]->getPropertyPath());
// Check that another entry which has a pending revision can not moved under
// another entry which has pending revision.
$parent3_pending = $entry_storage->createRevision($parent3, FALSE);
$parent3_pending->parent = $child1;
$violations = $parent3_pending->validate();
$this->assertCount(1, $violations);
$this->assertEquals($validation_message, $violations[0]->getMessage());
$this->assertEquals('parent', $violations[0]->getPropertyPath());
// Check that a new entry can be created under a entry that has a pending
// revision.
$child3 = $entry_storage->create([
'name' => $this->randomMachineName(),
'oid' => $outline_id,
'parent' => $child1->id(),
]);
$violations = $child3->validate();
$this->assertEmpty($violations);
}
}
