mirror of
https://github.com/Combodo/iTop.git
synced 2026-05-20 07:42:17 +02:00
Merge branch 'develop' into feature/uninstallation
This commit is contained in:
@@ -73,7 +73,7 @@ class QueryTest extends ItopDataTestCase
|
||||
* @param string $sOql query oql phrase
|
||||
* @param string|null $sFields fields to export
|
||||
*/
|
||||
private function CreateQueryOQL(string $sName, string $sDescription, string $sOql, string $sFields = null): QueryOQL
|
||||
private function CreateQueryOQL(string $sName, string $sDescription, string $sOql, ?string $sFields = null): QueryOQL
|
||||
{
|
||||
$oQuery = new QueryOQL();
|
||||
$oQuery->Set('name', $sName);
|
||||
|
||||
@@ -936,4 +936,46 @@ class utilsTest extends ItopTestCase
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
public function testLoadParamFile()
|
||||
{
|
||||
$sTmpFileInsideItop = APPROOT.'data/test/testLoadParamFile.params';
|
||||
$sDir = dirname($sTmpFileInsideItop);
|
||||
if (!is_dir($sDir)) {
|
||||
mkdir($sDir, 0777, true);
|
||||
}
|
||||
$sParamName = 'IP1';
|
||||
$sParamValue = 'IV1';
|
||||
$sParams = <<<INI
|
||||
# comment
|
||||
$sParamName = $sParamValue
|
||||
INI;
|
||||
file_put_contents($sTmpFileInsideItop, $sParams);
|
||||
|
||||
try {
|
||||
$this->expectException(\Exception::class);
|
||||
$this->expectExceptionMessage("File '$sTmpFileInsideItop' should be outside iTop");
|
||||
self::InvokeNonPublicStaticMethod(utils::class, 'LoadParamFile', [$sTmpFileInsideItop]);
|
||||
self::assertNotEquals($sParamValue, utils::ReadParam($sParamName, null), "utils::LoadParamFile() should NOT have loaded the file: $sTmpFileInsideItop");
|
||||
} finally {
|
||||
if (file_exists($sTmpFileInsideItop)) {
|
||||
unlink($sTmpFileInsideItop);
|
||||
}
|
||||
}
|
||||
|
||||
$sParamName = 'OP2';
|
||||
$sParamValue = 'OV2';
|
||||
|
||||
$sTmpFileOutsideItop = tempnam(sys_get_temp_dir(), 'utils-test');
|
||||
$sParams = <<<INI
|
||||
# comment
|
||||
$sParamName = $sParamValue
|
||||
INI;
|
||||
|
||||
file_put_contents($sTmpFileOutsideItop, $sParams);
|
||||
self::InvokeNonPublicStaticMethod(utils::class, 'LoadParamFile', [$sTmpFileOutsideItop]);
|
||||
self::assertEquals($sParamValue, utils::ReadParam($sParamName, null), "utils::LoadParamFile() should have loaded the file: $sTmpFileOutsideItop");
|
||||
|
||||
unlink($sTmpFileOutsideItop);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,13 +13,6 @@ class AttributeDefinitionTest extends ItopDataTestCase
|
||||
{
|
||||
public const CREATE_TEST_ORG = true;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
require_once(APPROOT.'core/attributedef.class.inc.php');
|
||||
|
||||
}
|
||||
|
||||
public function testGetImportColumns()
|
||||
{
|
||||
$oAttributeDefinition = MetaModel::GetAttributeDef("ApplicationSolution", "status");
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* @copyright Copyright (C) 2010-2026 Combodo SAS
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
namespace Combodo\iTop\Test\UnitTest\Core;
|
||||
|
||||
use AttributeText;
|
||||
use Combodo\iTop\Test\UnitTest\ItopDataTestCase;
|
||||
|
||||
class AttributeTextTest extends ItopDataTestCase
|
||||
{
|
||||
protected \Organization $oTestOrganizationForAttributeText;
|
||||
|
||||
public function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
$this->oTestOrganizationForAttributeText = $this->CreateOrganization('Test for AttributeTextTest');
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers AttributeText::RenderWikiHtml
|
||||
*/
|
||||
public function testRenderWikiHtml_nonWikiUrlVariants()
|
||||
{
|
||||
// String value
|
||||
$sInput = 'This hyperlink https://combodo.com should be in an anchor tag.';
|
||||
$sExpected = 'This hyperlink <a href="https://combodo.com">https://combodo.com</a> should be in an anchor tag.';
|
||||
$this->assertEquals($sExpected, AttributeText::RenderWikiHtml($sInput));
|
||||
|
||||
// Empty string value
|
||||
$this->assertEquals('', AttributeText::RenderWikiHtml(''));
|
||||
|
||||
// Null value
|
||||
$this->assertEquals('', AttributeText::RenderWikiHtml(null));
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers AttributeText::RenderWikiHtml
|
||||
*/
|
||||
public function testRenderWikiHtml_bWikiOnlyAbsentOrFalse_shouldTransformBothRegularAndWikiHyperlinks()
|
||||
{
|
||||
$sInput = 'A regular hyperlink https://combodo.com and a wiki hyperlink to an existing object [[Organization:'.$this->oTestOrganizationForAttributeText->GetKey().']]';
|
||||
|
||||
// bWikiOnly default value
|
||||
$sResult = AttributeText::RenderWikiHtml($sInput);
|
||||
$this->assertStringContainsString('<a href="https://combodo.com">', $sResult);
|
||||
$this->assertStringContainsString('class="object-ref-link"', $sResult);
|
||||
|
||||
// bWikiOnly = false
|
||||
$sResult = AttributeText::RenderWikiHtml($sInput, false);
|
||||
$this->assertStringContainsString('<a href="https://combodo.com">', $sResult);
|
||||
$this->assertStringContainsString('class="object-ref-link"', $sResult);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers AttributeText::RenderWikiHtml
|
||||
*/
|
||||
public function testRenderWikiHtml_bWikiOnlyToTrue_shouldNotTransformRegularHyperlinkButTransformWikiHyperlink()
|
||||
{
|
||||
$sInput = 'A regular hyperlink https://combodo.com and a wiki hyperlink to an existing object [[Organization:'.$this->oTestOrganizationForAttributeText->GetKey().']]';
|
||||
$sResult = AttributeText::RenderWikiHtml($sInput, true);
|
||||
$this->assertStringNotContainsString('<a href="https://combodo.com">', $sResult);
|
||||
$this->assertStringContainsString('class="object-ref-link"', $sResult);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers AttributeText::RenderWikiHtml
|
||||
*/
|
||||
public function testRenderWikiHtml_shouldTransformWikiHyperlinkForExistingObjectsOnly()
|
||||
{
|
||||
$sInput = 'A wiki hyperlink to a non existing object [[Organization:123456789]] and a wiki hyperlink to an existing object [[Organization:'.$this->oTestOrganizationForAttributeText->GetKey().']]';
|
||||
$sResult = AttributeText::RenderWikiHtml($sInput);
|
||||
$this->assertStringContainsString('wiki_broken_link', $sResult);
|
||||
$this->assertStringContainsString('class="object-ref-link"', $sResult);
|
||||
}
|
||||
}
|
||||
@@ -80,7 +80,7 @@ class BulkChangeTest extends ItopDataTestCase
|
||||
* @param $aExtKeys
|
||||
* @param $aReconcilKeys
|
||||
*/
|
||||
public function testBulkChangeWithoutInitData($aCSVData, $aAttributes, $aExtKeys, $aReconcilKeys, $aResult, array $aResultHTML = null)
|
||||
public function testBulkChangeWithoutInitData($aCSVData, $aAttributes, $aExtKeys, $aReconcilKeys, $aResult, ?array $aResultHTML = null)
|
||||
{
|
||||
$this->debug("aReconcilKeys:".$aReconcilKeys[0]);
|
||||
$oBulk = new BulkChange(
|
||||
|
||||
@@ -158,4 +158,173 @@ EOF;
|
||||
$this->assertEquals($sExpectedValue, $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider OrganizationsForExportSanitizeExcelExportProvider
|
||||
*
|
||||
* @param $aListOrg
|
||||
* @param $aExpectedValues
|
||||
* @return void
|
||||
* @throws \CoreCannotSaveObjectException
|
||||
* @throws \CoreException
|
||||
* @throws \CoreUnexpectedValue
|
||||
* @throws \OQLException
|
||||
* @throws \ReflectionException
|
||||
*/
|
||||
public function testExportWithSanitizeExcelExport(
|
||||
$aListOrg,
|
||||
$aExpectedValues,
|
||||
) {
|
||||
// Create tests organizations to have enough data
|
||||
$iFirstOrg = 0;
|
||||
foreach ($aListOrg as $aOrg) {
|
||||
$oObj = $this->CreateOrganization($aOrg[0]);
|
||||
if ($aOrg[1] === false) {
|
||||
$oObj->Set('status', 'inactive');
|
||||
$oObj->DBUpdate();
|
||||
}
|
||||
if ($iFirstOrg === 0) {
|
||||
$iFirstOrg = $oObj->GetKey();
|
||||
}
|
||||
}
|
||||
|
||||
$aStatusInfo = [
|
||||
"fields" => [
|
||||
[
|
||||
"sFieldSpec" => "name",
|
||||
"sAlias" => "Organization",
|
||||
"sClass" => "Organization",
|
||||
"sAttCode" => "name",
|
||||
"sLabel" => "Name",
|
||||
"sColLabel" => "Name",
|
||||
],
|
||||
],
|
||||
"text_qualifier" => "\"",
|
||||
"charset" => "UTF-8",
|
||||
"separator" => ",",
|
||||
"date_format" => "Y-m-d H:i:s",
|
||||
"formatted_text" => false,
|
||||
"show_obsolete_data" => false,
|
||||
'ignore_excel_sanitization' => false,
|
||||
];
|
||||
$sStatus = [];
|
||||
$oSearch = DBObjectSearch::FromOQL('SELECT Organization');
|
||||
$oExporter = BulkExport::FindExporter('csv', $oSearch);
|
||||
$oExporter->SetStatusInfo($aStatusInfo);
|
||||
$oExporter->SetObjectList($oSearch);
|
||||
$oExporter->SetChunkSize(EXPORTER_DEFAULT_CHUNK_SIZE);
|
||||
|
||||
$data = $oExporter->GetHeader();
|
||||
$data .= $oExporter->GetNextChunk($sStatus);
|
||||
|
||||
// Check that the value is sanitized as expected (with a ' prefix)
|
||||
foreach ($aExpectedValues as $sExpectedValue) {
|
||||
$this->assertStringContainsString($sExpectedValue, $data, "The value $sExpectedValue is expected to be found in the export result");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider OrganizationsForExportSanitizeExcelExportProvider
|
||||
*
|
||||
* @param $aListOrg
|
||||
* @param $aExpectedValues
|
||||
* @return void
|
||||
* @throws \CoreCannotSaveObjectException
|
||||
* @throws \CoreException
|
||||
* @throws \CoreUnexpectedValue
|
||||
* @throws \OQLException
|
||||
* @throws \ReflectionException
|
||||
*/
|
||||
public function testExportWithoutSanitizeExcelExport(
|
||||
$aListOrg,
|
||||
$aExpectedValues,
|
||||
) {
|
||||
// Create tests organizations to have enough data
|
||||
$iFirstOrg = 0;
|
||||
foreach ($aListOrg as $aOrg) {
|
||||
$oObj = $this->CreateOrganization($aOrg[0]);
|
||||
if ($aOrg[1] === false) {
|
||||
$oObj->Set('status', 'inactive');
|
||||
$oObj->DBUpdate();
|
||||
}
|
||||
if ($iFirstOrg === 0) {
|
||||
$iFirstOrg = $oObj->GetKey();
|
||||
}
|
||||
}
|
||||
|
||||
$aStatusInfo = [
|
||||
"fields" => [
|
||||
[
|
||||
"sFieldSpec" => "name",
|
||||
"sAlias" => "Organization",
|
||||
"sClass" => "Organization",
|
||||
"sAttCode" => "name",
|
||||
"sLabel" => "Name",
|
||||
"sColLabel" => "Name",
|
||||
],
|
||||
],
|
||||
"text_qualifier" => "\"",
|
||||
"charset" => "UTF-8",
|
||||
"separator" => ",",
|
||||
"date_format" => "Y-m-d H:i:s",
|
||||
"formatted_text" => false,
|
||||
"show_obsolete_data" => false,
|
||||
'ignore_excel_sanitization' => true,
|
||||
];
|
||||
$sStatus = [];
|
||||
$oSearch = DBObjectSearch::FromOQL('SELECT Organization');
|
||||
$oExporter = BulkExport::FindExporter('csv', $oSearch);
|
||||
$oExporter->SetStatusInfo($aStatusInfo);
|
||||
$oExporter->SetObjectList($oSearch);
|
||||
$oExporter->SetChunkSize(EXPORTER_DEFAULT_CHUNK_SIZE);
|
||||
|
||||
$data = $oExporter->GetHeader();
|
||||
$data .= $oExporter->GetNextChunk($sStatus);
|
||||
|
||||
// Check that the value is not sanitized
|
||||
foreach ($aListOrg as $sExpectedValue) {
|
||||
$this->assertStringContainsString($sExpectedValue[0], $data, "The value $sExpectedValue[0] is expected to be found in the export result");
|
||||
}
|
||||
}
|
||||
|
||||
public function OrganizationsForExportSanitizeExcelExportProvider()
|
||||
{
|
||||
return [
|
||||
'Page1' => [
|
||||
'list_org' => [
|
||||
['=org1', true],
|
||||
['+org2', true],
|
||||
['-org3', true],
|
||||
['@org4', true],
|
||||
["\t=org5", true],
|
||||
["\rorg6", true],
|
||||
["\r\t\r =org7", true],
|
||||
['=org8', true],
|
||||
['+org9', true],
|
||||
['-org10', true],
|
||||
['@org11', true],
|
||||
['|org12', true],
|
||||
['%3Dorg13', true],
|
||||
['%3dorg14', true],
|
||||
['org15', true],
|
||||
],
|
||||
'export_org' => [
|
||||
"'=org1",
|
||||
"'+org2",
|
||||
"'-org3",
|
||||
"'@org4",
|
||||
"'\t=org5",
|
||||
"'\rorg6",
|
||||
"'\r\t\r =org7",
|
||||
"'=org8",
|
||||
"'+org9",
|
||||
"'-org10",
|
||||
"'@org11",
|
||||
"'|org12",
|
||||
"'%3Dorg13",
|
||||
"'%3dorg14",
|
||||
"org15",
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -77,7 +77,7 @@ class CRUDEventReceiver
|
||||
}
|
||||
}
|
||||
|
||||
public function RegisterCRUDEventListeners(string $sEvent = null, $mEventSource = null)
|
||||
public function RegisterCRUDEventListeners(?string $sEvent = null, $mEventSource = null)
|
||||
{
|
||||
$this->Debug('Registering Test event listeners');
|
||||
if (is_null($sEvent)) {
|
||||
|
||||
@@ -183,4 +183,14 @@ class DBUnionSearchTest extends ItopDataTestCase
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
public function testAllowAllDataOnUnions()
|
||||
{
|
||||
$oSearch = \DBObjectSearch::FromOQL('SELECT Server UNION SELECT VirtualMachine');
|
||||
$oSearch->AllowAllData(false);
|
||||
self::assertFalse($oSearch->IsAllDataAllowed(), 'DBUnionSearch AllowData value');
|
||||
$oSearch->AllowAllData(true);
|
||||
self::assertTrue($oSearch->IsAllDataAllowed(), 'DBUnionSearch AllowData value');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ namespace Combodo\iTop\Test\UnitTest\Core;
|
||||
|
||||
use Combodo\iTop\Test\UnitTest\ItopDataTestCase;
|
||||
use InlineImage;
|
||||
use ormDocument;
|
||||
|
||||
class InlineImageTest extends ItopDataTestCase
|
||||
{
|
||||
@@ -59,4 +60,75 @@ class InlineImageTest extends ItopDataTestCase
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers InlineImage::FixUrls
|
||||
*/
|
||||
public function testFixUrls_shouldReturnAnEmptyStringIfNullOrEmptyStringPassed()
|
||||
{
|
||||
$sResult = InlineImage::FixUrls(null);
|
||||
$this->assertEquals('', $sResult);
|
||||
|
||||
$sResult = InlineImage::FixUrls('');
|
||||
$this->assertEquals('', $sResult);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers InlineImage::FixUrls
|
||||
*/
|
||||
public function testFixUrls_shouldReturnUnchangedValueIfValueContainsNoImage()
|
||||
{
|
||||
$sHtml = '<div><p>Texte sans image</p></div>';
|
||||
$sResult = InlineImage::FixUrls($sHtml);
|
||||
$this->assertEquals($sHtml, $sResult);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers InlineImage::FixUrls
|
||||
*/
|
||||
public function testFixUrls_shouldReplaceImagesSrcWithCurrentAppRootUrlAndSecret()
|
||||
{
|
||||
$sHtml = <<<HTML
|
||||
<div>
|
||||
<img src="/images/test1.png" data-img-id="123" data-img-secret="abc" />
|
||||
<img src="/images/test2.png" data-img-id="456" data-img-secret="def" />
|
||||
</div>
|
||||
HTML;
|
||||
$sResult = InlineImage::FixUrls($sHtml);
|
||||
$this->assertStringContainsString('<img', $sResult);
|
||||
$this->assertStringContainsString(\utils::EscapeHtml(\utils::GetAbsoluteUrlAppRoot().INLINEIMAGE_DOWNLOAD_URL.'123&s=abc'), $sResult);
|
||||
$this->assertStringContainsString(\utils::EscapeHtml(\utils::GetAbsoluteUrlAppRoot().INLINEIMAGE_DOWNLOAD_URL.'456&s=def'), $sResult);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers InlineImage::ReplaceInlineImagesWithBase64Representation
|
||||
*/
|
||||
public function testReplaceInlineImagesWithBase64Representation()
|
||||
{
|
||||
// create an inline image in the database
|
||||
$oInlineImage = $this->createObject(InlineImage::class, [
|
||||
'expire' => (new \DateTime('+1 day'))->format('Y-m-d H:i:s'),
|
||||
'item_class' => 'UserRequest',
|
||||
'item_id' => 999,
|
||||
'item_org_id' => 1,
|
||||
'contents' => new ormDocument('0x89504E470D0A1A0A0000000D494844520000000E0000000E08060000001F482DD1000000017352474200AECE1CE90000000467414D410000B18F0BFC6105000000097048597300000EC300000EC301C76FA8640000001E49444154384F63782BA3F29F1CCC802E402C1ED588078F6AC483E9AF11008B8BA9C08A7A3F290000000049454E44AE426082', 'image/png', 'square_red.png'),
|
||||
'secret' => 'a94bff3ea6a872bdbc359a1704cdddb3',
|
||||
]);
|
||||
$sInlineImageId = $oInlineImage->GetKey();
|
||||
$sInlineImageSecret = $oInlineImage->Get('secret');
|
||||
|
||||
// HTML with inline image
|
||||
$sHtml = <<<HTML
|
||||
<img src="http://host/iTop/pages/ajax.document.php?operation=download_inlineimage&id=$sInlineImageId&s=$sInlineImageSecret" data-img-id="$sInlineImageId" data-img-secret="$sInlineImageSecret" />
|
||||
HTML;
|
||||
|
||||
// expected HTML with base64 representation of the image
|
||||
$sExpected = <<<HTML
|
||||
<img src="data:image/png;base64,MHg4OTUwNEU0NzBEMEExQTBBMDAwMDAwMEQ0OTQ4NDQ1MjAwMDAwMDBFMDAwMDAwMEUwODA2MDAwMDAwMUY0ODJERDEwMDAwMDAwMTczNTI0NzQyMDBBRUNFMUNFOTAwMDAwMDA0Njc0MTRENDEwMDAwQjE4RjBCRkM2MTA1MDAwMDAwMDk3MDQ4NTk3MzAwMDAwRUMzMDAwMDBFQzMwMUM3NkZBODY0MDAwMDAwMUU0OTQ0NDE1NDM4NEY2Mzc4MkJBM0YyOUYxQ0NDODAyRTQwMkMxRUQ1ODgwNzhGNkFDNDgzRTlBRjExMDA4QjhCQTlDMDhBN0EzRjI5MDAwMDAwMDA0OTQ1NEU0NEFFNDI2MDgy" />
|
||||
HTML;
|
||||
|
||||
// test the method
|
||||
$sResult = InlineImage::ReplaceInlineImagesWithBase64Representation($sHtml);
|
||||
$this->assertEquals($sExpected, $sResult);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -220,7 +220,7 @@ class UserLocalTest extends ItopDataTestCase
|
||||
|
||||
],
|
||||
'expectedCheckStatus' => false,
|
||||
'expectedCheckIssues' => 'Password must be at least 8 characters and include uppercase, lowercase, numeric and special characters.',
|
||||
'expectedCheckIssues' => 'Password must be at least 12 characters and include uppercase, lowercase, numeric and special characters.',
|
||||
'userLanguage' => 'EN US',
|
||||
],
|
||||
'notValidPattern custom message string not array' => [
|
||||
|
||||
@@ -64,36 +64,6 @@ class ModelFactoryTest extends ItopTestCase
|
||||
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->formatOutput = true;
|
||||
$oExpectedDocument->loadXML($sXML);
|
||||
|
||||
$sSavedXML = $oExpectedDocument->SaveXML();
|
||||
|
||||
return str_replace(' encoding="UTF-8"', '', $sSavedXML);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $sExpected
|
||||
* @param $sActual
|
||||
* @param string $sMessage
|
||||
*/
|
||||
protected function AssertEqualiTopXML($sExpected, $sActual, string $sMessage = '')
|
||||
{
|
||||
// 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), $sMessage);
|
||||
}
|
||||
|
||||
/**
|
||||
* Assertion ignoring some of the unexpected decoration brought by DOM Elements.
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* @copyright Copyright (C) 2010-2025 Combodo SAS
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
namespace Combodo\iTop\Test\UnitTest\sources\Forms;
|
||||
|
||||
use Combodo\iTop\Forms\Block\AbstractFormBlock;
|
||||
use Combodo\iTop\Forms\Block\Base\FormBlock;
|
||||
use Combodo\iTop\Forms\IO\Format\StringIOFormat;
|
||||
use Combodo\iTop\Forms\IO\FormBlockIOException;
|
||||
use Combodo\iTop\Forms\IO\FormInput;
|
||||
use Combodo\iTop\Forms\IO\FormOutput;
|
||||
use Combodo\iTop\Forms\Register\IORegister;
|
||||
use Combodo\iTop\Test\UnitTest\ItopDataTestCase;
|
||||
use ReflectionClass;
|
||||
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2025 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
abstract class AbstractFormsTest extends ItopDataTestCase
|
||||
{
|
||||
/**
|
||||
* @throws FormBlockIOException
|
||||
*/
|
||||
public function GivenInput(string $sName, string $sType = StringIOFormat::class): FormInput
|
||||
{
|
||||
$oBlock = $this->GivenFormBlock($sName);
|
||||
|
||||
$oInput = new FormInput($sName, $sType);
|
||||
$oInput->SetOwnerBlock($oBlock);
|
||||
|
||||
return $oInput;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws FormBlockIOException
|
||||
*/
|
||||
public function GivenOutput(string $sName, string $sType = StringIOFormat::class): FormOutput
|
||||
{
|
||||
$oBlock = $this->GivenFormBlock($sName);
|
||||
|
||||
$oOutput = new FormOutput($sName, $sType);
|
||||
$oOutput->SetOwnerBlock($oBlock);
|
||||
|
||||
return $oOutput;
|
||||
}
|
||||
|
||||
public function GivenFormBlock(string $sName): FormBlock
|
||||
{
|
||||
return new FormBlock($sName, []);
|
||||
}
|
||||
|
||||
public function GivenSubFormBlock(FormBlock $oParent, string $sName, string $ssBlockClass = FormBlock::class): AbstractFormBlock
|
||||
{
|
||||
$oParent->Add($sName, $ssBlockClass, []);
|
||||
|
||||
return $oParent->Get($sName);
|
||||
}
|
||||
|
||||
public function GivenIORegister(AbstractFormBlock $oFormBlock): IORegister
|
||||
{
|
||||
$reflection = new ReflectionClass(AbstractFormBlock::class);
|
||||
$reflection_property = $reflection->getProperty('oIORegister');
|
||||
$reflection_property->setAccessible(true);
|
||||
return $reflection_property->getValue($oFormBlock);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,127 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* @copyright Copyright (C) 2010-2025 Combodo SAS
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
namespace Combodo\iTop\Test\UnitTest\Sources\Forms\Block;
|
||||
|
||||
use Combodo\iTop\Forms\Block\AbstractTypeFormBlock;
|
||||
use Combodo\iTop\Forms\Block\Base\CheckboxFormBlock;
|
||||
use Combodo\iTop\Forms\Block\Base\FormBlock;
|
||||
use Combodo\iTop\Forms\Block\Base\TextFormBlock;
|
||||
use Combodo\iTop\Forms\Block\FormBlockException;
|
||||
use Combodo\iTop\Forms\Block\IFormBlock;
|
||||
use Combodo\iTop\Forms\Forms;
|
||||
use Combodo\iTop\ItopSdkFormDemonstrator\Form\Block\Dashboard\GenericDashlet;
|
||||
use Combodo\iTop\Service\InterfaceDiscovery\InterfaceDiscovery;
|
||||
use Combodo\iTop\Test\UnitTest\sources\Forms\AbstractFormsTest;
|
||||
use OutOfBoundsException;
|
||||
use ReflectionException;
|
||||
use Symfony\Component\Form\AbstractType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\TextType;
|
||||
|
||||
/**
|
||||
* Test forms block.
|
||||
*
|
||||
*/
|
||||
class BlockTest extends AbstractFormsTest
|
||||
{
|
||||
/**
|
||||
* Block get form type must return a class derived from Symfony form AbstractType.
|
||||
*
|
||||
* @throws ReflectionException
|
||||
*/
|
||||
public function testGetFormTypeReturnSymfonyType(): void
|
||||
{
|
||||
$aFormBlocks = InterfaceDiscovery::GetInstance()->FindItopClasses(iFormBlock::class);
|
||||
foreach ($aFormBlocks as $sFormBlock) {
|
||||
$oChoiceBlock = new ($sFormBlock)($sFormBlock);
|
||||
if ($oChoiceBlock instanceof AbstractTypeFormBlock) {
|
||||
if (!$oChoiceBlock instanceof GenericDashlet) {
|
||||
$oClass = new \ReflectionClass($oChoiceBlock->GetFormType());
|
||||
$this->assertTrue($oClass->isSubclassOf(AbstractType::class));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Pass a Symfony type instead of a FormBlock type will raise an exception
|
||||
*
|
||||
* @throws ReflectionException
|
||||
*/
|
||||
public function testAddChildBlockExpectFormBlockClass(): void
|
||||
{
|
||||
$oFormBlock = new FormBlock('formBlock');
|
||||
$this->expectException(FormBlockException::class);
|
||||
$oFormBlock->Add('wrong', TextType::class, []);
|
||||
}
|
||||
|
||||
/**
|
||||
* All block must contain a reference to themselves in their options
|
||||
*/
|
||||
public function testBlockOptionsContainsBlockReference(): void
|
||||
{
|
||||
$aFormBlocks = InterfaceDiscovery::GetInstance()->FindItopClasses(iFormBlock::class);
|
||||
foreach ($aFormBlocks as $sFormBlock) {
|
||||
$oChoiceBlock = new ($sFormBlock)($sFormBlock);
|
||||
$this->assertTrue($oChoiceBlock->GetOption('form_block') === $oChoiceBlock);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check that a block with dependencies return true for HasDependenciesBlocks.
|
||||
*
|
||||
* @return void
|
||||
* @throws FormBlockException
|
||||
* @throws ReflectionException
|
||||
*/
|
||||
public function testCheckDependencyState(): void
|
||||
{
|
||||
$oFormBlock = new FormBlock('formBlock');
|
||||
$oFormBlock->Add('allow_age', CheckboxFormBlock::class, []);
|
||||
$oBirthdateBlock = $oFormBlock->Add('birthdate', TextFormBlock::class, [])
|
||||
->InputDependsOn(AbstractTypeFormBlock::INPUT_VISIBLE, 'allow_age', CheckboxFormBlock::OUTPUT_CHECKED);
|
||||
|
||||
$this->assertTrue($oBirthdateBlock->HasDependenciesBlocks());
|
||||
}
|
||||
|
||||
/**
|
||||
* Dependent fields are not added to the form directly.
|
||||
*
|
||||
* @return void
|
||||
* @throws FormBlockException
|
||||
* @throws ReflectionException
|
||||
*/
|
||||
public function testFormBlockNotContainsDependentFields(): void
|
||||
{
|
||||
// form with a dependent field
|
||||
$oFormBlock = new FormBlock('formBlock');
|
||||
$oFormBlock->Add('firstname', TextFormBlock::class, []);
|
||||
$oFormBlock->Add('lastname', TextFormBlock::class, []);
|
||||
$oFormBlock->Add('allow_age', CheckboxFormBlock::class, []);
|
||||
$oFormBlock->Add('birthdate', TextFormBlock::class, [])
|
||||
->InputDependsOn(AbstractTypeFormBlock::INPUT_VISIBLE, 'allow_age', CheckboxFormBlock::OUTPUT_CHECKED);
|
||||
|
||||
// form builder
|
||||
$oFormFactoryBuilder = Forms::createFormFactoryBuilder();
|
||||
$oForm = $oFormFactoryBuilder->getFormFactory()->createNamedBuilder($oFormBlock->GetName(), $oFormBlock->GetFormType(), [], $oFormBlock->GetOptions())->getForm();
|
||||
|
||||
// try to get the dependent field
|
||||
$this->expectException(OutOfBoundsException::class);
|
||||
$oForm->get('birthdate');
|
||||
}
|
||||
|
||||
public function testIsRootBlock(): void
|
||||
{
|
||||
/** @var FormBlock $oFormBlock */
|
||||
$oFormBlock = $this->GivenFormBlock('OneBlock');
|
||||
|
||||
$oFormBlock->Add('subform', FormBlock::class);
|
||||
|
||||
$this->assertTrue($oFormBlock->IsRootBlock());
|
||||
$this->assertFalse($oFormBlock->Get('subform')->IsRootBlock());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* @copyright Copyright (C) 2010-2025 Combodo SAS
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
namespace Combodo\iTop\Test\UnitTest\sources\Forms\IO;
|
||||
|
||||
use Combodo\iTop\Forms\IO\FormBlockIOException;
|
||||
use Combodo\iTop\Test\UnitTest\sources\Forms\AbstractFormsTest;
|
||||
use Symfony\Component\Form\FormEvents;
|
||||
|
||||
class AbstractFormIOTest extends AbstractFormsTest
|
||||
{
|
||||
public function testFormIoHasNoDataAtCreation()
|
||||
{
|
||||
|
||||
$oInput = $this->GivenInput('test');
|
||||
|
||||
$this->assertFalse($oInput->IsDataReady(), 'Created Input must no have data ready at creation');
|
||||
$this->assertFalse($oInput->HasValue(), 'Created Input must no have value at creation');
|
||||
$this->assertFalse($oInput->HasBindingOut());
|
||||
|
||||
$oOutput = $this->GivenOutput('test');
|
||||
|
||||
$this->assertFalse($oOutput->IsDataReady(), 'Created output must no have data ready at creation');
|
||||
$this->assertFalse($oOutput->HasValue(), 'Created output must no have value at creation');
|
||||
$this->assertFalse($oOutput->HasBindingOut());
|
||||
}
|
||||
|
||||
public function testFormIoHasDataAfterSetValue()
|
||||
{
|
||||
|
||||
$oInput = $this->GivenInput('test');
|
||||
$oInput->SetValue(FormEvents::POST_SET_DATA, 'test');
|
||||
|
||||
$this->assertTrue($oInput->IsDataReady(), 'Input must have data ready when set');
|
||||
$this->assertTrue($oInput->HasValue(), 'Input must have value when set');
|
||||
|
||||
$oOutput = $this->GivenOutput('test');
|
||||
$oOutput->SetValue(FormEvents::POST_SET_DATA, 'test');
|
||||
|
||||
$this->assertTrue($oOutput->IsDataReady(), 'Output must have data ready when set');
|
||||
$this->assertTrue($oOutput->HasValue(), 'Output must have value when set');
|
||||
}
|
||||
|
||||
public function testIOValueReflectsTheValuePostedOrTheValueSet()
|
||||
{
|
||||
$oInput = $this->GivenInput('test');
|
||||
|
||||
// When
|
||||
$oInput->SetValue(FormEvents::POST_SET_DATA, 'The value set');
|
||||
|
||||
// Then
|
||||
$this->assertEquals('The value set', $oInput->GetValue());
|
||||
|
||||
// When
|
||||
$oInput->SetValue(FormEvents::POST_SUBMIT, 'The value posted');
|
||||
|
||||
// Then
|
||||
$this->assertEquals('The value posted', $oInput->GetValue());
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider NameFormatSupportsOnlyLettersUnderscoreAndNumbersProvider
|
||||
* @return void
|
||||
* @throws \Combodo\iTop\Forms\IO\FormBlockIOException
|
||||
*/
|
||||
public function testNameFormatSupportsOnlyLettersUnderscoreAndNumbersAndDot(string $sName, bool $bGenerateException = true)
|
||||
{
|
||||
|
||||
if ($bGenerateException) {
|
||||
$this->expectException(FormBlockIOException::class);
|
||||
}
|
||||
$oInput = $this->GivenInput($sName);
|
||||
if (!$bGenerateException) {
|
||||
$this->assertEquals($sName, $oInput->GetName());
|
||||
}
|
||||
}
|
||||
|
||||
public function NameFormatSupportsOnlyLettersUnderscoreAndNumbersProvider()
|
||||
{
|
||||
return [
|
||||
// Incorrects
|
||||
'Spaces not supported' => ['The test name'],
|
||||
'Minus not supported' => ['The-test-name'],
|
||||
'Percent not supported' => ['name%'],
|
||||
'Accent not supported' => ['namé'],
|
||||
'emoji not supported' => ['🎄🎄🎄🎄🎄'],
|
||||
'.name not supported' => ['.name'],
|
||||
'name. not supported' => ['name.'],
|
||||
|
||||
// Corrects
|
||||
'Numbers OK' => ['name123', false],
|
||||
'Starting with number OK' => ['123name123', false],
|
||||
'Underscore OK' => ['The_test_name', false],
|
||||
'Camel OK' => ['TheTestName', false],
|
||||
'name.subname OK' => ['name.subname', false],
|
||||
];
|
||||
}
|
||||
|
||||
public function testCreatingIOWithUnknownFormatThrowsException()
|
||||
{
|
||||
$this->expectException(FormBlockIOException::class);
|
||||
$oInput = $this->GivenInput('test', 'test_toto');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,237 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* @copyright Copyright (C) 2010-2025 Combodo SAS
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
namespace Combodo\iTop\Test\UnitTest\Sources\Forms\IO;
|
||||
|
||||
use Combodo\iTop\Forms\IO\Format\AttributeIOFormat;
|
||||
use Combodo\iTop\Forms\IO\Format\BooleanIOFormat;
|
||||
use Combodo\iTop\Forms\IO\Format\ClassIOFormat;
|
||||
use Combodo\iTop\Forms\IO\Format\NumberIOFormat;
|
||||
use Combodo\iTop\Forms\IO\Format\StringIOFormat;
|
||||
use Combodo\iTop\Forms\IO\FormBinding;
|
||||
use Combodo\iTop\Forms\IO\FormBlockIOException;
|
||||
use Combodo\iTop\Test\UnitTest\sources\Forms\AbstractFormsTest;
|
||||
use Symfony\Component\Form\FormEvents;
|
||||
|
||||
/**
|
||||
* @copyright Copyright (C) 2010-2025 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
class FormBindingTest extends AbstractFormsTest
|
||||
{
|
||||
public function testCreatingABinding()
|
||||
{
|
||||
$oInputIO = $this->GivenInput('test');
|
||||
$oOutputIO = $this->GivenOutput('test');
|
||||
|
||||
// When Linking output to input
|
||||
new FormBinding($oOutputIO, $oInputIO);
|
||||
|
||||
// Then
|
||||
$this->assertTrue($oInputIO->IsBound(), 'DestinationIO must be Bound when creating a new binding');
|
||||
}
|
||||
|
||||
public function testBindingTwiceToTheSameInputIsNotPossible()
|
||||
{
|
||||
$oInputIO = $this->GivenInput('test');
|
||||
$oOutputIO1 = $this->GivenOutput('test1');
|
||||
$oOutputIO2 = $this->GivenOutput('test2');
|
||||
|
||||
// When
|
||||
new FormBinding($oOutputIO1, $oInputIO);
|
||||
|
||||
// Then
|
||||
$this->expectException(FormBlockIOException::class);
|
||||
new FormBinding($oOutputIO2, $oInputIO);
|
||||
}
|
||||
|
||||
public function testBindingTwiceToTheSameOutputIsNotPossible()
|
||||
{
|
||||
$oOutputIO1 = $this->GivenOutput('test1');
|
||||
$oOutputIO2 = $this->GivenOutput('test2');
|
||||
$oOutputIO3 = $this->GivenOutput('test3');
|
||||
|
||||
// When
|
||||
new FormBinding($oOutputIO1, $oOutputIO3);
|
||||
|
||||
// Then
|
||||
$this->expectException(FormBlockIOException::class);
|
||||
new FormBinding($oOutputIO2, $oOutputIO3);
|
||||
|
||||
}
|
||||
|
||||
public function testOutputCanBeBoundToInputAndInputIsBoundAfterThat()
|
||||
{
|
||||
$oInputIO = $this->GivenInput('test');
|
||||
$oOutputIO = $this->GivenOutput('test1');
|
||||
|
||||
$this->assertFalse($oInputIO->IsBound(), 'Input must not be Bound by default');
|
||||
|
||||
// When
|
||||
$oOutputIO->BindToInput($oInputIO);
|
||||
|
||||
// Then
|
||||
$this->assertTrue($oInputIO->IsBound(), 'Input must be Bound when binding from an output');
|
||||
}
|
||||
|
||||
public function testInputCanBeBoundToAnotherInputAndItIsBoundAfterThat()
|
||||
{
|
||||
$oInputIO1 = $this->GivenInput('test1');
|
||||
$oInputIO2 = $this->GivenInput('test2');
|
||||
|
||||
// When
|
||||
$oInputIO1->BindToInput($oInputIO2);
|
||||
|
||||
// Then
|
||||
$this->assertTrue($oInputIO2->IsBound(), 'Input must be Bound when binding from an input');
|
||||
}
|
||||
|
||||
public function testOutputCanBeBoundToAnotherOutputAndItIsBoundAfterThat()
|
||||
{
|
||||
$oOutputIO1 = $this->GivenOutput('test1');
|
||||
$oOutputIO2 = $this->GivenOutput('test2');
|
||||
|
||||
$this->assertFalse($oOutputIO2->IsBound(), 'Output must not be bound by default');
|
||||
|
||||
// When
|
||||
$oOutputIO1->BindToOutput($oOutputIO2);
|
||||
|
||||
// Then
|
||||
$this->assertTrue($oOutputIO2->IsBound(), 'Output must be Bound when binding from an output');
|
||||
}
|
||||
|
||||
public function testOutBindingsAreStoredWhenBindToInput()
|
||||
{
|
||||
$oInputIO1 = $this->GivenInput('test1');
|
||||
$oInputIO2 = $this->GivenInput('test2');
|
||||
$oOutputIO1 = $this->GivenOutput('test1');
|
||||
|
||||
// When
|
||||
$oBindingO2ToI1 = $oOutputIO1->BindToInput($oInputIO1);
|
||||
|
||||
// Then
|
||||
$this->assertTrue($oOutputIO1->HasBindingOut(), 'Must have bindings after BindToInput');
|
||||
$this->assertEquals([$oBindingO2ToI1], $oOutputIO1->GetBindingsToInputs(), 'Must have bindings after BindToInput');
|
||||
|
||||
// When
|
||||
$oBindingO1ToI2 = $oOutputIO1->BindToInput($oInputIO2);
|
||||
|
||||
// Then
|
||||
$this->assertEquals([$oBindingO2ToI1, $oBindingO1ToI2], $oOutputIO1->GetBindingsToInputs(), 'Must have bindings after BindToInput');
|
||||
}
|
||||
|
||||
public function testOutBindingsAreStoredWhenBindToOutput()
|
||||
{
|
||||
$oOutputIO1 = $this->GivenOutput('test1');
|
||||
$oOutputIO2 = $this->GivenOutput('test2');
|
||||
$oOutputIO3 = $this->GivenOutput('test3');
|
||||
|
||||
// When
|
||||
$oBindingO1ToO2 = $oOutputIO1->BindToOutput($oOutputIO2);
|
||||
|
||||
// Then
|
||||
$this->assertTrue($oOutputIO1->HasBindingOut(), 'Must have bindings after BindToInput');
|
||||
$this->assertEquals([$oBindingO1ToO2], $oOutputIO1->GetBindingsToOutputs(), 'Must have bindings after BindToOutput');
|
||||
|
||||
// When
|
||||
$oBindingO1ToO3 = $oOutputIO1->BindToOutput($oOutputIO3);
|
||||
|
||||
// Then
|
||||
$this->assertEquals([$oBindingO1ToO2, $oBindingO1ToO3], $oOutputIO1->GetBindingsToOutputs(), 'Must have bindings after BindToOutput');
|
||||
}
|
||||
|
||||
public function testSourceValueIsPropagatedToDestIO()
|
||||
{
|
||||
$oOutputIO1 = $this->GivenOutput('test1');
|
||||
$oInputIO1 = $this->GivenInput('test1');
|
||||
$oBinding = $oOutputIO1->BindToInput($oInputIO1);
|
||||
$oOutputIO1->SetValue(FormEvents::PRE_SET_DATA, 'The Value');
|
||||
|
||||
// When
|
||||
$oBinding->PropagateValues();
|
||||
|
||||
// Then
|
||||
$this->assertEquals('The Value', $oOutputIO1->GetValue(FormEvents::PRE_SET_DATA));
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider BindingIncompatibleFormatsProvider
|
||||
*
|
||||
* @param string $sSourceFormat
|
||||
* @param string $sDestinationFormat
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testBindingIncompatibleFormatsThrowsException(string $sSourceFormat, string $sDestinationFormat)
|
||||
{
|
||||
$oOutputIO = $this->GivenOutput('test', $sSourceFormat);
|
||||
$oInputIO = $this->GivenInput('test', $sDestinationFormat);
|
||||
|
||||
$this->expectException(FormBlockIOException::class);
|
||||
$oOutputIO->BindToInput($oInputIO);
|
||||
}
|
||||
|
||||
public function BindingIncompatibleFormatsProvider(): array
|
||||
{
|
||||
return [
|
||||
'Attribute -> Boolean' => [AttributeIOFormat::class, BooleanIOFormat::class],
|
||||
'Attribute -> Class' => [AttributeIOFormat::class, ClassIOFormat::class],
|
||||
'Attribute -> Number' => [AttributeIOFormat::class, NumberIOFormat::class],
|
||||
|
||||
'Boolean => Attribute' => [BooleanIOFormat::class, AttributeIOFormat::class],
|
||||
'Boolean => Class' => [BooleanIOFormat::class, ClassIOFormat::class],
|
||||
'Boolean => Number' => [BooleanIOFormat::class, NumberIOFormat::class],
|
||||
'Boolean -> String' => [BooleanIOFormat::class, StringIOFormat::class],
|
||||
|
||||
'Class => Attribute' => [ClassIOFormat::class, AttributeIOFormat::class],
|
||||
'Class => Boolean' => [ClassIOFormat::class, BooleanIOFormat::class],
|
||||
'Class => Number' => [ClassIOFormat::class, NumberIOFormat::class],
|
||||
|
||||
'Number => Attribute' => [NumberIOFormat::class, AttributeIOFormat::class],
|
||||
'Number => Class' => [NumberIOFormat::class, ClassIOFormat::class],
|
||||
'Number => Boolean' => [NumberIOFormat::class, BooleanIOFormat::class],
|
||||
'Number -> String' => [NumberIOFormat::class, StringIOFormat::class],
|
||||
|
||||
'String => Attribute' => [StringIOFormat::class, AttributeIOFormat::class],
|
||||
'String => Class' => [StringIOFormat::class, ClassIOFormat::class],
|
||||
'String => Boolean' => [StringIOFormat::class, BooleanIOFormat::class],
|
||||
'String -> Number' => [StringIOFormat::class, NumberIOFormat::class],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider BindingCompatibleFormatsProvider
|
||||
*
|
||||
* @param string $sSourceFormat
|
||||
* @param string $sDestinationFormat
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testBindingCompatibleFormatsWorks(string $sSourceFormat, string $sDestinationFormat)
|
||||
{
|
||||
$oOutputIO = $this->GivenOutput('test', $sSourceFormat);
|
||||
$oInputIO = $this->GivenInput('test', $sDestinationFormat);
|
||||
|
||||
$oBinding = $oOutputIO->BindToInput($oInputIO);
|
||||
$this->assertTrue(is_a($oBinding, FormBinding::class));
|
||||
}
|
||||
|
||||
public function BindingCompatibleFormatsProvider(): array
|
||||
{
|
||||
return [
|
||||
'Attribute -> Attribute' => [AttributeIOFormat::class, AttributeIOFormat::class],
|
||||
'Attribute -> String' => [AttributeIOFormat::class, StringIOFormat::class],
|
||||
'Boolean => Boolean' => [BooleanIOFormat::class, BooleanIOFormat::class],
|
||||
'Class => Class' => [ClassIOFormat::class, ClassIOFormat::class],
|
||||
'Class -> String' => [ClassIOFormat::class, StringIOFormat::class],
|
||||
'Number => Number' => [NumberIOFormat::class, NumberIOFormat::class],
|
||||
'String => String' => [StringIOFormat::class, StringIOFormat::class],
|
||||
];
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* @copyright Copyright (C) 2010-2025 Combodo SAS
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
namespace Combodo\iTop\Test\UnitTest\sources\Forms\IO\Format;
|
||||
|
||||
use Combodo\iTop\Forms\IO\Format\AttributeIOFormat;
|
||||
use Combodo\iTop\Test\UnitTest\sources\Forms\AbstractFormsTest;
|
||||
use Symfony\Component\Form\FormEvents;
|
||||
|
||||
class TestAttributeIOFormat extends AbstractFormsTest
|
||||
{
|
||||
public function testAttributeIOIsAString()
|
||||
{
|
||||
$oInputIO = $this->GivenInput('test', AttributeIOFormat::class);
|
||||
$oInputIO->SetValue(FormEvents::POST_SUBMIT, 'name');
|
||||
|
||||
$this->assertEquals('name', $oInputIO->GetValue());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* @copyright Copyright (C) 2010-2025 Combodo SAS
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
namespace Combodo\iTop\Test\UnitTest\sources\Forms\IO\Format;
|
||||
|
||||
use Combodo\iTop\Forms\IO\Format\BooleanIOFormat;
|
||||
use Combodo\iTop\Test\UnitTest\sources\Forms\AbstractFormsTest;
|
||||
use Symfony\Component\Form\FormEvents;
|
||||
|
||||
class TestBooleanIOFormat extends AbstractFormsTest
|
||||
{
|
||||
public function testBooleanIOFormatIsABoolean()
|
||||
{
|
||||
$oInputIO = $this->GivenInput('test', BooleanIOFormat::class);
|
||||
|
||||
$oInputIO->SetValue(FormEvents::POST_SUBMIT, 'true');
|
||||
|
||||
$this->assertEquals(true, $oInputIO->GetValue());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* @copyright Copyright (C) 2010-2025 Combodo SAS
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
namespace Combodo\iTop\Test\UnitTest\sources\Forms\IO\Format;
|
||||
|
||||
use Combodo\iTop\Test\UnitTest\sources\Forms\AbstractFormsTest;
|
||||
|
||||
class TestClassIOFormat extends AbstractFormsTest
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* @copyright Copyright (C) 2010-2025 Combodo SAS
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
namespace Combodo\iTop\Test\UnitTest\sources\Forms\IO\Format;
|
||||
|
||||
use Combodo\iTop\Test\UnitTest\sources\Forms\AbstractFormsTest;
|
||||
|
||||
class TestNumberIOFormat extends AbstractFormsTest
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,193 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* @copyright Copyright (C) 2010-2025 Combodo SAS
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
namespace Combodo\iTop\Test\UnitTest\Sources\Forms\Register;
|
||||
|
||||
use Combodo\iTop\Forms\Block\Base\CheckboxFormBlock;
|
||||
use Combodo\iTop\Forms\Block\Base\FormBlock;
|
||||
use Combodo\iTop\Forms\Block\Base\TextFormBlock;
|
||||
use Combodo\iTop\Forms\IO\Format\BooleanIOFormat;
|
||||
use Combodo\iTop\Forms\IO\Format\StringIOFormat;
|
||||
use Combodo\iTop\Forms\Register\IORegister;
|
||||
use Combodo\iTop\Forms\Register\RegisterException;
|
||||
use Combodo\iTop\Test\UnitTest\sources\Forms\AbstractFormsTest;
|
||||
|
||||
class IORegisterTest extends AbstractFormsTest
|
||||
{
|
||||
private FormBlock $oFormBlock;
|
||||
private IORegister $oIORegister;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->oFormBlock = $this->GivenFormBlock('OneBlock');
|
||||
$this->oIORegister = $this->GivenIORegister($this->oFormBlock);
|
||||
}
|
||||
|
||||
public function testAddInput(): void
|
||||
{
|
||||
$this->oIORegister->AddInput('input', StringIOFormat::class);
|
||||
|
||||
$this->assertTrue($this->oIORegister->HasInput('input'));
|
||||
$this->assertNotNull($this->oIORegister->GetInput('input'));
|
||||
}
|
||||
|
||||
public function testGetInputs(): void
|
||||
{
|
||||
$iOriginInputCount = count($this->oIORegister->GetInputs());
|
||||
$this->oIORegister->AddInput('input_1', StringIOFormat::class);
|
||||
$this->oIORegister->AddInput('input_2', BooleanIOFormat::class);
|
||||
$this->oIORegister->AddInput('input_3', StringIOFormat::class);
|
||||
|
||||
$this->assertCount(3 + $iOriginInputCount, $this->oIORegister->GetInputs());
|
||||
$this->assertArrayHasKey('input_1', $this->oIORegister->GetInputs());
|
||||
}
|
||||
|
||||
public function testGetOutputs(): void
|
||||
{
|
||||
$this->oIORegister->AddOutput('output_1', StringIOFormat::class);
|
||||
$this->oIORegister->AddOutput('output_2', BooleanIOFormat::class);
|
||||
|
||||
$this->assertCount(2, $this->oIORegister->GetOutputs());
|
||||
$this->assertArrayHasKey('output_1', $this->oIORegister->GetOutputs());
|
||||
}
|
||||
|
||||
public function testMissingInput(): void
|
||||
{
|
||||
$this->expectException(RegisterException::class);
|
||||
$this->oIORegister->GetInput('missing_input');
|
||||
}
|
||||
|
||||
public function testMissingOutput(): void
|
||||
{
|
||||
$this->expectException(RegisterException::class);
|
||||
$this->oIORegister->GetOutput('missing_output');
|
||||
}
|
||||
|
||||
public function testGetBoundInputs(): void
|
||||
{
|
||||
$this->GivenSubFormBlock($this->oFormBlock, 'SubFormA', TextFormBlock::class);
|
||||
$this->GivenSubFormBlock($this->oFormBlock, 'SubFormB', CheckboxFormBlock::class);
|
||||
$this->GivenSubFormBlock($this->oFormBlock, 'SubFormC', TextFormBlock::class);
|
||||
|
||||
$oSubForm = $this->GivenSubFormBlock($this->oFormBlock, 'SubForm', TextFormBlock::class);
|
||||
$oSubForm->AddInput('input_from_A', StringIOFormat::class);
|
||||
$oSubForm->AddInput('input_from_B', BooleanIOFormat::class);
|
||||
$oSubForm->AddInput('input_from_C', StringIOFormat::class);
|
||||
$oSubForm->AddInput('unbound_input', StringIOFormat::class);
|
||||
|
||||
$this->GivenIORegister($oSubForm)->InputDependsOn('input_from_A', 'SubFormA', TextFormBlock::OUTPUT_TEXT);
|
||||
$this->GivenIORegister($oSubForm)->InputDependsOn('input_from_B', 'SubFormB', CheckboxFormBlock::OUTPUT_CHECKED);
|
||||
$this->GivenIORegister($oSubForm)->InputDependsOn('input_from_C', 'SubFormC', TextFormBlock::OUTPUT_TEXT);
|
||||
|
||||
$aBoundInputs = $this->GivenIORegister($oSubForm)->GetBoundInputs();
|
||||
$this->assertCount(3, $aBoundInputs);
|
||||
}
|
||||
|
||||
public function testGetBoundOutputs(): void
|
||||
{
|
||||
$this->oFormBlock->AddOutput('output', StringIOFormat::class);
|
||||
|
||||
$oSubFormA = $this->GivenSubFormBlock($this->oFormBlock, 'SubFormA', TextFormBlock::class);
|
||||
$oIORegisterA = $this->GivenIORegister($oSubFormA);
|
||||
|
||||
$oIORegisterA->OutputImpactParent(TextFormBlock::OUTPUT_TEXT, 'output');
|
||||
|
||||
$this->assertCount(1, $this->oIORegister->GetBoundOutputs());
|
||||
}
|
||||
|
||||
public function testAddInputDependsOn(): void
|
||||
{
|
||||
$this->GivenSubFormBlock($this->oFormBlock, 'SubFormA', TextFormBlock::class);
|
||||
$oSubFormB = $this->GivenSubFormBlock($this->oFormBlock, 'SubFormB', TextFormBlock::class);
|
||||
$oIORegisterB = $this->GivenIORegister($oSubFormB);
|
||||
|
||||
$oIORegisterB->AddInputDependsOn('input', 'SubFormA', TextFormBlock::OUTPUT_TEXT);
|
||||
|
||||
$this->assertNotNull($oIORegisterB->GetInput('input'));
|
||||
}
|
||||
|
||||
public function testImpactParent(): void
|
||||
{
|
||||
$this->oFormBlock->AddOutput('output', StringIOFormat::class);
|
||||
|
||||
$oSubFormA = $this->GivenSubFormBlock($this->oFormBlock, 'SubFormA', TextFormBlock::class);
|
||||
$oIORegisterA = $this->GivenIORegister($oSubFormA);
|
||||
|
||||
$oIORegisterA->OutputImpactParent(TextFormBlock::OUTPUT_TEXT, 'output');
|
||||
|
||||
$this->assertTrue($this->oFormBlock->GetOutput('output')->IsBound());
|
||||
}
|
||||
|
||||
public function testAddingTwiceTheSameInputThrowsException(): void
|
||||
{
|
||||
$this->oIORegister->AddInput('test_input', StringIOFormat::class);
|
||||
$this->expectException(RegisterException::class);
|
||||
$this->oIORegister->AddInput('test_input', StringIOFormat::class);
|
||||
}
|
||||
|
||||
public function testAddingTwiceTheSameOutputThrowsException(): void
|
||||
{
|
||||
$this->oIORegister->AddOutput('test_output', StringIOFormat::class);
|
||||
$this->expectException(RegisterException::class);
|
||||
$this->oIORegister->AddOutput('test_output', StringIOFormat::class);
|
||||
}
|
||||
|
||||
public function testDependingOnNonExistingInputThrowsException(): void
|
||||
{
|
||||
$this->oIORegister->AddInput('test_input', StringIOFormat::class);
|
||||
$this->oIORegister->AddOutput('test_output', StringIOFormat::class);
|
||||
|
||||
$this->expectException(RegisterException::class);
|
||||
|
||||
$this->oIORegister->InputDependsOn('non_existing_input', 'OtherBlock', 'test_output');
|
||||
}
|
||||
|
||||
public function testDependingOnNonExistingOutputThrowsException(): void
|
||||
{
|
||||
$this->oIORegister->AddInput('test_input', StringIOFormat::class);
|
||||
|
||||
$this->expectException(RegisterException::class);
|
||||
$this->oIORegister->InputDependsOn('test_input', 'OtherBlock', 'non_existing_output');
|
||||
}
|
||||
|
||||
public function testDependingOnNonExistingBlockThrowsException(): void
|
||||
{
|
||||
$this->oIORegister->AddInput('test_input', StringIOFormat::class);
|
||||
$this->oIORegister->AddOutput('test_output', StringIOFormat::class);
|
||||
|
||||
$this->expectException(RegisterException::class);
|
||||
$this->oIORegister->InputDependsOn('test_input', 'UnknownBlock', 'test');
|
||||
}
|
||||
|
||||
public function testHasDependenciesBlocks(): void
|
||||
{
|
||||
$this->GivenSubFormBlock($this->oFormBlock, 'SubFormA', TextFormBlock::class);
|
||||
|
||||
$oSubForm = $this->GivenSubFormBlock($this->oFormBlock, 'SubForm', TextFormBlock::class);
|
||||
$oSubForm->AddInput('input_from_A', StringIOFormat::class);
|
||||
|
||||
$this->GivenIORegister($oSubForm)->InputDependsOn('input_from_A', 'SubFormA', TextFormBlock::OUTPUT_TEXT);
|
||||
$this->assertTrue($this->GivenIORegister($oSubForm)->HasDependenciesBlocks());
|
||||
|
||||
$this->assertFalse($this->oIORegister->HasDependenciesBlocks());
|
||||
}
|
||||
|
||||
public function testImpactBlocks(): void
|
||||
{
|
||||
$oSubFormA = $this->GivenSubFormBlock($this->oFormBlock, 'SubFormA', TextFormBlock::class);
|
||||
|
||||
$oSubForm = $this->GivenSubFormBlock($this->oFormBlock, 'SubForm', TextFormBlock::class);
|
||||
$oSubForm->AddInput('input_from_A', StringIOFormat::class);
|
||||
|
||||
$this->GivenIORegister($oSubForm)->InputDependsOn('input_from_A', 'SubFormA', TextFormBlock::OUTPUT_TEXT);
|
||||
$this->assertFalse($this->GivenIORegister($oSubForm)->IsImpactingBlocks());
|
||||
|
||||
$this->assertTrue($this->GivenIORegister($oSubFormA)->IsImpactingBlocks());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* @copyright Copyright (C) 2010-2025 Combodo SAS
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
namespace Combodo\iTop\Test\UnitTest\Sources\Forms\Register;
|
||||
|
||||
use Combodo\iTop\Forms\Register\OptionsRegister;
|
||||
use Combodo\iTop\Forms\Register\RegisterException;
|
||||
use Combodo\iTop\Test\UnitTest\ItopDataTestCase;
|
||||
|
||||
class OptionsRegisterTest extends ItopDataTestCase
|
||||
{
|
||||
private OptionsRegister $oOptionsRegister;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->oOptionsRegister = new OptionsRegister();
|
||||
}
|
||||
|
||||
public function testSetOptionWithInvalidName(): void
|
||||
{
|
||||
$this->oOptionsRegister->SetOption('valid_option_name', 'value');
|
||||
|
||||
$this->expectException(RegisterException::class);
|
||||
$this->oOptionsRegister->SetOption('not valid option name', 'value');
|
||||
}
|
||||
|
||||
public function testSetOptionTwice(): void
|
||||
{
|
||||
$this->oOptionsRegister->SetOption('valid_option_name', 'value');
|
||||
$this->oOptionsRegister->SetOption('valid_option_name', 'value2');
|
||||
|
||||
$this->assertEquals('value2', $this->oOptionsRegister->GetOption('valid_option_name'));
|
||||
}
|
||||
|
||||
public function testSetNonTypeOption(): void
|
||||
{
|
||||
$this->oOptionsRegister->SetOption('not_a_type_option', 'value', false);
|
||||
|
||||
$this->assertArrayNotHasKey('not_a_type_option', $this->oOptionsRegister->GetOptions());
|
||||
}
|
||||
|
||||
public function testSetOptionArrayValue(): void
|
||||
{
|
||||
$this->oOptionsRegister->SetOptionArrayValue('att', 'class', 'ibo-class');
|
||||
|
||||
$this->assertEquals('ibo-class', $this->oOptionsRegister->GetOption('att')['class']);
|
||||
}
|
||||
|
||||
public function testHasOption(): void
|
||||
{
|
||||
$this->oOptionsRegister->SetOption('option', true);
|
||||
|
||||
$this->assertTrue($this->oOptionsRegister->HasOption('option'));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,852 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* @copyright Copyright (C) 2010-2025 Combodo SAS
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
use Combodo\iTop\PropertyType\Compiler\PropertyTypeCompiler;
|
||||
use Combodo\iTop\Service\DependencyInjection\ServiceLocator;
|
||||
use Combodo\iTop\Test\UnitTest\ItopDataTestCase;
|
||||
|
||||
class FormsCompilerTest extends ItopDataTestCase
|
||||
{
|
||||
/**
|
||||
* @dataProvider CompileFormFromXMLProvider
|
||||
*
|
||||
* @param string $sXMLContent
|
||||
* @param string $sExpectedPHP
|
||||
*
|
||||
* @return void
|
||||
* @throws \Combodo\iTop\PropertyType\Compiler\PropertyTypeCompilerException
|
||||
* @throws \Combodo\iTop\PropertyType\PropertyTypeException
|
||||
* @throws \DOMFormatException
|
||||
*/
|
||||
public function testCompileFormFromXML(string $sXMLContent, string $sExpectedPHP)
|
||||
{
|
||||
ServiceLocator::GetInstance()->RegisterService('ModelReflection', new ModelReflectionRuntime());
|
||||
|
||||
$sProducedPHP = PropertyTypeCompiler::GetInstance()->CompileFormFromXML($sXMLContent);
|
||||
|
||||
$this->AssertPHPCodeIsValid($sProducedPHP);
|
||||
$sMessage = $this->dataName();
|
||||
$this->assertEquals($sExpectedPHP, $sProducedPHP, $sMessage);
|
||||
}
|
||||
|
||||
public function CompileFormFromXMLProvider()
|
||||
{
|
||||
return [
|
||||
'Basic scalar properties should generate PHP' => [
|
||||
'sXMLContent' => <<<XML
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<property_type id="basic_test" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="Combodo-PropertyType" xsi:noNamespaceSchemaLocation = "https://www.combodo.com/itop-schema/3.3">
|
||||
<extends>Dashlet</extends>
|
||||
<definition xsi:type="Combodo-ValueType-PropertyTree">
|
||||
<nodes>
|
||||
<node id="title_property" xsi:type="Combodo-ValueType-Label">
|
||||
<label>UI:BasicTest:Prop-Title</label>
|
||||
</node>
|
||||
<node id="class_property" xsi:type="Combodo-ValueType-Class">
|
||||
<label>UI:BasicTest:Prop-Class</label>
|
||||
<categories-csv>test</categories-csv>
|
||||
</node>
|
||||
</nodes>
|
||||
</definition>
|
||||
</property_type>
|
||||
XML,
|
||||
'sExpectedPHP' => <<<PHP
|
||||
class FormFor__basic_test extends Combodo\iTop\Forms\Block\Base\FormBlock
|
||||
{
|
||||
protected function BuildForm(): void
|
||||
{
|
||||
\$this->Add('title_property', 'Combodo\iTop\Forms\Block\DataModel\LabelFormBlock', [
|
||||
'label' => 'UI:BasicTest:Prop-Title',
|
||||
]);
|
||||
|
||||
\$this->Add('class_property', 'Combodo\iTop\Forms\Block\Base\ChoiceFormBlock', [
|
||||
'label' => 'UI:BasicTest:Prop-Class',
|
||||
'choices' => [
|
||||
],
|
||||
]);
|
||||
}
|
||||
}
|
||||
PHP,
|
||||
],
|
||||
|
||||
'Empty property tree should generate minimal PHP' => [
|
||||
'sXMLContent' => <<<XML
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<property_type id="EmptyTest" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="Combodo-PropertyType" xsi:noNamespaceSchemaLocation = "https://www.combodo.com/itop-schema/3.3">
|
||||
<extends>Dashlet</extends>
|
||||
<definition xsi:type="Combodo-ValueType-PropertyTree">
|
||||
<nodes>
|
||||
</nodes>
|
||||
</definition>
|
||||
</property_type>
|
||||
XML,
|
||||
'sExpectedPHP' => <<<PHP
|
||||
class FormFor__EmptyTest extends Combodo\iTop\Forms\Block\Base\FormBlock
|
||||
{
|
||||
protected function BuildForm(): void
|
||||
{ }
|
||||
}
|
||||
PHP,
|
||||
],
|
||||
|
||||
'Empty property tree lower case should generate lower case class name' => [
|
||||
'sXMLContent' => <<<XML
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<property_type id="empty_test" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="Combodo-PropertyType" xsi:noNamespaceSchemaLocation = "https://www.combodo.com/itop-schema/3.3">
|
||||
<extends>Dashlet</extends>
|
||||
<definition xsi:type="Combodo-ValueType-PropertyTree">
|
||||
<nodes>
|
||||
</nodes>
|
||||
</definition>
|
||||
</property_type>
|
||||
XML,
|
||||
'sExpectedPHP' => <<<PHP
|
||||
class FormFor__empty_test extends Combodo\iTop\Forms\Block\Base\FormBlock
|
||||
{
|
||||
protected function BuildForm(): void
|
||||
{ }
|
||||
}
|
||||
PHP,
|
||||
],
|
||||
|
||||
'Properties with all value-types' => [
|
||||
'sXMLContent' => <<<XML
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<property_type id="AllValueTypesTest" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="Combodo-PropertyType" xsi:noNamespaceSchemaLocation = "https://www.combodo.com/itop-schema/3.3">
|
||||
<extends>Dashlet</extends>
|
||||
<definition xsi:type="Combodo-ValueType-PropertyTree">
|
||||
<nodes>
|
||||
<node id="aggregate_function_property" xsi:type="Combodo-ValueType-AggregateFunction">
|
||||
<label>UI:AggregateFunction</label>
|
||||
</node>
|
||||
<node id="choice_property" xsi:type="Combodo-ValueType-Choice">
|
||||
<label>UI:Choice</label>
|
||||
<values>
|
||||
<value id="value_a">
|
||||
<label>Label A</label>
|
||||
</value>
|
||||
<value id="value_b">
|
||||
<label>Label B</label>
|
||||
</value>
|
||||
</values>
|
||||
</node>
|
||||
<node id="class_property" xsi:type="Combodo-ValueType-Class">
|
||||
<label>UI:Class</label>
|
||||
<categories-csv>test</categories-csv>
|
||||
</node>
|
||||
<node id="class_attribute_property" xsi:type="Combodo-ValueType-ClassAttribute">
|
||||
<label>UI:ClassAttribute</label>
|
||||
</node>
|
||||
<node id="class_attribute_group_by_property" xsi:type="Combodo-ValueType-ClassAttributeGroupBy">
|
||||
<label>UI:ClassAttributeGroupBy</label>
|
||||
</node>
|
||||
<node id="class_attribute_value_property" xsi:type="Combodo-ValueType-ClassAttributeValue">
|
||||
<label>UI:ClassAttributeValue</label>
|
||||
</node>
|
||||
<node id="integer_property" xsi:type="Combodo-ValueType-Integer">
|
||||
<label>UI:Integer</label>
|
||||
</node>
|
||||
<node id="label_property" xsi:type="Combodo-ValueType-Label">
|
||||
<label>UI:Label</label>
|
||||
</node>
|
||||
<node id="oql_property" xsi:type="Combodo-ValueType-OQL">
|
||||
<label>UI:OQL</label>
|
||||
</node>
|
||||
<node id="string_property" xsi:type="Combodo-ValueType-String">
|
||||
<label>UI:String</label>
|
||||
</node>
|
||||
<node id="choice_from_input" xsi:type="Combodo-ValueType-ChoiceFromInput">
|
||||
<label>UI:ChoiceFromInput</label>
|
||||
<values>
|
||||
<value id="value_a">
|
||||
<label>{{class_attribute_property.label}}</label>
|
||||
</value>
|
||||
<value id="value_b">
|
||||
<label>{{class_attribute_group_by_property.label}}</label>
|
||||
</value>
|
||||
</values>
|
||||
</node>
|
||||
</nodes>
|
||||
</definition>
|
||||
</property_type>
|
||||
XML,
|
||||
'sExpectedPHP' => <<<PHP
|
||||
class FormFor__AllValueTypesTest extends Combodo\iTop\Forms\Block\Base\FormBlock
|
||||
{
|
||||
protected function BuildForm(): void
|
||||
{
|
||||
\$this->Add('aggregate_function_property', 'Combodo\iTop\Forms\Block\DataModel\Dashlet\AggregateFunctionFormBlock', [
|
||||
'label' => 'UI:AggregateFunction',
|
||||
]);
|
||||
|
||||
\$this->Add('choice_property', 'Combodo\iTop\Forms\Block\Base\ChoiceFormBlock', [
|
||||
'label' => 'UI:Choice',
|
||||
'choices' => [
|
||||
\Dict::S('Label A') => 'value_a',
|
||||
\Dict::S('Label B') => 'value_b',
|
||||
],
|
||||
]);
|
||||
|
||||
\$this->Add('class_property', 'Combodo\iTop\Forms\Block\Base\ChoiceFormBlock', [
|
||||
'label' => 'UI:Class',
|
||||
'choices' => [
|
||||
],
|
||||
]);
|
||||
|
||||
\$this->Add('class_attribute_property', 'Combodo\iTop\Forms\Block\DataModel\AttributeChoiceFormBlock', [
|
||||
'label' => 'UI:ClassAttribute',
|
||||
]);
|
||||
|
||||
\$this->Add('class_attribute_group_by_property', 'Combodo\iTop\Forms\Block\DataModel\Dashlet\ClassAttributeGroupByFormBlock', [
|
||||
'label' => 'UI:ClassAttributeGroupBy',
|
||||
]);
|
||||
|
||||
\$this->Add('class_attribute_value_property', 'Combodo\iTop\Forms\Block\DataModel\AttributeValueChoiceFormBlock', [
|
||||
'label' => 'UI:ClassAttributeValue',
|
||||
]);
|
||||
|
||||
\$this->Add('integer_property', 'Combodo\iTop\Forms\Block\Base\IntegerFormBlock', [
|
||||
'label' => 'UI:Integer',
|
||||
]);
|
||||
|
||||
\$this->Add('label_property', 'Combodo\iTop\Forms\Block\DataModel\LabelFormBlock', [
|
||||
'label' => 'UI:Label',
|
||||
]);
|
||||
|
||||
\$this->Add('oql_property', 'Combodo\iTop\Forms\Block\DataModel\OqlFormBlock', [
|
||||
'label' => 'UI:OQL',
|
||||
]);
|
||||
|
||||
\$this->Add('string_property', 'Combodo\iTop\Forms\Block\Base\TextFormBlock', [
|
||||
'label' => 'UI:String',
|
||||
]);
|
||||
|
||||
\$this->Add('choice_from_input', 'Combodo\iTop\Forms\Block\Base\ChoiceFromInputsBlock', [
|
||||
'label' => 'UI:ChoiceFromInput',
|
||||
])
|
||||
->AddInputDependsOn('value_a', 'class_attribute_property', 'label')
|
||||
->AddInputDependsOn('value_b', 'class_attribute_group_by_property', 'label');
|
||||
}
|
||||
}
|
||||
PHP,
|
||||
],
|
||||
|
||||
'Collection of trees' => [
|
||||
'sXMLContent' => <<<XML
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<property_type id="collection_of_trees_test" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="Combodo-PropertyType" xsi:noNamespaceSchemaLocation = "https://www.combodo.com/itop-schema/3.3">
|
||||
<extends>Dashlet</extends>
|
||||
<definition xsi:type="Combodo-ValueType-PropertyTree">
|
||||
<nodes>
|
||||
<node id="sub_tree_collection" xsi:type="Combodo-ValueType-Collection">
|
||||
<label>UI:SubTree</label>
|
||||
<xml-format xsi:type="Combodo-XMLFormat-FlatArray">
|
||||
<count-tag>item_count</count-tag>
|
||||
<tag-format>item_\$rank\$_\$id\$</tag-format>
|
||||
</xml-format>
|
||||
<prototype>
|
||||
<node id="string_property" xsi:type="Combodo-ValueType-String">
|
||||
<label>UI:String</label>
|
||||
</node>
|
||||
<node id="integer_property" xsi:type="Combodo-ValueType-Integer">
|
||||
<label>UI:Integer</label>
|
||||
<relevance-condition>{{string_property.text != 'no-display'}}</relevance-condition>
|
||||
</node>
|
||||
</prototype>
|
||||
</node>
|
||||
</nodes>
|
||||
</definition>
|
||||
</property_type>
|
||||
XML,
|
||||
'sExpectedPHP' => <<<PHP
|
||||
class SubFormFor__collection_of_trees_test__sub_tree_collection extends Combodo\iTop\Forms\Block\Base\FormBlock
|
||||
{
|
||||
protected function BuildForm(): void
|
||||
{
|
||||
\$this->Add('string_property', 'Combodo\iTop\Forms\Block\Base\TextFormBlock', [
|
||||
'label' => 'UI:String',
|
||||
]);
|
||||
|
||||
\$this->Add('integer_property_visible_expression', 'Combodo\iTop\Forms\Block\Expression\BooleanExpressionFormBlock', [
|
||||
'expression' => 'string_property.text != \'no-display\'',
|
||||
])
|
||||
->AddInputDependsOn('string_property.text', 'string_property', 'text');
|
||||
|
||||
\$this->Add('integer_property', 'Combodo\iTop\Forms\Block\Base\IntegerFormBlock', [
|
||||
'label' => 'UI:Integer',
|
||||
])
|
||||
->InputDependsOn('visible', 'integer_property_visible_expression', 'result');
|
||||
}
|
||||
}
|
||||
|
||||
class FormFor__collection_of_trees_test extends Combodo\iTop\Forms\Block\Base\FormBlock
|
||||
{
|
||||
protected function BuildForm(): void
|
||||
{
|
||||
\$this->Add('sub_tree_collection', 'Combodo\iTop\Forms\Block\Base\CollectionBlock', [
|
||||
'label' => 'UI:SubTree',
|
||||
'button_label' => 'UI:AddSubTree',
|
||||
'block_entry_type' => 'SubFormFor__collection_of_trees_test__sub_tree_collection',
|
||||
]);
|
||||
}
|
||||
}
|
||||
PHP,
|
||||
],
|
||||
|
||||
'Static inputs should be bound and invalid input should be ignored' => [
|
||||
'sXMLContent' => <<<XML
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<property_type id="input_static_test" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="Combodo-PropertyType" xsi:noNamespaceSchemaLocation = "https://www.combodo.com/itop-schema/3.3">
|
||||
<extends>Dashlet</extends>
|
||||
<definition xsi:type="Combodo-ValueType-PropertyTree">
|
||||
<nodes>
|
||||
<node id="class_attribute_property" xsi:type="Combodo-ValueType-ClassAttribute">
|
||||
<label>UI:ClassAttribute</label>
|
||||
<class>Contact</class>
|
||||
<invalid-input>Test</invalid-input>
|
||||
</node>
|
||||
</nodes>
|
||||
</definition>
|
||||
</property_type>
|
||||
XML,
|
||||
'sExpectedPHP' => <<<PHP
|
||||
class FormFor__input_static_test extends Combodo\iTop\Forms\Block\Base\FormBlock
|
||||
{
|
||||
protected function BuildForm(): void
|
||||
{
|
||||
\$this->Add('class_attribute_property', 'Combodo\iTop\Forms\Block\DataModel\AttributeChoiceFormBlock', [
|
||||
'label' => 'UI:ClassAttribute',
|
||||
])
|
||||
->SetInputValue('class', 'Contact');
|
||||
}
|
||||
}
|
||||
PHP,
|
||||
],
|
||||
|
||||
'Quotes should be handled gracefully' => [
|
||||
'sXMLContent' => <<<XML
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<property_type id="input_quotes_test" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="Combodo-PropertyType" xsi:noNamespaceSchemaLocation = "https://www.combodo.com/itop-schema/3.3">
|
||||
<extends>Dashlet</extends>
|
||||
<definition xsi:type="Combodo-ValueType-PropertyTree">
|
||||
<nodes>
|
||||
<node id="class_attribute_property" xsi:type="Combodo-ValueType-ClassAttribute">
|
||||
<label>'Class' and "Attribute"</label>
|
||||
<class>{{CONCAT("'", '"')}}</class>
|
||||
<category>'Class' and "Attribute"</category>
|
||||
</node>
|
||||
</nodes>
|
||||
</definition>
|
||||
</property_type>
|
||||
XML,
|
||||
'sExpectedPHP' => <<<PHP
|
||||
class FormFor__input_quotes_test extends Combodo\iTop\Forms\Block\Base\FormBlock
|
||||
{
|
||||
protected function BuildForm(): void
|
||||
{
|
||||
\$this->Add('class_attribute_property_class_expression', 'Combodo\iTop\Forms\Block\Expression\StringExpressionFormBlock', [
|
||||
'expression' => 'CONCAT("\'", \'"\')',
|
||||
]);
|
||||
|
||||
\$this->Add('class_attribute_property', 'Combodo\iTop\Forms\Block\DataModel\AttributeChoiceFormBlock', [
|
||||
'label' => '\'Class\' and "Attribute"',
|
||||
])
|
||||
->InputDependsOn('class', 'class_attribute_property_class_expression', 'result')
|
||||
->SetInputValue('category', '\'Class\' and "Attribute"');
|
||||
}
|
||||
}
|
||||
PHP,
|
||||
],
|
||||
|
||||
'Dynamic input should be bound' => [
|
||||
'sXMLContent' => <<<XML
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<property_type id="input_binding_test" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="Combodo-PropertyType" xsi:noNamespaceSchemaLocation = "https://www.combodo.com/itop-schema/3.3">
|
||||
<extends>Dashlet</extends>
|
||||
<definition xsi:type="Combodo-ValueType-PropertyTree">
|
||||
<nodes>
|
||||
<node id="class_property" xsi:type="Combodo-ValueType-Class">
|
||||
<label>UI:Class</label>
|
||||
<categories-csv>test</categories-csv>
|
||||
</node>
|
||||
<node id="class_attribute_property" xsi:type="Combodo-ValueType-ClassAttribute">
|
||||
<label>UI:ClassAttribute</label>
|
||||
<class>{{class_property.text}}</class>
|
||||
</node>
|
||||
</nodes>
|
||||
</definition>
|
||||
</property_type>
|
||||
XML,
|
||||
'sExpectedPHP' => <<<PHP
|
||||
class FormFor__input_binding_test extends Combodo\iTop\Forms\Block\Base\FormBlock
|
||||
{
|
||||
protected function BuildForm(): void
|
||||
{
|
||||
\$this->Add('class_property', 'Combodo\iTop\Forms\Block\Base\ChoiceFormBlock', [
|
||||
'label' => 'UI:Class',
|
||||
'choices' => [
|
||||
],
|
||||
]);
|
||||
|
||||
\$this->Add('class_attribute_property', 'Combodo\iTop\Forms\Block\DataModel\AttributeChoiceFormBlock', [
|
||||
'label' => 'UI:ClassAttribute',
|
||||
])
|
||||
->InputDependsOn('class', 'class_property', 'text');
|
||||
}
|
||||
}
|
||||
PHP,
|
||||
],
|
||||
|
||||
'Dynamic input can be an expression' => [
|
||||
'sXMLContent' => <<<XML
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<property_type id="input_binding_expression" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="Combodo-PropertyType" xsi:noNamespaceSchemaLocation = "https://www.combodo.com/itop-schema/3.3">
|
||||
<extends>Dashlet</extends>
|
||||
<definition xsi:type="Combodo-ValueType-PropertyTree">
|
||||
<nodes>
|
||||
<node id="class_property" xsi:type="Combodo-ValueType-Class">
|
||||
<label>UI:Class</label>
|
||||
<categories-csv>test</categories-csv>
|
||||
</node>
|
||||
<node id="class_attribute_property" xsi:type="Combodo-ValueType-ClassAttribute">
|
||||
<label>UI:ClassAttribute</label>
|
||||
<class>{{IF(class_property.value = '', 'Person', class_property.value)}}</class>
|
||||
</node>
|
||||
</nodes>
|
||||
</definition>
|
||||
</property_type>
|
||||
XML,
|
||||
'sExpectedPHP' => <<<PHP
|
||||
class FormFor__input_binding_expression extends Combodo\iTop\Forms\Block\Base\FormBlock
|
||||
{
|
||||
protected function BuildForm(): void
|
||||
{
|
||||
\$this->Add('class_property', 'Combodo\iTop\Forms\Block\Base\ChoiceFormBlock', [
|
||||
'label' => 'UI:Class',
|
||||
'choices' => [
|
||||
],
|
||||
]);
|
||||
|
||||
\$this->Add('class_attribute_property_class_expression', 'Combodo\iTop\Forms\Block\Expression\StringExpressionFormBlock', [
|
||||
'expression' => 'IF(class_property.value = \'\', \'Person\', class_property.value)',
|
||||
])
|
||||
->AddInputDependsOn('class_property.value', 'class_property', 'value');
|
||||
|
||||
\$this->Add('class_attribute_property', 'Combodo\iTop\Forms\Block\DataModel\AttributeChoiceFormBlock', [
|
||||
'label' => 'UI:ClassAttribute',
|
||||
])
|
||||
->InputDependsOn('class', 'class_attribute_property_class_expression', 'result');
|
||||
}
|
||||
}
|
||||
PHP,
|
||||
],
|
||||
|
||||
'Relevance condition should generate a boolean block expression' => [
|
||||
'sXMLContent' => <<<XML
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<property_type id="RelevanceCondition" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="Combodo-PropertyType" xsi:noNamespaceSchemaLocation = "https://www.combodo.com/itop-schema/3.3">
|
||||
<extends>Dashlet</extends>
|
||||
<definition xsi:type="Combodo-ValueType-PropertyTree">
|
||||
<nodes>
|
||||
<node id="source_property" xsi:type="Combodo-ValueType-String">
|
||||
<label>UI:Source</label>
|
||||
</node>
|
||||
<node id="dependant_property" xsi:type="Combodo-ValueType-String">
|
||||
<label>UI:Dependant</label>
|
||||
<relevance-condition>{{source_property.text != 'count'}}</relevance-condition>
|
||||
</node>
|
||||
</nodes>
|
||||
</definition>
|
||||
</property_type>
|
||||
XML,
|
||||
'sExpectedPHP' => <<<PHP
|
||||
class FormFor__RelevanceCondition extends Combodo\iTop\Forms\Block\Base\FormBlock
|
||||
{
|
||||
protected function BuildForm(): void
|
||||
{
|
||||
\$this->Add('source_property', 'Combodo\iTop\Forms\Block\Base\TextFormBlock', [
|
||||
'label' => 'UI:Source',
|
||||
]);
|
||||
|
||||
\$this->Add('dependant_property_visible_expression', 'Combodo\iTop\Forms\Block\Expression\BooleanExpressionFormBlock', [
|
||||
'expression' => 'source_property.text != \'count\'',
|
||||
])
|
||||
->AddInputDependsOn('source_property.text', 'source_property', 'text');
|
||||
|
||||
\$this->Add('dependant_property', 'Combodo\iTop\Forms\Block\Base\TextFormBlock', [
|
||||
'label' => 'UI:Dependant',
|
||||
])
|
||||
->InputDependsOn('visible', 'dependant_property_visible_expression', 'result');
|
||||
}
|
||||
}
|
||||
PHP,
|
||||
],
|
||||
|
||||
'Complex Relevance condition should generate a boolean block expression' => [
|
||||
'sXMLContent' => <<<XML
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<property_type id="ComplexRelevanceCondition" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="Combodo-PropertyType" xsi:noNamespaceSchemaLocation = "https://www.combodo.com/itop-schema/3.3">
|
||||
<extends>Dashlet</extends>
|
||||
<definition xsi:type="Combodo-ValueType-PropertyTree">
|
||||
<nodes>
|
||||
<node id="source_a_property" xsi:type="Combodo-ValueType-String">
|
||||
<label>UI:Source</label>
|
||||
</node>
|
||||
<node id="source_b_property" xsi:type="Combodo-ValueType-String">
|
||||
<label>UI:Source</label>
|
||||
</node>
|
||||
<node id="dependant_property" xsi:type="Combodo-ValueType-String">
|
||||
<label>UI:Dependant</label>
|
||||
<relevance-condition>{{IF(source_a_property.text != '', source_a_property.text, source_b_property.text)}}</relevance-condition>
|
||||
</node>
|
||||
</nodes>
|
||||
</definition>
|
||||
</property_type>
|
||||
XML,
|
||||
'sExpectedPHP' => <<<PHP
|
||||
class FormFor__ComplexRelevanceCondition extends Combodo\iTop\Forms\Block\Base\FormBlock
|
||||
{
|
||||
protected function BuildForm(): void
|
||||
{
|
||||
\$this->Add('source_a_property', 'Combodo\iTop\Forms\Block\Base\TextFormBlock', [
|
||||
'label' => 'UI:Source',
|
||||
]);
|
||||
|
||||
\$this->Add('source_b_property', 'Combodo\iTop\Forms\Block\Base\TextFormBlock', [
|
||||
'label' => 'UI:Source',
|
||||
]);
|
||||
|
||||
\$this->Add('dependant_property_visible_expression', 'Combodo\iTop\Forms\Block\Expression\BooleanExpressionFormBlock', [
|
||||
'expression' => 'IF(source_a_property.text != \'\', source_a_property.text, source_b_property.text)',
|
||||
])
|
||||
->AddInputDependsOn('source_a_property.text', 'source_a_property', 'text')
|
||||
->AddInputDependsOn('source_b_property.text', 'source_b_property', 'text');
|
||||
|
||||
\$this->Add('dependant_property', 'Combodo\iTop\Forms\Block\Base\TextFormBlock', [
|
||||
'label' => 'UI:Dependant',
|
||||
])
|
||||
->InputDependsOn('visible', 'dependant_property_visible_expression', 'result');
|
||||
}
|
||||
}
|
||||
PHP,
|
||||
],
|
||||
'Sub form generate a sub-form' => [
|
||||
'sXMLContent' => <<<XML
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<property_typeproperty_type id="SubFormTest" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="Combodo-PropertyType" xsi:noNamespaceSchemaLocation = "https://www.combodo.com/itop-schema/3.3">
|
||||
<extends>Dashlet</extends>
|
||||
<definition xsi:type="Combodo-ValueType-PropertyTree">
|
||||
<nodes>
|
||||
<node id="sub_form_property" xsi:type="Combodo-ValueType-PropertyTree">
|
||||
<label>UI:SubForm:Title</label>
|
||||
<nodes>
|
||||
<node id="string_property" xsi:type="Combodo-ValueType-String">
|
||||
<label>UI:String</label>
|
||||
</node>
|
||||
</nodes>
|
||||
</node>
|
||||
</nodes>
|
||||
</definition>
|
||||
</property_typeproperty_type>
|
||||
XML,
|
||||
'sExpectedPHP' => <<<PHP
|
||||
class SubFormFor__SubFormTest__sub_form_property extends Combodo\iTop\Forms\Block\Base\FormBlock
|
||||
{
|
||||
protected function BuildForm(): void
|
||||
{
|
||||
\$this->Add('string_property', 'Combodo\iTop\Forms\Block\Base\TextFormBlock', [
|
||||
'label' => 'UI:String',
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
class FormFor__SubFormTest extends Combodo\iTop\Forms\Block\Base\FormBlock
|
||||
{
|
||||
protected function BuildForm(): void
|
||||
{
|
||||
\$this->Add('sub_form_property', 'SubFormFor__SubFormTest__sub_form_property', [
|
||||
'label' => 'UI:SubForm:Title',
|
||||
]);
|
||||
}
|
||||
}
|
||||
PHP,
|
||||
],
|
||||
'Collection of values' => [
|
||||
'sXMLContent' => <<<XML
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<property_typeproperty_type id="CollectionOfValuesTest" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="Combodo-PropertyType" xsi:noNamespaceSchemaLocation = "https://www.combodo.com/itop-schema/3.3">
|
||||
<extends>Dashlet</extends>
|
||||
<definition xsi:type="Combodo-ValueType-PropertyTree">
|
||||
<nodes>
|
||||
<node id="coll" xsi:type="Combodo-ValueType-CollectionOfValues">
|
||||
<label>UI:ClassAttributeValue</label>
|
||||
<xml-format xsi:type="Combodo-XMLFormat-CSV"/>
|
||||
<value-type xsi:type="Combodo-ValueType-ClassAttributeValue">
|
||||
<class>Contact</class>
|
||||
<attribute>status</attribute>
|
||||
</value-type>
|
||||
</node>
|
||||
</nodes>
|
||||
</definition>
|
||||
</property_typeproperty_type>
|
||||
XML,
|
||||
'sExpectedPHP' => <<<PHP
|
||||
class FormFor__CollectionOfValuesTest extends Combodo\iTop\Forms\Block\Base\FormBlock
|
||||
{
|
||||
protected function BuildForm(): void
|
||||
{
|
||||
\$this->Add('coll', 'Combodo\iTop\Forms\Block\DataModel\AttributeValueChoiceFormBlock', [
|
||||
'label' => 'UI:ClassAttributeValue',
|
||||
'multiple' => true,
|
||||
]);
|
||||
}
|
||||
}
|
||||
PHP,
|
||||
],
|
||||
'Single value' => [
|
||||
'sXMLContent' => <<<XML
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<property_typeproperty_type id="SingleValueTest" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="Combodo-PropertyType" xsi:noNamespaceSchemaLocation = "https://www.combodo.com/itop-schema/3.3">
|
||||
<extends>Dashlet</extends>
|
||||
<definition xsi:type="Combodo-ValueType-Label">
|
||||
<label>Single Test</label>
|
||||
</definition>
|
||||
</property_typeproperty_type>
|
||||
XML,
|
||||
'sExpectedPHP' => <<<PHP
|
||||
class FormFor__SingleValueTest extends Combodo\iTop\Forms\Block\DataModel\LabelFormBlock
|
||||
{
|
||||
}
|
||||
PHP,
|
||||
],
|
||||
'test' => [
|
||||
'sXMLContent' => <<<XML
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<property_typeproperty_type id="Test" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="Combodo-PropertyType" xsi:noNamespaceSchemaLocation = "https://www.combodo.com/itop-schema/3.3">
|
||||
<extends>Dashlet</extends>
|
||||
<definition xsi:type="Combodo-ValueType-PropertyTree">
|
||||
<nodes>
|
||||
</nodes>
|
||||
</definition>
|
||||
</property_typeproperty_type>
|
||||
XML,
|
||||
'sExpectedPHP' => <<<PHP
|
||||
class FormFor__Test extends Combodo\iTop\Forms\Block\Base\FormBlock
|
||||
{
|
||||
protected function BuildForm(): void
|
||||
{ }
|
||||
}
|
||||
PHP,
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider CompileFormFromInvalidXMLProvider
|
||||
*
|
||||
* @param string $sXMLContent
|
||||
* @param string $sExpectedClass
|
||||
* @param string $sExpectedMessage
|
||||
*
|
||||
* @return void
|
||||
* @throws \Combodo\iTop\PropertyType\Compiler\PropertyTypeCompilerException
|
||||
* @throws \Combodo\iTop\PropertyType\PropertyTypeException
|
||||
* @throws \DOMFormatException
|
||||
*/
|
||||
public function testCompileFormFromInvalidXML(string $sXMLContent, string $sExpectedClass, string $sExpectedMessage)
|
||||
{
|
||||
$this->expectException($sExpectedClass);
|
||||
$this->expectExceptionMessage($sExpectedMessage);
|
||||
PropertyTypeCompiler::GetInstance()->CompileFormFromXML($sXMLContent);
|
||||
}
|
||||
|
||||
public function CompileFormFromInvalidXMLProvider()
|
||||
{
|
||||
return [
|
||||
'Invalid OQL expression in condition' => [
|
||||
'sXMLContent' => <<<XML
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<property_type id="RelevanceCondition" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="Combodo-PropertyType" xsi:noNamespaceSchemaLocation = "https://www.combodo.com/itop-schema/3.3">
|
||||
<extends>Dashlet</extends>
|
||||
<definition xsi:type="Combodo-ValueType-PropertyTree">
|
||||
<nodes>
|
||||
<node id="dependant_property" xsi:type="Combodo-ValueType-String">
|
||||
<label>UI:Dependant</label>
|
||||
<relevance-condition>{{source_property.text == 'count'}}</relevance-condition>
|
||||
</node>
|
||||
</nodes>
|
||||
</definition>
|
||||
</property_type>
|
||||
XML,
|
||||
'sExpectedClass' => 'Combodo\iTop\PropertyType\PropertyTypeException',
|
||||
'sExpectedMessage' => 'Node: dependant_property, invalid syntax in condition: Unexpected token EQ - found \'=\' at 22 in \'source_property.text == \'count\'\'',
|
||||
],
|
||||
|
||||
'Unknown source in relevance condition' => [
|
||||
'sXMLContent' => <<<XML
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<property_type id="RelevanceCondition" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="Combodo-PropertyType" xsi:noNamespaceSchemaLocation = "https://www.combodo.com/itop-schema/3.3">
|
||||
<extends>Dashlet</extends>
|
||||
<definition xsi:type="Combodo-ValueType-PropertyTree">
|
||||
<nodes>
|
||||
<node id="dependant_property" xsi:type="Combodo-ValueType-String">
|
||||
<label>UI:Dependant</label>
|
||||
<relevance-condition>{{source_property.text = 'count'}}</relevance-condition>
|
||||
</node>
|
||||
</nodes>
|
||||
</definition>
|
||||
</property_type>
|
||||
XML,
|
||||
'sExpectedClass' => 'Combodo\iTop\PropertyType\PropertyTypeException',
|
||||
'sExpectedMessage' => 'Node: dependant_property, invalid source in condition: source_property',
|
||||
],
|
||||
|
||||
'Unknown output in relevance condition' => [
|
||||
'sXMLContent' => <<<XML
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<property_type id="RelevanceCondition" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="Combodo-PropertyType" xsi:noNamespaceSchemaLocation = "https://www.combodo.com/itop-schema/3.3">
|
||||
<extends>Dashlet</extends>
|
||||
<definition xsi:type="Combodo-ValueType-PropertyTree">
|
||||
<nodes>
|
||||
<node id="source_property" xsi:type="Combodo-ValueType-String">
|
||||
<label>UI:Source</label>
|
||||
</node>
|
||||
<node id="dependant_property" xsi:type="Combodo-ValueType-String">
|
||||
<label>UI:Dependant</label>
|
||||
<relevance-condition>{{source_property.text_output != 'count'}}</relevance-condition>
|
||||
</node>
|
||||
</nodes>
|
||||
</definition>
|
||||
</property_type>
|
||||
XML,
|
||||
'sExpectedClass' => 'Combodo\iTop\PropertyType\PropertyTypeException',
|
||||
'sExpectedMessage' => 'Node: dependant_property, invalid output in condition: source_property.text_output',
|
||||
],
|
||||
|
||||
'Missing output or source in relevance condition' => [
|
||||
'sXMLContent' => <<<XML
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<property_type id="RelevanceCondition" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="Combodo-PropertyType" xsi:noNamespaceSchemaLocation = "https://www.combodo.com/itop-schema/3.3">
|
||||
<extends>Dashlet</extends>
|
||||
<definition xsi:type="Combodo-ValueType-PropertyTree">
|
||||
<nodes>
|
||||
<node id="source_property" xsi:type="Combodo-ValueType-String">
|
||||
<label>UI:Source</label>
|
||||
</node>
|
||||
<node id="dependant_property" xsi:type="Combodo-ValueType-String">
|
||||
<label>UI:Dependant</label>
|
||||
<relevance-condition>{{source_property != 'count'}}</relevance-condition>
|
||||
</node>
|
||||
</nodes>
|
||||
</definition>
|
||||
</property_type>
|
||||
XML,
|
||||
'sExpectedClass' => 'Combodo\iTop\PropertyType\PropertyTypeException',
|
||||
'sExpectedMessage' => 'Node: dependant_property, missing output or source in condition: source_property',
|
||||
],
|
||||
|
||||
'Missing value-type in node specification' => [
|
||||
'sXMLContent' => <<<XML
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<property_type id="WrongDefinition" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="Combodo-PropertyType" xsi:noNamespaceSchemaLocation = "https://www.combodo.com/itop-schema/3.3">
|
||||
<extends>Dashlet</extends>
|
||||
<definition xsi:type="Combodo-ValueType-PropertyTree">
|
||||
<nodes>
|
||||
<node id="source_property">
|
||||
<label>UI:Source</label>
|
||||
</node>
|
||||
</nodes>
|
||||
</definition>
|
||||
</property_type>
|
||||
XML,
|
||||
'sExpectedClass' => 'Combodo\iTop\PropertyType\PropertyTypeException',
|
||||
'sExpectedMessage' => '/property_type[WrongDefinition]/definition/nodes/node[source_property]: Missing value-type in node specification',
|
||||
],
|
||||
'Wrong class for value-type in node specification' => [
|
||||
'sXMLContent' => <<<XML
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<property_type id="WrongDefinition" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="Combodo-PropertyType" xsi:noNamespaceSchemaLocation = "https://www.combodo.com/itop-schema/3.3">
|
||||
<extends>Dashlet</extends>
|
||||
<definition xsi:type="Combodo-ValueType-PropertyTree">
|
||||
<nodes>
|
||||
<node id="source_property" xsi:type="Test-Combodo">
|
||||
<label>UI:Source</label>
|
||||
</node>
|
||||
</nodes>
|
||||
</definition>
|
||||
</property_type>
|
||||
XML,
|
||||
'sExpectedClass' => 'Combodo\iTop\PropertyType\PropertyTypeException',
|
||||
'sExpectedMessage' => '/property_type[WrongDefinition]/definition/nodes/node[source_property]: Unknown value-type node class: "Test-Combodo"',
|
||||
],
|
||||
'Wrong class for xml-format in node specification' => [
|
||||
'sXMLContent' => <<<XML
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<property_type id="WrongDefinition" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="Combodo-PropertyType" xsi:noNamespaceSchemaLocation = "https://www.combodo.com/itop-schema/3.3">
|
||||
<extends>Dashlet</extends>
|
||||
<definition xsi:type="Combodo-ValueType-PropertyTree">
|
||||
<nodes>
|
||||
<node id="coll" xsi:type="Combodo-ValueType-CollectionOfValues">
|
||||
<label>UI:ClassAttributeValue</label>
|
||||
<xml-format xsi:type="Combodo-test"/>
|
||||
<value-type xsi:type="Combodo-ValueType-ClassAttributeValue">
|
||||
<class>Contact</class>
|
||||
<attribute>status</attribute>
|
||||
</value-type>
|
||||
</node>
|
||||
</nodes>
|
||||
</definition>
|
||||
</property_type>
|
||||
XML,
|
||||
'sExpectedClass' => 'Combodo\iTop\PropertyType\Serializer\SerializerException',
|
||||
'sExpectedMessage' => '/property_type[WrongDefinition]/definition/nodes/node[coll]/xml-format: Unknown type node class: "Combodo-test"',
|
||||
],
|
||||
'Missing class for xml-format in node specification' => [
|
||||
'sXMLContent' => <<<XML
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<property_type id="WrongDefinition" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="Combodo-PropertyType" xsi:noNamespaceSchemaLocation = "https://www.combodo.com/itop-schema/3.3">
|
||||
<extends>Dashlet</extends>
|
||||
<definition xsi:type="Combodo-ValueType-PropertyTree">
|
||||
<nodes>
|
||||
<node id="coll" xsi:type="Combodo-ValueType-CollectionOfValues">
|
||||
<label>UI:ClassAttributeValue</label>
|
||||
<xml-format/>
|
||||
<value-type xsi:type="Combodo-ValueType-ClassAttributeValue">
|
||||
<class>Contact</class>
|
||||
<attribute>status</attribute>
|
||||
</value-type>
|
||||
</node>
|
||||
</nodes>
|
||||
</definition>
|
||||
</property_type>
|
||||
XML,
|
||||
'sExpectedClass' => 'Combodo\iTop\PropertyType\Serializer\SerializerException',
|
||||
'sExpectedMessage' => '/property_type[WrongDefinition]/definition/nodes/node[coll]/xml-format: Missing xsi:type in node specification',
|
||||
],
|
||||
'Missing tag in xml-format ' => [
|
||||
'sXMLContent' => <<<XML
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<property_type id="WrongDefinition" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="Combodo-PropertyType" xsi:noNamespaceSchemaLocation = "https://www.combodo.com/itop-schema/3.3">
|
||||
<extends>Dashlet</extends>
|
||||
<definition xsi:type="Combodo-ValueType-PropertyTree">
|
||||
<nodes>
|
||||
<node xsi:type="Combodo-ValueType-CollectionOfValues">
|
||||
<xml-format xsi:type="Combodo-XMLFormat-ValueAsId">
|
||||
</xml-format>
|
||||
<value-type xsi:type="Combodo-ValueType-Class">
|
||||
</value-type>
|
||||
</node>
|
||||
</nodes>
|
||||
</definition>
|
||||
</property_type>
|
||||
XML,
|
||||
'sExpectedClass' => 'Combodo\iTop\PropertyType\Serializer\SerializerException',
|
||||
'sExpectedMessage' => '/property_type[WrongDefinition]/definition/nodes/node/xml-format: Missing <tag-name> element',
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,331 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* @copyright Copyright (C) 2010-2026 Combodo SAS
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
use Combodo\iTop\PropertyType\Compiler\PropertyTypeCompiler;
|
||||
use Combodo\iTop\PropertyType\PropertyTypeDesign;
|
||||
use Combodo\iTop\Service\DependencyInjection\ServiceLocator;
|
||||
use Combodo\iTop\Test\UnitTest\ItopDataTestCase;
|
||||
|
||||
class XMLSerializerTest extends ItopDataTestCase
|
||||
{
|
||||
/**
|
||||
* @dataProvider XMLSerializerProvider
|
||||
*
|
||||
* @param $inputContent
|
||||
* @param string $sPropertyTypeXML
|
||||
* @param string $sExpectedXMLContent
|
||||
*
|
||||
* @return void
|
||||
* @throws \DOMException
|
||||
*/
|
||||
public function testSerializeXML($inputContent, string $sPropertyTypeXML, string $sExpectedXMLContent)
|
||||
{
|
||||
ServiceLocator::GetInstance()->RegisterService('ModelReflection', new ModelReflectionRuntime());
|
||||
|
||||
$oDOMDocument = new PropertyTypeDesign();
|
||||
$oDOMDocument->preserveWhiteSpace = false;
|
||||
$oDOMDocument->formatOutput = true;
|
||||
|
||||
/** @var \Combodo\iTop\DesignElement $oRootNode */
|
||||
$oRootNode = $oDOMDocument->createElement('root');
|
||||
$oDOMDocument->appendChild($oRootNode);
|
||||
|
||||
Combodo\iTop\PropertyType\Serializer\XMLSerializer::GetInstance()->SerializeForPropertyType($inputContent, $oRootNode, $sPropertyTypeXML);
|
||||
|
||||
$sActualXML = $oDOMDocument->saveXML();
|
||||
|
||||
$this->AssertEqualiTopXML($sExpectedXMLContent, $sActualXML);
|
||||
}
|
||||
|
||||
public function XMLSerializerProvider()
|
||||
{
|
||||
return [
|
||||
'Basic test should serialize to XML' => [
|
||||
'inputContent' => 'text',
|
||||
'sPropertyTypeXML' => <<<XML
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<property_type id="basic_test" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="Combodo-PropertyType" xsi:noNamespaceSchemaLocation = "https://www.combodo.com/itop-schema/3.3">
|
||||
<extends>Dashlet</extends>
|
||||
<definition xsi:type="Combodo-ValueType-Label">
|
||||
</definition>
|
||||
</property_type>
|
||||
XML,
|
||||
'sExpectedXMLContent' => <<<XML
|
||||
<?xml version="1.0"?>
|
||||
<root>text</root>
|
||||
XML,
|
||||
],
|
||||
'Collection of values as CSV' => [
|
||||
'inputContent' => ['Contact', 'Organization'],
|
||||
'sPropertyTypeXML' => <<<XML
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<property_type id="basic_test" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="Combodo-PropertyType" xsi:noNamespaceSchemaLocation = "https://www.combodo.com/itop-schema/3.3">
|
||||
<extends>Dashlet</extends>
|
||||
<definition xsi:type="Combodo-ValueType-CollectionOfValues">
|
||||
<xml-format xsi:type="Combodo-XMLFormat-CSV"/>
|
||||
<value-type xsi:type="Combodo-ValueType-Class">
|
||||
</value-type>
|
||||
</definition>
|
||||
</property_type>
|
||||
XML,
|
||||
'sExpectedXMLContent' => <<<XML
|
||||
<?xml version="1.0"?>
|
||||
<root>Contact,Organization</root>
|
||||
XML,
|
||||
],
|
||||
'Collection of values as id attribute' => [
|
||||
'inputContent' => ['Contact', 'Organization'],
|
||||
'sPropertyTypeXML' => <<<XML
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<property_type id="class_test" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="Combodo-PropertyType" xsi:noNamespaceSchemaLocation = "https://www.combodo.com/itop-schema/3.3">
|
||||
<extends>Dashlet</extends>
|
||||
<definition xsi:type="Combodo-ValueType-CollectionOfValues">
|
||||
<xml-format xsi:type="Combodo-XMLFormat-ValueAsId">
|
||||
<tag-name>item</tag-name>
|
||||
</xml-format>
|
||||
<value-type xsi:type="Combodo-ValueType-Class">
|
||||
</value-type>
|
||||
</definition>
|
||||
</property_type>
|
||||
XML,
|
||||
'sExpectedXMLContent' => <<<XML
|
||||
<?xml version="1.0"?>
|
||||
<root>
|
||||
<item id="Contact"/>
|
||||
<item id="Organization"/>
|
||||
</root>
|
||||
XML,
|
||||
],
|
||||
'Collection of tree as flat array' => [
|
||||
'inputContent' => [
|
||||
[
|
||||
'title_property' => 'title_a',
|
||||
'class_property' => 'class_a',
|
||||
],
|
||||
[
|
||||
'title_property' => 'title_b',
|
||||
'class_property' => 'class_b',
|
||||
],
|
||||
],
|
||||
'sPropertyTypeXML' => <<<XML
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<property_type id="collection_test" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="Combodo-PropertyType" xsi:noNamespaceSchemaLocation = "https://www.combodo.com/itop-schema/3.3">
|
||||
<extends>Dashlet</extends>
|
||||
<definition xsi:type="Combodo-ValueType-Collection">
|
||||
<xml-format xsi:type="Combodo-XMLFormat-FlatArray">
|
||||
<count-tag>item_count</count-tag>
|
||||
<tag-format>item_\$rank\$_\$id\$</tag-format>
|
||||
</xml-format>
|
||||
<prototype>
|
||||
<node id="title_property" xsi:type="Combodo-ValueType-Label">
|
||||
<label>UI:BasicTest:Prop-Title</label>
|
||||
</node>
|
||||
<node id="class_property" xsi:type="Combodo-ValueType-Class">
|
||||
<label>UI:BasicTest:Prop-Class</label>
|
||||
<categories-csv>test</categories-csv>
|
||||
</node>
|
||||
</prototype>
|
||||
</definition>
|
||||
</property_type>
|
||||
XML,
|
||||
'sExpectedXMLContent' => <<<XML
|
||||
<?xml version="1.0"?>
|
||||
<root>
|
||||
<item_count>2</item_count>
|
||||
<item_0_title_property>title_a</item_0_title_property>
|
||||
<item_0_class_property>class_a</item_0_class_property>
|
||||
<item_1_title_property>title_b</item_1_title_property>
|
||||
<item_1_class_property>class_b</item_1_class_property>
|
||||
</root>
|
||||
XML,
|
||||
],
|
||||
'Property tree' => [
|
||||
'inputContent' => ['title_property' => 'title', 'class_property' => 'class'],
|
||||
'sPropertyTypeXML' => <<<XML
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<property_type id="property_tree_test" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="Combodo-PropertyType" xsi:noNamespaceSchemaLocation = "https://www.combodo.com/itop-schema/3.3">
|
||||
<extends>Dashlet</extends>
|
||||
<definition xsi:type="Combodo-ValueType-PropertyTree">
|
||||
<nodes>
|
||||
<node id="title_property" xsi:type="Combodo-ValueType-Label">
|
||||
<label>UI:BasicTest:Prop-Title</label>
|
||||
</node>
|
||||
<node id="class_property" xsi:type="Combodo-ValueType-Class">
|
||||
<label>UI:BasicTest:Prop-Class</label>
|
||||
<categories-csv>test</categories-csv>
|
||||
</node>
|
||||
</nodes>
|
||||
</definition>
|
||||
</property_type>
|
||||
XML,
|
||||
'sExpectedXMLContent' => <<<XML
|
||||
<?xml version="1.0"?>
|
||||
<root>
|
||||
<title_property>title</title_property>
|
||||
<class_property>class</class_property>
|
||||
</root>
|
||||
XML,
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider XMLUnserializerProvider
|
||||
*
|
||||
* @param $sInputXMLContent
|
||||
* @param string $sPropertyTypeXML
|
||||
* @param $expectedValue
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function testUnserializeXML($sInputXMLContent, string $sPropertyTypeXML, $expectedValue)
|
||||
{
|
||||
ServiceLocator::GetInstance()->RegisterService('ModelReflection', new ModelReflectionRuntime());
|
||||
|
||||
$oDoc = new PropertyTypeDesign();
|
||||
$oDoc->loadXML($sInputXMLContent);
|
||||
/** @var \Combodo\iTop\DesignElement $oRoot */
|
||||
$oRoot = $oDoc->firstChild;
|
||||
|
||||
$aActualValue = Combodo\iTop\PropertyType\Serializer\XMLSerializer::GetInstance()->UnserializeForPropertyType($oRoot, $sPropertyTypeXML);
|
||||
|
||||
$this->assertEquals($expectedValue, $aActualValue);
|
||||
}
|
||||
|
||||
public function XMLUnserializerProvider()
|
||||
{
|
||||
return [
|
||||
'Basic test should unserialize from XML' => [
|
||||
'sInputXMLContent' => <<<XML
|
||||
<?xml version="1.0"?>
|
||||
<root>text</root>
|
||||
XML,
|
||||
'sPropertyTypeXML' => <<<XML
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<property_type id="basic_test" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="Combodo-PropertyType" xsi:noNamespaceSchemaLocation = "https://www.combodo.com/itop-schema/3.3">
|
||||
<extends>Dashlet</extends>
|
||||
<definition xsi:type="Combodo-ValueType-Label">
|
||||
</definition>
|
||||
</property_type>
|
||||
XML,
|
||||
'expectedValue' => 'text',
|
||||
],
|
||||
'Collection of values as CSV' => [
|
||||
'sInputXMLContent' => <<<XML
|
||||
<?xml version="1.0"?>
|
||||
<root>Contact,Organization</root>
|
||||
XML,
|
||||
'sPropertyTypeXML' => <<<XML
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<property_type id="basic_test" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="Combodo-PropertyType" xsi:noNamespaceSchemaLocation = "https://www.combodo.com/itop-schema/3.3">
|
||||
<extends>Dashlet</extends>
|
||||
<definition xsi:type="Combodo-ValueType-CollectionOfValues">
|
||||
<xml-format xsi:type="Combodo-XMLFormat-CSV"/>
|
||||
<value-type xsi:type="Combodo-ValueType-Class">
|
||||
</value-type>
|
||||
</definition>
|
||||
</property_type>
|
||||
XML,
|
||||
'expectedValue' => ['Contact', 'Organization'],
|
||||
],
|
||||
'Collection of values as id attribute' => [
|
||||
'sInputXMLContent' => <<<XML
|
||||
<?xml version="1.0"?>
|
||||
<root>
|
||||
<item id="Contact"/>
|
||||
<item id="Organization"/>
|
||||
</root>
|
||||
XML,
|
||||
'sPropertyTypeXML' => <<<XML
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<property_type id="class_test" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="Combodo-PropertyType" xsi:noNamespaceSchemaLocation = "https://www.combodo.com/itop-schema/3.3">
|
||||
<extends>Dashlet</extends>
|
||||
<definition xsi:type="Combodo-ValueType-CollectionOfValues">
|
||||
<xml-format xsi:type="Combodo-XMLFormat-ValueAsId">
|
||||
<tag-name>item</tag-name>
|
||||
</xml-format>
|
||||
<value-type xsi:type="Combodo-ValueType-Class">
|
||||
</value-type>
|
||||
</definition>
|
||||
</property_type>
|
||||
XML,
|
||||
'expectedValue' => ['Contact', 'Organization'],
|
||||
],
|
||||
'Collection of tree as flat array' => [
|
||||
'sInputXMLContent' => <<<XML
|
||||
<?xml version="1.0"?>
|
||||
<root>
|
||||
<item_count>2</item_count>
|
||||
<item_0_title_property>title_a</item_0_title_property>
|
||||
<item_0_class_property>class_a</item_0_class_property>
|
||||
<item_1_title_property>title_b</item_1_title_property>
|
||||
<item_1_class_property>class_b</item_1_class_property>
|
||||
</root>
|
||||
XML,
|
||||
'sPropertyTypeXML' => <<<XML
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<property_type id="collection_test" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="Combodo-PropertyType" xsi:noNamespaceSchemaLocation = "https://www.combodo.com/itop-schema/3.3">
|
||||
<extends>Dashlet</extends>
|
||||
<definition xsi:type="Combodo-ValueType-Collection">
|
||||
<xml-format xsi:type="Combodo-XMLFormat-FlatArray">
|
||||
<count-tag>item_count</count-tag>
|
||||
<tag-format>item_\$rank\$_\$id\$</tag-format>
|
||||
</xml-format>
|
||||
<prototype>
|
||||
<node id="title_property" xsi:type="Combodo-ValueType-Label">
|
||||
<label>UI:BasicTest:Prop-Title</label>
|
||||
</node>
|
||||
<node id="class_property" xsi:type="Combodo-ValueType-Class">
|
||||
<label>UI:BasicTest:Prop-Class</label>
|
||||
<categories-csv>test</categories-csv>
|
||||
</node>
|
||||
</prototype>
|
||||
</definition>
|
||||
</property_type>
|
||||
XML,
|
||||
'expectedValue' => [
|
||||
[
|
||||
'title_property' => 'title_a',
|
||||
'class_property' => 'class_a',
|
||||
],
|
||||
[
|
||||
'title_property' => 'title_b',
|
||||
'class_property' => 'class_b',
|
||||
],
|
||||
],
|
||||
],
|
||||
'Property tree' => [
|
||||
'sInputXMLContent' => <<<XML
|
||||
<?xml version="1.0"?>
|
||||
<root>
|
||||
<title_property>title</title_property>
|
||||
<class_property>class</class_property>
|
||||
</root>
|
||||
XML,
|
||||
'sPropertyTypeXML' => <<<XML
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<property_type id="property_tree_test" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="Combodo-PropertyType" xsi:noNamespaceSchemaLocation = "https://www.combodo.com/itop-schema/3.3">
|
||||
<extends>Dashlet</extends>
|
||||
<definition xsi:type="Combodo-ValueType-PropertyTree">
|
||||
<nodes>
|
||||
<node id="title_property" xsi:type="Combodo-ValueType-Label">
|
||||
<label>UI:BasicTest:Prop-Title</label>
|
||||
</node>
|
||||
<node id="class_property" xsi:type="Combodo-ValueType-Class">
|
||||
<label>UI:BasicTest:Prop-Class</label>
|
||||
<categories-csv>test</categories-csv>
|
||||
</node>
|
||||
</nodes>
|
||||
</definition>
|
||||
</property_type>
|
||||
XML,
|
||||
'expectedValue' => ['title_property' => 'title', 'class_property' => 'class'],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
}
|
||||
@@ -156,10 +156,26 @@ class DataModelDependantCacheTest extends ItopTestCase
|
||||
$this->assertEquals($iRefTime, $this->oCacheService->GetEntryModificationTime('pool-A', 'key'), 'GetEntryModificationTime should return the modification time of the cache file');
|
||||
$this->assertEquals(null, $this->oCacheService->GetEntryModificationTime('pool-A', 'non-existing-key'), 'GetEntryModificationTime should return null for an invalid key');
|
||||
}
|
||||
|
||||
public function testKeyUndesiredCharactersShouldBeTransformedToUnderscore()
|
||||
{
|
||||
$sUglyKey = 'key with ugly characters:\{&"#@ç^²/,;[(|🤔';
|
||||
$sUglyKey = 'key with ugly characters:\{&"#@ç^²,;[(|🤔';
|
||||
$sFilePath = $this->InvokeNonPublicMethod(DataModelDependantCache::class, 'MakeCacheFileName', $this->oCacheService, ['pool-A', $sUglyKey]);
|
||||
$this->assertEquals('key_with_ugly_characters______________________.php', basename($sFilePath));
|
||||
$this->assertEquals('key_with_ugly_characters_____________________.php', basename($sFilePath));
|
||||
}
|
||||
|
||||
public function testKeyCanBeADirectoryTree()
|
||||
{
|
||||
$sBaseKey = 'test';
|
||||
$sBaseFilePath = $this->InvokeNonPublicMethod(DataModelDependantCache::class, 'MakeCacheFileName', $this->oCacheService, ['pool-A', $sBaseKey]);
|
||||
|
||||
$sKey = 'Path/To/KeyCanBePath';
|
||||
$sFilePath = $this->InvokeNonPublicMethod(DataModelDependantCache::class, 'MakeCacheFileName', $this->oCacheService, ['pool-A', $sKey]);
|
||||
|
||||
$this->assertEquals(dirname($sBaseFilePath).'/Path/To', dirname($sFilePath));
|
||||
|
||||
$this->oCacheService->Store('pool-A', $sKey, 'some data...');
|
||||
$this->assertTrue($this->oCacheService->HasEntry('pool-A', $sKey), 'The data should have been stored');
|
||||
$this->assertFileExists($sFilePath, 'A file should have been created in the corresponding directory');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -94,7 +94,6 @@ class RestTest extends ItopDataTestCase
|
||||
|
||||
public function testPostJSONDataAsCurlFile()
|
||||
{
|
||||
$sCallbackName = 'fooCallback';
|
||||
$sJsonData = '{"operation": "list_operations"}';
|
||||
|
||||
// Test regular JSON result
|
||||
@@ -269,7 +268,7 @@ JSON;
|
||||
*
|
||||
* @return bool|string
|
||||
*/
|
||||
private function CallRestApi_HTTP(string $sJsonDataContent = null, string $sCallbackName = null, bool $bJSONDataAsFile = false)
|
||||
private function CallRestApi_HTTP(?string $sJsonDataContent = null, ?string $sCallbackName = null, bool $bJSONDataAsFile = false)
|
||||
{
|
||||
$ch = curl_init();
|
||||
$aPostFields = [
|
||||
|
||||
Reference in New Issue
Block a user