Files
iTop/test/setup/ModelFactoryTest.php
Romain Quetiez cd010afb48 N°5704 - Unit tests on XML assembly (#329)
* Add a complete test suite for XML assembly

* Add a complete test suite for XML assembly

* Dispatched the test of GetDelta into real unit tests

* Add test for GetDelta on a rename operation

* Add comments on a weird case and a case on rename

* Update XML version after rebase from develop to support/2.7

* Fix phpdoc about coverage

* Remove ModelFactory::GetRootDirs and ItopTestCase::RecurseRmDir+CreateTmpDir+RecurseMkDir+RecurseCopy, that were meant to be introduced in iTop 3.0 and have been copied here by mistake, when rebasing the branch from develop to 2.7.0

* Update test/ItopTestCase.php

Co-authored-by: Molkobain <lajarige.guillaume@free.fr>

* Update test/setup/ModelFactoryTest.php

Co-authored-by: Molkobain <lajarige.guillaume@free.fr>

* Update test/ItopTestCase.php

Co-authored-by: Molkobain <lajarige.guillaume@free.fr>

Co-authored-by: Pierre Goiffon <pierre.goiffon@combodo.com>
Co-authored-by: Molkobain <lajarige.guillaume@free.fr>
2022-11-08 19:43:07 +01:00

1270 lines
29 KiB
PHP

<?php
namespace Combodo\iTop\Test\UnitTest\Core;
use Combodo\iTop\Test\UnitTest\ItopTestCase;
use DOMDocument;
use MFDocument;
use MFElement;
use ModelFactory;
/**
* Class ModelFactoryTest
*
* Test XML assembly, and in particular the following verbs
*
* ┌─────────────────┐
* │ │
* LoadDelta ──────►│ ModelFactory │
* │ ├──►GetDelta
* ApplyChanges ─────►│ ┌──────────┐ │
* ├───┤MFDocument├──┤
* Delete ────────►│ └──────────┘ │
* AddChildNode ────►│ │
* RedefineChildNode ──►│ MFElement │
* Rename ────────►│ │
* SetChildNode ────►│ │
* └─────────────────┘
* @covers ModelFactory
* @covers MFElement
*
*/
class ModelFactoryTest extends ItopTestCase
{
protected function setUp(): void
{
parent::setUp();
require_once(APPROOT.'setup/modelfactory.class.inc.php');
}
/**
* @param $sInitialXML
*
* @return \ModelFactory
* @throws \ReflectionException
*/
protected function MakeVanillaModelFactory($sInitialXML): ModelFactory
{
/* @var MFDocument $oFactoryRoot */
$oFactory = new ModelFactory([]);
$oInitialDocument = new MFDocument();
$oInitialDocument->preserveWhiteSpace = false;
$oInitialDocument->loadXML($sInitialXML);
$this->SetNonPublicProperty($oFactory, 'oDOMDocument', $oInitialDocument);
$this->SetNonPublicProperty($oFactory, 'oRoot', $oInitialDocument->firstChild);
return $oFactory;
}
/**
* @param $sXML
*
* @return false|string
*/
protected function CanonicalizeXML($sXML)
{
// Canonicalize the expected XML (to cope with indentation)
$oExpectedDocument = new DOMDocument();
$oExpectedDocument->preserveWhiteSpace = false;
$oExpectedDocument->loadXML($sXML);
$oExpectedDocument->formatOutput = true;
return $oExpectedDocument->saveXML($oExpectedDocument->firstChild);
}
/**
* @param $sExpected
* @param $sActual
*/
protected function AssertEqualiTopXML($sExpected, $sActual)
{
// Note: assertEquals reports the differences in a diff which is easier to interpret (in PHPStorm)
// as compared to the report given by assertEqualXMLStructure
static::assertEquals($this->CanonicalizeXML($sExpected), $this->CanonicalizeXML($sActual));
}
/**
* Assertion ignoring some of the unexpected decoration brought by DOM Elements.
*/
protected function AssertEqualModels(string $sExpectedXML, ModelFactory $oFactory)
{
return $this->AssertEqualiTopXML($sExpectedXML, $oFactory->Dump(null, true));
}
/**
* @dataProvider providerDeltas
* @covers ModelFactory::LoadDelta
* @covers ModelFactory::ApplyChanges
*/
public function testAlterationByXMLDelta($sInitialXML, $sDeltaXML, $sExpectedXML)
{
$oFactory = $this->MakeVanillaModelFactory($sInitialXML);
$oFactoryRoot = $this->GetNonPublicProperty($oFactory, 'oDOMDocument');
$oDocument = new MFDocument();
$oDocument->loadXML($sDeltaXML);
/* @var MFElement $oDeltaRoot */
$oDeltaRoot = $oDocument->firstChild;
if ($sExpectedXML === null) {
$this->expectException('Exception');
}
$oFactory->LoadDelta($oDeltaRoot, $oFactoryRoot);
$oFactory->ApplyChanges();
$this->AssertEqualModels($sExpectedXML, $oFactory);
}
/**
* @return array
*/
public function providerDeltas()
{
// Basic (structure)
$aDeltas['No change at all'] = [
'sInitialXML' => <<<XML
<nodeA>
<nodeB/>
</nodeA>
XML,
'sDeltaXML' => <<<XML
<nodeA>
<nodeB/>
</nodeA>
XML,
'sExpectedXML' => <<<XML
<nodeA>
<nodeB/>
</nodeA>
XML,
];
$aDeltas['No change at all - mini delta'] = [
'sInitialXML' => <<<XML
<nodeA>
<nodeB/>
</nodeA>
XML,
'sDeltaXML' => <<<XML
<nodeA/>
XML,
'sExpectedXML' => <<<XML
<nodeA>
<nodeB/>
</nodeA>
XML,
];
$aDeltas['_delta="merge" implicit'] = [
'sInitialXML' => <<<XML
<nodeA/>
XML,
'sDeltaXML' => <<<XML
<nodeA>
<nodeB/>
</nodeA>
XML,
'sExpectedXML' => <<<XML
<nodeA>
<nodeB/>
</nodeA>
XML,
];
$aDeltas['_delta="merge" explicit'] = [
'sInitialXML' => <<<XML
<nodeA/>
XML,
'sDeltaXML' => <<<XML
<nodeA>
<nodeB _delta="merge"/>
</nodeA>
XML,
'sExpectedXML' => <<<XML
<nodeA>
<nodeB/>
</nodeA>
XML,
];
$aDeltas['_delta="merge" does not handle data'] = [
'sInitialXML' => <<<XML
<nodeA/>
XML,
'sDeltaXML' => <<<XML
<nodeA>
<nodeB>Ghost busters!!!</nodeB>
</nodeA>
XML,
'sExpectedXML' => <<<XML
<nodeA>
<nodeB/>
</nodeA>
XML,
];
$aDeltas['_delta="merge" recursively'] = [
'sInitialXML' => <<<XML
<nodeA/>
XML,
'sDeltaXML' => <<<XML
<nodeA>
<nodeB>
<nodeC>
<nodeD/>
</nodeC>
</nodeB>
</nodeA>
XML,
'sExpectedXML' => <<<XML
<nodeA>
<nodeB>
<nodeC>
<nodeD/>
</nodeC>
</nodeB>
</nodeA>
XML,
];
// Define or redefine
$aDeltas['_delta="define" without id'] = [
'sInitialXML' => <<<XML
<nodeA/>
XML,
'sDeltaXML' => <<<XML
<nodeA>
<nodeB _delta="define"></nodeB>
</nodeA>
XML,
'sExpectedXML' => <<<XML
<nodeA>
<nodeB/>
</nodeA>
XML,
];
$aDeltas['_delta="define" with id'] = [
'sInitialXML' => <<<XML
<nodeA/>
XML,
'sDeltaXML' => <<<XML
<nodeA>
<item id="toto" _delta="define"></item>
</nodeA>
XML,
'sExpectedXML' => <<<XML
<nodeA>
<item id="toto"></item>
</nodeA>
XML,
];
$aDeltas['_delta="define" but existing node'] = [
'sInitialXML' => <<<XML
<nodeA>
<item id="toto" _delta="define"></item>
</nodeA>
XML,
'sDeltaXML' => <<<XML
<nodeA>
<item id="toto" _delta="define"></item>
</nodeA>
XML,
'sExpectedXML' => null,
];
$aDeltas['_delta="redefine" without id'] = [
'sInitialXML' => <<<XML
<nodeA>
<nodeB>Initial BB</nodeB>
</nodeA>
XML,
'sDeltaXML' => <<<XML
<nodeA>
<nodeB _delta="redefine">Gainsbourg</nodeB>
</nodeA>
XML,
'sExpectedXML' => <<<XML
<nodeA>
<nodeB>Gainsbourg</nodeB>
</nodeA>
XML,
];
$aDeltas['_delta="redefine" with id'] = [
'sInitialXML' => <<<XML
<nodeA>
<item id="toto">Initial BB</item>
</nodeA>
XML,
'sDeltaXML' => <<<XML
<nodeA>
<item id="toto" _delta="redefine">Gainsbourg</item>
</nodeA>
XML,
'sExpectedXML' => <<<XML
<nodeA>
<item id="toto">Gainsbourg</item>
</nodeA>
XML,
];
$aDeltas['_delta="redefine" but missing node'] = [
'sInitialXML' => <<<XML
<nodeA/>
XML,
'sDeltaXML' => <<<XML
<nodeA>
<item id="toto" _delta="redefine">Gainsbourg</item>
</nodeA>
XML,
'sExpectedXML' => null,
];
$aDeltas['_delta="force" without id + missing node'] = [
'sInitialXML' => <<<XML
<nodeA/>
XML,
'sDeltaXML' => <<<XML
<nodeA>
<nodeB _delta="force">Hulk</nodeB>
</nodeA>
XML,
'sExpectedXML' => <<<XML
<nodeA>
<nodeB>Hulk</nodeB>
</nodeA>
XML,
];
$aDeltas['_delta="force" with id + missing node'] = [
'sInitialXML' => <<<XML
<nodeA/>
XML,
'sDeltaXML' => <<<XML
<nodeA>
<item id="toto" _delta="force">Hulk</item>
</nodeA>
XML,
'sExpectedXML' => <<<XML
<nodeA>
<item id="toto">Hulk</item>
</nodeA>
XML,
];
$aDeltas['_delta="force" without id + existing node'] = [
'sInitialXML' => <<<XML
<nodeA>
<nodeB>Initial BB</nodeB>
</nodeA>
XML,
'sDeltaXML' => <<<XML
<nodeA>
<nodeB _delta="force">Gainsbourg</nodeB>
</nodeA>
XML,
'sExpectedXML' => <<<XML
<nodeA>
<nodeB>Gainsbourg</nodeB>
</nodeA>
XML,
];
$aDeltas['_delta="force" with id + existing node'] = [
'sInitialXML' => <<<XML
<nodeA>
<item id="toto">Initial BB</item>
</nodeA>
XML,
'sDeltaXML' => <<<XML
<nodeA>
<item id="toto" _delta="force">Gainsbourg</item>
</nodeA>
XML,
'sExpectedXML' => <<<XML
<nodeA>
<item id="toto">Gainsbourg</item>
</nodeA>
XML,
];
// Rename
$aDeltas['rename'] = [
'sInitialXML' => <<<XML
<nodeA>
<item id="Kent">Kryptonite</item>
</nodeA>
XML,
'sDeltaXML' => <<<XML
<nodeA>
<item id="Superman" _rename_from="Kent"/>
</nodeA>
XML,
'sExpectedXML' => <<<XML
<nodeA>
<item id="Superman">Kryptonite</item>
</nodeA>
XML,
];
$aDeltas['rename but missing node NOT INTUITIVE!!!'] = [
'sInitialXML' => <<<XML
<nodeA/>
XML,
'sDeltaXML' => <<<XML
<nodeA>
<item id="Superman" _rename_from="Kent"/>
</nodeA>
XML,
'sExpectedXML' => <<<XML
<nodeA>
<item id="Superman"/>
</nodeA>
XML,
];
// Delete
$aDeltas['_delta="delete" without id'] = [
'sInitialXML' => <<<XML
<nodeA>
<nodeB>Initial BB</nodeB>
</nodeA>
XML,
'sDeltaXML' => <<<XML
<nodeA>
<nodeB _delta="delete"/>
</nodeA>
XML,
'sExpectedXML' => <<<XML
<nodeA/>
XML,
];
$aDeltas['_delta="delete" with id'] = [
'sInitialXML' => <<<XML
<nodeA>
<item id="toto">Initial BB</item>
</nodeA>
XML,
'sDeltaXML' => <<<XML
<nodeA>
<item id="toto" _delta="delete"/>
</nodeA>
XML,
'sExpectedXML' => <<<XML
<nodeA/>
XML,
];
$aDeltas['_delta="delete" but missing node'] = [
'sInitialXML' => <<<XML
<nodeA/>
XML,
'sDeltaXML' => <<<XML
<nodeA>
<item id="toto" _delta="delete"/>
</nodeA>
XML,
'sExpectedXML' => null,
];
$aDeltas['_delta="delete_if_exists" without id + existing node'] = [
'sInitialXML' => <<<XML
<nodeA>
<nodeB>Initial BB</nodeB>
</nodeA>
XML,
'sDeltaXML' => <<<XML
<nodeA>
<nodeB _delta="delete_if_exists"/>
</nodeA>
XML,
'sExpectedXML' => <<<XML
<nodeA/>
XML,
];
$aDeltas['_delta="delete_if_exists" with id + existing node'] = [
'sInitialXML' => <<<XML
<nodeA>
<item id="toto">Initial BB</item>
</nodeA>
XML,
'sDeltaXML' => <<<XML
<nodeA>
<item id="toto" _delta="delete_if_exists"/>
</nodeA>
XML,
'sExpectedXML' => <<<XML
<nodeA/>
XML,
];
$aDeltas['_delta="delete_if_exists" without id + missing node'] = [
'sInitialXML' => <<<XML
<nodeA/>
XML,
'sDeltaXML' => <<<XML
<nodeA>
<nodeB _delta="delete_if_exists"/>
</nodeA>
XML,
'sExpectedXML' => <<<XML
<nodeA/>
XML,
];
$aDeltas['_delta="delete_if_exists" with id + missing node'] = [
'sInitialXML' => <<<XML
<nodeA/>
XML,
'sDeltaXML' => <<<XML
<nodeA>
<item id="toto" _delta="delete_if_exists"/>
</nodeA>
XML,
'sExpectedXML' => <<<XML
<nodeA/>
XML,
];
// Conditionals
$aDeltas['_delta="must_exist"'] = [
'sInitialXML' => <<<XML
<nodeA>
<nodeB/>
</nodeA>
XML,
'sDeltaXML' => <<<XML
<nodeA>
<nodeB _delta="must_exist">
<nodeC _delta="define"/>
</nodeB>
</nodeA>
XML,
'sExpectedXML' => <<<XML
<nodeA>
<nodeB>
<nodeC/>
</nodeB>
</nodeA>
XML,
];
$aDeltas['_delta="must_exist on missing node"'] = [
'sInitialXML' => <<<XML
<nodeA/>
XML,
'sDeltaXML' => <<<XML
<nodeA>
<nodeB _delta="must_exist">
<nodeC _delta="define"/>
</nodeB>
</nodeA>
XML,
'sExpectedXML' => null,
];
$aDeltas['_delta="if_exists on missing node"'] = [
'sInitialXML' => <<<XML
<nodeA>
</nodeA>
XML,
'sDeltaXML' => <<<XML
<nodeA>
<nodeB _delta="if_exists">
<nodeC _delta="define"/>
</nodeB>
</nodeA>
XML,
'sExpectedXML' => <<<XML
<nodeA>
</nodeA>
XML,
];
$aDeltas['_delta="if_exists on existing node"'] = [
'sInitialXML' => <<<XML
<nodeA>
<nodeB/>
</nodeA>
XML,
'sDeltaXML' => <<<XML
<nodeA>
<nodeB _delta="if_exists">
<nodeC _delta="define"/>
</nodeB>
</nodeA>
XML,
'sExpectedXML' => <<<XML
<nodeA>
<nodeB>
<nodeC/>
</nodeB>
</nodeA>
XML,
];
$aDeltas['_delta="define_if_not_exists on missing node"'] = [
'sInitialXML' => <<<XML
<nodeA/>
XML,
'sDeltaXML' => <<<XML
<nodeA>
<nodeB _delta="define_if_not_exists">The incredible Hulk</nodeB>
</nodeA>
XML,
'sExpectedXML' => <<<XML
<nodeA>
<nodeB>The incredible Hulk</nodeB>
</nodeA>
XML,
];
$aDeltas['_delta="define_if_not_exists on existing node"'] = [
'sInitialXML' => <<<XML
<nodeA>
<nodeB>Luke Banner</nodeB>
</nodeA>
XML,
'sDeltaXML' => <<<XML
<nodeA>
<nodeB _delta="define_if_not_exists">The incredible Hulk</nodeB>
</nodeA>
XML,
'sExpectedXML' => <<<XML
<nodeA>
<nodeB>Luke Banner</nodeB>
</nodeA>
XML,
];
return $aDeltas;
}
/**
* @dataProvider providerAlterationAPIs
* @covers \ModelFactory::GetDelta
* @covers \MFElement::AddChildNode
* @covers \MFElement::RedefineChildNode
* @covers \MFElement::SetChildNode
* @covers \MFElement::Delete
*/
public function testAlterationsByAPIs($sInitialXML, $sOperation, $sExpectedXML)
{
$oFactory = $this->MakeVanillaModelFactory($sInitialXML);
if ($sExpectedXML === null) {
$this->expectException('Exception');
}
switch ($sOperation) {
case 'Delete':
/* @var MFElement $oTargetNode */
$oTargetNode = $oFactory->GetNodes('//target_tag', null, false)->item(0);
$oTargetNode->Delete();
break;
case 'AddChildNodeToContainer':
$oContainerNode = $oFactory->GetNodes('//container_tag', null, false)->item(0);
$oFactoryRoot = $this->GetNonPublicProperty($oFactory, 'oDOMDocument');
$oChild = $oFactoryRoot->CreateElement('target_tag', 'Hello, I\'m a newly added node');
/* @var MFElement $oContainerNode */
$oContainerNode->AddChildNode($oChild);
break;
case 'RedefineChildNodeToContainer':
$oContainerNode = $oFactory->GetNodes('//container_tag', null, false)->item(0);
$oFactoryRoot = $this->GetNonPublicProperty($oFactory, 'oDOMDocument');
$oChild = $oFactoryRoot->CreateElement('target_tag', 'Hello, I\'m replacing the previous node');
/* @var MFElement $oContainerNode */
$oContainerNode->RedefineChildNode($oChild);
break;
case 'SetChildNodeToContainer':
$oContainerNode = $oFactory->GetNodes('//container_tag', null, false)->item(0);
$oFactoryRoot = $this->GetNonPublicProperty($oFactory, 'oDOMDocument');
$oChild = $oFactoryRoot->CreateElement('target_tag', 'Hello, I\'m replacing the previous node');
/* @var MFElement $oContainerNode */
$oContainerNode->SetChildNode($oChild);
break;
default:
static::fail("Unknown operation '$sOperation'");
}
if ($sExpectedXML !== null) {
$this->AssertEqualModels($sExpectedXML, $oFactory);
}
}
/**
* @return array[]
*/
public function providerAlterationAPIs()
{
define('CASE_NO_FLAG', <<<XML
<root_tag>
<container_tag>
<target_tag></target_tag>
</container_tag>
</root_tag>
XML
);
define('CASE_ABOVE_A_FLAG', <<<XML
<root_tag>
<container_tag>
<target_tag>
<child_tag _alteration="added">Blah</child_tag>
</target_tag>
</container_tag>
</root_tag>
XML
);
define('CASE_IN_A_DEFINITION', <<<XML
<root_tag>
<container_tag _alteration="added">
<target_tag>
<child_tag>Blah</child_tag>
</target_tag>
</container_tag>
</root_tag>
XML
);
define('CASE_FLAG_ON_TARGET_define', <<<XML
<root_tag>
<container_tag>
<target_tag _alteration="added"/>
</container_tag>
</root_tag>
XML
);
define('CASE_FLAG_ON_TARGET_redefine', <<<XML
<root_tag>
<container_tag>
<target_tag _alteration="replaced"/>
</container_tag>
</root_tag>
XML
);
define('CASE_FLAG_ON_TARGET_needed', <<<XML
<root_tag>
<container_tag>
<target_tag _alteration="needed"/>
</container_tag>
</root_tag>
XML
);
define('CASE_FLAG_ON_TARGET_forced', <<<XML
<root_tag>
<container_tag>
<target_tag _alteration="forced"/>
</container_tag>
</root_tag>
XML
);
define('CASE_FLAG_ON_TARGET_removed', <<<XML
<root_tag>
<container_tag>
<target_tag _alteration="removed"/>
</container_tag>
</root_tag>
XML
);
define('CASE_FLAG_ON_TARGET_old_id', <<<XML
<root_tag>
<container_tag>
<target_tag id="fraise" _old_id="tagada"/>
</container_tag>
</root_tag>
XML
);
define('CASE_MISSING_TARGET', <<<XML
<root_tag>
<container_tag/>
</root_tag>
XML
);
$aData = [
'CASE_NO_FLAG Delete' => [CASE_NO_FLAG , 'Delete', <<<XML
<root_tag>
<container_tag>
<target_tag _alteration="removed"/>
</container_tag>
</root_tag>
XML
],
'CASE_ABOVE_A_FLAG Delete' => [CASE_ABOVE_A_FLAG , 'Delete', <<<XML
<root_tag>
<container_tag>
<target_tag _alteration="removed"/>
</container_tag>
</root_tag>
XML
],
'CASE_IN_A_DEFINITION Delete' => [CASE_IN_A_DEFINITION , 'Delete', <<<XML
<root_tag>
<container_tag _alteration="added"/>
</root_tag>
XML
],
'CASE_FLAG_ON_TARGET_define Delete' => [CASE_FLAG_ON_TARGET_define , 'Delete', <<<XML
<root_tag>
<container_tag/>
</root_tag>
XML
],
'CASE_FLAG_ON_TARGET_redefine Delete' => [CASE_FLAG_ON_TARGET_redefine , 'Delete', <<<XML
<root_tag>
<container_tag>
<target_tag _alteration="removed"/>
</container_tag>
</root_tag>
XML
],
'CASE_FLAG_ON_TARGET_needed Delete' => [CASE_FLAG_ON_TARGET_needed , 'Delete', <<<XML
<root_tag>
<container_tag/>
</root_tag>
XML
],
'CASE_FLAG_ON_TARGET_forced Delete' => [CASE_FLAG_ON_TARGET_forced , 'Delete', <<<XML
<root_tag>
<container_tag/>
</root_tag>
XML
],
'CASE_FLAG_ON_TARGET_removed Delete' => [CASE_FLAG_ON_TARGET_removed , 'Delete', null
],
'CASE_FLAG_ON_TARGET_old_id Delete' => [CASE_FLAG_ON_TARGET_old_id , 'Delete', <<<XML
<root_tag>
<container_tag>
<target_tag id="fraise" _old_id="tagada" _alteration="removed"/>
</container_tag>
</root_tag>
XML
],
'CASE_NO_FLAG AddChildNode' => [CASE_NO_FLAG , 'AddChildNodeToContainer', null
],
'CASE_ABOVE_A_FLAG AddChildNode' => [CASE_ABOVE_A_FLAG , 'AddChildNodeToContainer', null
],
'CASE_IN_A_DEFINITION AddChildNode' => [CASE_IN_A_DEFINITION , 'AddChildNodeToContainer', null
],
'CASE_FLAG_ON_TARGET_define AddChildNode' => [CASE_FLAG_ON_TARGET_define , 'AddChildNodeToContainer', null
],
'CASE_FLAG_ON_TARGET_redefine AddChildNode' => [CASE_FLAG_ON_TARGET_redefine , 'AddChildNodeToContainer', null
],
'CASE_FLAG_ON_TARGET_needed AddChildNode' => [CASE_FLAG_ON_TARGET_needed , 'AddChildNodeToContainer', null
],
'CASE_FLAG_ON_TARGET_forced AddChildNode' => [CASE_FLAG_ON_TARGET_forced , 'AddChildNodeToContainer', null
],
'CASE_FLAG_ON_TARGET_removed AddChildNode' => [CASE_FLAG_ON_TARGET_removed , 'AddChildNodeToContainer', <<<XML
<root_tag>
<container_tag>
<target_tag _alteration="replaced">Hello, I'm a newly added node</target_tag>
</container_tag>
</root_tag>
XML
],
'CASE_FLAG_ON_TARGET_old_id AddChildNode' => [CASE_FLAG_ON_TARGET_old_id , 'AddChildNodeToContainer', null
],
'CASE_MISSING_TARGET AddChildNode' => [CASE_MISSING_TARGET , 'AddChildNodeToContainer', <<<XML
<root_tag>
<container_tag>
<target_tag _alteration="added">Hello, I'm a newly added node</target_tag>
</container_tag>
</root_tag>
XML
],
'CASE_NO_FLAG RedefineChildNode' => [CASE_NO_FLAG , 'RedefineChildNodeToContainer', <<<XML
<root_tag>
<container_tag>
<target_tag _alteration="replaced">Hello, I'm replacing the previous node</target_tag>
</container_tag>
</root_tag>
XML
],
'CASE_ABOVE_A_FLAG RedefineChildNode' => [CASE_ABOVE_A_FLAG , 'RedefineChildNodeToContainer', <<<XML
<root_tag>
<container_tag>
<target_tag _alteration="replaced">Hello, I'm replacing the previous node</target_tag>
</container_tag>
</root_tag>
XML
],
'CASE_IN_A_DEFINITION RedefineChildNode' => [CASE_IN_A_DEFINITION , 'RedefineChildNodeToContainer', <<<XML
<root_tag>
<container_tag _alteration="added">
<target_tag>Hello, I'm replacing the previous node</target_tag>
</container_tag>
</root_tag>
XML
],
'CASE_FLAG_ON_TARGET_define RedefineChildNode' => [CASE_FLAG_ON_TARGET_define , 'RedefineChildNodeToContainer', <<<XML
<root_tag>
<container_tag>
<target_tag _alteration="added">Hello, I'm replacing the previous node</target_tag>
</container_tag>
</root_tag>
XML
],
'CASE_FLAG_ON_TARGET_redefine RedefineChildNode' => [CASE_FLAG_ON_TARGET_redefine , 'RedefineChildNodeToContainer', <<<XML
<root_tag>
<container_tag>
<target_tag _alteration="replaced">Hello, I'm replacing the previous node</target_tag>
</container_tag>
</root_tag>
XML
],
// Note: buggy case ?
'CASE_FLAG_ON_TARGET_needed RedefineChildNode' => [CASE_FLAG_ON_TARGET_needed , 'RedefineChildNodeToContainer', <<<XML
<root_tag>
<container_tag>
<target_tag _alteration="needed">Hello, I'm replacing the previous node</target_tag>
</container_tag>
</root_tag>
XML
],
'CASE_FLAG_ON_TARGET_forced RedefineChildNode' => [CASE_FLAG_ON_TARGET_forced , 'RedefineChildNodeToContainer', <<<XML
<root_tag>
<container_tag>
<target_tag _alteration="forced">Hello, I'm replacing the previous node</target_tag>
</container_tag>
</root_tag>
XML
],
'CASE_FLAG_ON_TARGET_removed RedefineChildNode' => [CASE_FLAG_ON_TARGET_removed , 'RedefineChildNodeToContainer', null
],
'CASE_FLAG_ON_TARGET_old_id RedefineChildNode' => [CASE_FLAG_ON_TARGET_old_id , 'RedefineChildNodeToContainer', <<<XML
<root_tag>
<container_tag>
<target_tag _alteration="replaced">Hello, I'm replacing the previous node</target_tag>
</container_tag>
</root_tag>
XML
],
'CASE_MISSING_TARGET RedefineChildNode' => [CASE_MISSING_TARGET , 'RedefineChildNodeToContainer', null
],
'CASE_NO_FLAG SetChildNode' => [CASE_NO_FLAG , 'SetChildNodeToContainer', <<<XML
<root_tag>
<container_tag>
<target_tag _alteration="replaced">Hello, I'm replacing the previous node</target_tag>
</container_tag>
</root_tag>
XML
],
'CASE_ABOVE_A_FLAG SetChildNode' => [CASE_ABOVE_A_FLAG , 'SetChildNodeToContainer', <<<XML
<root_tag>
<container_tag>
<target_tag _alteration="replaced">Hello, I'm replacing the previous node</target_tag>
</container_tag>
</root_tag>
XML
],
'CASE_IN_A_DEFINITION SetChildNode' => [CASE_IN_A_DEFINITION , 'SetChildNodeToContainer', <<<XML
<root_tag>
<container_tag _alteration="added">
<target_tag>Hello, I'm replacing the previous node</target_tag>
</container_tag>
</root_tag>
XML
],
'CASE_FLAG_ON_TARGET_define SetChildNode' => [CASE_FLAG_ON_TARGET_define , 'SetChildNodeToContainer', <<<XML
<root_tag>
<container_tag>
<target_tag _alteration="added">Hello, I'm replacing the previous node</target_tag>
</container_tag>
</root_tag>
XML
],
'CASE_FLAG_ON_TARGET_redefine SetChildNode' => [CASE_FLAG_ON_TARGET_redefine , 'SetChildNodeToContainer', <<<XML
<root_tag>
<container_tag>
<target_tag _alteration="replaced">Hello, I'm replacing the previous node</target_tag>
</container_tag>
</root_tag>
XML
],
// Note: buggy case ?
'CASE_FLAG_ON_TARGET_needed SetChildNode' => [CASE_FLAG_ON_TARGET_needed , 'SetChildNodeToContainer', <<<XML
<root_tag>
<container_tag>
<target_tag _alteration="needed">Hello, I'm replacing the previous node</target_tag>
</container_tag>
</root_tag>
XML
],
'CASE_FLAG_ON_TARGET_forced SetChildNode' => [CASE_FLAG_ON_TARGET_forced , 'SetChildNodeToContainer', <<<XML
<root_tag>
<container_tag>
<target_tag _alteration="forced">Hello, I'm replacing the previous node</target_tag>
</container_tag>
</root_tag>
XML
],
'CASE_FLAG_ON_TARGET_removed SetChildNode' => [CASE_FLAG_ON_TARGET_removed , 'SetChildNodeToContainer', <<<XML
<root_tag>
<container_tag>
<target_tag _alteration="replaced">Hello, I'm replacing the previous node</target_tag>
</container_tag>
</root_tag>
XML
],
'CASE_FLAG_ON_TARGET_old_id SetChildNode' => [CASE_FLAG_ON_TARGET_old_id , 'SetChildNodeToContainer', <<<XML
<root_tag>
<container_tag>
<target_tag _old_id="tagada" _alteration="replaced">Hello, I'm replacing the previous node</target_tag>
</container_tag>
</root_tag>
XML
],
'CASE_MISSING_TARGET SetChildNode' => [CASE_MISSING_TARGET , 'SetChildNodeToContainer', <<<XML
<root_tag>
<container_tag>
<target_tag _alteration="added">Hello, I'm replacing the previous node</target_tag>
</container_tag>
</root_tag>
XML
],
];
return $aData;
}
/**
* @covers \ModelFactory::LoadDelta
* @covers \ModelFactory::GetDelta
* @covers \ModelFactory::GetDeltaDocument
* @dataProvider providerGetDelta
*/
public function testGetDelta($sInitialXMLInternal, $sExpectedXMLDelta)
{
// constants aren't accessible in the data provider :(
$sExpectedXMLDelta = str_replace('##ITOP_DESIGN_LATEST_VERSION##', ITOP_DESIGN_LATEST_VERSION, $sExpectedXMLDelta);
$oFactory = $this->MakeVanillaModelFactory($sInitialXMLInternal);
// Get the delta back
$sNewDeltaXML = $oFactory->GetDelta();
static::AssertEqualiTopXML($sExpectedXMLDelta, $sNewDeltaXML);
}
/**
* @return array[]
*/
public function providerGetDelta()
{
return [
'no alteration' => [
'sInitialXMLInternal' => <<<XML
<root_node>
<james_bond>Roger Moore</james_bond>
<stairway_to_heaven/>
<robot id="r2d2"/>
</root_node>
XML,
// Weird, but seems ok as of now
'sExpectedXMLDelta' => <<<XML
<?xml version="1.0" encoding="UTF-8"?>
<itop_design xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="##ITOP_DESIGN_LATEST_VERSION##"/>
XML
,
],
'_alteration="added" singleton' => [
'sInitialXMLInternal' => <<<XML
<root_node>
<james_bond _alteration="added"/>
</root_node>
XML,
'sExpectedXMLDelta' => <<<XML
<?xml version="1.0" encoding="UTF-8"?>
<root_node>
<james_bond _delta="define"/>
</root_node>
XML
],
'_alteration="added" with value' => [
'sInitialXMLInternal' => <<<XML
<root_node>
<james_bond _alteration="added">Roger Moore</james_bond>
</root_node>
XML,
'sExpectedXMLDelta' => <<<XML
<?xml version="1.0" encoding="UTF-8"?>
<root_node>
<james_bond _delta="define">Roger Moore</james_bond>
</root_node>
XML
],
'_alteration="added" with subtree' => [
'sInitialXMLInternal' => <<<XML
<root_node>
<james_bond _alteration="added">
<name>Moore</name>
<last_name>Roger</last_name>
</james_bond>
</root_node>
XML,
'sExpectedXMLDelta' => <<<XML
<?xml version="1.0" encoding="UTF-8"?>
<root_node>
<james_bond _delta="define">
<name>Moore</name>
<last_name>Roger</last_name>
</james_bond>
</root_node>
XML
],
'_alteration="forced" singleton' => [
'sInitialXMLInternal' => <<<XML
<root_node>
<james_bond _alteration="forced"/>
</root_node>
XML,
'sExpectedXMLDelta' => <<<XML
<?xml version="1.0" encoding="UTF-8"?>
<root_node>
<james_bond _delta="force"/>
</root_node>
XML
],
'_alteration="forced" with value' => [
'sInitialXMLInternal' => <<<XML
<root_node>
<james_bond _alteration="forced">Roger Moore</james_bond>
</root_node>
XML,
'sExpectedXMLDelta' => <<<XML
<?xml version="1.0" encoding="UTF-8"?>
<root_node>
<james_bond _delta="force">Roger Moore</james_bond>
</root_node>
XML
],
'_alteration="forced" with subtree' => [
'sInitialXMLInternal' => <<<XML
<root_node>
<james_bond _alteration="forced">
<name>Moore</name>
<last_name>Roger</last_name>
</james_bond>
</root_node>
XML,
'sExpectedXMLDelta' => <<<XML
<?xml version="1.0" encoding="UTF-8"?>
<root_node>
<james_bond _delta="force">
<name>Moore</name>
<last_name>Roger</last_name>
</james_bond>
</root_node>
XML
],
'_alteration="needed" singleton' => [
'sInitialXMLInternal' => <<<XML
<root_node>
<james_bond _alteration="needed"/>
</root_node>
XML,
'sExpectedXMLDelta' => <<<XML
<?xml version="1.0" encoding="UTF-8"?>
<root_node>
<james_bond _delta="define_if_not_exists"/>
</root_node>
XML
],
'_alteration="needed" with value' => [
'sInitialXMLInternal' => <<<XML
<root_node>
<james_bond _alteration="needed">Roger Moore</james_bond>
</root_node>
XML,
'sExpectedXMLDelta' => <<<XML
<?xml version="1.0" encoding="UTF-8"?>
<root_node>
<james_bond _delta="define_if_not_exists">Roger Moore</james_bond>
</root_node>
XML
],
'_alteration="needed" with subtree' => [
'sInitialXMLInternal' => <<<XML
<root_node>
<james_bond _alteration="needed">
<name>Moore</name>
<last_name>Roger</last_name>
</james_bond>
</root_node>
XML,
'sExpectedXMLDelta' => <<<XML
<?xml version="1.0" encoding="UTF-8"?>
<root_node>
<james_bond _delta="define_if_not_exists">
<name>Moore</name>
<last_name>Roger</last_name>
</james_bond>
</root_node>
XML
],
'_alteration="replaced" with value' => [
'sInitialXMLInternal' => <<<XML
<root_node>
<james_bond _alteration="replaced">Sean Connery</james_bond>
</root_node>
XML,
'sExpectedXMLDelta' => <<<XML
<?xml version="1.0" encoding="UTF-8"?>
<root_node>
<james_bond _delta="redefine">Sean Connery</james_bond>
</root_node>
XML
],
'_alteration="replaced" with subtree' => [
'sInitialXMLInternal' => <<<XML
<root_node>
<james_bond _alteration="added">
<name>Sean</name>
<last_name>Connery</last_name>
</james_bond>
</root_node>
XML,
'sExpectedXMLDelta' => <<<XML
<?xml version="1.0" encoding="UTF-8"?>
<root_node>
<james_bond _delta="define">
<name>Sean</name>
<last_name>Connery</last_name>
</james_bond>
</root_node>
XML
],
'_alteration="removed"' => [
'sInitialXMLInternal' => <<<XML
<root_node>
<james_bond _alteration="removed"/>
</root_node>
XML,
'sExpectedXMLDelta' => <<<XML
<?xml version="1.0" encoding="UTF-8"?>
<root_node>
<james_bond _delta="delete"/>
</root_node>
XML
],
'_old_id' => [
'sInitialXMLInternal' => <<<XML
<root_node>
<james_bond id="Sean" _old_id="Roger"/>
</root_node>
XML,
'sExpectedXMLDelta' => <<<XML
<?xml version="1.0" encoding="UTF-8"?>
<root_node>
<james_bond id="Sean" _rename_from="Roger" _delta="must_exist"/>
</root_node>
XML
],
'_old_id with subtree' => [
'sInitialXMLInternal' => <<<XML
<root_node>
<james_bond id="Sean" _old_id="Roger">
<subtree _alteration="added">etc.</subtree>
</james_bond>
</root_node>
XML,
'sExpectedXMLDelta' => <<<XML
<?xml version="1.0" encoding="UTF-8"?>
<root_node>
<james_bond id="Sean" _rename_from="Roger" _delta="must_exist">
<subtree _delta="define">etc.</subtree>
</james_bond>
</root_node>
XML
],
];
}
}