diff --git a/setup/itopdesignformat.class.inc.php b/setup/itopdesignformat.class.inc.php index 62b7bca4b..c44a9fb91 100644 --- a/setup/itopdesignformat.class.inc.php +++ b/setup/itopdesignformat.class.inc.php @@ -288,8 +288,6 @@ class iTopDesignFormat return $this->bStatus; } - - /** * Does the conversion, eventually in a recursive manner * @@ -976,6 +974,7 @@ class iTopDesignFormat * @param string $sNodeMetaVersion * * @return void + * @throws \Exception */ private function RestorePreviousNodes($sNodeMetaVersion) { @@ -993,6 +992,15 @@ class iTopDesignFormat while ($oNode) { $oNextNode = $oNode->nextSibling; if ($oNode->nodeType == XML_ELEMENT_NODE) { + // Check for collision + $sId = $oNode->getAttribute('id'); + $sNodeXPath = ($sId != '') ? $oNode->nodeName.'[@id="'.$sId.'"]' : $oNode->nodeName; + $sNodeXPath = $sXPath.'/'.$sNodeXPath; + $oTarget = $oXPath->query($sNodeXPath)->item(0); + if ($oTarget) { + // Do not continue migration + throw new Exception("Trying to restore an existing node $sNodeXPath from version $sNodeMetaVersion"); + } // Restore the modification flags $oModifiedNodeList = $oXPath->query('descendant-or-self::*[@_disabled_delta or @_disabled_rename_from]', $oNode); foreach ($oModifiedNodeList as $oModifiedNode) { diff --git a/test/setup/iTopDesignFormat/Convert-samples/1.6_to_1.7_2.input.xml b/test/setup/iTopDesignFormat/Convert-samples/1.6_to_1.7_2.input.xml index 080650363..673f9865b 100644 --- a/test/setup/iTopDesignFormat/Convert-samples/1.6_to_1.7_2.input.xml +++ b/test/setup/iTopDesignFormat/Convert-samples/1.6_to_1.7_2.input.xml @@ -1,13 +1,13 @@ - - + + - + - + diff --git a/test/setup/iTopDesignFormat/Convert-samples/1.7.input.xml b/test/setup/iTopDesignFormat/Convert-samples/1.7.input.xml new file mode 100644 index 000000000..68499ba8c --- /dev/null +++ b/test/setup/iTopDesignFormat/Convert-samples/1.7.input.xml @@ -0,0 +1,94 @@ + + + + + + + #C53030 + #C53030 + + + ../css/scss-variables.scss + ../css/css-variables.scss + + + ../css/custom.scss + ../css/ui-lightness/jqueryui.scss + ../css/main.scss + + + + + + ../css/css-variables.scss + + + ../css/ui-lightness/jqueryui.scss + ../css/light-grey.scss + + + + + + + + images/class-with-lifecycle.png + + + + + images/class-with-lifecycle.png + + + foo + + + + + images/class-with-lifecycle.png + + + + + images/class-with-lifecycle.png + + + + + + + + + + + true + + new + waiting_for_approval + + + + + ongoing + resolved + + + + + + + + 100 + WelcomeMenu + $$http://fr.wikipedia.org/ + true + + + 30 + + + + + images/itop-logo.png + + diff --git a/test/setup/iTopDesignFormat/Convert-samples/3.0_to_1.7_collision.expected.xml b/test/setup/iTopDesignFormat/Convert-samples/3.0_to_1.7_collision.expected.xml new file mode 100644 index 000000000..7d4e564c7 --- /dev/null +++ b/test/setup/iTopDesignFormat/Convert-samples/3.0_to_1.7_collision.expected.xml @@ -0,0 +1,127 @@ + + + + + + + #C53030 + #C53030 + + + ../css/scss-variables.scss + + + ../css/custom.scss + + + + + bla bla bla + + + + + + + + images/class-with-lifecycle.png + + + + + images/class-with-lifecycle.png + + + foo + + + + + images/class-with-lifecycle.png + + + + + images/class-with-lifecycle.png + + + + + + + + + + + true + + new + waiting_for_approval + + + + + ongoing + resolved + + + + + + + + 100 + WelcomeMenu + $$http://fr.wikipedia.org/ + true + + + 30 + + + + + images/itop-logo.png + + + + + + + /itop_design/branding/themes + + + + + ../css/css-variables.scss + + + ../css/ui-lightness/jqueryui.scss + ../css/light-grey.scss + + + + + + /itop_design/branding/themes/theme[@id="test-red"]/imports + + ../css/css-variables.scss + + + + /itop_design/branding/themes/theme[@id="test-red"]/stylesheets + + ../css/ui-lightness/jqueryui.scss + + + + /itop_design/branding/themes/theme[@id="test-red"]/stylesheets + + ../css/main.scss + + + + + + + diff --git a/test/setup/iTopDesignFormat/Convert-samples/3.0_to_1.7_collision.input.xml b/test/setup/iTopDesignFormat/Convert-samples/3.0_to_1.7_collision.input.xml new file mode 100644 index 000000000..7fec110e3 --- /dev/null +++ b/test/setup/iTopDesignFormat/Convert-samples/3.0_to_1.7_collision.input.xml @@ -0,0 +1,182 @@ + + + + + + + #C53030 + #C53030 + + + ../css/scss-variables.scss + + + ../css/custom.scss + + + + + bla bla bla + + + + + + + + + + foo + + + + + + + + foo + + + + + + + + + foo + bar + + + + + + + + bar + + + + + + + + + + true + + + new + + + + waiting_for_approval + + + + #2B6CB0 + #FFFFFF + + + + + + + ongoing + + + + resolved + + + + #2B6CB0 + #FFFFFF + + + + + + + + + 100 + WelcomeMenu + $$http://fr.wikipedia.org/ + true + + + 30 + + + + + + images/itop-logo.png + images/itop-logo-square.png + + + + + + + /itop_design/branding/themes + + + + + ../css/css-variables.scss + + + ../css/ui-lightness/jqueryui.scss + ../css/light-grey.scss + + + + + + /itop_design/branding/themes/theme[@id="test-red"]/imports + + ../css/css-variables.scss + + + + /itop_design/branding/themes/theme[@id="test-red"]/stylesheets + + ../css/ui-lightness/jqueryui.scss + + + + /itop_design/branding/themes/theme[@id="test-red"]/stylesheets + + ../css/main.scss + + + + + + + diff --git a/test/setup/iTopDesignFormat/iTopDesignFormatTest.php b/test/setup/iTopDesignFormat/iTopDesignFormatTest.php index 37c480ceb..3de9988b2 100644 --- a/test/setup/iTopDesignFormat/iTopDesignFormatTest.php +++ b/test/setup/iTopDesignFormat/iTopDesignFormatTest.php @@ -35,11 +35,10 @@ class TestForITopDesignFormatClass extends ItopTestCase * * @throws \Exception */ - public function testConvert($sTargetVersion, $sXmlFileName) + public function testConvert($sTargetVersion, $sXmlFileName, $iExpectedErrors = 0, $sFirstErrorMessage = '') { $sSamplesRelDirPath = 'Convert-samples/'; $sInputXml = $this->GetFileContent($sSamplesRelDirPath.$sXmlFileName.'.input'); - $sExpectedXml = $this->GetFileContent($sSamplesRelDirPath.$sXmlFileName.'.expected'); $oInputDocument = new DOMDocument(); libxml_clear_errors(); @@ -47,24 +46,84 @@ class TestForITopDesignFormatClass extends ItopTestCase $oInputDocument->loadXML($sInputXml); $oInputDocument->formatOutput = true; $oDesignFormat = new iTopDesignFormat($oInputDocument); - $oDesignFormat->Convert($sTargetVersion); - $sConvertedXml = $oInputDocument->saveXML(); + $bResult = $oDesignFormat->Convert($sTargetVersion); + $aErrors = $oDesignFormat->GetErrors(); + $this->assertCount($iExpectedErrors, $aErrors); + if ($iExpectedErrors > 0) { + $this->assertFalse($bResult); + $this->assertEquals($sFirstErrorMessage, $aErrors[0]); + } + $sConvertedXml = $oInputDocument->saveXML(); // Erase dynamic values $sConvertedXml = preg_replace('@GetFileContent($sSamplesRelDirPath.$sXmlFileName.'.expected'); $this->assertEquals($sExpectedXml, $sConvertedXml); } public function ConvertProvider() + { + return [ + '1.7 to 1.6' => ['1.6', '1.7_to_1.6'], + '1.6 to 1.7 2' => ['1.7', '1.6_to_1.7_2'], + '1.7 to 1.6 2' => ['1.6', '1.7_to_1.6_2'], + '1.7 to 3.0' => ['3.0', '1.7_to_3.0'], + '3.0 to 1.7' => ['1.7', '3.0_to_1.7'], + '3.0 to 1.7 no previous' => ['1.7', '3.0_to_1.7_no_previous'], + '3.0 to 1.7 collision' => ['1.7', '3.0_to_1.7_collision', 1, 'Trying to restore an existing node /itop_design/branding/themes/theme[@id="light-grey"] from version 1.7'], + ]; + } + + /** + * @covers iTopDesignFormat::Convert + * @dataProvider ConvertBackAndForthProvider + * + * @param string $sTargetVersion + * @param string $sXmlFileName Example "1.7_to_1.6". Corresponding files should exist with the ".input" and ".Expected" suffix + * + * @throws \Exception + */ + public function testConvertBackAndForth($sTargetVersion, $sXmlFileName) + { + $sSamplesRelDirPath = 'Convert-samples/'; + $sInputXml = $this->GetFileContent($sSamplesRelDirPath.$sXmlFileName.'.input'); + + $oInputDocument = new DOMDocument(); + libxml_clear_errors(); + $oInputDocument->preserveWhiteSpace = false; + $oInputDocument->loadXML($sInputXml); + + $oXPath = new DOMXPath($oInputDocument); + $oItopDesignNode = $oXPath->query('/itop_design')->item(0); + if (!$oItopDesignNode) { + $this->fail('Bad XML format'); + } + $sSourceVersion = $oItopDesignNode->getAttribute('version'); + + $oInputDocument->formatOutput = true; + $oDesignFormat = new iTopDesignFormat($oInputDocument); + $oDesignFormat->Convert($sTargetVersion); + $sConvertedXml = $oInputDocument->saveXML(); + + // Convert back + $oInputDocument = new DOMDocument(); + libxml_clear_errors(); + $oInputDocument->preserveWhiteSpace = false; + $oInputDocument->loadXML($sConvertedXml); + $oInputDocument->formatOutput = true; + $oDesignFormat = new iTopDesignFormat($oInputDocument); + $oDesignFormat->Convert($sSourceVersion); + $sConvertedXml = $oInputDocument->saveXML(); + + $this->assertEquals($sInputXml, $sConvertedXml); + } + + public function ConvertBackAndForthProvider() { return array( - '1.7 to 1.6' => array('1.6', '1.7_to_1.6'), - '1.6 to 1.7 2' => array('1.7', '1.6_to_1.7_2'), - '1.7 to 1.6 2' => array('1.6', '1.7_to_1.6_2'), - '1.7 to 3.0' => array('3.0', '1.7_to_3.0'), - '3.0 to 1.7' => array('1.7', '3.0_to_1.7'), - '3.0 to 1.7 no previous' => array('1.7', '3.0_to_1.7_no_previous'), + '1.6 to 1.7' => array('1.7', '1.6_to_1.7_2'), + '1.6 to 3.0' => array('3.0', '1.6_to_1.7_2'), + '1.7 to 3.0' => array('3.0', '1.7'), ); }