diff --git a/application/displayblock.class.inc.php b/application/displayblock.class.inc.php index 37515dd1e..89d1c32c7 100644 --- a/application/displayblock.class.inc.php +++ b/application/displayblock.class.inc.php @@ -1693,7 +1693,7 @@ JS $sHtmlValue = $oGroupByExp->MakeValueLabel($this->m_oFilter, $sValue, $sValue); $iTotalCount += $aRow['_itop_count_']; $aValues[] = array( - 'label' => html_entity_decode(strip_tags($sHtmlValue), ENT_QUOTES, 'UTF-8'), + 'label' => $sValue, 'label_html' => $sHtmlValue, 'value' => (float)$aRow[$sFctVar], ); diff --git a/tests/php-unit-tests/composer.json b/tests/php-unit-tests/composer.json index 263eba2f1..5352590ea 100644 --- a/tests/php-unit-tests/composer.json +++ b/tests/php-unit-tests/composer.json @@ -4,6 +4,9 @@ "sempro/phpunit-pretty-print": "^1.4" }, "autoload": { + "classmap": [ + "unitary-tests/" + ], "psr-4": { "Combodo\\iTop\\Test\\UnitTest\\": "src/BaseTestCase/", "Combodo\\iTop\\Test\\UnitTest\\Hook\\": "src/Hook/", diff --git a/tests/php-unit-tests/src/Service/UnitTestRunTimeEnvironment.php b/tests/php-unit-tests/src/Service/UnitTestRunTimeEnvironment.php index 63ded52c7..0c76e727f 100644 --- a/tests/php-unit-tests/src/Service/UnitTestRunTimeEnvironment.php +++ b/tests/php-unit-tests/src/Service/UnitTestRunTimeEnvironment.php @@ -9,9 +9,11 @@ namespace Combodo\iTop\Test\UnitTest\Service; use Combodo\iTop\Test\UnitTest\ItopCustomDatamodelTestCase; use IssueLog; +use LogChannels; use MFCoreModule; use ReflectionClass; use RunTimeEnvironment; +use utils; /** @@ -33,12 +35,15 @@ class UnitTestRunTimeEnvironment extends RunTimeEnvironment /** @var string[] $aDeltaFiles Referential of loaded deltas. Mostly to avoid duplicates. */ $aDeltaFiles = []; - foreach (get_declared_classes() as $sClass) { - // Filter on classes derived from this \Combodo\iTop\Test\UnitTest\ItopCustomDatamodelTestCaseItopCustomDatamodelTestCase - if (false === is_a($sClass, ItopCustomDatamodelTestCase::class, true)) { - continue; - } - + $aRelatedClasses = $this->GetClassesExtending( + ItopCustomDatamodelTestCase::class, + array( + '[\\\\/]tests[\\\\/]php-unit-tests[\\\\/]vendor[\\\\/]', + '[\\\\/]tests[\\\\/]php-unit-tests[\\\\/]unitary-tests[\\\\/]datamodels[\\\\/]2.x[\\\\/]authent-local', + )); + //Combodo\iTop\Test\UnitTest\Application\ApplicationExtensionTest + //Combodo\iTop\Test\UnitTest\Application\ApplicationExtensionTest + foreach ($aRelatedClasses as $sClass) { $oReflectionClass = new ReflectionClass($sClass); $oReflectionMethod = $oReflectionClass->getMethod('GetDatamodelDeltaAbsPath'); @@ -83,4 +88,50 @@ class UnitTestRunTimeEnvironment extends RunTimeEnvironment return $aRet; } + protected function GetClassesExtending (string $sExtendedClass, array $aExcludedPath = []) : array { + $aMatchingClasses = []; + + $aAutoloadClassMaps =[__DIR__."/../../vendor/composer/autoload_classmap.php"]; + + $aClassMap = []; + $aAutoloaderErrors = []; + foreach ($aAutoloadClassMaps as $sAutoloadFile) { + $aTmpClassMap = include $sAutoloadFile; + /** @noinspection SlowArrayOperationsInLoopInspection we are getting an associative array so the documented workarounds cannot be used */ + $aClassMap = array_merge($aClassMap, $aTmpClassMap); + } + foreach ($aClassMap as $sPHPClass => $sPHPFile) { + $bSkipped = false; + if (utils::IsNotNullOrEmptyString($sPHPFile)) { + $sPHPFile = utils::LocalPath($sPHPFile); + if ($sPHPFile !== false) { + $sPHPFile = '/'.$sPHPFile; // for regex + foreach ($aExcludedPath as $sExcludedPath) { + // Note: We use '#' as delimiters as usual '/' is often used in paths. + if ($sExcludedPath !== '' && preg_match('#'.$sExcludedPath.'#', $sPHPFile) === 1) { + $bSkipped = true; + break; + } + } + } else { + $bSkipped = true; // file not found + } + } + + if (!$bSkipped) { + try { + $oRefClass = new ReflectionClass($sPHPClass); + if ($oRefClass->isSubclassOf($sExtendedClass) && + !$oRefClass->isInterface() && !$oRefClass->isAbstract() && !$oRefClass->isTrait()) { + $aMatchingClasses[] = $sPHPClass; + } + } + catch (Exception $e) { + } + } + } + return $aMatchingClasses; + } + + } \ No newline at end of file diff --git a/tests/php-unit-tests/unitary-tests/application/DisplayBlock/Delta/add-enum-value-with-quote.xml b/tests/php-unit-tests/unitary-tests/application/DisplayBlock/Delta/add-enum-value-with-quote.xml new file mode 100644 index 000000000..97d4a7cdb --- /dev/null +++ b/tests/php-unit-tests/unitary-tests/application/DisplayBlock/Delta/add-enum-value-with-quote.xml @@ -0,0 +1,19 @@ + + + + + + + true + rank + + + New'status + 32 + + + + + + + \ No newline at end of file diff --git a/tests/php-unit-tests/unitary-tests/application/DisplayBlock/DisplayBlockTest.php b/tests/php-unit-tests/unitary-tests/application/DisplayBlock/DisplayBlockTest.php new file mode 100644 index 000000000..f111d101e --- /dev/null +++ b/tests/php-unit-tests/unitary-tests/application/DisplayBlock/DisplayBlockTest.php @@ -0,0 +1,95 @@ + [ // chart with UserRequest title (evaluating string/scalar escaping) + 'class to display' => 'UserRequest', + 'class attribute to display' => 'title', + 'class to edit' => 'UserRequest', + 'related class attribute to edit' => 'title', + 'expected' => "New'name", + 'nonExpected' => 'New'name', + ], + 'enum : status' => [ // chart with UserRequest status (evaluating enum escaping) + // not working because we need to allow a new value for the enum + 'class to display' => 'UserRequest', + 'attribute to display' => 'status', + 'class to edit' => 'UserRequest', + 'related class attribute to edit' => 'status', + 'expected' => "New'status", + 'nonExpected' => 'New'status', + ], + 'relation : Org name' => [ // chart with related organization name title (evaluating ext key escaping) + 'class to display' => 'UserRequest', + 'class attribute to display' => 'org_name', + 'class to edit' => 'Organization', + 'related class attribute to edit' => 'name', + 'expected' => "New'org_name", + 'nonExpected' => 'New'org_name', + ], + ]; + } + + /** + * @dataProvider renderChartAjaxProvider + */ + public function testRenderChartAjax(string $sClassToDisplay, string $sAttributeToDisplay, string $sRelatedClass, string $sRelatedClassAttributeToEdit, string $sExpected, string $sNonExpected): void + { + $oUserRequest = new UserRequest(); + $oUserRequest->Set('title', 'MyTitle'); + $oUserRequest->Set('org_id', $this->getTestOrgId()); + $oUserRequest->Set('description', "MyDescription"); + $oUserRequest->DBInsert(); + + if ($sRelatedClass !== "UserRequest") { + $oInstanceRelatedClass = MetaModel::GetObject($sRelatedClass, $this->getTestOrgId()); + } else { + $oInstanceRelatedClass = $oUserRequest; + } + + $oInstanceRelatedClass->Set($sRelatedClassAttributeToEdit, $sExpected); // attribute that shouldn't be encoded + $oInstanceRelatedClass->DBUpdate(); + + $oDisplayBlock = new DisplayBlock( + DBSearch::FromOQL("SELECT $sClassToDisplay"), + DisplayBlock::ENUM_STYLE_CHART_AJAX + ); + + $aExtraParams = [ + "group_by" => $sAttributeToDisplay, + "currentId" => "fake-dashlet-id", + "order_direction" => "asc", + "order_by" => $sAttributeToDisplay, + "limit" => 10, + ]; + /** @var BlockChartAjaxPie $oBlock */ + $oBlock = $this->InvokeNonPublicMethod(get_class($oDisplayBlock), "RenderChartAjax", $oDisplayBlock, [$aExtraParams]); + + $aJSNames = json_decode($oBlock->sJSNames, true); + + $this->assertFalse(in_array($sNonExpected, $aJSNames)); + $this->assertTrue(in_array($sExpected, $aJSNames)); + } +} \ No newline at end of file diff --git a/tests/php-unit-tests/unitary-tests/application/applicationextension/Delta/application-extension-usages-in-snippets.xml b/tests/php-unit-tests/unitary-tests/application/applicationextension/Delta/application-extension-usages-in-snippets.xml index 96d06ee9b..d71490820 100644 --- a/tests/php-unit-tests/unitary-tests/application/applicationextension/Delta/application-extension-usages-in-snippets.xml +++ b/tests/php-unit-tests/unitary-tests/application/applicationextension/Delta/application-extension-usages-in-snippets.xml @@ -292,6 +292,7 @@ class ExampleFor_iQueryModifier implements \iQueryModifier public function GetFieldExpression(QueryBuilderContext &$oBuild, $sClass, $sAttCode, $sColId, Expression $oFieldSQLExp, SQLQuery &$oSelect) { // Do nothing, we just need the class to exists for the unit test + return $oFieldSQLExp; } } ]]>