Source of file ChangeSetTest.php
Size: 27,825 Bytes - Last Modified: 2021-12-23T10:35:47+00:00
/var/www/docs.ssmods.com/process/src/tests/php/ChangeSetTest.php
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737 | <?php namespace SilverStripe\Versioned\Tests; use BadMethodCallException; use PHPUnit\Framework\ExpectationFailedException; use SebastianBergmann\Comparator\ComparisonFailure; use SilverStripe\Dev\SapphireTest; use SilverStripe\ORM\DataObject; use SilverStripe\Versioned\ChangeSet; use SilverStripe\Versioned\ChangeSetItem; use SilverStripe\Versioned\Tests\ChangeSetTest\BaseObject; use SilverStripe\Versioned\Tests\ChangeSetTest\ChangeSetSyncStub; use SilverStripe\Versioned\Tests\ChangeSetTest\MidObject; use SilverStripe\Versioned\Tests\ChangeSetTest\Permissions; use SilverStripe\Versioned\Versioned; /** * Test {@see ChangeSet} and {@see ChangeSetItem} models */ class ChangeSetTest extends SapphireTest { protected static $fixture_file = 'ChangeSetTest.yml'; protected static $extra_dataobjects = [ ChangeSetTest\BaseObject::class, ChangeSetTest\MidObject::class, ChangeSetTest\EndObject::class, ChangeSetTest\EndObjectChild::class, ChangeSetTest\UnversionedObject::class, ChangeSetTest\UnstagedObject::class, ]; protected function tearDown(): void { // Reset overridden permissions foreach ($this->getExtraDataObjects() as $dataObjectClass) { /** @var Permissions $dataObjectClass */ $dataObjectClass::reset(); } parent::tearDown(); } /** * Automatically publish all objects */ protected function publishAllFixtures() { $this->logInWithPermission('ADMIN'); foreach ($this->fixtureFactory->getFixtures() as $class => $fixtures) { foreach ($fixtures as $handle => $id) { /** @var Versioned|DataObject $object */ $object = $this->objFromFixture($class, $handle); if ($object->hasExtension(Versioned::class) && $object->hasStages()) { $object->publishSingle(); } } } } /** * Check that the changeset includes the given items * * @param ChangeSet $cs * @param array $match Array of object fixture keys with change type values */ protected function assertChangeSetLooksLike($cs, $match) { /** @var ChangeSetItem[] $items */ $items = $cs->Changes()->toArray(); foreach ($match as $key => $mode) { list($class, $identifier) = explode('.', $key); $objectID = $this->idFromFixture($class, $identifier); $objectClass = DataObject::getSchema()->baseDataClass($class); foreach ($items as $i => $item) { if ($item->ObjectClass == $objectClass && $item->ObjectID == $objectID && $item->Added == $mode ) { unset($items[$i]); continue 2; } } throw new ExpectationFailedException( 'Change set didn\'t include expected item', new ComparisonFailure( ['Class' => $class, 'ID' => $objectID, 'Added' => $mode], null, "$key => $mode", '' ) ); } if (count($items)) { $extra = []; foreach ($items as $item) { $extra[] = [ 'Class' => $item->ObjectClass, 'ID' => $item->ObjectID, 'Added' => $item->Added, 'ChangeType' => $item->getChangeType() ]; } throw new ExpectationFailedException( 'Change set included items that weren\'t expected', new ComparisonFailure([], $extra, '', print_r($extra, true)) ); } $this->assertTrue(true, 'Exception was thrown when it should not have been'); } public function testAddObject() { $cs = new ChangeSet(); $cs->write(); $cs->addObject($this->objFromFixture(ChangeSetTest\EndObject::class, 'end1')); $cs->addObject($this->objFromFixture(ChangeSetTest\EndObjectChild::class, 'endchild1')); $this->assertChangeSetLooksLike( $cs, [ ChangeSetTest\EndObject::class . '.end1' => ChangeSetItem::EXPLICITLY, ChangeSetTest\EndObjectChild::class . '.endchild1' => ChangeSetItem::EXPLICITLY ] ); } public function testDescription() { $cs = new ChangeSet(); $cs->write(); $cs->addObject($this->objFromFixture(ChangeSetTest\EndObject::class, 'end1')); $this->assertEquals('1 total (1 change)', $cs->getDetails()); $cs->addObject($this->objFromFixture(ChangeSetTest\EndObjectChild::class, 'endchild1')); $this->assertEquals('2 total (2 changes)', $cs->getDetails()); } public function testRepeatedSyncIsNOP() { $this->publishAllFixtures(); $cs = new ChangeSet(); $cs->write(); $base = $this->objFromFixture(ChangeSetTest\BaseObject::class, 'base'); $cs->addObject($base); $cs->sync(); $this->assertChangeSetLooksLike( $cs, [ ChangeSetTest\BaseObject::class . '.base' => ChangeSetItem::EXPLICITLY, ChangeSetTest\MidObject::class . '.mid1' => ChangeSetItem::IMPLICITLY, ChangeSetTest\MidObject::class . '.mid2' => ChangeSetItem::IMPLICITLY, ChangeSetTest\EndObject::class . '.end1' => ChangeSetItem::IMPLICITLY, ChangeSetTest\EndObject::class . '.end2' => ChangeSetItem::IMPLICITLY, ] ); $cs->sync(); $this->assertChangeSetLooksLike( $cs, [ ChangeSetTest\BaseObject::class . '.base' => ChangeSetItem::EXPLICITLY, ChangeSetTest\MidObject::class . '.mid1' => ChangeSetItem::IMPLICITLY, ChangeSetTest\MidObject::class . '.mid2' => ChangeSetItem::IMPLICITLY, ChangeSetTest\EndObject::class . '.end1' => ChangeSetItem::IMPLICITLY, ChangeSetTest\EndObject::class . '.end2' => ChangeSetItem::IMPLICITLY, ] ); } public function testSync() { $this->publishAllFixtures(); $cs = new ChangeSet(); $cs->write(); $base = $this->objFromFixture(ChangeSetTest\BaseObject::class, 'base'); $cs->addObject($base); $cs->sync(); $this->assertChangeSetLooksLike( $cs, [ ChangeSetTest\BaseObject::class . '.base' => ChangeSetItem::EXPLICITLY, ChangeSetTest\MidObject::class . '.mid1' => ChangeSetItem::IMPLICITLY, ChangeSetTest\MidObject::class . '.mid2' => ChangeSetItem::IMPLICITLY, ChangeSetTest\EndObject::class . '.end1' => ChangeSetItem::IMPLICITLY, ChangeSetTest\EndObject::class . '.end2' => ChangeSetItem::IMPLICITLY, ] ); // Modify one object $end = $this->objFromFixture(ChangeSetTest\EndObject::class, 'end1'); $end->Baz = 3; $end->write(); $cs->sync(); $this->assertChangeSetLooksLike( $cs, [ ChangeSetTest\BaseObject::class . '.base' => ChangeSetItem::EXPLICITLY, ChangeSetTest\MidObject::class . '.mid1' => ChangeSetItem::IMPLICITLY, ChangeSetTest\MidObject::class . '.mid2' => ChangeSetItem::IMPLICITLY, ChangeSetTest\EndObject::class . '.end1' => ChangeSetItem::IMPLICITLY, ChangeSetTest\EndObject::class . '.end2' => ChangeSetItem::IMPLICITLY, ] ); /** @var ChangeSetItem $baseItem */ $baseItem = ChangeSetItem::get_for_object($base)->first(); /** @var ChangeSetItem $endItem */ $endItem = ChangeSetItem::get_for_object($end)->first(); $this->assertEquals( [$baseItem->ID], $endItem->ReferencedBy()->column("ID") ); $this->assertListEquals( [ [ 'Added' => ChangeSetItem::EXPLICITLY, 'ObjectClass' => ChangeSetTest\BaseObject::class, 'ObjectID' => $base->ID, 'ChangeSetID' => $cs->ID ] ], $endItem->ReferencedBy() ); // Add mid2 explicitly, and delete, to ensure that cascading deletes are added $mid2 = $this->objFromFixture(ChangeSetTest\MidObject::class, 'mid2'); $mid2ID = $mid2->ID; $end2 = $this->objFromFixture(ChangeSetTest\EndObject::class, 'end2'); $cs->addObject($mid2); $mid2->delete(); $cs->sync(); $this->assertChangeSetLooksLike( $cs, [ ChangeSetTest\BaseObject::class . '.base' => ChangeSetItem::EXPLICITLY, ChangeSetTest\MidObject::class . '.mid1' => ChangeSetItem::IMPLICITLY, ChangeSetTest\MidObject::class . '.mid2' => ChangeSetItem::EXPLICITLY, ChangeSetTest\EndObject::class . '.end1' => ChangeSetItem::IMPLICITLY, ChangeSetTest\EndObject::class . '.end2' => ChangeSetItem::IMPLICITLY, ] ); // Ensure both mid1 and mid2 are deleted on draft /** @var ChangeSetItem $mid2Item */ $mid2Item = ChangeSetItem::get_for_object($mid2)->first(); /** @var ChangeSetItem $end2Item */ $end2Item = ChangeSetItem::get_for_object($end2)->first(); $this->assertEquals(ChangeSetItem::CHANGE_DELETED, $mid2Item->getChangeType()); $this->assertEquals(ChangeSetItem::CHANGE_DELETED, $end2Item->getChangeType()); $this->assertListEquals( [ [ 'Added' => ChangeSetItem::EXPLICITLY, 'ObjectClass' => ChangeSetTest\MidObject::class, 'ObjectID' => $mid2ID, 'ChangeSetID' => $cs->ID ] ], $end2Item->ReferencedBy() ); } /** * Test that sync includes implicit items */ public function testIsSynced() { $this->publishAllFixtures(); $cs = new ChangeSet(); $cs->write(); $base = $this->objFromFixture(ChangeSetTest\BaseObject::class, 'base'); $cs->addObject($base); $cs->sync(); $this->assertChangeSetLooksLike( $cs, [ ChangeSetTest\BaseObject::class . '.base' => ChangeSetItem::EXPLICITLY, ChangeSetTest\MidObject::class . '.mid1' => ChangeSetItem::IMPLICITLY, ChangeSetTest\MidObject::class . '.mid2' => ChangeSetItem::IMPLICITLY, ChangeSetTest\EndObject::class . '.end1' => ChangeSetItem::IMPLICITLY, ChangeSetTest\EndObject::class . '.end2' => ChangeSetItem::IMPLICITLY, ] ); $this->assertTrue($cs->isSynced()); $end = $this->objFromFixture(ChangeSetTest\MidObject::class, 'mid1'); $end->BaseID = null; $end->write(); $this->assertFalse($cs->isSynced()); $cs->sync(); $this->assertChangeSetLooksLike( $cs, [ ChangeSetTest\BaseObject::class . '.base' => ChangeSetItem::EXPLICITLY, ChangeSetTest\MidObject::class . '.mid2' => ChangeSetItem::IMPLICITLY, ChangeSetTest\EndObject::class . '.end2' => ChangeSetItem::IMPLICITLY, ] ); $this->assertTrue($cs->isSynced()); } public function testCanPublish() { // Create changeset containing all items (unpublished) $this->logInWithPermission('ADMIN'); $changeSet = new ChangeSet(); $changeSet->write(); $base = $this->objFromFixture(ChangeSetTest\BaseObject::class, 'base'); $changeSet->addObject($base); $changeSet->sync(); $this->assertEquals(5, $changeSet->Changes()->count()); // Test un-authenticated user cannot publish $this->logOut(); $this->assertFalse($changeSet->canPublish()); // With model publish permissions only publish is allowed $this->logInWithPermission('PERM_canPublish'); $this->assertTrue($changeSet->canPublish()); // Test user with the necessary minimum permissions can login $this->logInWithPermission( [ 'CMS_ACCESS_CampaignAdmin', 'PERM_canPublish' ] ); $this->assertTrue($changeSet->canPublish()); // campaign admin only permission doesn't grant publishing rights $this->logInWithPermission('CMS_ACCESS_CampaignAdmin'); $this->assertFalse($changeSet->canPublish()); // Test that you can still publish a changeset, even if canPublish() // returns false (e.g. externally rather than internally enforced) $changeSet->publish(); } /** * Test that nested can publish correctly respects implicit / explicit items */ public function testCanPublishNested() { // Create changeset containing all items (unpublished) $this->logInWithPermission('PERM_canPublish'); $changeSet = new ChangeSet(); $changeSet->write(); /** @var ChangeSetTest\BaseObject $base */ $base = $this->objFromFixture(ChangeSetTest\BaseObject::class, 'base'); /** @var ChangeSetTest\MidObject $mid1 */ $mid1 = $this->objFromFixture(ChangeSetTest\MidObject::class, 'mid1'); $changeSet->addObject($base); $changeSet->addObject($mid1); $changeSet->sync(); $this->assertEquals(5, $changeSet->Changes()->count()); // With model publish permissions only publish is allowed $this->assertTrue($changeSet->canPublish()); // setting canPublish = false on any implicit items in the changeset doesn't // deny publishing permissions /** @var ChangeSetTest\MidObject $mid2 */ $mid2 = $this->objFromFixture(ChangeSetTest\MidObject::class, 'mid2'); $mid2->setCan('canPublish', false); $this->assertTrue($changeSet->canPublish()); // Setting canPublish = false on any explicit item in the changeset // does deny publishing permissions $mid1->setCan('canPublish', false); $this->assertFalse($changeSet->canPublish()); // Test that you can still publish a changeset, even if canPublish() // returns false (e.g. externally rather than internally enforced) $changeSet->publish(); } public function testHasChanges() { // Create changeset containing all items (unpublished) Versioned::set_stage(Versioned::DRAFT); $this->logInWithPermission('ADMIN'); $changeSet = new ChangeSet(); $changeSet->write(); $base = new ChangeSetTest\BaseObject(); $base->Foo = 1; $base->write(); $changeSet->addObject($base); // New changeset with changes can be published $this->assertTrue($changeSet->canPublish()); $this->assertTrue($changeSet->hasChanges()); // Writing the record to live dissolves the changes in this changeset $base->publishSingle(); $this->assertTrue($changeSet->canPublish()); $this->assertFalse($changeSet->hasChanges()); // Changeset can be safely published without error $changeSet->publish(); } public function testCanEdit() { // Create changeset containing all items (unpublished) $this->logInWithPermission('ADMIN'); $changeSet = new ChangeSet(); $changeSet->write(); $base = $this->objFromFixture(ChangeSetTest\BaseObject::class, 'base'); $changeSet->addObject($base); $changeSet->sync(); $this->assertEquals(5, $changeSet->Changes()->count()); // Check canEdit $this->logOut(); $this->assertFalse($changeSet->canEdit()); $this->logInWithPermission('SomeWrongPermission'); $this->assertFalse($changeSet->canEdit()); $this->logInWithPermission('CMS_ACCESS_CampaignAdmin'); $this->assertTrue($changeSet->canEdit()); } public function testCanCreate() { // Check canCreate $this->logOut(); $this->assertFalse(ChangeSet::singleton()->canCreate()); $this->logInWithPermission('SomeWrongPermission'); $this->assertFalse(ChangeSet::singleton()->canCreate()); $this->logInWithPermission('CMS_ACCESS_CampaignAdmin'); $this->assertTrue(ChangeSet::singleton()->canCreate()); } public function testCanDelete() { // Create changeset containing all items (unpublished) $this->logInWithPermission('ADMIN'); $changeSet = new ChangeSet(); $changeSet->write(); $base = $this->objFromFixture(ChangeSetTest\BaseObject::class, 'base'); $changeSet->addObject($base); $changeSet->sync(); $this->assertEquals(5, $changeSet->Changes()->count()); // Check canDelete $this->logOut(); $this->assertFalse($changeSet->canDelete()); $this->logInWithPermission('SomeWrongPermission'); $this->assertFalse($changeSet->canDelete()); $this->logInWithPermission('CMS_ACCESS_CampaignAdmin'); $this->assertTrue($changeSet->canDelete()); } public function testCanView() { // Create changeset containing all items (unpublished) $this->logInWithPermission('ADMIN'); $changeSet = new ChangeSet(); $changeSet->write(); $base = $this->objFromFixture(ChangeSetTest\BaseObject::class, 'base'); $changeSet->addObject($base); $changeSet->sync(); $this->assertEquals(5, $changeSet->Changes()->count()); // Check canView $this->logOut(); $this->assertFalse($changeSet->canView()); $this->logInWithPermission('SomeWrongPermission'); $this->assertFalse($changeSet->canView()); $this->logInWithPermission('CMS_ACCESS_CampaignAdmin'); $this->assertTrue($changeSet->canView()); } public function testPublish() { $this->publishAllFixtures(); $base = $this->objFromFixture(ChangeSetTest\BaseObject::class, 'base'); $baseID = $base->ID; $baseBefore = $base->Version; $end1 = $this->objFromFixture(ChangeSetTest\EndObject::class, 'end1'); $end1ID = $end1->ID; $end1Before = $end1->Version; // Create a new changest $changeset = new ChangeSet(); $changeset->write(); $changeset->addObject($base); $changeset->addObject($end1); // Make a lot of changes // - ChangeSetTest_Base.base modified // - ChangeSetTest_End.end1 deleted // - new ChangeSetTest_Mid added $base->Foo = 343; $base->write(); $baseAfter = $base->Version; $midNew = new ChangeSetTest\MidObject(); $midNew->Bar = 39; $midNew->write(); $midNewID = $midNew->ID; $midNewAfter = $midNew->Version; $end1->delete(); $changeset->addObject($midNew); // Publish $this->logInWithPermission('ADMIN'); $this->assertTrue($changeset->canPublish()); $this->assertTrue($changeset->isSynced()); $changeset->publish(); $this->assertEquals(ChangeSet::STATE_PUBLISHED, $changeset->State); // Check each item has the correct before/after version applied $baseChange = $changeset->Changes()->filter( [ 'ObjectClass' => ChangeSetTest\BaseObject::class, 'ObjectID' => $baseID, ] )->first(); $this->assertEquals((int)$baseBefore, (int)$baseChange->VersionBefore); $this->assertEquals((int)$baseAfter + 1, (int)$baseChange->VersionAfter); // New live = draft + 1 $this->assertEquals((int)$baseChange->VersionBefore + 2, (int)$baseChange->VersionAfter); $this->assertEquals( (int)$baseChange->VersionAfter, (int)Versioned::get_versionnumber_by_stage(ChangeSetTest\BaseObject::class, Versioned::LIVE, $baseID) ); $end1Change = $changeset->Changes()->filter( [ 'ObjectClass' => ChangeSetTest\EndObject::class, 'ObjectID' => $end1ID, ] )->first(); $this->assertEquals((int)$end1Before, (int)$end1Change->VersionBefore); $this->assertEquals(0, (int)$end1Change->VersionAfter); $this->assertEquals( 0, (int)Versioned::get_versionnumber_by_stage(ChangeSetTest\EndObject::class, Versioned::LIVE, $end1ID) ); $midNewChange = $changeset->Changes()->filter( [ 'ObjectClass' => ChangeSetTest\MidObject::class, 'ObjectID' => $midNewID, ] )->first(); $this->assertEquals(0, (int)$midNewChange->VersionBefore); $this->assertEquals((int)$midNewAfter + 1, (int)$midNewChange->VersionAfter); // New live = draft + 1 $this->assertEquals( (int)$midNewChange->VersionAfter, (int)Versioned::get_versionnumber_by_stage(ChangeSetTest\MidObject::class, Versioned::LIVE, $midNewID) ); // Test trying to re-publish is blocked $this->expectException(BadMethodCallException::class); $this->expectExceptionMessage( "ChangeSet can't be published if it has been already published or reverted." ); $changeset->publish(); } /** * Ensure that related objects are disassociated on live */ public function testUnlinkDisassociated() { $this->publishAllFixtures(); /** * @var BaseObject $base */ $base = $this->objFromFixture(ChangeSetTest\BaseObject::class, 'base'); /** * @var MidObject $mid1 $mid2 */ $mid1 = $this->objFromFixture(ChangeSetTest\MidObject::class, 'mid1'); $mid2 = $this->objFromFixture(ChangeSetTest\MidObject::class, 'mid2'); // Remove mid1 from stage $this->assertEquals($base->ID, $mid1->BaseID); $this->assertEquals($base->ID, $mid2->BaseID); $mid1->deleteFromStage(Versioned::DRAFT); // Publishing recursively should unlinkd this object $changeset = new ChangeSet(); $changeset->write(); $changeset->addObject($base); // Assert changeset only contains root object $this->assertChangeSetLooksLike( $changeset, [ ChangeSetTest\BaseObject::class . '.base' => ChangeSetItem::EXPLICITLY, ChangeSetTest\MidObject::class . '.mid2' => ChangeSetItem::IMPLICITLY, ChangeSetTest\EndObject::class . '.end2' => ChangeSetItem::IMPLICITLY, ] ); $changeset->publish(); // mid1 on live exists, but has BaseID set to zero $mid1Live = Versioned::get_by_stage(ChangeSetTest\MidObject::class, Versioned::LIVE) ->byID($mid1->ID); $this->assertNotNull($mid1Live); $this->assertEquals($mid1->ID, $mid1Live->ID); $this->assertEquals(0, $mid1Live->BaseID); // mid2 on live exists and retains BaseID $mid2Live = Versioned::get_by_stage(ChangeSetTest\MidObject::class, Versioned::LIVE) ->byID($mid2->ID); $this->assertNotNull($mid2Live); $this->assertEquals($mid2->ID, $mid2Live->ID); $this->assertEquals($base->ID, $mid2Live->BaseID); } /** * Test that deletions of relations on a published object will cascade unpublishes on that relation, * using `cascade_deletes` */ public function testPartialCascadeDeletes() { $this->publishAllFixtures(); // Publish mid object with a deleted child /** @var ChangeSetTest\MidObject $mid1 */ $mid1 = $this->objFromFixture(ChangeSetTest\MidObject::class, 'mid1'); /** @var ChangeSetTest\EndObject $end1 */ $end1 = $this->objFromFixture(ChangeSetTest\EndObject::class, 'end1'); $end1->delete(); // Publishing recursively should unlinkd this object $changeset = new ChangeSet(); $changeset->write(); $changeset->addObject($mid1); // Assert changeset only contains root object $this->assertChangeSetLooksLike( $changeset, [ ChangeSetTest\MidObject::class . '.mid1' => ChangeSetItem::EXPLICITLY, ChangeSetTest\EndObject::class . '.end1' => ChangeSetItem::IMPLICITLY, ] ); // Check that change types match /** @var ChangeSetItem $mid1Change */ $mid1Change = ChangeSetItem::get_for_object($mid1)->first(); $this->assertEquals(ChangeSetItem::CHANGE_NONE, $mid1Change->getChangeType()); /** @var ChangeSetItem $end1Change */ $end1Change = ChangeSetItem::get_for_object($end1)->first(); $this->assertEquals(ChangeSetItem::CHANGE_DELETED, $end1Change->getChangeType()); // Ensure item is published $this->assertTrue($end1->isPublished()); $changeset->publish(); // Changeset will unpublish deleted item $this->assertFalse($end1->isPublished()); $this->assertFalse($end1->isOnDraft()); $this->assertTrue($mid1->isPublished()); $this->assertTrue($mid1->isOnDraft()); } public function testCascadeUnversionedDeletes() { $this->publishAllFixtures(); // Publish mid object with a deleted child /** @var ChangeSetTest\MidObject $mid1 */ $mid1 = $this->objFromFixture(ChangeSetTest\MidObject::class, 'mid1'); $unversioned1ID = $this->idFromFixture(ChangeSetTest\UnversionedObject::class, 'unversioned1'); /** @var ChangeSetTest\MidObject $mid2 */ $mid2 = $this->objFromFixture(ChangeSetTest\MidObject::class, 'mid2'); $unstaged1ID = $this->idFromFixture(ChangeSetTest\UnstagedObject::class, 'unstaged1'); // Publishing recursively should unlinkd this object $changeset = new ChangeSet(); $changeset->write(); $changeset->addObject($mid1); $changeset->addObject($mid2); // Assert unversioned object exists $this->assertNotEmpty(ChangeSetTest\UnversionedObject::get()->byID($unversioned1ID)); $this->assertNotEmpty(ChangeSetTest\UnstagedObject::get()->byID($unstaged1ID)); $mid1->delete(); $mid2->delete(); // Unversioned object is immediately deleted $this->assertEmpty(ChangeSetTest\UnversionedObject::get()->byID($unversioned1ID)); $this->assertEmpty(ChangeSetTest\UnstagedObject::get()->byID($unstaged1ID)); // Assert changeset only contains root object and no unversioned objects $this->assertChangeSetLooksLike( $changeset, [ ChangeSetTest\MidObject::class . '.mid1' => ChangeSetItem::EXPLICITLY, ChangeSetTest\EndObject::class . '.end1' => ChangeSetItem::IMPLICITLY, ChangeSetTest\MidObject::class . '.mid2' => ChangeSetItem::EXPLICITLY, ChangeSetTest\EndObject::class . '.end2' => ChangeSetItem::IMPLICITLY, ] ); } public function testIsSyncedCanBeSkipped() { $changeset = new ChangeSetSyncStub(); $changeset->publish(true); $this->assertFalse($changeset->isSyncCalled, 'isSynced is skipped when providing truthy argument to publish'); } } |