Merge remote-tracking branch 'refs/remotes/origin/support/3.2' into develop

This commit is contained in:
jf-cbd
2024-04-24 17:13:36 +02:00
6 changed files with 176 additions and 7 deletions

View File

@@ -1695,7 +1695,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],
);

View File

@@ -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/",

View File

@@ -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;
}
}

View File

@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<itop_design xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="3.0">
<classes>
<class id="UserRequest">
<fields>
<field id="status" xsi:type="AttributeEnum">
<always_load_in_tables>true</always_load_in_tables>
<sort_type>rank</sort_type>
<values>
<value id="New_org_name_with_quote" _delta="define">
<code>New'status</code>
<rank>32</rank>
</value>
</values>
</field>
</fields>
</class>
</classes>
</itop_design>

View File

@@ -0,0 +1,95 @@
<?php
/*
* @copyright Copyright (C) 2010-2024 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
namespace Combodo\iTop\Test\UnitTest\Application;
use Combodo\iTop\Application\UI\DisplayBlock\BlockChartAjaxPie\BlockChartAjaxPie;
use Combodo\iTop\Test\UnitTest\ItopCustomDatamodelTestCase;
use DBSearch;
use DisplayBlock;
use MetaModel;
use UserRequest;
class DisplayBlockTest extends ItopCustomDatamodelTestCase
{
const CREATE_TEST_ORG = true;
public function GetDatamodelDeltaAbsPath(): string
{
return __DIR__ . '/Delta/add-enum-value-with-quote.xml';
}
public function renderChartAjaxProvider(): array
{
return [
'simple string : name' => [ // 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&apos;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&apos;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&apos;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));
}
}

View File

@@ -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;
}
}
]]></content>